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