[gthumb] image navigator: moved the overview area to its own widget
- From: Paolo Bacchilega <paobac src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gthumb] image navigator: moved the overview area to its own widget
- Date: Sat, 9 Nov 2013 20:07:30 +0000 (UTC)
commit a239b05b26318669ea52cbdede13dbcdf4b55b2b
Author: Paolo Bacchilega <paobac src gnome org>
Date: Wed Oct 30 22:10:05 2013 +0100
image navigator: moved the overview area to its own widget
gthumb/Makefile.am | 2 +
gthumb/gth-image-navigator.c | 317 +++++---------------------
gthumb/gth-image-overview.c | 513 ++++++++++++++++++++++++++++++++++++++++++
gthumb/gth-image-overview.h | 67 ++++++
4 files changed, 643 insertions(+), 256 deletions(-)
---
diff --git a/gthumb/Makefile.am b/gthumb/Makefile.am
index 9d6586c..61ebdd7 100644
--- a/gthumb/Makefile.am
+++ b/gthumb/Makefile.am
@@ -66,6 +66,7 @@ PUBLIC_HEADER_FILES = \
gth-image-list-task.h \
gth-image-loader.h \
gth-image-navigator.h \
+ gth-image-overview.h \
gth-image-preloader.h \
gth-image-saver.h \
gth-image-selector.h \
@@ -199,6 +200,7 @@ gthumb_SOURCES = \
gth-image-list-task.c \
gth-image-loader.c \
gth-image-navigator.c \
+ gth-image-overview.c \
gth-image-preloader.c \
gth-image-saver.c \
gth-image-selector.c \
diff --git a/gthumb/gth-image-navigator.c b/gthumb/gth-image-navigator.c
index 685a573..161bbec 100644
--- a/gthumb/gth-image-navigator.c
+++ b/gthumb/gth-image-navigator.c
@@ -24,16 +24,14 @@
#include <gdk/gdkkeysyms.h>
#include "cairo-scale.h"
#include "gth-image-navigator.h"
+#include "gth-image-overview.h"
#include "gth-image-viewer.h"
#include "gtk-utils.h"
#include "pixbuf-utils.h"
-#define VISIBLE_AREA_BORDER 2.0
-#define POPUP_BORDER 2
-#define POPUP_BORDER_2 (POPUP_BORDER*2)
-#define POPUP_MAX_WIDTH 180
-#define POPUP_MAX_HEIGHT 180
+#define POPUP_BORDER 2
+#define POPUP_BORDER_2 (POPUP_BORDER*2)
/* Properties */
@@ -329,99 +327,17 @@ gth_image_navigator_class_init (GthImageNavigatorClass *klass)
typedef struct {
- GthImageViewer *viewer;
- int x_root, y_root;
- GtkWidget *popup_win;
- GtkWidget *preview;
- cairo_surface_t *image;
- int image_width, image_height;
- int original_width, original_height;
- int window_max_width, window_max_height;
- int popup_x, popup_y, popup_width, popup_height;
- cairo_rectangle_int_t visible_area;
- double zoom_factor;
- double quality_zoom;
+ GthImageViewer *viewer;
+ GtkWidget *popup_win;
+ GtkWidget *overview;
} NavigatorPopup;
static void
-get_visible_area_origin_as_double (NavigatorPopup *nav_popup,
- int mx,
- int my,
- double *x,
- double *y)
+navigator_popup_close (NavigatorPopup *nav_popup)
{
- *x = MIN (mx - POPUP_BORDER, nav_popup->window_max_width);
- *y = MIN (my - POPUP_BORDER, nav_popup->window_max_height);
-
- if (*x - nav_popup->visible_area.width / 2.0 < 0.0)
- *x = nav_popup->visible_area.width / 2.0;
-
- if (*y - nav_popup->visible_area.height / 2.0 < 0.0)
- *y = nav_popup->visible_area.height / 2.0;
-
- if (*x + nav_popup->visible_area.width / 2.0 > nav_popup->popup_width - 0)
- *x = nav_popup->popup_width - 0 - nav_popup->visible_area.width / 2.0;
-
- if (*y + nav_popup->visible_area.height / 2.0 > nav_popup->popup_height - 0)
- *y = nav_popup->popup_height - 0 - nav_popup->visible_area.height / 2.0;
-
- *x = *x - nav_popup->visible_area.width / 2.0;
- *y = *y - nav_popup->visible_area.height / 2.0;
-}
-
-
-static void
-update_popup_geometry (NavigatorPopup *nav_popup)
-{
- int zoomed_width;
- int zoomed_height;
- GtkAllocation allocation;
- int scroll_offset_x;
- int scroll_offset_y;
-
- zoomed_width = nav_popup->original_width * gth_image_viewer_get_zoom (nav_popup->viewer);
- zoomed_height = nav_popup->original_height * gth_image_viewer_get_zoom (nav_popup->viewer);
-
- nav_popup->window_max_width = MIN (zoomed_width, POPUP_MAX_WIDTH);
- nav_popup->window_max_height = MIN (zoomed_width, POPUP_MAX_HEIGHT);
- nav_popup->zoom_factor = MIN ((double) (nav_popup->window_max_width) / zoomed_width,
- (double) (nav_popup->window_max_height) / zoomed_height);
- nav_popup->quality_zoom = (double) nav_popup->original_width / nav_popup->image_width;
-
- /* popup window size */
-
- nav_popup->popup_width = MAX ((int) floor (nav_popup->zoom_factor * zoomed_width + 0.5), 1);
- nav_popup->popup_height = MAX ((int) floor (nav_popup->zoom_factor * zoomed_height + 0.5), 1);
-
- cairo_surface_destroy (nav_popup->image);
- nav_popup->image = _cairo_image_surface_scale_bilinear (gth_image_viewer_get_current_image
(nav_popup->viewer),
- nav_popup->popup_width,
- nav_popup->popup_height);
-
- /* visible area size */
-
- gtk_widget_get_allocation (GTK_WIDGET (nav_popup->viewer), &allocation);
- nav_popup->visible_area.width = (allocation.width - GTH_IMAGE_VIEWER_FRAME_BORDER2) *
nav_popup->zoom_factor;
- nav_popup->visible_area.width = MAX (nav_popup->visible_area.width, POPUP_BORDER);
- nav_popup->visible_area.width = MIN (nav_popup->visible_area.width, nav_popup->popup_width);
-
- nav_popup->visible_area.height = (allocation.height - GTH_IMAGE_VIEWER_FRAME_BORDER2) *
nav_popup->zoom_factor;
- nav_popup->visible_area.height = MAX (nav_popup->visible_area.height, POPUP_BORDER);
- nav_popup->visible_area.height = MIN (nav_popup->visible_area.height, nav_popup->popup_height);
-
- /* visible area position */
-
- gth_image_viewer_get_scroll_offset (nav_popup->viewer, &scroll_offset_x, &scroll_offset_y);
- nav_popup->visible_area.x = scroll_offset_x * (nav_popup->zoom_factor * nav_popup->quality_zoom);
- nav_popup->visible_area.y = scroll_offset_y * (nav_popup->zoom_factor * nav_popup->quality_zoom);
-
- /* popup window position */
-
- nav_popup->popup_x = MIN ((int) nav_popup->x_root - nav_popup->visible_area.x - POPUP_BORDER -
nav_popup->visible_area.width / 2,
- gdk_screen_width () - nav_popup->popup_width - POPUP_BORDER_2);
- nav_popup->popup_y = MIN ((int) nav_popup->y_root - nav_popup->visible_area.y - POPUP_BORDER -
nav_popup->visible_area.height / 2,
- gdk_screen_height () - nav_popup->popup_height - POPUP_BORDER_2);
+ gtk_widget_destroy (nav_popup->popup_win);
+ g_free (nav_popup);
}
@@ -430,43 +346,16 @@ popup_window_event_cb (GtkWidget *widget,
GdkEvent *event,
gpointer data)
{
- NavigatorPopup *nav_popup = data;
- GthImageViewer *viewer = nav_popup->viewer;
- GdkModifierType mask;
- int mx, my;
- double x, y;
+ NavigatorPopup *nav_popup = data;
switch (event->type) {
case GDK_BUTTON_RELEASE:
- /* Release keyboard focus. */
- /*gdk_keyboard_ungrab (GDK_CURRENT_TIME);*/
- /*gtk_grab_remove (nav_popup->popup_win);*/
- gdk_device_ungrab (gdk_event_get_device (event), ((GdkEventButton *)event)->time);
-
- gtk_widget_destroy (nav_popup->popup_win);
- cairo_surface_destroy (nav_popup->image);
- g_free (nav_popup);
-
+ navigator_popup_close (nav_popup);
return TRUE;
case GDK_MOTION_NOTIFY:
- gdk_window_get_device_position (gtk_widget_get_window (widget),
- gdk_event_get_device (event),
- &mx,
- &my,
- &mask);
-
- get_visible_area_origin_as_double (nav_popup, mx, my, &x, &y);
- nav_popup->visible_area.x = (int) x;
- nav_popup->visible_area.y = (int) y;
-
- mx = (int) (x / (nav_popup->quality_zoom * nav_popup->zoom_factor));
- my = (int) (y / (nav_popup->quality_zoom * nav_popup->zoom_factor));
- gth_image_viewer_set_scroll_offset (viewer, mx, my);
-
- gtk_widget_queue_draw (widget);
- gdk_window_process_updates (gtk_widget_get_window (widget), TRUE);
-
+ gtk_widget_event (nav_popup->overview, event);
+ gtk_widget_queue_draw (nav_popup->overview);
return TRUE;
case GDK_KEY_PRESS:
@@ -476,22 +365,19 @@ popup_window_event_cb (GtkWidget *widget,
case GDK_KEY_1:
switch (event->key.keyval) {
case GDK_KEY_plus:
- gth_image_viewer_zoom_in (viewer);
+ gth_image_viewer_zoom_in (nav_popup->viewer);
break;
case GDK_KEY_minus:
- gth_image_viewer_zoom_out (viewer);
+ gth_image_viewer_zoom_out (nav_popup->viewer);
break;
case GDK_KEY_1:
- gth_image_viewer_set_zoom (viewer, 1.0);
+ gth_image_viewer_set_zoom (nav_popup->viewer, 1.0);
break;
}
+ break;
- update_popup_geometry (nav_popup);
- nav_popup->visible_area.x = MAX (nav_popup->visible_area.x, 0);
- nav_popup->visible_area.x = MIN (nav_popup->visible_area.x, nav_popup->popup_width -
nav_popup->visible_area.width);
- nav_popup->visible_area.y = MAX (nav_popup->visible_area.y, 0);
- nav_popup->visible_area.y = MIN (nav_popup->visible_area.y, nav_popup->popup_height -
nav_popup->visible_area.height);
- gtk_widget_queue_draw (widget);
+ case GDK_KEY_Escape:
+ navigator_popup_close (nav_popup);
break;
default:
@@ -508,108 +394,30 @@ popup_window_event_cb (GtkWidget *widget,
static void
-nav_window_grab_pointer (NavigatorPopup *nav_popup,
- GdkDevice *device)
-{
- GdkCursor *cursor;
-
- gtk_grab_add (nav_popup->popup_win);
-
- cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET (nav_popup->viewer)),
GDK_FLEUR);
- gdk_device_grab (device,
- gtk_widget_get_window (nav_popup->popup_win),
- GDK_OWNERSHIP_WINDOW,
- TRUE,
- (GDK_BUTTON_RELEASE_MASK
- | GDK_POINTER_MOTION_HINT_MASK
- | GDK_BUTTON_MOTION_MASK),
- cursor,
- 0);
- g_object_unref (cursor);
-
- /* Capture keyboard events. */
-
- /*gdk_keyboard_grab (gtk_widget_get_window (nav_popup->popup_win), TRUE, GDK_CURRENT_TIME);*/
- gtk_widget_grab_focus (nav_popup->popup_win);
-}
-
-
-static gboolean
-navigator_popup_draw_cb (GtkWidget *widget,
- cairo_t *cr,
- NavigatorPopup *nav_popup)
-{
- if (nav_popup->image == NULL)
- return FALSE;
-
- cairo_save (cr);
- cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
- cairo_set_source_surface (cr, nav_popup->image, 0, 0);
- cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
- cairo_rectangle (cr,
- 0, 0,
- cairo_image_surface_get_width (nav_popup->image),
- cairo_image_surface_get_height (nav_popup->image));
- cairo_fill (cr);
- cairo_restore (cr);
-
- cairo_save (cr);
- cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
- cairo_rectangle (cr, 0, 0, nav_popup->popup_width, nav_popup->popup_height);
- cairo_fill (cr);
- cairo_restore (cr);
-
- if ((nav_popup->visible_area.width < nav_popup->popup_width)
- || (nav_popup->visible_area.height < nav_popup->popup_height))
- {
- cairo_save (cr);
- cairo_rectangle (cr,
- nav_popup->visible_area.x,
- nav_popup->visible_area.y,
- nav_popup->visible_area.width,
- nav_popup->visible_area.height);
- cairo_clip (cr);
- cairo_set_source_surface (cr, nav_popup->image, 0, 0);
- cairo_pattern_set_filter (cairo_get_source (cr), CAIRO_FILTER_FAST);
- cairo_rectangle (cr,
- 0, 0,
- cairo_image_surface_get_width (nav_popup->image),
- cairo_image_surface_get_height (nav_popup->image));
- 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,
- nav_popup->visible_area.x + 1.0,
- nav_popup->visible_area.y + 1.0,
- nav_popup->visible_area.width - VISIBLE_AREA_BORDER,
- nav_popup->visible_area.height - VISIBLE_AREA_BORDER);
- cairo_stroke (cr);
- cairo_restore (cr);
- }
-
- return TRUE;
-}
-
-
-static void
navigator_event_area_button_press_event_cb (GtkWidget *widget,
GdkEventButton *event,
gpointer user_data)
{
- GthImageNavigator *self = user_data;
- NavigatorPopup *nav_popup;
- GtkWidget *out_frame;
- GtkWidget *in_frame;
+ GthImageNavigator *self = user_data;
+ NavigatorPopup *nav_popup;
+ GtkWidget *out_frame;
+ GtkWidget *in_frame;
+ int popup_x, popup_y;
+ int popup_width, popup_height;
+ cairo_rectangle_int_t visible_area;
if ((self->priv->viewer == NULL) || gth_image_viewer_is_void (GTH_IMAGE_VIEWER (self->priv->viewer)))
return;
+ /* create the popup and its content */
+
nav_popup = g_new0 (NavigatorPopup, 1);
nav_popup->viewer = GTH_IMAGE_VIEWER (self->priv->viewer);
nav_popup->popup_win = gtk_window_new (GTK_WINDOW_POPUP);
+ g_signal_connect (G_OBJECT (nav_popup->popup_win),
+ "event",
+ G_CALLBACK (popup_window_event_cb),
+ nav_popup);
gtk_window_set_wmclass (GTK_WINDOW (nav_popup->popup_win), "", "gthumb_navigator");
out_frame = gtk_frame_new (NULL);
@@ -620,45 +428,40 @@ navigator_event_area_button_press_event_cb (GtkWidget *widget,
gtk_frame_set_shadow_type (GTK_FRAME (in_frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (out_frame), in_frame);
- nav_popup->preview = gtk_drawing_area_new ();
- gtk_container_add (GTK_CONTAINER (in_frame), nav_popup->preview);
- g_signal_connect (G_OBJECT (nav_popup->preview),
- "draw",
- G_CALLBACK (navigator_popup_draw_cb),
- nav_popup);
-
- nav_popup->x_root = event->x_root;
- nav_popup->y_root = event->y_root;
-
- nav_popup->image_width = gth_image_viewer_get_image_width (GTH_IMAGE_VIEWER (self->priv->viewer));
- nav_popup->image_height = gth_image_viewer_get_image_height (GTH_IMAGE_VIEWER (self->priv->viewer));
- gth_image_viewer_get_original_size (GTH_IMAGE_VIEWER (self->priv->viewer),
- &nav_popup->original_width,
- &nav_popup->original_height);
- update_popup_geometry (nav_popup);
-
- g_signal_connect (G_OBJECT (nav_popup->popup_win),
- "event",
- G_CALLBACK (popup_window_event_cb),
- nav_popup);
-
+ nav_popup->overview = gth_image_overview_new (GTH_IMAGE_VIEWER (self->priv->viewer));
+ gtk_container_add (GTK_CONTAINER (in_frame), nav_popup->overview);
+
+ /* show the popup */
+
+ gth_image_overview_get_size (GTH_IMAGE_OVERVIEW (nav_popup->overview),
+ &popup_width,
+ &popup_height);
+ gth_image_overview_get_visible_area (GTH_IMAGE_OVERVIEW (nav_popup->overview),
+ &visible_area.x,
+ &visible_area.y,
+ &visible_area.width,
+ &visible_area.height);
+ popup_x = MIN (event->x_root - visible_area.x - POPUP_BORDER - visible_area.width / 2,
+ gdk_screen_width () - popup_width - POPUP_BORDER_2);
+ popup_y = MIN (event->y_root - visible_area.y - POPUP_BORDER - visible_area.height / 2,
+ gdk_screen_height () - popup_height - POPUP_BORDER_2);
gtk_window_move (GTK_WINDOW (nav_popup->popup_win),
- nav_popup->popup_x,
- nav_popup->popup_y);
-
+ popup_x,
+ popup_y);
gtk_window_set_default_size (GTK_WINDOW (nav_popup->popup_win),
- nav_popup->popup_width + POPUP_BORDER_2,
- nav_popup->popup_height + POPUP_BORDER_2);
-
+ popup_width + POPUP_BORDER_2,
+ popup_height + POPUP_BORDER_2);
gtk_widget_show_all (nav_popup->popup_win);
- nav_window_grab_pointer (nav_popup, gdk_event_get_device ((GdkEvent *) event));
+ gth_image_overview_activate_scrolling (GTH_IMAGE_OVERVIEW (nav_popup->overview), TRUE, event);
}
static void
gth_image_navigator_init (GthImageNavigator *self)
{
+ GtkWidget *navigator_icon;
+
self->priv = G_TYPE_INSTANCE_GET_PRIVATE ((self), GTH_TYPE_IMAGE_NAVIGATOR, GthImageNavigatorPrivate);
gtk_widget_set_has_window (GTK_WIDGET (self), FALSE);
@@ -680,10 +483,12 @@ gth_image_navigator_init (GthImageNavigator *self)
/* navigator event area */
+ navigator_icon = gtk_image_new_from_icon_name ("image-navigator", GTK_ICON_SIZE_MENU);
+ gtk_image_set_pixel_size (GTK_IMAGE (navigator_icon), 12);
+
self->priv->navigator_event_area = gtk_event_box_new ();
gtk_widget_set_parent (GTK_WIDGET (self->priv->navigator_event_area), GTK_WIDGET (self));
- gtk_container_add (GTK_CONTAINER (self->priv->navigator_event_area),
- gtk_image_new_from_icon_name ("image-navigator", GTK_ICON_SIZE_MENU));
+ gtk_container_add (GTK_CONTAINER (self->priv->navigator_event_area), navigator_icon);
g_signal_connect (G_OBJECT (self->priv->navigator_event_area),
"button_press_event",
G_CALLBACK (navigator_event_area_button_press_event_cb),
@@ -695,7 +500,7 @@ gth_image_navigator_init (GthImageNavigator *self)
}
-G_DEFINE_TYPE(GthImageNavigator, gth_image_navigator, GTK_TYPE_CONTAINER)
+G_DEFINE_TYPE (GthImageNavigator, gth_image_navigator, GTK_TYPE_CONTAINER)
GtkWidget *
diff --git a/gthumb/gth-image-overview.c b/gthumb/gth-image-overview.c
new file mode 100644
index 0000000..db07a9c
--- /dev/null
+++ b/gthumb/gth-image-overview.c
@@ -0,0 +1,513 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <math.h>
+#include <gdk/gdkkeysyms.h>
+#include "cairo-scale.h"
+#include "gth-image-overview.h"
+#include "gth-image-viewer.h"
+
+
+#define VISIBLE_AREA_BORDER 2.0
+#define MAX_SIZE 180
+
+
+/* Properties */
+enum {
+ PROP_0,
+ PROP_VIEWER
+};
+
+
+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_rectangle_int_t visible_area;
+ double zoom_factor;
+ double quality_zoom;
+ gulong zoom_changed_id;
+ gboolean scrolling_active;
+};
+
+
+G_DEFINE_TYPE_WITH_CODE (GthImageOverview, gth_image_overview, GTK_TYPE_WIDGET,
+ G_ADD_PRIVATE (GthImageOverview))
+
+
+static void
+gth_image_overview_finalize (GObject *object)
+{
+ GthImageOverview *self;
+
+ g_return_if_fail (GTH_IS_IMAGE_OVERVIEW (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);
+
+ G_OBJECT_CLASS (gth_image_overview_parent_class)->finalize (object);
+}
+
+
+static void
+_gth_image_overview_update_visible_area (GthImageOverview *self)
+{
+ cairo_surface_t *image;
+ int zoomed_width;
+ int zoomed_height;
+ GtkAllocation allocation;
+ int scroll_offset_x;
+ int scroll_offset_y;
+
+ 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->visible_area.width = 0;
+ self->priv->visible_area.height = 0;
+ gtk_widget_queue_draw (GTK_WIDGET (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);
+
+ /* 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);
+
+ /* 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);
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
+
+static void
+viewer_zoom_changed_cb (GthImageViewer *viewer,
+ gpointer user_data)
+{
+ _gth_image_overview_update_visible_area (GTH_IMAGE_OVERVIEW (user_data));
+}
+
+
+static void
+_gth_image_overview_set_viewer (GthImageOverview *self,
+ GtkWidget *viewer)
+{
+ if (self->priv->viewer == (GthImageViewer *) viewer)
+ return;
+
+ 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;
+ }
+ self->priv->viewer = NULL;
+
+ if (viewer == NULL)
+ return;
+
+ self->priv->viewer = (GthImageViewer *) viewer;
+ _gth_image_overview_update_visible_area (self);
+ self->priv->zoom_changed_id = g_signal_connect (self->priv->viewer,
+ "zoom-changed",
+ G_CALLBACK (viewer_zoom_changed_cb),
+ self);
+
+ g_object_notify (G_OBJECT (self), "viewer");
+}
+
+
+static void
+gth_image_overview_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (object);
+
+ switch (property_id) {
+ case PROP_VIEWER:
+ _gth_image_overview_set_viewer (self, g_value_get_object (value));
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void
+gth_image_overview_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GthImageOverview *self = GTH_IMAGE_OVERVIEW (object);
+
+ switch (property_id) {
+ case PROP_VIEWER:
+ g_value_set_object (value, self->priv->viewer);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void
+gth_image_overview_realize (GtkWidget *widget)
+{
+ GtkAllocation allocation;
+ GdkWindowAttr attributes;
+ int attributes_mask;
+ GdkWindow *window;
+
+ g_return_if_fail (GTH_IS_IMAGE_OVERVIEW (widget));
+
+ gtk_widget_set_realized (widget, TRUE);
+ gtk_widget_get_allocation (widget, &allocation);
+
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.x = allocation.x;
+ attributes.y = allocation.y;
+ attributes.width = allocation.width;
+ attributes.height = allocation.height;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.event_mask = (gtk_widget_get_events (widget)
+ | GDK_EXPOSURE_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_BUTTON_RELEASE_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_POINTER_MOTION_HINT_MASK
+ | GDK_BUTTON_MOTION_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);
+ gtk_widget_set_window (widget, window);
+ gtk_style_context_set_background (gtk_widget_get_style_context (widget), window);
+}
+
+
+static void
+gth_image_overview_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ gtk_widget_set_allocation (widget, allocation);
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+ _gth_image_overview_update_visible_area (GTH_IMAGE_OVERVIEW (widget));
+}
+
+
+static gboolean
+gth_image_overview_draw (GtkWidget *widget,
+ cairo_t *cr)
+{
+ GthImageOverview *self;
+
+ self = GTH_IMAGE_OVERVIEW (widget);
+
+ if (self->priv->image == 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);
+
+ 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_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_rectangle (cr,
+ self->priv->visible_area.x,
+ self->priv->visible_area.y,
+ 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);
+ }
+
+ return TRUE;
+}
+
+
+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,
+ int my,
+ double *x,
+ double *y)
+{
+ *x = MIN (mx, self->priv->max_width);
+ *y = MIN (my, self->priv->max_height);
+
+ if (*x - self->priv->visible_area.width / 2.0 < 0.0)
+ *x = self->priv->visible_area.width / 2.0;
+
+ 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 (*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;
+
+ *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)
+{
+ GthImageOverview *self;
+ int mx, my;
+ double x, y;
+
+ self = GTH_IMAGE_OVERVIEW (widget);
+
+ if (! self->priv->scrolling_active)
+ return FALSE;
+
+ gdk_window_get_device_position (gtk_widget_get_window (widget),
+ gdk_event_get_device ((GdkEvent *) 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);
+
+ return FALSE;
+}
+
+
+static void
+gth_image_overview_class_init (GthImageOverviewClass *klass)
+{
+ GObjectClass *object_class;
+ GtkWidgetClass *widget_class;
+
+ object_class = (GObjectClass *) klass;
+ object_class->finalize = gth_image_overview_finalize;
+ object_class->set_property = gth_image_overview_set_property;
+ object_class->get_property = gth_image_overview_get_property;
+
+ widget_class = (GtkWidgetClass *) klass;
+ widget_class->realize = gth_image_overview_realize;
+ widget_class->size_allocate = gth_image_overview_size_allocate;
+ widget_class->draw = gth_image_overview_draw;
+ 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;
+
+ /* properties */
+
+ g_object_class_install_property (object_class,
+ PROP_VIEWER,
+ g_param_spec_object ("viewer",
+ "Viewer",
+ "The image viewer to use",
+ GTH_TYPE_IMAGE_VIEWER,
+ G_PARAM_READWRITE));
+}
+
+
+static void
+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->visible_area.width = 0;
+ self->priv->visible_area.height = 0;
+ self->priv->zoom_factor = 1.0;
+ self->priv->zoom_changed_id = 0;
+ self->priv->scrolling_active = FALSE;
+}
+
+
+GtkWidget *
+gth_image_overview_new (GthImageViewer *viewer)
+{
+ g_return_val_if_fail (viewer != NULL, NULL);
+ return (GtkWidget *) g_object_new (GTH_TYPE_IMAGE_OVERVIEW, "viewer", viewer, NULL);
+}
+
+
+void
+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;
+}
+
+
+void
+gth_image_overview_get_visible_area (GthImageOverview *self,
+ int *x,
+ int *y,
+ int *width,
+ int *height)
+{
+ if (x != NULL) *x = self->priv->visible_area.x;
+ if (y != NULL) *y = self->priv->visible_area.y;
+ if (width != NULL) *width = self->priv->visible_area.width;
+ if (height != NULL) *height = self->priv->visible_area.height;
+}
+
+
+void
+gth_image_overview_activate_scrolling (GthImageOverview *self,
+ gboolean active,
+ GdkEventButton *event)
+{
+ g_return_if_fail (event != NULL);
+
+ if (active && ! self->priv->scrolling_active) {
+ GdkCursor *cursor;
+
+ gtk_widget_realize (GTK_WIDGET (self));
+ gtk_grab_add (GTK_WIDGET (self));
+
+ /* capture mouse events */
+
+ cursor = gdk_cursor_new_for_display (gtk_widget_get_display (GTK_WIDGET
(self->priv->viewer)), GDK_FLEUR);
+ gdk_device_grab (gdk_event_get_device ((GdkEvent *) event),
+ gtk_widget_get_window (GTK_WIDGET (self)),
+ GDK_OWNERSHIP_WINDOW,
+ FALSE,
+ GDK_ALL_EVENTS_MASK,
+ cursor,
+ event->time);
+ g_object_unref (cursor);
+
+ /* capture keyboard events. */
+
+ gdk_keyboard_grab (gtk_widget_get_window (GTK_WIDGET (self)), FALSE, event->time);
+ gtk_widget_grab_focus (GTK_WIDGET (self));
+ }
+ else if (! active && self->priv->scrolling_active) {
+ gdk_device_ungrab (gdk_event_get_device ((GdkEvent *) event), event->time);
+ gdk_keyboard_ungrab (event->time);
+ }
+
+ self->priv->scrolling_active = active;
+}
diff --git a/gthumb/gth-image-overview.h b/gthumb/gth-image-overview.h
new file mode 100644
index 0000000..3a88a8c
--- /dev/null
+++ b/gthumb/gth-image-overview.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+
+/*
+ * GThumb
+ *
+ * Copyright (C) 2013 The Free Software Foundation, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GTH_IMAGE_OVERVIEW_H
+#define GTH_IMAGE_OVERVIEW_H
+
+#include <gtk/gtk.h>
+#include "gth-image-viewer.h"
+
+G_BEGIN_DECLS
+
+#define GTH_TYPE_IMAGE_OVERVIEW (gth_image_overview_get_type ())
+#define GTH_IMAGE_OVERVIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTH_TYPE_IMAGE_OVERVIEW,
GthImageOverview))
+#define GTH_IMAGE_OVERVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTH_TYPE_IMAGE_OVERVIEW,
GthImageOverviewClass))
+#define GTH_IS_IMAGE_OVERVIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTH_TYPE_IMAGE_OVERVIEW))
+#define GTH_IS_IMAGE_OVERVIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTH_TYPE_IMAGE_OVERVIEW))
+#define GTH_IMAGE_OVERVIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GTH_TYPE_IMAGE_OVERVIEW,
GthImageOverviewClass))
+
+typedef struct _GthImageOverview GthImageOverview;
+typedef struct _GthImageOverviewClass GthImageOverviewClass;
+typedef struct _GthImageOverviewPrivate GthImageOverviewPrivate;
+
+struct _GthImageOverview {
+ GtkWidget __parent;
+ GthImageOverviewPrivate *priv;
+};
+
+struct _GthImageOverviewClass {
+ GtkWidgetClass __parent;
+};
+
+GType gth_image_overview_get_type (void);
+GtkWidget * gth_image_overview_new (GthImageViewer *viewer);
+void gth_image_overview_get_size (GthImageOverview *viewer,
+ int *width,
+ int *height);
+void gth_image_overview_get_visible_area (GthImageOverview *viewer,
+ int *x,
+ int *y,
+ int *width,
+ int *height);
+void gth_image_overview_activate_scrolling (GthImageOverview *self,
+ gboolean active,
+ GdkEventButton *event);
+
+G_END_DECLS
+
+#endif /* GTH_IMAGE_OVERVIEW_H */
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]