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