2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
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.
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.
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
23 #include "vikaggregatelayer_pixmap.h"
27 #define DISCONNECT_UPDATE_SIGNAL(vl, val) g_signal_handlers_disconnect_matched(vl, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, val)
29 static void aggregate_layer_marshall( VikAggregateLayer
*val
, guint8
**data
, gint
*len
);
30 static VikAggregateLayer
*aggregate_layer_unmarshall( guint8
*data
, gint len
, VikViewport
*vvp
);
31 static void aggregate_layer_change_coord_mode ( VikAggregateLayer
*val
, VikCoordMode mode
);
32 static void aggregate_layer_drag_drop_request ( VikAggregateLayer
*val_src
, VikAggregateLayer
*val_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
);
34 VikLayerInterface vik_aggregate_layer_interface
= {
36 &aggregatelayer_pixbuf
,
48 (VikLayerFuncCreate
) vik_aggregate_layer_create
,
49 (VikLayerFuncRealize
) vik_aggregate_layer_realize
,
50 (VikLayerFuncPostRead
) NULL
,
51 (VikLayerFuncFree
) vik_aggregate_layer_free
,
53 (VikLayerFuncProperties
) NULL
,
54 (VikLayerFuncDraw
) vik_aggregate_layer_draw
,
55 (VikLayerFuncChangeCoordMode
) aggregate_layer_change_coord_mode
,
57 (VikLayerFuncSetMenuItemsSelection
) NULL
,
58 (VikLayerFuncGetMenuItemsSelection
) NULL
,
60 (VikLayerFuncAddMenuItems
) NULL
,
61 (VikLayerFuncSublayerAddMenuItems
) NULL
,
63 (VikLayerFuncSublayerRenameRequest
) NULL
,
64 (VikLayerFuncSublayerToggleVisible
) NULL
,
66 (VikLayerFuncMarshall
) aggregate_layer_marshall
,
67 (VikLayerFuncUnmarshall
) aggregate_layer_unmarshall
,
69 (VikLayerFuncSetParam
) NULL
,
70 (VikLayerFuncGetParam
) NULL
,
72 (VikLayerFuncReadFileData
) NULL
,
73 (VikLayerFuncWriteFileData
) NULL
,
75 (VikLayerFuncDeleteItem
) NULL
,
76 (VikLayerFuncCopyItem
) NULL
,
77 (VikLayerFuncPasteItem
) NULL
,
78 (VikLayerFuncFreeCopiedItem
) NULL
,
79 (VikLayerFuncDragDropRequest
) aggregate_layer_drag_drop_request
,
82 struct _VikAggregateLayer
{
87 GType
vik_aggregate_layer_get_type ()
89 static GType val_type
= 0;
93 static const GTypeInfo val_info
=
95 sizeof (VikAggregateLayerClass
),
97 NULL
, /* base_finalize */
98 NULL
, /* class init */
99 NULL
, /* class_finalize */
100 NULL
, /* class_data */
101 sizeof (VikAggregateLayer
),
103 NULL
/* instance init */
105 val_type
= g_type_register_static ( VIK_LAYER_TYPE
, "VikAggregateLayer", &val_info
, 0 );
111 VikAggregateLayer
*vik_aggregate_layer_create (VikViewport
*vp
)
113 VikAggregateLayer
*rv
= vik_aggregate_layer_new ();
114 vik_layer_rename ( VIK_LAYER(rv
), vik_aggregate_layer_interface
.name
);
118 static void aggregate_layer_marshall( VikAggregateLayer
*val
, guint8
**data
, gint
*datalen
)
120 GList
*child
= val
->children
;
121 VikLayer
*child_layer
;
124 GByteArray
* b
= g_byte_array_new ();
127 #define alm_append(obj, sz) \
129 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
130 g_byte_array_append ( b, (guint8 *)(obj), len );
132 vik_layer_marshall_params(VIK_LAYER(val
), &ld
, &ll
);
137 child_layer
= VIK_LAYER(child
->data
);
138 vik_layer_marshall ( child_layer
, &ld
, &ll
);
147 g_byte_array_free(b
, FALSE
);
151 static VikAggregateLayer
*aggregate_layer_unmarshall( guint8
*data
, gint len
, VikViewport
*vvp
)
153 #define alm_size (*(gint *)data)
155 len -= sizeof(gint) + alm_size; \
156 data += sizeof(gint) + alm_size;
158 VikAggregateLayer
*rv
= vik_aggregate_layer_new();
159 VikLayer
*child_layer
;
161 vik_layer_unmarshall_params ( VIK_LAYER(rv
), data
+sizeof(gint
), alm_size
, vvp
);
165 child_layer
= vik_layer_unmarshall ( data
+ sizeof(gint
), alm_size
, vvp
);
167 rv
->children
= g_list_append ( rv
->children
, child_layer
);
168 g_signal_connect_swapped ( G_OBJECT(child_layer
), "update", G_CALLBACK(vik_layer_emit_update_secondary
), rv
);
172 // g_print("aggregate_layer_unmarshall ended with len=%d\n", len);
178 VikAggregateLayer
*vik_aggregate_layer_new ()
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
;
186 void vik_aggregate_layer_insert_layer ( VikAggregateLayer
*val
, VikLayer
*l
, GtkTreeIter
*replace_iter
)
190 if ( VIK_LAYER(val
)->realized
)
192 vik_treeview_insert_layer ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
), &iter
, l
->name
, val
, l
, l
->type
, l
->type
, replace_iter
);
194 vik_treeview_item_set_visible ( VIK_LAYER(val
)->vt
, &iter
, FALSE
);
195 vik_layer_realize ( l
, VIK_LAYER(val
)->vt
, &iter
);
197 if ( val
->children
== NULL
)
198 vik_treeview_expand ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->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 );
205 val
->children
= g_list_append ( val
->children
, l
);
207 g_signal_connect_swapped ( G_OBJECT(l
), "update", G_CALLBACK(vik_layer_emit_update_secondary
), val
);
210 void vik_aggregate_layer_add_layer ( VikAggregateLayer
*val
, VikLayer
*l
)
214 if ( VIK_LAYER(val
)->realized
)
216 vik_treeview_add_layer ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
), &iter
, l
->name
, val
, l
, l
->type
, l
->type
);
218 vik_treeview_item_set_visible ( VIK_LAYER(val
)->vt
, &iter
, FALSE
);
219 vik_layer_realize ( l
, VIK_LAYER(val
)->vt
, &iter
);
221 if ( val
->children
== NULL
)
222 vik_treeview_expand ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
) );
225 val
->children
= g_list_append ( val
->children
, l
);
226 g_signal_connect_swapped ( G_OBJECT(l
), "update", G_CALLBACK(vik_layer_emit_update_secondary
), val
);
229 void vik_aggregate_layer_move_layer ( VikAggregateLayer
*val
, GtkTreeIter
*child_iter
, gboolean up
)
231 GList
*theone
, *first
, *second
;
232 vik_treeview_move_item ( VIK_LAYER(val
)->vt
, child_iter
, up
);
234 theone
= g_list_find ( val
->children
, vik_treeview_item_get_pointer ( VIK_LAYER(val
)->vt
, child_iter
) );
236 g_assert ( theone
!= NULL
);
238 /* the old switcheroo */
239 if ( up
&& theone
->next
)
242 second
= theone
->next
;
244 else if ( !up
&& theone
->prev
)
246 first
= theone
->prev
;
252 first
->next
= second
->next
;
253 second
->prev
= first
->prev
;
254 first
->prev
= second
;
255 second
->next
= first
;
257 /* second is now first */
260 second
->prev
->next
= second
;
262 first
->next
->prev
= first
;
264 if ( second
->prev
== NULL
)
265 val
->children
= second
;
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
277 void vik_aggregate_layer_draw ( VikAggregateLayer
*val
, gpointer data
)
279 GList
*iter
= val
->children
;
281 VikLayer
*trigger
= VIK_LAYER(vik_viewport_get_trigger( VIK_VIEWPORT(data
) ));
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
) );
289 vik_viewport_snapshot_save( VIK_VIEWPORT(data
) );
292 if ( vl
->type
== VIK_LAYER_AGGREGATE
|| vl
->type
== VIK_LAYER_GPS
|| ! vik_viewport_get_half_drawn( VIK_VIEWPORT(data
) ) )
293 vik_layer_draw ( vl
, data
);
298 static void aggregate_layer_change_coord_mode ( VikAggregateLayer
*val
, VikCoordMode mode
)
300 GList
*iter
= val
->children
;
303 vik_layer_change_coord_mode ( VIK_LAYER(iter
->data
), mode
);
308 static void disconnect_layer_signal ( VikLayer
*vl
, VikAggregateLayer
*val
)
310 g_assert(DISCONNECT_UPDATE_SIGNAL(vl
,val
)==1);
313 void vik_aggregate_layer_free ( VikAggregateLayer
*val
)
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
);
320 static void delete_layer_iter ( VikLayer
*vl
)
323 vik_treeview_item_delete ( vl
->vt
, &(vl
->iter
) );
326 void vik_aggregate_layer_clear ( VikAggregateLayer
*val
)
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
;
335 gboolean
vik_aggregate_layer_delete ( VikAggregateLayer
*val
, GtkTreeIter
*iter
)
337 VikLayer
*l
= VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(val
)->vt
, iter
) );
338 gboolean was_visible
= l
->visible
;
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
);
349 /* returns 0 == we're good, 1 == didn't find any layers, 2 == got rejected */
350 guint
vik_aggregate_layer_tool ( VikAggregateLayer
*val
, guint16 layer_type
, VikToolInterfaceFunc tool_func
, GdkEventButton
*event
, VikViewport
*vvp
)
352 GList
*iter
= val
->children
;
353 gboolean found_rej
= FALSE
;
361 /* if this layer "accepts" the tool call */
362 if ( VIK_LAYER(iter
->data
)->visible
&& VIK_LAYER(iter
->data
)->type
== layer_type
)
364 if ( tool_func ( VIK_LAYER(iter
->data
), event
, vvp
) )
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
)
373 gint rv
= vik_aggregate_layer_tool(VIK_AGGREGATE_LAYER(iter
->data
), layer_type
, tool_func
, event
, vvp
);
381 return found_rej
? 2 : 1; /* no one wanted to accept the tool call in this layer */
385 VikLayer
*vik_aggregate_layer_get_top_visible_layer_of_type ( VikAggregateLayer
*val
, gint type
)
388 GList
*ls
= val
->children
;
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
)
400 rv
= vik_aggregate_layer_get_top_visible_layer_of_type(VIK_AGGREGATE_LAYER(ls
->data
), type
);
409 GList
*vik_aggregate_layer_get_all_layers_of_type(VikAggregateLayer
*val
, GList
*layers
, gint type
)
412 GList
*children
= val
->children
;
416 if (VIK_LAYER(children
->data
)->type
== VIK_LAYER_AGGREGATE
)
417 l
= vik_aggregate_layer_get_all_layers_of_type(VIK_AGGREGATE_LAYER(children
->data
), l
, type
);
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
;
425 void vik_aggregate_layer_realize ( VikAggregateLayer
*val
, VikTreeview
*vt
, GtkTreeIter
*layer_iter
)
427 GList
*i
= val
->children
;
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
);
440 const GList
*vik_aggregate_layer_get_children ( VikAggregateLayer
*val
)
442 return val
->children
;
445 gboolean
vik_aggregate_layer_is_empty ( VikAggregateLayer
*val
)
452 static void aggregate_layer_drag_drop_request ( VikAggregateLayer
*val_src
, VikAggregateLayer
*val_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
)
454 VikTreeview
*vt
= VIK_LAYER(val_src
)->vt
;
455 VikLayer
*vl
= vik_treeview_item_get_pointer(vt
, src_item_iter
);
456 GtkTreeIter dest_iter
;
458 gboolean target_exists
;
460 dp
= gtk_tree_path_to_string(dest_path
);
461 target_exists
= vik_treeview_get_iter_from_path_str(vt
, &dest_iter
, dp
);
463 /* vik_aggregate_layer_delete unrefs, but we don't want that here.
464 * we're still using the layer. */
466 vik_aggregate_layer_delete(val_src
, src_item_iter
);
469 vik_aggregate_layer_insert_layer(val_dest
, vl
, &dest_iter
);
471 vik_aggregate_layer_insert_layer(val_dest
, vl
, NULL
); /* append */