1 /*
2 * GooCanvas Demo. Copyright (C) 2007 Damon Chaplin.
3 * Released under the GNU LGPL license. See COPYING for details.
4 *
5 * demo-large-rect.c - a demo item that exceeds the cairo 16-bit size limit.
6 * Note that it doesn't support rotations or shears.
7 */
8 #include <config.h>
9 #include "goocanvas.h"
10 #include "demo-large-rect.h"
11
12
13 /* Use the GLib convenience macro to define the type. GooDemoLargeRect is the
14 class struct, goo_demo_large_rect is the function prefix, and our class is a
15 subclass of GOO_TYPE_CANVAS_ITEM_SIMPLE. */
G_DEFINE_TYPE(GooDemoLargeRect,goo_demo_large_rect,GOO_TYPE_CANVAS_ITEM_SIMPLE)16 G_DEFINE_TYPE (GooDemoLargeRect, goo_demo_large_rect,
17 GOO_TYPE_CANVAS_ITEM_SIMPLE)
18
19
20 /* The standard object initialization function. */
21 static void
22 goo_demo_large_rect_init (GooDemoLargeRect *demo_large_rect)
23 {
24 demo_large_rect->x = 0.0;
25 demo_large_rect->y = 0.0;
26 demo_large_rect->width = 0.0;
27 demo_large_rect->height = 0.0;
28 }
29
30
31 /* The convenience function to create new items. This should start with a
32 parent argument and end with a variable list of object properties to fit
33 in with the standard canvas items. */
34 GooCanvasItem*
goo_demo_large_rect_new(GooCanvasItem * parent,gdouble x,gdouble y,gdouble width,gdouble height,...)35 goo_demo_large_rect_new (GooCanvasItem *parent,
36 gdouble x,
37 gdouble y,
38 gdouble width,
39 gdouble height,
40 ...)
41 {
42 GooCanvasItem *item;
43 GooDemoLargeRect *demo_large_rect;
44 const char *first_property;
45 va_list var_args;
46
47 item = g_object_new (GOO_TYPE_DEMO_LARGE_RECT, NULL);
48
49 demo_large_rect = (GooDemoLargeRect*) item;
50 demo_large_rect->x = x;
51 demo_large_rect->y = y;
52 demo_large_rect->width = width;
53 demo_large_rect->height = height;
54
55 va_start (var_args, height);
56 first_property = va_arg (var_args, char*);
57 if (first_property)
58 g_object_set_valist ((GObject*) item, first_property, var_args);
59 va_end (var_args);
60
61 if (parent)
62 {
63 goo_canvas_item_add_child (parent, item, -1);
64 g_object_unref (item);
65 }
66
67 return item;
68 }
69
70
71 /* The update method. This is called when the canvas is initially shown and
72 also whenever the object is updated and needs to change its size and/or
73 shape. It should calculate its new bounds in its own coordinate space,
74 storing them in simple->bounds. */
75 static void
goo_demo_large_rect_update(GooCanvasItemSimple * simple,cairo_t * cr)76 goo_demo_large_rect_update (GooCanvasItemSimple *simple,
77 cairo_t *cr)
78 {
79 GooDemoLargeRect *item = (GooDemoLargeRect*) simple;
80 gdouble half_line_width;
81
82 /* We can quickly compute the bounds as being just the rectangle's size
83 plus half the line width around each edge. */
84 half_line_width = goo_canvas_item_simple_get_line_width (simple) / 2;
85
86 simple->bounds.x1 = item->x - half_line_width;
87 simple->bounds.y1 = item->y - half_line_width;
88 simple->bounds.x2 = item->x + item->width + half_line_width;
89 simple->bounds.y2 = item->y + item->height + half_line_width;
90 }
91
92
93 static void
create_large_rect_path(GooDemoLargeRect * rect,cairo_t * cr,const GooCanvasBounds * bounds,gdouble line_width,gdouble x,gdouble y,gdouble width,gdouble height)94 create_large_rect_path (GooDemoLargeRect *rect,
95 cairo_t *cr,
96 const GooCanvasBounds *bounds,
97 gdouble line_width,
98 gdouble x,
99 gdouble y,
100 gdouble width,
101 gdouble height)
102 {
103 GooCanvasItem *item = (GooCanvasItem*) rect;
104 GooCanvasItemSimple *simple = (GooCanvasItemSimple*) rect;
105 GooCanvas *canvas = simple->canvas;
106 GooCanvasBounds tmp_bounds = *bounds;
107 gdouble x1 = x, y1 = y, x2 = x + width, y2 = y + height;
108
109 /* Transform the coordinates to the canvas device space, so we can clamp
110 the line to the bounds to be painted. */
111 goo_canvas_convert_from_item_space (canvas, item, &x1, &y1);
112 goo_canvas_convert_from_item_space (canvas, item, &x2, &y2);
113
114 /* Extend the bounds a bit to account for the line width, so when we clamp
115 the rect to the bounds the outside edges aren't visible. */
116 tmp_bounds.x1 -= line_width;
117 tmp_bounds.y1 -= line_width;
118 tmp_bounds.x2 += line_width;
119 tmp_bounds.y2 += line_width;
120
121 /* If the rect is completely outside the bounds just return. */
122 if (x1 > tmp_bounds.x2 || x2 < tmp_bounds.x1
123 || y1 > tmp_bounds.y2 || y2 < tmp_bounds.y1)
124 return;
125
126 /* Clamp the rect to the bounds. */
127 if (x1 < tmp_bounds.x1)
128 x1 = tmp_bounds.x1;
129 if (x2 > tmp_bounds.x2)
130 x2 = tmp_bounds.x2;
131
132 if (y1 < tmp_bounds.y1)
133 y1 = tmp_bounds.y1;
134 if (y2 > tmp_bounds.y2)
135 y2 = tmp_bounds.y2;
136
137 /* Convert back to item space. */
138 goo_canvas_convert_to_item_space (canvas, item, &x1, &y1);
139 goo_canvas_convert_to_item_space (canvas, item, &x2, &y2);
140
141 /* Create the path. */
142 cairo_move_to (cr, x1, y1);
143 cairo_line_to (cr, x2, y1);
144 cairo_line_to (cr, x2, y2);
145 cairo_line_to (cr, x1, y2);
146 cairo_close_path (cr);
147 }
148
149
150 /* The paint method. This should draw the item on the given cairo_t, using
151 the item's own coordinate space. */
152 static void
goo_demo_large_rect_paint(GooCanvasItemSimple * simple,cairo_t * cr,const GooCanvasBounds * bounds)153 goo_demo_large_rect_paint (GooCanvasItemSimple *simple,
154 cairo_t *cr,
155 const GooCanvasBounds *bounds)
156 {
157 GooDemoLargeRect *item = (GooDemoLargeRect*) simple;
158 gdouble line_width;
159
160 line_width = goo_canvas_item_simple_get_line_width (simple);
161 create_large_rect_path (item, cr, bounds, line_width,
162 item->x, item->y, item->width, item->height);
163 goo_canvas_item_simple_paint_path (simple, cr);
164 }
165
166
167 /* Hit detection. This should check if the given coordinate (in the item's
168 coordinate space) is within the item. If it is it should return TRUE,
169 otherwise it should return FALSE. */
170 static gboolean
goo_demo_large_rect_is_item_at(GooCanvasItemSimple * simple,gdouble x,gdouble y,cairo_t * cr,gboolean is_pointer_event)171 goo_demo_large_rect_is_item_at (GooCanvasItemSimple *simple,
172 gdouble x,
173 gdouble y,
174 cairo_t *cr,
175 gboolean is_pointer_event)
176 {
177 GooDemoLargeRect *item = (GooDemoLargeRect*) simple;
178 gdouble half_line_width;
179
180 /* We assume the item covers its rectangle + line widths. */
181 half_line_width = goo_canvas_item_simple_get_line_width (simple) / 2;
182
183 if ((x < item->x - half_line_width)
184 || (x > item->x + item->width + half_line_width)
185 || (y < item->y - half_line_width)
186 || (y > item->y + item->height + half_line_width))
187 return FALSE;
188
189 return TRUE;
190 }
191
192
193 /* The class initialization function. Here we set the class' update(), paint()
194 and is_item_at() methods. */
195 static void
goo_demo_large_rect_class_init(GooDemoLargeRectClass * klass)196 goo_demo_large_rect_class_init (GooDemoLargeRectClass *klass)
197 {
198 GooCanvasItemSimpleClass *simple_class = (GooCanvasItemSimpleClass*) klass;
199
200 simple_class->simple_update = goo_demo_large_rect_update;
201 simple_class->simple_paint = goo_demo_large_rect_paint;
202 simple_class->simple_is_item_at = goo_demo_large_rect_is_item_at;
203 }
204
205
206