/* vim:expandtab:ts=2 sw=2:
*/
/*  Grafx2 - The Ultimate 256-color bitmap paint program
    Copyright 2008 Yves Rizoud
    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 
*/
#define _XOPEN_SOURCE 500
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "const.h"
#include "struct.h"
#include "global.h"
#include "misc.h"
#include "graph.h"
#include "engine.h"
#include "readline.h"
#include "filesel.h"
#include "loadsave.h"
#include "init.h"
#include "buttons.h"
#include "operatio.h"
#include "pages.h"
#include "palette.h"
#include "errors.h"
#include "readini.h"
#include "saveini.h"
#include "shade.h"
#include "io.h"
#include "help.h"
#include "text.h"
#include "sdlscreen.h"
#include "windows.h"
#include "brush.h"
#include "input.h"
#include "special.h"
#ifdef __VBCC__
    #define __attribute__(x)
#endif
#if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
    #include 
    #include 
    #define isHidden(x) (0)
#elif defined(__WIN32__)
    #include 
    #include 
    #define isHidden(x) (GetFileAttributesA((x)->d_name)&FILE_ATTRIBUTE_HIDDEN)
#else
    #include 
    #define isHidden(x) ((x)->d_name[0]=='.')
#endif
extern char Program_version[]; // generated in pversion.c
extern short Old_MX;
extern short Old_MY;
//-- MODELE DE BOUTON DE MENU ------------------------------------------------
/*
void Bouton_***(void)
{
  short clicked_button;
  Open_window(310,190,"***");
  Window_set_normal_button(103,137,80,14,"OK",0,1,SDLK_RETURN); // 1
  Window_set_scroller_button(18,44,88,16,4,0);             // 2
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
  }
  while (clicked_button!=1);
  Close_window();
  Unselect_button(BOUTON_***);
  Display_cursor();
}
*/
void Message_out_of_memory(void)
{
  short clicked_button;
  Open_window(216,76,"Not enough memory!");
  Print_in_window(8,20,"Please consult the manual",MC_Black,MC_Light);
  Print_in_window(24,28,"to know how to obtain",MC_Black,MC_Light);
  Print_in_window(36,36,"more memory space.",MC_Black,MC_Light);
  Window_set_normal_button(60,53,40,14,"OK",1,1,SDLK_RETURN); // 1
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
    clicked_button=Window_clicked_button();
  while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=SDLK_o));
  if(clicked_button<=0) Key=0;
  Close_window();
  Display_cursor();
}
void Button_Message_initial(void)
{
  char  str[30];
  int   x_pos,offs_y,x,y;
  strcpy(str,"GrafX2 version ");
  strcat(str,Program_version);
  Open_window(260,172,str);
  Window_display_frame_in(10,20,239,62);
  Block(Window_pos_X+(Menu_factor_X*11),
        Window_pos_Y+(Menu_factor_Y*21),
        Menu_factor_X*237,Menu_factor_Y*60,MC_Black);
  for (y=23,offs_y=0; y<79; offs_y+=231,y++)
    for (x=14,x_pos=0; x_pos<231; x_pos++,x++)
      Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]);
  Print_in_window(130-4*26,88,"Copyright (c) 2007-2009 by",MC_Dark,MC_Light);
  Print_in_window(130-4*23,96,"the Grafx2 project team",MC_Black,MC_Light);
  Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light);
  Print_in_window(130-4*13,120,"Sunset Design",MC_Black,MC_Light);
  //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light);
  Print_in_window(130-4*28,136,"http://grafx2.googlecode.com",MC_Dark,MC_Light);
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  while(!Mouse_K && !Key) if(!Get_input()) SDL_Delay(20);
  if (Mouse_K)
    Wait_end_of_click();
  Close_window();
  Display_cursor();
}
void Change_paintbrush_shape(byte shape)
{
  Paintbrush_shape=shape;
  Display_paintbrush_in_menu();
  switch (Current_operation)
  {
    case OPERATION_FILL :
      Paintbrush_shape_before_fill=shape;
      Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
      break;
    case OPERATION_COLORPICK :
      Paintbrush_shape_before_colorpicker=shape;
      Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
      break;
    // Note: Il existe un Paintbrush_shape_before_lasso, mais comme le lasso aura
    // été automatiquement désactivé avant d'arriver ici, y'a pas de problème.
  }
}
//-------------------------------- UNDO/REDO ---------------------------------
void Button_Undo(void)
{
  Hide_cursor();
  Undo();
  Set_palette(Main_palette);
  Compute_optimal_menu_colors(Main_palette);
  Display_all_screen();
  Unselect_button(BUTTON_UNDO);
  Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode);
  Display_menu();
  Display_cursor();
}
void Button_Redo(void)
{
  Hide_cursor();
  Redo();
  Set_palette(Main_palette);
  Compute_optimal_menu_colors(Main_palette);
  Display_all_screen();
  Unselect_button(BUTTON_UNDO);
  Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode);
  Display_menu();
  Display_cursor();
}
//---------------------------- SCROLL PALETTE LEFT ---------------------------
void Button_Pal_left(void)
{
  short cells;
  cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y();
  Hide_cursor();
  if (First_color_in_palette)
  {
    if (First_color_in_palette>=cells)
      First_color_in_palette-=cells;
    else
      First_color_in_palette=0;
    Display_menu_palette();
  }
  Unselect_button(BUTTON_PAL_LEFT);
  Display_cursor();
}
void Button_Pal_left_fast(void)
{
  short cells_x = Palette_cells_X();
  short cells_y = Palette_cells_Y();
  Hide_cursor();
  if (First_color_in_palette)
  {
    if (First_color_in_palette>=cells_y*cells_x)
      First_color_in_palette-=cells_y*cells_x;
    else
      First_color_in_palette=0;
    Display_menu_palette();
  }
  Unselect_button(BUTTON_PAL_LEFT);
  Display_cursor();
}
//--------------------------- SCROLL PALETTE RIGHT ---------------------------
void Button_Pal_right(void)
{
  short cells;
  cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y();
  Hide_cursor();
  if ((int)First_color_in_palette+Palette_cells_X()*Palette_cells_Y()<256)
  {
    First_color_in_palette+=cells;
    Display_menu_palette();
  }
  
  Unselect_button(BUTTON_PAL_RIGHT);
  Display_cursor();
}
void Button_Pal_right_fast(void)
{
  short cells_x = Palette_cells_X();
  short cells_y = Palette_cells_Y();
  Hide_cursor();
  if ((int)First_color_in_palette+cells_y*cells_x<256)
  {
    if ((int)First_color_in_palette+(cells_y)*cells_x*2<256)
      First_color_in_palette+=cells_x*cells_y;
    else
      First_color_in_palette=255/cells_y*cells_y-(cells_x-1)*cells_y;
    Display_menu_palette();
  }
  Unselect_button(BUTTON_PAL_RIGHT);
  Display_cursor();
}
//-------------------- item de la forecolor dans le menu --------------------
void Button_Select_forecolor(void)
{
  static long time_click = 0;
  long time_previous;
  int color=Pick_color_in_palette();
  time_previous = time_click;
  time_click = SDL_GetTicks();
  if (color == Fore_color)
  {
    // Check if it's a double-click    
    if (time_click - time_previous < Config.Double_click_speed)
    {
      // Open palette window
      Button_Palette();
    }
  }
  else if (color!=-1)
  {
    Hide_cursor();
    Set_fore_color(color);
    Display_cursor();
  }
}
//-------------------- item de la backcolor dans le menu --------------------
void Button_Select_backcolor(void)
{
  int color=Pick_color_in_palette();
  if (color!=-1)
  {
    Hide_cursor();
    Set_back_color(color);
    Display_cursor();
  }
}
void Button_Hide_menu(void)
{
  Hide_cursor();
  if (Menu_is_visible)
  {
    Menu_is_visible=0;
    Menu_Y=Screen_height;
    if (Main_magnifier_mode)
    {
      Compute_magnifier_data();
      if (Main_magnifier_offset_Y+Main_magnifier_height>Main_image_height)
      {
        if (Main_magnifier_height>Main_image_height)
          Main_magnifier_offset_Y=0;
        else
          Main_magnifier_offset_Y=Main_image_height-Main_magnifier_height;
      }
    }
    //   On repositionne le décalage de l'image pour qu'il n'y ait pas d'in-
    // -cohérences lorsqu'on sortira du mode Loupe.
    if (Main_offset_Y+Screen_height>Main_image_height)
    {
      if (Screen_height>Main_image_height)
        Main_offset_Y=0;
      else
        Main_offset_Y=Main_image_height-Screen_height;
    }
    // On fait pareil pour le brouillon
    if (Spare_offset_Y+Screen_height>Spare_image_height)
    {
      if (Screen_height>Spare_image_height)
        Spare_offset_Y=0;
      else
        Spare_offset_Y=Spare_image_height-Screen_height;
    }
    Compute_magnifier_data();
    if (Main_magnifier_mode)
      Position_screen_according_to_zoom();
    Compute_limits();
    Compute_paintbrush_coordinates();
    Display_all_screen();
  }
  else
  {
    byte current_menu;
    Menu_is_visible=1;
    Menu_Y=Screen_height;
    for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++)
      if (Menu_bars[current_menu].Visible)
        Menu_Y -= Menu_bars[current_menu].Height * Menu_factor_Y;
    Compute_magnifier_data();
    if (Main_magnifier_mode)
      Position_screen_according_to_zoom();
    Compute_limits();
    Compute_paintbrush_coordinates();
    Display_menu();
    if (Main_magnifier_mode)
      Display_all_screen();
  }
  Unselect_button(BUTTON_HIDE);
  Display_cursor();
}
void Set_bar_visibility(word bar, byte visible)
{  
  if (!visible && Menu_bars[bar].Visible)
  {
    // Hide it
    Menu_bars[bar].Visible=0;
    Compute_menu_offsets();
    if (Main_magnifier_mode)
    {
      Compute_magnifier_data();
      if (Main_magnifier_offset_Y+Main_magnifier_height>Main_image_height)
      {
        if (Main_magnifier_height>Main_image_height)
          Main_magnifier_offset_Y=0;
        else
          Main_magnifier_offset_Y=Main_image_height-Main_magnifier_height;
      }
    }
    //   On repositionne le décalage de l'image pour qu'il n'y ait pas d'in-
    // -cohérences lorsqu'on sortira du mode Loupe.
    if (Main_offset_Y+Screen_height>Main_image_height)
    {
      if (Screen_height>Main_image_height)
        Main_offset_Y=0;
      else
        Main_offset_Y=Main_image_height-Screen_height;
    }
    // On fait pareil pour le brouillon
    if (Spare_offset_Y+Screen_height>Spare_image_height)
    {
      if (Screen_height>Spare_image_height)
        Spare_offset_Y=0;
      else
        Spare_offset_Y=Spare_image_height-Screen_height;
    }
    Compute_magnifier_data();
    if (Main_magnifier_mode)
      Position_screen_according_to_zoom();
    Compute_limits();
    Compute_paintbrush_coordinates();
    Display_menu();
    Display_all_screen();
  }
  else if (visible && !Menu_bars[bar].Visible)
  {
    // Show it
    Menu_bars[bar].Visible = 1;
    
    Compute_menu_offsets();
    Compute_magnifier_data();
    if (Main_magnifier_mode)
      Position_screen_according_to_zoom();
    Compute_limits();
    Compute_paintbrush_coordinates();
    Display_menu();
    if (Main_magnifier_mode)
      Display_all_screen();
  }
}
void Button_Toggle_toolbar(void)
{  
  T_Dropdown_button dropdown;
  T_Dropdown_choice *item;
  static char menu_name[2][9]= {
    " Tools",
    " Layers"
  };
  
  menu_name[0][0] = Menu_bars[MENUBAR_TOOLS ].Visible ? 22 : ' ';
  menu_name[1][0] = Menu_bars[MENUBAR_LAYERS].Visible ? 22 : ' ';
  Hide_cursor();
  
  dropdown.Pos_X         =Buttons_Pool[BUTTON_HIDE].X_offset;
  dropdown.Pos_Y         =Buttons_Pool[BUTTON_HIDE].Y_offset;
  dropdown.Height        =Buttons_Pool[BUTTON_HIDE].Height;
  dropdown.Dropdown_width=70;
  dropdown.First_item    =NULL;
  dropdown.Bottom_up     =1;
  Window_dropdown_add_item(&dropdown, 0, menu_name[0]);
  Window_dropdown_add_item(&dropdown, 1, menu_name[1]);
  item=Dropdown_activate(&dropdown,0,Menu_Y+Menu_bars[MENUBAR_STATUS].Top*Menu_factor_Y);
  
  if (item)
  {
    switch (item->Number)
    {
      case 0:
        Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible);
        break;
      case 1:
        Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible);
        break;
    }
  }
  
  // Closing
  Window_dropdown_clear_items(&dropdown);
  
  Unselect_button(BUTTON_HIDE);
  Display_cursor();
}
void Button_Toggle_all_toolbars(void)
{
  // This is used to memorize the bars' visibility when temporarily hidden
  static word Last_visibility = 0xFFFF;
  int i;
  word current_visibility;
  Hide_cursor();
  
  // Check which bars are visible
  current_visibility=0;
  for (i=MENUBAR_STATUS+1;iPages->Filename, Main_backups->Pages->File_directory);
      if ( (!File_exists(filename)) || Confirmation_box("Erase old file ?") )
      {
        T_IO_Context save_context;
        Hide_cursor();
        old_cursor_shape=Cursor_shape;
        Cursor_shape=CURSOR_SHAPE_HOURGLASS;
        Display_cursor();
       
        Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory);
        Save_image(&save_context);
        Destroy_context(&save_context);
        
        Hide_cursor();
        Cursor_shape=old_cursor_shape;
        Display_cursor();
       
        if (!File_error)
          // L'ayant sauvée avec succès,
          return 1; // On peut quitter
        else
          // Il y a eu une erreur lors de la sauvegarde,
          return 0; // On ne peut donc pas quitter
      }
      else
        // L'utilisateur ne veut pas écraser l'ancien fichier,
        return 0; // On doit donc rester
    case 3 : return 1; // Quitter
  }
  return 0;
}
void Button_Quit(void)
{
  //short clicked_button;
  if (Button_Quit_local_function())
  {
    if (Spare_image_is_modified)
    {
      Button_Page(); // On passe sur le brouillon
      // Si l'utilisateur présente les derniers symptomes de l'abandon
      if (Button_Quit_local_function())
        Quitting=1;
    }
    else
      Quitting=1;
  }
  if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) )
    Hide_cursor();
  Unselect_button(BUTTON_QUIT);
  if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) )
    Display_cursor();
}
//---------------------------- Effacer l'écran -------------------------------
void Button_Clear(void)
{
  Hide_cursor();
  Backup();
  if (Stencil_mode && Config.Clear_with_stencil)
    Clear_current_image_with_stencil(Main_backups->Pages->Transparent_color,Stencil);
  else
    Clear_current_image(Main_backups->Pages->Transparent_color);
  Redraw_layered_image();
  End_of_modification();
  Display_all_screen();
  Unselect_button(BUTTON_CLEAR);
  Display_cursor();
}
void Button_Clear_with_backcolor(void)
{
  Hide_cursor();
  Backup();
  if (Stencil_mode && Config.Clear_with_stencil)
    Clear_current_image_with_stencil(Back_color,Stencil);
  else
    Clear_current_image(Back_color);
  Redraw_layered_image();
  End_of_modification();
  Display_all_screen();
  Unselect_button(BUTTON_CLEAR);
  Display_cursor();
}
 
//------------------------------- Paramètres ---------------------------------
void Settings_display_config(T_Config * conf)
#define YES "YES"
#define NO  " NO"
{
  T_Scroller_button * slider=Window_scroller_button_list;
  char str[4];
  Hide_cursor();
  // slider = sensitivity slider for Y
  slider->Position=conf->Mouse_sensitivity_index_y-1;
  Window_draw_slider(slider);
  slider=slider->Next;
  // slider = sensitivity slider for X
  slider->Position=conf->Mouse_sensitivity_index_x-1;
  Window_draw_slider(slider);
  Print_in_window(273, 31,(conf->Show_hidden_files)?YES:NO,MC_Black,MC_Light);
  Print_in_window(273, 46,(conf->Show_hidden_directories)?YES:NO,MC_Black,MC_Light);
  Print_in_window(223, 84,(conf->Safety_colors)?YES:NO,MC_Black,MC_Light);
  Print_in_window(223, 99,(conf->Adjust_brush_pick)?YES:NO,MC_Black,MC_Light);
  Print_in_window(223,114,(conf->Auto_set_res)?YES:NO,MC_Black,MC_Light);
  Print_in_window(183,129,(conf->Coords_rel)?"Relative":"Absolute",MC_Black,MC_Light);
  Print_in_window( 91, 84,(conf->Clear_palette)?YES:NO,MC_Black,MC_Light);
  Print_in_window( 91, 99,(conf->Maximize_preview)?YES:NO,MC_Black,MC_Light);
  Print_in_window( 91,114,(conf->Backup)?YES:NO,MC_Black,MC_Light);
  Print_in_window(155,166,(conf->Auto_save)?YES:NO,MC_Black,MC_Light);
  Num2str(conf->Max_undo_pages,str,2);
  Window_input_content(Window_special_button_list,str);
  Display_cursor();
}
void Settings_save_config(T_Config * conf)
{
  if (Save_CFG())
    Error(0);
  else
    if (Save_INI(conf))
      Error(0);
}
void Settings_load_config(T_Config * conf)
{
  if (Load_CFG(0))
    Error(0);
  else
    if (Load_INI(conf))
      Error(0);
}
void Button_Settings(void)
{
  short clicked_button;
  T_Config Config_choisie;
  char str[3];
  byte config_is_reloaded=0;
  Config_choisie=Config;
  Open_window(307,182,"Settings");
  // On commence par dessiner tous les Cadres
  Window_display_frame(  5, 47,157,17); // Nb UNDO
  Window_display_frame(163, 16,139,48); // Show in filelist
  Window_display_frame(253, 77, 49,82); // Mouse sens.
  Window_display_frame(  5, 65,247,96); // |_ Misc.
  // On affiche maintenant tout le blabla
  Print_in_window(169, 19,"Show in filelist",MC_Dark,MC_Light);
  Print_in_window(  9, 52,"Nb of UNDO pages",MC_Dark,MC_Light);
  Print_in_window( 80, 70,"Miscellaneous"   ,MC_Dark,MC_Light);
  Print_in_window(258, 80,"Mouse"           ,MC_Dark,MC_Light);
  Print_in_window(258, 88,"Sens."           ,MC_Dark,MC_Light);
  Print_in_window(256,123,"X"               ,MC_Dark,MC_Light);
  Print_in_window(292,123,"Y"               ,MC_Dark,MC_Light);
  // Button Show/Hide dans le fileselect
  Window_set_normal_button(167, 28,131,14,"Hidden files:   ",0,1,SDLK_LAST); // 1
  Window_set_normal_button(167, 43,131,14,"Hidden dir. :   ",0,1,SDLK_LAST); // 2
  Window_set_normal_button(9, 81, 107, 14, "Clear pal:   ", 0, 1, SDLK_LAST); // 3
  Window_set_normal_button(9, 96, 107, 14, "Max prev.:   ", 0, 1, SDLK_LAST); // 4
  // Button Effectuer des backups à chaque sauvegarde
  Window_set_normal_button(  9,111,107,14,"Backup   :   ",0,1,SDLK_LAST); // 5
  // Button Safety colors
  Window_set_normal_button(117, 81,131,14,"Safe. colors:   ",0,1,SDLK_LAST); // 6
  // Button Adjust Brush Pick
  Window_set_normal_button(117, 96,131,14,"AdjBrushPick:   ",0,1,SDLK_LAST); // 7
  // Button Passer dans la résolution appropriée après un chargement
  Window_set_normal_button(117,111,131,14,"Auto-set res:   ",0,1,SDLK_LAST); // 8
  // Button Adapter la palette après un chargement (<=> Shift+BkSpc)
  Window_set_normal_button(117,126,131,14,"Coords:         ",0,1,SDLK_LAST); // 9
    // Button Reload
  Window_set_normal_button(  6,163, 51,14,"Reload"       ,0,1,SDLK_LAST); // 10
    // Button Auto-save
  Window_set_normal_button( 73,163,107,14,"Auto-save:   ",0,1,SDLK_LAST); // 11
    // Button Save
  Window_set_normal_button(183,163, 51,14,"Save"         ,0,1,SDLK_LAST); // 12
    // Button Close
  Window_set_normal_button(250,163, 51,14,"Close"        ,0,1,KEY_ESC); // 13
  // Jauges de sensibilité de la souris (X puis Y)
  Window_set_scroller_button(265,99,56,4,1,0); // 14
  Window_set_scroller_button(279,99,56,4,1,0); // 15
  // Zone de saisie du nb de pages de Undo
  Window_set_input_button(140,50,2);           // 16
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  Settings_display_config(&Config_choisie);
  do
  {
    clicked_button=Window_clicked_button();
    switch(clicked_button)
    {
      case  1 : // Hidden files
        Config_choisie.Show_hidden_files=(Config_choisie.Show_hidden_files)?0:-1;
        break;
      case  2 : // Hidden dir.
        Config_choisie.Show_hidden_directories=(Config_choisie.Show_hidden_directories)?0:-1;
        break;
      case  3 : // Clear palette
        Config_choisie.Clear_palette=!Config_choisie.Clear_palette;
        break;
      case  4 : // Maximize preview
        Config_choisie.Maximize_preview=!Config_choisie.Maximize_preview;
        break;
      case  5 : // Backup
        Config_choisie.Backup=!Config_choisie.Backup;
        break;
      case 6 : // Safety colors
        Config_choisie.Safety_colors=!Config_choisie.Safety_colors;
        break;
      case 7 : // Adjust brush pick
        Config_choisie.Adjust_brush_pick=!Config_choisie.Adjust_brush_pick;
        break;
      case 8 : // Auto-set resolution
        Config_choisie.Auto_set_res=!Config_choisie.Auto_set_res;
        break;
      case 9 : // Coordonnées
        Config_choisie.Coords_rel=!Config_choisie.Coords_rel;
        break;
      case 10 : // Reload
        Settings_load_config(&Config_choisie);
        config_is_reloaded=1;
        break;
      case 11 : // Auto-save
        Config_choisie.Auto_save=!Config_choisie.Auto_save;
        break;
      case 12 : // Save
        Settings_save_config(&Config_choisie);
        break;
      // 13 close
      case 14 : // X Sensib.
        Config_choisie.Mouse_sensitivity_index_x=Window_attribute2+1;
        break;
      case 15 : // Y Sensib.
        Config_choisie.Mouse_sensitivity_index_y=Window_attribute2+1;
        break;
      case 16 : // Nb pages Undo
        Num2str(Config_choisie.Max_undo_pages,str,2);
        Readline(142,52,str,2,1);
        Config_choisie.Max_undo_pages=atoi(str);
        // On corrige la valeur
        if (Config_choisie.Max_undo_pages>NB_MAX_PAGES_UNDO)
        {
          Config_choisie.Max_undo_pages=NB_MAX_PAGES_UNDO;
          Num2str(Config_choisie.Max_undo_pages,str,2);
          Window_input_content(Window_special_button_list,str);
        }
        else if (!Config_choisie.Max_undo_pages)
        {
          Config_choisie.Max_undo_pages=1;
          Num2str(Config_choisie.Max_undo_pages,str,2);
          Window_input_content(Window_special_button_list,str);
        }
        Display_cursor();
        Key=0;
        Wait_end_of_click();
    }
    if ((clicked_button>=3) && (clicked_button<=4))
    {
      Main_fileselector_position=0;
      Main_fileselector_offset=0;
      Spare_fileselector_position=0;
      Spare_fileselector_offset=0;
    }
    if ((clicked_button>=1) && (clicked_button<13))
      Settings_display_config(&Config_choisie);
      
    if (Is_shortcut(Key,0x100+BUTTON_HELP))
      Window_help(BUTTON_SETTINGS, NULL);
    else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS))
      clicked_button=13;
  }
  while ( (clicked_button!=13) && (Key!=SDLK_RETURN) );
  Config=Config_choisie;
  if (config_is_reloaded)
    Compute_optimal_menu_colors(Main_palette);
  Close_window();
  Unselect_button(BUTTON_SETTINGS);
  // Raffichage du menu pour que les inscriptions qui y figurent soient
  // retracées avec la nouvelle fonte
  Display_menu();
  Display_cursor();
  // On vérifie qu'on peut bien allouer le nombre de pages Undo.
  Set_number_of_backups(Config.Max_undo_pages);
}
// Data for skin selector
T_Fileselector Skin_files_list;
// Data for font selector
T_Fileselector Font_files_list;
//
char * Format_font_filename(const char * fname)
{
  static char result[12];
  int c;
  int length;
  
  fname+=5; // Assume "font_" prefix
  length=strlen(fname) - 4; // assume .png extension
  
  for (c=0;c<11 && c11)
    result[10] = ELLIPSIS_CHARACTER;
  return result;
}
// Add a skin to the list
void Add_font_or_skin(const char *name)
{
  const char * fname;
  int namelength;
  
  // Cut the long name to keep only filename (no directory)
  fname = Find_last_slash(name);
  if (fname)
    fname++;
  else
    fname = name;
  namelength = strlen(fname);
  if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, "skin_", 5)
    && (!strcasecmp(fname + namelength - 4,".png")
    || !strcasecmp(fname + namelength - 4,".gif")))
  {
    Add_element_to_list(&Skin_files_list, name, 0);
    
    if (fname[0]=='\0')
      return;
    // Remove directory from full name
    strcpy(Skin_files_list.First->Full_name, fname);
    // Reformat the short name differently
    strcpy(Skin_files_list.First->Short_name,
      Format_filename(Skin_files_list.First->Full_name, 0)
    );
  }
  else if (namelength>=10 && !strncasecmp(fname, "font_", 5)
    && (!strcasecmp(fname + namelength - 4, ".png")))
  {
    Add_element_to_list(&Font_files_list, name, 0);
    
    if (fname[0]=='\0')
      return;
    // Remove directory from full name
    strcpy(Font_files_list.First->Full_name, fname);
    // Reformat the short name differently
    strcpy(Font_files_list.First->Short_name,
      Format_font_filename(Font_files_list.First->Full_name));
  }
   
}
// Callback to display a skin name in the list
void Draw_one_skin_name(word x, word y, word index, byte highlighted)
{
  T_Fileselector_item * current_item;
  if (Skin_files_list.Nb_elements)
  {
    current_item = Get_item_by_index(&Skin_files_list, index);
    Print_in_window(x, y, current_item->Short_name, MC_Black,
      (highlighted)?MC_Dark:MC_Light);
  }
}
/// Skin selector window
void Button_Skins(void)
{
  short clicked_button;
  short temp;
  char skinsdir[MAX_PATH_CHARACTERS];
  T_Dropdown_button * font_dropdown;
  T_Dropdown_button * cursor_dropdown;
  T_List_button * skin_list;
  T_Scroller_button * file_scroller;
  int selected_font = 0;
  int selected_cursor = Config.Cursor;
  byte separatecolors = Config.Separate_colors;
  byte showlimits = Config.Display_image_limits;
  word x, y, x_pos, offs_y;
  
  char * cursors[] = { "Solid", "Transparent", "Thin" };
  T_Gui_skin * gfx = NULL;
  #define FILESEL_Y 34
  // Show preferred colors
  Set_color(MC_Dark, Config.Fav_menu_colors[1].R, Config.Fav_menu_colors[1].G, Config.Fav_menu_colors[1].B);
  Set_color(MC_Light, Config.Fav_menu_colors[2].R, Config.Fav_menu_colors[2].G, Config.Fav_menu_colors[2].B);
  
  // --- Read the contents of skins/ directory ------------------
  
  // Here we use the same data container as the fileselectors.
  // Reinitialize the list
  Free_fileselector_list(&Skin_files_list);
  Free_fileselector_list(&Font_files_list);
  // Browse the "skins" directory
  strcpy(skinsdir, Data_directory);
  strcat(skinsdir, "skins");
  // Add each found file to the list
  For_each_file(skinsdir, Add_font_or_skin);
  // Sort it
  Sort_list_of_files(&Skin_files_list);
  Sort_list_of_files(&Font_files_list);
  
  selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file);
  
  // --------------------------------------------------------------
  Open_window(290, 140, "Skins");
  // Frames
  Window_display_frame_in(6, FILESEL_Y - 2, 148, 84); // File selector
  // Texts
  Print_in_window( 172, 33,"Font:"            ,MC_Black,MC_Light);
  Print_in_window( 172, 59,"Cursor:"          ,MC_Black,MC_Light);
  // Ok button
  Window_set_normal_button(6, 120, 51, 14, "OK", 0, 1, SDLK_RETURN); // 1
  // List of skins
  skin_list = Window_set_list_button(
  // Fileselector
  Window_set_special_button(8, FILESEL_Y + 1, 144, 80), // 2
    // Scroller for the fileselector
    (file_scroller = Window_set_scroller_button(155, FILESEL_Y - 1, 82,
    Skin_files_list.Nb_elements, 10, 0)), // 3
    Draw_one_skin_name); // 4
  
  skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file);
  // Buttons to choose a font
  font_dropdown = Window_set_dropdown_button(172, 43, 104, 11, 0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 5
  for (temp=0; tempShort_name);
  // Cancel
  Window_set_normal_button(61, 120, 51,14,"Cancel",0,1,SDLK_ESCAPE); // 6
  // Dropdown list to choose cursor type
  cursor_dropdown = Window_set_dropdown_button(172, 69, 104, 11, 0,
    cursors[selected_cursor], 1, 0, 1, RIGHT_SIDE|LEFT_SIDE,0); // 7
  for (temp = 0; temp<3; temp++)
    Window_dropdown_add_item(cursor_dropdown, temp, cursors[temp]);
  Window_set_normal_button(172, 87, 14, 14,
    (Config.Display_image_limits)?"X":" ", -1, 1, SDLK_LAST); // 8
  Print_in_window( 190, 85,"Draw picture", MC_Dark, MC_Light);
  Print_in_window( 190, 94,"limits", MC_Dark, MC_Light);
  Window_set_normal_button(172, 111, 14, 14,
    (Config.Separate_colors)?"X":" ", -1, 1, SDLK_LAST); // 9
  Print_in_window( 190, 109,"Separate", MC_Dark, MC_Light);
  Print_in_window( 190, 118,"colors", MC_Dark, MC_Light);
  
  Window_redraw_list(skin_list);
  for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++)
    for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++)
      Pixel_in_window(x, y, Gfx->Preview[offs_y][x_pos]);
  Update_window_area(0, 0, Window_width, Window_height);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    if (Is_shortcut(Key,0x100+BUTTON_HELP))
      Window_help(BUTTON_SETTINGS, "SKINS");
    switch(clicked_button)
    {
      case 1 : // OK
        break;
      case 2 : // doesn't happen
        break;
      case 3 : // doesn't happen
        break;
      case 4 : // a file is selected
        // (Re-)load GUI graphics from selected skins
        strcpy(skinsdir, Get_item_by_index(&Skin_files_list,
          skin_list->List_start + skin_list->Cursor_position)->Full_name);
        gfx = Load_graphics(skinsdir);
        if (gfx == NULL) // Error
        {
          Verbose_message("Error!", Gui_loading_error_message);
          // Update preview
          Window_rectangle(6, 14, 173, 16, MC_Light);
        }
        else
        {
          // Update preview
          
          // Display the bitmap according to its own color indices
          for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++)
          for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++)
          {
            if (gfx->Preview[offs_y][x_pos] == gfx->Color_black)
              Pixel_in_window(x, y, MC_Black);
            else if (gfx->Preview[offs_y][x_pos] == gfx->Color_dark)
              Pixel_in_window(x, y,  MC_Dark);
            else if (gfx->Preview[offs_y][x_pos] == gfx->Color_white)
              Pixel_in_window(x, y, MC_White);
            else if (gfx->Preview[offs_y][x_pos] == gfx->Color_light)
              Pixel_in_window(x, y, MC_Light);
          }
          // Actualize current screen according to preferred GUI colors
          // Note this only updates onscreen colors
          Set_color(
            MC_Dark, 
            gfx->Default_palette[gfx->Color_dark].R,
            gfx->Default_palette[gfx->Color_dark].G,
            gfx->Default_palette[gfx->Color_dark].B);
          Set_color(
            MC_Light, 
            gfx->Default_palette[gfx->Color_light].R,
            gfx->Default_palette[gfx->Color_light].G,
            gfx->Default_palette[gfx->Color_light].B);
        }
        Update_window_area(6, 14, 173, 16);
        break;
      case 5 : // Font dropdown
        selected_font = Window_attribute2; // Get the index of the chosen font.
        break;
      // 6: Cancel
      case 7 : // Cursor
        selected_cursor = Window_attribute2;
        break;
      case 8: // Display limits
        showlimits = !showlimits;
        Hide_cursor();
        Print_in_window(175, 90, (showlimits)?"X":" ", MC_Black, MC_Light);
        Display_cursor();
        break;
      case 9: // Separate colors
        separatecolors = !separatecolors;
        Hide_cursor();
        Print_in_window(175, 114, (separatecolors)?"X":" ", MC_Black, MC_Light);
        Display_cursor();
        break;
    }
  }
  while ( (clicked_button!=1) && (clicked_button !=6) && (Key != SDLK_ESCAPE));
  if(clicked_button == 1)
  {
    byte * new_font;
    if (gfx != NULL)
    {
      Set_current_skin(skinsdir, gfx);
    }
    // (Re-)load the selected font
    new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name);
    if (new_font)
    {
      const char * fname;
      
      free(Menu_font);
      Menu_font = new_font;
      fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name;
      free(Config.Font_file);
      Config.Font_file = strdup(fname);
    }
    // Confirm the change of cursor shape
    Config.Cursor = selected_cursor;
    Config.Display_image_limits = showlimits;
    Config.Separate_colors = separatecolors;
    // Now find the best colors for the new skin in the current palette
    // and remap the skin
    Compute_optimal_menu_colors(Main_palette);
  }
  
  // We don't want to keep the skin's palette, as this would corrupt the current picture's one.
  Set_palette(Main_palette);
  Close_window();
  Unselect_button(BUTTON_SETTINGS);
  
  // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte
  Display_menu();
  Display_cursor();
}
//---------------------------- Changement de page ----------------------------
void Button_Page(void)
{
  byte   factor_index;
  char   Temp_buffer[256];
  
  Hide_cursor();
  // On dégrossit le travail avec les infos des listes de pages
  Exchange_main_and_spare();
  // On fait le reste du travail "à la main":
  SWAP_PBYTES(Main_visible_image.Image,Spare_visible_image.Image)
  SWAP_WORDS (Main_visible_image.Width,Spare_visible_image.Width)
  SWAP_WORDS (Main_visible_image.Height,Spare_visible_image.Height)
  SWAP_SHORTS(Main_offset_X,Spare_offset_X)
  SWAP_SHORTS(Main_offset_Y,Spare_offset_Y)
  SWAP_SHORTS(Old_main_offset_X,Old_spare_offset_X)
  SWAP_SHORTS(Old_main_offset_Y,Old_spare_offset_Y)
  SWAP_SHORTS(Main_separator_position,Spare_separator_position)
  SWAP_SHORTS(Main_X_zoom,Spare_X_zoom)
  SWAP_FLOATS(Main_separator_proportion,Spare_separator_proportion)
  SWAP_BYTES (Main_magnifier_mode,Spare_magnifier_mode)
  Pixel_preview=(Main_magnifier_mode)?Pixel_preview_magnifier:Pixel_preview_normal;
  SWAP_WORDS (Main_magnifier_factor,Spare_magnifier_factor)
  SWAP_WORDS (Main_magnifier_height,Spare_magnifier_height)
  SWAP_WORDS (Main_magnifier_width,Spare_magnifier_width)
  SWAP_SHORTS(Main_magnifier_offset_X,Spare_magnifier_offset_X)
  SWAP_SHORTS(Main_magnifier_offset_Y,Spare_magnifier_offset_Y)
  // Swap du booléen "Image modifiée"
  SWAP_BYTES (Main_image_is_modified,Spare_image_is_modified)
  // Swap des infos sur les fileselects
  strcpy(Temp_buffer            ,Spare_current_directory);
  strcpy(Spare_current_directory,Main_current_directory);
  strcpy(Main_current_directory,Temp_buffer             );
  SWAP_BYTES (Main_format,Spare_format)
  SWAP_WORDS (Main_fileselector_position,Spare_fileselector_position)
  SWAP_WORDS (Main_fileselector_offset,Spare_fileselector_offset)
  SWAP_BYTES (Main_current_layer,Spare_current_layer)
  SWAP_DWORDS(Main_layers_visible,Spare_layers_visible)
  
  SWAP_DWORDS(Main_safety_number,Spare_safety_number)
  SWAP_DWORDS(Main_edits_since_safety_backup,Spare_edits_since_safety_backup)
  SWAP_BYTES(Main_safety_backup_prefix,Spare_safety_backup_prefix)
  {
    Uint32 a;
    a=Main_time_of_safety_backup;
    Main_time_of_safety_backup=Spare_time_of_safety_backup;
    Spare_time_of_safety_backup=a;
  }
  //Redraw_layered_image();
  // replaced by
  Update_buffers(Main_image_width, Main_image_height);
  Update_depth_buffer();
  Update_screen_targets();
  End_of_modification();
  // --
  // A la fin, on affiche l'écran
  for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main_magnifier_factor; factor_index++);
  //Change_magnifier_factor(factor_index,0);
  Compute_magnifier_data();
  if (Main_magnifier_mode)
    Pixel_preview=Pixel_preview_magnifier;
  else
    Pixel_preview=Pixel_preview_normal;
  Compute_limits();
  Compute_paintbrush_coordinates();
  Set_palette(Main_palette);
  Compute_optimal_menu_colors(Main_palette);
  Display_all_screen();
  Unselect_button(BUTTON_PAGE);
  Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode);
  Display_menu();
  Display_cursor();
}
// -- Copie de page ---------------------------------------------------------
void Copy_image_only(void)
{
  word old_width=Spare_image_width;
  word old_height=Spare_image_height;
  
  if (Backup_and_resize_the_spare(Main_image_width,Main_image_height))
  {
    byte i;
        
    for (i=0; iPages->Nb_layers; i++)
    {
      if (i == Spare_current_layer)
      {
        // Copy the current layer
        memcpy(Spare_backups->Pages->Image[i],Main_backups->Pages->Image[Main_current_layer],Main_image_width*Main_image_height);
      }
      else
      {
        // Resize the original layer
        Copy_part_of_image_to_another(
        Spare_backups->Pages->Next->Image[i],0,0,Min(old_width,Spare_image_width),
        Min(old_height,Spare_image_height),old_width,
        Spare_backups->Pages->Image[i],0,0,Spare_image_width);
      }
    }
    // Copie des dimensions de l'image
    /*
      C'est inutile, le "Backuper et redimensionner brouillon" a déjà modifié
      ces valeurs pour qu'elles soient correctes.
    */
    /*
    Spare_image_width=Main_image_width;
    Spare_image_height=Main_image_height;
    */
    // Copie des décalages de la fenêtre principale (non zoomée) de l'image
    Spare_offset_X=Main_offset_X;
    Spare_offset_Y=Main_offset_Y;
    // Copie du booléen "Mode loupe" de l'image
    Spare_magnifier_mode=Main_magnifier_mode;
    // Copie du facteur de zoom du brouillon
    Spare_magnifier_factor=Main_magnifier_factor;
    // Copie des dimensions de la fenêtre de zoom
    Spare_magnifier_width=Main_magnifier_width;
    Spare_magnifier_height=Main_magnifier_height;
    // Copie des décalages de la fenêtre de zoom
    Spare_magnifier_offset_X=Main_magnifier_offset_X;
    Spare_magnifier_offset_Y=Main_magnifier_offset_Y;
    // Copie des données du split du zoom
    Spare_separator_position=Main_separator_position;
    Spare_X_zoom=Main_X_zoom;
    Spare_separator_proportion=Main_separator_proportion;
    
    // Update the visible buffer of the spare.
    // It's a bit complex because at the moment, to save memory,
    // the spare doesn't have a full visible_buffer + depth_buffer,
    // so I can't use exactly the same technique as for Main page.
    // (It's the same reason that the "Page" function gets complex,
    // it needs to rebuild a depth buffer only, trusting the
    // depth buffer that was already available in Spare_.)
    Update_spare_buffers(Spare_image_width,Spare_image_height);
    Redraw_spare_image();
  }
  else
    Message_out_of_memory();
}
void Copy_some_colors(void)
{
  short index;
  byte confirmation=0;
  static byte mask_color_to_copy[256]; // static to use less stack
  memset(mask_color_to_copy,1,256);
  Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF);
  if (confirmation)
  {
    // Make a backup with the same pixel data as previous history steps
    Backup_the_spare(0);
    for (index=0; index<256; index++)
    {
      if (mask_color_to_copy[index])
        memcpy(Spare_palette+index,Main_palette+index,
               sizeof(T_Components));
    }
  }
}
void Button_Copy_page(void)
{
  short clicked_button;
  Open_window(168,137,"Copy to spare page");
  Window_set_normal_button(10, 20,148,14,"Pixels + palette" , 0,1,SDLK_RETURN); // 1
  Window_set_normal_button(10, 37,148,14,"Pixels only"      , 3,1,SDLK_x); // 2
  Window_set_normal_button(10, 54,148,14,"Palette only"     , 1,1,SDLK_p); // 3
  Window_set_normal_button(10, 71,148,14,"Some colors only" , 6,1,SDLK_c); // 4
  Window_set_normal_button(10, 88,148,14,"Palette and remap",13,1,SDLK_r); // 5
  Window_set_normal_button(44,114, 80,14,"Cancel"           , 0,1,KEY_ESC); // 6
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    if (Is_shortcut(Key,0x100+BUTTON_HELP))
      Window_help(BUTTON_PAGE, NULL);
    else if (Is_shortcut(Key,0x200+BUTTON_PAGE))
      clicked_button=6;
  }
  while (clicked_button<=0);
  Close_window();
  Display_cursor();
  if (clicked_button!=6)
  {
    if (clicked_button==4)
    {
      // Will backup if needed
      Copy_some_colors();
    }
    else
    {
      if (clicked_button<=2)
      {
        Backup_the_spare(-1);
        Copy_image_only();
      }
      else
        Backup_the_spare(0);
      if (clicked_button==5)
        Remap_spare();
      if (clicked_button!=2) // copie de la palette
        memcpy(Spare_palette,Main_palette,sizeof(T_Palette));
      
      // Here is the 'end_of_modifications' for spare.
      Update_spare_buffers(Spare_image_width,Spare_image_height);
      Redraw_spare_image();
      Spare_image_is_modified=1;
    }
  }
  Hide_cursor();
  Unselect_button(BUTTON_PAGE);
  Display_cursor();
}
// -- Suppression d'une page -------------------------------------------------
void Button_Kill(void)
{
  if ( (Main_backups->List_size==1)
    || (!Confirmation_box("Delete the current page?")) )
  {
    if (Main_backups->List_size==1)
      Warning_message("You can't delete the last page.");
    Hide_cursor();
    Unselect_button(BUTTON_KILL);
    Display_cursor();
  }
  else
  {
    Hide_cursor();
    Free_current_page();
    Set_palette(Main_palette);
    Compute_optimal_menu_colors(Main_palette);
    Display_all_screen();
    Unselect_button(BUTTON_KILL);
    Draw_menu_button_frame(BUTTON_MAGNIFIER,Main_magnifier_mode);
    Display_menu();
    Display_cursor();
  }
}
//------------------------- Dimensions Image/Screen ---------------------------
void Check_mode_button(short x_pos, short y_pos, byte state)
{
  byte color;
  switch (state & 0x7F)
  {
    case 0 : color=MC_White; break;
    case 1 : color=MC_Light; break;
    case 2 : color=MC_Dark; break;
    default: color=MC_Black;
  }
  Block(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos,
        Menu_factor_X*9,Menu_factor_Y*3,color);
        
  Update_rect(Window_pos_X+Menu_factor_X*x_pos,Window_pos_Y+Menu_factor_Y*y_pos,
        Menu_factor_X*9,Menu_factor_Y*3);
}
/// Number of video modes to display in the resolution menu
#define MODELIST_LINES 10
void Display_modes_list(short list_start, short cursor_position)
{
  short index,current_mode;
  short y_pos;
  byte  text_color,background_color;
  char str[29];
  char *ratio;
  for (current_mode=list_start,index=0; indexPosition!=list_start)
  {
    Window_scroller_button_list->Position=list_start;
    Window_draw_slider(Window_scroller_button_list);
  }
  Display_modes_list(list_start,cursor_position);
  Display_cursor();
}
void Button_Resolution(void)
{
  short clicked_button;
  int   selected_mode;
  word  chosen_width;
  word  chosen_height;
  byte  chosen_pixel;
  short list_start;
  short cursor_position;
  short temp;
  char  str[5];
  T_Special_button * input_width_button, * input_button_height;
  T_Dropdown_button * pixel_button;
  static const char *pixel_ratio_labels[PIXEL_MAX] ={
    "Normal    (1x1)",
    "Wide      (2x1)",
    "Tall      (1x2)",
    "Double    (2x2)",
    "Triple    (3x3)",
    "Wide2     (4x2)",
    "Tall2     (2x4)",
    "Quadruple (4x4)"};
  Open_window(299,190,"Picture & screen sizes");
  Print_in_window( 12, 21,"Picture size:"   ,MC_Dark,MC_Light);
  Window_display_frame      ( 8,17,195, 33);
  Window_set_normal_button(223, 18,67,14,"OK"      ,0,1,SDLK_RETURN); // 1
  Window_set_normal_button(223, 35,67,14,"Cancel"  ,0,1,KEY_ESC);  // 2
  Print_in_window( 12, 37,"Width:"          ,MC_Dark,MC_Light);
  input_width_button=Window_set_input_button( 60, 35,4);            // 3
  
  Print_in_window(108, 37,"Height:"         ,MC_Dark,MC_Light);
  input_button_height=Window_set_input_button(164, 35,4);           // 4
  Window_display_frame      ( 8,72,283,110);
  Window_display_frame_in   (37,84,228,84);
  Window_rectangle          (38,85,226,82,MC_Black);  
  Print_in_window( 16, 76,"OK"              ,MC_Dark,MC_Light);
  Print_in_window( 55, 76,"X    Y"          ,MC_Dark,MC_Light);
  Print_in_window(120, 76,"Win / Full"      ,MC_Dark,MC_Light);
  Print_in_window(219, 76,"Ratio"           ,MC_Dark,MC_Light);
  Print_in_window( 30,170,"\03"             ,MC_Dark,MC_Light);
  Print_in_window( 62,170,"OK"              ,MC_Dark,MC_Light);
  Print_in_window(102,170,"Imperfect"       ,MC_Dark,MC_Light);
  Print_in_window(196,170,"Unsupported"     ,MC_Dark,MC_Light);
  Window_set_special_button(38,86,225,80);                       // 5
  selected_mode=Current_resolution;
  if (selected_mode>=MODELIST_LINES/2 && Nb_video_modes > MODELIST_LINES)
  {
    if (selected_mode>3;
        if (temp0)
          cursor_position--;
        else
          if (list_start>0)
            list_start--;
        Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
        Key=0;
        break;
      case SDLK_DOWN : // Bas
        if (cursor_position<(MODELIST_LINES-1) && cursor_position<(Nb_video_modes-1))
          cursor_position++;
        else
          if (list_start0)
          cursor_position=0;
        else
        {
          if (list_start>(MODELIST_LINES-1))
            list_start-=(MODELIST_LINES-1);
          else
            list_start=0;
        }
        Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
        Key=0;
        break;
      case SDLK_PAGEDOWN : // PageDown
        if (Nb_video_modesOPERATION_FILLED_CONTOUR)
    Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW;
  Hide_cursor();
  Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode);
  Start_operation_stack(Selected_freehand_mode);
  Display_cursor();
/* NOUVEAU CODE AVEC POPUP (EN COURS DE TEST) ***
    short clicked_button;
    Open_popup(16,Menu_Y/Menu_factor_X-32,18,50);
    Window_set_normal_button(1,1,16,16,"A",0,1,KEY_ESC); // 1
    Display_cursor();
    Update_rect(16*Menu_factor_X,Menu_Y-32*Menu_factor_X,18*Menu_factor_X,50*Menu_factor_X);
    do
    {
        while(!Get_input())Wait_VBL();
        clicked_button = Window_get_clicked_button();
        switch(clicked_button)
        {
            case 1:
                Selected_freehand_mode++;
                if (Selected_freehand_mode>OPERATION_FILLED_CONTOUR)
                    Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW;
                break;
        }
    }
    while (Mouse_K);
    Close_popup();
    Display_sprite_in_menu(BUTTON_DRAW,Selected_freehand_mode);
    Start_operation_stack(Selected_freehand_mode);
    Display_cursor();
*/
}
// -- Gestion des boutons de rectangle vide et plein ------------------------
void Button_Empty_rectangle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_EMPTY_RECTANGLE);
  Display_cursor();
}
void Button_Filled_rectangle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_FILLED_RECTANGLE);
  Display_cursor();
}
// -- Gestion des boutons de cercle (ellipse) vide et plein(e) --------------
void Button_Empty_circle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_EMPTY_CIRCLE);
  Display_cursor();
}
void Button_Empty_ellipse(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_EMPTY_ELLIPSE);
  Display_cursor();
}
void Button_Filled_circle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_FILLED_CIRCLE);
  Display_cursor();
}
void Button_Filled_ellipse(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_FILLED_ELLIPSE);
  Display_cursor();
}
// -- Gestion du menu des dégradés ------------------------------------------
void Draw_button_gradient_style(short x_pos,short y_pos,int technique)
{
  short line;
  // On commence par afficher les 2 côtés qui constituent le dégradé de base:
    // Côté gauche (noir)
  Block(Window_pos_X+((x_pos+2)*Menu_factor_X),
        Window_pos_Y+((y_pos+2)*Menu_factor_Y),
        Menu_factor_X*6,
        Menu_factor_Y*10,MC_Black);
    // Côté droit (blanc)
  Block(Window_pos_X+((x_pos+8)*Menu_factor_X),
        Window_pos_Y+((y_pos+2)*Menu_factor_Y),
        Menu_factor_X*5,
        Menu_factor_Y*10,MC_White);
  switch(technique)
  {
    case 1 : // Dégradé de trames simples
      // Au centre, on place 10 lignes tramées simplement
      for (line=2;line<2+10;line++)
        if (line&1)
        {
          // Lignes impaires
          Pixel_in_window(x_pos+ 5,y_pos+line,MC_White);
          Pixel_in_window(x_pos+ 7,y_pos+line,MC_White);
          Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black);
        }
        else
        {
          // Lignes paires
          Pixel_in_window(x_pos+ 6,y_pos+line,MC_White);
          Pixel_in_window(x_pos+ 9,y_pos+line,MC_Black);
        }
      break;
    case 2 : // Dégradé de trames étendues
      // Au centre, on place 10 lignes tramées de façon compliquée
      for (line=2;line<2+10;line++)
        if (line&1)
        {
          // Lignes impaires
          Pixel_in_window(x_pos+ 7,y_pos+line,MC_White);
          Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black);
          Pixel_in_window(x_pos+10,y_pos+line,MC_Black);
        }
        else
        {
          // Lignes paires
          Pixel_in_window(x_pos+ 4,y_pos+line,MC_White);
          Pixel_in_window(x_pos+ 6,y_pos+line,MC_White);
        }
  }
  
  Update_rect(Window_pos_X+((x_pos+2)*Menu_factor_X),Window_pos_Y+((y_pos+2)*Menu_factor_Y),
                    Menu_factor_X*10,Menu_factor_Y*10);  
}
void Load_gradient_data(int index)
{
  Gradient_lower_bound =Gradient_array[index].Start;
  Gradient_upper_bound =Gradient_array[index].End;
  Gradient_is_inverted          =Gradient_array[index].Inverse;
  Gradient_random_factor=Gradient_array[index].Mix+1;
  Gradient_bounds_range=(Gradient_lower_bound indice du dégradé dans le tableau
  Window_set_scroller_button(218,22,75,16,1,Current_gradient);  // 2
    // Définition du scrolleur de mélange du dégradé
  mix_scroller = Window_set_scroller_button(31,22,84,256,1,
    Gradient_array[Current_gradient].Mix);                      // 3
    // Définition du bouton de sens
  Window_set_normal_button(8,22,15,14,
    (Gradient_array[Current_gradient].Inverse)?"\033":"\032",0,1,SDLK_TAB); // 4
    // Définition du bouton de technique
  Window_set_normal_button(8,92,15,14,"",0,1,SDLK_TAB|MOD_SHIFT); // 5
  Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique);
  Window_set_normal_button(178,112,51,14,"OK",0,1,SDLK_RETURN);     // 6
  Window_set_normal_button(123,112,51,14,"Cancel",0,1,KEY_ESC);  // 7
  Print_in_window(5,60,"MIX",MC_Dark,MC_Light);
  // On tagge les couleurs qui vont avec
  Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End);
  Num2str(Current_gradient+1,str,2);
  Print_in_window(215,100,str,MC_Black,MC_Light);
    // On affiche le cadre autour de la préview
  Window_display_frame_in(7,111,110,16);
    // On affiche la preview
  Draw_gradient_preview(8,112,108,14,Current_gradient);
  first_color=last_color=(Gradient_array[Current_gradient].Inverse)?Gradient_array[Current_gradient].End:Gradient_array[Current_gradient].Start;
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
  {
    old_mouse_x=Mouse_X;
    old_mouse_y=Mouse_Y;
    old_mouse_k=Mouse_K;
    clicked_button=Window_clicked_button();
    switch(clicked_button)
    {
      case -1 :
      case  1 : // Palette
        if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
        {
          Hide_cursor();
          temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
          if (!old_mouse_k)
          {
            // On vient de clicker
            // On met à jour l'intervalle du dégradé
            first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color;
            // On tagge le bloc
            Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End);
            // Tracé de la preview:
            Draw_gradient_preview(8,112,108,14,Current_gradient);
          }
          else
          {
            // On maintient le click, on va donc tester si le curseur bouge
            if (temp_color!=last_color)
            {
              // On commence par ordonner la 1ère et dernière couleur du bloc
              if (first_colortemp_color)
              {
                Gradient_array[Current_gradient].Start=temp_color;
                Gradient_array[Current_gradient].End  =first_color;
              }
              else
                Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=first_color;
              // On tagge le bloc
              Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End);
              // Tracé de la preview:
              Draw_gradient_preview(8,112,108,14,Current_gradient);
              last_color=temp_color;
            }
          }
          Display_cursor();
        }
        break;
      case  2 : // Nouvel indice de dégradé
        Hide_cursor();
        // Nouvel indice dans Window_attribute2
        Current_gradient=Window_attribute2;
        // On affiche la valeur sous la jauge
        Num2str(Current_gradient+1,str,2);
        Print_in_window(215,100,str,MC_Black,MC_Light);
        // On tagge les couleurs qui vont avec
        Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End);
        // On affiche le sens qui va avec
        Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light);
        // On raffiche le mélange (jauge) qui va avec
        mix_scroller->Position=Gradient_array[Current_gradient].Mix;
        Window_draw_slider(mix_scroller);
        // On raffiche la technique qui va avec
        Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique);
        // On affiche la nouvelle preview
        Draw_gradient_preview(8,112,108,14,Current_gradient);
        Display_cursor();
        break;
      case  3 : // Nouveau mélange de dégradé
        Hide_cursor();
        // Nouvel mélange dans Window_attribute2
        Gradient_array[Current_gradient].Mix=Window_attribute2;
        // On affiche la nouvelle preview
        Draw_gradient_preview(8,112,108,14,Current_gradient);
        Display_cursor();
        break;
      case  4 : // Changement de sens
        Hide_cursor();
        // On inverse le sens (par un XOR de 1)
        Gradient_array[Current_gradient].Inverse^=1;
        Print_in_window(12,25,(Gradient_array[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light);
        // On affiche la nouvelle preview
        Draw_gradient_preview(8,112,108,14,Current_gradient);
        Display_cursor();
        break;
      case  5 : // Changement de technique
        Hide_cursor();
        // On change la technique par (+1)%3
        Gradient_array[Current_gradient].Technique=(Gradient_array[Current_gradient].Technique+1)%3;
        Draw_button_gradient_style(8,92,Gradient_array[Current_gradient].Technique);
        // On affiche la nouvelle preview
        Draw_gradient_preview(8,112,108,14,Current_gradient);
        Display_cursor();
    }
    if (!Mouse_K)
    switch (Key)
    {
      case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu
      case SDLK_COMMA :
        Get_color_behind_window(&color,&click);
        if (click)
        {
          Hide_cursor();
          temp_color=color;
          // On met à jour l'intervalle du dégradé
          first_color=last_color=Gradient_array[Current_gradient].Start=Gradient_array[Current_gradient].End=temp_color;
          // On tagge le bloc
          Tag_color_range(Gradient_array[Current_gradient].Start,Gradient_array[Current_gradient].End);
          // Tracé de la preview:
          Draw_gradient_preview(8,112,108,14,Current_gradient);
          Display_cursor();
          Wait_end_of_click();
        }
        Key=0;
        break;
      default:
        if (Is_shortcut(Key,0x100+BUTTON_HELP))
        {
          Window_help(BUTTON_GRADRECT, NULL);
          Key=0;
          break;
        }
        if (Is_shortcut(Key,0x200+BUTTON_GRADRECT))
          clicked_button=6;
    }
  }
  while (clicked_button<6);
  Close_window();
  // The Grad rect operation uses the same button as Grad menu.
  if (Current_operation != OPERATION_GRAD_RECTANGLE)
    Unselect_button(BUTTON_GRADRECT);
    
  Display_cursor();
  Gradient_pixel=Display_pixel;
  if (clicked_button==7) // Cancel
  {
    Current_gradient=old_current_gradient;
    memcpy(Gradient_array,backup_gradients,sizeof(T_Gradient_array)*16);
    Load_gradient_data(Current_gradient);
  }
}
// -- Gestion des boutons de cercle / ellipse / rectangle dégradés --------------------
void Button_Grad_circle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_GRAD_CIRCLE);
  Display_cursor();
}
void Button_Grad_ellipse(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_GRAD_ELLIPSE);
  Display_cursor();
}
void Button_Grad_rectangle(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_GRAD_RECTANGLE);
  Display_cursor();
}
// -- Gestion du bouton de remplissage ---------------------------------------
void Button_Fill(void)
{
  if (Current_operation!=OPERATION_FILL)
  {
    Hide_cursor();
    if (Current_operation!=OPERATION_REPLACE)
    {
      Paintbrush_shape_before_fill=Paintbrush_shape;
      Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
    }
    else
      if ( (Mouse_Y=Main_X_zoom) ) )
        Print_in_menu("X:       Y:             ",0);
    Start_operation_stack(OPERATION_FILL);
    Display_cursor();
  }
}
void Button_Replace(void)
{
  if (Current_operation!=OPERATION_REPLACE)
  {
    Hide_cursor();
    if (Current_operation!=OPERATION_FILL)
    {
      Paintbrush_shape_before_fill=Paintbrush_shape;
      Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
    }
    if ( (Mouse_Y=Main_X_zoom) ) )
      Print_in_menu("X:       Y:       (    )",0);
    Start_operation_stack(OPERATION_REPLACE);
    Display_cursor();
  }
}
void Button_Unselect_fill(void)
{
  Paintbrush_shape=Paintbrush_shape_before_fill;
  if (Current_operation==OPERATION_REPLACE)
    if ( (Mouse_Y=Main_X_zoom) ) )
      Print_in_menu("X:       Y:             ",0);
}
//---------------------------- Menu des pinceaux -----------------------------
void Button_Paintbrush_menu(void)
{
  short clicked_button;
  short x_pos,y_pos;
  byte index;
  Open_window(310,180,"Paintbrush menu");
  Window_display_frame(8,21,294,132);
  Window_set_normal_button(122,158,67,14,"Cancel",0,1,KEY_ESC); // 1
  for (index=0; index(NB_PAINTBRUSH_SPRITES+1))
    {
      index = clicked_button-NB_PAINTBRUSH_SPRITES-2;
      
      if (Window_attribute1==RIGHT_SIDE)
      {
        // Store
        
        x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24;
        y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25;
      
        Store_brush(index);
        Hide_cursor();
        Display_stored_brush_in_window(x_pos+2, y_pos+2, index);
        Display_cursor();
  }
      else
      {
        // Restore and exit
        if (Restore_brush(index))
        {
  Close_window();
          break;
        }
      }
    }
    else if (clicked_button>1 && Window_attribute1==LEFT_SIDE)
    // Standard paintbrushes
  {
      Close_window();
    index=clicked_button-2;
    Paintbrush_shape=Gfx->Paintbrush_type[index];
    Paintbrush_width=Gfx->Preset_paintbrush_width[index];
    Paintbrush_height=Gfx->Preset_paintbrush_height[index];
    Paintbrush_offset_X=Gfx->Preset_paintbrush_offset_X[index];
    Paintbrush_offset_Y=Gfx->Preset_paintbrush_offset_Y[index];
    for (y_pos=0; y_posPaintbrush_sprite[index][y_pos][x_pos];
    Change_paintbrush_shape(Gfx->Paintbrush_type[index]);
      
      break;
    }
    else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES))
    {
      Close_window();
      break;
    }
  }
  while (1);
  Unselect_button(BUTTON_PAINTBRUSHES);
  Display_cursor();
}
void Button_Brush_monochrome(void)
{
  Hide_cursor();
  // On passe en brosse monochrome:
  Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH);
  Unselect_button(BUTTON_PAINTBRUSHES);
  Display_cursor();
}
// -- Fonction renvoyant le mode vidéo le plus adapté à l'image chargée -----
#define TOLERANCE_X 8
#define TOLERANCE_Y 4
int Best_video_mode(void)
{
  short best_width,best_height;
  int best_mode;
  short temp_x,temp_y;
  int mode;
  // Si mode fenêtre, on reste dans ce mode.
  if (Current_resolution == 0)
    return 0;
    
  // On commence par borner les dimensions, ou du moins les rendre cohérentes
  if ((Original_screen_X<=0) || (Config.Set_resolution_according_to==2))
    Original_screen_X=Main_image_width;
  else
    if (Original_screen_X<320)
      Original_screen_X=320;
  if ((Original_screen_Y<=0) || (Config.Set_resolution_according_to==2))
    Original_screen_Y=Main_image_height;
  else
    if (Original_screen_Y<200)
      Original_screen_Y=200;
  if ((Original_screen_X>1024) || (Original_screen_Y>768))
  {
    Original_screen_X=1024;
    Original_screen_Y=768;
  }
  // Maintenant on peut chercher le mode qui correspond le mieux
  best_mode=Current_resolution;
  best_width=0;
  best_height=0;
  for (mode=1; mode On charge/sauve une image
  // Image=0 => On charge/sauve une brosse
{
  byte  confirm;
  byte  use_brush_palette = 0;
  byte  old_cursor_shape;
  int   new_mode;
  T_IO_Context context;
  static char filename [MAX_PATH_CHARACTERS];
  static char directory[MAX_PATH_CHARACTERS];
  
  if (image)
  {
    strcpy(filename, Main_backups->Pages->Filename);
    strcpy(directory, Main_backups->Pages->File_directory);
    Init_context_layered_image(&context, filename, directory);
  }
  else
  {
    strcpy(filename, Brush_filename);
    strcpy(directory, Main_current_directory);
    Init_context_brush(&context, Brush_filename, Main_current_directory);
  }
  confirm=Button_Load_or_Save(1, &context);
  if (confirm)
  {
    if (image)
    {
      if (Main_image_is_modified)
        confirm=Confirmation_box("Discard unsaved changes?");
    }
    else
      use_brush_palette=Confirmation_box("Use the palette of the brush?");
  }
  // confirm is modified inside the first if, that's why we check it
  // again here
  if (confirm)
  {
    old_cursor_shape=Cursor_shape;
    Hide_cursor();
    Cursor_shape=CURSOR_SHAPE_HOURGLASS;
    Display_cursor();
    if (image)
    {
      Original_screen_X=0;
      Original_screen_Y=0;
    }
    Load_image(&context);
    if (!image)
    {
      //if (!use_brush_palette)
      //  memcpy(Main_palette,initial_palette,sizeof(T_Palette));
      if (File_error==3) // On ne peut pas allouer la brosse
      {
        free(Brush);
        Brush=(byte *)malloc(1*1);
        Brush_height=1;
        Brush_width=1;
        *Brush=Fore_color;
        free(Smear_brush);
        Smear_brush=(byte *)malloc(MAX_PAINTBRUSH_SIZE*MAX_PAINTBRUSH_SIZE);
        Smear_brush_height=MAX_PAINTBRUSH_SIZE;
        Smear_brush_width=MAX_PAINTBRUSH_SIZE;
      }
      Tiling_offset_X=0;
      Tiling_offset_Y=0;
      Brush_offset_X=(Brush_width>>1);
      Brush_offset_Y=(Brush_height>>1);
      Select_button(BUTTON_DRAW,LEFT_SIDE);
      if (Config.Auto_discontinuous)
      {
        // On se place en mode Dessin discontinu à la main
        while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
          Select_button(BUTTON_DRAW,RIGHT_SIDE);
      }
      Hide_cursor();
      // On passe en brosse couleur:
      Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
    }
    else
    {
      Hide_cursor();
      Cursor_shape=old_cursor_shape;
    }
    
    
    if ( (File_error==1) || (Get_fileformat(Main_fileformat)->Palette_only) )
    {
      if (File_error!=1)
        Compute_optimal_menu_colors(Main_palette);
    }
    else
    {
      if (image)
      {
        if (Main_magnifier_mode)
        {
          Draw_menu_button_frame(BUTTON_MAGNIFIER,0);
          Pixel_preview=Pixel_preview_normal;
          Main_magnifier_mode=0;
        }
        new_mode=Best_video_mode();
        if ((Config.Auto_set_res) && (new_mode!=Current_resolution))
        {
          Init_mode_video(
            Video_mode[new_mode].Width,
            Video_mode[new_mode].Height,
            Video_mode[new_mode].Fullscreen,
            Pixel_ratio);
          Display_menu();
        }
        // In window mode, activate wide or tall pixels if the image says so.
        else if (!Video_mode[Current_resolution].Fullscreen &&
          ((context.Ratio == PIXEL_WIDE &&
            Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) ||
            (context.Ratio == PIXEL_TALL &&
            Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2)))
        {
          Init_mode_video(
            Video_mode[Current_resolution].Width,
            Video_mode[Current_resolution].Height,
            Video_mode[Current_resolution].Fullscreen,
            context.Ratio);
            Display_menu();
        }
        else
        {
          Main_offset_X=0;
          Main_offset_Y=0;
          Compute_limits();
          Compute_paintbrush_coordinates();
        }
      }
      Compute_optimal_menu_colors(Main_palette);
      Redraw_layered_image();
      End_of_modification();
      Display_all_screen();
      if (image)
        Main_image_is_modified=0;
    }
    Destroy_context(&context);
    Display_menu();
    Display_cursor();
  }
  //if (!image)
  //  Swap_data_of_image_and_brush();
  Hide_cursor();
  Print_filename();
  Display_cursor();
  Set_palette(Main_palette);
}
void Button_Load(void)
{
  // On sauve l'état actuel des paramètres de l'image pour pouvoir les
  // restituer en cas d'erreur n'affectant pas l'image
  Upload_infos_page_main(Main_backups->Pages);
  Load_picture(1);
}
void Button_Reload(void)
{
  byte old_cursor_shape;
  int  new_mode;
  // On sauve l'état actuel des paramètres de l'image pour pouvoir les
  // restituer en cas d'erreur n'affectant pas l'image
  Upload_infos_page_main(Main_backups->Pages);
  if ( (!Main_image_is_modified) || Confirmation_box("Discard unsaved changes ?") )
  {
    T_IO_Context context;
    
    Hide_cursor();
    old_cursor_shape=Cursor_shape;
    Cursor_shape=CURSOR_SHAPE_HOURGLASS;
    Display_cursor();
    Original_screen_X=0;
    Original_screen_Y=0;
    
    Init_context_layered_image(&context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory);
    Load_image(&context);
    Hide_cursor();
    Cursor_shape=old_cursor_shape;
    if (File_error!=1)
    {
      if (Main_magnifier_mode)
      {
        Draw_menu_button_frame(BUTTON_MAGNIFIER,0);
        Pixel_preview=Pixel_preview_normal;
        Main_magnifier_mode=0;
      }
      new_mode=Best_video_mode();     
      if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) &&
           (!Resolution_in_command_line) )
      {
        Init_mode_video(
        Video_mode[new_mode].Width,
        Video_mode[new_mode].Height,
        Video_mode[new_mode].Fullscreen,
        Pixel_ratio);
        Display_menu();
      }
      // In window mode, activate wide or tall pixels if the image says so.
      else if (!Video_mode[Current_resolution].Fullscreen &&
        ((context.Ratio == PIXEL_WIDE &&
          Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) ||
          (context.Ratio == PIXEL_TALL &&
          Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2)))
      {
        Init_mode_video(
          Video_mode[Current_resolution].Width,
          Video_mode[Current_resolution].Height,
          Video_mode[Current_resolution].Fullscreen,
          context.Ratio);
          Display_menu();
      }
      else
      {
        Main_offset_X=0;
        Main_offset_Y=0;
        Compute_limits();
        Compute_paintbrush_coordinates();
      }
      Redraw_layered_image();
      End_of_modification();
      Display_all_screen();
      Main_image_is_modified=0;
    }
    Destroy_context(&context);
  }
  else
    Hide_cursor();
  Compute_optimal_menu_colors(Main_palette);
  Display_menu();
  if (Config.Display_image_limits)
    Display_image_limits();
  Unselect_button(BUTTON_LOAD);
  Display_cursor();
}
void Backup_filename(char * fname, char * backup_name)
{
  short i;
  strcpy(backup_name,fname);
  for (i=strlen(fname)-strlen(Main_backups->Pages->Filename); backup_name[i]!='.'; i++);
  backup_name[i+1]='\0';
  strcat(backup_name,"BAK");
}
void Backup_existing_file(void)
{
  char filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier
  char new_filename[MAX_PATH_CHARACTERS]; // Nom complet du fichier backup
  Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory);
  // Calcul du nom complet du fichier backup
  Backup_filename(filename,new_filename);
  File_error=0;
  // On fait un backup si le nom du fichier n'est pas celui qu'on a choisi
  // pour nommer les backups (c'est évident!).
  if (strcmp(new_filename,filename))
  {
    // S'il y avait déjà un fichier Backup, on l'efface
    if ((File_exists(new_filename))
     && (remove(new_filename)!=0))
      File_error=1;
    if ((!File_error)
     && (rename(filename,new_filename)!=0))
      File_error=1;
  }
}
void Save_picture(byte image)
  // image=1 => On charge/sauve une image
  // image=0 => On charge/sauve une brosse
{
  byte  confirm;
  byte  old_cursor_shape;
  T_IO_Context save_context;
  static char filename [MAX_PATH_CHARACTERS];
  static char directory[MAX_PATH_CHARACTERS];
  
  if (image)
  {
    strcpy(filename, Main_backups->Pages->Filename);
    strcpy(directory, Main_backups->Pages->File_directory);
    Init_context_layered_image(&save_context, filename, directory);
    save_context.Format = Main_fileformat;
  }
  else
  {
    strcpy(filename, Brush_filename);
    strcpy(directory, Brush_file_directory);
    Init_context_brush(&save_context, filename, directory);
    save_context.Format = Main_fileformat;
  }
  
  //if (!image)
  //  Swap_data_of_image_and_brush();
  confirm=Button_Load_or_Save(0, &save_context);
  if (confirm && File_exists(save_context.File_name))
  {
    confirm=Confirmation_box("Erase old file ?");
    if (confirm && (Config.Backup))
    {
      Backup_existing_file();
      if (File_error)
      {
        confirm=0;
        Error(0);
      }
    }
  }
  if (confirm)
  {
    
    old_cursor_shape=Cursor_shape;
    Hide_cursor();
    Cursor_shape=CURSOR_SHAPE_HOURGLASS;
    Display_cursor();
    Save_image(&save_context);
    if (!File_error && image && !Get_fileformat(save_context.Format)->Palette_only)
    {
      Main_image_is_modified=0;
      strcpy(Main_backups->Pages->Filename, save_context.File_name);
      strcpy(Main_backups->Pages->File_directory, save_context.File_directory);
    }
    
    Hide_cursor();
    Cursor_shape=old_cursor_shape;
    Display_cursor();
  }
  Destroy_context(&save_context);
  Print_filename();
  Set_palette(Main_palette);
}
void Button_Save(void)
{
  Save_picture(1);
}
void Button_Autosave(void)
{
  byte old_cursor_shape;
  static char filename[MAX_PATH_CHARACTERS];
  byte file_already_exists;
  Get_full_filename(filename, Main_backups->Pages->Filename, Main_backups->Pages->File_directory);
  file_already_exists=File_exists(filename);
  if ( (!file_already_exists) || Confirmation_box("Erase old file ?") )
  {
    if ((file_already_exists) && (Config.Backup))
      Backup_existing_file();
    else
      File_error=0;
    Hide_cursor();
    if (!File_error)
    {
      T_IO_Context save_context;
    
      old_cursor_shape=Cursor_shape;
      Cursor_shape=CURSOR_SHAPE_HOURGLASS;
      Display_cursor();
      Init_context_layered_image(&save_context, Main_backups->Pages->Filename, Main_backups->Pages->File_directory);
      Save_image(&save_context);
      if (!File_error)
      {
        Main_image_is_modified=0;
      }
      Destroy_context(&save_context);
      Hide_cursor();
      Cursor_shape=old_cursor_shape;
    }
    else
      Error(0);
  }
  else
    Hide_cursor();
  Unselect_button(BUTTON_SAVE);
  Display_cursor();
}
// -- Gestion des boutons de ligne ------------------------------------------
void Button_Lines(void)
{
  Hide_cursor();
  Start_operation_stack(Selected_line_mode);
  Display_cursor();
}
void Button_Lines_switch_mode(void)
{
  if (Selected_line_mode==OPERATION_LINE)
    Selected_line_mode=OPERATION_K_LIGNE;
  else
  {
    if (Selected_line_mode==OPERATION_K_LIGNE)
      Selected_line_mode=OPERATION_CENTERED_LINES;
    else
      Selected_line_mode=OPERATION_LINE;
  }
  Hide_cursor();
  Display_sprite_in_menu(BUTTON_LINES,Selected_line_mode-OPERATION_LINE+7);
  Start_operation_stack(Selected_line_mode);
  Display_cursor();
}
// -- Button de brosse ------------------------------------------------------
void Button_Brush(void)
{
  Hide_cursor();
  if (Current_operation!=OPERATION_GRAB_BRUSH)
    Start_operation_stack(OPERATION_GRAB_BRUSH);
  else
    Unselect_button(BUTTON_BRUSH);
  Display_cursor();
}
void Button_Unselect_brush(void)
{
  // On fait de notre mieux pour restaurer l'ancienne opération:
  Start_operation_stack(Operation_before_interrupt);
}
void Button_Restore_brush(void)
{
  Hide_cursor();
  // On passe en brosse couleur:
  Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
  Unselect_button(BUTTON_BRUSH);
  Unselect_button(BUTTON_POLYBRUSH);
  Display_cursor();
}
// -- Button de prise de brosse au lasso ------------------------------------
void Button_Lasso(void)
{
  Hide_cursor();
  if (Current_operation!=OPERATION_POLYBRUSH)
  {
    Paintbrush_shape_before_lasso=Paintbrush_shape;
    Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
    Start_operation_stack(OPERATION_POLYBRUSH);
  }
  else
    Unselect_button(BUTTON_POLYBRUSH);
  Display_cursor();
}
void Button_Unselect_lasso(void)
{
  // On fait de notre mieux pour restaurer l'ancienne opération:
  Start_operation_stack(Operation_before_interrupt);
  Paintbrush_shape=Paintbrush_shape_before_lasso;
}
// -- Button de pipette -----------------------------------------------------
void Button_Colorpicker(void)
{
  Hide_cursor();
  if (Current_operation!=OPERATION_COLORPICK)
  {
    Colorpicker_color=-1;
    Start_operation_stack(OPERATION_COLORPICK);
    Paintbrush_shape_before_colorpicker=Paintbrush_shape;
    Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
    if (Operation_before_interrupt!=OPERATION_REPLACE)
      if ( (Mouse_Y=Main_X_zoom) ) )
        Print_in_menu("X:       Y:       (    )",0);
  }
  else
    Unselect_button(BUTTON_COLORPICKER);
  Display_cursor();
}
void Button_Unselect_colorpicker(void)
{
  if (Operation_before_interrupt!=OPERATION_REPLACE)
    if ( (Mouse_Y=Main_X_zoom) ) )
      Print_in_menu("X:       Y:             ",0);
  // On fait de notre mieux pour restaurer l'ancienne opération:
  if (Current_operation==OPERATION_COLORPICK)
  {
    Start_operation_stack(Operation_before_interrupt);
    Paintbrush_shape=Paintbrush_shape_before_colorpicker;
  }
}
  // -- Inversion de la couleur Fore et de la couleur Back --
void Button_Invert_foreback(void)
{
  byte temp_color;
  temp_color=Fore_color;
  Fore_color        =Back_color;
  Back_color        =temp_color;
  Hide_cursor();
  Frame_menu_color(Back_color);
  Frame_menu_color(Fore_color);
  Reposition_palette();
  Display_foreback();
  Unselect_button(BUTTON_COLORPICKER);
  Display_cursor();  
}
// -- Gestion du bouton Loupe -----------------------------------------------
byte Coming_from_zoom_factor_menu=0;
void Button_Magnify(void)
{
  Hide_cursor();
  if ( (Current_operation==OPERATION_MAGNIFY) || (Main_magnifier_mode) )
  {
    Unselect_button(BUTTON_MAGNIFIER);
  }
  else
  {
    Old_main_offset_X=Main_offset_X;
    Old_main_offset_Y=Main_offset_Y;
    Compute_magnifier_data();
    if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu)
    {
      Coming_from_zoom_factor_menu=0;
      Start_operation_stack(OPERATION_MAGNIFY);
    }
    else
    { /* Ceci est de la duplication de code de presque toute l'opération de */
      /* la loupe... Il serait peut-être plus propre de faire une procédure */
      /* qui s'en charge... */
      // On passe en mode loupe
      Main_magnifier_mode=1;
      // La fonction d'affichage dans la partie image est désormais un affichage
      // spécial loupe.
      Pixel_preview=Pixel_preview_magnifier;
      // On calcule l'origine de la loupe
      Main_magnifier_offset_X=Mouse_X-(Main_magnifier_width>>1);
      Main_magnifier_offset_Y=Mouse_Y-(Main_magnifier_height>>1);
      // Calcul du coin haut_gauche de la fenêtre devant être zoomée DANS L'ECRAN
      if (Main_magnifier_offset_X+Main_magnifier_width>=Limit_right-Main_offset_X)
        Main_magnifier_offset_X=Limit_right-Main_magnifier_width-Main_offset_X+1;
      if (Main_magnifier_offset_Y+Main_magnifier_height>=Limit_bottom-Main_offset_Y)
        Main_magnifier_offset_Y=Limit_bottom-Main_magnifier_height-Main_offset_Y+1;
      // Calcul des coordonnées absolues de ce coin DANS L'IMAGE
      Main_magnifier_offset_X+=Main_offset_X;
      Main_magnifier_offset_Y+=Main_offset_Y;
      if (Main_magnifier_offset_X<0)
        Main_magnifier_offset_X=0;
      if (Main_magnifier_offset_Y<0)
        Main_magnifier_offset_Y=0;
      // On calcule les bornes visibles dans l'écran
      Position_screen_according_to_zoom();
      Compute_limits();
      Display_all_screen();
      // Repositionner le curseur en fonction des coordonnées visibles
      Compute_paintbrush_coordinates();
    }
  }
  Display_cursor();
  Update_rect(0,0,0,0);
}
void Button_Magnify_menu(void)
{
  T_Dropdown_button dropdown;
  T_Dropdown_choice *item;
  int i;
  const char text[NB_ZOOM_FACTORS][4] =
    {"x2", "x3", "x4", "x5", "x6", "x8", "x10", "x12", "x14", "x16", "x18", "x20",
      "x24", "x28", "x32"};
  
  Hide_cursor();
  
  dropdown.Pos_X         =Buttons_Pool[BUTTON_MAGNIFIER].X_offset;
  dropdown.Pos_Y         =Buttons_Pool[BUTTON_MAGNIFIER].Y_offset;
  dropdown.Height        =Buttons_Pool[BUTTON_MAGNIFIER].Height;
  dropdown.Dropdown_width=28;
  dropdown.First_item    =NULL;
  dropdown.Bottom_up     =1;
  
  for(i = 0; i < NB_ZOOM_FACTORS; i++) {
    Window_dropdown_add_item(&dropdown, i, text[i]);
  }
  item=Dropdown_activate(&dropdown,0,Menu_Y);
  
  if (item)
  {
    Change_magnifier_factor(item->Number,0);
  }
  if ( (!item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Cancel
    Unselect_button(BUTTON_MAGNIFIER);
  Display_all_screen();
  Display_cursor();
  Update_rect(Main_separator_position,0,Screen_width-Main_separator_position,Menu_Y);
  if ( (item) && (!Main_magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Passage en mode zoom
  {
    Coming_from_zoom_factor_menu=1;
    Select_button(BUTTON_MAGNIFIER,LEFT_SIDE);
  }
  
  Window_dropdown_clear_items(&dropdown);
}
void Button_Unselect_magnifier(void)
{
  if (Main_magnifier_mode)
  {
    // On sort du mode loupe
    Main_magnifier_mode=0;
    /*
    // --> Recalculer le décalage de l'écran lorsqu'on sort de la loupe <--
    // Centrage "brut" de lécran par rapport à la loupe
    Main_offset_X=Main_magnifier_offset_X-((Screen_width-Main_magnifier_width)>>1);
    Main_offset_Y=Main_magnifier_offset_Y-((Menu_Y-Main_magnifier_height)>>1);
    */
    // Correction en cas de débordement de l'image
    if (Old_main_offset_X+Screen_width>Main_image_width)
      Main_offset_X=Main_image_width-Screen_width;
    else
      Main_offset_X=Old_main_offset_X;
    if (Main_offset_X<0)
      Main_offset_X=0;
    if (Old_main_offset_Y+Menu_Y>Main_image_height)
      Main_offset_Y=Main_image_height-Menu_Y;
    else
      Main_offset_Y=Old_main_offset_Y;
    if (Main_offset_Y<0)
      Main_offset_Y=0;
    // La fonction d'affichage dans l'image est désormais un affichage normal.
    Pixel_preview=Pixel_preview_normal;
    // Calculer les bornes visibles dans l'écran
    Compute_limits();
    Display_all_screen();  // <=> Display_screen();
    // Repositionner le curseur en fonction des coordonnées visibles
    Compute_paintbrush_coordinates();
    
    Old_MX = -1;
    Old_MY = -1;
  }
  else // On fait de notre mieux pour restaurer l'ancienne opération:
    Start_operation_stack(Operation_before_interrupt);
}
// ----------------------- Modifications de brosse ---------------------------
void Button_Brush_FX(void)
{
  short clicked_button;
  short index;
  Open_window(310,162,"Brush effects");
  Window_display_frame(  6,19,298,61);
  Window_display_frame(  6,83,122,53);
  Window_display_frame(137,83,167,53);
  Window_set_normal_button(236,141, 67,14,"Cancel"          ,0,1,KEY_ESC); // 1
  Window_set_normal_button( 19, 46, 27,14,"X\035"           ,0,1,Config_Key[SPECIAL_FLIP_X][0]); // 2
  Window_set_normal_button( 19, 61, 27,14,"Y\022"           ,0,1,Config_Key[SPECIAL_FLIP_Y][0]); // 3
  Window_set_normal_button( 58, 46, 37,14,"90°"             ,0,1,Config_Key[SPECIAL_ROTATE_90][0]); // 4
  Window_set_normal_button( 96, 46, 37,14,"180°"            ,0,1,Config_Key[SPECIAL_ROTATE_180][0]); // 5
  Window_set_normal_button( 58, 61, 75,14,"any angle"       ,0,1,Config_Key[SPECIAL_ROTATE_ANY_ANGLE][0]); // 6
  Window_set_normal_button(145, 46, 67,14,"Stretch"         ,0,1,Config_Key[SPECIAL_STRETCH][0]); // 7
  Window_set_normal_button(145, 61, 67,14,"Distort"         ,0,1,Config_Key[SPECIAL_DISTORT][0]); // 8
  Window_set_normal_button(155, 99,131,14,"Recolorize"      ,0,1,Config_Key[SPECIAL_RECOLORIZE_BRUSH][0]); // 9
  Window_set_normal_button(155,117,131,14,"Get brush colors",0,1,Config_Key[SPECIAL_GET_BRUSH_COLORS][0]); // 10
  // Boutons représentant les coins du brush handle: (HG,HD,C,BG,BD)
  Window_set_normal_button( 75, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_LEFT_ATTACHMENT][0]); // 11
  Window_set_normal_button(103, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_RIGHT_ATTACHMENT][0]); // 12
  Window_set_normal_button( 89,104,11,11,"",0,1,Config_Key[SPECIAL_CENTER_ATTACHMENT][0]); // 13
  Window_set_normal_button( 75,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_LEFT_ATTACHMENT][0]); // 14
  Window_set_normal_button(103,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_RIGHT_ATTACHMENT][0]); // 15
  Window_set_normal_button(224,46,67,14,"Outline",0,1,Config_Key[SPECIAL_OUTLINE][0]); // 16
  Window_set_normal_button(224,61,67,14,"Nibble" ,0,1,Config_Key[SPECIAL_NIBBLE][0]); // 17
  Window_set_normal_button(  7,141, 60,14,"Load",0,1,Config_Key[SPECIAL_LOAD_BRUSH][0]); // 18
  Window_set_normal_button( 70,141, 60,14,"Save",0,1,Config_Key[SPECIAL_SAVE_BRUSH][0]); // 19
  Print_in_window( 80, 24,"Shape modifications",MC_Dark,MC_Light);
  Print_in_window( 10, 36,"Mirror",MC_Dark,MC_Light);
  Print_in_window( 72, 36,"Rotate",MC_Dark,MC_Light);
  Print_in_window(155, 36,"Deform",MC_Dark,MC_Light);
  Print_in_window(230, 36,"Borders",MC_Dark,MC_Light);
  Print_in_window(141, 88,"Colors modifications",MC_Dark,MC_Light);
  Print_in_window( 20,102,"Brush",MC_Dark,MC_Light);
  Print_in_window( 16,110,"handle",MC_Dark,MC_Light);
  // Dessin des pointillés pour le "brush handle"
  for (index=0; index<13; index+=2)
  {
    Pixel_in_window( 88+index, 92,MC_Dark);
    Pixel_in_window( 88+index,126,MC_Dark);
    Pixel_in_window( 77,103+index,MC_Dark);
    Pixel_in_window(111,103+index,MC_Dark);
  }
  // Dessin des coins et du centre pour les boutons du "brush handle"
    // Coin HG
  Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black);
  Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black);
    // Coin HD
  Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X*7,Menu_factor_Y,MC_Black);
  Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y* 92),Menu_factor_X,Menu_factor_Y*7,MC_Black);
    // Centre
  Block(Window_pos_X+(Menu_factor_X* 91),Window_pos_Y+(Menu_factor_Y*109),Menu_factor_X*7,Menu_factor_Y,MC_Black);
  Block(Window_pos_X+(Menu_factor_X* 94),Window_pos_Y+(Menu_factor_Y*106),Menu_factor_X,Menu_factor_Y*7,MC_Black);
    // Coin BG
  Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black);
  Block(Window_pos_X+(Menu_factor_X* 77),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black);
    // Coin BD
  Block(Window_pos_X+(Menu_factor_X*105),Window_pos_Y+(Menu_factor_Y*126),Menu_factor_X*7,Menu_factor_Y,MC_Black);
  Block(Window_pos_X+(Menu_factor_X*111),Window_pos_Y+(Menu_factor_Y*120),Menu_factor_X,Menu_factor_Y*7,MC_Black);
  
  Update_window_area(0,0,Window_width, Window_height);
  
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    if (Is_shortcut(Key,0x100+BUTTON_HELP))
    {
      Key=0;
      Window_help(BUTTON_BRUSH_EFFECTS, NULL);
    }
    else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS))
    {
      clicked_button=1;
    }
  }
  while (clicked_button<=0);
  Close_window();
  Unselect_button(BUTTON_BRUSH_EFFECTS);
  // Gestion du bouton clické
  switch (clicked_button)
  {
    case  2 : // Flip X
      Flip_X_lowlevel(Brush, Brush_width, Brush_height);
      break;
    case  3 : // Flip Y
      Flip_Y_lowlevel(Brush, Brush_width, Brush_height);
      break;
    case  4 : // 90° Rotation
      Rotate_90_deg();
      break;
    case  5 : // 180° Rotation
      Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height);
      Brush_offset_X=(Brush_width>>1);
      Brush_offset_Y=(Brush_height>>1);
      break;
    case  6 : // Any angle rotation
      Start_operation_stack(OPERATION_ROTATE_BRUSH);
      break;
    case  7 : // Stretch
      Start_operation_stack(OPERATION_STRETCH_BRUSH);
      break;
    case  8 : // Distort
      Start_operation_stack(OPERATION_DISTORT_BRUSH);
      break;
    case  9 : // Recolorize
      Remap_brush();
      break;
    case 10 : // Get brush colors
      Display_cursor();
      Get_colors_from_brush();
      Hide_cursor();
      break;
    case 11 : // Brush Attachment: Top-Left
      Brush_offset_X=0;
      Brush_offset_Y=0;
      break;
    case 12 : // Brush Attachment: Top-Right
      Brush_offset_X=(Brush_width-1);
      Brush_offset_Y=0;
      break;
    case 13 : // Brush Attachment: Center
      Brush_offset_X=(Brush_width>>1);
      Brush_offset_Y=(Brush_height>>1);
      break;
    case 14 : // Brush Attachment: Bottom-Left
      Brush_offset_X=0;
      Brush_offset_Y=(Brush_height-1);
      break;
    case 15 : // Brush Attachment: Bottom-Right
      Brush_offset_X=(Brush_width-1);
      Brush_offset_Y=(Brush_height-1);
      break;
    case 16 : // Outline
      Outline_brush();
      break;
    case 17 : // Nibble
      Nibble_brush();
      break;
    case 18 : // Load
      Display_cursor();
      Load_picture(0);
      Hide_cursor();
      break;
    case 19 : // Save
      Display_cursor();
      Save_picture(0);
      Hide_cursor();
      break;
  }
  Display_cursor();
}
//---------------------------- Courbes de Bézier ----------------------------
void Button_Curves(void)
{
  Hide_cursor();
  Start_operation_stack(Selected_curve_mode);
  Display_cursor();
}
void Button_Curves_switch_mode(void)
{
  if (Selected_curve_mode==OPERATION_4_POINTS_CURVE)
    Selected_curve_mode=OPERATION_3_POINTS_CURVE;
  else
    Selected_curve_mode=OPERATION_4_POINTS_CURVE;
  Hide_cursor();
  Display_sprite_in_menu(BUTTON_CURVES,Selected_curve_mode-OPERATION_3_POINTS_CURVE+5);
  Start_operation_stack(Selected_curve_mode);
  Display_cursor();
}
//--------------------------------- Spray -----------------------------------
void Button_Airbrush(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_AIRBRUSH);
  Display_cursor();
}
void Refresh_airbrush_settings(byte selected_color, byte update_slider)
{
  char  str[3];
  if (update_slider)
  {
    Window_scroller_button_list->Position=49-Airbrush_multi_flow[selected_color];
    Window_draw_slider(Window_scroller_button_list);
  }
  Num2str(Airbrush_multi_flow[selected_color],str,2);
  Print_in_window(196,130,str,MC_Black,MC_Light);
  
  Update_rect(Window_pos_X+(Menu_factor_X*(Window_palette_button_list->Pos_X+4+(selected_color >> 4)*10)),
      Window_pos_Y+(Menu_factor_Y*(Window_palette_button_list->Pos_Y+3+(selected_color & 15)* 5)),
      Menu_factor_X<<1,Menu_factor_Y*5);
}
void Button_Airbrush_menu(void)
{
  static byte spray_init=0;
  short  clicked_button;
  char   str[4];
  word   index;
  byte   selected_color=Fore_color;
  byte   old_airbrush_mode     =Airbrush_mode;
  short  old_airbrush_size     =Airbrush_size;
  byte   old_airbrush_delay    =Airbrush_delay;
  byte   old_airbrush_mono_flow=Airbrush_mono_flow;
  byte   old_airbrush_multi_flow[256];
  T_Special_button * input_size_button;
  T_Special_button * input_delay_button;
  T_Special_button * input_flow_button;
  T_Special_button * input_init_button;
  word old_mouse_x;
  word old_mouse_y;
  byte old_mouse_k;
  byte color;
  byte click;
  memcpy(old_airbrush_multi_flow,Airbrush_multi_flow,256);
  Open_window(226,170,"Spray");
  Window_set_normal_button(110,148,51,14,"Cancel"    ,0,1,KEY_ESC); // 1
  Window_set_normal_button(166,148,51,14,"OK"        ,0,1,SDLK_RETURN); // 2
  Window_set_scroller_button(178,62,74,50,1,49-Airbrush_multi_flow[selected_color]); // 3
  Window_set_palette_button(7,56);                                 // 4
  Window_set_normal_button(  8,148,83,14,"Mode:     ",0,1,SDLK_TAB); // 5
  if (Airbrush_mode)
    Print_in_window(50,151," Mono",MC_Black,MC_Light);
  else
    Print_in_window(50,151,"Multi",MC_Black,MC_Light);
  Window_set_normal_button(194, 62,19,14,"+1"        ,0,1,SDLK_KP_PLUS); // 6
  Window_set_normal_button(194, 79,19,14,"-1"        ,0,1,SDLK_KP_MINUS); // 7
  Window_set_normal_button(194, 96,19,14,"x2"        ,0,1,SDLK_KP_MULTIPLY); // 8
  Window_set_normal_button(194,113,19,14,"÷2"        ,0,1,SDLK_KP_ENTER); // 9
  Window_set_normal_button(  8, 37,43,14,"Clear"     ,1,1,SDLK_c); // 10
  Print_in_window(142,25,"Size:"     ,MC_Dark,MC_Light);
  input_size_button = Window_set_input_button(186,23,3);                // 11
  Num2str(Airbrush_size,str,3);
  Window_input_content(input_size_button,str);
  Print_in_window(142,39,"Delay:"    ,MC_Dark,MC_Light);
  input_delay_button = Window_set_input_button(194,37,2);               // 12
  Num2str(Airbrush_delay,str,2);
  Window_input_content(input_delay_button,str);
  Print_in_window( 27,24,"Mono-Flow:",MC_Dark,MC_Light);
  input_flow_button = Window_set_input_button(111,22,2);           // 13
  Num2str(Airbrush_mono_flow,str,2);
  Window_input_content(input_flow_button,str);
  Print_in_window( 67,40,"Init:",MC_Dark,MC_Light);
  input_init_button = Window_set_input_button(111,38,2);                // 14
  Num2str(spray_init,str,2);
  Window_input_content(input_init_button,str);
  Window_display_frame(173,56,45,86);
  Window_display_frame(137,19,81,33);
  // On tagge toutes les couleurs utilisées
  for (index=0; index<256; index++)
    if (Airbrush_multi_flow[index])
      Stencil_tag_color(index,MC_Black);
  // Et enfin, on tagge la couleur sélectionnée
  Stencil_tag_color(selected_color,MC_White);
  Refresh_airbrush_settings(selected_color,0);
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  Stencil_update_color(selected_color);
  do
  {
    old_mouse_x=Mouse_X;
    old_mouse_y=Mouse_Y;
    old_mouse_k=Mouse_K;
    clicked_button=Window_clicked_button();
    switch (clicked_button)
    {
      case  0 :
      case  2 : // OK
        break;
      case  1 : // Cancel
        Airbrush_mode     =old_airbrush_mode;
        Airbrush_size     =old_airbrush_size;
        Airbrush_delay    =old_airbrush_delay;
        Airbrush_mono_flow=old_airbrush_mono_flow;
        memcpy(Airbrush_multi_flow,old_airbrush_multi_flow,256);
        break;
      case  3 : // Scroller
        Hide_cursor();
        Airbrush_multi_flow[selected_color]=49-Window_attribute2;
        Refresh_airbrush_settings(selected_color,0);
        Display_cursor();
        break;
      case -1 :
      case  4 : // Palette
        if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
        {
          Hide_cursor();
          Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light);
          Stencil_update_color(selected_color);
          // Mettre la couleur sélectionnée à jour suivant le click
          selected_color=(clicked_button==4) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
          if (Mouse_K==2)
            Airbrush_multi_flow[selected_color]=0;
          else
            if (Airbrush_multi_flow[selected_color]==0)
              Airbrush_multi_flow[selected_color]=spray_init;
          // Tagger la couleur sélectionnée en blanc
          Stencil_tag_color(selected_color,MC_White);
          Refresh_airbrush_settings(selected_color,1);
          Display_cursor();
          Stencil_update_color(selected_color);
        }
        break;
      case  5 : // Toggle Mode
        Airbrush_mode=(Airbrush_mode+1)&1;
        Hide_cursor();
        if (Airbrush_mode)
          Print_in_window(50,151," Mono",MC_Black,MC_Light);
        else
          Print_in_window(50,151,"Multi",MC_Black,MC_Light);
        Update_rect(Window_pos_X+50*Menu_factor_X,Window_pos_Y+151*Menu_factor_Y,5*8*Menu_factor_X,8*Menu_factor_Y);
        Display_cursor();
        break;
      case  6 : // +1
        for (index=0; index<256; index++)
        {
          if ( (Airbrush_multi_flow[index]) && (Airbrush_multi_flow[index]<49) )
            Airbrush_multi_flow[index]++;
        }
        Hide_cursor();
        Refresh_airbrush_settings(selected_color,1);
        Display_cursor();
        break;
      case  7 : // -1
        for (index=0; index<256; index++)
        {
          if (Airbrush_multi_flow[index]>1)
            Airbrush_multi_flow[index]--;
        }
        Hide_cursor();
        Refresh_airbrush_settings(selected_color,1);
        Display_cursor();
        break;
      case  8 : // x2
        for (index=0; index<256; index++)
        {
          if (Airbrush_multi_flow[index])
          {
            Airbrush_multi_flow[index]<<=1;
            if (Airbrush_multi_flow[index]>49)
              Airbrush_multi_flow[index]=49;
          }
        }
        Hide_cursor();
        Refresh_airbrush_settings(selected_color,1);
        Display_cursor();
        break;
      case  9 : // ÷2
        for (index=0; index<256; index++)
        {
          if (Airbrush_multi_flow[index]>1)
            Airbrush_multi_flow[index]>>=1;
        }
        Hide_cursor();
        Refresh_airbrush_settings(selected_color,1);
        Display_cursor();
        break;
      case 10 : // Clear
        memset(Airbrush_multi_flow,0,256);
        // On raffiche les infos de la couleur sélectionnée
        Refresh_airbrush_settings(selected_color,1);
        // On efface les anciens TAGs
        Window_clear_tags();
        // Tagger la couleur sélectionnée en blanc
        Stencil_tag_color(selected_color,MC_White);
        Stencil_update_color(selected_color);
        break;
      case 11 : // Size
        Num2str(Airbrush_size,str,3);
        Readline(188,25,str,3,1);
        Airbrush_size=atoi(str);
        // On corrige les dimensions
        if (Airbrush_size>256)
        {
          Airbrush_size=256;
          Num2str(Airbrush_size,str,3);
          Window_input_content(input_size_button,str);
        }
        else if (!Airbrush_size)
        {
          Airbrush_size=1;
          Num2str(Airbrush_size,str,3);
          Window_input_content(input_size_button,str);
        }
        Display_cursor();
        break;
      case 12 : // Delay
        Num2str(Airbrush_delay,str,2);
        Readline(196,39,str,2,1);
        Airbrush_delay=atoi(str);
        // On corrige le delai
        if (Airbrush_delay>99)
        {
          Airbrush_delay=99;
          Num2str(Airbrush_delay,str,2);
          Window_input_content(input_delay_button,str);
        }
        Display_cursor();
        break;
      case 13 : // Mono-Flow
        Num2str(Airbrush_mono_flow,str,2);
        Readline(113,24,str,2,1);
        Airbrush_mono_flow=atoi(str);
        // On corrige le flux
        if (!Airbrush_mono_flow)
        {
          Airbrush_mono_flow=1;
          Num2str(Airbrush_mono_flow,str,2);
          Window_input_content(input_flow_button,str);
        }
        Display_cursor();
        break;
      case 14 : // Init
        Num2str(spray_init,str,2);
        Readline(113,40,str,2,1);
        spray_init=atoi(str);
        // On corrige la valeur
        if (spray_init>=50)
        {
          spray_init=49;
          Num2str(spray_init,str,2);
          Window_input_content(input_init_button,str);
        }
        Display_cursor();
        break;
    }
    if (!Mouse_K)
    switch (Key)
    {
      case SDLK_BACKQUOTE : // Récupération d'une couleur derrière le menu
      case SDLK_COMMA :
        Get_color_behind_window(&color,&click);
        if (click)
        {
          Hide_cursor();
          Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light);
          Stencil_update_color(selected_color);
          // Mettre la couleur sélectionnée à jour suivant le click
          selected_color=color;
          if (click==2)
            Airbrush_multi_flow[selected_color]=0;
          else
            if (Airbrush_multi_flow[selected_color]==0)
              Airbrush_multi_flow[selected_color]=spray_init;
          // Tagger la couleur sélectionnée en blanc
          Stencil_tag_color(selected_color,MC_White);
          Refresh_airbrush_settings(selected_color,1);
          Display_cursor();
          Stencil_update_color(selected_color);
          Wait_end_of_click();
        }
        Key=0;
        break;
      default:
      if (Is_shortcut(Key,0x100+BUTTON_HELP))
      {
        Window_help(BUTTON_AIRBRUSH, NULL);
        Key=0;
        break;
      }
      if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH))
      {
        clicked_button=2;
        break;
      }
    }
  }
  while ( (clicked_button!=1) && (clicked_button!=2) );
  Close_window();
/*
  //   Tant que l'on aura pas résolu le problème du désenclenchement du mode
  // de dessin précedent, il faudra laisser ça en remarque et donc passer en
  // spray même si on a clické sur Cancel (idem pour OK (un peu plus bas)).
  if (clicked_button==1) // Cancel
  {
    if (Current_operation!=OPERATION_AIRBRUSH)
      Unselect_button(BUTTON_AIRBRUSH);
  }
*/
  Display_cursor();
/*
  if (clicked_button==2) // OK
*/
    if (Current_operation!=OPERATION_AIRBRUSH)
      Select_button(BUTTON_AIRBRUSH,LEFT_SIDE);
}
// -- Gestion des boutons de polygone vide et plein -------------------------
void Button_polygon(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_POLYGON);
  Display_cursor();
}
void Button_Polyform(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_POLYFORM);
  Display_cursor();
}
void Button_Polyfill(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_POLYFILL);
  Display_cursor();
}
void Button_Filled_polyform(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_FILLED_POLYFORM);
  Display_cursor();
}
// -- Boutons d'ajustement de l'image ---------------------------------------
void Button_Adjust(void)
{
  Hide_cursor();
  Start_operation_stack(OPERATION_SCROLL);
  Display_cursor();
}
// -- Menu des effets (Shade, Stencil, etc...) ------------------------------
void Display_effect_sprite(short sprite_number, short start_x, short start_y)
{
  short x,y,x_pos,y_pos;
  for (y=0,y_pos=start_y;yEffect_sprite[sprite_number][y][x]);
  Update_rect(ToWinX(start_x),ToWinY(start_y),MENU_SPRITE_WIDTH*Menu_factor_X,MENU_SPRITE_HEIGHT*Menu_factor_Y);
}
void Display_effect_state(short x, short y, char * label, byte state)
{
  Block(Window_pos_X+(x*Menu_factor_X),Window_pos_Y+(y*Menu_factor_Y),
        12*Menu_factor_X,Menu_factor_Y<<3,MC_Light);
  Print_in_window(x,y,label,(state)?MC_White:MC_Black,MC_Light);
  if (state)
    Print_in_window(x+56,y,":ON ",MC_White,MC_Light);
  else
    Print_in_window(x+56,y,":OFF",MC_Black,MC_Light);
}
void Display_effect_states(void)
{
  Display_effect_state( 30, 24,"Shade"  ,Shade_mode);
  Display_effect_state( 30, 43,"Q-shade",Quick_shade_mode);
  Display_effect_state( 30, 62,"Transp.",Colorize_mode);
  Display_effect_state( 30, 81,"Smooth" ,Smooth_mode);
  Display_effect_state( 30,100,"Smear"  ,Smear_mode);
  Display_effect_state(176, 24,"Stencil",Stencil_mode);
  Display_effect_state(176, 43,"Mask"   ,Mask_mode);
  Display_effect_state(176, 62,"Sieve"  ,Sieve_mode);
  Display_effect_state(176, 81,"Grid"   ,Snap_mode);
  Display_effect_state(176,100,"Tiling" ,Tiling_mode);
}
void Display_feedback_state(void)
{
  Print_in_window(159,134,(Config.FX_Feedback)?"YES":" NO",MC_Black,MC_Light);
}
void Button_Effects(void)
{
  short clicked_button;
  byte exit_by_close_button=0;
  Open_window(270,152,"Drawing modes (effects)");
  Window_set_normal_button(  7, 19, 16,16,"",0,1,Config_Key[SPECIAL_SHADE_MODE][0]); // 1
  Window_set_normal_button(  7, 38, 16,16,"",0,1,Config_Key[SPECIAL_QUICK_SHADE_MODE][0]); // 2
  Window_set_normal_button(  7, 57, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3
  Window_set_normal_button(  7, 76, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4
  Window_set_normal_button(  7, 95, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5
  Window_set_normal_button(153, 19, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6
  Window_set_normal_button(153, 38, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7
  Window_set_normal_button(153, 57, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8
  Window_set_normal_button(153, 76, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9
  Window_set_normal_button(153, 95, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10
  Window_set_normal_button(195,131, 68,14,"Close",0,1,SDLK_RETURN); // 11
  Window_set_normal_button(  7,131, 68,14,"All off",0,1,SDLK_DELETE); // 12
  Window_set_normal_button( 83,131,104,14,"Feedback:   ",1,1,SDLK_f); // 13
  Display_feedback_state();
  Display_effect_sprite(0,  8,20);
  Display_effect_sprite(0,  8,39);
  Display_effect_sprite(1,  8,58);
  Display_effect_sprite(2,  8,77);
  Display_effect_sprite(8,  8,96);
  Display_effect_sprite(4,154,20);
  Display_effect_sprite(7,154,39);
  Display_effect_sprite(5,154,58);
  Display_effect_sprite(6,154,77);
  Display_effect_sprite(3,154,96);
  Display_effect_states();
  Print_in_window(12,117,"click: Left:Switch / Right:Edit",MC_Dark,MC_Light);
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS))
    {
      clicked_button=11;
      Key=0;
    }
    else if (Is_shortcut(Key,0x100+BUTTON_HELP))
    {
      // Aide contextuelle
      switch(Window_get_clicked_button())
      {
        case 1:
          Window_help(BUTTON_EFFECTS, "SHADE");
          break;
        case 2:
          Window_help(BUTTON_EFFECTS, "QUICK SHADE");
          break;
        case 3:
          Window_help(BUTTON_EFFECTS, "TRANSPARENCY");
          break;
        case 4:
          Window_help(BUTTON_EFFECTS, "SMOOTH");
          break;
        case 5:
          Window_help(BUTTON_EFFECTS, "SMEAR");
          break;
        case 6:
          Window_help(BUTTON_EFFECTS, "STENCIL");
          break;
        case 7:
          Window_help(BUTTON_EFFECTS, "MASK");
          break;
        case 8:
          Window_help(BUTTON_EFFECTS, "SIEVE");
          break;
        case 9:
          Window_help(BUTTON_EFFECTS, "GRID");
          break;
        case 10:
          Window_help(BUTTON_EFFECTS, "TILING");
          break;
        default:
          Window_help(BUTTON_EFFECTS, NULL);
      }
      // Hack because we have used Window_get_clicked_button()
      Input_sticky_control=0;
      //
    }
    switch (clicked_button)
    {
      case 1 : // Shade
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Shade_mode();
          Hide_cursor();
          Display_effect_states();
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Shade_menu();
          clicked_button=11;
        }
        break;
      case 2 : // Quick-shade
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Quick_shade_mode();
          Hide_cursor();
          Display_effect_states();
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Quick_shade_menu();
          clicked_button=11;
        }
        break;
      case 3 : // Colorize / Transparency
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Colorize_mode();
          Hide_cursor();
          Display_effect_states();
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Colorize_menu();
          clicked_button=11;
        }
        break;
      case 4 : // Smooth
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Smooth_mode();
          Hide_cursor();
          Display_effect_states();
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Smooth_menu();
          clicked_button=11;
        }
        break;
      case 5 : // Smear
        Button_Smear_mode();
        Hide_cursor();
        Display_effect_states();
        Display_cursor();
        break;
      case 6 : // Stencil
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Stencil_mode();
          Hide_cursor();
          Display_effect_state(176,24,"Stencil",Stencil_mode);
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Stencil_menu();
          clicked_button=11;
        }
        break;
      case 7 : // Mask
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Mask_mode();
          Hide_cursor();
          Display_effect_state(176,43,"Mask",Mask_mode);
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Mask_menu();
          clicked_button=11;
        }
        break;
      case 8 : // Sieve
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Sieve_mode();
          Hide_cursor();
          Display_effect_state(176,62,"Sieve",Sieve_mode);
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Sieve_menu();
          clicked_button=11;
        }
        break;
      case 9 : // Grid
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Snap_mode();
          Hide_cursor();
          Display_effect_state(176,81,"Grid",Snap_mode);
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Grid_menu();
          clicked_button=11;
        }
        break;
      case 10 : // Tiling
        if (Window_attribute1==LEFT_SIDE)
        {
          Button_Tiling_mode();
          Hide_cursor();
          Display_effect_states();
          Display_cursor();
        }
        else
        {
          Close_window();
          Display_cursor();
          Button_Tiling_menu();
          clicked_button=11;
        }
        break;
      case 11 : // Close
        exit_by_close_button=1;
        break;
      case 12 : // All off
        Effects_off();
        Hide_cursor();
        Display_effect_states();
        Display_cursor();
        break;
      case 13 : // Feedback (pour Colorize et Shade)
        Config.FX_Feedback = !Config.FX_Feedback;
        Update_FX_feedback(Config.FX_Feedback);
        Hide_cursor();
        Display_feedback_state();
        Display_cursor();
        break;
    }
  }
  while (clicked_button!=11);
  if (exit_by_close_button)
    Close_window();
  else
    Hide_cursor();
  if (!(Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode))
    Unselect_button(BUTTON_EFFECTS);
  Display_cursor();
}
// Callback to display a font name in the list
void Draw_one_font_name(word x, word y, word index, byte highlighted)
{
  Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light);
}
void Button_Text()
{
  static char str[256]="";
  static int font_size=32;
  static int antialias=1;
  static short list_start=0; // index de le premiere fonte dans le selector
  static short cursor_position=0; // index de la ligne active dans le selector
  static short selected_font_index=0;
  static short is_bold=0;
  static short is_italic=0;
  byte * new_brush=NULL;
  int new_width;
  int new_height;
  int clicked_button;  
  const int NB_FONTS=8;
  char size_buffer[3];
  T_Special_button * input_size_button;
  T_Special_button * input_text_button;
  T_Special_button * preview_button;
  T_Special_button * font_list_button;
  T_Scroller_button * font_scroller;
  T_List_button * font_list;
  
  byte redraw_is_needed=1;
  byte preview_is_needed=1;
  
  Open_window(288,180,"Text");
  // Texte saisi
  Print_in_window(6,20,"Text:",MC_Dark,MC_Light);
  input_text_button = Window_set_input_button(48,18,29); // 1
  
  // TrueType options
  Window_display_frame_in(182,34,100,68);
  Print_in_window(199,31,"TrueType", MC_Dark, MC_Light);
  // AA
  Window_set_normal_button(188,58,13,11,antialias?"X":" ",0,1,SDLK_a); // 2
  Print_in_window(206,60,"AntiAlias", MC_Dark, MC_Light);
  // Bold
  Window_set_normal_button(188,72,13,11,is_bold?"X":" ",0,1,SDLK_b); // 3
  Print_in_window(206,75,"Bold", MC_Dark, MC_Light);
  // Italic
  Window_set_normal_button(188,86,13,11,is_italic?"X":" ",0,1,SDLK_i); // 4
  Print_in_window(206,89,"Italic", MC_Dark, MC_Light);
  
  // Scroller des fontes
  font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Nb_fonts,NB_FONTS,list_start); // 5
  // Liste des fontes disponibles
  font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8); // 6
  Window_display_frame_in(7, 33, 154, NB_FONTS*8+4);
  
  // Taille texte
  input_size_button = Window_set_input_button(220,43,3); // 7
  Window_set_repeatable_button(202,43,13,11,"-",0,1,SDLK_LAST); // 8
  Window_set_repeatable_button(251,43,13,11,"+",0,1,SDLK_LAST); // 9
  
  // Preview
  preview_button = Window_set_special_button(8,106,273,50); // 10
  Window_display_frame_in(7, 105, 275, 52);
  
  Window_set_normal_button(8,160,40,14,"OK",0,1,SDLK_RETURN); // 11
  Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12
  
  // List of fonts
  font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name); // 13
  // Restore its settings from last passage in screen
  font_list->List_start = list_start;
  font_list->Cursor_position = cursor_position;
  
  Window_redraw_list(font_list);
  
  Update_window_area(0,0,Window_width, Window_height);
  
  // str texte
  Window_input_content(input_text_button,str);
  // Taille police
  redraw_is_needed=1;
  // --
  while (1)
  {
    if (redraw_is_needed)
    {
      // Taille
      Num2str(font_size,size_buffer,3);
      Window_input_content(input_size_button,size_buffer);
    }
    if (preview_is_needed)
    {
      const char * preview_string = "AaBbCcDdEeFf012345";
      if (str[0])
        preview_string=str;
      Window_rectangle(8, 106, 273, 50,Back_color);
      free(new_brush);
      new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height);
      if (new_brush)
      {
        Display_brush(
          new_brush,
          Window_pos_X+preview_button->Pos_X*Menu_factor_X,
          Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y,
          0,
          0,
          Min(preview_button->Width*Menu_factor_X, new_width),
          Min(preview_button->Height*Menu_factor_Y, new_height),
          Back_color,
          new_width);
      }
      Update_rect(
        Window_pos_X+preview_button->Pos_X*Menu_factor_X,
        Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y,
        preview_button->Width*Menu_factor_X,
        preview_button->Height*Menu_factor_Y);
    }
    if (redraw_is_needed || preview_is_needed)
    {    
      redraw_is_needed=0;
      preview_is_needed=0;
      Display_cursor();
    }
  
    clicked_button=Window_clicked_button();
    if (clicked_button==0)
    {
      if (Is_shortcut(Key,0x100+BUTTON_HELP))
        Window_help(BUTTON_TEXT, NULL);
      else if (Is_shortcut(Key,0x100+BUTTON_TEXT))
        clicked_button=12;
    }
    switch(clicked_button)
    {
      case 1: // Texte saisi
      Readline_ex(50,20,str,29,250,0,0);
      preview_is_needed=1;
      break;
      case 2: // AA
      antialias = (antialias==0);
      Hide_cursor();
      Print_in_window(191,60,antialias?"X":" ", MC_Black, MC_Light);
      preview_is_needed=1;
      break;
      case 3: // Bold
      is_bold = (is_bold==0);
      Hide_cursor();
      Print_in_window(191,74,is_bold?"X":" ", MC_Black, MC_Light);
      preview_is_needed=1;
      break;
      case 4: // Italic
      is_italic = (is_italic==0);
      Hide_cursor();
      Print_in_window(191,88,is_italic?"X":" ", MC_Black, MC_Light);
      preview_is_needed=1;
      break;
      
      case 5: // Scroller des fontes
      /* Cannot happen, event is catched by the list control */
      break;
      
      case 6: // Selecteur de fonte
      /* Cannot happen, event is catched by the list control */
      break;
      
      case 13: // Font selection
        selected_font_index = Window_attribute2;
        Hide_cursor();
        preview_is_needed=1;
      break;
                  
      case 7: // Taille du texte (nombre)
      Readline(222,45,size_buffer,3,1);
      font_size=atoi(size_buffer);
      // On corrige les dimensions
      if (font_size < 1)
      {
        font_size = 1;
      }
      else if (font_size>500)
      {
        font_size = 500;
      }
      redraw_is_needed=1;
      preview_is_needed=1;
      break;
      
      case 8: // Taille -
      if (font_size > 1)
      {
        font_size--;
        Hide_cursor();
        redraw_is_needed=1;
        preview_is_needed=1;
      }
      break;
      
      case 9: // Taille +
      if (font_size < 255)
      {
        font_size++;
        Hide_cursor();
        redraw_is_needed=1;
        preview_is_needed=1;
      }
      break;
      
    
      case 11: // OK
      // Save the selector settings
      list_start = font_list->List_start;
      cursor_position = font_list->Cursor_position;
      
      if (!new_brush)
      {
        // Si echec de rendu
        Close_window();
        Unselect_button(BUTTON_TEXT);
        Display_cursor();
        Error(0);
        return;
      }
      free(Brush);
    
      Brush=new_brush;
      Brush_width=new_width;
      Brush_height=new_height;
      Brush_offset_X=Brush_width>>1;
      Brush_offset_Y=Brush_height>>1;
 
      // Fermeture
      Close_window();
      Unselect_button(BUTTON_TEXT);
      
      // On passe en brosse:
      Display_cursor();
      if (antialias || !TrueType_font(selected_font_index))
        Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
      else
        Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH);
      Select_button(BUTTON_DRAW,LEFT_SIDE);
      if (Config.Auto_discontinuous)
      {
        // On se place en mode Dessin discontinu à la main
        while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
          Select_button(BUTTON_DRAW,RIGHT_SIDE);
      }
      //Display_cursor();
      return;
      
      case 12: // Cancel
      // Save the selector settings
      list_start = font_list->List_start;
      cursor_position = font_list->Cursor_position;
      
      free(new_brush);
      new_brush = NULL;
      Close_window();
      Unselect_button(BUTTON_TEXT);
      Display_cursor();
      return;
    }
  }
}
void Display_stored_brush_in_window(word x_pos,word y_pos,int index)
{
  if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX)
  {
    int x,y;
    int offset_x=0, offset_y=0;
    //int brush_offset_x=0, brush_offset_y=0;
    
    // Determine draw offset (small brushes are stacked on corner of their preview)
    if (Brush_container[index].WidthBRUSH_CONTAINER_PREVIEW_WIDTH)
      brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2;
    if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT)
      brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2;
    for (y=0; yBRUSH_CONTAINER_PREVIEW_WIDTH ||
          Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT)
      {
        // Scale
        Rescale(Brush, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0);
      }
      else
      {
        // Direct copy
        Copy_part_of_image_to_another(Brush, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH);
      }
    }
    else
    {
      Error(0);
    }
  }
}
byte Restore_brush(int index)
{
  byte shape;
  word x_pos;
  word y_pos;
  
  shape = Brush_container[index].Paintbrush_shape;
  
  if (shape == PAINTBRUSH_SHAPE_MAX)
    return 0;
  // Mono brushes
  if (shape <= PAINTBRUSH_SHAPE_MISC)
  {
    Paintbrush_shape=shape;
    Paintbrush_width=Brush_container[index].Width;
    Paintbrush_height=Brush_container[index].Height;
    if (shape == PAINTBRUSH_SHAPE_HORIZONTAL_BAR)
      Paintbrush_height=1;
    else if (shape == PAINTBRUSH_SHAPE_VERTICAL_BAR)
      Paintbrush_width=1;
    
    if (Paintbrush_width <= BRUSH_CONTAINER_PREVIEW_WIDTH &&
        Paintbrush_height <= BRUSH_CONTAINER_PREVIEW_HEIGHT)
    {
      // Manually copy the "pixels"
      for (y_pos=0; y_pos>1;
      Paintbrush_offset_Y=Paintbrush_height>>1;
    }
    else
    {
      // Recreate the brush pixels from its shape and dimensions
      Set_paintbrush_size(Paintbrush_width,Paintbrush_height);
    }
  }
  // Color brushes
  if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH ||
     shape == PAINTBRUSH_SHAPE_MONO_BRUSH)
  {
    Paintbrush_shape=shape;
    Realloc_brush(Brush_container[index].Width,Brush_container[index].Height);
    // Realloc sets Brush_width and Brush_height to new size.
    memcpy(Brush, Brush_container[index].Brush, Brush_height*Brush_width);
    
    Brush_offset_X=Brush_width>>1;
    Brush_offset_Y=Brush_height>>1;
  }
  Change_paintbrush_shape(shape);
  return 1;
}
void Button_Brush_container(void)
{
  short clicked_button;
  short x_pos,y_pos;
  byte index;
  Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8,
    BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40,
    "Brushes");
  Window_set_normal_button(
    (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2,
    (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18,
    67,14,"Cancel",0,1,KEY_ESC); // 1
  index=0;
  for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++)
  {
    x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7;
    y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18;
    Window_set_normal_button(
      x_pos,
      y_pos,
      BRUSH_CONTAINER_PREVIEW_WIDTH+2,
      BRUSH_CONTAINER_PREVIEW_HEIGHT+2,
      "",0,1,SDLK_LAST);
    Display_stored_brush_in_window(x_pos+1, y_pos+1, index);
  }
  Update_window_area(0,0,Window_width, Window_height);
  Display_cursor();
  do
  {
    clicked_button=Window_clicked_button();
    //if (Is_shortcut(Key,0x100+BUTTON_HELP))
    //  Window_help(BUTTON_PAINTBRUSHES, NULL);
    
    if (clicked_button == 1)
      break;
      
    if (clicked_button>1)
    {
      index = clicked_button-2;
      
      if (Window_attribute1==RIGHT_SIDE)
      {
        // Store
        
        x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7;
        y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18;
      
        Store_brush(index);
        Hide_cursor();
        Display_stored_brush_in_window(x_pos+1, y_pos+1, index);
        Display_cursor();
      }
      else
      {
        // Restore and exit
      
        if (Restore_brush(index))
          break;
      }
    }
  }
  while (1);
  Close_window();
  //Unselect_button(BUTTON_PAINTBRUSHES);
  Display_cursor();
}