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 <string.h>
21 #include <stdlib.h>
22 
23 #include "global.h"
24 #include "graph.h"
25 #include "engine.h"
26 #include "errors.h"
27 #include "misc.h"
28 #include "readline.h"
29 #include "help.h"
30 #include "screen.h"
31 #include "windows.h"
32 #include "input.h"
33 #include "shade.h"
34 #include "keycodes.h"
35 
Button_Shade_mode(void)36 void Button_Shade_mode(void)
37 {
38   if (Shade_mode)
39     Effect_function=No_effect;
40   else
41   {
42     Effect_function=Effect_shade;
43     Quick_shade_mode=0;
44     Colorize_mode=0;
45     Smooth_mode=0;
46     Tiling_mode=0;
47     Smear_mode=0;
48   }
49   Shade_mode=!Shade_mode;
50 }
51 
52 
Button_Quick_shade_mode(void)53 void Button_Quick_shade_mode(void)
54 {
55   if (Quick_shade_mode)
56     Effect_function=No_effect;
57   else
58   {
59     Effect_function=Effect_quick_shade;
60     Shade_mode=0;
61     Colorize_mode=0;
62     Smooth_mode=0;
63     Tiling_mode=0;
64     Smear_mode=0;
65   }
66   Quick_shade_mode=!Quick_shade_mode;
67 }
68 
69 
Shade_draw_grad_ranges(void)70 void Shade_draw_grad_ranges(void)
71 {
72   word  cursor=0;
73   word  nb_shades=0;
74   short shade_processed,shade_processed_old;
75   word  shade_size=0;
76   word  start_shade=0;
77   short x_pos,y_pos;
78   short x_size,y_size;
79   short start_x,start_y,end_x,end_y;
80 
81   // On commence par compter le nombre de shades
82   while (cursor<512)
83   {
84     while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00))
85       cursor++;
86 
87     if (cursor<512)
88     {
89       nb_shades++;
90       while ( (cursor<512)
91          && (!(Shade_list[Shade_current].List[cursor]&0xFF00)) )
92         cursor++;
93     }
94   }
95 
96   // Maintenant qu'on sait combien il y en a, on les affiche:
97   if (nb_shades)
98   {
99     x_size=Menu_factor_X<<6;
100     y_size=Menu_factor_Y*48;
101     start_x=Window_pos_X+(Menu_factor_X*224);
102     start_y=Window_pos_Y+(Menu_factor_Y*35);
103     end_x=start_x+x_size;
104     end_y=start_y+y_size;
105 
106     cursor=0;
107     shade_processed_old=-1;
108 
109     for (y_pos=start_y;y_pos<end_y;y_pos++)
110     {
111       // On regarde quel shade on va afficher en preview
112       shade_processed=((y_pos-start_y)*nb_shades)/y_size;
113       // Si ce n'est pas le shade précédemment traité on calcule ses infos
114       if (shade_processed>shade_processed_old)
115       {
116         // On commence par sauter tous les vides jusqu'au prochain shade
117         while ((cursor<512) && (Shade_list[Shade_current].List[cursor]&0xFF00))
118           cursor++;
119         start_shade=cursor;
120         // puis regarde sa taille
121         while ((cursor<512) && (!(Shade_list[Shade_current].List[cursor]&0xFF00)))
122           cursor++;
123         shade_size=cursor-start_shade;
124         shade_processed_old=shade_processed;
125       }
126 
127       for (x_pos=start_x;x_pos<end_x;x_pos++)
128       {
129         Pixel(x_pos,y_pos,Shade_list[Shade_current].List
130               [(((x_pos-start_x)*shade_size)/x_size)+start_shade]);
131       }
132     }
133   }
134   else
135   {
136     Window_display_frame_out(224,35,64,48);
137     Window_rectangle(225,36,62,46,MC_Light);
138   }
139   Update_window_area(224,35,64,48);
140 }
141 
142 
Tag_shades(word selection_start,word selection_end)143 void Tag_shades(word selection_start,word selection_end)
144 {
145   word line, column;
146   word position;
147   word x_pos, y_pos;
148 
149 
150   if (selection_end<selection_start)
151   {
152     position    =selection_end;
153     selection_end  =selection_start;
154     selection_start=position;
155   }
156 
157   for (line=0; line<8; line++)
158     for (column=0; column<64; column++)
159     {
160       position=(line<<6)+column;
161       x_pos=Window_pos_X+(Menu_factor_X*((column<<2)+8));
162       y_pos=Window_pos_Y+(Menu_factor_Y*((line*7)+131));
163 
164       // On regarde si la case est "disablée"
165       if (Shade_list[Shade_current].List[position]&0x8000)
166       {
167         if ((position>=selection_start) && (position<=selection_end))
168         {
169           Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y,MC_White);
170           Block(x_pos,y_pos+Menu_factor_Y,Menu_factor_X<<2,Menu_factor_Y,MC_Black);
171         }
172         else
173           Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_White);
174       }
175       else // "enablée"
176       {
177         if ((position>=selection_start) && (position<=selection_end))
178           Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Black);
179         else
180           Block(x_pos,y_pos,Menu_factor_X<<2,Menu_factor_Y<<1,MC_Light);
181       }
182     }
183     Update_window_area(8,131,64<<2,8<<3);
184 }
185 
186 
Display_selected_cell_color(word selection_start,word selection_end)187 void Display_selected_cell_color(word selection_start,word selection_end)
188 {
189   char str[4];
190 
191   if ((selection_start!=selection_end)
192    || (Shade_list[Shade_current].List[selection_start]&0x0100))
193     strcpy(str,"   ");
194   else
195     Num2str(Shade_list[Shade_current].List[selection_start]&0xFF,str,3);
196 
197   Print_in_window(213,115,str,MC_Black,MC_Light);
198 }
199 
200 
Display_selected_color(word selection_start,word selection_end)201 void Display_selected_color(word selection_start,word selection_end)
202 {
203   char str[4];
204 
205   if (selection_start!=selection_end)
206     strcpy(str,"   ");
207   else
208     Num2str(selection_start,str,3);
209 
210   Print_in_window(213,106,str,MC_Black,MC_Light);
211 }
212 
213 
Display_shade_mode(short x,short y,byte mode)214 void Display_shade_mode(short x,short y,byte mode)
215 {
216   char str[7];
217 
218   switch (mode)
219   {
220     case SHADE_MODE_NORMAL :
221       strcpy(str,"Normal");
222       break;
223     case SHADE_MODE_LOOP :
224       strcpy(str," Loop ");
225       break;
226     default : // SHADE_MODE_NOSAT
227       strcpy(str,"No sat");
228   }
229   Print_in_window(x,y,str,MC_Black,MC_Light);
230 }
231 
232 
Display_all_shade(word selection_start1,word selection_end1,word selection_start2,word selection_end2)233 void Display_all_shade(word selection_start1,word selection_end1,
234                             word selection_start2,word selection_end2)
235 {
236   word line, column;
237   word position;
238 
239   for (line=0; line<8; line++)
240     for (column=0; column<64; column++)
241     {
242       position=(line<<6)+column;
243       // On regarde si c'est une couleur ou un bloc vide
244       if (Shade_list[Shade_current].List[position]&0x0100) // Vide
245       {
246         Window_display_frame_out((column<<2)+8,(line*7)+127,4,4);
247         Window_rectangle((column<<2)+9,
248               (line*7)+128,
249               2,2,MC_Light);
250       }
251       else // color
252         Window_rectangle((column<<2)+8,
253               (line*7)+127,
254               4,4,
255               Shade_list[Shade_current].List[position]&0xFF);
256     }
257   Update_window_area(7,126,(64<<2)+2,(8<<2)+2);
258   Tag_shades(selection_start2,selection_end2);
259   Shade_draw_grad_ranges();
260   Display_selected_cell_color(selection_start2,selection_end2);
261   Display_selected_color(selection_start1,selection_end1);
262   Display_shade_mode(250,110,Shade_list[Shade_current].Mode);
263 }
264 
265 
Remove_shade(word selection_start,word selection_end)266 void Remove_shade(word selection_start,word selection_end)
267 {
268   word temp;
269 
270   if (selection_end<selection_start)
271   {
272     temp        =selection_end;
273     selection_end  =selection_start;
274     selection_start=temp;
275   }
276 
277   for (selection_end++;selection_end<512;selection_start++,selection_end++)
278     Shade_list[Shade_current].List[selection_start]=Shade_list[Shade_current].List[selection_end];
279 
280   for (;selection_start<512;selection_start++)
281     Shade_list[Shade_current].List[selection_start]=0x0100;
282 }
283 
284 
Insert_shade(byte first_color,byte last_color,word selection_start)285 void Insert_shade(byte first_color, byte last_color, word selection_start)
286 {
287   word cursor,limit;
288   word temp;
289 
290   if (last_color<first_color)
291   {
292     temp            =last_color;
293     last_color=first_color;
294     first_color=temp;
295   }
296 
297   // Avant d'insérer quoi que ce soit, on efface les éventuelles couleurs que
298   // l'on va réinsérer:
299   limit=512-selection_start;
300   for (cursor=0; cursor<512; cursor++)
301   {
302     if (!(Shade_list[Shade_current].List[cursor]&0x0100))
303       for (temp=first_color; temp<=last_color; temp++)
304         if ( (temp-first_color<limit)
305           && ((Shade_list[Shade_current].List[cursor]&0xFF)==temp) )
306           Shade_list[Shade_current].List[cursor]=(Shade_list[Shade_current].List[cursor]&0x8000)|0x0100;
307   }
308   // Voilà... Maintenant on peut y aller peinard.
309 
310   temp=1+last_color-first_color;
311   limit=selection_start+temp;
312   if (limit>=512)
313     temp=512-selection_start;
314 
315   for (cursor=511;cursor>=limit;cursor--)
316     Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-temp];
317 
318   for (cursor=selection_start+temp;selection_start<cursor;selection_start++,first_color++)
319     Shade_list[Shade_current].List[selection_start]=first_color;
320 }
321 
322 
Insert_empty_cell_in_shade(word position)323 void Insert_empty_cell_in_shade(word position)
324 {
325   word cursor;
326 
327   if (position>=512) return;
328 
329   for (cursor=511;cursor>position;cursor--)
330     Shade_list[Shade_current].List[cursor]=Shade_list[Shade_current].List[cursor-1];
331 
332   Shade_list[Shade_current].List[position]=0x0100;
333 }
334 
335 
Wait_click_in_shade_table()336 short Wait_click_in_shade_table()
337 {
338   short selected_cell=-1;
339   byte  old_hide_cursor;
340 
341 
342   Hide_cursor();
343   old_hide_cursor=Cursor_hidden;
344   Cursor_hidden=0;
345   Cursor_shape=CURSOR_SHAPE_TARGET;
346   Display_cursor();
347 
348   while (selected_cell<0)
349   {
350     Get_input(20);
351 
352     if ( (Mouse_K==LEFT_SIDE)
353       && ( ( (Window_click_in_rectangle(8,127,263,179)) && (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4) )
354            || ( (Mouse_X<Window_pos_X) || (Mouse_Y<Window_pos_Y)
355              || (Mouse_X>=Window_pos_X+(Window_width*Menu_factor_X))
356              || (Mouse_Y>=Window_pos_Y+(Window_height*Menu_factor_Y)) ) )
357        )
358       selected_cell=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+
359                     ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2);
360 
361     if ((Mouse_K==RIGHT_SIDE) || (Key==KEY_ESC))
362       selected_cell=512; // valeur indiquant que l'on n'a rien choisi
363   }
364 
365   Hide_cursor();
366   Cursor_shape=CURSOR_SHAPE_ARROW;
367   Cursor_hidden=old_hide_cursor;
368   Display_cursor();
369   return selected_cell;
370 }
371 
372 
Swap_shade(short block_1_start,short block_2_start,short block_size)373 void Swap_shade(short block_1_start,short block_2_start,short block_size)
374 {
375   short  pos_1;
376   short  pos_2;
377   short  end_1;
378   short  end_2;
379   word   temp;
380   word * temp_shade;
381 
382   // On fait une copie de la liste
383   temp_shade=(word *)malloc(512*sizeof(word));
384   memcpy(temp_shade,Shade_list[Shade_current].List,512*sizeof(word));
385 
386   // On calcul les dernières couleurs de chaque bloc.
387   end_1=block_1_start+block_size-1;
388   end_2=block_2_start+block_size-1;
389 
390   if ((block_2_start>=block_1_start) && (block_2_start<=end_1))
391   {
392     // Le bloc destination commence dans le bloc source.
393     for (pos_1=block_1_start,pos_2=end_1+1;pos_1<=end_2;pos_1++)
394     {
395       // Il faut transformer la case pos_1 en pos_2:
396       Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2];
397       // On gère la mise à jour de pos_2
398       if (pos_2==end_2)
399         pos_2=block_1_start;
400       else
401         pos_2++;
402     }
403   }
404   else
405   if ((block_2_start<block_1_start) && (end_2>=block_1_start))
406   {
407     // Le bloc destination déborde dans le bloc source.
408     for (pos_1=block_2_start,pos_2=block_1_start;pos_1<=end_1;pos_1++)
409     {
410       // Il faut transformer la couleur pos_1 en pos_2:
411       Shade_list[Shade_current].List[pos_1]=temp_shade[pos_2];
412       // On gère la mise à jour de pos_2
413       if (pos_2==end_1)
414         pos_2=block_2_start;
415       else
416         pos_2++;
417     }
418   }
419   else
420   {
421     // Le bloc source et le bloc destination sont distincts.
422     for (pos_1=block_1_start,pos_2=block_2_start;pos_1<=end_1;pos_1++,pos_2++)
423     {
424       // On échange les cases
425       temp                                  =Shade_list[Shade_current].List[pos_1];
426       Shade_list[Shade_current].List[pos_1]=Shade_list[Shade_current].List[pos_2];
427       Shade_list[Shade_current].List[pos_2]=temp;
428     }
429   }
430 
431   free(temp_shade);
432 }
433 
434 
Menu_shade(void)435 int Menu_shade(void)
436 {
437   short clicked_button; // Numéro du bouton sur lequel l'utilisateur a clické
438   char str[4]; // str d'affichage du n° de shade actif et du Pas
439   word old_mouse_x, old_mouse_x2; // Mémo. de l'ancienne pos. du curseur
440   word old_mouse_y, old_mouse_y2;
441   byte old_mouse_k, old_mouse_k2;
442   byte temp_color; // Variables de gestion des clicks dans la palette
443   byte first_color = Fore_color;
444   byte last_color = Fore_color;
445   word selection_start = 0;
446   word selection_end = 0;
447   T_Special_button * input_button;
448   short temp, temp2;
449   word temp_cell;
450   word * buffer;       // buffer du Copy/Paste
451   word * undo_buffer;  // buffer du Undo
452   word * temp_ptr;
453   byte color;
454   byte click;
455 
456 
457   buffer       =(word *)malloc(512*sizeof(word));
458   undo_buffer  =(word *)malloc(512*sizeof(word));
459   temp_ptr=(word *)malloc(512*sizeof(word));
460 
461   // Ouverture de la fenêtre du menu
462   Open_window(310,190,"Shade");
463 
464   // Déclaration & tracé du bouton de palette
465   Window_set_palette_button(5,16);                             // 1
466 
467   // Déclaration & tracé du scroller de sélection du n° de dégradé
468   Window_set_scroller_button(192,17,84,8,1,Shade_current);      // 2
469 
470   // Déclaration & tracé de la zone de définition des dégradés
471   Window_set_special_button(8,127,256,53,0);                     // 3
472 
473   // Déclaration & tracé des boutons de sortie
474   Window_set_normal_button(207,17,51,14,"Cancel",0,1,KEY_ESC);   // 4
475   Window_set_normal_button(261,17,43,14,"OK"    ,0,1,KEY_RETURN);  // 5
476 
477   // Déclaration & tracé des boutons de copie de shade
478   Window_set_normal_button(206,87,27,14,"Cpy"   ,1,1,KEY_c);  // 6
479   Window_set_normal_button(234,87,43,14,"Paste" ,1,1,KEY_p);  // 7
480 
481   // On tagge le bloc
482   Tag_color_range(Fore_color,Fore_color);
483 
484   // Tracé d'un cadre creux autour du bloc dégradé
485   Window_display_frame_in(171,26,18,66);
486   Window_rectangle(172,27,16,64,MC_Black);
487   // Tracé d'un cadre creux autour de tous les dégradés
488   Window_display_frame_in(223,34,66,50);
489   Shade_draw_grad_ranges();
490   // Tracé d'un cadre autour de la zone de définition de dégradés
491   Window_display_frame(5,124,262,61);
492   Display_all_shade(first_color,last_color,selection_start,selection_end);
493 
494   // Déclaration & tracé des boutons d'édition de shade
495   Window_set_normal_button(  6,107,27,14,"Ins"  ,0,1,KEY_INSERT);  // 8
496   Window_set_normal_button( 38,107,27,14,"Del"  ,0,1,KEY_DELETE);  // 9
497   Window_set_normal_button( 66,107,43,14,"Blank",1,1,KEY_b);  // 10
498   Window_set_normal_button(110,107,27,14,"Inv"  ,1,1,KEY_i);  // 11
499   Window_set_normal_button(138,107,27,14,"Swp"  ,1,1,KEY_s);  // 12
500 
501   // Déclaration & tracé des boutons de taggage
502   Print_in_window(268,123,"Disbl"/*"Dsabl"*/,MC_Dark,MC_Light);
503   Window_set_normal_button(274,133,27,14,"Set"   ,0,1,KEY_F1); // 13
504   Window_set_normal_button(274,148,27,14,"Clr"   ,0,1,KEY_F2); // 14
505 
506   // Déclaration & tracé de la zone de saisie du pas
507   Print_in_window(272,165,"Step",MC_Dark,MC_Light);
508   input_button = Window_set_input_button(274,174,3);          // 15
509   Num2str(Shade_list[Shade_current].Step,str,3);
510   Window_input_content(input_button,str);
511 
512   // Button Undo
513   Window_set_normal_button(170,107,35,14,"Undo",1,1,KEY_u);   // 16
514   // Button Clear
515   Window_set_normal_button(278,87,27,14,"Clr",0,1,KEY_BACKSPACE);     // 17
516 
517   // Button Mode
518   Window_set_normal_button(244,107,60,14,"",0,1,KEY_TAB);       // 18
519 
520   // Affichage du n° de shade actif
521   Num2str(Shade_current+1,str,1);
522   Print_in_window(210,55,str,MC_Black,MC_Light);
523 
524   memcpy(buffer     ,Shade_list[Shade_current].List,512*sizeof(word));
525   memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
526 
527   Update_window_area(0,0,310,190);
528 
529   Display_cursor();
530 
531   do
532   {
533     old_mouse_x=old_mouse_x2=Mouse_X;
534     old_mouse_y=old_mouse_y2=Mouse_Y;
535     old_mouse_k=old_mouse_k2=Mouse_K;
536 
537     clicked_button=Window_clicked_button();
538 
539     switch (clicked_button)
540     {
541       case  0 :
542         break;
543       case -1 :
544       case  1 : // Gestion de la palette
545         if ( (Mouse_X!=old_mouse_x) || (Mouse_Y!=old_mouse_y) || (Mouse_K!=old_mouse_k) )
546         {
547           Hide_cursor();
548           temp_color=(clicked_button==1) ? Window_attribute2 : Read_pixel(Mouse_X,Mouse_Y);
549 
550           if (!old_mouse_k)
551           { // On vient de clicker
552 
553             // On met à jour l'intervalle du Shade
554             first_color=last_color=temp_color;
555             // On tagge le bloc
556             Tag_color_range(first_color,last_color);
557             // Tracé du bloc dégradé:
558             Display_grad_block_in_window(172,27,16,64,first_color,last_color);
559           }
560           else
561           { // On maintient le click, on va donc tester si le curseur bouge
562             if (temp_color!=last_color)
563             {
564               last_color=temp_color;
565 
566               // On tagge le bloc
567               if (first_color<=temp_color)
568               {
569                 Tag_color_range(first_color,last_color);
570                 Display_grad_block_in_window(172,27,16,64,first_color,last_color);
571               }
572               else
573               {
574                 Tag_color_range(last_color,first_color);
575                 Display_grad_block_in_window(172,27,16,64,last_color,first_color);
576               }
577             }
578           }
579 
580           // On affiche le numéro de la couleur sélectionnée
581           Display_selected_color(first_color,last_color);
582 
583           Display_cursor();
584         }
585         break;
586 
587       case  2 : // Gestion du changement de Shade (scroller)
588         Hide_cursor();
589         Shade_current=Window_attribute2;
590         // Affichade du n° de shade actif
591         Num2str(Shade_current+1,str,1);
592         Print_in_window(210,55,str,MC_Black,MC_Light);
593         // Affichade du Pas
594         Num2str(Shade_list[Shade_current].Step,str,3);
595         Print_in_window(276,176,str,MC_Black,MC_Light);
596         // Tracé du bloc dégradé:
597         Display_all_shade(first_color,last_color,selection_start,selection_end);
598         Display_cursor();
599         // On place le nouveau shade dans le buffer du Undo
600         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
601         break;
602 
603       case  3 : // Gestion de la zone de définition de shades
604         if (((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)%7)<4)
605         if ( (Mouse_X!=old_mouse_x2) || (Mouse_Y!=old_mouse_y2) || (Mouse_K!=old_mouse_k2) )
606         {
607           Hide_cursor();
608           selection_end=(((((Mouse_Y-Window_pos_Y)/Menu_factor_Y)-127)/7)<<6)+
609                       ((((Mouse_X-Window_pos_X)/Menu_factor_X)-8 )>>2);
610           if (!old_mouse_k2) // On vient de clicker
611             selection_start=selection_end;
612           Tag_shades(selection_start,selection_end);
613           Display_selected_cell_color(selection_start,selection_end);
614           Display_cursor();
615         }
616         break;
617 
618       case 5: // Ok
619         if (selection_start == selection_end && Shade_list[Shade_current].List[selection_start] > 0)
620           Set_fore_color(Shade_list[Shade_current].List[selection_start]);
621         else if (first_color == last_color)
622           Set_fore_color(first_color);
623         break;
624 
625       case  6 : // Copy
626         memcpy(buffer,Shade_list[Shade_current].List,512*sizeof(word));
627         break;
628 
629       case  7 : // Paste
630         // On place le shade dans le buffer du Undo
631         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
632         // Et on le modifie
633         memcpy(Shade_list[Shade_current].List,buffer,512*sizeof(word));
634         Hide_cursor();
635         Display_all_shade(first_color,last_color,selection_start,selection_end);
636         Display_cursor();
637         break;
638 
639       case  8 : // Insert
640         // On place le shade dans le buffer du Undo
641         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
642         // Et on le modifie
643         if (first_color<=last_color)
644           temp=last_color-first_color;
645         else
646           temp=first_color-last_color;
647 
648         if (selection_start==selection_end) // Une couleur sélectionnée
649         {
650           if (Window_attribute1==2)
651             Remove_shade(selection_start,selection_start+temp);
652         }
653         else                          // Un bloc sélectionné
654         {
655           Remove_shade(selection_start,selection_end);
656 
657           if (first_color<=last_color)
658             temp=last_color-first_color;
659           else
660             temp=first_color-last_color;
661 
662           if (selection_start<selection_end)
663             selection_end=selection_start+temp;
664           else
665           {
666             selection_start=selection_end;
667             selection_end+=temp;
668           }
669         }
670 
671         if (selection_start<selection_end)
672           selection_end=selection_start+temp;
673         else
674         {
675           selection_start=selection_end;
676           selection_end+=temp;
677         }
678         Insert_shade(first_color,last_color,selection_start);
679 
680         // On sélectionne la position juste après ce qu'on vient d'insérer
681         selection_start+=temp+1;
682         if (selection_start>=512)
683           selection_start=511;
684         selection_end=selection_start;
685 
686         Hide_cursor();
687         Display_all_shade(first_color,last_color,selection_start,selection_end);
688         Display_cursor();
689         break;
690 
691       case  9 : // Delete
692         // On place le shade dans le buffer du Undo
693         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
694         // Et on le modifie
695         Remove_shade(selection_start,selection_end);
696         if (selection_start<=selection_end)
697           selection_end=selection_start;
698         else
699           selection_start=selection_end;
700         Hide_cursor();
701         Display_all_shade(first_color,last_color,selection_start,selection_end);
702         Display_cursor();
703         break;
704 
705       case 10 : // Blank
706         // On place le shade dans le buffer du Undo
707         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
708         // Et on le modifie
709         if (Window_attribute1==RIGHT_SIDE)  // Click droit
710         {
711           if (selection_start!=selection_end)
712           {
713             if (selection_start<=selection_end)
714             {
715               Insert_empty_cell_in_shade(selection_start);
716               Insert_empty_cell_in_shade(selection_end+2);
717             }
718             else
719             {
720               Insert_empty_cell_in_shade(selection_end);
721               Insert_empty_cell_in_shade(selection_start+2);
722             }
723           }
724           else
725             Insert_empty_cell_in_shade(selection_start);
726 
727           if (selection_start<511) selection_start++;
728           if (selection_end<511) selection_end++;
729         }
730         else                              // Click gauche
731         {
732           if (selection_start<=selection_end)
733           {
734             temp=selection_start;
735             temp2=selection_end;
736           }
737           else
738           {
739             temp=selection_end;
740             temp2=selection_start;
741           }
742           while (temp<=temp2)
743             Shade_list[Shade_current].List[temp++]=0x0100;
744         }
745 
746         Hide_cursor();
747         Display_all_shade(first_color,last_color,selection_start,selection_end);
748         Display_cursor();
749         break;
750 
751       case 11 : // Invert
752         // On place le shade dans le buffer du Undo
753         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
754         // Et on le modifie
755         if (selection_start<=selection_end)
756         {
757           temp=selection_start;
758           temp2=selection_end;
759         }
760         else
761         {
762           temp=selection_end;
763           temp2=selection_start;
764         }
765 
766         for (;temp<temp2;temp++,temp2--)
767         {
768           temp_cell=Shade_list[Shade_current].List[temp];
769           Shade_list[Shade_current].List[temp]=Shade_list[Shade_current].List[temp2];
770           Shade_list[Shade_current].List[temp2]=temp_cell;
771         }
772 
773         Hide_cursor();
774         Display_all_shade(first_color,last_color,selection_start,selection_end);
775         Display_cursor();
776         break;
777 
778       case 12 : // Swap
779         temp_cell=Wait_click_in_shade_table();
780         if (temp_cell<512)
781         {
782           // On place le shade dans le buffer du Undo
783           memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
784           // Et on le modifie
785           // On échange le bloc avec sa destination
786           if (selection_start<=selection_end)
787           {
788             temp=(temp_cell+selection_end-selection_start<512)?selection_end+1-selection_start:512-temp_cell;
789             Swap_shade(selection_start,temp_cell,temp);
790           }
791           else
792           {
793             temp=(temp_cell+selection_start-selection_end<512)?selection_start+1-selection_end:512-temp_cell;
794             Swap_shade(selection_end,temp_cell,temp);
795           }
796           // On place la sélection sur la nouvelle position du bloc
797           selection_start=temp_cell;
798           selection_end=selection_start+temp-1;
799           // Et on raffiche tout
800           Hide_cursor();
801           Display_all_shade(first_color,last_color,selection_start,selection_end);
802           Display_cursor();
803         }
804         Wait_end_of_click();
805         break;
806 
807       case 13 : // Set (disable)
808       case 14 : // Clear (enable)
809         // On place le shade dans le buffer du Undo
810         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
811         // Et on le modifie
812         if (selection_start<selection_end)
813         {
814           temp=selection_start;
815           temp2=selection_end;
816         }
817         else
818         {
819           temp=selection_end;
820           temp2=selection_start;
821         }
822 
823         if (clicked_button==13)
824           for (;temp<=temp2;temp++)
825             Shade_list[Shade_current].List[temp]|=0x8000;
826         else
827           for (;temp<=temp2;temp++)
828             Shade_list[Shade_current].List[temp]&=0x7FFF;
829 
830         Hide_cursor();
831         Tag_shades(selection_start,selection_end);
832         Shade_draw_grad_ranges();
833         Display_cursor();
834         break;
835 
836       case 15 : // Saisie du pas
837         Num2str(Shade_list[Shade_current].Step,str,3);
838         Readline(276,176,str,3,INPUT_TYPE_INTEGER);
839         temp=atoi(str);
840         // On corrige le pas
841         if (!temp)
842         {
843           temp=1;
844           Num2str(temp,str,3);
845           Window_input_content(input_button,str);
846         }
847         else if (temp>255)
848         {
849           temp=255;
850           Num2str(temp,str,3);
851           Window_input_content(input_button,str);
852         }
853         Shade_list[Shade_current].Step=temp;
854         Display_cursor();
855         break;
856 
857       case 16 : // Undo
858         memcpy(temp_ptr,undo_buffer,512*sizeof(word));
859         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
860         memcpy(Shade_list[Shade_current].List,temp_ptr,512*sizeof(word));
861 
862         Hide_cursor();
863         Display_all_shade(first_color,last_color,selection_start,selection_end);
864         Display_cursor();
865         break;
866 
867       case 17 : // Clear
868         memcpy(undo_buffer,Shade_list[Shade_current].List,512*sizeof(word));
869         for (temp=0;temp<512;temp++)
870           Shade_list[Shade_current].List[temp]=0x0100;
871         Hide_cursor();
872         Display_all_shade(first_color,last_color,selection_start,selection_end);
873         Display_cursor();
874         break;
875 
876       case 18 : // Mode
877         Shade_list[Shade_current].Mode=(Shade_list[Shade_current].Mode+1)%3;
878         Hide_cursor();
879         Display_shade_mode(250,110,Shade_list[Shade_current].Mode);
880         Display_cursor();
881     }
882 
883     if (!Mouse_K)
884     switch (Key)
885     {
886       case KEY_LEFTBRACKET : // Décaler couleur dans palette vers la gauche
887       case KEY_RIGHTBRACKET : // Décaler couleur dans palette vers la droite
888         if (first_color==last_color)
889         {
890           if (Key==KEY_LEFTBRACKET)
891           {
892             first_color--;
893             last_color--;
894           }
895           else
896           {
897             first_color++;
898             last_color++;
899           }
900           Hide_cursor();
901           Tag_color_range(first_color,first_color);
902           Block(Window_pos_X+(Menu_factor_X*172),
903                 Window_pos_Y+(Menu_factor_Y*27),
904                 Menu_factor_X<<4,Menu_factor_Y*64,first_color);
905           // On affiche le numéro de la couleur sélectionnée
906           Display_selected_color(first_color,last_color);
907           Display_cursor();
908         }
909         Key=0;
910         break;
911 
912       case KEY_UP    : // Select Haut
913       case KEY_DOWN  : // Select Bas
914       case KEY_LEFT  : // Select Gauche
915       case KEY_RIGHT : // Select Droite
916         if (selection_start==selection_end)
917         {
918           switch (Key)
919           {
920             case KEY_UP : // Select Haut
921               if (selection_start>=64)
922               {
923                 selection_start-=64;
924                 selection_end-=64;
925               }
926               else
927                 selection_start=selection_end=0;
928               break;
929             case KEY_DOWN : // Select Bas
930               if (selection_start<448)
931               {
932                 selection_start+=64;
933                 selection_end+=64;
934               }
935               else
936                 selection_start=selection_end=511;
937               break;
938             case KEY_LEFT : // Select Gauche
939               if (selection_start>0)
940               {
941                 selection_start--;
942                 selection_end--;
943               }
944               break;
945             default :     // Select Droite
946               if (selection_start<511)
947               {
948                 selection_start++;
949                 selection_end++;
950               }
951           }
952           Hide_cursor();
953           Tag_shades(selection_start,selection_start);
954           Display_selected_cell_color(selection_start,selection_start);
955           Display_cursor();
956         }
957         Key=0;
958         break;
959 
960       case KEY_BACKQUOTE : // Récupération d'une couleur derrière le menu
961       case KEY_COMMA :
962         Get_color_behind_window(&color,&click);
963         if (click)
964         {
965           Hide_cursor();
966           temp_color=color;
967 
968           // On met à jour l'intervalle du Shade
969           first_color=last_color=temp_color;
970           // On tagge le bloc
971           Tag_color_range(first_color,last_color);
972           // Tracé du bloc dégradé:
973           Display_grad_block_in_window(172,27,16,64,first_color,last_color);
974 
975           // On affiche le numéro de la couleur sélectionnée
976           Display_selected_color(first_color,last_color);
977 
978           Display_cursor();
979           Wait_end_of_click();
980         }
981         Key=0;
982         break;
983       default:
984         if (Is_shortcut(Key,0x100+BUTTON_HELP))
985         {
986           Key=0;
987           Window_help(BUTTON_EFFECTS, "SHADE");
988         }
989         else if (Is_shortcut(Key,SPECIAL_SHADE_MENU))
990           clicked_button=5;
991     }
992   }
993   while ((clicked_button!=4) && (clicked_button!=5));
994 
995   Close_window();
996   free(undo_buffer);
997   free(buffer);
998   free(temp_ptr);
999 
1000   return (clicked_button==5);
1001 }
1002 
1003 /// Handles the screen with Shade settings.
1004 /// @return true if user clicked ok, false if he cancelled
Shade_settings_menu(void)1005 int Shade_settings_menu(void)
1006 {
1007   T_Shade * initial_shade_list; // Anciennes données des shades
1008   byte old_shade; // old n° de shade actif
1009   int return_code;
1010 
1011   // Backup des anciennes données
1012   initial_shade_list=(T_Shade *)malloc(sizeof(Shade_list));
1013   memcpy(initial_shade_list,Shade_list,sizeof(Shade_list));
1014   old_shade=Shade_current;
1015 
1016   return_code = Menu_shade();
1017   if (!return_code) // Cancel
1018   {
1019     memcpy(Shade_list,initial_shade_list,sizeof(Shade_list));
1020     Shade_current=old_shade;
1021   }
1022   else // OK
1023   {
1024     Shade_list_to_lookup_tables(Shade_list[Shade_current].List,
1025                  Shade_list[Shade_current].Step,
1026                  Shade_list[Shade_current].Mode,
1027                  Shade_table_left,Shade_table_right);
1028   }
1029 
1030   free(initial_shade_list);
1031 
1032   Display_cursor();
1033 
1034   return return_code;
1035 }
1036 
1037 
Button_Shade_menu(void)1038 void Button_Shade_menu(void)
1039 {
1040   if (Shade_settings_menu())
1041   {
1042     // If user clicked OK while in the menu, activate Shade mode.
1043     if (!Shade_mode)
1044       Button_Shade_mode();
1045   }
1046 }
1047 
1048 
Button_Quick_shade_menu(void)1049 void Button_Quick_shade_menu(void)
1050 {
1051   short clicked_button;
1052   int temp;
1053   char str[4];
1054   byte step_backup=Quick_shade_step; // Backup des
1055   byte loop_backup=Quick_shade_loop; // anciennes données
1056   T_Special_button * step_button;
1057 
1058   Open_window(142,56,"Quick-shade");
1059 
1060   Window_set_normal_button(76,36,60,14,"OK",0,1,KEY_RETURN);     // 1
1061   Window_set_normal_button( 6,36,60,14,"Cancel",0,1,KEY_ESC);  // 2
1062   Window_set_normal_button(76,18,60,14,"",0,1,KEY_TAB);          // 3
1063   Display_shade_mode(83,21,Quick_shade_loop);
1064 
1065   // Déclaration & tracé de la zone de saisie du pas
1066   Print_in_window(5,21,"Step",MC_Dark,MC_Light);
1067   step_button = Window_set_input_button(40,19,3);                  // 4
1068   Num2str(Quick_shade_step,str,3);
1069   Window_input_content(step_button,str);
1070 
1071   Update_window_area(0,0,142,56);
1072 
1073   Display_cursor();
1074 
1075   do
1076   {
1077     clicked_button=Window_clicked_button();
1078 
1079     switch (clicked_button)
1080     {
1081       case 3 : // Mode
1082         Quick_shade_loop=(Quick_shade_loop+1)%3;
1083         Hide_cursor();
1084         Display_shade_mode(83,21,Quick_shade_loop);
1085         Display_cursor();
1086         break;
1087 
1088       case 4 : // Saisie du pas
1089         Num2str(Quick_shade_step,str,3);
1090         Readline(42,21,str,3,INPUT_TYPE_INTEGER);
1091         temp=atoi(str);
1092         // On corrige le pas
1093         if (!temp)
1094         {
1095           temp=1;
1096           Num2str(temp,str,3);
1097           Window_input_content(step_button,str);
1098         }
1099         else if (temp>255)
1100         {
1101           temp=255;
1102           Num2str(temp,str,3);
1103           Window_input_content(step_button,str);
1104         }
1105         Quick_shade_step=temp;
1106         Display_cursor();
1107     }
1108     if (Is_shortcut(Key,0x100+BUTTON_HELP))
1109       Window_help(BUTTON_EFFECTS, "QUICK SHADE");
1110     else if (Is_shortcut(Key,SPECIAL_QUICK_SHADE_MENU))
1111       clicked_button=1;
1112   }
1113   while ((clicked_button!=1) && (clicked_button!=2));
1114 
1115   Close_window();
1116 
1117   if (clicked_button==2) // Cancel
1118   {
1119     Quick_shade_step=step_backup;
1120     Quick_shade_loop=loop_backup;
1121   }
1122   else // OK
1123   {
1124     // Si avant de rentrer dans le menu on n'était pas en mode Quick-Shade
1125     if (!Quick_shade_mode)
1126       Button_Quick_shade_mode(); // => On y passe (cool!)
1127   }
1128 
1129   Display_cursor();
1130 }
1131