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 "vikradiogroup.h"
25 /* functions common to all layers. */
26 /* TODO longone: rename interface free -> finalize */
28 extern VikLayerInterface vik_aggregate_layer_interface
;
29 extern VikLayerInterface vik_trw_layer_interface
;
30 extern VikLayerInterface vik_maps_layer_interface
;
31 extern VikLayerInterface vik_coord_layer_interface
;
32 extern VikLayerInterface vik_georef_layer_interface
;
38 static guint layer_signals
[VL_LAST_SIGNAL
] = { 0 };
40 static GObjectClass
*parent_class
;
42 static void layer_class_init ( VikLayerClass
*klass
);
43 static void layer_init ( VikLayer
*vl
);
44 static void layer_finalize ( VikLayer
*vl
);
45 static gboolean
layer_properties_factory ( VikLayer
*vl
, gpointer vp
);
48 /* TODO longone: rename vik_layer_init -> set_type */
50 GType
vik_layer_get_type ()
52 static GType vl_type
= 0;
56 static const GTypeInfo vl_info
=
58 sizeof (VikLayerClass
),
60 NULL
, /* base_finalize */
61 (GClassInitFunc
) layer_class_init
, /* class init */
62 NULL
, /* class_finalize */
63 NULL
, /* class_data */
66 (GInstanceInitFunc
) layer_init
/* instance init */
68 vl_type
= g_type_register_static ( G_TYPE_OBJECT
, "VikLayer", &vl_info
, 0 );
74 static void layer_class_init (VikLayerClass
*klass
)
76 GObjectClass
*object_class
;
78 object_class
= G_OBJECT_CLASS (klass
);
80 object_class
->finalize
= (GObjectFinalizeFunc
) layer_finalize
;
82 parent_class
= g_type_class_peek_parent (klass
);
84 layer_signals
[VL_UPDATE_SIGNAL
] = g_signal_new ( "update", G_TYPE_FROM_CLASS (klass
),
85 G_SIGNAL_RUN_FIRST
| G_SIGNAL_ACTION
, G_STRUCT_OFFSET (VikLayerClass
, update
), NULL
, NULL
,
86 g_cclosure_marshal_VOID__VOID
, G_TYPE_NONE
, 0);
89 void vik_layer_emit_update ( VikLayer
*vl
)
92 g_signal_emit ( G_OBJECT(vl
), layer_signals
[VL_UPDATE_SIGNAL
], 0 );
95 static VikLayerInterface
*vik_layer_interfaces
[VIK_LAYER_NUM_TYPES
] = {
96 &vik_aggregate_layer_interface
,
97 &vik_trw_layer_interface
,
98 &vik_coord_layer_interface
,
99 &vik_georef_layer_interface
,
100 &vik_maps_layer_interface
,
103 VikLayerInterface
*vik_layer_get_interface ( gint type
)
105 g_assert ( type
< VIK_LAYER_NUM_TYPES
);
106 return vik_layer_interfaces
[type
];
109 static void layer_init ( VikLayer
*vl
)
113 vl
->realized
= FALSE
;
116 void vik_layer_init ( VikLayer
*vl
, gint type
)
122 void vik_layer_rename ( VikLayer
*l
, const gchar
*new_name
)
124 g_assert ( l
!= NULL
);
127 l
->name
= g_strdup ( new_name
);
130 void vik_layer_rename_no_copy ( VikLayer
*l
, gchar
*new_name
)
132 g_assert ( l
!= NULL
);
138 VikLayer
*vik_layer_create ( gint type
, gpointer vp
, GtkWindow
*w
, gboolean interactive
)
140 VikLayer
*new_layer
= NULL
;
141 g_assert ( type
< VIK_LAYER_NUM_TYPES
);
143 new_layer
= vik_layer_interfaces
[type
]->create ( vp
);
145 g_assert ( new_layer
!= NULL
);
149 if ( vik_layer_properties ( new_layer
, vp
) )
150 vik_layer_rename ( VIK_LAYER(new_layer
), vik_layer_interfaces
[type
]->name
);
153 g_object_unref ( G_OBJECT(new_layer
) ); /* cancel that */
160 /* returns TRUE if OK was pressed */
161 gboolean
vik_layer_properties ( VikLayer
*layer
, gpointer vp
)
163 if ( vik_layer_interfaces
[layer
->type
]->properties
)
164 return vik_layer_interfaces
[layer
->type
]->properties ( layer
, vp
);
165 return layer_properties_factory ( layer
, vp
);
168 void vik_layer_draw ( VikLayer
*l
, gpointer data
)
171 if ( vik_layer_interfaces
[l
->type
]->draw
)
172 vik_layer_interfaces
[l
->type
]->draw ( l
, data
);
175 void vik_layer_change_coord_mode ( VikLayer
*l
, VikCoordMode mode
)
177 if ( vik_layer_interfaces
[l
->type
]->change_coord_mode
)
178 vik_layer_interfaces
[l
->type
]->change_coord_mode ( l
, mode
);
181 VikLayer
*vik_layer_copy ( VikLayer
*vl
, gpointer vp
)
183 if ( vik_layer_interfaces
[vl
->type
]->copy
)
185 VikLayer
*rv
= vik_layer_interfaces
[vl
->type
]->copy ( vl
, vp
);
188 vik_layer_rename ( rv
, vl
->name
);
189 rv
->visible
= vl
->visible
;
198 static void layer_finalize ( VikLayer
*vl
)
200 g_assert ( vl
!= NULL
);
201 if ( vik_layer_interfaces
[vl
->type
]->free
)
202 vik_layer_interfaces
[vl
->type
]->free ( vl
);
205 G_OBJECT_CLASS(parent_class
)->finalize(G_OBJECT(vl
));
208 /* sublayer switching */
209 gboolean
vik_layer_sublayer_toggle_visible ( VikLayer
*l
, gint subtype
, gpointer sublayer
)
211 if ( vik_layer_interfaces
[l
->type
]->sublayer_toggle_visible
)
212 return vik_layer_interfaces
[l
->type
]->sublayer_toggle_visible ( l
, subtype
, sublayer
);
213 return TRUE
; /* if unknown, will always be visible */
216 void vik_layer_realize ( VikLayer
*l
, VikTreeview
*vt
, GtkTreeIter
*layer_iter
)
219 l
->iter
= *layer_iter
;
221 if ( vik_layer_interfaces
[l
->type
]->realize
)
222 vik_layer_interfaces
[l
->type
]->realize ( l
, vt
, layer_iter
);
225 void vik_layer_add_menu_items ( VikLayer
*l
, GtkMenu
*menu
, gpointer vlp
)
227 if ( vik_layer_interfaces
[l
->type
]->add_menu_items
)
228 vik_layer_interfaces
[l
->type
]->add_menu_items ( l
, menu
, vlp
);
231 gboolean
vik_layer_sublayer_add_menu_items ( VikLayer
*l
, GtkMenu
*menu
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
233 if ( vik_layer_interfaces
[l
->type
]->sublayer_add_menu_items
)
234 return vik_layer_interfaces
[l
->type
]->sublayer_add_menu_items ( l
, menu
, vlp
, subtype
, sublayer
, iter
);
239 const gchar
*vik_layer_sublayer_rename_request ( VikLayer
*l
, const gchar
*newname
, gpointer vlp
, gint subtype
, gpointer sublayer
, GtkTreeIter
*iter
)
241 if ( vik_layer_interfaces
[l
->type
]->sublayer_rename_request
)
242 return vik_layer_interfaces
[l
->type
]->sublayer_rename_request ( l
, newname
, vlp
, subtype
, sublayer
, iter
);
246 GdkPixbuf
*vik_layer_load_icon ( gint type
)
248 g_assert ( type
< VIK_LAYER_NUM_TYPES
);
249 if ( vik_layer_interfaces
[type
]->icon
)
250 return gdk_pixbuf_from_pixdata ( vik_layer_interfaces
[type
]->icon
, FALSE
, NULL
);
254 gboolean
vik_layer_set_param ( VikLayer
*layer
, guint16 id
, VikLayerParamData data
, gpointer vp
)
256 if ( vik_layer_interfaces
[layer
->type
]->set_param
)
257 return vik_layer_interfaces
[layer
->type
]->set_param ( layer
, id
, data
, vp
);
261 void vik_layer_post_read ( VikLayer
*layer
, gpointer vp
)
263 if ( vik_layer_interfaces
[layer
->type
]->post_read
)
264 vik_layer_interfaces
[layer
->type
]->post_read ( layer
, vp
);
267 static GtkWidget
*properties_widget_new_widget ( VikLayerParam
*param
, VikLayerParamData data
)
270 switch ( param
->widget_type
)
272 case VIK_LAYER_WIDGET_COLOR
:
273 if ( param
->type
== VIK_LAYER_PARAM_COLOR
)
274 rv
= gtk_color_button_new_with_color ( &(data
.c
) );
276 case VIK_LAYER_WIDGET_CHECKBUTTON
:
277 if ( param
->type
== VIK_LAYER_PARAM_BOOLEAN
)
279 //rv = gtk_check_button_new_with_label ( //param->title );
280 rv
= gtk_check_button_new ();
282 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(rv
), TRUE
);
285 case VIK_LAYER_WIDGET_COMBOBOX
:
287 if ( param
->type
== VIK_LAYER_PARAM_UINT
&& param
->widget_data
)
289 gchar
**pstr
= param
->widget_data
;
290 rv
= gtk_combo_box_new_text ();
292 gtk_combo_box_append_text ( GTK_COMBO_BOX ( rv
), *(pstr
++) );
293 if ( param
->extra_widget_data
) /* map of alternate uint values for options */
296 for ( i
= 0; ((const char **)param
->widget_data
)[i
]; i
++ )
297 if ( ((guint
*)param
->extra_widget_data
)[i
] == data
.u
)
299 gtk_combo_box_set_active ( GTK_COMBO_BOX(rv
), i
);
303 gtk_combo_box_set_active ( GTK_COMBO_BOX ( rv
), data
.u
);
307 case VIK_LAYER_WIDGET_RADIOGROUP
:
308 if ( param
->type
== VIK_LAYER_PARAM_UINT
&& param
->widget_data
)
310 rv
= vik_radio_group_new ( (const gchar
**) param
->widget_data
);
311 if ( param
->extra_widget_data
) /* map of alternate uint values for options */
314 for ( i
= 0; ((const char **)param
->widget_data
)[i
]; i
++ )
315 if ( ((guint
*)param
->extra_widget_data
)[i
] == data
.u
)
317 vik_radio_group_set_selected ( VIK_RADIO_GROUP(rv
), i
);
321 else if ( data
.u
) /* zero is already default */
322 vik_radio_group_set_selected ( VIK_RADIO_GROUP(rv
), data
.u
);
325 case VIK_LAYER_WIDGET_SPINBUTTON
:
326 if ( (param
->type
== VIK_LAYER_PARAM_DOUBLE
|| param
->type
== VIK_LAYER_PARAM_UINT
327 || param
->type
== VIK_LAYER_PARAM_INT
) && param
->widget_data
)
329 gdouble init_val
= (param
->type
== VIK_LAYER_PARAM_DOUBLE
) ? data
.d
: (param
->type
== VIK_LAYER_PARAM_UINT
? data
.u
: data
.i
);
330 VikLayerParamScale
*scale
= (VikLayerParamScale
*) param
->widget_data
;
331 rv
= gtk_spin_button_new ( GTK_ADJUSTMENT(gtk_adjustment_new( init_val
, scale
->min
, scale
->max
, scale
->step
, scale
->step
, scale
->step
)), scale
->step
, scale
->digits
);
334 case VIK_LAYER_WIDGET_ENTRY
:
335 if ( param
->type
== VIK_LAYER_PARAM_STRING
)
337 rv
= gtk_entry_new ();
338 gtk_entry_set_text ( GTK_ENTRY(rv
), data
.s
);
341 case VIK_LAYER_WIDGET_FILEENTRY
:
342 if ( param
->type
== VIK_LAYER_PARAM_STRING
)
344 rv
= vik_file_entry_new ();
345 vik_file_entry_set_filename ( VIK_FILE_ENTRY(rv
), data
.s
);
348 case VIK_LAYER_WIDGET_HSCALE
:
349 if ( (param
->type
== VIK_LAYER_PARAM_DOUBLE
|| param
->type
== VIK_LAYER_PARAM_UINT
350 || param
->type
== VIK_LAYER_PARAM_INT
) && param
->widget_data
)
352 gdouble init_val
= (param
->type
== VIK_LAYER_PARAM_DOUBLE
) ? data
.d
: (param
->type
== VIK_LAYER_PARAM_UINT
? data
.u
: data
.i
);
353 VikLayerParamScale
*scale
= (VikLayerParamScale
*) param
->widget_data
;
354 rv
= gtk_hscale_new_with_range ( scale
->min
, scale
->max
, scale
->step
);
355 gtk_scale_set_digits ( GTK_SCALE(rv
), scale
->digits
);
356 gtk_range_set_value ( GTK_RANGE(rv
), init_val
);
362 static VikLayerParamData
properties_widget_get_value ( GtkWidget
*widget
, VikLayerParam
*param
)
364 VikLayerParamData rv
;
365 switch ( param
->widget_type
)
367 case VIK_LAYER_WIDGET_COLOR
:
368 gtk_color_button_get_color ( GTK_COLOR_BUTTON(widget
), &(rv
.c
) );
370 case VIK_LAYER_WIDGET_CHECKBUTTON
:
371 rv
.b
= gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget
));
373 case VIK_LAYER_WIDGET_COMBOBOX
:
375 rv
.i
= gtk_combo_box_get_active ( GTK_COMBO_BOX(widget
) );
376 if ( rv
.i
== -1 ) rv
.i
= 0;
378 if ( param
->extra_widget_data
)
379 rv
.u
= ((guint
*)param
->extra_widget_data
)[rv
.u
];
382 case VIK_LAYER_WIDGET_RADIOGROUP
:
383 rv
.u
= vik_radio_group_get_selected(VIK_RADIO_GROUP(widget
));
384 if ( param
->extra_widget_data
)
385 rv
.u
= ((guint
*)param
->extra_widget_data
)[rv
.u
];
387 case VIK_LAYER_WIDGET_SPINBUTTON
:
388 if ( param
->type
== VIK_LAYER_PARAM_UINT
)
389 rv
.u
= gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(widget
) );
390 else if ( param
->type
== VIK_LAYER_PARAM_INT
)
391 rv
.i
= gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(widget
) );
393 rv
.d
= gtk_spin_button_get_value ( GTK_SPIN_BUTTON(widget
) );
395 case VIK_LAYER_WIDGET_ENTRY
:
396 rv
.s
= gtk_entry_get_text ( GTK_ENTRY(widget
) );
398 case VIK_LAYER_WIDGET_FILEENTRY
:
399 rv
.s
= vik_file_entry_get_filename ( VIK_FILE_ENTRY(widget
) );
401 case VIK_LAYER_WIDGET_HSCALE
:
402 if ( param
->type
== VIK_LAYER_PARAM_UINT
)
403 rv
.u
= (guint32
) gtk_range_get_value ( GTK_RANGE(widget
) );
404 else if ( param
->type
== VIK_LAYER_PARAM_INT
)
405 rv
.i
= (gint32
) gtk_range_get_value ( GTK_RANGE(widget
) );
407 rv
.d
= gtk_range_get_value ( GTK_RANGE(widget
) );
413 /* false if cancel, true if OK */
414 /* some would claim this wasn't written to be human-readable. */
415 static gboolean
layer_properties_factory ( VikLayer
*vl
, gpointer vp
)
417 VikLayerParam
*params
= vik_layer_interfaces
[vl
->type
]->params
;
418 guint16 params_count
= vik_layer_interfaces
[vl
->type
]->params_count
;
419 guint16 i
, j
, widget_count
= 0;
420 gboolean must_redraw
= FALSE
;
423 return TRUE
; /* no params == no options, so all is good */
425 for ( i
= 0; i
< params_count
; i
++ )
426 if ( params
[i
].group
!= VIK_LAYER_NOT_IN_PROPERTIES
)
429 if ( widget_count
== 0)
433 /* create widgets and titles; place in table */
434 GtkWidget
*dialog
= gtk_dialog_new_with_buttons ( "Layer Properties",
435 VIK_GTK_WINDOW_FROM_WIDGET(vp
),
436 GTK_DIALOG_MODAL
| GTK_DIALOG_DESTROY_WITH_PARENT
,
437 GTK_STOCK_CANCEL
, GTK_RESPONSE_REJECT
,
438 GTK_STOCK_OK
, GTK_RESPONSE_ACCEPT
, NULL
);
441 gchar
**groups
= vik_layer_interfaces
[vl
->type
]->params_groups
;
442 guint8 groups_count
= vik_layer_interfaces
[vl
->type
]->params_groups_count
;
444 GtkWidget
*table
= NULL
;
445 GtkWidget
**tables
= NULL
; /* for more than one group */
447 GtkWidget
*notebook
= NULL
;
448 GtkWidget
**widgets
= g_malloc ( sizeof(GtkWidget
*) * widget_count
);
450 if ( groups
&& groups_count
)
452 guint8 current_group
;
453 guint16 tab_widget_count
;
454 notebook
= gtk_notebook_new ();
455 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog
)->vbox
), notebook
, FALSE
, FALSE
, 0);
456 tables
= g_malloc ( sizeof(GtkWidget
*) * groups_count
);
457 for ( current_group
= 0; current_group
< groups_count
; current_group
++ )
459 tab_widget_count
= 0;
460 for ( j
= 0; j
< params_count
; j
++ )
461 if ( params
[j
].group
== current_group
)
464 if ( tab_widget_count
)
466 tables
[current_group
] = gtk_table_new ( tab_widget_count
, 1, FALSE
);
467 gtk_notebook_append_page ( GTK_NOTEBOOK(notebook
), tables
[current_group
], gtk_label_new(groups
[current_group
]) );
473 table
= gtk_table_new( widget_count
, 1, FALSE
);
474 gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog
)->vbox
), table
, FALSE
, FALSE
, 0);
477 for ( i
= 0, j
= 0; i
< params_count
; i
++ )
479 if ( params
[i
].group
!= VIK_LAYER_NOT_IN_PROPERTIES
)
482 table
= tables
[MAX(0, params
[i
].group
)]; /* round up NOT_IN_GROUP, that's not reasonable here */
484 widgets
[j
] = properties_widget_new_widget ( &(params
[i
]),
485 vik_layer_interfaces
[vl
->type
]->get_param ( vl
, i
) );
487 g_assert ( widgets
[j
] != NULL
);
489 gtk_table_attach ( GTK_TABLE(table
), gtk_label_new(params
[i
].title
), 0, 1, j
, j
+1, 0, 0, 0, 0 );
490 gtk_table_attach ( GTK_TABLE(table
), widgets
[j
], 1, 2, j
, j
+1, GTK_EXPAND
| GTK_FILL
, 0, 2, 2 );
495 gtk_widget_show_all ( dialog
);
497 resp
= gtk_dialog_run (GTK_DIALOG (dialog
));
498 if ( resp
== GTK_RESPONSE_ACCEPT
)
500 for ( i
= 0, j
= 0; i
< params_count
; i
++ )
502 if ( params
[i
].group
!= VIK_LAYER_NOT_IN_PROPERTIES
)
504 if ( vik_layer_interfaces
[vl
->type
]->set_param ( vl
, i
,
505 properties_widget_get_value ( widgets
[j
], &(params
[i
]) ), vp
) )
510 vik_layer_post_read ( vl
, vp
); /* update any gc's */
512 gtk_widget_destroy ( dialog
); /* hide before redrawing. */
516 vik_layer_emit_update ( vl
); /* if this is a new layer, it won't redraw twice because no on'es listening to this signal. */
517 return TRUE
; /* user clicked OK */
522 gtk_widget_destroy ( dialog
);