2 * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
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.
25 /* Polygon item type 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.
30 * Author: Federico Mena <federico@nuclecu.unam.mx>
36 #include "libfoocanvas.h"
39 #define NUM_STATIC_POINTS 256 /* Number of static points to use to avoid allocating arrays */
42 #define GROW_BOUNDS(bx1, by1, bx2, by2, x, y) { \
64 PROP_OUTLINE_COLOR_GDK
,
65 PROP_OUTLINE_COLOR_RGBA
,
74 static void foo_canvas_polygon_class_init (FooCanvasPolygonClass
*klass
);
75 static void foo_canvas_polygon_init (FooCanvasPolygon
*poly
);
76 static void foo_canvas_polygon_destroy (GtkObject
*object
);
77 static void foo_canvas_polygon_set_property (GObject
*object
,
81 static void foo_canvas_polygon_get_property (GObject
*object
,
86 static void foo_canvas_polygon_update (FooCanvasItem
*item
,
87 double i2w_dx
, double i2w_dy
,
89 static void foo_canvas_polygon_draw (FooCanvasItem
*item
, GdkDrawable
*drawable
,
90 GdkEventExpose
*expose
);
91 static double foo_canvas_polygon_point (FooCanvasItem
*item
, double x
, double y
,
92 int cx
, int cy
, FooCanvasItem
**actual_item
);
93 static void foo_canvas_polygon_translate (FooCanvasItem
*item
, double dx
, double dy
);
94 static void foo_canvas_polygon_bounds (FooCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
);
97 static FooCanvasItemClass
*parent_class
;
99 G_DEFINE_TYPE (FooCanvasPolygon
, foo_canvas_polygon
, FOO_TYPE_CANVAS_ITEM
)
102 foo_canvas_polygon_class_init (FooCanvasPolygonClass
*klass
)
104 GObjectClass
*gobject_class
;
105 GtkObjectClass
*object_class
;
106 FooCanvasItemClass
*item_class
;
108 gobject_class
= (GObjectClass
*) klass
;
109 object_class
= (GtkObjectClass
*) klass
;
110 item_class
= (FooCanvasItemClass
*) klass
;
112 parent_class
= g_type_class_peek_parent (klass
);
114 gobject_class
->set_property
= foo_canvas_polygon_set_property
;
115 gobject_class
->get_property
= foo_canvas_polygon_get_property
;
117 g_object_class_install_property
120 g_param_spec_boxed ("points", NULL
, NULL
,
121 FOO_TYPE_CANVAS_POINTS
,
123 g_object_class_install_property
126 g_param_spec_string ("fill-color", NULL
, NULL
,
129 g_object_class_install_property
132 g_param_spec_boxed ("fill-color-gdk", NULL
, NULL
,
135 g_object_class_install_property
137 PROP_FILL_COLOR_RGBA
,
138 g_param_spec_uint ("fill-color-rgba", NULL
, NULL
,
141 g_object_class_install_property
144 g_param_spec_string ("outline-color", NULL
, NULL
,
147 g_object_class_install_property
149 PROP_OUTLINE_COLOR_GDK
,
150 g_param_spec_boxed ("outline-color-gdk", NULL
, NULL
,
153 g_object_class_install_property
155 PROP_OUTLINE_COLOR_RGBA
,
156 g_param_spec_uint ("outline-color-rgba", NULL
, NULL
,
159 g_object_class_install_property
162 g_param_spec_object ("fill-stipple", NULL
, NULL
,
165 g_object_class_install_property
167 PROP_OUTLINE_STIPPLE
,
168 g_param_spec_object ("outline-stipple", NULL
, NULL
,
171 g_object_class_install_property
174 g_param_spec_uint ("width-pixels", NULL
, NULL
,
177 g_object_class_install_property
180 g_param_spec_double ("width-units", NULL
, NULL
,
181 0.0, G_MAXDOUBLE
, 0.0,
183 g_object_class_install_property
186 g_param_spec_boolean ("aa", NULL
, NULL
,
190 object_class
->destroy
= foo_canvas_polygon_destroy
;
192 item_class
->update
= foo_canvas_polygon_update
;
193 item_class
->draw
= foo_canvas_polygon_draw
;
194 item_class
->point
= foo_canvas_polygon_point
;
195 item_class
->translate
= foo_canvas_polygon_translate
;
196 item_class
->bounds
= foo_canvas_polygon_bounds
;
200 foo_canvas_polygon_init (FooCanvasPolygon
*poly
)
207 foo_canvas_polygon_destroy (GtkObject
*object
)
209 FooCanvasPolygon
*poly
;
211 g_return_if_fail (object
!= NULL
);
212 g_return_if_fail (FOO_IS_CANVAS_POLYGON (object
));
214 poly
= FOO_CANVAS_POLYGON (object
);
216 /* remember, destroy can be run multiple times! */
219 g_free (poly
->coords
);
222 if (poly
->fill_stipple
)
223 g_object_unref (poly
->fill_stipple
);
224 poly
->fill_stipple
= NULL
;
226 if (poly
->outline_stipple
)
227 g_object_unref (poly
->outline_stipple
);
228 poly
->outline_stipple
= NULL
;
230 if (GTK_OBJECT_CLASS (parent_class
)->destroy
)
231 (* GTK_OBJECT_CLASS (parent_class
)->destroy
) (object
);
234 /* Computes the bounding box of the polygon. Assumes that the number of points in the polygon is
238 get_bounds (FooCanvasPolygon
*poly
, double *bx1
, double *by1
, double *bx2
, double *by2
)
241 double x1
, y1
, x2
, y2
;
245 if (poly
->num_points
== 0)
248 /* Compute bounds of vertices */
250 x1
= x2
= poly
->coords
[0];
251 y1
= y2
= poly
->coords
[1];
253 for (i
= 1, coords
= poly
->coords
+ 2; i
< poly
->num_points
; i
++, coords
+= 2) {
254 GROW_BOUNDS (x1
, y1
, x2
, y2
, coords
[0], coords
[1]);
257 /* Add outline width */
259 if (poly
->width_pixels
)
260 width
= poly
->width
/ poly
->item
.canvas
->pixels_per_unit
;
280 /* Computes the bounding box of the polygon, in canvas coordinates. Assumes that the number of points in the polygon is
284 get_bounds_canvas (FooCanvasPolygon
*poly
,
285 double *bx1
, double *by1
, double *bx2
, double *by2
,
286 double i2w_dx
, double i2w_dy
)
289 double bbox_x0
, bbox_y0
, bbox_x1
, bbox_y1
;
291 item
= FOO_CANVAS_ITEM (poly
);
293 if (!get_bounds (poly
, &bbox_x0
, &bbox_y0
, &bbox_x1
, &bbox_y1
))
301 foo_canvas_w2c_rect_d (item
->canvas
,
302 &bbox_x0
, &bbox_y0
, &bbox_x1
, &bbox_y1
);
304 /* include 1 pixel of fudge */
312 /* Sets the points of the polygon item to the specified ones. If needed, it will add a point to
316 set_points (FooCanvasPolygon
*poly
, FooCanvasPoints
*points
)
320 /* See if we need to duplicate the first point */
322 duplicate
= ((points
->coords
[0] != points
->coords
[2 * points
->num_points
- 2])
323 || (points
->coords
[1] != points
->coords
[2 * points
->num_points
- 1]));
326 poly
->num_points
= points
->num_points
+ 1;
328 poly
->num_points
= points
->num_points
;
330 poly
->coords
= g_new (double, 2 * poly
->num_points
);
331 memcpy (poly
->coords
, points
->coords
, 2 * points
->num_points
* sizeof (double));
334 poly
->coords
[2 * poly
->num_points
- 2] = poly
->coords
[0];
335 poly
->coords
[2 * poly
->num_points
- 1] = poly
->coords
[1];
340 foo_canvas_polygon_set_property (GObject
*object
,
346 FooCanvasPolygon
*poly
;
347 FooCanvasPoints
*points
;
348 GdkColor color
= { 0, 0, 0, 0, };
352 g_return_if_fail (object
!= NULL
);
353 g_return_if_fail (FOO_IS_CANVAS_POLYGON (object
));
355 item
= FOO_CANVAS_ITEM (object
);
356 poly
= FOO_CANVAS_POLYGON (object
);
361 points
= g_value_get_boxed (value
);
364 g_free (poly
->coords
);
369 poly
->num_points
= 0;
371 set_points (poly
, points
);
373 foo_canvas_item_request_update (item
);
376 case PROP_FILL_COLOR
:
377 case PROP_FILL_COLOR_GDK
:
378 case PROP_FILL_COLOR_RGBA
:
380 case PROP_FILL_COLOR
:
381 if (g_value_get_string (value
) &&
382 gdk_color_parse (g_value_get_string (value
), &color
))
383 poly
->fill_set
= TRUE
;
385 poly
->fill_set
= FALSE
;
387 poly
->fill_color
= ((color
.red
& 0xff00) << 16 |
388 (color
.green
& 0xff00) << 8 |
389 (color
.blue
& 0xff00) |
393 case PROP_FILL_COLOR_GDK
:
394 pcolor
= g_value_get_boxed (value
);
395 poly
->fill_set
= pcolor
!= NULL
;
398 GdkColormap
*colormap
;
401 colormap
= gtk_widget_get_colormap (GTK_WIDGET (item
->canvas
));
402 gdk_rgb_find_color (colormap
, &color
);
406 poly
->fill_color
= ((color
.red
& 0xff00) << 16 |
407 (color
.green
& 0xff00) << 8 |
408 (color
.blue
& 0xff00) |
412 case PROP_FILL_COLOR_RGBA
:
413 poly
->fill_set
= TRUE
;
414 poly
->fill_color
= g_value_get_uint (value
);
418 g_print ("poly fill color = %08x\n", poly
->fill_color
);
421 poly
->fill_pixel
= color
.pixel
;
423 poly
->fill_pixel
= foo_canvas_get_color_pixel (item
->canvas
,
426 foo_canvas_item_request_redraw (item
);
429 case PROP_OUTLINE_COLOR
:
430 case PROP_OUTLINE_COLOR_GDK
:
431 case PROP_OUTLINE_COLOR_RGBA
:
433 case PROP_OUTLINE_COLOR
:
434 if (g_value_get_string (value
) &&
435 gdk_color_parse (g_value_get_string (value
), &color
))
436 poly
->outline_set
= TRUE
;
438 poly
->outline_set
= FALSE
;
440 poly
->outline_color
= ((color
.red
& 0xff00) << 16 |
441 (color
.green
& 0xff00) << 8 |
442 (color
.blue
& 0xff00) |
446 case PROP_OUTLINE_COLOR_GDK
:
447 pcolor
= g_value_get_boxed (value
);
448 poly
->outline_set
= pcolor
!= NULL
;
451 GdkColormap
*colormap
;
454 colormap
= gtk_widget_get_colormap (GTK_WIDGET (item
->canvas
));
455 gdk_rgb_find_color (colormap
, &color
);
459 poly
->outline_color
= ((color
.red
& 0xff00) << 16 |
460 (color
.green
& 0xff00) << 8 |
461 (color
.blue
& 0xff00) |
465 case PROP_OUTLINE_COLOR_RGBA
:
466 poly
->outline_set
= TRUE
;
467 poly
->outline_color
= g_value_get_uint (value
);
471 g_print ("poly outline color = %08x\n", poly
->outline_color
);
474 poly
->outline_pixel
= color
.pixel
;
476 poly
->outline_pixel
= foo_canvas_get_color_pixel (item
->canvas
,
477 poly
->outline_color
);
479 foo_canvas_item_request_redraw (item
);
482 case PROP_FILL_STIPPLE
:
483 if (poly
->fill_stipple
)
484 g_object_unref (poly
->fill_stipple
);
485 poly
->fill_stipple
= (GdkBitmap
*) g_value_get_object (value
);
486 g_object_ref (poly
->fill_stipple
);
487 foo_canvas_item_request_update (item
);
490 case PROP_OUTLINE_STIPPLE
:
491 if (poly
->outline_stipple
)
492 g_object_unref (poly
->outline_stipple
);
493 poly
->outline_stipple
= (GdkBitmap
*) g_value_get_object (value
);
494 g_object_ref (poly
->outline_stipple
);
495 foo_canvas_item_request_update (item
);
498 case PROP_WIDTH_PIXELS
:
499 poly
->width
= g_value_get_uint (value
);
500 poly
->width_pixels
= TRUE
;
502 recalc_bounds (poly
);
504 foo_canvas_item_request_update (item
);
508 case PROP_WIDTH_UNITS
:
509 poly
->width
= fabs (g_value_get_double (value
));
510 poly
->width_pixels
= FALSE
;
512 recalc_bounds (poly
);
514 foo_canvas_item_request_update (item
);
518 poly
->aa
= g_value_get_boolean (value
);
519 foo_canvas_item_request_update (item
);
523 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
528 /* Allocates a GdkColor structure filled with the specified pixel, and puts it into the specified
529 * value for returning it in the get_property method.
532 get_color_value (FooCanvasPolygon
*poly
, gulong pixel
, GValue
*value
)
535 GdkColormap
*colormap
;
537 color
= g_new (GdkColor
, 1);
538 color
->pixel
= pixel
;
540 colormap
= gtk_widget_get_colormap (GTK_WIDGET (poly
));
541 gdk_rgb_find_color (colormap
, color
);
542 g_value_set_boxed (value
, color
);
546 foo_canvas_polygon_get_property (GObject
*object
,
551 FooCanvasPolygon
*poly
;
552 FooCanvasPoints
*points
;
554 g_return_if_fail (object
!= NULL
);
555 g_return_if_fail (FOO_IS_CANVAS_POLYGON (object
));
557 poly
= FOO_CANVAS_POLYGON (object
);
561 if (poly
->num_points
!= 0) {
562 points
= foo_canvas_points_new (poly
->num_points
);
563 memcpy (points
->coords
, poly
->coords
, 2 * poly
->num_points
* sizeof (double));
564 g_value_set_boxed (value
, points
);
566 g_value_set_boxed (value
, NULL
);
569 case PROP_FILL_COLOR_GDK
:
570 get_color_value (poly
, poly
->fill_pixel
, value
);
573 case PROP_OUTLINE_COLOR_GDK
:
574 get_color_value (poly
, poly
->outline_pixel
, value
);
577 case PROP_FILL_COLOR_RGBA
:
578 g_value_set_uint (value
, poly
->fill_color
);
581 case PROP_OUTLINE_COLOR_RGBA
:
582 g_value_set_uint (value
, poly
->outline_color
);
585 case PROP_FILL_STIPPLE
:
586 g_value_set_object (value
, (GObject
*) poly
->fill_stipple
);
589 case PROP_OUTLINE_STIPPLE
:
590 g_value_set_object (value
, (GObject
*) poly
->outline_stipple
);
594 g_value_set_boolean (value
, poly
->aa
);
598 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, param_id
, pspec
);
604 foo_canvas_polygon_update (FooCanvasItem
*item
,
605 double i2w_dx
, double i2w_dy
,
608 FooCanvasPolygon
*poly
;
609 double x1
, y1
, x2
, y2
;
611 poly
= FOO_CANVAS_POLYGON (item
);
613 if (parent_class
->update
)
614 (* parent_class
->update
) (item
, i2w_dx
, i2w_dy
, flags
);
616 if (get_bounds_canvas (poly
, &x1
, &y1
, &x2
, &y2
, i2w_dx
, i2w_dy
))
617 foo_canvas_update_bbox (item
, x1
, y1
, x2
, y2
);
620 /* Converts an array of world coordinates into an array of canvas pixel coordinates. Takes in the
621 * item->world deltas and the drawable deltas.
624 item_to_canvas (FooCanvas
*canvas
, double *item_coords
, GdkPoint
*canvas_coords
, int num_points
,
625 double i2w_dx
, double i2w_dy
)
629 for (i
= 0; i
< num_points
; i
++) {
630 foo_canvas_w2c (canvas
,
631 item_coords
[i
*2] + i2w_dx
,
632 item_coords
[i
*2+1] + i2w_dy
,
633 &canvas_coords
->x
, &canvas_coords
->y
);
639 foo_canvas_polygon_draw (FooCanvasItem
*item
, GdkDrawable
*drawable
,
640 GdkEventExpose
*expose
)
643 FooCanvasPolygon
*poly
;
644 GdkPoint static_points
[NUM_STATIC_POINTS
];
646 double i2w_dx
, i2w_dy
;
650 poly
= FOO_CANVAS_POLYGON (item
);
652 if (poly
->num_points
== 0)
655 /* Build array of canvas pixel coordinates */
657 if (poly
->num_points
<= NUM_STATIC_POINTS
)
658 points
= static_points
;
660 points
= g_new (GdkPoint
, poly
->num_points
);
664 foo_canvas_item_i2w (item
, &i2w_dx
, &i2w_dy
);
666 item_to_canvas (item
->canvas
,
667 poly
->coords
, points
, poly
->num_points
,
670 if (poly
->width_pixels
)
673 width
= poly
->width
* poly
->item
.canvas
->pixels_per_unit
;
675 cr
= gdk_cairo_create (drawable
);
677 cairo_set_antialias (cr
, CAIRO_ANTIALIAS_NONE
);
678 cairo_set_line_width (cr
, width
);
680 cairo_move_to (cr
, points
[0].x
, points
[0].y
);
681 for(i
= 1; i
< poly
->num_points
- 1; i
++)
683 cairo_line_to (cr
, points
[i
].x
, points
[i
].y
);
685 cairo_close_path (cr
);
687 if (poly
->fill_set
) {
688 /* FIXME: Set stripple */
689 cairo_set_source_rgba (cr
,
690 ((double) ((poly
->fill_color
& 0xff000000) >> 24)) / 255,
691 ((double) ((poly
->fill_color
& 0xff0000) >> 16)) / 255,
692 ((double) ((poly
->fill_color
& 0xff00) >> 8)) / 255,
693 ((double) ((poly
->fill_color
& 0xff))) / 255);
694 cairo_fill_preserve (cr
);
697 if (poly
->outline_set
) {
698 /* FIXME: Set stripple */
699 cairo_set_source_rgba (cr
,
700 ((double) ((poly
->outline_color
& 0xff000000) >> 24)) / 255,
701 ((double) ((poly
->outline_color
& 0xff0000) >> 16)) / 255,
702 ((double) ((poly
->outline_color
& 0xff00) >> 8)) / 255,
703 ((double) ((poly
->outline_color
& 0xff))) / 255);
709 if (points
!= static_points
)
714 foo_canvas_polygon_point (FooCanvasItem
*item
, double x
, double y
,
715 int cx
, int cy
, FooCanvasItem
**actual_item
)
717 FooCanvasPolygon
*poly
;
721 poly
= FOO_CANVAS_POLYGON (item
);
725 dist
= foo_canvas_polygon_to_point (poly
->coords
, poly
->num_points
, x
, y
);
727 if (poly
->outline_set
) {
728 if (poly
->width_pixels
)
729 width
= poly
->width
/ item
->canvas
->pixels_per_unit
;
743 foo_canvas_polygon_translate (FooCanvasItem
*item
, double dx
, double dy
)
745 FooCanvasPolygon
*poly
;
749 poly
= FOO_CANVAS_POLYGON (item
);
751 for (i
= 0, coords
= poly
->coords
; i
< poly
->num_points
; i
++, coords
+= 2) {
759 foo_canvas_polygon_bounds (FooCanvasItem
*item
, double *x1
, double *y1
, double *x2
, double *y2
)
761 FooCanvasPolygon
*poly
;
763 g_return_if_fail (item
!= NULL
);
764 g_return_if_fail (FOO_IS_CANVAS_POLYGON (item
));
766 poly
= FOO_CANVAS_POLYGON (item
);
768 if (poly
->num_points
== 0) {
769 *x1
= *y1
= *x2
= *y2
= 0.0;
773 get_bounds (poly
, x1
, y1
, x2
, y2
);