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