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 #include <math.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 
25 #include "const.h"
26 #include "struct.h"
27 #include "global.h"
28 #include "misc.h"
29 #include "engine.h"
30 #include "readline.h"
31 #include "buttons.h"
32 #include "pages.h"
33 #include "help.h"
34 #include "screen.h"
35 #include "errors.h"
36 #include "op_c.h"
37 #include "windows.h"
38 #include "input.h"
39 #include "palette.h"
40 #include "shade.h"
41 
42 static void Component_unit(int count);
43 
44 static byte Palette_view_is_RGB = 1; // Indique si on est en HSL ou en RGB
45 static float Gamma = 1.0;
46 
47 // Coordinates of the color count (on histogram button)
48 static const int COUNT_X = 138;
49 static const int COUNT_Y = 64;
50 
51 
52 // Nombre de graduations pour une composante RGB
53 int RGB_scale = 256; // 24bit
54 //int RGB_scale = 64; // VGA
55 //int RGB_scale = 16; // Amiga
56 //int RGB_scale =  4; // MSX2
57 //int RGB_scale =  3; // Amstrad CPC
58 
59 // Nombre de graduations pour une composante dans le mode actuel
60 int Color_count=256;
61 // Les composantes vont de 0 à (Color_count-1)
62 int Color_max=255;
63 // Le demi-pas est une quantité que l'on ajoute à une composante
64 // avant de faire un arrondi par division.
65 int Color_halfstep=0;
66 
67 
Set_palette_RGB_scale(int scale)68 void Set_palette_RGB_scale(int scale)
69 {
70   if (scale>= 2 && scale <= 256)
71   {
72     RGB_scale = scale;
73     Component_unit(RGB_scale);
74   }
75 }
76 
Get_palette_RGB_scale(void)77 int Get_palette_RGB_scale(void)
78 {
79   return RGB_scale;
80 }
81 
82 
Set_palette_Gamma(int gamma)83 void Set_palette_Gamma(int gamma)
84 {
85   Gamma = gamma / 10.0;
86 }
87 
88 ///
89 /// Round a 0-255 RGB component according to the RGB_scale and gamm correction.
90 //  The result is a color as similar as possible, but that can be encoded in the
91 //  picture colorspace.
92 /// The result is also in the 0-255 range.
Round_palette_component(byte comp)93 byte Round_palette_component(byte comp)
94 {
95   // Apply Gamma correction
96   float fc = pow(comp/255.0,Gamma)*255;
97 
98   // Convert to encodable value
99   comp = ceil(fc);
100   comp = (comp*RGB_scale/256+(RGB_scale-(256-1)*RGB_scale/256)/2) * (255/(RGB_scale-1));
101 
102   // Apply reverse Gamma correction
103   fc = pow(comp/255.0,1/Gamma)*255;
104 
105   return fc;
106 }
107 
108 ///
109 /// Turns a RGB component from 0-(RGB_scale-1) scale to 0-255 and apply reverse
110 //  gamma correction.
111 /// The passed value should come from Round_palette_component(),
112 /// otherwise the rounding will be "down".
Decode_component(int comp)113 static int Decode_component(int comp)
114 {
115   double res = pow((double)comp/Color_max, 1.0/Gamma) * 255.0;
116   return (int)res;
117 }
118 
119 
120 /// Turns a RGB component from 0-255 to 0-(RGB_scale-1) and apply Gamma correction.
Encode_component(int comp)121 int Encode_component(int comp)
122 {
123   double res = pow(comp/255.0, Gamma) * (double)Color_max;
124   return (int)ceil(res);
125 }
126 
127 
128 /// Compute the component at a given distance from the current one.
129 /// Used by the add/remove and lighten/darken operations.
Add_encoded(int comp,int offset)130 static int Add_encoded(int comp, int offset)
131 {
132 	int new = Decode_component(Encode_component(comp)+offset);
133 	if (new < 0)
134 		new = 0;
135 	if (new > 255)
136 		new = 255;
137 	return new;
138 }
139 
140 
141 // Définir les unités pour les graduations R G B ou H S V
Component_unit(int count)142 static void Component_unit(int count)
143 {
144   Color_count = count;
145   Color_max = count-1;
146   Color_halfstep = 256/count/2;
147 }
148 
Set_HSL(T_Palette start_palette,T_Palette end_palette,byte color,short diff_h,short diff_s,short diff_l)149 void Set_HSL(T_Palette start_palette, T_Palette end_palette, byte color, short diff_h, short diff_s, short diff_l)
150 {
151     byte h, s, l;
152     RGB_to_HSL(start_palette[color].R,start_palette[color].G,start_palette[color].B,&h,&s,&l);
153     // La teinte (Hue) est cyclique
154     h=(diff_h+256+h);
155     // Pour les autres (Saturation, Lightness), au lieu d'additionner,
156     // on va faire un ratio, cela utilise mieux la plage de valeurs 0-255
157     if (diff_s<0)
158       s=(255+diff_s)*s/255;
159     else if (diff_s>0)
160       s=255-(255-diff_s)*(255-s)/255;
161     if (diff_l<0)
162       l=(255+diff_l)*l/255;
163     else if (diff_l>0)
164       l=255-(255-diff_l)*(255-l)/255;
165     HSL_to_RGB(h,s,l,&end_palette[color].R,&end_palette[color].G,&end_palette[color].B);
166 }
167 
Set_red(byte color,short new_color,T_Palette palette)168 void Set_red(byte color, short new_color, T_Palette palette)
169 {
170   if (new_color< 0)
171     new_color= 0;
172   if (new_color>255)
173     new_color=255;
174   // Arrondi
175   new_color=Round_palette_component(new_color);
176 
177   palette[color].R=new_color;
178 }
179 
180 
Set_green(byte color,short new_color,T_Palette palette)181 void Set_green(byte color, short new_color, T_Palette palette)
182 {
183   if (new_color< 0)
184     new_color= 0;
185   if (new_color>255)
186     new_color=255;
187   // Arrondi
188   new_color=Round_palette_component(new_color);
189 
190   palette[color].G=new_color;
191 }
192 
193 
Set_blue(byte color,short new_color,T_Palette palette)194 void Set_blue(byte color, short new_color, T_Palette palette)
195 {
196   if (new_color< 0)
197     new_color= 0;
198   if (new_color>255)
199     new_color=255;
200   // Arrondi
201   new_color=Round_palette_component(new_color);
202 
203   palette[color].B=new_color;
204 }
205 
Format_component(byte value,char * str)206 void Format_component(byte value, char *str)
207 // Formate une chaine de 4 caractères+\0 : "nnn "
208 {
209   snprintf(str, 5, "%3u ", (unsigned)value);
210 }
211 
Spread_colors(short start,short end,T_Palette palette)212 void Spread_colors(short start,short end,T_Palette palette)
213 // Modifie la palette pour obtenir un dégradé de couleur entre les deux bornes
214 // passées en paramètre
215 {
216   short start_red;
217   short start_green;
218   short start_blue;
219   short end_red;
220   short end_green;
221   short end_blue;
222   short index;
223 
224   // On vérifie qu'il y ait assez de couleurs entre le début et la fin pour
225   // pouvoir faire un dégradé:
226   if ( (start!=end) && (start+1!=end) )
227   {
228     start_red   = Encode_component(palette[start].R);
229     start_green = Encode_component(palette[start].G);
230     start_blue  = Encode_component(palette[start].B);
231 
232     end_red     = Encode_component(palette[end  ].R);
233     end_green   = Encode_component(palette[end  ].G);
234     end_blue    = Encode_component(palette[end  ].B);
235 
236     for (index=start+1;index<end;index++)
237     {
238       Set_red  (index, Decode_component(((end_red  -start_red  ) * (index-start))/(end-start) + start_red),   palette);
239       Set_green(index, Decode_component(((end_green-start_green) * (index-start))/(end-start) + start_green), palette);
240       Set_blue (index, Decode_component(((end_blue -start_blue ) * (index-start))/(end-start) + start_blue),  palette);
241     }
242     Set_palette(palette);
243   }
244 }
245 
246 // FIXME: keep them in main function but pass them to Palette_edit_*()
247   T_Components * backup_palette;
248   T_Components * temp_palette;
249   T_Components * working_palette;
250 
251 byte Palette_undo_state = 0;
252 byte Palette_change_state = 0;
253 
254 /// Backup before doing one self-complete change.
Palette_edit_step()255 void Palette_edit_step()
256 {
257   // back up
258   memcpy(backup_palette,working_palette,sizeof(T_Palette));
259   Palette_change_state=0;
260   Palette_undo_state=0;
261 }
262 
263 /// Mode for incremental changes.
Palette_edit_select_range()264 void Palette_edit_select_range()
265 {
266   if (Palette_change_state)
267   {/*
268     // acknowledge pending changes and back up
269     memcpy(backup_palette,working_palette,sizeof(T_Palette));
270     memcpy(temp_palette,working_palette,sizeof(T_Palette));
271   */}
272   Palette_change_state=0;
273 }
274 
275 /// Perform incremental change in RGB channel of some color(s).
Palette_edit_alter_channel()276 void Palette_edit_alter_channel()
277 {
278   if (!Palette_change_state)
279   {
280     memcpy(backup_palette,working_palette,sizeof(T_Palette));
281     memcpy(temp_palette,working_palette,sizeof(T_Palette));
282   }
283   Palette_change_state=1;
284 }
285 
286 /// Undo
Palette_edit_undo_redo()287 void Palette_edit_undo_redo()
288 {
289   if (Palette_change_state)
290   {
291     // swap backup and working (temp serves as intermediate)
292     memcpy(temp_palette,backup_palette,sizeof(T_Palette));
293     memcpy(backup_palette,working_palette,sizeof(T_Palette));
294     memcpy(working_palette,temp_palette,sizeof(T_Palette));
295   }
296   else
297   {
298     // swap backup and working (temp serves as intermediate)
299     memcpy(temp_palette,backup_palette,sizeof(T_Palette));
300     memcpy(backup_palette,working_palette,sizeof(T_Palette));
301     memcpy(working_palette,temp_palette,sizeof(T_Palette));
302   }
303   Palette_undo_state=(Palette_undo_state==0);
304 }
305 
306 
Update_color_count(short * used_colors,dword * color_usage)307 void Update_color_count(short * used_colors, dword * color_usage)
308 {
309   char   str[4];
310 
311   Hide_cursor();
312   Cursor_shape=CURSOR_SHAPE_HOURGLASS;
313   Display_cursor();
314   *used_colors=Count_used_colors(color_usage);
315   Num2str(*used_colors,str,3);
316   Hide_cursor();
317   Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light);
318   Cursor_shape=CURSOR_SHAPE_ARROW;
319   Display_cursor();
320 }
321 
Remap_zone_highlevel(short x1,short y1,short x2,short y2,byte * conversion_table)322 void Remap_zone_highlevel(short x1, short y1, short x2, short y2,
323                      byte * conversion_table)
324 // Attention: Remappe une zone de coins x1,y1 et x2-1,y2-1 !!!
325 {
326   short x_pos;
327   short y_pos;
328 
329   for (y_pos=y1;y_pos<y2;y_pos++)
330     for (x_pos=x1;x_pos<x2;x_pos++)
331     {
332       if ((y_pos>=Window_pos_Y) && (y_pos<Window_pos_Y+(Window_height*Menu_factor_Y)) &&
333           (x_pos>=Window_pos_X) && (x_pos<Window_pos_X+(Window_width*Menu_factor_X)) )
334         x_pos=Window_pos_X+(Window_width*Menu_factor_X)-1;
335       else
336         Pixel(x_pos,y_pos,conversion_table[Read_pixel(x_pos,y_pos)]);
337     }
338 }
339 
Remap_image_highlevel(byte * conversion_table)340 void Remap_image_highlevel(byte * conversion_table)
341 {
342   short end_x;
343   short end_y;
344   short end_x_mag=0;
345   short end_y_mag=0;
346   int layer;
347 
348   // Remap the flatenned image view
349   if (Main.backups->Pages->Image_mode != IMAGE_MODE_ANIMATION
350       && Main.backups->Pages->Image_mode != IMAGE_MODE_MODE5
351       && Main.backups->Pages->Image_mode != IMAGE_MODE_RASTER)
352   {
353     Remap_general_lowlevel(conversion_table,Main.visible_image.Image,Main.visible_image.Image,
354                          Main.image_width,Main.image_height,Main.image_width);
355   }
356   // Remap all layers
357   for (layer=0; layer<Main.backups->Pages->Nb_layers; layer++)
358     Remap_general_lowlevel(conversion_table,Main.backups->Pages->Image[layer].Pixels,Main.backups->Pages->Image[layer].Pixels,Main.image_width,Main.image_height,Main.image_width);
359 
360   // Remap transparent color
361   Main.backups->Pages->Transparent_color =
362     conversion_table[Main.backups->Pages->Transparent_color];
363 
364   // On calcule les limites à l'écran de l'image
365   if (Main.image_height>=Menu_Y_before_window)
366     end_y=Menu_Y_before_window;
367   else
368     end_y=Main.image_height;
369 
370   if (!Main.magnifier_mode)
371   {
372     if (Main.image_width>=Screen_width)
373       end_x=Screen_width;
374     else
375       end_x=Main.image_width;
376 
377   }
378   else
379   {
380     if (Main.image_width>=Main.separator_position)
381       end_x=Main.separator_position;
382     else
383       end_x=Main.image_width;
384 
385     if ((Main.X_zoom+(Main.image_width*Main.magnifier_factor))>=Screen_width)
386       end_x_mag=Screen_width;
387     else
388       end_x_mag=(Main.X_zoom+(Main.image_width*Main.magnifier_factor));
389 
390     if (Main.image_height*Main.magnifier_factor>=Menu_Y_before_window)
391       end_y_mag=Menu_Y_before_window;
392     else
393       end_y_mag=Main.image_height*Main.magnifier_factor;
394   }
395 
396   // On doit maintenant faire la traduction à l'écran
397   Remap_zone_highlevel(0,0,end_x,end_y,conversion_table);
398 
399   if (Main.magnifier_mode)
400   {
401     Remap_zone_highlevel(Main.separator_position,0,end_x_mag,end_y_mag,conversion_table);
402     // Il peut encore rester le bas de la barre de split à remapper si la
403     // partie zoomée ne descend pas jusqu'en bas...
404     Remap_zone_highlevel(Main.separator_position,end_y_mag,
405                     (Main.separator_position+(SEPARATOR_WIDTH*Menu_factor_X)),
406                     Menu_Y_before_window,conversion_table);
407   }
408   // Remappe tous les fonds de fenetre (qui doivent contenir un bout d'écran)
409   Remap_window_backgrounds(conversion_table, 0, Menu_Y_before_window);
410 }
411 
412 
Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette,dword * color_usage)413 void Swap(int with_remap,short block_1_start,short block_2_start,short block_size,T_Palette palette, dword * color_usage)
414 {
415   short pos_1;
416   short pos_2;
417   short end_1;
418   short end_2;
419   byte  conversion_table[256];
420 
421   T_Components temp_palette[256];
422   dword temp_usage[256];
423 
424   // On fait une copie de la palette
425   memcpy(temp_palette, palette, sizeof(T_Palette));
426 
427   // On fait une copie de la table d'used des couleurs
428   memcpy(temp_usage, color_usage, sizeof(dword) * 256);
429 
430   // On commence à initialiser la table de conversion à un état où elle ne
431   // fera aucune conversion.
432   for (pos_1=0;pos_1<=255;pos_1++)
433     conversion_table[pos_1]=pos_1;
434 
435   // On calcul les dernières couleurs de chaque bloc.
436   end_1=block_1_start+block_size-1;
437   end_2=block_2_start+block_size-1;
438 
439   if ((block_2_start>=block_1_start) && (block_2_start<=end_1))
440   {
441     // Le bloc destination commence dans le bloc source.
442 
443     for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++)
444     {
445       // Il faut transformer la couleur pos_1 en pos_2:
446 
447       conversion_table[pos_2]=pos_1;
448       color_usage[pos_1]=temp_usage[pos_2];
449       palette[pos_1].R=temp_palette[pos_2].R;
450       palette[pos_1].G=temp_palette[pos_2].G;
451       palette[pos_1].B=temp_palette[pos_2].B;
452 
453       // On gère la mise à jour de pos_2
454       if (pos_2==end_2)
455         pos_2=block_1_start;
456       else
457         pos_2++;
458     }
459   }
460   else
461   if ((block_2_start<block_1_start) && (end_2>=block_1_start))
462   {
463     // Le bloc destination déborde dans le bloc source.
464 
465     for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++)
466     {
467       // Il faut transformer la couleur pos_1 en pos_2:
468 
469       conversion_table[pos_2]=pos_1;
470       color_usage[pos_1]=temp_usage[pos_2];
471       palette[pos_1].R=temp_palette[pos_2].R;
472       palette[pos_1].G=temp_palette[pos_2].G;
473       palette[pos_1].B=temp_palette[pos_2].B;
474 
475       // On gère la mise à jour de pos_2
476       if (pos_2==end_1)
477         pos_2=block_2_start;
478       else
479         pos_2++;
480     }
481   }
482   else
483   {
484     // Le bloc source et le bloc destination sont distincts.
485 
486     for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++)
487     {
488       // Il va falloir permutter la couleur pos_1 avec la couleur pos_2
489       conversion_table[pos_1]=pos_2;
490       conversion_table[pos_2]=pos_1;
491 
492       //   On intervertit le nombre d'used des couleurs pour garder une
493       // cohérence lors d'un éventuel "Zap unused".
494       SWAP_DWORDS(color_usage[pos_1], color_usage[pos_2])
495 
496       // On fait un changement de teinte:
497       SWAP_BYTES(palette[pos_1].R, palette[pos_2].R)
498       SWAP_BYTES(palette[pos_1].G, palette[pos_2].G)
499       SWAP_BYTES(palette[pos_1].B, palette[pos_2].B)
500     }
501   }
502 
503   if (with_remap)
504   {
505     Remap_image_highlevel(conversion_table);
506   }
507   else
508   {
509     // Restore color usage. Shouldn't have reordered it in the first place.
510     memcpy(color_usage, temp_usage, sizeof(dword) * 256);
511   }
512 }
513 
514 
515 
Set_nice_menu_colors(dword * color_usage,int not_picture)516 void Set_nice_menu_colors(dword * color_usage,int not_picture)
517 {
518   short index,index2;
519   byte color;
520   byte replace_table[256];
521   T_Components rgb[4];
522   short new_colors[4]={255,254,253,252};
523 
524   // On initialise la table de remplacement
525   for (index=0; index<256; index++)
526     replace_table[index]=index;
527 
528   // On recherche les 4 couleurs les moins utilisées dans l'image pour pouvoir
529   // les remplacer par les nouvelles couleurs.
530   for (index2=0; index2<4; index2++)
531     for (index=255; index>=0; index--)
532     {
533       if ((index!=new_colors[0]) && (index!=new_colors[1])
534        && (index!=new_colors[2]) && (index!=new_colors[3])
535        && (color_usage[index]<color_usage[new_colors[index2]]))
536         new_colors[index2]=index;
537     }
538 
539   // On trie maintenant la table dans le sens décroissant.
540   // (Ce n'est pas indispensable, mais ça fera plus joli dans la palette).
541   do
542   {
543     color=0; // Booléen qui dit si le tri n'est pas terminé.
544     for (index=0; index<3; index++)
545     {
546       if (new_colors[index]>new_colors[index+1])
547       {
548         index2            =new_colors[index];
549         new_colors[index]  =new_colors[index+1];
550         new_colors[index+1]=index2;
551         color=1;
552       }
553     }
554   } while (color);
555 
556   //   On sauvegarde dans rgb les teintes qu'on va remplacer et on met les
557   // couleurs du menu par défaut
558   for (index=0; index<4; index++)
559   {
560     const T_Components * target_rgb;
561 
562     target_rgb=Favorite_GUI_color(index);
563     color=new_colors[index];
564     rgb[index].R=Main.palette[color].R;
565     rgb[index].G=Main.palette[color].G;
566     rgb[index].B=Main.palette[color].B;
567     Main.palette[color].R=Round_palette_component(target_rgb->R);
568     Main.palette[color].G=Round_palette_component(target_rgb->G);
569     Main.palette[color].B=Round_palette_component(target_rgb->B);
570   }
571 
572   //   Maintenant qu'on a placé notre nouvelle palette, on va chercher quelles
573   // sont les couleurs qui peuvent remplacer les anciennes
574   Hide_cursor();
575   for (index=0; index<4; index++)
576     replace_table[new_colors[index]]=Best_color_nonexcluded
577                                   (rgb[index].R,rgb[index].G,rgb[index].B);
578 
579   if (not_picture)
580   {
581     // Remap caused by preview. Only remap screen
582     Remap_zone_highlevel(0,0,Screen_width,Screen_height,replace_table);
583   }
584   else
585   {
586     // On fait un changement des couleurs visibles à l'écran et dans l'image
587     Remap_image_highlevel(replace_table);
588   }
589   Display_cursor();
590 }
591 
592 
593 
Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage)594 void Reduce_palette(short * used_colors,int nb_colors_asked,T_Palette palette,dword * color_usage)
595 {
596   char  str[5];                // buffer d'affichage du compteur
597   byte  conversion_table[256]; // Table de conversion
598   int   color_1;                // |_ Variables de balayages
599   int   color_2;                // |  de la palette
600   int   best_color_1=0;
601   int   best_color_2=0;
602   long   best_difference;
603   dword used;
604   dword best_used;
605 
606   //   On commence par initialiser la table de conversion dans un état où
607   // aucune conversion ne sera effectuée.
608   for (color_1=0; color_1<=255; color_1++)
609     conversion_table[color_1]=color_1;
610 
611   //   Si on ne connait pas encore le nombre de couleurs utilisées, on le
612   // calcule! (!!! La fonction appelée Efface puis Affiche le curseur !!!)
613   if ((*used_colors)<0)
614     Update_color_count(used_colors,color_usage);
615 
616   Hide_cursor();
617 
618   //   On tasse la palette vers le début parce qu'elle doit ressembler à
619   // du Gruyère (et comme Papouille il aime pas le fromage...)
620 
621   // Pour cela, on va scruter la couleur color_1 et se servir de l'indice
622   // color_2 comme position de destination.
623   for (color_1=color_2=0;color_1<=255;color_1++)
624   {
625     if (color_usage[color_1])
626     {
627       // On commence par s'occuper des teintes de la palette
628       palette[color_2].R=palette[color_1].R;
629       palette[color_2].G=palette[color_1].G;
630       palette[color_2].B=palette[color_1].B;
631 
632       // Ensuite, on met à jour le tableau d'occupation des couleurs.
633       color_usage[color_2]=color_usage[color_1];
634 
635       // On va maintenant s'occuper de la table de conversion:
636       conversion_table[color_1]=color_2;
637 
638       // Maintenant, la place désignée par color_2 est occupée, alors on
639       // doit passer à un indice de destination suivant.
640       color_2++;
641     }
642   }
643 
644   // On met toutes les couleurs inutilisées en noir
645   for (;color_2<256;color_2++)
646   {
647     palette[color_2].R=0;
648     palette[color_2].G=0;
649     palette[color_2].B=0;
650     color_usage[color_2]=0;
651   }
652 
653   //   Maintenant qu'on a une palette clean, on va boucler en réduisant
654   // le nombre de couleurs jusqu'à ce qu'on atteigne le nombre désiré.
655   // (The stop condition is further down)
656   while (1)
657   {
658     //   Il s'agit de trouver les 2 couleurs qui se ressemblent le plus
659     // parmis celles qui sont utilisées (bien sûr) et de les remplacer par
660     // une seule couleur qui est la moyenne pondérée de ces 2 couleurs
661     // en fonction de leur utilisation dans l'image.
662 
663     best_difference =26*255*26*255+55*255*255+19*255*19*255;
664     best_used=0x7FFFFFFF;
665 
666     for (color_1=0;color_1<(*used_colors);color_1++)
667       for (color_2=color_1+1;color_2<(*used_colors);color_2++)
668         if (color_1!=color_2)
669         {
670           long dr, dg, db;
671           long difference;  // could also be called distance (or distance square)
672 
673           dr = (long)palette[color_1].R - (long)palette[color_2].R;
674           dg = (long)palette[color_1].G - (long)palette[color_2].G;
675           db = (long)palette[color_1].B - (long)palette[color_2].B;
676           difference =26*26*dr*dr + 55*55*dg*dg + 19*19*db*db;
677 
678           if (difference<=best_difference)
679           {
680             used=color_usage[color_1]+color_usage[color_2];
681             if ((difference<best_difference) || (used<best_used))
682             {
683               best_difference =difference;
684               best_used=used;
685               best_color_1  =color_1;
686               best_color_2  =color_2;
687             }
688           }
689         }
690 
691     // Stop condition: when no more duplicates exist
692     // and the number of colors has reached the target.
693     if (best_difference!=0 && (*used_colors)<=nb_colors_asked)
694       break;
695 
696     //   Maintenant qu'on les a trouvées, on va pouvoir mettre à jour nos
697     // données pour que le remplacement se fasse sans encombres.
698 
699     // En somme, on va remplacer best_color_2 par best_color_1,
700     // mais attention, on ne remplace pas best_color_1 par
701     // best_color_2 !
702 
703     // On met à jour la palette.
704     palette[best_color_1].R=Round_div((color_usage[best_color_1]*palette[best_color_1].R)+
705                                              (color_usage[best_color_2]*palette[best_color_2].R),
706                                              best_used);
707     palette[best_color_1].G=Round_div((color_usage[best_color_1]*palette[best_color_1].G)+
708                                              (color_usage[best_color_2]*palette[best_color_2].G),
709                                              best_used);
710     palette[best_color_1].B=Round_div((color_usage[best_color_1]*palette[best_color_1].B)+
711                                              (color_usage[best_color_2]*palette[best_color_2].B),
712                                              best_used);
713 
714     // On met à jour la table d'utilisation.
715     color_usage[best_color_1]+=color_usage[best_color_2];
716     color_usage[best_color_2]=0;
717 
718     // On met à jour la table de conversion.
719     for (color_1=0;color_1<=255;color_1++)
720     {
721       if (conversion_table[color_1]==best_color_2)
722       {
723         //   La color_1 avait déjà prévue de se faire remplacer par la
724         // couleur que l'on veut maintenant éliminer. On va maintenant
725         // demander à ce que la color_1 se fasse remplacer par la
726         // best_color_1.
727         conversion_table[color_1]=best_color_1;
728       }
729     }
730 
731     //   Bon, maintenant que l'on a fait bouger nos petites choses concernants
732     // la couleur à éliminer, on va s'occuper de faire bouger les couleurs
733     // situées après la couleur à éliminer pour qu'elles se déplaçent d'une
734     // couleur en arrière.
735     for (color_1=0;color_1<=255;color_1++)
736     {
737       //   Commençons par nous occuper des tables d'utilisation et de la
738       // palette.
739 
740       if (color_1>best_color_2)
741       {
742         // La color_1 va scroller en arrière.
743 
744         //   Donc on transfère son utilisation dans l'utilisation de la
745         // couleur qui la précède.
746         color_usage[color_1-1]=color_usage[color_1];
747 
748         //   Et on transfère ses teintes dans les teintes de la couleur qui
749         // la précède.
750         palette[color_1-1].R=palette[color_1].R;
751         palette[color_1-1].G=palette[color_1].G;
752         palette[color_1-1].B=palette[color_1].B;
753       }
754 
755       //   Une fois la palette et la table d'utilisation gérées, on peut
756       // s'occuper de notre table de conversion.
757       if (conversion_table[color_1]>best_color_2)
758         //   La color_1 avait l'intention de se faire remplacer par une
759         // couleur que l'on va (ou que l'on a déjà) bouger en arrière.
760         conversion_table[color_1]--;
761     }
762 
763     //   On vient d'éjecter une couleur, donc on peut mettre à jour le nombre
764     // de couleurs utilisées.
765     (*used_colors)--;
766 
767     // A la fin, on doit passer (dans la palette) les teintes du dernier
768     // élément de notre ensemble en noir.
769     palette[*used_colors].R=0;
770     palette[*used_colors].G=0;
771     palette[*used_colors].B=0;
772 
773     // Au passage, on va s'assurer que l'on a pas oublié de la mettre à une
774     // utilisation nulle.
775     color_usage[*used_colors]=0;
776 
777     // Après avoir éjecté une couleur, on le fait savoir à l'utilisateur par
778     // l'intermédiaire du compteur de nombre utilisées.
779     Num2str(*used_colors,str,3);
780     Print_in_window(COUNT_X,COUNT_Y,str,MC_Black,MC_Light);
781   }
782 
783   //   Maintenant, tous ces calculs doivent êtres pris en compte dans la
784   // palette, l'image et à l'écran.
785   Remap_image_highlevel(conversion_table); // Et voila pour l'image et l'écran
786   Display_cursor();
787 }
788 
789 
790 // Position of the numeric values of the R G B sliders
791 static const int NUMERIC_R_X = 216;
792 static const int NUMERIC_G_X = 243;
793 static const int NUMERIC_B_X = 270;
794 static const int NUMERIC_Y   = 183;
795 // Position of the whole button
796 static const int NUMERIC_BOX_X = 215;
797 static const int NUMERIC_BOX_Y = 181;
798 static const int NUMERIC_BOX_W = 81;
799 static const int NUMERIC_BOX_H = 12;
800 
Set_palette_slider(T_Scroller_button * slider,word nb_elements,word position,char * value,short x_pos)801 void Set_palette_slider(T_Scroller_button * slider,
802                             word nb_elements, word position,
803                             char * value, short x_pos)
804 {
805   slider->Nb_elements=nb_elements;
806   slider->Position=position;
807   Compute_slider_cursor_length(slider);
808   Window_draw_slider(slider);
809   Print_counter(x_pos,NUMERIC_Y,value,MC_Black,MC_Light);
810 }
811 
812 
813 
Display_sliders(T_Scroller_button * red_slider,T_Scroller_button * green_slider,T_Scroller_button * blue_slider,byte block_is_selected,T_Components * palette)814 void Display_sliders(T_Scroller_button * red_slider,
815                          T_Scroller_button * green_slider,
816                          T_Scroller_button * blue_slider,
817                          byte block_is_selected, T_Components * palette)
818 {
819   char str[5];
820 
821   if (block_is_selected)
822   {
823     Set_palette_slider(red_slider,Color_max*2+1,Color_max,"\xb1  0",NUMERIC_R_X);
824     Set_palette_slider(green_slider,Color_max*2+1,Color_max,"\xb1  0",NUMERIC_G_X);
825     Set_palette_slider(blue_slider,Color_max*2+1,Color_max,"\xb1  0",NUMERIC_B_X);
826   }
827   else
828   {
829     byte j1, j2, j3;
830     j1= palette[Fore_color].R;
831     j2= palette[Fore_color].G;
832     j3= palette[Fore_color].B;
833     if (!Palette_view_is_RGB)
834     {
835       RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3);
836     }
837 
838     Format_component(Encode_component(j1), str);
839     Set_palette_slider(red_slider,Color_count,Color_max-Encode_component(j1),str,NUMERIC_R_X);
840     Format_component(Encode_component(j2),str);
841     Set_palette_slider(green_slider,Color_count,Color_max-Encode_component(j2),str,NUMERIC_G_X);
842     Format_component(Encode_component(j3),str);
843     Set_palette_slider(blue_slider,Color_count,Color_max-Encode_component(j3),str,NUMERIC_B_X);
844   }
845 }
846 
Draw_all_palette_sliders(T_Scroller_button * red_slider,T_Scroller_button * green_slider,T_Scroller_button * blue_slider,T_Palette palette,byte start,byte end)847 void Draw_all_palette_sliders(T_Scroller_button * red_slider,
848                                T_Scroller_button * green_slider,
849                                T_Scroller_button * blue_slider,
850                                T_Palette palette,byte start,byte end)
851 {
852   char str[5];
853 
854   Hide_cursor();
855   // Réaffichage des jauges:
856   if (start!=end)
857   {
858     // Dans le cas d'un bloc, tout à 0.
859     red_slider->Position   =Color_max;
860     Window_draw_slider(red_slider);
861     Print_counter(NUMERIC_R_X,NUMERIC_Y,"\xb1  0",MC_Black,MC_Light);
862 
863     green_slider->Position   =Color_max;
864     Window_draw_slider(green_slider);
865     Print_counter(NUMERIC_G_X,NUMERIC_Y,"\xb1  0",MC_Black,MC_Light);
866 
867     blue_slider->Position   =Color_max;
868     Window_draw_slider(blue_slider);
869     Print_counter(NUMERIC_B_X,NUMERIC_Y,"\xb1  0",MC_Black,MC_Light);
870   }
871   else
872   {
873     // Dans le cas d'une seule couleur, composantes.
874     byte j1, j2, j3;
875     j1= palette[start].R;
876     j2= palette[start].G;
877     j3= palette[start].B;
878     if (!Palette_view_is_RGB)
879     {
880       RGB_to_HSL(j1,j2,j3,&j1,&j2,&j3);
881     }
882     Format_component(Encode_component(j1),str);
883     red_slider->Position=Color_max-Encode_component(j1);
884     Window_draw_slider(red_slider);
885     Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
886 
887     Format_component(Encode_component(j2),str);
888     green_slider->Position=Color_max-Encode_component(j2);
889     Window_draw_slider(green_slider);
890     Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
891 
892     Format_component(Encode_component(j3),str);
893     blue_slider->Position=Color_max-Encode_component(j3);
894     Window_draw_slider(blue_slider);
895     Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
896   }
897   Display_cursor();
898 }
899 
900 
Window_Histogram(unsigned char block_start,unsigned char block_end,dword * color_usage)901 int Window_Histogram(unsigned char block_start, unsigned char block_end, dword* color_usage)
902 {
903   int i, j;
904   unsigned int max_count = 0;
905   int old_height=0;
906   int hovered_color=-1;
907   int new_hovered_color;
908   int bar_width;
909   T_Special_button *histo;
910   int clicked_button;
911 
912   /* Draws an histogram of the selected range in a separate window */
913 
914   if (block_start == block_end) {
915     // only one color selected: auto-detect the range
916     for (block_start=0; block_start!=255; block_start++)
917       if (color_usage[block_start])
918         break;
919     for (block_end=255; block_end!=0; block_end--)
920       if (color_usage[block_end])
921         break;
922   }
923 
924   // Normalize the histogram towards the most used color
925   // Step 1 : find the most used color in the range
926   for(i=block_start; i<= block_end; i++) {
927     if(color_usage[i] > max_count) max_count = color_usage[i];
928   }
929 
930   if (max_count == 0)
931   {
932     Warning_message("All these colors are unused!");
933     Hide_cursor();
934     return -1;
935   }
936 
937   Open_window(263, 150, "Histogram");
938   Window_set_normal_button(120, 130, 42, 14, "Close",-1,1,KEY_RETURN);
939 
940   Print_in_window(6, 17, "Color:", MC_Dark, MC_Light);
941   Print_in_window(110+12*8, 17, "Pixels", MC_Dark, MC_Light);
942 
943   // Step 2 : draw bars
944   bar_width=256/(block_end-block_start+1);
945   j = 0;
946   for(i=block_start; i<= block_end; i++) {
947     int height = 100*color_usage[i]/max_count;
948     // Don't draw anything if the color is unused
949     if (color_usage[i]!=0)
950     {
951       // Draw at least one pixel if the color is used
952       if (height==0)
953         height=1;
954 
955       Window_rectangle(
956             3+j*bar_width,
957             127-height,
958             bar_width,
959             height, i);
960 
961       //if (i == MC_Light) {
962         Window_rectangle(
963               3+j*bar_width,
964               126-height,
965               bar_width,
966               1,MC_Black);
967       //}
968     }
969     // vertical outline
970     if (height>old_height)
971       Window_rectangle(
972               2+j*bar_width,
973               126-height,
974               1,
975               height-old_height+1,MC_Black);
976     else if (old_height>height)
977       Window_rectangle(
978               3+j*bar_width,
979               126-old_height,
980               1,
981               old_height-height+1,MC_Black);
982 
983     old_height=height;
984     j++;
985   }
986   // Last vertical outline
987   if (old_height!=0)
988   Window_rectangle(
989       3+j*(256/(block_end-block_start+1)),
990       126-old_height,
991       1,
992       old_height+1,MC_Black);
993 
994   histo = Window_set_special_button(3, 27, j*bar_width, 100,0); // 2
995 
996   Update_window_area(0,0,263,150);
997   Display_cursor();
998   do
999   {
1000     // Find hovered area
1001     if (Window_click_in_rectangle(histo->Pos_X,histo->Pos_Y,histo->Pos_X+histo->Width-1,histo->Pos_Y+histo->Height-1))
1002     {
1003       short x_pos;
1004       x_pos=((short)Mouse_X-Window_pos_X)/Menu_factor_X;
1005       new_hovered_color=block_start+(x_pos-histo->Pos_X)/bar_width;
1006     }
1007     else
1008       new_hovered_color=-1;
1009 
1010     // When changing hovered color, update the info area
1011     if (new_hovered_color!=hovered_color)
1012     {
1013       char str[20];
1014 
1015       hovered_color=new_hovered_color;
1016       Hide_cursor();
1017       if (hovered_color < 0)
1018       {
1019         Window_rectangle(6+6*8,17,3*8,7,MC_Light);
1020         Update_window_area(6+6*8,17,3*8,7);
1021         Window_rectangle(86,17,2*8,8,MC_Light);
1022         Update_window_area(86,17,2*8,8);
1023         Window_rectangle(110,17,11*8,7,MC_Light);
1024         Update_window_area(110,17,11*8,7);
1025       }
1026       else
1027       {
1028         Num2str(hovered_color,str  ,3);
1029         Print_in_window(6+6*8,17,str,MC_Black,MC_Light);
1030         Window_rectangle(86,17,2*8,8,hovered_color);
1031         Update_window_area(86,17,2*8,8);
1032         Num2str(color_usage[hovered_color],str  ,11);
1033         Print_in_window(110,17,str,MC_Black,MC_Light);
1034       }
1035       Display_cursor();
1036     }
1037     clicked_button=Window_clicked_button();
1038     if (Key == KEY_ESC)
1039       clicked_button=1;
1040 
1041   } while( clicked_button < 1 && !Quit_is_required);
1042   Close_window();
1043 
1044   if (clicked_button==2)
1045   {
1046     // This is a counter-hack. Close_window() sets Mouse_K to zero
1047     // on exit, I don't know why (It will become 1 again if you move
1048     // the mouse slightly)
1049     // Here I force it back to 1, so that the Wait_end_of_click()
1050     // will really wait for a release of mouse button.
1051     Mouse_K=1;
1052     return hovered_color;
1053   }
1054   return -1;
1055 }
1056 
Print_RGB_or_HSL(byte mode)1057 void Print_RGB_or_HSL(byte mode)
1058 {
1059   Print_in_window(224,16,mode?"H":"R",MC_Dark,MC_Light);
1060   Print_in_window(251,16,mode?"S":"G",MC_Dark,MC_Light);
1061   Print_in_window(278,16,mode?"L":"B",MC_Dark,MC_Light);
1062 }
1063 
Tag_used_colors(byte color,dword color_usage[])1064 void Tag_used_colors(byte color, dword color_usage[])
1065 {
1066   word index;
1067 
1068   for (index=0;index<=255;index++)
1069   {
1070     short x_pos=Window_palette_button_list->Pos_X+6+((index>>4)*10);
1071     short y_pos=Window_palette_button_list->Pos_Y+3+((index&15)* 5);
1072     byte col;
1073 
1074     col=(color&&color_usage[index])?MC_White:MC_Light;
1075     Window_rectangle(x_pos+5,y_pos+0,1,5,col);
1076   }
1077 
1078   Update_window_area(Window_palette_button_list->Pos_X+3,Window_palette_button_list->Pos_Y+3,12*16,5*16);
1079 }
1080 
Button_Palette(int btn)1081 void Button_Palette(int btn)
1082 {
1083   static const int BUTTON_PLUS_X = 180;
1084   static const int BUTTON_PLUS_Y = 79;
1085   static const int BUTTON_MINUS_X = 196;
1086   static const int BUTTON_MINUS_Y = 79;
1087 
1088   // Coordinates of the block that displays Backcolor
1089   static const int BGCOLOR_DISPLAY_X = 174;
1090   static const int BGCOLOR_DISPLAY_Y = 65 + 14 + 14;
1091   static const int BGCOLOR_DISPLAY_W = 40;
1092   static const int BGCOLOR_DISPLAY_H = 96 - 14;
1093 
1094   // Coordinates of the block that displays Forecolor
1095   static const int FGCOLOR_DISPLAY_X = 178;
1096   static const int FGCOLOR_DISPLAY_Y = 69 + 14 + 14;
1097   static const int FGCOLOR_DISPLAY_W = 32;
1098   static const int FGCOLOR_DISPLAY_H = 88 - 14;
1099 
1100   // Coordinates of the Color#
1101   static const int COLOR_X = 111;
1102   static const int COLOR_Y = 79;
1103 
1104 
1105   static short reduce_colors_number = 256;
1106   short temp_color; // Variable pouvant reservir pour différents calculs intermédiaires
1107   dword temp;
1108   byte  color,click; // Variables pouvant reservir pour différents calculs intermédiaires
1109   short clicked_button;
1110   word  old_mouse_x;
1111   word  old_mouse_y;
1112   byte  old_mouse_k;
1113   byte  block_start;
1114   byte  block_end;
1115   byte  first_color;
1116   byte  last_color;
1117   char  str[10];
1118   word  i;
1119   T_Scroller_button * red_slider;
1120   T_Scroller_button * green_slider;
1121   T_Scroller_button * blue_slider;
1122   T_Dropdown_button * reduce_dropdown;
1123   T_Dropdown_button * sort_dropdown;
1124   byte   image_is_backed_up = 0;
1125   byte   need_to_remap = 0;
1126 
1127   dword  color_usage[256];
1128   short  used_colors = -1; // -1 <=> Inconnu
1129   byte   conversion_table[256];
1130 
1131   //T_Components * backup_palette;
1132   //T_Components * temp_palette;
1133   //T_Components * working_palette;
1134 
1135   static byte show_used_colors=0;
1136 
1137   static const int C1_X = 5;
1138   static const int C1_W = 45;
1139   static const int C2_X = 51;
1140   static const int C2_W = 53;
1141   static const int C3_X = 105;
1142   static const int C3_W = 53;
1143   static const int C4_X = 159;
1144   static const int C4_W = 53;
1145 
1146   static const int L1 = 16;
1147   static const int L2 = 31;
1148   static const int L3 = 46;
1149   static const int L4 = 61;
1150 
1151   (void)btn;
1152   backup_palette =(T_Components *)malloc(sizeof(T_Palette));
1153   temp_palette=(T_Components *)malloc(sizeof(T_Palette));
1154   working_palette=(T_Components *)malloc(sizeof(T_Palette));
1155 
1156   Component_unit(RGB_scale);
1157 
1158   Open_window(299, 196,"Palette");
1159 
1160   memcpy(working_palette, Main.palette, sizeof(T_Palette));
1161   Palette_edit_step();
1162 
1163   Window_set_palette_button(5, 89); // 1
1164 
1165   // Frame around the palette sliders
1166   //Window_display_frame (172, 63, 122, 129);
1167 
1168   // Graduation des jauges de couleur
1169   Window_rectangle(220,39+32,17,1,MC_Dark);
1170   Window_rectangle(247,39+32,17,1,MC_Dark);
1171   Window_rectangle(274,39+32,17,1,MC_Dark);
1172   Window_rectangle(220,39+64,17,1,MC_Dark);
1173   Window_rectangle(247,39+64,17,1,MC_Dark);
1174   Window_rectangle(274,39+64,17,1,MC_Dark);
1175   Window_rectangle(220,39+96,17,1,MC_Dark);
1176   Window_rectangle(247,39+96,17,1,MC_Dark);
1177   Window_rectangle(274,39+96,17,1,MC_Dark);
1178   // Jauges de couleur
1179   red_slider = Window_set_scroller_button(223, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].R));// 2
1180   green_slider = Window_set_scroller_button(250, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].G));// 3
1181   blue_slider = Window_set_scroller_button(277, 27, 128+24,Color_count,1,Color_max-Decode_component(working_palette[Fore_color].B));// 4
1182 
1183   if(Palette_view_is_RGB==1) {
1184       Print_RGB_or_HSL(0);
1185       Component_unit(RGB_scale);
1186   } else {
1187       Print_RGB_or_HSL(1);
1188       Component_unit(256);
1189   }
1190 
1191   first_color=last_color=block_start=block_end=Fore_color;
1192   Tag_color_range(block_start,block_end);
1193 
1194   // Affichage dans le block de visu de la couleur en cours
1195   Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color);
1196   Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
1197 
1198   // Affichage des valeurs de la couleur courante (pour 1 couleur)
1199   Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette);
1200 
1201   Print_in_window(7, COLOR_Y, "Color number:", MC_Dark, MC_Light);
1202   Num2str(Fore_color, str, 3);
1203   Print_in_window(COLOR_X, COLOR_Y, str, MC_Black, MC_Light);
1204 
1205   Window_set_normal_button(C4_X,L3,C4_W,14,"Merge"  ,1,1,KEY_m);   // 5
1206   Window_set_normal_button(C2_X,L3,C2_W,14,"Gray"   ,1,1,KEY_g);   // 6
1207   Window_set_normal_button(C1_X,L1,C1_W,14,"Swap"   ,2,1,KEY_w);   // 7
1208   Window_set_normal_button(C2_X,L1,C2_W,14,"X-Swap" ,1,1,KEY_x);   // 8
1209   Window_set_normal_button(C3_X,L1,C3_W,14,"Copy"   ,1,1,KEY_c);   // 9
1210   Window_set_normal_button(C3_X,L3,C3_W,14,"Spread" ,4,1,KEY_e);   // 10
1211 
1212   reduce_dropdown = Window_set_dropdown_button(89, L4, 83, 14, 84, "Reduce", 0,
1213     0, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 11
1214   Window_dropdown_add_item(reduce_dropdown, 256, "to uniques");
1215   Window_dropdown_add_item(reduce_dropdown, 128, "to 128");
1216   Window_dropdown_add_item(reduce_dropdown,  64, "to 64");
1217   Window_dropdown_add_item(reduce_dropdown,  32, "to 32");
1218   Window_dropdown_add_item(reduce_dropdown,  16, "to 16");
1219   Window_dropdown_add_item(reduce_dropdown,   8, "to 8");
1220   Window_dropdown_add_item(reduce_dropdown,   4, "to 4");
1221   Window_dropdown_add_item(reduce_dropdown,   2, "to 2");
1222   Window_dropdown_add_item(reduce_dropdown,   0, "Other");
1223 
1224   Window_set_normal_button(  5,178,35,14,"Undo"  ,1,1,KEY_u);  // 12
1225   Window_set_normal_button(122,178,51,14,"Cancel",0,1,KEY_ESC);  // 13
1226   Window_set_normal_button(177,178,35,14,"OK"    ,0,1,KEY_RETURN);  // 14
1227 
1228   Window_set_normal_button(C4_X,L2,C4_W,14,"Used",4,1,KEY_d); // 15
1229   Window_set_normal_button(C1_X,L4,83,14,"Zap unused",0,1,KEY_DELETE);//16
1230 
1231   Window_set_repeatable_button(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1,KEY_KP_PLUS);       // 17
1232   Window_set_repeatable_button(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1,KEY_KP_MINUS);       // 18
1233 
1234   Window_set_normal_button(C1_X,L3,C1_W,14,"Neg"    ,1,1,KEY_n);   // 19
1235   Window_set_normal_button(C1_X,L2,C1_W,14,"Flip"   ,1,1,KEY_f);   // 20
1236   Window_set_normal_button(C2_X,L2,C2_W,14,"X-Flip" ,5,1,KEY_i);   // 21
1237 
1238   // Button without outline (RGB/HSL switch)
1239   Window_set_normal_button(NUMERIC_BOX_X,14,81,11,""    ,0,1,KEY_h);   // 22
1240   Window_display_frame_mono(NUMERIC_BOX_X-1,14-1,81+2,11+2,MC_Light);
1241 
1242   sort_dropdown = Window_set_dropdown_button(C3_X, L2, C3_W, 14, 80, " Sort", 0,
1243     1, 1, RIGHT_SIDE|LEFT_SIDE, 0); // 23
1244   Window_dropdown_add_item(sort_dropdown, 0, "Hue/Light");
1245   Window_dropdown_add_item(sort_dropdown, 1, "Lightness");
1246   Window_dropdown_add_item(sort_dropdown, 2, "Histogram");
1247 
1248   Window_set_normal_button(NUMERIC_BOX_X,NUMERIC_BOX_Y,NUMERIC_BOX_W,NUMERIC_BOX_H,"" ,0,1,KEY_NONE);   // 24
1249   // Button without outline
1250   Window_display_frame_mono(NUMERIC_BOX_X-1,NUMERIC_BOX_Y-1,NUMERIC_BOX_W+2,NUMERIC_BOX_H+2,MC_Light);
1251 
1252   Window_set_normal_button(C4_X,L1,C4_W,14,"Histo",4,1,KEY_t);// 25
1253 
1254   Window_set_normal_button( 44,178,35,14,"Load"  ,1,1,KEY_l);  // 26
1255   Window_set_normal_button( 83,178,35,14,"Save"  ,1,1,KEY_s);  // 27
1256 
1257   Window_set_normal_button( 89+84,L4,39,14,"EHB" ,3,1,KEY_b);  // 28
1258 
1259   // Dessin des petits effets spéciaux pour les boutons [+] et [-]
1260   Draw_thingumajig(BUTTON_PLUS_X-5, BUTTON_PLUS_Y,MC_White,-1);
1261   Draw_thingumajig(BUTTON_MINUS_X+16,BUTTON_MINUS_Y,MC_Dark,+1);
1262 
1263   Display_cursor();
1264 
1265   Update_color_count(&used_colors,color_usage);
1266   if (show_used_colors)
1267     Tag_used_colors(1, color_usage);
1268 
1269   Update_window_area(0,0,299,196);
1270 
1271   do
1272   {
1273     old_mouse_x=Mouse_X;
1274     old_mouse_y=Mouse_Y;
1275     old_mouse_k=Mouse_K;
1276     clicked_button = Window_clicked_button();
1277 
1278     switch (clicked_button)
1279     {
1280       case  0 : // Nulle part
1281         break;
1282       case -1 : // Hors de la fenêtre
1283       case  1 : // palette
1284         if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
1285         {
1286           Hide_cursor();
1287           temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
1288           // Right click outside the window
1289           if (Mouse_K==RIGHT_SIDE && clicked_button==-1)
1290           {
1291             if (Back_color!=temp_color)
1292             {
1293               Back_color=temp_color;
1294               // 4 blocks de back_color entourant la fore_color
1295               Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color);
1296               Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color);
1297               Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color);
1298               Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color);
1299               Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
1300             }
1301             Display_cursor();
1302           }
1303           // Right-click inside the palette
1304           else if (Mouse_K==RIGHT_SIDE)
1305           {
1306             // Contextual menu
1307             T_Dropdown_button dropdown;
1308             T_Dropdown_choice *item;
1309 
1310             dropdown.Pos_X         =0;
1311             dropdown.Pos_Y         =0;
1312             dropdown.Height        =0;
1313             dropdown.Dropdown_width=48;
1314             dropdown.First_item    =NULL;
1315             dropdown.Bottom_up     =1;
1316 
1317             Window_dropdown_add_item(&dropdown, 1, "Copy");
1318             Window_dropdown_add_item(&dropdown, 2, "Paste");
1319 
1320             item=Dropdown_activate(&dropdown,Mouse_X,Mouse_Y);
1321 
1322             if (item && item->Number == 1)
1323             {
1324               // Copy
1325               Set_clipboard_colors(block_end+1-block_start,working_palette + block_start);
1326               Display_cursor();
1327             }
1328             else if (item && item->Number == 2)
1329             {
1330               // Paste
1331               int nb_colors;
1332 
1333               // Backup
1334               Palette_edit_step();
1335 
1336               nb_colors = Get_clipboard_colors(working_palette, block_start);
1337               if (nb_colors>0)
1338               {
1339                 memcpy(temp_palette,working_palette,sizeof(T_Palette));
1340                 Set_palette(working_palette);
1341                 need_to_remap=1;
1342                 Display_cursor();
1343                 Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1344               }
1345               else
1346               {
1347                 Display_cursor();
1348               }
1349             }
1350             else if (Back_color!=temp_color)
1351             {
1352               // Just select back color
1353 
1354               Back_color=temp_color;
1355               // 4 blocks de back_color entourant la fore_color
1356               Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color);
1357               Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color);
1358               Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color);
1359               Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color);
1360               Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
1361 
1362               Display_cursor();
1363             }
1364             else
1365             {
1366               Display_cursor();
1367             }
1368             Window_dropdown_clear_items(&dropdown);
1369           }
1370           else
1371           {
1372             if (!old_mouse_k)
1373             {
1374               // On vient de clicker sur une couleur (et une seule)
1375               if ( (Fore_color!=temp_color) || (block_start!=block_end) )
1376               {
1377                 // La couleur en question est nouvelle ou elle annule un
1378                 // ancien bloc. Il faut donc sélectionner cette couleur comme
1379                 // unique couleur choisie.
1380 
1381                 Fore_color=first_color=last_color=block_start=block_end=temp_color;
1382                 Tag_color_range(block_start,block_end);
1383 
1384                 // Affichage du n° de la couleur sélectionnée
1385                 Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light);
1386                 Num2str(Fore_color,str,3);
1387                 Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1388                 Update_window_area(COLOR_X,COLOR_Y,56,7);
1389 
1390                 // Affichage des jauges
1391                 Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light);
1392                 Display_sliders(red_slider,green_slider,blue_slider,0,working_palette);
1393 
1394                 // Affichage dans le block de visu de la couleur en cours
1395                 Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
1396                 Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
1397 
1398                 Palette_edit_select_range();
1399               }
1400             }
1401             else
1402             {
1403               // On maintient le click, on va donc tester si le curseur bouge
1404               if (temp_color!=last_color)
1405               {
1406                 // On commence par ordonner la 1ère et dernière couleur du bloc
1407                 if (first_color<temp_color)
1408                 {
1409                   block_start=first_color;
1410                   block_end=temp_color;
1411 
1412                   // Affichage du n° de la couleur sélectionnée
1413                   snprintf(str, sizeof(str), "%3hu\x1a%3hu", (word)block_start, (word)block_end); // 0x1a : flèche vers la droite
1414                   Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1415 
1416                   // Affichage des jauges
1417                   Display_sliders(red_slider,green_slider,blue_slider,1,NULL);
1418 
1419                   // Affichage dans le block de visu du bloc (dégradé) en cours
1420                   Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end);
1421                 }
1422                 else if (first_color>temp_color)
1423                 {
1424                   block_start=temp_color;
1425                   block_end=first_color;
1426 
1427                   // Affichage du n° de la couleur sélectionnée
1428                   snprintf(str, sizeof(str), "%3hu\x1a%3hu", (word)block_start, (word)block_end); // 0x1a : flèche vers la droite
1429                   Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1430 
1431                   // Affichage des jauges
1432                   Display_sliders(red_slider,green_slider,blue_slider,1,NULL);
1433 
1434                   // Affichage dans le block de visu du bloc (dégradé) en cours
1435                   Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end);
1436                 }
1437                 else
1438                 {
1439                   block_start=block_end=first_color;
1440                   Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light);
1441 
1442                   // Affichage du n° de la couleur sélectionnée
1443                   Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light);
1444                   Update_window_area(COLOR_X+24,COLOR_Y,32,7);
1445                   Num2str(Fore_color,str,3);
1446                   Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1447 
1448                   // Affichage des jauges
1449                   Display_sliders(red_slider,green_slider,blue_slider,0,working_palette);
1450 
1451                   // Affichage dans le block de visu de la couleur en cours
1452                   Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
1453                   Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
1454                 }
1455 
1456                 // On tagge le bloc (ou la couleur)
1457                 Tag_color_range(block_start,block_end);
1458               }
1459 
1460               last_color=temp_color;
1461             }
1462             Display_cursor();
1463           }
1464 
1465         }
1466         break;
1467       case  2 : // Jauge rouge
1468         Hide_cursor();
1469         Palette_edit_alter_channel();
1470         if (block_start==block_end)
1471         {
1472           if(Palette_view_is_RGB)
1473           {
1474             Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette);
1475             Format_component(Color_max-red_slider->Position,str);
1476           }
1477           else
1478           {
1479             HSL_to_RGB(
1480               255-red_slider->Position,
1481               255-green_slider->Position,
1482               255-blue_slider->Position,
1483               &working_palette[Fore_color].R,
1484               &working_palette[Fore_color].G,
1485               &working_palette[Fore_color].B);
1486             Format_component((int)255-red_slider->Position,str);
1487           }
1488           Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
1489         }
1490         else
1491         {
1492           if(Palette_view_is_RGB)
1493           {
1494             for (i=block_start; i<=block_end; i++)
1495               Set_red(i,Add_encoded(temp_palette[i].R, Color_max-red_slider->Position),working_palette);
1496           }
1497           else
1498           {
1499             byte greys=0;
1500             byte non_greys=0;
1501             // Check if the range contains both greys and non-greys
1502             for (i=block_start; i<=block_end; i++)
1503               if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B)
1504                 non_greys=1;
1505               else
1506                 greys=1;
1507 
1508             for (i=block_start; i<=block_end; i++)
1509             {
1510               byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B;
1511               Set_HSL(
1512                 temp_palette,
1513                 working_palette,
1514                 i,
1515                 is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position,
1516                 is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position,
1517                 Color_max-blue_slider->Position
1518                 );
1519             }
1520           }
1521 
1522           if (red_slider->Position>Color_max)
1523           {
1524             // Jauge dans les négatifs:
1525             Num2str(-(Color_max-red_slider->Position),str,4);
1526             str[0]='-';
1527           }
1528           else if (red_slider->Position<Color_max)
1529           {
1530             // Jauge dans les positifs:
1531             Num2str(  Color_max-red_slider->Position ,str,4);
1532             str[0]='+';
1533           }
1534           else
1535           {
1536             // Jauge nulle:
1537             strcpy(str,"\xb1  0");
1538           }
1539           Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
1540 
1541         }
1542 
1543         need_to_remap=1;
1544 
1545         Display_cursor();
1546         Set_palette(working_palette);
1547         break;
1548       case  3 : // Jauge verte
1549         Hide_cursor();
1550         Palette_edit_alter_channel();
1551         if (block_start==block_end)
1552         {
1553           if(Palette_view_is_RGB)
1554           {
1555             Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette);
1556             Format_component(Color_max-green_slider->Position,str);
1557           }
1558           else
1559           {
1560             HSL_to_RGB(
1561               255-red_slider->Position,
1562               255-green_slider->Position,
1563               255-blue_slider->Position,
1564               &working_palette[Fore_color].R,
1565               &working_palette[Fore_color].G,
1566               &working_palette[Fore_color].B);
1567             Format_component((int)255-green_slider->Position,str);
1568           }
1569           Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
1570         }
1571         else
1572         {
1573           if(Palette_view_is_RGB)
1574           {
1575             for (i=block_start; i<=block_end; i++)
1576               Set_green (i,Add_encoded(temp_palette[i].G, Color_max-green_slider->Position),working_palette);
1577           }
1578           else
1579           {
1580             byte greys=0;
1581             byte non_greys=0;
1582             // Check if the range contains both greys and non-greys
1583             for (i=block_start; i<=block_end; i++)
1584               if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B)
1585                 non_greys=1;
1586               else
1587                 greys=1;
1588 
1589             for (i=block_start; i<=block_end; i++)
1590             {
1591               byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B;
1592               Set_HSL(
1593                 temp_palette,
1594                 working_palette,
1595                 i,
1596                 is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position,
1597                 is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position,
1598                 Color_max-blue_slider->Position
1599                 );
1600             }
1601           }
1602 
1603           if (green_slider->Position>Color_max)
1604           {
1605             // Jauge dans les négatifs:
1606             Num2str(-(Color_max-green_slider->Position),str,4);
1607             str[0]='-';
1608           }
1609           else if (green_slider->Position<Color_max)
1610           {
1611             // Jauge dans les positifs:
1612             Num2str(  Color_max-green_slider->Position ,str,4);
1613             str[0]='+';
1614           }
1615           else
1616           {
1617             // Jauge nulle:
1618             strcpy(str,"\xb1  0");
1619           }
1620           Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
1621         }
1622 
1623         need_to_remap=1;
1624 
1625         Display_cursor();
1626         Set_palette(working_palette);
1627         break;
1628 
1629       case  4 : // Jauge bleue
1630         Hide_cursor();
1631         Palette_edit_alter_channel();
1632         if (block_start==block_end)
1633         {
1634           if(Palette_view_is_RGB)
1635           {
1636             Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette);
1637             Format_component(Color_max-blue_slider->Position,str);
1638           }
1639           else
1640           {
1641             HSL_to_RGB(
1642               255-red_slider->Position,
1643               255-green_slider->Position,
1644               255-blue_slider->Position,
1645               &working_palette[Fore_color].R,
1646               &working_palette[Fore_color].G,
1647               &working_palette[Fore_color].B);
1648             Format_component((int)255-blue_slider->Position,str);
1649           }
1650           Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
1651         }
1652         else
1653         {
1654           if(Palette_view_is_RGB)
1655           {
1656           for (i=block_start; i<=block_end; i++)
1657               Set_blue(i,Add_encoded(temp_palette[i].B, Color_max-blue_slider->Position),working_palette);
1658           }
1659           else
1660           {
1661             byte greys=0;
1662             byte non_greys=0;
1663             // Check if the range contains both greys and non-greys
1664             for (i=block_start; i<=block_end; i++)
1665               if (temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B)
1666                 non_greys=1;
1667               else
1668                 greys=1;
1669 
1670             for (i=block_start; i<=block_end; i++)
1671             {
1672               byte is_grey = temp_palette[i].R==temp_palette[i].G && temp_palette[i].R == temp_palette[i].B;
1673               Set_HSL(
1674                 temp_palette,
1675                 working_palette,
1676                 i,
1677                 is_grey && greys && non_greys ? 0 : Color_max-red_slider->Position,
1678                 is_grey && greys && non_greys ? 0 : Color_max-green_slider->Position,
1679                 Color_max-blue_slider->Position
1680                 );
1681             }
1682           }
1683 
1684           if (blue_slider->Position>Color_max)
1685           {
1686             // Jauge dans les négatifs:
1687             Num2str(-(Color_max-blue_slider->Position),str,4);
1688             str[0]='-';
1689           }
1690           else if (blue_slider->Position<Color_max)
1691           {
1692             // Jauge dans les positifs:
1693             Num2str(  Color_max-blue_slider->Position ,str,4);
1694             str[0]='+';
1695           }
1696           else
1697           {
1698             // Jauge nulle:
1699             strcpy(str,"\xb1  0");
1700           }
1701           Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
1702         }
1703 
1704         need_to_remap=1;
1705 
1706         Display_cursor();
1707         Set_palette(working_palette);
1708         break;
1709 
1710       case 5 : // Merge
1711         if (block_start!=block_end)
1712         {
1713           dword sum_r=0, sum_g=0, sum_b=0, used=0;
1714 
1715           Palette_edit_step();
1716           // Compute weighted average
1717           for (i=block_start; i<=block_end; i++)
1718           {
1719             used+=color_usage[i];
1720             sum_r+=working_palette[i].R * color_usage[i];
1721             sum_g+=working_palette[i].G * color_usage[i];
1722             sum_b+=working_palette[i].B * color_usage[i];
1723           }
1724           // Do normal average if no pixels used
1725           if (used==0)
1726           {
1727             sum_r=sum_g=sum_b=used=0;
1728             for (i=block_start; i<=block_end; i++)
1729             {
1730               used+=1;
1731               sum_r+=working_palette[i].R;
1732               sum_g+=working_palette[i].G;
1733               sum_b+=working_palette[i].B;
1734             }
1735           }
1736           for (i=block_start; i<=block_end; i++)
1737           {
1738             Set_red  (i,sum_r/used,working_palette);
1739             Set_green(i,sum_g/used,working_palette);
1740             Set_blue (i,sum_b/used,working_palette);
1741           }
1742         }
1743         else
1744         {
1745           temp_color=Wait_click_in_palette(Window_palette_button_list);
1746           if (temp_color>=0)
1747           {
1748             dword sum_r=0, sum_g=0, sum_b=0, used;
1749             Palette_edit_step();
1750 
1751             // Compute weighted average
1752             used=color_usage[temp_color]+color_usage[Fore_color];
1753             if (used)
1754             {
1755               sum_r=(working_palette[temp_color].R * color_usage[temp_color]
1756                 +    working_palette[Fore_color].R * color_usage[Fore_color])
1757                 / used;
1758               sum_g=(working_palette[temp_color].G * color_usage[temp_color]
1759                 +    working_palette[Fore_color].G * color_usage[Fore_color])
1760                 / used;
1761               sum_b=(working_palette[temp_color].B * color_usage[temp_color]
1762                 +    working_palette[Fore_color].B * color_usage[Fore_color])
1763                 / used;
1764             }
1765             else // Normal average
1766             {
1767               sum_r=(working_palette[temp_color].R+working_palette[Fore_color].R)/2;
1768               sum_g=(working_palette[temp_color].G+working_palette[Fore_color].G)/2;
1769               sum_b=(working_palette[temp_color].B+working_palette[Fore_color].B)/2;
1770             }
1771             Set_red  (temp_color,sum_r,working_palette);
1772             Set_green(temp_color,sum_g,working_palette);
1773             Set_blue (temp_color,sum_b,working_palette);
1774             Set_red  (Fore_color,sum_r,working_palette);
1775             Set_green(Fore_color,sum_g,working_palette);
1776             Set_blue (Fore_color,sum_b,working_palette);
1777 
1778             Wait_end_of_click();
1779           }
1780         }
1781         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1782         // On prépare la "modifiabilité" des nouvelles couleurs
1783         Set_palette(working_palette);
1784         memcpy(temp_palette,working_palette,sizeof(T_Palette));
1785         need_to_remap=1;
1786 
1787         break;
1788 
1789       case 6 : // Grey scale
1790         // Backup
1791         Palette_edit_step();
1792         // Grey Scale
1793         for (i=block_start;i<=block_end;i++)
1794         {
1795           temp_color=(dword)( ((dword)working_palette[i].R*30) + ((dword)working_palette[i].G*59) + ((dword)working_palette[i].B*11) )/100;
1796           Set_red(i,temp_color,working_palette);
1797           Set_green (i,temp_color,working_palette);
1798           Set_blue (i,temp_color,working_palette);
1799         }
1800         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1801         // On prépare la "modifiabilité" des nouvelles couleurs
1802         Set_palette(working_palette);
1803         memcpy(temp_palette,working_palette,sizeof(T_Palette));
1804 
1805         need_to_remap=1;
1806         break;
1807 
1808       case  7 : // Swap
1809       case  8 : // X-Swap
1810         temp_color=Wait_click_in_palette(Window_palette_button_list);
1811         if ((temp_color>=0)
1812          && (temp_color!=block_start))
1813         {
1814           Hide_cursor();
1815           Palette_edit_step();
1816 
1817           // On calcule le nombre de couleurs a swapper sans risquer de sortir
1818           // de la palette (La var. first_color est utilisée pour économiser 1 var; c'est tout)
1819           first_color=(temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color;
1820 
1821           if (clicked_button==8) // On ne fait de backup de l'image que si on
1822                                 // est en mode X-SWAP.
1823             if (!image_is_backed_up)
1824             {
1825               Backup_layers(LAYER_ALL);
1826               image_is_backed_up=1;
1827             }
1828 
1829           Swap(clicked_button==8,block_start,temp_color,first_color,working_palette,color_usage);
1830 
1831           memcpy(temp_palette,working_palette,sizeof(T_Palette));
1832 
1833           // On déplace le bloc vers les modifs:
1834           last_color=block_end=temp_color+first_color-1;
1835           Fore_color=first_color=block_start=temp_color;
1836           // On raffiche le n° des bornes du bloc:
1837           if (block_start!=block_end)
1838           {
1839             // Cas d'un bloc multi-couleur
1840             snprintf(str, sizeof(str), "%3hu\x1a%3hu", (word)block_start, (word)block_end); // 0x1a : flèche vers la droite
1841             // Affichage dans le block de visu du bloc (dégradé) en cours
1842             Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end);
1843           }
1844           else
1845           {
1846             // Cas d'une seule couleur
1847             Num2str(Fore_color,str,3);
1848             Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light);
1849             // Affichage dans le block de visu de la couleur en cours
1850             Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
1851           }
1852           Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1853           // On tag le bloc (ou la couleur)
1854           Tag_color_range(block_start,block_end);
1855           if (show_used_colors)
1856             Tag_used_colors(1, color_usage);
1857 
1858           need_to_remap=1;
1859 
1860           Set_palette(working_palette);
1861 
1862           Display_cursor();
1863           Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1864 
1865           // En cas de X-Swap, tout l'ecran a pu changer de couleur.
1866           if (clicked_button==8)
1867           {
1868             Palette_edit_step(); // Disable Undo
1869             Update_rect(0, 0, Screen_width, Menu_Y_before_window);
1870             End_of_modification();
1871           }
1872           Wait_end_of_click();
1873         }
1874         break;
1875 
1876       case  9 : // Copy (to other slot)
1877         temp_color=Wait_click_in_palette(Window_palette_button_list);
1878         if ((temp_color>=0) && (temp_color!=block_start))
1879         {
1880           Hide_cursor();
1881           Palette_edit_step();
1882           memcpy(working_palette+temp_color,backup_palette+block_start,
1883                  ((temp_color+block_end-block_start<=255)?block_end+1-block_start:256-temp_color)*3);
1884           memcpy(temp_palette,working_palette,sizeof(T_Palette));
1885           Set_palette(working_palette);
1886           // On déplace le bloc vers les modifs:
1887           last_color=block_end=((temp_color+block_end-block_start<=255)?(temp_color+block_end-block_start):255);
1888           Fore_color=first_color=block_start=temp_color;
1889           // On raffiche le n° des bornes du bloc:
1890           if (block_start!=block_end)
1891           {
1892             // Cas d'un bloc multi-couleur
1893             snprintf(str, sizeof(str), "%3hu\x1a%3hu", (word)block_start, (word)block_end); // 0x1a : flèche vers la droite
1894             // Affichage dans le block de visu du bloc (dégradé) en cours
1895             Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end);
1896           }
1897           else
1898           {
1899             // Cas d'une seule couleur
1900             Num2str(Fore_color,str,3);
1901             Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light);
1902             // Affichage dans le block de visu de la couleur en cours
1903             Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
1904           }
1905           Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
1906           // On tag le bloc (ou la couleur)
1907           Tag_color_range(block_start,block_end);
1908 
1909           need_to_remap=1;
1910 
1911           Display_cursor();
1912           Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1913           Wait_end_of_click();
1914         }
1915         break;
1916 
1917       case 10 : // Spread
1918         if (block_start!=block_end)
1919         {
1920           Palette_edit_step();
1921           Spread_colors(block_start,block_end,working_palette);
1922         }
1923         else
1924         {
1925           temp_color=Wait_click_in_palette(Window_palette_button_list);
1926           if (temp_color>=0)
1927           {
1928             Palette_edit_step();
1929             if (temp_color<Fore_color)
1930               Spread_colors(temp_color,Fore_color,working_palette);
1931             else
1932               Spread_colors(Fore_color,temp_color,working_palette);
1933             Wait_end_of_click();
1934           }
1935         }
1936 
1937         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1938         // On prépare la "modifiabilité" des nouvelles couleurs
1939 
1940         Set_palette(working_palette);
1941 
1942         memcpy(temp_palette,working_palette,sizeof(T_Palette));
1943 
1944         need_to_remap=1;
1945         break;
1946 
1947       case 11: // Reduce
1948         Palette_edit_step();
1949         if (Window_attribute2==0) // User picked "other" choice
1950         {
1951           int choice;
1952 
1953           choice=Requester_window("Enter the max. number of colors",
1954                         reduce_colors_number);
1955 
1956           if (choice < 2 || choice > 256)
1957             break; // Cancel
1958 
1959           reduce_colors_number = choice;
1960         }
1961         else
1962           // Each other dropdown item has a number of colors as id.
1963           reduce_colors_number = Window_attribute2;
1964 
1965         if (reduce_colors_number >= 2)
1966         {
1967             if (!image_is_backed_up)
1968             {
1969                 Backup_layers(LAYER_ALL);
1970                 image_is_backed_up = 1;
1971             }
1972 
1973             Reduce_palette(&used_colors, reduce_colors_number, working_palette,
1974                     color_usage);
1975 
1976             if ((Config.Safety_colors) && (used_colors<4))
1977             {
1978                 memcpy(temp_palette, Main.palette, sizeof(T_Palette));
1979                 memcpy(Main.palette, working_palette, sizeof(T_Palette));
1980                 Set_nice_menu_colors(color_usage, 0);
1981                 memcpy(working_palette, Main.palette, sizeof(T_Palette));
1982                 memcpy(Main.palette, temp_palette, sizeof(T_Palette));
1983             }
1984 
1985             Set_palette(working_palette); // On définit la nouvelle palette
1986             Draw_all_palette_sliders(red_slider, green_slider, blue_slider,
1987                     working_palette, block_start, block_end);
1988             memcpy(temp_palette, working_palette, sizeof(T_Palette));
1989             Palette_edit_step(); // Disable Undo
1990             End_of_modification();
1991             need_to_remap = 1;
1992         }
1993         break;
1994 
1995       case 12: // Undo
1996         Palette_edit_undo_redo();
1997         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
1998         Set_palette(working_palette);
1999 
2000         need_to_remap=1;
2001         break;
2002 
2003       case 15 : // Used : show usage tags
2004         show_used_colors = !show_used_colors;
2005         Tag_used_colors(show_used_colors, color_usage);
2006         break;
2007 
2008       case 16 : // Zap unused
2009         Palette_edit_step();
2010         if (used_colors==-1)
2011           Update_color_count(&used_colors,color_usage);
2012         for (i=0; i<256; i++)
2013         {
2014           if (!color_usage[i])
2015           {
2016             temp_color=block_start+(i % (block_end+1-block_start));
2017             working_palette[i].R=backup_palette[temp_color].R;
2018             working_palette[i].G=backup_palette[temp_color].G;
2019             working_palette[i].B=backup_palette[temp_color].B;
2020           }
2021         }
2022 
2023         if ((Config.Safety_colors) && (used_colors<4) && (block_end==block_start))
2024         {
2025           memcpy(temp_palette,Main.palette,sizeof(T_Palette));
2026           memcpy(Main.palette,working_palette,sizeof(T_Palette));
2027           Set_nice_menu_colors(color_usage,0);
2028           memcpy(working_palette,Main.palette,sizeof(T_Palette));
2029           memcpy(Main.palette,temp_palette,sizeof(T_Palette));
2030         }
2031 
2032         Set_palette(working_palette);
2033         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2034 
2035         need_to_remap=1;
2036         break;
2037 
2038       case 17 : // [+]
2039        if (!Palette_view_is_RGB)
2040           break;
2041         Hide_cursor();
2042         Palette_edit_alter_channel();
2043         if (block_start==block_end)
2044         {
2045           if (red_slider->Position)
2046           {
2047             (red_slider->Position)--;
2048             Window_draw_slider(red_slider);
2049             Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette);
2050             Format_component(Color_max-red_slider->Position,str);
2051             Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
2052           }
2053           if (green_slider->Position)
2054           {
2055             (green_slider->Position)--;
2056             Window_draw_slider(green_slider);
2057             Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette);
2058             Format_component(Color_max-green_slider->Position,str);
2059             Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
2060           }
2061           if (blue_slider->Position)
2062           {
2063             (blue_slider->Position)--;
2064             Window_draw_slider(blue_slider);
2065             Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette);
2066             Format_component(Color_max-blue_slider->Position,str);
2067             Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
2068           }
2069         }
2070         else
2071         {
2072           if (red_slider->Position)
2073           {
2074             (red_slider->Position)--;
2075             Window_draw_slider(red_slider);
2076           }
2077           if (green_slider->Position)
2078           {
2079             (green_slider->Position)--;
2080             Window_draw_slider(green_slider);
2081           }
2082           if (blue_slider->Position)
2083           {
2084             (blue_slider->Position)--;
2085             Window_draw_slider(blue_slider);
2086           }
2087 
2088           for (i=block_start; i<=block_end; i++)
2089           {
2090             Set_red(i,Add_encoded(temp_palette[i].R, Color_max-red_slider->Position),working_palette);
2091             Set_green (i,Add_encoded(temp_palette[i].G, Color_max-green_slider->Position),working_palette);
2092             Set_blue (i,Add_encoded(temp_palette[i].B, Color_max-blue_slider->Position),working_palette);
2093           }
2094 
2095           // -- red --
2096           if (red_slider->Position>Color_max)
2097           {
2098             // Jauge dans les négatifs:
2099             Num2str(-(Color_max-red_slider->Position),str,4);
2100             str[0]='-';
2101           }
2102           else if (red_slider->Position<Color_max)
2103           {
2104             // Jauge dans les positifs:
2105             Num2str(  Color_max-red_slider->Position ,str,4);
2106             str[0]='+';
2107           }
2108           else
2109           {
2110             // Jauge nulle:
2111             strcpy(str,"\xb1  0");
2112           }
2113           Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
2114 
2115 
2116           // -- green --
2117           if (green_slider->Position>Color_max)
2118           {
2119             // Jauge dans les négatifs:
2120             Num2str(-(Color_max-green_slider->Position),str,4);
2121             str[0]='-';
2122           }
2123           else if (green_slider->Position<Color_max)
2124           {
2125             // Jauge dans les positifs:
2126             Num2str(  Color_max-green_slider->Position ,str,4);
2127             str[0]='+';
2128           }
2129           else
2130           {
2131             // Jauge nulle:
2132             strcpy(str,"\xb1  0");
2133           }
2134           Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
2135 
2136 
2137           // -- blue --
2138           if (blue_slider->Position>Color_max)
2139           {
2140             // Jauge dans les négatifs:
2141             Num2str(-(Color_max-blue_slider->Position),str,4);
2142             str[0]='-';
2143           }
2144           else if (blue_slider->Position<Color_max)
2145           {
2146             // Jauge dans les positifs:
2147             Num2str(  Color_max-blue_slider->Position ,str,4);
2148             str[0]='+';
2149           }
2150           else
2151           {
2152             // Jauge nulle:
2153             strcpy(str,"\xb1  0");
2154           }
2155           Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
2156         }
2157 
2158         need_to_remap=1;
2159 
2160         Display_cursor();
2161         Set_palette(working_palette);
2162         break;
2163 
2164       case 18 : // [-]
2165         if (!Palette_view_is_RGB)
2166           break;
2167         Hide_cursor();
2168         Palette_edit_alter_channel();
2169         if (block_start==block_end)
2170         {
2171           if (red_slider->Position<Color_max)
2172           {
2173             (red_slider->Position)++;
2174             Window_draw_slider(red_slider);
2175             Set_red(Fore_color,Decode_component(Color_max-red_slider->Position),working_palette);
2176             Format_component(Color_max-red_slider->Position,str);
2177             Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
2178           }
2179           if (green_slider->Position<Color_max)
2180           {
2181             (green_slider->Position)++;
2182             Window_draw_slider(green_slider);
2183             Set_green (Fore_color,Decode_component(Color_max-green_slider->Position),working_palette);
2184             Format_component(Color_max-green_slider->Position,str);
2185             Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
2186           }
2187           if (blue_slider->Position<Color_max)
2188           {
2189             (blue_slider->Position)++;
2190             Window_draw_slider(blue_slider);
2191             Set_blue (Fore_color,Decode_component(Color_max-blue_slider->Position),working_palette);
2192             Format_component(Color_max-blue_slider->Position,str);
2193             Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
2194           }
2195         }
2196         else
2197         {
2198           if (red_slider->Position<(Color_max*2))
2199           {
2200             (red_slider->Position)++;
2201             Window_draw_slider(red_slider);
2202           }
2203           if (green_slider->Position<(Color_max*2))
2204           {
2205             (green_slider->Position)++;
2206             Window_draw_slider(green_slider);
2207           }
2208           if (blue_slider->Position<(Color_max*2))
2209           {
2210             (blue_slider->Position)++;
2211             Window_draw_slider(blue_slider);
2212           }
2213 
2214           for (i=block_start; i<=block_end; i++)
2215           {
2216             Set_red(i,temp_palette[i].R+Decode_component(Color_max-red_slider->Position),working_palette);
2217             Set_green (i,temp_palette[i].G+Decode_component(Color_max-green_slider->Position),working_palette);
2218             Set_blue (i,temp_palette[i].B+Decode_component(Color_max-blue_slider->Position),working_palette);
2219           }
2220 
2221           // -- red --
2222           if (red_slider->Position>Color_max)
2223           {
2224             // Jauge dans les négatifs:
2225             Num2str(-(Color_max-red_slider->Position),str,4);
2226             str[0]='-';
2227           }
2228           else if (red_slider->Position<Color_max)
2229           {
2230             // Jauge dans les positifs:
2231             Num2str(  Color_max-red_slider->Position ,str,4);
2232             str[0]='+';
2233           }
2234           else
2235           {
2236             // Jauge nulle:
2237             strcpy(str,"\xb1  0");
2238           }
2239           Print_counter(NUMERIC_R_X,NUMERIC_Y,str,MC_Black,MC_Light);
2240 
2241 
2242           // -- green --
2243           if (green_slider->Position>Color_max)
2244           {
2245             // Jauge dans les négatifs:
2246             Num2str(-(Color_max-green_slider->Position),str,4);
2247             str[0]='-';
2248           }
2249           else if (green_slider->Position<Color_max)
2250           {
2251             // Jauge dans les positifs:
2252             Num2str(  Color_max-green_slider->Position ,str,4);
2253             str[0]='+';
2254           }
2255           else
2256           {
2257             // Jauge nulle:
2258             strcpy(str,"\xb1  0");
2259           }
2260           Print_counter(NUMERIC_G_X,NUMERIC_Y,str,MC_Black,MC_Light);
2261 
2262 
2263           // -- blue --
2264           if (blue_slider->Position>Color_max)
2265           {
2266             // Jauge dans les négatifs:
2267             Num2str(-(Color_max-blue_slider->Position),str,4);
2268             str[0]='-';
2269           }
2270           else if (blue_slider->Position<Color_max)
2271           {
2272             // Jauge dans les positifs:
2273             Num2str(  Color_max-blue_slider->Position ,str,4);
2274             str[0]='+';
2275           }
2276           else
2277           {
2278             // Jauge nulle:
2279             strcpy(str,"\xb1  0");
2280           }
2281           Print_counter(NUMERIC_B_X,NUMERIC_Y,str,MC_Black,MC_Light);
2282         }
2283 
2284         need_to_remap=1;
2285 
2286         Display_cursor();
2287         Set_palette(working_palette);
2288         break;
2289 
2290       case 19 : // Negative
2291         // Backup
2292         Palette_edit_step();
2293         // Negative
2294         for (i=block_start;i<=block_end;i++)
2295         {
2296           Set_red(i,255-working_palette[i].R,working_palette);
2297           Set_green (i,255-working_palette[i].G,working_palette);
2298           Set_blue (i,255-working_palette[i].B,working_palette);
2299         }
2300         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2301         Set_palette(working_palette);
2302         // On prépare la "modifiabilité" des nouvelles couleurs
2303         memcpy(temp_palette,working_palette,sizeof(T_Palette));
2304 
2305         need_to_remap=1;
2306         break;
2307 
2308       case 20 : // Inversion
2309       case 21 : // X-Inversion
2310         // Backup
2311         Palette_edit_step(); // Not undoable if X-Invert
2312         //   On initialise la table de conversion
2313         for (i=0; i<=255; i++)
2314           conversion_table[i]=i;
2315         // Inversion
2316         for (i=block_start; i < block_start + (block_end-block_start+1)/2;i++)
2317         {
2318           temp_color=block_end-(i-block_start);
2319 
2320           Set_red   (i,backup_palette[temp_color].R,working_palette);
2321           Set_green (i,backup_palette[temp_color].G,working_palette);
2322           Set_blue  (i,backup_palette[temp_color].B,working_palette);
2323           Set_red   (temp_color,backup_palette[i].R,working_palette);
2324           Set_green (temp_color,backup_palette[i].G,working_palette);
2325           Set_blue  (temp_color,backup_palette[i].B,working_palette);
2326 
2327           if (clicked_button==21)
2328           {
2329             conversion_table[i]=temp_color;
2330             conversion_table[temp_color]=i;
2331 
2332             temp=color_usage[i];
2333             color_usage[i]=color_usage[temp_color];
2334             color_usage[temp_color]=temp;
2335           }
2336         }
2337         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2338         // Si on est en X-Invert, on remap l'image (=> on fait aussi 1 backup)
2339         if (clicked_button==21)
2340         {
2341           if (!image_is_backed_up)
2342           {
2343             Backup_layers(LAYER_ALL);
2344             image_is_backed_up=1;
2345           }
2346           Hide_cursor();
2347           Remap_image_highlevel(conversion_table);
2348           Display_cursor();
2349           End_of_modification();
2350           Palette_edit_step(); // Disable Undo
2351         }
2352         // On prépare la "modifiabilité" des nouvelles couleurs
2353         Set_palette(working_palette);
2354         memcpy(temp_palette,working_palette,sizeof(T_Palette));
2355 
2356         need_to_remap=1;
2357         break;
2358 
2359       case 22 : // HSL <> RGB
2360 
2361         // Acte les changements en cours sur une ou plusieurs couleurs
2362         Palette_edit_select_range();
2363 
2364         Hide_cursor();
2365 
2366         Palette_view_is_RGB = !Palette_view_is_RGB;
2367         if(! Palette_view_is_RGB)
2368         {
2369           // On passe en HSL
2370           Print_RGB_or_HSL(1);
2371           Component_unit(256);
2372 
2373           // Display the + and - button as disabled
2374           Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,0);
2375           Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,0);
2376         }
2377         else
2378         {
2379           // On passe en RGB
2380           Print_RGB_or_HSL(0);
2381           Component_unit(RGB_scale);
2382 
2383           // Display the + and - button as enabled
2384           Window_draw_normal_bouton(BUTTON_PLUS_X, BUTTON_PLUS_Y,12,11,"+",0,1);
2385           Window_draw_normal_bouton(BUTTON_MINUS_X,BUTTON_MINUS_Y,12,11,"-",0,1);
2386         }
2387         Display_sliders(red_slider,green_slider,blue_slider,(block_start!=block_end),working_palette);
2388 
2389         Display_cursor();
2390 
2391         Update_window_area(BUTTON_PLUS_X-1,BUTTON_PLUS_Y-1,14,14);
2392         Update_window_area(BUTTON_MINUS_X-1,BUTTON_MINUS_Y-1,14,14);
2393       break;
2394 
2395       case 23 : // Sort palette
2396       {
2397         byte h = 0, l = 0, s=0;
2398         byte oh=0,ol=0,os=0; // Valeur pour la couleur précédente
2399         int swap=1;
2400         byte remap_table[256];
2401         byte inverted_table[256];
2402         byte begin, end;
2403         long lightness;
2404         long old_lightness;
2405 
2406 
2407         if(block_start==block_end)
2408         {
2409             begin = 0;
2410             end = 255;
2411         }
2412         else
2413         {
2414             begin = block_start;
2415             end = block_end;
2416         }
2417 
2418         // Init remap table
2419         for (i=0;i<256;i++)
2420           remap_table[i]=i;
2421         // Make a backup because remapping is an undoable modification
2422         if (!image_is_backed_up)
2423         {
2424           Backup_layers(LAYER_ALL);
2425           image_is_backed_up=1;
2426         }
2427 
2428         if(Window_attribute2==0)
2429         // Sort by Hue (H) and Lightness (L)
2430         while(swap==1)
2431         {
2432           swap=0;
2433           h=0;l=255;s=0;
2434           for(temp_color=begin;temp_color<=end;temp_color++)
2435           {
2436             oh=h; ol=l; os=s;
2437             RGB_to_HSL(working_palette[temp_color].R,
2438             working_palette[temp_color].G,
2439             working_palette[temp_color].B,&h,&s,&l);
2440 
2441             if(
2442                    ((s==0) && (os>0)) // A grey is before a saturated color
2443               || ((s>0 && os > 0) && (h<oh || (h==oh && l>ol))) // 2 saturated colors: sort by H, then by L
2444               || ((os==0 && s==0) && l>ol))  // Two greys: sort by L only
2445             {
2446               // Swap color with the previous one
2447               SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R)
2448               SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G)
2449               SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B)
2450 
2451               SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1])
2452 
2453               SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1])
2454 
2455               swap=1;
2456             }
2457           }
2458         }
2459 
2460         else if(Window_attribute2==1) // Sort only on perceived lightness
2461         while(swap==1)
2462         {
2463           swap=0;
2464           lightness=Perceptual_lightness(working_palette+begin);
2465           for(temp_color=begin+1;temp_color<=end;temp_color++)
2466           {
2467             old_lightness=lightness;
2468             lightness=Perceptual_lightness(working_palette+temp_color);
2469 
2470             if(lightness>old_lightness)
2471             {
2472               // Swap color with the previous one
2473               SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R)
2474               SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G)
2475               SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B)
2476 
2477               SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1])
2478 
2479               SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1])
2480 
2481               swap=1;
2482             }
2483           }
2484         }
2485 
2486         else // Sort by color usage in histogram
2487         while(swap==1)
2488         {
2489           swap=0;
2490           lightness=color_usage[begin];
2491           for(temp_color=begin+1;temp_color<=end;temp_color++)
2492           {
2493             old_lightness=lightness;
2494             lightness=color_usage[temp_color];
2495 
2496             if(lightness>old_lightness)
2497             {
2498               // Swap color with the previous one
2499               SWAP_BYTES(working_palette[temp_color].R, working_palette[temp_color-1].R)
2500               SWAP_BYTES(working_palette[temp_color].G, working_palette[temp_color-1].G)
2501               SWAP_BYTES(working_palette[temp_color].B, working_palette[temp_color-1].B)
2502 
2503               SWAP_DWORDS(color_usage[temp_color], color_usage[temp_color-1])
2504 
2505               SWAP_BYTES(remap_table[temp_color], remap_table[temp_color-1])
2506 
2507               swap=1;
2508             }
2509           }
2510         }
2511 
2512         for (i=0;i<256;i++)
2513           inverted_table[remap_table[i]]=i;
2514         Remap_image_highlevel(inverted_table);
2515         // Maintenant, tous ces calculs doivent êtres pris en compte dans la
2516         // palette, l'image et à l'écran.
2517         Set_palette(working_palette);
2518         Palette_edit_step(); // Disable Undo
2519 
2520         End_of_modification();
2521         need_to_remap=1;
2522       }
2523       break;
2524       case 24: // R G B value: Hex entry
2525       {
2526         char str[7];
2527         unsigned int new_color;
2528 
2529         Hide_cursor();
2530         Print_in_window(NUMERIC_BOX_X+2,NUMERIC_BOX_Y+2,"Hex",MC_Black,MC_Light);
2531         // Clear out remaining area
2532         Window_rectangle(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3,MC_Light);
2533         Update_window_area(NUMERIC_BOX_X+1+3*8,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-3-3*8, NUMERIC_BOX_H-3);
2534 
2535         str[0]='\0';
2536         Display_cursor();
2537         if (Readline(NUMERIC_BOX_X+NUMERIC_BOX_W-2-6*8, NUMERIC_BOX_Y+2, str, 6, INPUT_TYPE_HEXA))
2538         {
2539           int length = strlen(str);
2540           short new_red, new_blue, new_green;
2541 
2542           if (length==3 || length==6)
2543           {
2544             sscanf(str, "%x", &new_color);
2545             if (length==3)
2546             {
2547               new_color =
2548                 ((new_color&0xF00)*0x1100) |
2549                 ((new_color&0x0F0)*0x110) |
2550                 ((new_color&0x00F)*0x11);
2551             }
2552             new_red=(new_color&0xFF0000) >> 16;
2553             new_green=(new_color&0x00FF00) >> 8;
2554             new_blue=(new_color&0x0000FF);
2555 
2556             // Backup
2557             Palette_edit_step();
2558             // Assign color
2559             for (i=block_start;i<=block_end;i++)
2560             {
2561               Set_red(i,new_red,working_palette);
2562               Set_green (i,new_green,working_palette);
2563               Set_blue (i,new_blue,working_palette);
2564             }
2565             // On prépare la "modifiabilité" des nouvelles couleurs
2566             Set_palette(working_palette);
2567             memcpy(temp_palette,working_palette,sizeof(T_Palette));
2568             need_to_remap=1;
2569           }
2570         }
2571         // Clear out numeric area
2572         Window_rectangle(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2,MC_Light);
2573         Update_window_area(NUMERIC_BOX_X+1,NUMERIC_BOX_Y+1,NUMERIC_BOX_W-2, NUMERIC_BOX_H-2);
2574         Display_cursor();
2575         Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2576       }
2577       break;
2578 
2579       case 25: // Number of colors used: Open histogram
2580       {
2581         int selected_col;
2582 
2583         selected_col=Window_Histogram(block_start, block_end, color_usage);
2584         if (selected_col!=-1)
2585         {
2586           // Tag selected color
2587           Fore_color=first_color=last_color=block_start=block_end=selected_col;
2588           Tag_color_range(block_start,block_end);
2589 
2590           // Affichage du n° de la couleur sélectionnée
2591           Window_rectangle(COLOR_X,COLOR_Y,56,7,MC_Light);
2592           Num2str(Fore_color,str,3);
2593           Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
2594           Update_window_area(COLOR_X,COLOR_Y,56,7);
2595 
2596           // Affichage des jauges
2597           Window_rectangle(NUMERIC_R_X,NUMERIC_Y,72,7,MC_Light);
2598           Display_sliders(red_slider,green_slider,blue_slider,0,working_palette);
2599 
2600           // Affichage dans le block de visu de la couleur en cours
2601           Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
2602           Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
2603 
2604           Palette_edit_select_range();
2605 
2606         }
2607         Display_cursor();
2608         Input_sticky_control=0;
2609         Wait_end_of_click();
2610         break;
2611       }
2612 
2613       case 26: // Load palette
2614         memcpy(backup_palette, Main.palette, sizeof(T_Palette));
2615         memcpy(Main.palette, working_palette, sizeof(T_Palette));
2616         Load_picture(CONTEXT_PALETTE);
2617         memcpy(working_palette, Main.palette, sizeof(T_Palette));
2618         Set_palette(working_palette);
2619         memcpy(temp_palette,working_palette,sizeof(T_Palette));
2620         memcpy(Main.palette, backup_palette, sizeof(T_Palette));
2621         need_to_remap=1;
2622         break;
2623 
2624       case 27: // Save palette
2625         // Save the working palette (the one currently being edited)
2626         memcpy(backup_palette, Main.palette, sizeof(T_Palette));
2627         memcpy(Main.palette, working_palette, sizeof(T_Palette));
2628         Save_picture(CONTEXT_PALETTE);
2629         memcpy(Main.palette, backup_palette, sizeof(T_Palette));
2630         need_to_remap=1;
2631         break;
2632 
2633       case 28:  // EHB : Amiga Extra Half Bright
2634         for (i = 0; i < 32; i++)
2635         {
2636           working_palette[i+32].R = working_palette[i].R >> 1;
2637           working_palette[i+32].G = working_palette[i].G >> 1;
2638           working_palette[i+32].B = working_palette[i].B >> 1;
2639         }
2640         Set_palette(working_palette);
2641         break;
2642     }
2643 
2644 
2645     if (!Mouse_K)
2646     {
2647       if (Key)
2648       {
2649         if (Is_shortcut(Key,SPECIAL_PREVIOUS_FORECOLOR)) // Décaler Forecolor vers la gauche
2650         {
2651           if (block_start==block_end)
2652           {
2653             Fore_color--;
2654             first_color--;
2655             last_color--;
2656             block_start--;
2657             block_end--;
2658             Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2659             Hide_cursor();
2660             Tag_color_range(block_start,block_end);
2661             // Affichage du n° de la couleur sélectionnée
2662             Num2str(Fore_color,str,3);
2663             Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
2664             // Affichage dans le block de visu de la couleur en cours
2665             Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
2666             Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
2667             Display_cursor();
2668           }
2669           Key=0;
2670         }
2671         else if (Is_shortcut(Key,SPECIAL_NEXT_FORECOLOR)) // Décaler Forecolor vers la droite
2672         {
2673           if (block_start==block_end)
2674           {
2675             Fore_color++;
2676             first_color++;
2677             last_color++;
2678             block_start++;
2679             block_end++;
2680             Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2681             Hide_cursor();
2682             Tag_color_range(block_start,block_end);
2683             // Affichage du n° de la couleur sélectionnée
2684             Num2str(Fore_color,str,3);
2685             Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
2686             // Affichage dans le block de visu de la couleur en cours
2687             Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
2688             Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
2689             Display_cursor();
2690           }
2691           Key=0;
2692         }
2693         else if (Is_shortcut(Key,SPECIAL_PREVIOUS_BACKCOLOR))
2694         {
2695           Back_color--;
2696           Hide_cursor();
2697           Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color);
2698           Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color);
2699           Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color);
2700           Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color);
2701           Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
2702           Display_cursor();
2703           Key=0;
2704         }
2705         else if (Is_shortcut(Key,SPECIAL_NEXT_BACKCOLOR))
2706         {
2707           Back_color++;
2708           Hide_cursor();
2709           Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color);
2710           Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color);
2711           Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color);
2712           Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color);
2713           Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
2714           Display_cursor();
2715           Key=0;
2716         }
2717         else if (Key == KEY_BACKSPACE)
2718         // Remise des couleurs du menu à l'état normal en essayant
2719         // de ne pas trop modifier l'image.
2720         {
2721           if (!image_is_backed_up)
2722           {
2723             Backup_layers(LAYER_ALL);
2724             image_is_backed_up=1;
2725           }
2726           if (used_colors==-1)
2727             Update_color_count(&used_colors, color_usage);
2728 
2729           Palette_edit_step();
2730           memcpy(temp_palette,Main.palette,sizeof(T_Palette));
2731           memcpy(Main.palette,working_palette,sizeof(T_Palette));
2732           Set_nice_menu_colors(color_usage,0);
2733           memcpy(working_palette,Main.palette,sizeof(T_Palette));
2734           memcpy(Main.palette,temp_palette,sizeof(T_Palette));
2735           Set_palette(working_palette);
2736           memcpy(temp_palette,working_palette,sizeof(T_Palette));
2737           Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2738           Update_color_count(&used_colors,color_usage);
2739           // End_of_modification();
2740           // Not really needed, the change was in palette entries
2741           need_to_remap=1;
2742           Key=0;
2743         }
2744         else if (Is_shortcut(Key,0x100+BUTTON_COLORPICKER))
2745         {
2746           // Récupération d'une couleur derrière le menu
2747           Get_color_behind_window(&color,&click);
2748           if (click)
2749           {
2750             Hide_cursor();
2751             if (click==RIGHT_SIDE)
2752             {
2753               if (Back_color!=color)
2754               {
2755                 Back_color=color;
2756                 // 4 blocks de back_color entourant la fore_color
2757                 Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y-BGCOLOR_DISPLAY_Y,Back_color);
2758                 Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y+FGCOLOR_DISPLAY_H,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_Y+BGCOLOR_DISPLAY_H-FGCOLOR_DISPLAY_Y-FGCOLOR_DISPLAY_H,Back_color);
2759                 Window_rectangle(BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_X-BGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_H,Back_color);
2760                 Window_rectangle(FGCOLOR_DISPLAY_X+FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_X+BGCOLOR_DISPLAY_W-FGCOLOR_DISPLAY_X-FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Back_color);
2761                 Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
2762               }
2763             }
2764             else
2765             {
2766               Fore_color=first_color=last_color=block_start=block_end=color;
2767               Tag_color_range(block_start,block_end);
2768 
2769               // Affichage du n° de la couleur sélectionnée
2770               Window_rectangle(COLOR_X+24,COLOR_Y,32,7,MC_Light);
2771               Update_window_area(COLOR_X+24,COLOR_Y,32,7);
2772               Num2str(Fore_color,str,3);
2773               Print_in_window(COLOR_X,COLOR_Y,str,MC_Black,MC_Light);
2774 
2775               // Affichage des jauges
2776               Display_sliders(red_slider,green_slider,blue_slider,0,working_palette);
2777 
2778               // Affichage dans le block de visu de la couleur en cours
2779               Window_rectangle(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,Fore_color);
2780               Update_window_area(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H);
2781 
2782               Palette_edit_select_range();
2783             }
2784             Display_cursor();
2785             Wait_end_of_click();
2786           }
2787           Key=0;
2788         }
2789         else if (Is_shortcut(Key,0x100+BUTTON_HELP))
2790         {
2791           Key=0;
2792           Window_help(BUTTON_PALETTE, NULL);
2793         }
2794         else if (Is_shortcut(Key,0x100+BUTTON_PALETTE))
2795         {
2796           // Close (confirm)
2797           clicked_button=14;
2798         }
2799         else if (Key == SHORTCUT_COPY)
2800         {
2801           Set_clipboard_colors(block_end+1-block_start,working_palette + block_start);
2802         }
2803         else if (Key == SHORTCUT_PASTE)
2804         {
2805           int nb_colors;
2806 
2807           Hide_cursor();
2808           // Backup
2809           Palette_edit_step();
2810 
2811           nb_colors = Get_clipboard_colors(working_palette, block_start);
2812           if (nb_colors>0)
2813           {
2814             memcpy(temp_palette,working_palette,sizeof(T_Palette));
2815             Set_palette(working_palette);
2816             need_to_remap=1;
2817             Display_cursor();
2818             Draw_all_palette_sliders(red_slider,green_slider,blue_slider,working_palette,block_start,block_end);
2819           }
2820         }
2821       }
2822 
2823       if (need_to_remap)
2824       {
2825         Hide_cursor();
2826         Compute_optimal_menu_colors(working_palette);
2827 
2828         // On remappe brutalement
2829         Remap_screen_after_menu_colors_change();
2830         // Puis on remet les trucs qui ne devaient pas changer
2831         Window_draw_palette_bouton(5,89);
2832         if (show_used_colors)
2833           Tag_used_colors(1, color_usage);
2834         Window_rectangle(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H,Back_color);
2835         Update_window_area(BGCOLOR_DISPLAY_X,BGCOLOR_DISPLAY_Y,BGCOLOR_DISPLAY_W,BGCOLOR_DISPLAY_H);
2836 
2837         Display_grad_block_in_window(FGCOLOR_DISPLAY_X,FGCOLOR_DISPLAY_Y,FGCOLOR_DISPLAY_W,FGCOLOR_DISPLAY_H,block_start,block_end);
2838 
2839         Update_window_area(8,82,16*10,5*16);
2840 
2841         Display_cursor();
2842         need_to_remap=0;
2843       }
2844     }
2845   }
2846   while ((clicked_button!=13) && (clicked_button!=14) && !Quit_is_required);
2847 
2848   if (clicked_button==14)         // Sortie par OK
2849   {
2850     if ( (!image_is_backed_up)
2851       && memcmp(Main.palette,working_palette,sizeof(T_Palette)) )
2852       Backup_layers(LAYER_NONE);
2853     memcpy(Main.palette,working_palette,sizeof(T_Palette));
2854     End_of_modification();
2855     // Not really needed, the change was in palette entries
2856   }
2857 
2858   Compute_optimal_menu_colors(Main.palette);
2859 
2860   // La variable employée ici n'a pas vraiment de rapport avec son nom...
2861   need_to_remap=(Window_pos_Y+(Window_height*Menu_factor_Y)<Menu_Y_before_window);
2862 
2863   Close_window();
2864   Unselect_button(BUTTON_PALETTE);
2865 
2866   Reposition_palette();
2867 
2868   //   On affiche les "ForeBack" car le menu n'est raffiché que si la fenêtre
2869   // empiétait sur le menu. Mais si les couleurs on été modifiées, il faut
2870   // rafficher tout le menu remappé.
2871   if (need_to_remap)
2872     Display_menu();
2873 
2874   Display_cursor();
2875 
2876   if (clicked_button==13 || Quit_is_required)  // CANCEL was clicked
2877   {
2878     Set_palette(Main.palette);
2879     if (image_is_backed_up)
2880       Select_button(BUTTON_UNDO,LEFT_SIDE);
2881   }
2882 
2883   free(backup_palette);
2884   free(temp_palette);
2885   free(working_palette);
2886   backup_palette = temp_palette = working_palette = NULL;
2887 }
2888 
2889 
2890 //---------------------- Menu de palettes secondaires ------------------------
2891 
Button_Secondary_palette(int btn)2892 void Button_Secondary_palette(int btn)
2893 {
2894   short clicked_button;
2895   byte dummy;
2896   T_Scroller_button * columns_slider;
2897   T_Scroller_button * lines_slider;
2898   T_Scroller_button * rgb_scale_slider;
2899   T_Scroller_button * gamma_slider;
2900   char str[8];
2901   byte palette_vertical = Config.Palette_vertical;
2902   byte palette_cols, palette_lines;
2903   word rgb_scale;
2904   float gamma;
2905   byte palette_needs_redraw=0;
2906 
2907   static const int RGBScale_X = 161;
2908   static const int RGBScale_Y = 85;
2909 
2910   (void)btn;
2911   Open_window(218,146,"Palettes");
2912 
2913   Window_set_normal_button(10,20,180,14,"Colors for best match",12,1,KEY_b); // 1
2914   Window_set_normal_button(10,37,180,14,"User's color series"  ,14,1,KEY_s); // 2
2915   Window_set_normal_button(155,126,53,14,"OK"                  , 0,1,KEY_RETURN); // 3
2916   Window_set_normal_button( 96,126,53,14,"Cancel"              , 0,1,KEY_ESC); // 4
2917   Window_display_frame(10,55,122,66);
2918   Print_in_window(18,59,"Palette layout",MC_Dark,MC_Light);
2919   Print_in_window(35,77,"Cols",MC_Dark,MC_Light);
2920   Print_in_window(84,77,"Lines",MC_Dark,MC_Light);
2921 
2922   Print_in_window(137,57,"RGB Scale",MC_Dark,MC_Light);
2923   Print_in_window(137,99,"Gamma",MC_Dark,MC_Light);
2924 
2925   columns_slider = Window_set_scroller_button(19,72,29,255,1,256-Config.Palette_cells_X);// 5
2926   Num2str(Config.Palette_cells_X,str,3);
2927   Print_in_window(38,89,str,MC_Black,MC_Light);
2928 
2929   lines_slider = Window_set_scroller_button(70,72,29,15,1,16-Config.Palette_cells_Y);// 6
2930   Num2str(Config.Palette_cells_Y,str,3);
2931   Print_in_window(94,89,str,MC_Black,MC_Light);
2932 
2933   rgb_scale_slider = Window_set_horizontal_scroller_button(137,68,71,255,1,RGB_scale);// 7
2934   Num2str(RGB_scale,str,3);
2935   Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light);
2936 
2937   Window_set_normal_button(35,106,13,11,"",-1,1,KEY_NONE); // 8
2938   Print_in_window(38,108,(palette_vertical)?"X":" ",MC_Black,MC_Light);
2939   Print_in_window(51,108,"Vertical",MC_Dark,MC_Light);
2940 
2941   Window_set_normal_button(190,82,18,14,"x2"                  , 1,1,KEY_x); // 9
2942   Window_set_normal_button(137,82,18,14,"\xf7""2"             , 0,1,KEY_w); // 10
2943 
2944   gamma_slider = Window_set_horizontal_scroller_button(137,110,71,30, 1,Gamma*10);// 11
2945   Num2str(Gamma*10,str,2);
2946   Print_in_window(178,99,str,MC_Black,MC_Light);
2947 
2948   // I'm too lazy to format the number with a comma...
2949   Pixel_in_window(185,107,MC_Black);
2950   Pixel_in_window(184,108,MC_Black);
2951 
2952   Update_window_area(0,0,230,146);
2953 
2954   Display_cursor();
2955 
2956   do
2957   {
2958     clicked_button=Window_clicked_button();
2959     if (Is_shortcut(Key,0x100+BUTTON_HELP))
2960     {
2961       Key=0;
2962       Window_help(BUTTON_PALETTE, "PALETTE OPTIONS");
2963     }
2964     else if (Is_shortcut(Key,0x200+BUTTON_PALETTE))
2965       clicked_button=3;
2966 
2967     switch(clicked_button)
2968     {
2969       case 5:
2970         // Column slider
2971         Num2str(256-Window_attribute2,str,3);
2972         Print_in_window(38,89,str,MC_Black,MC_Light);
2973         break;
2974       case 6:
2975         // Line slider
2976         Num2str(16-Window_attribute2,str,3);
2977         Print_in_window(94,89,str,MC_Black,MC_Light);
2978         break;
2979       case 7:
2980         // RGB scale slider
2981         Num2str(Window_attribute2,str,3);
2982         Hide_cursor();
2983         Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light);
2984         Display_cursor();
2985         break;
2986       case 8:
2987         // Vertical switch
2988         palette_vertical = !palette_vertical;
2989         Hide_cursor();
2990         Print_in_window(38,108,(palette_vertical)?"X":" ",MC_Black,MC_Light);
2991         Display_cursor();
2992         break;
2993 
2994       case 9:
2995         // x2 RGB scale
2996         rgb_scale_slider->Position = (rgb_scale_slider->Position < 128)
2997             ? rgb_scale_slider->Position * 2
2998             : 256;
2999         Num2str(rgb_scale_slider->Position,str,3);
3000         Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light);
3001         Window_draw_slider(rgb_scale_slider);
3002         break;
3003 
3004       case 10:
3005         // /2 RGB scale
3006         rgb_scale_slider->Position = (rgb_scale_slider->Position <= 2)
3007             ? 1
3008             : (rgb_scale_slider->Position)/2;
3009         Num2str(rgb_scale_slider->Position,str,3);
3010         Print_in_window(RGBScale_X,RGBScale_Y,str,MC_Black,MC_Light);
3011         Window_draw_slider(rgb_scale_slider);
3012         break;
3013 
3014       case 11:
3015         // Gamma slider
3016         Num2str(Window_attribute2,str,2);
3017         Hide_cursor();
3018         Print_in_window(178,99,str,MC_Black,MC_Light);
3019         Display_cursor();
3020         break;
3021     }
3022   }
3023   while ((clicked_button <= 0 || clicked_button >= 5) && !Quit_is_required);
3024 
3025   // We need to get the sliders positions before closing the window, because they will be freed.
3026   palette_cols=256-columns_slider->Position;
3027   palette_lines=16-lines_slider->Position;
3028   rgb_scale=rgb_scale_slider->Position;
3029   gamma=gamma_slider->Position/10.f;
3030 
3031   Close_window();
3032   Unselect_button(BUTTON_PALETTE);
3033   Display_cursor();
3034 
3035   if (clicked_button==4 || Quit_is_required) // Cancel
3036     return;
3037 
3038   if (palette_vertical != Config.Palette_vertical)
3039   {
3040     Config.Palette_vertical=palette_vertical;
3041     palette_needs_redraw=1;
3042   }
3043   if (palette_cols!=Config.Palette_cells_X ||
3044     palette_lines!=Config.Palette_cells_Y)
3045   {
3046     Config.Palette_cells_X = palette_cols;
3047     Config.Palette_cells_Y = palette_lines;
3048     palette_needs_redraw=1;
3049   }
3050   if (rgb_scale!=RGB_scale || gamma != Gamma)
3051   {
3052     Gamma = gamma;
3053     Set_palette_RGB_scale(rgb_scale);
3054     Set_palette(Main.palette);
3055     Compute_optimal_menu_colors(Main.palette);
3056   }
3057 
3058   if (clicked_button==1)
3059   {
3060     Menu_tag_colors("Tag colors to exclude",Exclude_color,&dummy,1, NULL, SPECIAL_EXCLUDE_COLORS_MENU);
3061   }
3062   else if (clicked_button==2)
3063   {
3064     // Open the menu with Shade settings. Same as the shortcut, except
3065     // that this will not activate shade mode on exit.
3066     Shade_settings_menu();
3067   }
3068 
3069   if (palette_needs_redraw)
3070   {
3071     Change_palette_cells();
3072     Display_menu();
3073     Display_sprite_in_menu(BUTTON_PAL_LEFT,Config.Palette_vertical?MENU_SPRITE_VERTICAL_PALETTE_SCROLL:-1);
3074     Draw_menu_button(BUTTON_PAL_LEFT,BUTTON_RELEASED);
3075     Draw_menu_button(BUTTON_PAL_RIGHT,BUTTON_RELEASED);
3076   }
3077 }
3078 
3079 // ========= Clipboard management ==============
3080 
3081 int Palette_clipboard_count=0;
3082 T_Palette Palette_clipboard;
3083 
3084 /// Put some colors in the clipboard.
3085 /// @param nb_colors Number of colors to push
3086 /// @param colors First color of the input array
Set_clipboard_colors(int nb_colors,T_Components * colors)3087 void Set_clipboard_colors(int nb_colors, T_Components *colors)
3088 {
3089   Palette_clipboard_count=nb_colors;
3090   if (nb_colors)
3091   {
3092     memcpy(Palette_clipboard, colors, nb_colors*sizeof(T_Components));
3093   }
3094 }
3095 
3096 /// Get some RGB colors from clipboard.
3097 /// @param palette Target palette
3098 /// @param start_color  Index of first color to replace
3099 /// @return        Number of colors retrieved (0-256)
Get_clipboard_colors(T_Palette palette,byte start_color)3100 int Get_clipboard_colors(T_Palette palette, byte start_color)
3101 {
3102   int nb_colors = Palette_clipboard_count;
3103 
3104   if (nb_colors==0)
3105     return 0;
3106 
3107   if (start_color+nb_colors > 256)
3108   {
3109     nb_colors=256-start_color;
3110   }
3111   memcpy(palette+start_color, Palette_clipboard, nb_colors*sizeof(T_Components));
3112   return nb_colors;
3113 }
3114 
3115 /// Get the favorite color to use for GUI's black,dark,light or white.
Favorite_GUI_color(byte color_index)3116 const T_Components * Favorite_GUI_color(byte color_index)
3117 {
3118   static const T_Components cpc_colors[4] = {
3119     {  0,  0,  0},
3120     {  0,  0,128}, // Dark blue
3121     {128,128,128}, // Grey
3122     {255,255,255}
3123   };
3124 
3125   if (RGB_scale==3)
3126   {
3127     // Check if ALL GUI colors are compatible with /rgb 3
3128     int i;
3129     for (i=0; i<4; i++)
3130     {
3131       T_Components col;
3132       col=Gfx->Default_palette[Gfx->Color[i]];
3133       if ((col.R!=255 && col.R!=128 && col.R!=0)
3134         ||(col.G!=255 && col.G!=128 && col.G!=0)
3135         ||(col.B!=255 && col.B!=128 && col.B!=0))
3136         // Specialized colors for CPC palette
3137         return &cpc_colors[color_index];
3138     }
3139     // Skin has suitable colors
3140     return &(Gfx->Default_palette[Gfx->Color[color_index]]);
3141   }
3142   else
3143     // Should be Config.Fav_menu_colors[index] if using user colors
3144       return &(Gfx->Default_palette[Gfx->Color[color_index]]);
3145 }
3146 
3147