1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimpsymmetry-mirror.c
5  * Copyright (C) 2015 Jehan <jehan@gimp.org>
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
19  */
20 
21 #include "config.h"
22 
23 #include <string.h>
24 
25 #include <cairo.h>
26 #include <gegl.h>
27 #include <gdk-pixbuf/gdk-pixbuf.h>
28 
29 #include "libgimpconfig/gimpconfig.h"
30 
31 #include "core-types.h"
32 
33 #include "gimp.h"
34 #include "gimp-cairo.h"
35 #include "gimpbrush.h"
36 #include "gimpguide.h"
37 #include "gimpimage.h"
38 #include "gimpimage-guides.h"
39 #include "gimpimage-symmetry.h"
40 #include "gimpitem.h"
41 #include "gimpsymmetry-mirror.h"
42 
43 #include "gimp-intl.h"
44 
45 
46 enum
47 {
48   PROP_0,
49   PROP_HORIZONTAL_SYMMETRY,
50   PROP_VERTICAL_SYMMETRY,
51   PROP_POINT_SYMMETRY,
52   PROP_DISABLE_TRANSFORMATION,
53   PROP_MIRROR_POSITION_X,
54   PROP_MIRROR_POSITION_Y
55 };
56 
57 
58 /* Local function prototypes */
59 
60 static void       gimp_mirror_constructed             (GObject             *object);
61 static void       gimp_mirror_finalize                (GObject             *object);
62 static void       gimp_mirror_set_property            (GObject             *object,
63                                                        guint                property_id,
64                                                        const GValue        *value,
65                                                        GParamSpec          *pspec);
66 static void       gimp_mirror_get_property            (GObject             *object,
67                                                        guint                property_id,
68                                                        GValue              *value,
69                                                        GParamSpec          *pspec);
70 
71 static void       gimp_mirror_update_strokes          (GimpSymmetry        *mirror,
72                                                        GimpDrawable        *drawable,
73                                                        GimpCoords          *origin);
74 static void       gimp_mirror_get_transform           (GimpSymmetry        *mirror,
75                                                        gint                 stroke,
76                                                        gdouble             *angle,
77                                                        gboolean            *reflect);
78 static void       gimp_mirror_reset                   (GimpMirror          *mirror);
79 static void       gimp_mirror_add_guide               (GimpMirror          *mirror,
80                                                        GimpOrientationType  orientation);
81 static void       gimp_mirror_remove_guide            (GimpMirror          *mirror,
82                                                        GimpOrientationType  orientation);
83 static void       gimp_mirror_guide_removed_cb        (GObject             *object,
84                                                        GimpMirror          *mirror);
85 static void       gimp_mirror_guide_position_cb       (GObject             *object,
86                                                        GParamSpec          *pspec,
87                                                        GimpMirror          *mirror);
88 static void       gimp_mirror_active_changed          (GimpSymmetry        *sym);
89 static void       gimp_mirror_set_horizontal_symmetry (GimpMirror          *mirror,
90                                                        gboolean             active);
91 static void       gimp_mirror_set_vertical_symmetry   (GimpMirror          *mirror,
92                                                        gboolean             active);
93 static void       gimp_mirror_set_point_symmetry      (GimpMirror          *mirror,
94                                                        gboolean             active);
95 
96 static void       gimp_mirror_image_size_changed_cb   (GimpImage           *image,
97                                                        gint                 previous_origin_x,
98                                                        gint                 previous_origin_y,
99                                                        gint                 previous_width,
100                                                        gint                 previous_height,
101                                                        GimpSymmetry        *sym);
102 
G_DEFINE_TYPE(GimpMirror,gimp_mirror,GIMP_TYPE_SYMMETRY)103 G_DEFINE_TYPE (GimpMirror, gimp_mirror, GIMP_TYPE_SYMMETRY)
104 
105 #define parent_class gimp_mirror_parent_class
106 
107 
108 static void
109 gimp_mirror_class_init (GimpMirrorClass *klass)
110 {
111   GObjectClass      *object_class   = G_OBJECT_CLASS (klass);
112   GimpSymmetryClass *symmetry_class = GIMP_SYMMETRY_CLASS (klass);
113   GParamSpec        *pspec;
114 
115   object_class->constructed         = gimp_mirror_constructed;
116   object_class->finalize            = gimp_mirror_finalize;
117   object_class->set_property        = gimp_mirror_set_property;
118   object_class->get_property        = gimp_mirror_get_property;
119 
120   symmetry_class->label             = _("Mirror");
121   symmetry_class->update_strokes    = gimp_mirror_update_strokes;
122   symmetry_class->get_transform     = gimp_mirror_get_transform;
123   symmetry_class->active_changed    = gimp_mirror_active_changed;
124 
125   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_HORIZONTAL_SYMMETRY,
126                             "horizontal-symmetry",
127                             _("Horizontal Symmetry"),
128                             _("Reflect the initial stroke across a horizontal axis"),
129                             FALSE,
130                             GIMP_PARAM_STATIC_STRINGS |
131                             GIMP_SYMMETRY_PARAM_GUI);
132 
133   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_VERTICAL_SYMMETRY,
134                             "vertical-symmetry",
135                             _("Vertical Symmetry"),
136                             _("Reflect the initial stroke across a vertical axis"),
137                             FALSE,
138                             GIMP_PARAM_STATIC_STRINGS |
139                             GIMP_SYMMETRY_PARAM_GUI);
140 
141   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_POINT_SYMMETRY,
142                             "point-symmetry",
143                             _("Central Symmetry"),
144                             _("Invert the initial stroke through a point"),
145                             FALSE,
146                             GIMP_PARAM_STATIC_STRINGS |
147                             GIMP_SYMMETRY_PARAM_GUI);
148 
149   GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_DISABLE_TRANSFORMATION,
150                             "disable-transformation",
151                             _("Disable brush transform"),
152                             _("Disable brush reflection"),
153                             FALSE,
154                             GIMP_PARAM_STATIC_STRINGS |
155                             GIMP_SYMMETRY_PARAM_GUI);
156 
157   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_MIRROR_POSITION_X,
158                            "mirror-position-x",
159                            _("Vertical axis position"),
160                            NULL,
161                            0.0, G_MAXDOUBLE, 0.0,
162                            GIMP_PARAM_STATIC_STRINGS |
163                            GIMP_SYMMETRY_PARAM_GUI);
164 
165   pspec = g_object_class_find_property (object_class, "mirror-position-x");
166   gegl_param_spec_set_property_key (pspec, "unit", "pixel-coordinate");
167   gegl_param_spec_set_property_key (pspec, "axis", "x");
168 
169   GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_MIRROR_POSITION_Y,
170                            "mirror-position-y",
171                            _("Horizontal axis position"),
172                            NULL,
173                            0.0, G_MAXDOUBLE, 0.0,
174                            GIMP_PARAM_STATIC_STRINGS |
175                            GIMP_SYMMETRY_PARAM_GUI);
176 
177   pspec = g_object_class_find_property (object_class, "mirror-position-y");
178   gegl_param_spec_set_property_key (pspec, "unit", "pixel-coordinate");
179   gegl_param_spec_set_property_key (pspec, "axis", "y");
180 }
181 
182 static void
gimp_mirror_init(GimpMirror * mirror)183 gimp_mirror_init (GimpMirror *mirror)
184 {
185 }
186 
187 static void
gimp_mirror_constructed(GObject * object)188 gimp_mirror_constructed (GObject *object)
189 {
190   GimpSymmetry *sym = GIMP_SYMMETRY (object);
191 
192   g_signal_connect_object (sym->image, "size-changed-detailed",
193                            G_CALLBACK (gimp_mirror_image_size_changed_cb),
194                            sym, 0);
195 }
196 
197 static void
gimp_mirror_finalize(GObject * object)198 gimp_mirror_finalize (GObject *object)
199 {
200   GimpMirror *mirror = GIMP_MIRROR (object);
201 
202   g_clear_object (&mirror->horizontal_guide);
203   g_clear_object (&mirror->vertical_guide);
204 
205   G_OBJECT_CLASS (parent_class)->finalize (object);
206 }
207 
208 static void
gimp_mirror_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)209 gimp_mirror_set_property (GObject      *object,
210                           guint         property_id,
211                           const GValue *value,
212                           GParamSpec   *pspec)
213 {
214   GimpMirror *mirror = GIMP_MIRROR (object);
215   GimpImage  *image  = GIMP_SYMMETRY (mirror)->image;
216 
217   switch (property_id)
218     {
219     case PROP_HORIZONTAL_SYMMETRY:
220       gimp_mirror_set_horizontal_symmetry (mirror,
221                                            g_value_get_boolean (value));
222       break;
223 
224     case PROP_VERTICAL_SYMMETRY:
225       gimp_mirror_set_vertical_symmetry (mirror,
226                                          g_value_get_boolean (value));
227       break;
228 
229     case PROP_POINT_SYMMETRY:
230       gimp_mirror_set_point_symmetry (mirror,
231                                       g_value_get_boolean (value));
232       break;
233 
234     case PROP_DISABLE_TRANSFORMATION:
235       mirror->disable_transformation = g_value_get_boolean (value);
236       break;
237 
238     case PROP_MIRROR_POSITION_X:
239       if (g_value_get_double (value) >= 0.0 &&
240           g_value_get_double (value) < (gdouble) gimp_image_get_width (image))
241         {
242           mirror->mirror_position_x = g_value_get_double (value);
243 
244           if (mirror->vertical_guide)
245             {
246               g_signal_handlers_block_by_func (mirror->vertical_guide,
247                                                gimp_mirror_guide_position_cb,
248                                                mirror);
249               gimp_image_move_guide (image, mirror->vertical_guide,
250                                      mirror->mirror_position_x,
251                                      FALSE);
252               g_signal_handlers_unblock_by_func (mirror->vertical_guide,
253                                                  gimp_mirror_guide_position_cb,
254                                                  mirror);
255             }
256         }
257       break;
258 
259     case PROP_MIRROR_POSITION_Y:
260       if (g_value_get_double (value) >= 0.0 &&
261           g_value_get_double (value) < (gdouble) gimp_image_get_height (image))
262         {
263           mirror->mirror_position_y = g_value_get_double (value);
264 
265           if (mirror->horizontal_guide)
266             {
267               g_signal_handlers_block_by_func (mirror->horizontal_guide,
268                                                gimp_mirror_guide_position_cb,
269                                                mirror);
270               gimp_image_move_guide (image, mirror->horizontal_guide,
271                                      mirror->mirror_position_y,
272                                      FALSE);
273               g_signal_handlers_unblock_by_func (mirror->horizontal_guide,
274                                                  gimp_mirror_guide_position_cb,
275                                                  mirror);
276             }
277         }
278       break;
279 
280     default:
281       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
282       break;
283     }
284 }
285 
286 static void
gimp_mirror_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)287 gimp_mirror_get_property (GObject    *object,
288                           guint       property_id,
289                           GValue     *value,
290                           GParamSpec *pspec)
291 {
292   GimpMirror *mirror = GIMP_MIRROR (object);
293 
294   switch (property_id)
295     {
296     case PROP_HORIZONTAL_SYMMETRY:
297       g_value_set_boolean (value, mirror->horizontal_mirror);
298       break;
299     case PROP_VERTICAL_SYMMETRY:
300       g_value_set_boolean (value, mirror->vertical_mirror);
301       break;
302     case PROP_POINT_SYMMETRY:
303       g_value_set_boolean (value, mirror->point_symmetry);
304       break;
305     case PROP_DISABLE_TRANSFORMATION:
306       g_value_set_boolean (value, mirror->disable_transformation);
307       break;
308     case PROP_MIRROR_POSITION_X:
309       g_value_set_double (value, mirror->mirror_position_x);
310       break;
311     case PROP_MIRROR_POSITION_Y:
312       g_value_set_double (value, mirror->mirror_position_y);
313       break;
314     default:
315       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
316       break;
317     }
318 }
319 
320 static void
gimp_mirror_update_strokes(GimpSymmetry * sym,GimpDrawable * drawable,GimpCoords * origin)321 gimp_mirror_update_strokes (GimpSymmetry *sym,
322                             GimpDrawable *drawable,
323                             GimpCoords   *origin)
324 {
325   GimpMirror *mirror  = GIMP_MIRROR (sym);
326   GList      *strokes = NULL;
327   GimpCoords *coords;
328   gdouble     mirror_position_x, mirror_position_y;
329   gint        offset_x,          offset_y;
330 
331   gimp_item_get_offset (GIMP_ITEM (drawable), &offset_x, &offset_y);
332 
333   mirror_position_x = mirror->mirror_position_x - offset_x;
334   mirror_position_y = mirror->mirror_position_y - offset_y;
335 
336   g_list_free_full (sym->strokes, g_free);
337   strokes = g_list_prepend (strokes,
338                             g_memdup (origin, sizeof (GimpCoords)));
339 
340   if (mirror->horizontal_mirror)
341     {
342       coords = g_memdup (origin, sizeof (GimpCoords));
343       coords->y = 2.0 * mirror_position_y - origin->y;
344       strokes = g_list_prepend (strokes, coords);
345     }
346 
347   if (mirror->vertical_mirror)
348     {
349       coords = g_memdup (origin, sizeof (GimpCoords));
350       coords->x = 2.0 * mirror_position_x - origin->x;
351       strokes = g_list_prepend (strokes, coords);
352     }
353 
354   if (mirror->point_symmetry)
355     {
356       coords = g_memdup (origin, sizeof (GimpCoords));
357       coords->x = 2.0 * mirror_position_x - origin->x;
358       coords->y = 2.0 * mirror_position_y - origin->y;
359       strokes = g_list_prepend (strokes, coords);
360     }
361 
362   sym->strokes = g_list_reverse (strokes);
363 
364   g_signal_emit_by_name (sym, "strokes-updated", sym->image);
365 }
366 
367 static void
gimp_mirror_get_transform(GimpSymmetry * sym,gint stroke,gdouble * angle,gboolean * reflect)368 gimp_mirror_get_transform (GimpSymmetry *sym,
369                            gint          stroke,
370                            gdouble      *angle,
371                            gboolean     *reflect)
372 {
373   GimpMirror *mirror = GIMP_MIRROR (sym);
374 
375   if (mirror->disable_transformation)
376     return;
377 
378   if (! mirror->horizontal_mirror && stroke >= 1)
379     stroke++;
380 
381   if (! mirror->vertical_mirror && stroke >= 2)
382     stroke++;
383 
384   switch (stroke)
385     {
386     /* original */
387     case 0:
388       break;
389 
390     /* horizontal */
391     case 1:
392       *angle   = 180.0;
393       *reflect = TRUE;
394       break;
395 
396     /* vertical */
397     case 2:
398       *reflect = TRUE;
399       break;
400 
401     /* central */
402     case 3:
403       *angle   = 180.0;
404       break;
405 
406     default:
407       g_return_if_reached ();
408     }
409 }
410 
411 static void
gimp_mirror_reset(GimpMirror * mirror)412 gimp_mirror_reset (GimpMirror *mirror)
413 {
414   GimpSymmetry *sym = GIMP_SYMMETRY (mirror);
415 
416   if (sym->origin)
417     {
418       gimp_symmetry_set_origin (sym, sym->drawable,
419                                 sym->origin);
420     }
421 }
422 
423 static void
gimp_mirror_add_guide(GimpMirror * mirror,GimpOrientationType orientation)424 gimp_mirror_add_guide (GimpMirror          *mirror,
425                        GimpOrientationType  orientation)
426 {
427   GimpSymmetry *sym = GIMP_SYMMETRY (mirror);
428   GimpImage    *image;
429   Gimp         *gimp;
430   GimpGuide    *guide;
431   gdouble       position;
432 
433   image = sym->image;
434   gimp  = image->gimp;
435 
436   guide = gimp_guide_custom_new (orientation,
437                                  gimp->next_guide_ID++,
438                                  GIMP_GUIDE_STYLE_MIRROR);
439 
440   if (orientation == GIMP_ORIENTATION_HORIZONTAL)
441     {
442       /* Mirror guide position at first activation is at canvas middle. */
443       if (mirror->mirror_position_y < 1.0)
444         position = gimp_image_get_height (image) / 2.0;
445       else
446         position = mirror->mirror_position_y;
447 
448       g_object_set (mirror,
449                     "mirror-position-y", position,
450                     NULL);
451 
452       mirror->horizontal_guide = guide;
453     }
454   else
455     {
456       /* Mirror guide position at first activation is at canvas middle. */
457       if (mirror->mirror_position_x < 1.0)
458         position = gimp_image_get_width (image) / 2.0;
459       else
460         position = mirror->mirror_position_x;
461 
462       g_object_set (mirror,
463                     "mirror-position-x", position,
464                     NULL);
465 
466       mirror->vertical_guide = guide;
467     }
468 
469   g_signal_connect (guide, "removed",
470                     G_CALLBACK (gimp_mirror_guide_removed_cb),
471                     mirror);
472 
473   gimp_image_add_guide (image, guide, (gint) position);
474 
475   g_signal_connect (guide, "notify::position",
476                     G_CALLBACK (gimp_mirror_guide_position_cb),
477                     mirror);
478 }
479 
480 static void
gimp_mirror_remove_guide(GimpMirror * mirror,GimpOrientationType orientation)481 gimp_mirror_remove_guide (GimpMirror          *mirror,
482                           GimpOrientationType  orientation)
483 {
484   GimpSymmetry *sym = GIMP_SYMMETRY (mirror);
485   GimpImage    *image;
486   GimpGuide    *guide;
487 
488   image = sym->image;
489   guide = (orientation == GIMP_ORIENTATION_HORIZONTAL) ?
490     mirror->horizontal_guide : mirror->vertical_guide;
491 
492   /* The guide may have already been removed, for instance from GUI. */
493   if (guide)
494     {
495       g_signal_handlers_disconnect_by_func (G_OBJECT (guide),
496                                             gimp_mirror_guide_removed_cb,
497                                             mirror);
498       g_signal_handlers_disconnect_by_func (G_OBJECT (guide),
499                                             gimp_mirror_guide_position_cb,
500                                             mirror);
501 
502       gimp_image_remove_guide (image, guide, FALSE);
503       g_object_unref (guide);
504 
505       if (orientation == GIMP_ORIENTATION_HORIZONTAL)
506         mirror->horizontal_guide = NULL;
507       else
508         mirror->vertical_guide = NULL;
509     }
510 }
511 
512 static void
gimp_mirror_guide_removed_cb(GObject * object,GimpMirror * mirror)513 gimp_mirror_guide_removed_cb (GObject    *object,
514                               GimpMirror *mirror)
515 {
516   GimpSymmetry *symmetry = GIMP_SYMMETRY (mirror);
517 
518   g_signal_handlers_disconnect_by_func (object,
519                                         gimp_mirror_guide_removed_cb,
520                                         mirror);
521   g_signal_handlers_disconnect_by_func (object,
522                                         gimp_mirror_guide_position_cb,
523                                         mirror);
524 
525   if (GIMP_GUIDE (object) == mirror->horizontal_guide)
526     {
527       g_object_unref (mirror->horizontal_guide);
528       mirror->horizontal_guide    = NULL;
529 
530       g_object_set (mirror,
531                     "horizontal-symmetry", FALSE,
532                     NULL);
533       g_object_set (mirror,
534                     "point-symmetry", FALSE,
535                     NULL);
536       g_object_set (mirror,
537                     "mirror-position-y", 0.0,
538                     NULL);
539 
540       if (mirror->vertical_guide &&
541           ! mirror->vertical_mirror)
542         {
543           g_signal_handlers_disconnect_by_func (G_OBJECT (mirror->vertical_guide),
544                                                 gimp_mirror_guide_removed_cb,
545                                                 mirror);
546           g_signal_handlers_disconnect_by_func (G_OBJECT (mirror->vertical_guide),
547                                                 gimp_mirror_guide_position_cb,
548                                                 mirror);
549 
550           gimp_image_remove_guide (symmetry->image,
551                                    mirror->vertical_guide,
552                                    FALSE);
553           g_clear_object (&mirror->vertical_guide);
554         }
555     }
556   else if (GIMP_GUIDE (object) == mirror->vertical_guide)
557     {
558       g_object_unref (mirror->vertical_guide);
559       mirror->vertical_guide    = NULL;
560 
561       g_object_set (mirror,
562                     "vertical-symmetry", FALSE,
563                     NULL);
564       g_object_set (mirror,
565                     "point-symmetry", FALSE,
566                     NULL);
567       g_object_set (mirror,
568                     "mirror-position-x", 0.0,
569                     NULL);
570 
571       if (mirror->horizontal_guide &&
572           ! mirror->horizontal_mirror)
573         {
574           g_signal_handlers_disconnect_by_func (G_OBJECT (mirror->horizontal_guide),
575                                                 gimp_mirror_guide_removed_cb,
576                                                 mirror);
577           g_signal_handlers_disconnect_by_func (G_OBJECT (mirror->horizontal_guide),
578                                                 gimp_mirror_guide_position_cb,
579                                                 mirror);
580 
581           gimp_image_remove_guide (symmetry->image,
582                                    mirror->horizontal_guide,
583                                    FALSE);
584           g_clear_object (&mirror->horizontal_guide);
585         }
586     }
587 
588   if (mirror->horizontal_guide == NULL &&
589       mirror->vertical_guide   == NULL)
590     {
591       gimp_image_symmetry_remove (symmetry->image,
592                                   GIMP_SYMMETRY (mirror));
593     }
594   else
595     {
596       gimp_mirror_reset (mirror);
597       g_signal_emit_by_name (mirror, "gui-param-changed",
598                              GIMP_SYMMETRY (mirror)->image);
599     }
600 }
601 
602 static void
gimp_mirror_guide_position_cb(GObject * object,GParamSpec * pspec,GimpMirror * mirror)603 gimp_mirror_guide_position_cb (GObject    *object,
604                                GParamSpec *pspec,
605                                GimpMirror *mirror)
606 {
607   GimpGuide *guide = GIMP_GUIDE (object);
608 
609   if (guide == mirror->horizontal_guide)
610     {
611       g_object_set (mirror,
612                     "mirror-position-y", (gdouble) gimp_guide_get_position (guide),
613                     NULL);
614     }
615   else if (guide == mirror->vertical_guide)
616     {
617       g_object_set (mirror,
618                     "mirror-position-x", (gdouble) gimp_guide_get_position (guide),
619                     NULL);
620     }
621 }
622 
623 static void
gimp_mirror_active_changed(GimpSymmetry * sym)624 gimp_mirror_active_changed (GimpSymmetry *sym)
625 {
626   GimpMirror *mirror = GIMP_MIRROR (sym);
627 
628   if (sym->active)
629     {
630       if ((mirror->horizontal_mirror || mirror->point_symmetry) &&
631           ! mirror->horizontal_guide)
632         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
633 
634       if ((mirror->vertical_mirror || mirror->point_symmetry) &&
635           ! mirror->vertical_guide)
636         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_VERTICAL);
637     }
638   else
639     {
640       if (mirror->horizontal_guide)
641         gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
642 
643       if (mirror->vertical_guide)
644         gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_VERTICAL);
645     }
646 }
647 
648 static void
gimp_mirror_set_horizontal_symmetry(GimpMirror * mirror,gboolean active)649 gimp_mirror_set_horizontal_symmetry (GimpMirror *mirror,
650                                      gboolean    active)
651 {
652   if (active == mirror->horizontal_mirror)
653     return;
654 
655   mirror->horizontal_mirror = active;
656 
657   if (active)
658     {
659       if (! mirror->horizontal_guide)
660         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
661     }
662   else if (! mirror->point_symmetry)
663     {
664       gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
665     }
666 
667   gimp_mirror_reset (mirror);
668 }
669 
670 static void
gimp_mirror_set_vertical_symmetry(GimpMirror * mirror,gboolean active)671 gimp_mirror_set_vertical_symmetry (GimpMirror *mirror,
672                                    gboolean    active)
673 {
674   if (active == mirror->vertical_mirror)
675     return;
676 
677   mirror->vertical_mirror = active;
678 
679   if (active)
680     {
681       if (! mirror->vertical_guide)
682         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_VERTICAL);
683     }
684   else if (! mirror->point_symmetry)
685     {
686       gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_VERTICAL);
687     }
688 
689   gimp_mirror_reset (mirror);
690 }
691 
692 static void
gimp_mirror_set_point_symmetry(GimpMirror * mirror,gboolean active)693 gimp_mirror_set_point_symmetry (GimpMirror *mirror,
694                                 gboolean    active)
695 {
696   if (active == mirror->point_symmetry)
697     return;
698 
699   mirror->point_symmetry = active;
700 
701   if (active)
702     {
703       /* Show the horizontal guide unless already shown */
704       if (! mirror->horizontal_guide)
705         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
706 
707       /* Show the vertical guide unless already shown */
708       if (! mirror->vertical_guide)
709         gimp_mirror_add_guide (mirror, GIMP_ORIENTATION_VERTICAL);
710     }
711   else
712     {
713       /* Remove the horizontal guide unless needed by horizontal mirror */
714       if (! mirror->horizontal_mirror)
715         gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_HORIZONTAL);
716 
717       /* Remove the vertical guide unless needed by vertical mirror */
718       if (! mirror->vertical_mirror)
719         gimp_mirror_remove_guide (mirror, GIMP_ORIENTATION_VERTICAL);
720     }
721 
722   gimp_mirror_reset (mirror);
723 }
724 
725 static void
gimp_mirror_image_size_changed_cb(GimpImage * image,gint previous_origin_x,gint previous_origin_y,gint previous_width,gint previous_height,GimpSymmetry * sym)726 gimp_mirror_image_size_changed_cb (GimpImage    *image,
727                                    gint          previous_origin_x,
728                                    gint          previous_origin_y,
729                                    gint          previous_width,
730                                    gint          previous_height,
731                                    GimpSymmetry *sym)
732 {
733   if (previous_width != gimp_image_get_width (image) ||
734       previous_height != gimp_image_get_height (image))
735     {
736       g_signal_emit_by_name (sym, "gui-param-changed", sym->image);
737     }
738 }
739