am-project: rh #702849 crash when removing a target in the project root node
[anjuta.git] / libfoocanvas / foo-canvas-rect-ellipse.c
blob11a03ac04d78ee73782135110d5f792a1bdce66c
1 /*
2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
3 * All rights reserved.
5 * This file is part of the Gnome Library.
7 * The Gnome Library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
12 * The Gnome Library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with the Gnome Library; see the file COPYING.LIB. If not,
19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 @NOTATION@
25 /* Rectangle and ellipse item types for FooCanvas widget
27 * FooCanvas is basically a port of the Tk toolkit's most excellent canvas widget. Tk is
28 * copyrighted by the Regents of the University of California, Sun Microsystems, and other parties.
31 * Author: Federico Mena <federico@nuclecu.unam.mx>
34 #include <config.h>
35 #include <math.h>
36 #include "foo-canvas-rect-ellipse.h"
37 #include "foo-canvas-util.h"
38 #include <string.h>
40 #ifdef HAVE_RENDER
41 #include <gdk/gdkx.h>
42 #include <X11/extensions/Xrender.h>
43 #endif
45 /* Base class for rectangle and ellipse item types */
47 #define noVERBOSE
49 enum {
50 PROP_0,
51 PROP_X1,
52 PROP_Y1,
53 PROP_X2,
54 PROP_Y2,
55 PROP_FILL_COLOR,
56 PROP_FILL_COLOR_GDK,
57 PROP_FILL_COLOR_RGBA,
58 PROP_OUTLINE_COLOR,
59 PROP_OUTLINE_COLOR_GDK,
60 PROP_OUTLINE_COLOR_RGBA,
61 PROP_FILL_STIPPLE,
62 PROP_OUTLINE_STIPPLE,
63 PROP_WIDTH_PIXELS,
64 PROP_WIDTH_UNITS,
65 PROP_AA
69 static void foo_canvas_re_class_init (FooCanvasREClass *klass);
70 static void foo_canvas_re_init (FooCanvasRE *re);
71 static void foo_canvas_re_destroy (GtkObject *object);
72 static void foo_canvas_re_set_property (GObject *object,
73 guint param_id,
74 const GValue *value,
75 GParamSpec *pspec);
76 static void foo_canvas_re_get_property (GObject *object,
77 guint param_id,
78 GValue *value,
79 GParamSpec *pspec);
81 static void foo_canvas_re_update_shared (FooCanvasItem *item,
82 double i2w_dx, double i2w_dy, int flags);
83 static void foo_canvas_re_realize (FooCanvasItem *item);
84 static void foo_canvas_re_bounds (FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2);
85 static void foo_canvas_re_translate (FooCanvasItem *item, double dx, double dy);
86 static void foo_canvas_rect_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags);
87 static void foo_canvas_ellipse_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags);
89 typedef struct {
90 /*< public >*/
91 int x0, y0, x1, y1;
92 } Rect;
94 static Rect make_rect (int x0, int y0, int x1, int y1);
95 static void diff_rects (Rect r1, Rect r2, int *count, Rect result[4]);
97 static FooCanvasItemClass *re_parent_class;
98 static FooCanvasREClass *rect_parent_class;
101 GType
102 foo_canvas_re_get_type (void)
104 static GType re_type = 0;
106 if (!re_type) {
107 GTypeInfo re_info = {
108 sizeof (FooCanvasREClass),
109 (GBaseInitFunc) NULL,
110 (GBaseFinalizeFunc) NULL,
111 (GClassInitFunc) foo_canvas_re_class_init,
112 NULL, /* class_finalize */
113 NULL, /* class_data */
114 sizeof (FooCanvasRE),
115 0, /* n_preallocs */
116 (GInstanceInitFunc) foo_canvas_re_init
119 re_type = g_type_register_static (foo_canvas_item_get_type (),
120 "FooCanvasRE",
121 &re_info,
125 return re_type;
128 static void
129 foo_canvas_re_class_init (FooCanvasREClass *klass)
131 GObjectClass *gobject_class;
132 GtkObjectClass *object_class;
133 FooCanvasItemClass *item_class;
135 gobject_class = (GObjectClass *) klass;
136 object_class = (GtkObjectClass *) klass;
137 item_class = (FooCanvasItemClass *) klass;
139 re_parent_class = g_type_class_peek_parent (klass);
141 gobject_class->set_property = foo_canvas_re_set_property;
142 gobject_class->get_property = foo_canvas_re_get_property;
144 g_object_class_install_property
145 (gobject_class,
146 PROP_X1,
147 g_param_spec_double ("x1", NULL, NULL,
148 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
149 G_PARAM_READWRITE));
150 g_object_class_install_property
151 (gobject_class,
152 PROP_Y1,
153 g_param_spec_double ("y1", NULL, NULL,
154 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
155 G_PARAM_READWRITE));
156 g_object_class_install_property
157 (gobject_class,
158 PROP_X2,
159 g_param_spec_double ("x2", NULL, NULL,
160 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
161 G_PARAM_READWRITE));
162 g_object_class_install_property
163 (gobject_class,
164 PROP_Y2,
165 g_param_spec_double ("y2", NULL, NULL,
166 -G_MAXDOUBLE, G_MAXDOUBLE, 0,
167 G_PARAM_READWRITE));
168 g_object_class_install_property
169 (gobject_class,
170 PROP_FILL_COLOR,
171 g_param_spec_string ("fill-color", NULL, NULL,
172 NULL,
173 G_PARAM_READWRITE));
174 g_object_class_install_property
175 (gobject_class,
176 PROP_FILL_COLOR_GDK,
177 g_param_spec_boxed ("fill-color-gdk", NULL, NULL,
178 GDK_TYPE_COLOR,
179 G_PARAM_READWRITE));
180 g_object_class_install_property
181 (gobject_class,
182 PROP_FILL_COLOR_RGBA,
183 g_param_spec_uint ("fill-color-rgba", NULL, NULL,
184 0, G_MAXUINT, 0,
185 G_PARAM_READWRITE));
186 g_object_class_install_property
187 (gobject_class,
188 PROP_FILL_STIPPLE,
189 g_param_spec_object ("fill-stipple", NULL, NULL,
190 GDK_TYPE_DRAWABLE,
191 G_PARAM_READWRITE));
192 g_object_class_install_property
193 (gobject_class,
194 PROP_OUTLINE_COLOR,
195 g_param_spec_string ("outline-color", NULL, NULL,
196 NULL,
197 G_PARAM_READWRITE));
198 g_object_class_install_property
199 (gobject_class,
200 PROP_OUTLINE_COLOR_GDK,
201 g_param_spec_boxed ("outline-color-gdk", NULL, NULL,
202 GDK_TYPE_COLOR,
203 G_PARAM_READWRITE));
204 g_object_class_install_property
205 (gobject_class,
206 PROP_OUTLINE_COLOR_RGBA,
207 g_param_spec_uint ("outline-color-rgba", NULL, NULL,
208 0, G_MAXUINT, 0,
209 G_PARAM_READWRITE));
210 g_object_class_install_property
211 (gobject_class,
212 PROP_OUTLINE_STIPPLE,
213 g_param_spec_object ("outline-stipple", NULL, NULL,
214 GDK_TYPE_DRAWABLE,
215 G_PARAM_READWRITE));
216 g_object_class_install_property
217 (gobject_class,
218 PROP_WIDTH_PIXELS,
219 g_param_spec_uint ("width-pixels", NULL, NULL,
220 0, G_MAXUINT, 0,
221 G_PARAM_READWRITE));
222 g_object_class_install_property
223 (gobject_class,
224 PROP_WIDTH_UNITS,
225 g_param_spec_double ("width-units", NULL, NULL,
226 0.0, G_MAXDOUBLE, 0.0,
227 G_PARAM_READWRITE));
228 g_object_class_install_property
229 (gobject_class,
230 PROP_AA,
231 g_param_spec_boolean ("aa", NULL, NULL,
232 FALSE,
233 G_PARAM_READWRITE));
235 object_class->destroy = foo_canvas_re_destroy;
237 item_class->realize = foo_canvas_re_realize;
238 item_class->translate = foo_canvas_re_translate;
239 item_class->bounds = foo_canvas_re_bounds;
242 static void
243 foo_canvas_re_init (FooCanvasRE *re)
245 re->x1 = 0.0;
246 re->y1 = 0.0;
247 re->x2 = 0.0;
248 re->y2 = 0.0;
249 re->width = 1.0;
250 re->aa = TRUE;
253 static void
254 foo_canvas_re_destroy (GtkObject *object)
256 FooCanvasRE *re;
258 g_return_if_fail (object != NULL);
259 g_return_if_fail (FOO_IS_CANVAS_RE (object));
261 re = FOO_CANVAS_RE (object);
263 /* remember, destroy can be run multiple times! */
265 if (re->fill_stipple)
266 g_object_unref (re->fill_stipple);
267 re->fill_stipple = NULL;
269 if (re->outline_stipple)
270 g_object_unref (re->outline_stipple);
271 re->outline_stipple = NULL;
273 if (GTK_OBJECT_CLASS (re_parent_class)->destroy)
274 (* GTK_OBJECT_CLASS (re_parent_class)->destroy) (object);
277 static double
278 get_draw_width_pixels (FooCanvasRE *re)
280 double width;
281 if (re->width_pixels)
282 width = re->width;
283 else
284 width = re->width * re->item.canvas->pixels_per_unit;
285 width += 2.0; /* AA puts 1 px around for fuzzing */
286 return width;
289 static double
290 get_draw_width_units (FooCanvasRE *re)
292 double width = get_draw_width_pixels (re);
293 return (width / re->item.canvas->pixels_per_unit);
296 static void get_bounds (FooCanvasRE *re, double *px1, double *py1, double *px2, double *py2)
298 FooCanvasItem *item;
299 double x1, y1, x2, y2;
300 int cx1, cy1, cx2, cy2;
301 double hwidth;
303 #ifdef VERBOSE
304 g_print ("re get_bounds\n");
305 #endif
306 item = FOO_CANVAS_ITEM (re);
308 hwidth = get_draw_width_units (re) / 2.0;
309 x1 = re->x1;
310 y1 = re->y1;
311 x2 = re->x2;
312 y2 = re->y2;
314 foo_canvas_item_i2w (item, &x1, &y1);
315 foo_canvas_item_i2w (item, &x2, &y2);
316 foo_canvas_w2c (item->canvas, x1 - hwidth, y1 - hwidth, &cx1, &cy1);
317 foo_canvas_w2c (item->canvas, x2 + hwidth, y2 + hwidth, &cx2, &cy2);
318 *px1 = cx1;
319 *py1 = cy1;
320 *px2 = cx2;
321 *py2 = cy2;
323 /* Some safety fudging */
325 *px1 -= 2;
326 *py1 -= 2;
327 *px2 += 2;
328 *py2 += 2;
331 static void
332 foo_canvas_re_set_fill (FooCanvasRE *re, gboolean fill_set)
334 if (re->fill_set != fill_set) {
335 re->fill_set = fill_set;
336 foo_canvas_item_request_update (FOO_CANVAS_ITEM (re));
340 static void
341 foo_canvas_re_set_outline (FooCanvasRE *re, gboolean outline_set)
343 if (re->outline_set != outline_set) {
344 re->outline_set = outline_set;
345 foo_canvas_item_request_update (FOO_CANVAS_ITEM (re));
349 static void
350 foo_canvas_re_set_property (GObject *object,
351 guint param_id,
352 const GValue *value,
353 GParamSpec *pspec)
355 FooCanvasItem *item;
356 FooCanvasRE *re;
357 GdkColor color = { 0, 0, 0, 0, };
358 GdkColor *pcolor;
359 int have_pixel;
361 g_return_if_fail (object != NULL);
362 g_return_if_fail (FOO_IS_CANVAS_RE (object));
364 item = FOO_CANVAS_ITEM (object);
365 re = FOO_CANVAS_RE (object);
366 have_pixel = FALSE;
368 switch (param_id) {
369 case PROP_X1:
370 re->x1 = g_value_get_double (value);
372 foo_canvas_item_request_update (item);
373 break;
375 case PROP_Y1:
376 re->y1 = g_value_get_double (value);
378 foo_canvas_item_request_update (item);
379 break;
381 case PROP_X2:
382 re->x2 = g_value_get_double (value);
384 foo_canvas_item_request_update (item);
385 break;
387 case PROP_Y2:
388 re->y2 = g_value_get_double (value);
390 foo_canvas_item_request_update (item);
391 break;
393 case PROP_FILL_COLOR:
394 case PROP_FILL_COLOR_GDK:
395 case PROP_FILL_COLOR_RGBA:
396 switch (param_id) {
397 case PROP_FILL_COLOR:
398 if (g_value_get_string (value) &&
399 gdk_color_parse (g_value_get_string (value), &color))
400 foo_canvas_re_set_fill (re, TRUE);
401 else
402 foo_canvas_re_set_fill (re, FALSE);
404 re->fill_color = ((color.red & 0xff00) << 16 |
405 (color.green & 0xff00) << 8 |
406 (color.blue & 0xff00) |
407 0xff);
408 break;
410 case PROP_FILL_COLOR_GDK:
411 pcolor = g_value_get_boxed (value);
412 foo_canvas_re_set_fill (re, pcolor != NULL);
414 if (pcolor) {
415 GdkColormap *colormap;
417 color = *pcolor;
418 colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
419 gdk_rgb_find_color (colormap, &color);
420 have_pixel = TRUE;
423 re->fill_color = ((color.red & 0xff00) << 16 |
424 (color.green & 0xff00) << 8 |
425 (color.blue & 0xff00) |
426 0xff);
427 break;
429 case PROP_FILL_COLOR_RGBA:
430 foo_canvas_re_set_fill (re, TRUE);
431 re->fill_color = g_value_get_uint (value);
432 break;
434 #ifdef VERBOSE
435 g_print ("re fill color = %08x\n", re->fill_color);
436 #endif
437 if (have_pixel)
438 re->fill_pixel = color.pixel;
439 else
440 re->fill_pixel = foo_canvas_get_color_pixel (item->canvas, re->fill_color);
442 foo_canvas_item_request_redraw (item);
443 break;
445 case PROP_OUTLINE_COLOR:
446 case PROP_OUTLINE_COLOR_GDK:
447 case PROP_OUTLINE_COLOR_RGBA:
448 switch (param_id) {
449 case PROP_OUTLINE_COLOR:
450 if (g_value_get_string (value) &&
451 gdk_color_parse (g_value_get_string (value), &color))
452 foo_canvas_re_set_outline (re, TRUE);
453 else
454 foo_canvas_re_set_outline (re, FALSE);
456 re->outline_color = ((color.red & 0xff00) << 16 |
457 (color.green & 0xff00) << 8 |
458 (color.blue & 0xff00) |
459 0xff);
460 break;
462 case PROP_OUTLINE_COLOR_GDK:
463 pcolor = g_value_get_boxed (value);
464 foo_canvas_re_set_outline (re, pcolor != NULL);
466 if (pcolor) {
467 GdkColormap *colormap;
469 color = *pcolor;
470 colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
471 gdk_rgb_find_color (colormap, &color);
473 have_pixel = TRUE;
476 re->outline_color = ((color.red & 0xff00) << 16 |
477 (color.green & 0xff00) << 8 |
478 (color.blue & 0xff00) |
479 0xff);
480 break;
482 case PROP_OUTLINE_COLOR_RGBA:
483 foo_canvas_re_set_outline (re, TRUE);
484 re->outline_color = g_value_get_uint (value);
485 break;
487 #ifdef VERBOSE
488 g_print ("re outline color %x %x %x\n", color.red, color.green, color.blue);
489 #endif
490 if (have_pixel)
491 re->outline_pixel = color.pixel;
492 else
493 re->outline_pixel = foo_canvas_get_color_pixel (item->canvas,
494 re->outline_color);
496 foo_canvas_item_request_redraw (item);
497 break;
499 case PROP_FILL_STIPPLE:
500 if (re->fill_stipple)
501 g_object_unref (re->fill_stipple);
502 re->fill_stipple = (GdkBitmap *) g_value_get_object (value);
503 g_object_ref (re->fill_stipple);
504 break;
506 case PROP_OUTLINE_STIPPLE:
507 if (re->outline_stipple)
508 g_object_unref (re->outline_stipple);
509 re->outline_stipple = (GdkBitmap *) g_value_get_object (value);
510 g_object_ref (re->outline_stipple);
511 break;
513 case PROP_WIDTH_PIXELS:
514 re->width = g_value_get_uint (value);
515 re->width_pixels = TRUE;
516 foo_canvas_item_request_update (item);
517 break;
519 case PROP_WIDTH_UNITS:
520 re->width = fabs (g_value_get_double (value));
521 re->width_pixels = FALSE;
522 foo_canvas_item_request_update (item);
523 break;
525 case PROP_AA:
526 re->aa = g_value_get_boolean (value);
527 foo_canvas_item_request_update (item);
528 break;
530 default:
531 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
532 break;
536 /* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified
537 * value for returning it in the get_property method.
539 static void
540 get_color_value (FooCanvasRE *re, gulong pixel, GValue *value)
542 GdkColor color;
543 FooCanvasItem *item = (FooCanvasItem *) re;
544 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
546 gdk_colormap_query_color (colormap, pixel, &color);
547 g_value_set_boxed (value, &color);
550 static void
551 foo_canvas_re_get_property (GObject *object,
552 guint param_id,
553 GValue *value,
554 GParamSpec *pspec)
556 FooCanvasRE *re;
558 g_return_if_fail (object != NULL);
559 g_return_if_fail (FOO_IS_CANVAS_RE (object));
561 re = FOO_CANVAS_RE (object);
563 switch (param_id) {
564 case PROP_X1:
565 g_value_set_double (value, re->x1);
566 break;
568 case PROP_Y1:
569 g_value_set_double (value, re->y1);
570 break;
572 case PROP_X2:
573 g_value_set_double (value, re->x2);
574 break;
576 case PROP_Y2:
577 g_value_set_double (value, re->y2);
578 break;
580 case PROP_FILL_COLOR_GDK:
581 get_color_value (re, re->fill_pixel, value);
582 break;
584 case PROP_OUTLINE_COLOR_GDK:
585 get_color_value (re, re->outline_pixel, value);
586 break;
588 case PROP_FILL_COLOR_RGBA:
589 g_value_set_uint (value, re->fill_color);
590 break;
592 case PROP_OUTLINE_COLOR_RGBA:
593 g_value_set_uint (value, re->outline_color);
594 break;
596 case PROP_FILL_STIPPLE:
597 g_value_set_object (value, (GObject *) re->fill_stipple);
598 break;
600 case PROP_OUTLINE_STIPPLE:
601 g_value_set_object (value, (GObject *) re->outline_stipple);
602 break;
604 case PROP_AA:
605 g_value_set_boolean (value, re->aa);
606 break;
608 default:
609 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
610 break;
614 static void
615 foo_canvas_re_update_shared (FooCanvasItem *item, double i2w_dx, double i2w_dy, int flags)
617 FooCanvasRE *re;
619 #ifdef VERBOSE
620 g_print ("foo_canvas_re_update_shared\n");
621 #endif
622 re = FOO_CANVAS_RE (item);
624 if (re_parent_class->update)
625 (* re_parent_class->update) (item, i2w_dx, i2w_dy, flags);
627 #ifdef OLD_XFORM
628 recalc_bounds (re);
629 #endif
632 static void
633 foo_canvas_re_realize (FooCanvasItem *item)
635 FooCanvasRE *re;
637 #ifdef VERBOSE
638 g_print ("foo_canvas_re_realize\n");
639 #endif
640 re = FOO_CANVAS_RE (item);
642 if (re_parent_class->realize)
643 (* re_parent_class->realize) (item);
645 re->fill_pixel = foo_canvas_get_color_pixel (item->canvas, re->fill_color);
646 re->outline_pixel = foo_canvas_get_color_pixel (item->canvas, re->outline_color);
648 #ifdef OLD_XFORM
649 (* FOO_CANVAS_ITEM_CLASS (item->object.klass)->update) (item, NULL, NULL, 0);
650 #endif
653 static void
654 foo_canvas_re_translate (FooCanvasItem *item, double dx, double dy)
656 FooCanvasRE *re;
658 #ifdef VERBOSE
659 g_print ("foo_canvas_re_translate\n");
660 #endif
661 re = FOO_CANVAS_RE (item);
663 re->x1 += dx;
664 re->y1 += dy;
665 re->x2 += dx;
666 re->y2 += dy;
669 static void
670 foo_canvas_re_bounds (FooCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
672 FooCanvasRE *re;
673 double hwidth;
675 #ifdef VERBOSE
676 g_print ("foo_canvas_re_bounds\n");
677 #endif
678 re = FOO_CANVAS_RE (item);
680 hwidth = get_draw_width_units (re) / 2.0;
682 *x1 = re->x1 - hwidth;
683 *y1 = re->y1 - hwidth;
684 *x2 = re->x2 + hwidth;
685 *y2 = re->y2 + hwidth;
688 /* Rectangle item */
691 static void foo_canvas_rect_class_init (FooCanvasRectClass *klass);
692 static void foo_canvas_rect_init (FooCanvasRect *rect);
693 static void foo_canvas_rect_finalize (GObject *object);
694 static void foo_canvas_rect_realize (FooCanvasItem *item);
696 static void foo_canvas_rect_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose);
697 static double foo_canvas_rect_point (FooCanvasItem *item, double x, double y, int cx, int cy,
698 FooCanvasItem **actual_item);
700 struct _FooCanvasRectPrivate {
701 Rect last_update_rect;
702 Rect last_outline_update_rect;
703 int last_outline_update_width;
705 #ifdef HAVE_RENDER
706 gboolean use_render;
707 XRenderPictFormat *format;
708 #endif
711 GType
712 foo_canvas_rect_get_type (void)
714 static GType rect_type = 0;
716 if (!rect_type) {
717 GTypeInfo rect_info = {
718 sizeof (FooCanvasRectClass),
719 (GBaseInitFunc) NULL,
720 (GBaseFinalizeFunc) NULL,
721 (GClassInitFunc) foo_canvas_rect_class_init,
722 NULL, /* class_finalize */
723 NULL, /* class_data */
724 sizeof (FooCanvasRect),
725 0, /* n_preallocs */
726 (GInstanceInitFunc) foo_canvas_rect_init
729 rect_type = g_type_register_static (foo_canvas_re_get_type (),
730 "FooCanvasRect",
731 &rect_info,
735 return rect_type;
738 static void
739 foo_canvas_rect_class_init (FooCanvasRectClass *klass)
741 FooCanvasItemClass *item_class;
743 rect_parent_class = g_type_class_peek_parent (klass);
745 item_class = (FooCanvasItemClass *) klass;
747 item_class->draw = foo_canvas_rect_draw;
748 item_class->point = foo_canvas_rect_point;
749 item_class->update = foo_canvas_rect_update;
750 item_class->realize = foo_canvas_rect_realize;
752 G_OBJECT_CLASS (klass)->finalize = foo_canvas_rect_finalize;
756 static void
757 foo_canvas_rect_init (FooCanvasRect *rect)
759 rect->priv = g_new0 (FooCanvasRectPrivate, 1);
762 static void
763 foo_canvas_rect_finalize (GObject *object)
765 FooCanvasRect *rect = FOO_CANVAS_RECT (object);
767 if (rect->priv) {
768 g_free (rect->priv);
771 G_OBJECT_CLASS (rect_parent_class)->finalize (object);
774 static void
775 foo_canvas_rect_realize (FooCanvasItem *item)
777 if (FOO_CANVAS_ITEM_CLASS (rect_parent_class)->realize) {
778 (* FOO_CANVAS_ITEM_CLASS (rect_parent_class)->realize) (item);
782 static void
783 foo_canvas_rect_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose)
785 cairo_t *cr;
786 FooCanvasRE *re;
787 double x1, y1, x2, y2;
788 int cx1, cy1, cx2, cy2;
789 double i2w_dx, i2w_dy;
790 double width;
792 re = FOO_CANVAS_RE (item);
794 /* Get canvas pixel coordinates */
795 i2w_dx = 0.0;
796 i2w_dy = 0.0;
797 foo_canvas_item_i2w (item, &i2w_dx, &i2w_dy);
799 x1 = re->x1 + i2w_dx;
800 y1 = re->y1 + i2w_dy;
801 x2 = re->x2 + i2w_dx;
802 y2 = re->y2 + i2w_dy;
804 foo_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1);
805 foo_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2);
807 if (re->width_pixels)
808 width = re->width;
809 else
810 width = re->width * re->item.canvas->pixels_per_unit;
812 cr = gdk_cairo_create (drawable);
813 if (!re->aa)
814 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
815 cairo_set_line_width (cr, width);
817 if (re->fill_set) {
818 /* FIXME: Use stipple */
819 cairo_set_source_rgba (cr,
820 ((double) ((re->fill_color & 0xff000000) >> 24)) / 255,
821 ((double) ((re->fill_color & 0xff0000) >> 16)) / 255,
822 ((double) ((re->fill_color & 0xff00) >> 8)) / 255,
823 ((double) ((re->fill_color & 0xff))) / 255);
824 cairo_rectangle (cr, cx1, cy1, cx2 - cx1 + 1, cy2 - cy1 + 1);
825 cairo_fill (cr);
828 if (re->outline_set) {
829 /* FIXME: Use stipple */
830 cairo_set_source_rgba (cr,
831 ((double) ((re->outline_color & 0xff000000) >> 24)) / 255,
832 ((double) ((re->outline_color & 0xff0000) >> 16)) / 255,
833 ((double) ((re->outline_color & 0xff00) >> 8)) / 255,
834 ((double) ((re->outline_color & 0xff))) / 255);
835 cairo_rectangle (cr, cx1, cy1, cx2 - cx1, cy2 - cy1);
836 cairo_stroke (cr);
838 cairo_destroy (cr);
841 static double
842 foo_canvas_rect_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item)
844 FooCanvasRE *re;
845 double x1, y1, x2, y2;
846 double hwidth;
847 double dx, dy;
848 double tmp;
850 #ifdef VERBOSE
851 g_print ("foo_canvas_rect_point\n");
852 #endif
853 re = FOO_CANVAS_RE (item);
855 *actual_item = item;
857 /* Find the bounds for the rectangle plus its outline width */
859 x1 = re->x1;
860 y1 = re->y1;
861 x2 = re->x2;
862 y2 = re->y2;
864 if (re->outline_set) {
865 hwidth = get_draw_width_units (re) / 2.0;
866 x1 -= hwidth;
867 y1 -= hwidth;
868 x2 += hwidth;
869 y2 += hwidth;
870 } else
871 hwidth = 0.0;
873 /* Is point inside rectangle (which can be hollow if it has no fill set)? */
875 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2)) {
876 if (re->fill_set || !re->outline_set)
877 return 0.0;
879 dx = x - x1;
880 tmp = x2 - x;
881 if (tmp < dx)
882 dx = tmp;
884 dy = y - y1;
885 tmp = y2 - y;
886 if (tmp < dy)
887 dy = tmp;
889 if (dy < dx)
890 dx = dy;
892 dx -= 2.0 * hwidth;
894 if (dx < 0.0)
895 return 0.0;
896 else
897 return dx;
900 /* Point is outside rectangle */
902 if (x < x1)
903 dx = x1 - x;
904 else if (x > x2)
905 dx = x - x2;
906 else
907 dx = 0.0;
909 if (y < y1)
910 dy = y1 - y;
911 else if (y > y2)
912 dy = y - y2;
913 else
914 dy = 0.0;
916 return sqrt (dx * dx + dy * dy);
919 static void
920 request_redraw_borders (FooCanvas *canvas,
921 Rect *update_rect,
922 int width)
924 foo_canvas_request_redraw (canvas,
925 update_rect->x0, update_rect->y0,
926 update_rect->x1, update_rect->y0 + width);
927 foo_canvas_request_redraw (canvas,
928 update_rect->x0, update_rect->y1-width,
929 update_rect->x1, update_rect->y1);
930 foo_canvas_request_redraw (canvas,
931 update_rect->x0, update_rect->y0,
932 update_rect->x0+width, update_rect->y1);
933 foo_canvas_request_redraw (canvas,
934 update_rect->x1-width, update_rect->y0,
935 update_rect->x1, update_rect->y1);
939 static void
940 foo_canvas_rect_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, gint flags)
942 FooCanvasRE *re;
943 double x1, y1, x2, y2;
944 int cx1, cy1, cx2, cy2;
945 int repaint_rects_count, i;
946 int width_pixels;
947 int width_lt, width_rb;
948 Rect update_rect, repaint_rects[4];
949 FooCanvasRectPrivate *priv;
951 foo_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags);
953 re = FOO_CANVAS_RE (item);
954 priv = FOO_CANVAS_RECT (item)->priv;
956 x1 = re->x1 + i2w_dx;
957 y1 = re->y1 + i2w_dy;
958 x2 = re->x2 + i2w_dx;
959 y2 = re->y2 + i2w_dy;
961 foo_canvas_w2c (item->canvas, x1, y1, &cx1, &cy1);
962 foo_canvas_w2c (item->canvas, x2, y2, &cx2, &cy2);
964 update_rect = make_rect (cx1, cy1, cx2+1, cy2+1);
965 #if 0
966 foo_canvas_request_redraw (item->canvas,
967 update_rect.x0, update_rect.y0,
968 update_rect.x1, update_rect.y1);
969 foo_canvas_request_redraw (item->canvas,
970 priv->last_update_rect.x0, priv->last_update_rect.y0,
971 priv->last_update_rect.x1, priv->last_update_rect.y1);
972 #else
973 diff_rects (update_rect, priv->last_update_rect,
974 &repaint_rects_count, repaint_rects);
975 for (i = 0; i < repaint_rects_count; i++) {
976 foo_canvas_request_redraw (item->canvas,
977 repaint_rects[i].x0, repaint_rects[i].y0,
978 repaint_rects[i].x1, repaint_rects[i].y1);
980 #endif
981 priv->last_update_rect = update_rect;
983 if (re->outline_set) {
984 /* Outline and bounding box */
985 width_pixels = get_draw_width_pixels (re);
987 width_lt = width_pixels / 2;
988 width_rb = (width_pixels + 1) / 2;
990 cx1 -= width_lt;
991 cy1 -= width_lt;
992 cx2 += width_rb;
993 cy2 += width_rb;
995 update_rect = make_rect (cx1, cy1, cx2, cy2);
996 request_redraw_borders (item->canvas, &update_rect,
997 (width_lt + width_rb));
998 request_redraw_borders (item->canvas, &priv->last_outline_update_rect,
999 priv->last_outline_update_width);
1000 priv->last_outline_update_rect = update_rect;
1001 priv->last_outline_update_width = width_lt + width_rb;
1003 item->x1 = cx1;
1004 item->y1 = cy1;
1005 item->x2 = cx2+1;
1006 item->y2 = cy2+1;
1007 } else {
1008 item->x1 = cx1;
1009 item->y1 = cy1;
1010 item->x2 = cx2+1;
1011 item->y2 = cy2+1;
1015 /* Ellipse item */
1018 static void foo_canvas_ellipse_class_init (FooCanvasEllipseClass *klass);
1020 static void foo_canvas_ellipse_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose);
1021 static double foo_canvas_ellipse_point (FooCanvasItem *item, double x, double y, int cx, int cy,
1022 FooCanvasItem **actual_item);
1025 GType
1026 foo_canvas_ellipse_get_type (void)
1028 static GType ellipse_type = 0;
1030 if (!ellipse_type) {
1031 GTypeInfo ellipse_info = {
1032 sizeof (FooCanvasEllipseClass),
1033 (GBaseInitFunc) NULL,
1034 (GBaseFinalizeFunc) NULL,
1035 (GClassInitFunc) foo_canvas_ellipse_class_init,
1036 NULL, /* class_finalize */
1037 NULL, /* class_data */
1038 sizeof (FooCanvasEllipse),
1039 0, /* n_preallocs */
1040 (GInstanceInitFunc) NULL
1044 ellipse_type = g_type_register_static (foo_canvas_re_get_type (),
1045 "FooCanvasEllipse",
1046 &ellipse_info,
1050 return ellipse_type;
1053 static void
1054 foo_canvas_ellipse_class_init (FooCanvasEllipseClass *klass)
1056 FooCanvasItemClass *item_class;
1058 item_class = (FooCanvasItemClass *) klass;
1060 item_class->draw = foo_canvas_ellipse_draw;
1061 item_class->point = foo_canvas_ellipse_point;
1062 item_class->update = foo_canvas_ellipse_update;
1065 static void
1066 foo_canvas_ellipse_draw (FooCanvasItem *item, GdkDrawable *drawable, GdkEventExpose *expose)
1068 cairo_t *cr;
1069 FooCanvasRE *re;
1070 int x1, y1, x2, y2;
1071 double i2w_dx, i2w_dy;
1072 double width;
1074 re = FOO_CANVAS_RE (item);
1076 /* Get canvas pixel coordinates */
1078 i2w_dx = 0.0;
1079 i2w_dy = 0.0;
1080 foo_canvas_item_i2w (item, &i2w_dx, &i2w_dy);
1082 foo_canvas_w2c (item->canvas,
1083 re->x1 + i2w_dx,
1084 re->y1 + i2w_dy,
1085 &x1, &y1);
1086 foo_canvas_w2c (item->canvas,
1087 re->x2 + i2w_dx,
1088 re->y2 + i2w_dy,
1089 &x2, &y2);
1091 if (re->width_pixels)
1092 width = re->width;
1093 else
1094 width = re->width * re->item.canvas->pixels_per_unit;
1096 cr = gdk_cairo_create (drawable);
1097 if (!re->aa)
1098 cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE);
1099 cairo_set_line_width (cr, width);
1101 if (re->fill_set) {
1102 /* FIXME: set stipple as source */
1103 cairo_set_source_rgba (cr,
1104 ((double) ((re->fill_color & 0xff000000) >> 24)) / 255,
1105 ((double) ((re->fill_color & 0xff0000) >> 16)) / 255,
1106 ((double) ((re->fill_color & 0xff00) >> 8)) / 255,
1107 ((double) ((re->fill_color & 0xff))) / 255);
1108 cairo_save (cr);
1109 cairo_translate (cr, x1 + (x2 - x1)/2, y1 + (y2 - y1)/2);
1110 cairo_scale (cr, (x2 - x1)/2, (y2 - y1)/2);
1111 cairo_arc (cr, 0.0, 0.0, 1.0, 0 * 64, 360 * 64);
1112 cairo_restore (cr);
1113 cairo_fill_preserve (cr);
1116 if (re->outline_set) {
1117 /* FIXME: set stipple as source */
1119 cairo_set_source_rgba (cr,
1120 ((double) ((re->outline_color & 0xff000000) >> 24)) / 255,
1121 ((double) ((re->outline_color & 0xff0000) >> 16)) / 255,
1122 ((double) ((re->outline_color & 0xff00) >> 8)) / 255,
1123 ((double) ((re->outline_color & 0xff))) / 255);
1124 if (!re->fill_set)
1126 cairo_save (cr);
1127 cairo_translate (cr, x1 + (x2 - x1)/2, y1 + (y2 - y1)/2);
1128 cairo_scale (cr, (x2 - x1)/2, (y2 - y1)/2);
1129 cairo_arc (cr, 0.0, 0.0, 1.0, 0 * 64, 360 * 64);
1130 cairo_restore (cr);
1132 cairo_stroke (cr);
1134 cairo_destroy (cr);
1137 static double
1138 foo_canvas_ellipse_point (FooCanvasItem *item, double x, double y, int cx, int cy, FooCanvasItem **actual_item)
1140 FooCanvasRE *re;
1141 double dx, dy;
1142 double scaled_dist;
1143 double outline_dist;
1144 double center_dist;
1145 double width;
1146 double a, b;
1147 double diamx, diamy;
1149 re = FOO_CANVAS_RE (item);
1151 *actual_item = item;
1153 if (re->outline_set) {
1154 width = get_draw_width_units (re);
1155 } else
1156 width = 0.0;
1158 /* Compute the distance between the center of the ellipse and the point, with the ellipse
1159 * considered as being scaled to a circle.
1162 dx = x - (re->x1 + re->x2) / 2.0;
1163 dy = y - (re->y1 + re->y2) / 2.0;
1164 center_dist = sqrt (dx * dx + dy * dy);
1166 a = dx / ((re->x2 + width - re->x1) / 2.0);
1167 b = dy / ((re->y2 + width - re->y1) / 2.0);
1168 scaled_dist = sqrt (a * a + b * b);
1170 /* If the scaled distance is greater than 1, then we are outside. Compute the distance from
1171 * the point to the edge of the circle, then scale back to the original un-scaled coordinate
1172 * system.
1175 if (scaled_dist > 1.0)
1176 return (center_dist / scaled_dist) * (scaled_dist - 1.0);
1178 /* We are inside the outer edge of the ellipse. If it is filled, then we are "inside".
1179 * Otherwise, do the same computation as above, but also check whether we are inside the
1180 * outline.
1183 if (re->fill_set)
1184 return 0.0;
1186 if (scaled_dist > FOO_CANVAS_EPSILON)
1187 outline_dist = (center_dist / scaled_dist) * (1.0 - scaled_dist) - width;
1188 else {
1189 /* Handle very small distance */
1191 diamx = re->x2 - re->x1;
1192 diamy = re->y2 - re->y1;
1194 if (diamx < diamy)
1195 outline_dist = (diamx - width) / 2.0;
1196 else
1197 outline_dist = (diamy - width) / 2.0;
1200 if (outline_dist < 0.0)
1201 return 0.0;
1203 return outline_dist;
1206 static void
1207 foo_canvas_ellipse_update (FooCanvasItem *item, double i2w_dx, double i2w_dy, gint flags)
1209 FooCanvasRE *re;
1210 double x0, y0, x1, y1;
1212 #ifdef VERBOSE
1213 g_print ("foo_canvas_sllipse_update item %x\n", item);
1214 #endif
1216 foo_canvas_re_update_shared (item, i2w_dx, i2w_dy, flags);
1217 re = FOO_CANVAS_RE (item);
1219 get_bounds (re, &x0, &y0, &x1, &y1);
1220 foo_canvas_update_bbox (item, x0, y0, x1, y1);
1223 static int
1224 rect_empty (const Rect *src) {
1225 return (src->x1 <= src->x0 || src->y1 <= src->y0);
1228 static Rect
1229 make_rect (int x0, int y0, int x1, int y1)
1231 Rect r;
1233 r.x0 = x0;
1234 r.y0 = y0;
1235 r.x1 = x1;
1236 r.y1 = y1;
1237 return r;
1240 static gboolean
1241 rects_intersect (Rect r1, Rect r2)
1243 if (r1.x0 >= r2.x1) {
1244 return FALSE;
1246 if (r2.x0 >= r1.x1) {
1247 return FALSE;
1249 if (r1.y0 >= r2.y1) {
1250 return FALSE;
1252 if (r2.y0 >= r1.y1) {
1253 return FALSE;
1255 return TRUE;
1258 static void
1259 diff_rects_guts (Rect ra, Rect rb, int *count, Rect result[4])
1261 if (ra.x0 < rb.x0) {
1262 result[(*count)++] = make_rect (ra.x0, ra.y0, rb.x0, ra.y1);
1264 if (ra.y0 < rb.y0) {
1265 result[(*count)++] = make_rect (ra.x0, ra.y0, ra.x1, rb.y0);
1267 if (ra.x1 < rb.x1) {
1268 result[(*count)++] = make_rect (ra.x1, rb.y0, rb.x1, rb.y1);
1270 if (ra.y1 < rb.y1) {
1271 result[(*count)++] = make_rect (rb.x0, ra.y1, rb.x1, rb.y1);
1275 static void
1276 diff_rects (Rect r1, Rect r2, int *count, Rect result[4])
1278 g_assert (count != NULL);
1279 g_assert (result != NULL);
1281 *count = 0;
1283 if (rects_intersect (r1, r2)) {
1284 diff_rects_guts (r1, r2, count, result);
1285 diff_rects_guts (r2, r1, count, result);
1286 } else {
1287 if (!rect_empty (&r1)) {
1288 result[(*count)++] = r1;
1290 if (!rect_empty (&r2)) {
1291 result[(*count)++] = r2;