[cairo-commit] goocanvas/src Makefile.am, 1.2, 1.3 demo-paths.c,
NONE, 1.1 demo.c, 1.6, 1.7 goocanvaspath.c, NONE,
1.1 goocanvaspath.h, NONE, 1.1 goocanvaspathview.c, NONE,
1.1 goocanvaspathview.h, NONE, 1.1 goocanvaspolylineview.c,
1.5, 1.6 goocanvaspolylineview.h, 1.1.1.1, 1.2
Damon Chaplin
commit at pdx.freedesktop.org
Mon Apr 10 13:30:26 PDT 2006
Committed by: damon
Update of /cvs/cairo/goocanvas/src
In directory kemper:/tmp/cvs-serv27868/src
Modified Files:
Makefile.am demo.c goocanvaspolylineview.c
goocanvaspolylineview.h
Added Files:
demo-paths.c goocanvaspath.c goocanvaspath.h
goocanvaspathview.c goocanvaspathview.h
Log Message:
2006-04-10 Damon Chaplin <damon at gnome.org>
* src/goocanvaspathview.[hc]:
* src/goocanvaspath.[hc]: new path item and view, that uses the same
path spec strings as SVG. I think everything works, except the
elliptical arc, which I haven't finished yet.
* src/demo-paths.c: new demo page to test paths.
Index: Makefile.am
===================================================================
RCS file: /cvs/cairo/goocanvas/src/Makefile.am,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- Makefile.am 8 Apr 2006 13:14:17 -0000 1.2
+++ Makefile.am 10 Apr 2006 20:30:24 -0000 1.3
@@ -13,7 +13,7 @@
demo_SOURCES = \
demo.c demo-fifteen.c demo-scalability.c demo-grabs.c \
- demo-arrowhead.c demo-features.c demo-events.c \
+ demo-arrowhead.c demo-features.c demo-events.c demo-paths.c \
goocanvasmarshal.list \
goocanvasellipse.h goocanvasellipse.c \
goocanvasellipseview.h goocanvasellipseview.c \
@@ -28,6 +28,8 @@
goocanvasmodelsimple.h goocanvasmodelsimple.c \
goocanvaspolyline.h goocanvaspolyline.c \
goocanvaspolylineview.h goocanvaspolylineview.c \
+ goocanvaspath.h goocanvaspath.c \
+ goocanvaspathview.h goocanvaspathview.c \
goocanvasrect.h goocanvasrect.c \
goocanvasrectview.h goocanvasrectview.c \
goocanvastext.h goocanvastext.c \
--- NEW FILE: demo-paths.c ---
#include <config.h>
#include <string.h>
#include <gtk/gtk.h>
#include "goocanvasmodelsimple.h"
#include "goocanvasview.h"
#include "goocanvasitemview.h"
#include "goocanvasgroup.h"
#include "goocanvasgroupview.h"
#include "goocanvaspath.h"
static void
create_paths (GooCanvasModelSimple *canvas_model)
{
GooCanvasItem *root, *path;
root = goo_canvas_model_get_root_item (GOO_CANVAS_MODEL (canvas_model));
/* Test the simple commands like moveto and lineto: MmZzLlHhVv. */
path = goo_canvas_path_new (root, "M 20 20 L 40 40", NULL);
path = goo_canvas_path_new (root, "M30 20 l20, 20", NULL);
path = goo_canvas_path_new (root, "M 60 20 H 80", NULL);
path = goo_canvas_path_new (root, "M60 40 h20", NULL);
path = goo_canvas_path_new (root, "M 100,20 V 40", NULL);
path = goo_canvas_path_new (root, "M 120 20 v 20", NULL);
path = goo_canvas_path_new (root, "M 140 20 h20 v20 h-20 z", NULL);
path = goo_canvas_path_new (root,
"M 180 20 h20 v20 h-20 z m 5,5 h10 v10 h-10 z",
"fill-color", "red",
"fill-rule", CAIRO_FILL_RULE_EVEN_ODD,
NULL);
path = goo_canvas_path_new (root, "M 220 20 L 260 20 L 240 40 z",
"fill-color", "red",
"stroke-color", "blue",
"line-width", 3.0,
NULL);
/* Test the bezier curve commands: CcSsQqTt. */
path = goo_canvas_path_new (root,
"M20,100 C20,50 100,50 100,100 S180,150 180,100",
NULL);
path = goo_canvas_path_new (root,
"M220,100 c0,-50 80,-50 80,0 s80,50 80,0",
NULL);
path = goo_canvas_path_new (root,
"M20,200 Q60,130 100,200 T180,200",
NULL);
path = goo_canvas_path_new (root,
"M220,200 q40,-70 80,0 t80,0",
NULL);
/* Test the elliptical arc commands: Aa. */
}
GtkWidget *
create_paths_page (void)
{
GtkWidget *vbox, *alignment, *frame, *label, *canvas;
GooCanvasModelSimple *canvas_model;
vbox = gtk_vbox_new (FALSE, 4);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
gtk_widget_show (vbox);
/* Instructions */
label = gtk_label_new ("Demo Paths");
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
/*gtk_widget_show (label);*/
/* Frame and canvas */
alignment = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
gtk_widget_show (alignment);
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_container_add (GTK_CONTAINER (alignment), frame);
gtk_widget_show (frame);
canvas = goo_canvas_view_new ();
canvas_model = goo_canvas_model_simple_new ();
gtk_widget_set_size_request (canvas, 600, 450);
goo_canvas_view_set_bounds (GOO_CANVAS_VIEW (canvas), 0, 0, 600, 450);
gtk_container_add (GTK_CONTAINER (frame), canvas);
gtk_widget_show (canvas);
create_paths (canvas_model);
goo_canvas_view_set_model (GOO_CANVAS_VIEW (canvas),
GOO_CANVAS_MODEL (canvas_model));
g_object_unref (canvas_model);
return vbox;
}
Index: demo.c
===================================================================
RCS file: /cvs/cairo/goocanvas/src/demo.c,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- demo.c 8 Apr 2006 13:14:17 -0000 1.6
+++ demo.c 10 Apr 2006 20:30:24 -0000 1.7
@@ -32,6 +32,7 @@
GtkWidget *create_canvas_scalability (void);
GtkWidget *create_grabs_page (void);
GtkWidget *create_events_page (void);
+GtkWidget *create_paths_page (void);
static void
@@ -1268,6 +1269,11 @@
create_events_page (),
gtk_label_new ("Events"));
#endif
+#if 1
+ gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+ create_paths_page (),
+ gtk_label_new ("Paths"));
+#endif
return window;
}
--- NEW FILE: goocanvaspath.c ---
/*
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
* goocanvaspath.c - a path item, very similar to the SVG path element.
*/
#include <config.h>
#include <gtk/gtk.h>
#include "goocanvaspath.h"
#include "goocanvaspathview.h"
enum {
PROP_0,
PROP_DATA,
};
static void goo_canvas_path_finalize (GObject *object);
static void item_interface_init (GooCanvasItemIface *iface);
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);
G_DEFINE_TYPE_WITH_CODE (GooCanvasPath, goo_canvas_path,
GOO_TYPE_CANVAS_ITEM_SIMPLE,
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM,
item_interface_init));
static void
goo_canvas_path_class_init (GooCanvasPathClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) 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;
g_object_class_install_property (gobject_class, PROP_DATA,
g_param_spec_string ("data",
NULL, NULL,
NULL,
G_PARAM_WRITABLE));
}
static void
goo_canvas_path_init (GooCanvasPath *path)
{
}
static void
goo_canvas_path_finalize (GObject *object)
{
GooCanvasPath *path = (GooCanvasPath*) object;
if (path->commands)
g_array_free (path->commands, TRUE);
G_OBJECT_CLASS (goo_canvas_path_parent_class)->finalize (object);
}
static void
goo_canvas_path_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
/*GooCanvasPath *path = (GooCanvasPath*) object;*/
switch (prop_id)
{
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static gdouble
parse_double (gchar **pos,
gboolean *error)
{
gdouble result;
gchar *p;
/* If an error has already occurred, just return. */
if (*error)
return 0;
/* Skip whitespace and commas. */
p = *pos;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ',')
p++;
/* Parse the double, and set pos to the first char after it. */
result = g_ascii_strtod (p, pos);
/* If no characters were parsed, set the error flag. */
if (p == *pos)
*error = TRUE;
return result;
}
static gint
parse_flag (gchar **pos,
gboolean *error)
{
gint result = 0;
gchar *p;
/* If an error has already occurred, just return. */
if (*error)
return 0;
/* Skip whitespace and commas. */
p = *pos;
while (*p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' || *p == ',')
p++;
/* The flag must be a '0' or a '1'. */
if (*p == '0')
result = 0;
else if (*p == '1')
result = 1;
else
{
*error = TRUE;
return 0;
}
*pos = p + 1;
return result;
}
static void
goo_canvas_path_parse_data (GooCanvasPath *path,
const gchar *path_data)
{
GooCanvasPathCommand cmd;
gchar *pos, command = 0, next_command;
gboolean error = FALSE;
/* Free the current path data. */
if (path->commands)
g_array_free (path->commands, TRUE);
path->commands = g_array_new (0, 0, sizeof (GooCanvasPathCommand));
pos = (gchar*) path_data;
for (;;)
{
while (*pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n')
pos++;
if (!*pos)
break;
next_command = *pos;
/* If there is no command letter, we use the same command as the last
one, except for the first command, and 'moveto' (which becomes
'lineto'). */
if ((next_command < 'a' || next_command > 'z')
&& (next_command < 'A' || next_command > 'Z'))
{
/* If this is the first command, then set the error flag and assume
a simple close-path command. */
if (!command)
{
error = TRUE;
command = 'Z';
}
/* moveto commands change to lineto. */
else if (command == 'm')
command = 'l';
else if (command == 'M')
command = 'L';
}
else
{
command = next_command;
pos++;
}
cmd.simple.relative = 0;
switch (command)
{
/* Simple commands like moveto and lineto: MmZzLlHhVv. */
case 'm':
cmd.simple.relative = 1;
case 'M':
cmd.simple.type = GOO_CANVAS_PATH_MOVE_TO;
cmd.simple.x = parse_double (&pos, &error);
cmd.simple.y = parse_double (&pos, &error);
break;
case 'Z':
case 'z':
cmd.simple.type = GOO_CANVAS_PATH_CLOSE_PATH;
break;
case 'l':
cmd.simple.relative = 1;
case 'L':
cmd.simple.type = GOO_CANVAS_PATH_LINE_TO;
cmd.simple.x = parse_double (&pos, &error);
cmd.simple.y = parse_double (&pos, &error);
break;
case 'h':
cmd.simple.relative = 1;
case 'H':
cmd.simple.type = GOO_CANVAS_PATH_HORIZONTAL_LINE_TO;
cmd.simple.x = parse_double (&pos, &error);
break;
case 'v':
cmd.simple.relative = 1;
case 'V':
cmd.simple.type = GOO_CANVAS_PATH_VERTICAL_LINE_TO;
cmd.simple.y = parse_double (&pos, &error);
break;
/* Bezier curve commands: CcSsQqTt. */
case 'c':
cmd.curve.relative = 1;
case 'C':
cmd.curve.type = GOO_CANVAS_PATH_CURVE_TO;
cmd.curve.x1 = parse_double (&pos, &error);
cmd.curve.y1 = parse_double (&pos, &error);
cmd.curve.x2 = parse_double (&pos, &error);
cmd.curve.y2 = parse_double (&pos, &error);
cmd.curve.x = parse_double (&pos, &error);
cmd.curve.y = parse_double (&pos, &error);
break;
case 's':
cmd.curve.relative = 1;
case 'S':
cmd.curve.type = GOO_CANVAS_PATH_SMOOTH_CURVE_TO;
cmd.curve.x2 = parse_double (&pos, &error);
cmd.curve.y2 = parse_double (&pos, &error);
cmd.curve.x = parse_double (&pos, &error);
cmd.curve.y = parse_double (&pos, &error);
break;
case 'q':
cmd.curve.relative = 1;
case 'Q':
cmd.curve.type = GOO_CANVAS_PATH_QUADRATIC_CURVE_TO;
cmd.curve.x1 = parse_double (&pos, &error);
cmd.curve.y1 = parse_double (&pos, &error);
cmd.curve.x = parse_double (&pos, &error);
cmd.curve.y = parse_double (&pos, &error);
break;
case 't':
cmd.curve.relative = 1;
case 'T':
cmd.curve.type = GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO;
cmd.curve.x = parse_double (&pos, &error);
cmd.curve.y = parse_double (&pos, &error);
break;
/* The elliptical arc commands: Aa. */
case 'a':
cmd.arc.relative = 1;
case 'A':
cmd.arc.type = GOO_CANVAS_PATH_ELLIPTICAL_ARC;
cmd.arc.rx = parse_double (&pos, &error);
cmd.arc.ry = parse_double (&pos, &error);
cmd.arc.x_axis_rotation = parse_double (&pos, &error);
cmd.arc.large_arc_flag = parse_flag (&pos, &error);
cmd.arc.sweep_flag = parse_flag (&pos, &error);
cmd.arc.x = parse_double (&pos, &error);
cmd.arc.y = parse_double (&pos, &error);
break;
default:
error = TRUE;
break;
}
/* If an error has occurred, return without adding the new command.
Thus we include everything in the path up to the error, like SVG. */
if (error)
return;
g_array_append_val (path->commands, cmd);
}
}
static void
goo_canvas_path_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GooCanvasPath *path = (GooCanvasPath*) object;
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) object;
switch (prop_id)
{
case PROP_DATA:
goo_canvas_path_parse_data (path, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
if (simple->parent)
goo_canvas_item_simple_emit_changed (simple, TRUE);
}
static GooCanvasItemView*
goo_canvas_path_create_view (GooCanvasItem *item,
GooCanvasView *canvas_view,
GooCanvasItemView *parent_view)
{
return goo_canvas_path_view_new (parent_view, (GooCanvasPath*) item);
}
static void
item_interface_init (GooCanvasItemIface *iface)
{
iface->create_view = goo_canvas_path_create_view;
}
/**
* goo_canvas_path_new:
* @parent: the parent item, or %NULL. If a parent is specified, it will assume
* ownership of the item, and the item will automatically be freed when it is
* removed from the parent. Otherwise call g_object_unref() to free it.
* @path_data: a string specifying the path, using the same syntax as the path
* element in SVG.
* @...: optional pairs of property names and values, and a terminating %NULL.
*
* Creates a new path item.
*
* Returns: a new path item.
**/
GooCanvasItem*
goo_canvas_path_new (GooCanvasItem *parent,
gchar *path_data,
...)
{
GooCanvasItem *item;
GooCanvasPath *path;
va_list var_args;
const char *first_arg_name;
item = g_object_new (GOO_TYPE_CANVAS_PATH, NULL);
path = GOO_CANVAS_PATH (item);
goo_canvas_path_parse_data (path, path_data);
va_start (var_args, path_data);
first_arg_name = va_arg (var_args, char*);
g_object_set_valist (G_OBJECT (item), first_arg_name, var_args);
va_end (var_args);
if (parent)
{
goo_canvas_item_add_child (parent, item, -1);
g_object_unref (item);
}
return item;
}
--- NEW FILE: goocanvaspath.h ---
/*
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
* goocanvaspath.h - a path item, very similar to the SVG path element.
*/
#ifndef __GOO_CANVAS_PATH_H__
#define __GOO_CANVAS_PATH_H__
#include <gtk/gtk.h>
#include "goocanvasitemsimple.h"
G_BEGIN_DECLS
#define GOO_TYPE_CANVAS_PATH (goo_canvas_path_get_type ())
#define GOO_CANVAS_PATH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_CANVAS_PATH, GooCanvasPath))
#define GOO_CANVAS_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_CANVAS_PATH, GooCanvasPathClass))
#define GOO_IS_CANVAS_PATH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOO_TYPE_CANVAS_PATH))
#define GOO_IS_CANVAS_PATH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOO_TYPE_CANVAS_PATH))
#define GOO_CANVAS_PATH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOO_TYPE_CANVAS_PATH, GooCanvasPathClass))
typedef enum
{
/* Simple commands like moveto and lineto: MmZzLlHhVv. */
GOO_CANVAS_PATH_MOVE_TO,
GOO_CANVAS_PATH_CLOSE_PATH,
GOO_CANVAS_PATH_LINE_TO,
GOO_CANVAS_PATH_HORIZONTAL_LINE_TO,
GOO_CANVAS_PATH_VERTICAL_LINE_TO,
/* Bezier curve commands: CcSsQqTt. */
GOO_CANVAS_PATH_CURVE_TO,
GOO_CANVAS_PATH_SMOOTH_CURVE_TO,
GOO_CANVAS_PATH_QUADRATIC_CURVE_TO,
GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO,
/* The elliptical arc commands: Aa. */
GOO_CANVAS_PATH_ELLIPTICAL_ARC
} GooCanvasPathCommandType;
typedef union _GooCanvasPathCommand GooCanvasPathCommand;
/* Note that the command type is always the first element in each struct, so
we can always use it whatever type of command it is. */
union _GooCanvasPathCommand
{
/* Simple commands like moveto and lineto: MmZzLlHhVv. */
struct {
guint type : 5; /* GooCanvasPathCommandType */
guint relative : 1;
gdouble x, y;
} simple;
/* Bezier curve commands: CcSsQqTt. */
struct {
guint type : 5; /* GooCanvasPathCommandType */
guint relative : 1;
gdouble x, y, x1, y1, x2, y2;
} curve;
/* The elliptical arc commands: Aa. */
struct {
guint type : 5; /* GooCanvasPathCommandType */
guint relative : 1;
guint large_arc_flag : 1;
guint sweep_flag : 1;
gdouble rx, ry, x_axis_rotation, x, y;
} arc;
};
typedef struct _GooCanvasPath GooCanvasPath;
typedef struct _GooCanvasPathClass GooCanvasPathClass;
struct _GooCanvasPath
{
GooCanvasItemSimple parent;
/* The path data, an array of GooCanvasPathCommand. Apps can modify this
directly, but call goo_canvas_item_simple_emit_changed (item, TRUE)
afterwards to notify the views. */
GArray *commands;
};
struct _GooCanvasPathClass
{
GooCanvasItemSimpleClass parent_class;
};
GType goo_canvas_path_get_type (void) G_GNUC_CONST;
GooCanvasItem* goo_canvas_path_new (GooCanvasItem *parent,
gchar *path_data,
...);
G_END_DECLS
#endif /* __GOO_CANVAS_PATH_H__ */
--- NEW FILE: goocanvaspathview.c ---
/*
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
* goocanvaspathview.c - view for path item.
*/
#include <config.h>
#include <gtk/gtk.h>
#include "goocanvasview.h"
#include "goocanvaspathview.h"
static void canvas_item_view_interface_init (GooCanvasItemViewIface *iface);
static void goo_canvas_path_view_finalize (GObject *object);
static void on_path_changed (GooCanvasPath *path,
gboolean recompute_bounds,
GooCanvasPathView *view);
G_DEFINE_TYPE_WITH_CODE (GooCanvasPathView, goo_canvas_path_view,
G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (GOO_TYPE_CANVAS_ITEM_VIEW,
canvas_item_view_interface_init));
static void
goo_canvas_path_view_class_init (GooCanvasPathViewClass *klass)
{
GObjectClass *gobject_class = (GObjectClass*) klass;
gobject_class->finalize = goo_canvas_path_view_finalize;
}
static void
goo_canvas_path_view_init (GooCanvasPathView *path_view)
{
GooCanvasBounds *bounds = &path_view->bounds;
bounds->x1 = bounds->y1 = bounds->x2 = bounds->y2 = 0;
}
GooCanvasItemView*
goo_canvas_path_view_new (GooCanvasItemView *parent_view,
GooCanvasPath *path)
{
GooCanvasPathView *view;
view = g_object_new (GOO_TYPE_CANVAS_PATH_VIEW, NULL);
view->need_update = TRUE;
view->parent_view = parent_view;
view->path = path;
g_signal_connect (path, "changed", G_CALLBACK (on_path_changed), view);
return (GooCanvasItemView*) view;
}
static void
goo_canvas_path_view_finalize (GObject *object)
{
/*GooCanvasPathView *o = (GooCanvasPathView*) object;*/
G_OBJECT_CLASS (goo_canvas_path_view_parent_class)->finalize (object);
}
static void
goo_canvas_path_view_create_path (GooCanvasPath *path,
cairo_t *cr)
{
GooCanvasPathCommand *cmd;
GooCanvasPathCommandType prev_cmd_type = GOO_CANVAS_PATH_CLOSE_PATH;
gdouble x = 0, y = 0, path_start_x = 0, path_start_y = 0;
gdouble last_control_point_x, last_control_point_y, x1, y1, x2, y2;
gdouble qx1, qy1, qx2, qy2;
gint i;
cairo_new_path (cr);
if (!path->commands || path->commands->len == 0)
return;
for (i = 0; i < path->commands->len; i++)
{
cmd = &g_array_index (path->commands, GooCanvasPathCommand, i);
switch (cmd->simple.type)
{
/* Simple commands like moveto and lineto: MmZzLlHhVv. */
case GOO_CANVAS_PATH_MOVE_TO:
if (cmd->simple.relative)
{
x += cmd->simple.x;
y += cmd->simple.y;
}
else
{
x = cmd->simple.x;
y = cmd->simple.y;
}
path_start_x = x;
path_start_y = y;
cairo_move_to (cr, x, y);
break;
case GOO_CANVAS_PATH_CLOSE_PATH:
x = path_start_x;
y = path_start_y;
cairo_close_path (cr);
break;
case GOO_CANVAS_PATH_LINE_TO:
if (cmd->simple.relative)
{
x += cmd->simple.x;
y += cmd->simple.y;
}
else
{
x = cmd->simple.x;
y = cmd->simple.y;
}
cairo_line_to (cr, x, y);
break;
case GOO_CANVAS_PATH_HORIZONTAL_LINE_TO:
if (cmd->simple.relative)
x += cmd->simple.x;
else
x = cmd->simple.x;
cairo_line_to (cr, x, y);
break;
case GOO_CANVAS_PATH_VERTICAL_LINE_TO:
if (cmd->simple.relative)
y += cmd->simple.y;
else
y = cmd->simple.y;
cairo_line_to (cr, x, y);
break;
/* Bezier curve commands: CcSsQqTt. */
case GOO_CANVAS_PATH_CURVE_TO:
if (cmd->curve.relative)
{
cairo_curve_to (cr, x + cmd->curve.x1, y + cmd->curve.y1,
x + cmd->curve.x2, y + cmd->curve.y2,
x + cmd->curve.x, y + cmd->curve.y);
last_control_point_x = x + cmd->curve.x2;
last_control_point_y = y + cmd->curve.y2;
x += cmd->curve.x;
y += cmd->curve.y;
}
else
{
cairo_curve_to (cr, cmd->curve.x1, cmd->curve.y1,
cmd->curve.x2, cmd->curve.y2,
cmd->curve.x, cmd->curve.y);
last_control_point_x = cmd->curve.x2;
last_control_point_y = cmd->curve.y2;
x = cmd->curve.x;
y = cmd->curve.y;
}
break;
case GOO_CANVAS_PATH_SMOOTH_CURVE_TO:
/* If the last command was a curveto or smooth curveto, we use the
reflection of the last control point about the current point as
the first control point of this curve. Otherwise we use the
current point as the first control point. */
if (prev_cmd_type == GOO_CANVAS_PATH_CURVE_TO
|| prev_cmd_type == GOO_CANVAS_PATH_SMOOTH_CURVE_TO)
{
x1 = x + (x - last_control_point_x);
y1 = y + (y - last_control_point_y);
}
else
{
x1 = x;
y1 = y;
}
if (cmd->curve.relative)
{
cairo_curve_to (cr, x1, y1, x + cmd->curve.x2, y + cmd->curve.y2,
x + cmd->curve.x, y + cmd->curve.y);
last_control_point_x = x + cmd->curve.x2;
last_control_point_y = y + cmd->curve.y2;
x += cmd->curve.x;
y += cmd->curve.y;
}
else
{
cairo_curve_to (cr, x1, y1, cmd->curve.x2, cmd->curve.y2,
cmd->curve.x, cmd->curve.y);
last_control_point_x = cmd->curve.x2;
last_control_point_y = cmd->curve.y2;
x = cmd->curve.x;
y = cmd->curve.y;
}
break;
case GOO_CANVAS_PATH_QUADRATIC_CURVE_TO:
if (cmd->curve.relative)
{
qx1 = x + cmd->curve.x1;
qy1 = y + cmd->curve.y1;
qx2 = x + cmd->curve.x;
qy2 = y + cmd->curve.y;
}
else
{
qx1 = cmd->curve.x1;
qy1 = cmd->curve.y1;
qx2 = cmd->curve.x;
qy2 = cmd->curve.y;
}
/* We need to convert the quadratic into a cubic bezier. */
x1 = x + (qx1 - x) * 2.0 / 3.0;
y1 = y + (qy1 - y) * 2.0 / 3.0;
x2 = x1 + (qx2 - x) / 3.0;
y2 = y1 + (qy2 - y) / 3.0;
cairo_curve_to (cr, x1, y1, x2, y2, qx2, qy2);
x = qx2;
y = qy2;
last_control_point_x = qx1;
last_control_point_y = qy1;
break;
case GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO:
/* If the last command was a quadratic or smooth quadratic, we use
the reflection of the last control point about the current point
as the first control point of this curve. Otherwise we use the
current point as the first control point. */
if (prev_cmd_type == GOO_CANVAS_PATH_QUADRATIC_CURVE_TO
|| prev_cmd_type == GOO_CANVAS_PATH_SMOOTH_QUADRATIC_CURVE_TO)
{
qx1 = x + (x - last_control_point_x);
qy1 = y + (y - last_control_point_y);
}
else
{
qx1 = x;
qy1 = y;
}
if (cmd->curve.relative)
{
qx2 = x + cmd->curve.x;
qy2 = y + cmd->curve.y;
}
else
{
qx2 = cmd->curve.x;
qy2 = cmd->curve.y;
}
/* We need to convert the quadratic into a cubic bezier. */
x1 = x + (qx1 - x) * 2.0 / 3.0;
y1 = y + (qy1 - y) * 2.0 / 3.0;
x2 = x1 + (qx2 - x) / 3.0;
y2 = y1 + (qy2 - y) / 3.0;
cairo_curve_to (cr, x1, y1, x2, y2, qx2, qy2);
x = qx2;
y = qy2;
last_control_point_x = qx1;
last_control_point_y = qy1;
break;
/* The elliptical arc commands: Aa. */
case GOO_CANVAS_PATH_ELLIPTICAL_ARC:
/* If the endpoints are exactly the same, just return (See SVG). */
if (x == cmd->arc.x && y == cmd->arc.y)
return;
/* If either rx or ry is 0, do a simple lineto (See SVG). */
if (cmd->arc.rx == 0.0 || cmd->arc.ry == 0.0)
{
if (cmd->arc.relative)
{
x += cmd->arc.x;
y += cmd->arc.y;
}
else
{
x = cmd->arc.x;
y = cmd->arc.y;
}
cairo_line_to (cr, x, y);
return;
}
#if 0
/* Make sure rx & ry are positive. */
rx = cmd->arc.rx > 0 ? cmd->arc.rx : - cmd->arc.rx;
ry = cmd->arc.ry > 0 ? cmd->arc.ry : - cmd->arc.ry;
/* FIXME: Need to rotate according to x_axis_rotation, and scale
according to rx & ry. */
/*cairo_arc (cr, xc, yc, r, angle1, angle2);*/
#endif
break;
}
prev_cmd_type = cmd->simple.type;
}
}
static GooCanvasItemView*
goo_canvas_path_view_get_parent_view (GooCanvasItemView *view)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
return path_view->parent_view;
}
static void
goo_canvas_path_view_set_parent_view (GooCanvasItemView *view,
GooCanvasItemView *parent_view)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
path_view->parent_view = parent_view;
}
static GooCanvasItem*
goo_canvas_path_view_get_item (GooCanvasItemView *view)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
return (GooCanvasItem*) path_view->path;
}
static GooCanvasBounds*
goo_canvas_path_view_get_bounds (GooCanvasItemView *view)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
if (path_view->need_update)
goo_canvas_item_view_ensure_updated (view);
return &path_view->bounds;
}
static GooCanvasItemView*
goo_canvas_path_view_get_item_at (GooCanvasItemView *view,
gdouble x,
gdouble y,
cairo_t *cr,
gboolean is_pointer_event,
gboolean parent_visible,
gdouble scale)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
GooCanvasPath *path = path_view->path;
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) path;
GooCanvasItemView *found_view = NULL;
double user_x = x, user_y = y;
GooCanvasPointerEvents pointer_events = GOO_CANVAS_EVENTS_ALL;
if (path_view->need_update)
goo_canvas_item_view_ensure_updated (view);
if (!path->commands || path->commands->len == 0)
return NULL;
#if 0
g_print ("In path_view_get_item_at: %g, %g\n", x, y);
#endif
/* Check if the item should receive events. */
if (is_pointer_event)
{
if (simple->pointer_events == GOO_CANVAS_EVENTS_NONE)
return NULL;
if (simple->pointer_events & GOO_CANVAS_EVENTS_VISIBLE_MASK
&& (!parent_visible
|| simple->visibility == GOO_CANVAS_ITEM_INVISIBLE
|| (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
&& scale < simple->visibility_threshold)))
return NULL;
pointer_events = simple->pointer_events;
}
cairo_save (cr);
if (simple->transform)
cairo_transform (cr, simple->transform);
cairo_device_to_user (cr, &user_x, &user_y);
goo_canvas_path_view_create_path (path, cr);
if (goo_canvas_item_simple_check_in_path (simple, user_x, user_y, cr,
pointer_events))
found_view = view;
cairo_restore (cr);
return found_view;
}
static void
goo_canvas_path_view_compute_bounds (GooCanvasPathView *view,
cairo_t *cr,
GooCanvasBounds *bounds)
{
GooCanvasPath *path = view->path;
GooCanvasItemSimple *simple = GOO_CANVAS_ITEM_SIMPLE (path);
goo_canvas_path_view_create_path (path, cr);
goo_canvas_item_simple_get_path_bounds (simple, cr, bounds);
#if 0
g_print ("Path view bounds: %g, %g - %g, %g\n",
bounds->x1, bounds->y1, bounds->x2, bounds->y2);
#endif
}
static GooCanvasBounds*
goo_canvas_path_view_update (GooCanvasItemView *view,
gboolean entire_tree,
cairo_t *cr)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) path_view->path;
GooCanvasView *canvas_view;
GooCanvasBounds *bounds = &path_view->bounds;
if (entire_tree || path_view->need_update)
{
path_view->need_update = FALSE;
cairo_save (cr);
if (simple->transform)
cairo_transform (cr, simple->transform);
canvas_view = goo_canvas_item_view_get_canvas_view (path_view->parent_view);
/* Request a redraw of the existing bounds. */
goo_canvas_view_request_redraw (canvas_view, bounds);
/* Compute the new bounds. */
goo_canvas_path_view_compute_bounds (path_view, cr, bounds);
/* Request a redraw of the new bounds. */
goo_canvas_view_request_redraw (canvas_view, bounds);
cairo_restore (cr);
}
return bounds;
}
static void
goo_canvas_path_view_paint (GooCanvasItemView *view,
cairo_t *cr,
GooCanvasBounds *bounds,
gdouble scale)
{
GooCanvasPathView *path_view = (GooCanvasPathView*) view;
GooCanvasPath *path = path_view->path;
GooCanvasItemSimple *simple = (GooCanvasItemSimple*) path;
#if 0
g_print ("Painting path item %p\n", view);
#endif
if (!path->commands || path->commands->len == 0)
return;
/* Check if the item should be visible. */
if (simple->visibility == GOO_CANVAS_ITEM_INVISIBLE
|| (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
&& scale < simple->visibility_threshold))
return;
cairo_save (cr);
if (simple->transform)
cairo_transform (cr, simple->transform);
goo_canvas_path_view_create_path (path, cr);
goo_canvas_item_simple_paint_path (simple, cr);
cairo_restore (cr);
}
static void
canvas_item_view_interface_init (GooCanvasItemViewIface *iface)
{
iface->get_parent_view = goo_canvas_path_view_get_parent_view;
iface->set_parent_view = goo_canvas_path_view_set_parent_view;
iface->get_item = goo_canvas_path_view_get_item;
iface->get_bounds = goo_canvas_path_view_get_bounds;
iface->get_item_at = goo_canvas_path_view_get_item_at;
iface->update = goo_canvas_path_view_update;
iface->paint = goo_canvas_path_view_paint;
}
static void
on_path_changed (GooCanvasPath *path,
gboolean recompute_bounds,
GooCanvasPathView *view)
{
GooCanvasView *canvas_view;
#if 0
g_print ("Path changed\n");
#endif
if (recompute_bounds)
{
if (!view->need_update)
{
view->need_update = TRUE;
goo_canvas_item_view_request_update (view->parent_view);
}
}
else
{
canvas_view = goo_canvas_item_view_get_canvas_view (view->parent_view);
goo_canvas_view_request_redraw (canvas_view, &view->bounds);
}
}
--- NEW FILE: goocanvaspathview.h ---
/*
* GooCanvas. Copyright (C) 2005-6 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
* goocanvaspathview.h - view for path item.
*/
#ifndef __GOO_CANVAS_PATH_VIEW_H__
#define __GOO_CANVAS_PATH_VIEW_H__
#include <gtk/gtk.h>
#include "goocanvasitemview.h"
#include "goocanvaspath.h"
G_BEGIN_DECLS
#define GOO_TYPE_CANVAS_PATH_VIEW (goo_canvas_path_view_get_type ())
#define GOO_CANVAS_PATH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GOO_TYPE_CANVAS_PATH_VIEW, GooCanvasPathView))
#define GOO_CANVAS_PATH_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GOO_TYPE_CANVAS_PATH_VIEW, GooCanvasPathViewClass))
#define GOO_IS_CANVAS_PATH_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GOO_TYPE_CANVAS_PATH_VIEW))
#define GOO_IS_CANVAS_PATH_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GOO_TYPE_CANVAS_PATH_VIEW))
#define GOO_CANVAS_PATH_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GOO_TYPE_CANVAS_PATH_VIEW, GooCanvasPathViewClass))
typedef struct _GooCanvasPathView GooCanvasPathView;
typedef struct _GooCanvasPathViewClass GooCanvasPathViewClass;
struct _GooCanvasPathView
{
GObject parent;
/* The parent view. */
GooCanvasItemView *parent_view;
/* The item in the model. */
GooCanvasPath *path;
/* The bounds of the item, relative to the entire canvas. */
GooCanvasBounds bounds;
/* This is TRUE if we need to recompute our bounds & repaint. */
guint need_update : 1;
};
struct _GooCanvasPathViewClass
{
GObjectClass parent_class;
};
GType goo_canvas_path_view_get_type (void) G_GNUC_CONST;
GooCanvasItemView* goo_canvas_path_view_new (GooCanvasItemView *parent_view,
GooCanvasPath *path);
G_END_DECLS
#endif /* __GOO_CANVAS_PATH_VIEW_H__ */
Index: goocanvaspolylineview.c
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvaspolylineview.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- goocanvaspolylineview.c 8 Apr 2006 13:14:17 -0000 1.5
+++ goocanvaspolylineview.c 10 Apr 2006 20:30:24 -0000 1.6
@@ -2,7 +2,7 @@
* GooCanvas. Copyright (C) 2005 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
- * goocanvaspolylineview.c -
+ * goocanvaspolylineview.c - view for polyline item.
*/
#include <config.h>
#include <gtk/gtk.h>
@@ -370,7 +370,7 @@
goo_canvas_polyline_view_paint (GooCanvasItemView *view,
cairo_t *cr,
GooCanvasBounds *bounds,
- gdouble effective_scale)
+ gdouble scale)
{
GooCanvasPolylineView *polyline_view = (GooCanvasPolylineView*) view;
GooCanvasPolyline *polyline = polyline_view->polyline;
@@ -386,7 +386,7 @@
/* Check if the item should be visible. */
if (simple->visibility == GOO_CANVAS_ITEM_INVISIBLE
|| (simple->visibility == GOO_CANVAS_ITEM_VISIBLE_ABOVE_THRESHOLD
- && effective_scale < simple->visibility_threshold))
+ && scale < simple->visibility_threshold))
return;
cairo_save (cr);
Index: goocanvaspolylineview.h
===================================================================
RCS file: /cvs/cairo/goocanvas/src/goocanvaspolylineview.h,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -d -r1.1.1.1 -r1.2
--- goocanvaspolylineview.h 15 Dec 2005 15:32:02 -0000 1.1.1.1
+++ goocanvaspolylineview.h 10 Apr 2006 20:30:24 -0000 1.2
@@ -2,7 +2,7 @@
* GooCanvas. Copyright (C) 2005 Damon Chaplin.
* Released under the GNU LGPL license. See COPYING for details.
*
- * goocanvaspolylineview.h -
+ * goocanvaspolylineview.h - view for polyline item.
*/
#ifndef __GOO_CANVAS_POLYLINE_VIEW_H__
#define __GOO_CANVAS_POLYLINE_VIEW_H__
More information about the cairo-commit
mailing list