1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 /// @file engine.c: Window engine and interface management
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 
25 #ifdef _MSC_VER
26 #include <stdio.h>
27 #define strdup _strdup
28 #if _MSC_VER < 1900
29 #define snprintf _snprintf
30 #endif
31 #endif
32 
33 #include "const.h"
34 #include "struct.h"
35 #include "global.h"
36 #include "graph.h"
37 #include "misc.h"
38 #include "osdep.h"
39 #include "special.h"
40 #include "buttons.h"
41 #include "operatio.h"
42 #include "shade.h"
43 #include "errors.h"
44 #include "screen.h"
45 #include "windows.h"
46 #include "brush.h"
47 #include "input.h"
48 #include "engine.h"
49 #include "pages.h"
50 #include "layers.h"
51 #include "factory.h"
52 #include "loadsave.h"
53 #include "io.h"
54 #include "pxsimple.h"
55 #include "oldies.h"
56 #include "palette.h"
57 #include "unicode.h"
58 
59 #if defined(__GP2X__) || defined(__WIZ__) || defined(__CAANOO__) || defined(__SWITCH__)
60 // We don't want to underline the keyboard shortcuts as there is no keyboard
61 #define NO_KEYBOARD
62 #endif
63 
64 
65 // we need this as global
66 short Old_MX = -1;
67 short Old_MY = -1;
68 
69 //---------- Annuler les effets des modes de dessin (sauf la grille) ---------
70 
71 // Variables mémorisants les anciens effets
72 
73 byte Shade_mode_before_cancel;
74 byte Quick_shade_mode_before_cancel;
75 byte Stencil_mode_before_cancel;
76 byte Sieve_mode_before_cancel;
77 byte Colorize_mode_before_cancel;
78 byte Smooth_mode_before_cancel;
79 byte Tiling_mode_before_cancel;
80 Func_effect Effect_function_before_cancel;
81 
82 ///This table holds pointers to the saved window backgrounds. We can have up to 8 windows open at a time.
83 static byte* Window_background[8];
84 
85 ///Save a screen block (usually before erasing it with a new window or a dropdown menu)
Save_background(byte ** buffer,int x_pos,int y_pos,int width,int height)86 static void Save_background(byte **buffer, int x_pos, int y_pos, int width, int height)
87 {
88   int index;
89   if(*buffer != NULL)
90   {
91     GFX2_Log(GFX2_WARNING, "%s() WARNING : buffer already allocated !!!\n", __func__);
92     free(*buffer);
93   }
94   *buffer=(byte *) malloc(width*Menu_factor_X*height*Menu_factor_Y*Pixel_width);
95   if(*buffer==NULL)
96   {
97     Error(0);
98     return;
99   }
100   for (index=0; index<(height*Menu_factor_Y); index++)
101     Read_line(x_pos,y_pos+index,width*Menu_factor_X,(*buffer)+((int)index*width*Menu_factor_X*Pixel_width));
102 }
103 
104 ///Restores a screen block
Restore_background(byte ** buffer,int x_pos,int y_pos,int width,int height)105 static void Restore_background(byte **buffer, int x_pos, int y_pos, int width, int height)
106 {
107   int index;
108   if(*buffer==NULL) return;
109   for (index=0; index<height*Menu_factor_Y; index++)
110     Display_line_fast(x_pos,y_pos+index,width*Menu_factor_X,*buffer+((int)index*width*Menu_factor_X*Pixel_width));
111   free(*buffer);
112   *buffer = NULL;
113 }
114 
115 ///Draw a pixel in a saved screen block (when you sort colors in the palette, for example)
Pixel_background(int x_pos,int y_pos,byte color)116 void Pixel_background(int x_pos, int y_pos, byte color)
117 {
118   int x_repetition=Pixel_width;
119   while (x_repetition--)
120     (Window_background[0][x_pos*Pixel_width+x_repetition+y_pos*Window_width*Pixel_width*Menu_factor_X])=color;
121 }
122 
123 
124 ///Guess the number of the button that was just clicked
Button_under_mouse(void)125 int Button_under_mouse(void)
126 {
127   int btn_number;
128   short x_pos;
129   short y_pos;
130   byte current_menu;
131   byte first_button;
132 
133   x_pos = Mouse_X / Menu_factor_X;
134 
135   // Find in which menubar we are
136   for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu ++)
137   {
138     if (Menu_bars[current_menu].Visible)
139     {
140       if (Mouse_Y >= Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top) &&
141       Mouse_Y < Menu_Y+Menu_factor_Y*(Menu_bars[current_menu].Top + Menu_bars[current_menu].Height))
142         break;
143     }
144   }
145   if (current_menu==MENUBAR_COUNT)
146     return -1;
147 
148   y_pos=(Mouse_Y - Menu_Y)/Menu_factor_Y - Menu_bars[current_menu].Top;
149 
150   if (current_menu == 0) first_button = 0;
151   else first_button = Menu_bars[current_menu - 1].Last_button_index + 1;
152 
153   for (btn_number=first_button;btn_number<=Menu_bars[current_menu].Last_button_index;btn_number++)
154   {
155     switch(Buttons_Pool[btn_number].Shape)
156     {
157       case BUTTON_SHAPE_NO_FRAME :
158       case BUTTON_SHAPE_RECTANGLE  :
159 
160         if ((x_pos>=Buttons_Pool[btn_number].X_offset) &&
161             (y_pos>=Buttons_Pool[btn_number].Y_offset) &&
162             (x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) &&
163             (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height))
164           return btn_number;
165         break;
166 
167       case BUTTON_SHAPE_TRIANGLE_TOP_LEFT:
168         if ((x_pos>=Buttons_Pool[btn_number].X_offset) &&
169             (y_pos>=Buttons_Pool[btn_number].Y_offset) &&
170             (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset<=Buttons_Pool[btn_number].Width))
171           return btn_number;
172         break;
173 
174       case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT:
175         if ((x_pos<=Buttons_Pool[btn_number].X_offset+Buttons_Pool[btn_number].Width) &&
176             (y_pos<=Buttons_Pool[btn_number].Y_offset+Buttons_Pool[btn_number].Height) &&
177             (x_pos+y_pos-(short)Buttons_Pool[btn_number].Y_offset-(short)Buttons_Pool[btn_number].X_offset>=Buttons_Pool[btn_number].Width))
178           return btn_number;
179         break;
180     }
181   }
182   return -1;
183 }
184 
185 
186 ///Draw a menu button, selected or not
Draw_menu_button(byte btn_number,byte pressed)187 void Draw_menu_button(byte btn_number,byte pressed)
188 {
189   word start_x;
190   word start_y;
191   word width;
192   word height;
193   byte * bitmap;
194   word bitmap_width;
195   word x_pos;
196   word y_pos;
197   byte current_menu;
198   byte color;
199   signed char icon;
200 
201   // Find in which menu the button is
202   for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++)
203   {
204     // We found the right bar !
205     if (Menu_bars[current_menu].Last_button_index >= btn_number &&
206     (current_menu==0 || Menu_bars[current_menu -1].Last_button_index < btn_number))
207     {
208       break;
209     }
210   }
211 
212   start_x = Buttons_Pool[btn_number].X_offset;
213   start_y = Buttons_Pool[btn_number].Y_offset;
214   width = Buttons_Pool[btn_number].Width+1;
215   height = Buttons_Pool[btn_number].Height+1;
216   icon = Buttons_Pool[btn_number].Icon;
217 
218   if (icon==-1)
219   {
220     // Standard button
221     bitmap_width = Menu_bars[current_menu].Skin_width;
222     bitmap=&(Menu_bars[current_menu].Skin[pressed][start_y*Menu_bars[current_menu].Skin_width+start_x]);
223   }
224   else
225   {
226     // From Menu_buttons
227     bitmap_width = MENU_SPRITE_WIDTH;
228     bitmap=Gfx->Menu_sprite[pressed][(byte)icon][0];
229     // For bottom right: offset +1,+1
230     if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT)
231       bitmap += MENU_SPRITE_WIDTH+1;
232   }
233 
234   switch(Buttons_Pool[btn_number].Shape)
235   {
236     case BUTTON_SHAPE_NO_FRAME :
237       break;
238     case BUTTON_SHAPE_RECTANGLE  :
239     for (y_pos=0;y_pos<height;y_pos++)
240       for (x_pos=0;x_pos<width;x_pos++)
241       {
242         color=bitmap[x_pos+y_pos*bitmap_width];
243         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, start_y+y_pos, color);
244       }
245     break;
246     case BUTTON_SHAPE_TRIANGLE_TOP_LEFT:
247     for (y_pos=0;y_pos<15;y_pos++)
248       for (x_pos=0;x_pos<15-y_pos;x_pos++)
249       {
250         color=bitmap[x_pos+y_pos*bitmap_width];
251         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, start_y+y_pos, color);
252       }
253     break;
254     case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT:
255     for (y_pos=0;y_pos<15;y_pos++)
256       for (x_pos=14-y_pos;x_pos<15;x_pos++)
257       {
258         color=bitmap[(x_pos)+(y_pos)*bitmap_width];
259         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, start_y+y_pos, color);
260       }
261     break;
262   }
263   // Special: Show specific shape
264   if (btn_number==BUTTON_PAINTBRUSHES
265     && Paintbrush_shape!=PAINTBRUSH_SHAPE_COLOR_BRUSH
266     && Paintbrush_shape!=PAINTBRUSH_SHAPE_MONO_BRUSH)
267   {
268     short x_pos,y_pos;
269     short start_x;
270     short menu_x_pos,menu_y_pos;
271     short menu_start_x;
272 
273     // Print paintbrush shape
274     menu_start_x=8-Paintbrush_offset_X;
275     if (menu_start_x<1)
276     {
277       start_x=Paintbrush_offset_X-7;
278       menu_start_x=1;
279     }
280     else
281       start_x=0;
282 
283     menu_y_pos=9-Paintbrush_offset_Y;
284     if (menu_y_pos<2)
285     {
286       y_pos=Paintbrush_offset_Y-7;
287       menu_y_pos=2;
288     }
289     else
290       y_pos=0;
291 
292     for (;((y_pos<Paintbrush_height) && (menu_y_pos<16));menu_y_pos++,y_pos++)
293       for (menu_x_pos=menu_start_x,x_pos=start_x;((x_pos<Paintbrush_width) && (menu_x_pos<15));menu_x_pos++,x_pos++)
294       {
295         if (Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos])
296         Pixel_in_menu_and_skin(MENUBAR_TOOLS, menu_x_pos, menu_y_pos, MC_Black);
297       }
298   }
299 
300   if (Menu_is_visible && Menu_bars[current_menu].Visible)
301     Update_rect(Menu_factor_X*(Buttons_Pool[btn_number].X_offset),
302       (Buttons_Pool[btn_number].Y_offset+Menu_bars[current_menu].Top)*Menu_factor_Y+Menu_Y,
303       width*Menu_factor_X,height*Menu_factor_Y);
304 
305 /*
306   switch (pressed)
307   {
308     default:
309     case BUTTON_RELEASED:
310     color_top_left=MC_White;
311     color_bottom_right=MC_Dark;
312     color_diagonal=MC_Light;
313     break;
314 
315     case BUTTON_PRESSED:
316     color_top_left=MC_Dark;
317     color_bottom_right=MC_Black;
318     color_diagonal=MC_Black;
319     break;
320   }
321 
322   switch(Buttons_Pool[btn_number].Shape)
323   {
324     case BUTTON_SHAPE_NO_FRAME :
325       break;
326     case BUTTON_SHAPE_RECTANGLE  :
327       // On colorie le point haut droit
328       Pixel_in_menu_and_skin(current_menu, end_x, start_y, color_diagonal);
329       // On colorie le point bas gauche
330       Pixel_in_menu_and_skin(current_menu, start_x, end_y, color_diagonal);
331       // On colorie la partie haute
332       for (x_pos=start_x;x_pos<=end_x-1;x_pos++)
333       {
334         Pixel_in_menu_and_skin(current_menu, x_pos, start_y, color_top_left);
335       }
336       for (y_pos=start_y+1;y_pos<=end_y-1;y_pos++)
337       {
338         // On colorie la partie gauche
339         Pixel_in_menu_and_skin(current_menu, start_x, y_pos, color_top_left);
340         // On colorie la partie droite
341         Pixel_in_menu_and_skin(current_menu, end_x, y_pos, color_bottom_right);
342       }
343       // On colorie la partie basse
344       for (x_pos=start_x+1;x_pos<=end_x;x_pos++)
345       {
346         Pixel_in_menu_and_skin(current_menu, x_pos, end_y, color_bottom_right);
347       }
348       break;
349     case BUTTON_SHAPE_TRIANGLE_TOP_LEFT:
350       // On colorie le point haut droit
351       Pixel_in_menu_and_skin(current_menu, end_x, start_y, color_top_left);
352       // On colorie le point bas gauche
353       Pixel_in_menu_and_skin(current_menu, start_x, end_y, color_top_left);
354       // On colorie le coin haut gauche
355       for (x_pos=0;x_pos<Buttons_Pool[btn_number].Width;x_pos++)
356       {
357         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, start_y, color_top_left);
358         Pixel_in_menu_and_skin(current_menu, start_x, start_y+x_pos, color_top_left);
359       }
360       // On colorie la diagonale
361       for (x_pos=1;x_pos<Buttons_Pool[btn_number].Width;x_pos++)
362       {
363         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, end_y-x_pos, color_bottom_right);
364       }
365       break;
366     case BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT:
367       // On colorie le point haut droit
368       Pixel_in_menu_and_skin(current_menu, end_x, start_y, color_diagonal);
369       // On colorie le point bas gauche
370       Pixel_in_menu_and_skin(current_menu, start_x, end_y, color_diagonal);
371       // On colorie la diagonale
372       for (x_pos=1;x_pos<Buttons_Pool[btn_number].Width;x_pos++)
373       {
374         Pixel_in_menu_and_skin(current_menu, start_x+x_pos, end_y-x_pos, color_top_left);
375       }
376       // On colorie le coin bas droite
377       for (x_pos=0;x_pos<Buttons_Pool[btn_number].Width;x_pos++)
378       {
379         Pixel_in_menu_and_skin(current_menu, end_x-x_pos, end_y, color_bottom_right);
380         Pixel_in_menu_and_skin(current_menu, end_x, end_y-x_pos, color_bottom_right);
381       }
382   }
383   if (Menu_is_visible && Menu_bars[current_menu].Visible)
384   {
385     Update_rect(
386       start_x*Menu_factor_X,
387       (start_y+Menu_bars[current_menu].Top)*Menu_factor_Y + Menu_Y,
388       (end_x+1-start_x)*Menu_factor_X,
389       (end_y+1-start_y)*Menu_factor_Y);
390   }
391   */
392 }
393 
394 
395 ///Deselect a button
Unselect_button(int btn_number)396 void Unselect_button(int btn_number)
397 {
398   if (btn_number < 0 || btn_number >= NB_BUTTONS)
399     return;
400   if (Buttons_Pool[btn_number].Pressed)
401   {
402     // On considère que le bouton est relâché
403     Buttons_Pool[btn_number].Pressed=BUTTON_RELEASED;
404     // On affiche le cadre autour du bouton de façon à ce qu'il paraisse relâché
405     Draw_menu_button(btn_number,BUTTON_RELEASED);
406     // On appelle le désenclenchement particulier au bouton:
407     Buttons_Pool[btn_number].Unselect_action(btn_number);
408   }
409 }
410 
411 
412 ///Select a button and disable all his family (for example, selecting "freehand" unselect "curves", "lines", ...)
Select_button(int btn_number,byte click)413 void Select_button(int btn_number,byte click)
414 {
415   int family;
416   int b;
417   int icon;
418 
419   Hide_cursor();
420 
421   // Certains boutons ont deux icones
422   icon=-1;
423   switch(btn_number)
424   {
425     case BUTTON_POLYGONS:
426     case BUTTON_POLYFILL:
427       icon=MENU_SPRITE_POLYFORM;
428       break;
429     case BUTTON_FLOODFILL:
430       icon=MENU_SPRITE_REPLACE;
431       break;
432   }
433   if (icon!=-1)
434   {
435     // This changes the sprite number of both halves of a split button
436     Display_sprite_in_menu(btn_number,click==RIGHT_SIDE?icon:-1);
437 
438     // Redraw the other half if Unselect_button() won't do it.
439     if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_TOP_LEFT &&
440       !Buttons_Pool[btn_number+1].Pressed)
441       Draw_menu_button(btn_number+1, BUTTON_RELEASED);
442     else if (Buttons_Pool[btn_number].Shape==BUTTON_SHAPE_TRIANGLE_BOTTOM_RIGHT &&
443       !Buttons_Pool[btn_number-1].Pressed)
444       Draw_menu_button(btn_number-1, BUTTON_RELEASED);
445   }
446 
447   // On note déjà la famille du bouton (La "Famiglia" c'est sacré)
448   family=Buttons_Pool[btn_number].Family;
449 
450   switch (family)
451   {
452     case FAMILY_TOOLBAR: // On ne fait rien (on préserve les interruptions)
453       break;
454 
455     case FAMILY_INTERRUPTION: // Petit cas spécial dans la famille "Interruption":
456       if ((btn_number!=BUTTON_MAGNIFIER) || (!Main.magnifier_mode))
457       // Pour chaque bouton:
458       for (b=0; b<NB_BUTTONS; b++)
459         // S'il est de la même famille
460         if (
461              (b!=btn_number) &&
462              (Buttons_Pool[b].Family==FAMILY_INTERRUPTION) &&
463              (  (b!=BUTTON_MAGNIFIER) ||
464                ((b==BUTTON_MAGNIFIER) && (!Main.magnifier_mode)) )
465            )
466           // Alors on désenclenche le bouton
467           Unselect_button(b);
468       break;
469 
470     default:
471       // On désenclenche D'ABORD les interruptions
472       // Pour chaque bouton:
473       for (b=0; b<NB_BUTTONS; b++)
474         // S'il est de la famille interruption
475         if ( (b!=btn_number)
476           && (Buttons_Pool[b].Family==FAMILY_INTERRUPTION)
477           // Et que ce n'est pas la loupe, ou alors qu'on n'est pas en mode loupe
478           && (!(Main.magnifier_mode && (b==BUTTON_MAGNIFIER))) )
479           // Alors on désenclenche le bouton
480           Unselect_button(b);
481       // Right-clicking on Adjust opens a menu, so in this case we skip
482       // the unselection of all "Tool" buttons.
483       if (btn_number==BUTTON_ADJUST && click==RIGHT_SIDE)
484         break;
485       // Same case with the Grad. Rectangle button.
486       if (btn_number==BUTTON_GRADRECT && click==RIGHT_SIDE)
487         break;
488       // Pour chaque bouton:
489       for (b=0; b<NB_BUTTONS; b++)
490         // S'il est de la même famille
491         if ( (b!=btn_number)
492           && (Buttons_Pool[b].Family==family) )
493           // Alors on désenclenche le bouton
494           Unselect_button(b);
495   }
496 
497   // On considère que le bouton est enfoncé
498   Buttons_Pool[btn_number].Pressed=BUTTON_PRESSED;
499 
500   // On affiche le cadre autour du bouton de façon à ce qu'il paraisse enfoncé
501   Draw_menu_button(btn_number, BUTTON_PRESSED);
502 
503   Display_cursor();
504 
505   if ((click==1 && !Buttons_Pool[btn_number].Left_instant)
506     ||(click!=1 && !Buttons_Pool[btn_number].Right_instant))
507   {
508     // On attend ensuite que l'utilisateur lâche son bouton:
509     Wait_end_of_click();
510   }
511 
512   // Puis on se contente d'appeler l'action correspondant au bouton:
513   if (click==1)
514     Buttons_Pool[btn_number].Left_action(btn_number);
515   else
516     Buttons_Pool[btn_number].Right_action(btn_number);
517 }
518 
519 
520 ///Moves the splitbar between zoom and standard views
Move_separator(void)521 void Move_separator(void)
522 {
523   short old_main_separator_position=Main.separator_position;
524   short old_x_zoom=Main.X_zoom;
525   short offset=Main.X_zoom-Mouse_X;
526   byte  old_cursor_shape=Cursor_shape;
527   short old_mouse_x=-1;
528 
529   // Afficher la barre en XOR
530   Hide_cursor();
531   Windows_open=1;
532   Cursor_shape=CURSOR_SHAPE_HORIZONTAL;
533   Vertical_XOR_line(Main.separator_position,0,Menu_Y);
534   Vertical_XOR_line(Main.X_zoom-1,0,Menu_Y);
535   Display_cursor();
536   Update_rect(Main.separator_position,0,abs(Main.separator_position-Main.X_zoom)+1,Menu_Y);
537 
538   while (Mouse_K)
539   {
540     if (Mouse_X!=old_mouse_x)
541     {
542       old_mouse_x=Mouse_X;
543       Main.separator_proportion=(float)(Mouse_X+offset)/Screen_width;
544       Compute_separator_data();
545 
546       if (Main.X_zoom!=old_x_zoom)
547       {
548         Hide_cursor();
549 
550         // Effacer la barre en XOR
551         Vertical_XOR_line(old_main_separator_position,0,Menu_Y);
552         Vertical_XOR_line(old_x_zoom-1,0,Menu_Y);
553 
554         Update_rect(old_main_separator_position,0,abs(old_main_separator_position-old_x_zoom)+1,Menu_Y);
555 
556         old_main_separator_position=Main.separator_position;
557         old_x_zoom=Main.X_zoom;
558 
559         // Rafficher la barre en XOR
560         Vertical_XOR_line(Main.separator_position,0,Menu_Y);
561         Vertical_XOR_line(Main.X_zoom-1,0,Menu_Y);
562 
563         Update_rect(Main.separator_position,0,abs(Main.separator_position-Main.X_zoom)+1,Menu_Y);
564 
565         Display_cursor();
566       }
567     }
568     Get_input(20);
569   }
570 
571   // Effacer la barre en XOR
572   Hide_cursor();
573   Vertical_XOR_line(Main.separator_position,0,Menu_Y);
574   Vertical_XOR_line(Main.X_zoom-1,0,Menu_Y);
575   Windows_open=0;
576   Cursor_shape=old_cursor_shape;
577   Compute_magnifier_data();
578   Position_screen_according_to_zoom();
579   Compute_limits();
580   Display_all_screen();
581   Display_cursor();
582 }
583 
584 ///
585 /// Updates the status bar line with a color number.
586 /// Used when hovering the menu palette.
Status_print_palette_color(byte color)587 void Status_print_palette_color(byte color)
588 {
589   char str[25];
590   int i;
591 
592   i = snprintf(str, sizeof(str), "%s%d (%d,%d,%d)",
593            Buttons_Pool[BUTTON_CHOOSE_COL].Tooltip, color,
594            Encode_component(Main.palette[color].R),
595            Encode_component(Main.palette[color].G),
596            Encode_component(Main.palette[color].B));
597   // Pad spaces
598   while(i<24)
599     str[i++]=' ';
600   str[24]='\0';
601 
602   Print_in_menu(str,0);
603 }
604 
605 /// activate layer preview
Layer_preview_on(int * preview_is_visible)606 static void Layer_preview_on(int * preview_is_visible)
607 {
608   int x,y;
609   short layer;
610   short layercount = Main.backups->Pages->Nb_layers;
611   int previewW, previewH;
612 
613   if (! *preview_is_visible && layercount>1)
614   {
615     previewW = Min(Main.image_width/Menu_factor_X, Layer_button_width);
616     previewH = previewW * Main.image_height / Main.image_width * Menu_factor_X / Menu_factor_Y;
617     if (previewH > Screen_height/4)
618     {
619       previewH = Screen_height/4;
620       previewW = Main.image_width * previewH / Main.image_height * Menu_factor_Y / Menu_factor_X;
621     }
622 
623     Open_popup((Buttons_Pool[BUTTON_LAYER_SELECT].X_offset + 2) * Menu_factor_X,
624                Menu_Y - previewH * Menu_factor_Y,
625                Buttons_Pool[BUTTON_LAYER_SELECT].Width, previewH);
626     *preview_is_visible = 1;
627 
628     // Make the system think the menu is visible (Open_popup hides it)
629     // so Button_under_mouse still works
630     Menu_is_visible = Menu_is_visible_before_window;
631     Menu_Y = Menu_Y_before_window;
632 
633     Window_rectangle(0, 0, Window_width, Window_height, MC_Dark);
634 
635     for(layer = 0; layer < layercount; ++layer)
636     {
637       int offset;
638       // Stop if the window is too small to show the
639       // layer button (ex: 320x200 can only display 12 layers)
640       if (layer * Layer_button_width + previewW > Window_width)
641         break;
642 
643       offset = (Layer_button_width - previewW) / 2;
644       for (y = 0; y < previewH*Pixel_height*Menu_factor_Y-1; y++)
645       for (x = 0; x < previewW*Pixel_width*Menu_factor_X-1; x++)
646       {
647         int imgx = x * Main.image_width / (previewW*Pixel_width*Menu_factor_X-1);
648         int imgy = y * Main.image_height / (previewH*Pixel_height*Menu_factor_Y-1);
649         // Use Pixel_simple() in order to get highest resolution
650         Pixel_simple(x + ((layer*Layer_button_width+offset)*Menu_factor_X + Window_pos_X) * Pixel_width,
651                      y + Window_pos_Y*Pixel_height + 1,
652                      Read_pixel_from_layer(layer, imgx, imgy) );
653       }
654     }
655     Update_window_area(0, 0, Window_width, Window_height);
656   }
657 }
658 
Layer_preview_off(int * preview_is_visible)659 void Layer_preview_off(int * preview_is_visible)
660 {
661   if (*preview_is_visible)
662   {
663     int x = Mouse_K;
664     Close_popup();
665     Display_cursor();
666     Mouse_K = x; // Close_popup waits for end of click and resets Mouse_K...
667     *preview_is_visible = 0;
668   }
669 }
670 
671 ///Main handler for everything. This is the main loop of the program
Main_handler(void)672 void Main_handler(void)
673 {
674   static byte temp_color;
675   int  button_index;           // Numéro de bouton de menu en cours
676   int  prev_button_number=0; // Numéro de bouton de menu sur lequel on était précédemment
677   byte blink;                   // L'opération demande un effacement du curseur
678   int  key_index;           // index du tableau de touches spéciales correspondant à la touche enfoncée
679   byte temp;
680   byte effect_modified;
681   byte action;
682   dword key_pressed;
683 
684   int preview_is_visible=0;
685   // This is used for the layer preview
686 
687   do
688   {
689     // Resize requested
690     if (Resize_width || Resize_height)
691     {
692       if (Window_state == GFX2_WINDOW_STANDARD)
693       {
694         Default_window_width = Resize_width;
695         Default_window_height = Resize_height;
696       }
697 
698       Hide_cursor();
699       Init_mode_video(Resize_width, Resize_height, 0, Pixel_ratio);
700       // Reset the variables that indicate a resize was requested.
701       Display_menu();
702       Reposition_palette();
703       Display_all_screen();
704       Display_cursor();
705     }
706     else if (Drop_file_name)
707     {
708       // A file was dragged into Grafx2's window
709       if (Main.image_is_modified && !Confirmation_box("Discard unsaved changes ?"))
710       {
711         // do nothing
712       }
713       else
714       {
715         T_IO_Context context;
716         char* flimit;
717         byte old_cursor_shape;
718 
719         flimit = Find_last_separator(Drop_file_name);
720         if (flimit != NULL)
721         {
722           *(flimit++) = '\0';
723 
724           Upload_infos_page(&Main);
725 
726           Hide_cursor();
727           old_cursor_shape=Cursor_shape;
728           Cursor_shape=CURSOR_SHAPE_HOURGLASS;
729           Display_cursor();
730 
731           Init_context_layered_image(&context, flimit, Drop_file_name);
732           if (Drop_file_name_unicode != NULL)
733           {
734             word * file_name_unicode = Find_last_separator_unicode(Drop_file_name_unicode);
735             if (file_name_unicode != NULL)
736               context.File_name_unicode = Unicode_strdup(file_name_unicode + 1);
737             else
738               context.File_name_unicode = Unicode_strdup(Drop_file_name_unicode);
739           }
740           Load_image(&context);
741           if (File_error!=1)
742           {
743             Compute_limits();
744             Compute_paintbrush_coordinates();
745             Redraw_layered_image();
746             End_of_modification();
747             Main.image_is_modified=0;
748           }
749           Destroy_context(&context);
750 
751           Compute_optimal_menu_colors(Main.palette);
752           Check_menu_mode();
753           Display_menu();
754           if (Config.Display_image_limits)
755             Display_image_limits();
756 
757           Hide_cursor();
758           Cursor_shape=old_cursor_shape;
759           Display_all_screen();
760           Display_cursor();
761         }
762       }
763       free(Drop_file_name);
764       Drop_file_name=NULL;
765       free(Drop_file_name_unicode);
766       Drop_file_name_unicode=NULL;
767     }
768 
769     if(Get_input(0))
770     {
771       action = 0;
772 
773       // Inhibit all keys if a drawing operation is in progress.
774       // We make an exception for the freehand operations, but these will
775       // only accept a very limited number of shortcuts.
776       if (Operation_stack_size!=0 && !Allow_color_change_during_operation)
777         Key=0;
778 
779       // Evenement de fermeture
780       if (Quit_is_required)
781       {
782         Quit_is_required=0;
783         Button_Quit(BUTTON_QUIT);
784       }
785 
786       if (Pan_shortcut_pressed && Current_operation!=OPERATION_PAN_VIEW && Operation_stack_size==0)
787       {
788         Hide_cursor();
789         Start_operation_stack(OPERATION_PAN_VIEW);
790         Display_cursor();
791         action++;
792       }
793       else if (Key == SHORTCUT_PASTE) /// @todo create a SPECIAL_ACTIONS for Copy and Paste ?
794       {
795         // simulate loading of Brush
796         T_IO_Context brush_context;
797         Init_context_brush(&brush_context, NULL, NULL);
798         brush_context.Format = FORMAT_CLIPBOARD;
799         Load_image(&brush_context);
800         if (File_error == 0)
801         {
802           free(Brush_filename);
803           Brush_filename = strdup("NO_NAME.GIF");
804           free(Brush_filename_unicode);
805           Brush_filename_unicode = NULL;
806           Brush_fileformat = FORMAT_GIF;
807 
808           Tiling_offset_X=0;
809           Tiling_offset_Y=0;
810 
811           Brush_offset_X=(Brush_width>>1);
812           Brush_offset_Y=(Brush_height>>1);
813 
814           Select_button(BUTTON_DRAW,LEFT_SIDE);
815           if (Config.Auto_discontinuous)
816           {
817             // On se place en mode Dessin discontinu à la main
818             while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
819               Select_button(BUTTON_DRAW,RIGHT_SIDE);
820           }
821           Hide_cursor();
822           // On passe en brosse couleur:
823           Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
824         }
825         Destroy_context(&brush_context);
826       }
827       else if (Key == SHORTCUT_COPY)
828       {
829         if (Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH && Brush != NULL)
830         {
831           // simulate saving of Brush
832           T_IO_Context brush_context;
833           Init_context_brush(&brush_context, NULL, NULL);
834           brush_context.Format = FORMAT_CLIPBOARD;
835           Save_image(&brush_context);
836           Destroy_context(&brush_context);
837         }
838         else
839         {
840           // save whole image to clipboard
841           T_IO_Context image_context;
842           Init_context_layered_image(&image_context, NULL, NULL);
843           image_context.Format = FORMAT_CLIPBOARD;
844           Save_image(&image_context);
845           Destroy_context(&image_context);
846         }
847       }
848       else if (Key)
849       {
850         effect_modified = 0;
851 
852         for (key_index=SPECIAL_CLICK_RIGHT+1;key_index<NB_SPECIAL_SHORTCUTS;key_index++)
853         {
854           if (Is_shortcut(Key,key_index))
855           {
856             Layer_preview_off(&preview_is_visible);
857 
858             // Special keys (functions not hooked to a UI button)
859             switch(key_index)
860             {
861               case SPECIAL_NEXT_FORECOLOR : // Next foreground color
862                 Special_next_forecolor();
863                 action++;
864                 break;
865               case SPECIAL_PREVIOUS_FORECOLOR : // Previous foreground color
866                 Special_previous_forecolor();
867                 action++;
868                 break;
869               case SPECIAL_NEXT_BACKCOLOR : // Next background color
870                 Special_next_backcolor();
871                 action++;
872                 break;
873               case SPECIAL_PREVIOUS_BACKCOLOR : // Previous background color
874                 Special_previous_backcolor();
875                 action++;
876                 break;
877               case SPECIAL_SMALLER_PAINTBRUSH: // Rétrécir le pinceau
878                 Smaller_paintbrush();
879                 action++;
880                 break;
881               case SPECIAL_BIGGER_PAINTBRUSH: // Grossir le pinceau
882                 Bigger_paintbrush();
883                 action++;
884                 break;
885               case SPECIAL_NEXT_USER_FORECOLOR : // Next user-defined foreground color
886                 Special_next_user_forecolor();
887                 action++;
888                 break;
889               case SPECIAL_PREVIOUS_USER_FORECOLOR : // Previous user-defined foreground color
890                 Special_previous_user_forecolor();
891                 action++;
892                 break;
893               case SPECIAL_NEXT_USER_BACKCOLOR : // Next user-defined background color
894                 Special_next_user_backcolor();
895                 action++;
896                 break;
897               case SPECIAL_PREVIOUS_USER_BACKCOLOR : // Previous user-defined background color
898                 Special_previous_user_backcolor();
899                 action++;
900                 break;
901             }
902 
903             // Other shortcuts are forbidden while an operation is in progress
904             if (Operation_stack_size!=0)
905               continue;
906 
907             switch (key_index)
908             {
909               case SPECIAL_SCROLL_UP : // Scroll up
910                 if (Main.magnifier_mode)
911                   Scroll_magnifier(0,-(Main.magnifier_height>>2));
912                 else
913                   Scroll_screen(0,-(Screen_height>>3));
914                 action++;
915                 break;
916               case SPECIAL_SCROLL_DOWN : // Scroll down
917                 if (Main.magnifier_mode)
918                   Scroll_magnifier(0,(Main.magnifier_height>>2));
919                 else
920                   Scroll_screen(0,(Screen_height>>3));
921                 action++;
922                 break;
923               case SPECIAL_SCROLL_LEFT : // Scroll left
924                 if (Main.magnifier_mode)
925                   Scroll_magnifier(-(Main.magnifier_width>>2),0);
926                 else
927                   Scroll_screen(-(Screen_width>>3),0);
928                 action++;
929                 break;
930               case SPECIAL_SCROLL_RIGHT : // Scroll right
931                 if (Main.magnifier_mode)
932                   Scroll_magnifier((Main.magnifier_width>>2),0);
933                 else
934                   Scroll_screen((Screen_width>>3),0);
935                 action++;
936                 break;
937               case SPECIAL_SCROLL_UP_FAST : // Scroll up faster
938                 if (Main.magnifier_mode)
939                   Scroll_magnifier(0,-(Main.magnifier_height>>1));
940                 else
941                   Scroll_screen(0,-(Screen_height>>2));
942                 action++;
943                 break;
944               case SPECIAL_SCROLL_DOWN_FAST : // Scroll down faster
945                 if (Main.magnifier_mode)
946                   Scroll_magnifier(0,(Main.magnifier_height>>1));
947                 else
948                   Scroll_screen(0,(Screen_height>>2));
949                 action++;
950                 break;
951               case SPECIAL_SCROLL_LEFT_FAST : // Scroll left faster
952                 if (Main.magnifier_mode)
953                   Scroll_magnifier(-(Main.magnifier_width>>1),0);
954                 else
955                   Scroll_screen(-(Screen_width>>2),0);
956                 action++;
957                 break;
958               case SPECIAL_SCROLL_RIGHT_FAST : // Scroll right faster
959                 if (Main.magnifier_mode)
960                   Scroll_magnifier((Main.magnifier_width>>1),0);
961                 else
962                   Scroll_screen((Screen_width>>2),0);
963                 action++;
964                 break;
965               case SPECIAL_SCROLL_UP_SLOW : // Scroll up slower
966                 if (Main.magnifier_mode)
967                   Scroll_magnifier(0,-1);
968                 else
969                   Scroll_screen(0,-1);
970                 action++;
971                 break;
972               case SPECIAL_SCROLL_DOWN_SLOW : // Scroll down slower
973                 if (Main.magnifier_mode)
974                   Scroll_magnifier(0,1);
975                 else
976                   Scroll_screen(0,1);
977                 action++;
978                 break;
979               case SPECIAL_SCROLL_LEFT_SLOW : // Scroll left slower
980                 if (Main.magnifier_mode)
981                   Scroll_magnifier(-1,0);
982                 else
983                   Scroll_screen(-1,0);
984                 action++;
985                 break;
986               case SPECIAL_SCROLL_RIGHT_SLOW : // Scroll right slower
987                 if (Main.magnifier_mode)
988                   Scroll_magnifier(1,0);
989                 else
990                   Scroll_screen(1,0);
991                 action++;
992                 break;
993               case SPECIAL_SHOW_HIDE_CURSOR : // Show / Hide cursor
994                 Hide_cursor();
995                 Cursor_hidden=!Cursor_hidden;
996                 Display_cursor();
997                 action++;
998                 break;
999               case SPECIAL_DOT_PAINTBRUSH : // Paintbrush = "."
1000                 Hide_cursor();
1001                 Paintbrush_shape=PAINTBRUSH_SHAPE_ROUND;
1002                 Set_paintbrush_size(1,1);
1003                 Change_paintbrush_shape(PAINTBRUSH_SHAPE_ROUND);
1004                 Display_cursor();
1005                 action++;
1006                 break;
1007               case SPECIAL_CONTINUOUS_DRAW : // Continuous freehand drawing
1008                 Select_button(BUTTON_DRAW,LEFT_SIDE);
1009                 // ATTENTION CE TRUC EST MOCHE ET VA MERDER SI ON SE MET A UTILISER DES BOUTONS POPUPS
1010                 while (Current_operation!=OPERATION_CONTINUOUS_DRAW)
1011                   Select_button(BUTTON_DRAW,RIGHT_SIDE);
1012                 action++;
1013                 break;
1014               case SPECIAL_FLIP_X : // Flip X
1015                 Hide_cursor();
1016                 Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
1017                 // Remap according to the last used remap table
1018                 Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
1019                 Display_cursor();
1020                 action++;
1021                 break;
1022               case SPECIAL_FLIP_Y : // Flip Y
1023                 Hide_cursor();
1024                 Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
1025                 // Remap according to the last used remap table
1026                 Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
1027                 Display_cursor();
1028                 action++;
1029                 break;
1030               case SPECIAL_ROTATE_90 : // 90° brush rotation
1031                 Hide_cursor();
1032                 Rotate_90_deg();
1033                 Display_cursor();
1034                 action++;
1035                 break;
1036               case SPECIAL_ROTATE_180 : // 180° brush rotation
1037                 Hide_cursor();
1038                 Rotate_180_deg_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
1039                 // Remap according to the last used remap table
1040                 Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
1041                 Brush_offset_X=(Brush_width>>1);
1042                 Brush_offset_Y=(Brush_height>>1);
1043                 Display_cursor();
1044                 action++;
1045                 break;
1046               case SPECIAL_STRETCH : // Stretch brush
1047                 Hide_cursor();
1048                 Start_operation_stack(OPERATION_STRETCH_BRUSH);
1049                 Display_cursor();
1050                 action++;
1051                 break;
1052               case SPECIAL_DISTORT : // Distort brush
1053                 Hide_cursor();
1054                 Start_operation_stack(OPERATION_DISTORT_BRUSH);
1055                 Display_cursor();
1056                 action++;
1057                 break;
1058               case SPECIAL_ROTATE_ANY_ANGLE : // Rotate brush by any angle
1059                 Hide_cursor();
1060                 Start_operation_stack(OPERATION_ROTATE_BRUSH);
1061                 Display_cursor();
1062                 action++;
1063                 break;
1064               case SPECIAL_BRUSH_DOUBLE:
1065                 if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH
1066                  || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH)
1067                 {
1068                   Hide_cursor();
1069                   Stretch_brush(1,1,Brush_width*2,Brush_height*2);
1070                   Display_cursor();
1071                 }
1072                 action++;
1073                 break;
1074               case SPECIAL_BRUSH_DOUBLE_WIDTH:
1075                 if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH
1076                  || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH)
1077                 {
1078                   Hide_cursor();
1079                   Stretch_brush(1,1,Brush_width*2,Brush_height);
1080                   Display_cursor();
1081                 }
1082                 action++;
1083                 break;
1084               case SPECIAL_BRUSH_DOUBLE_HEIGHT:
1085                 if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH
1086                  || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH)
1087                 {
1088                   Hide_cursor();
1089                   Stretch_brush(1,1,Brush_width,Brush_height*2);
1090                   Display_cursor();
1091                 }
1092                 action++;
1093                 break;
1094               case SPECIAL_BRUSH_HALVE:
1095                 if (Paintbrush_shape==PAINTBRUSH_SHAPE_COLOR_BRUSH
1096                  || Paintbrush_shape==PAINTBRUSH_SHAPE_MONO_BRUSH)
1097                 {
1098                   Hide_cursor();
1099                   Stretch_brush(1,1,Brush_width/2,Brush_height/2);
1100                   Display_cursor();
1101                 }
1102                 action++;
1103                 break;
1104               case SPECIAL_OUTLINE : // Outline brush
1105                 Hide_cursor();
1106                 Outline_brush();
1107                 Display_cursor();
1108                 action++;
1109                 break;
1110               case SPECIAL_NIBBLE : // Nibble brush
1111                 Hide_cursor();
1112                 Nibble_brush();
1113                 Display_cursor();
1114                 action++;
1115                 break;
1116               case SPECIAL_GET_BRUSH_COLORS : // Get colors from brush
1117                 Get_colors_from_brush();
1118                 action++;
1119                 break;
1120               case SPECIAL_RECOLORIZE_BRUSH : // Recolorize brush
1121                 Hide_cursor();
1122                 Remap_brush();
1123                 Display_cursor();
1124                 action++;
1125                 break;
1126               case SPECIAL_LOAD_BRUSH :
1127                 Load_picture(CONTEXT_BRUSH);
1128                 action++;
1129                 break;
1130               case SPECIAL_SAVE_BRUSH :
1131                 Save_picture(CONTEXT_BRUSH);
1132                 action++;
1133                 break;
1134               case SPECIAL_ZOOM_IN : // Zoom in
1135                 Zoom(+1);
1136                 action++;
1137                 break;
1138               case SPECIAL_ZOOM_IN_MORE :
1139                 Zoom(+3);
1140                 action++;
1141                 break;
1142               case SPECIAL_ZOOM_OUT : // Zoom out
1143                 Zoom(-1);
1144                 action++;
1145                 break;
1146               case SPECIAL_ZOOM_OUT_MORE :
1147                 Zoom(-3);
1148                 action++;
1149                 break;
1150 
1151               case SPECIAL_CENTER_ATTACHMENT : // Center brush attachment
1152                 Hide_cursor();
1153                 Brush_offset_X=(Brush_width>>1);
1154                 Brush_offset_Y=(Brush_height>>1);
1155                 Display_cursor();
1156                 action++;
1157                 break;
1158               case SPECIAL_TOP_LEFT_ATTACHMENT : // Top-left brush attachment
1159                 Hide_cursor();
1160                 Brush_offset_X=0;
1161                 Brush_offset_Y=0;
1162                 Display_cursor();
1163                 action++;
1164                 break;
1165               case SPECIAL_TOP_RIGHT_ATTACHMENT : // Top-right brush attachment
1166                 Hide_cursor();
1167                 Brush_offset_X=(Brush_width-1);
1168                 Brush_offset_Y=0;
1169                 Display_cursor();
1170                 action++;
1171                 break;
1172               case SPECIAL_BOTTOM_LEFT_ATTACHMENT : // Bottom-left brush attachment
1173                 Hide_cursor();
1174                 Brush_offset_X=0;
1175                 Brush_offset_Y=(Brush_height-1);
1176                 Display_cursor();
1177                 action++;
1178                 break;
1179               case SPECIAL_BOTTOM_RIGHT_ATTACHMENT : // Bottom right brush attachment
1180                 Hide_cursor();
1181                 Brush_offset_X=(Brush_width-1);
1182                 Brush_offset_Y=(Brush_height-1);
1183                 Display_cursor();
1184                 action++;
1185                 break;
1186               case SPECIAL_EXCLUDE_COLORS_MENU : // Exclude colors menu
1187                 Menu_tag_colors("Tag colors to exclude",Exclude_color,&temp,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU);
1188                 action++;
1189                 break;
1190               case SPECIAL_INVERT_SIEVE :
1191                 Invert_trame();
1192                 action++;
1193                 break;
1194               case SPECIAL_SHADE_MODE :
1195                 Button_Shade_mode();
1196                 effect_modified = 1;
1197                 action++;
1198                 break;
1199               case SPECIAL_SHADE_MENU :
1200                 Button_Shade_menu();
1201                 effect_modified = 1;
1202                 action++;
1203                 break;
1204               case SPECIAL_QUICK_SHADE_MODE :
1205                 Button_Quick_shade_mode();
1206                 effect_modified = 1;
1207                 action++;
1208                 break;
1209               case SPECIAL_QUICK_SHADE_MENU :
1210                 Button_Quick_shade_menu();
1211                 effect_modified = 1;
1212                 action++;
1213                 break;
1214               case SPECIAL_STENCIL_MODE :
1215                 Button_Stencil_mode();
1216                 effect_modified = 1;
1217                 action++;
1218                 break;
1219               case SPECIAL_STENCIL_MENU :
1220                 Button_Stencil_menu();
1221                 effect_modified = 1;
1222                 action++;
1223                 break;
1224               case SPECIAL_MASK_MODE :
1225                 Button_Mask_mode();
1226                 effect_modified = 1;
1227                 action++;
1228                 break;
1229               case SPECIAL_MASK_MENU :
1230                 Button_Mask_menu();
1231                 effect_modified = 1;
1232                 action++;
1233                 break;
1234               case SPECIAL_GRID_MODE :
1235                 Button_Snap_mode();
1236                 effect_modified = 1;
1237                 action++;
1238                 break;
1239               case SPECIAL_GRID_MENU :
1240                 Button_Grid_menu();
1241                 effect_modified = 1;
1242                 action++;
1243                 break;
1244               case SPECIAL_SHOW_GRID :
1245                 Button_Show_grid();
1246                 effect_modified = 1;
1247                 action++;
1248                 break;
1249               case SPECIAL_SIEVE_MODE :
1250                 Button_Sieve_mode();
1251                 effect_modified = 1;
1252                 action++;
1253                 break;
1254               case SPECIAL_SIEVE_MENU :
1255                 Button_Sieve_menu();
1256                 effect_modified = 1;
1257                 action++;
1258                 break;
1259               case SPECIAL_COLORIZE_MODE :
1260                 Button_Colorize_mode();
1261                 effect_modified = 1;
1262                 action++;
1263                 break;
1264               case SPECIAL_COLORIZE_MENU :
1265                 Button_Colorize_menu();
1266                 effect_modified = 1;
1267                 action++;
1268                 break;
1269               case SPECIAL_SMOOTH_MODE :
1270                 Button_Smooth_mode();
1271                 effect_modified = 1;
1272                 action++;
1273                 break;
1274               case SPECIAL_SMOOTH_MENU :
1275                 Button_Smooth_menu();
1276                 effect_modified = 1;
1277                 action++;
1278                 break;
1279               case SPECIAL_SMEAR_MODE :
1280                 Button_Smear_mode();
1281                 effect_modified = 1;
1282                 action++;
1283                 break;
1284               case SPECIAL_TILING_MODE :
1285                 Button_Tiling_mode();
1286                 effect_modified = 1;
1287                 action++;
1288                 break;
1289               case SPECIAL_TILING_MENU :
1290                 effect_modified = 1;
1291                 Button_Tiling_menu();
1292                 action++;
1293                 break;
1294               case SPECIAL_TILEMAP_MODE :
1295                 Button_Tilemap_mode();
1296                 effect_modified = 1;
1297                 action++;
1298                 break;
1299               case SPECIAL_TILEMAP_MENU :
1300                 effect_modified = 1;
1301                 Button_Tilemap_menu();
1302                 action++;
1303                 break;
1304               case SPECIAL_EFFECTS_OFF :
1305                 Effects_off();
1306                 effect_modified = 1;
1307                 action++;
1308                 break;
1309               case SPECIAL_TRANSPARENCY_1 :
1310                 Transparency_set(1);
1311                 effect_modified = 1;
1312                 action++;
1313                 break;
1314               case SPECIAL_TRANSPARENCY_2 :
1315                 Transparency_set(2);
1316                 effect_modified = 1;
1317                 action++;
1318                 break;
1319               case SPECIAL_TRANSPARENCY_3 :
1320                 Transparency_set(3);
1321                 effect_modified = 1;
1322                 action++;
1323                 break;
1324               case SPECIAL_TRANSPARENCY_4 :
1325                 Transparency_set(4);
1326                 effect_modified = 1;
1327                 action++;
1328                 break;
1329               case SPECIAL_TRANSPARENCY_5 :
1330                 Transparency_set(5);
1331                 effect_modified = 1;
1332                 action++;
1333                 break;
1334               case SPECIAL_TRANSPARENCY_6 :
1335                 Transparency_set(6);
1336                 effect_modified = 1;
1337                 action++;
1338                 break;
1339               case SPECIAL_TRANSPARENCY_7 :
1340                 Transparency_set(7);
1341                 effect_modified = 1;
1342                 action++;
1343                 break;
1344               case SPECIAL_TRANSPARENCY_8 :
1345                 Transparency_set(8);
1346                 effect_modified = 1;
1347                 action++;
1348                 break;
1349               case SPECIAL_TRANSPARENCY_9 :
1350                 Transparency_set(9);
1351                 effect_modified = 1;
1352                 action++;
1353                 break;
1354               case SPECIAL_TRANSPARENCY_0 :
1355                 Transparency_set(0);
1356                 effect_modified = 1;
1357                 action++;
1358                 break;
1359               case SPECIAL_ZOOM_1 :
1360                 Zoom_set(-1);
1361                 action++;
1362                 break;
1363               case SPECIAL_ZOOM_2 :
1364                 Zoom_set(0);
1365                 action++;
1366                 break;
1367               case SPECIAL_ZOOM_3 :
1368                 Zoom_set(1);
1369                 action++;
1370                 break;
1371               case SPECIAL_ZOOM_4 :
1372                 Zoom_set(2);
1373                 action++;
1374                 break;
1375               case SPECIAL_ZOOM_5 :
1376                 Zoom_set(3);
1377                 action++;
1378                 break;
1379               case SPECIAL_ZOOM_6 :
1380                 Zoom_set(4);
1381                 action++;
1382                 break;
1383               case SPECIAL_ZOOM_8 :
1384                 Zoom_set(5);
1385                 action++;
1386                 break;
1387               case SPECIAL_ZOOM_10 :
1388                 Zoom_set(6);
1389                 action++;
1390                 break;
1391               case SPECIAL_ZOOM_12 :
1392                 Zoom_set(7);
1393                 action++;
1394                 break;
1395               case SPECIAL_ZOOM_14 :
1396                 Zoom_set(8);
1397                 action++;
1398                 break;
1399               case SPECIAL_ZOOM_16 :
1400                 Zoom_set(9);
1401                 action++;
1402                 break;
1403               case SPECIAL_ZOOM_18 :
1404                 Zoom_set(10);
1405                 action++;
1406                 break;
1407               case SPECIAL_ZOOM_20 :
1408                 Zoom_set(11);
1409                 action++;
1410                 break;
1411               case SPECIAL_LAYER1_SELECT:
1412               case SPECIAL_LAYER2_SELECT:
1413               case SPECIAL_LAYER3_SELECT:
1414               case SPECIAL_LAYER4_SELECT:
1415               case SPECIAL_LAYER5_SELECT:
1416               case SPECIAL_LAYER6_SELECT:
1417               case SPECIAL_LAYER7_SELECT:
1418               case SPECIAL_LAYER8_SELECT:
1419                 Layer_activate((key_index-SPECIAL_LAYER1_SELECT)/2, LEFT_SIDE);
1420                 action++;
1421                 break;
1422               case SPECIAL_LAYER1_TOGGLE:
1423               case SPECIAL_LAYER2_TOGGLE:
1424               case SPECIAL_LAYER3_TOGGLE:
1425               case SPECIAL_LAYER4_TOGGLE:
1426               case SPECIAL_LAYER5_TOGGLE:
1427               case SPECIAL_LAYER6_TOGGLE:
1428               case SPECIAL_LAYER7_TOGGLE:
1429               case SPECIAL_LAYER8_TOGGLE:
1430                 Layer_activate((key_index-SPECIAL_LAYER1_TOGGLE)/2, RIGHT_SIDE);
1431                 action++;
1432                 break;
1433 
1434               case SPECIAL_REPEAT_SCRIPT:
1435 #ifdef __ENABLE_LUA__
1436                 Repeat_script();
1437                 action++;
1438 #endif
1439                 break;
1440               case SPECIAL_RUN_SCRIPT_1:
1441               case SPECIAL_RUN_SCRIPT_2:
1442               case SPECIAL_RUN_SCRIPT_3:
1443               case SPECIAL_RUN_SCRIPT_4:
1444               case SPECIAL_RUN_SCRIPT_5:
1445               case SPECIAL_RUN_SCRIPT_6:
1446               case SPECIAL_RUN_SCRIPT_7:
1447               case SPECIAL_RUN_SCRIPT_8:
1448               case SPECIAL_RUN_SCRIPT_9:
1449               case SPECIAL_RUN_SCRIPT_10:
1450 #ifdef __ENABLE_LUA__
1451                 Run_numbered_script(key_index-SPECIAL_RUN_SCRIPT_1);
1452                 action++;
1453 #endif
1454                 break;
1455               case SPECIAL_CYCLE_MODE:
1456                 Cycling_mode= !Cycling_mode;
1457                 // Restore palette
1458                 if (!Cycling_mode)
1459                   Set_palette(Main.palette);
1460                 action++;
1461                 break;
1462               case SPECIAL_HOLD_PAN:
1463                 // already handled by Pan_shortcut_pressed
1464                 break;
1465             }
1466           }
1467         } // End of special keys
1468 
1469 
1470         // Shortcut for clicks of Menu buttons.
1471         // Disable all of them when an operation is in progress
1472         if (Operation_stack_size==0)
1473         {
1474           // Some functions open windows that clear the Key variable,
1475           // so we need to use a temporary replacement.
1476           key_pressed = Key;
1477           for (button_index=0;button_index<NB_BUTTONS;button_index++)
1478           {
1479             if (Is_shortcut(key_pressed,0x100+button_index))
1480             {
1481               Layer_preview_off(&preview_is_visible);
1482               Select_button(button_index,LEFT_SIDE);
1483               prev_button_number=-1;
1484               action++;
1485             }
1486             else if (Is_shortcut(key_pressed,0x200+button_index))
1487             {
1488               Layer_preview_off(&preview_is_visible);
1489               Select_button(button_index,RIGHT_SIDE);
1490               prev_button_number=-1;
1491               action++;
1492             }
1493           }
1494         }
1495 
1496         // Si on a modifié un effet, il faut rafficher le bouton des effets en
1497         // conséquence.
1498         if (effect_modified)
1499         {
1500           Hide_cursor();
1501           Draw_menu_button(BUTTON_EFFECTS, Any_effect_active());
1502           Display_cursor();
1503         }
1504       }
1505       if (action)
1506         Key=0;
1507     }
1508     else
1509     {
1510 #if defined(USE_SDL) || defined(USE_SDL2)
1511       // Removed all SDL_Delay() timing here: relying on Get_input()
1512       SDL_Delay(10);
1513 #endif
1514     }
1515 
1516     // Gestion de la souris
1517 
1518     Cursor_in_menu=(Mouse_Y>=Menu_Y) ||
1519                       ( (Main.magnifier_mode) && (Mouse_X>=Main.separator_position) &&
1520                         (Mouse_X<Main.X_zoom) );
1521 
1522     if (Cursor_in_menu)
1523     {
1524       // Le curseur se trouve dans le menu
1525 
1526       // On cherche sur quel bouton du menu se trouve la souris:
1527       button_index=Button_under_mouse();
1528 
1529       // Si le curseur vient de changer de zone
1530       if ( (button_index!=prev_button_number)
1531         || (!Cursor_in_menu_previous)
1532         || (prev_button_number==BUTTON_CHOOSE_COL) )
1533       {
1534         // Si le curseur n'est pas sur un bouton
1535         if (button_index==-1)
1536         {
1537           if (Menu_is_visible)
1538           {
1539             // On nettoie les coordonnées
1540             Hide_cursor();
1541 
1542             /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed)
1543               Draw_menu_button(prev_button_number, BUTTON_RELEASED);
1544             */
1545             Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light);
1546             Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3);
1547             Display_cursor();
1548           }
1549         }
1550         else
1551         {
1552           if ( (prev_button_number!=BUTTON_CHOOSE_COL)
1553             || (temp_color!=First_color_in_palette)
1554             || (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) )
1555           {
1556             // Le curseur est sur un nouveau bouton
1557             if (button_index!=BUTTON_CHOOSE_COL)
1558             {
1559               Hide_cursor();
1560 
1561               /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed)
1562                 Draw_menu_button(prev_button_number, BUTTON_RELEASED);
1563               */
1564 
1565               Print_in_menu(Buttons_Pool[button_index].Tooltip,0);
1566 
1567               /*if (Gfx->Hover_effect && !Buttons_Pool[button_index].Pressed)
1568                 Draw_menu_button(button_index, BUTTON_HIGHLIGHTED);
1569               */
1570 
1571               Display_cursor();
1572             }
1573             else
1574             { // Le curseur est-il sur une couleur de la palette?
1575               int color;
1576               if ((color=Pick_color_in_palette())!=-1)
1577               {
1578                 Hide_cursor();
1579                 Status_print_palette_color(color);
1580                 Display_cursor();
1581               }
1582               else
1583               {
1584                 if ( (Old_MX!=Mouse_X) || (Old_MY!=Mouse_Y) )
1585                 {
1586                   Hide_cursor();
1587                   Block(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,Menu_factor_Y<<3,MC_Light);
1588                   Update_rect(18*Menu_factor_X,Menu_status_Y,192*Menu_factor_X,8*Menu_factor_Y);
1589                   Display_cursor();
1590                 }
1591               }
1592             }
1593           }
1594         }
1595       }
1596 
1597       prev_button_number=button_index;
1598 
1599       // Gestion des clicks
1600       if (Mouse_K)
1601       {
1602         if (Mouse_Y>=Menu_Y)
1603         {
1604           if (button_index>=0)
1605           {
1606             Layer_preview_off(&preview_is_visible);
1607             Select_button(button_index,Mouse_K);
1608             prev_button_number=-1;
1609           }
1610         }
1611         else
1612           if (Main.magnifier_mode) Move_separator();
1613       }
1614 
1615       if (button_index == BUTTON_LAYER_SELECT)
1616         Layer_preview_on(&preview_is_visible);
1617       else
1618         Layer_preview_off(&preview_is_visible);
1619 
1620 
1621     }
1622     else // if (!Cursor_in_menu)
1623     {
1624       Layer_preview_off(&preview_is_visible);
1625     }
1626 
1627     // we need to refresh that one as we may come from a sub window
1628     Cursor_in_menu=(Mouse_Y>=Menu_Y) ||
1629                       ( (Main.magnifier_mode) && (Mouse_X>=Main.separator_position) &&
1630                         (Mouse_X<Main.X_zoom) );
1631 
1632 
1633     // Le curseur se trouve dans l'image
1634     if ( (!Cursor_in_menu) && (Menu_is_visible) && (Old_MY != Mouse_Y || Old_MX != Mouse_X || Key || Mouse_K)) // On ne met les coordonnées à jour que si l'utilisateur a fait un truc
1635     {
1636       if(Cursor_in_menu_previous)
1637       {
1638         Hide_cursor();
1639         /*if (Gfx->Hover_effect && prev_button_number > -1 && !Buttons_Pool[prev_button_number].Pressed)
1640           Draw_menu_button(prev_button_number, BUTTON_RELEASED);
1641         */
1642         if ( (Current_operation!=OPERATION_COLORPICK) && (Current_operation!=OPERATION_REPLACE) )
1643         {
1644           Print_in_menu("X:       Y:             ",0);
1645         }
1646         else
1647         {
1648           Print_in_menu("X:       Y:       (    )",0);
1649         }
1650 
1651         Display_cursor();
1652 
1653         Cursor_in_menu_previous = 0;
1654       }
1655     }
1656 
1657     if(Cursor_in_menu)
1658     {
1659         Cursor_in_menu_previous = 1;
1660     }
1661     else
1662     {
1663       blink=Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Hide_cursor;
1664 
1665       if (blink) Hide_cursor();
1666 
1667       Operation[Current_operation][Mouse_K_unique][Operation_stack_size].Action();
1668 
1669       if (blink) Display_cursor();
1670     }
1671     Old_MX=Mouse_X;
1672     Old_MY=Mouse_Y;
1673   }
1674   while (!Quitting);
1675 }
1676 
1677 
1678 
1679 
1680 
1681 //////////////////////////////////////////////////////////////////////////////
1682 //      différentes fonctions d'affichage utilisées dans les fenêtres       //
1683 //////////////////////////////////////////////////////////////////////////////
1684 
1685 //----------------------- Tracer une fenêtre d'options -----------------------
1686 
1687 /**
1688  * Open a GUI window
1689  *
1690  * @param width window width (max 320)
1691  * @param height window height (max 200)
1692  * @param title window title
1693  *
1694  * The mouse must be shown before calling this function. The mouse is hidden
1695  * when the function returns.
1696  *
1697  * The function Close_window() must be called afterward.
1698  */
Open_window(word width,word height,const char * title)1699 void Open_window(word width, word height, const char * title)
1700 {
1701   size_t title_length;
1702 
1703   Hide_cursor();
1704 
1705   /*if (Windows_open == 0 && Gfx->Hover_effect)
1706   {
1707     if (Cursor_in_menu)
1708     {
1709       int button_index=Button_under_mouse();
1710       if (button_index > -1 && !Buttons_Pool[button_index].Pressed)
1711               Draw_menu_button(button_index, BUTTON_RELEASED);
1712     }
1713   }*/
1714 
1715   Windows_open++;
1716 
1717   // Limit the window size to 320x200
1718   if (width > 320 || height > 200)
1719     GFX2_Log(GFX2_WARNING, "Open_window(%d, %d, \"%s\") maximum size for windows is 320x200 !\n", width, height, title);
1720   if (width > 320)
1721     width = 320;
1722   if (height > 200)
1723     height = 200;
1724 
1725   Window_width=width;
1726   Window_height=height;
1727 
1728   // Positionnement de la fenêtre
1729   Window_pos_X=(Screen_width-(width*Menu_factor_X))>>1;
1730 
1731   Window_pos_Y=(Screen_height-(height*Menu_factor_Y))>>1;
1732 
1733   Window_draggable=1;
1734 
1735   // Sauvegarde de ce que la fenêtre remplace
1736   Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height);
1737 
1738   // Fenêtre grise
1739   Window_rectangle(2,2,width-4,height-4,MC_Window);
1740 
1741   // -- Frame de la fenêtre ----- --- -- -  -
1742 
1743   // Frame noir puis en relief
1744   Window_display_frame_mono(0,0,width,height,MC_Black);
1745   Window_display_frame_out(1,1,width-2,height-2);
1746 
1747   // Barre sous le titre
1748   Window_rectangle(3,3,width-6,10,MC_White);
1749   Window_rectangle(2,12,width-4,1,MC_Dark);
1750 
1751   title_length = strlen(title);
1752   if (title_length+2 > (size_t)(width/8))
1753     title_length = width/8-2;
1754   Print_in_window_limited((width-(title_length<<3))>>1,4,title,title_length,MC_Black,MC_White);
1755 
1756   if (Windows_open == 1)
1757   {
1758     Menu_is_visible_before_window=Menu_is_visible;
1759     Menu_is_visible=0;
1760     Menu_Y_before_window=Menu_Y;
1761     Menu_Y=Screen_height;
1762     Cursor_shape_before_window=Cursor_shape;
1763     Cursor_shape=CURSOR_SHAPE_ARROW;
1764     Paintbrush_hidden_before_window=Paintbrush_hidden;
1765     Paintbrush_hidden=1;
1766     if (Allow_colorcycling)
1767     {
1768       Allow_colorcycling=0;
1769       // Restore palette
1770       Set_palette(Main.palette);
1771     }
1772     Allow_drag_and_drop(0);
1773   }
1774 
1775   // Initialisation des listes de boutons de la fenêtre
1776   Window_normal_button_list  =NULL;
1777   Window_palette_button_list =NULL;
1778   Window_scroller_button_list=NULL;
1779   Window_special_button_list =NULL;
1780   Window_dropdown_button_list=NULL;
1781   Window_nb_buttons            =0;
1782 
1783 }
1784 
1785 //----------------------- Fermer une fenêtre d'options -----------------------
1786 
1787 /**
1788  * Close a window previously open with Open_window()
1789  *
1790  * The mouse must be shown when this functions is called.
1791  * It is hidden when the function returns.
1792  */
Close_window(void)1793 void Close_window(void)
1794 {
1795   T_Normal_button   * temp1;
1796   T_Palette_button  * temp2;
1797   T_Scroller_button * temp3;
1798   T_Special_button  * temp4;
1799   T_Dropdown_button * temp5;
1800   T_List_button     * temp6;
1801 
1802   Hide_cursor();
1803 
1804   while (Window_normal_button_list)
1805   {
1806     temp1=Window_normal_button_list->Next;
1807     free(Window_normal_button_list);
1808     Window_normal_button_list=temp1;
1809   }
1810   while (Window_palette_button_list)
1811   {
1812     temp2=Window_palette_button_list->Next;
1813     free(Window_palette_button_list);
1814     Window_palette_button_list=temp2;
1815   }
1816   while (Window_scroller_button_list)
1817   {
1818     temp3=Window_scroller_button_list->Next;
1819     free(Window_scroller_button_list);
1820     Window_scroller_button_list=temp3;
1821   }
1822   while (Window_special_button_list)
1823   {
1824     temp4=Window_special_button_list->Next;
1825     free(Window_special_button_list);
1826     Window_special_button_list=temp4;
1827   }
1828   while (Window_dropdown_button_list)
1829   {
1830     temp5=Window_dropdown_button_list->Next;
1831     Window_dropdown_clear_items(Window_dropdown_button_list);
1832     free(Window_dropdown_button_list);
1833     Window_dropdown_button_list=temp5;
1834   }
1835   while (Window_list_button_list)
1836   {
1837     temp6=Window_list_button_list->Next;
1838     free(Window_list_button_list);
1839     Window_list_button_list=temp6;
1840   }
1841 
1842   if (Windows_open != 1)
1843   {
1844     // Restore de ce que la fenêtre cachait
1845     Restore_background(&Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
1846     Update_window_area(0,0,Window_width,Window_height);
1847     Windows_open--;
1848   }
1849   else
1850   {
1851     free(Window_background[Windows_open-1]);
1852     Window_background[Windows_open-1]=NULL;
1853     Windows_open--;
1854 
1855     Paintbrush_hidden=Paintbrush_hidden_before_window;
1856 
1857     Compute_paintbrush_coordinates();
1858 
1859     Menu_Y=Menu_Y_before_window;
1860     Menu_is_visible=Menu_is_visible_before_window;
1861     Cursor_shape=Cursor_shape_before_window;
1862 
1863     Check_menu_mode();
1864     Display_all_screen();
1865     Display_menu();
1866     Allow_colorcycling=1;
1867     Allow_drag_and_drop(1);
1868   }
1869 
1870   Key=0;
1871   Mouse_K=0;
1872 
1873   Old_MX = -1;
1874   Old_MY = -1;
1875 
1876 }
1877 
1878 
1879 //---------------- Dessiner un bouton normal dans une fenêtre ----------------
1880 // undersc_letter is 0 for no underscore, 1-indexed array index otherwise
Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height,const char * title,byte undersc_letter,byte clickable)1881 void Window_draw_normal_bouton(word x_pos,word y_pos,word width,word height,
1882                                     const char * title,byte undersc_letter,byte clickable)
1883 {
1884   byte title_color;
1885   word text_x_pos,text_y_pos;
1886 
1887   if (clickable)
1888   {
1889     Window_display_frame_out(x_pos,y_pos,width,height);
1890     Window_display_frame_generic(x_pos-1,y_pos-1,width+2,height+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark);
1891     title_color=MC_Black;
1892   }
1893   else
1894   {
1895     Window_display_frame_out(x_pos,y_pos,width,height);
1896     Window_display_frame_mono(x_pos-1,y_pos-1,width+2,height+2,MC_Light);
1897     title_color=MC_Dark;
1898   }
1899 
1900   text_x_pos=x_pos+( (width-(strlen(title)<<3)+1) >>1 );
1901   text_y_pos=y_pos+((height-7)>>1);
1902   Print_in_window(text_x_pos,text_y_pos,title,title_color,MC_Light);
1903 
1904 #if !defined(NO_KEYBOARD)
1905   if (undersc_letter)
1906     Window_rectangle(text_x_pos+((undersc_letter-1)<<3),
1907           text_y_pos+8,8,1,MC_Dark);
1908 #else
1909   (void)undersc_letter;
1910 #endif
1911 }
1912 
1913 
1914 // -- Button normal enfoncé dans la fenêtre --
Window_select_normal_button(word x_pos,word y_pos,word width,word height)1915 void Window_select_normal_button(word x_pos,word y_pos,word width,word height)
1916 {
1917   Window_display_frame_generic(x_pos,y_pos,width,height,MC_Dark,MC_Black,MC_Dark,MC_Dark,MC_Black);
1918   Update_window_area(x_pos, y_pos, width, height);
1919 }
1920 
1921 // -- Button normal désenfoncé dans la fenêtre --
Window_unselect_normal_button(word x_pos,word y_pos,word width,word height)1922 void Window_unselect_normal_button(word x_pos,word y_pos,word width,word height)
1923 {
1924   Window_display_frame_out(x_pos,y_pos,width,height);
1925   Update_window_area(x_pos, y_pos, width, height);
1926 }
1927 
1928 
1929 //--------------- Dessiner un bouton palette dans une fenêtre ----------------
Window_draw_palette_bouton(word x_pos,word y_pos)1930 void Window_draw_palette_bouton(word x_pos,word y_pos)
1931 {
1932   word color;
1933 
1934   for (color=0; color<=255; color++)
1935     Window_rectangle( ((color >> 4)*10)+x_pos+6,((color & 15)*5)+y_pos+3,5,5,color);
1936 
1937   Window_display_frame(x_pos,y_pos,164,86);
1938 }
1939 
1940 
1941 // -------------------- Effacer les TAGs sur les palette ---------------------
1942 // Cette fonct° ne sert plus que lorsqu'on efface les tags dans le menu Spray.
Window_clear_tags(void)1943 void Window_clear_tags(void)
1944 {
1945   word origin_x;
1946   word origin_y;
1947   word x_pos;
1948   word window_x_pos;
1949   //word window_y_pos;
1950 
1951   origin_x=Window_palette_button_list->Pos_X+3;
1952   origin_y=Window_palette_button_list->Pos_Y+3;
1953   for (x_pos=0,window_x_pos=origin_x;x_pos<16;x_pos++,window_x_pos+=10)
1954     Window_rectangle(window_x_pos,origin_y,3,80,MC_Light);
1955   Update_window_area(origin_x,origin_y,160,80);
1956 }
1957 
1958 
1959 // ---- Tracer les TAGs sur les palettes du menu Palette ou du menu Shade ----
Tag_color_range(byte start,byte end)1960 void Tag_color_range(byte start,byte end)
1961 {
1962   word origin_x;
1963   word origin_y;
1964   //word x_pos;
1965   word y_pos;
1966   //word window_x_pos;
1967   word window_y_pos;
1968   word index;
1969 
1970   // On efface les anciens TAGs
1971   for (index=0;index<=start;index++)
1972     Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10),
1973           Window_palette_button_list->Pos_Y+3+((index&15)* 5),
1974           3,5,MC_Light);
1975 
1976   for (index=end;index<256;index++)
1977     Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10),
1978           Window_palette_button_list->Pos_Y+3+((index&15)* 5),
1979           3,5,MC_Light);
1980 
1981   // On affiche le 1er TAG
1982   origin_x=(Window_palette_button_list->Pos_X+3)+(start>>4)*10;
1983   origin_y=(Window_palette_button_list->Pos_Y+3)+(start&15)* 5;
1984   for (y_pos=0,window_y_pos=origin_y  ;y_pos<5;y_pos++,window_y_pos++)
1985     Pixel_in_window(origin_x  ,window_y_pos,MC_Black);
1986   for (y_pos=0,window_y_pos=origin_y+1;y_pos<3;y_pos++,window_y_pos++)
1987     Pixel_in_window(origin_x+1,window_y_pos,MC_Black);
1988   Pixel_in_window(origin_x+2,origin_y+2,MC_Black);
1989 
1990   if (start!=end)
1991   {
1992     // On complète le 1er TAG
1993     Pixel_in_window(origin_x+1,origin_y+4,MC_Black);
1994 
1995     // On affiche le 2ème TAG
1996     origin_x=(Window_palette_button_list->Pos_X+3)+(end>>4)*10;
1997     origin_y=(Window_palette_button_list->Pos_Y+3)+(end&15)* 5;
1998     for (y_pos=0,window_y_pos=origin_y; y_pos<5; y_pos++,window_y_pos++)
1999       Pixel_in_window(origin_x  ,window_y_pos,MC_Black);
2000     for (y_pos=0,window_y_pos=origin_y; y_pos<4; y_pos++,window_y_pos++)
2001       Pixel_in_window(origin_x+1,window_y_pos,MC_Black);
2002     Pixel_in_window(origin_x+2,origin_y+2,MC_Black);
2003 
2004     // On TAG toutes les couleurs intermédiaires
2005     for (index=start+1;index<end;index++)
2006     {
2007       Window_rectangle(Window_palette_button_list->Pos_X+3+((index>>4)*10),
2008             Window_palette_button_list->Pos_Y+3+((index&15)* 5),
2009             2,5,MC_Black);
2010       // On efface l'éventuelle pointe d'une ancienne extrémité de l'intervalle
2011       Pixel_in_window(Window_palette_button_list->Pos_X+5+((index>>4)*10),
2012                          Window_palette_button_list->Pos_Y+5+((index&15)* 5),
2013                          MC_Light);
2014     }
2015 
2016 
2017   }
2018 
2019   Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16);
2020 
2021 }
2022 
2023 
2024 //------------------ Dessiner un scroller dans une fenêtre -------------------
2025 
Compute_slider_cursor_length(T_Scroller_button * button)2026 void Compute_slider_cursor_length(T_Scroller_button * button)
2027 {
2028   if (button->Nb_elements>button->Nb_visibles)
2029   {
2030     button->Cursor_length=(button->Nb_visibles*(button->Length-24))/button->Nb_elements;
2031     if (!(button->Cursor_length))
2032       button->Cursor_length=1;
2033   }
2034   else
2035   {
2036     button->Cursor_length=button->Length-24;
2037   }
2038 }
2039 
Window_draw_slider(T_Scroller_button * button)2040 void Window_draw_slider(T_Scroller_button * button)
2041 {
2042   word slider_position;
2043 
2044   if (button->Is_horizontal)
2045   {
2046     slider_position=button->Pos_X+12;
2047 
2048     Window_rectangle(slider_position,
2049           button->Pos_Y,
2050           button->Length-24,11,MC_Black/*MC_Dark*/);
2051 
2052     if (button->Nb_elements > button->Nb_visibles)
2053     {
2054       int pos = ( (button->Length - 24 - button->Cursor_length) * button->Position
2055                   + (button->Nb_elements - button->Nb_visibles) / 2)
2056                 / (button->Nb_elements - button->Nb_visibles);
2057       if ((pos + button->Cursor_length) > (button->Length - 24))
2058         pos = button->Length - 24 - button->Cursor_length;
2059       slider_position += pos;
2060     }
2061 
2062     Window_rectangle(slider_position,
2063           button->Pos_Y,
2064           button->Cursor_length,11,MC_OnBlack/*MC_White*/);
2065 
2066     Update_window_area(button->Pos_X,
2067           button->Pos_Y,
2068           button->Length,11);
2069   }
2070   else
2071   {
2072     slider_position=button->Pos_Y+12;
2073 
2074     Window_rectangle(button->Pos_X,
2075           slider_position,
2076           11,button->Length-24,MC_Black/*MC_Dark*/);
2077 
2078     if (button->Nb_elements > button->Nb_visibles)
2079     {
2080       int pos = ( (button->Length - 24 - button->Cursor_length) * button->Position
2081                   + (button->Nb_elements - button->Nb_visibles) / 2)
2082                 / (button->Nb_elements - button->Nb_visibles);
2083       if ((pos + button->Cursor_length) > (button->Length - 24))
2084         pos = button->Length - 24 - button->Cursor_length;
2085       slider_position += pos;
2086     }
2087 
2088     Window_rectangle(button->Pos_X,
2089           slider_position,
2090           11,button->Cursor_length,MC_OnBlack/*MC_White*/);
2091 
2092     Update_window_area(button->Pos_X,
2093           button->Pos_Y,
2094           11,button->Length);
2095   }
2096 }
2097 
Window_draw_scroller_button(T_Scroller_button * button)2098 void Window_draw_scroller_button(T_Scroller_button * button)
2099 {
2100   if (button->Is_horizontal)
2101   {
2102     Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,button->Length+2,13,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark);
2103     Window_display_frame_mono(button->Pos_X+11,button->Pos_Y-1,button->Length-22,13,MC_Black);
2104     Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11);
2105     Window_display_frame_out(button->Pos_X+button->Length-11,button->Pos_Y,11,11);
2106     Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\033",MC_Black,MC_Light);
2107     Print_in_window(button->Pos_X+button->Length-9,button->Pos_Y+2,"\032",MC_Black,MC_Light);
2108   }
2109   else
2110   {
2111     Window_display_frame_generic(button->Pos_X-1,button->Pos_Y-1,13,button->Length+2,MC_Black,MC_Black,MC_Dark,MC_Dark,MC_Dark);
2112     Window_display_frame_mono(button->Pos_X-1,button->Pos_Y+11,13,button->Length-22,MC_Black);
2113     Window_display_frame_out(button->Pos_X,button->Pos_Y,11,11);
2114     Window_display_frame_out(button->Pos_X,button->Pos_Y+button->Length-11,11,11);
2115     Print_in_window(button->Pos_X+2,button->Pos_Y+2,"\030",MC_Black,MC_Light);
2116     Print_in_window(button->Pos_X+2,button->Pos_Y+button->Length-9,"\031",MC_Black,MC_Light);
2117   }
2118   Window_draw_slider(button);
2119 }
2120 
2121 
2122 //--------------- Dessiner une zone de saisie dans une fenêtre ---------------
2123 
Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters)2124 void Window_draw_input_bouton(word x_pos,word y_pos,word width_in_characters)
2125 {
2126   Window_display_frame_in(x_pos,y_pos,(width_in_characters<<3)+3,11);
2127 }
2128 
2129 
2130 //------------ Modifier le contenu (caption) d'une zone de saisie ------------
2131 
Window_input_content(T_Special_button * button,const char * content)2132 void Window_input_content(T_Special_button * button, const char * content)
2133 {
2134   Print_in_window_limited(button->Pos_X+2,button->Pos_Y+2,content,button->Width/8,MC_Black,MC_Light);
2135 }
2136 
2137 //------------ Effacer le contenu (caption) d'une zone de saisie ------------
2138 
Window_clear_input_button(T_Special_button * button)2139 void Window_clear_input_button(T_Special_button * button)
2140 {
2141   Window_rectangle(button->Pos_X+2,button->Pos_Y+2,(button->Width/8)*8,8,MC_Light);
2142   Update_window_area(button->Pos_X+2,button->Pos_Y+2,button->Width/8*8,8);
2143 }
2144 
2145 
2146 //------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------
2147 // undersc_letter is 0 for no underscore, 1-indexed array index otherwise
Window_set_normal_button(word x_pos,word y_pos,word width,word height,const char * title,byte undersc_letter,byte clickable,word shortcut)2148 T_Normal_button * Window_set_normal_button(word x_pos, word y_pos,
2149                                    word width, word height,
2150                                    const char * title, byte undersc_letter,
2151                                    byte clickable, word shortcut)
2152 {
2153   T_Normal_button * temp=NULL;
2154 
2155   Window_nb_buttons++;
2156 
2157   if (clickable)
2158   {
2159     temp=(T_Normal_button *)malloc(sizeof(T_Normal_button));
2160     temp->Number   =Window_nb_buttons;
2161     temp->Pos_X    =x_pos;
2162     temp->Pos_Y    =y_pos;
2163     temp->Width    =width;
2164     temp->Height   =height;
2165     temp->Clickable=clickable;
2166     temp->Shortcut =shortcut;
2167     temp->Repeatable=0;
2168 
2169     temp->Next=Window_normal_button_list;
2170     Window_normal_button_list=temp;
2171   }
2172 
2173   Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable);
2174   return temp;
2175 }
2176 //------ Rajout d'un bouton à la liste de ceux présents dans la fenêtre ------
2177 // undersc_letter is 0 for no underscore, 1-indexed array index otherwise
Window_set_repeatable_button(word x_pos,word y_pos,word width,word height,const char * title,byte undersc_letter,byte clickable,word shortcut)2178 T_Normal_button * Window_set_repeatable_button(word x_pos, word y_pos,
2179                                    word width, word height,
2180                                    const char * title, byte undersc_letter,
2181                                    byte clickable, word shortcut)
2182 {
2183   T_Normal_button * temp=NULL;
2184 
2185   Window_nb_buttons++;
2186 
2187   if (clickable)
2188   {
2189     temp=(T_Normal_button *)malloc(sizeof(T_Normal_button));
2190     temp->Number   =Window_nb_buttons;
2191     temp->Pos_X    =x_pos;
2192     temp->Pos_Y    =y_pos;
2193     temp->Width  =width;
2194     temp->Height  =height;
2195     temp->Shortcut=shortcut;
2196     temp->Repeatable=1;
2197 
2198     temp->Next=Window_normal_button_list;
2199     Window_normal_button_list=temp;
2200   }
2201 
2202   Window_draw_normal_bouton(x_pos,y_pos,width,height,title,undersc_letter,clickable);
2203   return temp;
2204 }
2205 
Window_set_palette_button(word x_pos,word y_pos)2206 T_Palette_button * Window_set_palette_button(word x_pos, word y_pos)
2207 {
2208   T_Palette_button * temp;
2209 
2210   temp=(T_Palette_button *)malloc(sizeof(T_Palette_button));
2211   temp->Number   =++Window_nb_buttons;
2212   temp->Pos_X    =x_pos;
2213   temp->Pos_Y    =y_pos;
2214 
2215   temp->Next=Window_palette_button_list;
2216   Window_palette_button_list=temp;
2217 
2218   Window_draw_palette_bouton(x_pos,y_pos);
2219   return temp;
2220 }
2221 
2222 
Window_set_scroller_button(word x_pos,word y_pos,word height,word nb_elements,word nb_elements_visible,word initial_position)2223 T_Scroller_button * Window_set_scroller_button(word x_pos, word y_pos,
2224                                      word height,
2225                                      word nb_elements,
2226                                      word nb_elements_visible,
2227                                      word initial_position)
2228 {
2229   T_Scroller_button * temp;
2230 
2231   temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button));
2232   temp->Number        =++Window_nb_buttons;
2233   temp->Is_horizontal =0;
2234   temp->Pos_X         =x_pos;
2235   temp->Pos_Y         =y_pos;
2236   temp->Length        =height;
2237   temp->Nb_elements   =nb_elements;
2238   temp->Nb_visibles   =nb_elements_visible;
2239   temp->Position      =initial_position;
2240   Compute_slider_cursor_length(temp);
2241 
2242   temp->Next=Window_scroller_button_list;
2243   Window_scroller_button_list=temp;
2244 
2245   Window_draw_scroller_button(temp);
2246   return temp;
2247 }
2248 
Window_set_horizontal_scroller_button(word x_pos,word y_pos,word width,word nb_elements,word nb_elements_visible,word initial_position)2249 T_Scroller_button * Window_set_horizontal_scroller_button(word x_pos, word y_pos,
2250                                      word width,
2251                                      word nb_elements,
2252                                      word nb_elements_visible,
2253                                      word initial_position)
2254 {
2255   T_Scroller_button * temp;
2256 
2257   temp=(T_Scroller_button *)malloc(sizeof(T_Scroller_button));
2258   temp->Number        =++Window_nb_buttons;
2259   temp->Is_horizontal =1;
2260   temp->Pos_X         =x_pos;
2261   temp->Pos_Y         =y_pos;
2262   temp->Length        =width;
2263   temp->Nb_elements   =nb_elements;
2264   temp->Nb_visibles   =nb_elements_visible;
2265   temp->Position      =initial_position;
2266   Compute_slider_cursor_length(temp);
2267 
2268   temp->Next=Window_scroller_button_list;
2269   Window_scroller_button_list=temp;
2270 
2271   Window_draw_scroller_button(temp);
2272   return temp;
2273 }
2274 
Window_set_special_button(word x_pos,word y_pos,word width,word height,word shortcut)2275 T_Special_button * Window_set_special_button(word x_pos,word y_pos,word width,word height, word shortcut)
2276 {
2277   T_Special_button * temp;
2278 
2279   temp=(T_Special_button *)malloc(sizeof(T_Special_button));
2280   temp->Number   =++Window_nb_buttons;
2281   temp->Pos_X    =x_pos;
2282   temp->Pos_Y    =y_pos;
2283   temp->Width    =width;
2284   temp->Height   =height;
2285   temp->Shortcut =shortcut;
2286 
2287   temp->Next=Window_special_button_list;
2288   Window_special_button_list=temp;
2289   return temp;
2290 }
2291 
2292 
Window_set_input_button_s(word x_pos,word y_pos,word width_in_characters,word shortcut)2293 T_Special_button * Window_set_input_button_s(word x_pos,word y_pos,word width_in_characters, word shortcut)
2294 {
2295   T_Special_button *temp;
2296   temp=Window_set_special_button(x_pos,y_pos,(width_in_characters<<3)+3,11,shortcut);
2297   Window_draw_input_bouton(x_pos,y_pos,width_in_characters);
2298   return temp;
2299 }
2300 
Window_set_input_button(word x_pos,word y_pos,word width_in_characters)2301 T_Special_button * Window_set_input_button(word x_pos,word y_pos,word width_in_characters)
2302 {
2303   return Window_set_input_button_s(x_pos, y_pos, width_in_characters, 0);
2304 }
2305 
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,byte bottom_up)2306 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, byte bottom_up)
2307 {
2308   T_Dropdown_button *temp;
2309 
2310   temp=(T_Dropdown_button *)malloc(sizeof(T_Dropdown_button));
2311   temp->Number       =++Window_nb_buttons;
2312   temp->Pos_X        =x_pos;
2313   temp->Pos_Y        =y_pos;
2314   temp->Width      =width;
2315   temp->Height      =height;
2316   temp->Display_choice =display_choice;
2317   temp->First_item=NULL;
2318   temp->Dropdown_width=dropdown_width?dropdown_width:width;
2319   temp->Display_centered=display_centered;
2320   temp->Display_arrow=display_arrow;
2321   temp->Active_button=active_button;
2322   temp->Bottom_up=bottom_up;
2323 
2324   temp->Next=Window_dropdown_button_list;
2325   Window_dropdown_button_list=temp;
2326   Window_draw_normal_bouton(x_pos,y_pos,width,height,"",0,1);
2327   if (label && label[0])
2328     Print_in_window(temp->Pos_X+2,temp->Pos_Y+(temp->Height-7)/2,label,MC_Black,MC_Light);
2329   if (display_arrow)
2330     Window_display_icon_sprite(temp->Pos_X+temp->Width-10,temp->Pos_Y+(temp->Height-7)/2,ICON_DROPDOWN);
2331 
2332   return temp;
2333 }
2334 
2335 // Ajoute un choix à une dropdown. Le libellé est seulement référencé,
2336 // il doit pointer sur une zone qui doit être encore valide à la fermeture
2337 // de la fenêtre (comprise).
Window_dropdown_add_item(T_Dropdown_button * dropdown,word btn_number,const char * label)2338 void Window_dropdown_add_item(T_Dropdown_button * dropdown, word btn_number, const char *label)
2339 {
2340   T_Dropdown_choice *temp;
2341   T_Dropdown_choice *last;
2342 
2343   temp=(T_Dropdown_choice *)malloc(sizeof(T_Dropdown_choice));
2344   temp->Number =btn_number;
2345   temp->Label=label;
2346   temp->Next=NULL;
2347 
2348   last=dropdown->First_item;
2349   if (last)
2350   {
2351     // On cherche le dernier élément
2352     for (;last->Next;last=last->Next)
2353       ;
2354     last->Next=temp;
2355   }
2356   else
2357   {
2358     dropdown->First_item=temp;
2359   }
2360 }
2361 
2362 // ------------- Suppression de tous les choix d'une dropdown ---------
Window_dropdown_clear_items(T_Dropdown_button * dropdown)2363 void Window_dropdown_clear_items(T_Dropdown_button * dropdown)
2364 {
2365   T_Dropdown_choice * next_choice;
2366     while (dropdown->First_item)
2367     {
2368       next_choice=dropdown->First_item->Next;
2369       free(dropdown->First_item);
2370       dropdown->First_item=next_choice;
2371     }
2372 }
2373 
2374 //----------------------- Create a List control -----------------------
2375 // These controls are special. They work over two controls previously created:
2376 // - entry_button is the textual area where the list values will be printed.
2377 // - scroller is a scroller button attached to it
2378 
Window_set_list_button(T_Special_button * entry_button,T_Scroller_button * scroller,Func_draw_list_item draw_list_item,byte color_index)2379 T_List_button * Window_set_list_button(T_Special_button * entry_button, T_Scroller_button * scroller, Func_draw_list_item draw_list_item, byte color_index)
2380 {
2381   T_List_button *temp;
2382 
2383   temp=(T_List_button *)malloc(sizeof(T_List_button));
2384   temp->Number          =++Window_nb_buttons;
2385   temp->List_start      = 0;
2386   temp->Cursor_position = 0;
2387   temp->Entry_button    = entry_button;
2388   temp->Scroller        = scroller;
2389   temp->Draw_list_item  = draw_list_item;
2390   temp->Color_index     = color_index;
2391 
2392   temp->Next=Window_list_button_list;
2393   Window_list_button_list=temp;
2394   return temp;
2395 }
2396 
Window_redraw_list(T_List_button * list)2397 void Window_redraw_list(T_List_button * list)
2398 {
2399   int i;
2400 
2401   for (i=Min(list->Scroller->Nb_visibles-1, list->Scroller->Nb_elements-1); i>=0; i--)
2402   {
2403     list->Draw_list_item(
2404       list->Entry_button->Pos_X,
2405       list->Entry_button->Pos_Y + i * 8,
2406       list->List_start + i,
2407       i == list->Cursor_position);
2408   }
2409   // Remaining rectangle under list
2410   i=list->Scroller->Nb_visibles-list->Scroller->Nb_elements;
2411   if (i>0)
2412   {
2413     byte color;
2414     color = list->Color_index == 0 ? MC_Black :
2415            (list->Color_index == 1 ? MC_Dark :
2416            (list->Color_index == 2 ? MC_Light : MC_White));
2417 
2418     Window_rectangle(
2419       list->Entry_button->Pos_X,
2420       list->Entry_button->Pos_Y+list->Scroller->Nb_elements*8,
2421       list->Entry_button->Width,
2422       i*8,
2423       color);
2424   }
2425 }
2426 
2427 //----------------------- Ouverture d'un pop-up -----------------------
2428 
2429 /**
2430  * Open a popup window
2431  *
2432  * @param x_pos left position
2433  * @param y_pos top position
2434  * @param width width of the popup (max 320)
2435  * @param height height of the popup (max 200)
2436  *
2437  * The mouse cursor must be shown when calling this function. When the
2438  * function returns it is hidden.
2439  *
2440  * Popup windows are managed as sub-windows. They have their own
2441  * event loop, widget can be added inside, etc.
2442  * The differences with plain windows are almost only graphical :
2443  * - Possibility of fixing position (x_pos, y_pos)
2444  * - No title
2445  * - No 3D border, but a flat white border.
2446  */
Open_popup(word x_pos,word y_pos,word width,word height)2447 void Open_popup(word x_pos, word y_pos, word width,word height)
2448 {
2449   Windows_open++;
2450 
2451   if (height*Menu_factor_Y > Screen_height)
2452     height = Screen_height/Menu_factor_Y;
2453   if (y_pos + height*Menu_factor_Y > Screen_height) // fix dropdown that would get bellow the screen
2454     y_pos = Screen_height - height*Menu_factor_Y;
2455   if (x_pos + width*Menu_factor_X > Screen_width)
2456     x_pos = Screen_width - width*Menu_factor_X;
2457 
2458   Window_width=width;
2459   Window_height=height;
2460   Window_pos_X=x_pos;
2461   Window_pos_Y=y_pos;
2462   Window_draggable=0;
2463 
2464   // Sauvegarde de ce que la fenêtre remplace
2465   Save_background(&(Window_background[Windows_open-1]), Window_pos_X, Window_pos_Y, width, height);
2466 
2467 /*
2468   // Fenêtre grise
2469   Window_rectangle(1,1,width-2,height-2,MC_Light);
2470 
2471   // Frame noir puis en relief
2472   Window_display_frame_mono(0,0,width,height,MC_White);
2473 */
2474   if (Windows_open == 1)
2475   {
2476     Menu_is_visible_before_window=Menu_is_visible;
2477     Menu_is_visible=0;
2478     Menu_Y_before_window=Menu_Y;
2479     Menu_Y=Screen_height;
2480     Cursor_shape_before_window=Cursor_shape;
2481     Cursor_shape=CURSOR_SHAPE_ARROW;
2482     Paintbrush_hidden_before_window=Paintbrush_hidden;
2483     Paintbrush_hidden=1;
2484   }
2485 
2486   // Initialisation des listes de boutons de la fenêtre
2487   Window_normal_button_list  =NULL;
2488   Window_palette_button_list =NULL;
2489   Window_scroller_button_list=NULL;
2490   Window_special_button_list =NULL;
2491   Window_dropdown_button_list =NULL;
2492   Window_nb_buttons            =0;
2493 
2494 }
2495 
2496 //----------------------- Fermer une fenêtre d'options -----------------------
2497 
Close_popup(void)2498 void Close_popup(void)
2499 // Lors de l'appel à cette procedure, la souris doit être affichée.
2500 // En sortie de cette procedure, la souris est effacée.
2501 {
2502   T_Normal_button   * temp1;
2503   T_Palette_button  * temp2;
2504   T_Scroller_button * temp3;
2505   T_Special_button  * temp4;
2506   T_Dropdown_button * temp5;
2507   T_List_button     * temp6;
2508 
2509   Hide_cursor();
2510 
2511   while (Window_normal_button_list)
2512   {
2513     temp1=Window_normal_button_list->Next;
2514     free(Window_normal_button_list);
2515     Window_normal_button_list=temp1;
2516   }
2517   while (Window_palette_button_list)
2518   {
2519     temp2=Window_palette_button_list->Next;
2520     free(Window_palette_button_list);
2521     Window_palette_button_list=temp2;
2522   }
2523   while (Window_scroller_button_list)
2524   {
2525     temp3=Window_scroller_button_list->Next;
2526     free(Window_scroller_button_list);
2527     Window_scroller_button_list=temp3;
2528   }
2529   while (Window_special_button_list)
2530   {
2531     temp4=Window_special_button_list->Next;
2532     free(Window_special_button_list);
2533     Window_special_button_list=temp4;
2534   }
2535   while (Window_dropdown_button_list)
2536   {
2537     Window_dropdown_clear_items(Window_dropdown_button_list);
2538     temp5=Window_dropdown_button_list->Next;
2539     free(Window_dropdown_button_list);
2540     Window_dropdown_button_list=temp5;
2541   }
2542   while (Window_list_button_list)
2543   {
2544     temp6=Window_list_button_list->Next;
2545     free(Window_list_button_list);
2546     Window_list_button_list=temp6;
2547   }
2548 
2549   if (Windows_open != 1)
2550   {
2551     // Restore de ce que la fenêtre cachait
2552     Restore_background(&Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
2553     Update_window_area(0,0,Window_width,Window_height);
2554     Windows_open--;
2555   }
2556   else
2557   {
2558     free(Window_background[Windows_open-1]);
2559     Window_background[Windows_open-1] = NULL;
2560     Windows_open--;
2561 
2562     Paintbrush_hidden=Paintbrush_hidden_before_window;
2563 
2564     Compute_paintbrush_coordinates();
2565 
2566     Menu_Y=Menu_Y_before_window;
2567     Menu_is_visible=Menu_is_visible_before_window;
2568     Cursor_shape=Cursor_shape_before_window;
2569 
2570     Display_all_screen();
2571     Display_menu();
2572   }
2573 
2574   Key=0;
2575   Mouse_K=0;
2576 
2577   Old_MX = -1;
2578   Old_MY = -1;
2579 
2580 
2581 }
2582 //////////////////////////////////////////////////////////////////////////////
2583 //                                                                          //
2584 //       Mini-MOTEUR utilisé dans les fenêtres (menus des boutons...)       //
2585 //                                                                          //
2586 //////////////////////////////////////////////////////////////////////////////
2587 
2588 
2589 // -- Indique si on a cliqué dans une zone définie par deux points extremes --
Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y)2590 byte Window_click_in_rectangle(short start_x,short start_y,short end_x,short end_y)
2591 {
2592   short x_pos,y_pos;
2593 
2594   x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X;
2595   y_pos=((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y;
2596 
2597   return ((x_pos>=start_x) &&
2598           (y_pos>=start_y) &&
2599           (x_pos<=end_x)   &&
2600           (y_pos<=end_y));
2601 }
2602 
2603 
2604 // --- Attend que l'on clique dans la palette pour renvoyer la couleur choisie
2605 // ou bien renvoie -1 si on a annulé l'action pas click-droit ou Escape ------
Wait_click_in_palette(T_Palette_button * button)2606 short Wait_click_in_palette(T_Palette_button * button)
2607 {
2608   short start_x=button->Pos_X+5;
2609   short start_y=button->Pos_Y+3;
2610   short end_x  =button->Pos_X+160;
2611   short end_y  =button->Pos_Y+82;
2612   byte  selected_color;
2613   byte  old_hide_cursor;
2614   byte  old_main_magnifier_mode;
2615 
2616   Hide_cursor();
2617   old_hide_cursor=Cursor_hidden;
2618   old_main_magnifier_mode=Main.magnifier_mode;
2619   Main.magnifier_mode=0;
2620   Cursor_hidden=0;
2621   Cursor_shape=CURSOR_SHAPE_TARGET;
2622   Display_cursor();
2623 
2624   for (;;)
2625   {
2626     while (Get_input(20))
2627       ;
2628 
2629     if (Mouse_K==LEFT_SIDE)
2630     {
2631       if (Window_click_in_rectangle(start_x,start_y,end_x,end_y))
2632       {
2633         Hide_cursor();
2634         selected_color=(((Mouse_X-Window_pos_X)/Menu_factor_X)-(button->Pos_X+2)) / 10 * 16 +
2635         (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(button->Pos_Y+3)) / 5;
2636         Cursor_shape=CURSOR_SHAPE_ARROW;
2637         Cursor_hidden=old_hide_cursor;
2638         Main.magnifier_mode=old_main_magnifier_mode;
2639         Display_cursor();
2640         return selected_color;
2641       }
2642       if ((Mouse_X<Window_pos_X) || (Mouse_Y<Window_pos_Y) ||
2643           (Mouse_X>=Window_pos_X+(Window_width*Menu_factor_X)) ||
2644           (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) )
2645       {
2646         Hide_cursor();
2647         selected_color=Read_pixel(Mouse_X,Mouse_Y);
2648         Cursor_shape=CURSOR_SHAPE_ARROW;
2649         Cursor_hidden=old_hide_cursor;
2650         Main.magnifier_mode=old_main_magnifier_mode;
2651         Display_cursor();
2652         return selected_color;
2653       }
2654     }
2655 
2656     if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC))
2657     {
2658       Hide_cursor();
2659       Cursor_shape=CURSOR_SHAPE_ARROW;
2660       Cursor_hidden=old_hide_cursor;
2661       Main.magnifier_mode=old_main_magnifier_mode;
2662       Display_cursor();
2663       return -1;
2664     }
2665   }
2666 }
2667 
2668 
2669 
2670 // -------------- Récupération d'une couleur derrière un menu ----------------
Get_color_behind_window(byte * color,byte * click)2671 void Get_color_behind_window(byte * color, byte * click)
2672 {
2673   short old_x=-1;
2674   short old_y=-1;
2675   short index;
2676   short a,b,c,d; // Variables temporaires et multitâches...
2677   byte * buffer = NULL;
2678   char str[25];
2679   byte cursor_was_hidden;
2680 
2681 
2682   Hide_cursor();
2683 
2684   cursor_was_hidden=Cursor_hidden;
2685   Cursor_hidden=0;
2686 
2687   Save_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height);
2688   a=Menu_Y;
2689   Menu_Y=Menu_Y_before_window;
2690   b=Menu_is_visible;
2691   Menu_is_visible=Menu_is_visible_before_window;
2692   Display_all_screen();
2693   Display_menu();
2694   Menu_Y=a;
2695   Menu_is_visible=b;
2696 
2697   Cursor_shape=CURSOR_SHAPE_COLORPICKER;
2698   b=Paintbrush_hidden;
2699   Paintbrush_hidden=1;
2700   c=-1; // color pointée: au début aucune, comme ça on initialise tout
2701   if (Menu_is_visible_before_window)
2702     Print_in_menu(Buttons_Pool[BUTTON_CHOOSE_COL].Tooltip,0);
2703 
2704   Display_cursor();
2705 
2706   do
2707   {
2708     Get_input(20);
2709 
2710     if ((Mouse_X!=old_x) || (Mouse_Y!=old_y))
2711     {
2712       Hide_cursor();
2713       a=Read_pixel(Mouse_X,Mouse_Y);
2714       if (a!=c)
2715       {
2716         c=a; // Mise à jour de la couleur pointée
2717         if (Menu_is_visible_before_window)
2718         {
2719           d = snprintf(str, sizeof(str), "%d", a);  // position of the space to color
2720           index = snprintf(str+d, sizeof(str)-d, "   (%d,%d,%d)",
2721                    Main.palette[a].R, Main.palette[a].G, Main.palette[a].B);
2722           index += d;
2723           a=24-d;
2724           while (index<a)
2725             str[index++]=' ';
2726           str[a]=0;
2727           Print_in_menu(str,strlen(Buttons_Pool[BUTTON_CHOOSE_COL].Tooltip));
2728 
2729           Print_general((26+((d+strlen(Buttons_Pool[BUTTON_CHOOSE_COL].Tooltip))<<3))*Menu_factor_X,
2730               Menu_status_Y," ",0,c);
2731         }
2732       }
2733       Display_cursor();
2734     }
2735 
2736     old_x=Mouse_X;
2737     old_y=Mouse_Y;
2738   } while (!(Mouse_K || (Key==KEY_ESC)));
2739 
2740   if (Mouse_K)
2741   {
2742     Hide_cursor();
2743     *click=Mouse_K;
2744     *color=Read_pixel(Mouse_X,Mouse_Y);
2745   }
2746   else
2747   {
2748     *click=0;
2749     Hide_cursor();
2750   }
2751 
2752   Restore_background(&buffer,Window_pos_X,Window_pos_Y,Window_width,Window_height);
2753   Update_window_area(0, 0, Window_width, Window_height);
2754   Cursor_shape=CURSOR_SHAPE_ARROW;
2755   Paintbrush_hidden=b;
2756   Cursor_hidden=cursor_was_hidden;
2757   Display_cursor();
2758 }
2759 
2760 
2761 
2762 // ------------ Opération de déplacement de la fenêtre à l'écran -------------
Move_window(short dx,short dy)2763 void Move_window(short dx, short dy)
2764 {
2765   short new_x=Mouse_X-dx;
2766   short new_y=Mouse_Y-dy;
2767   short old_x;
2768   short old_y;
2769   short width=Window_width*Menu_factor_X;
2770   short height=Window_height*Menu_factor_Y;
2771   short a;
2772   byte  b;
2773   byte  *buffer=NULL;
2774 
2775   Hide_cursor();
2776 
2777   Horizontal_XOR_line(new_x,new_y,width);
2778   Vertical_XOR_line(new_x,new_y+1,height-2);
2779   Vertical_XOR_line(new_x+width-1,new_y+1,height-2);
2780   Horizontal_XOR_line(new_x,new_y+height-1,width);
2781   Update_rect(new_x,new_y,width,height);
2782   Cursor_shape=CURSOR_SHAPE_MULTIDIRECTIONAL;
2783   Display_cursor();
2784 
2785   while (Mouse_K)
2786   {
2787     old_x=new_x;
2788     old_y=new_y;
2789 
2790     do
2791     {
2792       Get_input(20);
2793     } while(Mouse_K && new_x==Mouse_X-dx && new_y==Mouse_Y-dy);
2794 
2795     new_x=Mouse_X-dx;
2796 
2797     if (new_x<0)
2798     {
2799       new_x=0;
2800       dx = Mouse_X;
2801     }
2802     if (new_x>Screen_width-width)
2803     {
2804       new_x=Screen_width-width;
2805       dx = Mouse_X - new_x;
2806     }
2807 
2808     new_y=Mouse_Y-dy;
2809 
2810     if (new_y<0)
2811     {
2812       new_y=0;
2813       dy = Mouse_Y;
2814     }
2815     if (new_y>Screen_height-height)
2816     {
2817       new_y=Screen_height-height;
2818       dy = Mouse_Y - new_y;
2819     }
2820 
2821     if ((new_x!=old_x) || (new_y!=old_y))
2822     {
2823       Hide_cursor();
2824 
2825       Horizontal_XOR_line(old_x,old_y,width);
2826       Vertical_XOR_line(old_x,old_y+1,height-2);
2827       Vertical_XOR_line(old_x+width-1,old_y+1,height-2);
2828       Horizontal_XOR_line(old_x,old_y+height-1,width);
2829 
2830       Horizontal_XOR_line(new_x,new_y,width);
2831       Vertical_XOR_line(new_x,new_y+1,height-2);
2832       Vertical_XOR_line(new_x+width-1,new_y+1,height-2);
2833       Horizontal_XOR_line(new_x,new_y+height-1,width);
2834 
2835       Display_cursor();
2836       Update_rect(old_x,old_y,width,height);
2837       Update_rect(new_x,new_y,width,height);
2838     }
2839   }
2840 
2841   Hide_cursor();
2842   Horizontal_XOR_line(new_x,new_y,width);
2843   Vertical_XOR_line(new_x,new_y+1,height-2);
2844   Vertical_XOR_line(new_x+width-1,new_y+1,height-2);
2845   Horizontal_XOR_line(new_x,new_y+height-1,width);
2846 
2847   if ((new_x!=Window_pos_X)
2848    || (new_y!=Window_pos_Y))
2849   {
2850     a=Menu_Y;
2851     Menu_Y=Menu_Y_before_window;
2852     b=Menu_is_visible;
2853     Menu_is_visible=Menu_is_visible_before_window;
2854     //Display_all_screen();
2855     //Display_menu();
2856     Menu_Y=a;
2857     Menu_is_visible=b;
2858 
2859     // Sauvegarde du contenu actuel de la fenêtre
2860     Save_background(&buffer, Window_pos_X, Window_pos_Y, Window_width, Window_height);
2861 
2862     // Restore de ce que la fenêtre cachait
2863     Restore_background(&Window_background[Windows_open-1], Window_pos_X, Window_pos_Y, Window_width, Window_height);
2864 
2865     // Sauvegarde de ce que la fenêtre remplace
2866     Save_background(&(Window_background[Windows_open-1]), new_x, new_y, Window_width, Window_height);
2867 
2868     // Raffichage de la fenêtre
2869     Restore_background(&buffer, new_x, new_y, Window_width, Window_height);
2870 
2871     // Mise à jour du rectangle englobant
2872     Update_rect(
2873       (new_x>Window_pos_X)?Window_pos_X:new_x,
2874       (new_y>Window_pos_Y)?Window_pos_Y:new_y,
2875       ((new_x>Window_pos_X)?(new_x-Window_pos_X):(Window_pos_X-new_x)) + Window_width*Menu_factor_X,
2876       ((new_y>Window_pos_Y)?(new_y-Window_pos_Y):(Window_pos_Y-new_y)) + Window_height*Menu_factor_Y);
2877     Window_pos_X=new_x;
2878     Window_pos_Y=new_y;
2879 
2880   }
2881   else
2882   {
2883     // Update pour effacer le rectangle XOR
2884     Update_window_area(0, 0, Window_width, Window_height);
2885   }
2886   Cursor_shape=CURSOR_SHAPE_ARROW;
2887   Display_cursor();
2888 
2889 }
2890 
2891 ///
2892 /// Displays a dropped-down menu and handles the UI logic until the user
2893 /// releases a mouse button.
2894 /// This function then clears the dropdown and returns the selected item,
2895 /// or NULL if the user wasn't highlighting an item when he closed.
Dropdown_activate(T_Dropdown_button * button,short off_x,short off_y)2896 T_Dropdown_choice * Dropdown_activate(T_Dropdown_button *button, short off_x, short off_y)
2897 {
2898   short nb_choices;
2899   short choice_index;
2900   short selected_index;
2901   short old_selected_index;
2902   short box_width, box_height;
2903   short x, y;
2904   short item_width;
2905   T_Dropdown_choice *item;
2906 
2907   // Taille de l'ombre portée (en plus des dimensions normales)
2908   #define SHADOW_RIGHT 3
2909   #define SHADOW_BOTTOM 4
2910 
2911 
2912   // Comptage des items pour calculer la taille
2913   nb_choices=0;
2914   for (item=button->First_item; item!=NULL; item=item->Next)
2915   {
2916     nb_choices++;
2917   }
2918   box_height = 3+nb_choices*8+1;
2919   box_width = item_width = button->Dropdown_width;
2920   if ((box_height+SHADOW_BOTTOM)*Menu_factor_Y >= Screen_height)
2921   {
2922     // Overflow : split to 2 columns
2923     box_width = 2*item_width - 5;
2924     box_height = 3+((nb_choices+1)/2)*8+1;
2925   }
2926 
2927   // Open a new stacked "window" to serve as drawing area.
2928   Open_popup(
2929     off_x+(button->Pos_X)*Menu_factor_X,
2930     off_y+(button->Pos_Y+(button->Bottom_up?-box_height:button->Height))*Menu_factor_Y,
2931     box_width+SHADOW_RIGHT,
2932     box_height+SHADOW_BOTTOM);
2933 
2934   // Dessin de la boite
2935 
2936   // Bord gauche
2937   Window_rectangle(0,0,1,box_height,MC_Black);
2938   // Frame fonce et blanc
2939   Window_display_frame_out(1,0,box_width-1,box_height);
2940   // Ombre portée
2941   if (SHADOW_BOTTOM)
2942   {
2943     Window_rectangle(SHADOW_RIGHT,
2944         box_height,
2945         box_width,
2946         SHADOW_BOTTOM,
2947         MC_Black);
2948     Window_rectangle(0,
2949         box_height,
2950         SHADOW_RIGHT,
2951         1,
2952         MC_Black);
2953   }
2954   if (SHADOW_RIGHT)
2955   {
2956     Window_rectangle(box_width,
2957         SHADOW_BOTTOM,
2958         SHADOW_RIGHT,
2959         box_height-SHADOW_BOTTOM,
2960         MC_Black);
2961     Window_rectangle(box_width,
2962         1,
2963         1,
2964         SHADOW_BOTTOM,
2965         MC_Black);
2966   }
2967 
2968   selected_index=-1;
2969   while (1)
2970   {
2971     old_selected_index = selected_index;
2972     // Fenêtre grise
2973     Window_rectangle(2, 1, box_width - 3, box_height - 2, MC_Light);
2974     x = 3;
2975     y = 2;
2976     // Affichage des items
2977     for(item = button->First_item, choice_index = 0; item != NULL; item = item->Next, choice_index++)
2978     {
2979       byte color_1;
2980       byte color_2;
2981       if (choice_index == selected_index)
2982       {
2983         color_1 = MC_White;
2984         color_2 = MC_Dark;
2985         Window_rectangle(x, y, item_width - 5, 8, MC_Dark);
2986       }
2987       else
2988       {
2989         color_1 = MC_Black;
2990         color_2 = MC_Light;
2991       }
2992       Print_in_window(x, y, item->Label, color_1, color_2);
2993       y += 8;
2994       if ((y+7) >= box_height)
2995       {
2996         y = 2;
2997         x += item_width - 5;
2998       }
2999     }
3000     Update_window_area(0, 0, Window_width, Window_height);
3001     Display_cursor();
3002 
3003     do
3004     {
3005       // Attente
3006       Get_input(20);
3007       // Mise à jour du survol
3008       if (Window_click_in_rectangle(2,2,box_width-2,box_height-3))
3009       {
3010         selected_index = ((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2) >> 3;
3011         if (((Mouse_X-Window_pos_X)/Menu_factor_X-2) > item_width)
3012           selected_index += (nb_choices + 1) / 2;
3013         if (selected_index != old_selected_index)
3014           GFX2_Log(GFX2_DEBUG, "x=%d y=%d index=%d\n",
3015                    ((Mouse_X-Window_pos_X)/Menu_factor_X-2),
3016                    ((Mouse_Y-Window_pos_Y)/Menu_factor_Y-2),
3017                    selected_index);
3018       }
3019       else
3020         selected_index = -1;
3021 
3022     } while (Mouse_K && selected_index==old_selected_index);
3023 
3024     if (!Mouse_K)
3025       break;
3026     Hide_cursor();
3027   }
3028 
3029   Close_popup();
3030 
3031   if (selected_index>=0 && selected_index<nb_choices)
3032   {
3033     for(item=button->First_item; selected_index; item=item->Next,selected_index--)
3034       ;
3035     return item;
3036   }
3037   return NULL;
3038 }
3039 
3040 // Gestion des dropdown
Window_dropdown_on_click(T_Dropdown_button * button)3041 short Window_dropdown_on_click(T_Dropdown_button *button)
3042 {
3043   T_Dropdown_choice * item;
3044 
3045   // Highlight the button
3046   Hide_cursor();
3047   Window_select_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height);
3048 
3049   // Handle the dropdown's logic
3050   item = Dropdown_activate(button, Window_pos_X, Window_pos_Y);
3051 
3052   // Unhighlight the button
3053   Window_unselect_normal_button(button->Pos_X,button->Pos_Y,button->Width,button->Height);
3054   Display_cursor();
3055 
3056   if (item == NULL)
3057   {
3058     Window_attribute2=-1;
3059     return 0;
3060   }
3061 
3062   if (button->Display_choice)
3063   {
3064     // Automatically update the label of the dropdown list.
3065     int text_length = (button->Width-4-(button->Display_arrow?8:0))/8;
3066     // Clear original label area
3067     Window_rectangle(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,text_length*8,8,MC_Light);
3068     Print_in_window_limited(button->Pos_X+2,button->Pos_Y+(button->Height-7)/2,item->Label,text_length ,MC_Black,MC_Light);
3069   }
3070 
3071   Window_attribute2=item->Number;
3072   return button->Number;
3073 
3074 }
3075 
3076 // --- Fonction de clic sur un bouton a peu près ordinaire:
3077 // Attend que l'on relache le bouton, et renvoie le numero du bouton si on
3078 // est resté dessus, 0 si on a annulé en sortant du bouton.
Window_normal_button_onclick(word x_pos,word y_pos,word width,word height,short btn_number)3079 short Window_normal_button_onclick(word x_pos, word y_pos, word width, word height, short btn_number)
3080 {
3081   while(1)
3082   {
3083     Hide_cursor();
3084     Window_select_normal_button(x_pos,y_pos,width,height);
3085     Display_cursor();
3086     while (Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1))
3087     {
3088       Get_input(20);
3089       if (!Mouse_K)
3090       {
3091         Hide_cursor();
3092         Window_unselect_normal_button(x_pos,y_pos,width,height);
3093         Display_cursor();
3094         return btn_number;
3095       }
3096     }
3097     Hide_cursor();
3098     Window_unselect_normal_button(x_pos,y_pos,width,height);
3099     Display_cursor();
3100     while (!(Window_click_in_rectangle(x_pos,y_pos,x_pos+width-1,y_pos+height-1)))
3101     {
3102       Get_input(20);
3103       if (!Mouse_K)
3104         return 0;
3105     }
3106   }
3107 }
3108 
3109 // --- Returns the number of the clicked button (-1:out of the window, 0:none) ---
Window_get_clicked_button(void)3110 short Window_get_clicked_button(void)
3111 {
3112   T_Normal_button   * temp1;
3113   T_Palette_button  * temp2;
3114   T_Scroller_button * temp3;
3115   T_Special_button  * temp4;
3116   T_Dropdown_button * temp5;
3117 
3118   Window_attribute1=Mouse_K;
3119 
3120   // Test click on normal buttons
3121   for (temp1=Window_normal_button_list; temp1; temp1=temp1->Next)
3122   {
3123     if ((Input_sticky_control == 0 || Input_sticky_control == temp1->Number)
3124       && Window_click_in_rectangle(temp1->Pos_X,temp1->Pos_Y,temp1->Pos_X+temp1->Width-1,temp1->Pos_Y+temp1->Height-1))
3125     {
3126       Input_sticky_control = temp1->Number;
3127       if (temp1->Repeatable)
3128       {
3129         Hide_cursor();
3130         Window_select_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height);
3131         Display_cursor();
3132         Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
3133         Hide_cursor();
3134         Window_unselect_normal_button(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height);
3135         Display_cursor();
3136         return temp1->Number;
3137       }
3138       return Window_normal_button_onclick(temp1->Pos_X,temp1->Pos_Y,temp1->Width,temp1->Height,temp1->Number);
3139     }
3140   }
3141 
3142   // Test click on "Palette" buttons
3143   for (temp2=Window_palette_button_list; temp2; temp2=temp2->Next)
3144   {
3145     if ((Input_sticky_control == 0 || Input_sticky_control == temp2->Number)
3146       && Window_click_in_rectangle(temp2->Pos_X+5,temp2->Pos_Y+3,temp2->Pos_X+160,temp2->Pos_Y+82))
3147     {
3148       Input_sticky_control = temp2->Number;
3149       // We store the clicked color in Attribute2
3150       Window_attribute2 = (((Mouse_X-Window_pos_X)/Menu_factor_X)-(temp2->Pos_X+2)) / 10 * 16 +
3151         (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-(temp2->Pos_Y+3)) / 5;
3152         return temp2->Number;
3153     }
3154   }
3155 
3156   // Test click on slider/scroller bars
3157   for (temp3=Window_scroller_button_list; temp3; temp3=temp3->Next)
3158   {
3159     // Button Up arrow
3160     if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|1024))
3161       && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y,temp3->Pos_X+10,temp3->Pos_Y+10))
3162     {
3163       Input_sticky_control = temp3->Number | 1024;
3164       Hide_cursor();
3165       Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11);
3166 
3167       if (temp3->Position)
3168       {
3169         temp3->Position--;
3170         Window_attribute1=1;
3171         Window_attribute2=temp3->Position;
3172         Window_draw_slider(temp3);
3173       }
3174       else
3175         Window_attribute1=0;
3176 
3177       Display_cursor();
3178 
3179       Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
3180 
3181       Hide_cursor();
3182       Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y,11,11);
3183       Display_cursor();
3184 
3185       return (Window_attribute1)? temp3->Number : 0;
3186     }
3187 
3188     // Button Down arrow
3189     if ((Input_sticky_control == 0 || Input_sticky_control == (temp3->Number|2048))
3190       && ((temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,temp3->Pos_X+temp3->Length-1,temp3->Pos_Y+10))
3191       || (!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-1))))
3192     {
3193       Input_sticky_control = temp3->Number | 2048;
3194       Hide_cursor();
3195       if (temp3->Is_horizontal)
3196         Window_select_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11);
3197       else
3198         Window_select_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11);
3199 
3200       if (temp3->Position+temp3->Nb_visibles<temp3->Nb_elements)
3201       {
3202         temp3->Position++;
3203         Window_attribute1=2;
3204         Window_attribute2=temp3->Position;
3205         Window_draw_slider(temp3);
3206       }
3207       else
3208         Window_attribute1=0;
3209 
3210       Display_cursor();
3211 
3212       Delay_with_active_mouse((Mouse_K==1)? Config.Delay_left_click_on_slider : Config.Delay_right_click_on_slider);
3213 
3214       Hide_cursor();
3215       if (temp3->Is_horizontal)
3216         Window_unselect_normal_button(temp3->Pos_X+temp3->Length-11,temp3->Pos_Y,11,11);
3217       else
3218         Window_unselect_normal_button(temp3->Pos_X,temp3->Pos_Y+temp3->Length-11,11,11);
3219       Display_cursor();
3220 
3221       return (Window_attribute1)? temp3->Number : 0;
3222     }
3223     // Middle slider
3224     if ((Input_sticky_control == temp3->Number) || (Input_sticky_control==0 &&
3225         ((!temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X,temp3->Pos_Y+12,temp3->Pos_X+10,temp3->Pos_Y+temp3->Length-13))
3226         ||(temp3->Is_horizontal && Window_click_in_rectangle(temp3->Pos_X+12,temp3->Pos_Y,temp3->Pos_X+temp3->Length-13,temp3->Pos_Y+10)))))
3227     {
3228       Input_sticky_control = temp3->Number;
3229       if (temp3->Nb_elements>temp3->Nb_visibles)
3230       {
3231         // If there is enough room to make the cursor move:
3232         long mouse_pos;
3233         long origin;
3234 
3235         // Window_attribute2 receives the position of the cursor.
3236         if (temp3->Is_horizontal)
3237           mouse_pos =(Mouse_X-Window_pos_X) / Menu_factor_X - (temp3->Pos_X+12);
3238         else
3239           mouse_pos =(Mouse_Y-Window_pos_Y) / Menu_factor_Y - (temp3->Pos_Y+12);
3240 
3241         // The following formula is wicked. The issue is that you want two
3242         // different behaviors:
3243         // *) If the range is bigger than the pixel precision, the last pixel
3244         //    should map to max value, exactly.
3245         // *) Otherwise, the possible cursor positions are separated by
3246         //    at least one full pixel, so we should find the valid position
3247         //    closest to the center of the mouse cursor position pixel.
3248 
3249         origin = (temp3->Nb_visibles-1)*(temp3->Length-24)/temp3->Nb_elements/2;
3250         Window_attribute2 = (mouse_pos - origin) * (temp3->Nb_elements-(temp3->Cursor_length>1?0:1)) / (temp3->Length-24-1);
3251 
3252         if (Window_attribute2<0)
3253           Window_attribute2=0;
3254         else if (Window_attribute2+temp3->Nb_visibles>temp3->Nb_elements)
3255           Window_attribute2=temp3->Nb_elements-temp3->Nb_visibles;
3256 
3257         // If the cursor moved
3258 
3259         if (temp3->Position!=Window_attribute2)
3260         {
3261           temp3->Position=Window_attribute2;
3262           Window_attribute1=3;
3263           Hide_cursor();
3264           Window_draw_slider(temp3);
3265           Display_cursor();
3266         }
3267         else
3268           // If the cursor moved
3269           Window_attribute1=0;
3270       }
3271       else
3272         // If there's not enough room to make the cursor move:
3273         Window_attribute1=0;
3274 
3275       return (Window_attribute1)? temp3->Number : 0;
3276     }
3277   }
3278 
3279   // Test click on a special button
3280   for (temp4=Window_special_button_list; temp4; temp4=temp4->Next)
3281   {
3282     if ((Input_sticky_control == 0 || Input_sticky_control == temp4->Number)
3283       && Window_click_in_rectangle(temp4->Pos_X,temp4->Pos_Y,temp4->Pos_X+temp4->Width-1,temp4->Pos_Y+temp4->Height-1))
3284     {
3285        Input_sticky_control = temp4->Number;
3286        return temp4->Number;
3287     }
3288   }
3289 
3290   // Test click on a dropdown box
3291   for (temp5=Window_dropdown_button_list; temp5; temp5=temp5->Next)
3292   {
3293     if ((Input_sticky_control == 0 || Input_sticky_control == temp5->Number)
3294      && Window_click_in_rectangle(temp5->Pos_X,temp5->Pos_Y,temp5->Pos_X+temp5->Width-1,temp5->Pos_Y+temp5->Height-1))
3295     {
3296       Input_sticky_control = temp5->Number;
3297       if (Mouse_K & temp5->Active_button)
3298         return Window_dropdown_on_click(temp5);
3299       else
3300       {
3301         Window_attribute2=-1;
3302         return Window_normal_button_onclick(temp5->Pos_X,temp5->Pos_Y,temp5->Width,temp5->Height,temp5->Number);
3303       }
3304     }
3305   }
3306 
3307   return 0;
3308 }
3309 
3310 
Window_get_button_shortcut(void)3311 short Window_get_button_shortcut(void)
3312 {
3313   T_Normal_button * temp;
3314   T_Special_button * temp2;
3315 
3316   if (Key & GFX2_MOD_SHIFT)
3317     Window_attribute1=RIGHT_SIDE;
3318   else
3319     Window_attribute1=LEFT_SIDE;
3320 
3321   // On fait une première recherche
3322   temp=Window_normal_button_list;
3323   while (temp!=NULL)
3324   {
3325     if (temp->Shortcut==Key)
3326     {
3327       Hide_cursor();
3328       Window_select_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height);
3329       Display_cursor();
3330 
3331       Delay_with_active_mouse(Config.Delay_right_click_on_slider);
3332 
3333       Hide_cursor();
3334       Window_unselect_normal_button(temp->Pos_X,temp->Pos_Y,temp->Width,temp->Height);
3335       Display_cursor();
3336 
3337       return temp->Number;
3338     }
3339     temp=temp->Next;
3340   }
3341 
3342   // Scan for shortcut in special button list
3343   temp2=Window_special_button_list;
3344   while (temp2!=NULL)
3345   {
3346     if (temp2->Shortcut==Key)
3347     {
3348       return temp2->Number;
3349     }
3350     temp2=temp2->Next;
3351   }
3352 
3353   // Si la recherche n'a pas été fructueuse ET que l'utilisateur appuyait sur
3354   // <Shift>, on regarde si un bouton ne pourrait pas réagir comme si <Shift>
3355   // n'était pas appuyé.
3356   if (Window_attribute1==RIGHT_SIDE)
3357   {
3358     temp=Window_normal_button_list;
3359     while (temp!=NULL)
3360     {
3361       if (temp->Shortcut==(Key&0x0FFF))
3362         return temp->Number;
3363       temp=temp->Next;
3364     }
3365   }
3366 
3367   // Handle arrow keys, end/home, and mouse wheel that have
3368   // a certain behavior if a list control is present.
3369   if (Window_list_button_list)
3370   {
3371     T_List_button *list = Window_list_button_list;
3372     // If there's more than one of such control, only capture
3373     // events if the mouse cursor is over it.
3374     if (list->Next)
3375     {
3376       // to do
3377     }
3378 
3379 
3380 
3381 
3382 
3383 
3384   }
3385   return 0;
3386 }
3387 
Window_clicked_button(void)3388 short Window_clicked_button(void)
3389 {
3390   short Button;
3391   byte old_mouse_k;
3392 
3393   old_mouse_k=Mouse_K;
3394   Get_input(20);
3395   // Handle clicks
3396   if (Mouse_K)
3397   {
3398     if ((Mouse_X<Window_pos_X) || (Mouse_Y<Window_pos_Y)
3399      || (Mouse_X>=Window_pos_X+(Window_width*Menu_factor_X))
3400      || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)))
3401     {
3402       if (Input_sticky_control == 0 || Input_sticky_control == -1)
3403       {
3404         Input_sticky_control = -1;
3405         return -1;
3406       }
3407       else
3408       {
3409         return 0;
3410       }
3411     }
3412 
3413     if (!Input_sticky_control && Window_draggable && Mouse_Y < Window_pos_Y+(12*Menu_factor_Y))
3414     {
3415       Move_window(Mouse_X-Window_pos_X,Mouse_Y-Window_pos_Y);
3416     }
3417     else
3418     {
3419       short clicked_button;
3420       T_List_button * list;
3421       static dword time_last_click = 0;
3422       static int last_list_number = -1;
3423       dword time_now;
3424 
3425       // Check which controls was clicked (by rectangular area)
3426       clicked_button = Window_get_clicked_button();
3427 
3428       // Check if it's part of a list control
3429       for (list=Window_list_button_list; list!=NULL; list=list->Next)
3430       {
3431         if (list->Entry_button->Number == clicked_button)
3432         {
3433           // Click in the textual part of a list.
3434           short clicked_line;
3435           clicked_line = (((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-list->Entry_button->Pos_Y)>>3;
3436           if (clicked_line >= list->Scroller->Nb_elements) // Below last line
3437             return 0;
3438           time_now = GFX2_GetTicks();
3439           if (clicked_line == list->Cursor_position)
3440           {
3441             // Double click check
3442             if (old_mouse_k==0 && last_list_number==list->Number && time_now - time_last_click < Config.Double_click_speed)
3443             {
3444               time_last_click = time_now;
3445               Input_sticky_control=0;
3446               // Store the selected value as attribute2
3447               Window_attribute2=list->List_start + list->Cursor_position;
3448               // Return the control ID of the "special button" that covers the list.
3449               return list->Entry_button->Number;
3450             }
3451             time_last_click = time_now;
3452             last_list_number=list->Number;
3453             // Already selected : don't activate anything
3454             return 0;
3455           }
3456 
3457           Hide_cursor();
3458           // Redraw one item as disabled
3459           if (list->Cursor_position>=0 && list->Cursor_position<list->Scroller->Nb_visibles)
3460             list->Draw_list_item(
3461               list->Entry_button->Pos_X,
3462               list->Entry_button->Pos_Y + list->Cursor_position * 8,
3463               list->List_start + list->Cursor_position,
3464               0);
3465           list->Cursor_position = clicked_line;
3466           // Redraw one item as enabled
3467           if (list->Cursor_position>=0 && list->Cursor_position<list->Scroller->Nb_visibles)
3468             list->Draw_list_item(
3469               list->Entry_button->Pos_X,
3470               list->Entry_button->Pos_Y + list->Cursor_position * 8,
3471               list->List_start + list->Cursor_position,
3472               1);
3473           Display_cursor();
3474 
3475           // Store the selected value as attribute2
3476           Window_attribute2=list->List_start + list->Cursor_position;
3477           // Return the control ID of the list.
3478           return list->Number;
3479         }
3480         else if (list->Scroller->Number == clicked_button)
3481         {
3482           // Click in the scroller part of a list
3483           if (list->List_start == list->Scroller->Position)
3484             return 0; // Didn't actually move
3485           // Update scroller indices
3486           list->Cursor_position += list->List_start;
3487           list->List_start = list->Scroller->Position;
3488           list->Cursor_position -= list->List_start;
3489           // Need to redraw all
3490           Hide_cursor();
3491           Window_redraw_list(list);
3492           Display_cursor();
3493         }
3494       }
3495       return clicked_button;
3496     }
3497   }
3498 
3499   // Intercept keys
3500   if (Key)
3501   {
3502     T_List_button * list;
3503 
3504     Button=Window_get_button_shortcut();
3505     if (Button)
3506     {
3507       Key=0;
3508       return Button;
3509     }
3510     // Check if there's a list control and the keys can control it
3511     for (list=Window_list_button_list; list!=NULL; list=list->Next)
3512     {
3513       // FIXME: Make only one list have the keyboard focus.
3514       if (1)
3515       {
3516         if (Key==KEY_UP && (list->Cursor_position+list->List_start)>0)
3517         {
3518           Key=0;
3519           Hide_cursor();
3520           list->Cursor_position--;
3521           if (list->Cursor_position<0)
3522           {
3523             list->List_start=list->List_start+list->Cursor_position;
3524             list->Cursor_position=0;
3525             // Mise à jour du scroller
3526             list->Scroller->Position=list->List_start;
3527             Window_draw_slider(list->Scroller);
3528           }
3529           Window_redraw_list(list);
3530           Display_cursor();
3531           // Store the selected value as attribute2
3532           Window_attribute2=list->List_start + list->Cursor_position;
3533           // Return the control ID of the list.
3534           return list->Number;
3535         }
3536         if (Key==KEY_DOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
3537         {
3538           Key=0;
3539           Hide_cursor();
3540           list->Cursor_position++;
3541           if (list->Cursor_position>(list->Scroller->Nb_visibles-1))
3542           {
3543             list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1);
3544             list->Cursor_position=(list->Scroller->Nb_visibles-1);
3545             // Mise à jour du scroller
3546             list->Scroller->Position=list->List_start;
3547             Window_draw_slider(list->Scroller);
3548           }
3549           Window_redraw_list(list);
3550           Display_cursor();
3551           // Store the selected value as attribute2
3552           Window_attribute2=list->List_start + list->Cursor_position;
3553           // Return the control ID of the list.
3554           return list->Number;
3555         }
3556         if (Key==KEY_HOME && (list->Cursor_position!=0 || list->List_start!=0))
3557         {
3558           Key=0;
3559           Hide_cursor();
3560           list->Cursor_position=0;
3561           list->List_start=0;
3562           // Mise à jour du scroller
3563           list->Scroller->Position=list->List_start;
3564           Window_draw_slider(list->Scroller);
3565           Window_redraw_list(list);
3566           Display_cursor();
3567           // Store the selected value as attribute2
3568           Window_attribute2=list->List_start + list->Cursor_position;
3569           // Return the control ID of the list.
3570           return list->Number;
3571         }
3572         if (Key==KEY_END && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
3573         {
3574           Key=0;
3575           Hide_cursor();
3576           list->Cursor_position=(list->Scroller->Nb_elements-1)-list->List_start;
3577           if (list->Cursor_position>(list->Scroller->Nb_visibles-1))
3578           {
3579             list->List_start=list->List_start+list->Cursor_position-(list->Scroller->Nb_visibles-1);
3580             list->Cursor_position=(list->Scroller->Nb_visibles-1);
3581             // Mise à jour du scroller
3582             list->Scroller->Position=list->List_start;
3583             Window_draw_slider(list->Scroller);
3584           }
3585           Window_redraw_list(list);
3586           Display_cursor();
3587           // Store the selected value as attribute2
3588           Window_attribute2=list->List_start + list->Cursor_position;
3589           // Return the control ID of the list.
3590           return list->Number;
3591         }
3592         if (Key==KEY_PAGEDOWN && (list->Cursor_position+list->List_start)<(list->Scroller->Nb_elements-1))
3593         {
3594           Key=0;
3595           Hide_cursor();
3596           if (list->Scroller->Nb_elements<list->Scroller->Nb_visibles)
3597           {
3598             list->Cursor_position=list->Scroller->Nb_elements-1;
3599           }
3600           else if(list->Cursor_position!=list->Scroller->Nb_visibles-1)
3601           {
3602             list->Cursor_position=list->Scroller->Nb_visibles-1;
3603           }
3604           else
3605           {
3606             list->List_start+=list->Scroller->Nb_visibles;
3607             if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements)
3608             {
3609               list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles;
3610             }
3611             // Mise à jour du scroller
3612             list->Scroller->Position=list->List_start;
3613             Window_draw_slider(list->Scroller);
3614           }
3615           Window_redraw_list(list);
3616           Display_cursor();
3617           // Store the selected value as attribute2
3618           Window_attribute2=list->List_start + list->Cursor_position;
3619           // Return the control ID of the list.
3620           return list->Number;
3621         }
3622         if (Key==KEY_PAGEUP && (list->Cursor_position+list->List_start)>0)
3623         {
3624           Key=0;
3625           Hide_cursor();
3626           if(list->Cursor_position!=0)
3627           {
3628             list->Cursor_position=0;
3629           }
3630           else
3631           {
3632             list->List_start-=list->Scroller->Nb_visibles;
3633             if (list->List_start<0)
3634             {
3635               list->List_start=0;
3636             }
3637             // Mise à jour du scroller
3638             list->Scroller->Position=list->List_start;
3639             Window_draw_slider(list->Scroller);
3640           }
3641           Window_redraw_list(list);
3642           Display_cursor();
3643           // Store the selected value as attribute2
3644           Window_attribute2=list->List_start + list->Cursor_position;
3645           // Return the control ID of the list.
3646           return list->Number;
3647         }
3648         if (Key == KEY_MOUSEWHEELUP && list->List_start>0)
3649         {
3650           list->Cursor_position+=list->List_start;
3651           if (list->List_start>=3)
3652             list->List_start-=3;
3653           else
3654             list->List_start=0;
3655           list->Cursor_position-=list->List_start;
3656           // On affiche à nouveau la liste
3657           Hide_cursor();
3658           Window_redraw_list(list);
3659           // Mise à jour du scroller
3660           list->Scroller->Position=list->List_start;
3661           Window_draw_slider(list->Scroller);
3662           Display_cursor();
3663         }
3664         if (Key==KEY_MOUSEWHEELDOWN && list->List_start<list->Scroller->Nb_elements-list->Scroller->Nb_visibles)
3665         {
3666           list->Cursor_position+=list->List_start;
3667           list->List_start+=3;
3668           if (list->List_start+list->Scroller->Nb_visibles>list->Scroller->Nb_elements)
3669           {
3670             list->List_start=list->Scroller->Nb_elements-list->Scroller->Nb_visibles;
3671           }
3672           list->Cursor_position-=list->List_start;
3673           // On affiche à nouveau la liste
3674           Hide_cursor();
3675           Window_redraw_list(list);
3676           // Mise à jour du scroller
3677           list->Scroller->Position=list->List_start;
3678           Window_draw_slider(list->Scroller);
3679           Display_cursor();
3680         }
3681 
3682       }
3683     }
3684   }
3685 
3686   return 0;
3687 }
3688 
3689 
3690 // Fonction qui sert à remapper les parties sauvegardées derriere les
3691 // fenetres ouvertes. C'est utilisé par exemple par la fenetre de palette
3692 // Qui remappe des couleurs, afin de propager les changements.
Remap_window_backgrounds(const byte * conversion_table,int Min_Y,int Max_Y)3693 void Remap_window_backgrounds(const byte * conversion_table, int Min_Y, int Max_Y)
3694 {
3695   int window_index;
3696   byte* EDI;
3697   int dx,cx;
3698 
3699   for (window_index=0; window_index<Windows_open; window_index++)
3700   {
3701     EDI = Window_background[window_index];
3702 
3703     // Pour chaque ligne
3704     for(dx=0; dx<Window_stack[window_index].Height*Menu_factor_Y;dx++)
3705     {
3706       if (dx+Window_stack[window_index].Pos_Y>Max_Y)
3707         return;
3708       if (dx+Window_stack[window_index].Pos_Y<Min_Y)
3709         EDI += Window_stack[window_index].Width*Menu_factor_X*Pixel_width;
3710       else
3711       { // Pour chaque pixel
3712         for(cx=Window_stack[window_index].Width*Menu_factor_X*Pixel_width;cx>0;cx--)
3713         {
3714           *EDI = conversion_table[*EDI];
3715           EDI ++;
3716         }
3717       }
3718     }
3719   }
3720 }
3721 
Remap_UI_in_window_backgrounds(const byte * conversion_table)3722 void Remap_UI_in_window_backgrounds(const byte * conversion_table)
3723 {
3724   int i, j;
3725   int pos_y;
3726 
3727   // all window backgrounds
3728   for (i = 0; i < Windows_open; i++)
3729   {
3730     // remap pixels of background that are either Menu or another window below
3731     byte * p = Window_background[i];
3732     for (pos_y = Window_stack[i].Pos_Y;
3733          pos_y < (Window_stack[i].Pos_Y + Window_stack[i].Height*Menu_factor_Y);
3734          pos_y++)
3735     {
3736       // for each line of the background
3737       int min_x = 0xffff;
3738       int max_x = 0;
3739       if (Menu_is_visible_before_window && pos_y >= Menu_Y_before_window)
3740       {
3741         min_x = 0;
3742         max_x = Screen_width;
3743       }
3744       else for(j = 0; j < i; j++)
3745       {
3746         // check all windows below
3747         if (pos_y < Window_stack[j].Pos_Y
3748          || pos_y >= (Window_stack[j].Pos_Y + Window_stack[j].Height*Menu_factor_Y) )
3749           continue; // this window doesn't occupy this screen row
3750         if (min_x > Window_stack[j].Pos_X)
3751           min_x = Window_stack[j].Pos_X;
3752         if (max_x < (Window_stack[j].Pos_X + Window_stack[j].Width*Menu_factor_X))
3753           max_x = Window_stack[j].Pos_X + Window_stack[j].Width*Menu_factor_X;
3754 
3755       }
3756       if (min_x < Window_stack[i].Pos_X)
3757         min_x = Window_stack[i].Pos_X;
3758       if (max_x > Window_stack[i].Pos_X + Window_stack[i].Width*Menu_factor_X)
3759         max_x = Window_stack[i].Pos_X + Window_stack[i].Width*Menu_factor_X;
3760       if (max_x > min_x)
3761       {
3762         int x;
3763         min_x -= Window_stack[i].Pos_X;
3764         max_x -= Window_stack[i].Pos_X;
3765         // do the conversion
3766         for (x = min_x * Pixel_width; x < max_x * Pixel_width; x++)
3767         {
3768           p[x] = conversion_table[p[x]];
3769         }
3770       }
3771       p += Window_stack[i].Width*Menu_factor_X*Pixel_width;
3772     }
3773   }
3774 }
3775 
Delay_with_active_mouse(int speed)3776 void Delay_with_active_mouse(int speed)
3777 {
3778   dword end;
3779   byte original_mouse_k = Mouse_K;
3780 
3781   end = GFX2_GetTicks()+speed*10;
3782 
3783   do
3784   {
3785     Get_input(20);
3786   } while (Mouse_K == original_mouse_k && GFX2_GetTicks()<end);
3787 }
3788 
3789 ///
3790 /// Based on which toolbars are visible, updates their offsets and
3791 /// computes ::Menu_height and ::Menu_Y
Compute_menu_offsets(void)3792 void Compute_menu_offsets(void)
3793 {
3794   int i;
3795   int offset;
3796 
3797   // Recompute all offsets
3798   offset=0;
3799   Menu_height=0;
3800   for (i = MENUBAR_COUNT-1; i >=0; i--)
3801   {
3802     Menu_bars[i].Top = offset;
3803     if(Menu_bars[i].Visible)
3804     {
3805       offset += Menu_bars[i].Height;
3806       Menu_height += Menu_bars[i].Height;
3807     }
3808   }
3809   // Update global menu coordinates
3810   Menu_Y = Screen_height - Menu_height * Menu_factor_Y;
3811 }
3812 
3813 ///
3814 /// Shows or hides a tolbar from the menu.
3815 /// If with_redraw is set to zero, the caller should
3816 /// redraw itself using Display_menu() and Display_all_screen().
Set_bar_visibility(word bar,int visible,int with_redraw)3817 void Set_bar_visibility(word bar, int visible, int with_redraw)
3818 {
3819   if (!visible && Menu_bars[bar].Visible)
3820   {
3821     // Hide it
3822     Menu_bars[bar].Visible=0;
3823 
3824     Compute_menu_offsets();
3825 
3826     if (Main.magnifier_mode)
3827     {
3828       Compute_magnifier_data();
3829     }
3830 
3831     //   On repositionne le décalage de l'image pour qu'il n'y ait pas d'in-
3832     // -cohérences lorsqu'on sortira du mode Loupe.
3833     if (Main.offset_Y+Screen_height>Main.image_height)
3834     {
3835       if (Screen_height>Main.image_height)
3836         Main.offset_Y=0;
3837       else
3838         Main.offset_Y=Main.image_height-Screen_height;
3839     }
3840     // On fait pareil pour le brouillon
3841     if (Spare.offset_Y+Screen_height>Spare.image_height)
3842     {
3843       if (Screen_height>Spare.image_height)
3844         Spare.offset_Y=0;
3845       else
3846         Spare.offset_Y=Spare.image_height-Screen_height;
3847     }
3848 
3849     Compute_magnifier_data();
3850     if (Main.magnifier_mode)
3851       Position_screen_according_to_zoom();
3852     Compute_limits();
3853     Compute_paintbrush_coordinates();
3854     if (with_redraw)
3855     {
3856       Display_menu();
3857       Display_all_screen();
3858     }
3859   }
3860   else if (visible && !Menu_bars[bar].Visible)
3861   {
3862     // Show it
3863     Menu_bars[bar].Visible = 1;
3864 
3865     Compute_menu_offsets();
3866     Compute_magnifier_data();
3867     if (Main.magnifier_mode)
3868       Position_screen_according_to_zoom();
3869     Compute_limits();
3870     Compute_paintbrush_coordinates();
3871     if (with_redraw)
3872     {
3873       Display_menu();
3874       if (Main.magnifier_mode)
3875         Display_all_screen();
3876     }
3877   }
3878 }
3879 
3880 ///
3881 /// Checks if the current menu toolbars suit the current image type :
3882 /// layered vs anim. If they don't fit, swap the toolbars and return 1:
3883 /// The caller is then responsible for refreshing the screen by calling
3884 /// Display_menu() and Display_all_screen()
Check_menu_mode(void)3885 int Check_menu_mode(void)
3886 {
3887   if (Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
3888   {
3889     if (Menu_bars[MENUBAR_LAYERS].Visible)
3890     {
3891       Set_bar_visibility(MENUBAR_LAYERS, 0, 0);
3892       Set_bar_visibility(MENUBAR_ANIMATION, 1, 0);
3893       return 1;
3894     }
3895   }
3896   else
3897   {
3898     if (Menu_bars[MENUBAR_ANIMATION].Visible)
3899     {
3900       Set_bar_visibility(MENUBAR_ANIMATION, 0, 0);
3901       Set_bar_visibility(MENUBAR_LAYERS, 1, 0);
3902       return 1;
3903     }
3904   }
3905   return 0;
3906 }
3907