4 #include <libgnomecanvas/libgnomecanvas.h>
6 #include "canvas-simplerect.h"
7 #include "rgb_macros.h"
9 #define _(Text) dgettext (PACKAGE,Text)
21 PROP_OUTLINE_COLOR_RGBA,
25 static void gnome_canvas_simplerect_class_init (GnomeCanvasSimpleRectClass *class);
27 static void gnome_canvas_simplerect_init (GnomeCanvasSimpleRect *simplerect);
29 static void gnome_canvas_simplerect_destroy (GtkObject *object);
31 static void gnome_canvas_simplerect_set_property (GObject *object,
36 static void gnome_canvas_simplerect_get_property (GObject *object,
41 static void gnome_canvas_simplerect_update (GnomeCanvasItem *item,
46 static void gnome_canvas_simplerect_bounds (GnomeCanvasItem *item,
52 static double gnome_canvas_simplerect_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item);
54 static void gnome_canvas_simplerect_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
56 static void gnome_canvas_simplerect_draw (GnomeCanvasItem *item, GdkDrawable *drawable, int x, int y, int w, int h);
58 static GnomeCanvasItemClass *parent_class;
62 gnome_canvas_simplerect_get_type (void)
64 static GType simplerect_type;
66 if (!simplerect_type) {
67 static const GTypeInfo object_info = {
68 sizeof (GnomeCanvasSimpleRectClass),
70 (GBaseFinalizeFunc) NULL,
71 (GClassInitFunc) gnome_canvas_simplerect_class_init,
72 (GClassFinalizeFunc) NULL,
73 NULL, /* class_data */
74 sizeof (GnomeCanvasSimpleRect),
76 (GInstanceInitFunc) gnome_canvas_simplerect_init,
77 NULL /* value_table */
80 simplerect_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasSimpleRect",
84 return simplerect_type;
88 gnome_canvas_simplerect_class_init (GnomeCanvasSimpleRectClass *class)
90 GObjectClass *gobject_class;
91 GtkObjectClass *object_class;
92 GnomeCanvasItemClass *item_class;
94 gobject_class = (GObjectClass *) class;
95 object_class = (GtkObjectClass *) class;
96 item_class = (GnomeCanvasItemClass *) class;
98 parent_class = g_type_class_peek_parent (class);
100 gobject_class->set_property = gnome_canvas_simplerect_set_property;
101 gobject_class->get_property = gnome_canvas_simplerect_get_property;
103 g_object_class_install_property (gobject_class,
105 g_param_spec_double ("x1",
107 _("x coordinate of upper left corner of rect"),
113 g_object_class_install_property (gobject_class,
115 g_param_spec_double ("y1",
117 _("y coordinate of upper left corner of rect "),
124 g_object_class_install_property (gobject_class,
126 g_param_spec_double ("x2",
128 _("x coordinate of lower right corner of rect"),
134 g_object_class_install_property (gobject_class,
136 g_param_spec_double ("y2",
138 _("y coordinate of lower right corner of rect "),
145 g_object_class_install_property (gobject_class,
147 g_param_spec_uint ("outline_pixels",
149 _("width in pixels of outline"),
156 g_object_class_install_property (gobject_class,
158 g_param_spec_uint ("outline_what",
160 _("which boundaries to outline (mask)"),
168 g_object_class_install_property (gobject_class,
170 g_param_spec_boolean ("fill",
176 g_object_class_install_property (gobject_class,
178 g_param_spec_boolean ("draw",
185 g_object_class_install_property (gobject_class,
186 PROP_OUTLINE_COLOR_RGBA,
187 g_param_spec_uint ("outline_color_rgba",
188 _("outline color rgba"),
189 _("color of outline"),
196 g_object_class_install_property (gobject_class,
197 PROP_FILL_COLOR_RGBA,
198 g_param_spec_uint ("fill_color_rgba",
199 _("fill color rgba"),
206 object_class->destroy = gnome_canvas_simplerect_destroy;
208 item_class->update = gnome_canvas_simplerect_update;
209 item_class->draw = gnome_canvas_simplerect_draw;
210 item_class->bounds = gnome_canvas_simplerect_bounds;
211 item_class->point = gnome_canvas_simplerect_point;
212 item_class->render = gnome_canvas_simplerect_render;
217 gnome_canvas_simplerect_init (GnomeCanvasSimpleRect *simplerect)
219 simplerect->x1 = 0.0;
220 simplerect->y1 = 0.0;
221 simplerect->x2 = 0.0;
222 simplerect->y2 = 0.0;
223 simplerect->fill = TRUE;
224 simplerect->draw = TRUE;
225 simplerect->full_draw_on_update = TRUE;
226 simplerect->fill_color = 0;
227 simplerect->outline_color = 0;
228 simplerect->outline_pixels = 1;
229 simplerect->outline_what = 0xf;
233 gnome_canvas_simplerect_destroy (GtkObject *object)
235 g_return_if_fail (object != NULL);
236 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object));
238 /* remember, destroy can be run multiple times! */
240 if (GTK_OBJECT_CLASS (parent_class)->destroy)
241 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
245 gnome_canvas_simplerect_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
247 GnomeCanvasSimpleRect *simplerect = GNOME_CANVAS_SIMPLERECT (item);
249 *x1 = simplerect->x1;
250 *y1 = simplerect->y1;
251 *x2 = simplerect->x2 + 1;
252 *y2 = simplerect->y2 + 1;
257 gnome_canvas_simplerect_reset_bounds (GnomeCanvasItem *item)
259 GnomeCanvasSimpleRect* simplerect;
260 double x1, x2, y1, y2;
261 double old_x1, old_x2, old_y1, old_y2;
262 ArtDRect unionrect, old, new;
269 gnome_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
270 gnome_canvas_item_i2w (item, &x1, &y1);
271 gnome_canvas_item_i2w (item, &x2, &y2);
278 /* now compute bounding box in canvas units */
280 simplerect = GNOME_CANVAS_SIMPLERECT (item);
282 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x1, y1, &simplerect->bbox_ulx, &simplerect->bbox_uly);
283 gnome_canvas_w2c (GNOME_CANVAS(item->canvas), x2, y2, &simplerect->bbox_lrx, &simplerect->bbox_lry);
285 /* now queue redraws for changed areas */
287 if (item->x1 == old_x1 && item->x2 == old_x2) {
289 /* no change in x-axis position */
291 if (item->y1 == old_y1) {
292 /* top didn't change, so just draw bottom */
294 double start_y = MIN (item->y2, old_y2);
295 double end_y = MAX (item->y2, old_y2);
297 gnome_canvas_request_redraw (item->canvas, item->x1, start_y - 0.5, item->x2, end_y + 1.5);
300 } else if (item->y2 == old_y2) {
302 /* bottom didn't change, just draw top */
304 double start_y = MIN (item->y1, old_y1);
305 double end_y = MAX (item->y1, old_y1);
307 gnome_canvas_request_redraw (item->canvas, item->x1, start_y - 0.5, item->x2, end_y + 1.5);
312 } else if (item->y1 == old_y1 && item->y2 == old_y2) {
314 /* no change in y-axis position */
316 if (item->x1 == old_x1) {
317 /* start didn't change, so just draw at the end */
319 double start_x = MIN (item->x2, old_x2);
320 double end_x = MAX (item->x2, old_x2);
322 gnome_canvas_request_redraw (item->canvas, start_x - 0.5, item->y1, end_x + 1.5, item->y2 + 0.5);
325 } else if (item->x2 == old_x2) {
327 /* end didn't change, so just draw at the start */
329 double start_x = MIN (item->x1, old_x1);
330 double end_x = MAX (item->x1, old_x1);
332 gnome_canvas_request_redraw (item->canvas, start_x - 0.5, item->y1, end_x + 1.5, item->y2 + 0.5);
348 art_drect_union (&unionrect, &old, &new);
349 gnome_canvas_request_redraw (item->canvas,
361 gnome_canvas_simplerect_set_property (GObject *object,
369 GnomeCanvasSimpleRect *simplerect;
371 int bounds_changed = FALSE;
372 g_return_if_fail (object != NULL);
373 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object));
375 simplerect = GNOME_CANVAS_SIMPLERECT (object);
379 if (simplerect->x1 != g_value_get_double (value)) {
380 simplerect->x1 = g_value_get_double (value);
381 bounds_changed = TRUE;
386 if (simplerect->y1 != g_value_get_double (value)) {
387 simplerect->y1 = g_value_get_double (value);
388 bounds_changed = TRUE;
393 if (simplerect->x2 != g_value_get_double (value)) {
394 simplerect->x2 = g_value_get_double (value);
395 bounds_changed = TRUE;
400 if (simplerect->y2 != g_value_get_double (value)) {
401 simplerect->y2 = g_value_get_double (value);
402 bounds_changed = TRUE;
407 if (simplerect->draw != g_value_get_boolean (value)) {
408 simplerect->draw = g_value_get_boolean (value);
415 if (simplerect->fill != g_value_get_boolean (value)) {
416 simplerect->fill = g_value_get_boolean (value);
421 case PROP_FILL_COLOR_RGBA:
422 if (simplerect->fill_color != g_value_get_uint(value)) {
423 simplerect->fill_color = g_value_get_uint(value);
428 case PROP_OUTLINE_COLOR_RGBA:
429 if (simplerect->outline_color != g_value_get_uint(value)) {
430 simplerect->outline_color = g_value_get_uint(value);
435 case PROP_OUTLINE_PIXELS:
436 if (simplerect->outline_pixels != g_value_get_uint(value)) {
437 simplerect->outline_pixels = g_value_get_uint(value);
442 case PROP_OUTLINE_WHAT:
443 if (simplerect->outline_what != g_value_get_uint(value)) {
444 simplerect->outline_what = g_value_get_uint(value);
453 if (!simplerect->full_draw_on_update) {
454 /* XXX: not sure about this;
456 * I changed the next line to be conditional, rather than always
457 * being executed. Without the condition, the following bug occurs:
459 * caller sets a property (e.g. outline colour); this sets update = TRUE and hence full_draw_on_update = TRUE
460 * update is requested (and it is intended, I suppose, that during this update, full_draw_on_update is noted)
461 * ... update does not occur before ...
462 * caller sets the same property again to the same value; this sets update = FALSE and hence full_draw_on_update = FALSE
463 * update now occurs, but full_draw_on_update is FALSE, so the full redraw does not happen,
464 * which results in graphical glitches.
468 simplerect->full_draw_on_update = update;
471 if (update || bounds_changed) {
472 gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(object));
477 gnome_canvas_simplerect_get_property (GObject *object,
482 GnomeCanvasSimpleRect *rect = GNOME_CANVAS_SIMPLERECT (object);
484 g_return_if_fail (object != NULL);
485 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object));
489 g_value_set_double (value, rect->x1);
492 g_value_set_double (value, rect->x2);
495 g_value_set_double (value, rect->y1);
498 g_value_set_double (value, rect->y2);
500 case PROP_OUTLINE_WHAT:
501 g_value_set_uint (value, rect->outline_what);
504 g_value_set_boolean (value, rect->fill);
506 case PROP_OUTLINE_PIXELS:
507 g_value_set_uint (value, rect->outline_pixels);
509 case PROP_FILL_COLOR_RGBA:
510 g_value_set_uint (value, rect->fill_color);
512 case PROP_OUTLINE_COLOR_RGBA:
513 g_value_set_uint (value, rect->outline_color);
516 g_value_set_boolean (value, rect->draw);
520 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
527 gnome_canvas_simplerect_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
529 GnomeCanvasSimpleRect *simplerect;
531 simplerect = GNOME_CANVAS_SIMPLERECT (item);
533 if (parent_class->update)
534 (* parent_class->update) (item, affine, clip_path, flags);
536 gnome_canvas_simplerect_reset_bounds (item);
538 if (simplerect->full_draw_on_update) {
539 gnome_canvas_request_redraw (item->canvas,
540 simplerect->bbox_ulx,
541 simplerect->bbox_uly,
542 simplerect->bbox_lrx+0.5,
543 simplerect->bbox_lry+0.5);
544 simplerect->full_draw_on_update = FALSE;
547 UINT_TO_RGBA (simplerect->fill_color, &simplerect->fill_r, &simplerect->fill_g, &simplerect->fill_b, &simplerect->fill_a);
548 UINT_TO_RGBA (simplerect->outline_color, &simplerect->outline_r, &simplerect->outline_g, &simplerect->outline_b, &simplerect->outline_a);
551 // this can be useful for debugging/understanding how the canvas redraws
554 #undef HARLEQUIN_DEBUGGING
556 #undef SIMPLERECT_FAST_RENDERER
557 #ifdef SIMPLERECT_FAST_RENDERER
560 gnome_canvas_simplerect_render (GnomeCanvasItem *item,
563 GnomeCanvasSimpleRect *simplerect;
567 ArtIRect intersection;
570 simplerect = GNOME_CANVAS_SIMPLERECT (item);
572 if (parent_class->render) {
573 (*parent_class->render) (item, buf);
578 #ifdef HARLEQUIN_DEBUGGING
579 gint randr, randg, randb;
580 randr = random() % 255;
581 randg = random() % 255;
582 randb = random() % 255;
583 PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
585 gnome_canvas_buf_ensure_buf (buf);
589 if (!simplerect->draw) {
593 self.x0 = simplerect->bbox_ulx;
594 self.y0 = simplerect->bbox_uly;
595 self.x1 = simplerect->bbox_lrx;
596 self.y1 = simplerect->bbox_lry;
598 art_irect_intersect (&intersection, &self, &buf->rect);
600 begin = MAX(simplerect->bbox_ulx, buf->rect.x0);
601 end = MIN((simplerect->bbox_lrx-1), buf->rect.x1);
603 sy = simplerect->bbox_uly;
604 ey = simplerect->bbox_lry-1;
606 if (simplerect->fill) {
608 // this can be useful for debugging/understanding how the canvas redraws
611 #ifdef HARLEQUIN_DEBUGGING
612 gint randr, randg, randb;
613 randr = random() % 255;
614 randg = random() % 255;
615 randb = random() % 255;
616 PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
618 PAINT_BOX (buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a,
619 intersection.x0, intersection.y0,
620 intersection.x1, intersection.y1);
625 if (simplerect->outline_a > 0) {
626 for (i = 0; i < simplerect->outline_pixels; ++i) {
628 if (simplerect->outline_what & 0x1) {
629 if (begin == simplerect->bbox_ulx) {
630 PAINT_VERTA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin + i, sy, ey);
634 if (simplerect->outline_what & 0x2) {
635 if (end == (simplerect->bbox_lrx - 1)) {
636 PAINT_VERTA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, end - i, sy, ey + 1);
640 if (simplerect->outline_what & 0x4) {
641 PAINT_HORIZA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin, end, sy+i);
644 if (simplerect->outline_what & 0x8) {
645 PAINT_HORIZA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin, end + 1, ey-i);
651 #else /* SIMPLERECT_FAST_RENDERER */
654 gnome_canvas_simplerect_render (GnomeCanvasItem *item,
657 GnomeCanvasSimpleRect *simplerect;
662 simplerect = GNOME_CANVAS_SIMPLERECT (item);
664 if (parent_class->render) {
665 (*parent_class->render) (item, buf);
670 #ifdef HARLEQUIN_DEBUGGING
671 gint randr, randg, randb;
672 randr = random() % 255;
673 randg = random() % 255;
674 randb = random() % 255;
675 PAINT_BOX(buf, randr, randg, randb, 255, buf->rect.x0, buf->rect.y0, buf->rect.x1, buf->rect.y1);
677 gnome_canvas_buf_ensure_buf (buf);
681 if (!simplerect->draw) {
685 begin = MAX(simplerect->bbox_ulx,buf->rect.x0);
686 end = MIN((simplerect->bbox_lrx-1),buf->rect.x1);
688 sy = simplerect->bbox_uly;
689 ey = simplerect->bbox_lry-1;
691 if (simplerect->fill) {
693 #ifdef HARLEQUIN_DEBUGGING
694 gint randr, randg, randb;
695 randr = random() % 255;
696 randg = random() % 255;
697 randb = random() % 255;
698 PAINT_BOX(buf, randr, randg, randb, simplerect->fill_a, begin, sy, end, ey);
700 PAINT_BOX(buf, simplerect->fill_r, simplerect->fill_g, simplerect->fill_b, simplerect->fill_a, begin, sy, end, ey);
704 if (simplerect->outline_a) {
705 for (i = 0; i < (int) simplerect->outline_pixels; ++i) {
707 if (simplerect->outline_what & 0x1) {
708 if (begin == simplerect->bbox_ulx) {
709 PAINT_VERTA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin + i, sy, ey);
713 if (simplerect->outline_what & 0x2) {
714 if (end == (simplerect->bbox_lrx - 1)) {
715 PAINT_VERTA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, end - i, sy, ey + 1);
719 if (simplerect->outline_what & 0x4) {
720 PAINT_HORIZA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin, end, sy+i);
723 if (simplerect->outline_what & 0x8) {
724 PAINT_HORIZA(buf, simplerect->outline_r, simplerect->outline_g, simplerect->outline_b, simplerect->outline_a, begin, end + 1, ey-i);
729 #endif /* SIMPLERECT_FAST_RENDERER */
732 gnome_canvas_simplerect_draw (GnomeCanvasItem *item,
733 GdkDrawable *drawable,
735 int width, int height)
737 GnomeCanvasSimpleRect *simplerect;
744 simplerect = GNOME_CANVAS_SIMPLERECT (item);
746 cr = gdk_cairo_create (drawable);
748 if (x > simplerect->bbox_ulx) {
751 ulx = simplerect->bbox_ulx;
754 if (y > simplerect->bbox_uly) {
757 uly = simplerect->bbox_uly;
760 if (x + width > simplerect->bbox_lrx) {
761 lrx = simplerect->bbox_lrx;
766 if (y + height > simplerect->bbox_lry) {
767 lry = simplerect->bbox_lry;
777 cairo_rectangle (cr, ulx, uly, lrx - ulx, lry - uly);
779 if (simplerect->fill) {
780 cairo_set_source_rgba (cr,
781 simplerect->fill_r/255.0,
782 simplerect->fill_g/255.0,
783 simplerect->fill_b/255.0,
784 simplerect->fill_a/255.0);
788 if (simplerect->outline_what && simplerect->outline_pixels) {
790 #define x_in_range(a) (x <= (a) && (a) < x + width)
791 #define y_in_range(a) (y <= (a) && (a) < y + height)
793 cairo_set_line_width (cr, simplerect->outline_pixels);
795 cairo_set_source_rgb (cr,
796 simplerect->outline_r/255.0,
797 simplerect->outline_g/255.0,
798 simplerect->outline_b/255.0);
800 if (simplerect->outline_what & 0x1) {
801 /* left edge, if visible */
802 if (x_in_range (simplerect->bbox_ulx)) {
803 cairo_move_to (cr, ulx+0.5, uly+0.5);
804 cairo_line_to (cr, ulx+0.5, lry+0.5);
809 if (simplerect->outline_what & 0x2) {
810 /* right edge, if visible */
811 if (x_in_range (simplerect->bbox_lrx)) {
812 cairo_move_to (cr, lrx+0.5, uly+0.5);
813 cairo_line_to (cr, lrx+0.5, lry+0.5);
818 if (simplerect->outline_what & 0x4) {
820 if (y_in_range (simplerect->bbox_uly)) {
821 cairo_move_to (cr, ulx+0.5, uly+0.5);
822 cairo_line_to (cr, lrx+0.5, uly+0.5);
827 if (simplerect->outline_what & 0x8) {
829 if (y_in_range (simplerect->bbox_lry)) {
830 cairo_move_to (cr, ulx+0.5, lry+0.5);
831 cairo_line_to (cr, lrx+0.5, lry+0.5);
841 gnome_canvas_simplerect_point (GnomeCanvasItem *item, double x, double y, int cx, int cy, GnomeCanvasItem **actual_item)
846 double x1, y1, x2, y2;
851 /* Find the bounds for the rectangle plus its outline width */
853 gnome_canvas_simplerect_bounds (item, &x1, &y1, &x2, &y2);
855 /* Is point inside rectangle */
857 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
861 /* Point is outside rectangle */
877 return sqrt (dx * dx + dy * dy);