[goffice] New cairo-based canvas.
- From: Jean Bréfort <jbrefort src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [goffice] New cairo-based canvas.
- Date: Sun, 9 Aug 2009 13:58:30 +0000 (UTC)
commit 335b8c9640b49feaccded6e4e1fb86eb3c900437
Author: Jean Brefort <jean brefort normalesup org>
Date: Sun Aug 9 15:58:03 2009 +0200
New cairo-based canvas.
NEWS | 1 +
configure.in | 1 +
goffice/Makefile.am | 3 +-
goffice/canvas/Makefile.am | 47 +++++
goffice/canvas/Makefile.am~ | 49 +++++
goffice/canvas/goc-canvas-impl.h | 46 +++++
goffice/canvas/goc-canvas.c | 373 +++++++++++++++++++++++++++++++++++
goffice/canvas/goc-canvas.h | 55 +++++
goffice/canvas/goc-circle-impl.h | 39 ++++
goffice/canvas/goc-circle.c | 208 +++++++++++++++++++
goffice/canvas/goc-circle.h | 38 ++++
goffice/canvas/goc-ellipse.c | 266 +++++++++++++++++++++++++
goffice/canvas/goc-ellipse.h | 38 ++++
goffice/canvas/goc-graph.c | 271 +++++++++++++++++++++++++
goffice/canvas/goc-graph.h | 37 ++++
goffice/canvas/goc-group-impl.h | 44 ++++
goffice/canvas/goc-group.c | 338 +++++++++++++++++++++++++++++++
goffice/canvas/goc-group.h | 45 +++++
goffice/canvas/goc-item-impl.h | 70 +++++++
goffice/canvas/goc-item.c | 357 +++++++++++++++++++++++++++++++++
goffice/canvas/goc-item.h | 71 +++++++
goffice/canvas/goc-line.c | 221 +++++++++++++++++++++
goffice/canvas/goc-line.h | 38 ++++
goffice/canvas/goc-pixbuf.c | 267 +++++++++++++++++++++++++
goffice/canvas/goc-pixbuf.h | 38 ++++
goffice/canvas/goc-polygon-impl.h | 42 ++++
goffice/canvas/goc-polygon.c | 243 +++++++++++++++++++++++
goffice/canvas/goc-polygon.h | 38 ++++
goffice/canvas/goc-rectangle-impl.h | 40 ++++
goffice/canvas/goc-rectangle.c | 235 ++++++++++++++++++++++
goffice/canvas/goc-rectangle.h | 38 ++++
goffice/canvas/goc-structs.h | 34 ++++
goffice/canvas/goc-styled-item.c | 219 ++++++++++++++++++++
goffice/canvas/goc-styled-item.h | 55 +++++
goffice/canvas/goc-text.c | 370 ++++++++++++++++++++++++++++++++++
goffice/canvas/goc-text.h | 38 ++++
goffice/canvas/goc-utils.c | 65 ++++++
goffice/canvas/goc-utils.h | 40 ++++
goffice/canvas/goc-widget-impl.h | 40 ++++
goffice/canvas/goc-widget.c | 258 ++++++++++++++++++++++++
goffice/canvas/goc-widget.h | 39 ++++
goffice/canvas/goffice-canvas.h | 73 +++++++
goffice/canvas/goffice-canvas.h~ | 75 +++++++
goffice/goffice.h | 1 +
goffice/graph/gog-guru.c | 248 ++++++++++++------------
goffice/gtk/go-3d-rotation-sel.c | 115 ++++++-----
goffice/gtk/go-font-sel.c | 30 +--
goffice/gtk/go-rotation-sel.c | 90 ++++-----
goffice/utils/go-style.c | 6 +-
goffice/utils/go-style.h | 13 +-
goffice/utils/go-styled-object.c | 67 +++++++
goffice/utils/go-styled-object.h | 2 +
52 files changed, 5224 insertions(+), 251 deletions(-)
---
diff --git a/NEWS b/NEWS
index 5f964a0..72be221 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,7 @@ Jean:
* Align surface ticks with grid. [#585298]
* Fixed various contour plots related issues. [#589511, #589512]
* Comparison line for probability plots. [#590416]
+ * New cairo based canvas.
Morten:
* Fix format localization problem. [#586567]
diff --git a/configure.in b/configure.in
index 48b8416..4029d46 100644
--- a/configure.in
+++ b/configure.in
@@ -613,6 +613,7 @@ goffice/gtk/Makefile
goffice/graph/Makefile
goffice/drawing/Makefile
goffice/math/Makefile
+goffice/canvas/Makefile
goffice/ms-compat/Makefile
goffice/component/Makefile
goffice/cut-n-paste/Makefile
diff --git a/goffice/Makefile.am b/goffice/Makefile.am
index c47aa73..3b0fcfc 100644
--- a/goffice/Makefile.am
+++ b/goffice/Makefile.am
@@ -12,11 +12,12 @@ libgoffice_ GOFFICE_API_VER@_la_LIBADD = \
$(GOFFICE_LIBS)
if WITH_GTK
-SUBDIRS += gtk drawing component
+SUBDIRS += gtk drawing component canvas
libgoffice_ GOFFICE_API_VER@_la_LIBADD += \
gtk/libgoffice-gtk.la \
drawing/libgoffice-drawing.la \
component/libgoffice-component.la \
+ canvas/libgoffice-canvas.la \
cut-n-paste/foocanvas/libfoocanvas.la
endif
diff --git a/goffice/canvas/Makefile.am b/goffice/canvas/Makefile.am
new file mode 100644
index 0000000..4bb3125
--- /dev/null
+++ b/goffice/canvas/Makefile.am
@@ -0,0 +1,47 @@
+noinst_LTLIBRARIES = libgoffice-canvas.la
+
+libgoffice_canvas_la_SOURCES = \
+ goc-canvas.c \
+ goc-circle.c \
+ goc-ellipse.c \
+ goc-graph.c \
+ goc-group.c \
+ goc-item.c \
+ goc-line.c \
+ goc-pixbuf.c \
+ goc-polygon.c \
+ goc-rectangle.c \
+ goc-styled-item.c \
+ goc-text.c \
+ goc-utils.c \
+ goc-widget.c
+
+libgoffice_canvas_ladir = $(goffice_include_dir)/canvas
+libgoffice_canvas_la_HEADERS = \
+ goc-canvas.h \
+ goc-canvas-impl.h \
+ goc-circle.h \
+ goc-circle-impl.h \
+ goc-ellipse.h \
+ goc-graph.h \
+ goc-group.h \
+ goc-group-impl.h \
+ goc-item.h \
+ goc-item-impl.h \
+ goc-line.h \
+ goc-pixbuf.h \
+ goc-polygon.h \
+ goc-polygon-impl.h \
+ goc-rectangle.h \
+ goc-rectangle-impl.h\
+ goc-structs.h \
+ goc-styled-item.h \
+ goc-text.h \
+ goc-utils.h \
+ goc-widget.h \
+ goc-widget-impl.h \
+ goffice-canvas.h
+
+include $(top_srcdir)/goffice.mk
+
+LIB_PUBLIC_HDRS = $(libgoffice_canvas_la_HEADERS)
diff --git a/goffice/canvas/Makefile.am~ b/goffice/canvas/Makefile.am~
new file mode 100644
index 0000000..7621d9e
--- /dev/null
+++ b/goffice/canvas/Makefile.am~
@@ -0,0 +1,49 @@
+noinst_LTLIBRARIES = libgoffice-canvas.la
+
+libgoffice_canvas_la_SOURCES = \
+ goc-canvas.c \
+ goc-circle.c \
+ goc-ellipse.c \
+ goc-graph.c \
+ goc-group.c \
+ goc-item.c \
+ goc-line.c \
+ goc-pixbuf.c \
+ goc-polygon.c \
+ goc-rectangle.c \
+ goc-styled-item.c \
+ goc-text.c \
+ goc-utils.c \
+ goc-widget.c
+
+libgoffice_canvas_ladir = $(goffice_include_dir)/canvas
+libgoffice_canvas_la_HEADERS = \
+ goc-canvas.h \
+ goc-canvas-impl.h \
+ goc-circle.h \
+ goc-circle-impl.h \
+ goc-component.h \
+ goc-ellipse.h \
+ goc-graph.h \
+ goc-group.h \
+ goc-group-impl.h \
+ goc-item.h \
+ goc-item-impl.h \
+ goc-line.h \
+ goc-pixbuf.h \
+ goc-polygon.h \
+ goc-polygon-impl.h \
+ goc-polyline.h \
+ goc-rectangle.h \
+ goc-rectangle-impl.h\
+ goc-structs.h \
+ goc-styled-item.h \
+ goc-text.h \
+ goc-utils.h \
+ goc-widget.h \
+ goc-widget-impl.h \
+ goffice-canvas.h
+
+include $(top_srcdir)/goffice.mk
+
+LIB_PUBLIC_HDRS = $(libgoffice_canvas_la_HEADERS)
diff --git a/goffice/canvas/goc-canvas-impl.h b/goffice/canvas/goc-canvas-impl.h
new file mode 100644
index 0000000..ed5d113
--- /dev/null
+++ b/goffice/canvas/goc-canvas-impl.h
@@ -0,0 +1,46 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas-impl.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_CANVAS_IMPL_H
+#define GOC_CANVAS_IMPL_H
+
+#include <goffice/goffice.h>
+
+struct _GocCanvas {
+ GtkLayout base;
+ double scroll_x1, scroll_y1;
+ double pixels_per_unit;
+ double width, height;
+ int wwidth, wheight;
+ GocGroup *root;
+ GocItem *grabbed_item;
+ GocItem *last_item;
+ GODoc *document;
+ GdkEvent *cur_event;
+};
+
+typedef struct {
+ GtkLayoutClass parent;
+
+} GocCanvasClass;
+
+#endif /* GOC_CANVAS_IMPL_H */
diff --git a/goffice/canvas/goc-canvas.c b/goffice/canvas/goc-canvas.c
new file mode 100644
index 0000000..7950916
--- /dev/null
+++ b/goffice/canvas/goc-canvas.c
@@ -0,0 +1,373 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas.c :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <math.h>
+
+static GObjectClass *parent_klass;
+
+static gboolean
+expose_cb (GocCanvas *canvas, GdkEventExpose *event, G_GNUC_UNUSED gpointer data)
+{
+ double x0, y0, x1, y1;
+ double ax0, ay0, ax1, ay1;
+
+ if (event->count)
+ return TRUE;
+ goc_item_get_bounds (GOC_ITEM (canvas->root),&x0, &y0, &x1, &y1);
+ ax0 = (double) event->area.x / canvas->pixels_per_unit + canvas->scroll_x1;
+ ay0 = (double) event->area.y / canvas->pixels_per_unit + canvas->scroll_y1;
+ ax1 = ((double) event->area.x + event->area.width) / canvas->pixels_per_unit + canvas->scroll_x1;
+ ay1 = ((double) event->area.y + event->area.height) / canvas->pixels_per_unit + canvas->scroll_y1;
+ if (x0 <= ax1 && x1 >= ax0 && y0 <= ay1 && y1 >= ay0) {
+ cairo_t *cr = gdk_cairo_create (event->window);
+ canvas->cur_event = (GdkEvent *) event;
+ goc_item_draw_region (GOC_ITEM (canvas->root), cr, ax0, ay0, ax1, ay1);
+ cairo_destroy (cr);
+ canvas->cur_event = NULL;
+ }
+ return TRUE;
+}
+
+static gboolean
+button_press_cb (GocCanvas *canvas, GdkEventButton *event, G_GNUC_UNUSED gpointer data)
+{
+ double x = canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+ double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+ GocItem *item = goc_canvas_get_item_at (canvas, x, y);
+ if (item) {
+ canvas->cur_event = (GdkEvent *) event;
+ if (event->type == GDK_2BUTTON_PRESS)
+ return GOC_ITEM_GET_CLASS (item)->button2_pressed (item, event->button, x, y);
+ return GOC_ITEM_GET_CLASS (item)->button_pressed (item, event->button, x, y);
+ canvas->cur_event = NULL;
+ }
+ return FALSE;
+}
+
+static gboolean
+button_release_cb (GocCanvas *canvas, GdkEventButton *event, G_GNUC_UNUSED gpointer data)
+{
+ double x = canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+ double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+ GocItem *item = (canvas->grabbed_item != NULL)?
+ canvas->grabbed_item:
+ goc_canvas_get_item_at (canvas, x, y);
+ if (item) {
+ canvas->cur_event = (GdkEvent *) event;
+ return GOC_ITEM_GET_CLASS (item)->button_released (item, event->button, x, y);
+ canvas->cur_event = NULL;
+ }
+ return FALSE;
+}
+
+static gboolean
+motion_cb (GocCanvas *canvas, GdkEventMotion *event, G_GNUC_UNUSED gpointer data)
+{
+ double x = canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+ double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+ GocItem *item;
+ if (canvas->grabbed_item != NULL)
+ item = canvas->grabbed_item;
+ else
+ item = goc_canvas_get_item_at (canvas, x, y);
+ canvas->cur_event = (GdkEvent *) event;
+ if (canvas->last_item && item != canvas->last_item) {
+ GOC_ITEM_GET_CLASS (canvas->last_item)->leave_notify (canvas->last_item, x, y);
+ canvas->last_item = NULL;
+ }
+ if (item) {
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ if (item != canvas->last_item) {
+ canvas->last_item = item;
+ klass->enter_notify (item, x, y);
+ }
+ return klass->motion (item, x, y);
+ }
+ canvas->cur_event = NULL;
+ return FALSE;
+}
+
+static void
+destroy_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+}
+
+static gboolean
+key_release_cb (GocCanvas *canvas, GdkEventKey* event, G_GNUC_UNUSED gpointer data)
+{
+ return FALSE;
+}
+
+static gboolean
+key_press_cb (GocCanvas *canvas, GdkEventKey* event, G_GNUC_UNUSED gpointer data)
+{
+ return FALSE;
+}
+
+static gboolean
+enter_notify_cb (GocCanvas *canvas, GdkEventCrossing* event, G_GNUC_UNUSED gpointer data)
+{
+ double x = canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+ double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+ GocItem *item = goc_canvas_get_item_at (canvas, x, y);
+ if (item) {
+ canvas->last_item = item;
+ return GOC_ITEM_GET_CLASS (item)->enter_notify (item, x, y);
+ }
+ return FALSE;
+}
+
+static gboolean
+leave_notify_cb (GocCanvas *canvas, GdkEventCrossing* event, G_GNUC_UNUSED gpointer data)
+{
+ double x = canvas->scroll_x1 + event->x / canvas->pixels_per_unit;
+ double y = canvas->scroll_y1 + event->y / canvas->pixels_per_unit;
+ if (canvas->last_item) {
+ gboolean result = GOC_ITEM_GET_CLASS (canvas->last_item)->leave_notify (canvas->last_item, x, y);
+ canvas->last_item = NULL;
+ return result;
+ }
+ return FALSE;
+}
+
+static void
+size_changed_cb (GocCanvas *canvas, GtkAllocation *alloc, G_GNUC_UNUSED gpointer data)
+{
+ canvas->wwidth = alloc->width;
+ canvas->wheight = alloc->height;
+}
+
+static void
+realize_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (canvas->root);
+ klass->realize (GOC_ITEM (canvas->root));
+}
+
+static void
+unrealize_cb (GocCanvas *canvas, G_GNUC_UNUSED gpointer data)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (canvas->root);
+ klass->unrealize (GOC_ITEM (canvas->root));
+}
+
+static void
+goc_canvas_finalize (GObject *obj)
+{
+ GocCanvas *canvas = GOC_CANVAS (obj);
+ g_object_unref (G_OBJECT (canvas->root));
+ (parent_klass->finalize) (obj);
+}
+
+static void
+goc_canvas_class_init (GObjectClass *klass)
+{
+ parent_klass = g_type_class_peek_parent (klass);
+ klass->finalize = goc_canvas_finalize;
+}
+
+static void
+goc_canvas_init (GocCanvas *canvas)
+{
+ GtkWidget *w = GTK_WIDGET (canvas);
+
+ canvas->root = GOC_GROUP (g_object_new (GOC_TYPE_GROUP, NULL));
+ canvas->root->base.canvas = canvas;
+ canvas->pixels_per_unit = 1.;
+ gtk_widget_add_events (w,
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK |
+ GDK_2BUTTON_PRESS |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK |
+ GDK_ENTER_NOTIFY_MASK
+ );
+ g_signal_connect (G_OBJECT (w), "button-press-event", G_CALLBACK (button_press_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "button-release-event", G_CALLBACK (button_release_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "motion-notify-event", G_CALLBACK (motion_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "destroy", G_CALLBACK (destroy_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "expose-event", G_CALLBACK (expose_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "key_press_event", (GCallback) key_press_cb, NULL);
+ g_signal_connect (G_OBJECT (w), "key_release_event", (GCallback) key_release_cb, NULL);
+ g_signal_connect (G_OBJECT (w), "size-allocate", (GCallback) size_changed_cb, NULL);
+ g_signal_connect (G_OBJECT (w), "enter-notify-event", G_CALLBACK (enter_notify_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "leave-notify-event", G_CALLBACK (leave_notify_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "realize", G_CALLBACK (realize_cb), NULL);
+ g_signal_connect (G_OBJECT (w), "unrealize", G_CALLBACK (unrealize_cb), NULL);
+}
+
+GSF_CLASS (GocCanvas, goc_canvas,
+ goc_canvas_class_init, goc_canvas_init,
+ GTK_TYPE_LAYOUT)
+
+GocGroup*
+goc_canvas_get_root (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+ return canvas->root;
+}
+
+void
+goc_canvas_set_scroll_region (GocCanvas *canvas, double width, double height)
+{
+ g_return_if_fail (GOC_IS_CANVAS (canvas));
+ canvas->width = width;
+ canvas->height = height;
+}
+
+double
+goc_canvas_get_width (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+ return canvas->width;
+}
+
+double
+goc_canvas_get_height (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+ return canvas->height;
+}
+
+void
+goc_canvas_scroll_to (GocCanvas *canvas, double x, double y)
+{
+ GocItemClass *klass;
+ g_return_if_fail (GOC_IS_CANVAS (canvas));
+ if (x == canvas->scroll_x1 && canvas->scroll_y1 == y)
+ return;
+ klass = GOC_ITEM_GET_CLASS (canvas->root);
+ canvas->scroll_x1 = x;
+ canvas->scroll_y1 = y;
+ klass->notify_scrolled (GOC_ITEM (canvas->root));
+ gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+ 0, 0, G_MAXINT, G_MAXINT);
+}
+
+void
+goc_canvas_get_scroll_position (GocCanvas *canvas, double *x, double *y)
+{
+ g_return_if_fail (GOC_IS_CANVAS (canvas));
+ if (x)
+ *x = canvas->scroll_x1;
+ if (y)
+ *y = canvas->scroll_y1;
+}
+
+void
+goc_canvas_set_pixels_per_unit (GocCanvas *canvas, double pixels_per_unit)
+{
+ GocItemClass *klass;
+ g_return_if_fail (GOC_IS_CANVAS (canvas));
+ if (pixels_per_unit == canvas->pixels_per_unit)
+ return;
+ klass = GOC_ITEM_GET_CLASS (canvas->root);
+ canvas->pixels_per_unit = pixels_per_unit;
+ klass->notify_scrolled (GOC_ITEM (canvas->root));
+ gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+ 0, 0, G_MAXINT, G_MAXINT);
+}
+
+double
+goc_canvas_get_pixels_per_unit (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), 0);
+ return canvas->pixels_per_unit;
+}
+
+void
+goc_canvas_invalidate (GocCanvas *canvas, double x0, double y0, double x1, double y1)
+{
+ if (!GTK_WIDGET_REALIZED (canvas))
+ return;
+ x0 = (x0 - canvas->scroll_x1) * canvas->pixels_per_unit;
+ y0 = (y0 - canvas->scroll_y1) * canvas->pixels_per_unit;
+ x1 = (x1 - canvas->scroll_x1) * canvas->pixels_per_unit;
+ y1 = (y1 - canvas->scroll_y1) * canvas->pixels_per_unit;
+ if (x0 < 0.)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 > canvas->wwidth)
+ x1 = canvas->wwidth;
+ if (y1 > canvas->wheight)
+ y1 = canvas->wheight;
+ if (x1 > x0 && y1 > y0)
+ gtk_widget_queue_draw_area (GTK_WIDGET (canvas),
+ (int) floor (x0), (int) floor (y0),
+ (int) ceil (x1), (int) ceil (y1));
+}
+
+GocItem*
+goc_canvas_get_item_at (GocCanvas *canvas, double x, double y)
+{
+ GocItem *result = NULL;
+ double d = goc_item_distance (GOC_ITEM (canvas->root), x, y, &result);
+ return (d == 0.)? result: NULL;
+}
+
+void
+goc_canvas_grab_item (GocCanvas *canvas, GocItem *item)
+{
+ g_return_if_fail (GOC_IS_CANVAS (canvas) && canvas->grabbed_item == NULL);
+ canvas->grabbed_item = item;
+}
+
+void
+goc_canvas_ungrab_item (GocCanvas *canvas)
+{
+ g_return_if_fail (GOC_IS_CANVAS (canvas) && canvas->grabbed_item != NULL);
+ canvas->grabbed_item = NULL;
+}
+
+GocItem *
+goc_canvas_get_grabbed_item (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+ return canvas->grabbed_item;
+}
+
+void
+goc_canvas_set_document (GocCanvas *canvas, GODoc *document)
+{
+ g_return_if_fail (GOC_IS_CANVAS (canvas));
+ canvas->document = document;
+}
+
+GODoc*
+goc_canvas_get_document (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+ return canvas->document;
+}
+
+GdkEvent*
+goc_canvas_get_cur_event (GocCanvas *canvas)
+{
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), NULL);
+ return canvas->cur_event;
+}
diff --git a/goffice/canvas/goc-canvas.h b/goffice/canvas/goc-canvas.h
new file mode 100644
index 0000000..7083cc8
--- /dev/null
+++ b/goffice/canvas/goc-canvas.h
@@ -0,0 +1,55 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-canvas.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_CANVAS_H
+#define GOC_CANVAS_H
+
+#include <goffice/goffice.h>
+#include <gdk/gdk.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_CANVAS (goc_canvas_get_type ())
+#define GOC_CANVAS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_CANVAS, GocCanvas))
+#define GOC_IS_CANVAS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_CANVAS))
+
+GType goc_canvas_get_type (void);
+
+GocGroup *goc_canvas_get_root (GocCanvas *canvas);
+void goc_canvas_set_scroll_region (GocCanvas *canvas, double width, double height);
+double goc_canvas_get_width (GocCanvas *canvas);
+double goc_canvas_get_height (GocCanvas *canvas);
+void goc_canvas_scroll_to (GocCanvas *canvas, double x, double y);
+void goc_canvas_get_scroll_position (GocCanvas *canvas, double *x, double *y);
+void goc_canvas_set_pixels_per_unit (GocCanvas *canvas, double pixels_per_unit);
+double goc_canvas_get_pixels_per_unit (GocCanvas *canvas);
+void goc_canvas_invalidate (GocCanvas *canvas, double x0, double y0, double x1, double y1);
+GocItem *goc_canvas_get_item_at (GocCanvas *canvas, double x, double y);
+void goc_canvas_grab_item (GocCanvas *canvas, GocItem *item);
+void goc_canvas_ungrab_item (GocCanvas *canvas);
+GocItem *goc_canvas_get_grabbed_item (GocCanvas *canvas);
+void goc_canvas_set_document (GocCanvas *canvas, GODoc *document);
+GODoc *goc_canvas_get_document (GocCanvas *canvas);
+GdkEvent *goc_canvas_get_cur_event (GocCanvas *canvas);
+G_END_DECLS
+
+#endif /* GOC_CANVAS_H */
diff --git a/goffice/canvas/goc-circle-impl.h b/goffice/canvas/goc-circle-impl.h
new file mode 100644
index 0000000..495351e
--- /dev/null
+++ b/goffice/canvas/goc-circle-impl.h
@@ -0,0 +1,39 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_CIRCLE_IMPL_H
+#define GOC_CIRCLE_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocCircle {
+ GocStyledItem base;
+
+ double x, y, radius;
+};
+
+typedef GocStyledItemClass GocCircleClass;
+
+G_END_DECLS
+
+#endif /* GOC_CIRCLE_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-circle.c b/goffice/canvas/goc-circle.c
new file mode 100644
index 0000000..b696375
--- /dev/null
+++ b/goffice/canvas/goc-circle.c
@@ -0,0 +1,208 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+enum {
+ CIRCLE_PROP_0,
+ CIRCLE_PROP_X,
+ CIRCLE_PROP_Y,
+ CIRCLE_PROP_R
+};
+
+static void
+goc_circle_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocCircle *circle = GOC_CIRCLE (gobject);
+
+ switch (param_id) {
+ case CIRCLE_PROP_X:
+ circle->x = g_value_get_double (value);
+ break;
+
+ case CIRCLE_PROP_Y:
+ circle->y = g_value_get_double (value);
+ break;
+
+ case CIRCLE_PROP_R:
+ circle->radius = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+}
+
+static void
+goc_circle_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocCircle *circle = GOC_CIRCLE (gobject);
+
+ switch (param_id) {
+ case CIRCLE_PROP_X:
+ g_value_set_double (value, circle->x);
+ break;
+
+ case CIRCLE_PROP_Y:
+ g_value_set_double (value, circle->y);
+ break;
+
+ case CIRCLE_PROP_R:
+ g_value_set_double (value, circle->radius);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static double
+goc_circle_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocCircle *circle = GOC_CIRCLE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ double d, extra_dist = 0.;
+ if (style->outline.dash_type != GO_LINE_NONE)
+ extra_dist = (style->outline.width)? style->outline.width / 2.: .5;
+ *near_item = item;
+ x -= circle->x;
+ y -= circle->y;
+ d = sqrt (x * x + y * y);
+ return MAX (d - circle->radius - extra_dist, 0);
+}
+
+static void
+goc_circle_draw (GocItem const *item, cairo_t *cr)
+{
+ GocCircle *circle = GOC_CIRCLE (item);
+ GOLineDashSequence *line_dash;
+ cairo_pattern_t *pat = NULL;
+ double width;
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, circle->x, circle->y);
+ cairo_scale (cr, circle->radius, circle->radius);
+ cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+ cairo_restore (cr);
+ /* Fill the shape */
+ pat = go_style_create_cairo_pattern (style, cr);
+ if (pat) {
+ cairo_set_source (cr, pat);
+ cairo_fill_preserve (cr);
+ cairo_pattern_destroy (pat);
+ }
+ /* Draw the line */
+ width = (style->outline.width)? style->outline.width: 1.;
+ cairo_set_line_width (cr, width);
+ line_dash = go_line_dash_get_sequence (style->outline.dash_type, width);
+ if (line_dash != NULL)
+ cairo_set_dash (cr,
+ line_dash->dash,
+ line_dash->n_dash,
+ line_dash->offset);
+ else
+ cairo_set_dash (cr, NULL, 0, 0);
+ cairo_set_source_rgba (cr,
+ UINT_RGBA_R (style->outline.color),
+ UINT_RGBA_B (style->outline.color),
+ UINT_RGBA_G (style->outline.color),
+ UINT_RGBA_A (style->outline.color));
+ cairo_stroke (cr);
+
+ if (line_dash != NULL)
+ go_line_dash_sequence_free (line_dash);
+}
+
+static void
+goc_circle_update_bounds (GocItem *item)
+{
+ GocCircle *circle = GOC_CIRCLE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ double r = circle->radius;
+ if (style->outline.dash_type != GO_LINE_NONE)
+ r += (style->outline.width)? style->outline.width / 2.: .5;
+ item->x0 = circle->x - r;
+ item->y0 = circle->y - r;
+ item->x1 = circle->x + r;
+ item->y1 = circle->y + r;
+}
+
+static void
+goc_circle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+ if (style->outline.auto_dash)
+ style->outline.dash_type = GO_LINE_SOLID;
+ if (style->outline.auto_color)
+ style->outline.color = RGBA_BLACK;
+ if (style->fill.auto_type)
+ style->fill.type = GO_STYLE_FILL_PATTERN;
+ if (style->fill.auto_fore)
+ go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_circle_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+ obj_klass->get_property = goc_circle_get_property;
+ obj_klass->set_property = goc_circle_set_property;
+ g_object_class_install_property (obj_klass, CIRCLE_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The circle center horizontal position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, CIRCLE_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The circle center vertical position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, CIRCLE_PROP_R,
+ g_param_spec_double ("radius",
+ _("Radius"),
+ _("The circle radius"),
+ 0., G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ gsi_klass->init_style = goc_circle_init_style;
+
+ item_klass->distance = goc_circle_distance;
+ item_klass->draw = goc_circle_draw;
+ item_klass->update_bounds = goc_circle_update_bounds;
+}
+
+GSF_CLASS (GocCircle, goc_circle,
+ goc_circle_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-circle.h b/goffice/canvas/goc-circle.h
new file mode 100644
index 0000000..e88e707
--- /dev/null
+++ b/goffice/canvas/goc-circle.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-circle.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_CIRCLE_H
+#define GOC_CIRCLE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_CIRCLE (goc_circle_get_type ())
+#define GOC_CIRCLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_CIRCLE, GocCircle))
+#define GOC_IS_CIRCLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_CIRCLE))
+
+GType goc_circle_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_CIRCLE_H */
diff --git a/goffice/canvas/goc-ellipse.c b/goffice/canvas/goc-ellipse.c
new file mode 100644
index 0000000..c27e0bd
--- /dev/null
+++ b/goffice/canvas/goc-ellipse.c
@@ -0,0 +1,266 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-ellipse.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+struct _GocEllipse {
+ GocStyledItem base;
+
+ double rotation; /* rotation around the center in radians */
+ double x, y, width, height;
+};
+
+typedef GocStyledItemClass GocEllipseClass;
+
+enum {
+ ELLIPSE_PROP_0,
+ ELLIPSE_PROP_X,
+ ELLIPSE_PROP_Y,
+ ELLIPSE_PROP_W,
+ ELLIPSE_PROP_H,
+ ELLIPSE_PROP_ROTATION
+};
+
+static void
+goc_ellipse_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocEllipse *ellipse = GOC_ELLIPSE (gobject);
+
+ switch (param_id) {
+ case ELLIPSE_PROP_X:
+ ellipse->x = g_value_get_double (value);
+ break;
+
+ case ELLIPSE_PROP_Y:
+ ellipse->y = g_value_get_double (value);
+ break;
+
+ case ELLIPSE_PROP_W:
+ ellipse->width = g_value_get_double (value);
+ break;
+
+ case ELLIPSE_PROP_H:
+ ellipse->height = g_value_get_double (value);
+ break;
+
+ case ELLIPSE_PROP_ROTATION:
+ ellipse->rotation = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_invalidate (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_ellipse_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocEllipse *ellipse = GOC_ELLIPSE (gobject);
+
+ switch (param_id) {
+ case ELLIPSE_PROP_X:
+ g_value_set_double (value, ellipse->x);
+ break;
+
+ case ELLIPSE_PROP_Y:
+ g_value_set_double (value, ellipse->y);
+ break;
+
+ case ELLIPSE_PROP_W:
+ g_value_set_double (value, ellipse->width);
+ break;
+
+ case ELLIPSE_PROP_H:
+ g_value_set_double (value, ellipse->height);
+ break;
+
+ case ELLIPSE_PROP_ROTATION:
+ g_value_set_double (value, ellipse->rotation);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (ellipse));
+}
+
+static void
+goc_ellipse_update_bounds (GocItem *item)
+{
+ GocEllipse *ellipse = GOC_ELLIPSE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: take rotation into account */
+ double extra_width = style->outline.width /2.;
+ if (extra_width <= 0.)
+ extra_width = .5;
+ item->x0 = ellipse->x - extra_width;
+ item->y0 = ellipse->y - extra_width;
+ item->x1 = ellipse->x + ellipse->width + extra_width;
+ item->y1 = ellipse->y + ellipse->height + extra_width;
+}
+
+static double
+goc_ellipse_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocEllipse *ellipse = GOC_ELLIPSE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: take rotation into account */
+ /* FIXME: we just consider that a point inside the ellipse is at distance 0
+ even if the ellipse is not filled */
+ double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+ double last = G_MAXDOUBLE, df, d2f, t, cs, sn,
+ a = ellipse->width / 2, b = ellipse->height / 2,
+ c = a * a - b * b;
+ *near_item = item;
+ x = fabs (x - ellipse->x - a);
+ y = fabs (y - ellipse->y - b);
+ if (y < DBL_EPSILON) {
+ x -= a + extra_width;
+ return (x > 0.)? x: 0.;
+ }
+ if (x < DBL_EPSILON) {
+ y -= b + extra_width;
+ return (y > 0.)? y: 0.;
+ }
+ if (hypot (x / a, y / b) < 1.)
+ return 0.;
+
+ /* initial value: */
+ t = atan2 (y, x);
+ /* iterate using the Newton method */
+ while (1) {
+ cs = cos (t);
+ sn = sin (t);
+ df = a * x * sn - b * y * cs - c * cs * sn;
+ d2f = a * x * cs + b * y * sn - c * (cs * cs - sn * sn);
+ t -= df / d2f;
+ if ( last == df || fabs (df) < DBL_EPSILON || fabs (df) >= fabs (last))
+ break;
+ last = df;
+ }
+ /* evaluate the distance and store in df */
+ df = hypot (x - a * cos (t), y - b * sin (t)) - extra_width;
+ return (df > 0.)? df: 0.;
+}
+
+static void
+goc_ellipse_draw (GocItem const *item, cairo_t *cr)
+{
+ GocEllipse *ellipse = GOC_ELLIPSE (item);
+ cairo_pattern_t *pat = NULL;
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, ellipse->x, ellipse->y);
+ cairo_translate (cr, ellipse->width / 2., ellipse->height / 2.);
+ cairo_scale (cr, ellipse->width / 2., ellipse->height / 2.);
+ cairo_rotate (cr, ellipse->rotation);
+ cairo_arc (cr, 0., 0., 1., 0., 2 * M_PI);
+ cairo_restore (cr);
+ /* Fill the shape */
+ pat = go_style_create_cairo_pattern (style, cr);
+ if (pat) {
+ cairo_set_source (cr, pat);
+ if (style->outline.dash_type != GO_LINE_NONE)
+ cairo_fill_preserve (cr);
+ else
+ cairo_fill (cr);
+ cairo_pattern_destroy (pat);
+ }
+ /* Draw the line */
+ if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+ cairo_stroke (cr);
+ else
+ cairo_new_path (cr);
+}
+
+static void
+goc_ellipse_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+ if (style->outline.auto_dash)
+ style->outline.dash_type = GO_LINE_SOLID;
+ if (style->outline.auto_color)
+ style->outline.color = RGBA_BLACK;
+ if (style->fill.auto_type)
+ style->fill.type = GO_STYLE_FILL_PATTERN;
+ if (style->fill.auto_fore)
+ go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_ellipse_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+ obj_klass->get_property = goc_ellipse_get_property;
+ obj_klass->set_property = goc_ellipse_set_property;
+ g_object_class_install_property (obj_klass, ELLIPSE_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The rectangle left position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, ELLIPSE_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The rectangle top position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, ELLIPSE_PROP_W,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The rectangle width"),
+ 0., G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, ELLIPSE_PROP_H,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The rectangle height"),
+ 0., G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/* g_object_class_install_property (obj_klass, ELLIPSE_PROP_ROTATION,
+ g_param_spec_double ("rotation",
+ _("Rotation"),
+ _("The rotation around top left position"),
+ 0., 2 * M_PI, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+
+ gsi_klass->init_style = goc_ellipse_init_style;
+
+ item_klass->update_bounds = goc_ellipse_update_bounds;
+ item_klass->distance = goc_ellipse_distance;
+ item_klass->draw = goc_ellipse_draw;
+}
+
+GSF_CLASS (GocEllipse, goc_ellipse,
+ goc_ellipse_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-ellipse.h b/goffice/canvas/goc-ellipse.h
new file mode 100644
index 0000000..9d7ac91
--- /dev/null
+++ b/goffice/canvas/goc-ellipse.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-ellipse.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_ELLIPSE_H
+#define GOC_ELLIPSE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_ELLIPSE (goc_ellipse_get_type ())
+#define GOC_ELLIPSE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_ELLIPSE, GocEllipse))
+#define GOC_IS_ELLIPSE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_ELLIPSE))
+
+GType goc_ellipse_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_ELLIPSE_H */
diff --git a/goffice/canvas/goc-graph.c b/goffice/canvas/goc-graph.c
new file mode 100644
index 0000000..a5bd038
--- /dev/null
+++ b/goffice/canvas/goc-graph.c
@@ -0,0 +1,271 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-graph.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <math.h>
+
+struct _GocGraph {
+ GocItem base;
+
+ double x, y, w, h;
+ GogRenderer *renderer;
+};
+
+typedef GocItemClass GocGraphClass;
+
+static GObjectClass *parent_klass;
+
+enum {
+ GRAPH_PROP_0,
+ GRAPH_PROP_X,
+ GRAPH_PROP_Y,
+ GRAPH_PROP_H,
+ GRAPH_PROP_W,
+ GRAPH_PROP_GRAPH,
+ GRAPH_PROP_RENDERER
+};
+
+static void
+goc_graph_set_property (GObject *obj, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocGraph *graph = GOC_GRAPH (obj);
+ gboolean setup_renderer = FALSE;
+
+ switch (param_id) {
+ case GRAPH_PROP_X: {
+ double x = g_value_get_double (value);
+ if (x == graph->x)
+ return;
+ graph->x = x;
+ return;
+ }
+ case GRAPH_PROP_Y: {
+ double y = g_value_get_double (value);
+ if (y == graph->y)
+ return;
+ graph->y = y;
+ break;
+ }
+ case GRAPH_PROP_H: {
+ double h = g_value_get_double (value);
+ if (h == graph->h)
+ return;
+ graph->h = h;
+ break;
+ }
+ case GRAPH_PROP_W: {
+ double w = g_value_get_double (value);
+ if (w == graph->w)
+ return;
+ graph->w = w;
+ break;
+ }
+ case GRAPH_PROP_GRAPH:
+ if (graph->renderer != NULL)
+ g_object_unref (graph->renderer);
+ graph->renderer = gog_renderer_new (g_value_get_object (value));
+ setup_renderer = graph->renderer != NULL;
+ break;
+
+ case GRAPH_PROP_RENDERER:
+ if (graph->renderer != NULL)
+ g_object_unref (graph->renderer);
+ graph->renderer = GOG_RENDERER (g_value_get_object (value));
+ if (graph->renderer != NULL) {
+ g_object_ref (graph->renderer);
+ setup_renderer = TRUE;
+ }
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+
+ if (setup_renderer)
+ g_signal_connect_object (G_OBJECT (graph->renderer),
+ "request-update",
+ G_CALLBACK (goc_item_invalidate),
+ graph, G_CONNECT_SWAPPED);
+ goc_item_bounds_changed (GOC_ITEM (graph));
+}
+
+static void
+goc_graph_get_property (GObject *obj, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocGraph *graph = GOC_GRAPH (obj);
+
+ switch (param_id) {
+ case GRAPH_PROP_X:
+ g_value_set_double (value, graph->x);
+ break;
+ case GRAPH_PROP_Y:
+ g_value_set_double (value, graph->y);
+ break;
+ case GRAPH_PROP_H:
+ g_value_set_double (value, graph->h);
+ break;
+ case GRAPH_PROP_W:
+ g_value_set_double (value, graph->w);
+ break;
+ case GRAPH_PROP_RENDERER:
+ g_value_set_object (value, graph->renderer);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+goc_graph_finalize (GObject *obj)
+{
+ GocGraph *graph = GOC_GRAPH (obj);
+
+ if (graph->renderer != NULL) {
+ g_object_unref (graph->renderer);
+ graph->renderer = NULL;
+ }
+ (*parent_klass->finalize) (obj);
+}
+
+static double
+goc_graph_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocGraph *graph = GOC_GRAPH (item);
+ double dx, dy;
+ x -= graph->x;
+ y -= graph->y;
+ if (x < 0) {
+ dx = -x;
+ } else if (x < graph->w) {
+ dx = 0;
+ } else {
+ dx = x - graph->w;
+ }
+ if (y < 0) {
+ dy = -y;
+ } else if (y < graph->h) {
+ dy = 0;
+ } else {
+ dy = y - graph->h;
+ }
+ *near_item = item;
+ return hypot (dx, dy);
+}
+
+static void
+goc_graph_draw (GocItem const *item, cairo_t *cr)
+{
+ GocGraph *graph = GOC_GRAPH (item);
+ GocCanvas *canvas = item->canvas;
+ cairo_surface_t *surf;
+ double x0 = item->x0, y0 = item->y0;
+ if (graph->renderer == NULL)
+ return;
+ goc_group_adjust_coords (item->parent, &x0, &y0);
+ cairo_save (cr);
+ cairo_translate (cr,
+ (int) (x0 - canvas->scroll_x1) * canvas->pixels_per_unit,
+ (int) (y0 - canvas->scroll_y1) * canvas->pixels_per_unit);
+ /* scaling only there gives a better rendering, and allows for caching */
+ gog_renderer_update (graph->renderer,
+ (int) (graph->w * canvas->pixels_per_unit),
+ (int) (graph->h * canvas->pixels_per_unit));
+ surf = gog_renderer_get_cairo_surface (graph->renderer);
+ cairo_set_source_surface (cr, surf, 0., 0.);
+ cairo_paint (cr);
+ cairo_restore (cr);
+}
+
+static void
+goc_graph_update_bounds (GocItem *item)
+{
+ GocGraph *graph = GOC_GRAPH (item);
+ item->x0 = graph->x;
+ item->y0 = graph->y;
+ item->x1 = graph->x + graph->w;
+ item->y1 = graph->y + graph->h;
+ gog_renderer_update (graph->renderer, graph->w, graph->h);
+}
+
+static void
+goc_graph_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+
+ parent_klass = g_type_class_peek_parent (obj_klass);
+
+ obj_klass->set_property = goc_graph_set_property;
+ obj_klass->get_property = goc_graph_get_property;
+ obj_klass->finalize = goc_graph_finalize;
+
+ g_object_class_install_property (obj_klass, GRAPH_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The graph left position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, GRAPH_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The graph top position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, GRAPH_PROP_H,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("Height"),
+ 0, G_MAXDOUBLE, 100.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, GRAPH_PROP_W,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("Width"),
+ 0, G_MAXDOUBLE, 100.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, GRAPH_PROP_GRAPH,
+ g_param_spec_object ("graph",
+ _("Graph"),
+ _("The GogGraph this object displays"),
+ GOG_TYPE_GRAPH,
+ GSF_PARAM_STATIC | G_PARAM_WRITABLE));
+ g_object_class_install_property (obj_klass, GRAPH_PROP_RENDERER,
+ g_param_spec_object ("renderer",
+ _("Renderer"),
+ _("The GogRenderer being displayed"),
+ GOG_TYPE_RENDERER,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ item_klass->draw = goc_graph_draw;
+ item_klass->update_bounds = goc_graph_update_bounds;
+ item_klass->distance = goc_graph_distance;
+}
+
+GSF_CLASS (GocGraph, goc_graph,
+ goc_graph_class_init, NULL,
+ GOC_TYPE_ITEM)
diff --git a/goffice/canvas/goc-graph.h b/goffice/canvas/goc-graph.h
new file mode 100644
index 0000000..dd434af
--- /dev/null
+++ b/goffice/canvas/goc-graph.h
@@ -0,0 +1,37 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-graph.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_GRAPH_H
+#define GOC_GRAPH_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_GRAPH (goc_graph_get_type ())
+#define GOC_GRAPH(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_GRAPH, GocGraph))
+#define GOC_IS_GRAPH(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_GRAPH))
+
+GType goc_graph_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_GRAPH_H */
diff --git a/goffice/canvas/goc-group-impl.h b/goffice/canvas/goc-group-impl.h
new file mode 100644
index 0000000..8f4a3f2
--- /dev/null
+++ b/goffice/canvas/goc-group-impl.h
@@ -0,0 +1,44 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group-impl.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_GROUP_IMPL_H
+#define GOC_GROUP_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocGroup {
+ GocItem base;
+
+ double x, y; /* group offset */
+ GList *children;
+};
+
+typedef struct {
+ GocItemClass base;
+
+} GocGroupClass ;
+
+G_END_DECLS
+
+#endif /* GOC_GROUP_IMPL_H */
diff --git a/goffice/canvas/goc-group.c b/goffice/canvas/goc-group.c
new file mode 100644
index 0000000..d917bff
--- /dev/null
+++ b/goffice/canvas/goc-group.c
@@ -0,0 +1,338 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group.c :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+static GObjectClass *parent_klass;
+
+enum {
+ GROUP_PROP_0,
+ GROUP_PROP_X,
+ GROUP_PROP_Y,
+};
+
+static void
+goc_group_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocGroup *group = GOC_GROUP (gobject);
+
+ switch (param_id) {
+ case GROUP_PROP_X:
+ group->x = g_value_get_double (value);
+ break;
+
+ case GROUP_PROP_Y:
+ group->y = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_group_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocGroup *group = GOC_GROUP (gobject);
+
+ switch (param_id) {
+ case GROUP_PROP_X:
+ g_value_set_double (value, group->x);
+ break;
+
+ case GROUP_PROP_Y:
+ g_value_set_double (value, group->y);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_group_update_bounds (GocItem *item)
+{
+ GocGroup *group = GOC_GROUP (item);
+ double x0, y0, x1, y1;
+ item->x0 = item->y0 = G_MAXDOUBLE;
+ item->x1 = item->y1 = -G_MAXDOUBLE;
+ if (group->children != NULL) {
+ GList *l = g_list_first (group->children);
+ while (l) {
+ if (l->data) {
+ goc_item_get_bounds (GOC_ITEM (l->data),
+ &x0, &y0, &x1, &y1);
+ if (x0 < item->x0)
+ item->x0 = x0;
+ if (y0 < item->y0)
+ item->y0 = y0;
+ if (x1 > item->x1)
+ item->x1 = x1;
+ if (y1 > item->y1)
+ item->y1 = y1;
+ }
+ l = g_list_next (l);
+ }
+ item->x0 += group->x;
+ item->y0 += group->y;
+ item->x1 += group->x;
+ item->y1 += group->y;
+ }
+}
+
+static gboolean
+goc_group_draw_region (GocItem const *item, cairo_t *cr,
+ double x0, double y0,
+ double x1, double y1)
+{
+ GocGroup *group = GOC_GROUP (item);
+ GList *l = g_list_first (group->children);
+ if (!l)
+ return TRUE;
+ cairo_save (cr);
+ x0 -= group->x;
+ y0 -= group->y;
+ x1 -= group->x;
+ y1 -= group->y;
+ while (l) {
+ double x, y, x_, y_;
+ GocItem *item = GOC_ITEM (l->data);
+ if (!goc_item_is_visible (item)) {
+ l = l->next;
+ continue;
+ }
+ goc_item_get_bounds (item, &x, &y, &x_, &y_);
+ if (x <= x1 && x_ >= x0 && y <= y1 && y_ >= y0) {
+ cairo_set_operator (cr, goc_item_get_operator (item));
+ if (!goc_item_draw_region (item, cr, x0, y0, x1, y1))
+ goc_item_draw (item, cr);
+ }
+ l = g_list_next (l);
+ }
+ cairo_restore (cr);
+ return TRUE;
+}
+
+/* we just need the distance method to know if an event occured on an item
+ so we don't need to know exact distances when they are large enough, to avoid
+ recalculate a lot of complex distnaces and to optimize, everything more than
+ some thershold (in pixels) will be considered at infinite */
+
+#define GOC_THRESHOLD 10 /* 10 pixels should be enough */
+
+static double
+goc_group_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocGroup *group = GOC_GROUP (item);
+ double result = G_MAXDOUBLE, dist;
+ GList *l;
+ GocItem *cur_item;
+ double th = GOC_THRESHOLD / item->canvas->pixels_per_unit;
+ x -= group->x;
+ y -= group->y;
+ for (l = g_list_last (group->children); l; l = g_list_previous (l)) {
+ GocItem *it = GOC_ITEM (l->data);
+ if (!it->visible || it->x0 > x + th || it->x1 < x - th
+ || it->y0 > y + th || it->y1 < y - th)
+ continue;
+ dist = goc_item_distance (GOC_ITEM (l->data), x, y, &cur_item);
+ if (dist < result) {
+ *near_item = cur_item;
+ result = dist;
+ }
+ if (result == 0.)
+ break;
+ }
+ return result;
+}
+
+static void
+goc_group_realize (GocItem *item)
+{
+ GocGroup *group = GOC_GROUP (item);
+ GList *l;
+ GocItemClass *klass;
+ for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+ klass = GOC_ITEM_GET_CLASS (l->data);
+ if (klass->realize)
+ klass->realize (GOC_ITEM (l->data));
+ }
+}
+
+static void
+goc_group_unrealize (GocItem *item)
+{
+ GocGroup *group = GOC_GROUP (item);
+ GList *l;
+ GocItemClass *klass;
+ for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+ klass = GOC_ITEM_GET_CLASS (l->data);
+ if (klass->unrealize)
+ klass->unrealize (GOC_ITEM (l->data));
+ }
+}
+
+static void
+goc_group_notify_scrolled (GocItem *item)
+{
+ GocGroup *group = GOC_GROUP (item);
+ GList *l;
+ GocItemClass *klass;
+ for (l = g_list_first (group->children); l; l = g_list_next (l)) {
+ klass = GOC_ITEM_GET_CLASS (l->data);
+ if (klass->notify_scrolled)
+ klass->notify_scrolled (GOC_ITEM (l->data));
+ }
+}
+
+static void
+goc_group_finalize (GObject *obj)
+{
+ GocGroup *group = GOC_GROUP (obj);
+ GList *l = g_list_first (group->children);
+ while (l) {
+ GOC_ITEM (l->data)->parent = NULL;
+ g_object_unref (G_OBJECT (l->data));
+ l = g_list_next (l);
+ }
+ g_list_free (group->children);
+ (parent_klass->finalize) (obj);
+}
+
+static void
+goc_group_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass*) item_klass;
+ parent_klass = g_type_class_peek_parent (item_klass);
+
+ obj_klass->get_property = goc_group_get_property;
+ obj_klass->set_property = goc_group_set_property;
+ obj_klass->finalize = goc_group_finalize;
+ g_object_class_install_property (obj_klass, GROUP_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The group horizontal offset"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, GROUP_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The group vertical offset"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ item_klass->draw_region = goc_group_draw_region;
+ item_klass->update_bounds = goc_group_update_bounds;
+ item_klass->distance = goc_group_distance;
+ item_klass->realize = goc_group_realize;
+ item_klass->unrealize = goc_group_unrealize;
+ item_klass->notify_scrolled = goc_group_notify_scrolled;
+}
+
+GSF_CLASS (GocGroup, goc_group,
+ goc_group_class_init, NULL,
+ GOC_TYPE_ITEM)
+
+GocGroup*
+goc_group_new (GocGroup *parent)
+{
+ GocGroup *group;
+
+ g_return_val_if_fail (GOC_IS_GROUP (parent), NULL);
+
+ group = GOC_GROUP (g_object_new (GOC_TYPE_GROUP, NULL));
+ g_return_val_if_fail ((group != NULL), NULL);
+
+ goc_group_add_child (parent, GOC_ITEM (group));
+
+ return group;
+}
+
+void
+goc_group_add_child (GocGroup *group, GocItem *item)
+{
+ g_return_if_fail (GOC_IS_GROUP (group));
+ g_return_if_fail (GOC_IS_ITEM (item));
+ if (item->parent == group)
+ return;
+ if (item->parent != NULL)
+ goc_group_remove_child (item->parent, item);
+ group->children = g_list_append (group->children, item);
+ item->parent = group;
+ item->canvas = group->base.canvas;
+ goc_item_parent_changed (item);
+ goc_item_bounds_changed (GOC_ITEM (group));
+}
+
+void
+goc_group_remove_child (GocGroup *group, GocItem *item)
+{
+ g_return_if_fail (GOC_IS_GROUP (group));
+ g_return_if_fail (GOC_IS_ITEM (item));
+ g_return_if_fail (item->parent == group);
+ group->children = g_list_remove (group->children, item);
+ item->parent = NULL;
+ item->canvas = NULL;
+ goc_item_bounds_changed (GOC_ITEM (group));
+}
+
+void
+goc_group_adjust_bounds (GocGroup const *group, double *x0, double *y0, double *x1, double *y1)
+{
+ g_return_if_fail (GOC_IS_GROUP (group));
+ *x0 += group->x;
+ *y0 += group->y;
+ *x1 += group->x;
+ *y1 += group->y;
+}
+
+void
+goc_group_adjust_coords (GocGroup const *group, double *x0, double *y0)
+{
+ GocGroup *parent;
+ g_return_if_fail (GOC_IS_GROUP (group));
+ *x0 += group->x;
+ *y0 += group->y;
+ parent = GOC_ITEM (group)->parent;
+ if (parent)
+ goc_group_adjust_coords (parent, x0, y0);
+}
+
+void goc_group_cairo_transform (GocGroup const *group, cairo_t *cr, double x, double y)
+{
+ GocGroup *parent;
+ g_return_if_fail (GOC_IS_GROUP (group));
+ parent = GOC_ITEM (group)->parent;
+ if (parent)
+ goc_group_cairo_transform (parent, cr, x + group->x, y + group->y);
+ else {
+ GocCanvas *canvas = GOC_ITEM (group)->canvas;
+ cairo_scale (cr, canvas->pixels_per_unit, canvas->pixels_per_unit);
+ cairo_translate (cr, x - canvas->scroll_x1, y - canvas->scroll_y1);
+ }
+}
diff --git a/goffice/canvas/goc-group.h b/goffice/canvas/goc-group.h
new file mode 100644
index 0000000..c227377
--- /dev/null
+++ b/goffice/canvas/goc-group.h
@@ -0,0 +1,45 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-group.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_GROUP_H
+#define GOC_GROUP_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_GROUP (goc_group_get_type ())
+#define GOC_GROUP(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_GROUP, GocGroup))
+#define GOC_IS_GROUP(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_GROUP))
+
+GType goc_group_get_type (void);
+
+GocGroup *goc_group_new (GocGroup *parent);
+void goc_group_add_child (GocGroup *parent, GocItem *item);
+void goc_group_remove_child (GocGroup *parent, GocItem *item);
+void goc_group_adjust_bounds (GocGroup const *group, double *x0, double *y0, double *x1, double *y1);
+void goc_group_adjust_coords (GocGroup const *group, double *x0, double *y0);
+void goc_group_cairo_transform (GocGroup const *group, cairo_t *cr, double x, double y);
+
+G_END_DECLS
+
+#endif /* GOC_GROUP_H */
diff --git a/goffice/canvas/goc-item-impl.h b/goffice/canvas/goc-item-impl.h
new file mode 100644
index 0000000..34ba4ec
--- /dev/null
+++ b/goffice/canvas/goc-item-impl.h
@@ -0,0 +1,70 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item-impl.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_ITEM_IMPL_H
+#define GOC_ITEM_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocItem {
+ GObject base;
+
+ GocCanvas *canvas;
+ GocGroup *parent;
+ gboolean cached_bounds;
+ gboolean needs_redraw;
+ gboolean visible;
+ double x0, y0, x1, y1; /* the bounds */
+};
+
+typedef struct {
+ GObjectClass base;
+
+ double (*distance) (GocItem *item,
+ double x, double y, GocItem **near_item);
+ void (*draw) (GocItem const *item, cairo_t *cr);
+ gboolean (*draw_region) (GocItem const *item, cairo_t *cr,
+ double x0, double y0, double x1, double y1);
+ void (*move) (GocItem *item, double x, double y);
+ void (*update_bounds) (GocItem *item);
+ void (*parent_changed) (GocItem *item);
+ cairo_operator_t
+ (*get_operator) (GocItem *item);
+ // events related functions
+ gboolean (*button_pressed) (GocItem *item, int button, double x, double y);
+ gboolean (*button2_pressed) (GocItem *item, int button, double x, double y);
+ gboolean (*button_released) (GocItem *item, int button, double x, double y);
+ gboolean (*motion) (GocItem *item, double x, double y);
+ gboolean (*enter_notify) (GocItem *item, double x, double y);
+ gboolean (*leave_notify) (GocItem *item, double x, double y);
+ void (*realize) (GocItem *item);
+ void (*unrealize) (GocItem *item);
+ gboolean (*key_pressed) (GocItem *item, GdkEventKey* ev);
+ gboolean (*key_released) (GocItem *item, GdkEventKey* ev);
+ void (*notify_scrolled) (GocItem *item);
+} GocItemClass ;
+
+G_END_DECLS
+
+#endif /* GOC_ITEM_IMPL_H */
diff --git a/goffice/canvas/goc-item.c b/goffice/canvas/goc-item.c
new file mode 100644
index 0000000..dfb7007
--- /dev/null
+++ b/goffice/canvas/goc-item.c
@@ -0,0 +1,357 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item.c :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gtk/gtk.h>
+#include <gsf/gsf-impl-utils.h>
+
+static GObjectClass *item_parent_class;
+
+static gboolean
+goc_item_button_pressed (GocItem *item, int button, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->button_pressed (GOC_ITEM (item->parent), button, x, y):
+ FALSE;
+}
+
+static gboolean
+goc_item_button2_pressed (GocItem *item, int button, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->button2_pressed (GOC_ITEM (item->parent), button, x, y):
+ FALSE;
+}
+
+static gboolean
+goc_item_button_released (GocItem *item, int button, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->button_released (GOC_ITEM (item->parent), button, x, y):
+ FALSE;
+}
+
+static gboolean
+goc_item_motion (GocItem *item, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->motion (GOC_ITEM (item->parent), x, y):
+ FALSE;
+}
+
+static gboolean
+goc_item_enter_notify (GocItem *item, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->enter_notify (GOC_ITEM (item->parent), x, y):
+ FALSE;
+}
+
+static gboolean
+goc_item_leave_notify (GocItem *item, double x, double y)
+{
+ return (item->parent)?
+ GOC_ITEM_GET_CLASS (item->parent)->leave_notify (GOC_ITEM (item->parent), x, y):
+ FALSE;
+}
+
+static void
+goc_item_finalize (GObject *object)
+{
+ GocItem *item = GOC_ITEM (object);
+ if (item->canvas->last_item == item)
+ item->canvas->last_item = NULL;
+ if (GTK_WIDGET_REALIZED (item->canvas)) {
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ if (klass->unrealize)
+ klass->unrealize (item);
+ goc_item_invalidate (item);
+ }
+ if (item->parent != NULL)
+ goc_group_remove_child (item->parent, item);
+ item_parent_class->finalize (object);
+}
+
+static void
+goc_item_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ item_parent_class = g_type_class_peek_parent (item_klass);
+
+ item_klass->button_pressed = goc_item_button_pressed;
+ item_klass->button2_pressed = goc_item_button2_pressed;
+ item_klass->button_released = goc_item_button_released;
+ item_klass->motion = goc_item_motion;
+ item_klass->enter_notify = goc_item_enter_notify;
+ item_klass->leave_notify = goc_item_leave_notify;
+
+ obj_klass->finalize = goc_item_finalize;
+}
+
+static void
+goc_item_init (GocItem *item)
+{
+ item->visible = TRUE;
+}
+
+GSF_CLASS (GocItem, goc_item,
+ goc_item_class_init, goc_item_init,
+ G_TYPE_OBJECT)
+
+GocItem*
+goc_item_new (GocGroup *group, GType type, const gchar *first_arg_name, ...)
+{
+ GocItem *item;
+ va_list args;
+
+ g_return_val_if_fail (GOC_IS_GROUP (group), NULL);
+
+ item = GOC_ITEM (g_object_new (type, NULL));
+ g_return_val_if_fail ((item != NULL), NULL);
+
+ goc_group_add_child (group, item);
+
+ va_start (args, first_arg_name);
+ g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+ va_end (args);
+
+ if (GTK_WIDGET_REALIZED (item->canvas)) {
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ if (klass->realize)
+ klass->realize (item);
+ }
+
+ return item;
+}
+
+void
+goc_item_set (GocItem *item, const gchar *first_arg_name, ...)
+{
+ va_list args;
+
+ goc_item_invalidate (item);
+
+ va_start (args, first_arg_name);
+ g_object_set_valist (G_OBJECT (item), first_arg_name, args);
+ va_end (args);
+
+ goc_item_invalidate (item);
+}
+
+double
+goc_item_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_val_if_fail (klass != NULL, G_MAXDOUBLE);
+
+ return (klass->distance)?
+ klass->distance (item, x, y, near_item): G_MAXDOUBLE;
+}
+
+void
+goc_item_draw (GocItem const *item, cairo_t *cr)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_if_fail (klass != NULL);
+
+ if (klass->draw)
+ klass->draw (item, cr);
+}
+
+gboolean
+goc_item_draw_region (GocItem const *item, cairo_t *cr,
+ double x0, double y0,
+ double x1, double y1)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_val_if_fail (klass != NULL, FALSE);
+
+ return (klass->draw_region)?
+ klass->draw_region (item, cr, x0, y0, x1, y1): FALSE;
+}
+
+cairo_operator_t
+goc_item_get_operator (GocItem *item)
+{
+ GocItemClass *klass;
+
+ g_return_val_if_fail (GOC_IS_ITEM (item), CAIRO_OPERATOR_OVER);
+ klass = GOC_ITEM_GET_CLASS (item);
+ g_return_val_if_fail (klass != NULL, CAIRO_OPERATOR_OVER);
+
+ return (klass->get_operator)?
+ klass->get_operator (item): CAIRO_OPERATOR_OVER;
+}
+
+void
+goc_item_move (GocItem *item, double x, double y)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_if_fail (klass != NULL);
+
+ if (klass->move)
+ klass->move (item, x, y);
+}
+
+void goc_item_invalidate (GocItem *item)
+{
+ GocGroup const *parent;
+ double x0, y0, x1, y1;
+
+ g_return_if_fail (GOC_IS_ITEM (item));
+ if (!GTK_WIDGET_REALIZED (item->canvas))
+ return;
+
+ parent = item->parent;
+ if (!item->cached_bounds)
+ goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+ x0 = item->x0;
+ y0 = item->y0;
+ x1 = item->x1;
+ y1 = item->y1;
+ while (parent) {
+ goc_group_adjust_bounds (parent, &x0, &y0, &x1, &y1);
+ parent = parent->base.parent;
+ }
+ goc_canvas_invalidate (item->canvas, x0, y0, x1, y1);
+}
+
+void
+goc_item_show (GocItem *item)
+{
+ g_return_if_fail (GOC_IS_ITEM (item));
+ item->visible = TRUE;
+ goc_item_invalidate (item);
+}
+
+void
+goc_item_hide (GocItem *item)
+{
+ g_return_if_fail (GOC_IS_ITEM (item));
+ item->visible = FALSE;
+ goc_item_invalidate (item);
+}
+
+gboolean
+goc_item_is_visible (GocItem *item)
+{
+ g_return_val_if_fail (GOC_IS_ITEM (item), FALSE);
+ return item->visible;
+}
+
+void
+goc_item_get_bounds (GocItem const *item, double *x0, double *y0, double *x1, double *y1)
+{
+ g_return_if_fail (GOC_IS_ITEM (item));
+ if (!item->cached_bounds) {
+ goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+ }
+ *x0 = item->x0;
+ *y0 = item->y0;
+ *x1 = item->x1;
+ *y1 = item->y1;
+}
+
+void
+goc_item_update_bounds (GocItem *item)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_if_fail (klass != NULL);
+
+ if (klass->update_bounds)
+ klass->update_bounds (item);
+ item->cached_bounds = TRUE;
+}
+
+void
+goc_item_bounds_changed (GocItem *item)
+{
+ g_return_if_fail (GOC_IS_ITEM (item));
+ item->cached_bounds = FALSE;
+ if (item->parent)
+ goc_item_bounds_changed (GOC_ITEM (item->parent));
+}
+
+void
+goc_item_parent_changed (GocItem *item)
+{
+ GocItemClass *klass = GOC_ITEM_GET_CLASS (item);
+ g_return_if_fail (klass != NULL);
+
+ if (klass->parent_changed)
+ klass->parent_changed (item);
+}
+
+void
+goc_item_grab (GocItem *item)
+{
+ g_return_if_fail (GOC_IS_ITEM (item));
+ goc_canvas_grab_item (item->canvas, item);
+}
+
+void
+goc_item_ungrab (GocItem *item)
+{
+ g_return_if_fail (item == goc_canvas_get_grabbed_item (item->canvas));
+ goc_canvas_ungrab_item (item->canvas);
+}
+
+void
+goc_item_raise (GocItem *item, int n)
+{
+ GList *orig = g_list_find (item->parent->children, item);
+ GList *dest = g_list_nth (orig, n + 1);
+ if (dest)
+ item->parent->children = g_list_insert_before (item->parent->children, dest, item);
+ else
+ item->parent->children = g_list_append (item->parent->children, item);
+ item->parent->children = g_list_remove_link (item->parent->children, orig);
+}
+
+void
+goc_item_lower (GocItem *item, int n)
+{
+ GList *orig = g_list_find (item->parent->children, item);
+ GList *dest = g_list_nth_prev (orig, n);
+ if (dest)
+ item->parent->children = g_list_insert_before (item->parent->children, dest, item);
+ else
+ item->parent->children = g_list_prepend (item->parent->children, item);
+ item->parent->children = g_list_remove_link (item->parent->children, orig);
+}
+
+void
+goc_item_lower_to_bottom (GocItem *item)
+{
+ g_return_if_fail (item->parent != NULL);
+ item->parent->children = g_list_remove (item->parent->children, item);
+ item->parent->children = g_list_prepend (item->parent->children, item);
+}
+
+void
+goc_item_raise_to_top (GocItem *item)
+{
+ g_return_if_fail (item->parent != NULL);
+ item->parent->children = g_list_remove (item->parent->children, item);
+ item->parent->children = g_list_append (item->parent->children, item);
+}
diff --git a/goffice/canvas/goc-item.h b/goffice/canvas/goc-item.h
new file mode 100644
index 0000000..e75cd93
--- /dev/null
+++ b/goffice/canvas/goc-item.h
@@ -0,0 +1,71 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-item.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_ITEM_H
+#define GOC_ITEM_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_ITEM (goc_item_get_type ())
+#define GOC_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_ITEM, GocItem))
+#define GOC_IS_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_ITEM))
+#define GOC_IS_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GOC_TYPE_ITEM))
+#define GOC_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOC_TYPE_ITEM, GocItemClass))
+
+GType goc_item_get_type (void);
+
+typedef struct {
+ GTypeInterface base;
+
+} GocItemClientClass;
+
+GocItem *goc_item_new (GocGroup *parent, GType type, const gchar *first_arg_name, ...);
+void goc_item_set (GocItem *item, const gchar *first_arg_name, ...);
+double goc_item_distance (GocItem *item, double x, double y, GocItem **near_item);
+void goc_item_draw (GocItem const *item, cairo_t *cr);
+gboolean goc_item_draw_region (GocItem const *item, cairo_t *cr,
+ double x0, double y0, double x1, double y1);
+cairo_operator_t
+ goc_item_get_operator (GocItem *item);
+void goc_item_move (GocItem *item, double x, double y);
+
+void goc_item_invalidate (GocItem *item);
+void goc_item_show (GocItem *item);
+void goc_item_hide (GocItem *item);
+gboolean goc_item_is_visible (GocItem *item);
+void goc_item_get_bounds (GocItem const *item,
+ double *x0, double *y0,
+ double *x1, double *y1);
+void goc_item_update_bounds (GocItem *item);
+void goc_item_bounds_changed (GocItem *item);
+void goc_item_parent_changed (GocItem *item);
+void goc_item_grab (GocItem *item);
+void goc_item_ungrab (GocItem *item);
+void goc_item_raise (GocItem *item, int n);
+void goc_item_lower (GocItem *item, int n);
+void goc_item_lower_to_bottom (GocItem *item);
+void goc_item_raise_to_top (GocItem *item);
+
+G_END_DECLS
+
+#endif /* GOC_ITEM_H */
diff --git a/goffice/canvas/goc-line.c b/goffice/canvas/goc-line.c
new file mode 100644
index 0000000..227b8c5
--- /dev/null
+++ b/goffice/canvas/goc-line.c
@@ -0,0 +1,221 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-line.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+ LINE_PROP_0,
+ LINE_PROP_X0,
+ LINE_PROP_Y0,
+ LINE_PROP_X1,
+ LINE_PROP_Y1
+};
+
+struct _GocLine {
+ GocStyledItem base;
+
+ /* using these to avoid confusion with x0 and others in GocItem */
+ double startx, starty, endx, endy;
+};
+
+typedef GocStyledItemClass GocLineClass;
+
+static void
+goc_line_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocLine *line = GOC_LINE (gobject);
+
+ switch (param_id) {
+ case LINE_PROP_X0:
+ line->startx = g_value_get_double (value);
+ break;
+
+ case LINE_PROP_Y0:
+ line->starty = g_value_get_double (value);
+ break;
+
+ case LINE_PROP_X1:
+ line->endx = g_value_get_double (value);
+ break;
+
+ case LINE_PROP_Y1:
+ line->endy = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+}
+
+static void
+goc_line_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocLine *line = GOC_LINE (gobject);
+
+ switch (param_id) {
+ case LINE_PROP_X0:
+ g_value_set_double (value, line->startx);
+ break;
+
+ case LINE_PROP_Y0:
+ g_value_set_double (value, line->starty);
+ break;
+
+ case LINE_PROP_X1:
+ g_value_set_double (value, line->endx);
+ break;
+
+ case LINE_PROP_Y1:
+ g_value_set_double (value, line->endy);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_line_update_bounds (GocItem *item)
+{
+ GocLine *line = GOC_LINE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: take rotation into account */
+ double extra_width = style->line.width /2.;
+ /* fix me, take ends and orientation into account */
+ if (extra_width <= 0.)
+ extra_width = .5;
+ if (line->startx < line->endx) {
+ item->x0 = line->startx - extra_width;
+ item->x1 = line->endx + extra_width;
+ } else {
+ item->x0 = line->endx - extra_width;
+ item->x1 = line->startx + extra_width;
+ }
+ if (line->starty < line->endy) {
+ item->y0 = line->starty - extra_width;
+ item->y1 = line->endy + extra_width;
+ } else {
+ item->y0 = line->endy - extra_width;
+ item->y1 = line->starty + extra_width;
+ }
+}
+
+static double
+goc_line_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocLine *line = GOC_LINE (item);
+ double dx, dy, l, t;
+ GOStyle *style;
+ dx = line->endx - line->startx;
+ dy = line->endy - line->starty;
+ l = hypot (dx, dy);
+ x -= line->startx;
+ y -= line->starty;
+ t = (x * dx + y * dy) / l;
+ y = (-x * dy + y * dx) / l;
+ *near_item = item;
+ if (t < 0.)
+ return hypot (t, y); /* that might be not fully exact,
+ but we don't need a large precision */
+ if (t > l)
+ return hypot (t - l, y);
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ t = y - style->line.width / 2.;
+ return (t > 0.)? t: 0.;
+}
+
+static void goc_line_draw (GocItem const *item, cairo_t *cr)
+{
+ GocLine *line = GOC_LINE (item);
+ if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr)) {
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, line->startx, line->starty);
+ cairo_move_to (cr, 0., 0.);
+ cairo_line_to (cr, line->endx - line->startx, line->endy - line->starty);
+ cairo_stroke (cr);
+ cairo_restore (cr);
+ }
+}
+
+static void
+goc_line_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_LINE;
+ if (style->line.auto_dash)
+ style->line.dash_type = GO_LINE_SOLID;
+ if (style->line.auto_color)
+ style->line.color = RGBA_BLACK;
+ if (style->line.auto_fore)
+ style->line.fore = 0;
+}
+
+static void
+goc_line_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+ gsi_klass->init_style = goc_line_init_style;
+
+ obj_klass->get_property = goc_line_get_property;
+ obj_klass->set_property = goc_line_set_property;
+ g_object_class_install_property (obj_klass, LINE_PROP_X0,
+ g_param_spec_double ("x0",
+ _("x0"),
+ _("The line start x coordinate"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, LINE_PROP_Y0,
+ g_param_spec_double ("y0",
+ _("y0"),
+ _("The line start y coordinate"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, LINE_PROP_X1,
+ g_param_spec_double ("x1",
+ _("x1"),
+ _("The line end x coordinate"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, LINE_PROP_Y1,
+ g_param_spec_double ("y1",
+ _("y1"),
+ _("The line end y coordinate"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ item_klass->update_bounds = goc_line_update_bounds;
+ item_klass->distance = goc_line_distance;
+ item_klass->draw = goc_line_draw;
+}
+
+GSF_CLASS (GocLine, goc_line,
+ goc_line_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
+
+G_END_DECLS
diff --git a/goffice/canvas/goc-line.h b/goffice/canvas/goc-line.h
new file mode 100644
index 0000000..5ededc9
--- /dev/null
+++ b/goffice/canvas/goc-line.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-line.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_LINE_H
+#define GOC_LINE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_LINE (goc_line_get_type ())
+#define GOC_LINE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_LINE, GocLine))
+#define GOC_IS_LINE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_LINE))
+
+GType goc_line_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_LINE_H */
diff --git a/goffice/canvas/goc-pixbuf.c b/goffice/canvas/goc-pixbuf.c
new file mode 100644
index 0000000..905881b
--- /dev/null
+++ b/goffice/canvas/goc-pixbuf.c
@@ -0,0 +1,267 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-pixbuf.c:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+ PIXBUF_PROP_0,
+ PIXBUF_PROP_X,
+ PIXBUF_PROP_Y,
+ PIXBUF_PROP_W,
+ PIXBUF_PROP_H,
+ PIXBUF_PROP_ROTATION,
+ PIXBUF_PROP_PIXBUF
+};
+
+struct _GocPixbuf {
+ GocItem base;
+
+ double x, y, width, height, rotation;
+ GdkPixbuf *pixbuf;
+};
+
+typedef GocItemClass GocPixbufClass;
+static GocItemClass *parent_class;
+
+static void
+goc_pixbuf_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+ switch (param_id) {
+ case PIXBUF_PROP_X:
+ pixbuf->x = g_value_get_double (value);
+ break;
+
+ case PIXBUF_PROP_Y:
+ pixbuf->y = g_value_get_double (value);
+ break;
+
+ case PIXBUF_PROP_W:
+ pixbuf->width = g_value_get_double (value);
+ break;
+
+ case PIXBUF_PROP_H:
+ pixbuf->height = g_value_get_double (value);
+ break;
+
+ case PIXBUF_PROP_ROTATION:
+ pixbuf->rotation = g_value_get_double (value);
+ break;
+
+ case PIXBUF_PROP_PIXBUF:
+ if (pixbuf->pixbuf)
+ g_object_unref (pixbuf);
+ pixbuf->pixbuf = GDK_PIXBUF (g_object_ref (g_value_get_object (value)));
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_pixbuf_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+ switch (param_id) {
+ case PIXBUF_PROP_X:
+ g_value_set_double (value, pixbuf->x);
+ break;
+
+ case PIXBUF_PROP_Y:
+ g_value_set_double (value, pixbuf->y);
+ break;
+
+ case PIXBUF_PROP_W:
+ g_value_set_double (value, pixbuf->width);
+ break;
+
+ case PIXBUF_PROP_H:
+ g_value_set_double (value, pixbuf->height);
+ break;
+
+ case PIXBUF_PROP_ROTATION:
+ g_value_set_double (value, pixbuf->rotation);
+ break;
+
+ case PIXBUF_PROP_PIXBUF:
+ if (pixbuf->pixbuf)
+ g_value_set_object (value, G_OBJECT (pixbuf->pixbuf));
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_pixbuf_finalize (GObject *gobject)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (gobject);
+
+ if (pixbuf->pixbuf)
+ g_object_unref (pixbuf->pixbuf);
+ ((GObjectClass *) parent_class)->finalize (gobject);
+}
+
+static void
+goc_pixbuf_update_bounds (GocItem *item)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (item);
+ if (!pixbuf->pixbuf)
+ return;
+ /* FIXME: take rotation into account */
+ item->x0 = pixbuf->x;
+ item->y0 = pixbuf->y;
+ item->x1 = pixbuf->x + ((pixbuf->width > 0.)? pixbuf->width: gdk_pixbuf_get_width (pixbuf->pixbuf));
+ item->y1 = pixbuf->y + ((pixbuf->height > 0.)? pixbuf->height: gdk_pixbuf_get_height (pixbuf->pixbuf));
+}
+
+static double
+goc_pixbuf_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (item);
+ /* FIXME: take rotation into account */
+ double dx, dy, w, h;
+ if (pixbuf->pixbuf == NULL)
+ return G_MAXDOUBLE;
+ w = (pixbuf->width >= 0.)? pixbuf->width: gdk_pixbuf_get_width (pixbuf->pixbuf);
+ h = (pixbuf->height >= 0.)? pixbuf->height: gdk_pixbuf_get_height (pixbuf->pixbuf);
+ if (x < pixbuf->x) {
+ dx = pixbuf->x - x;
+ } else if (x < pixbuf->x + w) {
+ dx = 0;
+ } else {
+ dx = x - pixbuf->x - w;
+ }
+ if (y < pixbuf->y) {
+ dy = pixbuf->y - y;
+ } else if (y < pixbuf->y + h) {
+ dy = 0;
+ } else {
+ dy = y - pixbuf->y - h;
+ }
+ *near_item = item;
+ return hypot (dx, dy);
+}
+
+static void
+goc_pixbuf_draw (GocItem const *item, cairo_t *cr)
+{
+ GocPixbuf *pixbuf = GOC_PIXBUF (item);
+ GOImage * image;
+ cairo_pattern_t *pat;
+ double height, width;
+ double scalex = 1., scaley = 1.;
+
+ if (pixbuf->pixbuf == NULL)
+ return;
+
+ image = go_image_new_from_pixbuf (pixbuf->pixbuf);
+ pat = go_image_create_cairo_pattern (image);
+ if (pixbuf->width < 0.)
+ width = gdk_pixbuf_get_width (pixbuf->pixbuf);
+ else {
+ width = pixbuf->width;
+ scalex = width / gdk_pixbuf_get_width (pixbuf->pixbuf);
+ }
+ if (pixbuf->height < 0.)
+ height = gdk_pixbuf_get_height (pixbuf->pixbuf);
+ else {
+ height = pixbuf->height;
+ scaley = height / gdk_pixbuf_get_height (pixbuf->pixbuf);
+ }
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, pixbuf->x, pixbuf->y);
+ cairo_rotate (cr, pixbuf->rotation);
+ if (scalex != 1. || scaley != 1.)
+ cairo_scale (cr, scalex, scaley);
+ cairo_rectangle (cr, 0., 0., width, height);
+ cairo_set_source (cr, pat);
+ cairo_pattern_destroy (pat);
+ cairo_fill (cr);
+ cairo_restore (cr);
+ g_object_unref (image);
+}
+
+static void
+goc_pixbuf_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ parent_class = g_type_class_peek_parent (item_klass);
+
+ obj_klass->finalize = goc_pixbuf_finalize;
+ obj_klass->get_property = goc_pixbuf_get_property;
+ obj_klass->set_property = goc_pixbuf_set_property;
+ g_object_class_install_property (obj_klass, PIXBUF_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The image left position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, PIXBUF_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The image top position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, PIXBUF_PROP_W,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The image width or -1 to use the image width"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, PIXBUF_PROP_H,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The image height or -1 to use the image height"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/* g_object_class_install_property (obj_klass, PIXBUF_PROP_ROTATION,
+ g_param_spec_double ("rotation",
+ _("Rotation"),
+ _("The rotation around top left position"),
+ 0., 2 * M_PI, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+ g_object_class_install_property (obj_klass, PIXBUF_PROP_PIXBUF,
+ g_param_spec_object ("pixbuf", _("Pixbuf"),
+ _("The GdkPixbuf to display"),
+ GDK_TYPE_PIXBUF,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ item_klass->update_bounds = goc_pixbuf_update_bounds;
+ item_klass->distance = goc_pixbuf_distance;
+ item_klass->draw = goc_pixbuf_draw;
+}
+
+GSF_CLASS (GocPixbuf, goc_pixbuf,
+ goc_pixbuf_class_init, NULL,
+ GOC_TYPE_ITEM)
diff --git a/goffice/canvas/goc-pixbuf.h b/goffice/canvas/goc-pixbuf.h
new file mode 100644
index 0000000..b6d4def
--- /dev/null
+++ b/goffice/canvas/goc-pixbuf.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-pixbuf.h:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_PIXBUF_H
+#define GOC_PIXBUF_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_PIXBUF (goc_pixbuf_get_type ())
+#define GOC_PIXBUF(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_PIXBUF, GocPixbuf))
+#define GOC_IS_PIXBUF(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_PIXBUF))
+
+GType goc_pixbuf_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_PIXBUF_H */
diff --git a/goffice/canvas/goc-polygon-impl.h b/goffice/canvas/goc-polygon-impl.h
new file mode 100644
index 0000000..a8d57ff
--- /dev/null
+++ b/goffice/canvas/goc-polygon-impl.h
@@ -0,0 +1,42 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon-impl.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_POLYGON_IMPL_H
+#define GOC_POLYGON_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+typedef GocStyledItemClass GocPolygonClass;
+
+struct _GocPolygon {
+ GocStyledItem base;
+
+ GocPoint *points;
+ unsigned nb_points;
+ gboolean use_spline;
+};
+
+G_END_DECLS
+
+#endif /* GOC_POLYGON_IMPL_H */
diff --git a/goffice/canvas/goc-polygon.c b/goffice/canvas/goc-polygon.c
new file mode 100644
index 0000000..64ff27b
--- /dev/null
+++ b/goffice/canvas/goc-polygon.c
@@ -0,0 +1,243 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon.c :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+ POLYGON_PROP_0,
+ POLYGON_PROP_POINTS,
+ POLYGON_PROP_SPLINE
+};
+
+static void
+goc_polygon_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocPolygon *polygon = GOC_POLYGON (gobject);
+
+ switch (param_id) {
+ case POLYGON_PROP_POINTS: {
+ unsigned i;
+ GocPoints *points = (GocPoints *) g_value_get_boxed (value);
+ polygon->nb_points = points->n;
+ if (polygon->points)
+ g_free (polygon->points);
+ polygon->points = g_new (GocPoint, points->n);
+ for (i = 0; i < points->n; i++)
+ polygon->points[i] = points->points[i];
+ break;
+ }
+ case POLYGON_PROP_SPLINE:
+ polygon->use_spline = g_value_get_boolean (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_polygon_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocPolygon *polygon = GOC_POLYGON (gobject);
+
+ switch (param_id) {
+ case POLYGON_PROP_POINTS: {
+ unsigned i;
+ GocPoints *points = goc_points_new (polygon->nb_points);
+ for (i = 0; i < points->n; i++)
+ points->points[i] = polygon->points[i];
+ g_value_set_boxed (value, points);
+ goc_points_unref (points);
+ break;
+ }
+ case POLYGON_PROP_SPLINE:
+ g_value_set_boolean (value, polygon->use_spline);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_polygon_update_bounds (GocItem *item)
+{
+ GocPolygon *polygon = GOC_POLYGON (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ double extra_width = style->outline.width;
+ unsigned i;
+ if (extra_width <= 0.)
+ extra_width = 1.;
+ if (polygon->nb_points == 0)
+ return;
+ /* FIXME: implement the use_spline case */
+ item->x0 = item->x1 = polygon->points[0].x;
+ item->y0 = item->y1 = polygon->points[0].y;
+ for (i = 1; i < polygon->nb_points; i++) {
+ if (polygon->points[i].x < item->x0)
+ item->x0 = polygon->points[i].x;
+ else if (polygon->points[i].x > item->x1)
+ item->x1 = polygon->points[i].x;
+ if (polygon->points[i].y < item->y0)
+ item->y0 = polygon->points[i].y;
+ else if (polygon->points[i].y > item->y1)
+ item->y1 = polygon->points[i].y;
+ }
+ item->x0 -= extra_width;
+ item->y0 -= extra_width;
+ item->x1 -= extra_width;
+ item->y1 -= extra_width;
+}
+
+static double
+goc_polygon_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocPolygon *polygon = GOC_POLYGON (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: implement the use_spline case */
+ double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+ double dx, dy, l, startx, starty, x_, y_, t, res = 0.;
+ int i, n;
+
+ *near_item = item;
+ /* FIXME: not tested!!! */
+ /* first test if the point is inside the polygon */
+ startx = atan2 (polygon->points[0].y - y, polygon->points[0].x - x);
+ for (i = polygon->nb_points - 1; i >= 0; i--) {
+ starty = atan2 (polygon->points[i].y - y, polygon->points[i].x - x);
+ startx -= starty;
+ if (startx > M_PI)
+ startx -= 2 * M_PI;
+ else if (startx < -M_PI)
+ startx += 2 * M_PI;
+ else if (startx == M_PI)
+ return 0.; /* the point is on the edge */
+ res += startx;
+ startx = starty;
+ }
+ n = res / 2. / M_PI;
+ if (n % 1)
+ return 0.; /* only odd-even fillinig supported for now */
+ startx = polygon->points[0].x;
+ starty = polygon->points[0].y;
+ res = G_MAXDOUBLE;
+ for (i = polygon->nb_points - 1; i >= 0; i--) {
+ dx = polygon->points[i].x - startx;
+ dy = polygon->points[i].y - starty;
+ l = hypot (dx, dy);
+ x_ = x - startx;
+ y_ = y - starty;
+ t = (x_ * dx + y_ * dy) / l;
+ y = (-x_ * dy + y_ * dx) / l;
+ x_ = t;
+ *near_item = item;
+ if (x < 0. ) {
+ t = hypot (x_, y_);
+ if (t < res)
+ res = t;
+ } else if (t <= l) {
+ if (y_ < res)
+ res = y_;
+ }
+ startx = polygon->points[i].x;
+ starty = polygon->points[i].y;
+ }
+ res -= extra_width; /* no need to be more precise */
+ return (res > 0.)? res: 0.;
+}
+
+static void
+goc_polygon_draw (GocItem const *item, cairo_t *cr)
+{
+ GocPolygon *polygon = GOC_POLYGON (item);
+ unsigned i;
+ if (polygon->nb_points == 0)
+ return;
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, polygon->points[0].x, polygon->points[0].y);
+ cairo_move_to (cr, 0., 0.);
+ /* FIXME: implement the use_spline case */
+
+ for (i = 1; i < polygon->nb_points; i++)
+ cairo_line_to (cr, polygon->points[i].x - polygon->points[0].x,
+ polygon->points[i].y - polygon->points[0].y);
+ cairo_close_path (cr);
+
+ if (go_styled_object_set_cairo_fill (GO_STYLED_OBJECT (item), cr))
+ cairo_fill_preserve (cr);
+
+ if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+ cairo_stroke (cr);
+ else
+ cairo_new_path (cr);
+ cairo_restore (cr);
+}
+
+static void
+goc_polygon_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+ if (style->outline.auto_dash)
+ style->outline.dash_type = GO_LINE_SOLID;
+ if (style->outline.auto_color)
+ style->outline.color = RGBA_BLACK;
+ if (style->fill.auto_type)
+ style->fill.type = GO_STYLE_FILL_PATTERN;
+ if (style->fill.auto_fore)
+ go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_polygon_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+ gsi_klass->init_style = goc_polygon_init_style;
+
+ obj_klass->get_property = goc_polygon_get_property;
+ obj_klass->set_property = goc_polygon_set_property;
+ g_object_class_install_property (obj_klass, POLYGON_PROP_POINTS,
+ g_param_spec_boxed ("points", _("points"), _("The polygon vertices"),
+ GOC_TYPE_POINTS,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, POLYGON_PROP_SPLINE,
+ g_param_spec_boolean ("use-spline",
+ _("Use spline"),
+ _("Use a Bezier closed cubic spline as contour"),
+ FALSE,
+ GSF_PARAM_STATIC | G_PARAM_READABLE));
+
+ item_klass->update_bounds = goc_polygon_update_bounds;
+ item_klass->distance = goc_polygon_distance;
+ item_klass->draw = goc_polygon_draw;
+}
+
+GSF_CLASS (GocPolygon, goc_polygon,
+ goc_polygon_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-polygon.h b/goffice/canvas/goc-polygon.h
new file mode 100644
index 0000000..5b4b435
--- /dev/null
+++ b/goffice/canvas/goc-polygon.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-polygon.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_POLYGON_H
+#define GOC_POLYGON_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_POLYGON (goc_polygon_get_type ())
+#define GOC_POLYGON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_POLYGON, GocPolygon))
+#define GOC_IS_POLYGON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_POLYGON))
+
+GType goc_polygon_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_POLYGON_H */
diff --git a/goffice/canvas/goc-rectangle-impl.h b/goffice/canvas/goc-rectangle-impl.h
new file mode 100644
index 0000000..a716e60
--- /dev/null
+++ b/goffice/canvas/goc-rectangle-impl.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_RECTANGLE_IMPL_H
+#define GOC_RECTANGLE_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocRectangle {
+ GocStyledItem base;
+
+ double rotation; /* rotation around the center in radians */
+ double x, y, width, height;
+};
+
+typedef GocStyledItemClass GocRectangleClass;
+
+G_END_DECLS
+
+#endif /* GOC_RECTANGLE_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-rectangle.c b/goffice/canvas/goc-rectangle.c
new file mode 100644
index 0000000..fce6d1f
--- /dev/null
+++ b/goffice/canvas/goc-rectangle.c
@@ -0,0 +1,235 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle.c:
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+enum {
+ RECT_PROP_0,
+ RECT_PROP_X,
+ RECT_PROP_Y,
+ RECT_PROP_W,
+ RECT_PROP_H,
+ RECT_PROP_ROTATION
+};
+
+static void
+goc_rectangle_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocRectangle *rect = GOC_RECTANGLE (gobject);
+
+ switch (param_id) {
+ case RECT_PROP_X:
+ rect->x = g_value_get_double (value);
+ break;
+
+ case RECT_PROP_Y:
+ rect->y = g_value_get_double (value);
+ break;
+
+ case RECT_PROP_W:
+ rect->width = g_value_get_double (value);
+ break;
+
+ case RECT_PROP_H:
+ rect->height = g_value_get_double (value);
+ break;
+
+ case RECT_PROP_ROTATION:
+ rect->rotation = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_rectangle_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocRectangle *rect = GOC_RECTANGLE (gobject);
+
+ switch (param_id) {
+ case RECT_PROP_X:
+ g_value_set_double (value, rect->x);
+ break;
+
+ case RECT_PROP_Y:
+ g_value_set_double (value, rect->y);
+ break;
+
+ case RECT_PROP_W:
+ g_value_set_double (value, rect->width);
+ break;
+
+ case RECT_PROP_H:
+ g_value_set_double (value, rect->height);
+ break;
+
+ case RECT_PROP_ROTATION:
+ g_value_set_double (value, rect->rotation);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_rectangle_update_bounds (GocItem *item)
+{
+ GocRectangle *rect = GOC_RECTANGLE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: take rotation into account */
+ double extra_width = style->outline.width /2.;
+ if (extra_width <= 0.)
+ extra_width = .5;
+ item->x0 = rect->x - extra_width;
+ item->y0 = rect->y - extra_width;
+ item->x1 = rect->x + rect->width + extra_width;
+ item->y1 = rect->y + rect->height + extra_width;
+}
+
+static double
+goc_rectangle_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocRectangle *rect = GOC_RECTANGLE (item);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ /* FIXME: take rotation into account */
+ double extra_width = (style->outline.width)? style->outline.width /2.: .5;
+ double dx, dy;
+ if (x < rect->x - extra_width) {
+ dx = rect->x - extra_width - x;
+ } else if (x < rect->x + rect->width + extra_width) {
+ dx = 0;
+ } else {
+ dx = x - extra_width - rect->x - rect->width;
+ }
+ if (y < rect->y - extra_width) {
+ dy = rect->y - extra_width - y;
+ } else if (y < rect->y + rect->height + extra_width) {
+ dy = 0;
+ } else {
+ dy = y - extra_width - rect->y - rect->height;
+ }
+ *near_item = item;
+ return hypot (dx, dy);
+}
+
+static void
+goc_rectangle_draw (GocItem const *item, cairo_t *cr)
+{
+ GocRectangle *rect = GOC_RECTANGLE (item);
+ cairo_pattern_t *pat = NULL;
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, rect->x, rect->y);
+ cairo_rotate (cr, rect->rotation);
+ cairo_rectangle (cr, 0., 0., rect->width, rect->height);
+ cairo_restore (cr);
+ /* Fill the shape */
+ pat = go_style_create_cairo_pattern (style, cr);
+ if (pat) {
+ cairo_set_source (cr, pat);
+ if (style->outline.dash_type != GO_LINE_NONE)
+ cairo_fill_preserve (cr);
+ else
+ cairo_fill (cr);
+ cairo_pattern_destroy (pat);
+ }
+ /* Draw the line */
+ if (go_styled_object_set_cairo_line (GO_STYLED_OBJECT (item), cr))
+ cairo_stroke (cr);
+ else
+ cairo_new_path (cr);
+}
+
+static void
+goc_rectangle_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL;
+ if (style->outline.auto_dash)
+ style->outline.dash_type = GO_LINE_SOLID;
+ if (style->outline.auto_color)
+ style->outline.color = RGBA_BLACK;
+ if (style->fill.auto_type)
+ style->fill.type = GO_STYLE_FILL_PATTERN;
+ if (style->fill.auto_fore)
+ go_pattern_set_solid (&style->fill.pattern, RGBA_WHITE);
+}
+
+static void
+goc_rectangle_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+
+ obj_klass->get_property = goc_rectangle_get_property;
+ obj_klass->set_property = goc_rectangle_set_property;
+ g_object_class_install_property (obj_klass, RECT_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The rectangle left position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, RECT_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The rectangle top position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, RECT_PROP_W,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The rectangle width"),
+ 0., G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, RECT_PROP_H,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The rectangle height"),
+ 0., G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+/* g_object_class_install_property (obj_klass, RECT_PROP_ROTATION,
+ g_param_spec_double ("rotation",
+ _("Rotation"),
+ _("The rotation around top left position"),
+ 0., 2 * M_PI, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));*/
+
+ gsi_klass->init_style = goc_rectangle_init_style;
+
+ item_klass->update_bounds = goc_rectangle_update_bounds;
+ item_klass->distance = goc_rectangle_distance;
+ item_klass->draw = goc_rectangle_draw;
+}
+
+GSF_CLASS (GocRectangle, goc_rectangle,
+ goc_rectangle_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-rectangle.h b/goffice/canvas/goc-rectangle.h
new file mode 100644
index 0000000..725ba61
--- /dev/null
+++ b/goffice/canvas/goc-rectangle.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-rectangle.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_RECTANGLE_H
+#define GOC_RECTANGLE_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_RECTANGLE (goc_rectangle_get_type ())
+#define GOC_RECTANGLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_RECTANGLE, GocRectangle))
+#define GOC_IS_RECTANGLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_RECTANGLE))
+
+GType goc_rectangle_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_RECTANGLE_H */
diff --git a/goffice/canvas/goc-structs.h b/goffice/canvas/goc-structs.h
new file mode 100644
index 0000000..0a594c0
--- /dev/null
+++ b/goffice/canvas/goc-structs.h
@@ -0,0 +1,34 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-structs.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_STRUCTS_H
+#define GOC_STRUCTS_H
+
+typedef struct {
+ double x, y;
+} GocPoint;
+
+typedef struct {
+ double x, y;
+ double width, height;
+} GocRect;
+
+#endif /* GOC_STRUCTS_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-styled-item.c b/goffice/canvas/goc-styled-item.c
new file mode 100644
index 0000000..8a7ac9e
--- /dev/null
+++ b/goffice/canvas/goc-styled-item.c
@@ -0,0 +1,219 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-styled-item.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+#include <string.h>
+
+enum {
+ STYLED_ITEM_PROP_0,
+ STYLED_ITEM_PROP_STYLE
+};
+
+enum {
+ STYLE_CHANGED,
+ LAST_SIGNAL
+};
+
+static void goc_styled_item_style_changed (GOStyledObject *obj);
+
+static gulong goc_styled_item_signals [LAST_SIGNAL] = { 0, };
+static GObjectClass *parent_klass;
+
+static void
+goc_styled_item_set_property (GObject *obj, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+ gboolean resize = FALSE;
+
+ switch (param_id) {
+
+ case STYLED_ITEM_PROP_STYLE :
+ resize = go_styled_object_set_style (GO_STYLED_OBJECT (gsi),
+ g_value_get_object (value));
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_invalidate (GOC_ITEM (obj));
+}
+
+static void
+goc_styled_item_get_property (GObject *obj, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+
+ switch (param_id) {
+ case STYLED_ITEM_PROP_STYLE :
+ g_value_set_object (value, gsi->style);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ break;
+ }
+}
+
+static void
+goc_styled_item_finalize (GObject *obj)
+{
+ GocStyledItem *gsi = GOC_STYLED_ITEM (obj);
+
+ if (gsi->style != NULL) {
+ g_object_unref (gsi->style);
+ gsi->style = NULL;
+ }
+
+ (*parent_klass->finalize) (obj);
+}
+
+static void
+goc_styled_item_parent_changed (GocItem *item)
+{
+ GocStyledItem *gsi = GOC_STYLED_ITEM (item);
+ go_styled_object_apply_theme (GO_STYLED_OBJECT (gsi), gsi->style);
+}
+
+static void
+goc_styled_item_init_style (GocStyledItem *gsi, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_OUTLINE | GO_STYLE_FILL; /* default */
+}
+
+static void
+goc_styled_item_class_init (GocItemClass *goc_klass)
+{
+ GObjectClass *gobject_klass = (GObjectClass *) goc_klass;
+ GocStyledItemClass *style_klass = (GocStyledItemClass *) goc_klass;
+
+ goc_styled_item_signals [STYLE_CHANGED] = g_signal_new ("style-changed",
+ G_TYPE_FROM_CLASS (goc_klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GocStyledItemClass, style_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE,
+ 1, G_TYPE_OBJECT);
+
+ parent_klass = g_type_class_peek_parent (goc_klass);
+
+ gobject_klass->set_property = goc_styled_item_set_property;
+ gobject_klass->get_property = goc_styled_item_get_property;
+ gobject_klass->finalize = goc_styled_item_finalize;
+ goc_klass->parent_changed = goc_styled_item_parent_changed;
+ style_klass->init_style = goc_styled_item_init_style;
+
+ g_object_class_install_property (gobject_klass, STYLED_ITEM_PROP_STYLE,
+ g_param_spec_object ("style",
+ _("Style"),
+ _("A pointer to the GOStyle object"),
+ go_style_get_type (),
+ GSF_PARAM_STATIC | G_PARAM_READWRITE | GO_PARAM_PERSISTENT));
+}
+
+static void
+goc_styled_item_init (GocStyledItem *gsi)
+{
+ gsi->style = GO_STYLE (g_object_new (go_style_get_type (), NULL)); /* use the defaults */
+}
+
+static gboolean
+goc_styled_item_set_style (GOStyledObject *gsi,
+ GOStyle *style)
+{
+ gboolean resize;
+ GocStyledItem *ggsi;
+
+ g_return_val_if_fail (GO_IS_STYLED_OBJECT (gsi), FALSE);
+ ggsi = GOC_STYLED_ITEM (gsi);
+ if (ggsi->style == style)
+ return FALSE;
+ style = go_style_dup (style);
+
+ /* which fields are we interested in for this object */
+ go_styled_object_apply_theme (gsi, style);
+ resize = go_style_is_different_size (ggsi->style, style);
+ if (ggsi->style != NULL)
+ g_object_unref (ggsi->style);
+ ggsi->style = style;
+ go_styled_object_style_changed (gsi);
+
+ return resize;
+}
+
+static GOStyle *
+goc_styled_item_get_style (GOStyledObject *gsi)
+{
+ g_return_val_if_fail (GO_IS_STYLED_OBJECT (gsi), NULL);
+ return GOC_STYLED_ITEM (gsi)->style;
+}
+
+static GOStyle *
+goc_styled_item_get_auto_style (GOStyledObject *gsi)
+{
+ GOStyle *res = go_style_dup (GOC_STYLED_ITEM (gsi)->style);
+ go_style_force_auto (res);
+ go_styled_object_apply_theme (gsi, res);
+ return res;
+}
+
+static void
+goc_styled_item_apply_theme (GOStyledObject *gsi, GOStyle *style)
+{
+ /* FIXME: do we need themes? */
+ GocStyledItemClass *klass = GOC_STYLED_ITEM_GET_CLASS (gsi);
+ (klass->init_style) (GOC_STYLED_ITEM (gsi), style);
+}
+
+static void
+goc_styled_item_style_changed (GOStyledObject *gsi)
+{
+ g_signal_emit (G_OBJECT (gsi),
+ goc_styled_item_signals [STYLE_CHANGED], 0, GOC_STYLED_ITEM (gsi)->style);
+}
+
+static GODoc*
+goc_styled_item_get_document (GOStyledObject *gsi)
+{
+ return goc_canvas_get_document (GOC_ITEM (gsi)->canvas);
+}
+
+static void
+goc_styled_item_so_init (GOStyledObjectClass *iface)
+{
+ iface->set_style = goc_styled_item_set_style;
+ iface->get_style = goc_styled_item_get_style;
+ iface->get_auto_style = goc_styled_item_get_auto_style;
+ iface->style_changed = goc_styled_item_style_changed;
+ iface->apply_theme = goc_styled_item_apply_theme;
+ iface->get_document = goc_styled_item_get_document;
+}
+
+GSF_CLASS_FULL (GocStyledItem, goc_styled_item, NULL, NULL,
+ goc_styled_item_class_init, NULL, goc_styled_item_init,
+ GOC_TYPE_ITEM, 0,
+ GSF_INTERFACE (goc_styled_item_so_init, GO_TYPE_STYLED_OBJECT))
diff --git a/goffice/canvas/goc-styled-item.h b/goffice/canvas/goc-styled-item.h
new file mode 100644
index 0000000..45d4276
--- /dev/null
+++ b/goffice/canvas/goc-styled-item.h
@@ -0,0 +1,55 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-styled-item.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_STYLED_ITEM_H
+#define GOC_STYLED_ITEM_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocStyledItem {
+ GocItem base;
+
+ GOStyle *style;
+};
+
+typedef struct {
+ GocItemClass base;
+
+ /* virtual */
+ void (*init_style) (GocStyledItem *item, GOStyle *style);
+
+ /* signal */
+ void (*style_changed) (GocStyledItem *item, GOStyle const *new_style);
+} GocStyledItemClass;
+
+#define GOC_TYPE_STYLED_ITEM (goc_styled_item_get_type ())
+#define GOC_STYLED_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_STYLED_ITEM, GocStyledItem))
+#define GOC_IS_STYLED_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_STYLED_ITEM))
+#define GOC_STYLED_ITEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GOC_TYPE_STYLED_ITEM, GocStyledItemClass))
+
+GType goc_styled_item_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_STYLED_ITEM_H */
diff --git a/goffice/canvas/goc-text.c b/goffice/canvas/goc-text.c
new file mode 100644
index 0000000..ef61e1d
--- /dev/null
+++ b/goffice/canvas/goc-text.c
@@ -0,0 +1,370 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-text.c:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+#include <gsf/gsf-impl-utils.h>
+#include <glib/gi18n-lib.h>
+
+enum {
+ TEXT_PROP_0,
+ TEXT_PROP_X,
+ TEXT_PROP_Y,
+ TEXT_PROP_ROTATION,
+ TEXT_PROP_ANCHOR,
+ TEXT_PROP_TEXT,
+ TEXT_PROP_ATTRIBUTES
+};
+
+struct _GocText {
+ GocStyledItem base;
+
+ double rotation; /* rotation around the center in radians */
+ double x, y, w, h;
+ char *text;
+ GtkAnchorType anchor;
+ PangoAttrList *attributes;
+ PangoLayout *layout;
+};
+
+typedef GocStyledItemClass GocTextClass;
+static GocItemClass *parent_class;
+
+static void
+goc_text_set_property (GObject *gobject, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocText *text = GOC_TEXT (gobject);
+
+ switch (param_id) {
+ case TEXT_PROP_X:
+ text->x = g_value_get_double (value);
+ break;
+
+ case TEXT_PROP_Y:
+ text->y = g_value_get_double (value);
+ break;
+
+ case TEXT_PROP_ROTATION:
+ text->rotation = g_value_get_double (value);
+ break;
+
+ case TEXT_PROP_ANCHOR:
+ text->anchor = (GtkAnchorType) g_value_get_enum (value);
+ break;
+
+ case TEXT_PROP_TEXT:
+ g_free (text->text);
+ text->text = g_value_dup_string (value);
+ if (text->layout)
+ pango_layout_set_text (text->layout, text->text, -1);
+ break;
+
+ case TEXT_PROP_ATTRIBUTES: {
+ PangoAttrList *attrs = (PangoAttrList *) g_value_get_boxed (value);
+ if (text->attributes)
+ pango_attr_list_unref (text->attributes);
+ text->attributes = (attrs)? pango_attr_list_copy (attrs): pango_attr_list_new ();
+ if (text->layout)
+ pango_layout_set_attributes (text->layout, text->attributes);
+ break;
+ }
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ goc_item_bounds_changed (GOC_ITEM (gobject));
+
+}
+
+static void
+goc_text_get_property (GObject *gobject, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocText *text = GOC_TEXT (gobject);
+
+ switch (param_id) {
+ case TEXT_PROP_X:
+ g_value_set_double (value, text->x);
+ break;
+
+ case TEXT_PROP_Y:
+ g_value_set_double (value, text->y);
+ break;
+
+ case TEXT_PROP_ROTATION:
+ g_value_set_double (value, text->rotation);
+ break;
+
+ case TEXT_PROP_ANCHOR:
+ g_value_set_enum (value, text->anchor);
+ break;
+
+ case TEXT_PROP_TEXT:
+ if (text->text)
+ g_value_set_string (value, text->text);
+ break;
+
+ case TEXT_PROP_ATTRIBUTES:
+ if (text->attributes)
+ g_value_set_boxed (value, text->attributes);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static void
+goc_text_realize (GocItem *item)
+{
+ GocText *text = GOC_TEXT (item);
+
+ if (parent_class->realize)
+ (*parent_class->realize) (item);
+
+ text->layout = pango_layout_new (gtk_widget_get_pango_context (GTK_WIDGET (item->canvas)));
+ pango_layout_set_text (text->layout, text->text, -1);
+ if (text->attributes)
+ pango_layout_set_attributes (text->layout, text->attributes);
+ goc_item_bounds_changed (item);
+}
+
+static void
+goc_text_unrealize (GocItem *item)
+{
+ GocText *text = GOC_TEXT (item);
+
+ if (text->layout)
+ g_object_unref (text->layout);
+ text->layout = NULL;
+
+ if (parent_class->unrealize)
+ (*parent_class->unrealize) (item);
+}
+
+static void
+goc_text_finalize (GObject *gobject)
+{
+ GocText *text = GOC_TEXT (gobject);
+
+ g_free (text->text);
+ if (text->attributes)
+ pango_attr_list_unref (text->attributes);
+ ((GObjectClass *) parent_class)->finalize (gobject);
+}
+
+static void
+goc_text_update_bounds (GocItem *item)
+{
+ GocText *text = GOC_TEXT (item);
+ PangoRectangle rect;
+ if (!text->layout)
+ return;
+ pango_layout_get_extents (text->layout, NULL, &rect);
+ text->w = (double) rect.width / PANGO_SCALE;
+ text->h = (double) rect.height / PANGO_SCALE;
+ item->x0 = text->x;
+ item->y0 = text->y;
+ /* adjust horizontally */
+ switch (text->anchor) {
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_NORTH:
+ case GTK_ANCHOR_SOUTH:
+ item->x0 -= text->w / 2.;
+ break;
+ case GTK_ANCHOR_NORTH_WEST:
+ case GTK_ANCHOR_SOUTH_WEST:
+ case GTK_ANCHOR_WEST:
+ break;
+ case GTK_ANCHOR_NORTH_EAST:
+ case GTK_ANCHOR_SOUTH_EAST:
+ case GTK_ANCHOR_EAST:
+ item->x0 -= text->w;
+ break;
+ default: /* should not occur */
+ break;
+ }
+ /* adjust vertically */
+ switch (text->anchor) {
+ case GTK_ANCHOR_NORTH:
+ case GTK_ANCHOR_NORTH_WEST:
+ case GTK_ANCHOR_NORTH_EAST:
+ break;
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_WEST:
+ case GTK_ANCHOR_EAST:
+ item->y0 -= text->h / 2.;
+ break;
+ case GTK_ANCHOR_SOUTH:
+ case GTK_ANCHOR_SOUTH_WEST:
+ case GTK_ANCHOR_SOUTH_EAST:
+ item->y0 -= text->h;
+ break;
+ default: /* should not occur */
+ break;
+ }
+ item->x1 = item->x0 + text->w;
+ item->y1 = item->y0 + text->h;
+ /* FIXME: take rotation into account */
+}
+
+static double
+goc_text_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ /* FIXME: take rotation into account */
+ double dx, dy;
+ if (x < item->x0)
+ dx = item->x0 - x;
+ else if (x > item->x1)
+ dx = item->x1 - x;
+ else
+ dx = 0.;
+ if (y < item->y0)
+ dy = item->y0 - y;
+ else if (y > item->y1)
+ dy = item->y1 - y;
+ else
+ dy = 0.;
+ *near_item = item;
+ return hypot (dx, dy);
+}
+
+static void
+goc_text_draw (GocItem const *item, cairo_t *cr)
+{
+ GocText *text = GOC_TEXT (item);
+ double x = text->x, y = text->y;
+ PangoLayout *pl = pango_cairo_create_layout (cr);
+ pango_layout_set_text (pl, text->text, -1);
+ if (text->attributes)
+ pango_layout_set_attributes (pl, text->attributes);
+ /* FIXME: take rotation into account */
+ /* adjust horizontally */
+ switch (text->anchor) {
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_NORTH:
+ case GTK_ANCHOR_SOUTH:
+ x -= text->w / 2.;
+ break;
+ case GTK_ANCHOR_NORTH_WEST:
+ case GTK_ANCHOR_SOUTH_WEST:
+ case GTK_ANCHOR_WEST:
+ break;
+ case GTK_ANCHOR_NORTH_EAST:
+ case GTK_ANCHOR_SOUTH_EAST:
+ case GTK_ANCHOR_EAST:
+ x -= text->w;
+ break;
+ default: /* should not occur */
+ break;
+ }
+ /* adjust vertically */
+ switch (text->anchor) {
+ case GTK_ANCHOR_NORTH:
+ case GTK_ANCHOR_NORTH_WEST:
+ case GTK_ANCHOR_NORTH_EAST:
+ break;
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_WEST:
+ case GTK_ANCHOR_EAST:
+ y -= text->h / 2.;
+ break;
+ case GTK_ANCHOR_SOUTH:
+ case GTK_ANCHOR_SOUTH_WEST:
+ case GTK_ANCHOR_SOUTH_EAST:
+ y -= text->h;
+ break;
+ default: /* should not occur */
+ break;
+ }
+ cairo_save (cr);
+ goc_group_cairo_transform (item->parent, cr, x, y);
+ cairo_move_to (cr, 0., 0.);
+ pango_cairo_show_layout (cr, pl);
+ cairo_restore (cr);
+ g_object_unref (pl);
+}
+
+static void
+goc_text_init_style (G_GNUC_UNUSED GocStyledItem *item, GOStyle *style)
+{
+ style->interesting_fields = GO_STYLE_FONT;
+ /* we might add more to display some extra decoration
+ without using a separate rectangle item */
+}
+
+static void
+goc_text_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+ GocStyledItemClass *gsi_klass = (GocStyledItemClass *) item_klass;
+ parent_class = g_type_class_peek_parent (item_klass);
+
+ obj_klass->finalize = goc_text_finalize;
+ obj_klass->get_property = goc_text_get_property;
+ obj_klass->set_property = goc_text_set_property;
+ g_object_class_install_property (obj_klass, TEXT_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The text horizontal position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, TEXT_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The text position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, TEXT_PROP_ROTATION,
+ g_param_spec_double ("rotation",
+ _("Rotation"),
+ _("The rotation around the anchor"),
+ 0., 2 * M_PI, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, TEXT_PROP_ANCHOR,
+ g_param_spec_enum ("anchor",
+ _("Anchor"),
+ _("The anchor point for the text"),
+ GTK_TYPE_ANCHOR_TYPE, GTK_ANCHOR_CENTER,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, TEXT_PROP_TEXT,
+ g_param_spec_string ("text",
+ _("Text"),
+ _("The text to display"), NULL,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, TEXT_PROP_ATTRIBUTES,
+ g_param_spec_boxed ("attributes", _("Attributes"), _("The attributes list as a PangoAttrList"),
+ PANGO_TYPE_ATTR_LIST,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ gsi_klass->init_style = goc_text_init_style;
+
+ item_klass->update_bounds = goc_text_update_bounds;
+ item_klass->distance = goc_text_distance;
+ item_klass->draw = goc_text_draw;
+ item_klass->realize = goc_text_realize;
+ item_klass->unrealize = goc_text_unrealize;
+}
+
+GSF_CLASS (GocText, goc_text,
+ goc_text_class_init, NULL,
+ GOC_TYPE_STYLED_ITEM)
diff --git a/goffice/canvas/goc-text.h b/goffice/canvas/goc-text.h
new file mode 100644
index 0000000..7822b71
--- /dev/null
+++ b/goffice/canvas/goc-text.h
@@ -0,0 +1,38 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-text.h:
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_TEXT_H
+#define GOC_TEXT_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_TEXT (goc_text_get_type ())
+#define GOC_TEXT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_TEXT, GocText))
+#define GOC_IS_TEXT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_TEXT))
+
+GType goc_text_get_type (void);
+
+G_END_DECLS
+
+#endif /* GOC_TEXT_H */
diff --git a/goffice/canvas/goc-utils.c b/goffice/canvas/goc-utils.c
new file mode 100644
index 0000000..8f12c5b
--- /dev/null
+++ b/goffice/canvas/goc-utils.c
@@ -0,0 +1,65 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-utils.c :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/canvas/goc-utils.h>
+
+GocPoints *
+goc_points_new (unsigned n)
+{
+ GocPoints *points = g_new (GocPoints, 1);
+ points->n = n;
+ points->refs = 1;
+ points->points = g_new0 (GocPoint, n);
+ return points;
+}
+
+GocPoints *
+goc_points_ref (GocPoints *points)
+{
+ points->refs++;
+ return points;
+}
+
+void
+goc_points_unref (GocPoints *points)
+{
+ points->refs--;
+ if (points->refs == 0) {
+ g_free (points->points);
+ points->points = NULL;
+ g_free (points);
+ }
+}
+
+GType
+goc_points_get_type (void)
+{
+ static GType type_points = 0;
+
+ if (!type_points)
+ type_points = g_boxed_type_register_static
+ ("GocPoints",
+ (GBoxedCopyFunc) goc_points_ref,
+ (GBoxedFreeFunc) goc_points_unref);
+
+ return type_points;
+}
diff --git a/goffice/canvas/goc-utils.h b/goffice/canvas/goc-utils.h
new file mode 100644
index 0000000..3281767
--- /dev/null
+++ b/goffice/canvas/goc-utils.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-utils.h :
+ *
+ * Copyright (C) 2008 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_UTILS_H
+#define GOC_UTILS_H
+
+#include <goffice/goffice.h>
+
+typedef struct {
+ unsigned n;
+ unsigned refs;
+ GocPoint *points;
+} GocPoints;
+
+GType goc_points_get_type (void);
+#define GOC_TYPE_POINTS goc_points_get_type ()
+
+GocPoints *goc_points_new (unsigned n);
+GocPoints *goc_points_ref (GocPoints *points);
+void goc_points_unref (GocPoints *points);
+
+#endif /* GOC_UTILS_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-widget-impl.h b/goffice/canvas/goc-widget-impl.h
new file mode 100644
index 0000000..66a05e9
--- /dev/null
+++ b/goffice/canvas/goc-widget-impl.h
@@ -0,0 +1,40 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget-impl.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_WIDGET_IMPL_H
+#define GOC_WIDGET_IMPL_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+struct _GocWidget {
+ GocItem base;
+
+ double x, y, w, h;
+ GtkWidget *widget;
+};
+
+typedef GocItemClass GocWidgetClass;
+
+G_END_DECLS
+
+#endif /* GOC_WIDGET_IMPL_H */
\ No newline at end of file
diff --git a/goffice/canvas/goc-widget.c b/goffice/canvas/goc-widget.c
new file mode 100644
index 0000000..7c1da33
--- /dev/null
+++ b/goffice/canvas/goc-widget.c
@@ -0,0 +1,258 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget.c :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#include <goffice/goffice-config.h>
+#include <goffice/goffice.h>
+
+#include <glib/gi18n-lib.h>
+#include <gsf/gsf-impl-utils.h>
+
+#include <math.h>
+
+enum {
+ WIDGET_PROP_0,
+ WIDGET_PROP_WIDGET,
+ WIDGET_PROP_X,
+ WIDGET_PROP_Y,
+ WIDGET_PROP_W,
+ WIDGET_PROP_H
+};
+
+static void
+goc_widget_notify_scrolled (GocItem *item)
+{
+ GocGroup const *parent;
+ double x0, y0, x1, y1;
+ GocWidget *widget = GOC_WIDGET (item);
+
+ parent = item->parent;
+ if (!item->cached_bounds)
+ goc_item_update_bounds (GOC_ITEM (item)); /* don't care about const */
+ x0 = item->x0;
+ y0 = item->y0;
+ x1 = item->x1;
+ y1 = item->y1;
+ while (parent) {
+ goc_group_adjust_bounds (parent, &x0, &y0, &x1, &y1);
+ parent = parent->base.parent;
+ }
+ x0 = (x0 - item->canvas->scroll_x1) * item->canvas->pixels_per_unit;
+ y0 = (y0 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
+ x1 = (x1 - item->canvas->scroll_x1) * item->canvas->pixels_per_unit;
+ y1 = (y1 - item->canvas->scroll_y1) * item->canvas->pixels_per_unit;
+ gtk_widget_set_size_request (widget->widget, x1 - x0, y1 - y0);
+ /* ensure we don't wrap throught he infinite */
+ if (x0 < G_MININT)
+ x0 = G_MININT;
+ else if (x1 > G_MAXINT)
+ x0 -= x1 - G_MAXINT;
+ if (y0 < G_MININT)
+ y0 = G_MININT;
+ else if (y1 > G_MAXINT)
+ y0 -= y1 - G_MAXINT;
+ gtk_layout_move (GTK_LAYOUT (item->canvas), widget->widget, x0, y0);
+}
+
+static void
+goc_widget_set_property (GObject *obj, guint param_id,
+ GValue const *value, GParamSpec *pspec)
+{
+ GocWidget *item = GOC_WIDGET (obj);
+
+ switch (param_id) {
+ case WIDGET_PROP_WIDGET: {
+ GtkWidget *widget = GTK_WIDGET (g_value_get_object (value));
+ if (widget == item->widget)
+ return;
+ if (item->widget) {
+ gtk_widget_destroy (item->widget);
+ }
+ item->widget = widget;
+ gtk_widget_show (widget);
+ gtk_layout_put (GTK_LAYOUT (GOC_ITEM (item)->canvas), widget, item->x, item->y);
+ goc_widget_notify_scrolled (GOC_ITEM (item));
+ return;
+ }
+ case WIDGET_PROP_X:
+ item->x = g_value_get_double (value);
+ break;
+
+ case WIDGET_PROP_Y:
+ item->y = g_value_get_double (value);
+ break;
+
+ case WIDGET_PROP_W:
+ item->w = g_value_get_double (value);
+ break;
+
+ case WIDGET_PROP_H:
+ item->h = g_value_get_double (value);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+ if (item->widget) {
+ goc_item_bounds_changed (GOC_ITEM (item));
+ goc_widget_notify_scrolled (GOC_ITEM (item));
+ }
+
+}
+
+static void
+goc_widget_get_property (GObject *obj, guint param_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GocWidget *item = GOC_WIDGET (obj);
+
+ switch (param_id) {
+ case WIDGET_PROP_WIDGET:
+ g_value_set_object (value, item->widget);
+ case WIDGET_PROP_X:
+ g_value_set_double (value, item->x);
+ break;
+
+ case WIDGET_PROP_Y:
+ g_value_set_double (value, item->y);
+ break;
+
+ case WIDGET_PROP_W:
+ g_value_set_double (value, item->w);
+ break;
+
+ case WIDGET_PROP_H:
+ g_value_set_double (value, item->h);
+ break;
+
+ default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
+ return; /* NOTE : RETURN */
+ }
+}
+
+static double
+goc_widget_distance (GocItem *item, double x, double y, GocItem **near_item)
+{
+ GocWidget *widget = GOC_WIDGET (item);
+ double dx, dy;
+ if (x < widget->x) {
+ dx = widget->x - x;
+ } else if (x < widget->x + widget->w) {
+ dx = 0;
+ } else {
+ dx = x - widget->x - widget->w;
+ }
+ if (y < widget->y) {
+ dy = widget->y - y;
+ } else if (x < widget->y + widget->h) {
+ dy = 0;
+ } else {
+ dy = y - widget->y - widget->h;
+ }
+ *near_item = item;
+ return hypot (dx, dy);
+}
+
+static void
+goc_widget_draw (GocItem const *item, cairo_t *cr)
+{
+ GocWidget *widget = GOC_WIDGET (item);
+ if (item->canvas->cur_event == NULL)
+ return; /* we do not draw for off-screen rendering, at least until this is implemented in gtk+ */
+ gtk_container_propagate_expose (GTK_CONTAINER (item->canvas),
+ widget->widget,
+ (GdkEventExpose *) goc_canvas_get_cur_event (item->canvas));
+}
+
+static void
+goc_widget_update_bounds (GocItem *item)
+{
+ GocWidget *widget = GOC_WIDGET (item);
+ item->x0 = widget->x;
+ item->y0 = widget->y;
+ item->x1 = widget->x + widget->w;
+ item->y1 = widget->y + widget->h;
+}
+
+static void
+goc_widget_class_init (GocItemClass *item_klass)
+{
+ GObjectClass *obj_klass = (GObjectClass *) item_klass;
+
+ obj_klass->get_property = goc_widget_get_property;
+ obj_klass->set_property = goc_widget_set_property;
+
+ g_object_class_install_property (obj_klass, WIDGET_PROP_WIDGET,
+ g_param_spec_object ("widget",
+ _("Widget"),
+ _("A pointer to the embedded widget"),
+ GTK_TYPE_WIDGET,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, WIDGET_PROP_X,
+ g_param_spec_double ("x",
+ _("x"),
+ _("The widget left position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, WIDGET_PROP_Y,
+ g_param_spec_double ("y",
+ _("y"),
+ _("The widget top position"),
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ /* Setting max size to 2048 which should be enough for all uses */
+ g_object_class_install_property (obj_klass, WIDGET_PROP_W,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The widget width"),
+ 0., 2048., 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+ g_object_class_install_property (obj_klass, WIDGET_PROP_H,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The widget height"),
+ 0., 2048., 0.,
+ GSF_PARAM_STATIC | G_PARAM_READWRITE));
+
+ item_klass->distance = goc_widget_distance;
+ item_klass->draw = goc_widget_draw;
+ item_klass->update_bounds = goc_widget_update_bounds;
+ item_klass->notify_scrolled = goc_widget_notify_scrolled;
+}
+
+GSF_CLASS (GocWidget, goc_widget,
+ goc_widget_class_init, NULL,
+ GOC_TYPE_ITEM)
+
+void
+goc_widget_set_bounds (GocWidget *widget, double left, double top, double width, double height)
+{
+ GocItem *item = GOC_ITEM (widget);
+ goc_item_invalidate (item);
+ widget->x = left;
+ widget->y = top;
+ widget->w = width;
+ widget->h = height;
+ goc_item_bounds_changed (item);
+ if (widget->widget)
+ goc_widget_notify_scrolled (item);
+ goc_item_invalidate (item);
+}
+
diff --git a/goffice/canvas/goc-widget.h b/goffice/canvas/goc-widget.h
new file mode 100644
index 0000000..ddaefd9
--- /dev/null
+++ b/goffice/canvas/goc-widget.h
@@ -0,0 +1,39 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goc-widget.h :
+ *
+ * Copyright (C) 2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOC_WIDGET_H
+#define GOC_WIDGET_H
+
+#include <goffice/goffice.h>
+
+G_BEGIN_DECLS
+
+#define GOC_TYPE_WIDGET (goc_widget_get_type ())
+#define GOC_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GOC_TYPE_WIDGET, GocWidget))
+#define GOC_IS_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GOC_TYPE_WIDGET))
+
+GType goc_widget_get_type (void);
+
+void goc_widget_set_bounds (GocWidget *widget, double left, double top, double width, double height);
+
+G_END_DECLS
+
+#endif /* GOC_WIDGET_H */
diff --git a/goffice/canvas/goffice-canvas.h b/goffice/canvas/goffice-canvas.h
new file mode 100644
index 0000000..3052bfb
--- /dev/null
+++ b/goffice/canvas/goffice-canvas.h
@@ -0,0 +1,73 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goffice-canvas.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOFFICE_CANVAS_H
+#define GOFFICE_CANVAS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GocCanvas GocCanvas;
+typedef struct _GocItem GocItem;
+typedef struct _GocGroup GocGroup;
+typedef struct _GocLine GocLine;
+typedef struct _GocPixbuf GocPixbuf;
+typedef struct _GocPolygon GocPolygon;
+typedef struct _GocRectangle GocRectangle;
+typedef struct _GocCircle GocCircle;
+typedef struct _GocEllipse GocEllipse;
+typedef struct _GocStyledItem GocStyledItem;
+typedef struct _GocText GocText;
+typedef struct _GocWidget GocWidget;
+typedef struct _GocGraph GocGraph;
+
+G_END_DECLS
+
+#include <goffice/goffice.h>
+
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-canvas-impl.h>
+#include <goffice/canvas/goc-item-impl.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-styled-item.h>
+#include <goffice/canvas/goc-structs.h>
+#include <goffice/canvas/goc-utils.h>
+
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-circle-impl.h>
+#include <goffice/canvas/goc-ellipse.h>
+#include <goffice/canvas/goc-graph.h>
+#include <goffice/canvas/goc-group.h>
+#include <goffice/canvas/goc-group-impl.h>
+#include <goffice/canvas/goc-line.h>
+#include <goffice/canvas/goc-pixbuf.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-polygon-impl.h>
+#include <goffice/canvas/goc-rectangle.h>
+#include <goffice/canvas/goc-rectangle-impl.h>
+#include <goffice/canvas/goc-text.h>
+#include <goffice/canvas/goc-widget.h>
+#include <goffice/canvas/goc-widget-impl.h>
+
+#endif /* GOFFICE_CANVAS_H */
diff --git a/goffice/canvas/goffice-canvas.h~ b/goffice/canvas/goffice-canvas.h~
new file mode 100644
index 0000000..207e40f
--- /dev/null
+++ b/goffice/canvas/goffice-canvas.h~
@@ -0,0 +1,75 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * goffice-canvas.h :
+ *
+ * Copyright (C) 2008-2009 Jean Brefort (jean brefort normalesup org)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+#ifndef GOFFICE_CANVAS_H
+#define GOFFICE_CANVAS_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GocCanvas GocCanvas;
+typedef struct _GocItem GocItem;
+typedef struct _GocGroup GocGroup;
+typedef struct _GocLine GocLine;
+typedef struct _GocPixbuf GocPixbuf;
+typedef struct _GocPolygon GocPolygon;
+typedef struct _GocRectangle GocRectangle;
+typedef struct _GocCircle GocCircle;
+typedef struct _GocEllipse GocEllipse;
+typedef struct _GocStyledItem GocStyledItem;
+typedef struct _GocText GocText;
+typedef struct _GocWidget GocWidget;
+typedef struct _GocGraph GocGraph;
+
+G_END_DECLS
+
+#include <goffice/goffice.h>
+
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-canvas-impl.h>
+#include <goffice/canvas/goc-item-impl.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-styled-item.h>
+#include <goffice/canvas/goc-structs.h>
+#include <goffice/canvas/goc-utils.h>
+
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-circle-impl.h>
+#include <goffice/canvas/goc-component.h>
+#include <goffice/canvas/goc-ellipse.h>
+#include <goffice/canvas/goc-graph.h>
+#include <goffice/canvas/goc-group.h>
+#include <goffice/canvas/goc-group-impl.h>
+#include <goffice/canvas/goc-line.h>
+#include <goffice/canvas/goc-pixbuf.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-polygon-impl.h>
+#include <goffice/canvas/goc-polyline.h>
+#include <goffice/canvas/goc-rectangle.h>
+#include <goffice/canvas/goc-rectangle-impl.h>
+#include <goffice/canvas/goc-text.h>
+#include <goffice/canvas/goc-widget.h>
+#include <goffice/canvas/goc-widget-impl.h>
+
+#endif /* GOFFICE_CANVAS_H */
diff --git a/goffice/goffice.h b/goffice/goffice.h
index 848e37c..7e23670 100644
--- a/goffice/goffice.h
+++ b/goffice/goffice.h
@@ -48,6 +48,7 @@
#include <goffice/math/goffice-math.h>
#ifdef GOFFICE_WITH_GTK
#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/canvas/goffice-canvas.h>
#endif
#include <goffice/graph/goffice-graph.h>
diff --git a/goffice/graph/gog-guru.c b/goffice/graph/gog-guru.c
index 21233f9..713ea43 100644
--- a/goffice/graph/gog-guru.c
+++ b/goffice/graph/gog-guru.c
@@ -23,28 +23,11 @@
#include <goffice/goffice-config.h>
#include <goffice/goffice-priv.h>
-#include <goffice/app/go-doc-control.h>
-#include <goffice/graph/gog-guru.h>
-#include <goffice/graph/gog-object.h>
-#include <goffice/graph/gog-graph.h>
-#include <goffice/graph/gog-object.h>
-#include <goffice/graph/gog-chart.h>
-#include <goffice/graph/gog-plot.h>
-#include <goffice/graph/gog-trend-line.h>
-#include <goffice/graph/gog-view.h>
-#include <goffice/graph/gog-plot-engine.h>
-#include <goffice/graph/gog-data-allocator.h>
-#include <goffice/graph/gog-control-foocanvas.h>
-#include <goffice/graph/gog-child-button.h>
-#include <goffice/gtk/go-pixbuf.h>
-#include <goffice/gtk/goffice-gtk.h>
+#include <goffice/goffice.h>
#include <glib/gi18n-lib.h>
#include <libxml/parser.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-pixbuf.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>
#include <string.h>
@@ -72,9 +55,9 @@ struct _GraphGuruState {
GtkNotebook *steps;
GtkWidget *delete_button;
- FooCanvasItem *sample_graph_item;
- FooCanvasItem *sample_graph_frame;
- FooCanvasItem *sample_graph_shadow;
+ GocItem *sample_graph_item;
+ GocItem *sample_graph_frame;
+ GocItem *sample_graph_shadow;
GtkContainer *prop_container;
GtkTreeSelection *prop_selection;
@@ -109,19 +92,19 @@ struct _GraphGuruTypeSelector {
GtkLabel *label;
GtkTreeView *list_view;
GtkListStore *model;
- FooCanvasItem *selector;
+ GocItem *selector;
- FooCanvasItem *sample_graph_item;
+ GocItem *sample_graph_item;
GraphGuruState *state;
- FooCanvasGroup *graph_group;
+ GocGroup *graph_group;
xmlNode const *plots;
GogPlotFamily *current_family;
GogPlotType *current_type;
- FooCanvasGroup const *current_family_item;
- FooCanvasItem const *current_minor_item;
+ GocGroup const *current_family_item;
+ GocItem const *current_minor_item;
int max_priority_so_far;
};
@@ -165,7 +148,7 @@ get_pos (int col, int row, double *x, double *y)
* Assumes that the item is visible
*/
static void
-graph_typeselect_minor (GraphGuruTypeSelector *typesel, FooCanvasItem *item)
+graph_typeselect_minor (GraphGuruTypeSelector *typesel, GocItem *item)
{
GraphGuruState *s = typesel->state;
GogPlotType *type;
@@ -182,10 +165,10 @@ graph_typeselect_minor (GraphGuruTypeSelector *typesel, FooCanvasItem *item)
typesel->current_type = type;
typesel->current_minor_item = item;
- foo_canvas_item_get_bounds (item, &x1, &y1, &x2, &y2);
- foo_canvas_item_set (FOO_CANVAS_ITEM (typesel->selector),
- "x1", x1-1., "y1", y1-1.,
- "x2", x2+1., "y2", y2+1.,
+ goc_item_get_bounds (item, &x1, &y1, &x2, &y2);
+ goc_item_set (GOC_ITEM (typesel->selector),
+ "x", x1-1., "y", y1-1.,
+ "width", x2-x1+2., "height", y2-y1+2.,
NULL);
gtk_label_set_text (typesel->label, _(type->description));
gtk_widget_set_sensitive (typesel->sample_button, TRUE);
@@ -219,13 +202,13 @@ static gboolean
graph_typeselect_minor_x_y (GraphGuruTypeSelector *typesel,
double x, double y)
{
- FooCanvasItem *item = foo_canvas_get_item_at (
- FOO_CANVAS (typesel->canvas), x, y);
+ GocItem *item = goc_canvas_get_item_at (
+ GOC_CANVAS (typesel->canvas), x, y);
if (item != NULL) {
if(item != typesel->selector)
graph_typeselect_minor (typesel, item);
- foo_canvas_item_grab_focus (item);
+ // goc_item_grab (item);
return TRUE;
}
@@ -283,14 +266,8 @@ static gint
cb_button_press_event (GtkWidget *widget, GdkEventButton *event,
GraphGuruTypeSelector *typesel)
{
- if (event->button == 1) {
- FooCanvas *c = FOO_CANVAS (widget);
- double x, y;
-
- foo_canvas_window_to_world (c, event->x, event->y, &x, &y);
-
- graph_typeselect_minor_x_y (typesel, x, y);
- }
+ if (event->button == 1)
+ graph_typeselect_minor_x_y (typesel, event->x, event->y);
return FALSE;
}
@@ -300,35 +277,35 @@ cb_selection_changed (GraphGuruTypeSelector *typesel)
{
GtkTreeSelection *selection = gtk_tree_view_get_selection (typesel->list_view);
GtkTreeIter iter;
- FooCanvasItem *item;
- FooCanvasGroup *group;
+ GocItem *item;
+ GocGroup *group;
if (typesel->current_family_item != NULL)
- foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->current_family_item));
+ goc_item_hide (GOC_ITEM (typesel->current_family_item));
if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
return;
gtk_tree_model_get (GTK_TREE_MODEL (typesel->model), &iter,
PLOT_FAMILY_TYPE_CANVAS_GROUP, &group,
-1);
- foo_canvas_item_show (FOO_CANVAS_ITEM (group));
+ goc_item_show (GOC_ITEM (group));
typesel->current_family_item = group;
- foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->selector));
+ goc_item_hide (GOC_ITEM (typesel->selector));
item = g_object_get_data (G_OBJECT (group), FIRST_MINOR_TYPE);
if (item != NULL)
graph_typeselect_minor (typesel, item);
- foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->selector));
+ goc_item_show (GOC_ITEM (typesel->selector));
}
static void
-cb_typesel_sample_plot_resize (FooCanvas *canvas,
+cb_typesel_sample_plot_resize (GocCanvas *canvas,
GtkAllocation *alloc, GraphGuruTypeSelector *typesel)
{
if (typesel->sample_graph_item != NULL)
- foo_canvas_item_set (typesel->sample_graph_item,
- "w", (double)alloc->width,
- "h", (double)alloc->height,
+ goc_item_set (typesel->sample_graph_item,
+ "width", (double)alloc->width,
+ "height", (double)alloc->height,
NULL);
}
@@ -340,19 +317,19 @@ cb_sample_pressed (GraphGuruTypeSelector *typesel)
if (typesel->sample_graph_item == NULL) {
GtkAllocation *size = >K_WIDGET (typesel->canvas)->allocation;
- typesel->sample_graph_item = foo_canvas_item_new (typesel->graph_group,
- GOG_TYPE_CONTROL_FOOCANVAS,
- "model", typesel->state->graph,
+ typesel->sample_graph_item = goc_item_new (typesel->graph_group,
+ GOC_TYPE_GRAPH,
+ "graph", typesel->state->graph,
NULL);
- cb_typesel_sample_plot_resize (FOO_CANVAS (typesel->canvas),
+ cb_typesel_sample_plot_resize (GOC_CANVAS (typesel->canvas),
size, typesel);
g_return_if_fail (typesel->sample_graph_item != NULL);
}
- foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->current_family_item));
- foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->selector));
- foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->graph_group));
+ goc_item_hide (GOC_ITEM (typesel->current_family_item));
+ goc_item_hide (GOC_ITEM (typesel->selector));
+ goc_item_show (GOC_ITEM (typesel->graph_group));
}
static void
@@ -361,15 +338,15 @@ cb_sample_released (GraphGuruTypeSelector *typesel)
if (typesel->current_family_item == NULL)
return;
- foo_canvas_item_hide (FOO_CANVAS_ITEM (typesel->graph_group));
- foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->current_family_item));
- foo_canvas_item_show (FOO_CANVAS_ITEM (typesel->selector));
+ goc_item_hide (GOC_ITEM (typesel->graph_group));
+ goc_item_show (GOC_ITEM (typesel->current_family_item));
+ goc_item_show (GOC_ITEM (typesel->selector));
}
typedef struct {
GraphGuruTypeSelector *typesel;
- FooCanvasGroup *group;
- FooCanvasItem *current_item;
+ GocGroup *group;
+ GocItem *current_item;
GogPlotType *current_type;
int col, row;
} type_list_closure;
@@ -379,7 +356,7 @@ cb_plot_types_init (char const *id, GogPlotType *type,
type_list_closure *closure)
{
double x1, y1, w, h;
- FooCanvasItem *item;
+ GocItem *item;
int col, row;
GdkPixbuf *image = go_pixbuf_get_from_cache (type->sample_image_file);
@@ -395,12 +372,11 @@ cb_plot_types_init (char const *id, GogPlotType *type,
if (h > MINOR_PIXMAP_HEIGHT)
h = MINOR_PIXMAP_HEIGHT;
- item = foo_canvas_item_new (closure->group,
- foo_canvas_pixbuf_get_type (),
+ item = goc_item_new (closure->group,
+ goc_pixbuf_get_type (),
"x", x1, "y", y1,
"width", w, "height", h,
"pixbuf", image,
- "point_ignores_alpha", TRUE,
NULL);
g_object_set_data (G_OBJECT (item), PLOT_TYPE_KEY, (gpointer)type);
@@ -418,7 +394,7 @@ static void
cb_plot_families_init (char const *id, GogPlotFamily *family,
GraphGuruTypeSelector *typesel)
{
- FooCanvasGroup *group;
+ GocGroup *group;
GtkTreeIter iter;
type_list_closure closure;
@@ -426,13 +402,13 @@ cb_plot_families_init (char const *id, GogPlotFamily *family,
return;
/* Define a canvas group for all the minor types */
- group = FOO_CANVAS_GROUP (foo_canvas_item_new (
- foo_canvas_root (FOO_CANVAS (typesel->canvas)),
- foo_canvas_group_get_type (),
+ group = GOC_GROUP (goc_item_new (
+ goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+ goc_group_get_type (),
"x", 0.0,
"y", 0.0,
NULL));
- foo_canvas_item_hide (FOO_CANVAS_ITEM (group));
+ goc_item_hide (GOC_ITEM (group));
gtk_list_store_append (typesel->model, &iter);
gtk_list_store_set (typesel->model, &iter,
@@ -786,7 +762,7 @@ populate_graph_item_list (GogObject *obj, GogObject *select, GraphGuruState *s,
}
static gint
-cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
+cb_canvas_select_item (GocCanvas *canvas, GdkEvent *event,
GraphGuruState *s)
{
double item_x, item_y;
@@ -797,7 +773,7 @@ cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
case GDK_MOTION_NOTIFY:
case GDK_BUTTON_RELEASE:
- g_return_val_if_fail (FOO_IS_CANVAS (canvas), FALSE);
+ g_return_val_if_fail (GOC_IS_CANVAS (canvas), FALSE);
g_object_get (G_OBJECT(s->sample_graph_item), "x", &item_x, "y", &item_y, NULL);
gog_graph_view_handle_event (s->graph_view, (GdkEvent *) event,
@@ -813,44 +789,60 @@ cb_canvas_select_item (FooCanvas *canvas, GdkEvent *event,
}
static void
-cb_sample_plot_resize (FooCanvas *canvas,
+cb_sample_plot_resize (GocCanvas *canvas,
GtkAllocation *alloc, GraphGuruState *state)
{
double aspect_ratio;
double width, height, x, y;
gog_graph_get_size (state->graph, &width, &height);
- aspect_ratio = width / height;
+ aspect_ratio = width / height;
if (alloc->width > alloc->height * aspect_ratio) {
height = alloc->height;
- width = height * aspect_ratio;
- x = (alloc->width - width) / 2.0;
+ width = floor (height * aspect_ratio + .5);
+ x = floor ((alloc->width - width) / 2.0 + .5);
y = 0.0;
} else {
width = alloc->width;
- height = width / aspect_ratio;
+ height = floor (width / aspect_ratio + .5);
x = 0.0;
- y = (alloc->height - height) / 2.0;
+ y = floor ((alloc->height - height) / 2.0 + .5);
}
-
- foo_canvas_item_set (state->sample_graph_item,
- "w", width > 2 ? width - 2 : 0,
- "h", height > 2 ? height - 2 : 0,
+
+ if (width > 2)
+ width -= 2;
+ else
+ width = 0;
+ if (height > 2)
+ height -= 2;
+ else
+ height = 0;
+ goc_item_set (state->sample_graph_item,
+ "width", width,
+ "height", height,
"x", x,
"y", y,
NULL);
- foo_canvas_item_set (state->sample_graph_frame,
- "x2", x + width - 3,
- "y2", y + height - 3,
- "x1", x,
- "y1", y,
+ if (width > .5)
+ width -= 1.;
+ if (height > .5)
+ height -= 1.;
+ goc_item_set (state->sample_graph_frame,
+ "width", width,
+ "height", height,
+ "x", x,
+ "y", y,
NULL);
- foo_canvas_item_set (state->sample_graph_shadow,
- "x2", x + width - 1,
- "y2", y + height - 1,
- "x1", x + 3,
- "y1", y + 3,
+ if (width > .5)
+ width -= 1.;
+ if (height > .5)
+ height -= 1.;
+ goc_item_set (state->sample_graph_shadow,
+ "width", width,
+ "height", height,
+ "x", x + 3,
+ "y", y + 3,
NULL);
}
@@ -885,6 +877,7 @@ graph_guru_init_format_page (GraphGuruState *s)
GtkWidget *w, *canvas;
GtkTreeViewColumn *column;
GogRenderer *rend;
+ GOStyle *style;
if (s->fmt_page_initialized)
return;
@@ -921,25 +914,27 @@ graph_guru_init_format_page (GraphGuruState *s)
/* Load up the sample view and make it fill the entire canvas */
w = glade_xml_get_widget (s->gui, "sample-alignment");
- canvas = foo_canvas_new ();
+ canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
gtk_container_add (GTK_CONTAINER (w), canvas);
- s->sample_graph_shadow = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
- FOO_TYPE_CANVAS_RECT,
- "width_pixels", 2,
- "outline_color_rgba", 0xa0a0a0ff, /* grey */
+ s->sample_graph_shadow = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+ GOC_TYPE_RECTANGLE,
NULL);
- s->sample_graph_frame = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
- FOO_TYPE_CANVAS_RECT,
- "width_pixels", 1,
- "fill_color_rgba", 0xffffffff, /* white */
- "outline_color_rgba", 0x707070ff, /* grey */
+ style= go_styled_object_get_style (GO_STYLED_OBJECT (s->sample_graph_shadow));
+ style->outline.width = 2;
+ style->outline.color = 0xa0a0a0ff; /* grey */
+ s->sample_graph_frame = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+ GOC_TYPE_RECTANGLE,
NULL);
- s->sample_graph_item = foo_canvas_item_new (foo_canvas_root (FOO_CANVAS (canvas)),
- GOG_TYPE_CONTROL_FOOCANVAS,
- "model", s->graph,
+ style= go_styled_object_get_style (GO_STYLED_OBJECT (s->sample_graph_frame));
+ style->outline.width = 1;
+ style->outline.color = 0x707070ff; /* grey */
+ style->fill.pattern.back = 0xffffffff; /* white */
+ s->sample_graph_item = goc_item_new (goc_canvas_get_root (GOC_CANVAS (canvas)),
+ GOC_TYPE_GRAPH,
+ "graph", s->graph,
NULL);
gtk_widget_add_events (canvas, GDK_POINTER_MOTION_HINT_MASK);
- cb_sample_plot_resize (FOO_CANVAS (canvas), &canvas->allocation, s);
+ cb_sample_plot_resize (GOC_CANVAS (canvas), &canvas->allocation, s);
g_signal_connect (G_OBJECT (canvas),
"size_allocate",
G_CALLBACK (cb_sample_plot_resize), s);
@@ -1097,15 +1092,17 @@ typesel_set_selection_color (GraphGuruTypeSelector *typesel)
GtkWidget *w = gtk_entry_new ();
GdkColor *color = &w->style->base [GTK_WIDGET_HAS_FOCUS (typesel->canvas)
? GTK_STATE_SELECTED : GTK_STATE_ACTIVE];
- guint32 select_color = 0;
+ GOColor select_color;
+ GOStyle *style;
- select_color |= ((color->red >> 8) & 0xff) << 24;
+ select_color = ((color->red >> 8) & 0xff) << 24;
select_color |= ((color->green >> 8) & 0xff) << 16;
select_color |= ((color->blue >> 8) & 0xff) << 8;
select_color |= 0x40; /* alpha of 25% */
- foo_canvas_item_set (typesel->selector,
- "fill_color_rgba", select_color,
- NULL);
+
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (typesel->selector));
+ style->fill.pattern.back = select_color;
+ goc_item_invalidate (typesel->selector);
gtk_object_destroy (GTK_OBJECT (w));
}
@@ -1116,6 +1113,7 @@ graph_guru_type_selector_new (GraphGuruState *s)
GraphGuruTypeSelector *typesel;
GtkWidget *selector;
GladeXML *gui;
+ GOStyle *style;
gui = go_glade_new ("gog-guru-type-selector.glade", "type_selector", GETTEXT_PACKAGE, s->cc);
@@ -1153,12 +1151,10 @@ graph_guru_type_selector_new (GraphGuruState *s)
/* Setup an canvas to display the sample image & the sample plot. */
- typesel->canvas = foo_canvas_new ();
- typesel->graph_group = FOO_CANVAS_GROUP (foo_canvas_item_new (
- foo_canvas_root (FOO_CANVAS (typesel->canvas)),
- foo_canvas_group_get_type (),
- "x", 0.0,
- "y", 0.0,
+ typesel->canvas = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
+ typesel->graph_group = GOC_GROUP (goc_item_new (
+ goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+ goc_group_get_type (),
NULL));
g_object_connect (typesel->canvas,
"signal::realize", G_CALLBACK (cb_canvas_realized), typesel,
@@ -1171,7 +1167,6 @@ graph_guru_type_selector_new (GraphGuruState *s)
gtk_widget_set_size_request (typesel->canvas,
MINOR_PIXMAP_WIDTH*3 + BORDER*5,
MINOR_PIXMAP_HEIGHT*3 + BORDER*5);
- foo_canvas_scroll_to (FOO_CANVAS (typesel->canvas), 0, 0);
gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (gui, "canvas_container")),
typesel->canvas);
@@ -1186,12 +1181,13 @@ graph_guru_type_selector_new (GraphGuruState *s)
G_CALLBACK (cb_selection_changed), typesel);
/* The alpha blended selection box */
- typesel->selector = foo_canvas_item_new (
- foo_canvas_root (FOO_CANVAS (typesel->canvas)),
- foo_canvas_rect_get_type (),
- "outline_color_rgba", 0x000000ff, /* black */
- "width_pixels", 1,
+ typesel->selector = goc_item_new (
+ goc_canvas_get_root (GOC_CANVAS (typesel->canvas)),
+ GOC_TYPE_RECTANGLE,
NULL);
+ style= go_styled_object_get_style (GO_STYLED_OBJECT (typesel->selector));
+ style->outline.width = 1;
+ style->outline.color = 0x000000ff; /* black */
typesel_set_selection_color (typesel);
/* Setup the description label */
diff --git a/goffice/gtk/go-3d-rotation-sel.c b/goffice/gtk/go-3d-rotation-sel.c
index 21a5f71..07eb2ff 100644
--- a/goffice/gtk/go-3d-rotation-sel.c
+++ b/goffice/gtk/go-3d-rotation-sel.c
@@ -21,12 +21,11 @@
#include <goffice/goffice-config.h>
#include <goffice/goffice.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-polygon.h>
+#include <goffice/canvas/goc-canvas.h>
+#include <goffice/canvas/goc-item.h>
+#include <goffice/canvas/goc-circle.h>
+#include <goffice/canvas/goc-polygon.h>
+#include <goffice/canvas/goc-structs.h>
#include <gsf/gsf-impl-utils.h>
#include <glib/gi18n-lib.h>
@@ -55,10 +54,10 @@ struct _GO3DRotationSel {
double bank;
g3d_point *cube_points;
int *cube_faces;
- FooCanvas *rotate_canvas;
- FooCanvasItem *dial;
- FooCanvasItem *bank_dial;
- FooCanvasItem *cube_polygons[6];
+ GocCanvas *rotate_canvas;
+ GocItem *dial;
+ GocItem *bank_dial;
+ GocItem *cube_polygons[6];
gulong motion_handle;
};
@@ -99,7 +98,6 @@ cb_rotation_changed (GO3DRotationSel *g3d)
double mgn = g3d->margin - 2;
double r = g3d->radius;
double d = 2 * r;
- double dr = g3d->bank_dial_r;
double dx = g3d->bank_dial_x = mgn + r * (1 - sin (g3d->bank));
double dy = g3d->bank_dial_y = mgn + r * (1 - cos (g3d->bank));
@@ -124,16 +122,9 @@ cb_rotation_changed (GO3DRotationSel *g3d)
};
int i;
- if (g3d->dial) {
- foo_canvas_item_set (g3d->dial,
- "x1", mgn, "y1", mgn,
- "x2", mgn + d, "y2", mgn + d, NULL);
- }
-
if (g3d->bank_dial) {
- foo_canvas_item_set (g3d->bank_dial,
- "x1", dx - dr, "y1", dy - dr,
- "x2", dx + dr, "y2", dy + dr, NULL);
+ goc_item_set (g3d->bank_dial,
+ "x", dx, "y", dy, NULL);
}
for (i = 0; i < 8; ++i) {
@@ -145,23 +136,22 @@ cb_rotation_changed (GO3DRotationSel *g3d)
}
for (i = 0; i < 6; ++i) {
- FooCanvasPoints *points;
+ GocPoints *points;
+ GOStyle *style;
double cx = mgn + r;
double mean_y;
if (g3d->cube_polygons[i] == NULL)
continue;
- points = foo_canvas_points_new (5);
- points->coords[0] = cp[cf[4 * i + 0]].x + cx;
- points->coords[1] = -cp[cf[4 * i + 0]].z + cx;
- points->coords[2] = cp[cf[4 * i + 1]].x + cx;
- points->coords[3] = -cp[cf[4 * i + 1]].z + cx;
- points->coords[4] = cp[cf[4 * i + 2]].x + cx;
- points->coords[5] = -cp[cf[4 * i + 2]].z + cx;
- points->coords[6] = cp[cf[4 * i + 3]].x + cx;
- points->coords[7] = -cp[cf[4 * i + 3]].z + cx;
- points->coords[8] = cp[cf[4 * i + 0]].x + cx;
- points->coords[9] = -cp[cf[4 * i + 0]].z + cx;
+ points = goc_points_new (4);
+ points->points[0].x = cp[cf[4 * i + 0]].x + cx;
+ points->points[0].y = -cp[cf[4 * i + 0]].z + cx;
+ points->points[1].x = cp[cf[4 * i + 1]].x + cx;
+ points->points[1].y = -cp[cf[4 * i + 1]].z + cx;
+ points->points[2].x = cp[cf[4 * i + 2]].x + cx;
+ points->points[2].y = -cp[cf[4 * i + 2]].z + cx;
+ points->points[3].x = cp[cf[4 * i + 3]].x + cx;
+ points->points[3].y = -cp[cf[4 * i + 3]].z + cx;
/* NOTE: This back face culling method works only with
* a cube in parallel projection*/
@@ -169,11 +159,16 @@ cb_rotation_changed (GO3DRotationSel *g3d)
mean_y += cp[cf[4 * i + 1]].y;
mean_y += cp[cf[4 * i + 2]].y;
mean_y += cp[cf[4 * i + 3]].y;
- foo_canvas_item_set (g3d->cube_polygons[i], "points", points,
- "width_units", (mean_y < 0) ? 4. : 0.5,
- "fill-color", (i == 1)? "light blue" : "none",
- NULL);
- foo_canvas_points_free (points);
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->cube_polygons[i]));
+ style->fill.auto_type = FALSE;
+ style->fill.type = GO_STYLE_FILL_PATTERN;
+ style->fill.auto_back = FALSE;
+ /* set the background light blue or transparent */
+ style->fill.pattern.back = (i == 1)? RGBA_TO_UINT (0xad, 0xd8, 0xe6, 0xff): 0;
+ style->outline.width = (mean_y < 0) ? 4. : 0.5;
+ goc_item_set (g3d->cube_polygons[i], "points", points,
+ "style", style, NULL);
+ goc_points_unref (points);
}
go_matrix3x3_to_euler (&g3d->mat, &g3d->psi, &g3d->theta, &g3d->phi);
@@ -199,31 +194,45 @@ cb_fov_changed (GtkRange *range, GdkEventButton *event, GO3DRotationSel *g3d)
}
static void
-cb_rotate_canvas_realize (FooCanvas *canvas, GO3DRotationSel *g3d)
+cb_rotate_canvas_realize (GocCanvas *canvas, GO3DRotationSel *g3d)
{
- FooCanvasGroup *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+ GocGroup *group = GOC_GROUP (goc_canvas_get_root (canvas));
GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
int i;
+ GOStyle *go_style;
+ double mgn = g3d->margin - 2 + g3d->radius;
style->bg[GTK_STATE_NORMAL] = style->white;
gtk_widget_set_style (GTK_WIDGET (canvas), style);
g_object_unref (style);
- foo_canvas_set_scroll_region (canvas, 0, 0, 220, 220);
- foo_canvas_scroll_to (canvas, 0, 0);
-
for (i = 0; i < 6; ++i) {
- g3d->cube_polygons[i] = foo_canvas_item_new (group,
- FOO_TYPE_CANVAS_POLYGON, "outline-color", "black",
- NULL);
+ g3d->cube_polygons[i] = goc_item_new (group,
+ GOC_TYPE_POLYGON, NULL);
+ go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->cube_polygons[i]));
+ go_style->outline.auto_color = FALSE;
+ go_style->outline.color = RGBA_BLACK;
+ go_style->outline.miter_limit = 1.414;
}
- g3d->dial = foo_canvas_item_new (group,
- FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
- "width_units", 2., NULL);
-
- g3d->bank_dial = foo_canvas_item_new (group,
- FOO_TYPE_CANVAS_ELLIPSE, "outline_color", "black",
- "fill_color", "white", "width_units", 3., NULL);
+ g3d->dial = goc_item_new (group, GOC_TYPE_CIRCLE,
+ "x", mgn, "y", mgn, "radius", (double) g3d->radius, NULL);
+ go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->dial));
+ go_style->outline.auto_color = FALSE;
+ go_style->outline.color = RGBA_BLACK;
+ go_style->outline.width = 2.;
+ go_style->fill.auto_type = FALSE;
+ go_style->fill.type = GO_STYLE_FILL_NONE;
+
+ g3d->bank_dial = goc_item_new (group,
+ GOC_TYPE_CIRCLE, "radius", (double) g3d->bank_dial_r, NULL);
+ go_style = go_styled_object_get_style (GO_STYLED_OBJECT (g3d->bank_dial));
+ go_style->outline.auto_color = FALSE;
+ go_style->outline.color = RGBA_BLACK;
+ go_style->outline.width = 3.;
+ go_style->fill.auto_type = FALSE;
+ go_style->fill.type = GO_STYLE_FILL_PATTERN;
+ go_style->fill.auto_back = FALSE;
+ go_style->fill.pattern.back = RGBA_WHITE;
cb_rotation_changed(g3d);
}
@@ -339,7 +348,7 @@ g3d_init (GO3DRotationSel *g3d)
g3d->dial = NULL;
g3d->bank_dial = NULL;
memset (g3d->cube_polygons, 0, sizeof (g3d->cube_polygons));
- g3d->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+ g3d->rotate_canvas = GOC_CANVAS (g_object_new (GOC_TYPE_CANVAS, NULL));
gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (g3d->gui,
"rotate_canvas")),
GTK_WIDGET (g3d->rotate_canvas));
diff --git a/goffice/gtk/go-font-sel.c b/goffice/gtk/go-font-sel.c
index 8f7a898..063c27e 100644
--- a/goffice/gtk/go-font-sel.c
+++ b/goffice/gtk/go-font-sel.c
@@ -11,9 +11,6 @@
#include <goffice/goffice-config.h>
#include <goffice/goffice.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-text.h>
-
#include <gsf/gsf-impl-utils.h>
#include <glib/gi18n-lib.h>
#include <errno.h>
@@ -32,8 +29,8 @@ struct _GOFontSel {
GtkTreeView *font_style_list;
GtkTreeView *font_size_list;
- FooCanvas *font_preview_canvas;
- FooCanvasItem *font_preview_text;
+ GocCanvas *font_preview_canvas;
+ GocItem *font_preview_text;
GOFont *base, *current;
PangoAttrList *modifications;
@@ -74,7 +71,7 @@ go_font_sel_emit_changed (GOFontSel *gfs)
{
g_signal_emit (G_OBJECT (gfs),
gfs_signals [FONT_CHANGED], 0, gfs->modifications);
- foo_canvas_item_set (gfs->font_preview_text,
+ goc_item_set (gfs->font_preview_text,
"attributes", gfs->modifications,
NULL);
}
@@ -326,13 +323,10 @@ canvas_size_changed (G_GNUC_UNUSED GtkWidget *widget,
int width = allocation->width - 1;
int height = allocation->height - 1;
- foo_canvas_item_set (gfs->font_preview_text,
+ goc_item_set (gfs->font_preview_text,
"x", (double)width/2.,
"y", (double)height/2.,
NULL);
-
- foo_canvas_set_scroll_region (gfs->font_preview_canvas, 0, 0,
- width, height);
}
static void
@@ -356,18 +350,16 @@ gfs_init (GOFontSel *gfs)
gfs->font_style_list = GTK_TREE_VIEW (glade_xml_get_widget (gfs->gui, "font-style-list"));
gfs->font_size_list = GTK_TREE_VIEW (glade_xml_get_widget (gfs->gui, "font-size-list"));
- w = foo_canvas_new ();
- gfs->font_preview_canvas = FOO_CANVAS (w);
- foo_canvas_set_scroll_region (gfs->font_preview_canvas, -1, -1, INT_MAX/2, INT_MAX/2);
- foo_canvas_scroll_to (gfs->font_preview_canvas, 0, 0);
+ w = GTK_WIDGET (g_object_new (GOC_TYPE_CANVAS, NULL));
+ gfs->font_preview_canvas = GOC_CANVAS (w);
gtk_widget_show_all (w);
w = glade_xml_get_widget (gfs->gui, "font-preview-frame");
gtk_container_add (GTK_CONTAINER (w), GTK_WIDGET (gfs->font_preview_canvas));
- gfs->font_preview_text = FOO_CANVAS_ITEM (foo_canvas_item_new (
- foo_canvas_root (gfs->font_preview_canvas),
- FOO_TYPE_CANVAS_TEXT,
- NULL));
+ gfs->font_preview_text = goc_item_new (
+ goc_canvas_get_root (gfs->font_preview_canvas),
+ GOC_TYPE_TEXT,
+ NULL);
go_font_sel_set_sample_text (gfs, NULL); /* init to default */
g_signal_connect (G_OBJECT (gfs->font_preview_canvas),
@@ -456,7 +448,7 @@ void
go_font_sel_set_sample_text (GOFontSel *gfs, char const *text)
{
g_return_if_fail (GO_IS_FONT_SEL (gfs));
- foo_canvas_item_set (gfs->font_preview_text,
+ goc_item_set (gfs->font_preview_text,
/* xgettext: This text is used as a sample when selecting a font
* please choose a translation that would produce common
* characters specific to the target alphabet. */
diff --git a/goffice/gtk/go-rotation-sel.c b/goffice/gtk/go-rotation-sel.c
index ed97090..5c297cf 100644
--- a/goffice/gtk/go-rotation-sel.c
+++ b/goffice/gtk/go-rotation-sel.c
@@ -20,12 +20,6 @@
#include <goffice/goffice-config.h>
#include <goffice/goffice.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-util.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-line.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-widget.h>
-#include <goffice/cut-n-paste/foocanvas/foo-canvas-rect-ellipse.h>
-
#include <gsf/gsf-impl-utils.h>
#include <glib/gi18n-lib.h>
#include <string.h>
@@ -36,11 +30,11 @@ struct _GORotationSel {
int angle;
GtkSpinButton *rotate_spinner;
- FooCanvas *rotate_canvas;
- FooCanvasItem *rotate_marks[13];
- FooCanvasItem *line;
+ GocCanvas *rotate_canvas;
+ GocItem *rotate_marks[13];
+ GocItem *line;
GtkWidget *text_widget;
- FooCanvasItem *text;
+ GocItem *text;
int rot_width, rot_height;
gulong motion_handle;
};
@@ -61,7 +55,7 @@ static GObjectClass *grs_parent_class;
static void
cb_rotate_changed (GORotationSel *grs)
{
- char const *colour;
+ GOColor colour;
int i;
go_rotation_sel_set_rotation (grs,
@@ -69,67 +63,72 @@ cb_rotate_changed (GORotationSel *grs)
for (i = 0 ; i <= 12 ; i++)
if (grs->rotate_marks[i] != NULL) {
- colour = (grs->angle == (i-6)*15) ? "green" : "black";
- foo_canvas_item_set (grs->rotate_marks[i], "fill-color", colour, NULL);
+ GOStyle *style = go_styled_object_get_style (GO_STYLED_OBJECT (grs->rotate_marks[i]));
+ colour = (grs->angle == (i-6)*15) ? RGBA_GREEN : RGBA_BLACK;
+ if (style->fill.pattern.back != colour){
+ style->fill.pattern.back = colour;
+ goc_item_invalidate (grs->rotate_marks[i]);
+ }
}
if (grs->line != NULL) {
- FooCanvasPoints *points = foo_canvas_points_new (2);
double rad = grs->angle * M_PI / 180.;
- points->coords[0] = 15 + cos (rad) * grs->rot_width;
- points->coords[1] = 100 - sin (rad) * grs->rot_width;
- points->coords[2] = 15 + cos (rad) * 72.;
- points->coords[3] = 100 - sin (rad) * 72.;
- foo_canvas_item_set (grs->line, "points", points, NULL);
- foo_canvas_points_free (points);
+ goc_item_set (grs->line,
+ "x0", 15 + cos (rad) * grs->rot_width,
+ "y0", 100 - sin (rad) * grs->rot_width,
+ "x1", 15 + cos (rad) * 72.,
+ "y1", 100 - sin (rad) * 72.,
+ NULL);
}
if (grs->text) {
double x = 15.0;
double y = 100.0;
double rad = grs->angle * M_PI / 180.;
+ double w = grs->rot_width * cos (fabs (rad)) + grs->rot_height * sin (fabs (rad));
+ double h = grs->rot_width * sin (fabs (rad)) + grs->rot_height * cos (fabs (rad));
x -= grs->rot_height * sin (fabs (rad)) / 2;
y -= grs->rot_height * cos (rad) / 2;
if (rad >= 0)
y -= grs->rot_width * sin (rad);
- foo_canvas_item_set (grs->text, "x", x, "y", y, NULL);
+ goc_item_set (grs->text, "x", x, "y", y,
+ "width", w, "height", h, NULL);
gtk_label_set_angle (GTK_LABEL (grs->text_widget),
(grs->angle + 360) % 360);
}
}
static void
-cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
+cb_rotate_canvas_realize (GocCanvas *canvas, GORotationSel *grs)
{
- FooCanvasGroup *group = FOO_CANVAS_GROUP (foo_canvas_root (canvas));
+ GocGroup *group = goc_canvas_get_root (canvas);
int i;
+ GOStyle *go_style;
GtkStyle *style = gtk_style_copy (GTK_WIDGET (canvas)->style);
style->bg[GTK_STATE_NORMAL] = style->white;
gtk_widget_set_style (GTK_WIDGET (canvas), style);
g_object_unref (style);
- foo_canvas_set_scroll_region (canvas, 0, 0, 100, 200);
- foo_canvas_scroll_to (canvas, 0, 0);
-
for (i = 0 ; i <= 12 ; i++) {
double rad = (i-6) * M_PI / 12.;
double x = 15 + cos (rad) * 80.;
double y = 100 - sin (rad) * 80.;
double size = (i % 3) ? 3.0 : 4.0;
- FooCanvasItem *item = foo_canvas_item_new (group,
- FOO_TYPE_CANVAS_ELLIPSE,
- "x1", x-size, "y1", y-size,
- "x2", x+size, "y2", y+size,
- "width-pixels", (int) 1,
- "outline-color","black",
- "fill-color", "black",
+ GocItem *item = goc_item_new (group,
+ GOC_TYPE_CIRCLE,
+ "x", x, "y", y,
+ "radius", size,
NULL);
+ go_style = go_styled_object_get_style (GO_STYLED_OBJECT (item));
+ go_style->outline.width = 1.;
+ go_style->outline.color = RGBA_BLACK;
+ go_style->fill.pattern.back = RGBA_BLACK;
grs->rotate_marks[i] = item;
}
- grs->line = foo_canvas_item_new (group, FOO_TYPE_CANVAS_LINE,
- "fill-color", "black",
- "width_units", 2.,
- NULL);
+ grs->line = goc_item_new (group, GOC_TYPE_LINE, NULL);
+ go_style = go_styled_object_get_style (GO_STYLED_OBJECT (grs->line));
+ go_style->outline.width = 2.;
+ go_style->outline.color = RGBA_BLACK;
{
int w, h;
@@ -152,7 +151,7 @@ cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
grs->rot_width = w;
grs->rot_height = h;
- grs->text = foo_canvas_item_new (group, FOO_TYPE_CANVAS_WIDGET,
+ grs->text = goc_item_new (group, GOC_TYPE_WIDGET,
"widget", tw, NULL);
gtk_widget_show (tw);
}
@@ -161,10 +160,9 @@ cb_rotate_canvas_realize (FooCanvas *canvas, GORotationSel *grs)
}
static void
-set_rot_from_point (GORotationSel *grs, FooCanvas *canvas, double x, double y)
+set_rot_from_point (GORotationSel *grs, double x, double y)
{
double degrees;
- foo_canvas_window_to_world (canvas, x, y, &x, &y);
x -= 15.; if (x < 0.) x = 0.;
y -= 100.;
@@ -175,20 +173,20 @@ set_rot_from_point (GORotationSel *grs, FooCanvas *canvas, double x, double y)
}
static gboolean
-cb_rotate_motion_notify_event (FooCanvas *canvas, GdkEventMotion *event,
+cb_rotate_motion_notify_event (G_GNUC_UNUSED GocCanvas *canvas, GdkEventMotion *event,
GORotationSel *grs)
{
- set_rot_from_point (grs, canvas, event->x, event->y);
+ set_rot_from_point (grs, event->x, event->y);
return TRUE;
}
static gboolean
-cb_rotate_canvas_button (FooCanvas *canvas, GdkEventButton *event, GORotationSel *grs)
+cb_rotate_canvas_button (GocCanvas *canvas, GdkEventButton *event, GORotationSel *grs)
{
if (event->type == GDK_BUTTON_PRESS) {
- set_rot_from_point (grs, canvas, event->x, event->y);
+ set_rot_from_point (grs, event->x, event->y);
if (grs->motion_handle == 0) {
- gdk_pointer_grab (canvas->layout.bin_window, FALSE,
+ gdk_pointer_grab (canvas->base.bin_window, FALSE,
GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
NULL, NULL, event->time);
@@ -221,7 +219,7 @@ grs_init (GORotationSel *grs)
grs->line = NULL;
grs->text = NULL;
grs->text_widget = NULL;
- grs->rotate_canvas = FOO_CANVAS (foo_canvas_new ());
+ grs->rotate_canvas = GOC_CANVAS (g_object_new (GOC_TYPE_CANVAS, NULL));
gtk_container_add (GTK_CONTAINER (glade_xml_get_widget (grs->gui,
"rotate_canvas_container")),
GTK_WIDGET (grs->rotate_canvas));
diff --git a/goffice/utils/go-style.c b/goffice/utils/go-style.c
index fbb5253..ab785fe 100644
--- a/goffice/utils/go-style.c
+++ b/goffice/utils/go-style.c
@@ -1176,8 +1176,10 @@ go_style_init (GOStyle *style)
style->disable_theming = 0;
go_style_force_auto (style);
style->line.dash_type = GO_LINE_SOLID;
- style->outline.dash_type = GO_LINE_SOLID;
- style->outline.width = 0;
+ style->line.width = 0;
+ style->line.cap = CAIRO_LINE_CAP_BUTT;
+ style->line.join = CAIRO_LINE_JOIN_MITER;
+ style->line.miter_limit = 10.;
style->fill.type = GO_STYLE_FILL_NONE;
style->fill.gradient.brightness = -1.;
go_pattern_set_solid (&style->fill.pattern, RGBA_BLACK);
diff --git a/goffice/utils/go-style.h b/goffice/utils/go-style.h
index 985b4a0..8b5d2ed 100644
--- a/goffice/utils/go-style.h
+++ b/goffice/utils/go-style.h
@@ -64,10 +64,15 @@ typedef struct {
float width;
GOLineDashType dash_type;
gboolean auto_dash;
- GOColor color;
+ GOColor color; /* color is used as background for compatibility
+ (pattern == 0 means filled with background color) */
+ GOColor fore;
gboolean auto_color;
- unsigned pattern_unimplemented_yet; /* TODO: implement. Not used
- and must not be used before implementation */
+ gboolean auto_fore;
+ GOPatternType pattern;
+ cairo_line_cap_t cap;
+ cairo_line_join_t join;
+ double miter_limit;
} GOStyleLine;
typedef struct {
@@ -83,7 +88,7 @@ struct _GOStyle {
GOStyleFlag interesting_fields;
GOStyleFlag disable_theming;
- GOStyleLine outline, line;
+ union {GOStyleLine outline, line;};
struct {
GOStyleFill type;
gboolean auto_type;
diff --git a/goffice/utils/go-styled-object.c b/goffice/utils/go-styled-object.c
index 8c0d448..be4b610 100644
--- a/goffice/utils/go-styled-object.c
+++ b/goffice/utils/go-styled-object.c
@@ -139,3 +139,70 @@ go_styled_object_get_document (GOStyledObject *gso)
return (klass->get_document)?
klass->get_document (gso): NULL;
}
+
+gboolean
+go_styled_object_set_cairo_line (GOStyledObject const *so, cairo_t *cr)
+{
+ GOStyle const *style;
+ double width;
+ GOLineDashSequence *line_dash;
+
+ g_return_val_if_fail (GO_IS_STYLED_OBJECT (so), FALSE);
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (so));
+ if (style->line.dash_type == GO_LINE_NONE)
+ return FALSE;
+ width = (style->line.width)? style->line.width: 1.;
+ cairo_set_line_width (cr, width);
+ cairo_set_line_cap (cr, style->line.cap);
+ cairo_set_line_join (cr, style->line.join);
+ cairo_set_miter_limit (cr, style->line.miter_limit);
+ line_dash = go_line_dash_get_sequence (style->line.dash_type, width);
+ if (line_dash != NULL)
+ cairo_set_dash (cr,
+ line_dash->dash,
+ line_dash->n_dash,
+ line_dash->offset);
+ else
+ cairo_set_dash (cr, NULL, 0, 0);
+ switch (style->line.pattern) {
+ case GO_PATTERN_SOLID:
+ cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.color));
+ break;
+ case GO_PATTERN_FOREGROUND_SOLID:
+ cairo_set_source_rgba (cr, GO_COLOR_TO_CAIRO (style->line.fore));
+ break;
+ default: {
+ GOPattern pat;
+ double scalex = 1., scaley = 1.;
+ cairo_pattern_t *cp;
+ cairo_matrix_t mat;
+ pat.fore = style->line.fore;
+ pat.back = style->line.color;
+ pat.pattern = style->line.pattern;
+ cp = go_pattern_create_cairo_pattern (&pat, cr);
+ cairo_user_to_device_distance (cr, &scalex, &scaley);
+ cairo_matrix_init_scale (&mat, scalex, scaley);
+ cairo_pattern_set_matrix (cp, &mat);
+ cairo_set_source (cr, cp);
+ break;
+ }
+ }
+ return TRUE;
+}
+
+gboolean
+go_styled_object_set_cairo_fill (GOStyledObject const *so, cairo_t *cr)
+{
+ GOStyle const *style;
+ cairo_pattern_t *pat = NULL;
+
+ g_return_val_if_fail (GO_IS_STYLED_OBJECT (so), FALSE);
+ style = go_styled_object_get_style (GO_STYLED_OBJECT (so));
+ pat = go_style_create_cairo_pattern (style, cr);
+ if (pat) {
+ cairo_set_source (cr, pat);
+ cairo_pattern_destroy (pat);
+ }
+ return TRUE;
+}
+
diff --git a/goffice/utils/go-styled-object.h b/goffice/utils/go-styled-object.h
index 10369b4..a8b75db 100644
--- a/goffice/utils/go-styled-object.h
+++ b/goffice/utils/go-styled-object.h
@@ -53,6 +53,8 @@ GOStyle *go_styled_object_get_auto_style (GOStyledObject *gso);
void go_styled_object_style_changed (GOStyledObject *gso);
void go_styled_object_apply_theme (GOStyledObject *gso, GOStyle *style);
GODoc *go_styled_object_get_document (GOStyledObject *gso);
+gboolean go_styled_object_set_cairo_line (GOStyledObject const *so, cairo_t *cr);
+gboolean go_styled_object_set_cairo_fill (GOStyledObject const *so, cairo_t *cr);
G_END_DECLS
#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]