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 
21 #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
22     #include <proto/dos.h>
23     #include <sys/types.h>
24 #endif
25 
26 #include <fcntl.h>
27 #include <stdio.h>
28 #include <string.h>
29 #if !defined(_MSC_VER)
30 #include <strings.h>
31 #else
32 #define strdup _strdup
33 #define strncasecmp _strnicmp
34 #if _MSC_VER < 1900
35 #define snprintf _snprintf
36 #endif
37 #endif
38 #include <stdlib.h>
39 #if !defined(__VBCC__) && !defined(_MSC_VER)
40 #include <unistd.h>
41 #endif
42 #include <ctype.h>
43 #include <sys/stat.h>
44 
45 #include "const.h"
46 #include "struct.h"
47 #include "global.h"
48 #include "misc.h"
49 #include "osdep.h"
50 #include "graph.h"
51 #include "engine.h"
52 #include "readline.h"
53 #include "filesel.h"
54 #include "fileseltools.h"
55 #include "loadsave.h"
56 #include "init.h"
57 #include "buttons.h"
58 #include "operatio.h"
59 #include "pages.h"
60 #include "palette.h"
61 #include "errors.h"
62 #include "readini.h"
63 #include "saveini.h"
64 #include "shade.h"
65 #include "io.h"
66 #include "help.h"
67 #include "text.h"
68 #include "screen.h"
69 #include "windows.h"
70 #include "brush.h"
71 #include "input.h"
72 #include "special.h"
73 #include "tiles.h"
74 #include "setup.h"
75 #include "unicode.h"
76 #include "keycodes.h"
77 
78 #if defined(__amigaos4__) || defined(__AROS__) || defined(__MORPHOS__) || defined(__amigaos__)
79     #include <proto/dos.h>
80     #include <dirent.h>
81 #elif defined(__MINT__)
82     #include <mint/sysbind.h>
83     #include <dirent.h>
84 #elif defined(WIN32)
85 #ifndef _MSC_VER
86     #include <dirent.h>
87 #endif
88 #else
89     #include <dirent.h>
90 #endif
91 
92 extern char Program_version[]; // generated in pversion.c
93 
94 extern short Old_MX;
95 extern short Old_MY;
96 
97 
98 //-- MODELE DE BOUTON DE MENU ------------------------------------------------
99 /*
100 void Bouton_***(void)
101 {
102   short clicked_button;
103 
104   Open_window(310,190,"***");
105 
106   Window_set_normal_button(103,137,80,14,"OK",0,1,KEY_RETURN); // 1
107   Window_set_scroller_button(18,44,88,16,4,0);             // 2
108 
109   Update_window_area(0,0,Window_width, Window_height);
110 
111   Display_cursor();
112 
113   do
114   {
115     clicked_button=Window_clicked_button();
116   }
117   while (clicked_button!=1);
118 
119   Close_window();
120   Unselect_button(BOUTON_***);
121   Display_cursor();
122 }
123 */
124 
Message_out_of_memory(void)125 void Message_out_of_memory(void)
126 {
127   short clicked_button;
128 
129   Open_window(216,76,"Not enough memory!");
130 
131   Print_in_window(8,20,"Please consult the manual",MC_Black,MC_Light);
132   Print_in_window(24,28,"to know how to obtain",MC_Black,MC_Light);
133   Print_in_window(36,36,"more memory space.",MC_Black,MC_Light);
134   Window_set_normal_button(60,53,40,14,"OK",1,1,KEY_RETURN); // 1
135   Update_window_area(0,0,Window_width, Window_height);
136   Display_cursor();
137 
138   do
139     clicked_button=Window_clicked_button();
140   while ((clicked_button<=0) && (Key!=KEY_ESC) && (Key!=KEY_o));
141 
142   if(clicked_button<=0) Key=0;
143   Close_window();
144   Display_cursor();
145 }
146 
147 
Button_Message_initial(void)148 void Button_Message_initial(void)
149 {
150   char  str[30];
151   int   x_pos,offs_y,x,y;
152   int clicked_button=0;
153 
154   snprintf(str,sizeof(str),"GrafX2 version %s",Program_version);
155   Open_window(260,172,str);
156 
157   Window_display_frame_in(10,20,239,62);
158   Window_rectangle(11,21,237,60,MC_Black);
159   for (y=23,offs_y=0; y<79; offs_y+=231,y++)
160     for (x=14,x_pos=0; x_pos<231; x_pos++,x++)
161       Pixel_in_window(x,y,Gfx->Logo_grafx2[offs_y+x_pos]);
162 
163   Print_in_window(130-4*26,88,"Copyright (c) 2007-2020 by",MC_Dark,MC_Light);
164   Print_in_window(130-4*23,100,"the Grafx2 project team",MC_Black,MC_Light);
165   Print_in_window(130-4*26,112,"Copyright (c) 1996-2001 by",MC_Dark,MC_Light);
166   Print_in_window(130-4*13,122,"Sunset Design",MC_Black,MC_Light);
167   //Print_in_window( 120-4*13,128,"(placeholder)",MC_Dark,MC_Light);
168   Print_in_window(130-4*16,136,"http://grafx2.tk",MC_Dark,MC_Light);
169 
170   Window_set_normal_button(56, 151, 71, 14, "Anim", 1, (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION), KEY_a);
171   Window_set_normal_button(133, 151, 71, 14, "Layers", 1, (Main.backups->Pages->Image_mode != IMAGE_MODE_LAYERED), KEY_l);
172 
173   Update_window_area(0,0,Window_width, Window_height);
174 
175   Display_cursor();
176 
177   while(!Mouse_K && !Key && !Quit_is_required)
178     Get_input(20);
179   if (Mouse_K)
180   {
181     clicked_button = Window_get_clicked_button();
182     Wait_end_of_click();
183   }
184   else
185     clicked_button = Window_get_button_shortcut();
186   GFX2_Log(GFX2_DEBUG, "Button_Message_initial() clicked_button=%d\n", clicked_button);
187   Close_window();
188 
189   if (clicked_button > 0)
190   {
191     if (Main.backups->Pages->Image_mode == IMAGE_MODE_LAYERED)
192     {
193       Switch_layer_mode(IMAGE_MODE_ANIMATION);
194       Config.Default_mode_layers = 0;
195     }
196     else
197     {
198       Switch_layer_mode(IMAGE_MODE_LAYERED);
199       Config.Default_mode_layers = 1;
200     }
201     if (Check_menu_mode())
202     {
203       Display_menu();
204       Display_all_screen();
205     }
206     // Modify the mode for the spare too
207     Spare.backups->Pages->Image_mode = Main.backups->Pages->Image_mode;
208     Update_spare_buffers(Spare.image_width,Spare.image_height);
209     Redraw_spare_image();
210   }
211   Display_cursor();
212 }
213 
214 
215 
Change_paintbrush_shape(byte shape)216 void Change_paintbrush_shape(byte shape)
217 {
218   Paintbrush_shape=shape;
219   Display_paintbrush_in_menu();
220 
221   switch (Current_operation)
222   {
223     case OPERATION_FILL :
224       Paintbrush_shape_before_fill=shape;
225       Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
226       break;
227     case OPERATION_COLORPICK :
228       Paintbrush_shape_before_colorpicker=shape;
229       Paintbrush_shape=PAINTBRUSH_SHAPE_NONE;
230       break;
231     // Note: Il existe un Paintbrush_shape_before_lasso, mais comme le lasso aura
232     // été automatiquement désactivé avant d'arriver ici, y'a pas de problème.
233   }
234 }
235 
236 
237 //-------------------------------- UNDO/REDO ---------------------------------
Button_Undo(int btn)238 void Button_Undo(int btn)
239 {
240   Hide_cursor();
241   Undo();
242   Set_palette(Main.palette);
243   Compute_optimal_menu_colors(Main.palette);
244 
245   Check_menu_mode();
246   Display_all_screen();
247   Unselect_button(btn);
248   Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
249   Display_menu();
250   Display_cursor();
251 }
252 
Button_Redo(int btn)253 void Button_Redo(int btn)
254 {
255   Hide_cursor();
256   Redo();
257   Set_palette(Main.palette);
258   Compute_optimal_menu_colors(Main.palette);
259 
260   Check_menu_mode();
261   Display_all_screen();
262   Unselect_button(btn);
263   Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
264   Display_menu();
265   Display_cursor();
266 }
267 
268 //---------------------------- SCROLL PALETTE LEFT ---------------------------
Button_Pal_left(int btn)269 void Button_Pal_left(int btn)
270 {
271   short cells;
272   cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y();
273 
274   Hide_cursor();
275   if (First_color_in_palette)
276   {
277     if (First_color_in_palette>=cells)
278       First_color_in_palette-=cells;
279     else
280       First_color_in_palette=0;
281     Display_menu_palette();
282   }
283   Unselect_button(btn);
284   Display_cursor();
285 }
286 
Button_Pal_left_fast(int btn)287 void Button_Pal_left_fast(int btn)
288 {
289   short cells_x = Palette_cells_X();
290   short cells_y = Palette_cells_Y();
291 
292   Hide_cursor();
293   if (First_color_in_palette)
294   {
295     if (First_color_in_palette>=cells_y*cells_x)
296       First_color_in_palette-=cells_y*cells_x;
297     else
298       First_color_in_palette=0;
299     Display_menu_palette();
300   }
301   Unselect_button(btn);
302   Display_cursor();
303 }
304 
305 
306 //--------------------------- SCROLL PALETTE RIGHT ---------------------------
Button_Pal_right(int btn)307 void Button_Pal_right(int btn)
308 {
309   short cells;
310   cells = (Config.Palette_vertical)?Palette_cells_X():Palette_cells_Y();
311 
312   Hide_cursor();
313   if ((int)First_color_in_palette+Palette_cells_X()*Palette_cells_Y()<256)
314   {
315     First_color_in_palette+=cells;
316     Display_menu_palette();
317   }
318 
319   Unselect_button(btn);
320   Display_cursor();
321 }
322 
Button_Pal_right_fast(int btn)323 void Button_Pal_right_fast(int btn)
324 {
325   short cells_x = Palette_cells_X();
326   short cells_y = Palette_cells_Y();
327 
328   Hide_cursor();
329   if ((int)First_color_in_palette+cells_y*cells_x<256)
330   {
331     if ((int)First_color_in_palette+(cells_y)*cells_x*2<256)
332       First_color_in_palette+=cells_x*cells_y;
333     else
334     {
335       if (Config.Palette_vertical)
336         First_color_in_palette=255/cells_x*cells_x-(cells_y-1)*cells_x;
337       else
338         First_color_in_palette=255/cells_y*cells_y-(cells_x-1)*cells_y;
339     }
340     Display_menu_palette();
341   }
342   Unselect_button(btn);
343   Display_cursor();
344 }
345 
346 //-------------------- item de la forecolor dans le menu --------------------
Button_Select_forecolor(int btn)347 void Button_Select_forecolor(int btn)
348 {
349   static long time_click = 0;
350   long time_previous;
351   int color;
352 
353   time_previous = time_click;
354   time_click = GFX2_GetTicks();
355 
356   color=Pick_color_in_palette();
357 
358   if (color == Fore_color)
359   {
360     // Check if it's a double-click
361     if (time_click - time_previous < Config.Double_click_speed)
362     {
363       // Open palette window
364       Button_Palette(btn);
365       return;
366     }
367   }
368 
369   do
370   {
371     if (color != Fore_color && color!=-1)
372     {
373       Hide_cursor();
374       Set_fore_color(color);
375       Display_cursor();
376     }
377     // Wait loop after initial click
378     while(Mouse_K)
379     {
380       Get_input(20);
381 
382       if (Button_under_mouse()==btn)
383       {
384         color=Pick_color_in_palette();
385         if (color != Fore_color && color!=-1)
386         {
387           Hide_cursor();
388           Status_print_palette_color(color);
389           Set_fore_color(color);
390           Display_cursor();
391         }
392       }
393     }
394   } while(Mouse_K);
395 }
396 
397 //-------------------- item de la backcolor dans le menu --------------------
Button_Select_backcolor(int btn)398 void Button_Select_backcolor(int btn)
399 {
400   int color;
401 
402   do
403   {
404     color=Pick_color_in_palette();
405 
406     if (color!=-1 && color != Back_color)
407     {
408       Hide_cursor();
409       Status_print_palette_color(color);
410       Set_back_color(color);
411       Display_cursor();
412     }
413     // Wait loop after initial click
414     do
415     {
416       Get_input(20);
417 
418       if (Button_under_mouse()==btn)
419         break; // This will repeat this button's action
420 
421     } while(Mouse_K);
422   } while(Mouse_K);
423 }
424 
Button_Hide_menu(int btn)425 void Button_Hide_menu(int btn)
426 {
427   Hide_cursor();
428   if (Menu_is_visible)
429   {
430     Menu_is_visible=0;
431     Menu_Y=Screen_height;
432 
433     if (Main.magnifier_mode)
434     {
435       Compute_magnifier_data();
436     }
437 
438     //   On repositionne le décalage de l'image pour qu'il n'y ait pas d'in-
439     // -cohérences lorsqu'on sortira du mode Loupe.
440     if (Main.offset_Y+Screen_height>Main.image_height)
441     {
442       if (Screen_height>Main.image_height)
443         Main.offset_Y=0;
444       else
445         Main.offset_Y=Main.image_height-Screen_height;
446     }
447     // On fait pareil pour le brouillon
448     if (Spare.offset_Y+Screen_height>Spare.image_height)
449     {
450       if (Screen_height>Spare.image_height)
451         Spare.offset_Y=0;
452       else
453         Spare.offset_Y=Spare.image_height-Screen_height;
454     }
455 
456     Compute_magnifier_data();
457     if (Main.magnifier_mode)
458       Position_screen_according_to_zoom();
459     Compute_limits();
460     Compute_paintbrush_coordinates();
461     Display_all_screen();
462   }
463   else
464   {
465     byte current_menu;
466     Menu_is_visible=1;
467     Menu_Y=Screen_height;
468     for (current_menu = 0; current_menu < MENUBAR_COUNT; current_menu++)
469       if (Menu_bars[current_menu].Visible)
470         Menu_Y -= Menu_bars[current_menu].Height * Menu_factor_Y;
471 
472     Compute_magnifier_data();
473     if (Main.magnifier_mode)
474       Position_screen_according_to_zoom();
475     Compute_limits();
476     Compute_paintbrush_coordinates();
477     Display_menu();
478     if (Main.magnifier_mode)
479       Display_all_screen();
480   }
481   Unselect_button(btn);
482   Display_cursor();
483 }
484 
Button_Toggle_toolbar(int btn)485 void Button_Toggle_toolbar(int btn)
486 {
487   T_Dropdown_button dropdown;
488   T_Dropdown_choice *item;
489   static char menu_name_tools[9] = " Tools";
490   static char menu_name_layers[9]= " Layers";
491   static char menu_name_anim[9]  = " Anim";
492 
493 
494   menu_name_tools[0]  = Menu_bars[MENUBAR_TOOLS ].Visible ? 22 : ' ';
495   menu_name_layers[0] = Menu_bars[MENUBAR_LAYERS].Visible ? 22 : ' ';
496   menu_name_anim[0]   = Menu_bars[MENUBAR_ANIMATION].Visible ? 22 : ' ';
497 
498   Hide_cursor();
499 
500   dropdown.Pos_X         =Buttons_Pool[BUTTON_HIDE].X_offset;
501   dropdown.Pos_Y         =Buttons_Pool[BUTTON_HIDE].Y_offset;
502   dropdown.Height        =Buttons_Pool[BUTTON_HIDE].Height;
503   dropdown.Dropdown_width=70;
504   dropdown.First_item    =NULL;
505   dropdown.Bottom_up     =1;
506 
507   Window_dropdown_add_item(&dropdown, 0, menu_name_tools);
508 
509   if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION ||
510       Main.backups->Pages->Nb_layers==1)
511     Window_dropdown_add_item(&dropdown, 1, menu_name_layers);
512 
513   if (Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION ||
514     (Main.backups->Pages->Image_mode == IMAGE_MODE_LAYERED && Main.backups->Pages->Nb_layers==1))
515     Window_dropdown_add_item(&dropdown, 2, menu_name_anim);
516 
517   item=Dropdown_activate(&dropdown,0,Menu_Y+Menu_bars[MENUBAR_STATUS].Top*Menu_factor_Y);
518 
519   if (item)
520   {
521     switch (item->Number)
522     {
523       case 0: // tools
524         Set_bar_visibility(MENUBAR_TOOLS, !Menu_bars[MENUBAR_TOOLS].Visible, 0);
525         break;
526       case 1: // layers
527         if (Menu_bars[MENUBAR_ANIMATION].Visible)
528         {
529           Set_bar_visibility(MENUBAR_ANIMATION, 0, 0);
530           Config.Default_mode_layers=1;
531         }
532         Set_bar_visibility(MENUBAR_LAYERS, !Menu_bars[MENUBAR_LAYERS].Visible, 0);
533 
534         if (Main.backups->Pages->Image_mode == IMAGE_MODE_ANIMATION)
535           Switch_layer_mode(IMAGE_MODE_LAYERED);
536 
537         break;
538       case 2: // anim
539         if (Menu_bars[MENUBAR_LAYERS].Visible)
540         {
541           Set_bar_visibility(MENUBAR_LAYERS, 0, 0);
542           Config.Default_mode_layers=0;
543         }
544         Set_bar_visibility(MENUBAR_ANIMATION, !Menu_bars[MENUBAR_ANIMATION].Visible, 0);
545 
546         if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION)
547           Switch_layer_mode(IMAGE_MODE_ANIMATION);
548 
549         break;
550     }
551     // redraw image and menu
552     Display_menu();
553     Display_all_screen();
554   }
555 
556   // Closing
557   Window_dropdown_clear_items(&dropdown);
558 
559   Unselect_button(btn);
560   Display_cursor();
561 }
562 
Button_Toggle_all_toolbars(int btn)563 void Button_Toggle_all_toolbars(int btn)
564 {
565   // This is used to memorize the bars' visibility when temporarily hidden
566   static word Last_visibility = 0xFFFF;
567   int i;
568   word current_visibility;
569 
570   Hide_cursor();
571 
572   // Check which bars are visible
573   current_visibility=0;
574   for (i=MENUBAR_STATUS+1;i<MENUBAR_COUNT;i++)
575     if (Menu_bars[i].Visible)
576       current_visibility |= (1<<i);
577 
578   if (current_visibility)
579   {
580     // At least one is visible: Hide all
581     Last_visibility=current_visibility;
582     for (i=MENUBAR_STATUS+1;i<MENUBAR_COUNT;i++)
583       Set_bar_visibility(i,0, 0);
584   }
585   else
586   {
587     // Restore all
588     for (i=MENUBAR_STATUS+1;i<MENUBAR_COUNT;i++)
589       Set_bar_visibility(i,(Last_visibility & (1<<i)) ? 1 : 0, 0);
590   }
591   Check_menu_mode();
592   Display_menu();
593   Display_all_screen();
594 
595   Unselect_button(btn);
596   Display_cursor();
597 }
598 
599 //--------------------------- Quitter le programme ---------------------------
Button_Quit_local_function(void)600 byte Button_Quit_local_function(void)
601 {
602   short clicked_button;
603   byte  old_cursor_shape;
604   char * filename;
605   int exists;
606 
607   if (!Main.image_is_modified)
608     return 1;
609 
610   // On commence par afficher la fenêtre de QUIT
611   Open_window(160,84,"Quit ?");
612   Window_set_normal_button(20,20,120,14,"Stay",0,1,KEY_ESC);          // 1
613   Window_set_normal_button(20,40,120,14,"Save & quit",1,1,KEY_s);   // 2
614   Window_set_normal_button(20,60,120,14,"Discard (Quit)",1,1,KEY_d);// 3
615   Update_window_area(0,0,Window_width, Window_height);
616   Display_cursor();
617 
618   do
619   {
620     Quit_is_required = 0; // ignore other QUIT messages from the system
621     clicked_button = Window_clicked_button();
622     if (Is_shortcut(Key,0x100+BUTTON_HELP))
623       Window_help(BUTTON_QUIT, NULL);
624     else if (Is_shortcut(Key,0x100+BUTTON_QUIT))
625       clicked_button=1;
626   }
627   while (clicked_button<=0);
628 
629   Close_window();
630   Display_cursor();
631 
632   switch(clicked_button)
633   {
634     case 1 : return 0; // Rester
635     case 2 : // Sauver et enregistrer
636       filename = Filepath_append_to_dir(Main.backups->Pages->File_directory, Main.backups->Pages->Filename);
637       exists = File_exists(filename);
638       free(filename);
639       if ( !exists || Confirmation_box("Erase old file ?") )
640       {
641         T_IO_Context save_context;
642 
643         Hide_cursor();
644         old_cursor_shape=Cursor_shape;
645         Cursor_shape=CURSOR_SHAPE_HOURGLASS;
646         Display_cursor();
647 
648         Init_context_layered_image(&save_context, Main.backups->Pages->Filename, Main.backups->Pages->File_directory);
649         save_context.File_name_unicode = Main.backups->Pages->Filename_unicode;
650         Save_image(&save_context);
651         Destroy_context(&save_context);
652 
653         Hide_cursor();
654         Cursor_shape=old_cursor_shape;
655         Display_cursor();
656 
657         if (!File_error)
658           // L'ayant sauvée avec succès,
659           return 1; // On peut quitter
660         else
661           // Il y a eu une erreur lors de la sauvegarde,
662           return 0; // On ne peut donc pas quitter
663       }
664       else
665         // L'utilisateur ne veut pas écraser l'ancien fichier,
666         return 0; // On doit donc rester
667     case 3 : return 1; // Quitter
668   }
669   return 0;
670 }
671 
672 
Button_Quit(int btn)673 void Button_Quit(int btn)
674 {
675   //short clicked_button;
676 
677   if (Button_Quit_local_function())
678   {
679     if (Spare.image_is_modified)
680     {
681       Button_Page(BUTTON_PAGE); // On passe sur le brouillon
682       // Si l'utilisateur présente les derniers symptomes de l'abandon
683       if (Button_Quit_local_function())
684         Quitting=1;
685     }
686     else
687       Quitting=1;
688   }
689 
690   if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) )
691     Hide_cursor();
692 
693   Unselect_button(btn);
694 
695   if ( (Menu_is_visible) && (Mouse_Y+8>Menu_Y) )
696     Display_cursor();
697 }
698 
699 
700 //---------------------------- Effacer l'écran -------------------------------
Button_Clear(int btn)701 void Button_Clear(int btn)
702 {
703   Hide_cursor();
704   Backup();
705   if (Stencil_mode && Config.Clear_with_stencil)
706     Clear_current_image_with_stencil(Main.backups->Pages->Transparent_color,Stencil);
707   else
708     Clear_current_image(Main.backups->Pages->Transparent_color);
709   Redraw_layered_image();
710   End_of_modification();
711   Display_all_screen();
712   Unselect_button(btn);
713   Display_cursor();
714 }
715 
Button_Clear_with_backcolor(int btn)716 void Button_Clear_with_backcolor(int btn)
717 {
718   Hide_cursor();
719   Backup();
720   if (Stencil_mode && Config.Clear_with_stencil)
721     Clear_current_image_with_stencil(Back_color,Stencil);
722   else
723     Clear_current_image(Back_color);
724   Redraw_layered_image();
725   End_of_modification();
726   Display_all_screen();
727   Unselect_button(btn);
728   Display_cursor();
729 }
730 
731 
732 //------------------------------- Paramètres ---------------------------------
733 
734 #define SETTING_PER_PAGE 11
735 #define SETTING_PAGES     5
736 
737 #define SETTING_HEIGHT   12
738 
739 typedef struct {
740   const char* Label; // Use NULL label to stop an array
741   int Code;
742 } T_Lookup;
743 
744 const T_Lookup Lookup_YesNo[] = {
745   {"NO",0},
746   {"YES",1},
747   {NULL,-1},
748 };
749 
750 const T_Lookup Lookup_FFF[] = {
751   {"All",0},
752   {"Files",1},
753   {"Dirs.",2},
754   {NULL,-1},
755 };
756 
757 const T_Lookup Lookup_AutoRes[] = {
758   {"Internal",1},
759   {"Real",2},
760   {NULL,-1},
761 };
762 
763 const T_Lookup Lookup_Coords[] = {
764   {"Relative",1},
765   {"Absolute",2},
766   {NULL,-1},
767 };
768 
769 const T_Lookup Lookup_MenuRatio[] = {
770   {"None",0},
771   {"x2",254}, // -2
772   {"x3",253}, // -3
773   {"x4",252}, // -4
774   {"Moderate",2},
775   {"Maximum",1},
776   {NULL,-1},
777 };
778 
779 const T_Lookup Lookup_MouseSpeed[] = {
780   {"Normal",1},
781   {"/2",2},
782   {"/3",3},
783   {"/4",4},
784   {NULL,-1},
785 };
786 
787 const T_Lookup Lookup_SwapButtons[] = {
788   {"None",0},
789   {"Control",GFX2_MOD_CTRL},
790   {"Alt",GFX2_MOD_ALT},
791   {NULL,-1},
792 };
793 
794 const T_Lookup Lookup_VirtualKeyboard[] = {
795   {"Auto",0},
796   {"ON",1},
797   {"OFF",2},
798   {NULL,-1},
799 };
800 
801 typedef struct {
802   const char* Label;
803   byte Type; // 0: label, 1+: setting (size in bytes)
804   void * Value;
805   int Min_value;
806   int Max_value;
807   int Digits; // Could be computed from Max_value...but don't bother.
808   const T_Lookup * Lookup;
809 } T_Setting;
810 
Get_setting_value(const T_Setting * item)811 long int Get_setting_value(const T_Setting *item)
812 {
813   switch(item->Type)
814   {
815     case 1:
816       return *((byte *)(item->Value));
817       break;
818     case 2:
819       return *((word *)(item->Value));
820       break;
821     case 4:
822     default:
823       return *((long int *)(item->Value));
824       break;
825   }
826 }
827 
Set_setting_value(const T_Setting * item,long int value)828 void Set_setting_value(const T_Setting *item, long int value)
829 {
830   switch(item->Type)
831   {
832     case 1:
833       *((byte *)(item->Value)) = value;
834       break;
835     case 2:
836       *((word *)(item->Value)) = value;
837       break;
838     case 4:
839     default:
840       *((long int *)(item->Value)) = value;
841       break;
842   }
843 }
844 
845 // Fetch a label in a lookup table. Unknown values get label 0.
Lookup_code(int code,const T_Lookup * lookup)846 const char *Lookup_code(int code, const T_Lookup *lookup)
847 {
848   int i;
849 
850   for(i=0; lookup[i].Label!=NULL; i++)
851   {
852     if (lookup[i].Code == code)
853       return lookup[i].Label;
854   }
855   return lookup[0].Label;
856 }
857 
858 /// Increase an enum to next-higher value (wrapping).
Lookup_next(int code,const T_Lookup * lookup)859 int Lookup_next(int code, const T_Lookup *lookup)
860 {
861   int i;
862 
863   for(i=0; lookup[i].Label!=NULL; i++)
864   {
865     if (lookup[i].Code == code)
866     {
867       if (lookup[i+1].Label==NULL)
868         return lookup[0].Code;
869       return lookup[i+1].Code;
870     }
871   }
872   return 0;
873 }
874 
875 /// Decrease an enum to previous value (wrapping).
Lookup_previous(int code,const T_Lookup * lookup)876 int Lookup_previous(int code, const T_Lookup *lookup)
877 {
878   int count;
879   int current=-1;
880 
881   for(count=0; lookup[count].Label!=NULL; count++)
882   {
883     if (lookup[count].Code == code)
884       current=count;
885   }
886 
887   return lookup[(current + count - 1) % count].Code;
888 }
889 
Settings_display_config(const T_Setting * setting,T_Config * conf,T_Special_button * panel)890 void Settings_display_config(const T_Setting *setting, T_Config * conf, T_Special_button *panel)
891 {
892   int i;
893 
894   // A single button
895   Print_in_window(155,166,(conf->Auto_save)?"YES":" NO",MC_Black,MC_Light);
896 
897   // Clear all
898   Window_rectangle(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1, MC_Light);
899   for (i=0; i<SETTING_PER_PAGE; i++)
900   {
901     Print_in_window(panel->Pos_X+3, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, setting[i].Label, i==0?MC_White:MC_Dark, MC_Light);
902     if(setting[i].Value)
903     {
904 
905       int value = Get_setting_value(&setting[i]);
906 
907       if (setting[i].Lookup)
908       {
909         // Use a lookup table to print a label
910         const char *str;
911         str = Lookup_code(value,setting[i].Lookup);
912         Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light);
913       }
914       else
915       {
916         // Print a number
917         char str[10];
918         Num2str(value,str,setting[i].Digits);
919         Print_in_window(panel->Pos_X+3+176, panel->Pos_Y+i*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2, str, MC_Black, MC_Light);
920       }
921     }
922   }
923   Update_window_area(panel->Pos_X, panel->Pos_Y, panel->Width, panel->Height+1);
924 }
925 
Settings_save_config(T_Config * conf)926 void Settings_save_config(T_Config * conf)
927 {
928   if (Save_CFG())
929     Error(0);
930   else
931     if (Save_INI(conf))
932       Error(0);
933 }
934 
Settings_load_config(T_Config * conf)935 void Settings_load_config(T_Config * conf)
936 {
937   if (Load_CFG(0))
938     Error(0);
939   else
940     if (Load_INI(conf))
941       Error(0);
942 }
943 
Button_Settings(int btn)944 void Button_Settings(int btn)
945 {
946   short clicked_button;
947   T_Config selected_config;
948   byte config_is_reloaded=0;
949   T_Special_button *panel;
950   byte need_redraw=1;
951   static byte current_page=0;
952 
953   // Definition of settings pages
954   //  Label,Type (0 = label, 1+ = setting size in bytes),
955   //  Value, min, max, digits, Lookup)
956 
957   const T_Setting setting[SETTING_PER_PAGE*SETTING_PAGES] = {
958 
959   {"           --- GUI  ---",0,NULL,0,0,0,NULL},
960   {"Opening message:",1,&(selected_config.Opening_message),0,1,0,Lookup_YesNo},
961   {"Menu ratio adapt:",1,&(selected_config.Ratio),0,1,0,Lookup_MenuRatio},
962   {"Draw limits:",1,&(selected_config.Display_image_limits),0,1,0,Lookup_YesNo},
963   {"Coordinates:",1,&(selected_config.Coords_rel),0,1,0,Lookup_Coords},
964   {"Separate colors:",1,&(selected_config.Separate_colors),0,1,0,Lookup_YesNo},
965   {"Safety colors:",1,&(selected_config.Safety_colors),0,1,0,Lookup_YesNo},
966   {"Sync views:",1,&(selected_config.Sync_views),0,1,0,Lookup_YesNo},
967   {"",0,NULL,0,0,0,NULL},
968   {"",0,NULL,0,0,0,NULL},
969   {"",0,NULL,0,0,0,NULL},
970 
971   {"           --- Input  ---",0,NULL,0,0,0,NULL},
972   {"Scrollbar speed",0,NULL,0,0,0,NULL},
973   {"  on left click:",1,&(selected_config.Delay_left_click_on_slider),1,255,4,NULL},
974   {"  on right click:",1,&(selected_config.Delay_right_click_on_slider),1,255,4,NULL},
975   {"Merge movement:",1,&(selected_config.Mouse_merge_movement),0,100,4,NULL},
976   {"Double click speed:",2,&(selected_config.Double_click_speed),1,1999,4,NULL},
977   {"Double key speed:",2,&(selected_config.Double_key_speed),1,1999,4,NULL},
978   //{"Mouse speed (fullscreen)",0,NULL,0,0,0,NULL},
979   //{"  horizontally:",1,&(selected_config.Mouse_sensitivity_index_x),1,4,0,Lookup_MouseSpeed},
980   //{"  vertically:",1,&(selected_config.Mouse_sensitivity_index_y),1,4,0,Lookup_MouseSpeed},
981   {"Key to swap buttons:",2,&(selected_config.Swap_buttons),0,0,0,Lookup_SwapButtons},
982   {"Virtual keyboard",1,&(selected_config.Use_virtual_keyboard),0,2,0,Lookup_VirtualKeyboard},
983   {"",0,NULL,0,0,0,NULL},
984   {"",0,NULL,0,0,0,NULL},
985 
986   {"          --- Editing  ---",0,NULL,0,0,0,NULL},
987   {"Adjust brush pick:",1,&(selected_config.Adjust_brush_pick),0,1,0,Lookup_YesNo},
988   {"Undo pages:",1,&(selected_config.Max_undo_pages),1,99,5,NULL},
989   {"Vertices per polygon:",4,&(selected_config.Nb_max_vertices_per_polygon),2,16384,5,NULL},
990   {"Fast zoom:",1,&(selected_config.Fast_zoom),0,1,0,Lookup_YesNo},
991   {"Clear with stencil:",1,&(selected_config.Clear_with_stencil),0,1,0,Lookup_YesNo},
992   {"Auto discontinuous:",1,&(selected_config.Auto_discontinuous),0,1,0,Lookup_YesNo},
993   {"Auto count colors:",1,&(selected_config.Auto_nb_used),0,1,0,Lookup_YesNo},
994   {"Right click colorpick:",1,&(selected_config.Right_click_colorpick),0,1,0,Lookup_YesNo},
995   {"Multi shortcuts:",1,&(selected_config.Allow_multi_shortcuts),0,1,0,Lookup_YesNo},
996   {"",0,NULL,0,0,0,NULL},
997 
998   {"      --- File selector  ---",0,NULL,0,0,0,NULL},
999   {"Show in fileselector",0,NULL,0,0,0,NULL},
1000   {"  Hidden files:",4,&(selected_config.Show_hidden_files),0,1,0,Lookup_YesNo},
1001   {"  Hidden dirs:",4,&(selected_config.Show_hidden_directories),0,1,0,Lookup_YesNo},
1002   {"Preview delay:",4,&(selected_config.Timer_delay), 1,256,3,NULL},
1003   {"Maximize preview:",1,&(selected_config.Maximize_preview), 0,1,0,Lookup_YesNo},
1004   {"Find file fast:",1,&(selected_config.Find_file_fast), 0,2,0,Lookup_FFF},
1005   {"Auto set resolution:",1,&(selected_config.Auto_set_res), 0,1,0,Lookup_YesNo},
1006   {"  According to:",1,&(selected_config.Set_resolution_according_to), 1,2,0,Lookup_AutoRes},
1007   {"Backup:",1,&(selected_config.Backup), 0,1,0,Lookup_YesNo},
1008   {"",0,NULL,0,0,0,NULL},
1009 
1010   {"      --- Format options  ---",0,NULL,0,0,0,NULL},
1011   {"Screen size in GIF:",1,&(selected_config.Screen_size_in_GIF),0,1,0,Lookup_YesNo},
1012   {"Clear palette:",1,&(selected_config.Clear_palette),0,1,0,Lookup_YesNo},
1013   {"MO6/TO8 palette gamma",1,&(selected_config.MOTO_gamma),10,30,2,NULL},
1014   {"",0,NULL,0,0,0,NULL},
1015   {"",0,NULL,0,0,0,NULL},
1016   {"",0,NULL,0,0,0,NULL},
1017   {"",0,NULL,0,0,0,NULL},
1018   {"",0,NULL,0,0,0,NULL},
1019   {"",0,NULL,0,0,0,NULL},
1020   {"",0,NULL,0,0,0,NULL},
1021 
1022 
1023   };
1024 
1025   const char * help_section[SETTING_PAGES] = {
1026     "GUI",
1027     "INPUT",
1028     "EDITING",
1029     "FILE SELECTOR",
1030     "FILE FORMAT OPTIONS",
1031   };
1032 
1033   selected_config=Config;
1034 
1035   Open_window(307,182,"Settings");
1036 
1037     // Button Reload
1038   Window_set_normal_button(  6,163, 51,14,"Reload"       ,1,1,KEY_r); // 1
1039     // Button Auto-save
1040   Window_set_normal_button( 73,163,107,14,"Auto-save:   ",1,1,KEY_a); // 2
1041     // Button Save
1042   Window_set_normal_button(183,163, 51,14,"Save"         ,1,1,KEY_s); // 3
1043     // Button Close
1044   Window_set_normal_button(250,163, 51,14,"Close"        ,0,1,KEY_ESC); // 4
1045 
1046   panel=Window_set_special_button(10, 21, 272,SETTING_PER_PAGE*SETTING_HEIGHT,0); // 5
1047   Window_set_scroller_button(285,21,SETTING_PER_PAGE*SETTING_HEIGHT,SETTING_PAGES,1,current_page); // 6
1048 
1049   Update_window_area(0,0,Window_width, Window_height);
1050   Display_cursor();
1051 
1052   do
1053   {
1054     if (need_redraw)
1055     {
1056       Hide_cursor();
1057       Settings_display_config(setting+current_page*SETTING_PER_PAGE, &selected_config, panel);
1058       if (need_redraw & 2)
1059       {
1060         // Including slider position
1061         Window_scroller_button_list->Position=current_page;
1062         Window_draw_slider(Window_scroller_button_list);
1063       }
1064 
1065       Display_cursor();
1066 
1067       need_redraw=0;
1068     }
1069 
1070     clicked_button=Window_clicked_button();
1071 
1072     switch(clicked_button)
1073     {
1074 
1075       case 1 : // Reload
1076         Settings_load_config(&selected_config);
1077         config_is_reloaded=1;
1078         need_redraw=1;
1079         break;
1080       case 2 : // Auto-save
1081         selected_config.Auto_save=!selected_config.Auto_save;
1082         need_redraw=1;
1083         break;
1084       case 3 : // Save
1085         Settings_save_config(&selected_config);
1086         break;
1087       // case 4: // Close
1088 
1089       case 5: // Panel area
1090         {
1091 
1092           int num=(((short)Mouse_Y-Window_pos_Y)/Menu_factor_Y - panel->Pos_Y)/SETTING_HEIGHT;
1093           if (num >= 0 && num < SETTING_PER_PAGE)
1094           {
1095             const T_Setting * item = &setting[current_page*SETTING_PER_PAGE+num];
1096             if (item->Type!=0)
1097             {
1098               // Remember which button is clicked
1099               byte old_mouse_k = Mouse_K;
1100 
1101               if (Window_normal_button_onclick(panel->Pos_X, panel->Pos_Y+num*SETTING_HEIGHT, panel->Width, SETTING_HEIGHT+1, 5))
1102               {
1103                 int value = Get_setting_value(item);
1104 
1105                 if (item->Lookup)
1106                 {
1107                   // Enum: toggle it
1108                   if (old_mouse_k & LEFT_SIDE)
1109                     value = Lookup_next(value, item->Lookup);
1110                   else
1111                     value = Lookup_previous(value, item->Lookup);
1112                   Set_setting_value(item, value);
1113                 }
1114                 else
1115                 {
1116                   // Numeric: edit it
1117                   char str[10];
1118                   str[0]='\0';
1119                   if (! (old_mouse_k & RIGHT_SIDE))
1120                     Num2str(value,str,item->Digits+1);
1121                   if (Readline(panel->Pos_X+3+176, panel->Pos_Y+num*SETTING_HEIGHT+(SETTING_HEIGHT-6)/2,str,item->Digits+1,INPUT_TYPE_INTEGER))
1122                   {
1123                     value=atoi(str);
1124                     if (value<item->Min_value)
1125                       value = item->Min_value;
1126                     else if (value>item->Max_value)
1127                       value = item->Max_value;
1128 
1129                     Set_setting_value(item, value);
1130                   }
1131                   Key=0; // Need to discard keys used during editing
1132                 }
1133               }
1134             }
1135           }
1136         }
1137         need_redraw=1;
1138         break;
1139       case 6: // Scroller
1140         current_page = Window_attribute2;
1141         need_redraw=1;
1142         break;
1143 
1144     }
1145 
1146     if (Key == KEY_MOUSEWHEELDOWN)
1147     {
1148       if (current_page < (SETTING_PAGES-1))
1149       {
1150         current_page++;
1151         need_redraw=2;
1152       }
1153     }
1154     else if (Key == KEY_MOUSEWHEELUP)
1155     {
1156       if (current_page > 0)
1157       {
1158         current_page--;
1159         need_redraw=2;
1160       }
1161     }
1162     else if (Is_shortcut(Key,0x100+BUTTON_HELP))
1163       Window_help(NB_BUTTONS+0, help_section[current_page]);
1164     else if (Is_shortcut(Key,0x100+BUTTON_SETTINGS))
1165       clicked_button=4;
1166   }
1167   while ( (clicked_button!=4) && (Key!=KEY_RETURN) && !Quit_is_required);
1168 
1169   // Checks on change
1170   if (Config.Show_hidden_directories!=selected_config.Show_hidden_directories
1171     ||Config.Show_hidden_files!=selected_config.Show_hidden_files)
1172   {
1173     // Reset fileselector offsets
1174     // since different files are shown now
1175     Main.selector.Position=0;
1176     Main.selector.Offset=0;
1177     Spare.selector.Position=0;
1178     Spare.selector.Offset=0;
1179     Brush_selector.Position=0;
1180     Brush_selector.Offset=0;
1181     Palette_selector.Position=0;
1182     Palette_selector.Offset=0;
1183   }
1184   if(Config.Allow_multi_shortcuts && !selected_config.Allow_multi_shortcuts)
1185   {
1186     // User just disabled multi shortcuts: make them unique now.
1187     Remove_duplicate_shortcuts();
1188   }
1189   // Copy all
1190   Config=selected_config;
1191 
1192   if (config_is_reloaded)
1193     Compute_optimal_menu_colors(Main.palette);
1194 
1195   Close_window();
1196   Unselect_button(btn);
1197   // Raffichage du menu pour que les inscriptions qui y figurent soient
1198   // retracées avec la nouvelle fonte
1199   Display_menu();
1200   Display_cursor();
1201 
1202   // On vérifie qu'on peut bien allouer le nombre de pages Undo.
1203   Set_number_of_backups(Config.Max_undo_pages);
1204 }
1205 
1206 // Data for skin selector
1207 T_Fileselector Skin_files_list;
1208 
1209 
1210 // Data for font selector
1211 T_Fileselector Font_files_list;
1212 
1213 //
Format_font_filename(const char * fname)1214 char * Format_font_filename(const char * fname)
1215 {
1216   static char result[12];
1217   int c;
1218   int length;
1219 
1220   fname+=strlen(FONT_PREFIX); // Omit file prefix
1221   length=strlen(fname) - 4; // assume .png extension
1222 
1223   for (c=0;c<11 && c<length ;c++)
1224   {
1225     result[c]=fname[c];
1226   }
1227   result[c]='\0';
1228   if (length>11)
1229     result[10] = ELLIPSIS_CHARACTER;
1230 
1231   return result;
1232 }
1233 
1234 // Add a skin to the list
Add_font_or_skin(const char * full_name,const char * fname)1235 static void Add_font_or_skin(const char * full_name, const char * fname)
1236 {
1237   size_t namelength;
1238   (void)full_name;
1239 
1240   namelength = strlen(fname);
1241   if (namelength>=10 && fname[0]!='_' && !strncasecmp(fname, SKIN_PREFIX, strlen(SKIN_PREFIX))
1242     && (!strcasecmp(fname + namelength - 4,".png")
1243     || !strcasecmp(fname + namelength - 4,".gif")))
1244   {
1245     Add_element_to_list(&Skin_files_list, fname, Format_filename(fname, 19, 0), FSOBJECT_FILE, ICON_NONE);
1246 
1247     if (fname[0]=='\0')
1248       return;
1249   }
1250   else if (namelength>=10 && !strncasecmp(fname, FONT_PREFIX, strlen(FONT_PREFIX))
1251     && (!strcasecmp(fname + namelength - 4, ".png")))
1252   {
1253     Add_element_to_list(&Font_files_list, fname, Format_font_filename(fname), FSOBJECT_FILE, ICON_NONE);
1254 
1255     if (fname[0]=='\0')
1256       return;
1257   }
1258 
1259 }
1260 
1261 // Callback to display a skin name in the list
Draw_one_skin_name(word x,word y,word index,byte highlighted)1262 void Draw_one_skin_name(word x, word y, word index, byte highlighted)
1263 {
1264   T_Fileselector_item * current_item;
1265 
1266   if (Skin_files_list.Nb_elements)
1267   {
1268     current_item = Get_item_by_index(&Skin_files_list, index);
1269     Print_in_window(x, y, current_item->Short_name, MC_Black,
1270       (highlighted)?MC_Dark:MC_Light);
1271   }
1272 }
1273 
1274 /// Skin selector window
Button_Skins(int btn)1275 void Button_Skins(int btn)
1276 {
1277   short clicked_button;
1278   short temp;
1279   char * skinsdir;
1280   T_Dropdown_button * font_dropdown;
1281   T_Dropdown_button * cursor_dropdown;
1282   T_List_button * skin_list;
1283   T_Scroller_button * file_scroller;
1284   int selected_font = 0;
1285   int selected_cursor = Config.Cursor;
1286   byte separatecolors = Config.Separate_colors;
1287   byte showlimits = Config.Display_image_limits;
1288   byte need_load=1;
1289   int button;
1290 
1291   word x, y, x_pos, offs_y;
1292 
1293   const char * cursors[] = { "Solid", "Transparent", "Thin" };
1294   T_Gui_skin * gfx = NULL;
1295   byte * new_font;
1296 
1297   #define FILESEL_Y 34
1298 
1299   // --- Read the contents of skins/ directory ------------------
1300 
1301   // Here we use the same data container as the fileselectors.
1302   // Reinitialize the list
1303   Free_fileselector_list(&Skin_files_list);
1304   Free_fileselector_list(&Font_files_list);
1305   // Browse the "skins" directory
1306   skinsdir = Filepath_append_to_dir(Data_directory, SKINS_SUBDIRECTORY);
1307   // Add each found file to the list
1308   For_each_file(skinsdir, Add_font_or_skin);
1309   // Sort it
1310   Sort_list_of_files(&Skin_files_list);
1311   Sort_list_of_files(&Font_files_list);
1312 
1313   selected_font = Find_file_in_fileselector(&Font_files_list, Config.Font_file);
1314   if (selected_font < 0)
1315     selected_font = 0;
1316 
1317   // --------------------------------------------------------------
1318 
1319   Open_window(290, 140, "Skins");
1320 
1321   // Frames
1322   Window_display_frame_in(6, FILESEL_Y - 2, 148, 84); // File selector
1323 
1324   // Texts
1325   Print_in_window( 172, 33,"Font:"            ,MC_Black,MC_Light);
1326   Print_in_window( 172, 59,"Cursor:"          ,MC_Black,MC_Light);
1327 
1328   // Ok button
1329   Window_set_normal_button(6, 120, 51, 14, "OK", 0, 1, KEY_RETURN); // 1
1330 
1331   // List of skins
1332   skin_list = Window_set_list_button(
1333   // Fileselector
1334   Window_set_special_button(8, FILESEL_Y + 1, 144, 80,0), // 2
1335     // Scroller for the fileselector
1336     (file_scroller = Window_set_scroller_button(155, FILESEL_Y - 1, 82,
1337     Skin_files_list.Nb_elements, 10, 0)), // 3
1338     Draw_one_skin_name, 2); // 4
1339 
1340   skin_list->Cursor_position = Find_file_in_fileselector(&Skin_files_list, Config.Skin_file);
1341   if (skin_list->Cursor_position < 0)
1342     skin_list->Cursor_position = 0;
1343 
1344   // Buttons to choose a font
1345   font_dropdown = Window_set_dropdown_button(172, 43, 104, 11, 0, Get_item_by_index(&Font_files_list,selected_font)->Short_name,1,0,1,RIGHT_SIDE|LEFT_SIDE,0); // 5
1346   for (temp=0; temp<Font_files_list.Nb_files; temp++)
1347     Window_dropdown_add_item(font_dropdown,temp,Get_item_by_index(&Font_files_list,temp)->Short_name);
1348 
1349   // Cancel
1350   Window_set_normal_button(61, 120, 51,14,"Cancel",0,1,KEY_ESCAPE); // 6
1351 
1352   // Dropdown list to choose cursor type
1353   cursor_dropdown = Window_set_dropdown_button(172, 69, 104, 11, 0,
1354     cursors[selected_cursor], 1, 0, 1, RIGHT_SIDE|LEFT_SIDE,0); // 7
1355   for (temp = 0; temp<3; temp++)
1356     Window_dropdown_add_item(cursor_dropdown, temp, cursors[temp]);
1357 
1358   Window_set_normal_button(172, 87, 14, 14,
1359     (Config.Display_image_limits)?"X":" ", -1, 1, KEY_NONE); // 8
1360   Print_in_window( 190, 85,"Draw picture", MC_Dark, MC_Light);
1361   Print_in_window( 190, 94,"limits", MC_Dark, MC_Light);
1362 
1363   Window_set_normal_button(172, 111, 14, 14,
1364     (Config.Separate_colors)?"X":" ", -1, 1, KEY_NONE); // 9
1365   Print_in_window( 190, 109,"Separate", MC_Dark, MC_Light);
1366   Print_in_window( 190, 118,"colors", MC_Dark, MC_Light);
1367 
1368   Window_redraw_list(skin_list);
1369 
1370   for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++)
1371     for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++)
1372       Pixel_in_window(x, y, Gfx->Preview[offs_y][x_pos]);
1373 
1374   Update_window_area(0, 0, Window_width, Window_height);
1375 
1376   Display_cursor();
1377 
1378   do
1379   {
1380     if (need_load)
1381     {
1382       need_load=0;
1383 
1384       Hide_cursor();
1385       // (Re-)load GUI graphics from selected skins
1386       free(skinsdir);
1387       skinsdir = strdup(Get_item_by_index(&Skin_files_list,
1388         skin_list->List_start + skin_list->Cursor_position)->Full_name);
1389 
1390       gfx = Load_graphics(skinsdir, NULL);
1391       if (gfx == NULL) // Error
1392       {
1393         Display_cursor();
1394         Verbose_message("Error!", Gui_loading_error_message);
1395         Hide_cursor();
1396         // Update preview
1397         Window_rectangle(6, 14, 173, 16, MC_Light);
1398       }
1399       else
1400       {
1401         // Update preview
1402 
1403         // Display the bitmap according to its own color indices
1404         for (y = 14, offs_y = 0; offs_y < 16; offs_y++, y++)
1405         for (x = 6, x_pos = 0; x_pos<173; x_pos++, x++)
1406         {
1407           if (gfx->Preview[offs_y][x_pos] == gfx->Color[0])
1408             Pixel_in_window(x, y, MC_Black);
1409           else if (gfx->Preview[offs_y][x_pos] == gfx->Color[1])
1410             Pixel_in_window(x, y,  MC_Dark);
1411           else if (gfx->Preview[offs_y][x_pos] == gfx->Color[3])
1412             Pixel_in_window(x, y, MC_White);
1413           else if (gfx->Preview[offs_y][x_pos] == gfx->Color[2])
1414             Pixel_in_window(x, y, MC_Light);
1415         }
1416         // Actualize current screen according to preferred GUI colors
1417         // Note this only updates onscreen colors
1418         Set_color(
1419           MC_Black,
1420           gfx->Default_palette[gfx->Color[0]].R,
1421           gfx->Default_palette[gfx->Color[0]].G,
1422           gfx->Default_palette[gfx->Color[0]].B);
1423         Set_color(
1424           MC_Dark,
1425           gfx->Default_palette[gfx->Color[1]].R,
1426           gfx->Default_palette[gfx->Color[1]].G,
1427           gfx->Default_palette[gfx->Color[1]].B);
1428         Set_color(
1429           MC_Light,
1430           gfx->Default_palette[gfx->Color[2]].R,
1431           gfx->Default_palette[gfx->Color[2]].G,
1432           gfx->Default_palette[gfx->Color[2]].B);
1433         Set_color(
1434           MC_White,
1435           gfx->Default_palette[gfx->Color[3]].R,
1436           gfx->Default_palette[gfx->Color[3]].G,
1437           gfx->Default_palette[gfx->Color[3]].B);
1438       }
1439       Update_window_area(6, 14, 173, 16);
1440       Display_cursor();
1441     }
1442 
1443     clicked_button=Window_clicked_button();
1444     if (Is_shortcut(Key,0x100+BUTTON_HELP))
1445       Window_help(BUTTON_SETTINGS, "SKINS");
1446 
1447     switch(clicked_button)
1448     {
1449       case 1 : // OK
1450         break;
1451       case 2 : // double-click file: do nothing
1452         break;
1453       case 3 : // doesn't happen
1454         break;
1455       case 4 : // a file is selected
1456           need_load=1;
1457         break;
1458       case 5 : // Font dropdown
1459       {
1460         T_Fileselector_item* fontName;
1461         selected_font = Window_attribute2; // Get the index of the chosen font.
1462         fontName = Get_item_by_index(&Font_files_list,selected_font);
1463         new_font = Load_font(fontName->Full_name, 1);
1464         if (new_font)
1465         {
1466           free(Menu_font);
1467           Menu_font = new_font;
1468           Print_in_window( 172, 33,"Font:"            ,MC_Black,MC_Light);
1469           Print_in_window_limited(font_dropdown->Pos_X+2,font_dropdown->Pos_Y+(font_dropdown->Height-7)/2,
1470             fontName->Short_name,(byte)strlen(fontName->Short_name) ,MC_Black,MC_Light);
1471           Update_window_area(172, 33, 8 * 5, 8);
1472         }
1473         break;
1474       }
1475       // 6: Cancel
1476       case 7 : // Cursor
1477         selected_cursor = Window_attribute2;
1478         break;
1479       case 8: // Display limits
1480         showlimits = !showlimits;
1481         Hide_cursor();
1482         Print_in_window(175, 90, (showlimits)?"X":" ", MC_Black, MC_Light);
1483         Display_cursor();
1484         break;
1485       case 9: // Separate colors
1486         separatecolors = !separatecolors;
1487         Hide_cursor();
1488         Print_in_window(175, 114, (separatecolors)?"X":" ", MC_Black, MC_Light);
1489         Display_cursor();
1490         break;
1491     }
1492   }
1493   while ( (clicked_button!=1) && (clicked_button !=6) && (Key != KEY_ESCAPE) && !Quit_is_required);
1494 
1495   if(clicked_button == 1)
1496   {
1497     if (gfx != NULL)
1498     {
1499       Set_current_skin(skinsdir, gfx);
1500     }
1501     // (Re-)load the selected font
1502     new_font = Load_font(Get_item_by_index(&Font_files_list,selected_font)->Full_name, 1);
1503     if (new_font)
1504     {
1505       const char * fname;
1506 
1507       free(Menu_font);
1508       Menu_font = new_font;
1509       fname = Get_item_by_index(&Font_files_list,selected_font)->Full_name;
1510       free(Config.Font_file);
1511       Config.Font_file = (char *)strdup(fname);
1512     }
1513     // Confirm the change of cursor shape
1514     Config.Cursor = selected_cursor;
1515     Config.Display_image_limits = showlimits;
1516     Config.Separate_colors = separatecolors;
1517 
1518     // Now find the best colors for the new skin in the current palette
1519     // and remap the skin
1520     Compute_optimal_menu_colors(Main.palette);
1521 
1522   }
1523 
1524   // We don't want to keep the skin's palette, as this would corrupt the current picture's one.
1525   Set_palette(Main.palette);
1526 
1527   Close_window();
1528   Unselect_button(btn);
1529 
1530   // Raffichage du menu pour que les inscriptions qui y figurent soient retracées avec la nouvelle fonte
1531   Display_menu();
1532   // Redraw all buttons, to ensure all specific sprites are in place.
1533   // This is necessary for multi-state buttons, for example Freehand.
1534   for (button=0; button<NB_BUTTONS; button++)
1535   {
1536     byte state=Buttons_Pool[button].Pressed;
1537     switch(button)
1538     {
1539       case BUTTON_MAGNIFIER:
1540         state|=Main.magnifier_mode;
1541         break;
1542       case BUTTON_EFFECTS:
1543         state|=Any_effect_active();
1544         break;
1545     }
1546     Draw_menu_button(button,state);
1547   }
1548   Display_cursor();
1549   free(skinsdir);
1550 }
1551 
1552 
1553 //---------------------------- Changement de page ----------------------------
Button_Page(int btn)1554 void Button_Page(int btn)
1555 {
1556   byte   factor_index;
1557   T_Document temp_doc;
1558 
1559   Hide_cursor();
1560 
1561   if (Config.Sync_views)
1562     Copy_view_to_spare();
1563 
1564   // First update the page descriptors before swapping them
1565   Upload_infos_page(&Main);
1566   Upload_infos_page(&Spare);
1567 
1568   // SWAP
1569   memcpy(&temp_doc, &Main, sizeof(T_Document));
1570   memcpy(&Main, &Spare, sizeof(T_Document));
1571   memcpy(&Spare, &temp_doc, sizeof(T_Document));
1572 
1573   Pixel_preview=(Main.magnifier_mode)?Pixel_preview_magnifier:Pixel_preview_normal;
1574 
1575   //Redraw_layered_image();
1576   // replaced by
1577   Update_buffers(Main.image_width, Main.image_height);
1578   Update_depth_buffer();
1579   Update_screen_targets();
1580   End_of_modification();
1581   // --
1582 
1583   // A la fin, on affiche l'écran
1584   for (factor_index=0; ZOOM_FACTOR[factor_index]!=Main.magnifier_factor; factor_index++);
1585   //Change.magnifier_factor(factor_index,0);
1586   Compute_magnifier_data();
1587   if (Main.magnifier_mode)
1588     Pixel_preview=Pixel_preview_magnifier;
1589   else
1590     Pixel_preview=Pixel_preview_normal;
1591   Compute_limits();
1592   Compute_paintbrush_coordinates();
1593 
1594   Set_palette(Main.palette);
1595   Compute_optimal_menu_colors(Main.palette);
1596   Check_menu_mode();
1597   Display_all_screen();
1598   Unselect_button(btn);
1599   Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
1600   // Tilemap mode might be different
1601   Draw_menu_button(BUTTON_EFFECTS,Any_effect_active());
1602   Display_menu();
1603 
1604   Display_cursor();
1605 }
1606 
1607 
1608 // -- Copie de page ---------------------------------------------------------
1609 
Copy_image_only(void)1610 void Copy_image_only(void)
1611 {
1612   word old_width=Spare.image_width;
1613   word old_height=Spare.image_height;
1614 
1615   if (Backup_and_resize_the_spare(Main.image_width,Main.image_height))
1616   {
1617     byte i;
1618 
1619     for (i=0; i<Spare.backups->Pages->Nb_layers; i++)
1620     {
1621       if (i == Spare.current_layer)
1622       {
1623         // Copy the current layer
1624         memcpy(Spare.backups->Pages->Image[i].Pixels,Main.backups->Pages->Image[Main.current_layer].Pixels,Main.image_width*Main.image_height);
1625       }
1626       else
1627       {
1628         // Resize the original layer
1629         Copy_part_of_image_to_another(
1630         Spare.backups->Pages->Next->Image[i].Pixels,0,0,Min(old_width,Spare.image_width),
1631         Min(old_height,Spare.image_height),old_width,
1632         Spare.backups->Pages->Image[i].Pixels,0,0,Spare.image_width);
1633       }
1634     }
1635 
1636     // Copie des dimensions de l'image
1637     /*
1638       C'est inutile, le "Backuper et redimensionner brouillon" a déjà modifié
1639       ces valeurs pour qu'elles soient correctes.
1640     */
1641     /*
1642     Spare.image_width=Main.image_width;
1643     Spare.image_height=Main.image_height;
1644     */
1645 
1646     Copy_view_to_spare();
1647 
1648     // Update the visible buffer of the spare.
1649     // It's a bit complex because at the moment, to save memory,
1650     // the spare doesn't have a full visible_buffer + depth_buffer,
1651     // so I can't use exactly the same technique as for Main page.
1652     // (It's the same reason that the "Page" function gets complex,
1653     // it needs to rebuild a depth buffer only, trusting the
1654     // depth buffer that was already available in Spare_.)
1655     Update_spare_buffers(Spare.image_width,Spare.image_height);
1656     Redraw_spare_image();
1657 
1658   }
1659   else
1660     Message_out_of_memory();
1661 }
1662 
1663 
Copy_some_colors(void)1664 void Copy_some_colors(void)
1665 {
1666   short index;
1667   byte confirmation=0;
1668   static byte mask_color_to_copy[256]; // static to use less stack
1669 
1670   memset(mask_color_to_copy,1,256);
1671   Menu_tag_colors("Tag colors to copy",mask_color_to_copy,&confirmation,0, NULL, 0xFFFF);
1672 
1673   if (confirmation)
1674   {
1675     // Make a backup with the same pixel data as previous history steps
1676     Backup_the_spare(LAYER_NONE);
1677     for (index=0; index<256; index++)
1678     {
1679       if (mask_color_to_copy[index])
1680         memcpy(Spare.palette+index,Main.palette+index,
1681                sizeof(T_Components));
1682     }
1683   }
1684 }
1685 
1686 
Button_Copy_page(int btn)1687 void Button_Copy_page(int btn)
1688 {
1689   short clicked_button;
1690 
1691 
1692   Open_window(168,137,"Copy to spare page");
1693 
1694   Window_set_normal_button(10, 20,148,14,"Pixels + palette" , 0,1,KEY_RETURN); // 1
1695   Window_set_normal_button(10, 37,148,14,"Pixels only"      , 3,1,KEY_x); // 2
1696   Window_set_normal_button(10, 54,148,14,"Palette only"     , 1,1,KEY_p); // 3
1697   Window_set_normal_button(10, 71,148,14,"Some colors only" , 6,1,KEY_c); // 4
1698   Window_set_normal_button(10, 88,148,14,"Palette and remap",13,1,KEY_r); // 5
1699   Window_set_normal_button(44,114, 80,14,"Cancel"           , 0,1,KEY_ESC); // 6
1700   Update_window_area(0,0,Window_width, Window_height);
1701 
1702   Display_cursor();
1703 
1704   do
1705   {
1706     clicked_button=Window_clicked_button();
1707     if (Is_shortcut(Key,0x100+BUTTON_HELP))
1708       Window_help(BUTTON_PAGE, NULL);
1709     else if (Is_shortcut(Key,0x200+BUTTON_PAGE))
1710       clicked_button=6;
1711   }
1712   while (clicked_button<=0 && !Quit_is_required);
1713 
1714   Close_window();
1715   Display_cursor();
1716 
1717   switch (clicked_button)
1718   {
1719     case 1: // Pixels+palette
1720       // backup is done by the following function
1721       Copy_image_only();
1722       // copie de la palette
1723       memcpy(Spare.palette,Main.palette,sizeof(T_Palette));
1724       // Equivalent of 'end_of_modifications' for spare.
1725       Update_spare_buffers(Spare.image_width,Spare.image_height);
1726       Redraw_spare_image();
1727       Spare.image_is_modified=1;
1728       if (Spare.tilemap_mode)
1729         Disable_tilemap(&Spare);
1730       break;
1731 
1732     case 2: // Pixels only
1733       // backup is done by the following function
1734       Copy_image_only();
1735       // Equivalent of 'end_of_modifications' for spare.
1736       Update_spare_buffers(Spare.image_width,Spare.image_height);
1737       Redraw_spare_image();
1738       Spare.image_is_modified=1;
1739       if (Spare.tilemap_mode)
1740         Disable_tilemap(&Spare);
1741       break;
1742 
1743     case 3: // Palette only
1744       Backup_the_spare(LAYER_NONE);
1745       // Copy palette
1746       memcpy(Spare.palette,Main.palette,sizeof(T_Palette));
1747       // Equivalent of 'end_of_modifications' for spare.
1748       Update_spare_buffers(Spare.image_width,Spare.image_height);
1749       Redraw_spare_image();
1750       Spare.image_is_modified=1;
1751       break;
1752 
1753     case 4: // Some colors
1754       // Will backup if needed
1755       Copy_some_colors();
1756       break;
1757 
1758     case 5: // Palette and remap
1759       Backup_the_spare(LAYER_ALL);
1760       Remap_spare();
1761       // Copy palette
1762       memcpy(Spare.palette,Main.palette,sizeof(T_Palette));
1763       // Equivalent of 'end_of_modifications' for spare.
1764       Update_spare_buffers(Spare.image_width,Spare.image_height);
1765       Redraw_spare_image();
1766       Spare.image_is_modified=1;
1767       break;
1768   }
1769 
1770   Hide_cursor();
1771   Unselect_button(btn);
1772   Display_cursor();
1773 }
1774 
1775 
1776 // -- Suppression d'une page -------------------------------------------------
Button_Kill(int btn)1777 void Button_Kill(int btn)
1778 {
1779   if ( (Main.backups->List_size==1)
1780     || (!Confirmation_box("Delete the current page?")) )
1781   {
1782     if (Main.backups->List_size==1)
1783       Warning_message("You can't delete the last page.");
1784     Hide_cursor();
1785     Unselect_button(btn);
1786     Display_cursor();
1787   }
1788   else
1789   {
1790     Hide_cursor();
1791     Free_current_page();
1792 
1793     Set_palette(Main.palette);
1794     Compute_optimal_menu_colors(Main.palette);
1795 
1796     Display_all_screen();
1797     Unselect_button(btn);
1798     Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
1799     Display_menu();
1800     Display_cursor();
1801   }
1802 }
1803 
1804 
1805 //------------------------- Dimensions Image/Screen ---------------------------
1806 
Check_mode_button(short x_pos,short y_pos,byte state)1807 void Check_mode_button(short x_pos, short y_pos, byte state)
1808 {
1809   byte color;
1810 
1811   switch (state & 0x7F)
1812   {
1813     case 0 : color=MC_White; break;
1814     case 1 : color=MC_Light; break;
1815     case 2 : color=MC_Dark; break;
1816     default: color=MC_Black;
1817   }
1818   Window_rectangle(x_pos, y_pos, 9, 3, color);
1819   Update_window_area(x_pos, y_pos,9,3);
1820 }
1821 
1822 /// Number of video modes to display in the resolution menu
1823 #define MODELIST_LINES 10
1824 
Display_modes_list(short list_start,short cursor_position)1825 void Display_modes_list(short list_start, short cursor_position)
1826 {
1827   short index,current_mode;
1828   short y_pos;
1829   byte  text_color,background_color;
1830   char str[29];
1831   char *ratio;
1832 
1833   for (current_mode=list_start,index=0; index<MODELIST_LINES && current_mode < Nb_video_modes ; index++,current_mode++)
1834   {
1835     y_pos=86+(index<<3);
1836     Check_mode_button(19,y_pos+2,Video_mode[current_mode].State);
1837 
1838     if (cursor_position!=index)
1839     {
1840       background_color =MC_Black;
1841       if ((Video_mode[current_mode].State & 3) == 3)
1842         text_color=MC_Dark;
1843       else
1844         text_color=MC_Light;
1845     }
1846     else
1847     {
1848       background_color =MC_Dark;
1849       if ((Video_mode[current_mode].State & 3) == 3)
1850         text_color=MC_Light;
1851       else
1852         text_color=MC_White;
1853     }
1854     snprintf(str, sizeof(str), "%4hu %4hu", Video_mode[current_mode].Width, Video_mode[current_mode].Height);
1855 
1856     if(Video_mode[current_mode].Fullscreen == 0)
1857       memcpy(str+9,"   Window          ",20);
1858     else
1859     {
1860       memcpy(str+9," Fullscreen ",13);
1861 
1862       if (Video_mode[current_mode].Width*3 == Video_mode[current_mode].Height*4)
1863         ratio="    4:3";
1864       else if (Video_mode[current_mode].Width*9 == Video_mode[current_mode].Height*16)
1865         ratio="   16:9";
1866       else if (Video_mode[current_mode].Width*10 == Video_mode[current_mode].Height*16)
1867         ratio="  16:10";
1868       else if (Video_mode[current_mode].Width*145 == Video_mode[current_mode].Height*192)
1869         ratio="192:145";
1870       else if (Video_mode[current_mode].Width*2 == Video_mode[current_mode].Height*3)
1871         ratio="    3:2";
1872       else if (Video_mode[current_mode].Width*3 == Video_mode[current_mode].Height*5)
1873         ratio="    5:3";
1874       else if (Video_mode[current_mode].Width*4 == Video_mode[current_mode].Height*5)
1875         ratio="    5:4";
1876       else if (Video_mode[current_mode].Width*16 == Video_mode[current_mode].Height*25)
1877         ratio="  25:16";
1878       else
1879         ratio="       ";
1880 
1881       strcpy(str+21,ratio);
1882     }
1883 
1884     Print_in_window(38,y_pos,str,text_color,background_color);
1885   }
1886 }
1887 
1888 
Scroll_list_of_modes(short list_start,short cursor_position,int * selected_mode)1889 void Scroll_list_of_modes(short list_start, short cursor_position, int * selected_mode)
1890 {
1891   Hide_cursor();
1892   *selected_mode=list_start+cursor_position;
1893   if (Window_scroller_button_list->Position!=list_start)
1894   {
1895     Window_scroller_button_list->Position=list_start;
1896     Window_draw_slider(Window_scroller_button_list);
1897   }
1898   Display_modes_list(list_start,cursor_position);
1899   Display_cursor();
1900 }
1901 
Button_Resolution(int btn)1902 void Button_Resolution(int btn)
1903 {
1904   short clicked_button;
1905   int   selected_mode;
1906   word  chosen_width;
1907   word  chosen_height;
1908   byte  chosen_pixel;
1909   short list_start;
1910   short cursor_position;
1911   short temp;
1912   char  str[8];
1913   T_Special_button * input_width_button, * input_button_height;
1914   T_Dropdown_button * pixel_button;
1915   static const char *pixel_ratio_labels[PIXEL_MAX] ={
1916     "Normal    (1x1)",
1917     "Wide      (2x1)",
1918     "Tall      (1x2)",
1919     "Double    (2x2)",
1920     "Triple    (3x3)",
1921     "Wide2     (4x2)",
1922     "Tall2     (2x4)",
1923     "Tall3     (3x4)",
1924     "Quadruple (4x4)"};
1925 
1926   Open_window(299,190,"Picture & screen sizes");
1927 
1928   Print_in_window( 12, 21,"Picture size:"   ,MC_Dark,MC_Light);
1929   Window_display_frame      ( 8,17,195, 33);
1930 
1931   Window_set_normal_button(223, 18,67,14,"OK"      ,0,1,KEY_RETURN); // 1
1932   Window_set_normal_button(223, 35,67,14,"Cancel"  ,0,1,KEY_ESC);  // 2
1933 
1934   Print_in_window_underscore( 12, 37,"Width:",MC_Dark,MC_Light,1);
1935   input_width_button=Window_set_input_button_s( 60, 35,4,KEY_w);     // 3
1936 
1937   Print_in_window_underscore(108, 37,"Height:",MC_Dark,MC_Light,1);
1938   input_button_height=Window_set_input_button_s(164, 35,4,KEY_h); // 4
1939 
1940   Window_display_frame      ( 8,72,283,110);
1941   Window_display_frame_in   (37,84,228,84);
1942   Window_rectangle          (38,85,226,82,MC_Black);
1943   Print_in_window( 16, 76,"OK"              ,MC_Dark,MC_Light);
1944   Print_in_window( 55, 76,"X    Y"          ,MC_Dark,MC_Light);
1945   Print_in_window(120, 76,"Win / Full"      ,MC_Dark,MC_Light);
1946   Print_in_window(219, 76,"Ratio"           ,MC_Dark,MC_Light);
1947   Print_in_window( 30,170,"\03"             ,MC_Dark,MC_Light);
1948   Print_in_window( 62,170,"OK"              ,MC_Dark,MC_Light);
1949   Print_in_window(102,170,"Imperfect"       ,MC_Dark,MC_Light);
1950   Print_in_window(196,170,"Unsupported"     ,MC_Dark,MC_Light);
1951   Window_set_special_button(38,86,225,80,0);                       // 5
1952 
1953   selected_mode=Current_resolution;
1954   if (selected_mode>=MODELIST_LINES/2 && Nb_video_modes > MODELIST_LINES)
1955   {
1956     if (selected_mode<Nb_video_modes-MODELIST_LINES/2)
1957     {
1958       list_start=selected_mode-(MODELIST_LINES/2-1);
1959       cursor_position=(MODELIST_LINES/2-1);
1960     }
1961     else
1962     {
1963       list_start=Nb_video_modes-MODELIST_LINES;
1964       cursor_position=selected_mode-list_start;
1965     }
1966   }
1967   else
1968   {
1969     list_start=0;
1970     cursor_position=selected_mode;
1971   }
1972   Window_set_scroller_button(271,85,81,Nb_video_modes,MODELIST_LINES,list_start); // 6
1973 
1974   chosen_pixel=Pixel_ratio;
1975   Print_in_window( 12, 57,"Pixel size:"    ,MC_Dark,MC_Light);
1976   pixel_button=Window_set_dropdown_button(108,55,17*8,11,17*8,pixel_ratio_labels[Pixel_ratio],1,0,1,LEFT_SIDE|RIGHT_SIDE,0);    // 7
1977   for (temp=0;temp<PIXEL_MAX;temp++)
1978     Window_dropdown_add_item(pixel_button,temp,pixel_ratio_labels[temp]);
1979 
1980   // 10 little buttons for the state of each visible mode
1981   for (temp=0; temp<MODELIST_LINES && temp < Nb_video_modes; temp++)
1982     Window_set_normal_button(17,86+(temp<<3),13,7,"",0,1,KEY_NONE);// 8..17
1983 
1984   // Dummy buttons as explainations of colors
1985   Window_draw_normal_bouton( 16,170,13,7,"",0,0);
1986   Check_mode_button( 18,172,0);
1987   Window_draw_normal_bouton( 48,170,13,7,"",0,0);
1988   Check_mode_button( 50,172,1);
1989   Window_draw_normal_bouton( 88,170,13,7,"",0,0);
1990   Check_mode_button( 90,172,2);
1991   Window_draw_normal_bouton(182,170,13,7,"",0,0);
1992   Check_mode_button(184,172,3);
1993 
1994 
1995   chosen_width=Main.image_width;
1996   Num2str(chosen_width,str,4);
1997   Window_input_content(input_width_button,str);
1998 
1999   chosen_height=Main.image_height;
2000   Num2str(chosen_height,str,4);
2001   Window_input_content(input_button_height,str);
2002 
2003   Display_modes_list(list_start,cursor_position);
2004 
2005   Update_window_area(0,0,Window_width, Window_height);
2006 
2007   Display_cursor();
2008 
2009   do
2010   {
2011     clicked_button=Window_clicked_button();
2012 
2013     switch (clicked_button)
2014     { case -1: case 0: case 1: case 2:
2015         break;
2016 
2017       case 3 : // Largeur
2018         Num2str(chosen_width,str,4);
2019         Readline(62,37,str,4,INPUT_TYPE_INTEGER);
2020         chosen_width=atoi(str);
2021         // On corrige les dimensions
2022         if (chosen_width==0)
2023         {
2024           chosen_width=1;
2025           Num2str(chosen_width,str,4);
2026           Window_input_content(input_width_button,str);
2027         }
2028         Display_cursor();
2029         break;
2030 
2031       case 4 : // Height
2032         Num2str(chosen_height,str,4);
2033         Readline(166,37,str,4,INPUT_TYPE_INTEGER);
2034         chosen_height=atoi(str);
2035         // On corrige les dimensions
2036         if (chosen_height==0)
2037         {
2038           chosen_height=1;
2039           Num2str(chosen_height,str,4);
2040           Window_input_content(input_button_height,str);
2041         }
2042         Display_cursor();
2043         break;
2044 
2045       case 5: // Liste des modes
2046         temp=(((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-86)>>3;
2047         if (temp<Nb_video_modes && ((Mouse_K==2) || (temp!=cursor_position)))
2048         {
2049           Hide_cursor();
2050           if (temp!=cursor_position)
2051           {
2052             cursor_position=temp;
2053             Display_modes_list(list_start,cursor_position);
2054           }
2055           selected_mode=list_start+cursor_position;
2056           // Si l'utilisateur s'est servi du bouton droit de la souris:
2057           if (Mouse_K==2)
2058           {
2059             // On affecte également les dimensions de l'image:
2060             chosen_width=Video_mode[selected_mode].Width/Pixel_width;
2061             Num2str(chosen_width,str,4);
2062             Window_input_content(input_width_button,str);
2063 
2064             chosen_height=Video_mode[selected_mode].Height/Pixel_height;
2065             Num2str(chosen_height,str,4);
2066             Window_input_content(input_button_height,str);
2067           }
2068           Display_cursor();
2069         }
2070         Wait_end_of_click();
2071         break;
2072 
2073       case 6: // Scroller
2074         list_start=Window_attribute2;
2075         selected_mode=list_start+cursor_position;
2076         Display_modes_list(list_start,cursor_position);
2077         break;
2078 
2079       case 7: // Pixel size
2080         chosen_pixel=Window_attribute2;
2081         break;
2082 
2083       default: // Boutons de tag des états des modes
2084         temp=list_start+clicked_button-8;
2085         if (Video_mode[temp].Fullscreen==1 && // On n'a pas le droit de cocher le mode fenêtré
2086             !(Video_mode[temp].State & 128)) // Ni ceux non détectés par SDL
2087         {
2088           if (Window_attribute1==LEFT_SIDE)
2089             Video_mode[temp].State=((Video_mode[temp].State&0x7F)+1)&3;
2090           else
2091             Video_mode[temp].State=((Video_mode[temp].State&0x7F)+3)&3;
2092 
2093           Hide_cursor();
2094           //Check_mode_button(19,16+(clicked_button<<3),Video_mode[temp].State);
2095           Display_modes_list(list_start,cursor_position);
2096           Display_cursor();
2097         }
2098     }
2099 
2100     // Gestion des touches de déplacement dans la liste
2101     switch (Key)
2102     {
2103       case KEY_UP : // Haut
2104         if (cursor_position>0)
2105           cursor_position--;
2106         else
2107           if (list_start>0)
2108             list_start--;
2109         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2110         Key=0;
2111         break;
2112       case KEY_DOWN : // Bas
2113         if (cursor_position<(MODELIST_LINES-1) && cursor_position<(Nb_video_modes-1))
2114           cursor_position++;
2115         else
2116           if (list_start<Nb_video_modes-MODELIST_LINES)
2117             list_start++;
2118         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2119         Key=0;
2120         break;
2121       case KEY_PAGEUP : // PageUp
2122         if (cursor_position>0)
2123           cursor_position=0;
2124         else
2125         {
2126           if (list_start>(MODELIST_LINES-1))
2127             list_start-=(MODELIST_LINES-1);
2128           else
2129             list_start=0;
2130         }
2131         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2132         Key=0;
2133         break;
2134       case KEY_PAGEDOWN : // PageDown
2135         if (Nb_video_modes<MODELIST_LINES)
2136           cursor_position=Nb_video_modes-1;
2137         else if (cursor_position<(MODELIST_LINES-1))
2138           cursor_position=(MODELIST_LINES-1);
2139         else
2140         {
2141           if (list_start<Nb_video_modes-(MODELIST_LINES*2-1))
2142             list_start+=(MODELIST_LINES-1);
2143           else
2144             list_start=Nb_video_modes-MODELIST_LINES;
2145         }
2146         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2147         Key=0;
2148         break;
2149       case KEY_HOME : // Home
2150         list_start=0;
2151         cursor_position=0;
2152         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2153         Key=0;
2154         break;
2155       case KEY_END : // End
2156         if (Nb_video_modes<MODELIST_LINES)
2157           cursor_position=Nb_video_modes-1;
2158         else
2159         {
2160           list_start=Nb_video_modes-MODELIST_LINES;
2161           cursor_position=(MODELIST_LINES-1);
2162         }
2163         Scroll_list_of_modes(list_start,cursor_position,&selected_mode);
2164         Key=0;
2165         break;
2166       default:
2167         if (Is_shortcut(Key,0x100+BUTTON_HELP))
2168         {
2169           Window_help(BUTTON_RESOL, NULL);
2170           Key=0;
2171           break;
2172         }
2173     }
2174 
2175   }
2176   while ((clicked_button!=1) && (clicked_button!=2) && !Quit_is_required);
2177 
2178   Close_window();
2179 
2180   if (clicked_button==1) // OK
2181   {
2182     if (Main.magnifier_mode)
2183       Unselect_button(BUTTON_MAGNIFIER);
2184 
2185     if ( (chosen_width!=Main.image_width)
2186       || (chosen_height!=Main.image_height) )
2187     {
2188       Resize_image(chosen_width,chosen_height);
2189       End_of_modification();
2190       Tilemap_update();
2191     }
2192 
2193     if ((Video_mode[selected_mode].State & 3) == 3 ||
2194       Init_mode_video(
2195         Video_mode[selected_mode].Width,
2196         Video_mode[selected_mode].Height,
2197         Video_mode[selected_mode].Fullscreen,
2198         chosen_pixel))
2199     {
2200       Error(0); // Tell user it is an invalid mode
2201       Pixel_ratio=PIXEL_SIMPLE;
2202       Init_mode_video(
2203         Video_mode[Current_resolution].Width,
2204         Video_mode[Current_resolution].Height,
2205         Video_mode[Current_resolution].Fullscreen,
2206         Pixel_ratio);
2207     }
2208 
2209     Display_menu();
2210     Reposition_palette();
2211     Display_all_screen();
2212   }
2213   Paintbrush_X = Mouse_X;
2214   Paintbrush_Y = Mouse_Y;
2215 
2216 
2217   Unselect_button(btn);
2218   Display_cursor();
2219 }
2220 
2221 
Button_Safety_resolution(int btn)2222 void Button_Safety_resolution(int btn)
2223 {
2224   // In windowed mode, do nothing
2225   if (Current_resolution==0)
2226   {
2227     Hide_cursor();
2228     Unselect_button(btn);
2229     Display_cursor();
2230     return;
2231   }
2232 
2233   Hide_cursor();
2234 
2235   Unselect_button(BUTTON_MAGNIFIER);
2236 
2237   Init_mode_video(
2238     Video_mode[0].Width,
2239     Video_mode[0].Height,
2240     Video_mode[0].Fullscreen,
2241     PIXEL_SIMPLE);
2242   Current_resolution=0;
2243   Display_menu();
2244   Reposition_palette();
2245   Display_all_screen();
2246 
2247   Unselect_button(btn);
2248   // Le pinceau est affiché à la position du clic et pas
2249   Display_cursor();
2250 }
2251 
2252 
2253 //------------------ Gestion des boutons de dessin à la main -----------------
2254 
Button_Draw(int btn)2255 void Button_Draw(int btn)
2256 {
2257   (void)btn;
2258   Hide_cursor();
2259   Start_operation_stack(Selected_freehand_mode);
2260   Display_cursor();
2261 }
2262 
2263 
Button_Draw_switch_mode(int btn)2264 void Button_Draw_switch_mode(int btn)
2265 {
2266   char icon;
2267 
2268   T_Dropdown_button dropdown;
2269   T_Dropdown_choice *item = NULL;
2270   int i;
2271   static const char text[4][14] =
2272     {"Continuous", "Discontinuous", "Single", "Contour fill"};
2273 
2274   dropdown.Pos_X         =Buttons_Pool[btn].X_offset;
2275   dropdown.Pos_Y         =Buttons_Pool[btn].Y_offset;
2276   dropdown.Height        =Buttons_Pool[btn].Height;
2277   dropdown.Dropdown_width=14*8;
2278   dropdown.First_item    =NULL;
2279   dropdown.Bottom_up     =1;
2280 
2281   Hide_cursor();
2282 
2283   // If we get here from a keyboard shortcut, don't show the menu and directly
2284   // switch to the next drawing mode.
2285   if (Mouse_K != 0) {
2286 
2287     for(i = 0; i < 4; i++) {
2288       Window_dropdown_add_item(&dropdown, i, text[i]);
2289     }
2290 
2291     item=Dropdown_activate(&dropdown,0,Menu_Y);
2292   }
2293 
2294   if (item)
2295   {
2296     Selected_freehand_mode = item->Number;
2297   } else {
2298     Selected_freehand_mode++;
2299     if (Selected_freehand_mode>OPERATION_FILLED_CONTOUR)
2300       Selected_freehand_mode=OPERATION_CONTINUOUS_DRAW;
2301   }
2302 
2303   switch(Selected_freehand_mode)
2304   {
2305     default:
2306     case OPERATION_CONTINUOUS_DRAW:
2307       icon=-1;
2308       break;
2309     case OPERATION_DISCONTINUOUS_DRAW:
2310       icon=MENU_SPRITE_DISCONTINUOUS_DRAW;
2311       break;
2312     case OPERATION_POINT_DRAW:
2313       icon=MENU_SPRITE_POINT_DRAW;
2314       break;
2315     case OPERATION_FILLED_CONTOUR:
2316       icon=MENU_SPRITE_CONTOUR_DRAW;
2317       break;
2318   }
2319   Display_sprite_in_menu(btn,icon);
2320   Draw_menu_button(btn,BUTTON_PRESSED);
2321   Start_operation_stack(Selected_freehand_mode);
2322 
2323   Display_cursor();
2324   Window_dropdown_clear_items(&dropdown);
2325 }
2326 
2327 
2328 // -- Gestion des boutons de rectangle vide et plein ------------------------
2329 
Button_Empty_rectangle(int btn)2330 void Button_Empty_rectangle(int btn)
2331 {
2332   (void)btn;
2333   Hide_cursor();
2334   Start_operation_stack(OPERATION_EMPTY_RECTANGLE);
2335   Display_cursor();
2336 }
2337 
2338 
Button_Filled_rectangle(int btn)2339 void Button_Filled_rectangle(int btn)
2340 {
2341   (void)btn;
2342   Hide_cursor();
2343   Start_operation_stack(OPERATION_FILLED_RECTANGLE);
2344   Display_cursor();
2345 }
2346 
2347 
2348 // -- Gestion des boutons de cercle (ellipse) vide et plein(e) --------------
2349 
Button_circle_ellipse(int btn)2350 void Button_circle_ellipse(int btn)
2351 {
2352   word operation;
2353 
2354   switch (btn)
2355   {
2356     default:
2357     case BUTTON_CIRCLES:
2358       operation = OPERATION_EMPTY_CIRCLE_CTR;
2359       break;
2360     case BUTTON_FILLCIRC:
2361       operation = OPERATION_FILLED_CIRCLE_CTR;
2362       break;
2363     case BUTTON_SPHERES:
2364       operation = OPERATION_GRAD_CIRCLE_CTR;
2365       break;
2366   }
2367   operation += Selected_circle_ellipse_mode;  // CIRCLE_CTR/CIRCLE_CRN/ELLIPSE_CTR/ELLIPSE_CRN;
2368   Hide_cursor();
2369   Start_operation_stack(operation);
2370   Display_cursor();
2371 }
2372 
Button_Circle_switch_mode(int btn)2373 void Button_Circle_switch_mode(int btn)
2374 {
2375   T_Dropdown_button dropdown;
2376   T_Dropdown_choice *item = NULL;
2377   int i;
2378   static const char * text[4] =
2379     { "Circle (center/radius)", "Circle (corners)",
2380       "Ellipse (center/radiuses)", "Ellipse (corners)" };
2381 
2382   dropdown.Pos_X         =Buttons_Pool[btn].X_offset;
2383   dropdown.Pos_Y         =Buttons_Pool[btn].Y_offset;
2384   dropdown.Height        =Buttons_Pool[btn].Height;
2385   dropdown.Dropdown_width=26*8;
2386   dropdown.First_item    =NULL;
2387   dropdown.Bottom_up     =1;
2388 
2389   Hide_cursor();
2390 
2391   // If we get here from a keyboard shortcut, don't show the menu and directly
2392   // switch to the next drawing mode.
2393   if (Mouse_K != 0) {
2394     for(i = 0; i < 4; i++) {
2395       Window_dropdown_add_item(&dropdown, i, text[i]);
2396     }
2397     item=Dropdown_activate(&dropdown,0,Menu_Y);
2398   }
2399 
2400   if (item)
2401   {
2402     Selected_circle_ellipse_mode = item->Number;
2403   } else {
2404     Selected_circle_ellipse_mode = (Selected_circle_ellipse_mode + 1) & 3;
2405   }
2406 
2407   Display_sprite_in_menu(BUTTON_CIRCLES,
2408     (Selected_circle_ellipse_mode >= 2) ? MENU_SPRITE_ELLIPSES : -1);
2409   Draw_menu_button(BUTTON_CIRCLES,BUTTON_RELEASED);
2410   Display_sprite_in_menu(BUTTON_FILLCIRC,
2411     (Selected_circle_ellipse_mode >= 2) ? MENU_SPRITE_ELLIPSES : -1);
2412   Draw_menu_button(BUTTON_FILLCIRC,BUTTON_RELEASED);
2413   Display_sprite_in_menu(BUTTON_SPHERES,
2414     (Selected_circle_ellipse_mode >= 2) ? MENU_SPRITE_GRAD_ELLIPSE : -1);
2415   Draw_menu_button(BUTTON_SPHERES,BUTTON_RELEASED);
2416   Draw_menu_button(btn,BUTTON_PRESSED);
2417 
2418   Display_cursor();
2419   Button_circle_ellipse(btn);
2420   Window_dropdown_clear_items(&dropdown);
2421 }
2422 
2423 // -- Gestion du menu des dégradés ------------------------------------------
Draw_button_gradient_style(short x_pos,short y_pos,int technique)2424 void Draw_button_gradient_style(short x_pos,short y_pos,int technique)
2425 {
2426   short line;
2427 
2428   // On commence par afficher les 2 côtés qui constituent le dégradé de base:
2429     // Côté gauche (noir)
2430   Window_rectangle(x_pos+2, y_pos+2, 6, 10, MC_Black);
2431     // Côté droit (blanc)
2432   Window_rectangle(x_pos+8, y_pos+2, 5, 10, MC_White);
2433 
2434   switch(technique)
2435   {
2436     case 1 : // Dégradé de trames simples
2437       // Au centre, on place 10 lignes tramées simplement
2438       for (line=2;line<2+10;line++)
2439         if (line&1)
2440         {
2441           // Lignes impaires
2442           Pixel_in_window(x_pos+ 5,y_pos+line,MC_White);
2443           Pixel_in_window(x_pos+ 7,y_pos+line,MC_White);
2444           Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black);
2445         }
2446         else
2447         {
2448           // Lignes paires
2449           Pixel_in_window(x_pos+ 6,y_pos+line,MC_White);
2450           Pixel_in_window(x_pos+ 9,y_pos+line,MC_Black);
2451         }
2452       break;
2453     case 2 : // Dégradé de trames étendues
2454       // Au centre, on place 10 lignes tramées de façon compliquée
2455       for (line=2;line<2+10;line++)
2456         if (line&1)
2457         {
2458           // Lignes impaires
2459           Pixel_in_window(x_pos+ 7,y_pos+line,MC_White);
2460           Pixel_in_window(x_pos+ 8,y_pos+line,MC_Black);
2461           Pixel_in_window(x_pos+10,y_pos+line,MC_Black);
2462         }
2463         else
2464         {
2465           // Lignes paires
2466           Pixel_in_window(x_pos+ 4,y_pos+line,MC_White);
2467           Pixel_in_window(x_pos+ 6,y_pos+line,MC_White);
2468         }
2469   }
2470 
2471   Update_window_area(x_pos+2,y_pos+2,10,10);
2472 }
2473 
Load_gradient_data(int index)2474 void Load_gradient_data(int index)
2475 {
2476   if (Main.backups->Pages->Gradients->Range[index].Start>Main.backups->Pages->Gradients->Range[index].End)
2477     Error(0);
2478   Gradient_lower_bound =Main.backups->Pages->Gradients->Range[index].Start;
2479   Gradient_upper_bound =Main.backups->Pages->Gradients->Range[index].End;
2480   Gradient_is_inverted          =Main.backups->Pages->Gradients->Range[index].Inverse;
2481   Gradient_random_factor=Main.backups->Pages->Gradients->Range[index].Mix+1;
2482 
2483   Gradient_bounds_range=(Gradient_lower_bound<Gradient_upper_bound)?
2484                             Gradient_upper_bound-Gradient_lower_bound:
2485                             Gradient_lower_bound-Gradient_upper_bound;
2486   Gradient_bounds_range++;
2487 
2488   switch(Main.backups->Pages->Gradients->Range[index].Technique)
2489   {
2490     case 0 : // Degradé de base
2491       Gradient_function=Gradient_basic;
2492       break;
2493     case 1 : // Dégradé de trames simples
2494       Gradient_function=Gradient_dithered;
2495       break;
2496     case 2 : // Dégradé de trames étendues
2497       Gradient_function=Gradient_extra_dithered;
2498   }
2499 }
2500 
2501 /// draw the gradient preview for the Gradation menu
Draw_gradient_preview(short start_x,short start_y,short width,short height,int index)2502 static void Draw_gradient_preview(short start_x,short start_y,short width,short height,int index)
2503 {
2504   short x_pos; // Variables de balayage du block en bas de l'écran.
2505   short y_pos;
2506   short end_x;
2507   short end_y;
2508 
2509   Load_gradient_data(index);
2510 
2511   start_x=Window_pos_X+(start_x*Menu_factor_X);
2512   start_y=Window_pos_Y+(start_y*Menu_factor_Y);
2513 
2514   Gradient_total_range=width*Menu_factor_X;
2515 
2516   end_x=start_x+Gradient_total_range;
2517   end_y=start_y+(height*Menu_factor_Y);
2518 
2519   for (y_pos=start_y;y_pos<end_y;y_pos++)
2520     for (x_pos=start_x;x_pos<end_x;x_pos++)
2521       Gradient_function(x_pos-start_x,x_pos,y_pos);
2522   Update_rect(start_x,start_y,width*Menu_factor_X,height*Menu_factor_Y);
2523 }
2524 
2525 /// Tag colors from a gradient range
Tag_color_gradient_range(const T_Gradient_range * range)2526 static void Tag_color_gradient_range(const T_Gradient_range * range)
2527 {
2528   Tag_color_range(range->Start, range->End);
2529 }
2530 
2531 /// Print the Color cycling speed in Hz, ms and in DP2E unit
Print_color_cycling_details(short y_pos)2532 static void Print_color_cycling_details(short y_pos)
2533 {
2534   char str[24];
2535 
2536   Num2str(Main.backups->Pages->Gradients->Range[Current_gradient].Speed, str, 3);
2537   Print_in_window(73+134, y_pos, str, MC_Black, MC_Light);
2538   if (Main.backups->Pages->Gradients->Range[Current_gradient].Speed > 0)
2539   {
2540     snprintf(str, sizeof(str), "Speed %7.4fHz %4ums",
2541              Main.backups->Pages->Gradients->Range[Current_gradient].Speed * 0.2856,
2542              (unsigned)(1000.0 / (Main.backups->Pages->Gradients->Range[Current_gradient].Speed * 0.2856)));
2543     Print_in_window(8, y_pos, str, MC_Black, MC_Light);
2544   }
2545   else
2546     Print_in_window(8, y_pos, "               STOPPED", MC_Black, MC_Light);
2547 }
2548 
Button_Gradients(int btn)2549 void Button_Gradients(int btn)
2550 {
2551   short clicked_button;
2552   char  str[4];
2553   T_Gradient_array backup_gradients;
2554   int   old_current_gradient;
2555   T_Scroller_button * mix_scroller;
2556   T_Scroller_button * speed_scroller;
2557   T_Scroller_button * gradient_scroller;
2558   short old_mouse_x;
2559   short old_mouse_y;
2560   byte  old_mouse_k;
2561   byte  temp_color;
2562   byte  first_color;
2563   byte  last_color;
2564   byte  color;
2565   byte  click;
2566   int  changed_gradient_index;
2567   byte cycling_mode=Cycling_mode;
2568 
2569   (void)btn;
2570   // Enable cycling while this window is open
2571   Cycling_mode=1;
2572 
2573   Gradient_pixel=Pixel;
2574   old_current_gradient=Current_gradient;
2575   changed_gradient_index=0;
2576   memcpy(&backup_gradients,Main.backups->Pages->Gradients,sizeof(T_Gradient_array));
2577 
2578   Open_window(235,146+12,"Gradation menu");
2579 
2580   Window_set_palette_button(48,19);                            // 1
2581   // Slider for gradient selection
2582   gradient_scroller=Window_set_scroller_button(218,20,75,16,1,Current_gradient);  // 2
2583   // Slider for mix
2584   mix_scroller = Window_set_scroller_button(31,20,84,256,1,
2585     Main.backups->Pages->Gradients->Range[Current_gradient].Mix);                      // 3
2586   // Direction
2587   Window_set_normal_button(8,20,15,14,
2588     (Main.backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",0,1,KEY_TAB); // 4
2589   // Technique
2590   Window_set_normal_button(8,90,15,14,"",0,1,KEY_TAB|GFX2_MOD_SHIFT); // 5
2591   Draw_button_gradient_style(8,90,Main.backups->Pages->Gradients->Range[Current_gradient].Technique);
2592 
2593   Window_set_normal_button(178,128+12,51,14,"OK",0,1,KEY_RETURN);     // 6
2594   Window_set_normal_button(123,128+12,51,14,"Cancel",0,1,KEY_ESC);  // 7
2595   // Scrolling speed
2596   //((250/2 = 125)+1 = 126) +24 = 150
2597   speed_scroller = Window_set_horizontal_scroller_button(79, 111, 150, COLOR_CYCLING_SPEED_MAX + 1, 1,
2598                                               Main.backups->Pages->Gradients->Range[Current_gradient].Speed);  // 8
2599   Print_color_cycling_details(113 + 14);
2600 
2601   Print_in_window(5,58,"MIX",MC_Dark,MC_Light);
2602 
2603   // Cycling mode on/off
2604   Window_set_normal_button(8,109,62,14,"",0,1,KEY_NONE); // 9
2605   Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light);
2606 
2607   // On tagge les couleurs qui vont avec
2608   Tag_color_gradient_range(&Main.backups->Pages->Gradients->Range[Current_gradient]);
2609 
2610   Num2str(Current_gradient+1,str,2);
2611   Print_in_window(215,100,str,MC_Black,MC_Light);
2612 
2613   // On affiche le cadre autour de la préview
2614   Window_display_frame_in(7,127+12,110,16);
2615   // On affiche la preview
2616   Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2617 
2618   first_color=last_color=(Main.backups->Pages->Gradients->Range[Current_gradient].Inverse)?Main.backups->Pages->Gradients->Range[Current_gradient].End:Main.backups->Pages->Gradients->Range[Current_gradient].Start;
2619   Update_window_area(0,0,Window_width, Window_height);
2620 
2621   Display_cursor();
2622 
2623   do
2624   {
2625     old_mouse_x=Mouse_X;
2626     old_mouse_y=Mouse_Y;
2627     old_mouse_k=Mouse_K;
2628     if (changed_gradient_index)
2629     {
2630       // User has changed which gradient (0-15) he's watching
2631       changed_gradient_index=0;
2632 
2633       Hide_cursor();
2634 
2635       // On affiche la valeur sous la jauge
2636       Num2str(Current_gradient+1,str,2);
2637       Print_in_window(215,100,str,MC_Black,MC_Light);
2638 
2639       // On tagge les couleurs qui vont avec
2640       Tag_color_gradient_range(&Main.backups->Pages->Gradients->Range[Current_gradient]);
2641 
2642       // On affiche le sens qui va avec
2643       Print_in_window(12,23,(Main.backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light);
2644 
2645       // On raffiche le mélange (jauge) qui va avec
2646       mix_scroller->Position=Main.backups->Pages->Gradients->Range[Current_gradient].Mix;
2647       Window_draw_slider(mix_scroller);
2648 
2649       // Update speed
2650       speed_scroller->Position=Main.backups->Pages->Gradients->Range[Current_gradient].Speed;
2651       Window_draw_slider(speed_scroller);
2652       Print_color_cycling_details(113 + 14);
2653 
2654       // Gradient #
2655       gradient_scroller->Position=Current_gradient;
2656       Window_draw_slider(gradient_scroller);
2657 
2658       // Technique (flat, dithered, very dithered)
2659       Draw_button_gradient_style(8,90,Main.backups->Pages->Gradients->Range[Current_gradient].Technique);
2660 
2661       // Rectangular gradient preview
2662       Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2663 
2664       Display_cursor();
2665     }
2666 
2667     clicked_button=Window_clicked_button();
2668     if (Input_sticky_control!=8 || !Mouse_K)
2669     {
2670       Allow_colorcycling=0;
2671       // Restore palette
2672       Set_palette(Main.palette);
2673     }
2674 
2675     switch(clicked_button)
2676     {
2677       case -1 :
2678       case  1 : // Palette
2679         if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
2680         {
2681           Hide_cursor();
2682           temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
2683 
2684           if (!old_mouse_k)
2685           {
2686             // On vient de clicker
2687 
2688             // On met à jour l'intervalle du dégradé
2689             first_color=last_color=Main.backups->Pages->Gradients->Range[Current_gradient].Start=Main.backups->Pages->Gradients->Range[Current_gradient].End=temp_color;
2690             // On tagge le bloc
2691             Tag_color_gradient_range(&Main.backups->Pages->Gradients->Range[Current_gradient]);
2692             // Tracé de la preview:
2693             Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2694           }
2695           else
2696           {
2697             // On maintient le click, on va donc tester si le curseur bouge
2698             if (temp_color!=last_color)
2699             {
2700               // On commence par ordonner la 1ère et dernière couleur du bloc
2701               if (first_color<temp_color)
2702               {
2703                 Main.backups->Pages->Gradients->Range[Current_gradient].Start=first_color;
2704                 Main.backups->Pages->Gradients->Range[Current_gradient].End  =temp_color;
2705               }
2706               else if (first_color>temp_color)
2707               {
2708                 Main.backups->Pages->Gradients->Range[Current_gradient].Start=temp_color;
2709                 Main.backups->Pages->Gradients->Range[Current_gradient].End  =first_color;
2710               }
2711               else
2712                 Main.backups->Pages->Gradients->Range[Current_gradient].Start=Main.backups->Pages->Gradients->Range[Current_gradient].End=first_color;
2713               // On tagge le bloc
2714               Tag_color_gradient_range(&Main.backups->Pages->Gradients->Range[Current_gradient]);
2715               // Tracé de la preview:
2716               Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2717               last_color=temp_color;
2718             }
2719           }
2720           Display_cursor();
2721         }
2722         break;
2723       case  2 : // Nouvel indice de dégradé
2724         // Nouvel indice dans Window_attribute2
2725         Current_gradient=Window_attribute2;
2726         changed_gradient_index=1;
2727         break;
2728       case  3 : // Nouveau mélange de dégradé
2729         Hide_cursor();
2730         // Nouvel mélange dans Window_attribute2
2731         Main.backups->Pages->Gradients->Range[Current_gradient].Mix=Window_attribute2;
2732         // On affiche la nouvelle preview
2733         Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2734         Display_cursor();
2735         break;
2736       case  4 : // Changement de sens
2737         Hide_cursor();
2738         // On inverse le sens (par un XOR de 1)
2739         Main.backups->Pages->Gradients->Range[Current_gradient].Inverse^=1;
2740         Print_in_window(12,23,(Main.backups->Pages->Gradients->Range[Current_gradient].Inverse)?"\033":"\032",MC_Black,MC_Light);
2741         // On affiche la nouvelle preview
2742         Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2743         Display_cursor();
2744         break;
2745       case  5 : // Changement de technique
2746         Hide_cursor();
2747         // On change la technique par (+1)%3
2748         Main.backups->Pages->Gradients->Range[Current_gradient].Technique=(Main.backups->Pages->Gradients->Range[Current_gradient].Technique+1)%3;
2749         Draw_button_gradient_style(8,90,Main.backups->Pages->Gradients->Range[Current_gradient].Technique);
2750         // On affiche la nouvelle preview
2751         Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2752         Display_cursor();
2753         break;
2754       case  8 : // Speed
2755         Main.backups->Pages->Gradients->Range[Current_gradient].Speed=Window_attribute2;
2756         Hide_cursor();
2757         Print_color_cycling_details(113 + 14);
2758         Display_cursor();
2759         Allow_colorcycling=1;
2760         break;
2761       case 9: // Cycling on/off
2762         cycling_mode = !cycling_mode;
2763         Hide_cursor();
2764         Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light);
2765         Display_cursor();
2766         break;
2767     }
2768 
2769     if (!Mouse_K)
2770     switch (Key)
2771     {
2772       case KEY_BACKQUOTE : // Récupération d'une couleur derrière le menu
2773       case KEY_COMMA :
2774         Get_color_behind_window(&color,&click);
2775         if (click)
2776         {
2777           Hide_cursor();
2778           temp_color=color;
2779 
2780           // On met à jour l'intervalle du dégradé
2781           first_color=last_color=Main.backups->Pages->Gradients->Range[Current_gradient].Start=Main.backups->Pages->Gradients->Range[Current_gradient].End=temp_color;
2782           // On tagge le bloc
2783           Tag_color_gradient_range(&Main.backups->Pages->Gradients->Range[Current_gradient]);
2784           // Tracé de la preview:
2785           Draw_gradient_preview(8,128+12,108,14,Current_gradient);
2786           Display_cursor();
2787           Wait_end_of_click();
2788         }
2789         Key=0;
2790         break;
2791       case KEY_MOUSEWHEELUP:
2792         if (Current_gradient>0)
2793         {
2794           Current_gradient--;
2795           changed_gradient_index=1;
2796         }
2797         break;
2798       case KEY_MOUSEWHEELDOWN:
2799         if (Current_gradient<15)
2800         {
2801           Current_gradient++;
2802           changed_gradient_index=1;
2803         }
2804         break;
2805 
2806       default:
2807         if (Is_shortcut(Key,0x100+BUTTON_HELP))
2808         {
2809           Window_help(BUTTON_GRADRECT, NULL);
2810           Key=0;
2811           break;
2812         }
2813         else if (Is_shortcut(Key,0x200+BUTTON_GRADRECT))
2814           clicked_button=6;
2815         else if (Is_shortcut(Key,SPECIAL_CYCLE_MODE))
2816         {
2817           // Cycling on/off
2818           cycling_mode = !cycling_mode;
2819           Hide_cursor();
2820           Print_in_window(11,112,"Cycling",cycling_mode?MC_Black:MC_Dark,MC_Light);
2821           Display_cursor();
2822         }
2823     }
2824   }
2825   while (clicked_button!=6 && clicked_button!=7 && !Quit_is_required);
2826 
2827   Close_window();
2828   // The Grad rect operation uses the same button as Grad menu.
2829   if (Current_operation != OPERATION_GRAD_RECTANGLE)
2830     Unselect_button(BUTTON_GRADRECT);
2831 
2832   Display_cursor();
2833 
2834   Gradient_pixel=Display_pixel;
2835   Cycling_mode=cycling_mode;
2836   if (clicked_button==7) // Cancel
2837   {
2838     Current_gradient=old_current_gradient;
2839     memcpy(Main.backups->Pages->Gradients,&backup_gradients,sizeof(T_Gradient_array));
2840   }
2841 }
2842 
2843 
2844 // -- Gestion des boutons de cercle / ellipse / rectangle dégradés --------------------
2845 
Button_Grad_rectangle(int btn)2846 void Button_Grad_rectangle(int btn)
2847 {
2848   (void)btn;
2849   Hide_cursor();
2850   Start_operation_stack(OPERATION_GRAD_RECTANGLE);
2851   Display_cursor();
2852 }
2853 
2854 
2855 // -- Gestion du bouton de remplissage ---------------------------------------
2856 
Button_Fill(int btn)2857 void Button_Fill(int btn)
2858 {
2859   (void)btn;
2860   if (Current_operation!=OPERATION_FILL)
2861   {
2862     Hide_cursor();
2863 
2864     if (Current_operation!=OPERATION_REPLACE)
2865     {
2866       Paintbrush_shape_before_fill=Paintbrush_shape;
2867       Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
2868     }
2869     else
2870       if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
2871            ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
2872         Print_in_menu("X:       Y:             ",0);
2873     Start_operation_stack(OPERATION_FILL);
2874     Display_cursor();
2875   }
2876 }
2877 
2878 
Button_Replace(int btn)2879 void Button_Replace(int btn)
2880 {
2881   (void)btn;
2882   if (Current_operation!=OPERATION_REPLACE)
2883   {
2884     Hide_cursor();
2885     if (Current_operation!=OPERATION_FILL)
2886     {
2887       Paintbrush_shape_before_fill=Paintbrush_shape;
2888       Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
2889     }
2890     if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
2891          ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
2892       Print_in_menu("X:       Y:       (    )",0);
2893     Start_operation_stack(OPERATION_REPLACE);
2894     Display_cursor();
2895   }
2896 }
2897 
2898 
Button_Unselect_fill(int btn)2899 void Button_Unselect_fill(int btn)
2900 {
2901   (void)btn;
2902   Paintbrush_shape=Paintbrush_shape_before_fill;
2903 
2904   if (Current_operation==OPERATION_REPLACE)
2905     if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
2906          ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
2907       Print_in_menu("X:       Y:             ",0);
2908 }
2909 
2910 
2911 //---------------------------- Menu des pinceaux -----------------------------
2912 
2913 /// Checks if the current brush is identical to a preset one.
Same_paintbrush(byte index)2914 byte Same_paintbrush(byte index)
2915 {
2916   if (Paintbrush_shape!=Paintbrush[index].Shape ||
2917       Paintbrush_width!=Paintbrush[index].Width ||
2918       Paintbrush_height!=Paintbrush[index].Height)
2919   return 0;
2920 
2921   if (Paintbrush_shape==PAINTBRUSH_SHAPE_MISC)
2922   {
2923     // Check all pixels
2924     int x,y;
2925     for(y=0;y<Paintbrush_height;y++)
2926       for(x=0;x<Paintbrush_width;x++)
2927         if(Paintbrush_sprite[(y*MAX_PAINTBRUSH_SIZE)+x]!=Paintbrush[index].Sprite[y][x])
2928           return 0;
2929   }
2930   return 1;
2931 }
2932 
Button_Paintbrush_menu(int btn)2933 void Button_Paintbrush_menu(int btn)
2934 {
2935   short clicked_button;
2936   short x_pos,y_pos;
2937   byte index;
2938 
2939   Open_window(310,180,"Paintbrush menu");
2940 
2941   Window_display_frame(8,21,294,132);
2942 
2943   Window_set_normal_button(10,158,67,14,"Cancel",0,1,KEY_ESC); // 1
2944 
2945   Window_set_dropdown_button(216, 158, 84,14,84,"Preset...", 0,0,1,RIGHT_SIDE|LEFT_SIDE,1);
2946   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_ROUND,         "Round");
2947   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_SQUARE,        "Square");
2948   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_HORIZONTAL_BAR,"Horizontal");
2949   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_VERTICAL_BAR,  "Vertical");
2950   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_SLASH,         "Slash");
2951   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_ANTISLASH,     "Antislash");
2952   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_RANDOM,        "Random");
2953   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_CROSS,         "Cross");
2954   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_PLUS,          "Plus");
2955   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_DIAMOND,       "Diamond");
2956   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_SIEVE_ROUND,   "Sieve Rnd");
2957   Window_dropdown_add_item(Window_dropdown_button_list,PAINTBRUSH_SHAPE_SIEVE_SQUARE,  "Sieve Sqr");
2958 
2959   for (index=0; index<NB_PAINTBRUSH_SPRITES; index++)
2960   {
2961     x_pos=13+(index%12)*24;
2962     y_pos=27+(index/12)*25;
2963     //Window_set_normal_button(x_pos  ,y_pos  ,20,20,"",0,1,KEY_NONE);
2964     Window_set_dropdown_button(x_pos  ,y_pos  ,20,20,28,NULL, 0,0,0,RIGHT_SIDE,0);
2965     Window_dropdown_add_item(Window_dropdown_button_list, 1, "Set");
2966     // Highlight selected brush
2967     if (Same_paintbrush(index))
2968       Window_rectangle(x_pos,y_pos,20,20,MC_White);
2969 
2970     Display_paintbrush_in_window(x_pos+2,y_pos+2,index);
2971   }
2972   for (index=0; index<BRUSH_CONTAINER_COLUMNS*BRUSH_CONTAINER_ROWS; index++)
2973   {
2974     x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24;
2975     y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25;
2976     Window_set_dropdown_button(x_pos  ,y_pos  ,20,20,28,NULL, 0,0,0,RIGHT_SIDE,0);
2977     Window_dropdown_add_item(Window_dropdown_button_list, 1, "Set");
2978     Display_stored_brush_in_window(x_pos+2, y_pos+2, index);
2979   }
2980 
2981   Update_window_area(0,0,Window_width, Window_height);
2982 
2983   Display_cursor();
2984 
2985   do
2986   {
2987     clicked_button=Window_clicked_button();
2988     if (Is_shortcut(Key,0x100+BUTTON_HELP))
2989       Window_help(BUTTON_PAINTBRUSHES, NULL);
2990     // Brush container
2991     if (clicked_button>=(NB_PAINTBRUSH_SPRITES+3))
2992     {
2993       index = clicked_button-NB_PAINTBRUSH_SPRITES-3;
2994 
2995       if (Window_attribute2==1) // Set
2996       {
2997         // Store
2998 
2999         x_pos=13+((index+NB_PAINTBRUSH_SPRITES)%12)*24;
3000         y_pos=27+((index+NB_PAINTBRUSH_SPRITES)/12)*25;
3001 
3002         Store_brush(index);
3003         Hide_cursor();
3004         Display_stored_brush_in_window(x_pos+2, y_pos+2, index);
3005         Display_cursor();
3006       }
3007       else
3008       {
3009         // Restore and exit
3010 
3011         if (Restore_brush(index))
3012         {
3013           Close_window();
3014           break;
3015         }
3016       }
3017 
3018     }
3019     else if (clicked_button>=3)
3020     // Standard paintbrushes
3021     {
3022       if (Window_attribute2!=1)
3023       {
3024         // Select paintbrush
3025         Close_window();
3026         Select_paintbrush(clicked_button-3);
3027         break;
3028       }
3029       else if (Window_attribute2==1)
3030       {
3031         // Store current
3032         index=clicked_button-3;
3033         if (!Store_paintbrush(index))
3034         {
3035           // Redraw
3036           Hide_cursor();
3037           x_pos=13+(index%12)*24;
3038           y_pos=27+(index/12)*25;
3039           Window_rectangle(x_pos,y_pos,20,20,MC_White);
3040           Display_paintbrush_in_window(x_pos+2,y_pos+2,index);
3041           Display_cursor();
3042         }
3043       }
3044     }
3045     else if (clicked_button==1 || Is_shortcut(Key,0x100+BUTTON_PAINTBRUSHES))
3046     {
3047       Close_window();
3048       break;
3049     }
3050     else if (clicked_button==2)
3051     {
3052       int size;
3053       // Pick a standard shape
3054       Paintbrush_shape=Window_attribute2;
3055       // Assign a reasonable size
3056       size=Max(Paintbrush_width,Paintbrush_height);
3057       if (size==1)
3058         size=3;
3059 
3060       switch (Paintbrush_shape)
3061       {
3062         case PAINTBRUSH_SHAPE_HORIZONTAL_BAR:
3063           Set_paintbrush_size(size, 1);
3064           break;
3065         case PAINTBRUSH_SHAPE_VERTICAL_BAR:
3066             Set_paintbrush_size(1, size);
3067           break;
3068         case PAINTBRUSH_SHAPE_CROSS:
3069         case PAINTBRUSH_SHAPE_PLUS:
3070         case PAINTBRUSH_SHAPE_DIAMOND:
3071           Set_paintbrush_size(size|1,size|1);
3072           break;
3073         default:
3074           Set_paintbrush_size(size,size);
3075           break;
3076 
3077       }
3078       Close_window();
3079       Change_paintbrush_shape(Paintbrush_shape);
3080       break;
3081     }
3082   }
3083   while (1);
3084 
3085   Unselect_button(btn);
3086   Display_cursor();
3087 }
3088 
3089 
Button_Brush_monochrome(int btn)3090 void Button_Brush_monochrome(int btn)
3091 {
3092   Hide_cursor();
3093   // On passe en brosse monochrome:
3094   Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH);
3095 
3096   Unselect_button(btn);
3097 
3098   Display_cursor();
3099 }
3100 
3101 // -- Fonction renvoyant le mode vidéo le plus adapté à l'image chargée -----
3102 #define TOLERANCE_X 8
3103 #define TOLERANCE_Y 4
Best_video_mode(void)3104 static int Best_video_mode(void)
3105 {
3106   short best_width,best_height;
3107   int best_mode;
3108   short temp_x,temp_y;
3109   int mode;
3110 
3111   // Si mode fenêtre, on reste dans ce mode.
3112   if (Current_resolution == 0)
3113     return 0;
3114 
3115   // On commence par borner les dimensions, ou du moins les rendre cohérentes
3116   if ((Original_screen_X<=0) || (Config.Set_resolution_according_to==2))
3117     Original_screen_X=Main.image_width;
3118   else
3119     if (Original_screen_X<320)
3120       Original_screen_X=320;
3121 
3122   if ((Original_screen_Y<=0) || (Config.Set_resolution_according_to==2))
3123     Original_screen_Y=Main.image_height;
3124   else
3125     if (Original_screen_Y<200)
3126       Original_screen_Y=200;
3127 
3128   GFX2_Log(GFX2_DEBUG, "Best_video_mode() looking for %dx%d\n", (int)Original_screen_X, (int)Original_screen_Y);
3129 
3130   if ((Original_screen_X > Video_mode[Nb_video_modes-1].Width) ||
3131       (Original_screen_Y > Video_mode[Nb_video_modes-1].Height))
3132   {
3133     // return the "biggest" video mode
3134     return Nb_video_modes-1;
3135   }
3136 
3137   // Maintenant on peut chercher le mode qui correspond le mieux
3138   best_mode=Current_resolution;
3139   best_width=0;
3140   best_height=0;
3141 
3142 
3143   for (mode=1; mode<Nb_video_modes; mode++)
3144   {
3145     if (Video_mode[mode].Fullscreen && (Video_mode[mode].State&3)<2)
3146     {
3147       temp_x=Video_mode[mode].Width;
3148       temp_y=Video_mode[mode].Height;
3149 
3150       if ( (Original_screen_X-TOLERANCE_X<=temp_x)
3151         && (Original_screen_Y-TOLERANCE_Y<=temp_y) )
3152         return mode;
3153       else
3154       {
3155         if ( (best_width<=temp_x)
3156           && (best_height<=temp_y)
3157           && (temp_x-TOLERANCE_X<=Original_screen_X)
3158           && (temp_y-TOLERANCE_Y<=Original_screen_Y) )
3159         {
3160           best_width=temp_x;
3161           best_height=temp_y;
3162           best_mode=mode;
3163         }
3164       }
3165     }
3166   }
3167 
3168   return best_mode;
3169 }
3170 
Load_picture(enum CONTEXT_TYPE type)3171 void Load_picture(enum CONTEXT_TYPE type)
3172 {
3173   byte  confirm;
3174   byte  old_cursor_shape;
3175   int   new_mode;
3176   T_IO_Context context;
3177   word * filename_unicode = NULL;
3178   T_Selector_settings * selector;
3179 
3180   switch (type)
3181   {
3182   case CONTEXT_MAIN_IMAGE:
3183     filename_unicode = Main.backups->Pages->Filename_unicode;
3184     Init_context_layered_image(&context, Main.backups->Pages->Filename, Main.backups->Pages->File_directory);
3185     selector = &Main.selector;
3186     break;
3187   case CONTEXT_BRUSH:
3188     filename_unicode = Brush_filename_unicode;
3189     Init_context_brush(&context, Brush_filename, Brush_file_directory);
3190     selector = &Brush_selector;
3191     break;
3192   case CONTEXT_PALETTE:
3193     Init_context_layered_image(&context, "", Main.backups->Pages->File_directory);
3194     context.Type = CONTEXT_PALETTE;
3195     context.Format = FORMAT_PAL;
3196     selector = &Palette_selector;
3197     break;
3198   default:
3199     return; // DO NOTHING
3200   }
3201   context.File_name_unicode = Unicode_strdup(filename_unicode);
3202   confirm = Button_Load_or_Save(selector, 1, &context);
3203 
3204   if (confirm)
3205   {
3206     if (type==CONTEXT_MAIN_IMAGE)
3207     {
3208       if (Main.image_is_modified)
3209         confirm=Confirmation_box("Discard unsaved changes?");
3210     }
3211   }
3212 
3213   // confirm is modified inside the first if, that's why we check it
3214   // again here
3215   if (confirm)
3216   {
3217     short old_image_width, old_image_height;
3218 
3219     old_image_width = Main.image_width;
3220     old_image_height = Main.image_height;
3221     old_cursor_shape=Cursor_shape;
3222     Hide_cursor();
3223     Cursor_shape=CURSOR_SHAPE_HOURGLASS;
3224     Display_cursor();
3225 
3226     if (type==CONTEXT_MAIN_IMAGE)
3227     {
3228       Original_screen_X=0;
3229       Original_screen_Y=0;
3230     }
3231 
3232     Load_image(&context);
3233 
3234     if (type==CONTEXT_BRUSH)
3235     {
3236       free(Brush_filename);
3237       Brush_filename = context.File_name; // "steal" heap string
3238       context.File_name = NULL;
3239       free(Brush_filename_unicode);
3240       Brush_filename_unicode = context.File_name_unicode; // "steal" heap string
3241       context.File_name_unicode = NULL;
3242       free(Brush_file_directory);
3243       Brush_file_directory = context.File_directory;  // "steal" heap string
3244       context.File_directory = NULL;
3245       Brush_fileformat = context.Format;
3246 
3247       Tiling_offset_X=0;
3248       Tiling_offset_Y=0;
3249 
3250       Brush_offset_X=(Brush_width>>1);
3251       Brush_offset_Y=(Brush_height>>1);
3252 
3253       Select_button(BUTTON_DRAW,LEFT_SIDE);
3254       if (Config.Auto_discontinuous)
3255       {
3256         // On se place en mode Dessin discontinu à la main
3257         while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
3258           Select_button(BUTTON_DRAW,RIGHT_SIDE);
3259       }
3260       Hide_cursor();
3261       // On passe en brosse couleur:
3262       Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
3263     }
3264     else
3265     {
3266       Hide_cursor();
3267       Cursor_shape=old_cursor_shape;
3268     }
3269 
3270 
3271     if ( (File_error==1) || (Get_fileformat(Main.fileformat)->Palette_only) )
3272     {
3273       if (File_error!=1)
3274         Compute_optimal_menu_colors(Main.palette);
3275     }
3276     else
3277     {
3278       if (type==CONTEXT_MAIN_IMAGE)
3279       {
3280         if (Main.magnifier_mode &&
3281             (Main.image_width > old_image_width || Main.image_height > old_image_height))
3282         {
3283           // disable magnifier
3284           Pixel_preview = Pixel_preview_normal;
3285           Main.magnifier_mode = 0;
3286           Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
3287         }
3288 
3289         new_mode=Best_video_mode();
3290         if ((Config.Auto_set_res) && (new_mode!=Current_resolution))
3291         {
3292           Init_mode_video(
3293             Video_mode[new_mode].Width,
3294             Video_mode[new_mode].Height,
3295             Video_mode[new_mode].Fullscreen,
3296             Pixel_ratio);
3297           Display_menu();
3298         }
3299         // In window mode, activate wide or tall pixels if the image says so.
3300         else if (!Video_mode[Current_resolution].Fullscreen &&
3301           ((context.Ratio == PIXEL_WIDE &&
3302             Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) ||
3303             (context.Ratio == PIXEL_TALL &&
3304             Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2) ||
3305             (context.Ratio == PIXEL_TALL3 &&
3306             Pixel_ratio != PIXEL_TALL3) ))
3307         {
3308           Init_mode_video(
3309             Video_mode[Current_resolution].Width,
3310             Video_mode[Current_resolution].Height,
3311             Video_mode[Current_resolution].Fullscreen,
3312             context.Ratio);
3313             Display_menu();
3314         }
3315         else
3316         {
3317           if (Main.image_width > old_image_width || Main.image_height > old_image_height)
3318           {
3319             Main.offset_X = 0;
3320             Main.offset_Y = 0;
3321           }
3322           Compute_limits();
3323           Compute_paintbrush_coordinates();
3324         }
3325 
3326         Compute_optimal_menu_colors(Main.palette);
3327         Redraw_layered_image();
3328         End_of_modification();
3329         Check_menu_mode();
3330         Display_all_screen();
3331         Main.image_is_modified=0;
3332       }
3333     }
3334 
3335     Display_menu();
3336     Display_cursor();
3337   }
3338 
3339   Destroy_context(&context);
3340 
3341   Hide_cursor();
3342   Print_filename();
3343   Display_cursor();
3344   Set_palette(Main.palette);
3345 }
3346 
3347 
Button_Load(int btn)3348 void Button_Load(int btn)
3349 {
3350   (void)btn;
3351   // On sauve l'état actuel des paramètres de l'image pour pouvoir les
3352   // restituer en cas d'erreur n'affectant pas l'image
3353   Upload_infos_page(&Main);
3354 
3355   Load_picture(CONTEXT_MAIN_IMAGE);
3356   Tilemap_update();
3357 }
3358 
3359 
Button_Reload(int btn)3360 void Button_Reload(int btn)
3361 {
3362   byte old_cursor_shape;
3363   int  new_mode;
3364 
3365   (void)btn;
3366   // On sauve l'état actuel des paramètres de l'image pour pouvoir les
3367   // restituer en cas d'erreur n'affectant pas l'image
3368   Upload_infos_page(&Main);
3369 
3370   if ( (!Main.image_is_modified) || Confirmation_box("Discard unsaved changes ?") )
3371   {
3372     T_IO_Context context;
3373 
3374     Hide_cursor();
3375     old_cursor_shape=Cursor_shape;
3376     Cursor_shape=CURSOR_SHAPE_HOURGLASS;
3377     Display_cursor();
3378 
3379     Original_screen_X=0;
3380     Original_screen_Y=0;
3381 
3382     Init_context_layered_image(&context, Main.backups->Pages->Filename, Main.backups->Pages->File_directory);
3383     Load_image(&context);
3384 
3385     Hide_cursor();
3386     Cursor_shape=old_cursor_shape;
3387 
3388     if (File_error!=1)
3389     {
3390       if (Main.magnifier_mode)
3391       {
3392         Pixel_preview=Pixel_preview_normal;
3393         Main.magnifier_mode=0;
3394         Draw_menu_button(BUTTON_MAGNIFIER,Main.magnifier_mode);
3395       }
3396 
3397       new_mode=Best_video_mode();
3398       if ( ((Config.Auto_set_res) && (new_mode!=Current_resolution)) &&
3399            (!Resolution_in_command_line) )
3400       {
3401         Init_mode_video(
3402         Video_mode[new_mode].Width,
3403         Video_mode[new_mode].Height,
3404         Video_mode[new_mode].Fullscreen,
3405         Pixel_ratio);
3406         Display_menu();
3407       }
3408       // In window mode, activate wide or tall pixels if the image says so.
3409       else if (!Video_mode[Current_resolution].Fullscreen &&
3410         ((context.Ratio == PIXEL_WIDE &&
3411           Pixel_ratio != PIXEL_WIDE && Pixel_ratio != PIXEL_WIDE2) ||
3412           (context.Ratio == PIXEL_TALL &&
3413           Pixel_ratio != PIXEL_TALL && Pixel_ratio != PIXEL_TALL2 &&
3414           Pixel_ratio != PIXEL_TALL3)))
3415       {
3416         Init_mode_video(
3417           Video_mode[Current_resolution].Width,
3418           Video_mode[Current_resolution].Height,
3419           Video_mode[Current_resolution].Fullscreen,
3420           context.Ratio);
3421           Display_menu();
3422       }
3423       else
3424       {
3425         Main.offset_X=0;
3426         Main.offset_Y=0;
3427         Compute_limits();
3428         Compute_paintbrush_coordinates();
3429       }
3430       Tilemap_update();
3431       Redraw_layered_image();
3432       End_of_modification();
3433       Check_menu_mode();
3434       Display_all_screen();
3435 
3436       Main.image_is_modified=0;
3437     }
3438     Destroy_context(&context);
3439   }
3440   else
3441     Hide_cursor();
3442 
3443   Compute_optimal_menu_colors(Main.palette);
3444   Display_menu();
3445   if (Config.Display_image_limits)
3446     Display_image_limits();
3447 
3448   Unselect_button(BUTTON_LOAD);
3449 
3450   Display_cursor();
3451 }
3452 
3453 
Backup_existing_file(const char * filename)3454 static void Backup_existing_file(const char * filename)
3455 {
3456   char * new_filename; // full filename of the backup file
3457   char * p;
3458   int i;
3459   size_t len;
3460 
3461   if (filename == NULL)
3462     return;
3463   len = strlen(filename);
3464   new_filename = malloc(len + 1 + 4); // spare bytes to concat ".BAK"
3465   memcpy(new_filename, filename, len + 1);
3466   p = Find_last_separator(new_filename);  // pointer to the filename part (after directory)
3467   if (p == NULL)
3468     p = new_filename;
3469   else
3470     p++;
3471   i = Position_last_dot(p);
3472   if (i >= 0)
3473     memcpy(p + i + 1, "BAK", 4);
3474   else
3475     memcpy(new_filename + len, ".BAK", 5);
3476 
3477   File_error=0;
3478 
3479   // On fait un backup si le nom du fichier n'est pas celui qu'on a choisi
3480   // pour nommer les backups (c'est évident!).
3481   if (strcmp(new_filename,filename))
3482   {
3483     // S'il y avait déjà un fichier Backup, on l'efface
3484     if ((File_exists(new_filename))
3485      && (Remove_path(new_filename)!=0))
3486       File_error=1;
3487 
3488     if ((!File_error)
3489      && (rename(filename,new_filename)!=0))
3490       File_error=1;
3491   }
3492   free(new_filename);
3493 }
3494 
3495 
Save_picture(enum CONTEXT_TYPE type)3496 void Save_picture(enum CONTEXT_TYPE type)
3497 {
3498   byte  confirm;
3499   byte  old_cursor_shape;
3500   T_IO_Context save_context;
3501   word * filename_unicode = NULL;
3502   T_Selector_settings * selector;
3503 
3504   if (type == CONTEXT_MAIN_IMAGE)
3505   {
3506     filename_unicode = Main.backups->Pages->Filename_unicode;
3507     Init_context_layered_image(&save_context, Main.backups->Pages->Filename, Main.backups->Pages->File_directory);
3508     save_context.Format = Main.fileformat;
3509     selector = &Main.selector;
3510   }
3511   else if (type == CONTEXT_BRUSH)
3512   {
3513     filename_unicode = Brush_filename_unicode;
3514     Init_context_brush(&save_context, Brush_filename, Brush_file_directory);
3515     save_context.Format = Brush_fileformat;
3516     selector = &Brush_selector;
3517   }
3518   else if (type == CONTEXT_PALETTE)
3519   {
3520     char* pal_filename;
3521     char* dotpos;
3522     size_t len = strlen(Main.backups->Pages->Filename);
3523 
3524     pal_filename = malloc(len + 4 + 1); // reserve space for ".pal"
3525     memcpy(pal_filename, Main.backups->Pages->Filename, len + 1);
3526     // Replace extension with PAL
3527     dotpos = strrchr(pal_filename, '.');
3528     if (dotpos == NULL)
3529       dotpos = pal_filename + len;
3530     strcpy(dotpos, ".pal");
3531 
3532     Init_context_layered_image(&save_context, pal_filename, Main.backups->Pages->File_directory);
3533     save_context.Type = CONTEXT_PALETTE;
3534 
3535     free(pal_filename);
3536 
3537     // Set format to PAL
3538     save_context.Format = FORMAT_PAL;
3539     selector = &Palette_selector;
3540   }
3541   else
3542     return;
3543 
3544   save_context.File_name_unicode = Unicode_strdup(filename_unicode);
3545   confirm=Button_Load_or_Save(selector, 0, &save_context);
3546 
3547   if (confirm && File_exists(save_context.File_name))
3548   {
3549     confirm=Confirmation_box("Erase old file ?");
3550     if (confirm && (Config.Backup))
3551     {
3552       char * full_filename = Filepath_append_to_dir(save_context.File_directory, save_context.File_name);
3553       Backup_existing_file(full_filename);
3554       free(full_filename);
3555       if (File_error)
3556       {
3557         confirm=0;
3558         Error(0);
3559       }
3560     }
3561   }
3562 
3563   if (confirm)
3564   {
3565     const T_Format * format;
3566 
3567     old_cursor_shape=Cursor_shape;
3568     Hide_cursor();
3569     Cursor_shape=CURSOR_SHAPE_HOURGLASS;
3570     Display_cursor();
3571 
3572     Save_image(&save_context);
3573 
3574     format=Get_fileformat(save_context.Format);
3575     if (!File_error && type == CONTEXT_MAIN_IMAGE && !format->Palette_only && (Main.backups->Pages->Nb_layers==1 || format->Supports_layers))
3576     {
3577       Main.image_is_modified = 0;
3578       Main.fileformat = save_context.Format;
3579       free(Main.backups->Pages->Filename);
3580       Main.backups->Pages->Filename = save_context.File_name; // "steal" string from heap
3581       save_context.File_name = NULL;
3582       free(Main.backups->Pages->Filename_unicode);
3583       Main.backups->Pages->Filename_unicode = save_context.File_name_unicode; // "steal" string
3584       save_context.File_name_unicode = NULL;
3585       free(Main.backups->Pages->File_directory);
3586       Main.backups->Pages->File_directory = save_context.File_directory;
3587       save_context.File_directory = NULL;
3588     }
3589     if (type == CONTEXT_BRUSH)
3590     {
3591       Brush_fileformat = save_context.Format;
3592       free(Brush_filename);
3593       Brush_filename = save_context.File_name;
3594       save_context.File_name = NULL;
3595       free(Brush_filename_unicode);
3596       Brush_filename_unicode = save_context.File_name_unicode;
3597       save_context.File_name_unicode = NULL;
3598       free(Brush_file_directory);
3599       Brush_file_directory = save_context.File_directory;
3600       save_context.File_directory = NULL;
3601     }
3602     Hide_cursor();
3603     Cursor_shape=old_cursor_shape;
3604     Display_cursor();
3605   }
3606   Destroy_context(&save_context);
3607 
3608   Print_filename();
3609   Set_palette(Main.palette);
3610 }
3611 
3612 
Button_Save(int btn)3613 void Button_Save(int btn)
3614 {
3615   (void)btn;
3616   Save_picture(CONTEXT_MAIN_IMAGE);
3617 }
3618 
3619 /// Save main image over existing file (no fileselector)
Button_Autosave(int btn)3620 void Button_Autosave(int btn)
3621 {
3622   byte old_cursor_shape;
3623   char * filename;
3624   byte file_already_exists;
3625 
3626   (void)btn;
3627   filename = Filepath_append_to_dir(Main.backups->Pages->File_directory, Main.backups->Pages->Filename);
3628   file_already_exists = File_exists(filename);
3629 
3630   if ( (!file_already_exists) || Confirmation_box("Erase old file ?") )
3631   {
3632     if ((file_already_exists) && (Config.Backup))
3633       Backup_existing_file(filename);
3634     else
3635       File_error=0;
3636 
3637     Hide_cursor();
3638 
3639     if (!File_error)
3640     {
3641       T_IO_Context save_context;
3642 
3643       old_cursor_shape=Cursor_shape;
3644       Cursor_shape=CURSOR_SHAPE_HOURGLASS;
3645       Display_cursor();
3646 
3647       Init_context_layered_image(&save_context, Main.backups->Pages->Filename, Main.backups->Pages->File_directory);
3648       save_context.File_name_unicode = Unicode_strdup(Main.backups->Pages->Filename_unicode);
3649       Save_image(&save_context);
3650       if (!File_error)
3651       {
3652         Main.image_is_modified=0;
3653       }
3654       Destroy_context(&save_context);
3655 
3656       Hide_cursor();
3657       Cursor_shape=old_cursor_shape;
3658     }
3659     else
3660       Error(0);
3661   }
3662   else
3663     Hide_cursor();
3664 
3665   free(filename);
3666   Unselect_button(BUTTON_SAVE);
3667 
3668   Display_cursor();
3669 }
3670 
3671 
3672 // -- Gestion des boutons de ligne ------------------------------------------
3673 
Button_Lines(int btn)3674 void Button_Lines(int btn)
3675 {
3676   (void)btn;
3677   Hide_cursor();
3678   Start_operation_stack(Selected_line_mode);
3679   Display_cursor();
3680 }
3681 
3682 
Button_Lines_switch_mode(int btn)3683 void Button_Lines_switch_mode(int btn)
3684 {
3685   char icon;
3686 
3687   if (Selected_line_mode==OPERATION_LINE)
3688   {
3689     Selected_line_mode=OPERATION_K_LINE;
3690     icon=MENU_SPRITE_K_LINE;
3691   }
3692   else if (Selected_line_mode==OPERATION_K_LINE)
3693   {
3694     Selected_line_mode=OPERATION_CENTERED_LINES;
3695     icon=MENU_SPRITE_CENTERED_LINES;
3696   }
3697   else
3698   {
3699     Selected_line_mode=OPERATION_LINE;
3700     icon=-1;
3701   }
3702 
3703   Hide_cursor();
3704   Display_sprite_in_menu(btn,icon);
3705   Draw_menu_button(btn,BUTTON_PRESSED);
3706   Start_operation_stack(Selected_line_mode);
3707   Display_cursor();
3708 }
3709 
3710 
3711 // -- Button de brosse ------------------------------------------------------
3712 
Button_Brush(int btn)3713 void Button_Brush(int btn)
3714 {
3715   Hide_cursor();
3716 
3717   if (Current_operation!=OPERATION_GRAB_BRUSH)
3718     Start_operation_stack(OPERATION_GRAB_BRUSH);
3719   else
3720     Unselect_button(btn);
3721 
3722   Display_cursor();
3723 }
3724 
3725 
Button_Unselect_brush(int btn)3726 void Button_Unselect_brush(int btn)
3727 {
3728   (void)btn;
3729   // On fait de notre mieux pour restaurer l'ancienne opération:
3730   Start_operation_stack(Operation_before_interrupt);
3731 }
3732 
3733 
Button_Restore_brush(int btn)3734 void Button_Restore_brush(int btn)
3735 {
3736   Hide_cursor();
3737   // On passe en brosse couleur:
3738   Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
3739 
3740   Unselect_button(btn);
3741 
3742   Display_cursor();
3743 }
3744 
3745 
3746 // -- Button de prise de brosse au lasso ------------------------------------
3747 
Button_Lasso(int btn)3748 void Button_Lasso(int btn)
3749 {
3750   Hide_cursor();
3751 
3752   if (Current_operation!=OPERATION_POLYBRUSH)
3753   {
3754     Paintbrush_shape_before_lasso=Paintbrush_shape;
3755     Paintbrush_shape=PAINTBRUSH_SHAPE_POINT;
3756     Start_operation_stack(OPERATION_POLYBRUSH);
3757   }
3758   else
3759     Unselect_button(btn);
3760 
3761   Display_cursor();
3762 }
3763 
3764 
Button_Unselect_lasso(int btn)3765 void Button_Unselect_lasso(int btn)
3766 {
3767   (void)btn;
3768 
3769   // If we aren't in OPERATION_POLYBRUSH, then we didn't save a brush shape,
3770   // and we shouldn't try to restore it.
3771   if (Current_operation==OPERATION_POLYBRUSH)
3772     Paintbrush_shape=Paintbrush_shape_before_lasso;
3773 
3774   // On fait de notre mieux pour restaurer l'ancienne opération:
3775   Start_operation_stack(Operation_before_interrupt);
3776 }
3777 
3778 
3779 // -- Button de pipette -----------------------------------------------------
3780 
Button_Colorpicker(int btn)3781 void Button_Colorpicker(int btn)
3782 {
3783   Hide_cursor();
3784 
3785   if (Current_operation!=OPERATION_COLORPICK)
3786   {
3787     Colorpicker_color=-1;
3788     Start_operation_stack(OPERATION_COLORPICK);
3789     Paintbrush_shape_before_colorpicker=Paintbrush_shape;
3790     Paintbrush_shape=PAINTBRUSH_SHAPE_NONE;
3791     if (Operation_before_interrupt!=OPERATION_REPLACE)
3792       if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
3793            ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
3794         Print_in_menu("X:       Y:       (    )",0);
3795   }
3796   else
3797     Unselect_button(btn);
3798 
3799   Display_cursor();
3800 }
3801 
3802 
Button_Unselect_colorpicker(int btn)3803 void Button_Unselect_colorpicker(int btn)
3804 {
3805   (void)btn;
3806   // Erase the color block which shows the picked color
3807   if (Operation_before_interrupt!=OPERATION_REPLACE)
3808     if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
3809          ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
3810       Print_in_menu("X:       Y:             ",0);
3811 
3812   // On fait de notre mieux pour restaurer l'ancienne opération:
3813   if (Current_operation==OPERATION_COLORPICK)
3814   {
3815     Start_operation_stack(Operation_before_interrupt);
3816     Paintbrush_shape=Paintbrush_shape_before_colorpicker;
3817   }
3818 }
3819 
3820 
3821   // -- Inversion de la couleur Fore et de la couleur Back --
Button_Invert_foreback(int btn)3822 void Button_Invert_foreback(int btn)
3823 {
3824   byte temp_color;
3825 
3826   temp_color=Fore_color;
3827   Fore_color        =Back_color;
3828   Back_color        =temp_color;
3829 
3830   Hide_cursor();
3831   Frame_menu_color(Back_color);
3832   Frame_menu_color(Fore_color);
3833   Reposition_palette();
3834   Display_foreback();
3835   Unselect_button(btn);
3836   Display_cursor();
3837 }
3838 
3839 
3840 // -- Gestion du bouton Loupe -----------------------------------------------
3841 
3842 byte Coming_from_zoom_factor_menu=0;
3843 
Button_Magnify(int btn)3844 void Button_Magnify(int btn)
3845 {
3846   Hide_cursor();
3847   if ( (Current_operation==OPERATION_MAGNIFY) || (Main.magnifier_mode) )
3848   {
3849     Unselect_button(btn);
3850   }
3851   else
3852   {
3853     Compute_magnifier_data();
3854     if ((!Config.Fast_zoom) || (Mouse_Y>=Menu_Y) || Coming_from_zoom_factor_menu)
3855     {
3856       Coming_from_zoom_factor_menu=0;
3857       Start_operation_stack(OPERATION_MAGNIFY);
3858     }
3859     else
3860     { /* Ceci est de la duplication de code de presque toute l'opération de */
3861       /* la loupe... Il serait peut-être plus propre de faire une procédure */
3862       /* qui s'en charge... */
3863       // On passe en mode loupe
3864       Main.magnifier_mode=1;
3865 
3866       // La fonction d'affichage dans la partie image est désormais un affichage
3867       // spécial loupe.
3868       Pixel_preview=Pixel_preview_magnifier;
3869 
3870       // On calcule l'origine de la loupe
3871       Main.magnifier_offset_X=Mouse_X-(Main.magnifier_width>>1);
3872       Main.magnifier_offset_Y=Mouse_Y-(Main.magnifier_height>>1);
3873 
3874      // Calcul des coordonnées absolues de ce coin DANS L'IMAGE
3875       Main.magnifier_offset_X+=Main.offset_X;
3876       Main.magnifier_offset_Y+=Main.offset_Y;
3877 
3878       Clip_magnifier_offsets(&Main.magnifier_offset_X, &Main.magnifier_offset_Y);
3879 
3880       // On calcule les bornes visibles dans l'écran
3881       Position_screen_according_to_zoom();
3882       Compute_limits();
3883       Display_all_screen();
3884 
3885       // Repositionner le curseur en fonction des coordonnées visibles
3886       Compute_paintbrush_coordinates();
3887     }
3888   }
3889   Display_cursor();
3890   Update_rect(0,0,0,0);
3891 }
3892 
Button_Magnify_menu(int btn)3893 void Button_Magnify_menu(int btn)
3894 {
3895   T_Dropdown_button dropdown;
3896   T_Dropdown_choice *item;
3897   int i;
3898   static const char * text[NB_ZOOM_FACTORS] =
3899     {"x2", "x3", "x4", "x5", "x6", "x8", "x10", "x12", "x14", "x16", "x18", "x20",
3900       "x24", "x28", "x32"};
3901 
3902   (void)btn;
3903   Hide_cursor();
3904 
3905   dropdown.Pos_X         =Buttons_Pool[BUTTON_MAGNIFIER].X_offset;
3906   dropdown.Pos_Y         =Buttons_Pool[BUTTON_MAGNIFIER].Y_offset;
3907   dropdown.Height        =Buttons_Pool[BUTTON_MAGNIFIER].Height;
3908   dropdown.Dropdown_width=28;
3909   dropdown.First_item    =NULL;
3910   dropdown.Bottom_up     =1;
3911 
3912   for(i = 0; i < NB_ZOOM_FACTORS; i++) {
3913     Window_dropdown_add_item(&dropdown, i, text[i]);
3914   }
3915 
3916   item=Dropdown_activate(&dropdown,0,Menu_Y);
3917 
3918   if (item)
3919   {
3920     Change_magnifier_factor(item->Number,0);
3921   }
3922 
3923   if ( (!item) && (!Main.magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Cancel
3924     Unselect_button(BUTTON_MAGNIFIER);
3925 
3926   Display_all_screen();
3927   Display_cursor();
3928   Update_rect(Main.separator_position,0,Screen_width-Main.separator_position,Menu_Y);
3929 
3930   if ( (item) && (!Main.magnifier_mode) && (Current_operation!=OPERATION_MAGNIFY) ) // Passage en mode zoom
3931   {
3932     Coming_from_zoom_factor_menu=1;
3933     Select_button(BUTTON_MAGNIFIER,LEFT_SIDE);
3934   }
3935 
3936   Window_dropdown_clear_items(&dropdown);
3937 }
3938 
Button_Unselect_magnifier(int btn)3939 void Button_Unselect_magnifier(int btn)
3940 {
3941   (void)btn;
3942   if (Main.magnifier_mode)
3943   {
3944     // On sort du mode loupe
3945     Main.magnifier_mode=0;
3946 
3947 
3948     // --> Recalculer le décalage de l'écran lorsqu'on sort de la loupe <--
3949     // Centrage "brut" de lécran par rapport à la loupe
3950     Main.offset_X=Main.magnifier_offset_X-((Screen_width-Main.magnifier_width)>>1);
3951     Main.offset_Y=Main.magnifier_offset_Y-((Menu_Y-Main.magnifier_height)>>1);
3952 
3953     // Correction en cas de débordement de l'image
3954     if (Main.offset_X+Screen_width>Main.image_width)
3955       Main.offset_X=Main.image_width-Screen_width;
3956     if (Main.offset_X<0)
3957       Main.offset_X=0;
3958 
3959     if (Main.offset_Y+Menu_Y>Main.image_height)
3960       Main.offset_Y=Main.image_height-Menu_Y;
3961     if (Main.offset_Y<0)
3962       Main.offset_Y=0;
3963 
3964     // La fonction d'affichage dans l'image est désormais un affichage normal.
3965     Pixel_preview=Pixel_preview_normal;
3966 
3967     // Calculer les bornes visibles dans l'écran
3968     Compute_limits();
3969     Display_all_screen();  // <=> Display_screen();
3970     // Repositionner le curseur en fonction des coordonnées visibles
3971     Compute_paintbrush_coordinates();
3972 
3973     Old_MX = -1;
3974     Old_MY = -1;
3975   }
3976   else // On fait de notre mieux pour restaurer l'ancienne opération:
3977     Start_operation_stack(Operation_before_interrupt);
3978 }
3979 
3980 
3981 // ----------------------- Modifications de brosse ---------------------------
3982 
Button_Brush_FX(int btn)3983 void Button_Brush_FX(int btn)
3984 {
3985   short clicked_button;
3986   short index;
3987 
3988   Open_window(310,162,"Brush effects");
3989 
3990   Window_display_frame(  6,19,298,61);
3991   Window_display_frame(  6,83,122,53);
3992   Window_display_frame(137,83,167,53);
3993 
3994   Window_set_normal_button(236,141, 67,14,"Cancel"          ,0,1,KEY_ESC); // 1
3995   Window_set_normal_button( 19, 46, 27,14,"X\035"           ,0,1,Config_Key[SPECIAL_FLIP_X][0]); // 2
3996   Window_set_normal_button( 19, 61, 27,14,"Y\022"           ,0,1,Config_Key[SPECIAL_FLIP_Y][0]); // 3
3997   Window_set_normal_button( 58, 46, 37,14,"90\xb0"             ,0,1,Config_Key[SPECIAL_ROTATE_90][0]); // 4
3998   Window_set_normal_button( 96, 46, 37,14,"180\xb0"            ,0,1,Config_Key[SPECIAL_ROTATE_180][0]); // 5
3999   Window_set_normal_button( 58, 61, 75,14,"any angle"       ,0,1,Config_Key[SPECIAL_ROTATE_ANY_ANGLE][0]); // 6
4000   Window_set_normal_button(145, 46, 67,14,"Stretch"         ,0,1,Config_Key[SPECIAL_STRETCH][0]); // 7
4001   Window_set_normal_button(145, 61, 67,14,"Distort"         ,0,1,Config_Key[SPECIAL_DISTORT][0]); // 8
4002   Window_set_normal_button(155, 99,131,14,"Recolorize"      ,0,1,Config_Key[SPECIAL_RECOLORIZE_BRUSH][0]); // 9
4003   Window_set_normal_button(155,117,131,14,"Get brush colors",0,1,Config_Key[SPECIAL_GET_BRUSH_COLORS][0]); // 10
4004 
4005   // Boutons représentant les coins du brush handle: (HG,HD,C,BG,BD)
4006   Window_set_normal_button( 75, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_LEFT_ATTACHMENT][0]); // 11
4007   Window_set_normal_button(103, 90,11,11,"",0,1,Config_Key[SPECIAL_TOP_RIGHT_ATTACHMENT][0]); // 12
4008   Window_set_normal_button( 89,104,11,11,"",0,1,Config_Key[SPECIAL_CENTER_ATTACHMENT][0]); // 13
4009   Window_set_normal_button( 75,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_LEFT_ATTACHMENT][0]); // 14
4010   Window_set_normal_button(103,118,11,11,"",0,1,Config_Key[SPECIAL_BOTTOM_RIGHT_ATTACHMENT][0]); // 15
4011 
4012   Window_set_normal_button(224,46,67,14,"Outline",0,1,Config_Key[SPECIAL_OUTLINE][0]); // 16
4013   Window_set_normal_button(224,61,67,14,"Nibble" ,0,1,Config_Key[SPECIAL_NIBBLE][0]); // 17
4014 
4015   Window_set_normal_button(  7,141, 60,14,"Load",0,1,Config_Key[SPECIAL_LOAD_BRUSH][0]); // 18
4016   Window_set_normal_button( 70,141, 60,14,"Save",0,1,Config_Key[SPECIAL_SAVE_BRUSH][0]); // 19
4017 
4018   Print_in_window( 80, 24,"Shape modifications",MC_Dark,MC_Light);
4019   Print_in_window( 10, 36,"Mirror",MC_Dark,MC_Light);
4020   Print_in_window( 72, 36,"Rotate",MC_Dark,MC_Light);
4021   Print_in_window(155, 36,"Deform",MC_Dark,MC_Light);
4022   Print_in_window(230, 36,"Borders",MC_Dark,MC_Light);
4023   Print_in_window(141, 88,"Colors modifications",MC_Dark,MC_Light);
4024   Print_in_window( 20,102,"Brush",MC_Dark,MC_Light);
4025   Print_in_window( 16,110,"handle",MC_Dark,MC_Light);
4026 
4027   // Dessin des pointillés pour le "brush handle"
4028   for (index=0; index<13; index+=2)
4029   {
4030     Pixel_in_window( 88+index, 92,MC_Dark);
4031     Pixel_in_window( 88+index,126,MC_Dark);
4032     Pixel_in_window( 77,103+index,MC_Dark);
4033     Pixel_in_window(111,103+index,MC_Dark);
4034   }
4035   // Dessin des coins et du centre pour les boutons du "brush handle"
4036     // Coin HG
4037   Window_rectangle(77, 92, 7, 1, MC_Black);
4038   Window_rectangle(77, 92, 1, 7, MC_Black);
4039     // Coin HD
4040   Window_rectangle(105, 92, 7, 1, MC_Black);
4041   Window_rectangle(111, 92, 1, 7, MC_Black);
4042     // Centre
4043   Window_rectangle(91, 109, 7, 1, MC_Black);
4044   Window_rectangle(94, 106, 1, 7, MC_Black);
4045     // Coin BG
4046   Window_rectangle(77, 126, 7, 1, MC_Black);
4047   Window_rectangle(77, 120, 1, 7, MC_Black);
4048     // Coin BD
4049   Window_rectangle(105, 126, 7, 1, MC_Black);
4050   Window_rectangle(111, 120, 1, 7, MC_Black);
4051 
4052   Update_window_area(0,0,Window_width, Window_height);
4053 
4054   Display_cursor();
4055 
4056   do
4057   {
4058     clicked_button=Window_clicked_button();
4059     if (Is_shortcut(Key,0x100+BUTTON_HELP))
4060     {
4061       Key=0;
4062       Window_help(BUTTON_BRUSH_EFFECTS, NULL);
4063     }
4064     else if (Is_shortcut(Key,0x100+BUTTON_BRUSH_EFFECTS))
4065     {
4066       clicked_button=1;
4067     }
4068   }
4069   while (clicked_button<=0 && !Quit_is_required);
4070 
4071   Close_window();
4072   Unselect_button(btn);
4073 
4074   // Gestion du bouton clické
4075   switch (clicked_button)
4076   {
4077     case  2 : // Flip X
4078       Flip_X_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
4079       // Remap according to the last used remap table
4080       Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
4081       break;
4082     case  3 : // Flip Y
4083       Flip_Y_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
4084       // Remap according to the last used remap table
4085       Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
4086       break;
4087     case  4 : // 90° Rotation
4088       Rotate_90_deg();
4089       break;
4090     case  5 : // 180° Rotation
4091       Rotate_180_deg_lowlevel(Brush_original_pixels, Brush_width, Brush_height);
4092       Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
4093       Brush_offset_X=(Brush_width>>1);
4094       Brush_offset_Y=(Brush_height>>1);
4095       break;
4096     case  6 : // Any angle rotation
4097       Start_operation_stack(OPERATION_ROTATE_BRUSH);
4098       break;
4099     case  7 : // Stretch
4100       Start_operation_stack(OPERATION_STRETCH_BRUSH);
4101       break;
4102     case  8 : // Distort
4103       Start_operation_stack(OPERATION_DISTORT_BRUSH);
4104       break;
4105     case  9 : // Recolorize
4106       Remap_brush();
4107       break;
4108     case 10 : // Get brush colors
4109       Display_cursor();
4110       Get_colors_from_brush();
4111       Hide_cursor();
4112       break;
4113     case 11 : // Brush Attachment: Top-Left
4114       Brush_offset_X=0;
4115       Brush_offset_Y=0;
4116       break;
4117     case 12 : // Brush Attachment: Top-Right
4118       Brush_offset_X=(Brush_width-1);
4119       Brush_offset_Y=0;
4120       break;
4121     case 13 : // Brush Attachment: Center
4122       Brush_offset_X=(Brush_width>>1);
4123       Brush_offset_Y=(Brush_height>>1);
4124       break;
4125     case 14 : // Brush Attachment: Bottom-Left
4126       Brush_offset_X=0;
4127       Brush_offset_Y=(Brush_height-1);
4128       break;
4129     case 15 : // Brush Attachment: Bottom-Right
4130       Brush_offset_X=(Brush_width-1);
4131       Brush_offset_Y=(Brush_height-1);
4132       break;
4133     case 16 : // Outline
4134       Outline_brush();
4135       break;
4136     case 17 : // Nibble
4137       Nibble_brush();
4138       break;
4139     case 18 : // Load
4140       Display_cursor();
4141       Load_picture(CONTEXT_BRUSH);
4142       Hide_cursor();
4143       break;
4144     case 19 : // Save
4145       Display_cursor();
4146       Save_picture(CONTEXT_BRUSH);
4147       Hide_cursor();
4148       break;
4149   }
4150 
4151   Display_cursor();
4152 }
4153 
4154 
4155 //---------------------------- Courbes de Bézier ----------------------------
4156 
Button_Curves(int btn)4157 void Button_Curves(int btn)
4158 {
4159   (void)btn;
4160   Hide_cursor();
4161   Start_operation_stack(Selected_curve_mode);
4162   Display_cursor();
4163 }
4164 
4165 
Button_Curves_switch_mode(int btn)4166 void Button_Curves_switch_mode(int btn)
4167 {
4168   if (Selected_curve_mode==OPERATION_4_POINTS_CURVE)
4169     Selected_curve_mode=OPERATION_3_POINTS_CURVE;
4170   else
4171     Selected_curve_mode=OPERATION_4_POINTS_CURVE;
4172 
4173   Hide_cursor();
4174   Display_sprite_in_menu(btn,Selected_curve_mode==OPERATION_4_POINTS_CURVE?MENU_SPRITE_4_POINTS_CURVE:-1);
4175   Draw_menu_button(btn,BUTTON_PRESSED);
4176   Start_operation_stack(Selected_curve_mode);
4177   Display_cursor();
4178 }
4179 
4180 
4181 //--------------------------------- Spray -----------------------------------
4182 
Button_Airbrush(int btn)4183 void Button_Airbrush(int btn)
4184 {
4185   (void)btn;
4186   Hide_cursor();
4187   Start_operation_stack(OPERATION_AIRBRUSH);
4188   Display_cursor();
4189 }
4190 
4191 
Refresh_airbrush_settings(byte selected_color,byte update_slider)4192 void Refresh_airbrush_settings(byte selected_color, byte update_slider)
4193 {
4194   char  str[4];
4195 
4196   if (update_slider)
4197   {
4198     Window_scroller_button_list->Position=49-Airbrush_multi_flow[selected_color];
4199     Window_draw_slider(Window_scroller_button_list);
4200   }
4201   Num2str(Airbrush_multi_flow[selected_color],str,2);
4202   Print_in_window(196,130,str,MC_Black,MC_Light);
4203 
4204   Update_window_area(Window_palette_button_list->Pos_X+4+(selected_color >> 4)*10,
4205       Window_palette_button_list->Pos_Y+3+(selected_color & 15)* 5,
4206       2,5);
4207 }
4208 
4209 
Button_Airbrush_menu(int btn)4210 void Button_Airbrush_menu(int btn)
4211 {
4212   static byte spray_init=1;
4213   short  clicked_button;
4214   char   str[4];
4215   word   index;
4216   byte   selected_color=Fore_color;
4217   byte   old_airbrush_mode     =Airbrush_mode;
4218   short  old_airbrush_size     =Airbrush_size;
4219   byte   old_airbrush_delay    =Airbrush_delay;
4220   byte   old_airbrush_mono_flow=Airbrush_mono_flow;
4221   byte   old_airbrush_multi_flow[256];
4222   T_Special_button * input_size_button;
4223   T_Special_button * input_delay_button;
4224   T_Special_button * input_flow_button;
4225   T_Special_button * input_init_button;
4226   word old_mouse_x;
4227   word old_mouse_y;
4228   byte old_mouse_k;
4229   byte color;
4230   byte click;
4231 
4232   (void)btn;
4233   memcpy(old_airbrush_multi_flow,Airbrush_multi_flow,256);
4234 
4235 
4236   Open_window(226,170,"Spray");
4237 
4238   Window_set_normal_button(110,148,51,14,"Cancel"    ,0,1,KEY_ESC); // 1
4239   Window_set_normal_button(166,148,51,14,"OK"        ,0,1,KEY_RETURN); // 2
4240 
4241   Window_set_scroller_button(178,62,74,50,1,49-Airbrush_multi_flow[selected_color]); // 3
4242 
4243   Window_set_palette_button(7,56);                                 // 4
4244 
4245   Window_set_normal_button(  8,148,83,14,"Mode:     ",0,1,KEY_TAB); // 5
4246   if (Airbrush_mode)
4247     Print_in_window(50,151," Mono",MC_Black,MC_Light);
4248   else
4249     Print_in_window(50,151,"Multi",MC_Black,MC_Light);
4250 
4251   Window_set_normal_button(194, 62,19,14,"+1"        ,0,1,KEY_KP_PLUS); // 6
4252   Window_set_normal_button(194, 79,19,14,"-1"        ,0,1,KEY_KP_MINUS); // 7
4253   Window_set_normal_button(194, 96,19,14,"x2"        ,0,1,KEY_KP_MULTIPLY); // 8
4254   Window_set_normal_button(194,113,19,14,"\xf7""2"   ,0,1,KEY_KP_ENTER); // 9
4255 
4256   Window_set_normal_button(  8, 37,43,14,"Clear"     ,1,1,KEY_c); // 10
4257 
4258   Print_in_window_underscore(142,25,"Size:"     ,MC_Dark,MC_Light,1);
4259   input_size_button = Window_set_input_button_s(186,23,3,KEY_s); // 11
4260   Num2str(Airbrush_size,str,3);
4261   Window_input_content(input_size_button,str);
4262 
4263   Print_in_window_underscore(142,39,"Delay:"    ,MC_Dark,MC_Light,1);
4264   input_delay_button = Window_set_input_button_s(194,37,2,KEY_d); // 12
4265   Num2str(Airbrush_delay,str,2);
4266   Window_input_content(input_delay_button,str);
4267 
4268   Print_in_window_underscore( 27,24,"Mono-Flow:",MC_Dark,MC_Light,1);
4269   input_flow_button = Window_set_input_button_s(111,22,2,KEY_m); // 13
4270   Num2str(Airbrush_mono_flow,str,2);
4271   Window_input_content(input_flow_button,str);
4272 
4273   Print_in_window_underscore( 67,40,"Init:",MC_Dark,MC_Light,1);
4274   input_init_button = Window_set_input_button_s(111,38,2,KEY_i); // 14
4275   Num2str(spray_init,str,2);
4276   Window_input_content(input_init_button,str);
4277 
4278   Window_display_frame(173,56,45,86);
4279   Window_display_frame(137,19,81,33);
4280 
4281   // On tagge toutes les couleurs utilisées
4282   for (index=0; index<256; index++)
4283     if (Airbrush_multi_flow[index])
4284       Stencil_tag_color(index,MC_Black);
4285   // Et enfin, on tagge la couleur sélectionnée
4286   Stencil_tag_color(selected_color,MC_White);
4287   Refresh_airbrush_settings(selected_color,0);
4288 
4289   Update_window_area(0,0,Window_width, Window_height);
4290   Display_cursor();
4291   Stencil_update_color(selected_color);
4292 
4293 
4294   do
4295   {
4296     old_mouse_x=Mouse_X;
4297     old_mouse_y=Mouse_Y;
4298     old_mouse_k=Mouse_K;
4299 
4300     clicked_button=Window_clicked_button();
4301 
4302     switch (clicked_button)
4303     {
4304       case  0 :
4305       case  2 : // OK
4306         break;
4307 
4308       case  1 : // Cancel
4309         Airbrush_mode     =old_airbrush_mode;
4310         Airbrush_size     =old_airbrush_size;
4311         Airbrush_delay    =old_airbrush_delay;
4312         Airbrush_mono_flow=old_airbrush_mono_flow;
4313         memcpy(Airbrush_multi_flow,old_airbrush_multi_flow,256);
4314         break;
4315 
4316       case  3 : // Scroller
4317         Hide_cursor();
4318         Airbrush_multi_flow[selected_color]=49-Window_attribute2;
4319         Refresh_airbrush_settings(selected_color,0);
4320         Display_cursor();
4321         break;
4322 
4323       case -1 :
4324       case  4 : // Palette
4325         if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
4326         {
4327           Hide_cursor();
4328           Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light);
4329           Stencil_update_color(selected_color);
4330           // Mettre la couleur sélectionnée à jour suivant le click
4331           selected_color=(clicked_button==4) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
4332           if (Mouse_K==2)
4333             Airbrush_multi_flow[selected_color]=0;
4334           else
4335             if (Airbrush_multi_flow[selected_color]==0)
4336               Airbrush_multi_flow[selected_color]=spray_init;
4337 
4338           // Tagger la couleur sélectionnée en blanc
4339           Stencil_tag_color(selected_color,MC_White);
4340           Refresh_airbrush_settings(selected_color,1);
4341           Display_cursor();
4342           Stencil_update_color(selected_color);
4343         }
4344         break;
4345 
4346       case  5 : // Toggle Mode
4347         Airbrush_mode=(Airbrush_mode+1)&1;
4348         Hide_cursor();
4349         if (Airbrush_mode)
4350           Print_in_window(50,151," Mono",MC_Black,MC_Light);
4351         else
4352           Print_in_window(50,151,"Multi",MC_Black,MC_Light);
4353         Update_window_area(50,151,5*8,8);
4354         Display_cursor();
4355         break;
4356 
4357       case  6 : // +1
4358         for (index=0; index<256; index++)
4359         {
4360           if ( (Airbrush_multi_flow[index]) && (Airbrush_multi_flow[index]<49) )
4361             Airbrush_multi_flow[index]++;
4362         }
4363         Hide_cursor();
4364         Refresh_airbrush_settings(selected_color,1);
4365         Display_cursor();
4366         break;
4367 
4368       case  7 : // -1
4369         for (index=0; index<256; index++)
4370         {
4371           if (Airbrush_multi_flow[index]>1)
4372             Airbrush_multi_flow[index]--;
4373         }
4374         Hide_cursor();
4375         Refresh_airbrush_settings(selected_color,1);
4376         Display_cursor();
4377         break;
4378 
4379       case  8 : // x2
4380         for (index=0; index<256; index++)
4381         {
4382           if (Airbrush_multi_flow[index])
4383           {
4384             Airbrush_multi_flow[index]<<=1;
4385             if (Airbrush_multi_flow[index]>49)
4386               Airbrush_multi_flow[index]=49;
4387           }
4388         }
4389         Hide_cursor();
4390         Refresh_airbrush_settings(selected_color,1);
4391         Display_cursor();
4392         break;
4393 
4394       case  9 : // ÷2
4395         for (index=0; index<256; index++)
4396         {
4397           if (Airbrush_multi_flow[index]>1)
4398             Airbrush_multi_flow[index]>>=1;
4399         }
4400         Hide_cursor();
4401         Refresh_airbrush_settings(selected_color,1);
4402         Display_cursor();
4403         break;
4404 
4405       case 10 : // Clear
4406         memset(Airbrush_multi_flow,0,256);
4407         // On raffiche les infos de la couleur sélectionnée
4408         Refresh_airbrush_settings(selected_color,1);
4409         // On efface les anciens TAGs
4410         Window_clear_tags();
4411         // Tagger la couleur sélectionnée en blanc
4412         Stencil_tag_color(selected_color,MC_White);
4413         Stencil_update_color(selected_color);
4414         break;
4415 
4416       case 11 : // Size
4417         Num2str(Airbrush_size,str,3);
4418         Readline(188,25,str,3,INPUT_TYPE_INTEGER);
4419         Airbrush_size=atoi(str);
4420         // On corrige les dimensions
4421         if (Airbrush_size>256)
4422         {
4423           Airbrush_size=256;
4424           Num2str(Airbrush_size,str,3);
4425           Window_input_content(input_size_button,str);
4426         }
4427         else if (!Airbrush_size)
4428         {
4429           Airbrush_size=1;
4430           Num2str(Airbrush_size,str,3);
4431           Window_input_content(input_size_button,str);
4432         }
4433         Display_cursor();
4434         break;
4435 
4436       case 12 : // Delay
4437         Num2str(Airbrush_delay,str,2);
4438         Readline(196,39,str,2,INPUT_TYPE_INTEGER);
4439         Airbrush_delay=atoi(str);
4440         // On corrige le delai
4441         if (Airbrush_delay>99)
4442         {
4443           Airbrush_delay=99;
4444           Num2str(Airbrush_delay,str,2);
4445           Window_input_content(input_delay_button,str);
4446         }
4447         Display_cursor();
4448         break;
4449 
4450       case 13 : // Mono-Flow
4451         Num2str(Airbrush_mono_flow,str,2);
4452         Readline(113,24,str,2,INPUT_TYPE_INTEGER);
4453         Airbrush_mono_flow=atoi(str);
4454         // On corrige le flux
4455         if (!Airbrush_mono_flow)
4456         {
4457           Airbrush_mono_flow=1;
4458           Num2str(Airbrush_mono_flow,str,2);
4459           Window_input_content(input_flow_button,str);
4460         }
4461         Display_cursor();
4462         break;
4463 
4464       case 14 : // Init
4465         Num2str(spray_init,str,2);
4466         Readline(113,40,str,2,INPUT_TYPE_INTEGER);
4467         spray_init=atoi(str);
4468         // On corrige la valeur
4469         if (spray_init>=50)
4470         {
4471           spray_init=49;
4472           Num2str(spray_init,str,2);
4473           Window_input_content(input_init_button,str);
4474         }
4475         else if (spray_init<1)
4476         {
4477           spray_init=1;
4478           Num2str(spray_init,str,2);
4479           Window_input_content(input_init_button,str);
4480         }
4481         Display_cursor();
4482         break;
4483     }
4484 
4485     if (!Mouse_K)
4486     switch (Key)
4487     {
4488       case KEY_BACKQUOTE : // Récupération d'une couleur derrière le menu
4489       case KEY_COMMA :
4490         Get_color_behind_window(&color,&click);
4491         if (click)
4492         {
4493           Hide_cursor();
4494           Stencil_tag_color(selected_color,(Airbrush_multi_flow[selected_color])?MC_Black:MC_Light);
4495           Stencil_update_color(selected_color);
4496           // Mettre la couleur sélectionnée à jour suivant le click
4497           selected_color=color;
4498           if (click==2)
4499             Airbrush_multi_flow[selected_color]=0;
4500           else
4501             if (Airbrush_multi_flow[selected_color]==0)
4502               Airbrush_multi_flow[selected_color]=spray_init;
4503 
4504           // Tagger la couleur sélectionnée en blanc
4505           Stencil_tag_color(selected_color,MC_White);
4506           Refresh_airbrush_settings(selected_color,1);
4507           Display_cursor();
4508           Stencil_update_color(selected_color);
4509           Wait_end_of_click();
4510         }
4511         Key=0;
4512         break;
4513       default:
4514       if (Is_shortcut(Key,0x100+BUTTON_HELP))
4515       {
4516         Window_help(BUTTON_AIRBRUSH, NULL);
4517         Key=0;
4518         break;
4519       }
4520       if (Is_shortcut(Key,0x200+BUTTON_AIRBRUSH))
4521       {
4522         clicked_button=2;
4523         break;
4524       }
4525     }
4526   }
4527   while ( (clicked_button!=1) && (clicked_button!=2) && !Quit_is_required);
4528 
4529   Close_window();
4530 
4531 /*
4532   //   Tant que l'on aura pas résolu le problème du désenclenchement du mode
4533   // de dessin précedent, il faudra laisser ça en remarque et donc passer en
4534   // spray même si on a clické sur Cancel (idem pour OK (un peu plus bas)).
4535   if (clicked_button==1) // Cancel
4536   {
4537     if (Current_operation!=OPERATION_AIRBRUSH)
4538       Unselect_button(BUTTON_AIRBRUSH);
4539   }
4540 */
4541 
4542   Display_cursor();
4543 
4544 /*
4545   if (clicked_button==2) // OK
4546 */
4547     if (Current_operation!=OPERATION_AIRBRUSH)
4548       Select_button(BUTTON_AIRBRUSH,LEFT_SIDE);
4549 }
4550 
4551 
4552 // -- Gestion des boutons de polygone vide et plein -------------------------
4553 
Button_polygon(int btn)4554 void Button_polygon(int btn)
4555 {
4556   (void)btn;
4557   Hide_cursor();
4558   Start_operation_stack(OPERATION_POLYGON);
4559   Display_cursor();
4560 }
4561 
4562 
Button_Polyform(int btn)4563 void Button_Polyform(int btn)
4564 {
4565   (void)btn;
4566   Hide_cursor();
4567   Start_operation_stack(OPERATION_POLYFORM);
4568   Display_cursor();
4569 }
4570 
4571 
Button_Polyfill(int btn)4572 void Button_Polyfill(int btn)
4573 {
4574   (void)btn;
4575   Hide_cursor();
4576   Start_operation_stack(OPERATION_POLYFILL);
4577   Display_cursor();
4578 }
4579 
4580 
Button_Filled_polyform(int btn)4581 void Button_Filled_polyform(int btn)
4582 {
4583   (void)btn;
4584   Hide_cursor();
4585   Start_operation_stack(OPERATION_FILLED_POLYFORM);
4586   Display_cursor();
4587 }
4588 
4589 
4590 // -- Boutons d'ajustement de l'image ---------------------------------------
4591 
Button_Adjust(int btn)4592 void Button_Adjust(int btn)
4593 {
4594   (void)btn;
4595   Hide_cursor();
4596   Start_operation_stack(OPERATION_SCROLL);
4597   Display_cursor();
4598 }
4599 
4600 
4601 // -- Menu des effets (Shade, Stencil, etc...) ------------------------------
4602 
Display_effect_sprite(int sprite_number,short start_x,short start_y)4603 void Display_effect_sprite(int sprite_number, short start_x, short start_y)
4604 {
4605   short x,y,x_pos,y_pos;
4606 
4607   for (y=0,y_pos=start_y;y<EFFECT_SPRITE_HEIGHT;y++,y_pos++)
4608     for (x=0,x_pos=start_x;x<EFFECT_SPRITE_WIDTH;x++,x_pos++)
4609       Pixel_in_window(x_pos,y_pos,Gfx->Effect_sprite[sprite_number][y][x]);
4610 
4611   Update_rect(ToWinX(start_x),ToWinY(start_y),EFFECT_SPRITE_WIDTH*Menu_factor_X,EFFECT_SPRITE_HEIGHT*Menu_factor_Y);
4612 }
4613 
4614 
Display_effect_state(short x,short y,char * label,byte state)4615 void Display_effect_state(short x, short y, char * label, byte state)
4616 {
4617   Window_rectangle(x+22,y+5,12,8,MC_Light);
4618 
4619   Print_in_window(x+22,y+5,label,(state)?MC_White:MC_Black,MC_Light);
4620   if (state)
4621     Window_select_normal_button(x, y, 16, 16);
4622   else
4623     Window_unselect_normal_button(x, y, 16, 16);
4624 }
4625 
4626 #define C1 10
4627 #define C2 99
4628 #define C3 184
4629 
4630 #define L1 19
4631 #define L2 38
4632 #define L3 57
4633 #define L4 76
4634 #define L5 95
4635 
Display_effect_states(void)4636 void Display_effect_states(void)
4637 {
4638   Display_effect_state(C1, L2, "Shade"  ,Shade_mode);
4639   Display_effect_state(C1, L3, "Q-shade",Quick_shade_mode);
4640   Display_effect_state(C1, L4, "Transp.",Colorize_mode);
4641   Display_effect_state(C1, L5, "Smooth" ,Smooth_mode);
4642   Display_effect_state(C2, L5, "Smear"  ,Smear_mode);
4643   Display_effect_state(C2, L1, "Stencil",Stencil_mode);
4644   Display_effect_state(C2, L2, "Mask"   ,Mask_mode);
4645   Display_effect_state(C2, L3, "Sieve"  ,Sieve_mode);
4646   Display_effect_state(C3, L2, "Snap"   ,Snap_mode);
4647   Display_effect_state(C3, L4, "Tiling" ,Tiling_mode);
4648 
4649   Display_effect_state(C2,L4, "8 bit"  ,Main.backups->Pages->Image_mode > IMAGE_MODE_ANIMATION);
4650   Display_effect_state(C3,L3, "Tilemap",Main.tilemap_mode);
4651 }
4652 
4653 
Display_feedback_state(void)4654 void Display_feedback_state(void)
4655 {
4656   Print_in_window(14,24,(Config.FX_Feedback)?"X":" ",MC_Black,MC_Light);
4657 }
4658 
4659 
Button_Effects(int btn)4660 void Button_Effects(int btn)
4661 {
4662   short clicked_button;
4663   byte exit_by_close_button=0;
4664 
4665   Open_window(270,152,"Drawing modes (effects)");
4666 
4667   Window_set_normal_button(C1, L2, 16,16,"",0,1,Config_Key[SPECIAL_SHADE_MODE][0]); // 1
4668   Window_set_normal_button(C1, L3, 16,16,"",0,1,Config_Key[SPECIAL_QUICK_SHADE_MODE][0]); // 2
4669   Window_set_normal_button(C1, L4, 16,16,"",0,1,Config_Key[SPECIAL_COLORIZE_MODE][0]); // 3
4670   Window_set_normal_button(C1, L5, 16,16,"",0,1,Config_Key[SPECIAL_SMOOTH_MODE][0]); // 4
4671   Window_set_normal_button(C2, L5, 16,16,"",0,1,Config_Key[SPECIAL_SMEAR_MODE][0]); // 5
4672   Window_set_normal_button(C2, L1, 16,16,"",0,1,Config_Key[SPECIAL_STENCIL_MODE][0]); // 6
4673   Window_set_normal_button(C2, L2, 16,16,"",0,1,Config_Key[SPECIAL_MASK_MODE][0]); // 7
4674   Window_set_normal_button(C2, L3, 16,16,"",0,1,Config_Key[SPECIAL_SIEVE_MODE][0]); // 8
4675   Window_set_normal_button(C3, L2, 16,16,"",0,1,Config_Key[SPECIAL_GRID_MODE][0]); // 9
4676   Window_set_normal_button(C3, L4, 16,16,"",0,1,Config_Key[SPECIAL_TILING_MODE][0]); // 10
4677 
4678   Window_set_normal_button(195,131, 68,14,"Close",0,1,KEY_RETURN); // 11
4679   Window_set_normal_button(118,131, 68,14,"All off",0,1,KEY_DELETE); // 12
4680 
4681   // "Feedback" frame
4682   Window_display_frame_mono(C1-5,L1+8,90,88,MC_Dark);
4683   Window_rectangle(C1-1, L1+2, 78, 14, MC_Light);
4684 
4685   Window_set_normal_button(C1+1,L1+2,14,14," ",0,1,KEY_f); // 13
4686   Print_in_window_underscore(28,24,"Feedback",MC_Dark,MC_Light,1);
4687 
4688   Window_set_normal_button(C2, L4, 16,16,"",0,1,Config_Key[SPECIAL_FORMAT_CHECKER_MENU][0]); // 14
4689   Window_set_normal_button(C3, L3, 16,16,"",0,1,Config_Key[SPECIAL_TILEMAP_MODE][0]); // 15
4690 
4691   // "Grid" frame
4692   Window_display_frame_mono(C3-5,L1+8,86,88,MC_Dark);
4693   Window_rectangle(C3-1, L1+2, 52, 14, MC_Light);
4694 
4695   Window_set_normal_button(C3+1,L1+2,14,14,Show_grid?"X":" ",0,1,Config_Key[SPECIAL_SHOW_GRID][0]); // 16
4696   Print_in_window(C3+17,L1+5,"Grid",MC_Dark,MC_Light);
4697 
4698   Display_feedback_state();
4699   Display_effect_sprite(EFFECTS_SPRITE_SHADE,  C1+1,L2+1);
4700   Display_effect_sprite(EFFECTS_SPRITE_SHADE,  C1+1,L3+1);
4701   Display_effect_sprite(EFFECTS_SPRITE_TRANSP, C1+1,L4+1);
4702   Display_effect_sprite(EFFECTS_SPRITE_SMOOTH, C1+1,L5+1);
4703   Display_effect_sprite(EFFECTS_SPRITE_SMEAR,  C2+1,L5+1);
4704   Display_effect_sprite(EFFECTS_SPRITE_STENCIL,C2+1,L1+1);
4705   Display_effect_sprite(EFFECTS_SPRITE_MASK,   C2+1,L2+1);
4706   Display_effect_sprite(EFFECTS_SPRITE_SIEVE,  C2+1,L3+1);
4707   Display_effect_sprite(EFFECTS_SPRITE_GRID,   C3+1,L2+1);
4708   Display_effect_sprite(EFFECTS_SPRITE_TILING, C3+1,L4+1);
4709   Display_effect_sprite(EFFECTS_SPRITE_8BIT,   C2+1,L4+1);
4710   Display_effect_sprite(EFFECTS_SPRITE_TILING, C3+1,L3+1); // tilemap
4711   Display_effect_states();
4712 
4713   Print_in_window(12,118,"click:",MC_Dark,MC_Light);
4714   Print_in_window(16,128,"Left:Switch",MC_Dark,MC_Light);
4715   Print_in_window(16,138,"Right:Edit",MC_Dark,MC_Light);
4716 
4717   Update_window_area(0,0,Window_width, Window_height);
4718   Display_cursor();
4719 
4720   do
4721   {
4722     clicked_button = Window_clicked_button();
4723 
4724     if (Key==KEY_ESC || Is_shortcut(Key,0x100+BUTTON_EFFECTS))
4725     {
4726       clicked_button=11;
4727       Key=0;
4728     }
4729     else if (Is_shortcut(Key,0x100+BUTTON_HELP))
4730     {
4731       // Aide contextuelle
4732       switch(Window_get_clicked_button())
4733       {
4734         case 1:
4735           Window_help(BUTTON_EFFECTS, "SHADE");
4736           break;
4737         case 2:
4738           Window_help(BUTTON_EFFECTS, "QUICK SHADE");
4739           break;
4740         case 3:
4741           Window_help(BUTTON_EFFECTS, "TRANSPARENCY");
4742           break;
4743         case 4:
4744           Window_help(BUTTON_EFFECTS, "SMOOTH");
4745           break;
4746         case 5:
4747           Window_help(BUTTON_EFFECTS, "SMEAR");
4748           break;
4749         case 6:
4750           Window_help(BUTTON_EFFECTS, "STENCIL");
4751           break;
4752         case 7:
4753           Window_help(BUTTON_EFFECTS, "MASK");
4754           break;
4755         case 8:
4756           Window_help(BUTTON_EFFECTS, "SIEVE");
4757           break;
4758         case 9:
4759           Window_help(BUTTON_EFFECTS, "GRID");
4760           break;
4761         case 10:
4762           Window_help(BUTTON_EFFECTS, "TILING");
4763           break;
4764         case 14:
4765           Window_help(BUTTON_EFFECTS, "8 BIT");
4766           break;
4767         case 15:
4768           Window_help(BUTTON_EFFECTS, "TILEMAP");
4769           break;
4770         default:
4771           Window_help(BUTTON_EFFECTS, NULL);
4772       }
4773       // Hack because we have used Window_get_clicked_button()
4774       Input_sticky_control=0;
4775       //
4776     }
4777 
4778     switch (clicked_button)
4779     {
4780       case 1 : // Shade
4781         if (Window_attribute1==LEFT_SIDE)
4782         {
4783           Button_Shade_mode();
4784           Hide_cursor();
4785           Display_effect_states();
4786           Display_cursor();
4787         }
4788         else
4789         {
4790           Close_window();
4791           Display_cursor();
4792           Button_Shade_menu();
4793           clicked_button=11;
4794         }
4795         break;
4796       case 2 : // Quick-shade
4797         if (Window_attribute1==LEFT_SIDE)
4798         {
4799           Button_Quick_shade_mode();
4800           Hide_cursor();
4801           Display_effect_states();
4802           Display_cursor();
4803         }
4804         else
4805         {
4806           Close_window();
4807           Display_cursor();
4808           Button_Quick_shade_menu();
4809           clicked_button=11;
4810         }
4811         break;
4812       case 3 : // Colorize / Transparency
4813         if (Window_attribute1==LEFT_SIDE)
4814         {
4815           Button_Colorize_mode();
4816           Hide_cursor();
4817           Display_effect_states();
4818           Display_cursor();
4819         }
4820         else
4821         {
4822           Close_window();
4823           Display_cursor();
4824           Button_Colorize_menu();
4825           clicked_button=11;
4826         }
4827         break;
4828       case 4 : // Smooth
4829         if (Window_attribute1==LEFT_SIDE)
4830         {
4831           Button_Smooth_mode();
4832           Hide_cursor();
4833           Display_effect_states();
4834           Display_cursor();
4835         }
4836         else
4837         {
4838           Close_window();
4839           Display_cursor();
4840           Button_Smooth_menu();
4841           clicked_button=11;
4842         }
4843         break;
4844       case 5 : // Smear
4845         Button_Smear_mode();
4846         Hide_cursor();
4847         Display_effect_states();
4848         Display_cursor();
4849         break;
4850       case 6 : // Stencil
4851         if (Window_attribute1==LEFT_SIDE)
4852         {
4853           Button_Stencil_mode();
4854           Hide_cursor();
4855           Display_effect_state(C2,L1,"Stencil",Stencil_mode);
4856           Display_cursor();
4857         }
4858         else
4859         {
4860           Close_window();
4861           Display_cursor();
4862           Button_Stencil_menu();
4863           clicked_button=11;
4864         }
4865         break;
4866       case 7 : // Mask
4867         if (Window_attribute1==LEFT_SIDE)
4868         {
4869           Button_Mask_mode();
4870           Hide_cursor();
4871           Display_effect_state(C2,L2,"Mask",Mask_mode);
4872           Display_cursor();
4873         }
4874         else
4875         {
4876           Close_window();
4877           Display_cursor();
4878           Button_Mask_menu();
4879           clicked_button=11;
4880         }
4881         break;
4882       case 8 : // Sieve
4883         if (Window_attribute1==LEFT_SIDE)
4884         {
4885           Button_Sieve_mode();
4886           Hide_cursor();
4887           Display_effect_state(C2,L3,"Sieve",Sieve_mode);
4888           Display_cursor();
4889         }
4890         else
4891         {
4892           Close_window();
4893           Display_cursor();
4894           Button_Sieve_menu();
4895           clicked_button=11;
4896         }
4897         break;
4898       case 9 : // Grid
4899         if (Window_attribute1==LEFT_SIDE)
4900         {
4901           Button_Snap_mode();
4902           Hide_cursor();
4903           Display_effect_state(C3,L2,"Snap",Snap_mode);
4904           Display_cursor();
4905         }
4906         else
4907         {
4908           Close_window();
4909           Display_cursor();
4910           Button_Grid_menu();
4911           clicked_button=11;
4912         }
4913         break;
4914       case 10 : // Tiling
4915         if (Window_attribute1==LEFT_SIDE)
4916         {
4917           Button_Tiling_mode();
4918           Hide_cursor();
4919           Display_effect_states();
4920           Display_cursor();
4921         }
4922         else
4923         {
4924           Close_window();
4925           Display_cursor();
4926           Button_Tiling_menu();
4927           clicked_button=11;
4928         }
4929         break;
4930       case 11 : // Close
4931         exit_by_close_button=1;
4932         break;
4933       case 12 : // All off
4934         Effects_off();
4935         Hide_cursor();
4936         Display_effect_states();
4937         Display_cursor();
4938         break;
4939       case 13 : // Feedback (pour Colorize et Shade)
4940         Config.FX_Feedback = !Config.FX_Feedback;
4941         Update_FX_feedback(Config.FX_Feedback);
4942         Hide_cursor();
4943         Display_feedback_state();
4944         Display_cursor();
4945         break;
4946 
4947 
4948       case 14: // Constraint checker/enforcer
4949         if (Window_attribute1==LEFT_SIDE && Selected_Constraint_Mode > IMAGE_MODE_ANIMATION)
4950         {
4951           Button_Constraint_mode();
4952           Hide_cursor();
4953           Display_effect_state(C2,L4, "8 bit" ,Main.backups->Pages->Image_mode > IMAGE_MODE_ANIMATION);
4954           Display_cursor();
4955         } else {
4956           Close_window();
4957           Display_cursor();
4958           Button_Constraint_menu();
4959           clicked_button = 11;
4960         }
4961         break;
4962       case 15: // Tilemap
4963         if (Window_attribute1==LEFT_SIDE)
4964         {
4965           Button_Tilemap_mode();
4966           Hide_cursor();
4967           Display_effect_state(C3,L3, "Tilemap" ,Main.tilemap_mode);
4968           Display_cursor();
4969         }
4970         else
4971         {
4972           Close_window();
4973           Display_cursor();
4974           Button_Tilemap_menu();
4975           clicked_button=11;
4976         }
4977         break;
4978       case 16: // Show grid
4979         Show_grid = !Show_grid;
4980         Hide_cursor();
4981         Print_in_window(C3+4, L1+5, Show_grid?"X":" ", MC_Black, MC_Light);
4982         Display_cursor();
4983     }
4984   }
4985   while (clicked_button!=11 && !Quit_is_required);
4986 
4987   if (exit_by_close_button || Quit_is_required)
4988     Close_window();
4989   else
4990     Hide_cursor();
4991 
4992   if (!Any_effect_active())
4993     Unselect_button(btn);
4994 
4995   Display_cursor();
4996 }
4997 
4998 #undef C2
4999 
5000 // Callback to display a font name in the list
Draw_one_font_name(word x,word y,word index,byte highlighted)5001 void Draw_one_font_name(word x, word y, word index, byte highlighted)
5002 {
5003   Print_in_window(x,y,Font_label(index), MC_Black, (highlighted)?MC_Dark:MC_Light);
5004 }
5005 
Button_Text(int btn)5006 void Button_Text(int btn)
5007 {
5008   static char str[256]="";
5009   static int font_size=32;
5010   static int antialias=1;
5011   static short list_start=0; // index de le premiere fonte dans le selector
5012   static short cursor_position=0; // index de la ligne active dans le selector
5013   static short selected_font_index=0;
5014   static short is_bold=0;
5015   static short is_italic=0;
5016 
5017   byte * new_brush=NULL;
5018   T_Palette text_palette;
5019   int new_width;
5020   int new_height;
5021   int clicked_button;
5022   const int NB_FONTS=8;
5023   char size_buffer[4];
5024   T_Special_button * input_size_button;
5025   T_Special_button * input_text_button;
5026   T_Special_button * preview_button;
5027   T_Special_button * font_list_button;
5028   T_Scroller_button * font_scroller;
5029   T_List_button * font_list;
5030 
5031   byte redraw_is_needed=1;
5032   byte preview_is_needed=1;
5033 
5034   (void)btn;
5035   Open_window(288,180,"Text");
5036 
5037   // Texte saisi
5038   Print_in_window_underscore(6,20,"Text:",MC_Dark,MC_Light,1);
5039   input_text_button = Window_set_input_button_s(48,18,29,KEY_t); // 1
5040 
5041   // TrueType options
5042   Window_display_frame_in(182,34,100,68);
5043   Print_in_window(199,31,"TrueType", MC_Dark, MC_Light);
5044   // AA
5045   Window_set_normal_button(188,58,13,11,antialias?"X":" ",0,1,KEY_a); // 2
5046   Print_in_window_underscore(206,60,"AntiAlias", MC_Dark, MC_Light,5);
5047   // Bold
5048   Window_set_normal_button(188,72,13,11,is_bold?"X":" ",0,1,KEY_b); // 3
5049   Print_in_window_underscore(206,75,"Bold", MC_Dark, MC_Light,1);
5050   // Italic
5051   Window_set_normal_button(188,86,13,11,is_italic?"X":" ",0,1,KEY_i); // 4
5052   Print_in_window_underscore(206,89,"Italic", MC_Dark, MC_Light,1);
5053 
5054   // Scroller des fontes
5055   font_scroller = Window_set_scroller_button(165,35,NB_FONTS*8,Font_count(),NB_FONTS,list_start); // 5
5056   // Liste des fontes disponibles
5057   font_list_button = Window_set_special_button(8,35,152,NB_FONTS*8,0); // 6
5058   Window_display_frame_in(7, 33, 154, NB_FONTS*8+4);
5059 
5060   // Taille texte
5061   input_size_button = Window_set_input_button_s(220,43,3,KEY_s); // 7
5062   Window_set_repeatable_button(202,43,13,11,"-",0,1,KEY_NONE); // 8
5063   Window_set_repeatable_button(251,43,13,11,"+",0,1,KEY_NONE); // 9
5064 
5065   // Preview
5066   preview_button = Window_set_special_button(8,106,273,50,0); // 10
5067   Window_display_frame_in(7, 105, 275, 52);
5068 
5069   Window_set_normal_button(8,160,40,14,"OK",0,1,KEY_RETURN); // 11
5070   Window_set_normal_button(54,160,60,14,"Cancel",0,1,KEY_ESC); // 12
5071 
5072   // List of fonts
5073   font_list = Window_set_list_button(font_list_button, font_scroller, Draw_one_font_name, 2); // 13
5074   // Restore its settings from last passage in screen
5075   font_list->List_start = list_start;
5076   font_list->Cursor_position = cursor_position;
5077 
5078   Window_redraw_list(font_list);
5079 
5080   Update_window_area(0,0,Window_width, Window_height);
5081 
5082   // str texte
5083   Window_input_content(input_text_button,str);
5084   // Taille police
5085   redraw_is_needed=1;
5086   // --
5087 
5088   while (1)
5089   {
5090     if (redraw_is_needed)
5091     {
5092       // Taille
5093       Num2str(font_size,size_buffer,3);
5094       Window_input_content(input_size_button,size_buffer);
5095     }
5096     if (preview_is_needed)
5097     {
5098       const char * preview_string = "AaBbCcDdEeFf012345";
5099       byte is_truetype;
5100 
5101       if (str[0])
5102         preview_string=str;
5103       is_truetype=TrueType_font(selected_font_index);
5104       free(new_brush);
5105       new_brush = Render_text(preview_string, selected_font_index, font_size, antialias, is_bold, is_italic, &new_width, &new_height, text_palette);
5106       // Background:
5107       if (antialias&&is_truetype)
5108         // Solid
5109         Window_rectangle(8, 106, 273, 50,MC_Black);
5110       else if (is_truetype)
5111       {
5112         long l = text_palette[Fore_color].R+text_palette[Fore_color].G+text_palette[Fore_color].B;
5113         Window_rectangle(8, 106, 273, 50,l>128*3? MC_Black:MC_Light);
5114       }
5115       else
5116       {
5117         long l = text_palette[Back_color].R+text_palette[Back_color].G+text_palette[Back_color].B;
5118         Window_rectangle(8, 106, 273, 50,l>128*3? MC_Light:MC_Black);
5119       }
5120       if (new_brush)
5121       {
5122         if (!is_truetype || (is_truetype&&antialias))
5123         {
5124           // Display brush in remapped form.
5125           byte *remapped_brush;
5126 
5127           remapped_brush=(byte *)malloc(new_width*new_height);
5128           if (remapped_brush)
5129           {
5130             // This code is mostly copied from Remap_brush()
5131             short x_pos;
5132             short y_pos;
5133             int   color;
5134             byte colmap[256];
5135 
5136             for (color=0;color<=255;color++)
5137               colmap[color]=0;
5138 
5139             for (y_pos=0;y_pos<new_height;y_pos++)
5140               for (x_pos=0;x_pos<new_width;x_pos++)
5141                 colmap[*(new_brush + y_pos * new_width + x_pos)]=1;
5142 
5143             colmap[Back_color]=0;
5144 
5145             for (color=0;color<=255;color++)
5146               if (colmap[color] != 0)
5147               {
5148                 byte r,g,b;
5149                 r=text_palette[color].R;
5150                 g=text_palette[color].G;
5151                 b=text_palette[color].B;
5152 
5153                 //if (r==Main.palette[color].R && g==Main.palette[color].G && b==Main.palette[color].B)
5154                 //  colmap[color]=color;
5155                 //else
5156                   colmap[color]=Best_color_perceptual_except(r,g,b,Back_color);
5157               }
5158 
5159             colmap[Back_color]=Back_color;
5160             Remap_general_lowlevel(colmap,new_brush,remapped_brush,new_width,new_height,new_width);
5161 
5162             Display_brush(
5163               remapped_brush,
5164               Window_pos_X+preview_button->Pos_X*Menu_factor_X,
5165               Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y,
5166               0,
5167               0,
5168               Min(preview_button->Width*Menu_factor_X, new_width),
5169               Min(preview_button->Height*Menu_factor_Y, new_height),
5170               Back_color,
5171               new_width);
5172 
5173             free(remapped_brush);
5174           }
5175 
5176         }
5177         else
5178         {
5179           // Solid
5180           Display_brush(
5181             new_brush,
5182             Window_pos_X+preview_button->Pos_X*Menu_factor_X,
5183             Window_pos_Y+preview_button->Pos_Y*Menu_factor_Y,
5184             0,
5185             0,
5186             Min(preview_button->Width*Menu_factor_X, new_width),
5187             Min(preview_button->Height*Menu_factor_Y, new_height),
5188             Back_color,
5189             new_width);
5190         }
5191 
5192       }
5193       Update_window_area(
5194         preview_button->Pos_X,
5195         preview_button->Pos_Y,
5196         preview_button->Width,
5197         preview_button->Height);
5198     }
5199     if (redraw_is_needed || preview_is_needed)
5200     {
5201       redraw_is_needed=0;
5202       preview_is_needed=0;
5203       Display_cursor();
5204     }
5205 
5206     clicked_button=Window_clicked_button();
5207     if (Quit_is_required)
5208       clicked_button = 12; // cancel
5209     if (clicked_button==0)
5210     {
5211       if (Is_shortcut(Key,0x100+BUTTON_HELP))
5212         Window_help(BUTTON_TEXT, NULL);
5213       else if (Is_shortcut(Key,0x100+BUTTON_TEXT))
5214         clicked_button = 12;  // cancel
5215     }
5216     switch(clicked_button)
5217     {
5218       case 1: // Texte saisi
5219       Readline_ex(50,20,str,29,250,INPUT_TYPE_STRING,0);
5220       preview_is_needed=1;
5221       break;
5222 
5223       case 2: // AA
5224       antialias = (antialias==0);
5225       Hide_cursor();
5226       Print_in_window(191,60,antialias?"X":" ", MC_Black, MC_Light);
5227       preview_is_needed=1;
5228       break;
5229 
5230       case 3: // Bold
5231       is_bold = (is_bold==0);
5232       Hide_cursor();
5233       Print_in_window(191,74,is_bold?"X":" ", MC_Black, MC_Light);
5234       preview_is_needed=1;
5235       break;
5236 
5237       case 4: // Italic
5238       is_italic = (is_italic==0);
5239       Hide_cursor();
5240       Print_in_window(191,88,is_italic?"X":" ", MC_Black, MC_Light);
5241       preview_is_needed=1;
5242       break;
5243 
5244       case 5: // Scroller des fontes
5245       /* Cannot happen, event is catched by the list control */
5246       break;
5247 
5248       case 13: // Font selection
5249         selected_font_index = Window_attribute2;
5250         Hide_cursor();
5251         preview_is_needed=1;
5252       break;
5253 
5254       case 7: // Taille du texte (nombre)
5255       Readline(222,45,size_buffer,3,INPUT_TYPE_INTEGER);
5256       font_size=atoi(size_buffer);
5257       // On corrige les dimensions
5258       if (font_size < 1)
5259       {
5260         font_size = 1;
5261       }
5262       else if (font_size>500)
5263       {
5264         font_size = 500;
5265       }
5266       redraw_is_needed=1;
5267       preview_is_needed=1;
5268       break;
5269 
5270       case 8: // Taille -
5271       if (font_size > 1)
5272       {
5273         font_size--;
5274         Hide_cursor();
5275         redraw_is_needed=1;
5276         preview_is_needed=1;
5277       }
5278       break;
5279 
5280       case 9: // Taille +
5281       if (font_size < 255)
5282       {
5283         font_size++;
5284         Hide_cursor();
5285         redraw_is_needed=1;
5286         preview_is_needed=1;
5287       }
5288       break;
5289 
5290 
5291       case 6: // Double-click font selector
5292       case 11: // OK
5293       // Save the selector settings
5294       list_start = font_list->List_start;
5295       cursor_position = font_list->Cursor_position;
5296 
5297       if (!new_brush)
5298       {
5299         // Si echec de rendu
5300         Close_window();
5301         Unselect_button(BUTTON_TEXT);
5302         Display_cursor();
5303         Error(0);
5304         return;
5305       }
5306       if (Realloc_brush(new_width, new_height, new_brush, NULL))
5307       {
5308         free(new_brush);
5309         Close_window();
5310         Unselect_button(BUTTON_TEXT);
5311         Display_cursor();
5312         Error(0);
5313       }
5314       // Grab palette
5315       memcpy(Brush_original_palette, text_palette,sizeof(T_Palette));
5316       // Remap to image's palette
5317       Remap_brush();
5318 
5319       Brush_offset_X=Brush_width>>1;
5320       Brush_offset_Y=Brush_height>>1;
5321 
5322       // Fermeture
5323       Close_window();
5324       Unselect_button(BUTTON_TEXT);
5325 
5326       // On passe en brosse:
5327       Display_cursor();
5328       if (antialias || !TrueType_font(selected_font_index))
5329         Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
5330       else
5331         Change_paintbrush_shape(PAINTBRUSH_SHAPE_MONO_BRUSH);
5332       // Activate alpha mode
5333       if (antialias && TrueType_font(selected_font_index))
5334       {
5335         Shade_mode=0;
5336         Quick_shade_mode=0;
5337         Smooth_mode=0;
5338         Tiling_mode=0;
5339         Smear_mode=0;
5340         Colorize_mode=1;
5341         Colorize_current_mode=3;
5342         Effect_function=Effect_alpha_colorize;
5343 
5344         Draw_menu_button(BUTTON_EFFECTS,BUTTON_PRESSED);
5345       }
5346 
5347       Select_button(BUTTON_DRAW,LEFT_SIDE);
5348       if (Config.Auto_discontinuous)
5349       {
5350         // On se place en mode Dessin discontinu à la main
5351         while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
5352           Select_button(BUTTON_DRAW,RIGHT_SIDE);
5353       }
5354       //Display_cursor();
5355       return;
5356 
5357       case 12: // Cancel
5358       // Save the selector settings
5359       list_start = font_list->List_start;
5360       cursor_position = font_list->Cursor_position;
5361 
5362       free(new_brush);
5363       new_brush = NULL;
5364       Close_window();
5365       Unselect_button(BUTTON_TEXT);
5366       Display_cursor();
5367       return;
5368     }
5369   }
5370 }
5371 
Display_stored_brush_in_window(word x_pos,word y_pos,int index)5372 void Display_stored_brush_in_window(word x_pos,word y_pos,int index)
5373 {
5374   if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX)
5375   {
5376     int x,y;
5377     int offset_x=0, offset_y=0;
5378     //int brush_offset_x=0, brush_offset_y=0;
5379 
5380     // Determine draw offset (small brushes are stacked on corner of their preview)
5381     if (Brush_container[index].Width<BRUSH_CONTAINER_PREVIEW_WIDTH)
5382       offset_x = (BRUSH_CONTAINER_PREVIEW_WIDTH-Brush_container[index].Width)/2;
5383     if (Brush_container[index].Height<BRUSH_CONTAINER_PREVIEW_HEIGHT)
5384       offset_y = (BRUSH_CONTAINER_PREVIEW_HEIGHT-Brush_container[index].Height)/2;
5385     // Determine corner pixel of paintbrush to draw (if bigger than preview area)
5386     //
5387 
5388     // Clear
5389     Window_rectangle(x_pos,y_pos,BRUSH_CONTAINER_PREVIEW_WIDTH,BRUSH_CONTAINER_PREVIEW_HEIGHT,MC_Light);
5390 
5391     // Draw up to 16x16
5392     for (y=0; y<Brush_container[index].Height && y<BRUSH_CONTAINER_PREVIEW_HEIGHT; y++)
5393     {
5394       for (x=0; x<Brush_container[index].Width && x<BRUSH_CONTAINER_PREVIEW_WIDTH; x++)
5395       {
5396         byte color;
5397         if (Brush_container[index].Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC)
5398           color = Brush_container[index].Thumbnail[y][x]?MC_Black:MC_Light;
5399         else
5400           color = Brush_container[index].Colormap[Brush_container[index].Thumbnail[y][x]];
5401         Pixel_in_window(x_pos+x+offset_x,y_pos+y+offset_y,color);
5402       }
5403     }
5404     Update_window_area(x_pos,y_pos,BRUSH_CONTAINER_PREVIEW_WIDTH,BRUSH_CONTAINER_PREVIEW_HEIGHT);
5405 
5406   }
5407 }
5408 
5409 /// Store the current brush in brush container
Store_brush(int index)5410 void Store_brush(int index)
5411 {
5412   if (Brush_container[index].Paintbrush_shape < PAINTBRUSH_SHAPE_MAX)
5413   {
5414     // Free previous stored brush
5415     Brush_container[index].Paintbrush_shape = PAINTBRUSH_SHAPE_MAX;
5416     free(Brush_container[index].Brush);
5417     Brush_container[index].Brush = NULL;
5418   }
5419 
5420   // Store a mono brush
5421   if (Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC)
5422   {
5423     int x,y;
5424     int brush_offset_x=0, brush_offset_y=0;
5425 
5426     Brush_container[index].Paintbrush_shape=Paintbrush_shape;
5427     Brush_container[index].Width=Paintbrush_width;
5428     Brush_container[index].Height=Paintbrush_height;
5429     //memcpy(Brush_container[index].Palette,Main.palette,sizeof(T_Palette));
5430     // Preview: pick center for big mono brush
5431     if (Paintbrush_width>BRUSH_CONTAINER_PREVIEW_WIDTH)
5432       brush_offset_x = (Paintbrush_width-BRUSH_CONTAINER_PREVIEW_WIDTH)/2;
5433     if (Paintbrush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT)
5434       brush_offset_y = (Paintbrush_height-BRUSH_CONTAINER_PREVIEW_HEIGHT)/2;
5435 
5436     for (y=0; y<BRUSH_CONTAINER_PREVIEW_HEIGHT && y<Paintbrush_height; y++)
5437       for (x=0; x<BRUSH_CONTAINER_PREVIEW_WIDTH && x<Paintbrush_width; x++)
5438         Brush_container[index].Thumbnail[y][x]=Paintbrush_sprite[((y+brush_offset_y)*MAX_PAINTBRUSH_SIZE)+x+brush_offset_x];
5439     // Re-init the rest
5440     Brush_container[index].Transp_color=0;
5441   }
5442   else if (Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH &&
5443     Brush_width <= BRUSH_CONTAINER_PREVIEW_WIDTH &&
5444     Brush_height <= BRUSH_CONTAINER_PREVIEW_HEIGHT)
5445   {
5446     // Color brush transformed into a real mono paintbrush
5447     int x,y;
5448 
5449     Brush_container[index].Paintbrush_shape=PAINTBRUSH_SHAPE_MISC;
5450     Brush_container[index].Width=Brush_width;
5451     Brush_container[index].Height=Brush_height;
5452     // Preview: pick center for big mono brush
5453     for (y=0; y<BRUSH_CONTAINER_PREVIEW_HEIGHT && y<Brush_height; y++)
5454       for (x=0; x<BRUSH_CONTAINER_PREVIEW_WIDTH && x<Brush_width; x++)
5455         Brush_container[index].Thumbnail[y][x]=(Brush[y*Brush_width+x]!=Back_color);
5456     // Re-init the rest
5457     Brush_container[index].Transp_color=0;
5458   }
5459   else if (Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH ||
5460      Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH)
5461   {
5462     // Color brush : saved bitmap and palette
5463     byte * buffer;
5464     buffer=(byte *)malloc(Brush_width*Brush_height);
5465     if (buffer)
5466     {
5467       Brush_container[index].Brush=buffer;
5468       Brush_container[index].Paintbrush_shape=Paintbrush_shape;
5469       Brush_container[index].Width=Brush_width;
5470       Brush_container[index].Height=Brush_height;
5471 
5472       memcpy(Brush_container[index].Brush, Brush_original_pixels,Brush_height*Brush_width);
5473       memcpy(Brush_container[index].Palette, Brush_original_palette,sizeof(T_Palette));
5474       memcpy(Brush_container[index].Colormap, Brush_colormap,256);
5475 
5476       // Scale for preview
5477       if (Brush_width>BRUSH_CONTAINER_PREVIEW_WIDTH ||
5478           Brush_height>BRUSH_CONTAINER_PREVIEW_HEIGHT)
5479       {
5480         // Scale
5481         Rescale(Brush_original_pixels, Brush_width, Brush_height, (byte *)(Brush_container[index].Thumbnail), BRUSH_CONTAINER_PREVIEW_WIDTH, BRUSH_CONTAINER_PREVIEW_HEIGHT, 0, 0);
5482       }
5483       else
5484       {
5485         // Direct copy
5486         Copy_part_of_image_to_another(Brush_original_pixels, 0,0,Brush_width, Brush_height,Brush_width,(byte *)(Brush_container[index].Thumbnail),0,0,BRUSH_CONTAINER_PREVIEW_WIDTH);
5487       }
5488     }
5489     else
5490     {
5491       Error(0);
5492     }
5493   }
5494 }
5495 
5496 /// Retrieve a normal paintbrush
Select_paintbrush(int index)5497 void Select_paintbrush(int index)
5498 {
5499   int x_pos,y_pos;
5500 
5501   Paintbrush_shape=Paintbrush[index].Shape;
5502 
5503   if (Paintbrush[index].Width<=PAINTBRUSH_WIDTH &&
5504     Paintbrush[index].Height<=PAINTBRUSH_HEIGHT)
5505   {
5506     Paintbrush_width=Paintbrush[index].Width;
5507     Paintbrush_height=Paintbrush[index].Height;
5508     Paintbrush_offset_X=Paintbrush[index].Offset_X;
5509     Paintbrush_offset_Y=Paintbrush[index].Offset_Y;
5510 
5511     for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
5512       for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
5513         Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=Paintbrush[index].Sprite[y_pos][x_pos];
5514   }
5515   else
5516   {
5517     // Too big to read from the preview: need re-generate it
5518     Set_paintbrush_size(Paintbrush[index].Width,Paintbrush[index].Height);
5519   }
5520   Change_paintbrush_shape(Paintbrush[index].Shape);
5521 }
5522 
5523 /// Store the current brush in paintbrush slot, if possible.
Store_paintbrush(int index)5524 byte Store_paintbrush(int index)
5525 {
5526   // Store a mono brush
5527   if (Paintbrush_shape <= PAINTBRUSH_SHAPE_MISC)
5528   {
5529     int x_pos,y_pos, x_off=0, y_off=0;
5530 
5531     Paintbrush[index].Shape=Paintbrush_shape;
5532     Paintbrush[index].Width=Paintbrush_width;
5533     Paintbrush[index].Height=Paintbrush_height;
5534     Paintbrush[index].Offset_X=Paintbrush_offset_X;
5535     Paintbrush[index].Offset_Y=Paintbrush_offset_Y;
5536 
5537     if (Paintbrush_width>PAINTBRUSH_WIDTH)
5538       x_off=(Paintbrush_width-PAINTBRUSH_WIDTH)/2;
5539     if (Paintbrush_height>PAINTBRUSH_HEIGHT)
5540       y_off=(Paintbrush_height-PAINTBRUSH_HEIGHT)/2;
5541 
5542     for (y_pos=0; y_pos<Paintbrush_height && y_pos<PAINTBRUSH_HEIGHT; y_pos++)
5543       for (x_pos=0; x_pos<Paintbrush_width && x_pos<PAINTBRUSH_WIDTH; x_pos++)
5544         Paintbrush[index].Sprite[y_pos][x_pos]=Paintbrush_sprite[((y_pos+y_off)*MAX_PAINTBRUSH_SIZE)+(x_pos+x_off)];
5545 
5546     return 0;
5547   }
5548 
5549   else if ((Paintbrush_shape == PAINTBRUSH_SHAPE_MONO_BRUSH ||
5550     Paintbrush_shape == PAINTBRUSH_SHAPE_COLOR_BRUSH))
5551   {
5552     // Color brush transformed into a real mono paintbrush
5553     int x_pos,y_pos;
5554 
5555     Paintbrush[index].Shape=PAINTBRUSH_SHAPE_MISC;
5556     Paintbrush[index].Width=Min(Brush_width,PAINTBRUSH_WIDTH);
5557     Paintbrush[index].Height=Min(Brush_height,PAINTBRUSH_HEIGHT);
5558     Paintbrush[index].Offset_X=Brush_offset_X*Paintbrush[index].Width/Brush_width;
5559     Paintbrush[index].Offset_Y=Brush_offset_Y*Paintbrush[index].Height/Brush_height;
5560 
5561     for (y_pos=0; y_pos<Brush_height&&y_pos<PAINTBRUSH_HEIGHT; y_pos++)
5562       for (x_pos=0; x_pos<Brush_width&&x_pos<PAINTBRUSH_WIDTH; x_pos++)
5563         Paintbrush[index].Sprite[y_pos][x_pos]=Brush[(y_pos*Brush_width)+x_pos]!=Back_color;
5564 
5565     return 0;
5566   }
5567   // Can't store it
5568   return 1;
5569 }
5570 
Restore_brush(int index)5571 byte Restore_brush(int index)
5572 {
5573   byte shape;
5574   word x_pos;
5575   word y_pos;
5576 
5577   shape = Brush_container[index].Paintbrush_shape;
5578 
5579   if (shape == PAINTBRUSH_SHAPE_MAX)
5580     return 0;
5581   // Mono brushes
5582   if (shape <= PAINTBRUSH_SHAPE_MISC)
5583   {
5584     Paintbrush_shape=shape;
5585     Paintbrush_width=Brush_container[index].Width;
5586     Paintbrush_height=Brush_container[index].Height;
5587     if (shape == PAINTBRUSH_SHAPE_HORIZONTAL_BAR)
5588       Paintbrush_height=1;
5589     else if (shape == PAINTBRUSH_SHAPE_VERTICAL_BAR)
5590       Paintbrush_width=1;
5591 
5592     if (Paintbrush_width <= BRUSH_CONTAINER_PREVIEW_WIDTH &&
5593         Paintbrush_height <= BRUSH_CONTAINER_PREVIEW_HEIGHT)
5594     {
5595       // Manually copy the "pixels"
5596       for (y_pos=0; y_pos<Paintbrush_height; y_pos++)
5597         for (x_pos=0; x_pos<Paintbrush_width; x_pos++)
5598           Paintbrush_sprite[(y_pos*MAX_PAINTBRUSH_SIZE)+x_pos]=Brush_container[index].Thumbnail[y_pos][x_pos];
5599 
5600       Paintbrush_offset_X=Paintbrush_width>>1;
5601       Paintbrush_offset_Y=Paintbrush_height>>1;
5602     }
5603     else
5604     {
5605       // Recreate the brush pixels from its shape and dimensions
5606       Set_paintbrush_size(Paintbrush_width,Paintbrush_height);
5607     }
5608   }
5609   // Color brushes
5610   if (shape == PAINTBRUSH_SHAPE_COLOR_BRUSH ||
5611      shape == PAINTBRUSH_SHAPE_MONO_BRUSH)
5612   {
5613     Paintbrush_shape=shape;
5614     if (!Realloc_brush(Brush_container[index].Width,Brush_container[index].Height,NULL,NULL))
5615     {
5616       // Recover pixels
5617       memcpy(Brush_original_pixels, Brush_container[index].Brush, (long)Brush_height*Brush_width);
5618       // Grab palette
5619       memcpy(Brush_original_palette, Brush_container[index].Palette, sizeof(T_Palette));
5620       // Recover colormap
5621       memcpy(Brush_colormap, Brush_container[index].Colormap, 256);
5622       // Remap using current colormap
5623       Remap_general_lowlevel(Brush_colormap,Brush_original_pixels,Brush,Brush_width,Brush_height,Brush_width);
5624 
5625       Brush_offset_X=Brush_width>>1;
5626       Brush_offset_Y=Brush_height>>1;
5627     }
5628 
5629   }
5630   Change_paintbrush_shape(shape);
5631 
5632   return 1;
5633 }
5634 
Button_Brush_container(void)5635 void Button_Brush_container(void)
5636 {
5637   short clicked_button;
5638   short x_pos,y_pos;
5639   byte index;
5640 
5641   Open_window(BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+8,
5642     BRUSH_CONTAINER_ROWS*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+40,
5643     "Brushes");
5644 
5645   Window_set_normal_button(
5646     (BRUSH_CONTAINER_COLUMNS*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)-59)/2,
5647     (BRUSH_CONTAINER_ROWS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18,
5648     67,14,"Cancel",0,1,KEY_ESC); // 1
5649 
5650   index=0;
5651   for (index=0; index < BRUSH_CONTAINER_ROWS*BRUSH_CONTAINER_COLUMNS; index++)
5652   {
5653     x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7;
5654     y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18;
5655     Window_set_normal_button(
5656       x_pos,
5657       y_pos,
5658       BRUSH_CONTAINER_PREVIEW_WIDTH+2,
5659       BRUSH_CONTAINER_PREVIEW_HEIGHT+2,
5660       "",0,1,KEY_NONE
5661       );
5662     Display_stored_brush_in_window(x_pos+1, y_pos+1, index);
5663   }
5664   Update_window_area(0,0,Window_width, Window_height);
5665 
5666   Display_cursor();
5667 
5668   do
5669   {
5670     clicked_button=Window_clicked_button();
5671     //if (Is_shortcut(Key,0x100+BUTTON_HELP))
5672     //  Window_help(BUTTON_PAINTBRUSHES, NULL);
5673 
5674     if (clicked_button == 1)
5675       break;
5676 
5677     if (clicked_button>1)
5678     {
5679       index = clicked_button-2;
5680 
5681       if (Window_attribute1==RIGHT_SIDE)
5682       {
5683         // Store
5684 
5685         x_pos = (index % BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_WIDTH+8)+7;
5686         y_pos = (index / BRUSH_CONTAINER_COLUMNS)*(BRUSH_CONTAINER_PREVIEW_HEIGHT+8)+18;
5687 
5688         Store_brush(index);
5689         Hide_cursor();
5690         Display_stored_brush_in_window(x_pos+1, y_pos+1, index);
5691         Display_cursor();
5692       }
5693       else
5694       {
5695         // Restore and exit
5696 
5697         if (Restore_brush(index))
5698           break;
5699       }
5700     }
5701   }
5702   while (1);
5703   Close_window();
5704 
5705   //Unselect_button(BUTTON_PAINTBRUSHES);
5706   Display_cursor();
5707 }
5708 
Any_effect_active(void)5709 byte Any_effect_active(void)
5710 {
5711     return Shade_mode||Quick_shade_mode||Colorize_mode||Smooth_mode||Tiling_mode||Smear_mode
5712       ||Stencil_mode||Mask_mode||Sieve_mode||Snap_mode||Main.tilemap_mode || (Main.backups->Pages->Image_mode > IMAGE_MODE_ANIMATION);
5713 }
5714