1 /*
2  *
3  * This program is free software; you can redistribute it and/or modify it
4  * under the terms of the GNU Lesser General Public License as published by
5  * the Free Software Foundation.
6  *
7  * This program is distributed in the hope that it will be useful, but
8  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
9  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
10  * for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public License
13  * along with this program; if not, see <http://www.gnu.org/licenses/>.
14  *
15  *
16  * Authors:
17  *		Chris Lahey <clahey@ximian.com>
18  *
19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
20  *
21  */
22 
23 #include "evolution-config.h"
24 
25 #include <libedataserver/libedataserver.h>
26 #include "e-canvas-utils.h"
27 
28 void
e_canvas_item_move_absolute(GnomeCanvasItem * item,gdouble dx,gdouble dy)29 e_canvas_item_move_absolute (GnomeCanvasItem *item,
30                              gdouble dx,
31                              gdouble dy)
32 {
33 	cairo_matrix_t translate;
34 
35 	g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
36 
37 	cairo_matrix_init_translate (&translate, dx, dy);
38 
39 	gnome_canvas_item_set_matrix (item, &translate);
40 }
41 
42 static double
compute_offset(gint top,gint bottom,gint page_top,gint page_bottom)43 compute_offset (gint top,
44                 gint bottom,
45                 gint page_top,
46                 gint page_bottom)
47 {
48 	gint size = bottom - top;
49 	gint offset = 0;
50 
51 	if (top <= page_top && bottom >= page_bottom)
52 		return 0;
53 
54 	if (bottom > page_bottom)
55 		offset = (bottom - page_bottom);
56 	if (top < page_top + offset)
57 		offset = (top - page_top);
58 
59 	if (top <= page_top + offset && bottom >= page_bottom + offset)
60 		return offset;
61 
62 	if (top < page_top + size * 3 / 2 + offset)
63 		offset = top - (page_top + size * 3 / 2);
64 	if (bottom > page_bottom - size * 3 / 2 + offset)
65 		offset = bottom - (page_bottom - size * 3 / 2);
66 	if (top < page_top + size * 3 / 2 + offset)
67 		offset = top - ((page_top + page_bottom - (bottom - top)) / 2);
68 
69 	return offset;
70 }
71 
72 static void
e_canvas_show_area(GnomeCanvas * canvas,gdouble x1,gdouble y1,gdouble x2,gdouble y2)73 e_canvas_show_area (GnomeCanvas *canvas,
74                     gdouble x1,
75                     gdouble y1,
76                     gdouble x2,
77                     gdouble y2)
78 {
79 	GtkAdjustment *h, *v;
80 	gint dx = 0, dy = 0;
81 	gdouble page_size;
82 	gdouble lower;
83 	gdouble upper;
84 	gdouble value;
85 
86 	g_return_if_fail (canvas != NULL);
87 	g_return_if_fail (GNOME_IS_CANVAS (canvas));
88 
89 	h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
90 	page_size = gtk_adjustment_get_page_size (h);
91 	lower = gtk_adjustment_get_lower (h);
92 	upper = gtk_adjustment_get_upper (h);
93 	value = gtk_adjustment_get_value (h);
94 	dx = compute_offset (x1, x2, value, value + page_size);
95 	if (dx)
96 		gtk_adjustment_set_value (h, CLAMP (value + dx, lower, upper - page_size));
97 
98 	v = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
99 	page_size = gtk_adjustment_get_page_size (v);
100 	lower = gtk_adjustment_get_lower (v);
101 	upper = gtk_adjustment_get_upper (v);
102 	value = gtk_adjustment_get_value (v);
103 	dy = compute_offset (y1, y2, value, value + page_size);
104 	if (dy)
105 		gtk_adjustment_set_value (v, CLAMP (value + dy, lower, upper - page_size));
106 }
107 
108 void
e_canvas_item_show_area(GnomeCanvasItem * item,gdouble x1,gdouble y1,gdouble x2,gdouble y2)109 e_canvas_item_show_area (GnomeCanvasItem *item,
110                          gdouble x1,
111                          gdouble y1,
112                          gdouble x2,
113                          gdouble y2)
114 {
115 	g_return_if_fail (item != NULL);
116 	g_return_if_fail (GNOME_IS_CANVAS_ITEM (item));
117 
118 	gnome_canvas_item_i2w (item, &x1, &y1);
119 	gnome_canvas_item_i2w (item, &x2, &y2);
120 
121 	e_canvas_show_area (item->canvas, x1, y1, x2, y2);
122 }
123 
124 static gboolean
e_canvas_area_shown(GnomeCanvas * canvas,gdouble x1,gdouble y1,gdouble x2,gdouble y2)125 e_canvas_area_shown (GnomeCanvas *canvas,
126                      gdouble x1,
127                      gdouble y1,
128                      gdouble x2,
129                      gdouble y2)
130 {
131 	GtkAdjustment *h, *v;
132 	gint dx = 0, dy = 0;
133 	gdouble page_size;
134 	gdouble lower;
135 	gdouble upper;
136 	gdouble value;
137 
138 	g_return_val_if_fail (canvas != NULL, FALSE);
139 	g_return_val_if_fail (GNOME_IS_CANVAS (canvas), FALSE);
140 
141 	h = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (canvas));
142 	page_size = gtk_adjustment_get_page_size (h);
143 	lower = gtk_adjustment_get_lower (h);
144 	upper = gtk_adjustment_get_upper (h);
145 	value = gtk_adjustment_get_value (h);
146 	dx = compute_offset (x1, x2, value, value + page_size);
147 	if (CLAMP (value + dx, lower, upper - page_size) - value != 0)
148 		return FALSE;
149 
150 	v = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (canvas));
151 	page_size = gtk_adjustment_get_page_size (v);
152 	lower = gtk_adjustment_get_lower (v);
153 	upper = gtk_adjustment_get_upper (v);
154 	value = gtk_adjustment_get_value (v);
155 	dy = compute_offset (y1, y2, value, value + page_size);
156 	if (CLAMP (value + dy, lower, upper - page_size) - value != 0)
157 		return FALSE;
158 	return TRUE;
159 }
160 
161 gboolean
e_canvas_item_area_shown(GnomeCanvasItem * item,gdouble x1,gdouble y1,gdouble x2,gdouble y2)162 e_canvas_item_area_shown (GnomeCanvasItem *item,
163                           gdouble x1,
164                           gdouble y1,
165                           gdouble x2,
166                           gdouble y2)
167 {
168 	g_return_val_if_fail (item != NULL, FALSE);
169 	g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), FALSE);
170 
171 	gnome_canvas_item_i2w (item, &x1, &y1);
172 	gnome_canvas_item_i2w (item, &x2, &y2);
173 
174 	return e_canvas_area_shown (item->canvas, x1, y1, x2, y2);
175 }
176 
177 typedef struct {
178 	gdouble x1;
179 	gdouble y1;
180 	gdouble x2;
181 	gdouble y2;
182 	GnomeCanvas *canvas;
183 } DoubsAndCanvas;
184 
185 static void
doubs_and_canvas_free(gpointer ptr)186 doubs_and_canvas_free (gpointer ptr)
187 {
188 	DoubsAndCanvas *dac = ptr;
189 
190 	if (dac) {
191 		g_object_unref (dac->canvas);
192 		g_free (dac);
193 	}
194 }
195 
196 static gboolean
show_area_timeout(gpointer data)197 show_area_timeout (gpointer data)
198 {
199 	DoubsAndCanvas *dac = data;
200 
201 	e_canvas_show_area (dac->canvas, dac->x1, dac->y1, dac->x2, dac->y2);
202 
203 	return FALSE;
204 }
205 
206 void
e_canvas_item_show_area_delayed(GnomeCanvasItem * item,gdouble x1,gdouble y1,gdouble x2,gdouble y2,gint delay)207 e_canvas_item_show_area_delayed (GnomeCanvasItem *item,
208                                  gdouble x1,
209                                  gdouble y1,
210                                  gdouble x2,
211                                  gdouble y2,
212                                  gint delay)
213 {
214 	GSource *source;
215 
216 	source = e_canvas_item_show_area_delayed_ex (item, x1, y1, x2, y2, delay);
217 	if (source)
218 		g_source_unref (source);
219 }
220 
221 /* Use g_source_unref() when done with the returned pointer. */
222 GSource *
e_canvas_item_show_area_delayed_ex(GnomeCanvasItem * item,gdouble x1,gdouble y1,gdouble x2,gdouble y2,gint delay)223 e_canvas_item_show_area_delayed_ex (GnomeCanvasItem *item,
224                                  gdouble x1,
225                                  gdouble y1,
226                                  gdouble x2,
227                                  gdouble y2,
228                                  gint delay)
229 {
230 	GSource *source;
231 	DoubsAndCanvas *dac;
232 
233 	g_return_val_if_fail (item != NULL, NULL);
234 	g_return_val_if_fail (GNOME_IS_CANVAS_ITEM (item), NULL);
235 
236 	gnome_canvas_item_i2w (item, &x1, &y1);
237 	gnome_canvas_item_i2w (item, &x2, &y2);
238 
239 	dac = g_new (DoubsAndCanvas, 1);
240 	dac->x1 = x1;
241 	dac->y1 = y1;
242 	dac->x2 = x2;
243 	dac->y2 = y2;
244 	dac->canvas = g_object_ref (item->canvas);
245 
246 	source = g_timeout_source_new (delay);
247 	g_source_set_callback (source, show_area_timeout, dac, doubs_and_canvas_free);
248 	g_source_set_name (source, G_STRFUNC);
249 	g_source_attach (source, NULL);
250 
251 	return source;
252 }
253