1 /*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
5 *
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9 * for more details.
10 *
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
13 *
14 *
15 * Authors:
16 * Chris Lahey <clahey@ximian.com>
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #include "evolution-config.h"
23
24 #include <math.h>
25
26 #include <gdk/gdkkeysyms.h>
27 #include <gtk/gtk.h>
28
29 #include <glib/gi18n.h>
30
31 #include "e-canvas.h"
32 #include "e-canvas-utils.h"
33 #include "e-canvas-vbox.h"
34
35 static void e_canvas_vbox_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
36 static void e_canvas_vbox_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
37 static void e_canvas_vbox_dispose (GObject *object);
38
39 static gint e_canvas_vbox_event (GnomeCanvasItem *item, GdkEvent *event);
40 static void e_canvas_vbox_realize (GnomeCanvasItem *item);
41
42 static void e_canvas_vbox_reflow (GnomeCanvasItem *item, gint flags);
43
44 static void e_canvas_vbox_real_add_item (ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
45 static void e_canvas_vbox_real_add_item_start (ECanvasVbox *e_canvas_vbox, GnomeCanvasItem *item);
46 static void e_canvas_vbox_resize_children (GnomeCanvasItem *item);
47
48 enum {
49 PROP_0,
50 PROP_WIDTH,
51 PROP_MINIMUM_WIDTH,
52 PROP_HEIGHT,
53 PROP_SPACING
54 };
55
G_DEFINE_TYPE(ECanvasVbox,e_canvas_vbox,GNOME_TYPE_CANVAS_GROUP)56 G_DEFINE_TYPE (
57 ECanvasVbox,
58 e_canvas_vbox,
59 GNOME_TYPE_CANVAS_GROUP)
60
61 static void
62 e_canvas_vbox_class_init (ECanvasVboxClass *class)
63 {
64 GObjectClass *object_class;
65 GnomeCanvasItemClass *item_class;
66
67 object_class = (GObjectClass *) class;
68 item_class = (GnomeCanvasItemClass *) class;
69
70 class->add_item = e_canvas_vbox_real_add_item;
71 class->add_item_start = e_canvas_vbox_real_add_item_start;
72
73 object_class->set_property = e_canvas_vbox_set_property;
74 object_class->get_property = e_canvas_vbox_get_property;
75 object_class->dispose = e_canvas_vbox_dispose;
76
77 /* GnomeCanvasItem method overrides */
78 item_class->event = e_canvas_vbox_event;
79 item_class->realize = e_canvas_vbox_realize;
80
81 g_object_class_install_property (
82 object_class,
83 PROP_WIDTH,
84 g_param_spec_double (
85 "width",
86 "Width",
87 "Width",
88 0.0, G_MAXDOUBLE, 0.0,
89 G_PARAM_READWRITE));
90 g_object_class_install_property (
91 object_class,
92 PROP_MINIMUM_WIDTH,
93 g_param_spec_double (
94 "minimum_width",
95 "Minimum width",
96 "Minimum Width",
97 0.0, G_MAXDOUBLE, 0.0,
98 G_PARAM_READWRITE));
99 g_object_class_install_property (
100 object_class,
101 PROP_HEIGHT,
102 g_param_spec_double (
103 "height",
104 "Height",
105 "Height",
106 0.0, G_MAXDOUBLE, 0.0,
107 G_PARAM_READABLE));
108 g_object_class_install_property (
109 object_class,
110 PROP_SPACING,
111 g_param_spec_double (
112 "spacing",
113 "Spacing",
114 "Spacing",
115 0.0, G_MAXDOUBLE, 0.0,
116 G_PARAM_READWRITE));
117 }
118
119 static void
e_canvas_vbox_init(ECanvasVbox * vbox)120 e_canvas_vbox_init (ECanvasVbox *vbox)
121 {
122 vbox->items = NULL;
123
124 vbox->width = 10;
125 vbox->minimum_width = 10;
126 vbox->height = 10;
127 vbox->spacing = 0;
128
129 e_canvas_item_set_reflow_callback (GNOME_CANVAS_ITEM (vbox), e_canvas_vbox_reflow);
130 }
131
132 static void
e_canvas_vbox_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)133 e_canvas_vbox_set_property (GObject *object,
134 guint property_id,
135 const GValue *value,
136 GParamSpec *pspec)
137 {
138 GnomeCanvasItem *item;
139 ECanvasVbox *e_canvas_vbox;
140
141 item = GNOME_CANVAS_ITEM (object);
142 e_canvas_vbox = E_CANVAS_VBOX (object);
143
144 switch (property_id) {
145 case PROP_WIDTH:
146 case PROP_MINIMUM_WIDTH:
147 e_canvas_vbox->minimum_width = g_value_get_double (value);
148 e_canvas_vbox_resize_children (item);
149 e_canvas_item_request_reflow (item);
150 break;
151 case PROP_SPACING:
152 e_canvas_vbox->spacing = g_value_get_double (value);
153 e_canvas_item_request_reflow (item);
154 break;
155 }
156 }
157
158 static void
e_canvas_vbox_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)159 e_canvas_vbox_get_property (GObject *object,
160 guint property_id,
161 GValue *value,
162 GParamSpec *pspec)
163 {
164 ECanvasVbox *e_canvas_vbox;
165
166 e_canvas_vbox = E_CANVAS_VBOX (object);
167
168 switch (property_id) {
169 case PROP_WIDTH:
170 g_value_set_double (value, e_canvas_vbox->width);
171 break;
172 case PROP_MINIMUM_WIDTH:
173 g_value_set_double (value, e_canvas_vbox->minimum_width);
174 break;
175 case PROP_HEIGHT:
176 g_value_set_double (value, e_canvas_vbox->height);
177 break;
178 case PROP_SPACING:
179 g_value_set_double (value, e_canvas_vbox->spacing);
180 break;
181 default:
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
183 break;
184 }
185 }
186
187 /* Used from g_list_foreach(); disconnects from an item's signals */
188 static void
disconnect_item_cb(gpointer data,gpointer user_data)189 disconnect_item_cb (gpointer data,
190 gpointer user_data)
191 {
192 ECanvasVbox *vbox;
193 GnomeCanvasItem *item;
194
195 vbox = E_CANVAS_VBOX (user_data);
196
197 item = GNOME_CANVAS_ITEM (data);
198 g_signal_handlers_disconnect_matched (
199 item,
200 G_SIGNAL_MATCH_DATA,
201 0, 0, NULL, NULL,
202 vbox);
203 }
204
205 static void
e_canvas_vbox_dispose(GObject * object)206 e_canvas_vbox_dispose (GObject *object)
207 {
208 ECanvasVbox *vbox = E_CANVAS_VBOX (object);
209
210 if (vbox->items) {
211 g_list_foreach (vbox->items, disconnect_item_cb, vbox);
212 g_list_free (vbox->items);
213 vbox->items = NULL;
214 }
215
216 G_OBJECT_CLASS (e_canvas_vbox_parent_class)->dispose (object);
217 }
218
219 static gint
e_canvas_vbox_event(GnomeCanvasItem * item,GdkEvent * event)220 e_canvas_vbox_event (GnomeCanvasItem *item,
221 GdkEvent *event)
222 {
223 gint return_val = TRUE;
224
225 switch (event->type) {
226 case GDK_KEY_PRESS:
227 switch (event->key.keyval) {
228 case GDK_KEY_Left:
229 case GDK_KEY_KP_Left:
230 case GDK_KEY_Right:
231 case GDK_KEY_KP_Right:
232 case GDK_KEY_Down:
233 case GDK_KEY_KP_Down:
234 case GDK_KEY_Up:
235 case GDK_KEY_KP_Up:
236 case GDK_KEY_Return:
237 case GDK_KEY_KP_Enter:
238 return_val = TRUE;
239 break;
240 default:
241 return_val = FALSE;
242 break;
243 }
244 break;
245 default:
246 return_val = FALSE;
247 break;
248 }
249 if (!return_val) {
250 if (GNOME_CANVAS_ITEM_CLASS (e_canvas_vbox_parent_class)->event)
251 return GNOME_CANVAS_ITEM_CLASS (e_canvas_vbox_parent_class)->event (item, event);
252 }
253 return return_val;
254
255 }
256
257 static void
e_canvas_vbox_realize(GnomeCanvasItem * item)258 e_canvas_vbox_realize (GnomeCanvasItem *item)
259 {
260 if (GNOME_CANVAS_ITEM_CLASS (e_canvas_vbox_parent_class)->realize)
261 (* GNOME_CANVAS_ITEM_CLASS (e_canvas_vbox_parent_class)->realize) (item);
262
263 e_canvas_vbox_resize_children (item);
264 e_canvas_item_request_reflow (item);
265 }
266
267 static void
e_canvas_vbox_remove_item(gpointer data,GObject * where_object_was)268 e_canvas_vbox_remove_item (gpointer data,
269 GObject *where_object_was)
270 {
271 ECanvasVbox *vbox = data;
272 vbox->items = g_list_remove (vbox->items, where_object_was);
273 }
274
275 static void
e_canvas_vbox_real_add_item(ECanvasVbox * e_canvas_vbox,GnomeCanvasItem * item)276 e_canvas_vbox_real_add_item (ECanvasVbox *e_canvas_vbox,
277 GnomeCanvasItem *item)
278 {
279 e_canvas_vbox->items = g_list_append (e_canvas_vbox->items, item);
280 g_object_weak_ref (
281 G_OBJECT (item),
282 e_canvas_vbox_remove_item, e_canvas_vbox);
283 if (GNOME_CANVAS_ITEM (e_canvas_vbox)->flags & GNOME_CANVAS_ITEM_REALIZED) {
284 gnome_canvas_item_set (
285 item,
286 "width", (gdouble) e_canvas_vbox->minimum_width,
287 NULL);
288 e_canvas_item_request_reflow (item);
289 }
290 }
291
292 static void
e_canvas_vbox_real_add_item_start(ECanvasVbox * e_canvas_vbox,GnomeCanvasItem * item)293 e_canvas_vbox_real_add_item_start (ECanvasVbox *e_canvas_vbox,
294 GnomeCanvasItem *item)
295 {
296 e_canvas_vbox->items = g_list_prepend (e_canvas_vbox->items, item);
297 g_object_weak_ref (
298 G_OBJECT (item),
299 e_canvas_vbox_remove_item, e_canvas_vbox);
300 if (GNOME_CANVAS_ITEM (e_canvas_vbox)->flags & GNOME_CANVAS_ITEM_REALIZED) {
301 gnome_canvas_item_set (
302 item,
303 "width", (gdouble) e_canvas_vbox->minimum_width,
304 NULL);
305 e_canvas_item_request_reflow (item);
306 }
307 }
308
309 static void
e_canvas_vbox_resize_children(GnomeCanvasItem * item)310 e_canvas_vbox_resize_children (GnomeCanvasItem *item)
311 {
312 GList *list;
313 ECanvasVbox *e_canvas_vbox;
314
315 e_canvas_vbox = E_CANVAS_VBOX (item);
316 for (list = e_canvas_vbox->items; list; list = list->next) {
317 GnomeCanvasItem *child = GNOME_CANVAS_ITEM (list->data);
318 gnome_canvas_item_set (
319 child,
320 "width", (gdouble) e_canvas_vbox->minimum_width,
321 NULL);
322 }
323 }
324
325 static void
e_canvas_vbox_reflow(GnomeCanvasItem * item,gint flags)326 e_canvas_vbox_reflow (GnomeCanvasItem *item,
327 gint flags)
328 {
329 ECanvasVbox *e_canvas_vbox = E_CANVAS_VBOX (item);
330 if (item->flags & GNOME_CANVAS_ITEM_REALIZED) {
331
332 gdouble old_height;
333 gdouble running_height;
334 gdouble old_width;
335 gdouble max_width;
336
337 old_width = e_canvas_vbox->width;
338 max_width = e_canvas_vbox->minimum_width;
339
340 old_height = e_canvas_vbox->height;
341 running_height = 0;
342
343 if (e_canvas_vbox->items == NULL) {
344 } else {
345 GList *list;
346 gdouble item_height;
347 gdouble item_width;
348
349 list = e_canvas_vbox->items;
350 g_object_get (
351 list->data,
352 "height", &item_height,
353 "width", &item_width,
354 NULL);
355 e_canvas_item_move_absolute (
356 GNOME_CANVAS_ITEM (list->data),
357 (gdouble) 0,
358 (gdouble) running_height);
359 running_height += item_height;
360 if (max_width < item_width)
361 max_width = item_width;
362 list = g_list_next (list);
363
364 for (; list; list = g_list_next (list)) {
365 running_height += e_canvas_vbox->spacing;
366
367 g_object_get (
368 list->data,
369 "height", &item_height,
370 "width", &item_width,
371 NULL);
372
373 e_canvas_item_move_absolute (
374 GNOME_CANVAS_ITEM (list->data),
375 (gdouble) 0,
376 (gdouble) running_height);
377
378 running_height += item_height;
379 if (max_width < item_width)
380 max_width = item_width;
381 }
382
383 }
384 e_canvas_vbox->height = running_height;
385 e_canvas_vbox->width = max_width;
386 if (old_height != e_canvas_vbox->height ||
387 old_width != e_canvas_vbox->width)
388 e_canvas_item_request_parent_reflow (item);
389 }
390 }
391
392 void
e_canvas_vbox_add_item(ECanvasVbox * e_canvas_vbox,GnomeCanvasItem * item)393 e_canvas_vbox_add_item (ECanvasVbox *e_canvas_vbox,
394 GnomeCanvasItem *item)
395 {
396 if (E_CANVAS_VBOX_CLASS (G_OBJECT_GET_CLASS (e_canvas_vbox))->add_item)
397 (E_CANVAS_VBOX_CLASS (G_OBJECT_GET_CLASS (e_canvas_vbox))->add_item) (e_canvas_vbox, item);
398 }
399
400 void
e_canvas_vbox_add_item_start(ECanvasVbox * e_canvas_vbox,GnomeCanvasItem * item)401 e_canvas_vbox_add_item_start (ECanvasVbox *e_canvas_vbox,
402 GnomeCanvasItem *item)
403 {
404 if (E_CANVAS_VBOX_CLASS (G_OBJECT_GET_CLASS (e_canvas_vbox))->add_item_start)
405 (E_CANVAS_VBOX_CLASS (G_OBJECT_GET_CLASS (e_canvas_vbox))->add_item_start) (e_canvas_vbox, item);
406 }
407
408