1 /* This file is part of Ganv.
2 * Copyright 2007-2016 David Robillard <http://drobilla.net>
3 *
4 * Ganv is free software: you can redistribute it and/or modify it under the
5 * terms of the GNU General Public License as published by the Free Software
6 * Foundation, either version 3 of the License, or any later version.
7 *
8 * Ganv is distributed in the hope that it will be useful, but WITHOUT ANY
9 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
11 *
12 * You should have received a copy of the GNU General Public License along
13 * with Ganv. If not, see <http://www.gnu.org/licenses/>.
14 */
15
16 /* Based on GnomeCanvas, by Federico Mena <federico@nuclecu.unam.mx>
17 * and Raph Levien <raph@gimp.org>
18 * Copyright 1997-2000 Free Software Foundation
19 */
20
21 #include "ganv-marshal.h"
22 #include "ganv-private.h"
23 #include "gettext.h"
24
25 #include "ganv/item.h"
26 #include "ganv/types.h"
27
28 #include <gdk/gdk.h>
29 #include <glib-object.h>
30 #include <glib.h>
31 #include <gtk/gtk.h>
32
33 #include <stdarg.h>
34 #include <stdio.h>
35
36 /* All canvas items are derived from GanvItem. The only information a GanvItem
37 * contains is its parent canvas, its parent canvas item, its bounding box in
38 * world coordinates, and its current affine transformation.
39 *
40 * Items inside a canvas are organized in a tree, where leaves are items
41 * without any children. Each canvas has a single root item, which can be
42 * obtained with the ganv_canvas_base_get_root() function.
43 *
44 * The abstract GanvItem class does not have any configurable or queryable
45 * attributes.
46 */
47
48 /* Update flags for items */
49 enum {
50 GANV_CANVAS_UPDATE_REQUESTED = 1 << 0,
51 GANV_CANVAS_UPDATE_AFFINE = 1 << 1,
52 GANV_CANVAS_UPDATE_VISIBILITY = 1 << 2
53 };
54
55 #define GCI_UPDATE_MASK (GANV_CANVAS_UPDATE_REQUESTED \
56 | GANV_CANVAS_UPDATE_AFFINE \
57 | GANV_CANVAS_UPDATE_VISIBILITY)
58
59 enum {
60 ITEM_PROP_0,
61 ITEM_PROP_PARENT,
62 ITEM_PROP_X,
63 ITEM_PROP_Y,
64 ITEM_PROP_MANAGED
65 };
66
67 enum {
68 ITEM_EVENT,
69 ITEM_LAST_SIGNAL
70 };
71
72 static guint item_signals[ITEM_LAST_SIGNAL];
73
74 G_DEFINE_TYPE_WITH_CODE(GanvItem, ganv_item, GTK_TYPE_OBJECT,
75 G_ADD_PRIVATE(GanvItem))
76
77 static GtkObjectClass* item_parent_class;
78
79 /* Object initialization function for GanvItem */
80 static void
ganv_item_init(GanvItem * item)81 ganv_item_init(GanvItem* item)
82 {
83 GanvItemPrivate* impl =
84 (GanvItemPrivate*)ganv_item_get_instance_private(item);
85
86 item->object.flags |= GANV_ITEM_VISIBLE;
87 item->impl = impl;
88 item->impl->managed = FALSE;
89 item->impl->wrapper = NULL;
90 }
91
92 /**
93 * ganv_item_new:
94 * @parent: The parent group for the new item.
95 * @type: The object type of the item.
96 * @first_arg_name: A list of object argument name/value pairs, NULL-terminated,
97 * used to configure the item. For example, "fill_color", "black",
98 * "width_units", 5.0, NULL.
99 * @...: first argument value, second argument name, second argument value, ...
100 *
101 * Creates a new canvas item with @parent as its parent group. The item is
102 * created at the top of its parent's stack, and starts up as visible. The item
103 * is of the specified @type, for example, it can be
104 * ganv_canvas_rect_get_type(). The list of object arguments/value pairs is
105 * used to configure the item. If you need to pass construct time parameters, you
106 * should use g_object_new() to pass the parameters and
107 * ganv_item_construct() to set up the canvas item.
108 *
109 * Return value: (transfer full): The newly-created item.
110 **/
111 GanvItem*
ganv_item_new(GanvItem * parent,GType type,const gchar * first_arg_name,...)112 ganv_item_new(GanvItem* parent, GType type, const gchar* first_arg_name, ...)
113 {
114 g_return_val_if_fail(g_type_is_a(type, ganv_item_get_type()), NULL);
115
116 GanvItem* item = GANV_ITEM(g_object_new(type, NULL));
117
118 va_list args;
119 va_start(args, first_arg_name);
120 ganv_item_construct(item, parent, first_arg_name, args);
121 va_end(args);
122
123 return item;
124 }
125
126 /* Performs post-creation operations on a canvas item (adding it to its parent
127 * group, etc.)
128 */
129 static void
item_post_create_setup(GanvItem * item)130 item_post_create_setup(GanvItem* item)
131 {
132 GanvItemClass* parent_class = GANV_ITEM_GET_CLASS(item->impl->parent);
133 if (!item->impl->managed) {
134 if (parent_class->add) {
135 parent_class->add(item->impl->parent, item);
136 } else {
137 g_warning("item added to non-parent item\n");
138 }
139 }
140 ganv_canvas_request_redraw_w(item->impl->canvas,
141 item->impl->x1, item->impl->y1,
142 item->impl->x2 + 1, item->impl->y2 + 1);
143 ganv_canvas_set_need_repick(item->impl->canvas);
144 }
145
146 static void
ganv_item_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)147 ganv_item_set_property(GObject* object,
148 guint prop_id,
149 const GValue* value,
150 GParamSpec* pspec)
151 {
152 g_return_if_fail(object != NULL);
153 g_return_if_fail(GANV_IS_ITEM(object));
154
155 GanvItem* item = GANV_ITEM(object);
156
157 switch (prop_id) {
158 case ITEM_PROP_PARENT:
159 if (item->impl->parent != NULL) {
160 g_warning("Cannot set `parent' argument after item has "
161 "already been constructed.");
162 } else if (g_value_get_object(value)) {
163 item->impl->parent = GANV_ITEM(g_value_get_object(value));
164 item->impl->canvas = item->impl->parent->impl->canvas;
165 item_post_create_setup(item);
166 }
167 break;
168 case ITEM_PROP_X:
169 item->impl->x = g_value_get_double(value);
170 ganv_item_request_update(item);
171 break;
172 case ITEM_PROP_Y:
173 item->impl->y = g_value_get_double(value);
174 ganv_item_request_update(item);
175 break;
176 case ITEM_PROP_MANAGED:
177 item->impl->managed = g_value_get_boolean(value);
178 break;
179 default:
180 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
181 break;
182 }
183 }
184
185 static void
ganv_item_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)186 ganv_item_get_property(GObject* object,
187 guint prop_id,
188 GValue* value,
189 GParamSpec* pspec)
190 {
191 g_return_if_fail(object != NULL);
192 g_return_if_fail(GANV_IS_ITEM(object));
193
194 GanvItem* item = GANV_ITEM(object);
195
196 switch (prop_id) {
197 case ITEM_PROP_PARENT:
198 g_value_set_object(value, item->impl->parent);
199 break;
200 case ITEM_PROP_X:
201 g_value_set_double(value, item->impl->x);
202 break;
203 case ITEM_PROP_Y:
204 g_value_set_double(value, item->impl->y);
205 break;
206 case ITEM_PROP_MANAGED:
207 g_value_set_boolean(value, item->impl->managed);
208 break;
209 default:
210 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
211 break;
212 }
213 }
214
215 /**
216 * ganv_item_construct:
217 * @item: An unconstructed canvas item.
218 * @parent: The parent group for the item.
219 * @first_arg_name: The name of the first argument for configuring the item.
220 * @args: The list of arguments used to configure the item.
221 *
222 * Constructs a canvas item; meant for use only by item implementations.
223 **/
224 void
ganv_item_construct(GanvItem * item,GanvItem * parent,const gchar * first_arg_name,va_list args)225 ganv_item_construct(GanvItem* item, GanvItem* parent,
226 const gchar* first_arg_name, va_list args)
227 {
228 g_return_if_fail(GANV_IS_ITEM(item));
229
230 item->impl->parent = parent;
231 item->impl->wrapper = NULL;
232 item->impl->canvas = item->impl->parent->impl->canvas;
233 item->impl->layer = 0;
234
235 g_object_set_valist(G_OBJECT(item), first_arg_name, args);
236
237 item_post_create_setup(item);
238 }
239
240 /* If the item is visible, requests a redraw of it. */
241 static void
redraw_if_visible(GanvItem * item)242 redraw_if_visible(GanvItem* item)
243 {
244 if (item->object.flags & GANV_ITEM_VISIBLE) {
245 ganv_canvas_request_redraw_w(item->impl->canvas,
246 item->impl->x1, item->impl->y1,
247 item->impl->x2 + 1, item->impl->y2 + 1);
248 }
249 }
250
251 /* Standard object dispose function for canvas items */
252 static void
ganv_item_dispose(GObject * object)253 ganv_item_dispose(GObject* object)
254 {
255 GanvItem* item = NULL;
256
257 g_return_if_fail(GANV_IS_ITEM(object));
258
259 item = GANV_ITEM(object);
260
261 if (item->impl->canvas) {
262 redraw_if_visible(item);
263 ganv_canvas_forget_item(item->impl->canvas, item);
264 }
265
266 /* Normal destroy stuff */
267
268 if (item->object.flags & GANV_ITEM_MAPPED) {
269 (*GANV_ITEM_GET_CLASS(item)->unmap)(item);
270 }
271
272 if (item->object.flags & GANV_ITEM_REALIZED) {
273 (*GANV_ITEM_GET_CLASS(item)->unrealize)(item);
274 }
275
276 if (!item->impl->managed && item->impl->parent) {
277 if (GANV_ITEM_GET_CLASS(item->impl->parent)->remove) {
278 GANV_ITEM_GET_CLASS(item->impl->parent)->remove(item->impl->parent, item);
279 } else {
280 fprintf(stderr, "warning: Item parent has no remove method\n");
281 }
282 }
283
284 G_OBJECT_CLASS(item_parent_class)->dispose(object);
285 /* items should remove any reference to item->impl->canvas after the
286 first ::destroy */
287 item->impl->canvas = NULL;
288 }
289
290 /* Realize handler for canvas items */
291 static void
ganv_item_realize(GanvItem * item)292 ganv_item_realize(GanvItem* item)
293 {
294 GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_REALIZED);
295
296 ganv_item_request_update(item);
297 }
298
299 /* Unrealize handler for canvas items */
300 static void
ganv_item_unrealize(GanvItem * item)301 ganv_item_unrealize(GanvItem* item)
302 {
303 GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_REALIZED);
304 }
305
306 /* Map handler for canvas items */
307 static void
ganv_item_map(GanvItem * item)308 ganv_item_map(GanvItem* item)
309 {
310 GTK_OBJECT_SET_FLAGS(item, GANV_ITEM_MAPPED);
311 }
312
313 /* Unmap handler for canvas items */
314 static void
ganv_item_unmap(GanvItem * item)315 ganv_item_unmap(GanvItem* item)
316 {
317 GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_MAPPED);
318 }
319
320 /* Update handler for canvas items */
321 static void
ganv_item_update(GanvItem * item,int flags)322 ganv_item_update(GanvItem* item, int flags)
323 {
324 (void)flags;
325
326 GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_UPDATE);
327 GTK_OBJECT_UNSET_FLAGS(item, GANV_ITEM_NEED_VIS);
328 }
329
330 /* Point handler for canvas items */
331 static double
ganv_item_point(GanvItem * item,double x,double y,GanvItem ** actual_item)332 ganv_item_point(GanvItem* item, double x, double y, GanvItem** actual_item)
333 {
334 (void)item;
335 (void)x;
336 (void)y;
337
338 *actual_item = NULL;
339 return G_MAXDOUBLE;
340 }
341
342 void
ganv_item_invoke_update(GanvItem * item,int flags)343 ganv_item_invoke_update(GanvItem* item, int flags)
344 {
345 int child_flags = flags;
346
347 /* apply object flags to child flags */
348
349 child_flags &= ~GANV_CANVAS_UPDATE_REQUESTED;
350
351 if (item->object.flags & GANV_ITEM_NEED_UPDATE) {
352 child_flags |= GANV_CANVAS_UPDATE_REQUESTED;
353 }
354
355 if (item->object.flags & GANV_ITEM_NEED_VIS) {
356 child_flags |= GANV_CANVAS_UPDATE_VISIBILITY;
357 }
358
359 if (child_flags & GCI_UPDATE_MASK) {
360 if (GANV_ITEM_GET_CLASS(item)->update) {
361 GANV_ITEM_GET_CLASS(item)->update(item, child_flags);
362 g_assert(!(GTK_OBJECT_FLAGS(item) & GANV_ITEM_NEED_UPDATE));
363 }
364 }
365 }
366
367 /**
368 * ganv_item_set:
369 * @item: A canvas item.
370 * @first_arg_name: The list of object argument name/value pairs used to configure the item.
371 * @...: first argument value, second argument name, second argument value, ...
372 *
373 * Configures a canvas item. The arguments in the item are set to the specified
374 * values, and the item is repainted as appropriate.
375 **/
376 void
ganv_item_set(GanvItem * item,const gchar * first_arg_name,...)377 ganv_item_set(GanvItem* item, const gchar* first_arg_name, ...)
378 {
379 va_list args;
380
381 va_start(args, first_arg_name);
382 ganv_item_set_valist(item, first_arg_name, args);
383 va_end(args);
384 }
385
386 /**
387 * ganv_item_set_valist:
388 * @item: A canvas item.
389 * @first_arg_name: The name of the first argument used to configure the item.
390 * @args: The list of object argument name/value pairs used to configure the item.
391 *
392 * Configures a canvas item. The arguments in the item are set to the specified
393 * values, and the item is repainted as appropriate.
394 **/
395 void
ganv_item_set_valist(GanvItem * item,const gchar * first_arg_name,va_list args)396 ganv_item_set_valist(GanvItem* item, const gchar* first_arg_name, va_list args)
397 {
398 g_return_if_fail(GANV_IS_ITEM(item));
399
400 g_object_set_valist(G_OBJECT(item), first_arg_name, args);
401
402 ganv_canvas_set_need_repick(item->impl->canvas);
403 }
404
405 GanvCanvas*
ganv_item_get_canvas(GanvItem * item)406 ganv_item_get_canvas(GanvItem* item)
407 {
408 return item->impl->canvas;
409 }
410
411 GanvItem*
ganv_item_get_parent(GanvItem * item)412 ganv_item_get_parent(GanvItem* item)
413 {
414 return item->impl->parent;
415 }
416
417 void
ganv_item_raise(GanvItem * item)418 ganv_item_raise(GanvItem* item)
419 {
420 ++item->impl->layer;
421 }
422
423 void
ganv_item_lower(GanvItem * item)424 ganv_item_lower(GanvItem* item)
425 {
426 --item->impl->layer;
427 }
428
429 /**
430 * ganv_item_move:
431 * @item: A canvas item.
432 * @dx: Horizontal offset.
433 * @dy: Vertical offset.
434 **/
435 void
ganv_item_move(GanvItem * item,double dx,double dy)436 ganv_item_move(GanvItem* item, double dx, double dy)
437 {
438 if (!item || !GANV_IS_ITEM(item)) {
439 return;
440 }
441
442 item->impl->x += dx;
443 item->impl->y += dy;
444
445 ganv_item_request_update(item);
446 ganv_canvas_set_need_repick(item->impl->canvas);
447 }
448
449 /**
450 * ganv_item_show:
451 * @item: A canvas item.
452 *
453 * Shows a canvas item. If the item was already shown, then no action is taken.
454 **/
455 void
ganv_item_show(GanvItem * item)456 ganv_item_show(GanvItem* item)
457 {
458 g_return_if_fail(GANV_IS_ITEM(item));
459
460 if (!(item->object.flags & GANV_ITEM_VISIBLE)) {
461 item->object.flags |= GANV_ITEM_VISIBLE;
462 ganv_canvas_request_redraw_w(item->impl->canvas,
463 item->impl->x1, item->impl->y1,
464 item->impl->x2 + 1, item->impl->y2 + 1);
465 ganv_canvas_set_need_repick(item->impl->canvas);
466 }
467 }
468
469 /**
470 * ganv_item_hide:
471 * @item: A canvas item.
472 *
473 * Hides a canvas item. If the item was already hidden, then no action is
474 * taken.
475 **/
476 void
ganv_item_hide(GanvItem * item)477 ganv_item_hide(GanvItem* item)
478 {
479 g_return_if_fail(GANV_IS_ITEM(item));
480
481 if (item->object.flags & GANV_ITEM_VISIBLE) {
482 item->object.flags &= ~GANV_ITEM_VISIBLE;
483 ganv_canvas_request_redraw_w(item->impl->canvas,
484 item->impl->x1, item->impl->y1,
485 item->impl->x2 + 1, item->impl->y2 + 1);
486 ganv_canvas_set_need_repick(item->impl->canvas);
487 }
488 }
489
490 void
ganv_item_i2w_offset(GanvItem * item,double * px,double * py)491 ganv_item_i2w_offset(GanvItem* item, double* px, double* py)
492 {
493 double x = 0.0;
494 double y = 0.0;
495 while (item) {
496 x += item->impl->x;
497 y += item->impl->y;
498 item = item->impl->parent;
499 }
500 *px = x;
501 *py = y;
502 }
503
504 /**
505 * ganv_item_i2w:
506 * @item: A canvas item.
507 * @x: X coordinate to convert (input/output value).
508 * @y: Y coordinate to convert (input/output value).
509 *
510 * Converts a coordinate pair from item-relative coordinates to world
511 * coordinates.
512 **/
513 void
ganv_item_i2w(GanvItem * item,double * x,double * y)514 ganv_item_i2w(GanvItem* item, double* x, double* y)
515 {
516 /*g_return_if_fail(GANV_IS_ITEM(item));
517 g_return_if_fail(x != NULL);
518 g_return_if_fail(y != NULL);*/
519
520 double off_x = 0.0;
521 double off_y = 0.0;
522 ganv_item_i2w_offset(item, &off_x, &off_y);
523
524 *x += off_x;
525 *y += off_y;
526 }
527
528 void
ganv_item_i2w_pair(GanvItem * item,double * x1,double * y1,double * x2,double * y2)529 ganv_item_i2w_pair(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
530 {
531 double off_x = 0.0;
532 double off_y = 0.0;
533 ganv_item_i2w_offset(item, &off_x, &off_y);
534
535 *x1 += off_x;
536 *y1 += off_y;
537 *x2 += off_x;
538 *y2 += off_y;
539 }
540
541 /**
542 * ganv_item_w2i:
543 * @item: A canvas item.
544 * @x: X coordinate to convert (input/output value).
545 * @y: Y coordinate to convert (input/output value).
546 *
547 * Converts a coordinate pair from world coordinates to item-relative
548 * coordinates.
549 **/
550 void
ganv_item_w2i(GanvItem * item,double * x,double * y)551 ganv_item_w2i(GanvItem* item, double* x, double* y)
552 {
553 double off_x = 0.0;
554 double off_y = 0.0;
555 ganv_item_i2w_offset(item, &off_x, &off_y);
556
557 *x -= off_x;
558 *y -= off_y;
559 }
560
561 /**
562 * ganv_item_grab_focus:
563 * @item: A canvas item.
564 *
565 * Makes the specified item take the keyboard focus, so all keyboard events will
566 * be sent to it. If the canvas widget itself did not have the focus, it grabs
567 * it as well.
568 **/
569 void
ganv_item_grab_focus(GanvItem * item)570 ganv_item_grab_focus(GanvItem* item)
571 {
572 ganv_canvas_grab_focus(item->impl->canvas, item);
573 }
574
575 void
ganv_item_emit_event(GanvItem * item,GdkEvent * event,gint * finished)576 ganv_item_emit_event(GanvItem* item, GdkEvent* event, gint* finished)
577 {
578 g_signal_emit(item, item_signals[ITEM_EVENT], 0, event, finished);
579 }
580
581 static void
ganv_item_default_bounds(GanvItem * item,double * x1,double * y1,double * x2,double * y2)582 ganv_item_default_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
583 {
584 (void)item;
585
586 *x1 = *y1 = *x2 = *y2 = 0.0;
587 }
588
589 /**
590 * ganv_item_get_bounds:
591 * @item: A canvas item.
592 * @x1: Leftmost edge of the bounding box (return value).
593 * @y1: Upper edge of the bounding box (return value).
594 * @x2: Rightmost edge of the bounding box (return value).
595 * @y2: Lower edge of the bounding box (return value).
596 *
597 * Queries the bounding box of a canvas item. The bounding box may not be
598 * exactly tight, but the canvas items will do the best they can. The bounds
599 * are returned in the coordinate system of the item's parent.
600 **/
601 void
ganv_item_get_bounds(GanvItem * item,double * x1,double * y1,double * x2,double * y2)602 ganv_item_get_bounds(GanvItem* item, double* x1, double* y1, double* x2, double* y2)
603 {
604 GANV_ITEM_GET_CLASS(item)->bounds(item, x1, y1, x2, y2);
605 }
606
607 /**
608 * ganv_item_request_update:
609 * @item: A canvas item.
610 *
611 * To be used only by item implementations. Requests that the canvas queue an
612 * update for the specified item.
613 **/
614 void
ganv_item_request_update(GanvItem * item)615 ganv_item_request_update(GanvItem* item)
616 {
617 if (!item->impl->canvas) {
618 /* Item is being / has been destroyed, ignore */
619 return;
620 }
621
622 item->object.flags |= GANV_ITEM_NEED_UPDATE;
623
624 if (item->impl->parent != NULL &&
625 !(item->impl->parent->object.flags & GANV_ITEM_NEED_UPDATE)) {
626 /* Recurse up the tree */
627 ganv_item_request_update(item->impl->parent);
628 } else {
629 /* Have reached the top of the tree, make sure the update call gets scheduled. */
630 ganv_canvas_request_update(item->impl->canvas);
631 }
632 }
633
634 void
ganv_item_set_wrapper(GanvItem * item,void * wrapper)635 ganv_item_set_wrapper(GanvItem* item, void* wrapper)
636 {
637 item->impl->wrapper = wrapper;
638 }
639
640 void*
ganv_item_get_wrapper(GanvItem * item)641 ganv_item_get_wrapper(GanvItem* item)
642 {
643 return item->impl->wrapper;
644 }
645
646 static gboolean
boolean_handled_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)647 boolean_handled_accumulator(GSignalInvocationHint* ihint,
648 GValue* return_accu,
649 const GValue* handler_return,
650 gpointer dummy)
651 {
652 (void)ihint;
653 (void)dummy;
654
655 gboolean continue_emission = FALSE;
656 gboolean signal_handled = FALSE;
657
658 signal_handled = g_value_get_boolean(handler_return);
659 g_value_set_boolean(return_accu, signal_handled);
660 continue_emission = !signal_handled;
661
662 return continue_emission;
663 }
664
665 /* Class initialization function for GanvItemClass */
666 static void
ganv_item_class_init(GanvItemClass * klass)667 ganv_item_class_init(GanvItemClass* klass)
668 {
669 GObjectClass* gobject_class = (GObjectClass*)klass;
670
671 item_parent_class = (GtkObjectClass*)g_type_class_peek_parent(klass);
672
673 gobject_class->set_property = ganv_item_set_property;
674 gobject_class->get_property = ganv_item_get_property;
675
676 g_object_class_install_property
677 (gobject_class, ITEM_PROP_PARENT,
678 g_param_spec_object("parent", NULL, NULL,
679 GANV_TYPE_ITEM,
680 (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
681
682 g_object_class_install_property
683 (gobject_class, ITEM_PROP_X,
684 g_param_spec_double("x",
685 _("X"),
686 _("X"),
687 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
688 (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
689 g_object_class_install_property
690 (gobject_class, ITEM_PROP_Y,
691 g_param_spec_double("y",
692 _("Y"),
693 _("Y"),
694 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
695 (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
696
697 g_object_class_install_property
698 (gobject_class, ITEM_PROP_MANAGED,
699 g_param_spec_boolean("managed",
700 _("Managed"),
701 _("Whether the item is managed by its parent"),
702 0,
703 (GParamFlags)(G_PARAM_READABLE | G_PARAM_WRITABLE)));
704
705 item_signals[ITEM_EVENT]
706 = g_signal_new("event",
707 G_TYPE_FROM_CLASS(klass),
708 G_SIGNAL_RUN_LAST,
709 G_STRUCT_OFFSET(GanvItemClass, event),
710 boolean_handled_accumulator, NULL,
711 ganv_marshal_BOOLEAN__BOXED,
712 G_TYPE_BOOLEAN, 1,
713 GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);
714
715 gobject_class->dispose = ganv_item_dispose;
716
717 klass->realize = ganv_item_realize;
718 klass->unrealize = ganv_item_unrealize;
719 klass->map = ganv_item_map;
720 klass->unmap = ganv_item_unmap;
721 klass->update = ganv_item_update;
722 klass->point = ganv_item_point;
723 klass->bounds = ganv_item_default_bounds;
724 }
725