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 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * published by the Free Software Foundation; either the
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * License along with the Gnome Library; see the file COPYING.LIB. If not,
18 */
19 /*
20 @NOTATION@
21 */
22 /* Widget item type for GnomeCanvas widget
23 *
24 * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
25 * widget. Tk is copyrighted by the Regents of the University of California,
26 * Sun Microsystems, and other parties.
27 *
28 *
29 * Author: Federico Mena <federico@nuclecu.unam.mx>
30 */
31
32 #include "evolution-config.h"
33
34 #include <math.h>
35 #include "gnome-canvas-widget.h"
36
37 enum {
38 PROP_0,
39 PROP_WIDGET,
40 PROP_X,
41 PROP_Y,
42 PROP_WIDTH,
43 PROP_HEIGHT,
44 PROP_SIZE_PIXELS
45 };
46
47 static void gnome_canvas_widget_dispose (GnomeCanvasItem *object);
48 static void gnome_canvas_widget_get_property (GObject *object,
49 guint param_id,
50 GValue *value,
51 GParamSpec *pspec);
52 static void gnome_canvas_widget_set_property (GObject *object,
53 guint param_id,
54 const GValue *value,
55 GParamSpec *pspec);
56
57 static void gnome_canvas_widget_update (GnomeCanvasItem *item,
58 const cairo_matrix_t *matrix,
59 gint flags);
60 static GnomeCanvasItem *gnome_canvas_widget_point (GnomeCanvasItem *item,
61 gdouble x,
62 gdouble y,
63 gint cx,
64 gint cy);
65 static void gnome_canvas_widget_bounds (GnomeCanvasItem *item,
66 gdouble *x1,
67 gdouble *y1,
68 gdouble *x2,
69 gdouble *y2);
70
71 static void gnome_canvas_widget_draw (GnomeCanvasItem *item,
72 cairo_t *cr,
73 gint x,
74 gint y,
75 gint width,
76 gint height);
77
G_DEFINE_TYPE(GnomeCanvasWidget,gnome_canvas_widget,GNOME_TYPE_CANVAS_ITEM)78 G_DEFINE_TYPE (
79 GnomeCanvasWidget,
80 gnome_canvas_widget,
81 GNOME_TYPE_CANVAS_ITEM)
82
83 static void
84 gnome_canvas_widget_class_init (GnomeCanvasWidgetClass *class)
85 {
86 GObjectClass *gobject_class;
87 GnomeCanvasItemClass *item_class;
88
89 gobject_class = (GObjectClass *) class;
90 item_class = (GnomeCanvasItemClass *) class;
91
92 gobject_class->set_property = gnome_canvas_widget_set_property;
93 gobject_class->get_property = gnome_canvas_widget_get_property;
94
95 g_object_class_install_property
96 (gobject_class,
97 PROP_WIDGET,
98 g_param_spec_object ("widget", NULL, NULL,
99 GTK_TYPE_WIDGET,
100 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
101 g_object_class_install_property
102 (gobject_class,
103 PROP_X,
104 g_param_spec_double ("x", NULL, NULL,
105 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
106 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
107 g_object_class_install_property
108 (gobject_class,
109 PROP_Y,
110 g_param_spec_double ("y", NULL, NULL,
111 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
112 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
113 g_object_class_install_property
114 (gobject_class,
115 PROP_WIDTH,
116 g_param_spec_double ("width", NULL, NULL,
117 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
118 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
119 g_object_class_install_property
120 (gobject_class,
121 PROP_HEIGHT,
122 g_param_spec_double ("height", NULL, NULL,
123 -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
124 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
125 g_object_class_install_property
126 (gobject_class,
127 PROP_SIZE_PIXELS,
128 g_param_spec_boolean ("size_pixels", NULL, NULL,
129 FALSE,
130 (G_PARAM_READABLE | G_PARAM_WRITABLE)));
131
132 item_class->dispose = gnome_canvas_widget_dispose;
133 item_class->update = gnome_canvas_widget_update;
134 item_class->point = gnome_canvas_widget_point;
135 item_class->bounds = gnome_canvas_widget_bounds;
136 item_class->draw = gnome_canvas_widget_draw;
137 }
138
139 static void
do_destroy(gpointer data,GObject * gone_object)140 do_destroy (gpointer data,
141 GObject *gone_object)
142 {
143 GnomeCanvasWidget *witem;
144
145 witem = data;
146
147 if (!witem->in_destroy) {
148 witem->in_destroy = TRUE;
149 g_object_run_dispose (G_OBJECT (witem));
150 }
151 }
152
153 static void
gnome_canvas_widget_init(GnomeCanvasWidget * witem)154 gnome_canvas_widget_init (GnomeCanvasWidget *witem)
155 {
156 witem->x = 0.0;
157 witem->y = 0.0;
158 witem->width = 0.0;
159 witem->height = 0.0;
160 witem->size_pixels = FALSE;
161 }
162
163 static void
gnome_canvas_widget_dispose(GnomeCanvasItem * object)164 gnome_canvas_widget_dispose (GnomeCanvasItem *object)
165 {
166 GnomeCanvasWidget *witem;
167
168 g_return_if_fail (object != NULL);
169 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
170
171 witem = GNOME_CANVAS_WIDGET (object);
172
173 if (witem->widget && !witem->in_destroy) {
174 g_object_weak_unref (G_OBJECT (witem->widget), do_destroy, witem);
175 gtk_widget_destroy (witem->widget);
176 witem->widget = NULL;
177 }
178
179 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_widget_parent_class)->
180 dispose (object);
181 }
182
183 static gboolean
reposition_widget_cb(gpointer user_data)184 reposition_widget_cb (gpointer user_data)
185 {
186 GnomeCanvasWidget *witem = user_data;
187
188 g_return_val_if_fail (GNOME_IS_CANVAS_WIDGET (witem), FALSE);
189
190 if (witem->widget)
191 gtk_widget_queue_resize (witem->widget);
192
193 return FALSE;
194 }
195
196 static void
recalc_bounds(GnomeCanvasWidget * witem)197 recalc_bounds (GnomeCanvasWidget *witem)
198 {
199 GnomeCanvasItem *item;
200 gdouble wx, wy;
201
202 item = GNOME_CANVAS_ITEM (witem);
203
204 /* Get world coordinates */
205
206 wx = witem->x;
207 wy = witem->y;
208 gnome_canvas_item_i2w (item, &wx, &wy);
209
210 /* Get canvas pixel coordinates */
211
212 gnome_canvas_w2c (item->canvas, wx, wy, &witem->cx, &witem->cy);
213
214 /* Bounds */
215
216 item->x1 = witem->cx;
217 item->y1 = witem->cy;
218 item->x2 = witem->cx + witem->cwidth;
219 item->y2 = witem->cy + witem->cheight;
220
221 if (witem->widget) {
222 gint current_x = 0, current_y = 0;
223
224 gtk_container_child_get (GTK_CONTAINER (item->canvas), witem->widget,
225 "x", ¤t_x,
226 "y", ¤t_y,
227 NULL);
228
229 if (current_x != ((gint) (witem->cx + item->canvas->zoom_xofs)) ||
230 current_y != ((gint) (witem->cy + item->canvas->zoom_yofs))) {
231 gtk_layout_move (
232 GTK_LAYOUT (item->canvas), witem->widget,
233 witem->cx + item->canvas->zoom_xofs,
234 witem->cy + item->canvas->zoom_yofs);
235
236 /* This is needed, because the gtk_layout_move() calls gtk_widget_queue_resize(),
237 which can be silently ignored when called inside "size-allocate" handler, causing
238 misposition of the child widget. */
239 g_idle_add_full (G_PRIORITY_HIGH_IDLE,
240 reposition_widget_cb, g_object_ref (witem), g_object_unref);
241 }
242 }
243 }
244
245 static void
gnome_canvas_widget_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)246 gnome_canvas_widget_set_property (GObject *object,
247 guint param_id,
248 const GValue *value,
249 GParamSpec *pspec)
250 {
251 GnomeCanvasItem *item;
252 GnomeCanvasWidget *witem;
253 GObject *obj;
254 gint update;
255 gint calc_bounds;
256
257 g_return_if_fail (object != NULL);
258 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
259
260 item = GNOME_CANVAS_ITEM (object);
261 witem = GNOME_CANVAS_WIDGET (object);
262
263 update = FALSE;
264 calc_bounds = FALSE;
265
266 switch (param_id) {
267 case PROP_WIDGET:
268 if (witem->widget) {
269 g_object_weak_unref (G_OBJECT (witem->widget), do_destroy, witem);
270 gtk_container_remove (GTK_CONTAINER (item->canvas), witem->widget);
271 }
272
273 obj = g_value_get_object (value);
274 if (obj) {
275 witem->widget = GTK_WIDGET (obj);
276 g_object_weak_ref (obj, do_destroy, witem);
277 gtk_layout_put (
278 GTK_LAYOUT (item->canvas), witem->widget,
279 witem->cx + item->canvas->zoom_xofs,
280 witem->cy + item->canvas->zoom_yofs);
281 }
282
283 update = TRUE;
284 break;
285
286 case PROP_X:
287 if (witem->x != g_value_get_double (value))
288 {
289 witem->x = g_value_get_double (value);
290 calc_bounds = TRUE;
291 }
292 break;
293
294 case PROP_Y:
295 if (witem->y != g_value_get_double (value))
296 {
297 witem->y = g_value_get_double (value);
298 calc_bounds = TRUE;
299 }
300 break;
301
302 case PROP_WIDTH:
303 if (witem->width != fabs (g_value_get_double (value)))
304 {
305 witem->width = fabs (g_value_get_double (value));
306 update = TRUE;
307 }
308 break;
309
310 case PROP_HEIGHT:
311 if (witem->height != fabs (g_value_get_double (value)))
312 {
313 witem->height = fabs (g_value_get_double (value));
314 update = TRUE;
315 }
316 break;
317
318 case PROP_SIZE_PIXELS:
319 if (witem->size_pixels != g_value_get_boolean (value))
320 {
321 witem->size_pixels = g_value_get_boolean (value);
322 update = TRUE;
323 }
324 break;
325
326 default:
327 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
328 break;
329 }
330
331 if (update)
332 (* GNOME_CANVAS_ITEM_GET_CLASS (item)->update) (item, NULL, 0);
333
334 if (calc_bounds)
335 recalc_bounds (witem);
336 }
337
338 static void
gnome_canvas_widget_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)339 gnome_canvas_widget_get_property (GObject *object,
340 guint param_id,
341 GValue *value,
342 GParamSpec *pspec)
343 {
344 GnomeCanvasWidget *witem;
345
346 g_return_if_fail (object != NULL);
347 g_return_if_fail (GNOME_IS_CANVAS_WIDGET (object));
348
349 witem = GNOME_CANVAS_WIDGET (object);
350
351 switch (param_id) {
352 case PROP_WIDGET:
353 g_value_set_object (value, (GObject *) witem->widget);
354 break;
355
356 case PROP_X:
357 g_value_set_double (value, witem->x);
358 break;
359
360 case PROP_Y:
361 g_value_set_double (value, witem->y);
362 break;
363
364 case PROP_WIDTH:
365 g_value_set_double (value, witem->width);
366 break;
367
368 case PROP_HEIGHT:
369 g_value_set_double (value, witem->height);
370 break;
371
372 case PROP_SIZE_PIXELS:
373 g_value_set_boolean (value, witem->size_pixels);
374 break;
375
376 default:
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
378 break;
379 }
380 }
381
382 static void
gnome_canvas_widget_update(GnomeCanvasItem * item,const cairo_matrix_t * matrix,gint flags)383 gnome_canvas_widget_update (GnomeCanvasItem *item,
384 const cairo_matrix_t *matrix,
385 gint flags)
386 {
387 GnomeCanvasWidget *witem;
388
389 witem = GNOME_CANVAS_WIDGET (item);
390
391 GNOME_CANVAS_ITEM_CLASS (gnome_canvas_widget_parent_class)->
392 update (item, matrix, flags);
393
394 if (witem->widget) {
395 witem->cwidth = (gint) (witem->width + 0.5);
396 witem->cheight = (gint) (witem->height + 0.5);
397
398 gtk_widget_set_size_request (witem->widget, witem->cwidth, witem->cheight);
399 } else {
400 witem->cwidth = 0.0;
401 witem->cheight = 0.0;
402 }
403
404 recalc_bounds (witem);
405 }
406
407 static void
gnome_canvas_widget_draw(GnomeCanvasItem * item,cairo_t * cr,gint x,gint y,gint width,gint height)408 gnome_canvas_widget_draw (GnomeCanvasItem *item,
409 cairo_t *cr,
410 gint x,
411 gint y,
412 gint width,
413 gint height)
414 {
415 #if 0
416 GnomeCanvasWidget *witem;
417
418 witem = GNOME_CANVAS_WIDGET (item);
419
420 if (witem->widget)
421 gtk_widget_queue_draw (witem->widget);
422 #endif
423 }
424
425 static GnomeCanvasItem *
gnome_canvas_widget_point(GnomeCanvasItem * item,gdouble x,gdouble y,gint cx,gint cy)426 gnome_canvas_widget_point (GnomeCanvasItem *item,
427 gdouble x,
428 gdouble y,
429 gint cx,
430 gint cy)
431 {
432 GnomeCanvasWidget *witem;
433 gdouble x1, y1, x2, y2;
434
435 witem = GNOME_CANVAS_WIDGET (item);
436
437 gnome_canvas_c2w (item->canvas, witem->cx, witem->cy, &x1, &y1);
438
439 x2 = x1 + (witem->cwidth - 1);
440 y2 = y1 + (witem->cheight - 1);
441
442 /* Is point inside widget bounds? */
443
444 if ((x >= x1) && (y >= y1) && (x <= x2) && (y <= y2))
445 return item;
446
447 /* Point is outside widget bounds */
448 return NULL;
449 }
450
451 static void
gnome_canvas_widget_bounds(GnomeCanvasItem * item,gdouble * x1,gdouble * y1,gdouble * x2,gdouble * y2)452 gnome_canvas_widget_bounds (GnomeCanvasItem *item,
453 gdouble *x1,
454 gdouble *y1,
455 gdouble *x2,
456 gdouble *y2)
457 {
458 GnomeCanvasWidget *witem;
459
460 witem = GNOME_CANVAS_WIDGET (item);
461
462 *x1 = witem->x;
463 *y1 = witem->y;
464
465 *x2 = *x1 + witem->width;
466 *y2 = *y1 + witem->height;
467 }
468