]> git.street.me.uk Git - andy/viking.git/blob - src/dialog.c
fix warnings and remove some debug output
[andy/viking.git] / src / dialog.c
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"
23 #include "thumbnails.h"
24 #include "garminsymbols.h"
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 void a_dialog_msg ( GtkWindow *parent, gint type, const gchar *info, const gchar *extra )
31 {
32   GtkWidget *msgbox = gtk_message_dialog_new ( parent, GTK_DIALOG_DESTROY_WITH_PARENT, type, GTK_BUTTONS_OK, info, extra );
33   gtk_dialog_run ( GTK_DIALOG(msgbox) );
34   gtk_widget_destroy ( msgbox );
35 }
36
37 gboolean a_dialog_goto_latlon ( GtkWindow *parent, struct LatLon *ll, const struct LatLon *old )
38 {
39   GtkWidget *dialog = gtk_dialog_new_with_buttons ("Go to Lat/Lon",
40                                                   parent,
41                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
42                                                   GTK_STOCK_CANCEL,
43                                                   GTK_RESPONSE_REJECT,
44                                                   GTK_STOCK_OK,
45                                                   GTK_RESPONSE_ACCEPT,
46                                                   NULL);
47   GtkWidget *latlabel, *lonlabel;
48   GtkWidget *lat, *lon;
49   gchar *tmp_lat, *tmp_lon;
50
51   latlabel = gtk_label_new ("Latitude:");
52   lat = gtk_entry_new ();
53   tmp_lat = g_strdup_printf ( "%f", old->lat );
54   gtk_entry_set_text ( GTK_ENTRY(lat), tmp_lat );
55   g_free ( tmp_lat );
56
57   lonlabel = gtk_label_new ("Longitude:");
58   lon = gtk_entry_new ();
59   tmp_lon = g_strdup_printf ( "%f", old->lon );
60   gtk_entry_set_text ( GTK_ENTRY(lon), tmp_lon );
61   g_free ( tmp_lon );
62
63   gtk_widget_show ( latlabel );
64   gtk_widget_show ( lonlabel );
65   gtk_widget_show ( lat );
66   gtk_widget_show ( lon );
67
68   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), latlabel,  FALSE, FALSE, 0);
69   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lat, FALSE, FALSE, 0);
70   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonlabel,  FALSE, FALSE, 0);
71   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lon,  FALSE, FALSE, 0);
72
73   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
74   {
75     ll->lat = atof ( gtk_entry_get_text ( GTK_ENTRY(lat) ) );
76     ll->lon = atof ( gtk_entry_get_text ( GTK_ENTRY(lon) ) );
77     gtk_widget_destroy ( dialog );
78     return TRUE;
79   }
80
81   gtk_widget_destroy ( dialog );
82   return FALSE;
83 }
84
85 gboolean a_dialog_goto_utm ( GtkWindow *parent, struct UTM *utm, const struct UTM *old )
86 {
87   GtkWidget *dialog = gtk_dialog_new_with_buttons ("Go to Lat/Lon",
88                                                   parent,
89                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
90                                                   GTK_STOCK_CANCEL,
91                                                   GTK_RESPONSE_REJECT,
92                                                   GTK_STOCK_OK,
93                                                   GTK_RESPONSE_ACCEPT,
94                                                   NULL);
95   GtkWidget *norlabel, *easlabel, *nor, *eas;
96   GtkWidget *zonehbox, *zonespin, *letterentry;
97   gchar *tmp_eas, *tmp_nor;
98   gchar tmp_letter[2];
99
100   norlabel = gtk_label_new ("Northing:");
101   nor = gtk_entry_new ();
102   tmp_nor = g_strdup_printf("%ld", (long) old->northing );
103   gtk_entry_set_text ( GTK_ENTRY(nor), tmp_nor );
104   g_free ( tmp_nor );
105
106   easlabel = gtk_label_new ("Easting:");
107   eas = gtk_entry_new ();
108   tmp_eas = g_strdup_printf("%ld", (long) old->easting );
109   gtk_entry_set_text ( GTK_ENTRY(eas), tmp_eas );
110   g_free ( tmp_eas );
111
112   zonehbox = gtk_hbox_new ( FALSE, 0 );
113   gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( "Zone:" ), FALSE, FALSE, 5 );
114   zonespin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( old->zone, 1, 60, 1, 5, 5 ), 1, 0 );
115   gtk_box_pack_start ( GTK_BOX(zonehbox), zonespin, TRUE, TRUE, 5 );
116   gtk_box_pack_start ( GTK_BOX(zonehbox), gtk_label_new ( "Letter:" ), FALSE, FALSE, 5 );
117   letterentry = gtk_entry_new ();
118   gtk_entry_set_max_length ( GTK_ENTRY(letterentry), 1 );
119   gtk_entry_set_width_chars ( GTK_ENTRY(letterentry), 2 );
120   tmp_letter[0] = old->letter;
121   tmp_letter[1] = '\0';
122   gtk_entry_set_text ( GTK_ENTRY(letterentry), tmp_letter );
123   gtk_box_pack_start ( GTK_BOX(zonehbox), letterentry, FALSE, FALSE, 5 );
124
125   gtk_widget_show ( norlabel );
126   gtk_widget_show ( easlabel );
127   gtk_widget_show ( nor );
128   gtk_widget_show ( eas );
129
130   gtk_widget_show_all ( zonehbox );
131
132   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), norlabel, FALSE, FALSE, 0);
133   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), nor, FALSE, FALSE, 0);
134   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), easlabel,  FALSE, FALSE, 0);
135   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), eas,  FALSE, FALSE, 0);
136   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), zonehbox,  FALSE, FALSE, 0);
137
138   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
139   {
140     const gchar *letter;
141     utm->northing = atof ( gtk_entry_get_text ( GTK_ENTRY(nor) ) );
142     utm->easting = atof ( gtk_entry_get_text ( GTK_ENTRY(eas) ) );
143     utm->zone = gtk_spin_button_get_value_as_int ( GTK_SPIN_BUTTON(zonespin) );
144     letter = gtk_entry_get_text ( GTK_ENTRY(letterentry) );
145     if (*letter)
146        utm->letter = toupper(*letter);
147     gtk_widget_destroy ( dialog );
148     return TRUE;
149   }
150
151   gtk_widget_destroy ( dialog );
152   return FALSE;
153 }
154
155 void a_dialog_response_accept ( GtkDialog *dialog )
156 {
157   gtk_dialog_response ( dialog, GTK_RESPONSE_ACCEPT );
158 }
159
160 /* todo: less on this side, like add track */
161 gboolean a_dialog_new_waypoint ( GtkWindow *parent, gchar **dest, VikWaypoint *wp, GHashTable *waypoints, VikCoordMode coord_mode )
162 {
163   GtkWidget *dialog = gtk_dialog_new_with_buttons ("Create",
164                                                    parent,
165                                                    GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
166                                                    GTK_STOCK_CANCEL,
167                                                    GTK_RESPONSE_REJECT,
168                                                    GTK_STOCK_OK,
169                                                    GTK_RESPONSE_ACCEPT,
170                                                    NULL);
171   struct LatLon ll;
172   GtkWidget *latlabel, *lonlabel, *namelabel, *latentry, *lonentry, *altentry, *altlabel, *nameentry, *commentlabel, 
173     *commententry, *imagelabel, *imageentry, *symbollabel, *symbolentry;
174   GtkListStore *store;
175
176
177
178
179   gchar *lat, *lon, *alt;
180
181   vik_coord_to_latlon ( &(wp->coord), &ll );
182
183   lat = g_strdup_printf ( "%f", ll.lat );
184   lon = g_strdup_printf ( "%f", ll.lon );
185   alt = g_strdup_printf ( "%f", wp->altitude );
186
187   if ( dest != NULL )
188   {
189     namelabel = gtk_label_new ("Name:");
190     nameentry = gtk_entry_new ();
191     g_signal_connect_swapped ( nameentry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
192     gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), namelabel, FALSE, FALSE, 0);
193     gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), nameentry, FALSE, FALSE, 0);
194   }
195
196   latlabel = gtk_label_new ("Latitude:");
197   latentry = gtk_entry_new ();
198   gtk_entry_set_text ( GTK_ENTRY(latentry), lat );
199   g_free ( lat );
200
201   lonlabel = gtk_label_new ("Longitude:");
202   lonentry = gtk_entry_new ();
203   gtk_entry_set_text ( GTK_ENTRY(lonentry), lon );
204   g_free ( lon );
205
206   altlabel = gtk_label_new ("Altitude:");
207   altentry = gtk_entry_new ();
208   gtk_entry_set_text ( GTK_ENTRY(altentry), alt );
209   g_free ( alt );
210
211   commentlabel = gtk_label_new ("Comment:");
212   commententry = gtk_entry_new ();
213
214   imagelabel = gtk_label_new ("Image:");
215   imageentry = vik_file_entry_new ();
216
217   {
218     GtkCellRenderer *r;
219     symbollabel = gtk_label_new ("Symbol:");
220     GtkTreeIter iter;
221
222     store = gtk_list_store_new(2, G_TYPE_STRING, GDK_TYPE_PIXBUF);
223     symbolentry = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store));
224     gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(symbolentry), 3);
225     gtk_list_store_append (store, &iter);
226     gtk_list_store_set (store, &iter, 0, "(none)", 1, NULL, -1);
227     a_populate_sym_list(store);
228
229     r = gtk_cell_renderer_pixbuf_new ();
230     gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE);
231     gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "pixbuf", 1, NULL);
232
233     if ( dest == NULL && wp->symbol ) {
234       gboolean ok;
235       gchar *sym;
236       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)) {
237         gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
238         if (!strcmp(sym, wp->symbol)) {
239           g_free(sym);
240           break;
241         } else {
242           g_free(sym);
243         }
244       }
245       gtk_combo_box_set_active_iter(GTK_COMBO_BOX(symbolentry), &iter);
246     }
247   }
248
249   if ( dest == NULL && wp->comment )
250     gtk_entry_set_text ( GTK_ENTRY(commententry), wp->comment );
251
252   if ( dest == NULL && wp->image )
253     vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), wp->image );
254
255
256   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), latlabel, FALSE, FALSE, 0);
257   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), latentry, FALSE, FALSE, 0);
258   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonlabel, FALSE, FALSE, 0);
259   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), lonentry, FALSE, FALSE, 0);
260   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), altlabel, FALSE, FALSE, 0);
261   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), altentry, FALSE, FALSE, 0);
262   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), commentlabel, FALSE, FALSE, 0);
263   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), commententry, FALSE, FALSE, 0);
264   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), imagelabel, FALSE, FALSE, 0);
265   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), imageentry, FALSE, FALSE, 0);
266   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), symbollabel, FALSE, FALSE, 0);
267   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), GTK_WIDGET(symbolentry), FALSE, FALSE, 0);
268
269   gtk_widget_show_all ( GTK_DIALOG(dialog)->vbox );
270
271   while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
272   {
273     if ( dest )
274     {
275       const gchar *constname = gtk_entry_get_text ( GTK_ENTRY(nameentry) );
276       if ( strlen(constname) == 0 ) /* TODO: other checks (isalpha or whatever ) */
277         a_dialog_info_msg ( parent, "Please enter a name for the waypoint." );
278       else {
279         int i;
280         gchar *name = g_strdup ( constname );
281
282         for ( i = strlen ( name ) - 1; i >= 0; i-- )
283           name[i] = toupper(name[i]); /* all caps for stardandization */
284
285         if ( g_hash_table_lookup ( waypoints, name ) && !a_dialog_overwrite ( parent, "The waypoint \"%s\" exists, do you want to overwrite it?", name ) )
286           g_free ( name );
287         else
288         {
289           /* Do It */
290           *dest = name;
291           ll.lat = atof ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
292           ll.lon = atof ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
293           vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
294           wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
295           vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
296           vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
297           if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
298             a_thumbnails_create ( wp->image );
299
300           {
301             GtkTreeIter iter, first;
302             gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
303             if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
304               vik_waypoint_set_symbol ( wp, NULL );
305             } else {
306               gchar *sym;
307               gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
308               vik_waypoint_set_symbol ( wp, sym );
309               g_free(sym);
310             }
311           }             
312
313           gtk_widget_destroy ( dialog );
314           return TRUE;
315         }
316       } /* else (valid name) */
317     }
318     else
319     {
320       ll.lat = atof ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) );
321       ll.lon = atof ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) );
322       vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll );
323       wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) );
324       if ( (! wp->comment) || strcmp ( wp->comment, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ) != 0 )
325         vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) );
326       if ( (! wp->image) || strcmp ( wp->image, vik_file_entry_get_filename ( VIK_FILE_ENTRY ( imageentry ) ) ) != 0 )
327       {
328         vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) );
329         if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) )
330           a_thumbnails_create ( wp->image );
331       }
332
333       {
334         GtkTreeIter iter, first;
335         gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first );
336         if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) {
337           vik_waypoint_set_symbol ( wp, NULL );
338         } else {
339           gchar *sym;
340           gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 );
341           vik_waypoint_set_symbol ( wp, sym );
342           g_free(sym);
343         }
344       }         
345
346       gtk_widget_destroy ( dialog );
347
348       return TRUE;
349     }
350   }
351   gtk_widget_destroy ( dialog );
352   return FALSE;
353 }
354
355 gchar *a_dialog_new_track ( GtkWindow *parent, GHashTable *tracks )
356 {
357   GtkWidget *dialog = gtk_dialog_new_with_buttons ("Add Track",
358                                                   parent,
359                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
360                                                   GTK_STOCK_CANCEL,
361                                                   GTK_RESPONSE_REJECT,
362                                                   GTK_STOCK_OK,
363                                                   GTK_RESPONSE_ACCEPT,
364                                                   NULL);
365   GtkWidget *label = gtk_label_new ( "Track Name:" );
366   GtkWidget *entry = gtk_entry_new ();
367
368   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), label, FALSE, FALSE, 0);
369   gtk_box_pack_start (GTK_BOX(GTK_DIALOG(dialog)->vbox), entry, FALSE, FALSE, 0);
370
371   g_signal_connect_swapped ( entry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) );
372
373   gtk_widget_show ( label );
374   gtk_widget_show ( entry );
375
376   while ( gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT )
377   {
378     const gchar *constname = gtk_entry_get_text ( GTK_ENTRY(entry) );
379     if ( *constname == '\0' )
380       a_dialog_info_msg ( parent, "Please enter a name for the track." );
381     else {
382       gchar *name = g_strdup ( constname );
383       gint i;
384
385       for ( i = strlen ( name ) - 1; i >= 0; i-- )
386         name[i] = toupper(name[i]); /* all caps for stardandization */
387
388       if ( g_hash_table_lookup( tracks, name ) && !a_dialog_overwrite ( parent, "The track \"%s\" exists, do you want to overwrite it?", gtk_entry_get_text ( GTK_ENTRY(entry) ) ) )
389       {
390         g_free ( name );
391       }
392       else
393       {
394         gtk_widget_destroy ( dialog );
395         return name;
396       }
397     }
398   }
399   gtk_widget_destroy ( dialog );
400   return NULL;
401 }
402
403 /* creates a vbox full of labels */
404 GtkWidget *a_dialog_create_label_vbox ( gchar **texts, int label_count )
405 {
406   GtkWidget *vbox, *label;
407   int i;
408   vbox = gtk_vbox_new( TRUE, 3 );
409
410   for ( i = 0; i < label_count; i++ )
411   {
412     label = gtk_label_new(NULL);
413     gtk_label_set_markup ( GTK_LABEL(label), texts[i] );
414     gtk_box_pack_start ( GTK_BOX(vbox), label, FALSE, TRUE, 5 );
415   }
416   return vbox;
417 }
418
419 gboolean a_dialog_overwrite ( GtkWindow *parent, const gchar *message, const gchar *extra )
420 {
421   GtkWidget *dia;
422   dia = gtk_message_dialog_new ( parent,
423                                  GTK_DIALOG_DESTROY_WITH_PARENT,
424                                  GTK_MESSAGE_QUESTION,
425                                  GTK_BUTTONS_YES_NO,
426                                  message, extra );
427
428   if ( gtk_dialog_run ( GTK_DIALOG(dia) ) == GTK_RESPONSE_YES )
429   {
430     gtk_widget_destroy ( dia );
431     return TRUE;
432   }
433   else
434   {
435     gtk_widget_destroy ( dia );
436     return FALSE;
437   }
438 }
439
440 static void zoom_spin_changed ( GtkSpinButton *spin, GtkWidget *pass_along[3] )
441 {
442   if ( gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(pass_along[2]) ) )
443     gtk_spin_button_set_value ( 
444         GTK_SPIN_BUTTON(pass_along[GTK_WIDGET(spin) == pass_along[0] ? 1 : 0]),
445         gtk_spin_button_get_value ( spin ) );
446 }
447
448 gboolean a_dialog_custom_zoom ( GtkWindow *parent, gdouble *xmpp, gdouble *ympp )
449 {
450   GtkWidget *dialog = gtk_dialog_new_with_buttons ("Zoom Factors...",
451                                                   parent,
452                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
453                                                   GTK_STOCK_CANCEL,
454                                                   GTK_RESPONSE_REJECT,
455                                                   GTK_STOCK_OK,
456                                                   GTK_RESPONSE_ACCEPT,
457                                                   NULL);
458   GtkWidget *table, *label, *xlabel, *xspin, *ylabel, *yspin, *samecheck;
459   GtkWidget *pass_along[3];
460
461   table = gtk_table_new ( 4, 2, FALSE );
462   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
463
464   label = gtk_label_new ( "Zoom factor (in meters per pixel:" );
465   xlabel = gtk_label_new ( "X (easting): ");
466   ylabel = gtk_label_new ( "Y (northing): ");
467
468   pass_along[0] = xspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *xmpp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 5 ), 1, 8 );
469   pass_along[1] = yspin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *ympp, VIK_VIEWPORT_MIN_ZOOM, VIK_VIEWPORT_MAX_ZOOM, 1, 5, 5 ), 1, 8 );
470
471   pass_along[2] = samecheck = gtk_check_button_new_with_label ( "X and Y zoom factors must be equal" );
472   /* TODO -- same factor */
473   /*  samecheck = gtk_check_button_new_with_label ( "Same x/y zoom factor" ); */
474
475   if ( *xmpp == *ympp )
476     gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(samecheck), TRUE );
477
478   gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
479   gtk_table_attach_defaults ( GTK_TABLE(table), xlabel, 0, 1, 1, 2 );
480   gtk_table_attach_defaults ( GTK_TABLE(table), xspin, 1, 2, 1, 2 );
481   gtk_table_attach_defaults ( GTK_TABLE(table), ylabel, 0, 1, 2, 3 );
482   gtk_table_attach_defaults ( GTK_TABLE(table), yspin, 1, 2, 2, 3 );
483   gtk_table_attach_defaults ( GTK_TABLE(table), samecheck, 0, 2, 3, 4 );
484
485   gtk_widget_show_all ( table );
486
487   g_signal_connect ( G_OBJECT(xspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
488   g_signal_connect ( G_OBJECT(yspin), "value-changed", G_CALLBACK(zoom_spin_changed), pass_along );
489
490   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
491   {
492     *xmpp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(xspin) );
493     *ympp = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(yspin) );
494     gtk_widget_destroy ( dialog );
495     return TRUE;
496   }
497   gtk_widget_destroy ( dialog );
498   return FALSE;
499 }
500
501 static void split_spin_focused ( GtkSpinButton *spin, GtkWidget *pass_along[1] )
502 {
503   gtk_toggle_button_set_active    (GTK_TOGGLE_BUTTON(pass_along[0]), 1);
504 }
505
506 gboolean a_dialog_time_threshold ( GtkWindow *parent, gchar *title_text, gchar *label_text, guint *thr )
507 {
508   GtkWidget *dialog = gtk_dialog_new_with_buttons (title_text, 
509                                                   parent,
510                                                   GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
511                                                   GTK_STOCK_CANCEL,
512                                                   GTK_RESPONSE_REJECT,
513                                                   GTK_STOCK_OK,
514                                                   GTK_RESPONSE_ACCEPT,
515                                                   NULL);
516   GtkWidget *table, *t1, *t2, *t3, *t4, *spin, *label;
517   GtkWidget *pass_along[1];
518
519   table = gtk_table_new ( 4, 2, FALSE );
520   gtk_box_pack_start ( GTK_BOX(GTK_DIALOG(dialog)->vbox), table, TRUE, TRUE, 0 );
521
522   label = gtk_label_new (label_text);
523
524   t1 = gtk_radio_button_new_with_label ( NULL, "1 min" );
525   t2 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t1), "1 hour" );
526   t3 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t2), "1 day" );
527   t4 = gtk_radio_button_new_with_label_from_widget ( GTK_RADIO_BUTTON(t3), "Custom (in minutes):" );
528
529   pass_along[0] = t4;
530
531   spin = gtk_spin_button_new ( (GtkAdjustment *) gtk_adjustment_new ( *thr, 0, 65536, 1, 5, 5 ), 1, 0 );
532
533   gtk_table_attach_defaults ( GTK_TABLE(table), label, 0, 2, 0, 1 );
534   gtk_table_attach_defaults ( GTK_TABLE(table), t1, 0, 1, 1, 2 );
535   gtk_table_attach_defaults ( GTK_TABLE(table), t2, 0, 1, 2, 3 );
536   gtk_table_attach_defaults ( GTK_TABLE(table), t3, 0, 1, 3, 4 );
537   gtk_table_attach_defaults ( GTK_TABLE(table), t4, 0, 1, 4, 5 );
538   gtk_table_attach_defaults ( GTK_TABLE(table), spin, 1, 2, 4, 5 );
539
540   gtk_widget_show_all ( table );
541
542   g_signal_connect ( G_OBJECT(spin), "grab-focus", G_CALLBACK(split_spin_focused), pass_along );
543
544   if ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT )
545   {
546     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t1))) {
547       *thr = 1;
548     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t2))) {
549       *thr = 60;
550     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t3))) {
551       *thr = 60 * 24;
552     } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(t4))) {
553       *thr = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(spin) );
554     }
555     gtk_widget_destroy ( dialog );
556     return TRUE;
557   }
558   gtk_widget_destroy ( dialog );
559   return FALSE;
560 }