Author: abrander
Date: 2009-07-04 16:23:21 +0200 (Sat, 04 Jul 2009)
New Revision: 2529

Added:
   trunk/src/rs-navigator.c
   trunk/src/rs-navigator.h
Modified:
   trunk/src/Makefile.am
Log:
Added shiny display navigator for 100% view.

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am       2009-07-04 14:20:21 UTC (rev 2528)
+++ trunk/src/Makefile.am       2009-07-04 14:23:21 UTC (rev 2529)
@@ -37,6 +37,7 @@
        rs-cache.c rs-cache.h \
        rs-batch.c rs-batch.h \
        rs-toolbox.c rs-toolbox.h \
+       rs-navigator.c rs-navigator.h \
        rs-photo.c rs-photo.h \
        rs-jpeg.c rs-jpeg.h \
        rs-tiff.c rs-tiff.h \

Added: trunk/src/rs-navigator.c
===================================================================
--- trunk/src/rs-navigator.c                            (rev 0)
+++ trunk/src/rs-navigator.c    2009-07-04 14:23:21 UTC (rev 2529)
@@ -0,0 +1,339 @@
+/*
+ * Copyright (C) 2006-2009 Anders Brander <[email protected]> and 
+ * Anders Kvist <[email protected]>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
+ */
+
+#include "rs-navigator.h"
+
+G_DEFINE_TYPE (RSNavigator, rs_navigator, GTK_TYPE_DRAWING_AREA)
+
+static gboolean button_press_event(GtkWidget *widget, GdkEventButton *event);
+static gboolean motion_notify_event(GtkWidget *widget, GdkEventMotion *event);
+static gboolean expose(GtkWidget *widget, GdkEventExpose *event);
+static void size_allocate(GtkWidget *widget, GtkAllocation *allocation, 
gpointer user_data);
+static void h_changed(GtkAdjustment *adjustment, RSNavigator *navigator);
+static void v_changed(GtkAdjustment *adjustment, RSNavigator *navigator);
+static void h_value_changed(GtkAdjustment *adjustment, RSNavigator *navigator);
+static void v_value_changed(GtkAdjustment *adjustment, RSNavigator *navigator);
+static void filter_changed(RSFilter *filter, RSNavigator *navigator);
+static void redraw(RSNavigator *navigator);
+
+static void
+rs_navigator_finalize(GObject *object)
+{
+       RSNavigator *navigator = RS_NAVIGATOR(object);
+
+       g_object_unref(navigator->cache);
+
+       g_signal_handler_disconnect(navigator->vadjustment, 
navigator->vadjustment_signal1);
+       g_signal_handler_disconnect(navigator->vadjustment, 
navigator->vadjustment_signal2);
+       g_signal_handler_disconnect(navigator->hadjustment, 
navigator->hadjustment_signal1);
+       g_signal_handler_disconnect(navigator->hadjustment, 
navigator->hadjustment_signal2);
+
+       g_object_unref(navigator->vadjustment);
+       g_object_unref(navigator->hadjustment);
+
+       G_OBJECT_CLASS (rs_navigator_parent_class)->finalize (object);
+}
+
+static void
+rs_navigator_class_init(RSNavigatorClass *klass)
+{
+       GObjectClass *object_class = G_OBJECT_CLASS (klass);
+       GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
+
+       object_class->finalize = rs_navigator_finalize;
+       widget_class->button_press_event = button_press_event;
+       widget_class->motion_notify_event = motion_notify_event;
+       widget_class->expose_event = expose;
+}
+
+static void
+rs_navigator_init(RSNavigator *navigator)
+{
+       navigator->cache = rs_filter_new("RSCache", NULL);
+       g_signal_connect(navigator->cache, "changed", 
G_CALLBACK(filter_changed), navigator);
+
+       g_signal_connect(navigator, "size-allocate", G_CALLBACK(size_allocate), 
NULL);
+
+       gtk_widget_set_events(GTK_WIDGET(navigator), 0
+               | GDK_BUTTON_PRESS_MASK
+               | GDK_POINTER_MOTION_MASK);
+       gtk_widget_set_app_paintable(GTK_WIDGET(navigator), TRUE);
+}
+
+RSNavigator *
+rs_navigator_new(void)
+{
+       return g_object_new(RS_TYPE_NAVIGATOR, NULL);
+}
+
+void
+rs_navigator_set_adjustments(RSNavigator *navigator, GtkAdjustment 
*vadjustment, GtkAdjustment *hadjustment)
+{
+       g_assert(RS_IS_NAVIGATOR(navigator));
+       g_assert(GTK_IS_ADJUSTMENT(vadjustment));
+       g_assert(GTK_IS_ADJUSTMENT(hadjustment));
+
+       navigator->vadjustment = g_object_ref(vadjustment);
+       navigator->hadjustment = g_object_ref(hadjustment);
+
+       navigator->vadjustment_signal1 = g_signal_connect(vadjustment, 
"changed", G_CALLBACK(v_changed), navigator);
+       navigator->vadjustment_signal2 = g_signal_connect(vadjustment, 
"value-changed", G_CALLBACK(v_value_changed), navigator);
+       navigator->hadjustment_signal1 = g_signal_connect(hadjustment, 
"changed", G_CALLBACK(h_changed), navigator);
+       navigator->hadjustment_signal2 = g_signal_connect(hadjustment, 
"value-changed", G_CALLBACK(h_value_changed), navigator);
+}
+
+void
+rs_navigator_set_source_filter(RSNavigator *navigator, RSFilter *source_filter)
+{
+       g_assert(RS_IS_NAVIGATOR(navigator));
+       g_assert(RS_IS_FILTER(source_filter));
+
+       rs_filter_set_previous(navigator->cache, source_filter);
+}
+
+static void
+get_placement(RSNavigator *navigator, GdkRectangle *placement)
+{
+       placement->width = rs_filter_get_width(navigator->cache);
+       placement->height = rs_filter_get_height(navigator->cache);
+       placement->x = navigator->widget_width/2 - placement->width/2;
+       placement->y = navigator->widget_height/2 - placement->height/2;
+}
+
+static void
+move_to(RSNavigator *navigator, gdouble x, gdouble y)
+{
+       if (navigator->widget_width && navigator->width && 
navigator->vadjustment && navigator->hadjustment)
+       {
+               GdkRectangle placement;
+               get_placement(navigator, &placement);
+               gdouble dx, dy;
+
+               x -= placement.x;
+               y -= placement.y;
+               const gdouble scale = ((gdouble) placement.width) / 
navigator->width;
+
+               /* Scale back to original size */
+               dx = ((gdouble) x) / scale;
+               dy = ((gdouble) y) / scale;
+
+               /* Center pointer */
+               dx -= navigator->x_page/2;
+               dy -= navigator->y_page/2;
+
+               /* Clamp */
+               dx = CLAMP(dx, 0, navigator->width - navigator->x_page - 1);
+               dy = CLAMP(dy, 0, navigator->height - navigator->y_page - 1);
+
+               /* Modify adjusters */
+               g_object_set(navigator->hadjustment, "value", dx, NULL);
+               g_object_set(navigator->vadjustment, "value", dy, NULL);
+       }
+}
+
+static gboolean
+button_press_event(GtkWidget *widget, GdkEventButton *event)
+{
+       RSNavigator *navigator = RS_NAVIGATOR(widget);
+
+       move_to(navigator, event->x, event->y);
+
+       return TRUE;
+}
+
+static gboolean
+motion_notify_event(GtkWidget *widget, GdkEventMotion *event)
+{
+       RSNavigator *navigator = RS_NAVIGATOR(widget);
+       GdkWindow *window = widget->window;
+       GdkModifierType mask;
+       gint x, y;
+
+       gdk_window_get_pointer(window, &x, &y, &mask);
+
+       if ((x == navigator->last_x) && (y == navigator->last_y))
+               return TRUE;
+
+       navigator->last_x = x;
+       navigator->last_y = y;
+
+       if (mask & (GDK_BUTTON1_MASK|GDK_BUTTON2_MASK|GDK_BUTTON3_MASK))
+               move_to(navigator, (gdouble) x, (gdouble) y);
+
+       return TRUE;
+}
+
+static gboolean
+expose(GtkWidget *widget, GdkEventExpose *event)
+{
+       redraw(RS_NAVIGATOR(widget));
+
+       return FALSE;
+}
+
+static void
+size_allocate(GtkWidget *widget, GtkAllocation *allocation, gpointer user_data)
+{
+       RSNavigator *navigator = RS_NAVIGATOR(widget);
+       navigator->widget_width = allocation->width;
+       navigator->widget_height = allocation->height;
+
+       redraw(navigator);
+}
+
+static void
+h_changed(GtkAdjustment *adjustment, RSNavigator *navigator)
+{
+       gboolean do_redraw = FALSE;
+
+       const gint width = (gint) (gtk_adjustment_get_upper(adjustment)+0.5);
+       if (width != navigator->width)
+       {
+               navigator->width = width;
+               do_redraw = TRUE;
+       }
+       const gint x_page = (gint) 
(gtk_adjustment_get_page_size(adjustment)+0.5);
+       if (x_page != navigator->x_page)
+       {
+               navigator->x_page = x_page;
+               do_redraw = TRUE;
+       }
+
+       if (do_redraw)
+               redraw(navigator);
+}
+
+static void
+v_changed(GtkAdjustment *adjustment, RSNavigator *navigator)
+{
+       gboolean do_redraw = FALSE;
+
+       const gint height = (gint) (gtk_adjustment_get_upper(adjustment)+0.5);
+       if (height != navigator->height)
+       {
+               navigator->height = height;
+               do_redraw = TRUE;
+       }
+       const gint y_page = (gint) 
(gtk_adjustment_get_page_size(adjustment)+0.5);
+       if (y_page != navigator->y_page)
+       {
+               navigator->y_page = y_page;
+               do_redraw = TRUE;
+       }
+
+       if (do_redraw)
+               redraw(navigator);
+}
+
+static void
+h_value_changed(GtkAdjustment *adjustment, RSNavigator *navigator)
+{
+       const gint x = (gint) (gtk_adjustment_get_value(adjustment)+0.5);
+       if (x != navigator->x)
+       {
+               navigator->x = x;
+               redraw(navigator);
+       }
+}
+
+static void
+v_value_changed(GtkAdjustment *adjustment, RSNavigator *navigator)
+{
+       const gint y = (gint) (gtk_adjustment_get_value(adjustment)+0.5);
+       if (y != navigator->y)
+       {
+               navigator->y = y;
+               redraw(navigator);
+       }
+}
+
+static void
+filter_changed(RSFilter *filter, RSNavigator *navigator)
+{
+       redraw(navigator);
+}
+
+static void
+redraw(RSNavigator *navigator)
+{
+       if ((navigator->widget_width==0) || (navigator->widget_height==0))
+               return;
+
+       if (!GTK_WIDGET_DRAWABLE(GTK_WIDGET(navigator)))
+               return;
+
+       GtkWidget *widget = GTK_WIDGET(navigator);
+       GdkDrawable *drawable = GDK_DRAWABLE(widget->window);
+       GdkPixmap *blitter = gdk_pixmap_new(drawable, navigator->widget_width, 
navigator->widget_height, -1);
+       cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(blitter));
+       GdkGC *gc = gdk_gc_new(GDK_DRAWABLE(blitter));
+
+       if (navigator->cache->previous)
+       {
+               GdkPixbuf *pixbuf = rs_filter_get_image8(navigator->cache, 
NULL);
+               GdkRectangle placement, rect;
+
+               placement.width = rs_filter_get_width(navigator->cache);
+               placement.height = rs_filter_get_height(navigator->cache);
+               placement.x = navigator->widget_width/2 - placement.width/2;
+               placement.y = navigator->widget_height/2 - placement.height/2;
+
+               const gdouble scale = ((gdouble) placement.width) / 
navigator->width;
+
+               cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 1.0);
+               cairo_paint(cr);
+               cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
+
+               /* creates a rectangle that matches the photo */
+               gdk_cairo_rectangle(cr, &placement);
+
+               /* Translate to image placement */
+               cairo_translate(cr, placement.x, placement.y);
+
+               /* Paint the pixbuf */
+               gdk_cairo_set_source_pixbuf(cr, pixbuf, 0.0, 0.0);
+               cairo_fill_preserve(cr);
+
+               /* creates a rectangle that matches ROI */
+               rect.x = scale * navigator->x + 0.5;
+               rect.y = scale * navigator->y + 0.5;
+               rect.width = scale * navigator->x_page + 0.5;
+               rect.height = scale * navigator->y_page + 0.5;
+               gdk_cairo_rectangle(cr, &rect);
+
+               cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
+               cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.35);
+               /* fill acording to rule */
+               cairo_fill_preserve (cr);
+               /* roi rectangle */
+               cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.0);
+               cairo_stroke (cr);
+
+               /* Draw white rectangle */
+               cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5);
+               gdk_cairo_rectangle(cr, &rect);
+               cairo_stroke (cr);
+
+               g_object_unref(pixbuf);
+       }
+
+       gdk_draw_drawable(drawable, gc, blitter, 0, 0, 0, 0, 
navigator->widget_width, navigator->widget_height);
+       g_object_unref(gc);
+       cairo_destroy(cr);
+}

Added: trunk/src/rs-navigator.h
===================================================================
--- trunk/src/rs-navigator.h                            (rev 0)
+++ trunk/src/rs-navigator.h    2009-07-04 14:23:21 UTC (rev 2529)
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006-2009 Anders Brander <[email protected]> and 
+ * Anders Kvist <[email protected]>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA.
+ */
+
+#ifndef RS_NAVIGATOR_H
+#define RS_NAVIGATOR_H
+
+#include <rawstudio.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define RS_TYPE_NAVIGATOR rs_navigator_get_type()
+#define RS_NAVIGATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), 
RS_TYPE_NAVIGATOR, RSNavigator))
+#define RS_NAVIGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), 
RS_TYPE_NAVIGATOR, RSNavigatorClass))
+#define RS_IS_NAVIGATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), 
RS_TYPE_NAVIGATOR))
+#define RS_IS_NAVIGATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), 
RS_TYPE_NAVIGATOR))
+#define RS_NAVIGATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), 
RS_TYPE_NAVIGATOR, RSNavigatorClass))
+
+typedef struct {
+       GtkDrawingArea parent;
+
+       gint widget_width;
+       gint widget_height;
+
+       gint last_x;
+       gint last_y;
+
+       GtkAdjustment *vadjustment;
+       GtkAdjustment *hadjustment;
+
+       gulong vadjustment_signal1;
+       gulong hadjustment_signal1;
+       gulong vadjustment_signal2;
+       gulong hadjustment_signal2;
+
+       gdouble scale;
+
+       RSFilter *cache;
+
+       gint width;
+       gint height;
+       gint x;
+       gint y;
+       gint x_page;
+       gint y_page;
+} RSNavigator;
+
+typedef struct {
+       GtkDrawingAreaClass parent_class;
+} RSNavigatorClass;
+
+GType rs_navigator_get_type(void);
+
+RSNavigator *rs_navigator_new(void);
+
+void rs_navigator_set_adjustments(RSNavigator *navigator, GtkAdjustment 
*vadjustment, GtkAdjustment *hadjustment);
+void rs_navigator_set_source_filter(RSNavigator *navigator, RSFilter 
*source_filter);
+
+G_END_DECLS
+
+#endif /* RS_NAVIGATOR_H */


_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit

Reply via email to