[Xfce4-commits] <ristretto:master> Improve zooming
Stephan Arts
noreply at xfce.org
Mon Aug 8 15:04:14 CEST 2011
Updating branch refs/heads/master
to 407c2cfe5622b9248a5abfa6ed4e6f1d19829fb6 (commit)
from d02948da5e54dabaeac34727ea54bcc1b608013a (commit)
commit 407c2cfe5622b9248a5abfa6ed4e6f1d19829fb6
Author: Stephan Arts <stephan at xfce.org>
Date: Wed Jul 27 20:57:16 2011 +0200
Improve zooming
- Introduce a maximum scale for large images
- Prevent small images to scale beyond the window-size
- Introduce a minimum size for images of 32x32 pixels unless the image itself is smaller then this.
- Correctly calculate the scale
- Fix a memory-leak
src/image_viewer.c | 246 +++++++++++++++++++++++++++++++++++++++++++++++----
src/image_viewer.h | 2 +-
src/main_window.c | 4 +-
3 files changed, 229 insertions(+), 23 deletions(-)
diff --git a/src/image_viewer.c b/src/image_viewer.c
index c92f21b..a7c1d16 100644
--- a/src/image_viewer.c
+++ b/src/image_viewer.c
@@ -36,6 +36,10 @@
#define RSTTO_IMAGE_VIEWER_BUFFER_SIZE 131072
#endif
+#ifndef RSTTO_MAX_SCALE
+#define RSTTO_MAX_SCALE 2.0
+#endif
+
typedef enum
{
RSTTO_IMAGE_VIEWER_MOTION_STATE_NORMAL = 0,
@@ -166,6 +170,9 @@ static void
cb_rstto_image_viewer_button_release_event (RsttoImageViewer *viewer, GdkEventButton *event);
static void
+cb_rstto_image_viewer_bgcolor_changed (GObject *settings, GParamSpec *pspec, gpointer user_data);
+
+static void
rstto_image_viewer_load_image (RsttoImageViewer *viewer, GFile *file);
static void
rstto_image_viewer_transaction_free (RsttoImageViewerTransaction *tr);
@@ -213,6 +220,9 @@ rstto_image_viewer_init(RsttoImageViewer *viewer)
viewer->priv->image_width = 0;
viewer->priv->image_height = 0;
+ g_signal_connect (G_OBJECT(viewer->priv->settings), "notify::bgcolor", G_CALLBACK (cb_rstto_image_viewer_bgcolor_changed), viewer);
+ g_signal_connect (G_OBJECT(viewer->priv->settings), "notify::bgcolor-override", G_CALLBACK (cb_rstto_image_viewer_bgcolor_changed), viewer);
+
gtk_widget_set_double_buffered (GTK_WIDGET(viewer), TRUE);
/* Set to false, experimental...
@@ -675,7 +685,7 @@ rstto_image_viewer_new (void)
* - cancellable...
*/
void
-rstto_image_viewer_set_file (RsttoImageViewer *viewer, GFile *file)
+rstto_image_viewer_set_file (RsttoImageViewer *viewer, GFile *file, gdouble scale)
{
/*
@@ -705,14 +715,14 @@ rstto_image_viewer_set_file (RsttoImageViewer *viewer, GFile *file)
g_object_unref (viewer->priv->file);
viewer->priv->file = g_file_dup(file);
- viewer->priv->scale = -1;
+ viewer->priv->scale = scale;
rstto_image_viewer_load_image (viewer, viewer->priv->file);
}
}
else
{
viewer->priv->file = g_file_dup(file);
- viewer->priv->scale = -1;
+ viewer->priv->scale = scale;
rstto_image_viewer_load_image (viewer, viewer->priv->file);
}
}
@@ -789,12 +799,82 @@ rstto_image_viewer_set_scale (RsttoImageViewer *viewer, gdouble scale)
{
gdouble tmp_x, tmp_y;
+
if (scale == 0)
{
viewer->priv->auto_scale = TRUE;
}
else
{
+ /*
+ * If the image is larger then the screen-dimensions,
+ * there is no reason to zoom in beyond RSTTO_MAX_SCALE.
+ *
+ * If the image is smaller then the screen-dimensions,
+ * zoom in to RSTTO_MAX_SCALE OR the window-size, whichever comes last.
+ *
+ */
+ if (viewer->priv->image_scale < 1.0)
+ {
+ if (scale > RSTTO_MAX_SCALE)
+ {
+ scale = RSTTO_MAX_SCALE;
+ }
+ }
+ else
+ {
+ /*
+ * Assuming image_scale == 1.0
+ */
+
+ gdouble v_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.height) / (gdouble)viewer->priv->image_height;
+ gdouble h_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.width) / (gdouble)viewer->priv->image_width;
+ if ((h_scale > RSTTO_MAX_SCALE) || (v_scale > RSTTO_MAX_SCALE))
+ {
+ if(h_scale < v_scale)
+ {
+ if (scale > h_scale)
+ {
+ scale = h_scale;
+ }
+ }
+ else
+ {
+ if (scale > v_scale)
+ {
+ scale = v_scale;
+ }
+ }
+ }
+ }
+
+ /*
+ * There is no need to zoom out beyond 32x32 pixels
+ * unless, ofcourse the image itself is smaller then 32x32 pixels.
+ */
+ if (viewer->priv->image_width > viewer->priv->image_height)
+ {
+ if ((viewer->priv->image_width >= 32) && ((scale * viewer->priv->image_width) < 32))
+ {
+ scale = (32.0 / (gdouble)viewer->priv->image_width);
+ }
+ if ((viewer->priv->image_width < 32) && (scale < 1.0))
+ {
+ scale = 1.0;
+ }
+ }
+ else
+ {
+ if ((viewer->priv->image_height >= 32) && ((scale * viewer->priv->image_height) < 32))
+ {
+ scale = (32.0 / (gdouble)viewer->priv->image_height);
+ }
+ if ((viewer->priv->image_height < 32) && (scale < 1.0))
+ {
+ scale = 1.0;
+ }
+ }
+
viewer->priv->auto_scale = FALSE;
/*
@@ -812,6 +892,8 @@ rstto_image_viewer_set_scale (RsttoImageViewer *viewer, gdouble scale)
viewer->priv->scale = scale;
+
+
rstto_image_viewer_queued_repaint (viewer, TRUE);
}
@@ -974,7 +1056,14 @@ cb_rstto_image_loader_size_prepared (GdkPixbufLoader *loader, gint width, gint h
gdk_pixbuf_loader_set_size (loader, (gint)((gdouble)width/(gdouble)height*(gdouble)s_width), s_height);
}
}
-
+ else
+ {
+ /*
+ * Image-size won't be limited to screen-size (since it's smaller)
+ * Set the image_scale to 1.0 (100%)
+ */
+ transaction->image_scale = 1.0;
+ }
}
static void
@@ -1053,8 +1142,8 @@ cb_rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer)
width = gdk_pixbuf_get_width (viewer->priv->pixbuf);
height = gdk_pixbuf_get_height (viewer->priv->pixbuf);
- v_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.height) / (gdouble)height;
- h_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.width) / (gdouble)width;
+ v_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.height) / (gdouble)viewer->priv->image_height;
+ h_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.width) / (gdouble)viewer->priv->image_width;
/*
* Scale == -1, this means the image is not loaded before,
@@ -1126,40 +1215,53 @@ cb_rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer)
*
*
*/
- if ((gtk_adjustment_get_page_size (viewer->vadjustment) + gtk_adjustment_get_value(viewer->vadjustment)) > (height*viewer->priv->scale))
+ if ((gtk_adjustment_get_page_size (viewer->vadjustment) +
+ gtk_adjustment_get_value(viewer->vadjustment)) > (viewer->priv->image_height*viewer->priv->scale))
{
gtk_adjustment_set_value (viewer->vadjustment,
- (height*viewer->priv->scale) - gtk_adjustment_get_page_size (viewer->vadjustment));
+ (height*(viewer->priv->scale/viewer->priv->image_scale)) -
+ gtk_adjustment_get_page_size (viewer->vadjustment));
}
- if ((gtk_adjustment_get_page_size (viewer->hadjustment) + gtk_adjustment_get_value(viewer->hadjustment)) > (width*viewer->priv->scale))
+ if ((gtk_adjustment_get_page_size (viewer->hadjustment) +
+ gtk_adjustment_get_value(viewer->hadjustment)) > (viewer->priv->image_width*viewer->priv->scale))
{
gtk_adjustment_set_value (viewer->hadjustment,
- (width*viewer->priv->scale) - gtk_adjustment_get_page_size (viewer->hadjustment));
+ (width*(viewer->priv->scale/viewer->priv->image_scale)) -
+ gtk_adjustment_get_page_size (viewer->hadjustment));
}
if (gtk_adjustment_get_page_size (viewer->vadjustment) > 0)
{
+
GdkPixbuf *tmp_pixbuf = gdk_pixbuf_new_subpixbuf (viewer->priv->pixbuf,
- (gint)(gtk_adjustment_get_value (viewer->hadjustment) / viewer->priv->scale),
- (gint)(gtk_adjustment_get_value (viewer->vadjustment) / viewer->priv->scale),
- (gint)((gtk_adjustment_get_page_size (viewer->hadjustment) / viewer->priv->scale) < width)?
- (gtk_adjustment_get_page_size (viewer->hadjustment) / viewer->priv->scale):
+ (gint)(gtk_adjustment_get_value (viewer->hadjustment) / (viewer->priv->scale/viewer->priv->image_scale)),
+ (gint)(gtk_adjustment_get_value (viewer->vadjustment) / (viewer->priv->scale/viewer->priv->image_scale)),
+ (gint)((gtk_adjustment_get_page_size (viewer->hadjustment) / (viewer->priv->scale/viewer->priv->image_scale)) < width)?
+ (gtk_adjustment_get_page_size (viewer->hadjustment) / (viewer->priv->scale/viewer->priv->image_scale)):
(width),
- (gint)((gtk_adjustment_get_page_size (viewer->vadjustment) / viewer->priv->scale) < height)?
- (gtk_adjustment_get_page_size (viewer->vadjustment) / viewer->priv->scale):
+ (gint)((gtk_adjustment_get_page_size (viewer->vadjustment) / (viewer->priv->scale/viewer->priv->image_scale)) < height)?
+ (gtk_adjustment_get_page_size (viewer->vadjustment) / (viewer->priv->scale/viewer->priv->image_scale)):
(height));
+ if (viewer->priv->dst_pixbuf)
+ {
+ g_object_unref (viewer->priv->dst_pixbuf);
+ viewer->priv->dst_pixbuf = NULL;
+ }
+
viewer->priv->dst_pixbuf = gdk_pixbuf_scale_simple (tmp_pixbuf,
- (gint)(gdk_pixbuf_get_width(tmp_pixbuf)*viewer->priv->scale),
- (gint)(gdk_pixbuf_get_height(tmp_pixbuf)*viewer->priv->scale),
+ (gint)(gdk_pixbuf_get_width(tmp_pixbuf)*(viewer->priv->scale/viewer->priv->image_scale)),
+ (gint)(gdk_pixbuf_get_height(tmp_pixbuf)*(viewer->priv->scale/viewer->priv->image_scale)),
GDK_INTERP_BILINEAR);
+
+ g_object_unref (tmp_pixbuf);
}
/*
* Set adjustments
*/
- gtk_adjustment_set_upper (viewer->hadjustment, (gdouble)width*(viewer->priv->scale));
- gtk_adjustment_set_upper (viewer->vadjustment, (gdouble)height*(viewer->priv->scale));
+ gtk_adjustment_set_upper (viewer->hadjustment, (gdouble)width*(viewer->priv->scale/viewer->priv->image_scale));
+ gtk_adjustment_set_upper (viewer->vadjustment, (gdouble)height*(viewer->priv->scale/viewer->priv->image_scale));
}
else
@@ -1184,6 +1286,103 @@ cb_rstto_image_viewer_queued_repaint (RsttoImageViewer *viewer)
static void
cb_rstto_image_viewer_scroll_event (RsttoImageViewer *viewer, GdkEventScroll *event)
{
+ gdouble tmp_x, tmp_y;
+ gdouble scale;
+
+ if ((event->state & (GDK_CONTROL_MASK)))
+ {
+ viewer->priv->auto_scale = FALSE;
+ tmp_x = (gtk_adjustment_get_value(viewer->hadjustment) + event->x) / viewer->priv->scale;
+ tmp_y = (gtk_adjustment_get_value(viewer->vadjustment) + event->y) / viewer->priv->scale;
+
+ switch(event->direction)
+ {
+ case GDK_SCROLL_UP:
+ case GDK_SCROLL_LEFT:
+ scale = viewer->priv->scale / 1.1;
+ break;
+ case GDK_SCROLL_DOWN:
+ case GDK_SCROLL_RIGHT:
+ scale = viewer->priv->scale * 1.1;
+ break;
+ }
+
+ /*
+ * If the image is larger then the screen-dimensions,
+ * there is no reason to zoom in beyond RSTTO_MAX_SCALE.
+ *
+ * If the image is smaller then the screen-dimensions,
+ * zoom in to RSTTO_MAX_SCALE OR the window-size, whichever comes last.
+ *
+ */
+ if (viewer->priv->image_scale < 1.0)
+ {
+ if (scale > RSTTO_MAX_SCALE)
+ {
+ scale = RSTTO_MAX_SCALE;
+ }
+ }
+ else
+ {
+ /*
+ * Assuming image_scale == 1.0
+ */
+
+ gdouble v_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.height) / (gdouble)viewer->priv->image_height;
+ gdouble h_scale = (gdouble)(GTK_WIDGET (viewer)->allocation.width) / (gdouble)viewer->priv->image_width;
+ if ((h_scale > RSTTO_MAX_SCALE) || (v_scale > RSTTO_MAX_SCALE))
+ {
+ if(h_scale < v_scale)
+ {
+ if (scale > h_scale)
+ {
+ scale = h_scale;
+ }
+ }
+ else
+ {
+ if (scale > v_scale)
+ {
+ scale = v_scale;
+ }
+ }
+ }
+ }
+
+ /*
+ * There is no need to zoom out beyond 32x32 pixels
+ * unless, ofcourse the image itself is smaller then 32x32 pixels.
+ */
+ if (viewer->priv->image_width > viewer->priv->image_height)
+ {
+ if ((viewer->priv->image_width >= 32) && ((scale * viewer->priv->image_width) < 32))
+ {
+ scale = (32.0 / (gdouble)viewer->priv->image_width);
+ }
+ if ((viewer->priv->image_width < 32) && (scale < 1.0))
+ {
+ scale = 1.0;
+ }
+ }
+ else
+ {
+ if ((viewer->priv->image_height >= 32) && ((scale * viewer->priv->image_height) < 32))
+ {
+ scale = (32.0 / (gdouble)viewer->priv->image_height);
+ }
+ if ((viewer->priv->image_height < 32) && (scale < 1.0))
+ {
+ scale = 1.0;
+ }
+ }
+
+ viewer->priv->scale = scale;
+
+ gtk_adjustment_set_value (viewer->hadjustment, (tmp_x * scale - event->x));
+ gtk_adjustment_set_value (viewer->vadjustment, (tmp_y * scale - event->y));
+
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
+ }
}
static gboolean
@@ -1274,3 +1473,10 @@ cb_rstto_image_viewer_button_release_event (RsttoImageViewer *viewer, GdkEventBu
break;
}
}
+
+static void
+cb_rstto_image_viewer_bgcolor_changed (GObject *settings, GParamSpec *pspec, gpointer user_data)
+{
+ RsttoImageViewer *viewer = RSTTO_IMAGE_VIEWER (user_data);
+ rstto_image_viewer_queued_repaint (viewer, TRUE);
+}
diff --git a/src/image_viewer.h b/src/image_viewer.h
index b3ef109..497a108 100644
--- a/src/image_viewer.h
+++ b/src/image_viewer.h
@@ -68,7 +68,7 @@ struct _RsttoImageViewerClass
GType rstto_image_viewer_get_type();
GtkWidget *rstto_image_viewer_new ();
-void rstto_image_viewer_set_file (RsttoImageViewer *viewer, GFile *file);
+void rstto_image_viewer_set_file (RsttoImageViewer *viewer, GFile *file, gdouble scale);
void rstto_image_viewer_set_scale (RsttoImageViewer *viewer, gdouble scale);
gdouble rstto_image_viewer_get_scale (RsttoImageViewer *viewer);
diff --git a/src/main_window.c b/src/main_window.c
index a4874ef..b711b7e 100644
--- a/src/main_window.c
+++ b/src/main_window.c
@@ -821,7 +821,7 @@ rstto_main_window_image_list_iter_changed (RsttoMainWindow *window)
file_info = g_file_query_info (file, "standard::content-type", 0, NULL, NULL);
content_type = g_file_info_get_content_type (file_info);
- rstto_image_viewer_set_file (RSTTO_IMAGE_VIEWER(window->priv->image_viewer), file);
+ rstto_image_viewer_set_file (RSTTO_IMAGE_VIEWER(window->priv->image_viewer), file, -1);
app_list = g_app_info_get_all_for_type (content_type);
@@ -862,7 +862,7 @@ rstto_main_window_image_list_iter_changed (RsttoMainWindow *window)
gtk_menu_shell_append (GTK_MENU_SHELL (open_with_menu), menu_item);
gtk_widget_set_sensitive (menu_item, FALSE);
- rstto_image_viewer_set_file (RSTTO_IMAGE_VIEWER(window->priv->image_viewer), NULL);
+ rstto_image_viewer_set_file (RSTTO_IMAGE_VIEWER(window->priv->image_viewer), NULL, -1);
menu_item = gtk_image_menu_item_new_with_label (_("Empty"));
More information about the Xfce4-commits
mailing list