evolution-3.6.4/libgnomecanvas/gnome-canvas-rect.c

No issues found

  1 /* Generic bezier rect item for GnomeCanvasWidget.  Most code taken
  2  * from gnome-canvas-bpath but made into a rect item.
  3  *
  4  * GnomeCanvas is basically a port of the Tk toolkit's most excellent
  5  * canvas widget.  Tk is copyrighted by the Regents of the University
  6  * of California, Sun Microsystems, and other parties.
  7  *
  8  * Copyright (C) 1998,1999 The Free Software Foundation
  9  *
 10  * Authors: Federico Mena <federico@nuclecu.unam.mx>
 11  *          Raph Levien <raph@acm.org>
 12  *          Lauris Kaplinski <lauris@ximian.com>
 13  *          Miguel de Icaza <miguel@kernel.org>
 14  *          Cody Russell <bratsche@gnome.org>
 15  *          Rusty Conover <rconover@bangtail.net>
 16  */
 17 
 18 /* These includes are set up for standalone compile. If/when this codebase
 19  * is integrated into libgnomeui, the includes will need to change. */
 20 
 21 #ifdef HAVE_CONFIG_H
 22 #include <config.h>
 23 #endif
 24 
 25 #include <math.h>
 26 #include <string.h>
 27 
 28 #include <gtk/gtk.h>
 29 #include <cairo-gobject.h>
 30 #include "gnome-canvas.h"
 31 #include "gnome-canvas-util.h"
 32 
 33 #include "gnome-canvas-rect.h"
 34 
 35 #define GNOME_CANVAS_RECT_GET_PRIVATE(obj) \
 36 	(G_TYPE_INSTANCE_GET_PRIVATE \
 37 	((obj), GNOME_TYPE_CANVAS_RECT, GnomeCanvasRectPrivate))
 38 
 39 struct _GnomeCanvasRectPrivate {
 40 	cairo_path_t *path;             /* Our bezier path representation */
 41 
 42 	gdouble x1, y1, x2, y2;
 43 
 44 	gdouble scale;			/* CTM scaling (for pen) */
 45 
 46 	guint fill_set : 1;		/* Is fill color set? */
 47 	guint outline_set : 1;		/* Is outline color set? */
 48 
 49 	gdouble line_width;		/* Width of outline, in user coords */
 50 
 51 	guint32 fill_rgba;		/* Fill color, RGBA */
 52 	guint32 outline_rgba;		/* Outline color, RGBA */
 53 
 54 	cairo_line_cap_t cap;		/* Cap style for line */
 55 	cairo_line_join_t join;		/* Join style for line */
 56 	cairo_fill_rule_t wind;		/* Winding rule */
 57 	gdouble miterlimit;		/* Miter limit */
 58 
 59         guint n_dash;                   /* Number of elements in dashing pattern */
 60 	gdouble *dash;		/* Dashing pattern */
 61         gdouble dash_offset;            /* Dashing offset */
 62 };
 63 
 64 enum {
 65 	PROP_0,
 66 	PROP_X1,
 67 	PROP_Y1,
 68 	PROP_X2,
 69 	PROP_Y2,
 70 	PROP_FILL_COLOR,
 71 	PROP_FILL_COLOR_GDK,
 72 	PROP_FILL_COLOR_RGBA,
 73 	PROP_OUTLINE_COLOR,
 74 	PROP_OUTLINE_COLOR_GDK,
 75 	PROP_OUTLINE_COLOR_RGBA,
 76 	PROP_LINE_WIDTH,
 77 	PROP_CAP_STYLE,
 78 	PROP_JOIN_STYLE,
 79 	PROP_WIND,
 80 	PROP_MITERLIMIT,
 81 	PROP_DASH
 82 };
 83 
 84 static void   gnome_canvas_rect_bounds      (GnomeCanvasItem *item,
 85 					      gdouble *x1, gdouble *y1, gdouble *x2, gdouble *y2);
 86 
 87 G_DEFINE_TYPE (GnomeCanvasRect, gnome_canvas_rect, GNOME_TYPE_CANVAS_ITEM)
 88 
 89 static guint32
 90 get_rgba_from_color (GdkColor *color)
 91 {
 92 	return ((color->red & 0xff00) << 16) |
 93 		((color->green & 0xff00) << 8) |
 94 		(color->blue & 0xff00) | 0xff;
 95 }
 96 
 97 static gboolean
 98 gnome_canvas_rect_setup_for_fill (GnomeCanvasRect *rect,
 99                                   cairo_t *cr)
100 {
101 	if (!rect->priv->fill_set)
102 		return FALSE;
103 
104 	cairo_set_source_rgba (
105 		cr,
106 		((rect->priv->fill_rgba >> 24) & 0xff) / 255.0,
107 		((rect->priv->fill_rgba >> 16) & 0xff) / 255.0,
108 		((rect->priv->fill_rgba >>  8) & 0xff) / 255.0,
109 		( rect->priv->fill_rgba        & 0xff) / 255.0);
110 	cairo_set_fill_rule (cr, rect->priv->wind);
111 
112 	return TRUE;
113 }
114 
115 static gboolean
116 gnome_canvas_rect_setup_for_stroke (GnomeCanvasRect *rect,
117                                     cairo_t *cr)
118 {
119 	if (!rect->priv->outline_set)
120 		return FALSE;
121 
122 	cairo_set_source_rgba (
123 		cr,
124 		((rect->priv->outline_rgba >> 24) & 0xff) / 255.0,
125 		((rect->priv->outline_rgba >> 16) & 0xff) / 255.0,
126 		((rect->priv->outline_rgba >>  8) & 0xff) / 255.0,
127 		( rect->priv->outline_rgba        & 0xff) / 255.0);
128 	cairo_set_line_width (cr, rect->priv->line_width);
129 	cairo_set_line_cap (cr, rect->priv->cap);
130 	cairo_set_line_join (cr, rect->priv->join);
131 	cairo_set_miter_limit (cr, rect->priv->miterlimit);
132 	cairo_set_dash (
133 		cr, rect->priv->dash, rect->priv->n_dash,
134 		rect->priv->dash_offset);
135 
136 	return TRUE;
137 }
138 
139 static void
140 gnome_canvas_rect_set_property (GObject *object,
141                                 guint property_id,
142                                 const GValue *value,
143                                 GParamSpec *pspec)
144 {
145 	GnomeCanvasItem *item;
146 	GnomeCanvasRect *rect;
147 	GnomeCanvasRectPrivate *priv;
148 	GdkColor color;
149 	GdkColor *colorptr;
150 	const gchar *color_string;
151 
152 	item = GNOME_CANVAS_ITEM (object);
153 	rect = GNOME_CANVAS_RECT (object);
154 	priv = rect->priv;
155 
156 	switch (property_id) {
157 	case PROP_X1:
158 		priv->x1 = g_value_get_double (value);
159 		gnome_canvas_item_request_update (item);
160 		break;
161 
162 	case PROP_Y1:
163 		priv->y1 = g_value_get_double (value);
164 		gnome_canvas_item_request_update (item);
165 		break;
166 
167 	case PROP_X2:
168 		priv->x2 = g_value_get_double (value);
169 		gnome_canvas_item_request_update (item);
170 		break;
171 
172 	case PROP_Y2:
173 		priv->y2 = g_value_get_double (value);
174 		gnome_canvas_item_request_update (item);
175 		break;
176 
177 	case PROP_FILL_COLOR:
178 		color_string = g_value_get_string (value);
179 		if (color_string != NULL) {
180 			if (!gdk_color_parse (color_string, &color)) {
181 				g_warning (
182 					"Failed to parse color '%s'",
183 					color_string);
184 				break;
185 			}
186 			priv->fill_set = TRUE;
187 			priv->fill_rgba = get_rgba_from_color (&color);
188 		} else if (priv->fill_set)
189 			priv->fill_set = FALSE;
190 		else
191 			break;
192 
193 		gnome_canvas_item_request_update (item);
194 		break;
195 
196 	case PROP_FILL_COLOR_GDK:
197 		colorptr = g_value_get_boxed (value);
198 		if (colorptr != NULL) {
199 			priv->fill_set = TRUE;
200 			priv->fill_rgba = get_rgba_from_color (colorptr);
201 		} else if (priv->fill_set)
202 			priv->fill_set = FALSE;
203 		else
204 			break;
205 
206 		gnome_canvas_item_request_update (item);
207 		break;
208 
209 	case PROP_FILL_COLOR_RGBA:
210 		priv->fill_set = TRUE;
211 		priv->fill_rgba = g_value_get_uint (value);
212 
213 		gnome_canvas_item_request_update (item);
214 		break;
215 
216 	case PROP_OUTLINE_COLOR:
217 		color_string = g_value_get_string (value);
218 		if (color_string != NULL) {
219 			if (!gdk_color_parse (color_string, &color)) {
220 				g_warning (
221 					"Failed to parse color '%s'",
222 					color_string);
223 				break;
224 			}
225 			priv->outline_set = TRUE;
226 			priv->outline_rgba = get_rgba_from_color (&color);
227 		} else if (priv->outline_set)
228 			priv->outline_set = FALSE;
229 		else
230 			break;
231 
232 		gnome_canvas_item_request_update (item);
233 		break;
234 
235 	case PROP_OUTLINE_COLOR_GDK:
236 		colorptr = g_value_get_boxed (value);
237 		if (colorptr != NULL) {
238 			priv->outline_set = TRUE;
239 			priv->outline_rgba = get_rgba_from_color (colorptr);
240 		} else if (priv->outline_set)
241 			priv->outline_set = FALSE;
242 		else
243 			break;
244 
245 		gnome_canvas_item_request_update (item);
246 		break;
247 
248 	case PROP_OUTLINE_COLOR_RGBA:
249 		priv->outline_set = TRUE;
250 		priv->outline_rgba = g_value_get_uint (value);
251 
252 		gnome_canvas_item_request_update (item);
253 		break;
254 
255 	case PROP_LINE_WIDTH:
256 		priv->line_width = g_value_get_double (value);
257 
258 		gnome_canvas_item_request_update (item);
259 		break;
260 
261 	case PROP_WIND:
262 		priv->wind = g_value_get_enum (value);
263 		gnome_canvas_item_request_update (item);
264 		break;
265 
266 	case PROP_CAP_STYLE:
267 		priv->cap = g_value_get_enum (value);
268 		gnome_canvas_item_request_update (item);
269 		break;
270 
271 	case PROP_JOIN_STYLE:
272 		priv->join = g_value_get_enum (value);
273 		gnome_canvas_item_request_update (item);
274 		break;
275 
276 	case PROP_MITERLIMIT:
277 		priv->miterlimit = g_value_get_double (value);
278 		gnome_canvas_item_request_update (item);
279 		break;
280 
281 	case PROP_DASH:
282 		/* XXX */
283 		g_warn_if_reached ();
284 		break;
285 
286 	default:
287 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
288 		break;
289 	}
290 }
291 
292 static void
293 gnome_canvas_rect_get_property (GObject *object,
294                                 guint property_id,
295                                 GValue *value,
296                                 GParamSpec *pspec)
297 {
298 	GnomeCanvasRect *rect = GNOME_CANVAS_RECT (object);
299 	GnomeCanvasRectPrivate *priv = rect->priv;
300 
301 	switch (property_id) {
302 
303 	case PROP_X1:
304 		g_value_set_double (value, priv->x1);
305 		break;
306 
307 	case PROP_Y1:
308 		g_value_set_double (value, priv->y1);
309 		break;
310 
311 	case PROP_X2:
312 		g_value_set_double (value, priv->x2);
313 		break;
314 
315 	case PROP_Y2:
316 		g_value_set_double (value, priv->y2);
317 		break;
318 
319 	case PROP_FILL_COLOR_RGBA:
320 		g_value_set_uint (value, priv->fill_rgba);
321 		break;
322 
323 	case PROP_OUTLINE_COLOR_RGBA:
324 		g_value_set_uint (value, priv->outline_rgba);
325 		break;
326 
327 	case PROP_WIND:
328 		g_value_set_uint (value, priv->wind);
329 		break;
330 
331 	case PROP_CAP_STYLE:
332 		g_value_set_enum (value, priv->cap);
333 		break;
334 
335 	case PROP_JOIN_STYLE:
336 		g_value_set_enum (value, priv->join);
337 		break;
338 
339 	case PROP_LINE_WIDTH:
340 		g_value_set_double (value, priv->line_width);
341 		break;
342 
343 	case PROP_MITERLIMIT:
344 		g_value_set_double (value, priv->miterlimit);
345 		break;
346 
347 	case PROP_DASH:
348 		/* XXX */
349 		g_warn_if_reached ();
350 		break;
351 
352 	default:
353 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
354 		break;
355 	}
356 }
357 
358 static void
359 gnome_canvas_rect_dispose (GnomeCanvasItem *object)
360 {
361 	GnomeCanvasRect *rect;
362 
363 	g_return_if_fail (GNOME_IS_CANVAS_RECT (object));
364 
365 	rect = GNOME_CANVAS_RECT (object);
366 
367 	if (rect->priv->path != NULL) {
368 		cairo_path_destroy (rect->priv->path);
369 		rect->priv->path = NULL;
370 	}
371 
372 	g_free (rect->priv->dash);
373 	rect->priv->dash = NULL;
374 
375 	if (GNOME_CANVAS_ITEM_CLASS (gnome_canvas_rect_parent_class)->dispose)
376 		GNOME_CANVAS_ITEM_CLASS (gnome_canvas_rect_parent_class)->dispose (object);
377 }
378 
379 static void
380 gnome_canvas_rect_update (GnomeCanvasItem *item,
381                           const cairo_matrix_t *i2c,
382                           gint flags)
383 {
384 	gdouble x1, x2, y1, y2;
385 
386 	GNOME_CANVAS_ITEM_CLASS (gnome_canvas_rect_parent_class)->
387 		update (item, i2c, flags);
388 
389 	gnome_canvas_rect_bounds (item, &x1, &y1, &x2, &y2);
390 	gnome_canvas_matrix_transform_rect (i2c, &x1, &y1, &x2, &y2);
391 
392 	gnome_canvas_update_bbox (
393 		item, floor (x1), floor (y1), ceil (x2), ceil (y2));
394 }
395 
396 static void
397 gnome_canvas_rect_draw (GnomeCanvasItem *item,
398                         cairo_t *cr,
399                         gint x,
400                         gint y,
401                         gint width,
402                         gint height)
403 {
404 	GnomeCanvasRect *rect;
405 	cairo_matrix_t matrix;
406 
407 	rect = GNOME_CANVAS_RECT (item);
408 
409 	cairo_save (cr);
410 
411 	gnome_canvas_item_i2c_matrix (item, &matrix);
412 	cairo_transform (cr, &matrix);
413 
414 	if (gnome_canvas_rect_setup_for_fill (rect, cr)) {
415 		cairo_rectangle (
416 			cr,
417 			rect->priv->x1 - x,
418 			rect->priv->y1 - y,
419 			rect->priv->x2 - rect->priv->x1,
420 			rect->priv->y2 - rect->priv->y1);
421 		cairo_fill (cr);
422 	}
423 
424 	if (gnome_canvas_rect_setup_for_stroke (rect, cr)) {
425 		cairo_rectangle (
426 			cr,
427 			rect->priv->x1 - x,
428 			rect->priv->y1 - y,
429 			rect->priv->x2 - rect->priv->x1,
430 			rect->priv->y2 - rect->priv->y1);
431 		cairo_stroke (cr);
432 	}
433 
434 	cairo_restore (cr);
435 }
436 
437 static GnomeCanvasItem *
438 gnome_canvas_rect_point (GnomeCanvasItem *item,
439                          gdouble x,
440                          gdouble y,
441                          gint cx,
442                          gint cy)
443 {
444 	GnomeCanvasRect *rect;
445 	cairo_t *cr;
446 
447 	rect = GNOME_CANVAS_RECT (item);
448 
449 	cr = gnome_canvas_cairo_create_scratch ();
450 
451 	cairo_rectangle (
452 		cr,
453 		rect->priv->x1,
454 		rect->priv->y1,
455 		rect->priv->x2 - rect->priv->x1,
456 		rect->priv->y2 - rect->priv->y1);
457 
458 	if (gnome_canvas_rect_setup_for_fill (rect, cr) &&
459 	    cairo_in_fill (cr, x, y)) {
460 		cairo_destroy (cr);
461 		return item;
462 	}
463 
464 	if (gnome_canvas_rect_setup_for_stroke (rect, cr) &&
465 	    cairo_in_stroke (cr, x, y)) {
466 		cairo_destroy (cr);
467 		return item;
468 	}
469 
470 	cairo_destroy (cr);
471 
472 	return NULL;
473 }
474 
475 static void
476 gnome_canvas_rect_bounds (GnomeCanvasItem *item,
477                           gdouble *x1,
478                           gdouble *y1,
479                           gdouble *x2,
480                           gdouble *y2)
481 {
482 	GnomeCanvasRect *rect;
483 	cairo_t *cr;
484 
485 	rect = GNOME_CANVAS_RECT (item);
486 
487 	cr = gnome_canvas_cairo_create_scratch ();
488 
489 	cairo_rectangle (
490 		cr,
491 		rect->priv->x1,
492 		rect->priv->y1,
493 		rect->priv->x2 - rect->priv->x1,
494 		rect->priv->y2 - rect->priv->y1);
495 
496 	if (gnome_canvas_rect_setup_for_stroke (rect, cr))
497 		cairo_stroke_extents (cr, x1, y1, x2, y2);
498 	else if (gnome_canvas_rect_setup_for_fill (rect, cr))
499 		cairo_fill_extents (cr, x1, y1, x2, y2);
500 	else {
501 		*x1 = *x2 = *y1 = *y2 = 0;
502 	}
503 
504 	cairo_destroy (cr);
505 }
506 
507 static void
508 gnome_canvas_rect_class_init (GnomeCanvasRectClass *class)
509 {
510 	GObjectClass *object_class;
511 	GnomeCanvasItemClass *item_class;
512 
513 	g_type_class_add_private (class, sizeof (GnomeCanvasRectPrivate));
514 
515 	object_class = G_OBJECT_CLASS (class);
516 	object_class->set_property = gnome_canvas_rect_set_property;
517 	object_class->get_property = gnome_canvas_rect_get_property;
518 
519 	item_class = GNOME_CANVAS_ITEM_CLASS (class);
520 	item_class->dispose = gnome_canvas_rect_dispose;
521 	item_class->update = gnome_canvas_rect_update;
522 	item_class->draw = gnome_canvas_rect_draw;
523 	item_class->point = gnome_canvas_rect_point;
524 	item_class->bounds = gnome_canvas_rect_bounds;
525 
526 	g_object_class_install_property (
527 		object_class,
528 		PROP_X1,
529 		g_param_spec_double (
530 			"x1",
531 			NULL,
532 			NULL,
533 			-G_MAXDOUBLE,
534 			G_MAXDOUBLE,
535 			0,
536 			G_PARAM_READWRITE));
537 
538 	g_object_class_install_property (
539 		object_class,
540 		PROP_Y1,
541 		g_param_spec_double (
542 			"y1",
543 			NULL,
544 			NULL,
545 			-G_MAXDOUBLE,
546 			G_MAXDOUBLE,
547 			0,
548 			G_PARAM_READWRITE));
549 
550 	g_object_class_install_property (
551 		object_class,
552 		PROP_X2,
553 		g_param_spec_double (
554 			"x2",
555 			NULL,
556 			NULL,
557 			-G_MAXDOUBLE,
558 			G_MAXDOUBLE,
559 			0,
560 			G_PARAM_READWRITE));
561 
562 	g_object_class_install_property (
563 		object_class,
564 		PROP_Y2,
565 		g_param_spec_double (
566 			"y2",
567 			NULL,
568 			NULL,
569 			-G_MAXDOUBLE,
570 			G_MAXDOUBLE,
571 			0,
572 			G_PARAM_READWRITE));
573 
574 	g_object_class_install_property (
575 		object_class,
576 		PROP_FILL_COLOR,
577 		g_param_spec_string (
578 			"fill_color",
579 			NULL,
580 			NULL,
581 			NULL,
582 			G_PARAM_WRITABLE));
583 
584 	g_object_class_install_property (
585 		object_class,
586 		PROP_FILL_COLOR_GDK,
587 		g_param_spec_boxed (
588 			"fill_color_gdk",
589 			NULL,
590 			NULL,
591 			GDK_TYPE_COLOR,
592 			G_PARAM_WRITABLE));
593 
594 	g_object_class_install_property (
595 		object_class,
596 		PROP_FILL_COLOR_RGBA,
597 		g_param_spec_uint (
598 			"fill_rgba",
599 			NULL,
600 			NULL,
601 			0,
602 			G_MAXUINT,
603 			0,
604 			G_PARAM_READWRITE));
605 
606 	g_object_class_install_property (
607 		object_class,
608 		PROP_OUTLINE_COLOR,
609 		g_param_spec_string (
610 			"outline_color",
611 			NULL,
612 			NULL,
613 			NULL,
614 			G_PARAM_WRITABLE));
615 
616 	g_object_class_install_property (
617 		object_class,
618 		PROP_OUTLINE_COLOR_GDK,
619 		g_param_spec_boxed (
620 			"outline_color_gdk",
621 			NULL,
622 			NULL,
623 			GDK_TYPE_COLOR,
624 			G_PARAM_WRITABLE));
625 
626 	g_object_class_install_property (
627 		object_class,
628 		PROP_OUTLINE_COLOR_RGBA,
629 		g_param_spec_uint (
630 			"outline_rgba",
631 			NULL,
632 			NULL,
633 			0,
634 			G_MAXUINT,
635 			0,
636 			G_PARAM_READWRITE));
637 
638 	g_object_class_install_property (
639 		object_class,
640 		PROP_LINE_WIDTH,
641 		g_param_spec_double (
642 			"line_width",
643 			NULL,
644 			NULL,
645 			0.0,
646 			G_MAXDOUBLE,
647 			1.0,
648 			G_PARAM_READWRITE));
649 
650 	g_object_class_install_property (
651 		object_class,
652 		PROP_CAP_STYLE,
653 		g_param_spec_enum (
654 			"cap_style",
655 			NULL,
656 			NULL,
657 			CAIRO_GOBJECT_TYPE_LINE_CAP,
658 			CAIRO_LINE_CAP_BUTT,
659 			G_PARAM_READWRITE));
660 
661 	g_object_class_install_property (
662 		object_class,
663 		PROP_JOIN_STYLE,
664 		g_param_spec_enum (
665 			"join_style",
666 			NULL,
667 			NULL,
668 			CAIRO_GOBJECT_TYPE_LINE_JOIN,
669 			CAIRO_LINE_JOIN_MITER,
670 			G_PARAM_READWRITE));
671 
672 	g_object_class_install_property (
673 		object_class,
674 		PROP_WIND,
675 		g_param_spec_enum (
676 			"wind",
677 			NULL,
678 			NULL,
679 			CAIRO_GOBJECT_TYPE_FILL_RULE,
680 			CAIRO_FILL_RULE_EVEN_ODD,
681 			G_PARAM_READWRITE));
682 
683 	g_object_class_install_property (
684 		object_class,
685 		PROP_MITERLIMIT,
686 		g_param_spec_double (
687 			"miterlimit",
688 			NULL,
689 			NULL,
690 			0.0,
691 			G_MAXDOUBLE,
692 			10.43,
693 			G_PARAM_READWRITE));
694 
695 #if 0
696 	/* XXX: Find a good way to pass dash properties in a property */
697 	g_object_class_install_property (
698 		object_class,
699 		PROP_DASH,
700 		g_param_spec_pointer (
701 			"dash",
702 			NULL,
703 			NULL,
704 			G_PARAM_READWRITE));
705 #endif
706 }
707 
708 static void
709 gnome_canvas_rect_init (GnomeCanvasRect *rect)
710 {
711 	rect->priv = GNOME_CANVAS_RECT_GET_PRIVATE (rect);
712 
713 	rect->priv->scale = 1.0;
714 
715 	rect->priv->fill_set = FALSE;
716 	rect->priv->outline_set = FALSE;
717 
718 	rect->priv->line_width = 1.0;
719 
720 	rect->priv->fill_rgba = 0x0000003f;
721 	rect->priv->outline_rgba = 0x0000007f;
722 
723 	rect->priv->cap = CAIRO_LINE_CAP_BUTT;
724 	rect->priv->join = CAIRO_LINE_JOIN_MITER;
725 	rect->priv->wind = CAIRO_FILL_RULE_EVEN_ODD;
726 	rect->priv->miterlimit = 10.43;	   /* X11 default */
727 
728 	rect->priv->n_dash = 0;
729 	rect->priv->dash = NULL;
730 }