2 * viking -- GPS Data and Topo Analyzer, Explorer, and Manager
4 * Copyright (C) 2003-2005, Evan Battaglia <gtoevan@gmx.net>
5 * Copyright (C) 2008, Hein Ragas <viking@ragas.nl>
6 * Copyright (C) 2010, Rob Norris <rw_norris@hotmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 #include "thumbnails.h"
30 #include "garminsymbols.h"
31 #include "degrees_converters.h"
33 #include "documenters.h"
37 #include <glib/gi18n.h>
43 void a_dialog_msg ( GtkWindow *parent, gint type, const gchar *info, const gchar *extra )
45 GtkWidget *msgbox = gtk_message_dialog_new ( parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, info, extra );
46 gtk_dialog_run ( GTK_DIALOG(msgbox) );
47 gtk_widget_destroy ( msgbox );
50 gboolean a_dialog_goto_latlon ( GtkWindow *parent, struct LatLon *ll, const struct LatLon *old )
52 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Go to Lat/Lon"),
54 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
60 GtkWidget *latlabel, *lonlabel;
62 gchar *tmp_lat, *tmp_lon;
64 latlabel = gtk_label_new (_("Latitude:"));
65 lat = gtk_entry_new ();
66 tmp_lat = g_strdup_printf ( "%f", old->lat );
67 gtk_entry_set_text ( GTK_ENTRY(lat), tmp_lat );
70 lonlabel = gtk_label_new (_("Longitude:"));
71 lon = gtk_entry_new ();
72 tmp_lon = g_strdup_printf ( "%f", old->lon );
73 gtk_entry_set_text ( GTK_ENTRY(lon), tmp_lon );
76 gtk_widget_show ( latlabel );
77 gtk_widget_show ( lonlabel );
78 gtk_widget_show ( lat );
79 gtk_widget_show ( lon );
81 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel, FALSE, FALSE, 0);
82 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lat, FALSE, FALSE, 0);
83 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonlabel, FALSE, FALSE, 0);
84 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lon, FALSE, FALSE, 0);
86 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
88 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
90 ll->lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lat) ) );
91 ll->lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lon) ) );
92 gtk_widget_destroy ( dialog );
96 gtk_widget_destroy ( dialog );
100 gboolean a_dialog_goto_utm ( GtkWindow *parent, struct UTM *utm, const struct UTM *old )
102 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Go to UTM"),
104 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
110 GtkWidget *norlabel, *easlabel, *nor, *eas;
111 GtkWidget *zonehbox, *zonespin, *letterentry;
112 gchar *tmp_eas, *tmp_nor;
115 norlabel = gtk_label_new (_("Northing:"));
116 nor = gtk_entry_new ();
117 tmp_nor = g_strdup_printf("%ld", (long) old->northing );
118 gtk_entry_set_text ( GTK_ENTRY(nor), tmp_nor );
121 easlabel = gtk_label_new (_("Easting:"));
122 eas = gtk_entry_new ();
123 tmp_eas = g_strdup_printf("%ld", (long) old->easting );
124 gtk_entry_set_text ( GTK_ENTRY(eas), tmp_eas );
127 zonehbox = gtk_hbox_new ( FALSE, 0 );
128 gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( _("Zone:") ), FALSE, FALSE, 5 );
129 zonespin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( old->zone, 1, 60, 1, 5, 0 ), 1, 0 );
130 gtk_box_pack_start ( GTK_BOX(zonehbox), zonespin, TRUE, TRUE, 5 );
131 gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( _("Letter:") ), FALSE, FALSE, 5 );
132 letterentry = gtk_entry_new ();
133 gtk_entry_set_max_length ( GTK_ENTRY(letterentry), 1 );
134 gtk_entry_set_width_chars ( GTK_ENTRY(letterentry), 2 );
135 tmp_letter[0] = old->letter;
136 tmp_letter[1] = '\0';
137 gtk_entry_set_text ( GTK_ENTRY(letterentry), tmp_letter );
138 gtk_box_pack_start ( GTK_BOX(zonehbox), letterentry, FALSE, FALSE, 5 );
140 gtk_widget_show ( norlabel );
141 gtk_widget_show ( easlabel );
142 gtk_widget_show ( nor );
143 gtk_widget_show ( eas );
145 gtk_widget_show_all ( zonehbox );
147 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), norlabel, FALSE, FALSE, 0);
148 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), nor, FALSE, FALSE, 0);
149 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), easlabel, FALSE, FALSE, 0);
150 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), eas, FALSE, FALSE, 0);
151 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), zonehbox, FALSE, FALSE, 0);
153 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
155 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
158 utm->northing = atof ( gtk_entry_get_text ( GTK_ENTRY(nor) ) );
159 utm->easting = atof ( gtk_entry_get_text ( GTK_ENTRY(eas) ) );
160 utm->zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(zonespin) );
161 letter = gtk_entry_get_text ( GTK_ENTRY(letterentry) );
163 utm->letter = toupper(*letter);
164 gtk_widget_destroy ( dialog );
168 gtk_widget_destroy ( dialog );
172 void a_dialog_response_accept ( GtkDialog *dialog )
174 gtk_dialog_response ( dialog, GTK_RESPONSE_ACCEPT );
177 static void symbol_entry_changed_cb(GtkWidget *combo, GtkListStore *store)
182 if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(combo), &iter))
185 gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
186 /* Note: symm is NULL when "(none)" is select (first cell is empty) */
187 gtk_widget_set_tooltip_text(combo, sym);
191 /* Specify if a new waypoint or not */
192 /* If a new waypoint then it uses the default_name for the suggested name allowing the user to change it.
193 The name to use is returned
194 When an existing waypoint the default name is shown but is not allowed to be changed and NULL is returned
196 /* todo: less on this side, like add track */
197 gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *vtl, VikWaypoint *wp, VikCoordMode coord_mode, gboolean is_new, gboolean *updated )
199 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Waypoint Properties"),
201 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
208 GtkWidget *latlabel, *lonlabel, *namelabel, *latentry, *lonentry, *altentry, *altlabel, *nameentry=NULL;
209 GtkWidget *commentlabel, *commententry, *descriptionlabel, *descriptionentry, *imagelabel, *imageentry, *symbollabel, *symbolentry;
212 gchar *lat, *lon, *alt;
214 vik_coord_to_latlon ( &(wp->coord), &ll );
216 lat = g_strdup_printf ( "%f", ll.lat );
217 lon = g_strdup_printf ( "%f", ll.lon );
218 vik_units_height_t height_units = a_vik_get_units_height ();
219 switch (height_units) {
220 case VIK_UNITS_HEIGHT_METRES:
221 alt = g_strdup_printf ( "%f", wp->altitude );
223 case VIK_UNITS_HEIGHT_FEET:
224 alt = g_strdup_printf ( "%f", VIK_METERS_TO_FEET(wp->altitude) );
227 alt = g_strdup_printf ( "%f", wp->altitude );
228 g_critical("Houston, we've had a problem. height=%d", height_units);
233 namelabel = gtk_label_new (_("Name:"));
234 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), namelabel, FALSE, FALSE, 0);
237 // New waypoint, so name is still changeable
238 nameentry = gtk_entry_new ();
240 gtk_entry_set_text( GTK_ENTRY(nameentry), default_name );
241 g_signal_connect_swapped ( nameentry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
244 // Existing waypoint - so can not change the name this way - but at least can see it
246 nameentry = gtk_label_new ( default_name );
249 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), nameentry, FALSE, FALSE, 0);
251 latlabel = gtk_label_new (_("Latitude:"));
252 latentry = gtk_entry_new ();
253 gtk_entry_set_text ( GTK_ENTRY(latentry), lat );
256 lonlabel = gtk_label_new (_("Longitude:"));
257 lonentry = gtk_entry_new ();
258 gtk_entry_set_text ( GTK_ENTRY(lonentry), lon );
261 altlabel = gtk_label_new (_("Altitude:"));
262 altentry = gtk_entry_new ();
263 gtk_entry_set_text ( GTK_ENTRY(altentry), alt );
266 commentlabel = gtk_label_new (_("Comment:"));
267 commententry = gtk_entry_new ();
269 // Auto put in some kind of 'name' as a comment if one previously 'goto'ed this exact location
270 cmt = a_vik_goto_get_search_string_for_this_place(VIK_WINDOW(parent));
272 gtk_entry_set_text(GTK_ENTRY(commententry), cmt);
274 descriptionlabel = gtk_label_new (_("Description:"));
275 descriptionentry = gtk_entry_new ();
277 imagelabel = gtk_label_new (_("Image:"));
278 imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN);
282 symbollabel = gtk_label_new (_("Symbol:"));
285 store = gtk_list_store_new(3, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING);
286 symbolentry = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
287 gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(symbolentry), 6);
289 g_signal_connect(symbolentry, "changed", G_CALLBACK(symbol_entry_changed_cb), store);
290 gtk_list_store_append (store, &iter);
291 gtk_list_store_set (store, &iter, 0, NULL, 1, NULL, 2, _("(none)"), -1);
292 a_populate_sym_list(store);
294 r = gtk_cell_renderer_pixbuf_new ();
295 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE);
296 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "pixbuf", 1, NULL);
298 r = gtk_cell_renderer_text_new ();
299 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE);
300 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "text", 2, NULL);
302 if ( !is_new && wp->symbol ) {
305 for (ok = gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &iter ); ok; ok = gtk_tree_model_iter_next ( GTK_TREE_MODEL(store), &iter)) {
306 gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
307 if (sym && !strcmp(sym, wp->symbol)) {
314 // Ensure is it a valid symbol in the given symbol set (large vs small)
315 // Not all symbols are available in both
316 // The check prevents a Gtk Critical message
318 gtk_combo_box_set_active_iter(GTK_COMBO_BOX(symbolentry), &iter);
322 if ( !is_new && wp->comment )
323 gtk_entry_set_text ( GTK_ENTRY(commententry), wp->comment );
325 if ( !is_new && wp->description )
326 gtk_entry_set_text ( GTK_ENTRY(descriptionentry), wp->description );
328 if ( !is_new && wp->image )
329 vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), wp->image );
332 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel, FALSE, FALSE, 0);
333 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latentry, FALSE, FALSE, 0);
334 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonlabel, FALSE, FALSE, 0);
335 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonentry, FALSE, FALSE, 0);
336 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altlabel, FALSE, FALSE, 0);
337 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altentry, FALSE, FALSE, 0);
338 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commentlabel, FALSE, FALSE, 0);
339 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commententry, FALSE, FALSE, 0);
340 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionlabel, FALSE, FALSE, 0);
341 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionentry, FALSE, FALSE, 0);
342 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imagelabel, FALSE, FALSE, 0);
343 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imageentry, FALSE, FALSE, 0);
344 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), symbollabel, FALSE, FALSE, 0);
345 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(symbolentry), FALSE, FALSE, 0);
347 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
349 gtk_widget_show_all ( gtk_dialog_get_content_area(GTK_DIALOG(dialog)) );
352 // Shift left<->right to try not to obscure the waypoint.
353 trw_layer_dialog_shift ( vtl, GTK_WINDOW(dialog), &(wp->coord), FALSE );
356 while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
360 if ( strlen((gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) )) == 0 ) /* TODO: other checks (isalpha or whatever ) */
361 a_dialog_info_msg ( parent, _("Please enter a name for the waypoint.") );
363 // NB: No check for unique names - this allows generation of same named entries.
364 gchar *entered_name = g_strdup ( (gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) ) );
367 ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
368 ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
369 vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
370 // Always store in metres
371 switch (height_units) {
372 case VIK_UNITS_HEIGHT_METRES:
373 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
375 case VIK_UNITS_HEIGHT_FEET:
376 wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
379 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
380 g_critical("Houston, we've had a problem. height=%d", height_units);
382 vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
383 vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
384 vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
385 if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
386 a_thumbnails_create ( wp->image );
388 GtkTreeIter iter, first;
389 gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
390 if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
391 vik_waypoint_set_symbol ( wp, NULL );
394 gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
395 vik_waypoint_set_symbol ( wp, sym );
399 gtk_widget_destroy ( dialog );
405 ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
406 ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
407 vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
408 switch (height_units) {
409 case VIK_UNITS_HEIGHT_METRES:
410 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
412 case VIK_UNITS_HEIGHT_FEET:
413 wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ));
416 wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
417 g_critical("Houston, we've had a problem. height=%d", height_units);
419 if ( (! wp->comment) || strcmp ( wp->comment, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ) != 0 )
420 vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
421 if ( (! wp->description) || strcmp ( wp->description, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) ) != 0 )
422 vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) );
423 if ( (! wp->image) || strcmp ( wp->image, vik_file_entry_get_filename ( VIK_FILE_ENTRY ( imageentry ) ) ) != 0 )
425 vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
426 if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
427 a_thumbnails_create ( wp->image );
431 GtkTreeIter iter, first;
432 gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
433 if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
434 vik_waypoint_set_symbol ( wp, NULL );
437 gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
438 vik_waypoint_set_symbol ( wp, sym );
443 gtk_widget_destroy ( dialog );
449 gtk_widget_destroy ( dialog );
453 static void get_selected_foreach_func(GtkTreeModel *model,
460 gtk_tree_model_get (model, iter, 0, &name, -1);
461 *list = g_list_prepend(*list, name);
464 GList *a_dialog_select_from_list ( GtkWindow *parent, GList *names, gboolean multiple_selection_allowed, const gchar *title, const gchar *msg )
467 GtkCellRenderer *renderer;
470 GtkWidget *dialog = gtk_dialog_new_with_buttons (title,
472 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
478 /* When something is selected then OK */
479 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
480 GtkWidget *response_w = NULL;
481 #if GTK_CHECK_VERSION (2, 20, 0)
482 /* Default to not apply - as initially nothing is selected! */
483 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_REJECT );
485 GtkListStore *store = gtk_list_store_new(1, G_TYPE_STRING);
487 GtkWidget *scrolledwindow;
489 GList *runner = names;
492 gtk_list_store_append(store, &iter);
493 gtk_list_store_set(store, &iter, 0, runner->data, -1);
494 runner = g_list_next(runner);
497 view = gtk_tree_view_new();
498 renderer = gtk_cell_renderer_text_new();
499 // Use the column header to display the message text,
500 // this makes the overall widget allocation simple as treeview takes up all the space
501 GtkTreeViewColumn *column;
502 column = gtk_tree_view_column_new_with_attributes (msg, renderer, "text", 0, NULL );
503 gtk_tree_view_column_set_sort_column_id (column, 0);
504 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
506 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
507 gtk_tree_selection_set_mode( gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
508 multiple_selection_allowed ? GTK_SELECTION_MULTIPLE : GTK_SELECTION_BROWSE );
509 g_object_unref(store);
511 scrolledwindow = gtk_scrolled_window_new ( NULL, NULL );
512 gtk_scrolled_window_set_policy ( GTK_SCROLLED_WINDOW(scrolledwindow), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC );
513 gtk_container_add ( GTK_CONTAINER(scrolledwindow), view );
515 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), scrolledwindow, TRUE, TRUE, 0 );
516 // Ensure a reasonable number of items are shown, but let the width be automatically sized
517 gtk_widget_set_size_request ( dialog, -1, 400) ;
519 gtk_widget_show_all ( dialog );
522 gtk_widget_grab_focus ( response_w );
524 while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
527 GtkTreeSelection *selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
528 gtk_tree_selection_selected_foreach(selection, get_selected_foreach_func, &names);
531 gtk_widget_destroy ( dialog );
534 a_dialog_error_msg(parent, _("Nothing was selected"));
536 gtk_widget_destroy ( dialog );
540 gchar *a_dialog_new_track ( GtkWindow *parent, GHashTable *tracks, gchar *default_name, gboolean is_route )
542 GtkWidget *dialog = gtk_dialog_new_with_buttons ( is_route ? _("Add Route") : _("Add Track"),
544 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
550 GtkWidget *label = gtk_label_new ( is_route ? _("Route Name:") : _("Track Name:") );
551 GtkWidget *entry = gtk_entry_new ();
554 gtk_entry_set_text ( GTK_ENTRY(entry), default_name );
556 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), label, FALSE, FALSE, 0);
557 gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), entry, FALSE, FALSE, 0);
559 g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
561 gtk_widget_show ( label );
562 gtk_widget_show ( entry );
564 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
566 while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
568 const gchar *constname = gtk_entry_get_text ( GTK_ENTRY(entry) );
569 if ( *constname == '\0' )
570 a_dialog_info_msg ( parent, _("Please enter a name for the track.") );
572 gchar *name = g_strdup ( constname );
573 gtk_widget_destroy ( dialog );
577 gtk_widget_destroy ( dialog );
581 /* creates a vbox full of labels */
582 GtkWidget *a_dialog_create_label_vbox ( gchar **texts, int label_count )
584 GtkWidget *vbox, *label;
586 vbox = gtk_vbox_new( TRUE, 3 );
588 for ( i = 0; i < label_count; i++ )
590 label = gtk_label_new(NULL);
591 gtk_label_set_markup ( GTK_LABEL(label), _(texts[i]) );
592 gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, TRUE, 5 );
597 gboolean a_dialog_yes_or_no ( GtkWindow *parent, const gchar *message, const gchar *extra )
600 dia = gtk_message_dialog_new ( parent,
601 GTK_DIALOG_DESTROY_WITH_PARENT,
602 GTK_MESSAGE_QUESTION,
606 if ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_YES )
608 gtk_widget_destroy ( dia );
613 gtk_widget_destroy ( dia );
618 static void zoom_spin_changed ( GtkSpinButton *spin, GtkWidget *pass_along[3] )
620 if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(pass_along[2]) ) )
621 gtk_spin_button_set_value (
622 GTK_SPIN_BUTTON(pass_along[GTK_WIDGET(spin) == pass_along[0] ? 1 : 0]),
623 gtk_spin_button_get_value ( spin ) );
626 gboolean a_dialog_custom_zoom ( GtkWindow *parent, gdouble *xmpp, gdouble *ympp )
628 GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Zoom Factors..."),
630 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
636 GtkWidget *table, *label, *xlabel, *xspin, *ylabel, *yspin, *samecheck;
637 GtkWidget *pass_along[3];
639 table = gtk_table_new ( 4, 2, FALSE );
640 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
642 label = gtk_label_new ( _("Zoom factor (in meters per pixel):") );
643 xlabel = gtk_label_new ( _("X (easting): "));
644 ylabel = gtk_label_new ( _("Y (northing): "));
646 pass_along[0] = xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *xmpp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
647 pass_along[1] = yspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *ympp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 0 ), 1, 8 );
649 pass_along[2] = samecheck = gtk_check_button_new_with_label ( _("X and Y zoom factors must be equal") );
650 /* TODO -- same factor */
651 /* samecheck = gtk_check_button_new_with_label ( "Same x/y zoom factor" ); */
653 if ( *xmpp == *ympp )
654 gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(samecheck), TRUE );
656 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
657 gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 1, 2 );
658 gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 1, 2 );
659 gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 2, 3 );
660 gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 2, 3 );
661 gtk_table_attach_defaults ( GTK_TABLE(table), samecheck, 0, 2, 3, 4 );
663 gtk_widget_show_all ( table );
665 g_signal_connect ( G_OBJECT(xspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
666 g_signal_connect ( G_OBJECT(yspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
668 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
670 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
672 *xmpp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
673 *ympp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
674 gtk_widget_destroy ( dialog );
677 gtk_widget_destroy ( dialog );
681 static void split_spin_focused ( GtkSpinButton *spin, GtkWidget *pass_along[1] )
683 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(pass_along[0]), 1);
686 gboolean a_dialog_time_threshold ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint *thr )
688 GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text,
690 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
696 GtkWidget *table, *t1, *t2, *t3, *t4, *spin, *label;
697 GtkWidget *pass_along[1];
699 table = gtk_table_new ( 4, 2, FALSE );
700 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
702 label = gtk_label_new (label_text);
704 t1 = gtk_radio_button_new_with_label ( NULL, _("1 min") );
705 t2 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t1), _("1 hour") );
706 t3 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t2), _("1 day") );
707 t4 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t3), _("Custom (in minutes):") );
711 spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *thr, 0, 65536, 1, 5, 0 ), 1, 0 );
713 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
714 gtk_table_attach_defaults ( GTK_TABLE(table), t1, 0, 1, 1, 2 );
715 gtk_table_attach_defaults ( GTK_TABLE(table), t2, 0, 1, 2, 3 );
716 gtk_table_attach_defaults ( GTK_TABLE(table), t3, 0, 1, 3, 4 );
717 gtk_table_attach_defaults ( GTK_TABLE(table), t4, 0, 1, 4, 5 );
718 gtk_table_attach_defaults ( GTK_TABLE(table), spin, 1, 2, 4, 5 );
720 gtk_widget_show_all ( table );
722 g_signal_connect ( G_OBJECT(spin), "grab-focus", G_CALLBACK(split_spin_focused), pass_along );
724 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
726 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
728 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t1))) {
730 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t2))) {
732 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t3))) {
734 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t4))) {
735 *thr = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
737 gtk_widget_destroy ( dialog );
740 gtk_widget_destroy ( dialog );
745 * Dialog to return a positive number via a spinbox within the supplied limits
746 * A return value of zero indicates the dialog was cancelled
748 guint a_dialog_get_positive_number ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint default_num, guint min, guint max, guint step )
750 GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text,
752 GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
758 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
759 GtkWidget *response_w = NULL;
760 #if GTK_CHECK_VERSION (2, 20, 0)
761 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
764 GtkWidget *table, *spin, *label;
765 guint result = default_num;
767 table = gtk_table_new ( 2, 1, FALSE );
768 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), table, TRUE, TRUE, 0 );
770 label = gtk_label_new (label_text);
771 spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( default_num, min, max, step, 5, 0 ), 1, 0 );
773 gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 1, 0, 1 );
774 gtk_table_attach_defaults ( GTK_TABLE(table), spin, 0, 1, 1, 2 );
777 gtk_widget_grab_focus ( response_w );
779 gtk_widget_show_all ( table );
781 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
783 result = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
784 gtk_widget_destroy ( dialog );
789 gtk_widget_destroy ( dialog );
793 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 24)
794 static void about_url_hook (GtkAboutDialog *about,
798 open_url (GTK_WINDOW(about), link);
801 static void about_email_hook (GtkAboutDialog *about,
805 new_email (GTK_WINDOW(about), email);
809 void a_dialog_about ( GtkWindow *parent )
811 const gchar *program_name = PACKAGE_NAME;
812 const gchar *version = VIKING_VERSION;
813 const gchar *website = VIKING_URL;
814 const gchar *copyright = "2003-2008, Evan Battaglia\n2008-2010, Viking's contributors";
815 const gchar *comments = _("GPS Data and Topo Analyzer, Explorer, and Manager.");
816 const gchar *license = _("This program is free software; you can redistribute it and/or modify "
817 "it under the terms of the GNU General Public License as published by "
818 "the Free Software Foundation; either version 2 of the License, or "
819 "(at your option) any later version."
821 "This program is distributed in the hope that it will be useful, "
822 "but WITHOUT ANY WARRANTY; without even the implied warranty of "
823 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the "
824 "GNU General Public License for more details."
826 "You should have received a copy of the GNU General Public License "
827 "along with this program; if not, write to the Free Software "
828 "Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA");
830 // Newer versions of GTK 'just work', calling gtk_show_uri() on the URL or email and opens up the appropriate program
831 // This is the old method:
832 #if (GTK_MAJOR_VERSION == 2 && GTK_MINOR_VERSION < 24)
833 gtk_about_dialog_set_url_hook (about_url_hook, NULL, NULL);
834 gtk_about_dialog_set_email_hook (about_email_hook, NULL, NULL);
836 gtk_show_about_dialog (parent,
837 /* TODO do not set program-name and correctly set info for g_get_application_name */
838 "program-name", program_name,
841 "comments", comments,
842 "copyright", copyright,
844 "wrap-license", TRUE,
845 /* logo automatically retrieved via gtk_window_get_default_icon_list */
847 "documenters", DOCUMENTERS,
848 "translator-credits", _("Translation is coordinated on http://launchpad.net/viking"),
852 gboolean a_dialog_map_n_zoom(GtkWindow *parent, gchar *mapnames[], gint default_map, gchar *zoom_list[], gint default_zoom, gint *selected_map, gint *selected_zoom)
856 GtkWidget *dialog = gtk_dialog_new_with_buttons ( _("Download along track"), parent, 0, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL );
857 gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
858 GtkWidget *response_w = NULL;
859 #if GTK_CHECK_VERSION (2, 20, 0)
860 response_w = gtk_dialog_get_widget_for_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT );
863 GtkWidget *map_label = gtk_label_new(_("Map type:"));
864 GtkWidget *map_combo = vik_combo_box_text_new();
865 for (s = mapnames; *s; s++)
866 vik_combo_box_text_append (GTK_COMBO_BOX(map_combo), *s);
867 gtk_combo_box_set_active (GTK_COMBO_BOX(map_combo), default_map);
869 GtkWidget *zoom_label = gtk_label_new(_("Zoom level:"));
870 GtkWidget *zoom_combo = vik_combo_box_text_new();
871 for (s = zoom_list; *s; s++)
872 vik_combo_box_text_append (GTK_COMBO_BOX(zoom_combo), *s);
873 gtk_combo_box_set_active (GTK_COMBO_BOX(zoom_combo), default_zoom);
875 GtkTable *box = GTK_TABLE(gtk_table_new(2, 2, FALSE));
876 gtk_table_attach_defaults(box, map_label, 0, 1, 0, 1);
877 gtk_table_attach_defaults(box, map_combo, 1, 2, 0, 1);
878 gtk_table_attach_defaults(box, zoom_label, 0, 1, 1, 2);
879 gtk_table_attach_defaults(box, zoom_combo, 1, 2, 1, 2);
881 gtk_box_pack_start ( GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(box), FALSE, FALSE, 5 );
884 gtk_widget_grab_focus ( response_w );
886 gtk_widget_show_all ( dialog );
887 if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) != GTK_RESPONSE_ACCEPT ) {
888 gtk_widget_destroy(dialog);
892 *selected_map = gtk_combo_box_get_active(GTK_COMBO_BOX(map_combo));
893 *selected_zoom = gtk_combo_box_get_active(GTK_COMBO_BOX(zoom_combo));
895 gtk_widget_destroy(dialog);
900 * Display a dialog presenting the license of a map.
901 * Allow to read the license by launching a web browser.
903 void a_dialog_license ( GtkWindow *parent, const gchar *map, const gchar *license, const gchar *url)
905 GtkWidget *dialog = gtk_message_dialog_new (parent,
906 GTK_DIALOG_DESTROY_WITH_PARENT,
909 _("The map data is licensed: %s."),
911 gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
912 _("The data provided by '<b>%s</b>' are licensed under the following license: <b>%s</b>.\n"
913 "Please, read the license before continuing."),
915 #define RESPONSE_OPEN_LICENSE 600
917 gtk_dialog_add_button (GTK_DIALOG (dialog), _("Open license"), RESPONSE_OPEN_LICENSE);
921 response = gtk_dialog_run (GTK_DIALOG (dialog));
922 if (response == RESPONSE_OPEN_LICENSE) {
923 open_url (parent, url);
925 } while (response != GTK_RESPONSE_DELETE_EVENT && response != GTK_RESPONSE_OK);
926 gtk_widget_destroy (dialog);