Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/src/goocanvas/src/goocanvaspath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/goocanvas/src/goocanvaspath.c')
-rw-r--r--src/goocanvas/src/goocanvaspath.c359
1 files changed, 324 insertions, 35 deletions
diff --git a/src/goocanvas/src/goocanvaspath.c b/src/goocanvas/src/goocanvaspath.c
index d6af970..0254a66 100644
--- a/src/goocanvas/src/goocanvaspath.c
+++ b/src/goocanvas/src/goocanvaspath.c
@@ -33,26 +33,21 @@
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include "goocanvaspath.h"
+#include "goocanvas.h"
enum {
PROP_0,
PROP_DATA,
+
+ PROP_X,
+ PROP_Y,
+ PROP_WIDTH,
+ PROP_HEIGHT
};
static void canvas_item_interface_init (GooCanvasItemIface *iface);
-static void goo_canvas_path_finalize (GObject *object);
-static void goo_canvas_path_get_property (GObject *object,
- guint param_id,
- GValue *value,
- GParamSpec *pspec);
-static void goo_canvas_path_set_property (GObject *object,
- guint param_id,
- const GValue *value,
- GParamSpec *pspec);
-static void goo_canvas_path_create_path (GooCanvasItemSimple *simple,
- cairo_t *cr);
G_DEFINE_TYPE_WITH_CODE (GooCanvasPath, goo_canvas_path,
GOO_TYPE_CANVAS_ITEM_SIMPLE,
@@ -76,23 +71,36 @@ goo_canvas_path_install_common_properties (GObjectClass *gobject_class)
_("The sequence of path commands"),
NULL,
G_PARAM_WRITABLE));
-}
-
-
-static void
-goo_canvas_path_class_init (GooCanvasPathClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass*) klass;
- GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
-
- gobject_class->finalize = goo_canvas_path_finalize;
- gobject_class->get_property = goo_canvas_path_get_property;
- gobject_class->set_property = goo_canvas_path_set_property;
-
- simple_class->simple_create_path = goo_canvas_path_create_path;
-
- goo_canvas_path_install_common_properties (gobject_class);
+ g_object_class_install_property (gobject_class, PROP_X,
+ g_param_spec_double ("x",
+ "X",
+ _("The x coordinate of the path"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_Y,
+ g_param_spec_double ("y",
+ "Y",
+ _("The y coordinate of the path"),
+ -G_MAXDOUBLE,
+ G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_WIDTH,
+ g_param_spec_double ("width",
+ _("Width"),
+ _("The width of the path"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (gobject_class, PROP_HEIGHT,
+ g_param_spec_double ("height",
+ _("Height"),
+ _("The height of the path"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READWRITE));
}
@@ -200,16 +208,164 @@ goo_canvas_path_finalize (GObject *object)
G_OBJECT_CLASS (goo_canvas_path_parent_class)->finalize (object);
}
+static void
+goo_canvas_path_common_get_extent (GooCanvas *canvas,
+ GooCanvasPathData *path_data,
+ GooCanvasBounds *bounds)
+{
+ cairo_t *cr;
+
+ cr = goo_canvas_create_cairo_context (canvas);
+ goo_canvas_create_path (path_data->path_commands, cr);
+ cairo_fill_extents (cr, &bounds->x1, &bounds->y1, &bounds->x2, &bounds->y2);
+ cairo_destroy (cr);
+}
+
+
+/* Moves all the absolute points in the command by the given amounts.
+ Relative points don't need to be moved. */
+static void
+goo_canvas_path_move_command (GooCanvasPathCommand *cmd,
+ gdouble x_offset,
+ gdouble y_offset)
+{
+ switch (cmd->simple.type)
+ {
+ case GOO_CANVAS_PATH_MOVE_TO:
+ case GOO_CANVAS_PATH_CLOSE_PATH:
+ case GOO_CANVAS_PATH_LINE_TO:
+ case GOO_CANVAS_PATH_HORIZONTAL_LINE_TO:
+ case GOO_CANVAS_PATH_VERTICAL_LINE_TO:
+ if (!cmd->simple.relative)
+ {
+ cmd->simple.x += x_offset;
+ cmd->simple.y += y_offset;
+ }
+ break;
+ case GOO_CANVAS_PATH_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_CURVE_TO:
+ case GOO_CANVAS_PATH_QUADRATIC_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO:
+ if (!cmd->curve.relative)
+ {
+ cmd->curve.x += x_offset;
+ cmd->curve.y += y_offset;
+ cmd->curve.x1 += x_offset;
+ cmd->curve.y1 += y_offset;
+ cmd->curve.x2 += x_offset;
+ cmd->curve.y2 += y_offset;
+ }
+ break;
+ case GOO_CANVAS_PATH_ELLIPTICAL_ARC:
+ if (!cmd->arc.relative)
+ {
+ cmd->arc.x += x_offset;
+ cmd->arc.y += y_offset;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
+
+
+/* Scales all the points in the command by the given amounts. Absolute points
+ are scaled about the given origin. */
+static void
+goo_canvas_path_scale_command (GooCanvasPathCommand *cmd,
+ gdouble x_origin,
+ gdouble y_origin,
+ gdouble x_scale,
+ gdouble y_scale)
+{
+ switch (cmd->simple.type)
+ {
+ case GOO_CANVAS_PATH_MOVE_TO:
+ case GOO_CANVAS_PATH_CLOSE_PATH:
+ case GOO_CANVAS_PATH_LINE_TO:
+ case GOO_CANVAS_PATH_HORIZONTAL_LINE_TO:
+ case GOO_CANVAS_PATH_VERTICAL_LINE_TO:
+ if (cmd->simple.relative)
+ {
+ cmd->simple.x *= x_scale;
+ cmd->simple.y *= y_scale;
+ }
+ else
+ {
+ cmd->simple.x = x_origin + (cmd->simple.x - x_origin) * x_scale;
+ cmd->simple.y = y_origin + (cmd->simple.y - y_origin) * y_scale;
+ }
+ break;
+ case GOO_CANVAS_PATH_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_CURVE_TO:
+ case GOO_CANVAS_PATH_QUADRATIC_CURVE_TO:
+ case GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO:
+ if (cmd->curve.relative)
+ {
+ cmd->curve.x *= x_scale;
+ cmd->curve.y *= y_scale;
+ cmd->curve.x1 *= x_scale;
+ cmd->curve.y1 *= y_scale;
+ cmd->curve.x2 *= x_scale;
+ cmd->curve.y2 *= y_scale;
+ }
+ else
+ {
+ cmd->curve.x = x_origin + (cmd->curve.x - x_origin) * x_scale;
+ cmd->curve.y = y_origin + (cmd->curve.y - y_origin) * y_scale;
+ cmd->curve.x1 = x_origin + (cmd->curve.x1 - x_origin) * x_scale;
+ cmd->curve.y1 = y_origin + (cmd->curve.y1 - y_origin) * y_scale;
+ cmd->curve.x2 = x_origin + (cmd->curve.x2 - x_origin) * x_scale;
+ cmd->curve.y2 = y_origin + (cmd->curve.y2 - y_origin) * y_scale;
+ }
+ break;
+ case GOO_CANVAS_PATH_ELLIPTICAL_ARC:
+ if (cmd->arc.relative)
+ {
+ cmd->arc.x *= x_scale;
+ cmd->arc.y *= y_scale;
+ }
+ else
+ {
+ cmd->arc.x = x_origin + (cmd->arc.x - x_origin) * x_scale;
+ cmd->arc.y = y_origin + (cmd->arc.y - y_origin) * y_scale;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+}
static void
goo_canvas_path_get_common_property (GObject *object,
+ GooCanvas *canvas,
GooCanvasPathData *path_data,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
+ GooCanvasBounds extent;
+
switch (prop_id)
{
+ case PROP_X:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.x1);
+ break;
+ case PROP_Y:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.y1);
+ break;
+ case PROP_WIDTH:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.x2 - extent.x1);
+ break;
+ case PROP_HEIGHT:
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ g_value_set_double (value, extent.y2 - extent.y1);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -223,26 +379,113 @@ goo_canvas_path_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
+ GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
GooCanvasPath *path = (GooCanvasPath*) object;
- goo_canvas_path_get_common_property (object, path->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_get_common_property (object, simple->canvas,
+ path->path_data, prop_id, value, pspec);
}
static void
goo_canvas_path_set_common_property (GObject *object,
+ GooCanvas *canvas,
GooCanvasPathData *path_data,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
+ GooCanvasBounds extent;
+ GooCanvasPathCommand *cmd;
+ gdouble x_offset, y_offset, x_scale, y_scale;
+ guint i;
+
switch (prop_id)
{
case PROP_DATA:
if (path_data->path_commands)
g_array_free (path_data->path_commands, TRUE);
path_data->path_commands = goo_canvas_parse_path_data (g_value_get_string (value));
+ g_object_notify (object, "x");
+ g_object_notify (object, "y");
+ g_object_notify (object, "width");
+ g_object_notify (object, "height");
+ break;
+ case PROP_X:
+ if (path_data->path_commands->len > 0)
+ {
+ /* Calculate the x offset from the current position. */
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ x_offset = g_value_get_double (value) - extent.x1;
+
+ /* Add the offset to all the absolute x coordinates. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_move_command (cmd, x_offset, 0.0);
+ }
+ g_object_notify (object, "data");
+ }
+ break;
+ case PROP_Y:
+ if (path_data->path_commands->len > 0)
+ {
+ /* Calculate the y offset from the current position. */
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ y_offset = g_value_get_double (value) - extent.y1;
+
+ /* Add the offset to all the absolute y coordinates. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_move_command (cmd, 0.0, y_offset);
+ }
+ g_object_notify (object, "data");
+ }
+ break;
+ case PROP_WIDTH:
+ if (path_data->path_commands->len >= 2)
+ {
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ if (extent.x2 - extent.x1 != 0.0)
+ {
+ /* Calculate the amount to scale the path. */
+ x_scale = g_value_get_double (value) / (extent.x2 - extent.x1);
+
+ /* Scale the x coordinates, relative to the left-most point. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_scale_command (cmd, extent.x1, 0.0,
+ x_scale, 1.0);
+ }
+ g_object_notify (object, "data");
+ }
+ }
+ break;
+ case PROP_HEIGHT:
+ if (path_data->path_commands->len >= 2)
+ {
+ goo_canvas_path_common_get_extent (canvas, path_data, &extent);
+ if (extent.y2 - extent.y1 != 0.0)
+ {
+ /* Calculate the amount to scale the polyline. */
+ y_scale = g_value_get_double (value) / (extent.y2 - extent.y1);
+
+ /* Scale the y coordinates, relative to the top-most point. */
+ for (i = 0; i < path_data->path_commands->len; i++)
+ {
+ cmd = &g_array_index (path_data->path_commands,
+ GooCanvasPathCommand, i);
+ goo_canvas_path_scale_command (cmd, 0.0, extent.y1,
+ 1.0, y_scale);
+ }
+ g_object_notify (object, "data");
+ }
+ }
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -266,8 +509,8 @@ goo_canvas_path_set_property (GObject *object,
return;
}
- goo_canvas_path_set_common_property (object, path->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_set_common_property (object, simple->canvas, path->path_data,
+ prop_id, value, pspec);
goo_canvas_item_simple_changed (simple, TRUE);
}
@@ -282,6 +525,34 @@ goo_canvas_path_create_path (GooCanvasItemSimple *simple,
}
+static gboolean
+goo_canvas_path_is_item_at (GooCanvasItemSimple *simple,
+ gdouble x,
+ gdouble y,
+ cairo_t *cr,
+ gboolean is_pointer_event)
+{
+ GooCanvasItemSimpleData *simple_data = simple->simple_data;
+ GooCanvasPointerEvents pointer_events = GOO_CANVAS_EVENTS_ALL;
+ gboolean do_fill;
+
+ /* By default only check the fill if a fill color/pattern is specified. */
+ do_fill = goo_canvas_style_set_fill_options (simple_data->style, cr);
+ if (!do_fill)
+ pointer_events &= ~GOO_CANVAS_EVENTS_FILL_MASK;
+
+ /* If is_pointer_event is set use the pointer_events property instead. */
+ if (is_pointer_event)
+ pointer_events = simple_data->pointer_events;
+
+ goo_canvas_path_create_path (simple, cr);
+ if (goo_canvas_item_simple_check_in_path (simple, x, y, cr, pointer_events))
+ return TRUE;
+
+ return FALSE;
+}
+
+
static void
goo_canvas_path_set_model (GooCanvasItem *item,
GooCanvasItemModel *model)
@@ -313,6 +584,24 @@ canvas_item_interface_init (GooCanvasItemIface *iface)
}
+static void
+goo_canvas_path_class_init (GooCanvasPathClass *klass)
+{
+ GObjectClass *gobject_class = (GObjectClass*) klass;
+ GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
+
+ gobject_class->finalize = goo_canvas_path_finalize;
+
+ gobject_class->get_property = goo_canvas_path_get_property;
+ gobject_class->set_property = goo_canvas_path_set_property;
+
+ simple_class->simple_create_path = goo_canvas_path_create_path;
+ simple_class->simple_is_item_at = goo_canvas_path_is_item_at;
+
+ goo_canvas_path_install_common_properties (gobject_class);
+}
+
+
/**
* SECTION:goocanvaspathmodel
* @Title: GooCanvasPathModel
@@ -478,8 +767,8 @@ goo_canvas_path_model_get_property (GObject *object,
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
- goo_canvas_path_get_common_property (object, &pmodel->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_get_common_property (object, NULL, &pmodel->path_data,
+ prop_id, value, pspec);
}
@@ -491,8 +780,8 @@ goo_canvas_path_model_set_property (GObject *object,
{
GooCanvasPathModel *pmodel = (GooCanvasPathModel*) object;
- goo_canvas_path_set_common_property (object, &pmodel->path_data, prop_id,
- value, pspec);
+ goo_canvas_path_set_common_property (object, NULL, &pmodel->path_data,
+ prop_id, value, pspec);
g_signal_emit_by_name (pmodel, "changed", TRUE);
}