/*  Grafx2 - The Ultimate 256-color bitmap paint program
    Copyright 2008      Franck Charlet
    Copyright 2007-2008 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  or
    write to the Free Software Foundation, Inc.,
    59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
********************************************************************************
    Graphical interface management functions (windows, menu, cursor)
*/
#include 
#include  // strncpy() strlen()
#include "windows.h"
#include "global.h"
#include "graph.h"
#include "engine.h"
#include "misc.h"
#include "sdlscreen.h"
#include "errors.h"
// L'encapsulation tente une percée...ou un dernier combat.
// Nombre de cellules réel dans la palette du menu
word Menu_cells_X;
word Palette_cells_X()
{
  return Menu_cells_X;
}
word Menu_cells_Y;
word Palette_cells_Y()
{
  return Menu_cells_Y;
}
// Affichage d'un pixel dans le menu (le menu doit être visible)
void Pixel_in_toolbar(word x,word y,byte color)
{
  Block(x*Menu_factor_X,(y*Menu_factor_Y)+Menu_Y,Menu_factor_X,Menu_factor_Y,color);
}
// Affichage d'un pixel dans la fenêtre (la fenêtre doit être visible)
void Pixel_in_window(word x,word y,byte color)
{
    Block((x*Menu_factor_X)+Window_pos_X,(y*Menu_factor_Y)+Window_pos_Y,Menu_factor_X,Menu_factor_Y,color);
}
// Affichage d'un rectangle dans la fenêtre (la fenêtre doit être visible)
void Window_rectangle(word x_pos,word y_pos,word width,word height,byte color)
{
  Block((x_pos*Menu_factor_X)+Window_pos_X,(y_pos*Menu_factor_Y)+Window_pos_Y,width*Menu_factor_X,height*Menu_factor_Y,color);
}
// -- Affichages de différents cadres dans une fenêtre -----------------------
  // -- Frame général avec couleurs paramètrables --
void Window_display_frame_generic(word x_pos,word y_pos,word width,word height,
                                    byte color_tl,byte color_br,byte color_s,byte color_tlc,byte color_brc)
// Paramètres de couleurs:
// color_tl =Bords Haut et Gauche
// color_br =Bords Bas et Droite
// color_s  =Coins Haut-Droite et Bas-Gauche
// color_tlc=Coin Haut-Gauche
// color_brc=Coin Bas-Droite
{
  // Bord haut (sans les extrémités)
  Block(Window_pos_X+((x_pos+1)*Menu_factor_X),
        Window_pos_Y+(y_pos*Menu_factor_Y),
        (width-2)*Menu_factor_X,Menu_factor_Y,color_tl);
  // Bord bas (sans les extrémités)
  Block(Window_pos_X+((x_pos+1)*Menu_factor_X),
        Window_pos_Y+((y_pos+height-1)*Menu_factor_Y),
        (width-2)*Menu_factor_X,Menu_factor_Y,color_br);
  // Bord gauche (sans les extrémités)
  Block(Window_pos_X+(x_pos*Menu_factor_X),
        Window_pos_Y+((y_pos+1)*Menu_factor_Y),
        Menu_factor_X,(height-2)*Menu_factor_Y,color_tl);
  // Bord droite (sans les extrémités)
  Block(Window_pos_X+((x_pos+width-1)*Menu_factor_X),
        Window_pos_Y+((y_pos+1)*Menu_factor_Y),
        Menu_factor_X,(height-2)*Menu_factor_Y,color_br);
  // Coin haut gauche
  Pixel_in_window(x_pos,y_pos,color_tlc);
  // Coin haut droite
  Pixel_in_window(x_pos+width-1,y_pos,color_s);
  // Coin bas droite
  Pixel_in_window(x_pos+width-1,y_pos+height-1,color_brc);
  // Coin bas gauche
  Pixel_in_window(x_pos,y_pos+height-1,color_s);
}
  // -- Frame dont tout le contour est d'une seule couleur --
void Window_display_frame_mono(word x_pos,word y_pos,word width,word height,byte color)
{
  Window_display_frame_generic(x_pos,y_pos,width,height,color,color,color,color,color);
}
  // -- Frame creux: foncé en haut-gauche et clair en bas-droite --
void Window_display_frame_in(word x_pos,word y_pos,word width,word height)
{
  Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_White,MC_Light,MC_Dark,MC_White);
}
  // -- Frame bombé: clair en haut-gauche et foncé en bas-droite --
void Window_display_frame_out(word x_pos,word y_pos,word width,word height)
{
  Window_display_frame_generic(x_pos,y_pos,width,height,MC_White,MC_Dark,MC_Light,MC_White,MC_Dark);
}
  // -- Frame de séparation: un cadre bombé dans un cadre creux (3D!!!) --
void Window_display_frame(word x_pos,word y_pos,word width,word height)
{
  Window_display_frame_in(x_pos,y_pos,width,height);
  Window_display_frame_out(x_pos+1,y_pos+1,width-2,height-2);
}
//-- Affichages relatifs à la palette dans le menu ---------------------------
  // -- Affichage des couleurs courante (fore/back) de pinceau dans le menu --
void Display_foreback(void)
{
  if (Menu_is_visible)
  {
    Block((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7,Back_color);
    Block((MENU_WIDTH-13)*Menu_factor_X,Menu_Y+(Menu_factor_Y<<1),Menu_factor_X<<3,Menu_factor_Y*5,Fore_color);
    Update_rect((MENU_WIDTH-17)*Menu_factor_X,Menu_Y+Menu_factor_Y,Menu_factor_X<<4,Menu_factor_Y*7);
  }
}
/*! Get the top left corner for the palette cell of a color
    @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y.
*/
word Palette_cell_X(byte index)
{
  if (Config.Palette_vertical)
  {
    return (MENU_WIDTH+1+((index-First_color_in_palette)%Menu_cells_X)*Menu_palette_cell_width)*Menu_factor_X;
  }
  else
  {
    return (MENU_WIDTH+1+((index-First_color_in_palette)/Menu_cells_Y)*Menu_palette_cell_width)*Menu_factor_X;
  }
}
/*! Get the top left corner for the palette cell of a color
    @param index Index of the color, starting at 0 for the top left one. Limited to Menu_cells_X/Menu_cells_Y.
*/
word Palette_cell_Y(byte index)
{
  if (Config.Palette_vertical)
  {
    return Menu_Y+((2+(((index-First_color_in_palette)/Menu_cells_X)*(32/Menu_cells_Y)))*Menu_factor_Y);
  }
  else
  {
    return Menu_Y+((2+(((index-First_color_in_palette)%Menu_cells_Y)*(32/Menu_cells_Y)))*Menu_factor_Y);
  }
}
///
/// Redraw the cell in the menu palette for ::Fore_color.
/// This function checks bounds, it won't draw anything if Fore_color is not visible.
/// @param color: Pass MC_White to mark the color with a frame, MC_Black to unmark it.
void Frame_menu_color(byte color)
{
  word start_x,start_y,end_x,end_y;
  word index;
  word cell_height=32/Menu_cells_Y;
  if ((Fore_color>=First_color_in_palette) && (Fore_color=First_color_in_palette+Menu_cells_X*Menu_cells_Y)
      First_color_in_palette+=cells;
  }
  if (old_color!=First_color_in_palette)
    Display_menu_palette();
}
void Change_palette_cells()
{
  // On initialise avec la configuration de l'utilisateur
  Menu_cells_X=Config.Palette_cells_X;
  Menu_cells_Y=Config.Palette_cells_Y;
  // Mais on sait jamais
  if (Menu_cells_X<1)
    Menu_cells_X=1;
  if (Menu_cells_Y<1)
    Menu_cells_Y=1;
  
  while (1)
  {
    Menu_palette_cell_width = ((Screen_width/Menu_factor_X)-(MENU_WIDTH+2)) / Menu_cells_X;
    // Si ça tient, c'est bon. Sinon, on retente avec une colonne de moins
    if (Menu_palette_cell_width>2)
      break;
    Menu_cells_X--;
  }
  
  // Cale First_color_in_palette sur un multiple du nombre de cellules (arrondi inférieur)
  if (Config.Palette_vertical)
    First_color_in_palette=First_color_in_palette/Menu_cells_X*Menu_cells_X;
  else
    First_color_in_palette=First_color_in_palette/Menu_cells_Y*Menu_cells_Y;
  // Si le nombre de cellules a beaucoup augmenté et qu'on était près de
  // la fin, il faut reculer First_color_in_palette pour montrer plein
  // de couleurs.
  if ((int)First_color_in_palette+(Menu_cells_Y)*Menu_cells_X*2>=256)
    First_color_in_palette=255/Menu_cells_Y*Menu_cells_Y-(Menu_cells_X-1)*Menu_cells_Y;
  // Mise à jour de la taille du bouton dans le menu. C'est pour pas que
  // la bordure noire soit active.
  Button[BUTTON_CHOOSE_COL].Width=(Menu_palette_cell_width*Menu_cells_X)-1;
  Button[BUTTON_CHOOSE_COL].Height=32/Menu_cells_Y*Menu_cells_Y-1;
}
// Retrouve la couleur sur laquelle pointe le curseur souris.
// Cette fonction suppose qu'on a déja vérifié que le curseur est dans
// la zone rectangulaire du BUTTON_CHOOSE_COL
// La fonction renvoie -1 si on est "trop à gauche" (pas possible)
// ou après la couleur 255 (Ce qui peut arriver si la palette est affichée
// avec un nombre de lignes qui n'est pas une puissance de deux.)
int Pick_color_in_palette()
{
  int color;
  int line;
  int column;
  line=(((Mouse_Y-Menu_Y)/Menu_factor_Y)-2)/(32/Menu_cells_Y);
  column=(((Mouse_X/Menu_factor_X)-(MENU_WIDTH+1))/Menu_palette_cell_width);
  if (Config.Palette_vertical)
  {
    color=First_color_in_palette+line*Menu_cells_X+column;
  }
  else
  {
    color=First_color_in_palette+line+column*Menu_cells_Y;
  }
  if (color<0 || color>255)
    return -1;
  return color;
}
  // -- Afficher tout le menu --
void Display_menu(void)
{
  word x_pos;
  word y_pos;
  char str[4];
  if (Menu_is_visible)
  {
    // Affichage du sprite du menu
    for (y_pos=0;y_pos=Main_X_zoom) ))
      {
        // Dans ces deux cas, on met dans la barre les XY courant, même s'il y a des chances que ça soit recouvert si la souris est sur un bouton (trop chiant à vérifier)
        if ( (Current_operation!=OPERATION_COLORPICK)
          && (Current_operation!=OPERATION_REPLACE) )
          Print_in_menu("X:       Y:             ",0);
        else
        {
          Print_in_menu("X:       Y:       (    )",0);
          Num2str(Colorpicker_color,str,3);
          Print_in_menu(str,20);
          Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color);
        }
        Print_coordinates();
      }
      Print_filename();
    }
    Update_rect(0,Menu_Y,Screen_width,MENU_HEIGHT*Menu_factor_Y); // on met toute la largur à jour, ça inclut la palette et la zone d'état avec le nom du fichier
  }
}
// -- Affichage de texte -----------------------------------------------------
  // -- Afficher une chaîne n'importe où à l'écran --
void Print_general(short x,short y,const char * str,byte text_color,byte background_color)
{
  word  index;
  int x_pos;
  int y_pos;
  byte *font_pixel;
  short real_x;
  short real_y;
  byte repeat_menu_x_factor;
  byte repeat_menu_y_factor;
  real_y=y;
  for (y_pos=0;y_pos<8<<3;y_pos+=1<<3)
  {
    real_x=0; // Position dans le buffer
    for (index=0;str[index]!='\0';index++)
    {
      // Pointeur sur le premier pixel du caractère
      font_pixel=Menu_font+(((unsigned char)str[index])<<6);
      for (x_pos=0;x_pos<8;x_pos+=1)
        for (repeat_menu_x_factor=0;repeat_menu_x_factor size)
  {
    display_string[size-1]=ELLIPSIS_CHARACTER;
  }
  Print_in_window(x, y, display_string, text_color, background_color);
}
  // -- Afficher une chaîne dans une fenêtre --
void Print_in_window(short x,short y,const char * str,byte text_color,byte background_color)
{
  Print_general((x*Menu_factor_X)+Window_pos_X,
                (y*Menu_factor_Y)+Window_pos_Y,
                str,text_color,background_color);
  Update_rect(x*Menu_factor_X+Window_pos_X,y*Menu_factor_Y+Window_pos_Y,8*Menu_factor_X*strlen(str),8*Menu_factor_Y);
}
  // -- Afficher une chaîne dans le menu --
void Print_in_menu(const char * str, short position)
{
  Print_general((18+(position<<3))*Menu_factor_X,Menu_status_Y,str,MC_Black,MC_Light);
  Update_rect((18+(position<<3))*Menu_factor_X,Menu_status_Y,strlen(str)*8*Menu_factor_X,8*Menu_factor_Y);
}
  // -- Afficher les coordonnées du pinceau dans le menu --
// Note : cette fonction n'affiche que les chiffres, pas les X: Y: qui sont dans la gestion principale, car elle est apellée très souvent.
void Print_coordinates(void)
{
  char temp[5];
  if (Menu_is_visible && !Cursor_in_menu)
  {
    if ( (Current_operation==OPERATION_COLORPICK)
      || (Current_operation==OPERATION_REPLACE) )
    {
      if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0)
        && (Paintbrush_X12)
    {
      display_name[11]=ELLIPSIS_CHARACTER;
      name_size = 12;
    }
    
    Block(Screen_width-96*Menu_factor_X,
          Menu_status_Y,Menu_factor_X*96,Menu_factor_Y<<3,MC_Light);
    Print_general(Screen_width-name_size*8*Menu_factor_X,Menu_status_Y,display_name,MC_Black,MC_Light);
  }
}
// Fonction d'affichage d'une chaine numérique avec une fonte très fine
// Spécialisée pour les compteurs RGB
void Print_counter(short x,short y,const char * str,byte text_color,byte background_color)
{
  // Macros pour écrire des litteraux binaires.
  // Ex: Ob(11110000) == 0xF0
  #define Ob(x)  ((unsigned)Ob_(0 ## x ## uL))
  #define Ob_(x) ((x & 1) | (x >> 2 & 2) | (x >> 4 & 4) | (x >> 6 & 8) |                \
          (x >> 8 & 16) | (x >> 10 & 32) | (x >> 12 & 64) | (x >> 14 & 128))
  byte thin_font[14][8] = {
   { // 0
    Ob(00011100),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00011100)
   },
   { // 1
    Ob(00001100),
    Ob(00011100),
    Ob(00111100),
    Ob(00001100),
    Ob(00001100),
    Ob(00001100),
    Ob(00001100),
    Ob(00001100)
   },
   { // 2
    Ob(00011100),
    Ob(00110110),
    Ob(00000110),
    Ob(00000110),
    Ob(00000110),
    Ob(00001100),
    Ob(00011000),
    Ob(00111110)
   },
   { // 3
    Ob(00011100),
    Ob(00110110),
    Ob(00000110),
    Ob(00001100),
    Ob(00000110),
    Ob(00000110),
    Ob(00110110),
    Ob(00011100)
   },
   { // 4
    Ob(00001100),
    Ob(00001100),
    Ob(00011000),
    Ob(00011000),
    Ob(00110000),
    Ob(00110100),
    Ob(00111110),
    Ob(00000100)
   },
   { // 5
    Ob(00111110),
    Ob(00110000),
    Ob(00110000),
    Ob(00111100),
    Ob(00000110),
    Ob(00000110),
    Ob(00110110),
    Ob(00011100)
   },
   { // 6
    Ob(00011100),
    Ob(00110110),
    Ob(00110000),
    Ob(00111100),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00011100)
   },
   { // 7
    Ob(00111110),
    Ob(00000110),
    Ob(00000110),
    Ob(00001100),
    Ob(00011000),
    Ob(00011000),
    Ob(00011000),
    Ob(00011000)
   },
   { // 8
    Ob(00011100),
    Ob(00110110),
    Ob(00110110),
    Ob(00011100),
    Ob(00110110),
    Ob(00110110),
    Ob(00110110),
    Ob(00011100)
   },
   { // 9
    Ob(00011100),
    Ob(00110110),
    Ob(00110110),
    Ob(00011110),
    Ob(00000110),
    Ob(00000110),
    Ob(00110110),
    Ob(00011100)
   },
   { // (espace)
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000)
   },
   { // +
    Ob(00000000),
    Ob(00001000),
    Ob(00001000),
    Ob(00111110),
    Ob(00001000),
    Ob(00001000),
    Ob(00000000),
    Ob(00000000)
   },
   { // -
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00111110),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000),
    Ob(00000000)
   },
   { // +-
    Ob(00001000),
    Ob(00001000),
    Ob(00111110),
    Ob(00001000),
    Ob(00001000),
    Ob(00000000),
    Ob(00111110),
    Ob(00000000)
   } };
  word  index;
  short x_pos;
  short y_pos;
  for (index=0;str[index]!='\0';index++)
  {
    int char_number;
    switch(str[index])
    {
      case '0':
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
        char_number=str[index]-'0';
        break;
      case ' ':
      default:
        char_number=10;
        break;
      case '+':
        char_number=11;
        break;
      case '-':
        char_number=12;
        break;
      case '±':
        char_number=13;
        break;
    }
    for (y_pos=0;y_pos<8;y_pos++)
    {
      for (x_pos=0;x_pos<6;x_pos++)
      {
        byte color = (thin_font[char_number][y_pos] & (1 << (6-x_pos))) ? text_color:background_color;
        Pixel_in_window(x+(index*6+x_pos),y+y_pos,color);
      }
    }
  }
  Update_rect(Window_pos_X+x*Menu_factor_X,Window_pos_Y+y*Menu_factor_Y,strlen(str)*Menu_factor_X*6,8*Menu_factor_Y);
}
//---- Fenêtre demandant de confirmer une action et renvoyant la réponse -----
byte Confirmation_box(char * message)
{
  short clicked_button;
  word  window_width;
  window_width=(strlen(message)<<3)+20;
  if (window_width<120)
    window_width=120;
  Open_window(window_width,60,"Confirmation");
  Print_in_window((window_width>>1)-(strlen(message)<<2),20,message,MC_Black,MC_Light);
  Window_set_normal_button((window_width/3)-20     ,37,40,14,"Yes",1,1,SDLK_y); // 1
  Window_set_normal_button(((window_width<<1)/3)-20,37,40,14,"No" ,1,1,SDLK_n); // 2
  Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*window_width,Menu_factor_Y*60);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    if (Key==SDLK_RETURN) clicked_button=1;
    if (Key==KEY_ESC) clicked_button=2;
  }
  while (clicked_button<=0);
  Key=0;
  Close_window();
  Display_cursor();
  return (clicked_button==1)? 1 : 0;
}
//---- Fenêtre avertissant de quelque chose et attendant un click sur OK -----
void Warning_message(char * message)
{
  short clicked_button;
  word  window_width;
  window_width=(strlen(message)<<3)+20;
  if (window_width<120)
    window_width=120;
  Open_window(window_width,60,"Warning!");
  Print_in_window((window_width>>1)-(strlen(message)<<2),20,message,MC_Black,MC_Light);
  Window_set_normal_button((window_width>>1)-20     ,37,40,14,"OK",1,1,SDLK_RETURN); // 1
  Update_rect(Window_pos_X,Window_pos_Y,Menu_factor_X*window_width,Menu_factor_Y*60);
  Display_cursor();
  do
    clicked_button=Window_clicked_button();
  while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o));
  Key=0;
  Close_window();
  Display_cursor();
}
  // -- Redessiner le sprite d'un bouton dans le menu --
void Display_sprite_in_menu(int btn_number,int sprite_number)
{
  word x_pos;
  word y_pos;
  word menu_x_pos;
  word menu_y_pos;
  byte color;
  menu_y_pos=Button[btn_number].Y_offset;
  menu_x_pos=Button[btn_number].X_offset;
  if (Button[btn_number].Shape != BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT)
  {
    menu_y_pos+=1;
    menu_x_pos+=1;
  }
  
  for (y_pos=0;y_pos à 64 lignes fct(Menu_Facteur)
  word nb_colors   =(block_start<=block_end)?block_end-block_start+1:block_start-block_end+1;
  word Selected_line_mode=(block_start<=block_end)?0:total_lines-1;
  word start_x       =Window_pos_X+(Menu_factor_X*x_pos);
  word line_width =Menu_factor_X<<4; // <=> à 16 pixels fct(Menu_Facteur)
  word start_y       =Window_pos_Y+(Menu_factor_Y*y_pos);
  word end_y         =start_y+total_lines;
  word index;
  if (block_start>block_end)
  {
    index=block_start;
    block_start=block_end;
    block_end=index;
  }
  for (index=start_y;index=corner_y) || (end_x<=Window_pos_X) || (start_x>=corner_x) )
        Block(start_x,start_y,width,height,real_color);
      else
      {
        if (start_x>=Window_pos_X)
        {
          if ( (end_x>corner_x) || (end_y>corner_y) )
          {
            if ( (end_x>corner_x) && (end_y>corner_y) )
            {
              Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color);
              Block(start_x,corner_y,width,end_y-corner_y,real_color);
            }
            else
            {
              if (end_y>corner_y)
                Block(start_x,corner_y,width,end_y-corner_y,real_color);
              else
                Block(corner_x,start_y,end_x-corner_x,height,real_color);
            }
          }
        }
        else
        {
          if (end_xcorner_y)
            {
              Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color);
              Block(start_x,corner_y,width,end_y-corner_y,real_color);
            }
            else
              Block(start_x,start_y,Window_pos_X-start_x,height,real_color);
          }
          else
          {
            if (end_y>corner_y)
            {
              Block(start_x,start_y,Window_pos_X-start_x,corner_y-start_y,real_color);
              Block(corner_x,start_y,end_x-corner_x,corner_y-start_y,real_color);
              Block(start_x,corner_y,width,end_y-corner_y,real_color);
            }
            else
            {
              Block(start_x,start_y,Window_pos_X-start_x,height,real_color);
              Block(corner_x,start_y,end_x-corner_x,height,real_color);
            }
          }
        }
      }
      {
        // Affichage du bloc directement dans le "buffer de fond" de la fenetre.
        // Cela permet au bloc de couleur d'apparaitre si on déplace la fenetre.
        short x_pos;
        short y_pos;
        short relative_x; // besoin d'une variable signée
        short relative_y; // besoin d'une variable signée
        // Attention aux unités
        relative_x = ((short)start_x - (short)Window_pos_X);
        relative_y = ((short)start_y - (short)Window_pos_Y);
        for (y_pos=relative_y;y_pos<(relative_y+height)&&y_pos=0&&y_pos>=0)
              Pixel_background(x_pos,y_pos,real_color);
      }
    }
  }
  Update_rect(MENU_WIDTH*Menu_factor_X,Menu_Y_before_window,Screen_width-(MENU_WIDTH*Menu_factor_X),(MENU_HEIGHT-9)*Menu_factor_Y);
}
// -------- Calcul des bornes de la partie d'image visible à l'écran ---------
void Compute_limits(void)
/*
  Avant l'appel à cette fonction, les données de la loupe doivent être à jour.
*/
{
  if (Main_magnifier_mode)
  {
    // -- Calcul des limites de la partie non zoomée de l'image --
    Limit_top  =Main_offset_Y;
    Limit_left=Main_offset_X;
    Limit_visible_bottom   =Limit_top+Menu_Y-1;
    Limit_visible_right=Limit_left+Main_separator_position-1;
    if (Limit_visible_bottom>=Main_image_height)
      Limit_bottom=Main_image_height-1;
    else
      Limit_bottom=Limit_visible_bottom;
    if (Limit_visible_right>=Main_image_width)
      Limit_right=Main_image_width-1;
    else
      Limit_right=Limit_visible_right;
    // -- Calcul des limites de la partie zoomée de l'image --
    Limit_top_zoom  =Main_magnifier_offset_Y;
    Limit_left_zoom=Main_magnifier_offset_X;
    Limit_visible_bottom_zoom   =Limit_top_zoom+Main_magnifier_height-1;
    Limit_visible_right_zoom=Limit_left_zoom+Main_magnifier_width-1;
    if (Limit_visible_bottom_zoom>=Main_image_height)
      Limit_bottom_zoom=Main_image_height-1;
    else
      Limit_bottom_zoom=Limit_visible_bottom_zoom;
    if (Limit_visible_right_zoom>=Main_image_width)
      Limit_right_zoom=Main_image_width-1;
    else
      Limit_right_zoom=Limit_visible_right_zoom;
  }
  else
  {
    // -- Calcul des limites de la partie visible de l'image --
    Limit_top  =Main_offset_Y;
    Limit_left=Main_offset_X;
    Limit_visible_bottom   =Limit_top+(Menu_is_visible?Menu_Y:Screen_height)-1; // A REVOIR POUR SIMPLIFICATION
    Limit_visible_right=Limit_left+Screen_width-1;
    if (Limit_visible_bottom>=Main_image_height)
      Limit_bottom=Main_image_height-1;
    else
      Limit_bottom=Limit_visible_bottom;
    if (Limit_visible_right>=Main_image_width)
      Limit_right=Main_image_width-1;
    else
      Limit_right=Limit_visible_right;
  }
}
// -- Calculer les coordonnées du pinceau en fonction du snap et de la loupe -
void Compute_paintbrush_coordinates(void)
{
  if ((Main_magnifier_mode) && (Mouse_X>=Main_X_zoom))
  {
    Paintbrush_X=((Mouse_X-Main_X_zoom)/Main_magnifier_factor)+Main_magnifier_offset_X;
    Paintbrush_Y=(Mouse_Y/Main_magnifier_factor)+Main_magnifier_offset_Y;
  }
  else
  {
    Paintbrush_X=Mouse_X+Main_offset_X;
    Paintbrush_Y=Mouse_Y+Main_offset_Y;
  }
  if (Snap_mode)
  {
    Paintbrush_X=(((Paintbrush_X+(Snap_width>>1)-Snap_offset_X)/Snap_width)*Snap_width)+Snap_offset_X;
    Paintbrush_Y=(((Paintbrush_Y+(Snap_height>>1)-Snap_offset_Y)/Snap_height)*Snap_height)+Snap_offset_Y;
  }
}
// -- Affichage de la limite de l'image -------------------------------------
void Display_image_limits(void)
{
  short start;
  short pos;
  short end;
  byte right_is_visible;
  byte bottom_is_visible;
  short old_zoom_limit;
  right_is_visible=Main_image_width<((Main_magnifier_mode)?Main_separator_position:Screen_width);
  bottom_is_visible   =Main_image_heightMain_separator_position)
  {
    Main_offset_X=Main_magnifier_offset_X+(Main_magnifier_width>>1)
                         -(Main_separator_position>>1);
    if (Main_offset_X<0)
      Main_offset_X=0;
    else
    if (Main_image_widthMenu_Y)
  {
    Main_offset_Y=Main_magnifier_offset_Y+(Main_magnifier_height>>1)
                         -(Menu_Y>>1);
    if (Main_offset_Y<0)
      Main_offset_Y=0;
    else
    if (Main_image_height>1)-theoric_X)/Main_magnifier_factor)*Main_magnifier_factor);
  Main_separator_position=Main_X_zoom-(Menu_factor_X*SEPARATOR_WIDTH);
  // Correction en cas de débordement sur la gauche
  while (Main_separator_position*(Main_magnifier_factor+1)=theoric_X)
  {
    Main_separator_position-=Main_magnifier_factor;
    Main_X_zoom-=Main_magnifier_factor;
  }
}
// -------------------- Calcul des information de la loupe -------------------
void Compute_magnifier_data(void)
/*
  Après modification des données de la loupe, il faut recalculer les limites.
*/
{
  Compute_separator_data();
  Main_magnifier_width=(Screen_width-Main_X_zoom)/Main_magnifier_factor;
  Main_magnifier_height=Menu_Y/Main_magnifier_factor;
  if (Menu_Y%Main_magnifier_factor)
    Main_magnifier_height++;
  if (Main_magnifier_mode && Main_magnifier_offset_X)
  {
    if (Main_image_width>1);
  center_y=Main_magnifier_offset_Y+(Main_magnifier_height>>1);
  Main_magnifier_factor=ZOOM_FACTOR[factor_index];
  Zoom_factor_table=Magnify_table[factor_index];
  Compute_magnifier_data();
  if (Main_magnifier_mode)
  {
    // Recalculer le décalage de la loupe
    // Centrage "brut" de lécran par rapport à la loupe
    Main_magnifier_offset_X=center_x-(Main_magnifier_width>>1);
    Main_magnifier_offset_Y=center_y-(Main_magnifier_height>>1);
    // Correction en cas de débordement de l'image
    if (Main_magnifier_offset_X+Main_magnifier_width>Main_image_width)
      Main_magnifier_offset_X=Main_image_width-Main_magnifier_width;
    if (Main_magnifier_offset_Y+Main_magnifier_height>Main_image_height)
      Main_magnifier_offset_Y=Main_image_height-Main_magnifier_height;
    if (Main_magnifier_offset_X<0)
      Main_magnifier_offset_X=0;
    if (Main_magnifier_offset_Y<0)
      Main_magnifier_offset_Y=0;
    Position_screen_according_to_zoom();
    Pixel_preview=Pixel_preview_magnifier;
  }
  else
    Pixel_preview=Pixel_preview_normal;
  Compute_limits();
  Compute_paintbrush_coordinates();
}
  // -- Afficher la barre de séparation entre les parties zoomées ou non en
  //    mode Loupe --
void Display_separator(void)
{
  // Partie grise du milieu
  Block(Main_separator_position+(Menu_factor_X<<1),Menu_factor_Y,
        (SEPARATOR_WIDTH-4)*Menu_factor_X,
        Menu_Y-(Menu_factor_Y<<1),MC_Light);
  // Barre noire de gauche
  Block(Main_separator_position,0,Menu_factor_X,Menu_Y,MC_Black);
  // Barre noire de droite
  Block(Main_X_zoom-Menu_factor_X,0,Menu_factor_X,Menu_Y,MC_Black);
  // Bord haut (blanc)
  Block(Main_separator_position+Menu_factor_X,0,
        (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_White);
  // Bord gauche (blanc)
  Block(Main_separator_position+Menu_factor_X,Menu_factor_Y,
        Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_White);
  // Bord droite (gris foncé)
  Block(Main_X_zoom-(Menu_factor_X<<1),Menu_factor_Y,
        Menu_factor_X,(Menu_Y-(Menu_factor_Y<<1)),MC_Dark);
  // Bord bas (gris foncé)
  Block(Main_separator_position+(Menu_factor_X<<1),Menu_Y-Menu_factor_Y,
        (SEPARATOR_WIDTH-3)*Menu_factor_X,Menu_factor_Y,MC_Dark);
  // Coin bas gauche
  Block(Main_separator_position+Menu_factor_X,Menu_Y-Menu_factor_Y,
        Menu_factor_X,Menu_factor_Y,MC_Light);
  // Coin haut droite
  Block(Main_X_zoom-(Menu_factor_X<<1),0,
        Menu_factor_X,Menu_factor_Y,MC_Light);
  Update_rect(Main_separator_position,0,SEPARATOR_WIDTH*Menu_factor_X,Menu_Y); // On réaffiche toute la partie à gauche du split, ce qui permet d'effacer son ancienne position
}
// -- Fonctions de manipulation du curseur -----------------------------------
  // -- Afficher une barre horizontale XOR zoomée
void Horizontal_XOR_line_zoom(short x_pos, short y_pos, short width)
{
  short real_x_pos=Main_X_zoom+(x_pos-Main_magnifier_offset_X)*Main_magnifier_factor;
  short real_y_pos=(y_pos-Main_magnifier_offset_Y)*Main_magnifier_factor;
  short real_width=width*Main_magnifier_factor;
  short end_y_pos=(real_y_pos+Main_magnifier_factor=Main_X_zoom) ) )
    || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) )
    shape=Cursor_shape;
  else
    shape=CURSOR_SHAPE_ARROW;
  switch(shape)
  {
    case CURSOR_SHAPE_TARGET :
      if (!Paintbrush_hidden)
        Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1);
      if (!Cursor_hidden)
      {
        if (Config.Cursor==1)
        {
          start_y=(Mouse_Y<6)?6-Mouse_Y:0;
          if (start_y<4)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+start_y-6,4-start_y);
          start_x=(Mouse_X<6)?(short)6-Mouse_X:0;
          if (start_x<4)
            Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x);
          end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0;
          if (end_x<4)
            Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x);
          end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0;
          if (end_y<4)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+3,4-end_y);
          Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y);
        }
        else
        {
          temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET;
          start_x=Mouse_X-Cursor_offset_X[temp];
          start_y=Mouse_Y-Cursor_offset_Y[temp];
          for (x_pos=start_x,counter_x=0;counter_x<15 && x_pos < Screen_width;x_pos++,counter_x++)
                {
                  if( x_pos < 0 ) continue;
            for (y_pos=start_y,counter_y=0;counter_y<15 && y_pos < Screen_height;y_pos++,counter_y++)
            {
                    if( y_pos < 0 || y_pos >= Screen_height) continue;
              color=GFX_cursor_sprite[temp][counter_y][counter_x];
              CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos);
              if (color!=MC_Trans)
                Pixel(x_pos,y_pos,color);
            }
                }
          Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y);
        }
      }
      break;
    case CURSOR_SHAPE_COLORPICKER:
      if (!Paintbrush_hidden)
        Display_paintbrush(Paintbrush_X,Paintbrush_Y,Fore_color,1);
      if (!Cursor_hidden)
      {
        if (Config.Cursor==1)
        {
          // Barres formant la croix principale
          start_y=(Mouse_Y<5)?5-Mouse_Y:0;
          if (start_y<3)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+start_y-5,3-start_y);
          start_x=(Mouse_X<5)?(short)5-Mouse_X:0;
          if (start_x<3)
            Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x);
          end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0;
          if (end_x<3)
            Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x);
          end_y=(Mouse_Y+6>Menu_Y/*Screen_height*/)?Mouse_Y+6-Menu_Y/*Screen_height*/:0;
          if (end_y<3)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+3,3-end_y);
          // Petites barres aux extrémités
          start_x=(!Mouse_X);
          start_y=(!Mouse_Y);
          end_x=(Mouse_X>=Screen_width-1);
          end_y=(Mouse_Y>=Menu_Y-1);
          if (Mouse_Y>5)
            Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x));
          if (Mouse_X>5)
            Vertical_XOR_line  (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y));
          if (Mouse_X=0) && (x_pos=0) && (y_pos=Screen_width) break;
        for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++)
        {
          if(y_pos<0) continue;
          if(y_pos>=Screen_height) break;
          color=GFX_cursor_sprite[shape][counter_y][counter_x];
          // On sauvegarde dans CURSOR_BACKGROUND pour restaurer plus tard
          CURSOR_BACKGROUND[counter_y][counter_x]=Read_pixel(x_pos,y_pos);
          if (color!=MC_Trans)
              Pixel(x_pos,y_pos,color);
        }
      }
      Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y);
      break;
    case CURSOR_SHAPE_XOR_TARGET :
      x_pos=Paintbrush_X-Main_offset_X;
      y_pos=Paintbrush_Y-Main_offset_Y;
      counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR
      if ((y_pos=Limit_top))
      {
        Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x);
        Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1);
      }
      if ((x_pos=Limit_left))
      {
        Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y);
        Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y);
      }
      if (Main_magnifier_mode)
      {
        // UPDATERECT
        if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom))
          Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width);
        if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom))
          Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height);
      }
      break;
    case CURSOR_SHAPE_XOR_RECTANGLE :
      // !!! Cette forme ne peut pas être utilisée en mode Loupe !!!
      // Petite croix au centre
      start_x=(Mouse_X-3);
      start_y=(Mouse_Y-3);
      end_x  =(Mouse_X+4);
      end_y  =(Mouse_Y+4);
      if (start_x<0)
        start_x=0;
      if (start_y<0)
        start_y=0;
      if (end_x>Screen_width)
        end_x=Screen_width;
      if (end_y>Menu_Y)
        end_y=Menu_Y;
      Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x);
      Vertical_XOR_line  (Mouse_X,start_y,end_y-start_y);
      // Grand rectangle autour
      start_x=Mouse_X-(Main_magnifier_width>>1);
      start_y=Mouse_Y-(Main_magnifier_height>>1);
      if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X)
        start_x=Limit_right-Main_magnifier_width-Main_offset_X+1;
      if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y)
        start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1;
      if (start_x<0)
        start_x=0;
      if (start_y<0)
        start_y=0;
      end_x=start_x+Main_magnifier_width-1;
      end_y=start_y+Main_magnifier_height-1;
      Horizontal_XOR_line(start_x,start_y,Main_magnifier_width);
      Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2);
      Vertical_XOR_line(  end_x,start_y+1,Main_magnifier_height-2);
      Horizontal_XOR_line(start_x,  end_y,Main_magnifier_width);
      Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y);
      break;
    default: //case CURSOR_SHAPE_XOR_ROTATION :
      start_x=1-(Brush_width>>1);
      start_y=1-(Brush_height>>1);
      end_x=start_x+Brush_width-1;
      end_y=start_y+Brush_height-1;
      if (Brush_rotation_center_is_defined)
      {
        if ( (Brush_rotation_center_X==Paintbrush_X)
          && (Brush_rotation_center_Y==Paintbrush_Y) )
        {
          cos_a=1.0;
          sin_a=0.0;
        }
        else
        {
          x_pos=Paintbrush_X-Brush_rotation_center_X;
          y_pos=Paintbrush_Y-Brush_rotation_center_Y;
          cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos));
          sin_a=sin(acos(cos_a));
          if (y_pos>0) sin_a=-sin_a;
        }
        Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1);
        Transform_point(end_x  ,start_y, cos_a,sin_a, &x2,&y2);
        Transform_point(start_x,end_y  , cos_a,sin_a, &x3,&y3);
        Transform_point(end_x  ,end_y  , cos_a,sin_a, &x4,&y4);
        x1+=Brush_rotation_center_X;
        y1+=Brush_rotation_center_Y;
        x2+=Brush_rotation_center_X;
        y2+=Brush_rotation_center_Y;
        x3+=Brush_rotation_center_X;
        y3+=Brush_rotation_center_Y;
        x4+=Brush_rotation_center_X;
        y4+=Brush_rotation_center_Y;
        Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0);
        Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0);
      }
      else
      {
        x1=x3=1-Brush_width;
        y1=y2=start_y;
        x2=x4=Paintbrush_X;
        y3=y4=end_y;
        x1+=Paintbrush_X;
        y1+=Paintbrush_Y;
        y2+=Paintbrush_Y;
        x3+=Paintbrush_X;
        y3+=Paintbrush_Y;
        y4+=Paintbrush_Y;
        Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0);
        Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0);
      }
      Draw_line_preview_xor(x1,y1,x2,y2,0);
      Draw_line_preview_xor(x2,y2,x4,y4,0);
      Draw_line_preview_xor(x4,y4,x3,y3,0);
      Draw_line_preview_xor(x3,y3,x1,y1,0);
  }
}
  // -- Effacer le curseur --
void Hide_cursor(void)
{
  byte  shape;
  int start_x; // int car sont parfois négatifs ! (quand on dessine sur un bord)
  int start_y;
  short end_x;
  short end_y;
  int x_pos;
  int y_pos;
  short counter_x;
  short counter_y;
  //short end_counter_x; // Position X ou s'arrête l'affichage de la brosse/pinceau
  //short end_counter_y; // Position Y ou s'arrête l'affichage de la brosse/pinceau
  int   temp;
  //byte  color;
  float cos_a,sin_a;
  short x1,y1,x2,y2,x3,y3,x4,y4;
  if ( ( (Mouse_Y=Main_X_zoom) ) )
    || (Windows_open) || (Cursor_shape==CURSOR_SHAPE_HOURGLASS) )
    shape=Cursor_shape;
  else
    shape=CURSOR_SHAPE_ARROW;
  switch(shape)
  {
    case CURSOR_SHAPE_TARGET :
      if (!Cursor_hidden)
      {
        if (Config.Cursor==1)
        {
          start_y=(Mouse_Y<6)?6-Mouse_Y:0;
          if (start_y<4)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+start_y-6,4-start_y);
          start_x=(Mouse_X<6)?(short)6-Mouse_X:0;
          if (start_x<4)
            Horizontal_XOR_line(Mouse_X+start_x-6,Mouse_Y,4-start_x);
          end_x=(Mouse_X+7>Screen_width)?Mouse_X+7-Screen_width:0;
          if (end_x<4)
            Horizontal_XOR_line(Mouse_X+3,Mouse_Y,4-end_x);
          end_y=(Mouse_Y+7>Screen_height)?Mouse_Y+7-Screen_height:0;
          if (end_y<4)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+3,4-end_y);
          Update_rect(Mouse_X+start_x-6,Mouse_Y+start_y-6,13-end_x,13-end_y);
        }
        else
        {
          temp=(Config.Cursor)?CURSOR_SHAPE_THIN_TARGET:CURSOR_SHAPE_TARGET;
          start_x=Mouse_X-Cursor_offset_X[temp];
          start_y=Mouse_Y-Cursor_offset_Y[temp];
          for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++)
          {
            if(y_pos>=Screen_height) break;
            for (x_pos=start_x,counter_x=0;counter_x<15;x_pos++,counter_x++)
            {
              if ( (x_pos<0) || (y_pos < 0)) continue;
              else if (x_pos>=Screen_width) break;
              Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]);
            }
          }
          Update_rect(Max(start_x,0),Max(start_y,0),x_pos-start_x,y_pos-start_y);
        }
      }
      if (!Paintbrush_hidden)
      {
        Hide_paintbrush(Paintbrush_X,Paintbrush_Y);
      }
      break;
    case CURSOR_SHAPE_COLORPICKER:
      if (!Cursor_hidden)
      {
        if (Config.Cursor==1)
        {
          // Barres formant la croix principale
          start_y=(Mouse_Y<5)?5-Mouse_Y:0;
          if (start_y<3)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+start_y-5,3-start_y);
          start_x=(Mouse_X<5)?(short)5-Mouse_X:0;
          if (start_x<3)
            Horizontal_XOR_line(Mouse_X+start_x-5,Mouse_Y,3-start_x);
          end_x=(Mouse_X+6>Screen_width)?Mouse_X+6-Screen_width:0;
          if (end_x<3)
            Horizontal_XOR_line(Mouse_X+3,Mouse_Y,3-end_x);
          end_y=(Mouse_Y+6>Screen_height)?Mouse_Y+6-Screen_height:0;
          if (end_y<3)
            Vertical_XOR_line  (Mouse_X,Mouse_Y+3,3-end_y);
          start_x=(!Mouse_X);
          start_y=(!Mouse_Y);
          end_x=(Mouse_X>=Screen_width-1);
          end_y=(Mouse_Y>=Menu_Y-1);
          if (Mouse_Y>5)
            Horizontal_XOR_line(start_x+Mouse_X-1,Mouse_Y-6,3-(start_x+end_x));
          if (Mouse_X>5)
            Vertical_XOR_line  (Mouse_X-6,start_y+Mouse_Y-1,3-(start_y+end_y));
          if (Mouse_X=0) && (x_pos=0) && (y_pos=Screen_width) break;
        for (y_pos=start_y,counter_y=0;counter_y<15;y_pos++,counter_y++)
        {
            if(y_pos<0) continue;
            if(y_pos>=Screen_height) break;
            Pixel(x_pos,y_pos,CURSOR_BACKGROUND[counter_y][counter_x]);
        }
      }
      Update_rect(Max(start_x,0),Max(start_y,0),counter_x,counter_y);
      break;
    case CURSOR_SHAPE_XOR_TARGET :
      x_pos=Paintbrush_X-Main_offset_X;
      y_pos=Paintbrush_Y-Main_offset_Y;
      counter_x=(Main_magnifier_mode)?Main_separator_position:Screen_width; // width de la barre XOR
      if ((y_pos=Limit_top))
      {
        Horizontal_XOR_line(0,Paintbrush_Y-Main_offset_Y,counter_x);
        Update_rect(0,Paintbrush_Y-Main_offset_Y,counter_x,1);
      }
      if ((x_pos=Limit_left))
      {
        Vertical_XOR_line(Paintbrush_X-Main_offset_X,0,Menu_Y);
        Update_rect(Paintbrush_X-Main_offset_X,0,1,Menu_Y);
      }
      if (Main_magnifier_mode)
      {
        // UPDATERECT
        if ((Paintbrush_Y>=Limit_top_zoom) && (Paintbrush_Y<=Limit_visible_bottom_zoom))
          Horizontal_XOR_line_zoom(Limit_left_zoom,Paintbrush_Y,Main_magnifier_width);
        if ((Paintbrush_X>=Limit_left_zoom) && (Paintbrush_X<=Limit_visible_right_zoom))
          Vertical_XOR_line_zoom(Paintbrush_X,Limit_top_zoom,Main_magnifier_height);
      }
      break;
    case CURSOR_SHAPE_XOR_RECTANGLE :
      // !!! Cette forme ne peut pas être utilisée en mode Loupe !!!
      // Petite croix au centre
      start_x=(Mouse_X-3);
      start_y=(Mouse_Y-3);
      end_x  =(Mouse_X+4);
      end_y  =(Mouse_Y+4);
      if (start_x<0)
        start_x=0;
      if (start_y<0)
        start_y=0;
      if (end_x>Screen_width)
        end_x=Screen_width;
      if (end_y>Menu_Y)
        end_y=Menu_Y;
      Horizontal_XOR_line(start_x,Mouse_Y,end_x-start_x);
      Vertical_XOR_line  (Mouse_X,start_y,end_y-start_y);
      // Grand rectangle autour
      start_x=Mouse_X-(Main_magnifier_width>>1);
      start_y=Mouse_Y-(Main_magnifier_height>>1);
      if (start_x+Main_magnifier_width>=Limit_right-Main_offset_X)
        start_x=Limit_right-Main_magnifier_width-Main_offset_X+1;
      if (start_y+Main_magnifier_height>=Limit_bottom-Main_offset_Y)
        start_y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1;
      if (start_x<0)
        start_x=0;
      if (start_y<0)
        start_y=0;
      end_x=start_x+Main_magnifier_width-1;
      end_y=start_y+Main_magnifier_height-1;
      Horizontal_XOR_line(start_x,start_y,Main_magnifier_width);
      Vertical_XOR_line(start_x,start_y+1,Main_magnifier_height-2);
      Vertical_XOR_line(  end_x,start_y+1,Main_magnifier_height-2);
      Horizontal_XOR_line(start_x,  end_y,Main_magnifier_width);
      Update_rect(start_x,start_y,end_x+1-start_x,end_y+1-start_y);
      break;
    default: //case CURSOR_SHAPE_XOR_ROTATION :
      start_x=1-(Brush_width>>1);
      start_y=1-(Brush_height>>1);
      end_x=start_x+Brush_width-1;
      end_y=start_y+Brush_height-1;
      if (Brush_rotation_center_is_defined)
      {
        if ( (Brush_rotation_center_X==Paintbrush_X)
          && (Brush_rotation_center_Y==Paintbrush_Y) )
        {
          cos_a=1.0;
          sin_a=0.0;
        }
        else
        {
          x_pos=Paintbrush_X-Brush_rotation_center_X;
          y_pos=Paintbrush_Y-Brush_rotation_center_Y;
          cos_a=(float)x_pos/sqrt((x_pos*x_pos)+(y_pos*y_pos));
          sin_a=sin(acos(cos_a));
          if (y_pos>0) sin_a=-sin_a;
        }
        Transform_point(start_x,start_y, cos_a,sin_a, &x1,&y1);
        Transform_point(end_x  ,start_y, cos_a,sin_a, &x2,&y2);
        Transform_point(start_x,end_y  , cos_a,sin_a, &x3,&y3);
        Transform_point(end_x  ,end_y  , cos_a,sin_a, &x4,&y4);
        x1+=Brush_rotation_center_X;
        y1+=Brush_rotation_center_Y;
        x2+=Brush_rotation_center_X;
        y2+=Brush_rotation_center_Y;
        x3+=Brush_rotation_center_X;
        y3+=Brush_rotation_center_Y;
        x4+=Brush_rotation_center_X;
        y4+=Brush_rotation_center_Y;
        Pixel_figure_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,0);
        Draw_line_preview_xor(Brush_rotation_center_X,Brush_rotation_center_Y,Paintbrush_X,Paintbrush_Y,0);
      }
      else
      {
        x1=x3=1-Brush_width;
        y1=y2=start_y;
        x2=x4=Paintbrush_X;
        y3=y4=end_y;
        x1+=Paintbrush_X;
        y1+=Paintbrush_Y;
        y2+=Paintbrush_Y;
        x3+=Paintbrush_X;
        y3+=Paintbrush_Y;
        y4+=Paintbrush_Y;
        Pixel_figure_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,0);
        Draw_line_preview_xor(Paintbrush_X-end_x,Paintbrush_Y,Paintbrush_X,Paintbrush_Y,0);
      }
      Draw_line_preview_xor(x1,y1,x2,y2,0);
      Draw_line_preview_xor(x2,y2,x4,y4,0);
      Draw_line_preview_xor(x4,y4,x3,y3,0);
      Draw_line_preview_xor(x3,y3,x1,y1,0);
  }
}
// -- Fonction diverses d'affichage ------------------------------------------
  // -- Reafficher toute l'image (en prenant en compte le facteur de zoom) --
void Display_all_screen(void)
{
  word width;
  word height;
  // ---/\/\/\  Partie non zoomée: /\/\/\---
  if (Main_magnifier_mode)
  {
    if (Main_image_width