goocanvas r38 - in trunk: . demo src
- From: damon svn gnome org
- To: svn-commits-list gnome org
- Subject: goocanvas r38 - in trunk: . demo src
- Date: Mon, 12 Jan 2009 23:22:22 +0000 (UTC)
Author: damon
Date: Mon Jan 12 23:22:22 2009
New Revision: 38
URL: http://svn.gnome.org/viewvc/goocanvas?rev=38&view=rev
Log:
2009-01-12 Armin Burgmeier <armin openismus com>
* src/goocanvasellipse.c:
* src/goocanvaspolyline.c:
* src/goocanvasgroup.c:
* src/goocanvaspath.c:
* src/goocanvaswidget.c:
* src/goocanvastext.c:
* src/goocanvastable.c: Added "x", "y", "width" and "height"
properties where they do not exist already. GooCanvasGroup clips its
children if they are out of the specified area, and GooCanvasText
clips the text. It is possible to turn off the clipping by using -1
for width or height, respectively, which is the default.
* demo/generic-position-demo.c:
* demo/mv-generic-position-demo.c:
* demo/Makefile.am: Added a demo showing how this can be used to
generically resize items using drag and drop.
(Patch from bug #555097 committed with quite a few changes by Damon)
Added:
trunk/demo/generic-position-demo.c
trunk/demo/mv-generic-position-demo.c
Modified:
trunk/ChangeLog
trunk/demo/Makefile.am
trunk/src/goocanvasellipse.c
trunk/src/goocanvasgroup.c
trunk/src/goocanvaspath.c
trunk/src/goocanvaspolyline.c
trunk/src/goocanvastable.c
trunk/src/goocanvastext.c
trunk/src/goocanvaswidget.c
Modified: trunk/demo/Makefile.am
==============================================================================
--- trunk/demo/Makefile.am (original)
+++ trunk/demo/Makefile.am Mon Jan 12 23:22:22 2009
@@ -9,7 +9,7 @@
# -DGDK_DISABLE_DEPRECATED -DGDK_PIXBUF_DISABLE_DEPRECATED \
# -DGTK_DISABLE_DEPRECATED
-noinst_PROGRAMS = demo table-demo simple-demo scalability-demo units-demo widgets-demo mv-demo mv-table-demo mv-simple-demo mv-scalability-demo
+noinst_PROGRAMS = demo table-demo generic-position-demo simple-demo scalability-demo units-demo widgets-demo mv-demo mv-table-demo mv-generic-position-demo mv-simple-demo mv-scalability-demo
demo_SOURCES = \
demo.c demo-fifteen.c demo-scalability.c demo-grabs.c \
@@ -68,5 +68,15 @@
widgets_demo_LDADD = $(top_builddir)/src/libgoocanvas.la @PACKAGE_LIBS@ $(INTLLIBS)
+generic_position_demo_SOURCES = \
+ generic-position-demo.c
+
+generic_position_demo_LDADD = $(top_builddir)/src/libgoocanvas.la @PACKAGE_LIBS@ $(INTLLIBS)
+
+mv_generic_position_demo_SOURCES = \
+ mv-generic-position-demo.c
+
+mv_generic_position_demo_LDADD = $(top_builddir)/src/libgoocanvas.la @PACKAGE_LIBS@ $(INTLLIBS)
+
EXTRA_DIST = flower.png toroid.png
Added: trunk/demo/generic-position-demo.c
==============================================================================
--- (empty file)
+++ trunk/demo/generic-position-demo.c Mon Jan 12 23:22:22 2009
@@ -0,0 +1,217 @@
+#include <stdlib.h>
+#include <goocanvas.h>
+
+typedef enum {
+ MODE_MOVE,
+ MODE_RESIZE
+} Mode;
+
+Mode drag_mode;
+GooCanvasItem *drag_item = NULL;
+gdouble drag_x = 0.0;
+gdouble drag_y = 0.0;
+
+gdouble item_x = 0.0;
+gdouble item_y = 0.0;
+gdouble item_width = 0.0;
+gdouble item_height = 0.0;
+
+static gboolean
+on_button_press_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ if (event->button == 1 || event->button == 3)
+ {
+ if (event->button == 1)
+ drag_mode = MODE_MOVE;
+ else
+ drag_mode = MODE_RESIZE;
+
+ drag_item = item;
+ drag_x = event->x;
+ drag_y = event->y;
+
+ g_object_get (G_OBJECT (item),
+ "x", &item_x,
+ "y", &item_y,
+ "width", &item_width,
+ "height", &item_height,
+ NULL);
+
+ goo_canvas_pointer_grab (GOO_CANVAS (user_data), item, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK, NULL, event->time);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_button_release_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ if (drag_item == item && drag_item != NULL)
+ {
+ goo_canvas_pointer_ungrab (GOO_CANVAS (user_data), drag_item, event->time);
+ drag_item = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_motion_notify_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventMotion *event,
+ gpointer user_data)
+{
+ if (drag_item == item && drag_item != NULL)
+ {
+ gdouble rel_x = event->x - drag_x;
+ gdouble rel_y = event->y - drag_y;
+
+ if (drag_mode == MODE_MOVE)
+ {
+ g_object_set (G_OBJECT (item), "x", item_x + rel_x, "y", item_y + rel_y, NULL);
+ }
+ else
+ {
+ gdouble new_width = MAX (item_width + rel_x, 5.0);
+ gdouble new_height = MAX (item_height + rel_y, 5.0);
+
+ g_object_set (G_OBJECT (item), "width", new_width, "height", new_height, NULL);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+setup_dnd_handlers (GooCanvas *canvas,
+ GooCanvasItem *item)
+{
+ g_signal_connect (G_OBJECT (item), "button-press-event", G_CALLBACK (on_button_press_event_cb), canvas);
+ g_signal_connect (G_OBJECT (item), "button-release-event", G_CALLBACK (on_button_release_event_cb), canvas);
+/* g_signal_connect (G_OBJECT (item), "grab-broken-event", G_CALLBACK (on_button_release_event_cb), canvas);*/
+ g_signal_connect (G_OBJECT (item), "motion-notify-event", G_CALLBACK (on_motion_notify_event_cb), canvas);
+}
+
+
+void
+setup_canvas (GtkWidget *canvas)
+{
+ GooCanvasItem *root;
+ GooCanvasItem *item;
+ GdkPixbuf *pixbuf;
+ GtkWidget *button;
+ GooCanvasItem* child;
+
+ root = goo_canvas_get_root_item (GOO_CANVAS (canvas));
+
+ /* Test clipping of GooCanvasGroup: We put the rectangle and the ellipse into
+ * a group with width=200 and height=200. */
+ item = goo_canvas_group_new (root, "x", 50.0, "y", 350.0, "width", 200.0, "height", 200.0, NULL);
+ /*goo_canvas_item_rotate(item, 45.0, 150.0, 450.0);*/
+
+ child = goo_canvas_rect_new (item, 0.0, 0.0, 100, 100, "fill-color", "blue", NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+ goo_canvas_item_rotate(child, 45.0, 50.0, 50.0);
+
+ child = goo_canvas_ellipse_new (item, 150, 00, 50, 50, "fill-color", "red", NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+
+ item = goo_canvas_polyline_new (root, FALSE, 5.0, 250.0, 350.0, 275.0, 400.0, 300.0, 350.0, 325.0, 400.0, 350.0, 350.0, "stroke-color", "cyan", "line-width", 5.0, NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ item = goo_canvas_path_new (root, "M20,500 C20,450 100,450 100,500", "stroke-color", "green", "line-width", 5.0, NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ pixbuf = gtk_widget_render_icon (GTK_WIDGET (canvas), GTK_STOCK_DIALOG_WARNING, GTK_ICON_SIZE_DIALOG, NULL);
+ item = goo_canvas_image_new (root, pixbuf, 150, 450, /*"fill-color", "yellow", */NULL);
+ g_object_unref (pixbuf);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ item = goo_canvas_text_new (root, "Hello, World!", 250, 450, -1, GTK_ANCHOR_NW, "fill-color", "magenta", "wrap", PANGO_WRAP_WORD_CHAR, NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ button = gtk_label_new ("GtkLabel");
+ item = goo_canvas_widget_new (root, button, 50, 550, -1, -1, NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ item = goo_canvas_table_new (root, "horz-grid-line-width", 2.0, "vert-grid-line-width", 2.0, "row-spacing", 2.0, "column-spacing", 2.0, NULL);
+ goo_canvas_item_translate (item, 10.0, 10.0);
+ setup_dnd_handlers (GOO_CANVAS (canvas), item);
+
+ child = goo_canvas_rect_new (item, 10.0, 10.0, 50.0, 50.0, "fill-color", "blue", "x", 10.0, "y", 25.0, NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+ goo_canvas_item_set_child_properties (item, child, "column", 0, "row", 0, "columns", 1, "rows", 1, NULL);
+ /*goo_canvas_item_translate (child, 10.0, 10.0);*/
+
+ child = goo_canvas_rect_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "red", NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+ goo_canvas_item_set_child_properties (item, child, "column", 1, "row", 0, "columns", 1, "rows", 1, NULL);
+
+ child = goo_canvas_rect_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "green", NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+ goo_canvas_item_set_child_properties (item, child, "column", 0, "row", 1, "columns", 1, "rows", 1, NULL);
+
+ child = goo_canvas_rect_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "yellow", NULL);
+ setup_dnd_handlers (GOO_CANVAS (canvas), child);
+ goo_canvas_item_set_child_properties (item, child, "column", 1, "row", 1, "columns", 1, "rows", 1, NULL);
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window, *vbox, *label, *scrolled_win, *canvas;
+
+ /* Initialize GTK+. */
+ gtk_set_locale ();
+ gtk_init (&argc, &argv);
+
+ /* Create the window and widgets. */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
+ gtk_widget_show (window);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 4);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ label = gtk_label_new ("Use Ctrl+Left Click to move items or Ctrl+Right Click to resize items");
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* Create top canvas. */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_SHADOW_IN);
+ gtk_widget_show (scrolled_win);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
+
+ canvas = goo_canvas_new ();
+ g_object_set (G_OBJECT (canvas), "integer-layout", TRUE, NULL);
+/* gtk_widget_set_size_request (canvas, 600, 250);*/
+ goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
+ gtk_widget_show (canvas);
+ gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);
+
+ setup_canvas (canvas);
+
+ gtk_main ();
+
+ return 0;
+}
Added: trunk/demo/mv-generic-position-demo.c
==============================================================================
--- (empty file)
+++ trunk/demo/mv-generic-position-demo.c Mon Jan 12 23:22:22 2009
@@ -0,0 +1,250 @@
+#include <stdlib.h>
+#include <goocanvas.h>
+
+typedef enum {
+ MODE_MOVE,
+ MODE_RESIZE
+} Mode;
+
+Mode drag_mode;
+GooCanvasItem *drag_item = NULL;
+gdouble drag_x = 0.0;
+gdouble drag_y = 0.0;
+
+gdouble item_x = 0.0;
+gdouble item_y = 0.0;
+gdouble item_width = 0.0;
+gdouble item_height = 0.0;
+
+static gboolean
+on_button_press_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ GooCanvasItemModel *model = goo_canvas_item_get_model (item);
+
+ if (event->state & GDK_CONTROL_MASK)
+ {
+ if (event->button == 1 || event->button == 3)
+ {
+ if (event->button == 1)
+ drag_mode = MODE_MOVE;
+ else
+ drag_mode = MODE_RESIZE;
+
+ drag_item = item;
+ drag_x = event->x;
+ drag_y = event->y;
+
+ g_object_get (G_OBJECT (model),
+ "x", &item_x,
+ "y", &item_y,
+ "width", &item_width,
+ "height", &item_height,
+ NULL);
+
+ goo_canvas_pointer_grab (GOO_CANVAS (user_data), item, GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_RELEASE_MASK, NULL, event->time);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_button_release_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventButton *event,
+ gpointer user_data)
+{
+ if (drag_item == item && drag_item != NULL)
+ {
+ goo_canvas_pointer_ungrab (GOO_CANVAS (user_data), drag_item, event->time);
+ drag_item = NULL;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+on_motion_notify_event_cb (GooCanvasItem *item,
+ GooCanvasItem *target_item,
+ GdkEventMotion *event,
+ gpointer user_data)
+{
+ GooCanvasItemModel *model = goo_canvas_item_get_model (item);
+
+ if (drag_item == item && drag_item != NULL)
+ {
+ gdouble rel_x = event->x - drag_x;
+ gdouble rel_y = event->y - drag_y;
+
+ if (drag_mode == MODE_MOVE)
+ {
+ g_object_set (G_OBJECT (model), "x", item_x + rel_x, "y", item_y + rel_y, NULL);
+ }
+ else
+ {
+ gdouble new_width = MAX (item_width + rel_x, 5.0);
+ gdouble new_height = MAX (item_height + rel_y, 5.0);
+
+ g_object_set (G_OBJECT (model), "width", new_width, "height", new_height, NULL);
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void
+on_item_created (GooCanvas *canvas,
+ GooCanvasItem *item,
+ GooCanvasItemModel *model,
+ gpointer data)
+{
+ if (g_object_get_data (G_OBJECT (model), "setup-dnd-signals"))
+ {
+ g_signal_connect (G_OBJECT (item), "button-press-event", G_CALLBACK (on_button_press_event_cb), canvas);
+ g_signal_connect (G_OBJECT (item), "button-release-event", G_CALLBACK (on_button_release_event_cb), canvas);
+ /* g_signal_connect (G_OBJECT (item), "grab-broken-event", G_CALLBACK (on_button_release_event_cb), canvas);*/
+ g_signal_connect (G_OBJECT (item), "motion-notify-event", G_CALLBACK (on_motion_notify_event_cb), canvas);
+ }
+}
+
+
+static GooCanvasItemModel*
+create_model (GdkPixbuf *pixbuf)
+{
+ GooCanvasItemModel *root;
+ GooCanvasItemModel *item;
+ GooCanvasItemModel* child;
+
+ root = goo_canvas_group_model_new (NULL, NULL);
+
+ /* Test clipping of GooCanvasGroup: We put the rectangle and the ellipse into
+ * a group with width=200 and height=200. */
+ item = goo_canvas_group_model_new (root, "x", 50.0, "y", 350.0, "width", 200.0, "height", 200.0, NULL);
+ /*goo_canvas_item_model_rotate(item, 45.0, 150.0, 450.0);*/
+
+ child = goo_canvas_rect_model_new (item, 0.0, 0.0, 100, 100, "fill-color", "blue", NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+ goo_canvas_item_model_rotate(child, 45.0, 50.0, 50.0);
+
+ child = goo_canvas_ellipse_model_new (item, 150, 00, 50, 50, "fill-color", "red", NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+
+ item = goo_canvas_polyline_model_new (root, FALSE, 5.0, 250.0, 350.0, 275.0, 400.0, 300.0, 350.0, 325.0, 400.0, 350.0, 350.0, "stroke-color", "cyan", "line-width", 5.0, NULL);
+ g_object_set_data (G_OBJECT (item), "setup-dnd-signals", "TRUE");
+
+ item = goo_canvas_path_model_new (root, "M20,500 C20,450 100,450 100,500", "stroke-color", "green", "line-width", 5.0, NULL);
+ g_object_set_data (G_OBJECT (item), "setup-dnd-signals", "TRUE");
+
+ item = goo_canvas_image_model_new (root, pixbuf, 150, 450, /*"fill-color", "yellow", */NULL);
+ g_object_unref (pixbuf);
+ g_object_set_data (G_OBJECT (item), "setup-dnd-signals", "TRUE");
+
+ item = goo_canvas_text_model_new (root, "Hello, World!", 250, 450, -1, GTK_ANCHOR_NW, "fill-color", "magenta", "wrap", PANGO_WRAP_WORD_CHAR, NULL);
+ g_object_set_data (G_OBJECT (item), "setup-dnd-signals", "TRUE");
+
+ item = goo_canvas_table_model_new (root, "horz-grid-line-width", 2.0, "vert-grid-line-width", 2.0, "row-spacing", 2.0, "column-spacing", 2.0, NULL);
+ goo_canvas_item_model_translate (item, 10.0, 10.0);
+ g_object_set_data (G_OBJECT (item), "setup-dnd-signals", "TRUE");
+
+ child = goo_canvas_rect_model_new (item, 10.0, 10.0, 50.0, 50.0, "fill-color", "blue", "x", 10.0, "y", 25.0, NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+ goo_canvas_item_model_set_child_properties (item, child, "column", 0, "row", 0, "columns", 1, "rows", 1, NULL);
+ /*goo_canvas_item_model_translate (child, 10.0, 10.0);*/
+
+ child = goo_canvas_rect_model_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "red", NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+ goo_canvas_item_model_set_child_properties (item, child, "column", 1, "row", 0, "columns", 1, "rows", 1, NULL);
+
+ child = goo_canvas_rect_model_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "green", NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+ goo_canvas_item_model_set_child_properties(item, child, "column", 0, "row", 1, "columns", 1, "rows", 1, NULL);
+
+ child = goo_canvas_rect_model_new (item, 0.0, 0.0, 50.0, 50.0, "fill-color", "yellow", NULL);
+ g_object_set_data (G_OBJECT (child), "setup-dnd-signals", "TRUE");
+ goo_canvas_item_model_set_child_properties (item, child, "column", 1, "row", 1, "columns", 1, "rows", 1, NULL);
+
+ return root;
+}
+
+
+static GtkWidget*
+create_window (GooCanvasItemModel *model)
+{
+ GtkWidget *window, *vbox, *label, *scrolled_win, *canvas;
+
+ /* Create the window and widgets. */
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size (GTK_WINDOW (window), 640, 600);
+ gtk_widget_show (window);
+ g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+
+ vbox = gtk_vbox_new (FALSE, 4);
+ gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
+ gtk_widget_show (vbox);
+ gtk_container_add (GTK_CONTAINER (window), vbox);
+
+ label = gtk_label_new ("Use Ctrl+Left Click to move items or Ctrl+Right Click to resize items");
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0);
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
+ gtk_widget_show (label);
+
+ /* Create top canvas. */
+ scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_win),
+ GTK_SHADOW_IN);
+ gtk_widget_show (scrolled_win);
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled_win, TRUE, TRUE, 0);
+
+ canvas = goo_canvas_new ();
+ g_object_set (G_OBJECT (canvas), "integer-layout", TRUE, NULL);
+/* gtk_widget_set_size_request (canvas, 600, 250);*/
+ goo_canvas_set_bounds (GOO_CANVAS (canvas), 0, 0, 1000, 1000);
+ gtk_widget_show (canvas);
+ gtk_container_add (GTK_CONTAINER (scrolled_win), canvas);
+
+ g_signal_connect (canvas, "item_created",
+ G_CALLBACK (on_item_created), NULL);
+
+ goo_canvas_set_root_item_model (GOO_CANVAS (canvas), model);
+
+ return window;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GooCanvasItemModel *model;
+ GdkPixbuf *pixbuf;
+
+ /* Initialize GTK+. */
+ gtk_set_locale ();
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ pixbuf = gtk_widget_render_icon (window, GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG, NULL);
+
+ model = create_model (pixbuf);
+
+ /* Create 2 windows to show off multiple views. */
+ window = create_window (model);
+#if 1
+ window = create_window (model);
+#endif
+
+ g_object_unref (model);
+
+ gtk_main ();
+
+ return 0;
+}
Modified: trunk/src/goocanvasellipse.c
==============================================================================
--- trunk/src/goocanvasellipse.c (original)
+++ trunk/src/goocanvasellipse.c Mon Jan 12 23:22:22 2009
@@ -23,6 +23,10 @@
*
* To get or set the properties of an existing #GooCanvasEllipse, use
* g_object_get() and g_object_set().
+ *
+ * The ellipse can be specified either with the "center-x", "center-y",
+ * "radius-x" and "radius-y" properties, or with the "x", "y", "width" and
+ * "height" properties.
*/
#include <config.h>
#include <math.h>
@@ -37,7 +41,12 @@
PROP_CENTER_X,
PROP_CENTER_Y,
PROP_RADIUS_X,
- PROP_RADIUS_Y
+ PROP_RADIUS_Y,
+
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT
};
@@ -92,6 +101,36 @@
_("The vertical radius of the ellipse"),
0.0, G_MAXDOUBLE, 0.0,
G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_X,
+ g_param_spec_double ("x",
+ "X",
+ _("The x coordinate of the left side of the ellipse"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_Y,
+ g_param_spec_double ("y",
+ "Y",
+ _("The y coordinate of the top of the ellipse"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The width of the ellipse"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height of the ellipse"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
}
@@ -224,6 +263,18 @@
case PROP_RADIUS_Y:
g_value_set_double (value, ellipse_data->radius_y);
break;
+ case PROP_X:
+ g_value_set_double (value, ellipse_data->center_x - ellipse_data->radius_x);
+ break;
+ case PROP_Y:
+ g_value_set_double (value, ellipse_data->center_y - ellipse_data->radius_y);
+ break;
+ case PROP_WIDTH:
+ g_value_set_double (value, 2.0 * ellipse_data->radius_x);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_double (value, 2.0 * ellipse_data->radius_y);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -251,19 +302,55 @@
const GValue *value,
GParamSpec *pspec)
{
+ gdouble x, y;
+
switch (prop_id)
{
case PROP_CENTER_X:
ellipse_data->center_x = g_value_get_double (value);
+ g_object_notify (object, "x");
break;
case PROP_CENTER_Y:
ellipse_data->center_y = g_value_get_double (value);
+ g_object_notify (object, "y");
break;
case PROP_RADIUS_X:
ellipse_data->radius_x = g_value_get_double (value);
+ g_object_notify (object, "width");
break;
case PROP_RADIUS_Y:
ellipse_data->radius_y = g_value_get_double (value);
+ g_object_notify (object, "height");
+ break;
+ case PROP_X:
+ ellipse_data->center_x = g_value_get_double (value) + ellipse_data->radius_x;
+ g_object_notify (object, "center-x");
+ break;
+ case PROP_Y:
+ ellipse_data->center_y = g_value_get_double (value) + ellipse_data->radius_y;
+ g_object_notify (object, "center-y");
+ break;
+ case PROP_WIDTH:
+ /* Calculate the current x coordinate. */
+ x = ellipse_data->center_x - ellipse_data->radius_x;
+ /* Calculate the new radius_x, which is half the width. */
+ ellipse_data->radius_x = g_value_get_double (value) / 2.0;
+ /* Now calculate the new center_x. */
+ ellipse_data->center_x = x + ellipse_data->radius_x;
+
+ g_object_notify (object, "center-x");
+ g_object_notify (object, "radius-x");
+ break;
+ case PROP_HEIGHT:
+ /* Calculate the current y coordinate. */
+ y = ellipse_data->center_y - ellipse_data->radius_y;
+ /* Calculate the new radius_y, which is half the height. */
+ ellipse_data->radius_y = g_value_get_double (value) / 2.0;
+ /* Now calculate the new center_y. */
+ ellipse_data->center_y = y + ellipse_data->radius_y;
+
+ g_object_notify (object, "center-y");
+ g_object_notify (object, "radius-y");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -356,6 +443,10 @@
* To get or set the properties of an existing #GooCanvasEllipseModel, use
* g_object_get() and g_object_set().
*
+ * The ellipse can be specified either with the "center-x", "center-y",
+ * "radius-x" and "radius-y" properties, or with the "x", "y", "width" and
+ * "height" properties.
+ *
* To respond to events such as mouse clicks on the ellipse you must connect
* to the signal handlers of the corresponding #GooCanvasEllipse objects.
* (See goo_canvas_get_item() and #GooCanvas::item-created.)
Modified: trunk/src/goocanvasgroup.c
==============================================================================
--- trunk/src/goocanvasgroup.c (original)
+++ trunk/src/goocanvasgroup.c Mon Jan 12 23:22:22 2009
@@ -25,6 +25,9 @@
* goo_canvas_item_rotate(), and the properties such as "visibility" and
* "pointer-events".
*
+ * If the #GooCanvasGroup:width and #GooCanvasGroup:height properties are
+ * set to positive values then the group is clipped to the given size.
+ *
* To create a #GooCanvasGroup use goo_canvas_group_new().
*
* To get or set the properties of an existing #GooCanvasGroup, use
@@ -40,9 +43,38 @@
#include "goocanvasmarshal.h"
#include "goocanvasatk.h"
+typedef struct _GooCanvasGroupPrivate GooCanvasGroupPrivate;
+struct _GooCanvasGroupPrivate {
+ gdouble x;
+ gdouble y;
+ gdouble width;
+ gdouble height;
+};
+
+#define GOO_CANVAS_GROUP_GET_PRIVATE(group) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((group), GOO_TYPE_CANVAS_GROUP, GooCanvasGroupPrivate))
+#define GOO_CANVAS_GROUP_MODEL_GET_PRIVATE(group) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((group), GOO_TYPE_CANVAS_GROUP_MODEL, GooCanvasGroupPrivate))
+
+enum {
+ PROP_0,
+
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT
+};
static void goo_canvas_group_dispose (GObject *object);
static void goo_canvas_group_finalize (GObject *object);
+static void goo_canvas_group_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void goo_canvas_group_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
static void canvas_item_interface_init (GooCanvasItemIface *iface);
G_DEFINE_TYPE_WITH_CODE (GooCanvasGroup, goo_canvas_group,
@@ -50,14 +82,53 @@
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
canvas_item_interface_init))
+static void
+goo_canvas_group_install_common_properties (GObjectClass *gobject_class)
+{
+ g_object_class_install_property (gobject_class, PROP_X,
+ g_param_spec_double ("x",
+ "X",
+ _("The x coordinate of the group"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_Y,
+ g_param_spec_double ("y",
+ "Y",
+ _("The y coordinate of the group"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The width of the group, or -1 to use the default width"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, -1.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height of the group, or -1 to use the default height"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, -1.0,
+ G_PARAM_READWRITE));
+}
static void
goo_canvas_group_class_init (GooCanvasGroupClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
+ g_type_class_add_private (gobject_class, sizeof (GooCanvasGroupPrivate));
+
gobject_class->dispose = goo_canvas_group_dispose;
gobject_class->finalize = goo_canvas_group_finalize;
+ gobject_class->get_property = goo_canvas_group_get_property;
+ gobject_class->set_property = goo_canvas_group_set_property;
/* Register our accessible factory, but only if accessibility is enabled. */
if (!ATK_IS_NO_OP_OBJECT_FACTORY (atk_registry_get_factory (atk_get_default_registry (), GTK_TYPE_WIDGET)))
@@ -66,13 +137,22 @@
GOO_TYPE_CANVAS_GROUP,
goo_canvas_item_accessible_factory_get_type ());
}
+
+ goo_canvas_group_install_common_properties (gobject_class);
}
static void
goo_canvas_group_init (GooCanvasGroup *group)
{
+ GooCanvasGroupPrivate* priv = GOO_CANVAS_GROUP_GET_PRIVATE (group);
+
group->items = g_ptr_array_sized_new (8);
+
+ priv->x = 0.0;
+ priv->y = 0.0;
+ priv->width = -1.0;
+ priv->height = -1.0;
}
@@ -146,6 +226,105 @@
}
+/* Gets the private data to use, from the model or from the item itself. */
+static GooCanvasGroupPrivate*
+goo_canvas_group_get_private (GooCanvasGroup *group)
+{
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple*) group;
+
+ if (simple->model)
+ return GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (simple->model);
+ else
+ return GOO_CANVAS_GROUP_GET_PRIVATE (group);
+}
+
+
+static void
+goo_canvas_group_get_common_property (GObject *object,
+ GooCanvasGroupPrivate *priv,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_X:
+ g_value_set_double (value, priv->x);
+ break;
+ case PROP_Y:
+ g_value_set_double (value, priv->y);
+ break;
+ case PROP_WIDTH:
+ g_value_set_double (value, priv->width);
+ break;
+ case PROP_HEIGHT:
+ g_value_set_double (value, priv->height);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+goo_canvas_group_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GooCanvasGroup *group = (GooCanvasGroup*) object;
+ GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
+
+ goo_canvas_group_get_common_property (object, priv, prop_id, value, pspec);
+}
+
+static void
+goo_canvas_group_set_common_property (GObject *object,
+ GooCanvasGroupPrivate *priv,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (prop_id)
+ {
+ case PROP_X:
+ priv->x = g_value_get_double (value);
+ break;
+ case PROP_Y:
+ priv->y = g_value_get_double (value);
+ break;
+ case PROP_WIDTH:
+ priv->width = g_value_get_double (value);
+ break;
+ case PROP_HEIGHT:
+ priv->height = g_value_get_double (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+goo_canvas_group_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
+ GooCanvasGroup *group = (GooCanvasGroup*) object;
+ GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
+
+ if (simple->model)
+ {
+ g_warning ("Can't set property of a canvas item with a model - set the model property instead");
+ return;
+ }
+
+ goo_canvas_group_set_common_property (object, priv, prop_id, value, pspec);
+ goo_canvas_item_simple_changed (simple, TRUE);
+}
+
static void
goo_canvas_group_add_child (GooCanvasItem *item,
GooCanvasItem *child,
@@ -238,11 +417,11 @@
child_num, child_atk_obj);
}
+ g_ptr_array_remove_index (group->items, child_num);
+
goo_canvas_item_set_parent (child, NULL);
g_object_unref (child);
- g_ptr_array_remove_index (group->items, child_num);
-
goo_canvas_item_request_update (item);
}
@@ -405,6 +584,7 @@
{
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
GooCanvasGroup *group = (GooCanvasGroup*) item;
+ GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
GooCanvasBounds child_bounds;
gboolean initial_bounds = TRUE;
gint i;
@@ -424,35 +604,38 @@
cairo_save (cr);
if (simple->simple_data->transform)
- cairo_transform (cr, simple->simple_data->transform);
+ cairo_transform (cr, simple->simple_data->transform);
+
+ cairo_translate (cr, priv->x, priv->y);
for (i = 0; i < group->items->len; i++)
- {
- GooCanvasItem *child = group->items->pdata[i];
+ {
+ GooCanvasItem *child = group->items->pdata[i];
+
+ goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
+
+ /* If the child has non-empty bounds, compute the union. */
+ if (child_bounds.x1 < child_bounds.x2
+ && child_bounds.y1 < child_bounds.y2)
+ {
+ if (initial_bounds)
+ {
+ simple->bounds.x1 = child_bounds.x1;
+ simple->bounds.y1 = child_bounds.y1;
+ simple->bounds.x2 = child_bounds.x2;
+ simple->bounds.y2 = child_bounds.y2;
+ initial_bounds = FALSE;
+ }
+ else
+ {
+ simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
+ simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
+ simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
+ simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
+ }
+ }
+ }
- goo_canvas_item_update (child, entire_tree, cr, &child_bounds);
-
- /* If the child has non-empty bounds, compute the union. */
- if (child_bounds.x1 < child_bounds.x2
- && child_bounds.y1 < child_bounds.y2)
- {
- if (initial_bounds)
- {
- simple->bounds.x1 = child_bounds.x1;
- simple->bounds.y1 = child_bounds.y1;
- simple->bounds.x2 = child_bounds.x2;
- simple->bounds.y2 = child_bounds.y2;
- initial_bounds = FALSE;
- }
- else
- {
- simple->bounds.x1 = MIN (simple->bounds.x1, child_bounds.x1);
- simple->bounds.y1 = MIN (simple->bounds.y1, child_bounds.y1);
- simple->bounds.x2 = MAX (simple->bounds.x2, child_bounds.x2);
- simple->bounds.y2 = MAX (simple->bounds.y2, child_bounds.y2);
- }
- }
- }
cairo_restore (cr);
}
@@ -472,6 +655,7 @@
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
GooCanvasItemSimpleData *simple_data = simple->simple_data;
GooCanvasGroup *group = (GooCanvasGroup*) item;
+ GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
gboolean visible = parent_visible;
int i;
@@ -499,6 +683,8 @@
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, priv->x, priv->y);
+
/* If the group has a clip path, check if the point is inside it. */
if (simple_data->clip_path_commands)
{
@@ -514,6 +700,19 @@
}
}
+ if (priv->width > 0.0 && priv->height > 0.0)
+ {
+ double user_x = x, user_y = y;
+
+ cairo_device_to_user (cr, &user_x, &user_y);
+ if (user_x < 0.0 || user_x >= priv->width
+ || user_y < 0.0 || user_y >= priv->height)
+ {
+ cairo_restore (cr);
+ return found_items;
+ }
+ }
+
/* Step up from the bottom of the children to the top, adding any items
found to the start of the list. */
for (i = 0; i < group->items->len; i++)
@@ -539,6 +738,7 @@
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
GooCanvasItemSimpleData *simple_data = simple->simple_data;
GooCanvasGroup *group = (GooCanvasGroup*) item;
+ GooCanvasGroupPrivate *priv = goo_canvas_group_get_private (group);
gint i;
/* Skip the item if the bounds don't intersect the expose rectangle. */
@@ -557,6 +757,8 @@
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, priv->x, priv->y);
+
/* Clip with the group's clip path, if it is set. */
if (simple_data->clip_path_commands)
{
@@ -565,6 +767,12 @@
cairo_clip (cr);
}
+ if (priv->width > 0.0 && priv->height > 0.0)
+ {
+ cairo_rectangle (cr, 0.0, 0.0, priv->width, priv->height);
+ cairo_clip (cr);
+ }
+
for (i = 0; i < group->items->len; i++)
{
GooCanvasItem *child = group->items->pdata[i];
@@ -627,6 +835,14 @@
static void item_model_interface_init (GooCanvasItemModelIface *iface);
static void goo_canvas_group_model_dispose (GObject *object);
static void goo_canvas_group_model_finalize (GObject *object);
+static void goo_canvas_group_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void goo_canvas_group_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
G_DEFINE_TYPE_WITH_CODE (GooCanvasGroupModel, goo_canvas_group_model,
GOO_TYPE_CANVAS_ITEM_MODEL_SIMPLE,
@@ -638,16 +854,27 @@
goo_canvas_group_model_class_init (GooCanvasGroupModelClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
+ g_type_class_add_private (gobject_class, sizeof (GooCanvasGroupPrivate));
gobject_class->dispose = goo_canvas_group_model_dispose;
gobject_class->finalize = goo_canvas_group_model_finalize;
+ gobject_class->get_property = goo_canvas_group_model_get_property;
+ gobject_class->set_property = goo_canvas_group_model_set_property;
+
+ goo_canvas_group_install_common_properties (gobject_class);
}
static void
goo_canvas_group_model_init (GooCanvasGroupModel *gmodel)
{
+ GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (gmodel);
gmodel->children = g_ptr_array_sized_new (8);
+
+ priv->x = 0.0;
+ priv->y = 0.0;
+ priv->width = -1.0;
+ priv->height = -1.0;
}
@@ -720,6 +947,28 @@
G_OBJECT_CLASS (goo_canvas_group_model_parent_class)->finalize (object);
}
+static void goo_canvas_group_model_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GooCanvasGroupModel *model = (GooCanvasGroupModel*) object;
+ GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (model);
+
+ goo_canvas_group_get_common_property (object, priv, prop_id, value, pspec);
+}
+
+static void goo_canvas_group_model_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GooCanvasGroupModel *model = (GooCanvasGroupModel*) object;
+ GooCanvasGroupPrivate *priv = GOO_CANVAS_GROUP_MODEL_GET_PRIVATE (model);
+
+ goo_canvas_group_set_common_property (object, priv, prop_id, value, pspec);
+ g_signal_emit_by_name (model, "changed", TRUE);
+}
extern void _goo_canvas_item_model_emit_child_added (GooCanvasItemModel *model,
gint position);
@@ -772,11 +1021,12 @@
child = gmodel->children->pdata[child_num];
goo_canvas_item_model_set_parent (child, NULL);
- g_object_unref (child);
g_ptr_array_remove_index (gmodel->children, child_num);
g_signal_emit_by_name (gmodel, "child-removed", child_num);
+
+ g_object_unref (child);
}
Modified: trunk/src/goocanvaspath.c
==============================================================================
--- trunk/src/goocanvaspath.c (original)
+++ trunk/src/goocanvaspath.c Mon Jan 12 23:22:22 2009
@@ -33,12 +33,18 @@
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "goocanvaspath.h"
+#include "goocanvas.h"
enum {
PROP_0,
PROP_DATA,
+
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT
};
static void canvas_item_interface_init (GooCanvasItemIface *iface);
@@ -65,6 +71,36 @@
_("The sequence of path commands"),
NULL,
G_PARAM_WRITABLE));
+
+ g_object_class_install_property (gobject_class, PROP_X,
+ g_param_spec_double ("x",
+ "X",
+ _("The x coordinate of the path"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_Y,
+ g_param_spec_double ("y",
+ "Y",
+ _("The y coordinate of the path"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The width of the path"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height of the path"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
}
@@ -172,16 +208,164 @@
G_OBJECT_CLASS (goo_canvas_path_parent_class)->finalize (object);
}
+static void
+goo_canvas_path_common_get_extent (GooCanvas *canvas,
+ GooCanvasPathData *path_data,
+ GooCanvasBounds *bounds)
+{
+ cairo_t *cr;
+
+ cr = goo_canvas_create_cairo_context (canvas);
+ goo_canvas_create_path (path_data->path_commands, cr);
+ cairo_fill_extents (cr, &bounds->x1, &bounds->y1, &bounds->x2, &bounds->y2);
+ cairo_destroy (cr);
+}
+
+
+/* Moves all the absolute points in the command by the given amounts.
+ Relative points don't need to be moved. */
+static void
+goo_canvas_path_move_command (GooCanvasPathCommand *cmd,
+ gdouble x_offset,
+ gdouble y_offset)
+{
+ switch (cmd->simple.type)
+ {
+ case GOO_CANVAS_PATH_MOVE_TO:
+ case GOO_CANVAS_PATH_CLOSE_PATH:
+ case GOO_CANVAS_PATH_LINE_TO:
+ case GOO_CANVAS_PATH_HORIZONTAL_LINE_TO:
+ case GOO_CANVAS_PATH_VERTICAL_LINE_TO:
+ if (!cmd->simple.relative)
+ {
+ cmd->simple.x += x_offset;
+ cmd->simple.y += y_offset;
+ }
+ break;
+ case GOO_CANVAS_PATH_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_CURVE_TO:
+ case GOO_CANVAS_PATH_QUADRATIC_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO:
+ if (!cmd->curve.relative)
+ {
+ cmd->curve.x += x_offset;
+ cmd->curve.y += y_offset;
+ cmd->curve.x1 += x_offset;
+ cmd->curve.y1 += y_offset;
+ cmd->curve.x2 += x_offset;
+ cmd->curve.y2 += y_offset;
+ }
+ break;
+ case GOO_CANVAS_PATH_ELLIPTICAL_ARC:
+ if (!cmd->arc.relative)
+ {
+ cmd->arc.x += x_offset;
+ cmd->arc.y += y_offset;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+
+/* Scales all the points in the command by the given amounts. Absolute points
+ are scaled about the given origin. */
+static void
+goo_canvas_path_scale_command (GooCanvasPathCommand *cmd,
+ gdouble x_origin,
+ gdouble y_origin,
+ gdouble x_scale,
+ gdouble y_scale)
+{
+ switch (cmd->simple.type)
+ {
+ case GOO_CANVAS_PATH_MOVE_TO:
+ case GOO_CANVAS_PATH_CLOSE_PATH:
+ case GOO_CANVAS_PATH_LINE_TO:
+ case GOO_CANVAS_PATH_HORIZONTAL_LINE_TO:
+ case GOO_CANVAS_PATH_VERTICAL_LINE_TO:
+ if (cmd->simple.relative)
+ {
+ cmd->simple.x *= x_scale;
+ cmd->simple.y *= y_scale;
+ }
+ else
+ {
+ cmd->simple.x = x_origin + (cmd->simple.x - x_origin) * x_scale;
+ cmd->simple.y = y_origin + (cmd->simple.y - y_origin) * y_scale;
+ }
+ break;
+ case GOO_CANVAS_PATH_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_CURVE_TO:
+ case GOO_CANVAS_PATH_QUADRATIC_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO:
+ if (cmd->curve.relative)
+ {
+ cmd->curve.x *= x_scale;
+ cmd->curve.y *= y_scale;
+ cmd->curve.x1 *= x_scale;
+ cmd->curve.y1 *= y_scale;
+ cmd->curve.x2 *= x_scale;
+ cmd->curve.y2 *= y_scale;
+ }
+ else
+ {
+ cmd->curve.x = x_origin + (cmd->curve.x - x_origin) * x_scale;
+ cmd->curve.y = y_origin + (cmd->curve.y - y_origin) * y_scale;
+ cmd->curve.x1 = x_origin + (cmd->curve.x1 - x_origin) * x_scale;
+ cmd->curve.y1 = y_origin + (cmd->curve.y1 - y_origin) * y_scale;
+ cmd->curve.x2 = x_origin + (cmd->curve.x2 - x_origin) * x_scale;
+ cmd->curve.y2 = y_origin + (cmd->curve.y2 - y_origin) * y_scale;
+ }
+ break;
+ case GOO_CANVAS_PATH_ELLIPTICAL_ARC:
+ if (cmd->arc.relative)
+ {
+ cmd->arc.x *= x_scale;
+ cmd->arc.y *= y_scale;
+ }
+ else
+ {
+ cmd->arc.x = x_origin + (cmd->arc.x - x_origin) * x_scale;
+ cmd->arc.y = y_origin + (cmd->arc.y - y_origin) * y_scale;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
static void
goo_canvas_path_get_common_property (GObject *object,
+ GooCanvas *canvas,
GooCanvasPathData *path_data,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
+ GooCanvasBounds extent;
+
switch (prop_id)
{
+ case PROP_X:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.x1);
+ break;
+ case PROP_Y:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.y1);
+ break;
+ case PROP_WIDTH:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.x2 - extent.x1);
+ break;
+ case PROP_HEIGHT:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.y2 - extent.y1);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -195,26 +379,113 @@
GValue *value,
GParamSpec *pspec)
{
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
GooCanvasPath *path = (GooCanvasPath*) object;
- goo_canvas_path_get_common_property (object, path->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_get_common_property (object, simple->canvas,
+ path->path_data, prop_id, value, pspec);
}
static void
goo_canvas_path_set_common_property (GObject *object,
+ GooCanvas *canvas,
GooCanvasPathData *path_data,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
+ GooCanvasBounds extent;
+ GooCanvasPathCommand *cmd;
+ gdouble x_offset, y_offset, x_scale, y_scale;
+ guint i;
+
switch (prop_id)
{
case PROP_DATA:
if (path_data->path_commands)
g_array_free (path_data->path_commands, TRUE);
path_data->path_commands = goo_canvas_parse_path_data (g_value_get_string (value));
+ g_object_notify (object, "x");
+ g_object_notify (object, "y");
+ g_object_notify (object, "width");
+ g_object_notify (object, "height");
+ break;
+ case PROP_X:
+ if (path_data->path_commands->len > 0)
+ {
+ /* Calculate the x offset from the current position. */
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ x_offset = g_value_get_double (value) - extent.x1;
+
+ /* Add the offset to all the absolute x coordinates. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_move_command (cmd, x_offset, 0.0);
+ }
+ g_object_notify (object, "data");
+ }
+ break;
+ case PROP_Y:
+ if (path_data->path_commands->len > 0)
+ {
+ /* Calculate the y offset from the current position. */
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ y_offset = g_value_get_double (value) - extent.y1;
+
+ /* Add the offset to all the absolute y coordinates. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_move_command (cmd, 0.0, y_offset);
+ }
+ g_object_notify (object, "data");
+ }
+ break;
+ case PROP_WIDTH:
+ if (path_data->path_commands->len >= 2)
+ {
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ if (extent.x2 - extent.x1 != 0.0)
+ {
+ /* Calculate the amount to scale the path. */
+ x_scale = g_value_get_double (value) / (extent.x2 - extent.x1);
+
+ /* Scale the x coordinates, relative to the left-most point. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_scale_command (cmd, extent.x1, 0.0,
+ x_scale, 1.0);
+ }
+ g_object_notify (object, "data");
+ }
+ }
+ break;
+ case PROP_HEIGHT:
+ if (path_data->path_commands->len >= 2)
+ {
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ if (extent.y2 - extent.y1 != 0.0)
+ {
+ /* Calculate the amount to scale the polyline. */
+ y_scale = g_value_get_double (value) / (extent.y2 - extent.y1);
+
+ /* Scale the y coordinates, relative to the top-most point. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_scale_command (cmd, 0.0, extent.y1,
+ 1.0, y_scale);
+ }
+ g_object_notify (object, "data");
+ }
+ }
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -238,8 +509,8 @@
return;
}
- goo_canvas_path_set_common_property (object, path->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_set_common_property (object, simple->canvas, path->path_data,
+ prop_id, value, pspec);
goo_canvas_item_simple_changed (simple, TRUE);
}
@@ -496,8 +767,8 @@
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
- goo_canvas_path_get_common_property (object, &pmodel->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_get_common_property (object, NULL, &pmodel->path_data,
+ prop_id, value, pspec);
}
@@ -509,8 +780,8 @@
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
- goo_canvas_path_set_common_property (object, &pmodel->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_set_common_property (object, NULL, &pmodel->path_data,
+ prop_id, value, pspec);
g_signal_emit_by_name (pmodel, "changed", TRUE);
}
Modified: trunk/src/goocanvaspolyline.c
==============================================================================
--- trunk/src/goocanvaspolyline.c (original)
+++ trunk/src/goocanvaspolyline.c Mon Jan 12 23:22:22 2009
@@ -117,7 +117,12 @@
PROP_END_ARROW,
PROP_ARROW_LENGTH,
PROP_ARROW_WIDTH,
- PROP_ARROW_TIP_LENGTH
+ PROP_ARROW_TIP_LENGTH,
+
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT
};
@@ -180,6 +185,36 @@
_("The length of the arrow tip, as a multiple of the line width"),
0.0, G_MAXDOUBLE, 4.0,
G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_X,
+ g_param_spec_double ("x",
+ "X",
+ _("The x coordinate of the left-most point of the polyline"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_Y,
+ g_param_spec_double ("y",
+ "Y",
+ _("The y coordinate of the top-most point of the polyline"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The width of the polyline"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height of the polyline"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
}
@@ -212,6 +247,32 @@
static void
+goo_canvas_polyline_get_extent (GooCanvasPolylineData *polyline_data,
+ GooCanvasBounds *bounds)
+{
+ guint i;
+
+ if (polyline_data->num_points == 0)
+ {
+ bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0.0;
+ }
+ else
+ {
+ bounds->x1 = bounds->x2 = polyline_data->coords[0];
+ bounds->y1 = bounds->y2 = polyline_data->coords[1];
+
+ for (i = 1; i < polyline_data->num_points; i++)
+ {
+ bounds->x1 = MIN (bounds->x1, polyline_data->coords[2 * i]);
+ bounds->y1 = MIN (bounds->y1, polyline_data->coords[2 * i + 1]);
+ bounds->x2 = MAX (bounds->x2, polyline_data->coords[2 * i]);
+ bounds->y2 = MAX (bounds->y2, polyline_data->coords[2 * i + 1]);
+ }
+ }
+}
+
+
+static void
goo_canvas_polyline_get_common_property (GObject *object,
GooCanvasPolylineData *polyline_data,
guint prop_id,
@@ -219,6 +280,7 @@
GParamSpec *pspec)
{
GooCanvasPoints *points;
+ GooCanvasBounds extent;
switch (prop_id)
{
@@ -257,6 +319,22 @@
g_value_set_double (value, polyline_data->arrow_data
? polyline_data->arrow_data->arrow_tip_length : 4.0);
break;
+ case PROP_X:
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ g_value_set_double (value, extent.x1);
+ break;
+ case PROP_Y:
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ g_value_set_double (value, extent.y1);
+ break;
+ case PROP_WIDTH:
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ g_value_set_double (value, extent.x2 - extent.x1);
+ break;
+ case PROP_HEIGHT:
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ g_value_set_double (value, extent.y2 - extent.y1);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -428,6 +506,9 @@
GParamSpec *pspec)
{
GooCanvasPoints *points;
+ GooCanvasBounds extent;
+ gdouble x_offset, y_offset, x_scale, y_scale;
+ guint i;
switch (prop_id)
{
@@ -452,6 +533,10 @@
polyline_data->num_points * 2 * sizeof (double));
}
polyline_data->reconfigure_arrows = TRUE;
+ g_object_notify (object, "x");
+ g_object_notify (object, "y");
+ g_object_notify (object, "width");
+ g_object_notify (object, "height");
break;
case PROP_CLOSE_PATH:
polyline_data->close_path = g_value_get_boolean (value);
@@ -480,6 +565,68 @@
polyline_data->arrow_data->arrow_tip_length = g_value_get_double (value);
polyline_data->reconfigure_arrows = TRUE;
break;
+ case PROP_X:
+ if (polyline_data->num_points > 0)
+ {
+ /* Calculate the x offset from the current position. */
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ x_offset = g_value_get_double (value) - extent.x1;
+
+ /* Add the offset to all the x coordinates. */
+ for (i = 0; i < polyline_data->num_points; i++)
+ polyline_data->coords[2 * i] += x_offset;
+
+ g_object_notify (object, "points");
+ }
+ break;
+ case PROP_Y:
+ if (polyline_data->num_points > 0)
+ {
+ /* Calculate the y offset from the current position. */
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ y_offset = g_value_get_double (value) - extent.y1;
+
+ /* Add the offset to all the y coordinates. */
+ for (i = 0; i < polyline_data->num_points; i++)
+ polyline_data->coords[2 * i + 1] += y_offset;
+
+ g_object_notify (object, "points");
+ }
+ break;
+ case PROP_WIDTH:
+ if (polyline_data->num_points >= 2)
+ {
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ if (extent.x2 - extent.x1 != 0.0)
+ {
+ /* Calculate the amount to scale the polyline. */
+ x_scale = g_value_get_double (value) / (extent.x2 - extent.x1);
+
+ /* Scale the x coordinates, relative to the left-most point. */
+ for (i = 0; i < polyline_data->num_points; i++)
+ polyline_data->coords[2 * i] = extent.x1 + (polyline_data->coords[2 * i] - extent.x1) * x_scale;
+
+ g_object_notify (object, "points");
+ }
+ }
+ break;
+ case PROP_HEIGHT:
+ if (polyline_data->num_points >= 2)
+ {
+ goo_canvas_polyline_get_extent (polyline_data, &extent);
+ if (extent.y2 - extent.y1 != 0.0)
+ {
+ /* Calculate the amount to scale the polyline. */
+ y_scale = g_value_get_double (value) / (extent.y2 - extent.y1);
+
+ /* Scale the y coordinates, relative to the top-most point. */
+ for (i = 0; i < polyline_data->num_points; i++)
+ polyline_data->coords[2 * i + 1] = extent.y1 + (polyline_data->coords[2 * i + 1] - extent.y1) * y_scale;
+
+ g_object_notify (object, "points");
+ }
+ }
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
Modified: trunk/src/goocanvastable.c
==============================================================================
--- trunk/src/goocanvastable.c (original)
+++ trunk/src/goocanvastable.c Mon Jan 12 23:22:22 2009
@@ -51,6 +51,8 @@
enum
{
PROP_0,
+ PROP_X,
+ PROP_Y,
PROP_WIDTH,
PROP_HEIGHT,
PROP_ROW_SPACING,
@@ -164,6 +166,10 @@
GooCanvasTableDimensionLayoutData *dldata[2];
GooCanvasTableChildLayoutData *children;
+ /* Position of the table */
+ gdouble x;
+ gdouble y;
+
/* This is TRUE if we are rounding everything to the nearest integer. */
gboolean integer_layout;
@@ -219,20 +225,11 @@
goo_canvas_table_install_common_properties (GObjectClass *gobject_class,
InstallChildPropertyFunc install_child_property)
{
- g_object_class_install_property (gobject_class, PROP_WIDTH,
- g_param_spec_double ("width",
- _("Width"),
- _("The requested width of the table, or -1 to use the default width"),
- -G_MAXDOUBLE,
- G_MAXDOUBLE, -1.0,
- G_PARAM_READWRITE));
- g_object_class_install_property (gobject_class, PROP_HEIGHT,
- g_param_spec_double ("height",
- _("Height"),
- _("The requested height of the table, or -1 to use the default height"),
- -G_MAXDOUBLE,
- G_MAXDOUBLE, -1.0,
- G_PARAM_READWRITE));
+ /* Override from GooCanvasGroup */
+ g_object_class_override_property (gobject_class, PROP_X, "x");
+ g_object_class_override_property (gobject_class, PROP_Y, "y");
+ g_object_class_override_property (gobject_class, PROP_WIDTH, "width");
+ g_object_class_override_property (gobject_class, PROP_HEIGHT, "height");
/* FIXME: Support setting individual row/col spacing. */
g_object_class_install_property (gobject_class, PROP_ROW_SPACING,
@@ -430,6 +427,9 @@
table_data->children = g_array_new (0, 0, sizeof (GooCanvasTableChild));
table_data->layout_data = g_slice_new (GooCanvasTableLayoutData);
+ table_data->layout_data->x = 0.0;
+ table_data->layout_data->y = 0.0;
+
table_data->layout_data->children = NULL;
for (d = 0; d < 2; d++)
{
@@ -572,6 +572,12 @@
{
switch (prop_id)
{
+ case PROP_X:
+ g_value_set_double (value, table_data->layout_data->x);
+ break;
+ case PROP_Y:
+ g_value_set_double (value, table_data->layout_data->y);
+ break;
case PROP_WIDTH:
g_value_set_double (value, table_data->width);
break;
@@ -618,7 +624,7 @@
GooCanvasTable *table = (GooCanvasTable*) object;
goo_canvas_table_get_common_property (object, table->table_data,
- prop_id, value, pspec);
+ prop_id, value, pspec);
}
@@ -633,6 +639,12 @@
switch (prop_id)
{
+ case PROP_X:
+ table_data->layout_data->x = g_value_get_double (value);
+ break;
+ case PROP_Y:
+ table_data->layout_data->y = g_value_get_double (value);
+ break;
case PROP_WIDTH:
table_data->width = g_value_get_double (value);
break;
@@ -1929,7 +1941,7 @@
GooCanvasItemSimpleData *simple_data = simple->simple_data;
GooCanvasTable *table = (GooCanvasTable*) item;
GooCanvasTableData *table_data = table->table_data;
- GooCanvasTableLayoutData *layout_data;
+ GooCanvasTableLayoutData *layout_data = table_data->layout_data;
GooCanvasTableDimensionLayoutData *rows, *columns;
gdouble width = 0.0, height = 0.0;
gint row, column, end;
@@ -1953,6 +1965,8 @@
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
+
/* Initialize the layout data, get the requested sizes of all children, and
set the expand, shrink and empty flags. */
goo_canvas_table_init_layout_data (table);
@@ -1964,7 +1978,6 @@
goo_canvas_table_size_request_pass3 (table, HORZ);
goo_canvas_table_size_request_pass2 (table, HORZ);
- layout_data = table_data->layout_data;
rows = layout_data->dldata[VERT];
columns = layout_data->dldata[HORZ];
@@ -2049,6 +2062,8 @@
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
+
/* Convert the width from the parent's coordinate space. Note that we only
need to support a simple scale operation here. */
if (simple_data->transform)
@@ -2132,12 +2147,14 @@
-(allocated_area->y1 - requested_area->y1));
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
goo_canvas_table_update_requested_heights (item, cr);
cairo_restore (cr);
cairo_save (cr);
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
/* Calculate the table's bounds. */
simple->bounds.x1 = simple->bounds.y1 = 0.0;
@@ -2233,6 +2250,7 @@
cairo_save (cr);
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
/* Clip with the table's clip path, if it is set. */
if (simple_data->clip_path_commands)
@@ -2536,6 +2554,7 @@
cairo_save (cr);
if (simple_data->transform)
cairo_transform (cr, simple_data->transform);
+ cairo_translate (cr, layout_data->x, layout_data->y);
cairo_device_to_user (cr, &user_x, &user_y);
Modified: trunk/src/goocanvastext.c
==============================================================================
--- trunk/src/goocanvastext.c (original)
+++ trunk/src/goocanvastext.c Mon Jan 12 23:22:22 2009
@@ -19,6 +19,10 @@
* #GooCanvasItem functions such as goo_canvas_item_raise() and
* goo_canvas_item_rotate().
*
+ * The #GooCanvasText:width and #GooCanvasText:height properties specify the
+ * area of the item. If it exceeds that area because there is too much text,
+ * it is clipped. The properties can be set to -1 to disable clipping.
+ *
* To create a #GooCanvasText use goo_canvas_text_new().
*
* To get or set the properties of an existing #GooCanvasText, use
@@ -30,6 +34,15 @@
#include "goocanvastext.h"
#include "goocanvas.h"
+typedef struct _GooCanvasTextPrivate GooCanvasTextPrivate;
+struct _GooCanvasTextPrivate {
+ gdouble height;
+};
+
+#define GOO_CANVAS_TEXT_GET_PRIVATE(text) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((text), GOO_TYPE_CANVAS_TEXT, GooCanvasTextPrivate))
+#define GOO_CANVAS_TEXT_MODEL_GET_PRIVATE(text) \
+ (G_TYPE_INSTANCE_GET_PRIVATE ((text), GOO_TYPE_CANVAS_TEXT_MODEL, GooCanvasTextPrivate))
enum {
PROP_0,
@@ -37,6 +50,7 @@
PROP_X,
PROP_Y,
PROP_WIDTH,
+ PROP_HEIGHT,
PROP_TEXT,
PROP_USE_MARKUP,
PROP_ANCHOR,
@@ -45,6 +59,15 @@
PROP_WRAP
};
+static PangoLayout*
+goo_canvas_text_create_layout (GooCanvasItemSimpleData *simple_data,
+ GooCanvasTextData *text_data,
+ gdouble layout_width,
+ cairo_t *cr,
+ GooCanvasBounds *bounds,
+ gdouble *origin_x_return,
+ gdouble *origin_y_return);
+
static void goo_canvas_text_finalize (GObject *object);
static void canvas_item_interface_init (GooCanvasItemIface *iface);
static void goo_canvas_text_get_property (GObject *object,
@@ -121,6 +144,15 @@
G_MAXDOUBLE, -1.0,
G_PARAM_READWRITE));
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height to use to layout the text, or -1 to use the natural height"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, -1.0,
+ G_PARAM_READWRITE));
+
+
g_object_class_install_property (gobject_class, PROP_ANCHOR,
g_param_spec_enum ("anchor",
_("Anchor"),
@@ -142,6 +174,8 @@
static void
goo_canvas_text_init (GooCanvasText *text)
{
+ GooCanvasTextPrivate *priv = GOO_CANVAS_TEXT_GET_PRIVATE (text);
+
text->text_data = g_slice_new0 (GooCanvasTextData);
text->text_data->width = -1.0;
text->text_data->anchor = GTK_ANCHOR_NW;
@@ -149,6 +183,8 @@
text->text_data->wrap = PANGO_WRAP_WORD;
text->layout_width = -1.0;
+
+ priv->height = -1.0;
}
@@ -243,9 +279,23 @@
}
+/* Gets the private data to use, from the model or from the item itself. */
+static GooCanvasTextPrivate*
+goo_canvas_text_get_private (GooCanvasText *text)
+{
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple*) text;
+
+ if (simple->model)
+ return GOO_CANVAS_TEXT_MODEL_GET_PRIVATE (simple->model);
+ else
+ return GOO_CANVAS_TEXT_GET_PRIVATE (text);
+}
+
+
static void
goo_canvas_text_get_common_property (GObject *object,
GooCanvasTextData *text_data,
+ GooCanvasTextPrivate *priv,
guint prop_id,
GValue *value,
GParamSpec *pspec)
@@ -261,6 +311,9 @@
case PROP_WIDTH:
g_value_set_double (value, text_data->width);
break;
+ case PROP_HEIGHT:
+ g_value_set_double (value, priv->height);
+ break;
case PROP_TEXT:
g_value_set_string (value, text_data->text);
break;
@@ -293,15 +346,17 @@
GParamSpec *pspec)
{
GooCanvasText *text = (GooCanvasText*) object;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
- goo_canvas_text_get_common_property (object, text->text_data, prop_id,
- value, pspec);
+ goo_canvas_text_get_common_property (object, text->text_data, priv,
+ prop_id, value, pspec);
}
static void
goo_canvas_text_set_common_property (GObject *object,
GooCanvasTextData *text_data,
+ GooCanvasTextPrivate *priv,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
@@ -317,6 +372,9 @@
case PROP_WIDTH:
text_data->width = g_value_get_double (value);
break;
+ case PROP_HEIGHT:
+ priv->height = g_value_get_double (value);
+ break;
case PROP_TEXT:
g_free (text_data->text);
text_data->text = g_value_dup_string (value);
@@ -351,6 +409,7 @@
{
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
GooCanvasText *text = (GooCanvasText*) object;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
if (simple->model)
{
@@ -358,7 +417,7 @@
return;
}
- goo_canvas_text_set_common_property (object, text->text_data, prop_id,
+ goo_canvas_text_set_common_property (object, text->text_data, priv, prop_id,
value, pspec);
goo_canvas_item_simple_changed (simple, TRUE);
}
@@ -534,6 +593,7 @@
cairo_t *cr)
{
GooCanvasText *text = (GooCanvasText*) simple;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
PangoLayout *layout;
/* Initialize the layout width to the text item's specified width property.
@@ -546,6 +606,10 @@
text->layout_width, cr,
&simple->bounds, NULL, NULL);
g_object_unref (layout);
+
+ /* If the height is set, use that. */
+ if (priv->height > 0.0)
+ simple->bounds.y2 = simple->bounds.y1 + priv->height;
}
@@ -573,6 +637,7 @@
{
GooCanvasItemSimpleData *simple_data = simple->simple_data;
GooCanvasText *text = (GooCanvasText*) simple;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
PangoLayout *layout;
GooCanvasBounds bounds;
PangoLayoutIter *iter;
@@ -591,6 +656,10 @@
&& goo_canvas_text_is_unpainted (simple_data->style))
return FALSE;
+ /* Check if the point is outside the clipped height. */
+ if (priv->height > 0.0 && y > priv->height)
+ return FALSE;
+
layout = goo_canvas_text_create_layout (simple_data, text->text_data,
text->layout_width, cr, &bounds,
&origin_x, &origin_y);
@@ -643,6 +712,7 @@
const GooCanvasBounds *bounds)
{
GooCanvasText *text = (GooCanvasText*) simple;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
PangoLayout *layout;
GooCanvasBounds layout_bounds;
gdouble origin_x, origin_y;
@@ -658,8 +728,18 @@
text->layout_width, cr,
&layout_bounds,
&origin_x, &origin_y);
+ cairo_save (cr);
+
+ if (priv->height > 0.0)
+ {
+ cairo_rectangle (cr, origin_x, origin_y,
+ text->layout_width, priv->height);
+ cairo_clip (cr);
+ }
cairo_move_to (cr, origin_x, origin_y);
pango_cairo_show_layout (cr, layout);
+
+ cairo_restore (cr);
g_object_unref (layout);
}
@@ -672,6 +752,7 @@
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) item;
GooCanvasItemSimpleData *simple_data = simple->simple_data;
GooCanvasText *text = (GooCanvasText*) item;
+ GooCanvasTextPrivate *priv = goo_canvas_text_get_private (text);
PangoLayout *layout;
gdouble height;
@@ -692,15 +773,23 @@
if (simple_data->transform)
text->layout_width /= simple_data->transform->xx;
- /* Create layout with given width. */
- layout = goo_canvas_text_create_layout (simple_data, text->text_data,
- text->layout_width, cr,
- &simple->bounds, NULL, NULL);
- g_object_unref (layout);
+ if (priv->height < 0.0)
+ {
+ /* Create layout with given width. */
+ layout = goo_canvas_text_create_layout (simple_data, text->text_data,
+ text->layout_width, cr,
+ &simple->bounds, NULL, NULL);
+ g_object_unref (layout);
+
+ height = simple->bounds.y2 - simple->bounds.y1;
+ }
+ else
+ {
+ height = priv->height;
+ }
- /* Convert to the parent's coordinate space. As above, we only need to
+ /* Convert to the parent's coordinate space. As above, we only need to
support a simple scale operation here. */
- height = simple->bounds.y2 - simple->bounds.y1;
if (simple_data->transform)
height *= simple_data->transform->yy;
@@ -782,6 +871,8 @@
GObjectClass *gobject_class = (GObjectClass*) klass;
GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
+ g_type_class_add_private (gobject_class, sizeof (GooCanvasTextPrivate));
+
gobject_class->finalize = goo_canvas_text_finalize;
gobject_class->get_property = goo_canvas_text_get_property;
@@ -842,6 +933,8 @@
{
GObjectClass *gobject_class = (GObjectClass*) klass;
+ g_type_class_add_private (gobject_class, sizeof (GooCanvasTextPrivate));
+
gobject_class->finalize = goo_canvas_text_model_finalize;
gobject_class->get_property = goo_canvas_text_model_get_property;
@@ -854,10 +947,14 @@
static void
goo_canvas_text_model_init (GooCanvasTextModel *tmodel)
{
+ GooCanvasTextPrivate *priv = GOO_CANVAS_TEXT_MODEL_GET_PRIVATE (tmodel);
+
tmodel->text_data.width = -1.0;
tmodel->text_data.anchor = GTK_ANCHOR_NW;
tmodel->text_data.ellipsize = PANGO_ELLIPSIZE_NONE;
tmodel->text_data.wrap = PANGO_WRAP_WORD;
+
+ priv->height = -1.0;
}
@@ -951,9 +1048,10 @@
GParamSpec *pspec)
{
GooCanvasTextModel *tmodel = (GooCanvasTextModel*) object;
+ GooCanvasTextPrivate *priv = GOO_CANVAS_TEXT_MODEL_GET_PRIVATE (tmodel);
- goo_canvas_text_get_common_property (object, &tmodel->text_data, prop_id,
- value, pspec);
+ goo_canvas_text_get_common_property (object, &tmodel->text_data, priv,
+ prop_id, value, pspec);
}
@@ -964,9 +1062,10 @@
GParamSpec *pspec)
{
GooCanvasTextModel *tmodel = (GooCanvasTextModel*) object;
+ GooCanvasTextPrivate *priv = GOO_CANVAS_TEXT_MODEL_GET_PRIVATE (tmodel);
- goo_canvas_text_set_common_property (object, &tmodel->text_data, prop_id,
- value, pspec);
+ goo_canvas_text_set_common_property (object, &tmodel->text_data, priv,
+ prop_id, value, pspec);
g_signal_emit_by_name (tmodel, "changed", TRUE);
}
Modified: trunk/src/goocanvaswidget.c
==============================================================================
--- trunk/src/goocanvaswidget.c (original)
+++ trunk/src/goocanvaswidget.c Mon Jan 12 23:22:22 2009
@@ -12,6 +12,10 @@
*
* GooCanvasWidget provides support for placing any GtkWidget in the canvas.
*
+ * The #GooCanvasWidget:width and #GooCanvasWidget:height properties specify
+ * the widget's size. If either of them is -1, then the requested size of the
+ * widget is used instead, which is the default for both width and height.
+ *
* Note that there are a number of limitations in the use of #GooCanvasWidget:
*
* <itemizedlist><listitem><para>
@@ -155,6 +159,73 @@
}
+/* Returns the anchor position, within the given width. */
+static gdouble
+goo_canvas_widget_anchor_horizontal_pos (GtkAnchorType anchor,
+ gdouble width)
+{
+ switch(anchor)
+ {
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ return width / 2.0;
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ return width;
+ default:
+ return 0.0;
+ }
+}
+
+
+/* Returns the anchor position, within the given height. */
+static gdouble
+goo_canvas_widget_anchor_vertical_pos (GtkAnchorType anchor,
+ gdouble height)
+{
+ switch (anchor)
+ {
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ return height / 2.0;
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ return height;
+ default:
+ return 0.0;
+ }
+}
+
+
+/* Returns the size to use for the widget, either the item's width & height
+ properties or the widget's own requested width & height. */
+static void
+goo_canvas_widget_get_widget_size (GooCanvasWidget *witem,
+ gdouble *width,
+ gdouble *height)
+{
+ GtkRequisition requisition;
+
+ if (witem->widget)
+ {
+ /* Get the widget's requested size, if we need it. */
+ if (witem->width < 0 || witem->height < 0)
+ gtk_widget_size_request (witem->widget, &requisition);
+
+ *width = witem->width < 0 ? requisition.width : witem->width;
+ *height = witem->height < 0 ? requisition.height : witem->height;
+ }
+ else
+ {
+ *width = *height = 0.0;
+ }
+}
+
+
static void
goo_canvas_widget_set_widget (GooCanvasWidget *witem,
GtkWidget *widget)
@@ -349,53 +420,19 @@
cairo_t *cr)
{
GooCanvasWidget *witem = (GooCanvasWidget*) simple;
- GtkRequisition requisition;
gdouble width, height;
if (witem->widget)
{
- /* Compute the new bounds. */
- if (witem->width < 0 || witem->height < 0)
- {
- gtk_widget_size_request (witem->widget, &requisition);
- }
+ goo_canvas_widget_get_widget_size (witem, &width, &height);
simple->bounds.x1 = witem->x;
simple->bounds.y1 = witem->y;
- width = witem->width < 0 ? requisition.width : witem->width;
- height = witem->height < 0 ? requisition.height : witem->height;
-
- switch (witem->anchor)
- {
- case GTK_ANCHOR_N:
- case GTK_ANCHOR_CENTER:
- case GTK_ANCHOR_S:
- simple->bounds.x1 -= width / 2.0;
- break;
- case GTK_ANCHOR_NE:
- case GTK_ANCHOR_E:
- case GTK_ANCHOR_SE:
- simple->bounds.x1 -= width;
- break;
- default:
- break;
- }
- switch (witem->anchor)
- {
- case GTK_ANCHOR_W:
- case GTK_ANCHOR_CENTER:
- case GTK_ANCHOR_E:
- simple->bounds.y1 -= height / 2.0;
- break;
- case GTK_ANCHOR_SW:
- case GTK_ANCHOR_S:
- case GTK_ANCHOR_SE:
- simple->bounds.y1 -= height;
- break;
- default:
- break;
- }
+ simple->bounds.x1 -=
+ goo_canvas_widget_anchor_horizontal_pos (witem->anchor, width);
+ simple->bounds.y1 -=
+ goo_canvas_widget_anchor_vertical_pos (witem->anchor, height);
simple->bounds.x2 = simple->bounds.x1 + width;
simple->bounds.y2 = simple->bounds.y1 + height;
@@ -546,6 +583,7 @@
G_MAXDOUBLE, -1.0,
G_PARAM_READWRITE));
+
g_object_class_install_property (gobject_class, PROP_ANCHOR,
g_param_spec_enum ("anchor",
_("Anchor"),
@@ -557,5 +595,3 @@
g_object_class_override_property (gobject_class, PROP_VISIBILITY,
"visibility");
}
-
-
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]