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