From 4bb1605386b247bca5c12a726757f79f2753f014 Mon Sep 17 00:00:00 2001 From: Philipp Matthias Schaefer Date: Sat, 21 Jan 2017 19:51:13 +0100 Subject: [PATCH] Allow images to be flipped vertically and horizontally A new menu (_Flip) has been added under View with two entries for vertically and horizontally flipping the image. --- src/image_viewer.c | 84 ++++++++++++++++++++++++++++++- src/main_window.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ src/main_window_ui.xml | 4 ++ 3 files changed, 221 insertions(+), 1 deletion(-) diff --git a/src/image_viewer.c b/src/image_viewer.c index 43cfd8b..72c4b30 100644 --- a/src/image_viewer.c +++ b/src/image_viewer.c @@ -741,11 +741,15 @@ set_scale (RsttoImageViewer *viewer, gdouble scale ) { case RSTTO_IMAGE_ORIENT_90: case RSTTO_IMAGE_ORIENT_270: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: v_scale = (gdouble)(allocation.width) / (gdouble)viewer->priv->image_height; h_scale = (gdouble)(allocation.height) / (gdouble)viewer->priv->image_width; break; case RSTTO_IMAGE_ORIENT_NONE: case RSTTO_IMAGE_ORIENT_180: + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: default: v_scale = (gdouble)(allocation.width) / (gdouble)viewer->priv->image_width; h_scale = (gdouble)(allocation.height) / (gdouble)viewer->priv->image_height; @@ -990,6 +994,8 @@ correct_adjustments (RsttoImageViewer *viewer) { case RSTTO_IMAGE_ORIENT_NONE: case RSTTO_IMAGE_ORIENT_180: + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: default: gtk_adjustment_set_upper ( viewer->hadjustment, @@ -1027,6 +1033,8 @@ correct_adjustments (RsttoImageViewer *viewer) break; case RSTTO_IMAGE_ORIENT_90: case RSTTO_IMAGE_ORIENT_270: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: gtk_adjustment_set_upper ( viewer->hadjustment, floor(image_height * scale)); @@ -1173,6 +1181,7 @@ paint_image (GtkWidget *widget, cairo_t *ctx) gint block_height = 10; gdouble bg_scale = 1.0; GtkAllocation allocation; + cairo_matrix_t transform_matrix; gtk_widget_get_allocation (widget, &allocation); @@ -1182,6 +1191,8 @@ paint_image (GtkWidget *widget, cairo_t *ctx) { case RSTTO_IMAGE_ORIENT_90: case RSTTO_IMAGE_ORIENT_270: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: viewer->priv->rendering.x_offset = ((gdouble)allocation.width - ( (gdouble)viewer->priv->image_height * viewer->priv->scale) ) / 2.0; @@ -1195,6 +1206,8 @@ paint_image (GtkWidget *widget, cairo_t *ctx) break; case RSTTO_IMAGE_ORIENT_NONE: case RSTTO_IMAGE_ORIENT_180: + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: default: viewer->priv->rendering.x_offset = ((gdouble)allocation.width - ( (gdouble)viewer->priv->image_width * @@ -1272,9 +1285,74 @@ paint_image (GtkWidget *widget, cairo_t *ctx) /* END PAINT CHECKERED BACKGROUND */ cairo_restore (ctx); - /* TODO: make this work for all rotations */ switch (viewer->priv->orientation) { + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + cairo_translate ( + ctx, + 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment)), + 0.0 - floor(gtk_adjustment_get_value (viewer->vadjustment))); + cairo_translate ( + ctx, + viewer->priv->image_width * viewer->priv->scale, + 0.0); + cairo_translate ( + ctx, + x_offset, + y_offset); + cairo_matrix_init_identity(&transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform(ctx, &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + cairo_translate ( + ctx, + 0.0 - floor(gtk_adjustment_get_value (viewer->hadjustment)), + 0.0 - floor(gtk_adjustment_get_value (viewer->vadjustment))); + cairo_translate ( + ctx, + 0.0, + viewer->priv->image_height * viewer->priv->scale); + cairo_translate ( + ctx, + x_offset, + y_offset); + cairo_matrix_init_identity(&transform_matrix); + transform_matrix.yy = -1.0; + cairo_transform(ctx, &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + cairo_rotate ( ctx, M_PI*1.5); + cairo_translate ( + ctx, + floor(gtk_adjustment_get_value (viewer->vadjustment)), + floor(0.0 - gtk_adjustment_get_value (viewer->hadjustment))); + cairo_translate ( + ctx, + -1.0 * y_offset, + x_offset); + cairo_matrix_init_identity(&transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform(ctx, &transform_matrix); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + cairo_rotate ( ctx, M_PI*0.5); + cairo_translate ( + ctx, + floor(0.0 - gtk_adjustment_get_value (viewer->vadjustment)), + floor(gtk_adjustment_get_value (viewer->hadjustment))); + cairo_translate ( + ctx, + viewer->priv->image_width * viewer->priv->scale, + -1.0 * viewer->priv->image_height * viewer->priv->scale); + cairo_translate ( + ctx, + y_offset, + -1.0 * x_offset); + cairo_matrix_init_identity(&transform_matrix); + transform_matrix.xx = -1.0; + cairo_transform(ctx, &transform_matrix); + break; case RSTTO_IMAGE_ORIENT_90: cairo_rotate ( ctx, @@ -2277,11 +2355,15 @@ rstto_scroll_event (GtkWidget *widget, GdkEventScroll *event) { case RSTTO_IMAGE_ORIENT_90: case RSTTO_IMAGE_ORIENT_270: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: v_scale = (gdouble)(allocation.width) / (gdouble)viewer->priv->image_height; h_scale = (gdouble)(allocation.height) / (gdouble)viewer->priv->image_width; break; case RSTTO_IMAGE_ORIENT_NONE: case RSTTO_IMAGE_ORIENT_180: + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: default: v_scale = (gdouble)(allocation.width) / (gdouble)viewer->priv->image_width; h_scale = (gdouble)(allocation.height) / (gdouble)viewer->priv->image_height; diff --git a/src/main_window.c b/src/main_window.c index 2db3f77..cbf2fa5 100644 --- a/src/main_window.c +++ b/src/main_window.c @@ -205,6 +205,11 @@ static void cb_rstto_main_window_rotate_ccw (GtkWidget *widget, RsttoMainWindow *window); static void +cb_rstto_main_window_flip_hz (GtkWidget *widget, RsttoMainWindow *window); +static void +cb_rstto_main_window_flip_vt (GtkWidget *widget, RsttoMainWindow *window); + +static void cb_rstto_main_window_next_image (GtkWidget *widget, RsttoMainWindow *window); static void cb_rstto_main_window_previous_image (GtkWidget *widget, RsttoMainWindow *window); @@ -500,6 +505,23 @@ static GtkActionEntry action_entries[] = "bracketleft", /* Keyboard shortcut */ NULL, /* Tooltip text */ G_CALLBACK (cb_rstto_main_window_rotate_ccw), }, +/* Flip submenu */ + { "flip-menu", + NULL, + N_ ("_Flip"), + NULL, }, + { "flip-horizontally", + "object-flip-horizontal", + N_ ("Flip _Horizontally"), /* Label-text */ + "braceright", /* Keyboard shortcut */ + NULL, /* Tooltip text */ + G_CALLBACK (cb_rstto_main_window_flip_hz), }, + { "flip-vertically", + "object-flip-vertical", + N_ ("Flip _Vertically"), /* Label-text */ + "braceleft", /* Keyboard shortcut */ + NULL, /* Tooltip text */ + G_CALLBACK (cb_rstto_main_window_flip_vt), }, /* Go Menu */ { "go-menu", NULL, @@ -2817,6 +2839,18 @@ cb_rstto_main_window_rotate_cw (GtkWidget *widget, RsttoMainWindow *window) case RSTTO_IMAGE_ORIENT_270: rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_NONE); break; + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_VERTICAL); + break; } rstto_main_window_update_statusbar(window); } @@ -2847,6 +2881,106 @@ cb_rstto_main_window_rotate_ccw (GtkWidget *widget, RsttoMainWindow *window) case RSTTO_IMAGE_ORIENT_270: rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_180); break; + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_VERTICAL); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL); + break; + } + rstto_main_window_update_statusbar(window); +} + +/**********************/ +/* FLIP CALLBACKS */ +/**********************/ + +/** + * cb_rstto_main_window_flip_hz: + * @widget: + * @window: + * + * + */ +static void +cb_rstto_main_window_flip_hz (GtkWidget *widget, RsttoMainWindow *window) +{ + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER(window->priv->image_viewer); + switch (rstto_image_viewer_get_orientation (viewer)) + { + default: + case RSTTO_IMAGE_ORIENT_NONE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL); + break; + case RSTTO_IMAGE_ORIENT_90: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE); + break; + case RSTTO_IMAGE_ORIENT_180: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_VERTICAL); + break; + case RSTTO_IMAGE_ORIENT_270: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_NONE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_180); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_90); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_270); + break; + } + rstto_main_window_update_statusbar(window); +} + +/** + * cb_rstto_main_window_flip_vt: + * @widget: + * @window: + * + * + */ +static void +cb_rstto_main_window_flip_vt (GtkWidget *widget, RsttoMainWindow *window) +{ + RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER(window->priv->image_viewer); + switch (rstto_image_viewer_get_orientation (viewer)) + { + default: + case RSTTO_IMAGE_ORIENT_NONE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_VERTICAL); + break; + case RSTTO_IMAGE_ORIENT_90: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE); + break; + case RSTTO_IMAGE_ORIENT_180: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL); + break; + case RSTTO_IMAGE_ORIENT_270: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_HORIZONTAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_180); + break; + case RSTTO_IMAGE_ORIENT_FLIP_VERTICAL: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_NONE); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSPOSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_270); + break; + case RSTTO_IMAGE_ORIENT_FLIP_TRANSVERSE: + rstto_image_viewer_set_orientation (viewer, RSTTO_IMAGE_ORIENT_90); + break; } rstto_main_window_update_statusbar(window); } diff --git a/src/main_window_ui.xml b/src/main_window_ui.xml index 435f2db..6fc324b 100644 --- a/src/main_window_ui.xml +++ b/src/main_window_ui.xml @@ -59,6 +59,10 @@ + + + + -- 2.10.2