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 GnomeCanvasSimpleRect
*rect
;
237 g_return_if_fail (object
!= NULL
);
238 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object
));
240 rect
= GNOME_CANVAS_SIMPLERECT (object
);
242 /* remember, destroy can be run multiple times! */
244 if (GTK_OBJECT_CLASS (parent_class
)->destroy
)
245 (* GTK_OBJECT_CLASS (parent_class
)->destroy
) (object
);
249 gnome_canvas_simplerect_bounds (GnomeCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
251 GnomeCanvasSimpleRect
*simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
253 *x1
= simplerect
->x1
;
254 *y1
= simplerect
->y1
;
255 *x2
= simplerect
->x2
+ 1;
256 *y2
= simplerect
->y2
+ 1;
261 gnome_canvas_simplerect_reset_bounds (GnomeCanvasItem
*item
)
263 GnomeCanvasSimpleRect
* simplerect
;
264 double x1
, x2
, y1
, y2
;
265 double old_x1
, old_x2
, old_y1
, old_y2
;
266 ArtDRect unionrect
, old
, new;
273 gnome_canvas_simplerect_bounds (item
, &x1
, &y1
, &x2
, &y2
);
274 gnome_canvas_item_i2w (item
, &x1
, &y1
);
275 gnome_canvas_item_i2w (item
, &x2
, &y2
);
282 /* now compute bounding box in canvas units */
284 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
286 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x1
, y1
, &simplerect
->bbox_ulx
, &simplerect
->bbox_uly
);
287 gnome_canvas_w2c (GNOME_CANVAS(item
->canvas
), x2
, y2
, &simplerect
->bbox_lrx
, &simplerect
->bbox_lry
);
289 /* now queue redraws for changed areas */
291 if (item
->x1
== old_x1
&& item
->x2
== old_x2
) {
293 /* no change in x-axis position */
295 if (item
->y1
== old_y1
) {
296 /* top didn't change, so just draw bottom */
298 double start_y
= MIN (item
->y2
, old_y2
);
299 double end_y
= MAX (item
->y2
, old_y2
);
301 gnome_canvas_request_redraw (item
->canvas
, item
->x1
, start_y
- 0.5, item
->x2
, end_y
+ 1.5);
304 } else if (item
->y2
== old_y2
) {
306 /* bottom didn't change, just draw top */
308 double start_y
= MIN (item
->y1
, old_y1
);
309 double end_y
= MAX (item
->y1
, old_y1
);
311 gnome_canvas_request_redraw (item
->canvas
, item
->x1
, start_y
- 0.5, item
->x2
, end_y
+ 1.5);
316 } else if (item
->y1
== old_y1
&& item
->y2
== old_y2
) {
318 /* no change in y-axis position */
320 if (item
->x1
== old_x1
) {
321 /* start didn't change, so just draw at the end */
323 double start_x
= MIN (item
->x2
, old_x2
);
324 double end_x
= MAX (item
->x2
, old_x2
);
326 gnome_canvas_request_redraw (item
->canvas
, start_x
- 0.5, item
->y1
, end_x
+ 1.5, item
->y2
);
329 } else if (item
->x2
== old_x2
) {
331 /* end didn't change, so just draw at the start */
333 double start_x
= MIN (item
->x1
, old_x1
);
334 double end_x
= MAX (item
->x1
, old_x1
);
336 gnome_canvas_request_redraw (item
->canvas
, start_x
- 0.5, item
->y1
, end_x
+ 1.5, item
->y2
+ 0.5);
352 art_drect_union (&unionrect
, &old
, &new);
353 gnome_canvas_request_redraw (item
->canvas
,
365 gnome_canvas_simplerect_set_property (GObject
*object
,
373 GnomeCanvasSimpleRect
*simplerect
;
375 int bounds_changed
= FALSE
;
376 g_return_if_fail (object
!= NULL
);
377 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object
));
379 simplerect
= GNOME_CANVAS_SIMPLERECT (object
);
383 if (simplerect
->x1
!= g_value_get_double (value
)) {
384 simplerect
->x1
= g_value_get_double (value
);
385 bounds_changed
= TRUE
;
390 if (simplerect
->y1
!= g_value_get_double (value
)) {
391 simplerect
->y1
= g_value_get_double (value
);
392 bounds_changed
= TRUE
;
397 if (simplerect
->x2
!= g_value_get_double (value
)) {
398 simplerect
->x2
= g_value_get_double (value
);
399 bounds_changed
= TRUE
;
404 if (simplerect
->y2
!= g_value_get_double (value
)) {
405 simplerect
->y2
= g_value_get_double (value
);
406 bounds_changed
= TRUE
;
411 if (simplerect
->draw
!= g_value_get_boolean (value
)) {
412 simplerect
->draw
= g_value_get_boolean (value
);
419 if (simplerect
->fill
!= g_value_get_boolean (value
)) {
420 simplerect
->fill
= g_value_get_boolean (value
);
425 case PROP_FILL_COLOR_RGBA
:
426 if (simplerect
->fill_color
!= g_value_get_uint(value
)) {
427 simplerect
->fill_color
= g_value_get_uint(value
);
432 case PROP_OUTLINE_COLOR_RGBA
:
433 if (simplerect
->outline_color
!= g_value_get_uint(value
)) {
434 simplerect
->outline_color
= g_value_get_uint(value
);
439 case PROP_OUTLINE_PIXELS
:
440 if (simplerect
->outline_pixels
!= g_value_get_uint(value
)) {
441 simplerect
->outline_pixels
= g_value_get_uint(value
);
446 case PROP_OUTLINE_WHAT
:
447 if (simplerect
->outline_what
!= g_value_get_uint(value
)) {
448 simplerect
->outline_what
= g_value_get_uint(value
);
457 if (!simplerect
->full_draw_on_update
) {
458 /* XXX: not sure about this;
460 * I changed the next line to be conditional, rather than always
461 * being executed. Without the condition, the following bug occurs:
463 * caller sets a property (e.g. outline colour); this sets update = TRUE and hence full_draw_on_update = TRUE
464 * update is requested (and it is intended, I suppose, that during this update, full_draw_on_update is noted)
465 * ... update does not occur before ...
466 * caller sets the same property again to the same value; this sets update = FALSE and hence full_draw_on_update = FALSE
467 * update now occurs, but full_draw_on_update is FALSE, so the full redraw does not happen,
468 * which results in graphical glitches.
472 simplerect
->full_draw_on_update
= update
;
475 if (update
|| bounds_changed
) {
476 gnome_canvas_item_request_update (GNOME_CANVAS_ITEM(object
));
481 gnome_canvas_simplerect_get_property (GObject
*object
,
486 GnomeCanvasSimpleRect
*rect
= GNOME_CANVAS_SIMPLERECT (object
);
488 g_return_if_fail (object
!= NULL
);
489 g_return_if_fail (GNOME_IS_CANVAS_SIMPLERECT (object
));
493 g_value_set_double (value
, rect
->x1
);
496 g_value_set_double (value
, rect
->x2
);
499 g_value_set_double (value
, rect
->y1
);
502 g_value_set_double (value
, rect
->y2
);
504 case PROP_OUTLINE_WHAT
:
505 g_value_set_uint (value
, rect
->outline_what
);
508 g_value_set_boolean (value
, rect
->fill
);
510 case PROP_OUTLINE_PIXELS
:
511 g_value_set_uint (value
, rect
->outline_pixels
);
513 case PROP_FILL_COLOR_RGBA
:
514 g_value_set_uint (value
, rect
->fill_color
);
516 case PROP_OUTLINE_COLOR_RGBA
:
517 g_value_set_uint (value
, rect
->outline_color
);
520 g_value_set_boolean (value
, rect
->draw
);
524 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
531 gnome_canvas_simplerect_update (GnomeCanvasItem
*item
, double *affine
, ArtSVP
*clip_path
, int flags
)
533 GnomeCanvasSimpleRect
*simplerect
;
536 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
538 if (parent_class
->update
)
539 (* parent_class
->update
) (item
, affine
, clip_path
, flags
);
541 gnome_canvas_simplerect_reset_bounds (item
);
543 if (simplerect
->full_draw_on_update
) {
544 gnome_canvas_request_redraw (item
->canvas
,
545 simplerect
->bbox_ulx
,
546 simplerect
->bbox_uly
,
547 simplerect
->bbox_lrx
+0.5,
548 simplerect
->bbox_lry
+0.5);
549 simplerect
->full_draw_on_update
= FALSE
;
552 UINT_TO_RGBA (simplerect
->fill_color
, &simplerect
->fill_r
, &simplerect
->fill_g
, &simplerect
->fill_b
, &simplerect
->fill_a
);
553 UINT_TO_RGBA (simplerect
->outline_color
, &simplerect
->outline_r
, &simplerect
->outline_g
, &simplerect
->outline_b
, &foo
);
556 // this can be useful for debugging/understanding how the canvas redraws
559 #undef HARLEQUIN_DEBUGGING
561 #undef SIMPLERECT_FAST_RENDERER
562 #ifdef SIMPLERECT_FAST_RENDERER
565 gnome_canvas_simplerect_render (GnomeCanvasItem
*item
,
568 GnomeCanvasSimpleRect
*simplerect
;
572 ArtIRect intersection
;
575 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
577 if (parent_class
->render
) {
578 (*parent_class
->render
) (item
, buf
);
583 #ifdef HARLEQUIN_DEBUGGING
584 gint randr
, randg
, randb
;
585 randr
= random() % 255;
586 randg
= random() % 255;
587 randb
= random() % 255;
588 PAINT_BOX(buf
, randr
, randg
, randb
, 255, buf
->rect
.x0
, buf
->rect
.y0
, buf
->rect
.x1
, buf
->rect
.y1
);
590 gnome_canvas_buf_ensure_buf (buf
);
594 if (!simplerect
->draw
) {
598 self
.x0
= simplerect
->bbox_ulx
;
599 self
.y0
= simplerect
->bbox_uly
;
600 self
.x1
= simplerect
->bbox_lrx
;
601 self
.y1
= simplerect
->bbox_lry
;
603 art_irect_intersect (&intersection
, &self
, &buf
->rect
);
605 begin
= MAX(simplerect
->bbox_ulx
, buf
->rect
.x0
);
606 end
= MIN((simplerect
->bbox_lrx
-1), buf
->rect
.x1
);
608 sy
= simplerect
->bbox_uly
;
609 ey
= simplerect
->bbox_lry
-1;
611 if (simplerect
->fill
) {
613 // this can be useful for debugging/understanding how the canvas redraws
616 #ifdef HARLEQUIN_DEBUGGING
617 gint randr
, randg
, randb
;
618 randr
= random() % 255;
619 randg
= random() % 255;
620 randb
= random() % 255;
621 PAINT_BOX(buf
, randr
, randg
, randb
, simplerect
->fill_a
, begin
, sy
, end
, ey
);
623 PAINT_BOX (buf
, simplerect
->fill_r
, simplerect
->fill_g
, simplerect
->fill_b
, simplerect
->fill_a
,
624 intersection
.x0
, intersection
.y0
,
625 intersection
.x1
, intersection
.y1
);
630 for (i
= 0; i
< simplerect
->outline_pixels
; ++i
) {
632 if (simplerect
->outline_what
& 0x1) {
633 if (begin
== simplerect
->bbox_ulx
) {
634 PAINT_VERT(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
+ i
, sy
, ey
);
638 if (simplerect
->outline_what
& 0x2) {
639 if (end
== (simplerect
->bbox_lrx
- 1)) {
640 PAINT_VERT(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, end
- i
, sy
, ey
+ 1);
644 if (simplerect
->outline_what
& 0x4) {
645 PAINT_HORIZ(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
, end
, sy
+i
);
648 if (simplerect
->outline_what
& 0x8) {
649 PAINT_HORIZ(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
, end
+ 1, ey
-i
);
654 #else /* SIMPLERECT_FAST_RENDERER */
657 gnome_canvas_simplerect_render (GnomeCanvasItem
*item
,
660 GnomeCanvasSimpleRect
*simplerect
;
665 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
667 if (parent_class
->render
) {
668 (*parent_class
->render
) (item
, buf
);
673 #ifdef HARLEQUIN_DEBUGGING
674 gint randr
, randg
, randb
;
675 randr
= random() % 255;
676 randg
= random() % 255;
677 randb
= random() % 255;
678 PAINT_BOX(buf
, randr
, randg
, randb
, 255, buf
->rect
.x0
, buf
->rect
.y0
, buf
->rect
.x1
, buf
->rect
.y1
);
680 gnome_canvas_buf_ensure_buf (buf
);
684 if (!simplerect
->draw
) {
688 begin
= MAX(simplerect
->bbox_ulx
,buf
->rect
.x0
);
689 end
= MIN((simplerect
->bbox_lrx
-1),buf
->rect
.x1
);
691 sy
= simplerect
->bbox_uly
;
692 ey
= simplerect
->bbox_lry
-1;
694 if (simplerect
->fill
) {
696 #ifdef HARLEQUIN_DEBUGGING
697 gint randr
, randg
, randb
;
698 randr
= random() % 255;
699 randg
= random() % 255;
700 randb
= random() % 255;
701 PAINT_BOX(buf
, randr
, randg
, randb
, simplerect
->fill_a
, begin
, sy
, end
, ey
);
703 PAINT_BOX(buf
, simplerect
->fill_r
, simplerect
->fill_g
, simplerect
->fill_b
, simplerect
->fill_a
, begin
, sy
, end
, ey
);
707 for (i
= 0; i
< simplerect
->outline_pixels
; ++i
) {
709 if (simplerect
->outline_what
& 0x1) {
710 if (begin
== simplerect
->bbox_ulx
) {
711 PAINT_VERT(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
+ i
, sy
, ey
);
715 if (simplerect
->outline_what
& 0x2) {
716 if (end
== (simplerect
->bbox_lrx
- 1)) {
717 PAINT_VERT(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, end
- i
, sy
, ey
+ 1);
721 if (simplerect
->outline_what
& 0x4) {
722 PAINT_HORIZ(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
, end
, sy
+i
);
725 if (simplerect
->outline_what
& 0x8) {
726 PAINT_HORIZ(buf
, simplerect
->outline_r
, simplerect
->outline_g
, simplerect
->outline_b
, begin
, end
+ 1, ey
-i
);
730 #endif /* SIMPLERECT_FAST_RENDERER */
733 gnome_canvas_simplerect_draw (GnomeCanvasItem
*item
,
734 GdkDrawable
*drawable
,
736 int width
, int height
)
738 GnomeCanvasSimpleRect
*simplerect
;
745 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
747 cr
= gdk_cairo_create (drawable
);
749 if (x
> simplerect
->bbox_ulx
) {
752 ulx
= simplerect
->bbox_ulx
;
755 if (y
> simplerect
->bbox_uly
) {
758 uly
= simplerect
->bbox_uly
;
761 if (x
+ width
> simplerect
->bbox_lrx
) {
762 lrx
= simplerect
->bbox_lrx
;
767 if (y
+ height
> simplerect
->bbox_lry
) {
768 lry
= simplerect
->bbox_lry
;
778 cairo_rectangle (cr
, ulx
, uly
, lrx
- ulx
, lry
- uly
);
780 if (simplerect
->fill
) {
781 cairo_set_source_rgba (cr
,
782 simplerect
->fill_r
/255.0,
783 simplerect
->fill_g
/255.0,
784 simplerect
->fill_b
/255.0,
785 simplerect
->fill_a
/255.0);
789 if (simplerect
->outline_what
&& simplerect
->outline_pixels
) {
791 #define x_in_range(a) (x <= (a) && (a) < x + width)
792 #define y_in_range(a) (y <= (a) && (a) < y + height)
794 cairo_set_line_width (cr
, simplerect
->outline_pixels
);
796 cairo_set_source_rgb (cr
,
797 simplerect
->outline_r
/255.0,
798 simplerect
->outline_g
/255.0,
799 simplerect
->outline_b
/255.0);
801 if (simplerect
->outline_what
& 0x1) {
802 /* left edge, if visible */
803 if (x_in_range (simplerect
->bbox_ulx
)) {
804 cairo_move_to (cr
, ulx
+0.5, uly
+0.5);
805 cairo_line_to (cr
, ulx
+0.5, lry
+0.5);
810 if (simplerect
->outline_what
& 0x2) {
811 /* right edge, if visible */
812 if (x_in_range (simplerect
->bbox_lrx
)) {
813 cairo_move_to (cr
, lrx
+0.5, uly
+0.5);
814 cairo_line_to (cr
, lrx
+0.5, lry
+0.5);
819 if (simplerect
->outline_what
& 0x4) {
821 if (y_in_range (simplerect
->bbox_uly
)) {
822 cairo_move_to (cr
, ulx
+0.5, uly
+0.5);
823 cairo_line_to (cr
, lrx
+0.5, uly
+0.5);
828 if (simplerect
->outline_what
& 0x8) {
830 if (y_in_range (simplerect
->bbox_lry
)) {
831 cairo_move_to (cr
, ulx
+0.5, lry
+0.5);
832 cairo_line_to (cr
, lrx
+0.5, lry
+0.5);
842 gnome_canvas_simplerect_point (GnomeCanvasItem
*item
, double x
, double y
, int cx
, int cy
, GnomeCanvasItem
**actual_item
)
847 GnomeCanvasSimpleRect
*simplerect
;
848 double x1
, y1
, x2
, y2
;
851 simplerect
= GNOME_CANVAS_SIMPLERECT (item
);
855 /* Find the bounds for the rectangle plus its outline width */
857 gnome_canvas_simplerect_bounds (item
, &x1
, &y1
, &x2
, &y2
);
859 /* Is point inside rectangle */
861 if ((x
>= x1
) && (y
>= y1
) && (x
<= x2
) && (y
<= y2
)) {
865 /* Point is outside rectangle */
881 return sqrt (dx
* dx
+ dy
* dy
);