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