[gegl-gtk] GeglGtkView: Implement configurable autoscaling



commit d7052f3771d9d58f57e7275a58351ed9248b7497
Author: Jon Nordby <jononor gmail com>
Date:   Sun Oct 9 20:29:18 2011 +0200

    GeglGtkView: Implement configurable autoscaling

 examples/c/gegl-gtk-basic.c     |    2 +-
 examples/c/gegl-gtk-paint.c     |    2 +-
 examples/c/gegl-gtk-scroll.c    |    1 +
 gegl-gtk/.gitignore             |    1 +
 gegl-gtk/Makefile.am            |   17 ++++++-
 gegl-gtk/gegl-gtk-enums.h       |   35 +++++++++++++++
 gegl-gtk/gegl-gtk-view.c        |   31 +++++++++++--
 gegl-gtk/gegl-gtk-view.h        |    5 ++
 gegl-gtk/internal/view-helper.c |   91 +++++++++++++++++++++++++++-----------
 gegl-gtk/internal/view-helper.h |    7 +++-
 10 files changed, 155 insertions(+), 37 deletions(-)
---
diff --git a/examples/c/gegl-gtk-basic.c b/examples/c/gegl-gtk-basic.c
index 2498432..010c1c0 100644
--- a/examples/c/gegl-gtk-basic.c
+++ b/examples/c/gegl-gtk-basic.c
@@ -53,7 +53,7 @@ main (gint    argc,
   window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
   gtk_window_set_title (GTK_WINDOW (window), "GEGL-GTK basic example");
 
-  view = gegl_gtk_view_new_for_node(node);
+  view = GTK_WIDGET(gegl_gtk_view_new_for_node(node));
   gtk_container_add (GTK_CONTAINER (window), view);
 
   g_signal_connect (window, "destroy", 
diff --git a/examples/c/gegl-gtk-paint.c b/examples/c/gegl-gtk-paint.c
index 2dbad93..7e50848 100644
--- a/examples/c/gegl-gtk-paint.c
+++ b/examples/c/gegl-gtk-paint.c
@@ -165,7 +165,7 @@ main (gint    argc,
 
     gegl_node_link_many (loadbuf, out, NULL);
 
-    view = gegl_gtk_view_new_for_node(out);
+    view = GTK_WIDGET(gegl_gtk_view_new_for_node(out));
     top  = loadbuf;
   }
 
diff --git a/examples/c/gegl-gtk-scroll.c b/examples/c/gegl-gtk-scroll.c
index ffcf9e0..6fd85a4 100644
--- a/examples/c/gegl-gtk-scroll.c
+++ b/examples/c/gegl-gtk-scroll.c
@@ -58,6 +58,7 @@ main (gint    argc,
   scrolled = gtk_scrolled_window_new(NULL, NULL);
 
   view = GTK_WIDGET(gegl_gtk_view_new_for_node(node));
+  gegl_gtk_view_set_autoscale_policy(GEGL_GTK_VIEW(view), GEGL_GTK_VIEW_AUTOSCALE_WIDGET);
 
   gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), view);
 
diff --git a/gegl-gtk/.gitignore b/gegl-gtk/.gitignore
index 2f12be8..ce962ec 100644
--- a/gegl-gtk/.gitignore
+++ b/gegl-gtk/.gitignore
@@ -1,3 +1,4 @@
 *.gir
 *.typelib
 *.vapi
+gegl-gtk-enums.c
diff --git a/gegl-gtk/Makefile.am b/gegl-gtk/Makefile.am
index 15a0eb8..c5feda7 100644
--- a/gegl-gtk/Makefile.am
+++ b/gegl-gtk/Makefile.am
@@ -1,12 +1,25 @@
 CLEANFILES = 
 
-headers = gegl-gtk.h gegl-gtk-view.h
-sources = gegl-gtk-view.c
+gen_sources = gegl-gtk-enums.c
+CLEANFILES += $(gen_sources)
+
+headers = gegl-gtk.h gegl-gtk-view.h gegl-gtk-enums.h
+sources = gegl-gtk-view.c $(gen_sources)
 INCLUDES = $(GTK_CFLAGS) $(GEGL_CFLAGS)
 
 internal_headers = internal/view-helper.h
 internal_sources = internal/view-helper.c
 
+gegl-gtk-enums.c: $(srcdir)/gegl-gtk-enums.h
+	glib-mkenums \
+			   --fhead "/* This is a generated file, do not edit directly */\n\n#include \"config.h\"\n#include <glib-object.h>\n#include \"gegl-gtk-enums.h\"" \
+			   --fprod "\n/* enumerations from \"@filename \" */" \
+			   --vhead "GType\n enum_name@_get_type (void)\n{\n  static GType etype = 0;\n  if (etype == 0) {\n	static const G Type@Value values[] = {" \
+			   --vprod "	  { @VALUENAME@, \"@valuenick \", \"@valuenick \" }," \
+			   --vtail "	  { 0, NULL, NULL }\n	};\n	etype = g_ type@_register_static (\"@EnumName \", values);\n  }\n  return etype;\n}\n\n" \
+			   $(srcdir)/gegl-gtk-enums.h > gegl-gtk-enums.c
+
+
 gegl_gtk_includedir=$(includedir)/gegl-gtk$(GEGL_GTK_GTK_VERSION)-$(GEGL_GTK_API_VERSION)
 gegl_gtk_include_HEADERS = $(headers)
 
diff --git a/gegl-gtk/gegl-gtk-enums.h b/gegl-gtk/gegl-gtk-enums.h
new file mode 100644
index 0000000..63f9385
--- /dev/null
+++ b/gegl-gtk/gegl-gtk-enums.h
@@ -0,0 +1,35 @@
+/* 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) 2011 Jon Nordby <jononor gmail com>
+ */
+
+#ifndef __GEGL_GTK_ENUMS_H__
+#define __GEGL_GTK_ENUMS_H__
+
+G_BEGIN_DECLS
+
+typedef enum {
+  GEGL_GTK_VIEW_AUTOSCALE_DISABLED = 0,
+  GEGL_GTK_VIEW_AUTOSCALE_WIDGET,
+  GEGL_GTK_VIEW_AUTOSCALE_CONTENT
+} GeglGtkViewAutoscale;
+
+GType gegl_gtk_view_autoscale_get_type   (void) G_GNUC_CONST;
+#define GEGL_GTK_TYPE_VIEW_AUTOSCALE (gegl_gtk_view_autoscale_get_type())
+
+G_END_DECLS
+
+#endif /* __GEGL_GTK_ENUMS_H__ */
diff --git a/gegl-gtk/gegl-gtk-view.c b/gegl-gtk/gegl-gtk-view.c
index dde9e22..392802f 100644
--- a/gegl-gtk/gegl-gtk-view.c
+++ b/gegl-gtk/gegl-gtk-view.c
@@ -46,7 +46,8 @@ enum
   PROP_X,
   PROP_Y,
   PROP_SCALE,
-  PROP_BLOCK
+  PROP_BLOCK,
+  PROP_AUTOSCALE_POLICY
 };
 
 
@@ -141,6 +142,12 @@ gegl_gtk_view_class_init (GeglGtkViewClass * klass)
                                                         "Make sure all data requested to blit is generated.",
                                                         FALSE,
                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class, PROP_AUTOSCALE_POLICY,
+                                   g_param_spec_enum ("autoscale-policy", NULL, NULL,
+                                                      GEGL_GTK_TYPE_VIEW_AUTOSCALE,
+                                                      GEGL_GTK_VIEW_AUTOSCALE_CONTENT,
+                                                      G_PARAM_READWRITE |
+                                                      G_PARAM_CONSTRUCT));
 
 }
 
@@ -191,6 +198,9 @@ set_property (GObject      *gobject,
     case PROP_SCALE:
       gegl_gtk_view_set_scale(self, g_value_get_double(value));
       break;
+    case PROP_AUTOSCALE_POLICY:
+      gegl_gtk_view_set_autoscale_policy(self, g_value_get_enum(value));
+      break;
     default:
 
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
@@ -224,6 +234,9 @@ get_property (GObject      *gobject,
     case PROP_SCALE:
       g_value_set_double (value, gegl_gtk_view_get_scale(self));
       break;
+    case PROP_AUTOSCALE_POLICY:
+      g_value_set_enum (value, gegl_gtk_view_get_autoscale_policy(self));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, property_id, pspec);
       break;
@@ -276,8 +289,6 @@ draw (GtkWidget * widget, cairo_t *cr)
 
   view_helper_draw (priv, cr, &rect);
 
-  view_helper_repaint (priv); /* Only needed due to possible allocation changes? */
-
   return FALSE;
 }
 #endif
@@ -304,8 +315,6 @@ expose_event (GtkWidget      *widget,
 
   cairo_destroy (cr);
 
-  view_helper_repaint (priv); /* Only needed due to possible allocation changes? */
-
   return FALSE;
 }
 #endif
@@ -378,3 +387,15 @@ gegl_gtk_view_get_y(GeglGtkView *self)
 {
     return view_helper_get_y(GET_PRIVATE(self));
 }
+
+void
+gegl_gtk_view_set_autoscale_policy(GeglGtkView *self, GeglGtkViewAutoscale autoscale)
+{
+    view_helper_set_autoscale_policy(GET_PRIVATE(self), autoscale);
+}
+
+GeglGtkViewAutoscale
+gegl_gtk_view_get_autoscale_policy(GeglGtkView *self)
+{
+    return view_helper_get_autoscale_policy(GET_PRIVATE(self));
+}
diff --git a/gegl-gtk/gegl-gtk-view.h b/gegl-gtk/gegl-gtk-view.h
index 9ea904b..6cf36e4 100644
--- a/gegl-gtk/gegl-gtk-view.h
+++ b/gegl-gtk/gegl-gtk-view.h
@@ -22,6 +22,8 @@
 #include <gtk/gtk.h>
 #include <gegl.h>
 
+#include "gegl-gtk-enums.h"
+
 G_BEGIN_DECLS
 
 #define GEGL_GTK_TYPE_VIEW            (gegl_gtk_view_get_type ())
@@ -67,6 +69,9 @@ float gegl_gtk_view_get_x(GeglGtkView *self);
 void gegl_gtk_view_set_y(GeglGtkView *self, float y);
 float gegl_gtk_view_get_y(GeglGtkView *self);
 
+void gegl_gtk_view_set_autoscale_policy(GeglGtkView *self, GeglGtkViewAutoscale autoscale);
+GeglGtkViewAutoscale gegl_gtk_view_get_autoscale_policy(GeglGtkView *self);
+
 G_END_DECLS
 
 #endif /* __GEGL_GTK_VIEW_H__ */
diff --git a/gegl-gtk/internal/view-helper.c b/gegl-gtk/internal/view-helper.c
index add98a3..62e5ee7 100644
--- a/gegl-gtk/internal/view-helper.c
+++ b/gegl-gtk/internal/view-helper.c
@@ -75,11 +75,12 @@ view_helper_init (ViewHelper *self)
   self->x           = 0;
   self->y           = 0;
   self->scale       = 1.0;
+  self->autoscale_policy = GEGL_GTK_VIEW_AUTOSCALE_CONTENT;
+
   self->monitor_id  = 0;
   self->processor   = NULL;
 
   self->widget_allocation = invalid_gdkrect;
-  self->view_bbox   = invalid_rect;
 }
 
 static void
@@ -115,6 +116,35 @@ model_rect_to_view_rect(ViewHelper *self, GeglRectangle *rect)
 }
 
 static void
+update_autoscale(ViewHelper *self)
+{
+    GdkRectangle viewport = self->widget_allocation;
+    GeglRectangle bbox = gegl_node_get_bounding_box(self->node);
+    model_rect_to_view_rect(self, &bbox);
+
+    if (!self->node || viewport.width < 0 || viewport.height < 0
+        || bbox.width < 0 || bbox.height < 0)
+        return;
+
+    if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_WIDGET) {
+        /* Request widget size change */
+        /* XXX: Should we reset scale/x/y here? */
+        g_signal_emit (self, view_helper_signals[SIGNAL_SIZE_CHANGED],
+             0, &bbox, NULL);
+
+    } else if (self->autoscale_policy == GEGL_GTK_VIEW_AUTOSCALE_CONTENT) {
+        /* Calculate and set scaling factor to make the content fit inside */
+        float width_ratio = bbox.width / (float)viewport.width;
+        float height_ratio = bbox.height / (float)viewport.height;
+        float max_ratio = width_ratio >= height_ratio ? width_ratio : height_ratio;
+
+        float current_scale = view_helper_get_scale(self);
+        view_helper_set_scale(self, current_scale*(1.0/max_ratio));
+    }
+
+}
+
+static void
 invalidated_event (GeglNode      *node,
                    GeglRectangle *rect,
                    ViewHelper    *self)
@@ -127,6 +157,7 @@ task_monitor (ViewHelper *self)
 {
   if (self->processor==NULL)
     return FALSE;
+
   if (gegl_processor_work (self->processor, NULL))
     return TRUE;
 
@@ -146,22 +177,14 @@ computed_event (GeglNode      *node,
                 GeglRectangle *rect,
                 ViewHelper    *self)
 {
-  /* Notify about potential size change */
-  GeglRectangle bbox = gegl_node_get_bounding_box(node);
-  model_rect_to_view_rect(self, &bbox);
-
-  if (!gegl_rectangle_equal(&bbox, &(self->view_bbox))) {
-      self->view_bbox = bbox;
-      g_signal_emit (self, view_helper_signals[SIGNAL_SIZE_CHANGED],
-                 0, &bbox, NULL);
-  }
+    update_autoscale(self);
 
-  /* Emit redraw-needed */
-  GeglRectangle redraw_rect = *rect;
-  model_rect_to_view_rect(self, &redraw_rect);
+    /* Emit redraw-needed */
+    GeglRectangle redraw_rect = *rect;
+    model_rect_to_view_rect(self, &redraw_rect);
 
-  g_signal_emit (self, view_helper_signals[SIGNAL_REDRAW_NEEDED],
-	         0, &redraw_rect, NULL);
+    g_signal_emit (self, view_helper_signals[SIGNAL_REDRAW_NEEDED],
+             0, &redraw_rect, NULL);
 }
 
 ViewHelper *
@@ -213,7 +236,7 @@ void
 view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation)
 {
     self->widget_allocation = *allocation;
-    view_helper_repaint(self);
+    update_autoscale(self);
 }
 
 /* Trigger processing of the GeglNode */
@@ -222,27 +245,25 @@ view_helper_repaint (ViewHelper *self)
 {
   GeglRectangle    roi;
 
+  if (!self->node)
+      return;
+
   roi.x = self->x / self->scale;
   roi.y = self->y / self->scale;
 
   roi.width = ceil(self->widget_allocation.width / self->scale+1);
   roi.height = ceil(self->widget_allocation.height / self->scale+1);
 
-  if (self->monitor_id == 0)
-    {
+  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);
+      gegl_processor_set_rectangle (self->processor, &roi);
+  else
+      self->processor = gegl_node_new_processor (self->node, &roi);
 }
 
 void
@@ -273,7 +294,7 @@ view_helper_set_node(ViewHelper *self, GeglNode *node)
                                G_CALLBACK (invalidated_event),
                                self, 0);
 
-        view_helper_repaint (self);
+        invalidate(self);
 
     } else
         self->node = NULL;
@@ -332,3 +353,19 @@ view_helper_get_y(ViewHelper *self)
 {
     return self->y;
 }
+
+void
+view_helper_set_autoscale_policy(ViewHelper *self, GeglGtkViewAutoscale autoscale)
+{
+    if (self->autoscale_policy == autoscale)
+        return;
+
+    self->autoscale_policy = autoscale;
+    update_autoscale(self);
+}
+
+GeglGtkViewAutoscale
+view_helper_get_autoscale_policy(ViewHelper *self)
+{
+    return self->autoscale_policy;
+}
diff --git a/gegl-gtk/internal/view-helper.h b/gegl-gtk/internal/view-helper.h
index 51df6b5..b2f749d 100644
--- a/gegl-gtk/internal/view-helper.h
+++ b/gegl-gtk/internal/view-helper.h
@@ -22,6 +22,8 @@
 #include <glib-object.h>
 #include <gegl.h>
 #include <gtk/gtk.h>
+24ea1a60d4497df6cff9828093a8f6b9eed644cf
+#include <gegl-gtk-enums.h>
 
 G_BEGIN_DECLS
 
@@ -44,10 +46,11 @@ struct _ViewHelper
   gfloat         y;
   gdouble        scale;
   gboolean       block;    /* blocking render */
+  GeglGtkViewAutoscale autoscale_policy;
+
   guint          monitor_id;
   GeglProcessor *processor;
   GdkRectangle   widget_allocation; /* The allocated size of the widget */
-  GeglRectangle  view_bbox; /* Bounding box of the node, in view coordinates */
 };
 
 struct _ViewHelperClass
@@ -76,6 +79,8 @@ float view_helper_get_x(ViewHelper *self);
 void view_helper_set_y(ViewHelper *self, float y);
 float view_helper_get_y(ViewHelper *self);
 
+void view_helper_set_autoscale_policy(ViewHelper *self, GeglGtkViewAutoscale autoscale);
+GeglGtkViewAutoscale view_helper_get_autoscale_policy(ViewHelper *self);
 
 G_END_DECLS
 



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