[gegl-gtk] GeglGtkView: Set size of widget to match node bounding box
- From: Jon Nordby <jonnor src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl-gtk] GeglGtkView: Set size of widget to match node bounding box
- Date: Sun, 9 Oct 2011 14:34:47 +0000 (UTC)
commit 842bbef29f474a59a7de5300e1a3d9b9793fe729
Author: Jon Nordby <jononor gmail com>
Date: Sun Oct 9 16:08:17 2011 +0200
GeglGtkView: Set size of widget to match node bounding box
Especially useful for putting the widget in a scrolled window,
see the gegl-gtk-scroll example.
examples/c/gegl-gtk-scroll.c | 13 +++----
gegl-gtk/gegl-gtk-view.c | 20 +++++++++--
gegl-gtk/internal/view-helper.c | 76 +++++++++++++++++++++++++++++---------
gegl-gtk/internal/view-helper.h | 3 +-
4 files changed, 82 insertions(+), 30 deletions(-)
---
diff --git a/examples/c/gegl-gtk-scroll.c b/examples/c/gegl-gtk-scroll.c
index 64f1e6a..ffcf9e0 100644
--- a/examples/c/gegl-gtk-scroll.c
+++ b/examples/c/gegl-gtk-scroll.c
@@ -45,7 +45,7 @@ main (gint argc,
/* Build graph that loads an image */
graph = gegl_node_new ();
node = gegl_node_new_child (graph,
- "operation", "gegl:load",
+ "operation", "gegl:load",
"path", argv[1], NULL);
gegl_node_process (node);
@@ -53,20 +53,17 @@ main (gint argc,
/* Setup */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "GEGL-GTK scrolled example");
-
-
+
+
scrolled = gtk_scrolled_window_new(NULL, NULL);
view = GTK_WIDGET(gegl_gtk_view_new_for_node(node));
- // FIXME: should be possible for the widget to do this automatically, and take changes into account
- gtk_widget_set_size_request(view, 500, 500);
-
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrolled), view);
-
+
gtk_container_add (GTK_CONTAINER (window), scrolled);
- g_signal_connect (window, "destroy",
+ g_signal_connect (window, "destroy",
G_CALLBACK (gtk_main_quit), NULL);
gtk_widget_show_all (window);
diff --git a/gegl-gtk/gegl-gtk-view.c b/gegl-gtk/gegl-gtk-view.c
index 0259eba..dde9e22 100644
--- a/gegl-gtk/gegl-gtk-view.c
+++ b/gegl-gtk/gegl-gtk-view.c
@@ -86,6 +86,8 @@ trigger_redraw(ViewHelper* priv, GeglRectangle *rect, GeglGtkView *view);
static void
size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data);
+static void
+view_size_changed(ViewHelper* priv, GeglRectangle *rect, GeglGtkView *view);
static void
gegl_gtk_view_class_init (GeglGtkViewClass * klass)
@@ -148,7 +150,8 @@ gegl_gtk_view_init (GeglGtkView *self)
self->priv = (GeglGtkViewPrivate *)view_helper_new();
g_signal_connect(self->priv, "redraw-needed", G_CALLBACK (trigger_redraw), (gpointer)self);
-
+ g_signal_connect(self->priv, "size-changed", G_CALLBACK (view_size_changed), (gpointer)self);
+
g_signal_connect(self, "size-allocate", G_CALLBACK (size_allocate), NULL);
}
@@ -233,13 +236,24 @@ trigger_redraw (ViewHelper *priv,
GeglRectangle *rect,
GeglGtkView *view)
{
- if (rect->width < 0 || rect->height < 0)
+ 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);
}
+/* Bounding box of the node view changed */
+static void
+view_size_changed(ViewHelper* priv, GeglRectangle *rect, GeglGtkView *view)
+{
+ /* Resize the widget to fit the entire view bounding box
+ * TODO: implement a policy for this
+ * consumers should be able to have the view not autoscale at all
+ * or to have it autoscale the content to fit the size of widget */
+ gtk_widget_set_size_request(GTK_WIDGET(view), rect->width, rect->height);
+}
+
static void
size_allocate(GtkWidget *widget, GdkRectangle *allocation, gpointer user_data)
{
@@ -287,7 +301,7 @@ expose_event (GtkWidget *widget,
gdk_region_get_clipbox (event->region, &rect);
view_helper_draw (priv, cr, &rect);
-
+
cairo_destroy (cr);
view_helper_repaint (priv); /* Only needed due to possible allocation changes? */
diff --git a/gegl-gtk/internal/view-helper.c b/gegl-gtk/internal/view-helper.c
index 682d6d6..add98a3 100644
--- a/gegl-gtk/internal/view-helper.c
+++ b/gegl-gtk/internal/view-helper.c
@@ -28,6 +28,7 @@ G_DEFINE_TYPE (ViewHelper, view_helper, G_TYPE_OBJECT)
enum
{
SIGNAL_REDRAW_NEEDED,
+ SIGNAL_SIZE_CHANGED,
N_SIGNALS
};
@@ -42,7 +43,7 @@ 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),
@@ -52,17 +53,33 @@ view_helper_class_init (ViewHelperClass * klass)
g_cclosure_marshal_VOID__BOXED,
G_TYPE_NONE, 1,
GEGL_TYPE_RECTANGLE);
+
+ /* Emitted when the size of the view changes, with the new size. */
+ view_helper_signals[SIGNAL_SIZE_CHANGED] = g_signal_new ("size-changed",
+ 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)
{
+ GeglRectangle invalid_rect = {0, 0, -1, -1};
+ GdkRectangle invalid_gdkrect = {0, 0, -1, -1};
+
self->node = NULL;
self->x = 0;
self->y = 0;
self->scale = 1.0;
self->monitor_id = 0;
self->processor = NULL;
+
+ self->widget_allocation = invalid_gdkrect;
+ self->view_bbox = invalid_rect;
}
static void
@@ -71,7 +88,7 @@ finalize (GObject *gobject)
ViewHelper *self = VIEW_HELPER(gobject);
if (self->monitor_id)
- {
+ {
g_source_remove (self->monitor_id);
self->monitor_id = 0;
}
@@ -81,8 +98,21 @@ finalize (GObject *gobject)
if (self->processor)
g_object_unref (self->processor);
-}
+}
+
+/* Transform a rectangle from model to view coordinates. */
+static void
+model_rect_to_view_rect(ViewHelper *self, GeglRectangle *rect)
+{
+ GeglRectangle temp;
+ temp.x = self->scale * (rect->x) - rect->x;
+ temp.y = self->scale * (rect->y) - rect->y;
+ temp.width = ceil (self->scale * rect->width);
+ temp.height = ceil (self->scale * rect->height);
+
+ *rect = temp;
+}
static void
invalidated_event (GeglNode *node,
@@ -107,18 +137,28 @@ task_monitor (ViewHelper *self)
/* 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 */
+ * find out if the size of the vie changed and
+ * emit the "size-changed" signal to notify view
+ * find out which area in the view was computed and emit the
+ * "redraw-needed" 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};
+ /* 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);
+ }
+
+ /* 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);
@@ -131,9 +171,9 @@ view_helper_new(void)
}
/* Draw the view of the GeglNode to the provided cairo context,
- * taking into account transformations et.c.
+ * 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)
@@ -157,9 +197,9 @@ view_helper_draw (ViewHelper *self, cairo_t *cr, GdkRectangle *rect)
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,
+ 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);
@@ -172,7 +212,7 @@ view_helper_draw (ViewHelper *self, cairo_t *cr, GdkRectangle *rect)
void
view_helper_set_allocation(ViewHelper *self, GdkRectangle *allocation)
{
- self->allocation = *allocation;
+ self->widget_allocation = *allocation;
view_helper_repaint(self);
}
@@ -185,8 +225,8 @@ view_helper_repaint (ViewHelper *self)
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);
+ 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)
{
diff --git a/gegl-gtk/internal/view-helper.h b/gegl-gtk/internal/view-helper.h
index ec07835..51df6b5 100644
--- a/gegl-gtk/internal/view-helper.h
+++ b/gegl-gtk/internal/view-helper.h
@@ -46,7 +46,8 @@ struct _ViewHelper
gboolean block; /* blocking render */
guint monitor_id;
GeglProcessor *processor;
- GdkRectangle allocation;
+ GdkRectangle widget_allocation; /* The allocated size of the widget */
+ GeglRectangle view_bbox; /* Bounding box of the node, in view coordinates */
};
struct _ViewHelperClass
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]