1 /*
2  * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
3  * All rights reserved.
4  *
5  * This file is part of the Gnome Library.
6  *
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.
11  *
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.
16  *
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.
21  */
22 /*
23   @NOTATION@
24  */
25 /* Rectangle and ellipse item types for GnomeCanvas widget
26  *
27  * GnomeCanvas 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.
29  *
30  *
31  * Authors: Federico Mena <federico@nuclecu.unam.mx>
32  *          Rusty Conover <rconover@bangtail.net>
33  */
34 
35 #include <config.h>
36 #include <math.h>
37 #include "gnome-canvas-rect-ellipse.h"
38 #include "gnome-canvas-util.h"
39 #include "gnome-canvas-shape.h"
40 
41 
42 #include "libart_lgpl/art_vpath.h"
43 #include "libart_lgpl/art_svp.h"
44 #include "libart_lgpl/art_svp_vpath.h"
45 #include "libart_lgpl/art_rgb_svp.h"
46 
47 /* Base class for rectangle and ellipse item types */
48 
49 #define noVERBOSE
50 
51 enum {
52 	PROP_0,
53 	PROP_X1,
54 	PROP_Y1,
55 	PROP_X2,
56 	PROP_Y2
57 };
58 
59 
60 static void gnome_canvas_re_class_init (GnomeCanvasREClass *class);
61 static void gnome_canvas_re_init       (GnomeCanvasRE      *re);
62 static void gnome_canvas_re_destroy    (GtkObject          *object);
63 static void gnome_canvas_re_set_property (GObject              *object,
64 					  guint                 param_id,
65 					  const GValue         *value,
66 					  GParamSpec           *pspec);
67 static void gnome_canvas_re_get_property (GObject              *object,
68 					  guint                 param_id,
69 					  GValue               *value,
70 					  GParamSpec           *pspec);
71 
72 static void gnome_canvas_rect_update      (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
73 static void gnome_canvas_ellipse_update      (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags);
74 
75 static GnomeCanvasItemClass *re_parent_class;
76 
77 
78 GType
gnome_canvas_re_get_type(void)79 gnome_canvas_re_get_type (void)
80 {
81 	static GType re_type;
82 
83 	if (!re_type) {
84 		const GTypeInfo object_info = {
85 			sizeof (GnomeCanvasREClass),
86 			(GBaseInitFunc) NULL,
87 			(GBaseFinalizeFunc) NULL,
88 			(GClassInitFunc) gnome_canvas_re_class_init,
89 			(GClassFinalizeFunc) NULL,
90 			NULL,			/* class_data */
91 			sizeof (GnomeCanvasRE),
92 			0,			/* n_preallocs */
93 			(GInstanceInitFunc) gnome_canvas_re_init,
94 			NULL			/* value_table */
95 		};
96 
97 		re_type = g_type_register_static (GNOME_TYPE_CANVAS_SHAPE, "GnomeCanvasRE",
98 						  &object_info, 0);
99 	}
100 
101 	return re_type;
102 }
103 
104 static void
gnome_canvas_re_class_init(GnomeCanvasREClass * class)105 gnome_canvas_re_class_init (GnomeCanvasREClass *class)
106 {
107 	GObjectClass *gobject_class;
108 	GtkObjectClass *object_class;
109 
110 	gobject_class = (GObjectClass *) class;
111 	object_class = (GtkObjectClass *) class;
112 
113 	re_parent_class = g_type_class_peek_parent (class);
114 
115 	gobject_class->set_property = gnome_canvas_re_set_property;
116 	gobject_class->get_property = gnome_canvas_re_get_property;
117 
118         g_object_class_install_property
119                 (gobject_class,
120                  PROP_X1,
121                  g_param_spec_double ("x1", NULL, NULL,
122 				      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
123 				      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
124         g_object_class_install_property
125                 (gobject_class,
126                  PROP_Y1,
127                  g_param_spec_double ("y1", NULL, NULL,
128 				      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
129 				      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
130         g_object_class_install_property
131                 (gobject_class,
132                  PROP_X2,
133                  g_param_spec_double ("x2", NULL, NULL,
134 				      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
135 				      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
136         g_object_class_install_property
137                 (gobject_class,
138                  PROP_Y2,
139                  g_param_spec_double ("y2", NULL, NULL,
140 				      -G_MAXDOUBLE, G_MAXDOUBLE, 0,
141 				      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
142 
143 	object_class->destroy = gnome_canvas_re_destroy;
144 }
145 
146 static void
gnome_canvas_re_init(GnomeCanvasRE * re)147 gnome_canvas_re_init (GnomeCanvasRE *re)
148 {
149 	re->x1 = 0.0;
150 	re->y1 = 0.0;
151 	re->x2 = 0.0;
152 	re->y2 = 0.0;
153 	re->path_dirty = 0;
154 }
155 
156 static void
gnome_canvas_re_destroy(GtkObject * object)157 gnome_canvas_re_destroy (GtkObject *object)
158 {
159 	g_return_if_fail (object != NULL);
160 	g_return_if_fail (GNOME_IS_CANVAS_RE (object));
161 
162 	if (GTK_OBJECT_CLASS (re_parent_class)->destroy)
163 		(* GTK_OBJECT_CLASS (re_parent_class)->destroy) (object);
164 }
165 
166 static void
gnome_canvas_re_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)167 gnome_canvas_re_set_property (GObject              *object,
168 			      guint                 param_id,
169 			      const GValue         *value,
170 			      GParamSpec           *pspec)
171 {
172 	GnomeCanvasItem *item;
173 	GnomeCanvasRE *re;
174 
175 	g_return_if_fail (object != NULL);
176 	g_return_if_fail (GNOME_IS_CANVAS_RE (object));
177 
178 	item = GNOME_CANVAS_ITEM (object);
179 	re = GNOME_CANVAS_RE (object);
180 
181 	switch (param_id) {
182 	case PROP_X1:
183 		re->x1 = g_value_get_double (value);
184 		re->path_dirty = 1;
185 		gnome_canvas_item_request_update (item);
186 		break;
187 
188 	case PROP_Y1:
189 		re->y1 = g_value_get_double (value);
190 		re->path_dirty = 1;
191 		gnome_canvas_item_request_update (item);
192 		break;
193 
194 	case PROP_X2:
195 		re->x2 = g_value_get_double (value);
196 		re->path_dirty = 1;
197 		gnome_canvas_item_request_update (item);
198 		break;
199 
200 	case PROP_Y2:
201 		re->y2 = g_value_get_double (value);
202 		re->path_dirty = 1;
203 		gnome_canvas_item_request_update (item);
204 		break;
205 
206 	default:
207 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
208 		break;
209 	}
210 }
211 
212 static void
gnome_canvas_re_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)213 gnome_canvas_re_get_property (GObject              *object,
214 			      guint                 param_id,
215 			      GValue               *value,
216 			      GParamSpec           *pspec)
217 {
218 	GnomeCanvasRE *re;
219 
220 	g_return_if_fail (object != NULL);
221 	g_return_if_fail (GNOME_IS_CANVAS_RE (object));
222 
223 	re = GNOME_CANVAS_RE (object);
224 
225 	switch (param_id) {
226 	case PROP_X1:
227 		g_value_set_double (value,  re->x1);
228 		break;
229 
230 	case PROP_Y1:
231 		g_value_set_double (value,  re->y1);
232 		break;
233 
234 	case PROP_X2:
235 		g_value_set_double (value,  re->x2);
236 		break;
237 
238 	case PROP_Y2:
239 		g_value_set_double (value,  re->y2);
240 		break;
241 
242 	default:
243 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
244 		break;
245 	}
246 }
247 
248 /* Rectangle item */
249 static void gnome_canvas_rect_class_init (GnomeCanvasRectClass *class);
250 
251 
252 
253 GType
gnome_canvas_rect_get_type(void)254 gnome_canvas_rect_get_type (void)
255 {
256 	static GType rect_type;
257 
258 	if (!rect_type) {
259 		const GTypeInfo object_info = {
260 			sizeof (GnomeCanvasRectClass),
261 			(GBaseInitFunc) NULL,
262 			(GBaseFinalizeFunc) NULL,
263 			(GClassInitFunc) gnome_canvas_rect_class_init,
264 			(GClassFinalizeFunc) NULL,
265 			NULL,			/* class_data */
266 			sizeof (GnomeCanvasRect),
267 			0,			/* n_preallocs */
268 			(GInstanceInitFunc) NULL,
269 			NULL			/* value_table */
270 		};
271 
272 		rect_type = g_type_register_static (GNOME_TYPE_CANVAS_RE, "GnomeCanvasRect",
273 						    &object_info, 0);
274 	}
275 
276 	return rect_type;
277 }
278 
279 static void
gnome_canvas_rect_class_init(GnomeCanvasRectClass * class)280 gnome_canvas_rect_class_init (GnomeCanvasRectClass *class)
281 {
282 	GnomeCanvasItemClass *item_class;
283 
284 	item_class = (GnomeCanvasItemClass *) class;
285 
286 	item_class->update = gnome_canvas_rect_update;
287 }
288 
289 static void
gnome_canvas_rect_update(GnomeCanvasItem * item,double affine[6],ArtSVP * clip_path,gint flags)290 gnome_canvas_rect_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags)
291 {	GnomeCanvasRE *re;
292 
293 	GnomeCanvasPathDef *path_def;
294 
295 	re = GNOME_CANVAS_RE(item);
296 
297 	if (re->path_dirty) {
298 		path_def = gnome_canvas_path_def_new ();
299 
300 		gnome_canvas_path_def_moveto(path_def, re->x1, re->y1);
301 		gnome_canvas_path_def_lineto(path_def, re->x2, re->y1);
302 		gnome_canvas_path_def_lineto(path_def, re->x2, re->y2);
303 		gnome_canvas_path_def_lineto(path_def, re->x1, re->y2);
304 		gnome_canvas_path_def_lineto(path_def, re->x1, re->y1);
305 		gnome_canvas_path_def_closepath_current(path_def);
306 		gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (item), path_def);
307 		gnome_canvas_path_def_unref(path_def);
308 		re->path_dirty = 0;
309 	}
310 
311 	if (re_parent_class->update)
312 		(* re_parent_class->update) (item, affine, clip_path, flags);
313 }
314 
315 /* Ellipse item */
316 
317 
318 static void gnome_canvas_ellipse_class_init (GnomeCanvasEllipseClass *class);
319 
320 
321 GType
gnome_canvas_ellipse_get_type(void)322 gnome_canvas_ellipse_get_type (void)
323 {
324 	static GType ellipse_type;
325 
326 	if (!ellipse_type) {
327 		const GTypeInfo object_info = {
328 			sizeof (GnomeCanvasEllipseClass),
329 			(GBaseInitFunc) NULL,
330 			(GBaseFinalizeFunc) NULL,
331 			(GClassInitFunc) gnome_canvas_ellipse_class_init,
332 			(GClassFinalizeFunc) NULL,
333 			NULL,			/* class_data */
334 			sizeof (GnomeCanvasEllipse),
335 			0,			/* n_preallocs */
336 			(GInstanceInitFunc) NULL,
337 			NULL			/* value_table */
338 		};
339 
340 		ellipse_type = g_type_register_static (GNOME_TYPE_CANVAS_RE, "GnomeCanvasEllipse",
341 						       &object_info, 0);
342 	}
343 
344 	return ellipse_type;
345 }
346 
347 static void
gnome_canvas_ellipse_class_init(GnomeCanvasEllipseClass * class)348 gnome_canvas_ellipse_class_init (GnomeCanvasEllipseClass *class)
349 {
350 	GnomeCanvasItemClass *item_class;
351 
352 	item_class = (GnomeCanvasItemClass *) class;
353 
354 	item_class->update = gnome_canvas_ellipse_update;
355 }
356 
357 #define N_PTS 90
358 
359 static void
gnome_canvas_ellipse_update(GnomeCanvasItem * item,double affine[6],ArtSVP * clip_path,gint flags)360 gnome_canvas_ellipse_update (GnomeCanvasItem *item, double affine[6], ArtSVP *clip_path, gint flags) {
361 	GnomeCanvasPathDef *path_def;
362 	GnomeCanvasRE *re;
363 
364 	re = GNOME_CANVAS_RE(item);
365 
366 	if (re->path_dirty) {
367 		gdouble cx, cy, rx, ry;
368 		gdouble beta = 0.26521648983954400922; /* 4*(1-cos(pi/8))/(3*sin(pi/8)) */
369 		gdouble sincosA = 0.70710678118654752440; /* sin (pi/4), cos (pi/4) */
370 		gdouble dx1, dy1, dx2, dy2;
371 		gdouble mx, my;
372 
373 		path_def = gnome_canvas_path_def_new();
374 
375 		cx = (re->x2 + re->x1) * 0.5;
376 		cy = (re->y2 + re->y1) * 0.5;
377 		rx = re->x2 - cx;
378 		ry = re->y2 - cy;
379 
380 		dx1 = beta * rx;
381 		dy1 = beta * ry;
382 		dx2 = beta * rx * sincosA;
383 		dy2 = beta * ry * sincosA;
384 		mx = rx * sincosA;
385 		my = ry * sincosA;
386 
387 		gnome_canvas_path_def_moveto (path_def, cx + rx, cy);
388 		gnome_canvas_path_def_curveto (path_def,
389 					       cx + rx, cy - dy1,
390 					       cx + mx + dx2, cy - my + dy2,
391 					       cx + mx, cy - my);
392 		gnome_canvas_path_def_curveto (path_def,
393 					       cx + mx - dx2, cy - my - dy2,
394 					       cx + dx1, cy - ry,
395 					       cx, cy - ry);
396 		gnome_canvas_path_def_curveto (path_def,
397 					       cx - dx1, cy - ry,
398 					       cx - mx + dx2, cy - my - dy2,
399 					       cx - mx, cy - my);
400 		gnome_canvas_path_def_curveto (path_def,
401 					       cx - mx - dx2, cy - my + dy2,
402 					       cx - rx, cy - dy1,
403 					       cx - rx, cy);
404 
405 		gnome_canvas_path_def_curveto (path_def,
406 					       cx - rx, cy + dy1,
407 					       cx - mx - dx2, cy + my - dy2,
408 					       cx - mx, cy + my);
409 		gnome_canvas_path_def_curveto (path_def,
410 					       cx - mx + dx2, cy + my + dy2,
411 					       cx - dx1, cy + ry,
412 					       cx, cy + ry);
413 		gnome_canvas_path_def_curveto (path_def,
414 					       cx + dx1, cy + ry,
415 					       cx + mx - dx2, cy + my + dy2,
416 					       cx + mx, cy + my);
417 		gnome_canvas_path_def_curveto (path_def,
418 					       cx + mx + dx2, cy + my - dy2,
419 					       cx + rx, cy + dy1,
420 					       cx + rx, cy);
421 
422 		gnome_canvas_path_def_closepath_current(path_def);
423 
424 		gnome_canvas_shape_set_path_def (GNOME_CANVAS_SHAPE (item), path_def);
425 		gnome_canvas_path_def_unref(path_def);
426 		re->path_dirty = 0;
427 	}
428 
429 	if (re_parent_class->update)
430 		(* re_parent_class->update) (item, affine, clip_path, flags);
431 }
432