]> git.street.me.uk Git - andy/viking.git/blame - src/vikaggregatelayer.c
Releasing viking 1.1
[andy/viking.git] / src / vikaggregatelayer.c
CommitLineData
50a14534
EB
1/*
2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
3 *
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22#include "viking.h"
5bfafde9 23#include "icons/icons.h"
50a14534
EB
24
25#include <string.h>
26
27#define DISCONNECT_UPDATE_SIGNAL(vl, val) g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, val)
28
0a6cab71
AF
29static void aggregate_layer_marshall( VikAggregateLayer *val, guint8 **data, gint *len );
30static VikAggregateLayer *aggregate_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp );
50a14534 31static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode );
70a23263 32static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path );
50a14534
EB
33
34VikLayerInterface vik_aggregate_layer_interface = {
35 "Aggregate",
5bfafde9 36 &vikaggregatelayer_pixbuf,
50a14534
EB
37
38 NULL,
39 0,
40
41 NULL,
42 0,
43 NULL,
44 0,
45
5a4a28bf
QT
46 VIK_MENU_ITEM_ALL,
47
50a14534
EB
48 (VikLayerFuncCreate) vik_aggregate_layer_create,
49 (VikLayerFuncRealize) vik_aggregate_layer_realize,
50 (VikLayerFuncPostRead) NULL,
51 (VikLayerFuncFree) vik_aggregate_layer_free,
52
53 (VikLayerFuncProperties) NULL,
54 (VikLayerFuncDraw) vik_aggregate_layer_draw,
55 (VikLayerFuncChangeCoordMode) aggregate_layer_change_coord_mode,
20c7a3a0
QT
56
57 (VikLayerFuncSetMenuItemsSelection) NULL,
58 (VikLayerFuncGetMenuItemsSelection) NULL,
50a14534
EB
59
60 (VikLayerFuncAddMenuItems) NULL,
61 (VikLayerFuncSublayerAddMenuItems) NULL,
62
63 (VikLayerFuncSublayerRenameRequest) NULL,
64 (VikLayerFuncSublayerToggleVisible) NULL,
9da7faf2 65 (VikLayerFuncSublayerTooltip) NULL,
1e8b7f57 66 (VikLayerFuncLayerTooltip) NULL,
50a14534 67
0a6cab71
AF
68 (VikLayerFuncMarshall) aggregate_layer_marshall,
69 (VikLayerFuncUnmarshall) aggregate_layer_unmarshall,
50a14534
EB
70
71 (VikLayerFuncSetParam) NULL,
72 (VikLayerFuncGetParam) NULL,
73
74 (VikLayerFuncReadFileData) NULL,
75 (VikLayerFuncWriteFileData) NULL,
76
33534cd8 77 (VikLayerFuncDeleteItem) NULL,
d5874ef9 78 (VikLayerFuncCutItem) NULL,
50a14534
EB
79 (VikLayerFuncCopyItem) NULL,
80 (VikLayerFuncPasteItem) NULL,
81 (VikLayerFuncFreeCopiedItem) NULL,
70a23263 82 (VikLayerFuncDragDropRequest) aggregate_layer_drag_drop_request,
50a14534
EB
83};
84
85struct _VikAggregateLayer {
86 VikLayer vl;
87 GList *children;
88};
89
90GType vik_aggregate_layer_get_type ()
91{
92 static GType val_type = 0;
93
94 if (!val_type)
95 {
96 static const GTypeInfo val_info =
97 {
98 sizeof (VikAggregateLayerClass),
99 NULL, /* base_init */
100 NULL, /* base_finalize */
101 NULL, /* class init */
102 NULL, /* class_finalize */
103 NULL, /* class_data */
104 sizeof (VikAggregateLayer),
105 0,
106 NULL /* instance init */
107 };
108 val_type = g_type_register_static ( VIK_LAYER_TYPE, "VikAggregateLayer", &val_info, 0 );
109 }
110
111 return val_type;
112}
113
114VikAggregateLayer *vik_aggregate_layer_create (VikViewport *vp)
115{
116 VikAggregateLayer *rv = vik_aggregate_layer_new ();
117 vik_layer_rename ( VIK_LAYER(rv), vik_aggregate_layer_interface.name );
118 return rv;
119}
120
0a6cab71
AF
121static void aggregate_layer_marshall( VikAggregateLayer *val, guint8 **data, gint *datalen )
122{
123 GList *child = val->children;
124 VikLayer *child_layer;
125 guint8 *ld;
126 gint ll;
127 GByteArray* b = g_byte_array_new ();
128 gint len;
129
130#define alm_append(obj, sz) \
131 len = (sz); \
132 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
133 g_byte_array_append ( b, (guint8 *)(obj), len );
134
135 vik_layer_marshall_params(VIK_LAYER(val), &ld, &ll);
136 alm_append(ld, ll);
137 g_free(ld);
138
139 while (child) {
140 child_layer = VIK_LAYER(child->data);
141 vik_layer_marshall ( child_layer, &ld, &ll );
142 if (ld) {
143 alm_append(ld, ll);
144 g_free(ld);
145 }
146 child = child->next;
147 }
148 *data = b->data;
149 *datalen = b->len;
150 g_byte_array_free(b, FALSE);
151#undef alm_append
152}
153
154static VikAggregateLayer *aggregate_layer_unmarshall( guint8 *data, gint len, VikViewport *vvp )
155{
156#define alm_size (*(gint *)data)
157#define alm_next \
158 len -= sizeof(gint) + alm_size; \
159 data += sizeof(gint) + alm_size;
160
161 VikAggregateLayer *rv = vik_aggregate_layer_new();
162 VikLayer *child_layer;
163
164 vik_layer_unmarshall_params ( VIK_LAYER(rv), data+sizeof(gint), alm_size, vvp );
165 alm_next;
166
167 while (len>0) {
168 child_layer = vik_layer_unmarshall ( data + sizeof(gint), alm_size, vvp );
169 if (child_layer) {
170 rv->children = g_list_append ( rv->children, child_layer );
0df66d57 171 g_signal_connect_swapped ( G_OBJECT(child_layer), "update", G_CALLBACK(vik_layer_emit_update_secondary), rv );
0a6cab71
AF
172 }
173 alm_next;
174 }
175 // g_print("aggregate_layer_unmarshall ended with len=%d\n", len);
176 return rv;
177#undef alm_size
178#undef alm_next
179}
180
50a14534
EB
181VikAggregateLayer *vik_aggregate_layer_new ()
182{
183 VikAggregateLayer *val = VIK_AGGREGATE_LAYER ( g_object_new ( VIK_AGGREGATE_LAYER_TYPE, NULL ) );
184 vik_layer_init ( VIK_LAYER(val), VIK_LAYER_AGGREGATE );
185 val->children = NULL;
186 return val;
187}
188
189void vik_aggregate_layer_insert_layer ( VikAggregateLayer *val, VikLayer *l, GtkTreeIter *replace_iter )
190{
50a14534 191 GtkTreeIter iter;
e673b75f 192
50a14534
EB
193 if ( VIK_LAYER(val)->realized )
194 {
195 vik_treeview_insert_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type, replace_iter );
196 if ( ! l->visible )
197 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
198 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
199
200 if ( val->children == NULL )
201 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
202 }
50a14534 203
e673b75f
AF
204 if (replace_iter) {
205 GList *theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, replace_iter ) );
206 val->children = g_list_insert ( val->children, l, g_list_position(val->children,theone)+1 );
207 } else {
208 val->children = g_list_append ( val->children, l );
209 }
0df66d57 210 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update_secondary), val );
50a14534
EB
211}
212
213void vik_aggregate_layer_add_layer ( VikAggregateLayer *val, VikLayer *l )
214{
215 GtkTreeIter iter;
216
217 if ( VIK_LAYER(val)->realized )
218 {
219 vik_treeview_add_layer ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter), &iter, l->name, val, l, l->type, l->type);
220 if ( ! l->visible )
221 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
222 vik_layer_realize ( l, VIK_LAYER(val)->vt, &iter );
223
224 if ( val->children == NULL )
225 vik_treeview_expand ( VIK_LAYER(val)->vt, &(VIK_LAYER(val)->iter) );
226 }
227
228 val->children = g_list_append ( val->children, l );
0df66d57 229 g_signal_connect_swapped ( G_OBJECT(l), "update", G_CALLBACK(vik_layer_emit_update_secondary), val );
50a14534
EB
230}
231
232void vik_aggregate_layer_move_layer ( VikAggregateLayer *val, GtkTreeIter *child_iter, gboolean up )
233{
234 GList *theone, *first, *second;
235 vik_treeview_move_item ( VIK_LAYER(val)->vt, child_iter, up );
236
237 theone = g_list_find ( val->children, vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, child_iter ) );
238
239 g_assert ( theone != NULL );
240
241 /* the old switcheroo */
242 if ( up && theone->next )
243 {
244 first = theone;
245 second = theone->next;
246 }
247 else if ( !up && theone->prev )
248 {
249 first = theone->prev;
250 second = theone;
251 }
252 else
253 return;
254
255 first->next = second->next;
256 second->prev = first->prev;
257 first->prev = second;
258 second->next = first;
259
260 /* second is now first */
261
262 if ( second->prev )
263 second->prev->next = second;
264 if ( first->next )
265 first->next->prev = first;
266
267 if ( second->prev == NULL )
268 val->children = second;
269}
270
0df66d57
EB
271/* Draw the aggregate layer. If vik viewport is in half_drawn mode, this means we are only
272 * to draw the layers above and including the trigger layer.
273 * To do this we don't draw any layers if in half drawn mode, unless we find the
274 * trigger layer, in which case we pull up the saved pixmap, turn off half drawn mode and
275 * start drawing layers.
276 * Also, if we were never in half drawn mode, we save a snapshot
277 * of the pixmap before drawing the trigger layer so we can use it again
278 * later.
279 */
50a14534
EB
280void vik_aggregate_layer_draw ( VikAggregateLayer *val, gpointer data )
281{
0df66d57
EB
282 GList *iter = val->children;
283 VikLayer *vl;
284 VikLayer *trigger = VIK_LAYER(vik_viewport_get_trigger( VIK_VIEWPORT(data) ));
285 while ( iter ) {
286 vl = VIK_LAYER(iter->data);
287 if ( vl == trigger ) {
288 if ( vik_viewport_get_half_drawn ( VIK_VIEWPORT(data) ) ) {
289 vik_viewport_set_half_drawn ( VIK_VIEWPORT(data), FALSE );
290 vik_viewport_snapshot_load( VIK_VIEWPORT(data) );
291 } else {
292 vik_viewport_snapshot_save( VIK_VIEWPORT(data) );
293 }
294 }
8fcff869 295 if ( vl->type == VIK_LAYER_AGGREGATE || vl->type == VIK_LAYER_GPS || ! vik_viewport_get_half_drawn( VIK_VIEWPORT(data) ) )
0df66d57
EB
296 vik_layer_draw ( vl, data );
297 iter = iter->next;
298 }
50a14534
EB
299}
300
301static void aggregate_layer_change_coord_mode ( VikAggregateLayer *val, VikCoordMode mode )
302{
303 GList *iter = val->children;
304 while ( iter )
305 {
306 vik_layer_change_coord_mode ( VIK_LAYER(iter->data), mode );
307 iter = iter->next;
308 }
309}
310
311static void disconnect_layer_signal ( VikLayer *vl, VikAggregateLayer *val )
312{
313 g_assert(DISCONNECT_UPDATE_SIGNAL(vl,val)==1);
314}
315
316void vik_aggregate_layer_free ( VikAggregateLayer *val )
317{
318 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
319 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
320 g_list_free ( val->children );
321}
322
323static void delete_layer_iter ( VikLayer *vl )
324{
325 if ( vl->realized )
326 vik_treeview_item_delete ( vl->vt, &(vl->iter) );
327}
328
329void vik_aggregate_layer_clear ( VikAggregateLayer *val )
330{
331 g_list_foreach ( val->children, (GFunc)(disconnect_layer_signal), val );
332 g_list_foreach ( val->children, (GFunc)(delete_layer_iter), NULL );
333 g_list_foreach ( val->children, (GFunc)(g_object_unref), NULL );
334 g_list_free ( val->children );
335 val->children = NULL;
336}
337
338gboolean vik_aggregate_layer_delete ( VikAggregateLayer *val, GtkTreeIter *iter )
339{
340 VikLayer *l = VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(val)->vt, iter ) );
341 gboolean was_visible = l->visible;
342
343 vik_treeview_item_delete ( VIK_LAYER(val)->vt, iter );
344 val->children = g_list_remove ( val->children, l );
345 g_assert(DISCONNECT_UPDATE_SIGNAL(l,val)==1);
346 g_object_unref ( l );
347
348 return was_visible;
349}
350
941aa6e9 351#if 0
50a14534
EB
352/* returns 0 == we're good, 1 == didn't find any layers, 2 == got rejected */
353guint vik_aggregate_layer_tool ( VikAggregateLayer *val, guint16 layer_type, VikToolInterfaceFunc tool_func, GdkEventButton *event, VikViewport *vvp )
354{
355 GList *iter = val->children;
356 gboolean found_rej = FALSE;
357 if (!iter)
358 return FALSE;
359 while (iter->next)
360 iter = iter->next;
361
362 while ( iter )
363 {
364 /* if this layer "accepts" the tool call */
365 if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == layer_type )
366 {
367 if ( tool_func ( VIK_LAYER(iter->data), event, vvp ) )
368 return 0;
369 else
370 found_rej = TRUE;
371 }
372
373 /* recursive -- try the same for the child aggregate layer. */
374 else if ( VIK_LAYER(iter->data)->visible && VIK_LAYER(iter->data)->type == VIK_LAYER_AGGREGATE )
375 {
376 gint rv = vik_aggregate_layer_tool(VIK_AGGREGATE_LAYER(iter->data), layer_type, tool_func, event, vvp);
377 if ( rv == 0 )
378 return 0;
379 else if ( rv == 2 )
380 found_rej = TRUE;
381 }
382 iter = iter->prev;
383 }
384 return found_rej ? 2 : 1; /* no one wanted to accept the tool call in this layer */
385}
941aa6e9 386#endif
50a14534
EB
387
388VikLayer *vik_aggregate_layer_get_top_visible_layer_of_type ( VikAggregateLayer *val, gint type )
389{
390 VikLayer *rv;
391 GList *ls = val->children;
392 if (!ls)
393 return NULL;
394 while (ls->next)
395 ls = ls->next;
396
397 while ( ls )
398 {
399 if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == type )
400 return VIK_LAYER(ls->data);
401 else if ( VIK_LAYER(ls->data)->visible && VIK_LAYER(ls->data)->type == VIK_LAYER_AGGREGATE )
402 {
403 rv = vik_aggregate_layer_get_top_visible_layer_of_type(VIK_AGGREGATE_LAYER(ls->data), type);
404 if ( rv )
405 return rv;
406 }
407 ls = ls->prev;
408 }
409 return NULL;
410}
411
7114e879
QT
412GList *vik_aggregate_layer_get_all_layers_of_type(VikAggregateLayer *val, GList *layers, gint type)
413{
414 GList *l = layers;
415 GList *children = val->children;
416 if (!children)
417 return layers;
418 while (children) {
419 if (VIK_LAYER(children->data)->type == VIK_LAYER_AGGREGATE)
8ece78c0 420 l = vik_aggregate_layer_get_all_layers_of_type(VIK_AGGREGATE_LAYER(children->data), l, type);
7114e879
QT
421 else if (VIK_LAYER(children->data)->type == type)
422 l = g_list_prepend(l, children->data); /* now in top down order */
423 children = children->next;
424 }
425 return l;
426}
427
50a14534
EB
428void vik_aggregate_layer_realize ( VikAggregateLayer *val, VikTreeview *vt, GtkTreeIter *layer_iter )
429{
430 GList *i = val->children;
431 GtkTreeIter iter;
432 while ( i )
433 {
434 vik_treeview_add_layer ( VIK_LAYER(val)->vt, layer_iter, &iter, VIK_LAYER(i->data)->name, val,
435 VIK_LAYER(i->data), VIK_LAYER(i->data)->type, VIK_LAYER(i->data)->type );
436 if ( ! VIK_LAYER(i->data)->visible )
437 vik_treeview_item_set_visible ( VIK_LAYER(val)->vt, &iter, FALSE );
438 vik_layer_realize ( VIK_LAYER(i->data), VIK_LAYER(val)->vt, &iter );
439 i = i->next;
440 }
441}
442
443const GList *vik_aggregate_layer_get_children ( VikAggregateLayer *val )
444{
445 return val->children;
446}
447
448gboolean vik_aggregate_layer_is_empty ( VikAggregateLayer *val )
449{
450 if ( val->children )
451 return FALSE;
452 return TRUE;
453}
70a23263
AF
454
455static void aggregate_layer_drag_drop_request ( VikAggregateLayer *val_src, VikAggregateLayer *val_dest, GtkTreeIter *src_item_iter, GtkTreePath *dest_path )
456{
457 VikTreeview *vt = VIK_LAYER(val_src)->vt;
458 VikLayer *vl = vik_treeview_item_get_pointer(vt, src_item_iter);
e673b75f 459 GtkTreeIter dest_iter;
c390aa71
AF
460 gchar *dp;
461 gboolean target_exists;
e673b75f 462
c390aa71
AF
463 dp = gtk_tree_path_to_string(dest_path);
464 target_exists = vik_treeview_get_iter_from_path_str(vt, &dest_iter, dp);
801ce684
EB
465
466 /* vik_aggregate_layer_delete unrefs, but we don't want that here.
467 * we're still using the layer. */
468 g_object_ref ( vl );
469 vik_aggregate_layer_delete(val_src, src_item_iter);
470
c390aa71 471 if (target_exists) {
e673b75f
AF
472 vik_aggregate_layer_insert_layer(val_dest, vl, &dest_iter);
473 } else {
474 vik_aggregate_layer_insert_layer(val_dest, vl, NULL); /* append */
475 }
c390aa71 476 g_free(dp);
70a23263
AF
477}
478