1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 //////////////////////////////////////////////////////////////////////////////
21 ///@file brush_ops.c
22 /// Code for operations about the brush (grabbing, rotating, ...) and magnifier
23 //////////////////////////////////////////////////////////////////////////////
24 
25 #include <math.h>
26 #include <stdlib.h>
27 
28 #include "brush.h"
29 #include "buttons.h"
30 #include "engine.h"
31 #include "global.h"
32 #include "graph.h"
33 #include "misc.h"
34 #include "operatio.h"
35 #include "pages.h"
36 #include "screen.h"
37 #include "windows.h"
38 #include "keyboard.h"
39 
40 #ifndef M_PI
41     #define M_PI 3.141592653589793238462643
42 #endif
43 
44 /// Simulates clicking the "Draw" button.
Return_to_draw_mode(void)45 void Return_to_draw_mode(void)
46 {
47 
48   // Comme l'enclenchement du bouton efface le curseur, il faut l'afficher au
49   // préalable:
50   Display_cursor();
51   if (Mouse_K)
52     Wait_end_of_click();
53   // !!! Efface la croix puis affiche le viseur !!!
54   Select_button(BUTTON_DRAW,LEFT_SIDE); // Désenclenche au passage le bouton brosse
55   if (Config.Auto_discontinuous)
56   {
57     // On se place en mode Dessin discontinu à la main
58     while (Current_operation!=OPERATION_DISCONTINUOUS_DRAW)
59       Select_button(BUTTON_DRAW,RIGHT_SIDE);
60   }
61   // Maintenant, il faut réeffacer le curseur parce qu'il sera raffiché en fin
62   // d'appel à cette action:
63   Hide_cursor();
64 
65   // On passe en brosse couleur:
66   Change_paintbrush_shape(PAINTBRUSH_SHAPE_COLOR_BRUSH);
67 
68   if ((Config.Coords_rel) && (Menu_is_visible))
69     Print_in_menu("X:       Y:",0);
70   Print_coordinates();
71 }
72 
73 // ---------------------------------------------------------- OPERATION_MAGNIFY
74 
75 
Magnifier_12_0(void)76 void Magnifier_12_0(void)
77 
78 // Opération   : 4      (item d'une Loupe)
79 // Click Souris: 1 ou 2
80 // Taille_Pile : 0
81 //
82 // Souris effacée: Oui
83 
84 {
85 
86   // On passe en mode loupe
87   Main.magnifier_mode=1;
88 
89   // La fonction d'affichage dans la partie image est désormais un affichage
90   // spécial loupe.
91   Pixel_preview=Pixel_preview_magnifier;
92 
93   // On calcule l'origine de la loupe
94   Main.magnifier_offset_X=Mouse_X-(Main.magnifier_width>>1);
95   Main.magnifier_offset_Y=Mouse_Y-(Main.magnifier_height>>1);
96 
97   // Calcul des coordonnées absolues de ce coin DANS L'IMAGE
98   Main.magnifier_offset_X+=Main.offset_X;
99   Main.magnifier_offset_Y+=Main.offset_Y;
100 
101   Clip_magnifier_offsets(&Main.magnifier_offset_X, &Main.magnifier_offset_Y);
102 
103   // On calcule les bornes visibles dans l'écran
104   Position_screen_according_to_zoom();
105   Compute_limits();
106   Display_all_screen();
107 
108   // Repositionner le curseur en fonction des coordonnées visibles
109   Compute_paintbrush_coordinates();
110 
111   // On fait de notre mieux pour restaurer l'ancienne opération:
112   Start_operation_stack(Operation_before_interrupt);
113   Display_cursor();
114   Wait_end_of_click();
115 }
116 
117 
118 /////////////////////////////////////////////////////////// OPERATION_COLORPICK
119 
120 
Colorpicker_12_0(void)121 void Colorpicker_12_0(void)
122 //
123 // Opération   : OPERATION_COLORPICK
124 // Click Souris: 1 ou 2
125 // Taille_Pile : 0
126 //
127 // Souris effacée: Oui
128 //
129 {
130   Init_start_operation();
131 
132   if (Mouse_K==LEFT_SIDE)
133   {
134     Set_fore_color(Colorpicker_color);
135   }
136   else
137   {
138     Set_back_color(Colorpicker_color);
139   }
140   Operation_push(Mouse_K);
141 }
142 
143 
Colorpicker_1_1(void)144 void Colorpicker_1_1(void)
145 //
146 // Opération   : OPERATION_COLORPICK
147 // Click Souris: 1
148 // Taille_Pile : 1
149 //
150 // Souris effacée: Non
151 //
152 {
153   char str[4];
154 
155   if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0)
156     && (Paintbrush_X<Main.image_width)
157     && (Paintbrush_Y<Main.image_height) )
158     Colorpicker_color=Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y);
159   else
160     Colorpicker_color=0;
161 
162   if ( (Colorpicker_X!=Paintbrush_X)
163     || (Colorpicker_Y!=Paintbrush_Y) )
164   {
165     Hide_cursor();
166     Colorpicker_X=Paintbrush_X;
167     Colorpicker_Y=Paintbrush_Y;
168 
169     if (Colorpicker_color!=Fore_color)
170     {
171       Set_fore_color(Colorpicker_color);
172     }
173 
174     if (Menu_is_visible)
175     {
176       Print_coordinates();
177       Num2str(Colorpicker_color,str,3);
178       Print_in_menu(str,20);
179       Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color);
180     }
181     Display_cursor();
182   }
183 }
184 
185 
Colorpicker_2_1(void)186 void Colorpicker_2_1(void)
187 //
188 // Opération   : OPERATION_COLORPICK
189 // Click Souris: 2
190 // Taille_Pile : 1
191 //
192 // Souris effacée: Non
193 //
194 {
195   char str[4];
196 
197   if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0)
198     && (Paintbrush_X<Main.image_width)
199     && (Paintbrush_Y<Main.image_height) )
200     Colorpicker_color=Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y);
201   else
202     Colorpicker_color=0;
203 
204   if ( (Colorpicker_X!=Paintbrush_X)
205     || (Colorpicker_Y!=Paintbrush_Y) )
206   {
207     Hide_cursor();
208     Colorpicker_X=Paintbrush_X;
209     Colorpicker_Y=Paintbrush_Y;
210 
211     if (Colorpicker_color!=Back_color)
212     {
213       Set_back_color(Colorpicker_color);
214     }
215 
216     if (Menu_is_visible)
217     {
218       Print_coordinates();
219       Num2str(Colorpicker_color,str,3);
220       Print_in_menu(str,20);
221       Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color);
222     }
223     Display_cursor();
224   }
225 }
226 
227 
228 
Colorpicker_0_1(void)229 void Colorpicker_0_1(void)
230 //
231 // Opération   : OPERATION_COLORPICK
232 // Click Souris: 0
233 // Taille_Pile : 1
234 //
235 // Souris effacée: Oui
236 //
237 {
238   short click;
239 
240   Operation_pop(&click);
241   if (click==LEFT_SIDE)
242   {
243     Set_fore_color(Colorpicker_color);
244   }
245   else
246   {
247     Set_back_color(Colorpicker_color);
248   }
249   Unselect_button(BUTTON_COLORPICKER);
250 }
251 
252 /////////////////////////////////////////////////////////// OPERATION_RMB_COLORPICK
253 
254 
Rightclick_colorpick(byte cursor_visible)255 byte Rightclick_colorpick(byte cursor_visible)
256 {
257   // Check if the rightclick colorpick should take over:
258   if (!Config.Right_click_colorpick)
259     return 0;
260   if (Mouse_K!=RIGHT_SIDE)
261     return 0;
262   // In these modes, the Foreground color is ignored,
263   // so the RMB should act as normal.
264   if (Shade_mode||Quick_shade_mode||Tiling_mode)
265     return 0;
266 
267   Colorpicker_color=-1;
268   Colorpicker_X=-1;
269   Colorpicker_Y=-1;
270 
271   if (cursor_visible)
272     Hide_cursor();
273   Start_operation_stack(OPERATION_RMB_COLORPICK);
274 
275   Init_start_operation();
276 
277   // Just an indicator to go to next step
278   Operation_push(1);
279   Rightclick_colorpick_2_1();
280 
281   if (cursor_visible)
282     Display_cursor();
283 
284   return 1;
285 }
286 
Rightclick_colorpick_2_1(void)287 void Rightclick_colorpick_2_1(void)
288 //
289 // Opération   : OPERATION_RMB_COLORPICK
290 // Click Souris: 2
291 // Taille_Pile : 1
292 //
293 // Souris effacée: Non
294 //
295 {
296   char str[4];
297 
298   if ( (Colorpicker_X!=Paintbrush_X)
299     || (Colorpicker_Y!=Paintbrush_Y) )
300   {
301     if ( (Paintbrush_X>=0) && (Paintbrush_Y>=0)
302       && (Paintbrush_X<Main.image_width)
303       && (Paintbrush_Y<Main.image_height) )
304       Colorpicker_color=Read_pixel_from_current_screen(Paintbrush_X,Paintbrush_Y);
305     else
306       Colorpicker_color=0;
307 
308     Colorpicker_X=Paintbrush_X;
309     Colorpicker_Y=Paintbrush_Y;
310 
311     if (Menu_is_visible)
312     {
313       Print_coordinates();
314       Num2str(Colorpicker_color,str,3);
315       Print_in_menu(str,20);
316       Print_general(170*Menu_factor_X,Menu_status_Y," ",0,Colorpicker_color);
317     }
318   }
319 }
320 
321 
322 
Rightclick_colorpick_0_1(void)323 void Rightclick_colorpick_0_1(void)
324 //
325 // Opération   : OPERATION_RMB_COLORPICK
326 // Click Souris: 0
327 // Taille_Pile : 1
328 //
329 // Souris effacée: Non
330 //
331 {
332   short dummy;
333 
334   Hide_cursor();
335 
336   Operation_pop(&dummy);
337   Set_fore_color(Colorpicker_color);
338 
339   // Restore previous operation
340   Start_operation_stack(Operation_before_interrupt);
341 
342   // Erase the color block which shows the picked color
343   if (Operation_before_interrupt!=OPERATION_REPLACE)
344     if ( (Mouse_Y<Menu_Y) && (Menu_is_visible) &&
345          ( (!Main.magnifier_mode) || (Mouse_X<Main.separator_position) || (Mouse_X>=Main.X_zoom) ) )
346       Print_in_menu("X:       Y:             ",0);
347 
348   Print_coordinates();
349 
350   Display_cursor();
351 }
352 
353 ////////////////////////////////////////////////////// OPERATION_GRAB_BRUSH
354 
355 
Brush_12_0(void)356 void Brush_12_0(void)
357 //
358 // Opération   : OPERATION_GRAB_BRUSH
359 // Click Souris: 1 ou 2
360 // Taille_Pile : 0
361 //
362 // Souris effacée: Oui
363 //
364 {
365   Init_start_operation();
366   if (Mouse_K==RIGHT_SIDE) // Besoin d'effacer la brosse après ?
367   {
368     Operation_push(1);
369     // Puisque la zone où on prend la brosse sera effacée, on fait un backup
370     Backup();
371   }
372   else
373     Operation_push(0);
374 
375   // On laisse une trace du curseur pour que l'utilisateur puisse visualiser
376   // où demarre sa brosse:
377   Display_cursor();
378 
379   Operation_push(Paintbrush_X); // Début X
380   Operation_push(Paintbrush_Y); // Début Y
381   Operation_push(Paintbrush_X); // Dernière position X
382   Operation_push(Paintbrush_Y); // Dernière position Y
383 
384   if ((Config.Coords_rel) && (Menu_is_visible))
385     Print_in_menu("\035:   1   \022:   1",0);
386 }
387 
388 
Brush_12_5(void)389 void Brush_12_5(void)
390 //
391 // Opération   : OPERATION_GRAB_BRUSH
392 // Click Souris: 1 ou 2
393 // Taille_Pile : 5
394 //
395 // Souris effacée: Non
396 //
397 {
398   char  str[5];
399   short start_x;
400   short start_y;
401   short old_x;
402   short old_y;
403   short width;
404   short height;
405 
406   Operation_pop(&old_y);
407   Operation_pop(&old_x);
408 
409   if ( (Menu_is_visible) && ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y)) )
410   {
411     if (Config.Coords_rel)
412     {
413       Operation_pop(&start_y);
414       Operation_pop(&start_x);
415       Operation_push(start_x);
416       Operation_push(start_y);
417 
418       width=((start_x<Paintbrush_X)?Paintbrush_X-start_x:start_x-Paintbrush_X)+1;
419       height=((start_y<Paintbrush_Y)?Paintbrush_Y-start_y:start_y-Paintbrush_Y)+1;
420 
421       Num2str(width,str,4);
422       Print_in_menu(str,2);
423       Num2str(height,str,4);
424       Print_in_menu(str,11);
425     }
426     else
427       Print_coordinates();
428   }
429 
430   Operation_push(Paintbrush_X);
431   Operation_push(Paintbrush_Y);
432 }
433 
434 
Brush_0_5(void)435 void Brush_0_5(void)
436 //
437 // Opération   : OPERATION_GRAB_BRUSH
438 // Click Souris: 0
439 // Taille_Pile : 5
440 //
441 // Souris effacée: Oui
442 //
443 {
444   short start_x;
445   short start_y;
446   short old_paintbrush_x;
447   short old_paintbrush_y;
448   short clear;
449 
450   // Comme on a demandé l'effacement du curseur, il n'y a plus de croix en
451   // (Paintbrush_X,Paintbrush_Y). C'est une bonne chose.
452 
453   Operation_stack_size-=2;
454   Operation_pop(&start_y);
455   Operation_pop(&start_x);
456   Operation_pop(&clear);
457 
458   // On efface l'ancienne croix:
459   old_paintbrush_x=Paintbrush_X;
460   old_paintbrush_y=Paintbrush_Y;
461   Paintbrush_X=start_x;
462   Paintbrush_Y=start_y;
463   Hide_cursor(); // Maintenant, il n'y a plus de croix à l'écran.
464 
465   Paintbrush_X=old_paintbrush_x;
466   Paintbrush_Y=old_paintbrush_y;
467 
468   // Prise de la brosse
469   if ((Snap_mode) && (Config.Adjust_brush_pick))
470   {
471     if (Paintbrush_X<start_x)
472     {
473       old_paintbrush_x=start_x;
474       start_x=Paintbrush_X;
475     }
476     if (Paintbrush_Y<start_y)
477     {
478       old_paintbrush_y=start_y;
479       start_y=Paintbrush_Y;
480     }
481     if (old_paintbrush_x!=start_x)
482       old_paintbrush_x--;
483     if (old_paintbrush_y!=start_y)
484       old_paintbrush_y--;
485   }
486   Capture_brush(start_x,start_y,old_paintbrush_x,old_paintbrush_y,clear);
487   if ((Snap_mode) && (Config.Adjust_brush_pick))
488   {
489     Brush_offset_X=(Brush_offset_X/Snap_width)*Snap_width;
490     Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height;
491   }
492 
493   End_of_modification();
494   Return_to_draw_mode();
495 }
496 
497 
498 //////////////////////////////////////////////////////// OPERATION_POLYBRUSH
499 
500 
Polybrush_12_8(void)501 void Polybrush_12_8(void)
502 //  Opération   : OPERATION_POLYBRUSH
503 //  Click Souris: 1 ou 2
504 //  Taille_Pile : 8
505 //
506 //  Souris effacée: Non
507 {
508   short click;
509   short end_y;
510   short end_x;
511   short start_y;
512   short start_x;
513   short color;
514   short initial_y;
515   short initial_x;
516 
517   Operation_pop(&click);
518   Operation_pop(&end_y);
519   Operation_pop(&end_x);
520   Operation_pop(&start_y);
521   Operation_pop(&start_x);
522 
523   if (click==Mouse_K)
524   {
525     // L'utilisateur clique toujours avec le bon bouton de souris
526 
527     if (((start_x!=Paintbrush_X) || (start_y!=Paintbrush_Y)) &&
528         (Polyfill_number_of_points<Config.Nb_max_vertices_per_polygon))
529     {
530       // Il existe un nouveau segment défini par
531       // (start_x,start_y)-(Paintbrush_X,Paintbrush_Y)
532 
533       Hide_cursor();
534       Print_coordinates();
535 
536       // On le place à l'écran
537       Draw_line_preview_xor(start_x,start_y,end_x,end_y,0);
538       Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0);
539 
540       // On peut le rajouter au polygone
541 
542       Polyfill_table_of_points[Polyfill_number_of_points<<1]    =Paintbrush_X;
543       Polyfill_table_of_points[(Polyfill_number_of_points<<1)+1]=Paintbrush_Y;
544       Polyfill_number_of_points++;
545 
546       Operation_push(Paintbrush_X); // Nouveau start_x
547       Operation_push(Paintbrush_Y); // Nouveau start_y
548       Operation_push(Paintbrush_X); // Nouveau end_x
549       Operation_push(Paintbrush_Y); // Nouveau end_y
550       Operation_push(click);
551 
552       Display_cursor();
553     }
554     else
555     {
556       if (Polyfill_number_of_points==Config.Nb_max_vertices_per_polygon)
557       {
558         // Le curseur bouge alors qu'on ne peut plus stocker de segments ?
559 
560         if ((end_x!=Paintbrush_X) || (end_y!=Paintbrush_Y))
561         {
562           Hide_cursor();
563           Print_coordinates();
564 
565           // On le place à l'écran
566           Draw_line_preview_xor(start_x,start_y,end_x,end_y,0);
567           Draw_line_preview_xor(start_x,start_y,Paintbrush_X,Paintbrush_Y,0);
568           Display_cursor();
569         }
570 
571         // On remet les mêmes valeurs (comme si on n'avait pas cliqué):
572         Operation_push(start_x);
573         Operation_push(start_y);
574         Operation_push(Paintbrush_X);
575         Operation_push(Paintbrush_Y);
576         Operation_push(click);
577       }
578       else
579       {
580         Operation_push(Paintbrush_X); // Nouveau start_x
581         Operation_push(Paintbrush_Y); // Nouveau start_y
582         Operation_push(Paintbrush_X); // Nouveau end_x
583         Operation_push(Paintbrush_Y); // Nouveau end_y
584         Operation_push(click);
585       }
586     }
587   }
588   else
589   {
590     // L'utilisateur souhaite arrêter l'opération et refermer le polygone
591 
592     Operation_pop(&color);
593     Operation_pop(&initial_y);
594     Operation_pop(&initial_x);
595 
596     Hide_cursor();
597     Print_coordinates();
598 
599     // Pas besoin d'effacer la ligne (start_x,start_y)-(end_x,end_y)
600     // puisqu'on les efface toutes d'un coup.
601 
602     Capture_brush_with_lasso(Polyfill_number_of_points,Polyfill_table_of_points,click==RIGHT_SIDE);
603     free(Polyfill_table_of_points);
604     Polyfill_table_of_points = NULL;
605 
606     if (click==RIGHT_SIDE)
607       End_of_modification();
608 
609     // On raffiche l'écran pour effacer les traits en xor et pour raffraichir
610     // l'écran si on a découpé une partie de l'image en prenant la brosse.
611     Display_all_screen();
612 
613     Paintbrush_hidden=0;
614 
615     if ((Snap_mode) && (Config.Adjust_brush_pick))
616     {
617       Brush_offset_X=(Brush_offset_X/Snap_width)*Snap_width;
618       Brush_offset_Y=(Brush_offset_Y/Snap_height)*Snap_height;
619     }
620 
621     Return_to_draw_mode();
622     Display_cursor();
623   }
624 }
625 
626 
627 ///////////////////////////////////////////////////// OPERATION_STRETCH_BRUSH
628 
629 
Stretch_brush_12_0(void)630 void Stretch_brush_12_0(void)
631 //
632 // Opération   : OPERATION_STRETCH_BRUSH
633 // Click Souris: 1 ou 2
634 // Taille_Pile : 0
635 //
636 // Souris effacée: Oui
637 //
638 {
639   Init_start_operation();
640   if (Mouse_K==LEFT_SIDE)
641   {
642     // On laisse une trace du curseur pour que l'utilisateur puisse visualiser
643     // où demarre sa brosse:
644     Display_cursor();
645 
646     Operation_push(Paintbrush_X); // Dernier calcul X
647     Operation_push(Paintbrush_Y); // Dernier calcul Y
648     Operation_push(Paintbrush_X); // Début X
649     Operation_push(Paintbrush_Y); // Début Y
650     Operation_push(Paintbrush_X); // Dernière position X
651     Operation_push(Paintbrush_Y); // Dernière position Y
652     Operation_push(1); // State précédent
653 
654     if ((Config.Coords_rel) && (Menu_is_visible))
655       Print_in_menu("\035:   1   \022:   1",0);
656   }
657   else
658   {
659     Wait_end_of_click();
660     Start_operation_stack(Operation_before_interrupt);
661   }
662 }
663 
664 
665 
Stretch_brush_1_7(void)666 void Stretch_brush_1_7(void)
667 //
668 // Opération   : OPERATION_STRETCH_BRUSH
669 // Click Souris: 1
670 // Taille_Pile : 7
671 //
672 // Souris effacée: Non
673 //
674 {
675   char  str[5];
676   short start_x;
677   short start_y;
678   short old_x;
679   short old_y;
680   short width;
681   short height;
682   short prev_state;
683   short dx,dy,x,y;
684 
685   Operation_pop(&prev_state);
686   Operation_pop(&old_y);
687   Operation_pop(&old_x);
688 
689   if ( (Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=2) )
690   {
691     Hide_cursor();
692     Operation_pop(&start_y);
693     Operation_pop(&start_x);
694 
695     if (Menu_is_visible)
696     {
697       if (Config.Coords_rel)
698       {
699         width=((start_x<Paintbrush_X)?Paintbrush_X-start_x:start_x-Paintbrush_X)+1;
700         height=((start_y<Paintbrush_Y)?Paintbrush_Y-start_y:start_y-Paintbrush_Y)+1;
701 
702         if (Snap_mode && Config.Adjust_brush_pick)
703         {
704           if (width>1) width--;
705           if (height>1) height--;
706         }
707 
708         Num2str(width,str,4);
709         Print_in_menu(str,2);
710         Num2str(height,str,4);
711         Print_in_menu(str,11);
712       }
713       else
714         Print_coordinates();
715     }
716 
717     Display_all_screen();
718 
719     x=Paintbrush_X;
720     y=Paintbrush_Y;
721     if (Snap_mode && Config.Adjust_brush_pick)
722     {
723       dx=Paintbrush_X-start_x;
724       dy=Paintbrush_Y-start_y;
725       if (dx<0) x++; else {if (dx>0) x--;}
726       if (dy<0) y++; else {if (dy>0) y--;}
727       Stretch_brush_preview(start_x,start_y,x,y);
728     }
729     else
730       Stretch_brush_preview(start_x,start_y,Paintbrush_X,Paintbrush_Y);
731 
732     old_x=Paintbrush_X;
733     old_y=Paintbrush_Y;
734     Paintbrush_X=start_x;
735     Paintbrush_Y=start_y;
736     Display_cursor();
737     Paintbrush_X=old_x;
738     Paintbrush_Y=old_y;
739     Display_cursor();
740 
741     Operation_stack_size-=2;
742     Operation_push(x);
743     Operation_push(y);
744 
745     Operation_push(start_x);
746     Operation_push(start_y);
747   }
748 
749   Operation_push(Paintbrush_X);
750   Operation_push(Paintbrush_Y);
751   Operation_push(2);
752 }
753 
754 
755 
Stretch_brush_0_7(void)756 void Stretch_brush_0_7(void)
757 //
758 // Opération   : OPERATION_STRETCH_BRUSH
759 // Click Souris: 0
760 // Taille_Pile : 7
761 //
762 // Souris effacée: Non
763 //
764 {
765   char  str[5];
766   short start_x;
767   short start_y;
768   short old_x;
769   short old_y;
770   short width=0;
771   short height=0;
772   byte  size_change;
773   short prev_state;
774 
775   Operation_pop(&prev_state);
776   Operation_pop(&old_y);
777   Operation_pop(&old_x);
778   Operation_pop(&start_y);
779   Operation_pop(&start_x);
780 
781   if ((Paintbrush_X!=old_x) || (Paintbrush_Y!=old_y) || (prev_state!=3))
782   {
783     if (Menu_is_visible)
784     {
785       if (Config.Coords_rel)
786       {
787         width=((start_x<Paintbrush_X)?Paintbrush_X-start_x:start_x-Paintbrush_X)+1;
788         height=((start_y<Paintbrush_Y)?Paintbrush_Y-start_y:start_y-Paintbrush_Y)+1;
789 
790         Num2str(width,str,4);
791         Print_in_menu(str,2);
792         Num2str(height,str,4);
793         Print_in_menu(str,11);
794       }
795       else
796         Print_coordinates();
797     }
798   }
799 
800   // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier
801   // à zero si une operation est en cours (Operation_stack_size!=0)
802   if (Key_ANSI)
803   {
804     size_change=1;
805     switch (Key_ANSI)
806     {
807       case 'd': // Double
808         width=start_x+(Brush_width<<1)-1;
809         height=start_y+(Brush_height<<1)-1;
810         break;
811       case 'x': // Double X
812         width=start_x+(Brush_width<<1)-1;
813         height=start_y+Brush_height-1;
814         break;
815       case 'y': // Double Y
816         width=start_x+Brush_width-1;
817         height=start_y+(Brush_height<<1)-1;
818         break;
819       case 'h': // Moitié
820         width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1;
821         height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1;
822         break;
823       case 'X': // Moitié X
824         width=(Brush_width>1)?start_x+(Brush_width>>1)-1:1;
825         height=start_y+Brush_height-1;
826         break;
827       case 'Y': // Moitié Y
828         width=start_x+Brush_width-1;
829         height=(Brush_height>1)?start_y+(Brush_height>>1)-1:1;
830         break;
831       case 'n': // Normal
832         width=start_x+Brush_width-1;
833         height=start_y+Brush_height-1;
834         break;
835       default :
836         size_change=0;
837     }
838     Key_ANSI=0;
839   }
840   else
841     size_change=0;
842 
843   if (size_change)
844   {
845     // On efface la preview de la brosse (et la croix)
846     Display_all_screen();
847 
848     old_x=Paintbrush_X;
849     old_y=Paintbrush_Y;
850     Paintbrush_X=start_x;
851     Paintbrush_Y=start_y;
852     Display_cursor();
853     Paintbrush_X=old_x;
854     Paintbrush_Y=old_y;
855 
856     Stretch_brush_preview(start_x,start_y,width,height);
857     Display_cursor();
858 
859     Operation_stack_size-=2;
860     Operation_push(width);
861     Operation_push(height);
862   }
863 
864   Operation_push(start_x);
865   Operation_push(start_y);
866   Operation_push(Paintbrush_X);
867   Operation_push(Paintbrush_Y);
868   Operation_push(3);
869 }
870 
871 
Stretch_brush_2_7(void)872 void Stretch_brush_2_7(void)
873 //
874 // Opération   : OPERATION_STRETCH_BRUSH
875 // Click Souris: 2
876 // Taille_Pile : 7
877 //
878 // Souris effacée: Oui
879 //
880 {
881   short computed_x;
882   short computed_y;
883   short start_x;
884   short start_y;
885 
886 
887   Operation_stack_size-=3;
888   Operation_pop(&start_y);
889   Operation_pop(&start_x);
890   Operation_pop(&computed_y);
891   Operation_pop(&computed_x);
892 
893   // On efface la preview de la brosse (et la croix)
894   Display_all_screen();
895 
896   // Et enfin on stocke pour de bon la nouvelle brosse étirée
897   Stretch_brush(start_x,start_y,computed_x,computed_y);
898 
899   Return_to_draw_mode();
900 }
901 
902 
903 //////////////////////////////////////////////////// OPERATION_ROTATE_BRUSH
904 
905 
Rotate_brush_12_0(void)906 void Rotate_brush_12_0(void)
907 //
908 // Opération   : OPERATION_ROTATE_BRUSH
909 // Click Souris: 1 ou 2
910 // Taille_Pile : 0
911 //
912 // Souris effacée: Oui
913 //
914 {
915   Init_start_operation();
916   if (Mouse_K==LEFT_SIDE)
917   {
918     Brush_rotation_center_X=Paintbrush_X+(Brush_width>>1)-Brush_width;
919     Brush_rotation_center_Y=Paintbrush_Y;
920     Brush_rotation_center_is_defined=1;
921     Operation_push(Paintbrush_X); // Dernière position calculée X
922     Operation_push(Paintbrush_Y); // Dernière position calculée Y
923     Operation_push(Paintbrush_X); // Dernière position X
924     Operation_push(Paintbrush_Y); // Dernière position Y
925     Operation_push(1); // State précédent
926 
927     if ((Config.Coords_rel) && (Menu_is_visible))
928       Print_in_menu("Angle:   0\xb0    ",0);
929   }
930   else
931   {
932     Start_operation_stack(Operation_before_interrupt);
933     Wait_end_of_click(); // FIXME: celui-la il donne un résultat pas très chouette en visuel
934   }
935 }
936 
937 
938 
Rotate_brush_1_5(void)939 void Rotate_brush_1_5(void)
940 //
941 // Opération   : OPERATION_ROTATE_BRUSH
942 // Click Souris: 1
943 // Taille_Pile : 5
944 //
945 // Souris effacée: Non
946 //
947 {
948   char  str[8];
949   short old_x;
950   short old_y;
951   short prev_state;
952   double angle;
953   short cursor_x,cursor_y;
954 
955   Operation_pop(&prev_state);
956   Operation_pop(&old_y);
957   Operation_pop(&old_x);
958 
959   // On corrige les coordonnées de la ligne si la touche shift est appuyée...
960   cursor_x = Paintbrush_X;
961   cursor_y = Paintbrush_Y;
962   if(Get_Key_modifiers() & GFX2_MOD_SHIFT)
963     Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&cursor_x,&cursor_y);
964 
965   if ( (cursor_x!=old_x) || (cursor_y!=old_y) || (prev_state!=2) )
966   {
967     if ( (Brush_rotation_center_X==cursor_x)
968       && (Brush_rotation_center_Y==cursor_y) )
969       angle=0.0;
970     else
971     {
972       // Angle from 0 to 2 PI
973       int dx = cursor_x - Brush_rotation_center_X;
974       int dy = -(cursor_y - Brush_rotation_center_Y);
975       angle = atan2((double)dy, (double)dx);
976     }
977 
978     if (Menu_is_visible)
979     {
980       if (Config.Coords_rel)
981       {
982         snprintf(str, sizeof(str), "%4d", (int)(angle*180.0/M_PI));
983         Print_in_menu(str, 6);
984       }
985       else
986         Print_coordinates();
987     }
988 
989     Display_all_screen();
990     Rotate_brush_preview(angle);
991     Display_cursor();
992 
993     Operation_stack_size-=2;
994     Operation_push(cursor_x);
995     Operation_push(cursor_y);
996   }
997 
998 
999   Operation_push(cursor_x);
1000   Operation_push(cursor_y);
1001   Operation_push(2);
1002 }
1003 
1004 
1005 
Rotate_brush_0_5(void)1006 void Rotate_brush_0_5(void)
1007 //
1008 // Opération   : OPERATION_ROTATE_BRUSH
1009 // Click Souris: 0
1010 // Taille_Pile : 5
1011 //
1012 // Souris effacée: Non
1013 //
1014 {
1015   char  str[8];
1016   short old_x;
1017   short old_y;
1018   short computed_x=0;
1019   short computed_y=0;
1020   byte  angle_change;
1021   short prev_state;
1022   double angle=0.0;
1023   short cursor_x, cursor_y;
1024 
1025 
1026   Operation_pop(&prev_state);
1027   Operation_pop(&old_y);
1028   Operation_pop(&old_x);
1029 
1030   // On corrige les coordonnées de la ligne si la touche shift est appuyée...
1031   cursor_x = Paintbrush_X;
1032   cursor_y = Paintbrush_Y;
1033   if(Get_Key_modifiers() & GFX2_MOD_SHIFT)
1034     Clamp_coordinates_regular_angle(Brush_rotation_center_X,Brush_rotation_center_Y,&cursor_x,&cursor_y);
1035 
1036   if ((cursor_x!=old_x) || (cursor_y!=old_y) || (prev_state!=3))
1037   {
1038     Hide_cursor();
1039     if ( (Brush_rotation_center_X==cursor_x)
1040       && (Brush_rotation_center_Y==cursor_y) )
1041       angle=0.0;
1042     else
1043     {
1044       // Angle from 0 to 2 PI
1045       int dx = cursor_x - Brush_rotation_center_X;
1046       int dy = -(cursor_y - Brush_rotation_center_Y);
1047       angle = atan2((double)dy, (double)dx);
1048     }
1049 
1050     if (Menu_is_visible)
1051     {
1052       if (Config.Coords_rel)
1053       {
1054         snprintf(str, sizeof(str), "%4d", (int)(angle*180.0/M_PI));
1055         Print_in_menu(str, 6);
1056       }
1057       else
1058         Print_coordinates();
1059     }
1060     Display_cursor();
1061   }
1062 
1063   // Utilise Key_ANSI au lieu de Key, car Get_input() met ce dernier
1064   // à zero si une operation est en cours (Operation_stack_size!=0)
1065   if (Key_ANSI)
1066   {
1067     angle_change=1;
1068     computed_x=Brush_rotation_center_X;
1069     computed_y=Brush_rotation_center_Y;
1070     switch (Key_ANSI)
1071     {
1072       case '6': angle =       0.0; computed_x++;               break;
1073       case '9': angle = M_PI*0.25; computed_x++; computed_y--; break;
1074       case '8': angle = M_PI*0.5 ;               computed_y--; break;
1075       case '7': angle = M_PI*0.75; computed_x--; computed_y--; break;
1076       case '4': angle = M_PI     ; computed_x--;               break;
1077       case '1': angle =-M_PI*0.75; computed_x--; computed_y++; break;
1078       case '2': angle =-M_PI*0.5 ;               computed_y++; break;
1079       case '3': angle =-M_PI*0.25; computed_x++; computed_y++; break;
1080       default :
1081         angle_change=0;
1082     }
1083     Key_ANSI=0;
1084   }
1085   else
1086     angle_change=0;
1087 
1088   if (angle_change)
1089   {
1090     // On efface la preview de la brosse
1091     Display_all_screen();
1092     Rotate_brush_preview(angle);
1093     Display_cursor();
1094 
1095     Operation_stack_size-=2;
1096     Operation_push(computed_x);
1097     Operation_push(computed_y);
1098   }
1099 
1100   Operation_push(cursor_x);
1101   Operation_push(cursor_y);
1102   Operation_push(3);
1103 }
1104 
1105 
Rotate_brush_2_5(void)1106 void Rotate_brush_2_5(void)
1107 //
1108 // Opération   : OPERATION_ROTATE_BRUSH
1109 // Click Souris: 2
1110 // Taille_Pile : 5
1111 //
1112 // Souris effacée: Oui
1113 //
1114 {
1115   short computed_x;
1116   short computed_y;
1117   int dx,dy;
1118   float angle;
1119 
1120 
1121   // On efface la preview de la brosse
1122   Display_all_screen();
1123 
1124   Operation_stack_size-=3;
1125   Operation_pop(&computed_y);
1126   Operation_pop(&computed_x);
1127 
1128   // Calcul de l'angle par rapport à la dernière position calculée
1129   if ( (Brush_rotation_center_X==computed_x)
1130     && (Brush_rotation_center_Y==computed_y) )
1131     angle=0.0;
1132   else
1133   {
1134     dx=computed_x-Brush_rotation_center_X;
1135     dy=computed_y-Brush_rotation_center_Y;
1136     angle=acos(((float)dx)/sqrt((dx*dx)+(dy*dy)));
1137     if (dy>0) angle=M_2PI-angle;
1138   }
1139 
1140   // Et enfin on stocke pour de bon la nouvelle brosse étirée
1141   Rotate_brush(angle);
1142 
1143   Return_to_draw_mode();
1144 }
1145 
1146 ///////////////////////////////////////////////////// OPERATION_DISTORT_BRUSH
1147 
1148 /// Draws a 2x2 XOR square at the specified picture coordinates, on the screen.
Draw_stretch_spot(short x_pos,short y_pos)1149 void Draw_stretch_spot(short x_pos, short y_pos)
1150 {
1151   short x,y;
1152 
1153   for (y=y_pos-1;y<y_pos+1;y++)
1154     if (y>=Limit_top && y<=Limit_visible_bottom)
1155       for (x=x_pos-1;x<x_pos+1;x++)
1156         if (x>=Limit_left && x<=Limit_visible_right)
1157           Pixel_preview(x,y,xor_lut[Read_pixel(x-Main.offset_X,y-Main.offset_Y)]);
1158   Update_part_of_screen(x_pos-1, y_pos-1, 2, 2);
1159 }
1160 
Distort_brush_0_0(void)1161 void Distort_brush_0_0(void)
1162 //
1163 // Opération   : OPERATION_DISTORT_BRUSH
1164 // Click Souris: 0
1165 // Taille_Pile : 0
1166 //
1167 // Souris effacée: Non
1168 //
1169 {
1170   if ( Menu_is_visible )
1171   {
1172       Print_in_menu("POSITION BRUSH TO START ",0);
1173   }
1174 }
1175 
Distort_brush_1_0(void)1176 void Distort_brush_1_0(void)
1177 //
1178 // Opération   : OPERATION_DISTORT_BRUSH
1179 // Click Souris: 1
1180 // Taille_Pile : 0
1181 //
1182 // Souris effacée: Non
1183 //
1184 {
1185   short x_pos, y_pos;
1186 
1187   Init_start_operation();
1188   Paintbrush_hidden=1;
1189   Hide_cursor();
1190 
1191   // Top left angle
1192   x_pos=Paintbrush_X-Brush_offset_X;
1193   y_pos=Paintbrush_Y-Brush_offset_Y;
1194   Draw_stretch_spot(x_pos,y_pos);
1195   Operation_push(x_pos);
1196   Operation_push(y_pos);
1197 
1198   // Top right angle
1199   x_pos+=Brush_width;
1200   Draw_stretch_spot(x_pos,y_pos);
1201   Operation_push(x_pos);
1202   Operation_push(y_pos);
1203 
1204   // Bottom right angle
1205   y_pos+=Brush_height;
1206   Draw_stretch_spot(x_pos,y_pos);
1207   Operation_push(x_pos);
1208   Operation_push(y_pos);
1209 
1210   // Bottom left angle
1211   x_pos-=Brush_width;
1212   Draw_stretch_spot(x_pos,y_pos);
1213   Operation_push(x_pos);
1214   Operation_push(y_pos);
1215 
1216   Distort_brush_preview(
1217     Operation_stack[1],
1218     Operation_stack[2],
1219     Operation_stack[3],
1220     Operation_stack[4],
1221     Operation_stack[5],
1222     Operation_stack[6],
1223     Operation_stack[7],
1224     Operation_stack[8]);
1225   Display_cursor();
1226   Update_part_of_screen(Paintbrush_X-Brush_offset_X, Paintbrush_Y-Brush_offset_Y, Brush_width, Brush_height);
1227   Wait_end_of_click();
1228   // Erase the message in status bar
1229   if ( (Config.Coords_rel) && (Menu_is_visible) )
1230   {
1231       Print_in_menu("X:       Y:             ",0);
1232   }
1233 }
1234 
Distort_brush_1_8(void)1235 void Distort_brush_1_8(void)
1236 //
1237 //  Opération   : OPERATION_DISTORT_BRUSH
1238 //  Click Souris: 1
1239 //  Taille_Pile : 8
1240 //
1241 //  Souris effacée: No
1242 //
1243 {
1244   // How far (in pixels) you can catch a handle
1245   #define REACH_DISTANCE 100
1246   short i;
1247   short x[4];
1248   short y[4];
1249   long best_distance=REACH_DISTANCE;
1250   short best_spot=-1;
1251 
1252   for (i=3;i>=0;i--)
1253   {
1254     long distance;
1255     Operation_pop(&y[i]);
1256     Operation_pop(&x[i]);
1257     distance=Distance(Paintbrush_X,Paintbrush_Y,x[i],y[i]);
1258     if (distance<best_distance)
1259     {
1260       best_spot=i;
1261       best_distance=distance;
1262     }
1263   }
1264 
1265   for (i=0;i<4;i++)
1266   {
1267     Operation_push(x[i]);
1268     Operation_push(y[i]);
1269   }
1270 
1271   if (best_spot>-1)
1272   {
1273     Operation_push(best_spot);
1274   }
1275   if ( (Config.Coords_rel) && (Menu_is_visible) )
1276   {
1277       Print_in_menu("X:       Y:             ",0);
1278       Print_coordinates();
1279   }
1280 }
1281 
Distort_brush_1_9(void)1282 void Distort_brush_1_9(void)
1283 //
1284 //  Opération   : OPERATION_DISTORT_BRUSH
1285 //  Click Souris: 1
1286 //  Taille_Pile : 9
1287 //
1288 //  Souris effacée: No
1289 //
1290 {
1291   short i;
1292   short x[4];
1293   short y[4];
1294   short selected_corner;
1295 
1296   // Pop all arguments
1297   Operation_pop(&selected_corner);
1298   for (i=3;i>=0;i--)
1299   {
1300     Operation_pop(&y[i]);
1301     Operation_pop(&x[i]);
1302   }
1303 
1304   if (Paintbrush_X!=x[selected_corner] || Paintbrush_Y!=y[selected_corner])
1305   {
1306     Hide_cursor();
1307 
1308     // Easiest refresh mode: make no assumptions on how the brush was
1309     // displayed before.
1310     Display_all_screen();
1311 
1312     x[selected_corner]=Paintbrush_X;
1313     y[selected_corner]=Paintbrush_Y;
1314 
1315     for (i=0;i<4;i++)
1316       Draw_stretch_spot(x[i],y[i]);
1317 
1318     Distort_brush_preview(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]);
1319 
1320     Display_cursor();
1321 
1322     if ( (Config.Coords_rel) && (Menu_is_visible) )
1323     {
1324         Print_in_menu("X:       Y:             ",0);
1325         Print_coordinates();
1326     }
1327     Update_rect(0,0,Screen_width,Menu_Y);
1328   }
1329 
1330   // Push back all arguments
1331   for (i=0;i<4;i++)
1332   {
1333     Operation_push(x[i]);
1334     Operation_push(y[i]);
1335   }
1336   Operation_push(selected_corner);
1337 
1338 }
Distort_brush_0_9(void)1339 void Distort_brush_0_9(void)
1340 //
1341 //  Opération   : OPERATION_DISTORT_BRUSH
1342 //  Click Souris: 0
1343 //  Taille_Pile : 9
1344 //
1345 //  Souris effacée: No
1346 //
1347 {
1348   short selected_corner;
1349   Operation_pop(&selected_corner);
1350 
1351 }
1352 
Distort_brush_2_0(void)1353 void Distort_brush_2_0(void)
1354 //
1355 // Opération   : OPERATION_DISTORT_BRUSH
1356 // Click Souris: 2
1357 // Taille_Pile : 0
1358 //
1359 // Souris effacée: Oui
1360 //
1361 {
1362   Paintbrush_hidden=0;
1363   Display_all_screen();
1364   // Erase the message in status bar
1365   if ( (Config.Coords_rel) && (Menu_is_visible) )
1366   {
1367       Print_in_menu("X:       Y:             ",0);
1368   }
1369   Return_to_draw_mode();
1370 }
1371 
Distort_brush_2_8(void)1372 void Distort_brush_2_8(void)
1373 //
1374 // Opération   : OPERATION_DISTORT_BRUSH
1375 // Click Souris: 2
1376 // Taille_Pile : 8
1377 //
1378 // Souris effacée: Oui
1379 //
1380 {
1381   short i;
1382   short x[4];
1383   short y[4];
1384 
1385   // Pop all arguments
1386   for (i=3;i>=0;i--)
1387   {
1388     Operation_pop(&y[i]);
1389     Operation_pop(&x[i]);
1390   }
1391   Distort_brush(x[0],y[0],x[1],y[1],x[2],y[2],x[3],y[3]);
1392 
1393   Paintbrush_hidden=0;
1394   Display_all_screen();
1395 
1396   Return_to_draw_mode();
1397 }
1398 
1399