grafX2/pages.c
Adrien Destugues 306a004e36 First upload of the code.
git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@2 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2007-04-14 20:18:30 +00:00

1017 lines
35 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//////////////////////////////////////////////////////////////////////////
/////////////////////////// GESTION DU BACKUP ////////////////////////////
//////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "linux.h"
#include "global.h"
#include "pages.h"
#include "graph.h"
// On dclare mchamment le prototype de Erreur pour viter de faire un
// fichier "main.h":
void Erreur(int Code);
///
/// GESTION DES PAGES
///
void Initialiser_S_Page(S_Page * Page)
{
// Important: appeler cette fonction sur toute nouvelle structure S_Page!
if (Page!=NULL)
{
Page->Image=NULL;
Page->Largeur=0;
Page->Hauteur=0;
memset(Page->Palette,0,sizeof(T_Palette));
memset(Page->Commentaire,0,TAILLE_COMMENTAIRE+1);
memset(Page->Repertoire_fichier,0,256);
memset(Page->Nom_fichier,0,13);
Page->Format_fichier=FORMAT_PAR_DEFAUT;
/*
Page->Decalage_X=0;
Page->Decalage_Y=0;
Page->Ancien_Decalage_X=0;
Page->Ancien_Decalage_Y=0;
Page->Split=0;
Page->X_Zoom=0;
Page->Proportion_split=PROPORTION_SPLIT;
Page->Loupe_Mode=0;
Page->Loupe_Facteur=FACTEUR_DE_ZOOM_PAR_DEFAUT;
Page->Loupe_Hauteur=0;
Page->Loupe_Largeur=0;
Page->Loupe_Decalage_X=0;
Page->Loupe_Decalage_Y=0;
*/
}
}
void Download_infos_page_principal(S_Page * Page)
{
int Indice_facteur;
int Dimensions_modifiees;
if (Page!=NULL)
{
Dimensions_modifiees=(Principal_Largeur_image!=Page->Largeur) ||
(Principal_Hauteur_image!=Page->Hauteur);
Principal_Ecran=Page->Image;
Principal_Largeur_image=Page->Largeur;
Principal_Hauteur_image=Page->Hauteur;
memcpy(Principal_Palette,Page->Palette,sizeof(T_Palette));
memcpy(Principal_Commentaire,Page->Commentaire,TAILLE_COMMENTAIRE+1);
memcpy(Principal_Repertoire_fichier,Page->Repertoire_fichier,256);
memcpy(Principal_Nom_fichier,Page->Nom_fichier,13);
Principal_Format_fichier=Page->Format_fichier;
/*
Principal_Decalage_X=Page->Decalage_X;
Principal_Decalage_Y=Page->Decalage_Y;
// On corrige les dcalages en fonction de la dimension de l'cran
if ( (Principal_Decalage_X>0) &&
(Principal_Decalage_X+Largeur_ecran>Principal_Largeur_image) )
Principal_Decalage_X=Max(0,Principal_Largeur_image-Largeur_ecran);
if ( (Principal_Decalage_Y>0) &&
(Principal_Decalage_Y+Menu_Ordonnee>Principal_Hauteur_image) )
Principal_Decalage_Y=Max(0,Principal_Hauteur_image-Menu_Ordonnee);
Ancien_Principal_Decalage_X=Page->Ancien_Decalage_X;
Ancien_Principal_Decalage_Y=Page->Ancien_Decalage_Y;
Principal_Split=Page->Split;
Principal_X_Zoom=Page->X_Zoom;
Principal_Proportion_split=Page->Proportion_split;
Loupe_Mode=Page->Loupe_Mode;
Loupe_Facteur=Page->Loupe_Facteur;
Loupe_Hauteur=Page->Loupe_Hauteur;
Loupe_Largeur=Page->Loupe_Largeur;
Loupe_Decalage_X=Page->Loupe_Decalage_X;
Loupe_Decalage_Y=Page->Loupe_Decalage_Y;
// Comme le facteur de zoom a des chances d'avoir chang, on appelle
// "Changer_facteur_loupe".
for (Indice_facteur=0; FACTEUR_ZOOM[Indice_facteur]!=Loupe_Facteur; Indice_facteur++);
Changer_facteur_loupe(Indice_facteur);
*/
if (Dimensions_modifiees)
{
Loupe_Mode=0;
Principal_Decalage_X=0;
Principal_Decalage_Y=0;
Pixel_Preview=Pixel_Preview_Normal;
Calculer_limites();
Calculer_coordonnees_pinceau();
}
}
}
void Upload_infos_page_principal(S_Page * Page)
{
if (Page!=NULL)
{
Page->Image=Principal_Ecran;
Page->Largeur=Principal_Largeur_image;
Page->Hauteur=Principal_Hauteur_image;
memcpy(Page->Palette,Principal_Palette,sizeof(T_Palette));
memcpy(Page->Commentaire,Principal_Commentaire,TAILLE_COMMENTAIRE+1);
memcpy(Page->Repertoire_fichier,Principal_Repertoire_fichier,256);
memcpy(Page->Nom_fichier,Principal_Nom_fichier,13);
Page->Format_fichier=Principal_Format_fichier;
/*
Page->Decalage_X=Principal_Decalage_X;
Page->Decalage_Y=Principal_Decalage_Y;
Page->Ancien_Decalage_X=Ancien_Principal_Decalage_X;
Page->Ancien_Decalage_X=Ancien_Principal_Decalage_Y;
Page->Split=Principal_Split;
Page->X_Zoom=Principal_X_Zoom;
Page->Proportion_split=Principal_Proportion_split;
Page->Loupe_Mode=Loupe_Mode;
Page->Loupe_Facteur=Loupe_Facteur;
Page->Loupe_Hauteur=Loupe_Hauteur;
Page->Loupe_Largeur=Loupe_Largeur;
Page->Loupe_Decalage_X=Loupe_Decalage_X;
Page->Loupe_Decalage_Y=Loupe_Decalage_Y;
*/
}
}
void Download_infos_page_brouillon(S_Page * Page)
{
if (Page!=NULL)
{
Brouillon_Ecran=Page->Image;
Brouillon_Largeur_image=Page->Largeur;
Brouillon_Hauteur_image=Page->Hauteur;
memcpy(Brouillon_Palette,Page->Palette,sizeof(T_Palette));
memcpy(Brouillon_Commentaire,Page->Commentaire,TAILLE_COMMENTAIRE+1);
memcpy(Brouillon_Repertoire_fichier,Page->Repertoire_fichier,256);
memcpy(Brouillon_Nom_fichier,Page->Nom_fichier,13);
Brouillon_Format_fichier=Page->Format_fichier;
/*
Brouillon_Decalage_X=Page->Decalage_X;
Brouillon_Decalage_Y=Page->Decalage_Y;
Ancien_Brouillon_Decalage_X=Page->Ancien_Decalage_X;
Ancien_Brouillon_Decalage_Y=Page->Ancien_Decalage_Y;
Brouillon_Split=Page->Split;
Brouillon_X_Zoom=Page->X_Zoom;
Brouillon_Proportion_split=Page->Proportion_split;
Brouillon_Loupe_Mode=Page->Loupe_Mode;
Brouillon_Loupe_Facteur=Page->Loupe_Facteur;
Brouillon_Loupe_Hauteur=Page->Loupe_Hauteur;
Brouillon_Loupe_Largeur=Page->Loupe_Largeur;
Brouillon_Loupe_Decalage_X=Page->Loupe_Decalage_X;
Brouillon_Loupe_Decalage_Y=Page->Loupe_Decalage_Y;
*/
}
}
void Upload_infos_page_brouillon(S_Page * Page)
{
if (Page!=NULL)
{
Page->Image=Brouillon_Ecran;
Page->Largeur=Brouillon_Largeur_image;
Page->Hauteur=Brouillon_Hauteur_image;
memcpy(Page->Palette,Brouillon_Palette,sizeof(T_Palette));
memcpy(Page->Commentaire,Brouillon_Commentaire,TAILLE_COMMENTAIRE+1);
memcpy(Page->Repertoire_fichier,Brouillon_Repertoire_fichier,256);
memcpy(Page->Nom_fichier,Brouillon_Nom_fichier,13);
Page->Format_fichier=Brouillon_Format_fichier;
/*
Page->Decalage_X=Brouillon_Decalage_X;
Page->Decalage_Y=Brouillon_Decalage_Y;
Page->Ancien_Decalage_X=Ancien_Brouillon_Decalage_X;
Page->Ancien_Decalage_Y=Ancien_Brouillon_Decalage_Y;
Page->Split=Brouillon_Split;
Page->X_Zoom=Brouillon_X_Zoom;
Page->Proportion_split=Brouillon_Proportion_split;
Page->Loupe_Mode=Brouillon_Loupe_Mode;
Page->Loupe_Facteur=Brouillon_Loupe_Facteur;
Page->Loupe_Hauteur=Brouillon_Loupe_Hauteur;
Page->Loupe_Largeur=Brouillon_Loupe_Largeur;
Page->Loupe_Decalage_X=Brouillon_Loupe_Decalage_X;
Page->Loupe_Decalage_Y=Brouillon_Loupe_Decalage_Y;
*/
}
}
void Download_infos_backup(S_Liste_de_pages * Liste)
{
Ecran_backup=Liste->Pages[1].Image;
if (Config.FX_Feedback)
FX_Feedback_Ecran=Liste->Pages[0].Image;
else
FX_Feedback_Ecran=Liste->Pages[1].Image;
}
int Allouer_une_page(S_Page * Page,int Largeur,int Hauteur)
{
// Important: la S_Page ne doit pas dj… dsigner une page alloue auquel
// cas celle-ci serait perdue.
/* Debug : if (Page->Image!=NULL) exit(666); */
// On alloue la mmoire pour le bitmap
Page->Image=(byte *)malloc(Largeur*Hauteur);
// On vrifie que l'allocation se soit bien passe
if (Page->Image==NULL)
return 0; // Echec
else
{
Page->Largeur=Largeur;
Page->Hauteur=Hauteur;
// Important: La mise … jour des autres infos est du ressort de
// l'appelant.
return 1; // SuccŠs
}
}
void Liberer_une_page(S_Page * Page)
{
// On peut appeler cette fonction sur une page non alloue.
if (Page->Image!=NULL)
free(Page->Image);
Page->Image=NULL;
Page->Largeur=0;
Page->Hauteur=0;
// On ne se proccupe pas de ce que deviens le reste des infos de l'image.
}
void Copier_S_page(S_Page * Destination,S_Page * Source)
{
*Destination=*Source;
}
int Taille_d_une_page(S_Page * Page)
{
return sizeof(S_Page)+(Page->Largeur*Page->Hauteur)+8;
// 8 = 4 + 4
// (Toute zone alloue en mmoire est prcde d'un mot double indiquant sa
// taille, or la taille d'un mot double est de 4 octets, et on utilise deux
// allocations de mmoires: une pour la S_Page et une pour l'image)
}
///
/// GESTION DES LISTES DE PAGES
///
void Initialiser_S_Liste_de_pages(S_Liste_de_pages * Liste)
{
// Important: appeler cette fonction sur toute nouvelle structure
// S_Liste_de_pages!
Liste->Taille_liste=0;
Liste->Nb_pages_allouees=0;
Liste->Pages=NULL;
}
int Allouer_une_liste_de_pages(S_Liste_de_pages * Liste,int Taille)
{
// Important: la S_Liste_de_pages ne doit pas dj… dsigner une liste de
// pages alloue auquel cas celle-ci serait perdue.
int Indice;
/* Debug : if (Liste->Pages!=NULL) exit(666); */
// On alloue la mmoire pour la liste
Liste->Pages=(S_Page *)malloc(Taille*sizeof(S_Page));
// On vrifie que l'allocation se soit bien passe
if (Liste->Pages==NULL)
return 0; // Echec
else
{
// On initialise chacune des nouvelles pages
for (Indice=0;Indice<Taille;Indice++)
Initialiser_S_Page(Liste->Pages+Indice);
Liste->Taille_liste=Taille;
Liste->Nb_pages_allouees=0;
return 1; // SuccŠs
}
}
void Liberer_une_liste_de_pages(S_Liste_de_pages * Liste)
{
// On peut appeler cette fonction sur une liste de pages non alloue.
// Important: cette fonction ne libŠre pas les pages de la liste. Il faut
// donc le faire pralablement si ncessaire.
if (Liste->Pages!=NULL)
free(Liste->Pages);
Liste->Pages=NULL;
Liste->Taille_liste=0;
Liste->Nb_pages_allouees=0;
}
int Taille_d_une_liste_de_pages(S_Liste_de_pages * Liste)
{
int Resultat=0;
int Indice;
for (Indice=0;Indice<Liste->Nb_pages_allouees;Indice++)
Resultat+=Taille_d_une_page(Liste->Pages+Indice);
return Resultat+sizeof(S_Liste_de_pages)+4;
// C.F. la remarque … propos de Taille_d_une_page pour la valeur 4.
}
void Reculer_dans_une_liste_de_pages(S_Liste_de_pages * Liste)
{
// Cette fonction fait l'quivalent d'un "Undo" dans la liste de pages.
// Elle effectue une sorte de ROL (Rotation Left) sur la liste:
// ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» |
// º0º1³2³3³4³5³6³7³8³9³Aº |
// ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | 0=Page courante
// ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ |_ A=Page la plus ancienne
// v v v v v v v v v v v | 1=DerniŠre page (1er backup)
// ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» |
// º1º2³3³4³5³6³7³8³9³A³0º |
// ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ |
// Pour simuler un vritable Undo, l'appelant doit mettre la structure
// de page courante … jour avant l'appel, puis en rextraire les infos en
// sortie, ainsi que celles relatives … la plus rcente page d'undo (1Šre
// page de la liste).
int Indice;
S_Page * Page_tempo;
if (Liste->Nb_pages_allouees>1)
{
// On cre la page tempo
Page_tempo=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Page_tempo);
// On copie la 1Šre page (Page 0) dans la page temporaire
Copier_S_page(Page_tempo,Liste->Pages);
// On copie toutes les pages 1-A … leur gauche
for (Indice=1;Indice<Liste->Nb_pages_allouees;Indice++)
Copier_S_page(Liste->Pages+Indice-1,Liste->Pages+Indice);
// On copie la page 0 (dont la sauvegarde a t effectue dans la page
// temporaire) en derniŠre position
Copier_S_page(Liste->Pages+Liste->Nb_pages_allouees-1,Page_tempo);
// On dtruit la page tempo
free(Page_tempo);
}
}
void Avancer_dans_une_liste_de_pages(S_Liste_de_pages * Liste)
{
// Cette fonction fait l'quivalent d'un "Redo" dans la liste de pages.
// Elle effectue une sorte de ROR (Rotation Right) sur la liste:
// ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» |
// º0º1³2³3³4³5³6³7³8³9³Aº |
// ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ | 0=Page courante
// ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ |_ A=Page la plus ancienne
// v v v v v v v v v v v | 1=DerniŠre page (1er backup)
// ÉÍËÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍÑÍ» |
// ºAº0³1³2³3³4³5³6³7³8³9º |
// ÈÍÊÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏÍÏͼ |
// Pour simuler un vritable Redo, l'appelant doit mettre la structure
// de page courante … jour avant l'appel, puis en rextraire les infos en
// sortie, ainsi que celles relatives … la plus rcente page d'undo (1Šre
// page de la liste).
int Indice;
S_Page * Page_tempo;
if (Liste->Nb_pages_allouees>1)
{
// On cre la page tempo
Page_tempo=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Page_tempo);
// On copie la derniŠre page dans la page temporaire
Copier_S_page(Page_tempo,Liste->Pages+Liste->Nb_pages_allouees-1);
// On copie toutes les pages 0-9 … leur droite
for (Indice=Liste->Nb_pages_allouees-1;Indice>0;Indice--)
Copier_S_page(Liste->Pages+Indice,Liste->Pages+Indice-1);
// On copie la page plus ancienne page (la "A", dont la sauvegarde a t
// effectue dans la page temporaire) en 1Šre position
Copier_S_page(Liste->Pages,Page_tempo);
// On dtruit la page tempo
free(Page_tempo);
}
}
int Nouvelle_page_possible(S_Page * Nouvelle_page,S_Liste_de_pages * Liste_courante,S_Liste_de_pages * Liste_secondaire)
{
int Taille_immediatement_disponible;
int Taille_liste_courante;
int Taille_liste_brouillon;
int Taille_page_courante;
int Taille_page_brouillon;
int Taille_nouvelle_page;
Taille_immediatement_disponible=Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER;
Taille_liste_courante =Taille_d_une_liste_de_pages(Liste_courante);
Taille_liste_brouillon=Taille_d_une_liste_de_pages(Liste_secondaire);
Taille_page_courante =Taille_d_une_page(Liste_courante->Pages);
Taille_page_brouillon =Taille_d_une_page(Liste_secondaire->Pages);
Taille_nouvelle_page =Taille_d_une_page(Nouvelle_page);
// Il faut pouvoir loger la nouvelle page et son backup dans la page
// courante, en conservant au pire la 1Šre page de brouillon.
if ((Taille_immediatement_disponible+Taille_liste_courante+
Taille_liste_brouillon-Taille_page_brouillon)<(2*Taille_nouvelle_page))
return 0;
// Il faut pouvoir loger le brouillon et son backup dans la page de
// brouillon, en conservant au pire un exemplaire de la nouvelle page dans
// la page courante. (pour permettre … l'utilisateur de travailler sur son
// brouillon)
if ((Taille_immediatement_disponible+Taille_liste_courante+
Taille_liste_brouillon-Taille_nouvelle_page)<(2*Taille_page_brouillon))
return 0;
return 1;
}
void Detruire_derniere_page_allouee_de_la_liste(S_Liste_de_pages * Liste)
{
if (Liste!=NULL)
{
if (Liste->Nb_pages_allouees>0)
{
Liste->Nb_pages_allouees--;
Liberer_une_page(Liste->Pages+Liste->Nb_pages_allouees);
}
}
}
void Creer_nouvelle_page(S_Page * Nouvelle_page,S_Liste_de_pages * Liste_courante,S_Liste_de_pages * Liste_secondaire)
{
// Cette fonction cre une nouvelle page dont les attributs correspondent …
// ceux de Nouvelle_page (Largeur,Hauteur,...) (le champ Image est invalide
// … l'appel, c'est la fonction qui le met … jour), et l'enfile dans
// Liste_courante.
// Il est impratif que la cration de cette page soit possible,
// ventuellement au dtriment des backups de la page de brouillon
// (Liste_secondaire). Afin de s'en assurer, il faut vrifier cette
// possibilit … l'aide de
// Nouvelle_page_possible(Nouvelle_page,Liste_courante,Liste_secondaire) avant
// l'appel … cette fonction.
// De plus, il faut qu'il y ait au moins une page dans chacune des listes.
int Il_faut_liberer;
S_Liste_de_pages * Liste_a_raboter;
S_Page * Page_a_supprimer;
int Indice;
// On regarde s'il faut librer des pages:
Il_faut_liberer=
// C'est le cas si la Liste_courante est pleine
( (Liste_courante->Taille_liste==Liste_courante->Nb_pages_allouees)
// ou qu'il ne reste plus assez de place pour allouer la Nouvelle_page
|| ( (Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)<
(Nouvelle_page->Hauteur*Nouvelle_page->Largeur) ) );
if (!Il_faut_liberer)
{
// On a assez de place pour allouer une page, et de plus la Liste_courante
// n'est pas pleine. On n'a donc aucune page … supprimer. On peut en
// allouer une directement.
Nouvelle_page->Image=(byte *)malloc(Nouvelle_page->Hauteur*Nouvelle_page->Largeur);
}
else
{
// On manque de mmoire ou la Liste_courante est pleine. Dans tous les
// cas, il faut librer une page... qui peut-ˆtre pourra re-servir.
// Tant qu'il faut librer
while (Il_faut_liberer)
{
// On cherche sur quelle liste on va virer une page
// S'il reste des pages … librer dans la Liste_courante
if (Liste_courante->Nb_pages_allouees>1)
// Alors on va dtruire la derniŠre page alloue de la Liste_courante
Liste_a_raboter=Liste_courante;
else
{
if (Liste_secondaire->Nb_pages_allouees>1)
{
// Sinon on va dtruire la derniŠre page alloue de la
// Liste_secondaire
Liste_a_raboter=Liste_secondaire;
}
else
{
Erreur(ERREUR_SORRY_SORRY_SORRY);
}
}
// Puis on dtermine la page que l'on va supprimer (c'est la derniŠre de
// la liste)
Page_a_supprimer=Liste_a_raboter->Pages+(Liste_a_raboter->Nb_pages_allouees)-1;
// On regarde si on peut recycler directement la page (cas o— elle
// aurait la mˆme surface que la Nouvelle_page)
if ((Page_a_supprimer->Hauteur*Page_a_supprimer->Largeur)==
(Nouvelle_page->Hauteur*Nouvelle_page->Largeur))
{
// Alors
// On rcupŠre le bitmap de la page … supprimer (vite de faire des
// allocations/dsallocations fastidieuses et inutiles)
Nouvelle_page->Image=Page_a_supprimer->Image;
// On fait semblant que la derniŠre page alloue ne l'est pas
Liste_a_raboter->Nb_pages_allouees--;
// On n'a plus besoin de librer de la mmoire puisqu'on a refil
// Nouvelle_page un bitmap valide
Il_faut_liberer=0;
}
else
{
// Sinon
// Dtruire la derniŠre page alloue dans la Liste_…_raboter
Detruire_derniere_page_allouee_de_la_liste(Liste_a_raboter);
// On regarde s'il faut continuer … librer de la place
Il_faut_liberer=(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)
<(Nouvelle_page->Hauteur*Nouvelle_page->Largeur);
// S'il ne faut pas, c'est qu'on peut allouer un bitmap
// pour la Nouvelle_page
if (!Il_faut_liberer)
Nouvelle_page->Image=(byte *)malloc(Nouvelle_page->Hauteur*Nouvelle_page->Largeur);
}
}
}
// D'aprŠs l'hypothŠse de dpart, la boucle ci-dessus doit s'arrˆter car
// on a assez de mmoire pour allouer la nouvelle page.
// Dsormais Nouvelle_page contient un pointeur sur une zone bitmap valide.
// Dcaler la Liste_courante d'un cran vers le pass.
for (Indice=Liste_courante->Taille_liste-1;Indice>0;Indice--)
Copier_S_page(Liste_courante->Pages+Indice,Liste_courante->Pages+Indice-1);
// Recopier la Nouvelle_page en 1Šre position de la Liste_courante
Copier_S_page(Liste_courante->Pages,Nouvelle_page);
Liste_courante->Nb_pages_allouees++;
}
void Changer_nombre_de_pages_d_une_liste(S_Liste_de_pages * Liste,int Nb)
{
int Indice;
S_Page * Nouvelles_pages;
// Si la liste a dj… la taille demande
if (Liste->Taille_liste==Nb)
// Alors il n'y a rien … faire
return;
// Si la liste contient plus de pages que souhait
if (Liste->Taille_liste>Nb)
// Alors pour chaque page en excs
for (Indice=Nb;Indice<Liste->Taille_liste;Indice++)
// On libŠre la page
Liberer_une_page(Liste->Pages+Indice);
// On fait une nouvelle liste de pages:
Nouvelles_pages=(S_Page *)malloc(Nb*sizeof(S_Page));
for (Indice=0;Indice<Nb;Indice++)
Initialiser_S_Page(Nouvelles_pages+Indice);
// On recopie les pages … conserver de l'ancienne liste
for (Indice=0;Indice<Min(Nb,Liste->Taille_liste);Indice++)
Copier_S_page(Nouvelles_pages+Indice,Liste->Pages+Indice);
// On libŠre l'ancienne liste
free(Liste->Pages);
// On met … jour les champs de la nouvelle liste
Liste->Pages=Nouvelles_pages;
Liste->Taille_liste=Nb;
if (Liste->Nb_pages_allouees>Nb)
Liste->Nb_pages_allouees=Nb;
}
void Detruire_la_page_courante_d_une_liste(S_Liste_de_pages * Liste)
{
// On ne peut pas dtruire la page courante de la liste si aprŠs
// destruction il ne reste pas encore au moins une page.
if (Liste->Nb_pages_allouees>1)
{
// On fait faire un undo … la liste, comme ‡a, la nouvelle page courante
// est la page prcdente
Reculer_dans_une_liste_de_pages(Principal_Backups);
// Puis on dtruit la derniŠre page, qui est l'ancienne page courante
Detruire_derniere_page_allouee_de_la_liste(Liste);
}
}
///
/// GESTION DES BACKUPS
///
int Initialiser_les_listes_de_backups_en_debut_de_programme(int Taille,int Largeur,int Hauteur)
{
// Taille correspond au nombre de pages que l'on souhaite dans chaque liste
// (1 pour la page courante, puis 1 pour chaque backup, soit 2 au minimum).
// Largeur et Hauteur correspondent … la dimension des images de dpart.
S_Page * Page;
int Retour=0;
if (Allouer_une_liste_de_pages(Principal_Backups,Taille) &&
Allouer_une_liste_de_pages(Brouillon_Backups,Taille))
{
// On a russi … allouer deux listes de pages dont la taille correspond …
// celle demande par l'utilisateur.
// On cre un descripteur de page correspondant … la page principale
Page=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Page);
Upload_infos_page_principal(Page);
// On y met les infos sur la dimension de dmarrage
Page->Largeur=Largeur;
Page->Hauteur=Hauteur;
// On regarde si on peut ajouter cette page
if (Nouvelle_page_possible(Page,Principal_Backups,Brouillon_Backups))
{
// On peut, donc on va la crer
Creer_nouvelle_page(Page,Principal_Backups,Brouillon_Backups);
Download_infos_page_principal(Page);
Download_infos_backup(Principal_Backups);
// Maintenant, on regarde si on a le droit de crer la mˆme page dans
// la page de brouillon.
if (Nouvelle_page_possible(Page,Brouillon_Backups,Principal_Backups))
{
// On peut donc on le fait
Creer_nouvelle_page(Page,Brouillon_Backups,Principal_Backups);
Download_infos_page_brouillon(Page);
// Et on efface les 2 images en les remplacant de "0"
memset(Principal_Ecran,0,Principal_Largeur_image*Principal_Hauteur_image);
memset(Brouillon_Ecran,0,Brouillon_Largeur_image*Brouillon_Hauteur_image);
Retour=1;
}
else
{
// Il n'est pas possible de dmarrer le programme avec la page
// principale et la page de brouillon aux dimensions demande par
// l'utilisateur. ==> On l'envoie ballader
Retour=0;
}
}
else
{
// On ne peut pas dmarrer le programme avec ne serait-ce qu'une page
// de la dimension souhaite, donc on laisse tout tomber et on le
// renvoie chier.
Retour=0;
}
}
else
{
// On n'a mˆme pas russi … crer les listes. Donc c'est mˆme pas la
// peine de continuer : l'utilisateur ne pourra jamais rien faire, autant
// avorter le chargement du programme.
Retour=0;
}
return Retour;
}
void Detruire_les_listes_de_backups_en_fin_de_programme(void)
{
// On commence par supprimer les pages une … une dans chacune des listes
// Liste de la page principale
while (Principal_Backups->Nb_pages_allouees>0)
Detruire_derniere_page_allouee_de_la_liste(Principal_Backups);
// Liste de la page de brouillon
while (Brouillon_Backups->Nb_pages_allouees>0)
Detruire_derniere_page_allouee_de_la_liste(Brouillon_Backups);
// Puis on peut dtruire les structures de liste elles-mˆmes
Liberer_une_liste_de_pages(Principal_Backups);
Liberer_une_liste_de_pages(Brouillon_Backups);
free(Principal_Backups);
free(Brouillon_Backups);
}
void Nouveau_nombre_de_backups(int Nouveau)
{
Changer_nombre_de_pages_d_une_liste(Principal_Backups,Nouveau+1);
Changer_nombre_de_pages_d_une_liste(Brouillon_Backups,Nouveau+1);
// Le +1 vient du fait que dans chaque liste, en 1Šre position on retrouve
// les infos de la page courante sur le brouillon et la page principale.
// (Nouveau = Nombre de backups, sans compter les pages courantes)
}
int Backup_avec_nouvelles_dimensions(int Upload,int Largeur,int Hauteur)
{
// Retourne 1 si une nouvelle page est disponible (alors pleine de 0) et
// 0 sinon.
S_Page * Nouvelle_page;
int Retour=0;
if (Upload)
// On remet … jour l'tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On cre un descripteur pour la nouvelle page courante
Nouvelle_page=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Nouvelle_page);
Upload_infos_page_principal(Nouvelle_page);
Nouvelle_page->Largeur=Largeur;
Nouvelle_page->Hauteur=Hauteur;
if (Nouvelle_page_possible(Nouvelle_page,Principal_Backups,Brouillon_Backups))
{
Creer_nouvelle_page(Nouvelle_page,Principal_Backups,Brouillon_Backups);
Download_infos_page_principal(Nouvelle_page);
Download_infos_backup(Principal_Backups);
// On nettoie la nouvelle image:
memset(Principal_Ecran,0,Principal_Largeur_image*Principal_Hauteur_image);
Retour=1;
}
// On dtruit le descripteur de la page courante
free(Nouvelle_page);
return Retour;
}
int Backuper_et_redimensionner_brouillon(int Largeur,int Hauteur)
{
// Retourne 1 si la page de dimension souhaitee est disponible en brouillon
// et 0 sinon.
S_Page * Nouvelle_page;
int Retour=0;
// On remet … jour l'tat des infos de la page de brouillon (pour pouvoir
// les retrouver plus tard)
Upload_infos_page_brouillon(Brouillon_Backups->Pages);
// On cre un descripteur pour la nouvelle page de brouillon
Nouvelle_page=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Nouvelle_page);
Upload_infos_page_brouillon(Nouvelle_page);
Nouvelle_page->Largeur=Largeur;
Nouvelle_page->Hauteur=Hauteur;
if (Nouvelle_page_possible(Nouvelle_page,Brouillon_Backups,Principal_Backups))
{
Creer_nouvelle_page(Nouvelle_page,Brouillon_Backups,Principal_Backups);
Download_infos_page_brouillon(Nouvelle_page);
Retour=1;
}
// On dtruit le descripteur de la page courante
free(Nouvelle_page);
return Retour;
}
void Backup(void)
{
S_Page * Nouvelle_page;
// On remet … jour l'tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On cre un descripteur pour la nouvelle page courante
Nouvelle_page=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Nouvelle_page);
// Enrichissement de l'historique
Copier_S_page(Nouvelle_page,Principal_Backups->Pages);
Creer_nouvelle_page(Nouvelle_page,Principal_Backups,Brouillon_Backups);
Download_infos_page_principal(Nouvelle_page);
Download_infos_backup(Principal_Backups);
// On copie l'image du backup vers la page courante:
memcpy(Principal_Ecran,Ecran_backup,Principal_Largeur_image*Principal_Hauteur_image);
// On dtruit le descripteur de la page courante
free(Nouvelle_page);
// On allume l'indicateur de modification de l'image
Principal_Image_modifiee=1;
}
void Undo(void)
{
// On remet … jour l'tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On fait faire un undo … la liste des backups de la page principale
Reculer_dans_une_liste_de_pages(Principal_Backups);
// On extrait ensuite les infos sur la nouvelle page courante
Download_infos_page_principal(Principal_Backups->Pages);
// Et celles du backup
Download_infos_backup(Principal_Backups);
// Note: le backup n'a pas obligatoirement les mˆmes dimensions ni la mˆme
// palette que la page courante. Mais en temps normal, le backup
// n'est pas utilis … la suite d'un Undo. Donc ‡a ne devrait pas
// poser de problŠmes.
}
void Redo(void)
{
// On remet … jour l'tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On fait faire un redo … la liste des backups de la page principale
Avancer_dans_une_liste_de_pages(Principal_Backups);
// On extrait ensuite les infos sur la nouvelle page courante
Download_infos_page_principal(Principal_Backups->Pages);
// Et celles du backup
Download_infos_backup(Principal_Backups);
// Note: le backup n'a pas obligatoirement les mˆmes dimensions ni la mˆme
// palette que la page courante. Mais en temps normal, le backup
// n'est pas utilis … la suite d'un Redo. Donc ‡a ne devrait pas
// poser de problŠmes.
}
void Detruire_la_page_courante(void)
{
// On dtruit la page courante de la liste principale
Detruire_la_page_courante_d_une_liste(Principal_Backups);
// On extrait ensuite les infos sur la nouvelle page courante
Download_infos_page_principal(Principal_Backups->Pages);
// Et celles du backup
Download_infos_backup(Principal_Backups);
// Note: le backup n'a pas obligatoirement les mˆmes dimensions ni la mˆme
// palette que la page courante. Mais en temps normal, le backup
// n'est pas utilis … la suite d'une destruction de page. Donc ‡a ne
// devrait pas poser de problŠmes.
}
void Interchanger_image_principale_et_brouillon(void)
{
S_Liste_de_pages * Liste_tempo;
// On commence par mettre … jour dans les descripteurs les infos sur les
// pages qu'on s'apprˆte … changer, pour qu'on se retrouve pas avec de
// vieilles valeurs qui datent de mathuzalem.
Upload_infos_page_principal(Principal_Backups->Pages);
Upload_infos_page_brouillon(Brouillon_Backups->Pages);
// On inverse les listes de pages
Liste_tempo=Principal_Backups;
Principal_Backups=Brouillon_Backups;
Brouillon_Backups=Liste_tempo;
// On extrait ensuite les infos sur les nouvelles pages courante, brouillon
// et backup.
/* SECTION GROS CACA PROUT PROUT */
// Auparavant on ruse en mettant dj… … jour les dimensions de la
// nouvelle page courante. Si on ne le fait pas, le "Download" va dtecter
// un changement de dimensions et va bˆtement sortir du mode loupe, alors
// que lors d'un changement de page, on veut bien conserver l'tat du mode
// loupe du brouillon.
Principal_Largeur_image=Principal_Backups->Pages->Largeur;
Principal_Hauteur_image=Principal_Backups->Pages->Hauteur;
Download_infos_page_principal(Principal_Backups->Pages);
Download_infos_page_brouillon(Brouillon_Backups->Pages);
Download_infos_backup(Principal_Backups);
}
int Emprunt_memoire_de_page_possible(int taille)
{
int Taille_immediatement_disponible;
int Taille_liste_courante;
int Taille_liste_brouillon;
int Taille_page_courante;
int Taille_page_brouillon;
Taille_immediatement_disponible=Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER;
Taille_liste_courante =Taille_d_une_liste_de_pages(Principal_Backups);
Taille_liste_brouillon=Taille_d_une_liste_de_pages(Brouillon_Backups);
Taille_page_courante =Taille_d_une_page(Principal_Backups->Pages);
Taille_page_brouillon =Taille_d_une_page(Brouillon_Backups->Pages);
// Il faut pouvoir loger la zone mmoire ainsi qu'un exemplaire de la page
// courante, en conservant au pire la 1Šre page de brouillon.
if ((Taille_immediatement_disponible
+Taille_liste_courante
+Taille_liste_brouillon
-Taille_page_courante
-Taille_page_brouillon)<taille)
return 0;
return 1;
}
void * Emprunter_memoire_de_page(int taille)
{
int Il_faut_liberer;
S_Liste_de_pages * Liste_a_raboter;
S_Page * Page_a_supprimer;
int Indice;
if (Emprunt_memoire_de_page_possible(taille))
{
// On regarde s'il faut librer des pages:
Il_faut_liberer=
(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)<taille;
if (!Il_faut_liberer)
{
// On a assez de place pour allouer une page. On n'a donc aucune page
// … supprimer. On peut allouer de la mmoire directement.
return malloc(taille);
}
else
{
// On manque de mmoire. Il faut librer une page...
// Tant qu'il faut librer
while (Il_faut_liberer)
{
// On cherche sur quelle liste on va virer une page
// S'il reste des pages … librer dans la liste des brouillons
if (Brouillon_Backups->Nb_pages_allouees>1)
// Alors on va dtruire la derniŠre page alloue de la liste des
// brouillons
Liste_a_raboter=Brouillon_Backups;
else
{
if (Principal_Backups->Nb_pages_allouees>1)
{
// Sinon on va dtruire la derniŠre page alloue de la
// liste principale
Liste_a_raboter=Principal_Backups;
}
else
{
// Dans cette branche, il tait prvu qu'on obtienne la mmoire
// ncessaire mais on n'arrive pas … la trouver. On indique donc
// qu'elle n'est pas disponible, et on aura perdu des backups
// pour rien
return 0;
}
}
// Puis on dtermine la page que l'on va supprimer (c'est la derniŠre
// de la liste)
Page_a_supprimer=Liste_a_raboter->Pages+(Liste_a_raboter->Nb_pages_allouees)-1;
// Dtruire la derniŠre page alloue dans la Liste_…_raboter
Detruire_derniere_page_allouee_de_la_liste(Liste_a_raboter);
// On regarde s'il faut continuer … librer de la place
Il_faut_liberer=
(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)<taille;
// S'il ne faut pas, c'est qu'on peut allouer un bitmap
// pour la Nouvelle_page
if (!Il_faut_liberer)
return malloc(taille);
}
}
}
else
{
// Il n'y a pas assez de place pour allouer la mmoire temporaire dans
// la mmoire rserve aux pages.
return 0;
}
// Pour que le compilateur ne dise pas qu'il manque une valeur de sortie:
return 0;
}