grafX2/pages.c
Yves Rizoud 761d62f761 Removed some unneeded dependencies to speed up compile.
Code "cleanup": Functions that create a button now return its address.
This helps reduce the number of files that use the globals "Fenetre_Liste_boutons_*"


git-svn-id: svn://pulkomandy.tk/GrafX2/trunk@642 416bcca6-2ee7-4201-b75f-2eb2f807beb1
2009-02-19 02:10:40 +00:00

1064 lines
36 KiB
C
Raw Blame History

/* Grafx2 - The Ultimate 256-color bitmap paint program
Copyright 2008 Franck Charlet
Copyright 2007 Adrien Destugues
Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud)
Grafx2 is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; version 2
of the License.
Grafx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Grafx2; if not, see <http://www.gnu.org/licenses/> or
write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//////////////////////////////////////////////////////////////////////////
/////////////////////////// GESTION DU BACKUP ////////////////////////////
//////////////////////////////////////////////////////////////////////////
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "global.h"
#include "pages.h"
#include "erreurs.h"
#include "divers.h"
#include "windows.h"
///
/// 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));
Page->Commentaire[0]='\0';
Page->Repertoire_fichier[0]='\0';
Page->Nom_fichier[0]='\0';
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)
// Affiche la page <20> l'<27>cran
{
//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));
strcpy(Principal_Commentaire,Page->Commentaire);
strcpy(Principal_Repertoire_fichier,Page->Repertoire_fichier);
strcpy(Principal_Nom_fichier,Page->Nom_fichier);
Principal_Format_fichier=Page->Format_fichier;
/*
Principal_Decalage_X=Page->Decalage_X;
Principal_Decalage_Y=Page->Decalage_Y;
// On corrige les d<>calages en fonction de la dimension de l'<27>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<6E>, 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)
// Sauve l'<27>cran courant dans la 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));
strcpy(Page->Commentaire,Principal_Commentaire);
strcpy(Page->Repertoire_fichier,Principal_Repertoire_fichier);
strcpy(Page->Nom_fichier,Principal_Nom_fichier);
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));
strcpy(Brouillon_Commentaire,Page->Commentaire);
strcpy(Brouillon_Repertoire_fichier,Page->Repertoire_fichier);
strcpy(Brouillon_Nom_fichier,Page->Nom_fichier);
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));
strcpy(Page->Commentaire,Brouillon_Commentaire);
strcpy(Page->Repertoire_fichier,Brouillon_Repertoire_fichier);
strcpy(Page->Nom_fichier,Brouillon_Nom_fichier);
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 d<>j<EFBFBD> d<>signer une page allou<6F>e auquel
// cas celle-ci serait perdue.
/* Debug : if (Page->Image!=NULL) exit(666); */
// On alloue la m<>moire pour le bitmap
Page->Image=(byte *)malloc(Largeur*Hauteur);
// On v<>rifie que l'allocation se soit bien pass<73>e
if (Page->Image==NULL)
return 0; // Echec
else
{
Page->Largeur=Largeur;
Page->Hauteur=Hauteur;
// Important: La mise <20> jour des autres infos est du ressort de
// l'appelant.
return 1; // Succ<63>s
}
}
void Liberer_une_page(S_Page * Page)
{
// On peut appeler cette fonction sur une page non allou<6F>e.
if (Page->Image!=NULL)
free(Page->Image);
Page->Image=NULL;
Page->Largeur=0;
Page->Hauteur=0;
// On ne se pr<70>occupe 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 allou<6F>e en m<>moire est pr<70>c<EFBFBD>d<EFBFBD>e d'un mot double indiquant sa
// taille, or la taille d'un mot double est de 4 octets, et on utilise deux
// allocations de m<>moires: 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 d<>j<EFBFBD> d<>signer une liste de
// pages allou<6F>e auquel cas celle-ci serait perdue.
int Indice;
/* Debug : if (Liste->Pages!=NULL) exit(666); */
// On alloue la m<>moire pour la liste
Liste->Pages=(S_Page *)malloc(Taille*sizeof(S_Page));
// On v<>rifie que l'allocation se soit bien pass<73>e
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<63>s
}
}
void Liberer_une_liste_de_pages(S_Liste_de_pages * Liste)
{
// On peut appeler cette fonction sur une liste de pages non allou<6F>e.
// Important: cette fonction ne lib<69>re pas les pages de la liste. Il faut
// donc le faire pr<70>alablement si n<>cessaire.
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 <20> 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'<27>quivalent d'un "Undo" dans la liste de pages.
// Elle effectue une sorte de ROL (Rotation Left) sur la liste:
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ |
// <20>0<EFBFBD>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>6<EFBFBD>7<EFBFBD>8<EFBFBD>9<EFBFBD>A<EFBFBD> |
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ | 0=Page courante
// <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> |_ A=Page la plus ancienne
// v v v v v v v v v v v | 1=Derni<6E>re page (1er backup)
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ |
// <20>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>6<EFBFBD>7<EFBFBD>8<EFBFBD>9<EFBFBD>A<EFBFBD>0<EFBFBD> |
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ |
// Pour simuler un v<>ritable Undo, l'appelant doit mettre la structure
// de page courante <20> jour avant l'appel, puis en r<>extraire les infos en
// sortie, ainsi que celles relatives <20> la plus r<>cente page d'undo (1<>re
// page de la liste).
int Indice;
S_Page * Page_tempo;
if (Liste->Nb_pages_allouees>1)
{
// On cr<63>e 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 <20> 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 <20>t<EFBFBD> effectu<74>e dans la page
// temporaire) en derni<6E>re position
Copier_S_page(Liste->Pages+Liste->Nb_pages_allouees-1,Page_tempo);
// On d<>truit la page tempo
free(Page_tempo);
}
}
void Avancer_dans_une_liste_de_pages(S_Liste_de_pages * Liste)
{
// Cette fonction fait l'<27>quivalent d'un "Redo" dans la liste de pages.
// Elle effectue une sorte de ROR (Rotation Right) sur la liste:
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ |
// <20>0<EFBFBD>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>6<EFBFBD>7<EFBFBD>8<EFBFBD>9<EFBFBD>A<EFBFBD> |
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ | 0=Page courante
// <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> <20> |_ A=Page la plus ancienne
// v v v v v v v v v v v | 1=Derni<6E>re page (1er backup)
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͻ |
// <20>A<EFBFBD>0<EFBFBD>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>6<EFBFBD>7<EFBFBD>8<EFBFBD>9<EFBFBD> |
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼ |
// Pour simuler un v<>ritable Redo, l'appelant doit mettre la structure
// de page courante <20> jour avant l'appel, puis en r<>extraire les infos en
// sortie, ainsi que celles relatives <20> la plus r<>cente page d'undo (1<>re
// page de la liste).
int Indice;
S_Page * Page_tempo;
if (Liste->Nb_pages_allouees>1)
{
// On cr<63>e la page tempo
Page_tempo=(S_Page *)malloc(sizeof(S_Page));
Initialiser_S_Page(Page_tempo);
// On copie la derni<6E>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 <20> 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 <20>t<EFBFBD>
// effectu<74>e dans la page temporaire) en 1<>re position
Copier_S_page(Liste->Pages,Page_tempo);
// On d<>truit 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
)
{
unsigned long Taille_immediatement_disponible;
unsigned long Taille_liste_courante;
unsigned long Taille_liste_brouillon;
unsigned long Taille_page_courante;
unsigned long Taille_page_brouillon;
unsigned long 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 <20> 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 cr<63>e une nouvelle page dont les attributs correspondent <20>
// ceux de Nouvelle_page (Largeur,Hauteur,...) (le champ Image est invalide
// <20> l'appel, c'est la fonction qui le met <20> jour), et l'enfile dans
// Liste_courante.
// Il est imp<EFBFBD>ratif que la cr<EFBFBD>ation de cette page soit possible,
// <20>ventuellement au d<>triment des backups de la page de brouillon
// (Liste_secondaire). Afin de s'en assurer, il faut v<>rifier cette
// possibilit<69> <20> l'aide de
// Nouvelle_page_possible(Nouvelle_page,Liste_courante,Liste_secondaire) avant
// l'appel <20> 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=NULL;
S_Page * Page_a_supprimer;
int Indice;
// On regarde s'il faut lib<69>rer 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)<
(unsigned long)(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 <20> supprimer. On peut en
// allouer une directement.
Nouvelle_page->Image=(byte *)malloc(Nouvelle_page->Hauteur*Nouvelle_page->Largeur);
}
else
{
// On manque de m<>moire ou la Liste_courante est pleine. Dans tous les
// cas, il faut lib<69>rer une page... qui peut-<2D>tre pourra re-servir.
// Tant qu'il faut lib<69>rer
while (Il_faut_liberer)
{
// On cherche sur quelle liste on va virer une page
// S'il reste des pages <20> lib<69>rer dans la Liste_courante
if (Liste_courante->Nb_pages_allouees>1)
// Alors on va d<>truire la derni<6E>re page allou<6F>e de la Liste_courante
Liste_a_raboter=Liste_courante;
else
{
if (Liste_secondaire->Nb_pages_allouees>1)
{
// Sinon on va d<>truire la derni<6E>re page allou<6F>e de la
// Liste_secondaire
Liste_a_raboter=Liste_secondaire;
}
else
{
// Bon, alors l<>, on vient de vider toutes les pages et on a toujours pas asez de m<>moire... C'est donc qu'un vilain programmeur a oubli<6C> de v<>rifier avec Noiuvelle_page_possible avant de venir ici.
// On sort m<>chament du programme sans sauvegarde ni rien. De toutes fa<66>ons, <20>a ne devrait jamais se produire...
Erreur(ERREUR_SORRY_SORRY_SORRY);
}
}
// Puis on d<>termine la page que l'on va supprimer (c'est la derni<6E>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 r<>cup<75>re le bitmap de la page <20> supprimer (<28>vite de faire des
// allocations/d<>sallocations fastidieuses et inutiles)
Nouvelle_page->Image=Page_a_supprimer->Image;
// On fait semblant que la derni<6E>re page allou<6F>e ne l'est pas
Liste_a_raboter->Nb_pages_allouees--;
// On n'a plus besoin de lib<69>rer de la m<>moire puisqu'on a refil<69> <20>
// Nouvelle_page un bitmap valide
Il_faut_liberer=0;
}
else
{
// Sinon
// D<>truire la derni<6E>re page allou<6F>e dans la Liste_<65>_raboter
Detruire_derniere_page_allouee_de_la_liste(Liste_a_raboter);
// On regarde s'il faut continuer <20> lib<69>rer de la place
Il_faut_liberer=(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)
<(unsigned long)(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<70>s l'hypoth<74>se de d<>part, la boucle ci-dessus doit s'arr<72>ter car
// on a assez de m<>moire pour allouer la nouvelle page.
// D<>sormais Nouvelle_page contient un pointeur sur une zone bitmap valide.
// D<>caler la Liste_courante d'un cran vers le pass<73>.
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 d<>j<EFBFBD> la taille demand<6E>e
if (Liste->Taille_liste==Nb)
// Alors il n'y a rien <20> faire
return;
// Si la liste contient plus de pages que souhait<69>
if (Liste->Taille_liste>Nb)
// Alors pour chaque page en exc<78>s
for (Indice=Nb;Indice<Liste->Taille_liste;Indice++)
// On lib<69>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 <20> 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<69>re l'ancienne liste
free(Liste->Pages);
// On met <20> 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 d<>truire la page courante de la liste si apr<70>s
// destruction il ne reste pas encore au moins une page.
if (Liste->Nb_pages_allouees>1)
{
// On fait faire un undo <20> la liste, comme <20>a, la nouvelle page courante
// est la page pr<70>c<EFBFBD>dente
Reculer_dans_une_liste_de_pages(Principal_Backups);
// Puis on d<>truit la derni<6E>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 <20> la dimension des images de d<>part.
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 r<>ussi <20> allouer deux listes de pages dont la taille correspond <20>
// celle demand<6E>e par l'utilisateur.
// On cr<63>e un descripteur de page correspondant <20> 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 d<>marrage
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 cr<63>er
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 cr<63>er 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 d<>marrer le programme avec la page
// principale et la page de brouillon aux dimensions demand<6E>e par
// l'utilisateur. ==> On l'envoie ballader
Retour=0;
}
}
else
{
// On ne peut pas d<>marrer le programme avec ne serait-ce qu'une
// page de la dimension souhait<69>e, donc on laisse tout tomber et on
// le renvoie chier.
free(Page);
Retour=0;
}
}
else
{
// On n'a m<>me pas r<>ussi <20> cr<63>er 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 <20> 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 d<>truire 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 <20> jour l'<27>tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On cr<63>e 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 d<>truit 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 <20> jour l'<27>tat des infos de la page de brouillon (pour pouvoir
// les retrouver plus tard)
Upload_infos_page_brouillon(Brouillon_Backups->Pages);
// On cr<63>e 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 d<>truit le descripteur de la page courante
free(Nouvelle_page);
return Retour;
}
void Backup(void)
// Sauve la page courante comme premi<6D>re page de backup et cr<63>e une nouvelle page
// pur continuer <20> dessiner. Utilis<69> par exemple pour le fill
{
#if defined(__macosx__) || defined(__FreeBSD__)
S_Page Nouvelle_page;
#else
S_Page *Nouvelle_page;
#endif
// On remet <20> jour l'<27>tat des infos de la page courante (pour pouvoir les
// retrouver plus tard)
Upload_infos_page_principal(Principal_Backups->Pages);
// On cr<63>e un descripteur pour la nouvelle page courante
#if defined(__macosx__) || defined(__FreeBSD__)
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);
#else
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);
#endif
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 d<>truit le descripteur de la page courante
#if !(defined(__macosx__) || defined(__FreeBSD__))
free(Nouvelle_page);
#endif
// On allume l'indicateur de modification de l'image
Principal_Image_modifiee=1;
}
void Undo(void)
{
// On remet <20> jour l'<27>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 <20> 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<69> <20> la suite d'un Undo. Donc <20>a ne devrait pas
// poser de probl<62>mes.
}
void Redo(void)
{
// On remet <20> jour l'<27>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 <20> 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<69> <20> la suite d'un Redo. Donc <20>a ne devrait pas
// poser de probl<62>mes.
}
void Detruire_la_page_courante(void)
{
// On d<>truit 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<69> <20> la suite d'une destruction de page. Donc <20>a ne
// devrait pas poser de probl<62>mes.
}
void Interchanger_image_principale_et_brouillon(void)
{
S_Liste_de_pages * Liste_tempo;
// On commence par mettre <20> jour dans les descripteurs les infos sur les
// pages qu'on s'appr<70>te <20> <20>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 d<>j<EFBFBD> <20> jour les dimensions de la
// nouvelle page courante. Si on ne le fait pas, le "Download" va d<>tecter
// 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'<27>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 m<>moire 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 lib<69>rer des pages:
Il_faut_liberer=
(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)<(unsigned long)taille;
if (!Il_faut_liberer)
{
// On a assez de place pour allouer une page. On n'a donc aucune page
// <20> supprimer. On peut allouer de la m<>moire directement.
return malloc(taille);
}
else
{
// On manque de m<>moire. Il faut lib<69>rer une page...
// Tant qu'il faut lib<69>rer
while (Il_faut_liberer)
{
// On cherche sur quelle liste on va virer une page
// S'il reste des pages <20> lib<69>rer dans la liste des brouillons
if (Brouillon_Backups->Nb_pages_allouees>1)
// Alors on va d<>truire la derni<6E>re page allou<6F>e de la liste des
// brouillons
Liste_a_raboter=Brouillon_Backups;
else
{
if (Principal_Backups->Nb_pages_allouees>1)
{
// Sinon on va d<>truire la derni<6E>re page allou<6F>e de la
// liste principale
Liste_a_raboter=Principal_Backups;
}
else
{
// Dans cette branche, il <20>tait pr<70>vu qu'on obtienne la m<>moire
// n<>cessaire mais on n'arrive pas <20> la trouver. On indique donc
// qu'elle n'est pas disponible, et on aura perdu des backups
// pour rien
return 0;
}
}
// Puis on d<>termine la page que l'on va supprimer (c'est la derni<6E>re
// de la liste)
Page_a_supprimer=Liste_a_raboter->Pages+(Liste_a_raboter->Nb_pages_allouees)-1;
// D<>truire la derni<6E>re page allou<6F>e dans la Liste_<65>_raboter
Detruire_derniere_page_allouee_de_la_liste(Liste_a_raboter);
// On regarde s'il faut continuer <20> lib<69>rer de la place
Il_faut_liberer=
(Memoire_libre()-QUANTITE_MINIMALE_DE_MEMOIRE_A_CONSERVER)<(unsigned long)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 m<>moire temporaire dans
// la m<>moire r<>serv<72>e aux pages.
return 0;
}
// Pour que le compilateur ne dise pas qu'il manque une valeur de sortie:
return 0;
}