[gegl-gtk] GeglGtkView: Move most logic to a private class



commit 6c15741bc4d8d0437e6f0abb9f74f225832f9d9e
Author: Jon Nordby <jononor gmail com>
Date:   Wed Oct 5 21:19:02 2011 +0200

    GeglGtkView: Move most logic to a private class

 gegl-gtk/Makefile.am            |    5 +-
 gegl-gtk/gegl-gtk-view.c        |  299 +++++++++------------------------------
 gegl-gtk/gegl-gtk-view.h        |    6 +-
 gegl-gtk/internal/view-helper.c |  294 ++++++++++++++++++++++++++++++++++++++
 gegl-gtk/internal/view-helper.h |   81 +++++++++++
 5 files changed, 450 insertions(+), 235 deletions(-)
---
diff --git a/gegl-gtk/Makefile.am b/gegl-gtk/Makefile.am
index bfb9d77..15a0eb8 100644
--- a/gegl-gtk/Makefile.am
+++ b/gegl-gtk/Makefile.am
@@ -4,10 +4,13 @@ headers = gegl-gtk.h gegl-gtk-view.h
 sources = gegl-gtk-view.c
 INCLUDES = $(GTK_CFLAGS) $(GEGL_CFLAGS)
 
+internal_headers = internal/view-helper.h
+internal_sources = internal/view-helper.c
+
 gegl_gtk_includedir=$(includedir)/gegl-gtk$(GEGL_GTK_GTK_VERSION)-$(GEGL_GTK_API_VERSION)
 gegl_gtk_include_HEADERS = $(headers)
 
-gegl_gtk_SOURCES = $(headers) $(sources)
+gegl_gtk_SOURCES = $(headers) $(sources) $(internal_headers) $(internal_sources)
 gegl_gtk_LIBADD  = $(GTK_LIBS) $(GEGL_LIBS)
 gegl_gtk_CFLAGS  = $(INCLUDES) $(CFLAGS)
 
diff --git a/gegl-gtk/gegl-gtk-view.c b/gegl-gtk/gegl-gtk-view.c
index cc8d860..0259eba 100644
--- a/gegl-gtk/gegl-gtk-view.c
+++ b/gegl-gtk/gegl-gtk-view.c
@@ -18,13 +18,26 @@
 
 #include "config.h"
 
-#include <math.h>
-#include <babl/babl.h>
 #include <glib-object.h>
 #include <gtk/gtk.h>
 #include <gegl.h>
 
 #include "gegl-gtk-view.h"
+#include "internal/view-helper.h"
+
+
+/**
+ * This class is responsible for providing the public interface
+ * consumers expect of the view widget, and for rendering onto the widget.
+ * Tracking changes in the GeglNode, dealing with model<->view transformations
+ * et.c. is delegated to the internal/private class ViewHelper.
+ *
+ * This separation of concerns keeps the classes small and "stupid", and
+ * allows to test a lot of functionality without having to instantiate
+ * a widget and rely on the presence and behaviour of a windowing system.
+ */
+
+G_DEFINE_TYPE (GeglGtkView, gegl_gtk_view, GTK_TYPE_DRAWING_AREA)
 
 enum
 {
@@ -36,31 +49,15 @@ enum
   PROP_BLOCK
 };
 
-enum
-{
-  SIGNAL_REDRAW,
-  N_SIGNALS
-};
-
 
-typedef struct _GeglGtkViewPrivate
+static ViewHelper *
+get_private(GeglGtkView *self)
 {
-  GeglNode      *node;
-  gfloat         x;
-  gfloat         y;
-  gdouble        scale;
-  gboolean       block;    /* blocking render */
-
-  guint          monitor_id;
-  GeglProcessor *processor;
-} GeglGtkViewPrivate;
+    return VIEW_HELPER(self->priv);
+}
 
+#define GET_PRIVATE(self) (get_private(self))
 
-G_DEFINE_TYPE (GeglGtkView, gegl_gtk_view, GTK_TYPE_DRAWING_AREA)
-#define GEGL_GTK_VIEW_GET_PRIVATE(obj) \
-  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GEGL_GTK_TYPE_VIEW, GeglGtkViewPrivate))
-
-static guint gegl_gtk_view_signals[N_SIGNALS] = { 0 };
 
 static void      gegl_gtk_view_class_init (GeglGtkViewClass  *klass);
 static void      gegl_gtk_view_init       (GeglGtkView       *self);
@@ -73,6 +70,7 @@ static void      get_property         (GObject        *gobject,
                                        guint           prop_id,
                                        GValue         *value,
                                        GParamSpec     *pspec);
+
 #ifdef HAVE_GTK2
 static gboolean  expose_event         (GtkWidget      *widget,
                                        GdkEventExpose *event);
@@ -82,11 +80,12 @@ static gboolean  draw                 (GtkWidget * widget,
                                        cairo_t *cr);
 #endif
 
-static void      redraw_event (GeglGtkView *view,
-                               GeglRectangle *rect,
-                               gpointer data);
 
-static void      gegl_gtk_view_repaint       (GeglGtkView *view);
+static void
+trigger_redraw(ViewHelper* priv, GeglRectangle *rect, GeglGtkView *view);
+static void
+size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data);
+
 
 static void
 gegl_gtk_view_class_init (GeglGtkViewClass * klass)
@@ -141,89 +140,26 @@ gegl_gtk_view_class_init (GeglGtkViewClass * klass)
                                                         FALSE,
                                                         G_PARAM_READWRITE));
 
-  /* Emitted when a redraw is needed, with the area that needs redrawing.
-   * Exposed so that it can be tested. */
-  gegl_gtk_view_signals[SIGNAL_REDRAW] = g_signal_new ("redraw",
-                G_TYPE_FROM_CLASS (klass),
-                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
-                0,
-                NULL, NULL,
-                g_cclosure_marshal_VOID__BOXED,
-                G_TYPE_NONE, 1,
-                GEGL_TYPE_RECTANGLE);
-
-   g_type_class_add_private (klass, sizeof (GeglGtkViewPrivate));
 }
 
 static void
 gegl_gtk_view_init (GeglGtkView *self)
 {
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
-  priv->node        = NULL;
-  priv->x           = 0;
-  priv->y           = 0;
-  priv->scale       = 1.0;
-  priv->monitor_id  = 0;
-  priv->processor   = NULL;
-
-  g_signal_connect(self, "redraw", G_CALLBACK (redraw_event), NULL);
-}
-
-static void
-finalize (GObject *gobject)
-{
-  GeglGtkView * self = GEGL_GTK_VIEW (gobject);
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
-
-  if (priv->monitor_id)
-    {  
-      g_source_remove (priv->monitor_id);
-      priv->monitor_id = 0;
-    }
-
-  if (priv->node)
-    g_object_unref (priv->node);
-
-  if (priv->processor)
-    g_object_unref (priv->processor);
-
-  G_OBJECT_CLASS (gegl_gtk_view_parent_class)->finalize (gobject);
-}
-
-static void
-computed_event (GeglNode      *self,
-                GeglRectangle *rect,
-                GeglGtkView      *view)
-{
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (view);
-  gint x = priv->scale * (rect->x) - priv->x;
-  gint y = priv->scale * (rect->y) - priv->y;
-  gint w = ceil (priv->scale * rect->width);
-  gint h = ceil (priv->scale * rect->height);
-  GeglRectangle redraw_rect = {x, y, w, h};
-
-  g_signal_emit (view, gegl_gtk_view_signals[SIGNAL_REDRAW],
-	         0, &redraw_rect, NULL);
+  self->priv = (GeglGtkViewPrivate *)view_helper_new();
 
+  g_signal_connect(self->priv, "redraw-needed", G_CALLBACK (trigger_redraw), (gpointer)self);
+  
+  g_signal_connect(self, "size-allocate", G_CALLBACK (size_allocate), NULL);
 }
 
 static void
-redraw_event (GeglGtkView *view,
-              GeglRectangle *rect,
-              gpointer data)
+finalize (GObject *gobject)
 {
-  gtk_widget_queue_draw_area (GTK_WIDGET (view),
-			      rect->x, rect->y,
-			      rect->width, rect->height);
-}
+  GeglGtkView *self = GEGL_GTK_VIEW (gobject);
 
+  g_object_unref(G_OBJECT(self->priv));
 
-static void
-invalidated_event (GeglNode      *self,
-                   GeglRectangle *rect,
-                   GeglGtkView      *view)
-{
-  gegl_gtk_view_repaint (view);
+  G_OBJECT_CLASS(gegl_gtk_view_parent_class)->finalize(gobject);
 }
 
 static void
@@ -233,7 +169,7 @@ set_property (GObject      *gobject,
               GParamSpec   *pspec)
 {
   GeglGtkView *self = GEGL_GTK_VIEW (gobject);
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
+  ViewHelper *priv = GET_PRIVATE (self);
 
   switch (property_id)
     {
@@ -266,7 +202,7 @@ get_property (GObject      *gobject,
               GParamSpec   *pspec)
 {
   GeglGtkView *self = GEGL_GTK_VIEW (gobject);
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
+  ViewHelper *priv = GET_PRIVATE (self);
 
   switch (property_id)
     {
@@ -291,38 +227,24 @@ get_property (GObject      *gobject,
     }
 }
 
+/* Trigger a redraw */
 static void
-draw_implementation (GeglGtkViewPrivate *priv, cairo_t *cr, GdkRectangle *rect)
+trigger_redraw (ViewHelper *priv,
+              GeglRectangle *rect,
+              GeglGtkView *view)
 {
-  cairo_surface_t *surface = NULL;
-  guchar          *buf = NULL;
-  GeglRectangle   roi;
-
-  roi.x = priv->x + rect->x;
-  roi.y = priv->y + rect->y;
-  roi.width  = rect->width;
-  roi.height = rect->height;
-
-  buf = g_malloc ((roi.width) * (roi.height) * 4);
-
-  gegl_node_blit (priv->node,
-                  priv->scale,
-                  &roi,
-                  babl_format ("B'aG'aR'aA u8"),
-                  (gpointer)buf,
-                  GEGL_AUTO_ROWSTRIDE,
-                  GEGL_BLIT_CACHE | (priv->block ? 0 : GEGL_BLIT_DIRTY));
-
-  surface = cairo_image_surface_create_for_data (buf, 
-                                                 CAIRO_FORMAT_ARGB32, 
-                                                 roi.width, roi.height, 
-                                                 roi.width*4);
-  cairo_set_source_surface (cr, surface, rect->x, rect->y);
-  cairo_paint (cr);
-
-  cairo_surface_destroy (surface);
-  g_free (buf);
+    if (rect->width < 0 || rect->height < 0) 
+        gtk_widget_queue_draw(GTK_WIDGET(view));
+    else
+        gtk_widget_queue_draw_area(GTK_WIDGET(view),
+			      rect->x, rect->y, rect->width, rect->height);
+}
 
+static void
+size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data)
+{
+    GeglGtkView *self = GEGL_GTK_VIEW (widget);
+    view_helper_set_allocation(GET_PRIVATE(self), allocation);
 }
 
 #ifdef HAVE_GTK3
@@ -330,7 +252,7 @@ static gboolean
 draw (GtkWidget * widget, cairo_t *cr)
 {
   GeglGtkView      *view = GEGL_GTK_VIEW (widget);
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (view);
+  ViewHelper *priv = GET_PRIVATE (view);
   GdkRectangle rect;
 
   if (!priv->node)
@@ -338,9 +260,9 @@ draw (GtkWidget * widget, cairo_t *cr)
 
   gdk_cairo_get_clip_rectangle (cr, &rect);
 
-  draw_implementation (priv, cr, &rect);
+  view_helper_draw (priv, cr, &rect);
 
-  gegl_gtk_view_repaint (view);
+  view_helper_repaint (priv); /* Only needed due to possible allocation changes? */
 
   return FALSE;
 }
@@ -352,7 +274,7 @@ expose_event (GtkWidget      *widget,
               GdkEventExpose *event)
 {
   GeglGtkView      *view = GEGL_GTK_VIEW (widget);
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (view);
+  ViewHelper *priv = GET_PRIVATE (view);
   cairo_t      *cr;
   GdkRectangle rect;
 
@@ -364,60 +286,16 @@ expose_event (GtkWidget      *widget,
   cairo_clip (cr);
   gdk_region_get_clipbox (event->region, &rect);
 
-  draw_implementation (priv, cr, &rect);
+  view_helper_draw (priv, cr, &rect);
+  
   cairo_destroy (cr);
 
-  gegl_gtk_view_repaint (view);
+  view_helper_repaint (priv); /* Only needed due to possible allocation changes? */
 
   return FALSE;
 }
 #endif
 
-static gboolean
-task_monitor (GeglGtkView *view)
-{
-  GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (view);
-  if (priv->processor==NULL)
-    return FALSE;
-  if (gegl_processor_work (priv->processor, NULL))
-    return TRUE;
-
-  priv->monitor_id = 0;
-
-  return FALSE;
-}
-
-void
-gegl_gtk_view_repaint (GeglGtkView *view)
-{
-  GtkWidget       *widget = GTK_WIDGET (view);
-  GeglGtkViewPrivate *priv   = GEGL_GTK_VIEW_GET_PRIVATE (view);
-  GeglRectangle    roi;
-  GtkAllocation    allocation;
-
-  roi.x = priv->x / priv->scale;
-  roi.y = priv->y / priv->scale;
-  gtk_widget_get_allocation (widget, &allocation);
-  roi.width = ceil(allocation.width / priv->scale+1);
-  roi.height = ceil(allocation.height / priv->scale+1);
-
-  if (priv->monitor_id == 0)
-    {
-      priv->monitor_id = g_idle_add_full (G_PRIORITY_LOW,
-                                          (GSourceFunc) task_monitor, view,
-                                          NULL);
-
-      if (priv->processor == NULL)
-        {
-          if (priv->node)
-            priv->processor = gegl_node_new_processor (priv->node, &roi);
-        }
-    }
-
-  if (priv->processor)
-    gegl_processor_set_rectangle (priv->processor, &roi);
-}
-
 
 GeglGtkView *
 gegl_gtk_view_new()
@@ -437,30 +315,7 @@ gegl_gtk_view_new_for_node(GeglNode *node)
 void
 gegl_gtk_view_set_node(GeglGtkView *self, GeglNode *node)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
-
-    if (priv->node == node)
-        return;
-
-    if (priv->node)
-        g_object_unref (priv->node);
-
-    if (node) {
-        g_object_ref (node);
-        priv->node = node;
-
-        g_signal_connect_object (priv->node, "computed",
-                               G_CALLBACK (computed_event),
-                               self, 0);
-        g_signal_connect_object (priv->node, "invalidated",
-                               G_CALLBACK (invalidated_event),
-                               self, 0);
-
-        gegl_gtk_view_repaint (self);
-
-    } else
-        priv->node = NULL;
-
+    view_helper_set_node(GET_PRIVATE (self), node);
 }
 
 /**
@@ -471,63 +326,41 @@ gegl_gtk_view_set_node(GeglGtkView *self, GeglNode *node)
 GeglNode *
 gegl_gtk_view_get_node(GeglGtkView *self)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE (self);
-    return priv->node;
+    return view_helper_get_node(GET_PRIVATE(self));
 }
 
 void
 gegl_gtk_view_set_scale(GeglGtkView *self, float scale)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-
-    if (priv->scale == scale)
-        return;
-
-    priv->scale = scale;
-    gtk_widget_queue_draw(GTK_WIDGET (self));
+    view_helper_set_scale(GET_PRIVATE(self), scale);
 }
 
 float
 gegl_gtk_view_get_scale(GeglGtkView *self)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-    return priv->scale;
+    return view_helper_get_scale(GET_PRIVATE(self));
 }
 
 void
 gegl_gtk_view_set_x(GeglGtkView *self, float x)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-
-    if (priv->x == x)
-        return;
-
-    priv->x = x;
-    gtk_widget_queue_draw(GTK_WIDGET (self));
+    view_helper_set_x(GET_PRIVATE(self), x);
 }
 
 float
 gegl_gtk_view_get_x(GeglGtkView *self)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-    return priv->x;
+    return view_helper_get_x(GET_PRIVATE(self));
 }
 
 void
 gegl_gtk_view_set_y(GeglGtkView *self, float y)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-
-    if (priv->y == y)
-        return;
-
-    priv->y = y;
-    gtk_widget_queue_draw(GTK_WIDGET (self));
+    view_helper_set_y(GET_PRIVATE(self), y);
 }
 
 float
 gegl_gtk_view_get_y(GeglGtkView *self)
 {
-    GeglGtkViewPrivate *priv = GEGL_GTK_VIEW_GET_PRIVATE(self);
-    return priv->y;
+    return view_helper_get_y(GET_PRIVATE(self));
 }
diff --git a/gegl-gtk/gegl-gtk-view.h b/gegl-gtk/gegl-gtk-view.h
index 03dbe1e..9ea904b 100644
--- a/gegl-gtk/gegl-gtk-view.h
+++ b/gegl-gtk/gegl-gtk-view.h
@@ -34,14 +34,18 @@ G_BEGIN_DECLS
 typedef struct _GeglGtkView        GeglGtkView;
 typedef struct _GeglGtkViewClass   GeglGtkViewClass;
 
+typedef struct _ViewHelper GeglGtkViewPrivate;
+
 struct _GeglGtkView
 {
+  /*< private >*/
   GtkDrawingArea parent_instance;
-
+  GeglGtkViewPrivate *priv; /* Can't use the GType private mechanism for GObjects */
 };
 
 struct _GeglGtkViewClass
 {
+  /*< private >*/
   GtkDrawingAreaClass parent_class;
 };
 
diff --git a/gegl-gtk/internal/view-helper.c b/gegl-gtk/internal/view-helper.c
new file mode 100644
index 0000000..682d6d6
--- /dev/null
+++ b/gegl-gtk/internal/view-helper.c
@@ -0,0 +1,294 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Ãyvind KolÃs <pippin gimp org>
+ */
+
+#include "view-helper.h"
+
+#include <math.h>
+#include <babl/babl.h>
+
+
+G_DEFINE_TYPE (ViewHelper, view_helper, G_TYPE_OBJECT)
+
+
+enum
+{
+  SIGNAL_REDRAW_NEEDED,
+  N_SIGNALS
+};
+
+static guint view_helper_signals[N_SIGNALS] = { 0 };
+
+static void
+finalize (GObject *gobject);
+
+static void
+view_helper_class_init (ViewHelperClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = finalize;
+    
+  /* Emitted when a redraw is needed, with the area that needs redrawing. */
+  view_helper_signals[SIGNAL_REDRAW_NEEDED] = g_signal_new ("redraw-needed",
+                G_TYPE_FROM_CLASS (klass),
+                G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                0,
+                NULL, NULL,
+                g_cclosure_marshal_VOID__BOXED,
+                G_TYPE_NONE, 1,
+                GEGL_TYPE_RECTANGLE);
+}
+
+static void
+view_helper_init (ViewHelper *self)
+{
+  self->node        = NULL;
+  self->x           = 0;
+  self->y           = 0;
+  self->scale       = 1.0;
+  self->monitor_id  = 0;
+  self->processor   = NULL;
+}
+
+static void
+finalize (GObject *gobject)
+{
+   ViewHelper *self = VIEW_HELPER(gobject);
+
+  if (self->monitor_id)
+    {  
+      g_source_remove (self->monitor_id);
+      self->monitor_id = 0;
+    }
+
+  if (self->node)
+    g_object_unref (self->node);
+
+  if (self->processor)
+    g_object_unref (self->processor);
+}    
+
+
+static void
+invalidated_event (GeglNode      *node,
+                   GeglRectangle *rect,
+                   ViewHelper    *self)
+{
+  view_helper_repaint (self);
+}
+
+static gboolean
+task_monitor (ViewHelper *self)
+{
+  if (self->processor==NULL)
+    return FALSE;
+  if (gegl_processor_work (self->processor, NULL))
+    return TRUE;
+
+  self->monitor_id = 0;
+
+  return FALSE;
+}
+
+
+/* When the GeglNode has been computed,
+ * find out which area in the view changed and emit the
+ * "redraw" signal to notify it that a redraw is needed */
+static void
+computed_event (GeglNode      *node,
+                GeglRectangle *rect,
+                ViewHelper    *self)
+{
+  gint x = self->scale * (rect->x) - self->x;
+  gint y = self->scale * (rect->y) - self->y;
+  gint w = ceil (self->scale * rect->width);
+  gint h = ceil (self->scale * rect->height);
+  GeglRectangle redraw_rect = {x, y, w, h};
+
+  g_signal_emit (self, view_helper_signals[SIGNAL_REDRAW_NEEDED],
+	         0, &redraw_rect, NULL);
+}
+
+ViewHelper *
+view_helper_new(void)
+{
+    return VIEW_HELPER(g_object_new(VIEW_HELPER_TYPE, NULL));
+}
+
+/* Draw the view of the GeglNode to the provided cairo context,
+ * taking into account transformations et.c. 
+ * @rect the bounding box of the area to draw in view coordinates
+ * 
+ * For instance called by widget during the draw/expose */
+void
+view_helper_draw (ViewHelper *self, cairo_t *cr, GdkRectangle *rect)
+{
+  cairo_surface_t *surface = NULL;
+  guchar          *buf = NULL;
+  GeglRectangle   roi;
+
+  roi.x = self->x + rect->x;
+  roi.y = self->y + rect->y;
+  roi.width  = rect->width;
+  roi.height = rect->height;
+
+  buf = g_malloc ((roi.width) * (roi.height) * 4);
+
+  gegl_node_blit (self->node,
+                  self->scale,
+                  &roi,
+                  babl_format ("B'aG'aR'aA u8"),
+                  (gpointer)buf,
+                  GEGL_AUTO_ROWSTRIDE,
+                  GEGL_BLIT_CACHE | (self->block ? 0 : GEGL_BLIT_DIRTY));
+
+  surface = cairo_image_surface_create_for_data (buf, 
+                                                 CAIRO_FORMAT_ARGB32, 
+                                                 roi.width, roi.height, 
+                                                 roi.width*4);
+  cairo_set_source_surface (cr, surface, rect->x, rect->y);
+  cairo_paint (cr);
+
+  cairo_surface_destroy (surface);
+  g_free (buf);
+
+}
+
+void
+view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation)
+{
+    self->allocation = *allocation;
+    view_helper_repaint(self);
+}
+
+/* Trigger processing of the GeglNode */
+void
+view_helper_repaint (ViewHelper *self)
+{
+  GeglRectangle    roi;
+
+  roi.x = self->x / self->scale;
+  roi.y = self->y / self->scale;
+
+  roi.width = ceil(self->allocation.width / self->scale+1);
+  roi.height = ceil(self->allocation.height / self->scale+1);
+
+  if (self->monitor_id == 0)
+    {
+      self->monitor_id = g_idle_add_full (G_PRIORITY_LOW,
+                                          (GSourceFunc) task_monitor, self,
+                                          NULL);
+
+      if (self->processor == NULL)
+        {
+          if (self->node)
+            self->processor = gegl_node_new_processor (self->node, &roi);
+        }
+    }
+
+  if (self->processor)
+    gegl_processor_set_rectangle (self->processor, &roi);
+}
+
+void
+invalidate(ViewHelper *self)
+{
+    GeglRectangle redraw_rect = {0, 0, -1, -1}; /* Indicates full redraw */
+    g_signal_emit (self, view_helper_signals[SIGNAL_REDRAW_NEEDED],
+            0, &redraw_rect, NULL);
+}
+
+void
+view_helper_set_node(ViewHelper *self, GeglNode *node)
+{
+    if (self->node == node)
+        return;
+
+    if (self->node)
+        g_object_unref (self->node);
+
+    if (node) {
+        g_object_ref (node);
+        self->node = node;
+
+        g_signal_connect_object (self->node, "computed",
+                               G_CALLBACK (computed_event),
+                               self, 0);
+        g_signal_connect_object (self->node, "invalidated",
+                               G_CALLBACK (invalidated_event),
+                               self, 0);
+
+        view_helper_repaint (self);
+
+    } else
+        self->node = NULL;
+}
+
+GeglNode *
+view_helper_get_node(ViewHelper *self)
+{
+    return self->node;
+}
+
+void
+view_helper_set_scale(ViewHelper *self, float scale)
+{
+    if (self->scale == scale)
+        return;
+
+    self->scale = scale;
+    invalidate(self);
+}
+
+float
+view_helper_get_scale(ViewHelper *self)
+{
+    return self->scale;
+}
+
+void
+view_helper_set_x(ViewHelper *self, float x)
+{
+    if (self->x == x)
+        return;
+
+    self->x = x;
+    invalidate(self);
+}
+
+float
+view_helper_get_x(ViewHelper *self)
+{
+    return self->x;
+}
+
+void
+view_helper_set_y(ViewHelper *self, float y)
+{
+    if (self->y == y)
+        return;
+
+    self->y = y;
+    invalidate(self);
+}
+
+float
+view_helper_get_y(ViewHelper *self)
+{
+    return self->y;
+}
diff --git a/gegl-gtk/internal/view-helper.h b/gegl-gtk/internal/view-helper.h
new file mode 100644
index 0000000..ec07835
--- /dev/null
+++ b/gegl-gtk/internal/view-helper.h
@@ -0,0 +1,81 @@
+/* This file is part of GEGL-GTK
+ *
+ * GEGL-GTK is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL-GTK 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL-GTK; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright (C) 2003, 2004, 2006 Ãyvind KolÃs <pippin gimp org>
+ */
+
+#ifndef __VIEW_HELPER_H__
+#define __VIEW_HELPER_H__
+
+#include <glib-object.h>
+#include <gegl.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define VIEW_HELPER_TYPE            (view_helper_get_type ())
+#define VIEW_HELPER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), VIEW_HELPER_TYPE, ViewHelper))
+#define VIEW_HELPER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass),  VIEW_HELPER_TYPE, ViewHelperClass))
+#define IS_VIEW_HELPER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), VIEW_HELPER_TYPE))
+#define IS_VIEW_HELPER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),  VIEW_HELPER_TYPE))
+#define VIEW_HELPER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj),  VIEW_HELPER_TYPE, ViewHelperClass))
+
+typedef struct _ViewHelper        ViewHelper;
+typedef struct _ViewHelperClass   ViewHelperClass;
+
+struct _ViewHelper
+{
+  GObject parent_instance;
+
+  GeglNode      *node;
+  gfloat         x;
+  gfloat         y;
+  gdouble        scale;
+  gboolean       block;    /* blocking render */
+  guint          monitor_id;
+  GeglProcessor *processor;
+  GdkRectangle   allocation;
+};
+
+struct _ViewHelperClass
+{
+  GObjectClass parent_class;
+};
+
+
+GType view_helper_get_type      (void) G_GNUC_CONST;
+
+ViewHelper *view_helper_new(void);
+void view_helper_node_changed(ViewHelper *self);
+void view_helper_repaint(ViewHelper *self);
+void view_helper_draw(ViewHelper *self, cairo_t *cr, GdkRectangle *rect);
+void view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation);
+
+void view_helper_set_node(ViewHelper *self, GeglNode *node);
+GeglNode *view_helper_get_node(ViewHelper *self);
+
+void view_helper_set_scale(ViewHelper *self, float scale);
+float view_helper_get_scale(ViewHelper *self);
+
+void view_helper_set_x(ViewHelper *self, float x);
+float view_helper_get_x(ViewHelper *self);
+
+void view_helper_set_y(ViewHelper *self, float y);
+float view_helper_get_y(ViewHelper *self);
+
+
+G_END_DECLS
+
+#endif /* __VIEW_HELPER_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]