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 VikAggregateLayer
*aggregate_layer_copy ( VikAggregateLayer
*val
, gpointer vp
);
30 static void aggregate_layer_marshall( VikAggregateLayer
*val
, guint8
**data
, gint
*len
);
31 static VikAggregateLayer
*aggregate_layer_unmarshall( guint8
*data
, gint len
, VikViewport
*vvp
);
32 static void aggregate_layer_change_coord_mode ( VikAggregateLayer
*val
, VikCoordMode mode
);
33 static void aggregate_layer_drag_drop_request ( VikAggregateLayer
*val_src
, VikAggregateLayer
*val_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
);
35 VikLayerInterface vik_aggregate_layer_interface
= {
37 &aggregatelayer_pixbuf
,
49 (VikLayerFuncCreate
) vik_aggregate_layer_create
,
50 (VikLayerFuncRealize
) vik_aggregate_layer_realize
,
51 (VikLayerFuncPostRead
) NULL
,
52 (VikLayerFuncFree
) vik_aggregate_layer_free
,
54 (VikLayerFuncProperties
) NULL
,
55 (VikLayerFuncDraw
) vik_aggregate_layer_draw
,
56 (VikLayerFuncChangeCoordMode
) aggregate_layer_change_coord_mode
,
58 (VikLayerFuncSetMenuItemsSelection
) NULL
,
59 (VikLayerFuncGetMenuItemsSelection
) NULL
,
61 (VikLayerFuncAddMenuItems
) NULL
,
62 (VikLayerFuncSublayerAddMenuItems
) NULL
,
64 (VikLayerFuncSublayerRenameRequest
) NULL
,
65 (VikLayerFuncSublayerToggleVisible
) NULL
,
67 (VikLayerFuncCopy
) aggregate_layer_copy
,
68 (VikLayerFuncMarshall
) aggregate_layer_marshall
,
69 (VikLayerFuncUnmarshall
) aggregate_layer_unmarshall
,
71 (VikLayerFuncSetParam
) NULL
,
72 (VikLayerFuncGetParam
) NULL
,
74 (VikLayerFuncReadFileData
) NULL
,
75 (VikLayerFuncWriteFileData
) NULL
,
77 (VikLayerFuncDeleteItem
) NULL
,
78 (VikLayerFuncCopyItem
) NULL
,
79 (VikLayerFuncPasteItem
) NULL
,
80 (VikLayerFuncFreeCopiedItem
) NULL
,
81 (VikLayerFuncDragDropRequest
) aggregate_layer_drag_drop_request
,
84 struct _VikAggregateLayer
{
89 GType
vik_aggregate_layer_get_type ()
91 static GType val_type
= 0;
95 static const GTypeInfo val_info
=
97 sizeof (VikAggregateLayerClass
),
99 NULL
, /* base_finalize */
100 NULL
, /* class init */
101 NULL
, /* class_finalize */
102 NULL
, /* class_data */
103 sizeof (VikAggregateLayer
),
105 NULL
/* instance init */
107 val_type
= g_type_register_static ( VIK_LAYER_TYPE
, "VikAggregateLayer", &val_info
, 0 );
113 VikAggregateLayer
*vik_aggregate_layer_create (VikViewport
*vp
)
115 VikAggregateLayer
*rv
= vik_aggregate_layer_new ();
116 vik_layer_rename ( VIK_LAYER(rv
), vik_aggregate_layer_interface
.name
);
120 static VikAggregateLayer
*aggregate_layer_copy ( VikAggregateLayer
*val
, gpointer vp
)
122 VikAggregateLayer
*rv
= vik_aggregate_layer_new ();
123 VikLayer
*child_layer
;
124 GList
*child
= val
->children
;
127 child_layer
= vik_layer_copy ( VIK_LAYER(child
->data
), vp
);
129 rv
->children
= g_list_append ( rv
->children
, child_layer
);
130 g_signal_connect_swapped ( G_OBJECT(child_layer
), "update", G_CALLBACK(vik_layer_emit_update
), rv
);
137 static void aggregate_layer_marshall( VikAggregateLayer
*val
, guint8
**data
, gint
*datalen
)
139 GList
*child
= val
->children
;
140 VikLayer
*child_layer
;
143 GByteArray
* b
= g_byte_array_new ();
146 #define alm_append(obj, sz) \
148 g_byte_array_append ( b, (guint8 *)&len, sizeof(len) ); \
149 g_byte_array_append ( b, (guint8 *)(obj), len );
151 vik_layer_marshall_params(VIK_LAYER(val
), &ld
, &ll
);
156 child_layer
= VIK_LAYER(child
->data
);
157 vik_layer_marshall ( child_layer
, &ld
, &ll
);
166 g_byte_array_free(b
, FALSE
);
170 static VikAggregateLayer
*aggregate_layer_unmarshall( guint8
*data
, gint len
, VikViewport
*vvp
)
172 #define alm_size (*(gint *)data)
174 len -= sizeof(gint) + alm_size; \
175 data += sizeof(gint) + alm_size;
177 VikAggregateLayer
*rv
= vik_aggregate_layer_new();
178 VikLayer
*child_layer
;
180 vik_layer_unmarshall_params ( VIK_LAYER(rv
), data
+sizeof(gint
), alm_size
, vvp
);
184 child_layer
= vik_layer_unmarshall ( data
+ sizeof(gint
), alm_size
, vvp
);
186 rv
->children
= g_list_append ( rv
->children
, child_layer
);
187 g_signal_connect_swapped ( G_OBJECT(child_layer
), "update", G_CALLBACK(vik_layer_emit_update
), rv
);
191 // g_print("aggregate_layer_unmarshall ended with len=%d\n", len);
197 VikAggregateLayer
*vik_aggregate_layer_new ()
199 VikAggregateLayer
*val
= VIK_AGGREGATE_LAYER ( g_object_new ( VIK_AGGREGATE_LAYER_TYPE
, NULL
) );
200 vik_layer_init ( VIK_LAYER(val
), VIK_LAYER_AGGREGATE
);
201 val
->children
= NULL
;
205 void vik_aggregate_layer_insert_layer ( VikAggregateLayer
*val
, VikLayer
*l
, GtkTreeIter
*replace_iter
)
209 if ( VIK_LAYER(val
)->realized
)
211 vik_treeview_insert_layer ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
), &iter
, l
->name
, val
, l
, l
->type
, l
->type
, replace_iter
);
213 vik_treeview_item_set_visible ( VIK_LAYER(val
)->vt
, &iter
, FALSE
);
214 vik_layer_realize ( l
, VIK_LAYER(val
)->vt
, &iter
);
216 if ( val
->children
== NULL
)
217 vik_treeview_expand ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
) );
221 GList
*theone
= g_list_find ( val
->children
, vik_treeview_item_get_pointer ( VIK_LAYER(val
)->vt
, replace_iter
) );
222 val
->children
= g_list_insert ( val
->children
, l
, g_list_position(val
->children
,theone
)+1 );
224 val
->children
= g_list_append ( val
->children
, l
);
226 g_signal_connect_swapped ( G_OBJECT(l
), "update", G_CALLBACK(vik_layer_emit_update
), val
);
229 void vik_aggregate_layer_add_layer ( VikAggregateLayer
*val
, VikLayer
*l
)
233 if ( VIK_LAYER(val
)->realized
)
235 vik_treeview_add_layer ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
), &iter
, l
->name
, val
, l
, l
->type
, l
->type
);
237 vik_treeview_item_set_visible ( VIK_LAYER(val
)->vt
, &iter
, FALSE
);
238 vik_layer_realize ( l
, VIK_LAYER(val
)->vt
, &iter
);
240 if ( val
->children
== NULL
)
241 vik_treeview_expand ( VIK_LAYER(val
)->vt
, &(VIK_LAYER(val
)->iter
) );
244 val
->children
= g_list_append ( val
->children
, l
);
245 g_signal_connect_swapped ( G_OBJECT(l
), "update", G_CALLBACK(vik_layer_emit_update
), val
);
248 void vik_aggregate_layer_move_layer ( VikAggregateLayer
*val
, GtkTreeIter
*child_iter
, gboolean up
)
250 GList
*theone
, *first
, *second
;
251 vik_treeview_move_item ( VIK_LAYER(val
)->vt
, child_iter
, up
);
253 theone
= g_list_find ( val
->children
, vik_treeview_item_get_pointer ( VIK_LAYER(val
)->vt
, child_iter
) );
255 g_assert ( theone
!= NULL
);
257 /* the old switcheroo */
258 if ( up
&& theone
->next
)
261 second
= theone
->next
;
263 else if ( !up
&& theone
->prev
)
265 first
= theone
->prev
;
271 first
->next
= second
->next
;
272 second
->prev
= first
->prev
;
273 first
->prev
= second
;
274 second
->next
= first
;
276 /* second is now first */
279 second
->prev
->next
= second
;
281 first
->next
->prev
= first
;
283 if ( second
->prev
== NULL
)
284 val
->children
= second
;
287 void vik_aggregate_layer_draw ( VikAggregateLayer
*val
, gpointer data
)
289 g_list_foreach ( val
->children
, (GFunc
)(vik_layer_draw
), data
);
292 static void aggregate_layer_change_coord_mode ( VikAggregateLayer
*val
, VikCoordMode mode
)
294 GList
*iter
= val
->children
;
297 vik_layer_change_coord_mode ( VIK_LAYER(iter
->data
), mode
);
302 static void disconnect_layer_signal ( VikLayer
*vl
, VikAggregateLayer
*val
)
304 g_assert(DISCONNECT_UPDATE_SIGNAL(vl
,val
)==1);
307 void vik_aggregate_layer_free ( VikAggregateLayer
*val
)
309 g_list_foreach ( val
->children
, (GFunc
)(disconnect_layer_signal
), val
);
310 g_list_foreach ( val
->children
, (GFunc
)(g_object_unref
), NULL
);
311 g_list_free ( val
->children
);
314 static void delete_layer_iter ( VikLayer
*vl
)
317 vik_treeview_item_delete ( vl
->vt
, &(vl
->iter
) );
320 void vik_aggregate_layer_clear ( VikAggregateLayer
*val
)
322 g_list_foreach ( val
->children
, (GFunc
)(disconnect_layer_signal
), val
);
323 g_list_foreach ( val
->children
, (GFunc
)(delete_layer_iter
), NULL
);
324 g_list_foreach ( val
->children
, (GFunc
)(g_object_unref
), NULL
);
325 g_list_free ( val
->children
);
326 val
->children
= NULL
;
329 gboolean
vik_aggregate_layer_delete ( VikAggregateLayer
*val
, GtkTreeIter
*iter
)
331 VikLayer
*l
= VIK_LAYER( vik_treeview_item_get_pointer ( VIK_LAYER(val
)->vt
, iter
) );
332 gboolean was_visible
= l
->visible
;
334 vik_treeview_item_delete ( VIK_LAYER(val
)->vt
, iter
);
335 val
->children
= g_list_remove ( val
->children
, l
);
336 g_assert(DISCONNECT_UPDATE_SIGNAL(l
,val
)==1);
337 g_object_unref ( l
);
343 /* returns 0 == we're good, 1 == didn't find any layers, 2 == got rejected */
344 guint
vik_aggregate_layer_tool ( VikAggregateLayer
*val
, guint16 layer_type
, VikToolInterfaceFunc tool_func
, GdkEventButton
*event
, VikViewport
*vvp
)
346 GList
*iter
= val
->children
;
347 gboolean found_rej
= FALSE
;
355 /* if this layer "accepts" the tool call */
356 if ( VIK_LAYER(iter
->data
)->visible
&& VIK_LAYER(iter
->data
)->type
== layer_type
)
358 if ( tool_func ( VIK_LAYER(iter
->data
), event
, vvp
) )
364 /* recursive -- try the same for the child aggregate layer. */
365 else if ( VIK_LAYER(iter
->data
)->visible
&& VIK_LAYER(iter
->data
)->type
== VIK_LAYER_AGGREGATE
)
367 gint rv
= vik_aggregate_layer_tool(VIK_AGGREGATE_LAYER(iter
->data
), layer_type
, tool_func
, event
, vvp
);
375 return found_rej
? 2 : 1; /* no one wanted to accept the tool call in this layer */
379 VikLayer
*vik_aggregate_layer_get_top_visible_layer_of_type ( VikAggregateLayer
*val
, gint type
)
382 GList
*ls
= val
->children
;
390 if ( VIK_LAYER(ls
->data
)->visible
&& VIK_LAYER(ls
->data
)->type
== type
)
391 return VIK_LAYER(ls
->data
);
392 else if ( VIK_LAYER(ls
->data
)->visible
&& VIK_LAYER(ls
->data
)->type
== VIK_LAYER_AGGREGATE
)
394 rv
= vik_aggregate_layer_get_top_visible_layer_of_type(VIK_AGGREGATE_LAYER(ls
->data
), type
);
403 GList
*vik_aggregate_layer_get_all_layers_of_type(VikAggregateLayer
*val
, GList
*layers
, gint type
)
406 GList
*children
= val
->children
;
410 if (VIK_LAYER(children
->data
)->type
== VIK_LAYER_AGGREGATE
)
411 l
= vik_aggregate_layer_get_all_layers_of_type(VIK_LAYER(children
->data
), l
, type
);
412 else if (VIK_LAYER(children
->data
)->type
== type
)
413 l
= g_list_prepend(l
, children
->data
); /* now in top down order */
414 children
= children
->next
;
419 void vik_aggregate_layer_realize ( VikAggregateLayer
*val
, VikTreeview
*vt
, GtkTreeIter
*layer_iter
)
421 GList
*i
= val
->children
;
425 vik_treeview_add_layer ( VIK_LAYER(val
)->vt
, layer_iter
, &iter
, VIK_LAYER(i
->data
)->name
, val
,
426 VIK_LAYER(i
->data
), VIK_LAYER(i
->data
)->type
, VIK_LAYER(i
->data
)->type
);
427 if ( ! VIK_LAYER(i
->data
)->visible
)
428 vik_treeview_item_set_visible ( VIK_LAYER(val
)->vt
, &iter
, FALSE
);
429 vik_layer_realize ( VIK_LAYER(i
->data
), VIK_LAYER(val
)->vt
, &iter
);
434 const GList
*vik_aggregate_layer_get_children ( VikAggregateLayer
*val
)
436 return val
->children
;
439 gboolean
vik_aggregate_layer_is_empty ( VikAggregateLayer
*val
)
446 static void aggregate_layer_drag_drop_request ( VikAggregateLayer
*val_src
, VikAggregateLayer
*val_dest
, GtkTreeIter
*src_item_iter
, GtkTreePath
*dest_path
)
448 VikTreeview
*vt
= VIK_LAYER(val_src
)->vt
;
449 VikLayer
*vl
= vik_treeview_item_get_pointer(vt
, src_item_iter
);
450 GtkTreeIter dest_iter
;
452 gboolean target_exists
;
454 dp
= gtk_tree_path_to_string(dest_path
);
455 target_exists
= vik_treeview_get_iter_from_path_str(vt
, &dest_iter
, dp
);
457 /* vik_aggregate_layer_delete unrefs, but we don't want that here.
458 * we're still using the layer. */
460 vik_aggregate_layer_delete(val_src
, src_item_iter
);
463 vik_aggregate_layer_insert_layer(val_dest
, vl
, &dest_iter
);
465 vik_aggregate_layer_insert_layer(val_dest
, vl
, NULL
); /* append */