[gnome-photos] application, help-overlay, preview-view: Hook up zooming to GActions
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-photos] application, help-overlay, preview-view: Hook up zooming to GActions
- Date: Tue, 6 Jun 2017 09:54:22 +0000 (UTC)
commit c7ddf601fe714c06899ea779d0de2ba364717b34
Author: Debarshi Ray <debarshir gnome org>
Date: Wed Mar 29 11:03:39 2017 +0200
application, help-overlay, preview-view: Hook up zooming to GActions
There is no upper limit for the zoom, but we use the best-fit zoom
level as the lower limit. Best-fit is defined as the size of the image
in device pixels or the ImageView's allocation in device pixels,
whichever is smaller. See commit ccf511c2d6e2dd90 for a longer
explanation.
The initial zoom-in is much bigger compared to subsequent increments,
but zooming out always uses the smaller increments.
All the above policy is implemented in PreviewView, outside the
ImageView widget. Currently, we don't update the best-fit zoom factor
value when the window is resized. Users with particularly large
displays will notice that increasing the window size lets them
zoom-out beyond the best-fit value corresponding to the bigger window.
Similarly shrinking the window might skip the last few zoom-out steps
and jump directly to the best-fit level. However, the zoom increments
seem large enough for this to not be an issue in practice. Even if
someone does encounter this oddity, it is unlikely to be a real
annoyance.
https://bugzilla.gnome.org/show_bug.cgi?id=742662
src/photos-application.c | 27 +++++++++
src/photos-help-overlay.ui | 21 +++++++
src/photos-preview-view.c | 136 ++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 184 insertions(+), 0 deletions(-)
---
diff --git a/src/photos-application.c b/src/photos-application.c
index 35505c4..5b7c604 100644
--- a/src/photos-application.c
+++ b/src/photos-application.c
@@ -111,6 +111,9 @@ struct _PhotosApplication
GSimpleAction *set_ss_action;
GSimpleAction *share_action;
GSimpleAction *sharpen_action;
+ GSimpleAction *zoom_best_fit_action;
+ GSimpleAction *zoom_in_action;
+ GSimpleAction *zoom_out_action;
GtkWidget *main_window;
PhotosBaseManager *shr_pnt_mngr;
PhotosCameraCache *camera_cache;
@@ -337,6 +340,9 @@ photos_application_actions_update (PhotosApplication *self)
selection = photos_selection_controller_get_selection (self->sel_cntrlr);
selection_mode = photos_utils_get_selection_mode ();
+ g_simple_action_set_enabled (self->zoom_best_fit_action, FALSE);
+ g_simple_action_set_enabled (self->zoom_out_action, FALSE);
+
enable = (mode == PHOTOS_WINDOW_MODE_EDIT);
g_simple_action_set_enabled (self->blacks_exposure_action, enable);
g_simple_action_set_enabled (self->brightness_contrast_action, enable);
@@ -367,6 +373,7 @@ photos_application_actions_update (PhotosApplication *self)
g_simple_action_set_enabled (self->gear_action, enable);
g_simple_action_set_enabled (self->set_bg_action, enable);
g_simple_action_set_enabled (self->set_ss_action, enable);
+ g_simple_action_set_enabled (self->zoom_in_action, enable);
enable = ((load_state == PHOTOS_LOAD_STATE_FINISHED && mode == PHOTOS_WINDOW_MODE_PREVIEW)
|| (selection_mode && item != NULL));
@@ -817,6 +824,8 @@ photos_application_edit_current (PhotosApplication *self)
item = PHOTOS_BASE_ITEM (photos_base_manager_get_active_object (self->state->item_mngr));
g_return_if_fail (item != NULL);
+ g_action_activate (G_ACTION (self->zoom_best_fit_action), NULL);
+
photos_base_item_pipeline_snapshot (item);
photos_mode_controller_set_window_mode (self->state->mode_cntrlr, PHOTOS_WINDOW_MODE_EDIT);
}
@@ -1689,6 +1698,9 @@ photos_application_startup (GApplication *application)
const gchar *save_accels[2] = {"<Primary>x", NULL};
const gchar *search_accels[2] = {"<Primary>f", NULL};
const gchar *select_all_accels[2] = {"<Primary>a", NULL};
+ const gchar *zoom_best_fit_accels[3] = {"<Primary>0", NULL};
+ const gchar *zoom_in_accels[3] = {"<Primary>plus", "<Primary>equal", NULL};
+ const gchar *zoom_out_accels[2] = {"<Primary>minus", NULL};
G_APPLICATION_CLASS (photos_application_parent_class)->startup (application);
@@ -1901,6 +1913,15 @@ photos_application_startup (GApplication *application)
self->sharpen_action = g_simple_action_new ("sharpen-current", G_VARIANT_TYPE_DOUBLE);
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->sharpen_action));
+ self->zoom_best_fit_action = g_simple_action_new ("zoom-best-fit", NULL);
+ g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_best_fit_action));
+
+ self->zoom_in_action = g_simple_action_new ("zoom-in", NULL);
+ g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_in_action));
+
+ self->zoom_out_action = g_simple_action_new ("zoom-out", NULL);
+ g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (self->zoom_out_action));
+
g_signal_connect_swapped (self->state->mode_cntrlr,
"window-mode-changed",
G_CALLBACK (photos_application_window_mode_changed),
@@ -1921,6 +1942,9 @@ photos_application_startup (GApplication *application)
gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.save-current", save_accels);
gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.search", search_accels);
gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.select-all", select_all_accels);
+ gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.zoom-best-fit", zoom_best_fit_accels);
+ gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.zoom-in", zoom_in_accels);
+ gtk_application_set_accels_for_action (GTK_APPLICATION (self), "app.zoom-out", zoom_out_accels);
g_signal_connect_swapped (self->state->item_mngr,
"load-finished",
@@ -1995,6 +2019,9 @@ photos_application_dispose (GObject *object)
g_clear_object (&self->set_ss_action);
g_clear_object (&self->share_action);
g_clear_object (&self->sharpen_action);
+ g_clear_object (&self->zoom_best_fit_action);
+ g_clear_object (&self->zoom_in_action);
+ g_clear_object (&self->zoom_out_action);
g_clear_object (&self->shr_pnt_mngr);
g_clear_object (&self->camera_cache);
g_clear_object (&self->sel_cntrlr);
diff --git a/src/photos-help-overlay.ui b/src/photos-help-overlay.ui
index 5f00de8..ff09da7 100644
--- a/src/photos-help-overlay.ui
+++ b/src/photos-help-overlay.ui
@@ -146,6 +146,27 @@
<child>
<object class="GtkShortcutsShortcut">
<property name="visible">1</property>
+ <property name="title" translatable="yes" context="shortcut window">Zoom in</property>
+ <property name="accelerator"><Primary>plus</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="visible">1</property>
+ <property name="title" translatable="yes" context="shortcut window">Zoom out</property>
+ <property name="accelerator"><Primary>minus</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="visible">1</property>
+ <property name="title" translatable="yes" context="shortcut window">Best fit</property>
+ <property name="accelerator"><Primary>0</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkShortcutsShortcut">
+ <property name="visible">1</property>
<property name="title" translatable="yes" context="shortcut window">Delete</property>
<property name="accelerator">Delete</property>
</object>
diff --git a/src/photos-preview-view.c b/src/photos-preview-view.c
index c901a4f..11990d4 100644
--- a/src/photos-preview-view.c
+++ b/src/photos-preview-view.c
@@ -39,11 +39,14 @@
#include "photos-preview-view.h"
#include "photos-search-context.h"
#include "photos-tool.h"
+#include "photos-utils.h"
struct _PhotosPreviewView
{
GtkBin parent_instance;
+ GAction *zoom_best_fit_action;
+ GAction *zoom_out_action;
GCancellable *cancellable;
GeglNode *node;
GtkWidget *overlay;
@@ -54,6 +57,7 @@ struct _PhotosPreviewView
PhotosModeController *mode_cntrlr;
PhotosPreviewNavButtons *nav_buttons;
PhotosTool *current_tool;
+ gdouble zoom_best_fit;
};
struct _PhotosPreviewViewClass
@@ -71,6 +75,10 @@ enum
G_DEFINE_TYPE (PhotosPreviewView, photos_preview_view, GTK_TYPE_BIN);
+static const gdouble ZOOM_FACTOR_1 = 2.8561;
+static const gdouble ZOOM_FACTOR_2 = 1.69;
+
+
static GtkWidget *photos_preview_view_create_view_with_container (PhotosPreviewView *self);
@@ -230,6 +238,45 @@ photos_preview_view_motion_notify_event (GtkWidget *widget, GdkEvent *event, gpo
static void
+photos_preview_view_update_zoom_best_fit (PhotosPreviewView *self, PhotosImageView *view)
+{
+ GtkWidget *current_view;
+ GtkWidget *current_view_container;
+ gdouble zoom;
+
+ current_view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+ current_view = photos_preview_view_get_view_from_view_container (current_view_container);
+ g_return_if_fail (view == PHOTOS_IMAGE_VIEW (current_view));
+
+ zoom = photos_image_view_get_zoom (view);
+ if (!photos_image_view_get_best_fit (view) || zoom == 0.0)
+ return;
+
+ self->zoom_best_fit = zoom;
+}
+
+
+static void
+photos_preview_view_notify_best_fit (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ PhotosPreviewView *self = PHOTOS_PREVIEW_VIEW (user_data);
+ PhotosImageView *view = PHOTOS_IMAGE_VIEW (object);
+
+ photos_preview_view_update_zoom_best_fit (self, view);
+}
+
+
+static void
+photos_preview_view_notify_zoom (GObject *object, GParamSpec *pspec, gpointer user_data)
+{
+ PhotosPreviewView *self = PHOTOS_PREVIEW_VIEW (user_data);
+ PhotosImageView *view = PHOTOS_IMAGE_VIEW (object);
+
+ photos_preview_view_update_zoom_best_fit (self, view);
+}
+
+
+static void
photos_preview_view_navigate (PhotosPreviewView *self, gint position)
{
GeglNode *node;
@@ -288,6 +335,8 @@ photos_preview_view_create_view_with_container (PhotosPreviewView *self)
g_signal_connect_swapped (view, "draw-background", G_CALLBACK (photos_preview_view_draw_background), self);
g_signal_connect_swapped (view, "draw-overlay", G_CALLBACK (photos_preview_view_draw_overlay), self);
g_signal_connect (view, "motion-notify-event", G_CALLBACK (photos_preview_view_motion_notify_event), self);
+ g_signal_connect (view, "notify::best-fit", G_CALLBACK (photos_preview_view_notify_best_fit), self);
+ g_signal_connect (view, "notify::zoom", G_CALLBACK (photos_preview_view_notify_zoom), self);
/* It has to be visible to become the visible child of self->stack. */
gtk_widget_show_all (sw);
@@ -663,6 +712,75 @@ photos_preview_view_window_mode_changed (PhotosPreviewView *self, PhotosWindowMo
static void
+photos_preview_view_zoom_best_fit (PhotosPreviewView *self)
+{
+ GtkWidget *view;
+ GtkWidget *view_container;
+
+ view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+ view = photos_preview_view_get_view_from_view_container (view_container);
+ photos_image_view_set_best_fit (PHOTOS_IMAGE_VIEW (view), TRUE);
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), FALSE);
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), FALSE);
+}
+
+
+static void
+photos_preview_view_zoom_in (PhotosPreviewView *self)
+{
+ GtkWidget *view;
+ GtkWidget *view_container;
+ gboolean best_fit;
+ gdouble zoom;
+ gdouble zoom_factor;
+
+ g_return_if_fail (self->zoom_best_fit > 0.0);
+
+ view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+ view = photos_preview_view_get_view_from_view_container (view_container);
+
+ best_fit = photos_image_view_get_best_fit (PHOTOS_IMAGE_VIEW (view));
+ zoom_factor = best_fit ? ZOOM_FACTOR_1 : ZOOM_FACTOR_2;
+
+ zoom = photos_image_view_get_zoom (PHOTOS_IMAGE_VIEW (view));
+ zoom *= zoom_factor;
+
+ photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom);
+
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), TRUE);
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), TRUE);
+}
+
+
+static void
+photos_preview_view_zoom_out (PhotosPreviewView *self)
+{
+ GtkWidget *view;
+ GtkWidget *view_container;
+ gdouble zoom;
+
+ g_return_if_fail (self->zoom_best_fit > 0.0);
+
+ view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+ view = photos_preview_view_get_view_from_view_container (view_container);
+
+ zoom = photos_image_view_get_zoom (PHOTOS_IMAGE_VIEW (view));
+ zoom /= ZOOM_FACTOR_2;
+
+ if (zoom < self->zoom_best_fit || photos_utils_equal_double (self->zoom_best_fit, zoom))
+ {
+ photos_image_view_set_best_fit (PHOTOS_IMAGE_VIEW (view), TRUE);
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_best_fit_action), FALSE);
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (self->zoom_out_action), FALSE);
+ }
+ else
+ {
+ photos_image_view_set_zoom (PHOTOS_IMAGE_VIEW (view), zoom);
+ }
+}
+
+
+static void
photos_preview_view_dispose (GObject *object)
{
PhotosPreviewView *self = PHOTOS_PREVIEW_VIEW (object);
@@ -816,6 +934,23 @@ photos_preview_view_init (PhotosPreviewView *self)
action = g_action_map_lookup_action (G_ACTION_MAP (app), "sharpen-current");
g_signal_connect_object (action, "activate", G_CALLBACK (photos_preview_view_sharpen), self,
G_CONNECT_SWAPPED);
+
+ self->zoom_best_fit_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-best-fit");
+ g_signal_connect_object (self->zoom_best_fit_action,
+ "activate",
+ G_CALLBACK (photos_preview_view_zoom_best_fit),
+ self,
+ G_CONNECT_SWAPPED);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-in");
+ g_signal_connect_object (action, "activate", G_CALLBACK (photos_preview_view_zoom_in), self,
G_CONNECT_SWAPPED);
+
+ self->zoom_out_action = g_action_map_lookup_action (G_ACTION_MAP (app), "zoom-out");
+ g_signal_connect_object (self->zoom_out_action,
+ "activate",
+ G_CALLBACK (photos_preview_view_zoom_out),
+ self,
+ G_CONNECT_SWAPPED);
}
@@ -868,6 +1003,7 @@ photos_preview_view_set_node (PhotosPreviewView *self, GeglNode *node)
return;
view_container = gtk_stack_get_visible_child (GTK_STACK (self->stack));
+ self->zoom_best_fit = 0.0;
g_clear_object (&self->node);
if (node == NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]