[gimp] Bug 758049 - Please add canvas flipping



commit c6b6031f316c7a371d626578d4d4f9dd4ef034a9
Author: Michael Natterer <mitch gimp org>
Date:   Fri Nov 13 18:51:32 2015 +0100

    Bug 758049 - Please add canvas flipping
    
    Enable flipping in the canvas rotate transform matrix, and add some
    menu items to control it. Rename the "Rotate" menu to "Flip & Rotate".

 app/actions/view-actions.c               |  154 ++++++++++++++++++++----------
 app/actions/view-commands.c              |   41 ++++++++
 app/actions/view-commands.h              |    5 +
 app/display/gimpdisplayshell-rotate.c    |   36 +++++++-
 app/display/gimpdisplayshell-rotate.h    |    4 +
 app/display/gimpdisplayshell-transform.h |    9 +-
 app/display/gimpdisplayshell.c           |    4 +-
 app/display/gimpdisplayshell.h           |    2 +
 app/widgets/gimphelp-ids.h               |    1 +
 menus/image-menu.xml.in                  |    3 +
 10 files changed, 201 insertions(+), 58 deletions(-)
---
diff --git a/app/actions/view-actions.c b/app/actions/view-actions.c
index 6efcd9d..a9533a0 100644
--- a/app/actions/view-actions.c
+++ b/app/actions/view-actions.c
@@ -68,7 +68,7 @@ static const GimpActionEntry view_actions[] =
 {
   { "view-menu",                NULL, NC_("view-action", "_View")          },
   { "view-zoom-menu",           NULL, NC_("view-action", "_Zoom")          },
-  { "view-rotate-menu",         NULL, NC_("view-action", "_Rotate")        },
+  { "view-rotate-menu",         NULL, NC_("view-action", "_Flip & Rotate") },
   { "view-padding-color-menu",  NULL, NC_("view-action", "_Padding Color") },
   { "view-move-to-screen-menu", GIMP_STOCK_MOVE_TO_SCREEN,
     NC_("view-action", "Move to Screen"), NULL, NULL, NULL,
@@ -394,6 +394,21 @@ static const GimpRadioActionEntry view_zoom_explicit_actions[] =
     GIMP_HELP_VIEW_ZOOM_OTHER }
 };
 
+static const GimpToggleActionEntry view_flip_actions[] =
+{
+  { "view-flip-horizontally", GIMP_STOCK_FLIP_HORIZONTAL,
+    NC_("view-action", "Flip Horizontally"), NULL, NULL,
+    G_CALLBACK (view_flip_horizontally_cmd_callback),
+    FALSE,
+    GIMP_HELP_VIEW_FLIP },
+
+  { "view-flip-vertically", GIMP_STOCK_FLIP_VERTICAL,
+    NC_("view-action", "Flip Vertically"), NULL, NULL,
+    G_CALLBACK (view_flip_vertically_cmd_callback),
+    FALSE,
+    GIMP_HELP_VIEW_FLIP }
+};
+
 static const GimpEnumActionEntry view_rotate_absolute_actions[] =
 {
   { "view-rotate-set-absolute", NULL,
@@ -402,8 +417,9 @@ static const GimpEnumActionEntry view_rotate_absolute_actions[] =
     NULL },
 
   { "view-rotate-reset", GIMP_STOCK_RESET,
-    NC_("view-action", "_Reset to 0°"), "exclam",
-    NC_("view-action", "Reset the angle of rotation to 0°"),
+    NC_("view-action", "_Reset Flip & Rotate"), "exclam",
+    NC_("view-action",
+        "Reset flipping to unflipped and the angle of rotation to 0°"),
     GIMP_ACTION_SELECT_SET_TO_DEFAULT, FALSE,
     GIMP_HELP_VIEW_ROTATE_RESET },
 };
@@ -577,6 +593,10 @@ view_actions_setup (GimpActionGroup *group)
                                        10000,
                                        G_CALLBACK (view_zoom_explicit_cmd_callback));
 
+  gimp_action_group_add_toggle_actions (group, "view-action",
+                                        view_flip_actions,
+                                        G_N_ELEMENTS (view_flip_actions));
+
   gimp_action_group_add_enum_actions (group, "view-action",
                                       view_rotate_absolute_actions,
                                       G_N_ELEMENTS (view_rotate_absolute_actions),
@@ -633,13 +653,15 @@ void
 view_actions_update (GimpActionGroup *group,
                      gpointer         data)
 {
-  GimpDisplay        *display        = action_data_get_display (data);
-  GimpImage          *image          = NULL;
-  GimpDisplayShell   *shell          = NULL;
-  GimpDisplayOptions *options        = NULL;
-  gchar              *label          = NULL;
-  gboolean            fullscreen     = FALSE;
-  gboolean            revert_enabled = FALSE;   /* able to revert zoom? */
+  GimpDisplay        *display           = action_data_get_display (data);
+  GimpImage          *image             = NULL;
+  GimpDisplayShell   *shell             = NULL;
+  GimpDisplayOptions *options           = NULL;
+  gchar              *label             = NULL;
+  gboolean            fullscreen        = FALSE;
+  gboolean            revert_enabled    = FALSE;   /* able to revert zoom? */
+  gboolean            flip_horizontally = FALSE;
+  gboolean            flip_vertically   = FALSE;
 
   if (display)
     {
@@ -657,6 +679,9 @@ view_actions_update (GimpActionGroup *group,
                  shell->no_image_options);
 
       revert_enabled = gimp_display_shell_scale_can_revert (shell);
+
+      flip_horizontally = shell->flip_horizontally;
+      flip_vertically   = shell->flip_vertically;
     }
 
 #define SET_ACTIVE(action,condition) \
@@ -686,44 +711,50 @@ view_actions_update (GimpActionGroup *group,
                                           _("Re_vert Zoom"));
     }
 
-  SET_SENSITIVE ("view-zoom",            image);
-  SET_SENSITIVE ("view-zoom-minimum",    image);
-  SET_SENSITIVE ("view-zoom-maximum",    image);
-  SET_SENSITIVE ("view-zoom-in",         image);
-  SET_SENSITIVE ("view-zoom-in-accel",   image);
-  SET_SENSITIVE ("view-zoom-in-skip",    image);
-  SET_SENSITIVE ("view-zoom-out",        image);
-  SET_SENSITIVE ("view-zoom-out-accel",  image);
-  SET_SENSITIVE ("view-zoom-out-skip",   image);
-
-  SET_SENSITIVE ("view-zoom-fit-in",     image);
-  SET_SENSITIVE ("view-zoom-fill",       image);
-  SET_SENSITIVE ("view-zoom-selection",  image);
-  SET_SENSITIVE ("view-zoom-revert",     image);
-
-  SET_SENSITIVE ("view-zoom-16-1",       image);
-  SET_SENSITIVE ("view-zoom-16-1-accel", image);
-  SET_SENSITIVE ("view-zoom-8-1",        image);
-  SET_SENSITIVE ("view-zoom-8-1-accel",  image);
-  SET_SENSITIVE ("view-zoom-4-1",        image);
-  SET_SENSITIVE ("view-zoom-4-1-accel",  image);
-  SET_SENSITIVE ("view-zoom-2-1",        image);
-  SET_SENSITIVE ("view-zoom-2-1-accel",  image);
-  SET_SENSITIVE ("view-zoom-1-1",        image);
-  SET_SENSITIVE ("view-zoom-1-1-accel",  image);
-  SET_SENSITIVE ("view-zoom-1-2",        image);
-  SET_SENSITIVE ("view-zoom-1-4",        image);
-  SET_SENSITIVE ("view-zoom-1-8",        image);
-  SET_SENSITIVE ("view-zoom-1-16",       image);
-  SET_SENSITIVE ("view-zoom-other",      image);
-
-  SET_SENSITIVE ("view-rotate-reset",    image);
-  SET_SENSITIVE ("view-rotate-15",       image);
-  SET_SENSITIVE ("view-rotate-345",      image);
-  SET_SENSITIVE ("view-rotate-90",       image);
-  SET_SENSITIVE ("view-rotate-180",      image);
-  SET_SENSITIVE ("view-rotate-270",      image);
-  SET_SENSITIVE ("view-rotate-other",    image);
+  SET_SENSITIVE ("view-zoom",              image);
+  SET_SENSITIVE ("view-zoom-minimum",      image);
+  SET_SENSITIVE ("view-zoom-maximum",      image);
+  SET_SENSITIVE ("view-zoom-in",           image);
+  SET_SENSITIVE ("view-zoom-in-accel",     image);
+  SET_SENSITIVE ("view-zoom-in-skip",      image);
+  SET_SENSITIVE ("view-zoom-out",          image);
+  SET_SENSITIVE ("view-zoom-out-accel",    image);
+  SET_SENSITIVE ("view-zoom-out-skip",     image);
+
+  SET_SENSITIVE ("view-zoom-fit-in",       image);
+  SET_SENSITIVE ("view-zoom-fill",         image);
+  SET_SENSITIVE ("view-zoom-selection",    image);
+  SET_SENSITIVE ("view-zoom-revert",       image);
+
+  SET_SENSITIVE ("view-zoom-16-1",         image);
+  SET_SENSITIVE ("view-zoom-16-1-accel",   image);
+  SET_SENSITIVE ("view-zoom-8-1",          image);
+  SET_SENSITIVE ("view-zoom-8-1-accel",    image);
+  SET_SENSITIVE ("view-zoom-4-1",          image);
+  SET_SENSITIVE ("view-zoom-4-1-accel",    image);
+  SET_SENSITIVE ("view-zoom-2-1",          image);
+  SET_SENSITIVE ("view-zoom-2-1-accel",    image);
+  SET_SENSITIVE ("view-zoom-1-1",          image);
+  SET_SENSITIVE ("view-zoom-1-1-accel",    image);
+  SET_SENSITIVE ("view-zoom-1-2",          image);
+  SET_SENSITIVE ("view-zoom-1-4",          image);
+  SET_SENSITIVE ("view-zoom-1-8",          image);
+  SET_SENSITIVE ("view-zoom-1-16",         image);
+  SET_SENSITIVE ("view-zoom-other",        image);
+
+  SET_SENSITIVE ("view-flip-horizontally", image);
+  SET_ACTIVE    ("view-flip-horizontally", flip_horizontally);
+
+  SET_SENSITIVE ("view-flip-vertically",   image);
+  SET_ACTIVE    ("view-flip-vertically",   flip_vertically);
+
+  SET_SENSITIVE ("view-rotate-reset",      image);
+  SET_SENSITIVE ("view-rotate-15",         image);
+  SET_SENSITIVE ("view-rotate-345",        image);
+  SET_SENSITIVE ("view-rotate-90",         image);
+  SET_SENSITIVE ("view-rotate-180",        image);
+  SET_SENSITIVE ("view-rotate-270",        image);
+  SET_SENSITIVE ("view-rotate-other",      image);
 
   if (image)
     {
@@ -866,9 +897,32 @@ static void
 view_actions_set_rotate (GimpActionGroup  *group,
                          GimpDisplayShell *shell)
 {
-  gchar *label;
+  const gchar *flip;
+  gchar       *label;
+
+  if (shell->flip_horizontally &&
+      shell->flip_vertically)
+    {
+      /* please preserve the trailing space */
+      flip = _("(H+V) ");
+    }
+  else if (shell->flip_horizontally)
+    {
+      /* please preserve the trailing space */
+      flip = _("(H) ");
+    }
+  else if (shell->flip_vertically)
+    {
+      /* please preserve the trailing space */
+      flip = _("(V) ");
+    }
+  else
+    {
+      flip = "";
+    }
 
-  label = g_strdup_printf (_("_Rotate (%d°)"), (gint) shell->rotate_angle);
+  label = g_strdup_printf (_("_Flip %s& Rotate (%d°)"),
+                           flip, (gint) shell->rotate_angle);
   gimp_action_group_set_action_label (group, "view-rotate-menu", label);
   g_free (label);
 }
diff --git a/app/actions/view-commands.c b/app/actions/view-commands.c
index 8662696..08e0a41 100644
--- a/app/actions/view-commands.c
+++ b/app/actions/view-commands.c
@@ -306,6 +306,44 @@ view_dot_for_dot_cmd_callback (GtkAction *action,
 }
 
 void
+view_flip_horizontally_cmd_callback (GtkAction *action,
+                                     gpointer   data)
+{
+  GimpDisplay      *display;
+  GimpDisplayShell *shell;
+  gboolean          active;
+  return_if_no_display (display, data);
+
+  shell = gimp_display_get_shell (display);
+
+  active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+
+  if (active != shell->flip_horizontally)
+    {
+      gimp_display_shell_flip (shell, active, shell->flip_vertically);
+    }
+}
+
+void
+view_flip_vertically_cmd_callback (GtkAction *action,
+                                   gpointer   data)
+{
+  GimpDisplay      *display;
+  GimpDisplayShell *shell;
+  gboolean          active;
+  return_if_no_display (display, data);
+
+  shell = gimp_display_get_shell (display);
+
+  active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
+
+  if (active != shell->flip_vertically)
+    {
+      gimp_display_shell_flip (shell, shell->flip_horizontally, active);
+    }
+}
+
+void
 view_rotate_absolute_cmd_callback (GtkAction *action,
                                    gint       value,
                                    gpointer   data)
@@ -324,6 +362,9 @@ view_rotate_absolute_cmd_callback (GtkAction *action,
                                TRUE);
 
   gimp_display_shell_rotate_to (shell, angle);
+
+  if (value == GIMP_ACTION_SELECT_SET_TO_DEFAULT)
+    gimp_display_shell_flip (shell, FALSE, FALSE);
 }
 
 void
diff --git a/app/actions/view-commands.h b/app/actions/view-commands.h
index df79065..91b3a3a 100644
--- a/app/actions/view-commands.h
+++ b/app/actions/view-commands.h
@@ -50,6 +50,11 @@ void   view_scroll_vertical_cmd_callback       (GtkAction *action,
                                                 gint       value,
                                                 gpointer   data);
 
+void   view_flip_horizontally_cmd_callback     (GtkAction *action,
+                                                gpointer   data);
+void   view_flip_vertically_cmd_callback       (GtkAction *action,
+                                                gpointer   data);
+
 void   view_rotate_absolute_cmd_callback       (GtkAction *action,
                                                 gint       value,
                                                 gpointer   data);
diff --git a/app/display/gimpdisplayshell-rotate.c b/app/display/gimpdisplayshell-rotate.c
index 676c5bd..e928843 100644
--- a/app/display/gimpdisplayshell-rotate.c
+++ b/app/display/gimpdisplayshell-rotate.c
@@ -34,6 +34,24 @@
 /*  public functions  */
 
 void
+gimp_display_shell_flip (GimpDisplayShell *shell,
+                         gboolean          flip_horizontally,
+                         gboolean          flip_vertically)
+{
+  g_return_if_fail (GIMP_IS_DISPLAY_SHELL (shell));
+
+  if (flip_horizontally != shell->flip_horizontally ||
+      flip_vertically   != shell->flip_vertically)
+    {
+      shell->flip_horizontally = flip_horizontally ? TRUE : FALSE;
+      shell->flip_vertically   = flip_vertically   ? TRUE : FALSE;
+
+      gimp_display_shell_rotated (shell);
+      gimp_display_shell_expose_full (shell);
+    }
+}
+
+void
 gimp_display_shell_rotate (GimpDisplayShell *shell,
                            gdouble           delta)
 {
@@ -119,7 +137,10 @@ gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell)
   g_free (shell->rotate_transform);
   g_free (shell->rotate_untransform);
 
-  if (shell->rotate_angle != 0.0 && gimp_display_get_image (shell->display))
+  if ((shell->rotate_angle != 0.0 ||
+       shell->flip_horizontally   ||
+       shell->flip_vertically) &&
+      gimp_display_get_image (shell->display))
     {
       gint    image_width, image_height;
       gdouble cx, cy;
@@ -134,8 +155,17 @@ gimp_display_shell_rotate_update_transform (GimpDisplayShell *shell)
       cy = -shell->offset_y + image_height / 2;
 
       cairo_matrix_init_translate (shell->rotate_transform, cx, cy);
-      cairo_matrix_rotate (shell->rotate_transform,
-                           shell->rotate_angle / 180.0 * G_PI);
+
+      if (shell->rotate_angle != 0.0)
+        cairo_matrix_rotate (shell->rotate_transform,
+                             shell->rotate_angle / 180.0 * G_PI);
+
+      if (shell->flip_horizontally)
+        cairo_matrix_scale (shell->rotate_transform, -1.0, 1.0);
+
+      if (shell->flip_vertically)
+        cairo_matrix_scale (shell->rotate_transform, 1.0, -1.0);
+
       cairo_matrix_translate (shell->rotate_transform, -cx, -cy);
 
       *shell->rotate_untransform = *shell->rotate_transform;
diff --git a/app/display/gimpdisplayshell-rotate.h b/app/display/gimpdisplayshell-rotate.h
index 82d3cb1..4d2b09c 100644
--- a/app/display/gimpdisplayshell-rotate.h
+++ b/app/display/gimpdisplayshell-rotate.h
@@ -19,6 +19,10 @@
 #define __GIMP_DISPLAY_SHELL_ROTATE_H__
 
 
+void   gimp_display_shell_flip                    (GimpDisplayShell *shell,
+                                                   gboolean          flip_horizontally,
+                                                   gboolean          flip_vertically);
+
 void   gimp_display_shell_rotate                  (GimpDisplayShell *shell,
                                                    gdouble           delta);
 void   gimp_display_shell_rotate_to               (GimpDisplayShell *shell,
diff --git a/app/display/gimpdisplayshell-transform.h b/app/display/gimpdisplayshell-transform.h
index f365236..d263cbd 100644
--- a/app/display/gimpdisplayshell-transform.h
+++ b/app/display/gimpdisplayshell-transform.h
@@ -61,8 +61,8 @@ void  gimp_display_shell_zoom_segments        (const GimpDisplayShell *shell,
                                                gdouble                 offset_y);
 
 
-/*  rotate: functions to transform from unrotated but zoomed display
- *  space to rotated display space and back
+/*  rotate: functions to transform from unrotated and unflipped but
+ *  zoomed display space to rotated and filpped display space and back
  */
 
 void  gimp_display_shell_rotate_coords        (const GimpDisplayShell *shell,
@@ -114,8 +114,9 @@ void  gimp_display_shell_unrotate_bounds      (GimpDisplayShell       *shell,
                                                gdouble                *ny2);
 
 
-/*  transform: functions to transform from image space to rotated display
- *  space and back, taking into account scroll offset, scale, and rotation
+/*  transform: functions to transform from image space to rotated
+ *  display space and back, taking into account scroll offset, scale,
+ *  rotation and flipping
  */
 
 void  gimp_display_shell_transform_coords     (const GimpDisplayShell *shell,
diff --git a/app/display/gimpdisplayshell.c b/app/display/gimpdisplayshell.c
index f256810..58f4b4b 100644
--- a/app/display/gimpdisplayshell.c
+++ b/app/display/gimpdisplayshell.c
@@ -1472,7 +1472,9 @@ gimp_display_shell_empty (GimpDisplayShell *shell)
 
   gimp_statusbar_empty (GIMP_STATUSBAR (shell->statusbar));
 
-  shell->rotate_angle = 0.0;
+  shell->flip_horizontally = FALSE;
+  shell->flip_vertically   = FALSE;
+  shell->rotate_angle      = 0.0;
   gimp_display_shell_rotate_update_transform (shell);
 
   gimp_display_shell_expose_full (shell);
diff --git a/app/display/gimpdisplayshell.h b/app/display/gimpdisplayshell.h
index 6419d19..cf09fa7 100644
--- a/app/display/gimpdisplayshell.h
+++ b/app/display/gimpdisplayshell.h
@@ -67,6 +67,8 @@ struct _GimpDisplayShell
   gdouble            scale_x;          /*  horizontal scale factor            */
   gdouble            scale_y;          /*  vertical scale factor              */
 
+  gboolean           flip_horizontally;
+  gboolean           flip_vertically;
   gdouble            rotate_angle;
   cairo_matrix_t    *rotate_transform;
   cairo_matrix_t    *rotate_untransform;
diff --git a/app/widgets/gimphelp-ids.h b/app/widgets/gimphelp-ids.h
index e0e9423..6187064 100644
--- a/app/widgets/gimphelp-ids.h
+++ b/app/widgets/gimphelp-ids.h
@@ -88,6 +88,7 @@
 #define GIMP_HELP_VIEW_ZOOM_FILL                  "gimp-view-zoom-fill"
 #define GIMP_HELP_VIEW_ZOOM_SELECTION             "gimp-view-zoom-selection"
 #define GIMP_HELP_VIEW_ZOOM_OTHER                 "gimp-view-zoom-other"
+#define GIMP_HELP_VIEW_FLIP                       "gimp-view-flip"
 #define GIMP_HELP_VIEW_ROTATE_RESET               "gimp-view-rotate-reset"
 #define GIMP_HELP_VIEW_ROTATE_15                  "gimp-view-rotate-15"
 #define GIMP_HELP_VIEW_ROTATE_90                  "gimp-view-rotate-90"
diff --git a/menus/image-menu.xml.in b/menus/image-menu.xml.in
index 5777f06..bd7eaae 100644
--- a/menus/image-menu.xml.in
+++ b/menus/image-menu.xml.in
@@ -277,6 +277,9 @@
       <menu action="view-rotate-menu" name="Rotate">
         <menuitem action="view-rotate-reset" />
         <separator />
+       <menuitem action="view-flip-horizontally" />
+       <menuitem action="view-flip-vertically" />
+        <separator />
         <menuitem action="view-rotate-15" />
         <menuitem action="view-rotate-345" />
         <menuitem action="view-rotate-90" />


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]