[gthumb] image viewer: use a GthImageOverview to scroll the image
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] image viewer: use a GthImageOverview to scroll the image
- Date: Sat, 9 Nov 2013 20:08:36 +0000 (UTC)
commit c6ff64314345e57a20fb1a310938362e1a4b61c4
Author: Paolo Bacchilega <paobac src gnome org>
Date: Fri Nov 1 20:00:35 2013 +0100
image viewer: use a GthImageOverview to scroll the image
extensions/image_viewer/gth-image-viewer-page.c | 170 +++++++--
gthumb/gth-image-overview.c | 461 +++++++++++++++++------
gthumb/gth-image-overview.h | 2 +
gthumb/gth-image-viewer.c | 41 ++-
gthumb/gth-image-viewer.h | 2 +
5 files changed, 504 insertions(+), 172 deletions(-)
---
diff --git a/extensions/image_viewer/gth-image-viewer-page.c b/extensions/image_viewer/gth-image-viewer-page.c
index 214b0c1..b51963e 100644
--- a/extensions/image_viewer/gth-image-viewer-page.c
+++ b/extensions/image_viewer/gth-image-viewer-page.c
@@ -28,8 +28,8 @@
#include "preferences.h"
-#define HEADER_BUTTONS 5
#define UPDATE_QUALITY_DELAY 100
+#define N_HEADER_BAR_BUTTONS 2
static void gth_viewer_page_interface_init (GthViewerPageInterface *iface);
@@ -74,6 +74,8 @@ struct _GthImageViewerPagePrivate {
GthBrowser *browser;
GSettings *settings;
GtkWidget *image_navigator;
+ GtkWidget *overview_revealer;
+ GtkWidget *overview;
GtkWidget *viewer;
GthImagePreloader *preloader;
guint file_popup_merge_id;
@@ -84,7 +86,9 @@ struct _GthImageViewerPagePrivate {
GFile *last_loaded;
gboolean can_paste;
guint update_quality_event;
- GtkWidget *buttons[HEADER_BUTTONS];
+ GtkWidget *buttons[N_HEADER_BAR_BUTTONS];
+ gboolean pointer_on_viewer;
+ gboolean pointer_on_overview;
};
@@ -256,7 +260,15 @@ update_image_quality_if_required (GthImageViewerPage *self)
}
-static gboolean
+static void
+update_overview_visibility (GthImageViewerPage *self)
+{
+ gtk_revealer_set_reveal_child (GTK_REVEALER (self->priv->overview_revealer),
+ self->priv->pointer_on_overview || (self->priv->pointer_on_viewer &&
gth_image_viewer_has_scrollbars (GTH_IMAGE_VIEWER (self->priv->viewer))));
+}
+
+
+static void
viewer_zoom_changed_cb (GtkWidget *widget,
GthImageViewerPage *self)
{
@@ -265,14 +277,22 @@ viewer_zoom_changed_cb (GtkWidget *widget,
gth_viewer_page_update_sensitivity (GTH_VIEWER_PAGE (self));
update_image_quality_if_required (self);
+ self->priv->pointer_on_viewer = TRUE;
+ update_overview_visibility (self);
zoom = gth_image_viewer_get_zoom (GTH_IMAGE_VIEWER (self->priv->viewer));
text = g_strdup_printf (" %d%% ", (int) (zoom * 100));
gth_statusbar_set_secondary_text (GTH_STATUSBAR (gth_browser_get_statusbar (self->priv->browser)),
text);
g_free (text);
+}
- return TRUE;
+
+static void
+viewer_image_changed_cb (GtkWidget *widget,
+ GthImageViewerPage *self)
+{
+ update_overview_visibility (self);
}
@@ -286,6 +306,40 @@ viewer_button_press_event_cb (GtkWidget *widget,
static gboolean
+viewer_button_enter_notify_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GthImageViewerPage *self = user_data;
+
+ if (widget == self->priv->overview)
+ self->priv->pointer_on_overview = TRUE;
+ else if (widget == self->priv->viewer)
+ self->priv->pointer_on_viewer = TRUE;
+ update_overview_visibility (self);
+
+ return FALSE;
+}
+
+
+static gboolean
+viewer_button_leave_notify_event_cb (GtkWidget *widget,
+ GdkEvent *event,
+ gpointer user_data)
+{
+ GthImageViewerPage *self = user_data;
+
+ if (widget == self->priv->overview)
+ self->priv->pointer_on_overview = gth_image_overview_get_scrolling_is_active
(GTH_IMAGE_OVERVIEW (self->priv->overview));
+ else if (widget == self->priv->viewer)
+ self->priv->pointer_on_viewer = FALSE;
+ update_overview_visibility (self);
+
+ return FALSE;
+}
+
+
+static gboolean
viewer_popup_menu_cb (GtkWidget *widget,
GthImageViewerPage *self)
{
@@ -296,8 +350,8 @@ viewer_popup_menu_cb (GtkWidget *widget,
static gboolean
viewer_scroll_event_cb (GtkWidget *widget,
- GdkEventScroll *event,
- GthImageViewerPage *self)
+ GdkEventScroll *event,
+ GthImageViewerPage *self)
{
return gth_browser_viewer_scroll_event_cb (self->priv->browser, event);
}
@@ -579,12 +633,35 @@ paint_comment_over_image_func (GthImageViewer *image_viewer,
}
+static gboolean
+image_navigator_get_child_position_cb (GtkOverlay *overlay,
+ GtkWidget *widget,
+ GdkRectangle *allocation,
+ gpointer user_data)
+{
+ GthImageViewerPage *self = GTH_IMAGE_VIEWER_PAGE (user_data);
+
+ if (widget == self->priv->overview_revealer) {
+ GtkAllocation main_alloc;
+
+ gtk_widget_get_allocation (gtk_bin_get_child (GTK_BIN (overlay)), &main_alloc);
+ gtk_widget_get_preferred_width (widget, NULL, &allocation->width);
+ gtk_widget_get_preferred_height (widget, NULL, &allocation->height);
+ allocation->x = main_alloc.width - allocation->width - 10;
+ allocation->y = 10;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
static void
gth_image_viewer_page_real_activate (GthViewerPage *base,
GthBrowser *browser)
{
GthImageViewerPage *self;
- GthImageViewerTool *dragger;
self = (GthImageViewerPage*) base;
@@ -595,53 +672,36 @@ gth_image_viewer_page_real_activate (GthViewerPage *base,
browser);
self->priv->buttons[0] =
gth_browser_add_header_bar_button (browser,
- GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS,
- "view-zoom-in-symbolic",
- _("Zoom in"),
- "win.image-zoom-in",
- NULL);
- self->priv->buttons[1] =
- gth_browser_add_header_bar_button (browser,
- GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS,
- "view-zoom-out-symbolic",
- _("Zoom out"),
- "win.image-zoom-out",
- NULL);
- self->priv->buttons[2] =
- gth_browser_add_header_bar_button (browser,
- GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS,
+ GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW,
"view-zoom-original-symbolic",
- _("Actual size"),
+ NULL,
"win.image-zoom-100",
NULL);
- self->priv->buttons[3] =
+ self->priv->buttons[1] =
gth_browser_add_header_bar_button (browser,
- GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS,
+ GTH_BROWSER_HEADER_SECTION_VIEWER_VIEW,
"view-zoom-fit-symbolic",
- _("Zoom to fit window"),
+ NULL,
"win.image-zoom-fit",
NULL);
- self->priv->buttons[4] =
- gth_browser_add_header_bar_button (browser,
- GTH_BROWSER_HEADER_SECTION_VIEWER_COMMANDS,
- "view-zoom-fit-width-symbolic",
- _("Zoom to fit width"),
- "win.image-zoom-fit-width",
- NULL);
gth_window_add_accelerators (GTH_WINDOW (browser), accelerators, G_N_ELEMENTS (accelerators));
self->priv->preloader = gth_browser_get_image_preloader (browser);
self->priv->viewer = gth_image_viewer_new ();
+ gtk_widget_add_events (self->priv->viewer, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
gth_image_viewer_page_reset_viewer_tool (self);
-
gtk_widget_show (self->priv->viewer);
g_signal_connect (G_OBJECT (self->priv->viewer),
- "zoom_changed",
+ "zoom-changed",
G_CALLBACK (viewer_zoom_changed_cb),
self);
g_signal_connect (G_OBJECT (self->priv->viewer),
+ "image-changed",
+ G_CALLBACK (viewer_image_changed_cb),
+ self);
+ g_signal_connect (G_OBJECT (self->priv->viewer),
"popup-menu",
G_CALLBACK (viewer_popup_menu_cb),
self);
@@ -650,6 +710,14 @@ gth_image_viewer_page_real_activate (GthViewerPage *base,
G_CALLBACK (viewer_button_press_event_cb),
self);
g_signal_connect_after (G_OBJECT (self->priv->viewer),
+ "enter-notify-event",
+ G_CALLBACK (viewer_button_enter_notify_event_cb),
+ self);
+ g_signal_connect_after (G_OBJECT (self->priv->viewer),
+ "leave-notify-event",
+ G_CALLBACK (viewer_button_leave_notify_event_cb),
+ self);
+ g_signal_connect_after (G_OBJECT (self->priv->viewer),
"scroll_event",
G_CALLBACK (viewer_scroll_event_cb),
self);
@@ -670,9 +738,34 @@ gth_image_viewer_page_real_activate (GthViewerPage *base,
G_CALLBACK (viewer_unrealize_cb),
self);
- self->priv->image_navigator = gth_image_navigator_new (GTH_IMAGE_VIEWER (self->priv->viewer));
+ self->priv->image_navigator = gtk_overlay_new ();
+ g_signal_connect (self->priv->image_navigator,
+ "get-child-position",
+ G_CALLBACK (image_navigator_get_child_position_cb),
+ self);
+ gtk_container_add (GTK_CONTAINER (self->priv->image_navigator), self->priv->viewer);
gtk_widget_show (self->priv->image_navigator);
+ self->priv->overview_revealer = gtk_revealer_new ();
+ gtk_revealer_set_transition_duration (GTK_REVEALER (self->priv->overview_revealer), 500);
+ gtk_revealer_set_transition_type (GTK_REVEALER (self->priv->overview_revealer),
GTK_REVEALER_TRANSITION_TYPE_CROSSFADE);
+ gtk_widget_show (self->priv->overview_revealer);
+ gtk_overlay_add_overlay (GTK_OVERLAY (self->priv->image_navigator), self->priv->overview_revealer);
+
+ self->priv->overview = gth_image_overview_new (GTH_IMAGE_VIEWER (self->priv->viewer));
+ gtk_widget_add_events (self->priv->overview, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK);
+ gtk_widget_show (self->priv->overview);
+ gtk_container_add (GTK_CONTAINER (self->priv->overview_revealer), self->priv->overview);
+
+ g_signal_connect_after (G_OBJECT (self->priv->overview),
+ "enter-notify-event",
+ G_CALLBACK (viewer_button_enter_notify_event_cb),
+ self);
+ g_signal_connect_after (G_OBJECT (self->priv->overview),
+ "leave-notify-event",
+ G_CALLBACK (viewer_button_leave_notify_event_cb),
+ self);
+
gth_browser_set_viewer_widget (browser, self->priv->image_navigator);
gth_viewer_page_focus (GTH_VIEWER_PAGE (self));
@@ -701,7 +794,7 @@ gth_image_viewer_page_real_deactivate (GthViewerPage *base)
self = (GthImageViewerPage*) base;
- for (i = 0; i < HEADER_BUTTONS; i++) {
+ for (i = 0; i < N_HEADER_BAR_BUTTONS; i++) {
gtk_widget_destroy (self->priv->buttons[i]);
self->priv->buttons[i] = NULL;
}
@@ -948,8 +1041,7 @@ static void
gth_image_viewer_page_real_fullscreen (GthViewerPage *base,
gboolean active)
{
- GthImageViewerPage *self = GTH_IMAGE_VIEWER_PAGE (base);
- gth_image_navigator_set_automatic_scrollbars (GTH_IMAGE_NAVIGATOR (self->priv->image_navigator), !
active);
+ /* void */
}
diff --git a/gthumb/gth-image-overview.c b/gthumb/gth-image-overview.c
index db07a9c..ab565b2 100644
--- a/gthumb/gth-image-overview.c
+++ b/gthumb/gth-image-overview.c
@@ -24,11 +24,14 @@
#include <gdk/gdkkeysyms.h>
#include "cairo-scale.h"
#include "gth-image-overview.h"
+#include "gth-image-utils.h"
#include "gth-image-viewer.h"
-#define VISIBLE_AREA_BORDER 2.0
-#define MAX_SIZE 180
+#define MAX_ALLOCATION_SIZE 180
+#define IMAGE_BORDER 3.0
+#define VISIBLE_AREA_BORDER 2.0
+#define MAX_IMAGE_SIZE (MAX_ALLOCATION_SIZE - (IMAGE_BORDER * 2))
/* Properties */
@@ -40,17 +43,21 @@ enum {
struct _GthImageOverviewPrivate {
GthImageViewer *viewer;
- cairo_surface_t *image;
- int original_width;
- int original_height;
- int max_width;
- int max_height;
- int overview_width;
- int overview_height;
+ cairo_surface_t *preview;
+ int preview_width;
+ double preview_frame_border;
+ int preview_image_width;
+ int preview_image_height;
+ int preview_height;
cairo_rectangle_int_t visible_area;
double zoom_factor;
double quality_zoom;
gulong zoom_changed_id;
+ gulong image_changed_id;
+ gulong vadj_vchanged_id;
+ gulong hadj_vchanged_id;
+ gulong vadj_changed_id;
+ gulong hadj_changed_id;
gboolean scrolling_active;
};
@@ -68,34 +75,27 @@ gth_image_overview_finalize (GObject *object)
self = GTH_IMAGE_OVERVIEW (object);
- if (self->priv->zoom_changed_id > 0) {
- g_signal_handler_disconnect (self->priv->viewer, self->priv->zoom_changed_id);
- self->priv->zoom_changed_id = 0;
- }
- cairo_surface_destroy (self->priv->image);
+ cairo_surface_destroy (self->priv->preview);
G_OBJECT_CLASS (gth_image_overview_parent_class)->finalize (object);
}
static void
-_gth_image_overview_update_visible_area (GthImageOverview *self)
+_gth_image_overview_update_preview (GthImageOverview *self)
{
cairo_surface_t *image;
- int zoomed_width;
- int zoomed_height;
- GtkAllocation allocation;
- int scroll_offset_x;
- int scroll_offset_y;
+ int width, height;
+ int frame_border;
+ double zoom_factor;
+
+ cairo_surface_destroy (self->priv->preview);
+ self->priv->preview = NULL;
image = gth_image_viewer_get_current_image (self->priv->viewer);
if (image == NULL) {
- cairo_surface_destroy (self->priv->image);
- self->priv->image = NULL;
- self->priv->max_width = 0;
- self->priv->max_height = 0;
- self->priv->overview_width = 0;
- self->priv->overview_height = 0;
+ self->priv->preview_width = 0;
+ self->priv->preview_height = 0;
self->priv->visible_area.width = 0;
self->priv->visible_area.height = 0;
gtk_widget_queue_draw (GTK_WIDGET (self));
@@ -103,35 +103,73 @@ _gth_image_overview_update_visible_area (GthImageOverview *self)
return;
}
- gth_image_viewer_get_original_size (self->priv->viewer, &self->priv->original_width,
&self->priv->original_height);
- zoomed_width = self->priv->original_width * gth_image_viewer_get_zoom (self->priv->viewer);
- zoomed_height = self->priv->original_height * gth_image_viewer_get_zoom (self->priv->viewer);
- self->priv->max_width = MIN (zoomed_width, MAX_SIZE);
- self->priv->max_height = MIN (zoomed_width, MAX_SIZE);
- self->priv->zoom_factor = MIN ((double) (self->priv->max_width) / zoomed_width,
- (double) (self->priv->max_height) / zoomed_height);
- self->priv->quality_zoom = (double) self->priv->original_width / cairo_image_surface_get_width
(image);
- self->priv->overview_width = MAX ((int) floor (self->priv->zoom_factor * zoomed_width + 0.5), 1);
- self->priv->overview_height = MAX ((int) floor (self->priv->zoom_factor * zoomed_height + 0.5), 1);
-
- cairo_surface_destroy (self->priv->image);
- self->priv->image = _cairo_image_surface_scale_bilinear (image,
- self->priv->overview_width,
- self->priv->overview_height);
+ gth_image_viewer_get_original_size (self->priv->viewer, &width, &height);
+ frame_border = gth_image_viewer_get_frame_border (self->priv->viewer);
+ width += (frame_border * 2);
+ height += (frame_border * 2);
+
+ self->priv->preview_width = width;
+ self->priv->preview_height = height;
+ scale_keeping_ratio (&self->priv->preview_width,
+ &self->priv->preview_height,
+ MAX_IMAGE_SIZE,
+ MAX_IMAGE_SIZE,
+ FALSE);
+
+ zoom_factor = MIN ((double) (self->priv->preview_width) / width,
+ (double) (self->priv->preview_height) / height);
+ self->priv->preview_frame_border = frame_border * zoom_factor;
+ self->priv->preview_image_width = self->priv->preview_width - (self->priv->preview_frame_border * 2);
+ self->priv->preview_image_height = self->priv->preview_height - (self->priv->preview_frame_border *
2);
+
+ self->priv->preview = _cairo_image_surface_scale_bilinear (image,
+ self->priv->preview_image_width,
+ self->priv->preview_image_height);
+}
+
+
+static void
+_gth_image_overview_update_zoom_info (GthImageOverview *self)
+{
+ cairo_surface_t *image;
+ int width, height;
+ double zoom;
+ int frame_border;
+
+ if (self->priv->preview == NULL)
+ return;
+
+ image = gth_image_viewer_get_current_image (self->priv->viewer);
+ if (image == NULL)
+ return;
+
+ gth_image_viewer_get_original_size (self->priv->viewer, &width, &height);
+ self->priv->quality_zoom = (double) width / cairo_image_surface_get_width (image);
+
+ zoom = gth_image_viewer_get_zoom (self->priv->viewer);
+ frame_border = gth_image_viewer_get_frame_border (self->priv->viewer);
+ width = width * zoom + (frame_border * 2);
+ height = height * zoom + (frame_border * 2);
+
+ self->priv->zoom_factor = MIN ((double) (self->priv->preview_width) / width,
+ (double) (self->priv->preview_height) / height);
+}
+
+static void
+_gth_image_overview_update_visible_area (GthImageOverview *self)
+{
/* visible area size */
- gtk_widget_get_allocation (GTK_WIDGET (self->priv->viewer), &allocation);
- self->priv->visible_area.width = (allocation.width - (gth_image_viewer_get_frame_border
(self->priv->viewer) * 2)) * self->priv->zoom_factor;
- self->priv->visible_area.width = MIN (self->priv->visible_area.width, self->priv->max_width);
- self->priv->visible_area.height = (allocation.height - (gth_image_viewer_get_frame_border
(self->priv->viewer) * 2)) * self->priv->zoom_factor;
- self->priv->visible_area.height = MIN (self->priv->visible_area.height, self->priv->max_height);
+ self->priv->visible_area.width = self->priv->viewer->visible_area.width * self->priv->zoom_factor;
+ self->priv->visible_area.width = MIN (self->priv->visible_area.width, self->priv->preview_width);
+ self->priv->visible_area.height = self->priv->viewer->visible_area.height * self->priv->zoom_factor;
+ self->priv->visible_area.height = MIN (self->priv->visible_area.height, self->priv->preview_height);
/* visible area position */
- gth_image_viewer_get_scroll_offset (self->priv->viewer, &scroll_offset_x, &scroll_offset_y);
- self->priv->visible_area.x = scroll_offset_x * (self->priv->zoom_factor * self->priv->quality_zoom);
- self->priv->visible_area.y = scroll_offset_y * (self->priv->zoom_factor * self->priv->quality_zoom);
+ self->priv->visible_area.x = self->priv->viewer->visible_area.x * self->priv->zoom_factor;
+ self->priv->visible_area.y = self->priv->viewer->visible_area.y * self->priv->zoom_factor;
gtk_widget_queue_draw (GTK_WIDGET (self));
}
@@ -141,6 +179,31 @@ static void
viewer_zoom_changed_cb (GthImageViewer *viewer,
gpointer user_data)
{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (user_data);
+
+ _gth_image_overview_update_zoom_info (self);
+ _gth_image_overview_update_visible_area (self);
+}
+
+
+static void
+viewer_image_changed_cb (GthImageViewer *viewer,
+ gpointer user_data)
+{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (user_data);
+
+ _gth_image_overview_update_preview (self);
+ _gth_image_overview_update_zoom_info (self);
+ _gth_image_overview_update_visible_area (self);
+
+ gtk_widget_queue_resize (GTK_WIDGET (user_data));
+}
+
+
+static void
+viewer_adj_value_changed_cb (GtkAdjustment *adjustment,
+ gpointer user_data)
+{
_gth_image_overview_update_visible_area (GTH_IMAGE_OVERVIEW (user_data));
}
@@ -153,9 +216,35 @@ _gth_image_overview_set_viewer (GthImageOverview *self,
return;
if (self->priv->zoom_changed_id > 0) {
- g_signal_handler_disconnect (self->priv->viewer, self->priv->zoom_changed_id);
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer, self->priv->zoom_changed_id);
self->priv->zoom_changed_id = 0;
}
+ if (self->priv->image_changed_id > 0) {
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer, self->priv->image_changed_id);
+ self->priv->image_changed_id = 0;
+ }
+ if (self->priv->vadj_vchanged_id > 0) {
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer->vadj, self->priv->vadj_vchanged_id);
+ self->priv->vadj_vchanged_id = 0;
+ }
+ if (self->priv->hadj_vchanged_id > 0) {
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer->hadj, self->priv->hadj_vchanged_id);
+ self->priv->hadj_vchanged_id = 0;
+ }
+ if (self->priv->vadj_changed_id > 0) {
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer->vadj, self->priv->vadj_changed_id);
+ self->priv->vadj_changed_id = 0;
+ }
+ if (self->priv->hadj_changed_id > 0) {
+ if (self->priv->viewer != NULL)
+ g_signal_handler_disconnect (self->priv->viewer->hadj, self->priv->hadj_changed_id);
+ self->priv->hadj_changed_id = 0;
+ }
self->priv->viewer = NULL;
if (viewer == NULL)
@@ -167,6 +256,26 @@ _gth_image_overview_set_viewer (GthImageOverview *self,
"zoom-changed",
G_CALLBACK (viewer_zoom_changed_cb),
self);
+ self->priv->image_changed_id = g_signal_connect (self->priv->viewer,
+ "image-changed",
+ G_CALLBACK (viewer_image_changed_cb),
+ self);
+ self->priv->vadj_vchanged_id = g_signal_connect (self->priv->viewer->vadj,
+ "value-changed",
+ G_CALLBACK (viewer_adj_value_changed_cb),
+ self);
+ self->priv->hadj_vchanged_id = g_signal_connect (self->priv->viewer->hadj,
+ "value-changed",
+ G_CALLBACK (viewer_adj_value_changed_cb),
+ self);
+ self->priv->vadj_changed_id = g_signal_connect (self->priv->viewer->vadj,
+ "changed",
+ G_CALLBACK (viewer_adj_value_changed_cb),
+ self);
+ self->priv->hadj_changed_id = g_signal_connect (self->priv->viewer->hadj,
+ "changed",
+ G_CALLBACK (viewer_adj_value_changed_cb),
+ self);
g_object_notify (G_OBJECT (self), "viewer");
}
@@ -237,7 +346,8 @@ gth_image_overview_realize (GtkWidget *widget)
| GDK_BUTTON_RELEASE_MASK
| GDK_POINTER_MOTION_MASK
| GDK_POINTER_MOTION_HINT_MASK
- | GDK_BUTTON_MOTION_MASK);
+ | GDK_BUTTON_MOTION_MASK
+ | GDK_SCROLL_MASK);
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL;
window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
gtk_widget_register_window (widget, window);
@@ -266,50 +376,51 @@ gth_image_overview_draw (GtkWidget *widget,
cairo_t *cr)
{
GthImageOverview *self;
+ GtkAllocation allocation;
self = GTH_IMAGE_OVERVIEW (widget);
- if (self->priv->image == NULL)
+ if (self->priv->preview == NULL)
return FALSE;
- cairo_save (cr);
- cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
- cairo_set_source_surface (cr, self->priv->image, 0, 0);
- cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
- cairo_rectangle (cr, 0, 0, self->priv->overview_width, self->priv->overview_height);
- cairo_fill (cr);
- cairo_restore (cr);
+ gtk_widget_get_allocation (widget, &allocation);
cairo_save (cr);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
- cairo_rectangle (cr, 0, 0, self->priv->overview_width, self->priv->overview_height);
+ cairo_rectangle (cr, 0.5, 0.5, allocation.width - 1, allocation.height - 1);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_stroke_preserve (cr);
+ cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_fill (cr);
cairo_restore (cr);
- if ((self->priv->visible_area.width < self->priv->overview_width)
- || (self->priv->visible_area.height < self->priv->overview_height))
+ cairo_save (cr);
+ cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
+ cairo_set_source_surface (cr, self->priv->preview,
+ IMAGE_BORDER + self->priv->preview_frame_border,
+ IMAGE_BORDER + self->priv->preview_frame_border);
+ cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
+ cairo_rectangle (cr,
+ IMAGE_BORDER + self->priv->preview_frame_border,
+ IMAGE_BORDER + self->priv->preview_frame_border,
+ self->priv->preview_image_width,
+ self->priv->preview_image_height);
+ cairo_fill_preserve (cr);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+
+ if ((self->priv->visible_area.width < self->priv->preview_width)
+ || (self->priv->visible_area.height < self->priv->preview_height))
{
cairo_save (cr);
+ cairo_set_line_width (cr, VISIBLE_AREA_BORDER);
+ cairo_set_source_rgb (cr, 1.0, 0.0, 0.0);
cairo_rectangle (cr,
- self->priv->visible_area.x,
- self->priv->visible_area.y,
+ self->priv->visible_area.x + IMAGE_BORDER,
+ self->priv->visible_area.y + IMAGE_BORDER,
self->priv->visible_area.width,
self->priv->visible_area.height);
- cairo_clip (cr);
- cairo_set_source_surface (cr, self->priv->image, 0, 0);
- cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
- cairo_rectangle (cr, 0, 0, self->priv->overview_width, self->priv->overview_height);
- cairo_fill (cr);
- cairo_restore (cr);
-
- cairo_save (cr);
- cairo_set_line_width (cr, VISIBLE_AREA_BORDER);
- cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
- cairo_rectangle (cr,
- self->priv->visible_area.x + 1.0,
- self->priv->visible_area.y + 1.0,
- self->priv->visible_area.width - VISIBLE_AREA_BORDER,
- self->priv->visible_area.height - VISIBLE_AREA_BORDER);
cairo_stroke (cr);
cairo_restore (cr);
}
@@ -318,27 +429,6 @@ gth_image_overview_draw (GtkWidget *widget,
}
-static gboolean
-gth_image_overview_button_press_event (GtkWidget *widget,
- GdkEventButton *event)
-{
- gth_image_overview_activate_scrolling (GTH_IMAGE_OVERVIEW (widget), TRUE, event);
- return FALSE;
-}
-
-
-static gboolean
-gth_image_overview_button_release_event (GtkWidget *widget,
- GdkEventButton *event)
-{
- gth_image_overview_activate_scrolling (GTH_IMAGE_OVERVIEW (widget), FALSE, event);
- return FALSE;
-}
-
-
-/* -- gth_image_overview_motion_notify_event -- */
-
-
static void
get_visible_area_origin_as_double (GthImageOverview *self,
int mx,
@@ -346,8 +436,8 @@ get_visible_area_origin_as_double (GthImageOverview *self,
double *x,
double *y)
{
- *x = MIN (mx, self->priv->max_width);
- *y = MIN (my, self->priv->max_height);
+ *x = MIN (mx, self->priv->preview_width);
+ *y = MIN (my, self->priv->preview_height);
if (*x - self->priv->visible_area.width / 2.0 < 0.0)
*x = self->priv->visible_area.width / 2.0;
@@ -355,48 +445,144 @@ get_visible_area_origin_as_double (GthImageOverview *self,
if (*y - self->priv->visible_area.height / 2.0 < 0.0)
*y = self->priv->visible_area.height / 2.0;
- if (*x + self->priv->visible_area.width / 2.0 > self->priv->overview_width - 0)
- *x = self->priv->overview_width - 0 - self->priv->visible_area.width / 2.0;
+ if (*x + self->priv->visible_area.width / 2.0 > self->priv->preview_width - 0)
+ *x = self->priv->preview_width - 0 - self->priv->visible_area.width / 2.0;
- if (*y + self->priv->visible_area.height / 2.0 > self->priv->overview_height - 0)
- *y = self->priv->overview_height - 0 - self->priv->visible_area.height / 2.0;
+ if (*y + self->priv->visible_area.height / 2.0 > self->priv->preview_height - 0)
+ *y = self->priv->preview_height - 0 - self->priv->visible_area.height / 2.0;
*x = *x - self->priv->visible_area.width / 2.0;
*y = *y - self->priv->visible_area.height / 2.0;
}
-static gboolean
-gth_image_overview_motion_notify_event (GtkWidget *widget,
- GdkEventMotion *event)
+static void
+update_offset (GthImageOverview *self,
+ GdkEvent *event)
{
- GthImageOverview *self;
- int mx, my;
- double x, y;
-
- self = GTH_IMAGE_OVERVIEW (widget);
-
- if (! self->priv->scrolling_active)
- return FALSE;
+ int mx, my;
+ double x, y;
- gdk_window_get_device_position (gtk_widget_get_window (widget),
- gdk_event_get_device ((GdkEvent *) event),
+ gdk_window_get_device_position (gtk_widget_get_window (GTK_WIDGET (self)),
+ gdk_event_get_device (event),
&mx,
&my,
NULL);
get_visible_area_origin_as_double (self, mx, my, &x, &y);
- self->priv->visible_area.x = (int) x;
- self->priv->visible_area.y = (int) y;
mx = (int) (x / (self->priv->quality_zoom * self->priv->zoom_factor));
my = (int) (y / (self->priv->quality_zoom * self->priv->zoom_factor));
gth_image_viewer_set_scroll_offset (self->priv->viewer, mx, my);
+}
+
+
+static gboolean
+gth_image_overview_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ if (event->window != gtk_widget_get_window (widget))
+ return FALSE;
+
+ gth_image_overview_activate_scrolling (GTH_IMAGE_OVERVIEW (widget), TRUE, event);
+ update_offset (GTH_IMAGE_OVERVIEW (widget), (GdkEvent*) event);
+
+ return TRUE;
+}
+
+
+static gboolean
+gth_image_overview_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ gth_image_overview_activate_scrolling (GTH_IMAGE_OVERVIEW (widget), FALSE, event);
+ return TRUE;
+}
+
+
+static gboolean
+gth_image_overview_motion_notify_event (GtkWidget *widget,
+ GdkEventMotion *event)
+{
+ GthImageOverview *self;
+
+ self = GTH_IMAGE_OVERVIEW (widget);
+
+ if (self->priv->scrolling_active) {
+ update_offset (self, (GdkEvent*) event);
+ return TRUE;
+ }
return FALSE;
}
+static gboolean
+gth_image_overview_scroll_event (GtkWidget *widget,
+ GdkEventScroll *event)
+{
+ GthImageOverview *self;
+
+ self = GTH_IMAGE_OVERVIEW (widget);
+
+ switch (event->direction) {
+ case GDK_SCROLL_UP:
+ case GDK_SCROLL_DOWN:
+ if (event->direction == GDK_SCROLL_UP)
+ gth_image_viewer_zoom_in (self->priv->viewer);
+ else
+ gth_image_viewer_zoom_out (self->priv->viewer);
+ return TRUE;
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static GtkSizeRequestMode
+gth_image_overview_get_request_mode (GtkWidget *widget)
+{
+ return GTK_SIZE_REQUEST_CONSTANT_SIZE;
+}
+
+
+static void
+gth_image_overview_get_preferred_width (GtkWidget *widget,
+ int *minimum_width,
+ int *natural_width)
+{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (widget);
+ int size;
+
+ if (self->priv->viewer != NULL)
+ size = self->priv->preview_width + (IMAGE_BORDER * 2);
+ else
+ size = MAX_ALLOCATION_SIZE;
+ *minimum_width = *natural_width = size;
+}
+
+
+static void
+gth_image_overview_get_preferred_height (GtkWidget *widget,
+ int *minimum_height,
+ int *natural_height)
+{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (widget);
+ int size;
+
+ if (self->priv->viewer != NULL)
+ size = self->priv->preview_height + (IMAGE_BORDER * 2);
+ else
+ size = MAX_ALLOCATION_SIZE;
+
+ *minimum_height = *natural_height = size;
+}
+
+
static void
gth_image_overview_class_init (GthImageOverviewClass *klass)
{
@@ -415,6 +601,10 @@ gth_image_overview_class_init (GthImageOverviewClass *klass)
widget_class->button_press_event = gth_image_overview_button_press_event;
widget_class->button_release_event = gth_image_overview_button_release_event;
widget_class->motion_notify_event = gth_image_overview_motion_notify_event;
+ widget_class->scroll_event = gth_image_overview_scroll_event;
+ widget_class->get_request_mode = gth_image_overview_get_request_mode;
+ widget_class->get_preferred_width = gth_image_overview_get_preferred_width;
+ widget_class->get_preferred_height = gth_image_overview_get_preferred_height;
/* properties */
@@ -433,12 +623,25 @@ gth_image_overview_init (GthImageOverview *self)
{
self->priv = gth_image_overview_get_instance_private (self);
self->priv->viewer = NULL;
- self->priv->image = NULL;
+ self->priv->preview = NULL;
self->priv->visible_area.width = 0;
self->priv->visible_area.height = 0;
self->priv->zoom_factor = 1.0;
self->priv->zoom_changed_id = 0;
+ self->priv->image_changed_id = 0;
+ self->priv->vadj_vchanged_id = 0;
+ self->priv->hadj_vchanged_id = 0;
+ self->priv->vadj_changed_id = 0;
+ self->priv->hadj_changed_id = 0;
self->priv->scrolling_active = FALSE;
+
+ /* do not use the rgba visual on the drawing area */
+ {
+ GdkVisual *visual;
+ visual = gdk_screen_get_system_visual (gtk_widget_get_screen (GTK_WIDGET (self)));
+ if (visual != NULL)
+ gtk_widget_set_visual (GTK_WIDGET (self), visual);
+ }
}
@@ -455,8 +658,8 @@ gth_image_overview_get_size (GthImageOverview *self,
int *width,
int *height)
{
- if (width != NULL) *width = self->priv->overview_width;
- if (height != NULL) *height = self->priv->overview_height;
+ if (width != NULL) *width = self->priv->preview_width;
+ if (height != NULL) *height = self->priv->preview_height;
}
@@ -507,7 +710,15 @@ gth_image_overview_activate_scrolling (GthImageOverview *self,
else if (! active && self->priv->scrolling_active) {
gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time);
gdk_keyboard_ungrab (event->time);
+ gtk_grab_remove (GTK_WIDGET (self));
}
self->priv->scrolling_active = active;
}
+
+
+gboolean
+gth_image_overview_get_scrolling_is_active (GthImageOverview *self)
+{
+ return self->priv->scrolling_active;
+}
diff --git a/gthumb/gth-image-overview.h b/gthumb/gth-image-overview.h
index 3a88a8c..2807118 100644
--- a/gthumb/gth-image-overview.h
+++ b/gthumb/gth-image-overview.h
@@ -60,6 +60,8 @@ void gth_image_overview_get_visible_area (GthImageOverview *viewer,
void gth_image_overview_activate_scrolling (GthImageOverview *self,
gboolean active,
GdkEventButton *event);
+gboolean gth_image_overview_get_scrolling_is_active
+ (GthImageOverview *self);
G_END_DECLS
diff --git a/gthumb/gth-image-viewer.c b/gthumb/gth-image-viewer.c
index 22ee0d9..55572de 100644
--- a/gthumb/gth-image-viewer.c
+++ b/gthumb/gth-image-viewer.c
@@ -64,6 +64,7 @@ enum {
ZOOM_OUT,
SET_ZOOM,
SET_FIT_MODE,
+ IMAGE_CHANGED,
ZOOM_CHANGED,
SCROLL,
LAST_SIGNAL
@@ -299,6 +300,15 @@ _gth_image_viewer_update_image_area (GthImageViewer *self)
}
+static void
+_gth_image_viewer_image_changed (GthImageViewer *self)
+{
+ if (self->priv->tool != NULL)
+ gth_image_viewer_tool_image_changed (self->priv->tool);
+ g_signal_emit (G_OBJECT (self), gth_image_viewer_signals[IMAGE_CHANGED], 0);
+}
+
+
static void _set_surface (GthImageViewer *self,
cairo_surface_t *surface,
int original_width,
@@ -348,16 +358,14 @@ set_zoom (GthImageViewer *self,
_gth_image_viewer_update_image_area (self);
if (self->priv->update_image_after_zoom) {
- gth_image_viewer_tool_image_changed (self->priv->tool);
+ _gth_image_viewer_image_changed (self);
self->priv->update_image_after_zoom = FALSE;
}
else
gth_image_viewer_tool_zoom_changed (self->priv->tool);
if (! self->priv->skip_zoom_change)
- g_signal_emit (G_OBJECT (self),
- gth_image_viewer_signals[ZOOM_CHANGED],
- 0);
+ g_signal_emit (G_OBJECT (self), gth_image_viewer_signals[ZOOM_CHANGED], 0);
else
self->priv->skip_zoom_change = FALSE;
}
@@ -1318,6 +1326,15 @@ gth_image_viewer_class_init (GthImageViewerClass *class)
G_TYPE_NONE,
1,
GTH_TYPE_FIT);
+ gth_image_viewer_signals[IMAGE_CHANGED] =
+ g_signal_new ("image_changed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GthImageViewerClass, image_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
gth_image_viewer_signals[ZOOM_CHANGED] =
g_signal_new ("zoom_changed",
G_TYPE_FROM_CLASS (class),
@@ -1616,7 +1633,7 @@ _gth_image_viewer_content_changed (GthImageViewer *self,
}
if (better_quality || ! self->priv->zoom_enabled) {
- gth_image_viewer_tool_image_changed (self->priv->tool);
+ _gth_image_viewer_image_changed (self);
return;
}
@@ -1629,7 +1646,7 @@ _gth_image_viewer_content_changed (GthImageViewer *self,
break;
case GTH_ZOOM_CHANGE_KEEP_PREV:
- gth_image_viewer_tool_image_changed (self->priv->tool);
+ _gth_image_viewer_image_changed (self);
gtk_widget_queue_resize (GTK_WIDGET (self));
break;
@@ -2203,7 +2220,7 @@ gth_image_viewer_set_tool (GthImageViewer *self,
gth_image_viewer_tool_set_viewer (self->priv->tool, self);
if (gtk_widget_get_realized (GTK_WIDGET (self)))
gth_image_viewer_tool_realize (self->priv->tool);
- gth_image_viewer_tool_image_changed (self->priv->tool);
+ _gth_image_viewer_image_changed (self);
gtk_widget_queue_resize (GTK_WIDGET (self));
}
@@ -2388,6 +2405,15 @@ gth_image_viewer_needs_scrollbars (GthImageViewer *self,
}
+gboolean
+gth_image_viewer_has_scrollbars (GthImageViewer *self)
+{
+ int zoomed_width, zoomed_height;
+ _gth_image_viewer_get_zoomed_size (self, &zoomed_width, &zoomed_height);
+ return (self->visible_area.width < zoomed_width) || (self->visible_area.height < zoomed_height);
+}
+
+
void
gth_image_viewer_show_cursor (GthImageViewer *self)
{
@@ -2576,7 +2602,6 @@ gth_image_viewer_paint_frame (GthImageViewer *self,
|| image_has_alpha (self))
{
return;
-
}
cairo_save (cr);
diff --git a/gthumb/gth-image-viewer.h b/gthumb/gth-image-viewer.h
index 709f557..ead7d5e 100644
--- a/gthumb/gth-image-viewer.h
+++ b/gthumb/gth-image-viewer.h
@@ -112,6 +112,7 @@ struct _GthImageViewerClass
/* -- Signals -- */
void (* clicked) (GthImageViewer *viewer);
+ void (* image_changed) (GthImageViewer *viewer);
void (* zoom_changed) (GthImageViewer *viewer);
/* -- Key binding signals -- */
@@ -246,6 +247,7 @@ void gth_image_viewer_needs_scrollbars (GthImageViewer
GtkWidget *vscrollbar,
gboolean *hscrollbar_visible,
gboolean *vscrollbar_visible);
+gboolean gth_image_viewer_has_scrollbars (GthImageViewer *self);
/* Cursor. */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]