/*  Grafx2 - The Ultimate 256-color bitmap paint program
    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 
*/
/// @file Window engine and interface management
#include 
#include 
#include 
#include "const.h"
#include "struct.h"
#include "global.h"
#include "graph.h"
#include "misc.h"
#include "special.h"
#include "buttons.h"
#include "operatio.h"
#include "shade.h"
#include "errors.h"
#include "sdlscreen.h"
#include "windows.h"
#include "brush.h"
#include "input.h"
#include "engine.h"
// we need this as global
short Old_MX = -1;
short Old_MY = -1;
//---------- Annuler les effets des modes de dessin (sauf la grille) ---------
// Variables mémorisants les anciens effets
byte Shade_mode_before_cancel;
byte Quick_shade_mode_before_cancel;
byte Stencil_mode_before_cancel;
byte Sieve_mode_before_cancel;
byte Colorize_mode_before_cancel;
byte Smooth_mode_before_cancel;
byte Tiling_mode_before_cancel;
Func_effect Effect_function_before_cancel;
///This table holds pointers to the saved window backgrounds. We can have up to 8 windows open at a time.
byte* Window_background[8];
///Table of tooltip texts for menu buttons
char * Menu_tooltip[NB_BUTTONS]=
{
  "Paintbrush choice       ",
  "Adjust / Transform menu ",
  "Freehand draw. / Toggle ",
  "Splines / Toggle        ",
  "Lines / Toggle          ",
  "Spray / Menu            ",
  "Floodfill / Replace col.",
  "Polylines / Polyforms   ",
  "Polyfill / Filled Pforms",
  "Empty rectangles        ",
  "Filled rectangles       ",
  "Empty circles / ellipses",
  "Filled circles / ellips.",
  "Grad. rect / Grad. menu ",
  "Grad. spheres / ellipses",
  "Brush grab. / Restore   ",
  "Lasso / Restore brush   ",
  "Brush effects           ",
  "Drawing modes (effects) ",
  "Text                    ",
  "Magnify mode / Menu     ",
  "Pipette / Invert colors ",
  "Screen size / Safe. res.",
  "Go / Copy to other page ",
  "Save as / Save          ",
  "Load / Re-load          ",
  "Settings / Skins        ",
  "Clear / with backcolor  ",
  "Help / Statistics       ",
  "Undo / Redo             ",
  "Kill current page       ",
  "Quit                    ",
  "Palette editor / setup  ",
  "Scroll pal. bkwd / Fast ",
  "Scroll pal. fwd / Fast  ",
  "Color #"                 ,
  "Hide tool bar           "
};
///Save a screen block (usually before erasing it with a new window or a dropdown menu)
void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height)
{
  int index;
  if(*buffer != NULL) DEBUG("WARNING : buffer already allocated !!!",0);
  *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width);
  if(*buffer==NULL) Error(0);
  for (index=0; index<(height*Menu_factor_Y); index++)
    Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width));
}
///Restores a screen block
void Restore_background(byte *buffer, int x_pos, int y_pos, int width, int height)
{
  int index;
  for (index=0; index=Buttons_Pool[btn_number].X_offset) &&
            (y_pos>=Buttons_Pool[btn_number].Y_offset) &&
            (x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) &&
            (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height))
          return btn_number;
        break;
      case BUTTON_SHAPE_TRIANGLE_TOP_LEFT:
        if ((x_pos>=Buttons_Pool[btn_number].X_offset) &&
            (y_pos>=Buttons_Pool[btn_number].Y_offset) &&
            (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset<=Buttons_Pool[btn_number].Width))
          return btn_number;
        break;
      case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT:
        if ((x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) &&
            (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height) &&
            (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset>=Buttons_Pool[btn_number].Width))
          return btn_number;
        break;
    }
  }
  return -1;
}
///Draw the frame for a menu button
void Draw_menu_button_frame(byte btn_number,byte pressed)
{
  byte color_top_left;
  byte color_bottom_right;
  byte color_diagonal;
  word start_x;
  word start_y;
  word end_x;
  word end_y;
  word x_pos;
  word y_pos;
  start_x=Buttons_Pool[btn_number].X_offset;
  start_y=Buttons_Pool[btn_number].Y_offset;
  end_x  =start_x+Buttons_Pool[btn_number].Width;
  end_y  =start_y+Buttons_Pool[btn_number].Height;
  if (!pressed)
  {
    color_top_left=MC_White;
    color_bottom_right=MC_Dark;
    color_diagonal=MC_Light;
  }
  else
  {
    color_top_left=MC_Dark;
    color_bottom_right=MC_Black;
    color_diagonal=MC_Dark;
  }
  switch(Buttons_Pool[btn_number].Shape)
  {
    case BUTTON_SHAPE_NO_FRAME :
      break;
    case BUTTON_SHAPE_RECTANGLE  :
      // On colorie le point haut droit
      Pixel_in_menu(end_x,start_y,color_diagonal);
      Gfx->Menu_block[start_y][end_x]=color_diagonal;
      // On colorie le point bas gauche
      Pixel_in_menu(start_x,end_y,color_diagonal);
      Gfx->Menu_block[end_y][start_x]=color_diagonal;
      // On colorie la partie haute
      for (x_pos=start_x;x_pos<=end_x-1;x_pos++)
      {
        Pixel_in_menu(x_pos,start_y,color_top_left);
        Gfx->Menu_block[start_y][x_pos]=color_top_left;
      }
      for (y_pos=start_y+1;y_pos<=end_y-1;y_pos++)
      {
        // On colorie la partie gauche
        Pixel_in_menu(start_x,y_pos,color_top_left);
        Gfx->Menu_block[y_pos][start_x]=color_top_left;
        // On colorie la partie droite
        Pixel_in_menu(end_x,y_pos,color_bottom_right);
        Gfx->Menu_block[y_pos][end_x]=color_bottom_right;
      }
      // On colorie la partie basse
      for (x_pos=start_x+1;x_pos<=end_x;x_pos++)
      {
        Pixel_in_menu(x_pos,end_y,color_bottom_right);
        Gfx->Menu_block[end_y][x_pos]=color_bottom_right;
      }
      break;
    case BUTTON_SHAPE_TRIANGLE_TOP_LEFT:
      // On colorie le point haut droit
      Pixel_in_menu(end_x,start_y,color_diagonal);
      Gfx->Menu_block[start_y][end_x]=color_diagonal;
      // On colorie le point bas gauche
      Pixel_in_menu(start_x,end_y,color_diagonal);
      Gfx->Menu_block[end_y][start_x]=color_diagonal;
      // On colorie le coin haut gauche
      for (x_pos=0;x_posMenu_block[start_y][start_x+x_pos]=color_top_left;
        Pixel_in_menu(start_x,start_y+x_pos,color_top_left);
        Gfx->Menu_block[start_y+x_pos][start_x]=color_top_left;
      }
      // On colorie la diagonale
      for (x_pos=1;x_posMenu_block[end_y-x_pos][start_x+x_pos]=color_bottom_right;
      }
      break;
    case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT:
      // On colorie le point haut droit
      Pixel_in_menu(end_x,start_y,color_diagonal);
      Gfx->Menu_block[start_y][end_x]=color_diagonal;
      // On colorie le point bas gauche
      Pixel_in_menu(start_x,end_y,color_diagonal);
      Gfx->Menu_block[end_y][start_x]=color_diagonal;
      // On colorie la diagonale
      for (x_pos=1;x_posMenu_block[end_y-x_pos][start_x+x_pos]=color_top_left;
      }
      // On colorie le coin bas droite
      for (x_pos=0;x_posMenu_block[end_y][end_x-x_pos]=color_bottom_right;
        Pixel_in_menu(end_x,end_y-x_pos,color_bottom_right);
        Gfx->Menu_block[end_y-x_pos][end_x]=color_bottom_right;
      }
  }
  if (Menu_is_visible)
  {
    Update_rect(
      start_x*Menu_factor_X,
      start_y*Menu_factor_Y + Menu_Y,
      (end_x+1-start_x)*Menu_factor_X,
      (end_y+1-start_y)*Menu_factor_Y);
  }
}
///Deselect a button
void Unselect_button(int btn_number)
{
  if (Buttons_Pool[btn_number].Pressed)
  {
    // On affiche le cadre autour du bouton de façon à ce qu'il paraisse relâché
    Draw_menu_button_frame(btn_number,BUTTON_RELEASED);
    // On considère que le bouton est relâché
    Buttons_Pool[btn_number].Pressed=BUTTON_RELEASED;
    // On appelle le désenclenchement particulier au bouton:
    Buttons_Pool[btn_number].Unselect_action();
  }
}
///Select a button and disable all his family (for example, selecting "freehand" unselect "curves", "lines", ...)
void Select_button(int btn_number,byte click)
{
  int family;
  int b;
  int icon;
  Hide_cursor();
  // Certains boutons ont deux icones
  icon=-1;
  switch(btn_number)
  {
    case BUTTON_POLYGONS:
    case BUTTON_POLYFILL:
      icon=12;break;
    case BUTTON_FLOODFILL:
      icon=14;break;
    case BUTTON_CIRCLES:
    case BUTTON_FILLCIRC:
      icon=10;break;
    case BUTTON_SPHERES:
      icon=16;break;
  }
  if (icon!=-1)
    Display_sprite_in_menu(btn_number,icon+(click==RIGHT_SIDE));
  // On note déjà la famille du bouton (La "Famiglia" c'est sacré)
  family=Buttons_Pool[btn_number].Family;
  switch (family)
  {
    case FAMILY_TOOLBAR: // On ne fait rien (on préserve les interruptions)
      break;
    case FAMILY_INTERRUPTION: // Petit cas spécial dans la famille "Interruption":
      if ((btn_number!=BUTTON_MAGNIFIER) || (!Main_magnifier_mode))
      // Pour chaque bouton:
      for (b=0; bSPECIAL_CLICK_RIGHT)
      switch(key_index)
      {
        case SPECIAL_SCROLL_UP : // Scroll up
          if (Main_magnifier_mode)
            Scroll_magnifier(0,-(Main_magnifier_height>>2));
          else
            Scroll_screen(0,-(Screen_height>>3));
          Key=0;
          break;
        case SPECIAL_SCROLL_DOWN : // Scroll down
          if (Main_magnifier_mode)
            Scroll_magnifier(0,(Main_magnifier_height>>2));
          else
            Scroll_screen(0,(Screen_height>>3));
          Key=0;
          break;
        case SPECIAL_SCROLL_LEFT : // Scroll left
          if (Main_magnifier_mode)
            Scroll_magnifier(-(Main_magnifier_width>>2),0);
          else
            Scroll_screen(-(Screen_width>>3),0);
          Key=0;
          break;
        case SPECIAL_SCROLL_RIGHT : // Scroll right
          if (Main_magnifier_mode)
            Scroll_magnifier((Main_magnifier_width>>2),0);
          else
            Scroll_screen((Screen_width>>3),0);
          Key=0;
          break;
        case SPECIAL_SCROLL_UP_FAST : // Scroll up faster
          if (Main_magnifier_mode)
            Scroll_magnifier(0,-(Main_magnifier_height>>1));
          else
            Scroll_screen(0,-(Screen_height>>2));
          Key=0;
          break;
        case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster
          if (Main_magnifier_mode)
            Scroll_magnifier(0,(Main_magnifier_height>>1));
          else
            Scroll_screen(0,(Screen_height>>2));
          Key=0;
          break;
        case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster
          if (Main_magnifier_mode)
            Scroll_magnifier(-(Main_magnifier_width>>1),0);
          else
            Scroll_screen(-(Screen_width>>2),0);
          Key=0;
          break;
        case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster
          if (Main_magnifier_mode)
            Scroll_magnifier((Main_magnifier_width>>1),0);
          else
            Scroll_screen((Screen_width>>2),0);
          Key=0;
          break;
        case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower
          if (Main_magnifier_mode)
            Scroll_magnifier(0,-1);
          else
            Scroll_screen(0,-1);
          Key=0;
          break;
        case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower
          if (Main_magnifier_mode)
            Scroll_magnifier(0,1);
          else
            Scroll_screen(0,1);
          Key=0;
          break;
        case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower
          if (Main_magnifier_mode)
            Scroll_magnifier(-1,0);
          else
            Scroll_screen(-1,0);
          Key=0;
          break;
        case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower
          if (Main_magnifier_mode)
            Scroll_magnifier(1,0);
          else
            Scroll_screen(1,0);
          Key=0;
          break;
        case SPECIAL_NEXT_FORECOLOR : // Next foreground color
          Special_next_forecolor();
          Key=0;
          break;
        case SPECIAL_PREVIOUS_FORECOLOR : // Previous foreground color
          Special_previous_forecolor();
          Key=0;
          break;
        case SPECIAL_NEXT_BACKCOLOR : // Next background color
          Special_next_backcolor();
          Key=0;
          break;
        case SPECIAL_PREVIOUS_BACKCOLOR : // Previous background color
          Special_previous_backcolor();
          Key=0;
          break;
        case SPECIAL_SMALLER_PAINTBRUSH: // Rétrécir le pinceau
          Smaller_paintbrush();
          Key=0;
          break;
        case SPECIAL_BIGGER_PAINTBRUSH: // Grossir le pinceau
          Bigger_paintbrush();
          Key=0;
          break;
        case SPECIAL_NEXT_USER_FORECOLOR : // Next user-defined foreground color
          Special_next_user_forecolor();
          Key=0;
          break;
        case SPECIAL_PREVIOUS_USER_FORECOLOR : // Previous user-defined foreground color
          Special_previous_user_forecolor();
          Key=0;
          break;
        case SPECIAL_NEXT_USER_BACKCOLOR : // Next user-defined background color
          Special_next_user_backcolor();
          Key=0;
          break;
        case SPECIAL_PREVIOUS_USER_BACKCOLOR : // Previous user-defined background color
          Special_previous_user_backcolor();
          Key=0;
          break;
        case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor
          Hide_cursor();
          Cursor_hidden=!Cursor_hidden;
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "."
          Hide_cursor();
          Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND;
          Set_paintbrush_size(1,1);
          Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing
          Select_button(BUTTON_DRAW,LEFT_SIDE);
          // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS
          while (Current_operation!=OPERATION_CONTINUOUS_DRAW)
            Select_button(BUTTON_DRAW,RIGHT_SIDE);
          Key=0;
          break;
        case SPECIAL_FLIP_X : // Flip X
          Hide_cursor();
          Flip_X_lowlevel(Brush, Brush_width, Brush_height);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_FLIP_Y : // Flip Y
          Hide_cursor();
          Flip_Y_lowlevel(Brush, Brush_width, Brush_height);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_ROTATE_90 : // 90° brush rotation
          Hide_cursor();
          Rotate_90_deg();
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_ROTATE_180 : // 180° brush rotation
          Hide_cursor();
          Rotate_180_deg_lowlevel(Brush, Brush_width, Brush_height);
          Brush_offset_X=(Brush_width>>1);
          Brush_offset_Y=(Brush_height>>1);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_STRETCH : // Stretch brush
          Hide_cursor();
          Start_operation_stack(OPERATION_STRETCH_BRUSH);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_DISTORT : // Distort brush
          Hide_cursor();
          Start_operation_stack(OPERATION_DISTORT_BRUSH);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle
          Hide_cursor();
          Start_operation_stack(OPERATION_ROTATE_BRUSH);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_OUTLINE : // Outline brush
          Hide_cursor();
          Outline_brush();
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_NIBBLE : // Nibble brush
          Hide_cursor();
          Nibble_brush();
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush
          Get_colors_from_brush();
          Key=0;
          break;
        case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush
          Hide_cursor();
          Remap_brush();
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_LOAD_BRUSH :
          Load_picture(0);
          Key=0;
          break;
        case SPECIAL_SAVE_BRUSH :
          Save_picture(0);
          Key=0;
          break;
        case SPECIAL_ZOOM_IN : // Zoom in
          Zoom(+1);
          Key=0;
          break;
        case SPECIAL_ZOOM_OUT : // Zoom out
          Zoom(-1);
          Key=0;
          break;
        case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment
          Hide_cursor();
          Brush_offset_X=(Brush_width>>1);
          Brush_offset_Y=(Brush_height>>1);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment
          Hide_cursor();
          Brush_offset_X=0;
          Brush_offset_Y=0;
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment
          Hide_cursor();
          Brush_offset_X=(Brush_width-1);
          Brush_offset_Y=0;
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment
          Hide_cursor();
          Brush_offset_X=0;
          Brush_offset_Y=(Brush_height-1);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment
          Hide_cursor();
          Brush_offset_X=(Brush_width-1);
          Brush_offset_Y=(Brush_height-1);
          Display_cursor();
          Key=0;
          break;
        case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu
          Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL);
          Key=0;
          break;
        case SPECIAL_INVERT_SIEVE :
          Invert_trame();
          Key=0;
          break;
        case SPECIAL_SHADE_MODE :
          Button_Shade_mode();
          Key=0;
          break;
        case SPECIAL_SHADE_MENU :
          Button_Shade_menu();
          Key=0;
          break;
        case SPECIAL_QUICK_SHADE_MODE :
          Button_Quick_shade_mode();
          Key=0;
          break;
        case SPECIAL_QUICK_SHADE_MENU :
          Button_Quick_shade_menu();
          Key=0;
          break;
        case SPECIAL_STENCIL_MODE :
          Button_Stencil_mode();
          Key=0;
          break;
        case SPECIAL_STENCIL_MENU :
          Button_Stencil_menu();
          Key=0;
          break;
        case SPECIAL_MASK_MODE :
          Button_Mask_mode();
          Key=0;
          break;
        case SPECIAL_MASK_MENU :
          Button_Mask_menu();
          Key=0;
          break;
        case SPECIAL_GRID_MODE :
          Button_Snap_mode();
          Key=0;
          break;
        case SPECIAL_GRID_MENU :
          Button_Grid_menu();
          Key=0;
          break;
        case SPECIAL_SIEVE_MODE :
          Button_Sieve_mode();
          Key=0;
          break;
        case SPECIAL_SIEVE_MENU :
          Button_Sieve_menu();
          Key=0;
          break;
        case SPECIAL_COLORIZE_MODE :
          Button_Colorize_mode();
          Key=0;
          break;
        case SPECIAL_COLORIZE_MENU :
          Button_Colorize_menu();
          Key=0;
          break;
        case SPECIAL_SMOOTH_MODE :
          Button_Smooth_mode();
          Key=0;
          break;
        case SPECIAL_SMOOTH_MENU :
          Button_Smooth_menu();
          Key=0;
          break;
        case SPECIAL_SMEAR_MODE :
          Button_Smear_mode();
          Key=0;
          break;
        case SPECIAL_TILING_MODE :
          Button_Tiling_mode();
          Key=0;
          break;
        case SPECIAL_TILING_MENU :
          Button_Tiling_menu();
          Key=0;
          break;
        case SPECIAL_EFFECTS_OFF :
          Effects_off();
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_1 :
          Transparency_set(1);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_2 :
          Transparency_set(2);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_3 :
          Transparency_set(3);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_4 :
          Transparency_set(4);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_5 :
          Transparency_set(5);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_6 :
          Transparency_set(6);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_7 :
          Transparency_set(7);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_8 :
          Transparency_set(8);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_9 :
          Transparency_set(9);
          Key=0;
          break;
        case SPECIAL_TRANSPARENCY_0 :
          Transparency_set(0);
          Key=0;
          break;
	case SPECIAL_ZOOM_1 :
	  Zoom_set(-1);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_2 :
	  Zoom_set(0);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_3 :
	  Zoom_set(1);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_4 :
	  Zoom_set(2);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_5 :
	  Zoom_set(3);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_6 :
	  Zoom_set(4);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_8 :
	  Zoom_set(5);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_10 :
	  Zoom_set(6);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_12 :
	  Zoom_set(7);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_14 :
	  Zoom_set(8);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_16 :
	  Zoom_set(9);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_18 :
	  Zoom_set(10);
	  Key=0;
	  break;
	case SPECIAL_ZOOM_20 :
	  Zoom_set(11);
	  Key=0;
	  break;
        default   : // Gestion des touches de raccourci de bouton:
          // Pour chaque bouton
          shortcut_button=-1;
          for (button_index=0;button_index=SPECIAL_SHADE_MODE)
       && (key_index<=SPECIAL_TILING_MENU))
      {
        Hide_cursor();
        Draw_menu_button_frame(BUTTON_EFFECTS,
          (Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode));
        Display_cursor();
      }
    }
    }
    else
	{
		// No event : we go asleep for a while, but we try to get waked up at constant intervals of time
		// no matter the machine speed or system load. The time is fixed to 10ms (that should be about a cpu slice on most systems)
		// This allows nice smooth mouse movement.
    	const int delay = 10;
		Uint32 debut;
		debut = SDL_GetTicks();
		// Première attente : le complément de "delay" millisecondes
		SDL_Delay(delay - (debut % delay));
		// Si ça ne suffit pas, on complète par des attentes successives de "1ms".
		// (Remarque, Windows arrondit généralement aux 10ms supérieures)
		while ( SDL_GetTicks()/delay <= debut/delay)
		{
			SDL_Delay(1);
		}
	}
    // Gestion de la souris
    Cursor_in_menu=(Mouse_Y>=Menu_Y) ||
                      ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) &&
                        (Mouse_X=Menu_Y)
        {
          if (button_index>=0)
          {
            Select_button(button_index,Mouse_K);
            prev_button_number=-1;
          }
        }
        else
          if (Main_magnifier_mode) Move_separator();
      }
    }
    // we need to refresh that one as we may come from a sub window
    Cursor_in_menu=(Mouse_Y>=Menu_Y) ||
                      ( (Main_magnifier_mode) && (Mouse_X>=Main_separator_position) &&
                        (Mouse_X>1;
  Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1;
  // Sauvegarde de ce que la fenêtre remplace
  Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height);
  // Fenêtre grise
  Block(Window_pos_X+(Menu_factor_X<<1),Window_pos_Y+(Menu_factor_Y<<1),(width-4)*Menu_factor_X,(height-4)*Menu_factor_Y,MC_Light);
  // -- Frame de la fenêtre ----- --- -- -  -
  // Frame noir puis en relief
  Window_display_frame_mono(0,0,width,height,MC_Black);
  Window_display_frame_out(1,1,width-2,height-2);
  // Barre sous le titre
  Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(11*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_Dark);
  Block(Window_pos_X+(Menu_factor_X<<3),Window_pos_Y+(12*Menu_factor_Y),(width-16)*Menu_factor_X,Menu_factor_Y,MC_White);
  Print_in_window((width-(strlen(title)<<3))>>1,3,title,MC_Black,MC_Light);
  if (Windows_open == 1)
  {
    Menu_is_visible_before_window=Menu_is_visible;
    Menu_is_visible=0;
    Menu_Y_before_window=Menu_Y;
    Menu_Y=Screen_height;
    Cursor_shape_before_window=Cursor_shape;
    Cursor_shape=CURSOR_SHAPE_ARROW;
    Paintbrush_hidden_before_window=Paintbrush_hidden;
    Paintbrush_hidden=1;
  }
  // Initialisation des listes de boutons de la fenêtre
  Window_normal_button_list  =NULL;
  Window_palette_button_list =NULL;
  Window_scroller_button_list=NULL;
  Window_special_button_list =NULL;
  Window_dropdown_button_list=NULL;
  Window_nb_buttons            =0;
}
//----------------------- Fermer une fenêtre d'options -----------------------
void Close_window(void)
// Lors de l'appel à cette procedure, la souris doit être affichée.
// En sortie de cette procedure, la souris est effacée.
{
  T_Normal_button   * temp1;
  T_Palette_button  * temp2;
  T_Scroller_button * temp3;
  T_Special_button  * temp4;
  T_Dropdown_button * temp5;
  T_List_button     * temp6;
  Hide_cursor();
  while (Window_normal_button_list)
  {
    temp1=Window_normal_button_list->Next;
    free(Window_normal_button_list);
    Window_normal_button_list=temp1;
  }
  while (Window_palette_button_list)
  {
    temp2=Window_palette_button_list->Next;
    free(Window_palette_button_list);
    Window_palette_button_list=temp2;
  }
  while (Window_scroller_button_list)
  {
    temp3=Window_scroller_button_list->Next;
    free(Window_scroller_button_list);
    Window_scroller_button_list=temp3;
  }
  while (Window_special_button_list)
  {
    temp4=Window_special_button_list->Next;
    free(Window_special_button_list);
    Window_special_button_list=temp4;
  }
  while (Window_dropdown_button_list)
  {
    temp5=Window_dropdown_button_list->Next;
    Window_dropdown_clear_items(Window_dropdown_button_list);
    free(Window_dropdown_button_list);
    Window_dropdown_button_list=temp5;
  }
  while (Window_list_button_list)
  {
    temp6=Window_list_button_list->Next;
    free(Window_list_button_list);
    Window_list_button_list=temp6;
  }
  if (Windows_open != 1)
  {
    // Restore de ce que la fenêtre cachait
    Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
    Window_background[Windows_open-1]=NULL;
    Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y);
    Windows_open--;
  }
  else
  {
    free(Window_background[Windows_open-1]);
    Window_background[Windows_open-1]=NULL;
    Windows_open--;
  
    Paintbrush_hidden=Paintbrush_hidden_before_window;
  
    Compute_paintbrush_coordinates();
  
    Menu_Y=Menu_Y_before_window;
    Menu_is_visible=Menu_is_visible_before_window;
    Cursor_shape=Cursor_shape_before_window;
    
    Display_all_screen();
    Display_menu();
  }
  Key=0;
  Mouse_K=0;
  
  Old_MX = -1;
  Old_MY = -1;
}
//---------------- Dessiner un bouton normal dans une fenêtre ----------------
void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height,
                                    char * title,byte undersc_letter,byte clickable)
{
  byte title_color;
  word text_x_pos,text_y_pos;
  if (clickable)
  {
    Window_display_frame_out(x_pos,y_pos,width,height);
    Window_display_frame_generic(x_pos-1,y_pos-1,width+2,height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark);
    title_color=MC_Black;
  }
  else
  {
    Window_display_frame_out(x_pos,y_pos,width,height);
    Window_display_frame_mono(x_pos-1,y_pos-1,width+2,height+2,MC_Light);
    title_color=MC_Dark;
  }
  text_x_pos=x_pos+( (width-(strlen(title)<<3)+1) >>1 );
  text_y_pos=y_pos+((height-7)>>1);
  Print_in_window(text_x_pos,text_y_pos,title,title_color,MC_Light);
  if (undersc_letter)
    Block(Window_pos_X+((text_x_pos+((undersc_letter-1)<<3))*Menu_factor_X),
          Window_pos_Y+((text_y_pos+8)*Menu_factor_Y),
          Menu_factor_X<<3,Menu_factor_Y,MC_Dark);
}
// -- Button normal enfoncé dans la fenêtre --
void Window_select_normal_button(word x_pos,word y_pos,word width,word height)
{
  Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_Black,MC_Dark,MC_Dark,MC_Black);
  Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y);
}
// -- Button normal désenfoncé dans la fenêtre --
void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height)
{
  Window_display_frame_out(x_pos,y_pos,width,height);
  Update_rect(Window_pos_X+x_pos*Menu_factor_X, Window_pos_Y+y_pos*Menu_factor_Y, width*Menu_factor_X, height*Menu_factor_Y);
}
//--------------- Dessiner un bouton palette dans une fenêtre ----------------
void Window_draw_palette_bouton(word x_pos,word y_pos)
{
  word color;
  for (color=0; color<=255; color++)
    Block( Window_pos_X+((((color >> 4)*10)+x_pos+6)*Menu_factor_X),Window_pos_Y+((((color & 15)*5)+y_pos+3)*Menu_factor_Y),Menu_factor_X*5,Menu_factor_Y*5,color);
  Window_display_frame(x_pos,y_pos,164,86);
}
// -------------------- Effacer les TAGs sur les palette ---------------------
// Cette fonct° ne sert plus que lorsqu'on efface les tags dans le menu Spray.
void Window_clear_tags(void)
{
  word origin_x;
  word origin_y;
  word x_pos;
  word window_x_pos;
  //word window_y_pos;
  origin_x=Window_pos_X+(Window_palette_button_list->Pos_X+3)*Menu_factor_X;
  origin_y=Window_pos_Y+(Window_palette_button_list->Pos_Y+3)*Menu_factor_Y;
  for (x_pos=0,window_x_pos=origin_x;x_pos<16;x_pos++,window_x_pos+=(Menu_factor_X*10))
    Block(window_x_pos,origin_y,Menu_factor_X*3,Menu_factor_Y*80,MC_Light);
  Update_rect(origin_x,origin_y,ToWinL(160),ToWinH(80));
}
// ---- Tracer les TAGs sur les palettes du menu Palette ou du menu Shade ----
void Tag_color_range(byte start,byte end)
{
  word origin_x;
  word origin_y;
  //word x_pos;
  word y_pos;
  //word window_x_pos;
  word window_y_pos;
  word index;
  // On efface les anciens TAGs
  for (index=0;index<=start;index++)
    Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X,
          Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y,
          Menu_factor_X*3,Menu_factor_Y*5,MC_Light);
  for (index=end;index<256;index++)
    Block(Window_pos_X+(Window_palette_button_list->Pos_X+3+((index>>4)*10))*Menu_factor_X,
          Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y,
          Menu_factor_X*3,Menu_factor_Y*5,MC_Light);
  // On affiche le 1er TAG
  origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10;
  origin_y=(Window_palette_button_list->Pos_Y+3)+(start&15)* 5;
  for (y_pos=0,window_y_pos=origin_y  ;y_pos<5;y_pos++,window_y_pos++)
    Pixel_in_window(origin_x  ,window_y_pos,MC_Black);
  for (y_pos=0,window_y_pos=origin_y+1;y_pos<3;y_pos++,window_y_pos++)
    Pixel_in_window(origin_x+1,window_y_pos,MC_Black);
  Pixel_in_window(origin_x+2,origin_y+2,MC_Black);
  if (start!=end)
  {
    // On complète le 1er TAG
    Pixel_in_window(origin_x+1,origin_y+4,MC_Black);
    // On affiche le 2ème TAG
    origin_x=(Window_palette_button_list->Pos_X+3)+(end>>4)*10;
    origin_y=(Window_palette_button_list->Pos_Y+3)+(end&15)* 5;
    for (y_pos=0,window_y_pos=origin_y; y_pos<5; y_pos++,window_y_pos++)
      Pixel_in_window(origin_x  ,window_y_pos,MC_Black);
    for (y_pos=0,window_y_pos=origin_y; y_pos<4; y_pos++,window_y_pos++)
      Pixel_in_window(origin_x+1,window_y_pos,MC_Black);
    Pixel_in_window(origin_x+2,origin_y+2,MC_Black);
    // On TAG toutes les couleurs intermédiaires
    for (index=start+1;indexPos_X+3+((index>>4)*10))*Menu_factor_X,
            Window_pos_Y+(Window_palette_button_list->Pos_Y+3+((index&15)* 5))*Menu_factor_Y,
            Menu_factor_X*2,Menu_factor_Y*5,MC_Black);
      // On efface l'éventuelle pointe d'une ancienne extrémité de l'intervalle
      Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10),
                         Window_palette_button_list->Pos_Y+5+((index&15)* 5),
                         MC_Light);
    }
  }
  Update_rect(ToWinX(Window_palette_button_list->Pos_X+3),ToWinY(Window_palette_button_list->Pos_Y+3),ToWinL(12*16),ToWinH(5*16));
}
//------------------ Dessiner un scroller dans une fenêtre -------------------
void Compute_slider_cursor_height(T_Scroller_button * button)
{
  if (button->Nb_elements>button->Nb_visibles)
  {
    button->Cursor_height=(button->Nb_visibles*(button->Height-24))/button->Nb_elements;
    if (!(button->Cursor_height))
      button->Cursor_height=1;
  }
  else
  {
    button->Cursor_height=button->Height-24;
  }
}
void Window_draw_slider(T_Scroller_button * button)
{
  word slider_position;
  slider_position=button->Pos_Y+12;
  Block(Window_pos_X+(button->Pos_X*Menu_factor_X),
        Window_pos_Y+(slider_position*Menu_factor_Y),
        11*Menu_factor_X,(button->Height-24)*Menu_factor_Y,MC_Black/*MC_Dark*/);
  if (button->Nb_elements>button->Nb_visibles)
    slider_position+=Round_div(button->Position*(button->Height-24-button->Cursor_height),button->Nb_elements-button->Nb_visibles);
  Block(Window_pos_X+(button->Pos_X*Menu_factor_X),
        Window_pos_Y+(slider_position*Menu_factor_Y),
        11*Menu_factor_X,button->Cursor_height*Menu_factor_Y,MC_Dark/*MC_White*/);
  Update_rect(Window_pos_X+(button->Pos_X*Menu_factor_X),
        Window_pos_Y+button->Pos_Y*Menu_factor_Y,
        11*Menu_factor_X,(button->Height)*Menu_factor_Y);
}
void Window_draw_scroller_bouton(T_Scroller_button * button)
{
  Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark);
  Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Height-22,MC_Black);
  Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11);
  Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Height-11,11,11);
  Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light);
  Print_in_window(button->Pos_X+2,button->Pos_Y+button->Height-9,"\031",MC_Black,MC_Light);
  Window_draw_slider(button);
}
//--------------- Dessiner une zone de saisie dans une fenêtre ---------------
void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters)
{
  Window_display_frame_in(x_pos,y_pos,(width_in_characters<<3)+3,11);
}
//------------ Modifier le contenu (caption) d'une zone de saisie ------------
void Window_input_content(T_Special_button * button, char * content)
{
  Print_in_window_limited(button->Pos_X+2,button->Pos_Y+2,content,button->Width/8,MC_Black,MC_Light);
}
//------------ Effacer le contenu (caption) d'une zone de saisie ------------
void Window_clear_input_button(T_Special_button * button)
{
  Block((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,(button->Width/8)*8*Menu_factor_X,8*Menu_factor_Y,MC_Light);
  Update_rect((button->Pos_X+2)*Menu_factor_X+Window_pos_X,(button->Pos_Y+2)*Menu_factor_Y+Window_pos_Y,button->Width/8*8*Menu_factor_X,8*Menu_factor_Y);
}
//------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------
T_Normal_button * Window_set_normal_button(word x_pos, word y_pos,
                                   word width, word height,
                                   char * title, byte undersc_letter,
                                   byte clickable, word shortcut)
{
  T_Normal_button * temp=NULL;
  Window_nb_buttons++;
  if (clickable)
  {
    temp=(T_Normal_button *)malloc(sizeof(T_Normal_button));
    temp->Number   =Window_nb_buttons;
    temp->Pos_X    =x_pos;
    temp->Pos_Y    =y_pos;
    temp->Width    =width;
    temp->Height   =height;
    temp->Clickable=clickable;
    temp->Shortcut =shortcut;
    temp->Repeatable=0;
    temp->Next=Window_normal_button_list;
    Window_normal_button_list=temp;
  }
  Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable);
  return temp;
}
//------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------
T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos,
                                   word width, word height,
                                   char * title, byte undersc_letter,
                                   byte clickable, word shortcut)
{
  T_Normal_button * temp=NULL;
  Window_nb_buttons++;
  if (clickable)
  {
    temp=(T_Normal_button *)malloc(sizeof(T_Normal_button));
    temp->Number   =Window_nb_buttons;
    temp->Pos_X    =x_pos;
    temp->Pos_Y    =y_pos;
    temp->Width  =width;
    temp->Height  =height;
    temp->Shortcut=shortcut;
    temp->Repeatable=1;
    temp->Next=Window_normal_button_list;
    Window_normal_button_list=temp;
  }
  Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable);
  return temp;
}
T_Palette_button * Window_set_palette_button(word x_pos, word y_pos)
{
  T_Palette_button * temp;
  temp=(T_Palette_button *)malloc(sizeof(T_Palette_button));
  temp->Number   =++Window_nb_buttons;
  temp->Pos_X    =x_pos;
  temp->Pos_Y    =y_pos;
  temp->Next=Window_palette_button_list;
  Window_palette_button_list=temp;
  Window_draw_palette_bouton(x_pos,y_pos);
  return temp;
}
T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos,
                                     word height,
                                     word nb_elements,
                                     word nb_elements_visible,
                                     word initial_position)
{
  T_Scroller_button * temp;
  temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button));
  temp->Number        =++Window_nb_buttons;
  temp->Pos_X         =x_pos;
  temp->Pos_Y         =y_pos;
  temp->Height       =height;
  temp->Nb_elements   =nb_elements;
  temp->Nb_visibles   =nb_elements_visible;
  temp->Position      =initial_position;
  Compute_slider_cursor_height(temp);
  temp->Next=Window_scroller_button_list;
  Window_scroller_button_list=temp;
  Window_draw_scroller_bouton(temp);
  return temp;
}
T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height)
{
  T_Special_button * temp;
  temp=(T_Special_button *)malloc(sizeof(T_Special_button));
  temp->Number   =++Window_nb_buttons;
  temp->Pos_X    =x_pos;
  temp->Pos_Y    =y_pos;
  temp->Width  =width;
  temp->Height  =height;
  temp->Next=Window_special_button_list;
  Window_special_button_list=temp;
  return temp;
}
T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters)
{
  T_Special_button *temp;
  temp=Window_set_special_button(x_pos,y_pos,(width_in_characters<<3)+3,11);
  Window_draw_input_bouton(x_pos,y_pos,width_in_characters);
  return temp;
}
T_Dropdown_button * Window_set_dropdown_button(word x_pos,word y_pos,word width,word height,word dropdown_width,const char *label,byte display_choice,byte display_centered,byte display_arrow,byte active_button)
{
  T_Dropdown_button *temp;
  
  temp=(T_Dropdown_button *)malloc(sizeof(T_Dropdown_button));
  temp->Number       =++Window_nb_buttons;
  temp->Pos_X        =x_pos;
  temp->Pos_Y        =y_pos;
  temp->Width      =width;
  temp->Height      =height;
  temp->Display_choice =display_choice;
  temp->First_item=NULL;
  temp->Dropdown_width=dropdown_width?dropdown_width:width;
  temp->Display_centered=display_centered;
  temp->Display_arrow=display_arrow;
  temp->Active_button=active_button;
  temp->Next=Window_dropdown_button_list;
  Window_dropdown_button_list=temp;
  Window_draw_normal_bouton(x_pos,y_pos,width,height,"",-1,1);
  if (label && label[0])
    Print_in_window(temp->Pos_X+2,temp->Pos_Y+(temp->Height-7)/2,label,MC_Black,MC_Light);
  if (display_arrow)
    Window_display_icon_sprite(temp->Pos_X+temp->Width-10,temp->Pos_Y+(temp->Height-7)/2,ICON_DROPDOWN);
  
  return temp;
}
// Ajoute un choix à une dropdown. Le libellé est seulement référencé,
// il doit pointer sur une zone qui doit être encore valide à la fermeture 
// de la fenêtre (comprise).
void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label)
{
  T_Dropdown_choice *temp;
  T_Dropdown_choice *last;
  
  temp=(T_Dropdown_choice *)malloc(sizeof(T_Dropdown_choice));
  temp->Number =btn_number;
  temp->Label=label;
  temp->Next=NULL;
  last=dropdown->First_item;
  if (last)
  {
    // On cherche le dernier élément
    for (;last->Next;last=last->Next)
      ;
    last->Next=temp;
  }
  else
  {
    dropdown->First_item=temp;
  }
}
// ------------- Suppression de tous les choix d'une dropdown ---------
void Window_dropdown_clear_items(T_Dropdown_button * dropdown)
{
  T_Dropdown_choice * next_choice;
    while (dropdown->First_item)
    {
      next_choice=dropdown->First_item->Next;
      free(dropdown->First_item);
      dropdown->First_item=next_choice;
    }
}
//----------------------- Create a List control -----------------------
// These controls are special. They work over two controls previously created:
// - entry_button is the textual area where the list values will be printed.
// - scroller is a scroller button attached to it
T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item)
{
  T_List_button *temp;
  temp=(T_List_button *)malloc(sizeof(T_List_button));
  temp->Number          =++Window_nb_buttons;
  temp->List_start      = 0;
  temp->Cursor_position = 0;
  temp->Entry_button    = entry_button;
  temp->Scroller        = scroller;
  temp->Draw_list_item  = draw_list_item;
  temp->Next=Window_list_button_list;
  Window_list_button_list=temp;
  return temp;
}
void Window_redraw_list(T_List_button * list)
{
  int i;
  for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--)
  {
    list->Draw_list_item(
      list->Entry_button->Pos_X,
      list->Entry_button->Pos_Y + i * 8,
      list->List_start + i,
      i == list->Cursor_position);
  }
}
//----------------------- Ouverture d'un pop-up -----------------------
void Open_popup(word x_pos, word y_pos, word width,word height)
// Lors de l'appel à cette procédure, la souris doit être affichée.
// En sortie de cette procedure, la souris est effacée.
// Note : les pop-ups sont gérés comme s'ils étaient des sous-fenêtres, ils ont donc leur propre boucle d'évènements et tout, on peut ajouter des widgets dedans, ...
// Les différences sont surtout graphiques :
    // -Possibilité de préciser la position XY
    // -Pas de titre
    // -Pas de cadre en relief mais seulement un plat, et il est blanc au lieu de noir.
{
  Windows_open++;
  Window_width=width;
  Window_height=height;
  Window_pos_X=x_pos;
  Window_pos_Y=y_pos;
  // Sauvegarde de ce que la fenêtre remplace
  Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height);
/*
  // Fenêtre grise
  Block(Window_pos_X+1*Menu_factor_X,
        Window_pos_Y+1*Menu_factor_Y,
        (width-2)*Menu_factor_X,(height-2)*Menu_factor_Y,MC_Light);
  // Frame noir puis en relief
  Window_display_frame_mono(0,0,width,height,MC_White);
*/
  if (Windows_open == 1)
  {
    Menu_is_visible_before_window=Menu_is_visible;
    Menu_is_visible=0;
    Menu_Y_before_window=Menu_Y;
    Menu_Y=Screen_height;
    Cursor_shape_before_window=Cursor_shape;
    Cursor_shape=CURSOR_SHAPE_ARROW;
    Paintbrush_hidden_before_window=Paintbrush_hidden;
    Paintbrush_hidden=1;
  }
  // Initialisation des listes de boutons de la fenêtre
  Window_normal_button_list  =NULL;
  Window_palette_button_list =NULL;
  Window_scroller_button_list=NULL;
  Window_special_button_list =NULL;
  Window_dropdown_button_list =NULL;
  Window_nb_buttons            =0;
}
//----------------------- Fermer une fenêtre d'options -----------------------
void Close_popup(void)
// Lors de l'appel à cette procedure, la souris doit être affichée.
// En sortie de cette procedure, la souris est effacée.
{
  T_Normal_button   * temp1;
  T_Palette_button  * temp2;
  T_Scroller_button * temp3;
  T_Special_button  * temp4;
  T_Dropdown_button * temp5;
  T_List_button     * temp6;
  Hide_cursor();
  while (Window_normal_button_list)
  {
    temp1=Window_normal_button_list->Next;
    free(Window_normal_button_list);
    Window_normal_button_list=temp1;
  }
  while (Window_palette_button_list)
  {
    temp2=Window_palette_button_list->Next;
    free(Window_palette_button_list);
    Window_palette_button_list=temp2;
  }
  while (Window_scroller_button_list)
  {
    temp3=Window_scroller_button_list->Next;
    free(Window_scroller_button_list);
    Window_scroller_button_list=temp3;
  }
  while (Window_special_button_list)
  {
    temp4=Window_special_button_list->Next;
    free(Window_special_button_list);
    Window_special_button_list=temp4;
  }
  while (Window_dropdown_button_list)
  {
    Window_dropdown_clear_items(Window_dropdown_button_list);
    temp5=Window_dropdown_button_list->Next;
    free(Window_dropdown_button_list);
    Window_dropdown_button_list=temp5;
  }
  while (Window_list_button_list)
  {
    temp6=Window_list_button_list->Next;
    free(Window_list_button_list);
    Window_list_button_list=temp6;
  }
  
  if (Windows_open != 1)
  {
    // Restore de ce que la fenêtre cachait
    Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
    Window_background[Windows_open-1]=NULL;
    Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y);
    Windows_open--;
  }
  else
  {
    free(Window_background[Windows_open-1]);
    Windows_open--;
  
    Paintbrush_hidden=Paintbrush_hidden_before_window;
  
    Compute_paintbrush_coordinates();
  
    Menu_Y=Menu_Y_before_window;
    Menu_is_visible=Menu_is_visible_before_window;
    Cursor_shape=Cursor_shape_before_window;
    
    Display_all_screen();
    Display_menu();
  }
  Key=0;
  Mouse_K=0;
  
  Old_MX = -1;
  Old_MY = -1;
}
//////////////////////////////////////////////////////////////////////////////
//                                                                          //
//       Mini-MOTEUR utilisé dans les fenêtres (menus des boutons...)       //
//                                                                          //
//////////////////////////////////////////////////////////////////////////////
// -- Indique si on a cliqué dans une zone définie par deux points extremes --
byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y)
{
  short x_pos,y_pos;
  x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X;
  y_pos=((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y;
  return ((x_pos>=start_x) &&
          (y_pos>=start_y) &&
          (x_pos<=end_x)   &&
          (y_pos<=end_y));
}
// --- Attend que l'on clique dans la palette pour renvoyer la couleur choisie
// ou bien renvoie -1 si on a annulé l'action pas click-droit ou Escape ------
short Wait_click_in_palette(T_Palette_button * button)
{
  short start_x=button->Pos_X+5;
  short start_y=button->Pos_Y+3;
  short end_x  =button->Pos_X+160;
  short end_y  =button->Pos_Y+82;
  byte  selected_color;
  byte  old_hide_cursor;
  byte  old_main_magnifier_mode;
  Hide_cursor();
  old_hide_cursor=Cursor_hidden;
  old_main_magnifier_mode=Main_magnifier_mode;
  Main_magnifier_mode=0;
  Cursor_hidden=0;
  Cursor_shape=CURSOR_SHAPE_TARGET;
  Display_cursor();
  for (;;)
  {
    while(!Get_input())SDL_Delay(20);
    if (Mouse_K==LEFT_SIDE)
    {
      if (Window_click_in_rectangle(start_x,start_y,end_x,end_y))
      {
        Hide_cursor();
        selected_color=(((Mouse_X-Window_pos_X)/Menu_factor_X)-(button->Pos_X+2)) / 10 * 16 +
        (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(button->Pos_Y+3)) / 5;
        Cursor_shape=CURSOR_SHAPE_ARROW;
        Cursor_hidden=old_hide_cursor;
        Main_magnifier_mode=old_main_magnifier_mode;
        Display_cursor();
        return selected_color;
      }
      if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X)) ||
          (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) )
      {
        Hide_cursor();
        selected_color=Read_pixel(Mouse_X,Mouse_Y);
        Cursor_shape=CURSOR_SHAPE_ARROW;
        Cursor_hidden=old_hide_cursor;
        Main_magnifier_mode=old_main_magnifier_mode;
        Display_cursor();
        return selected_color;
      }
    }
    if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC))
    {
      Hide_cursor();
      Cursor_shape=CURSOR_SHAPE_ARROW;
      Cursor_hidden=old_hide_cursor;
      Main_magnifier_mode=old_main_magnifier_mode;
      Display_cursor();
      return -1;
    }
  }
}
// -------------- Récupération d'une couleur derrière un menu ----------------
void Get_color_behind_window(byte * color, byte * click)
{
  short old_x=-1;
  short old_y=-1;
  short index;
  short a,b,c,d; // Variables temporaires et multitâches...
  byte * buffer = NULL;
  char str[25];
  byte cursor_was_hidden;
  Hide_cursor();
  cursor_was_hidden=Cursor_hidden;
  Cursor_hidden=0;
  Save_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height);
  a=Menu_Y;
  Menu_Y=Menu_Y_before_window;
  b=Menu_is_visible;
  Menu_is_visible=Menu_is_visible_before_window;
  Display_all_screen();
  Display_menu();
  Menu_Y=a;
  Menu_is_visible=b;
  Cursor_shape=CURSOR_SHAPE_COLORPICKER;
  b=Paintbrush_hidden;
  Paintbrush_hidden=1;
  c=-1; // color pointée: au début aucune, comme ça on initialise tout
  if (Menu_is_visible_before_window)
	  Print_in_menu(Menu_tooltip[BUTTON_CHOOSE_COL],0);
  Display_cursor();
  do
  {
	  if(!Get_input())SDL_Delay(20);
	  if ((Mouse_X!=old_x) || (Mouse_Y!=old_y))
	  {
		  Hide_cursor();
		  a=Read_pixel(Mouse_X,Mouse_Y);
		  if (a!=c)
		  {
			  c=a; // Mise à jour de la couleur pointée
			  if (Menu_is_visible_before_window)
			  {
				  sprintf(str,"%d",a);
				  d=strlen(str);
				  strcat(str,"   (");
				  sprintf(str+strlen(str),"%d",Main_palette[a].R);
				  strcat(str,",");
				  sprintf(str+strlen(str),"%d",Main_palette[a].G);
				  strcat(str,",");
				  sprintf(str+strlen(str),"%d",Main_palette[a].B);
				  strcat(str,")");
				  a=24-d;
				  for (index=strlen(str); indexScreen_width-width)
    {
      new_x=Screen_width-width;
      dx = Mouse_X - new_x;
    }
    new_y=Mouse_Y-dy;
    if (new_y<0)
    {
      new_y=0;
      dy = Mouse_Y;
    }
    if (new_y>Screen_height-height)
    {
      new_y=Screen_height-height;
      dy = Mouse_Y - new_y;
    }
    if ((new_x!=old_x) || (new_y!=old_y))
    {
      Hide_cursor();
      Horizontal_XOR_line(old_x,old_y,width);
      Vertical_XOR_line(old_x,old_y+1,height-2);
      Vertical_XOR_line(old_x+width-1,old_y+1,height-2);
      Horizontal_XOR_line(old_x,old_y+height-1,width);
      Horizontal_XOR_line(new_x,new_y,width);
      Vertical_XOR_line(new_x,new_y+1,height-2);
      Vertical_XOR_line(new_x+width-1,new_y+1,height-2);
      Horizontal_XOR_line(new_x,new_y+height-1,width);
      Display_cursor();
      Update_rect(old_x,old_y,width,height);
      Update_rect(new_x,new_y,width,height);
    }
  }
  Hide_cursor();
  Horizontal_XOR_line(new_x,new_y,width);
  Vertical_XOR_line(new_x,new_y+1,height-2);
  Vertical_XOR_line(new_x+width-1,new_y+1,height-2);
  Horizontal_XOR_line(new_x,new_y+height-1,width);
  if ((new_x!=Window_pos_X)
   || (new_y!=Window_pos_Y))
  {
    a=Menu_Y;
    Menu_Y=Menu_Y_before_window;
    b=Menu_is_visible;
    Menu_is_visible=Menu_is_visible_before_window;
    //Display_all_screen();
    //Display_menu();
    Menu_Y=a;
    Menu_is_visible=b;
    // Sauvegarde du contenu actuel de la fenêtre
    Save_background(&buffer, Window_pos_X, Window_pos_Y, Window_width, Window_height);
    
    // Restore de ce que la fenêtre cachait
    Restore_background(Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
    Window_background[Windows_open-1] = NULL;
    // Sauvegarde de ce que la fenêtre remplace
    Save_background(&(Window_background[Windows_open-1]), new_x, new_y, Window_width, Window_height);
    // Raffichage de la fenêtre
    Restore_background(buffer, new_x, new_y, Window_width, Window_height);
    buffer = NULL;
    // Mise à jour du rectangle englobant
    Update_rect(
      (new_x>Window_pos_X)?Window_pos_X:new_x,
      (new_y>Window_pos_Y)?Window_pos_Y:new_y,
      ((new_x>Window_pos_X)?(new_x-Window_pos_X):(Window_pos_X-new_x)) + Window_width*Menu_factor_X,
      ((new_y>Window_pos_Y)?(new_y-Window_pos_Y):(Window_pos_Y-new_y)) + Window_height*Menu_factor_Y);
    Window_pos_X=new_x;
    Window_pos_Y=new_y;
  }
  else
  {
    // Update pour effacer le rectangle XOR
    Update_rect(Window_pos_X, Window_pos_Y, Window_width*Menu_factor_X, Window_height*Menu_factor_Y);
  }    
  Cursor_shape=CURSOR_SHAPE_ARROW;
  Display_cursor();
}
// Gestion des dropdown
short Window_dropdown_on_click(T_Dropdown_button *Button)
{
  short nb_choices;
  short choice_index;
  short selected_index;
  short old_selected_index;
  short box_height;
  T_Dropdown_choice *item;
  // Taille de l'ombre portée (en plus des dimensions normales)
  #define SHADOW_RIGHT 3
  #define SHADOW_BOTTOM 4
  
  // Comptage des items pour calculer la taille
  nb_choices=0;
  for (item=Button->First_item; item!=NULL; item=item->Next)
  {
    nb_choices++;
  }
  box_height=3+nb_choices*8+1;
  
  Hide_cursor();
  Window_select_normal_button(Button->Pos_X,Button->Pos_Y,Button->Width,Button->Height);
  Open_popup(
    Window_pos_X+(Button->Pos_X)*Menu_factor_X,
    Window_pos_Y+(Button->Pos_Y+Button->Height)*Menu_factor_Y,
    Button->Dropdown_width+SHADOW_RIGHT,
    box_height+SHADOW_BOTTOM);
  // Dessin de la boite
  // Bord gauche
  Block(Window_pos_X,Window_pos_Y,Menu_factor_X,box_height*Menu_factor_Y,MC_Black);
  // Frame fonce et blanc
  Window_display_frame_out(1,0,Button->Dropdown_width-1,box_height);
  // Ombre portée
  if (SHADOW_BOTTOM)
  {
    Block(Window_pos_X+SHADOW_RIGHT*Menu_factor_X,
        Window_pos_Y+box_height*Menu_factor_Y,
        Button->Dropdown_width*Menu_factor_X,
        SHADOW_BOTTOM*Menu_factor_Y,
        MC_Black);
    Block(Window_pos_X,
        Window_pos_Y+box_height*Menu_factor_Y,
        SHADOW_RIGHT*Menu_factor_X,
        Menu_factor_Y,
        MC_Black);
  }
  if (SHADOW_RIGHT)
  {
    Block(Window_pos_X+Button->Dropdown_width*Menu_factor_X,
        Window_pos_Y+SHADOW_BOTTOM*Menu_factor_Y,
        SHADOW_RIGHT*Menu_factor_X,
        (box_height-SHADOW_BOTTOM)*Menu_factor_Y,
        MC_Black);
    Block(Window_pos_X+Button->Dropdown_width*Menu_factor_X,
        Window_pos_Y,
        Menu_factor_X,
        SHADOW_BOTTOM*Menu_factor_Y,
        MC_Black);
  }
  selected_index=-1;
  while (1)
  {
    old_selected_index = selected_index;
    // Fenêtre grise
    Block(Window_pos_X+2*Menu_factor_X,
        Window_pos_Y+1*Menu_factor_Y,
        (Button->Dropdown_width-3)*Menu_factor_X,(box_height-2)*Menu_factor_Y,MC_Light);
    // Affichage des items
    for(item=Button->First_item,choice_index=0; item!=NULL; item=item->Next,choice_index++)
    {
      byte color_1;
      byte color_2;
      if (choice_index==selected_index)
      {
        color_1=MC_White;
        color_2=MC_Dark;
        Block(Window_pos_X+3*Menu_factor_X,
        Window_pos_Y+((2+choice_index*8)*Menu_factor_Y),
        (Button->Dropdown_width-5)*Menu_factor_X,(8)*Menu_factor_Y,MC_Dark);
      }
      else
      {
        color_1=MC_Black;
        color_2=MC_Light;
      }
      Print_in_window(3,2+choice_index*8,item->Label,color_1,color_2);
    }
    Update_rect(Window_pos_X,Window_pos_Y,Window_width*Menu_factor_X,Window_height*Menu_factor_Y);
    Display_cursor();
    do 
    {
      // Attente
      if(!Get_input()) SDL_Delay(20);
      // Mise à jour du survol
      selected_index=Window_click_in_rectangle(2,2,Button->Dropdown_width-2,box_height-1)?
        (((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2)>>3) : -1;
    } while (Mouse_K && selected_index==old_selected_index);
    
    if (!Mouse_K)
      break;
    Hide_cursor();
  }
  Close_popup();  
  Window_unselect_normal_button(Button->Pos_X,Button->Pos_Y,Button->Width,Button->Height);
  Display_cursor();
  if (selected_index>=0 && selected_indexFirst_item; selected_index; item=item->Next,selected_index--)
      ;
    Window_attribute2=item->Number;
    if (Button->Display_choice)
    {
      // Automatically update the label of the dropdown list.
      int text_length = (Button->Width-4-(Button->Display_arrow?8:0))/8;
      // Clear original label area
      Window_rectangle(Button->Pos_X+2,Button->Pos_Y+(Button->Height-7)/2,text_length*8,8,MC_Light);
      Print_in_window_limited(Button->Pos_X+2,Button->Pos_Y+(Button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light);
    }
    return Button->Number;
  }
  Window_attribute2=-1;
  return 0;
}
// --- Fonction de clic sur un bouton a peu près ordinaire:
// Attend que l'on relache le bouton, et renvoie le numero du bouton si on
// est resté dessus, 0 si on a annulé en sortant du bouton.
short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number)
{
  while(1)
  {
    Hide_cursor();
    Window_select_normal_button(x_pos,y_pos,width,height);
    Display_cursor();
    while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))
    {
      if(!Get_input()) SDL_Delay(20);
      if (!Mouse_K)
      {
        Hide_cursor();
        Window_unselect_normal_button(x_pos,y_pos,width,height);
        Display_cursor();
        return btn_number;
      }
    }
    Hide_cursor();
    Window_unselect_normal_button(x_pos,y_pos,width,height);
    Display_cursor();
    while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)))
    {
      if(!Get_input()) SDL_Delay(20);
      if (!Mouse_K)
        return 0;
    }
  }
}
// --- Returns the number of the clicked button (-1:out of the window, 0:none) ---
short Window_get_clicked_button(void)
{
  T_Normal_button   * temp1;
  T_Palette_button  * temp2;
  T_Scroller_button * temp3;
  T_Special_button  * temp4;
  T_Dropdown_button * temp5;
  long max_slider_height;
  Window_attribute1=Mouse_K;
  // Test click on normal buttons
  for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next)
  {
    if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number)
      && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1))
    {
      Input_sticky_control = temp1->Number;
      if (temp1->Repeatable)
      {
        Hide_cursor();
        Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height);
        Display_cursor();
        Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
        Hide_cursor();
        Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height);
        Display_cursor();        
        return temp1->Number;
      }
      return Window_normal_button_onclick(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height,temp1->Number);
    }
  }
  // Test click on "Palette" buttons
  for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next)
  {
    if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number)
      && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82))
    {
      Input_sticky_control = temp2->Number;
      // We store the clicked color in Attribute2
      Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 +
        (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5;
        return temp2->Number;
    }
  }
  // Test click oin slider/scroller bars
  for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next)
  {
    // Button Up arrow
    if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024))
      && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10))
    {
      Input_sticky_control = temp3->Number | 1024;
      Hide_cursor();
      Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11);
      if (temp3->Position)
      {
        temp3->Position--;
        Window_attribute1=1;
        Window_attribute2=temp3->Position;
        Window_draw_slider(temp3);
      }
      else
        Window_attribute1=0;
      
      Display_cursor();
      Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
      Hide_cursor();
      Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11);
      Display_cursor();
      
      return (Window_attribute1)? temp3->Number : 0;
    }
    
    // Button Down arrow
    if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048))
      && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-1))
    {
      Input_sticky_control = temp3->Number | 2048;
      Hide_cursor();
      Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11);
      if (temp3->Position+temp3->Nb_visiblesNb_elements)
      {
        temp3->Position++;
        Window_attribute1=2;
        Window_attribute2=temp3->Position;
        Window_draw_slider(temp3);
      }
      else
        Window_attribute1=0;
      Display_cursor();
      Slider_timer((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
      Hide_cursor();
      Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Height-11,11,11);
      Display_cursor();
      
      return (Window_attribute1)? temp3->Number : 0;
    }
    // Middle slider
    if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 &&
        Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Height-13)))
    {
      Input_sticky_control = temp3->Number;
      if (temp3->Nb_elements>temp3->Nb_visibles)
      {
        // If there is enough room to make the cursor move:
        max_slider_height=(temp3->Height-24);
        // Window_attribute2 receives the position of the cursor.
        Window_attribute2 =(Mouse_Y-Window_pos_Y) / Menu_factor_Y;
        Window_attribute2-=(temp3->Pos_Y+12+((temp3->Cursor_height-1)>>1));
        Window_attribute2*=(temp3->Nb_elements-temp3->Nb_visibles);
        if (Window_attribute2<0)
          Window_attribute2=0;
        else
        {
          Window_attribute2 =Round_div(Window_attribute2,max_slider_height-temp3->Cursor_height);
          if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements)
            Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles;
        }
        // If the cursor moved
        if (temp3->Position!=Window_attribute2)
        {
          temp3->Position=Window_attribute2;
          Window_attribute1=3;
          Hide_cursor();
          Window_draw_slider(temp3);
          Display_cursor();
        }
        else
          // If the cursor moved
          Window_attribute1=0;
      }
      else
        // If there's not enough room to make the cursor move:
        Window_attribute1=0;
        
      return (Window_attribute1)? temp3->Number : 0; 
    }
  }
  // Test click on a special button
  for (temp4=Window_special_button_list; temp4; temp4=temp4->Next)
  {
    if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number)
      && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1))
    {
       Input_sticky_control = temp4->Number;
       return temp4->Number;
    }
  }
  // Test click on a dropdown box
  for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next)
  {
    if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number)
     && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1))
    {
      Input_sticky_control = temp5->Number;
      if (Mouse_K & temp5->Active_button)
        return Window_dropdown_on_click(temp5);
      else
      {
        Window_attribute2=-1;
        return Window_normal_button_onclick(temp5->Pos_X,temp5->Pos_Y,temp5->Width,temp5->Height,temp5->Number);
      }
    }
  }
  return 0;
}
short Window_get_button_shortcut(void)
{
  T_Normal_button * temp;
  if (Key & MOD_SHIFT)
    Window_attribute1=RIGHT_SIDE;
  else
    Window_attribute1=LEFT_SIDE;
  // On fait une première recherche
  temp=Window_normal_button_list;
  while (temp!=NULL)
  {
    if (temp->Shortcut==Key)
    {
      Hide_cursor();
      Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height);
      Display_cursor();
      
      Slider_timer(Config.Delay_right_click_on_slider);
      
      Hide_cursor();
      Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height);
      Display_cursor();
      return temp->Number;
    }
    temp=temp->Next;
  }
  // Si la recherche n'a pas été fructueuse ET que l'utilisateur appuyait sur
  // , on regarde si un bouton ne pourrait pas réagir comme si 
  // n'était pas appuyé.
  if (Window_attribute1==RIGHT_SIDE)
  {
    temp=Window_normal_button_list;
    while (temp!=NULL)
    {
      if (temp->Shortcut==(Key&0x0FFF))
        return temp->Number;
      temp=temp->Next;
    }
  }
  
  // Handle arrow keys, end/home, and mouse wheel that have
  // a certain behavior if a list control is present.
  if (Window_list_button_list)
  {
    T_List_button *list = Window_list_button_list;
    // If there's more than one of such control, only capture
    // events if the mouse cursor is over it.
    if (list->Next)
    {
      // to do
    }
  
  
  
  
  
  
  }
  return 0;
}
short Window_clicked_button(void)
{
  short Button;
  if(!Get_input())SDL_Delay(20);
  // Handle clicks
  if (Mouse_K)
  {
    if ((Mouse_X=Window_pos_X+(Window_width*Menu_factor_X))
     || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)))
    {
      if (Input_sticky_control == 0 || Input_sticky_control == -1)
      {
        Input_sticky_control = -1;
        return -1;
      }
      else
      {
        return 0;
      }
    }
     
    if (!Input_sticky_control && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y))
    {
      Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y);
    }
    else
    {
      short clicked_button;
      T_List_button * list;
      
      // Check which controls was clicked (by rectangular area)
      clicked_button = Window_get_clicked_button();
      
      // Check if it's part of a list control
      for (list=Window_list_button_list; list!=NULL; list=list->Next)
      {
        if (list->Entry_button->Number == clicked_button)
        {
          // Click in the textual part of a list.
          short clicked_line;            
          clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3;
          if (clicked_line == list->Cursor_position ||   // Same as before
            clicked_line >= list->Scroller->Nb_elements) // Below last line              
            return 0;
          
          Hide_cursor();
          // Redraw one item as disabled
          if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles)
            list->Draw_list_item(
              list->Entry_button->Pos_X,
              list->Entry_button->Pos_Y + list->Cursor_position * 8,
              list->List_start + list->Cursor_position,
              0);
          list->Cursor_position = clicked_line;
          // Redraw one item as enabled
          if (list->Cursor_position>=0 && list->Cursor_positionScroller->Nb_visibles)
            list->Draw_list_item(
              list->Entry_button->Pos_X,
              list->Entry_button->Pos_Y + list->Cursor_position * 8,
              list->List_start + list->Cursor_position,
              1);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        else if (list->Scroller->Number == clicked_button)
        {
          // Click in the scroller part of a list
          if (list->List_start == list->Scroller->Position)
            return 0; // Didn't actually move
          // Update scroller indices
          list->Cursor_position += list->List_start;
          list->List_start = list->Scroller->Position;
          list->Cursor_position -= list->List_start;
          // Need to redraw all
          Hide_cursor();
          Window_redraw_list(list);
          Display_cursor();
        }
      }
      return clicked_button;
    }
  }
  // Intercept keys
  if (Key)
  {
    T_List_button * list;
    Button=Window_get_button_shortcut();
    if (Button)
    {
      Key=0;
      return Button;
    }
    // Check if there's a list control and the keys can control it
    for (list=Window_list_button_list; list!=NULL; list=list->Next)
    {
      // FIXME: Make only one list have the keyboard focus.
      if (1)
      {
        if (Key==SDLK_UP && (list->Cursor_position+list->List_start)>0)
        {
          Key=0;
          Hide_cursor();
          list->Cursor_position--;
          if (list->Cursor_position<0)
          {
            list->List_start=list->List_start+list->Cursor_position;
            list->Cursor_position=0;
            // Mise à jour du scroller
            list->Scroller->Position=list->List_start;
            Window_draw_slider(list->Scroller);
          }
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key==SDLK_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
        {
          Key=0;
          Hide_cursor();
          list->Cursor_position++;
          if (list->Cursor_position>(list->Scroller->Nb_visibles-1))
          {
            list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1);
            list->Cursor_position=(list->Scroller->Nb_visibles-1);
            // Mise à jour du scroller
            list->Scroller->Position=list->List_start;
            Window_draw_slider(list->Scroller);
          }
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key==SDLK_HOME && (list->Cursor_position!=0 || list->List_start!=0))
        {
          Key=0;
          Hide_cursor();
          list->Cursor_position=0;
          list->List_start=0;
          // Mise à jour du scroller
          list->Scroller->Position=list->List_start;
          Window_draw_slider(list->Scroller);
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key==SDLK_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
        {
          Key=0;
          Hide_cursor();
          list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start;
          if (list->Cursor_position>(list->Scroller->Nb_visibles-1))
          {
            list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1);
            list->Cursor_position=(list->Scroller->Nb_visibles-1);
            // Mise à jour du scroller
            list->Scroller->Position=list->List_start;
            Window_draw_slider(list->Scroller);
          }
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key==SDLK_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
        {
          Key=0;
          Hide_cursor();
          if (list->Scroller->Nb_elementsScroller->Nb_visibles)
          {
            list->Cursor_position=list->Scroller->Nb_elements-1;
          }
          else if(list->Cursor_position!=list->Scroller->Nb_visibles-1)
          {
            list->Cursor_position=list->Scroller->Nb_visibles-1;
          }
          else
          {
            list->List_start+=list->Scroller->Nb_visibles;
            if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements)
            {
              list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles;
            }
            // Mise à jour du scroller
            list->Scroller->Position=list->List_start;
            Window_draw_slider(list->Scroller);
          }
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key==SDLK_PAGEUP && (list->Cursor_position+list->List_start)>0)
        {
          Key=0;
          Hide_cursor();
          if(list->Cursor_position!=0)
          {
            list->Cursor_position=0;
          }
          else
          {
            list->List_start-=list->Scroller->Nb_visibles;
            if (list->List_start<0)
            {
              list->List_start=0;
            }
            // Mise à jour du scroller
            list->Scroller->Position=list->List_start;
            Window_draw_slider(list->Scroller);
          }
          Window_redraw_list(list);
          Display_cursor();
          // Store the selected value as attribute2
          Window_attribute2=list->List_start + list->Cursor_position;
          // Return the control ID of the list.
          return list->Number;
        }
        if (Key == KEY_MOUSEWHEELUP && list->List_start>0)
        {
          list->Cursor_position+=list->List_start;
          if (list->List_start>=3)
            list->List_start-=3;
          else
            list->List_start=0;
          list->Cursor_position-=list->List_start;
          // On affiche à nouveau la liste
          Hide_cursor();
          Window_redraw_list(list);
          // Mise à jour du scroller
          list->Scroller->Position=list->List_start;
          Window_draw_slider(list->Scroller);
          Display_cursor();
        }
        if (Key==KEY_MOUSEWHEELDOWN && list->List_startScroller->Nb_elements-list->Scroller->Nb_visibles)
        {
          list->Cursor_position+=list->List_start;
          list->List_start+=3;
          if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements)
          {
            list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles;
          }          
          list->Cursor_position-=list->List_start;
          // On affiche à nouveau la liste
          Hide_cursor();
          Window_redraw_list(list);
          // Mise à jour du scroller
          list->Scroller->Position=list->List_start;
          Window_draw_slider(list->Scroller);
          Display_cursor();
        }
      
      }
    }
  }
  return 0;
}
// Fonction qui sert à remapper les parties sauvegardées derriere les
// fenetres ouvertes. C'est utilisé par exemple par la fenetre de palette
// Qui remappe des couleurs, afin de propager les changements.
void Remap_window_backgrounds(byte * conversion_table, int Min_Y, int Max_Y)
{
  int window_index; 
        byte* EDI;
        int dx,cx;
  for (window_index=0; window_indexMax_Y)
            return;
          if (dx+Window_stack_pos_Y[window_index]0;cx--)
                {
                        *EDI = conversion_table[*EDI];
                        EDI ++;
                }
        }
  }
}