Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 221 - (hide annotations)
Mon Nov 30 21:28:04 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 40249 byte(s)
Fremantle coordinate picker
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of GPXView.
5     *
6     * GPXView 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 3 of the License, or
9     * (at your option) any later version.
10     *
11     * GPXView 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 GPXView. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include <math.h>
21     #include <string.h>
22     #include <ctype.h>
23    
24 harbaum 77 #include <glib.h>
25     #include <glib/gstdio.h>
26    
27 harbaum 1 #include "gpxview.h"
28    
29 harbaum 190 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
30     #include <hildon/hildon-entry.h>
31 harbaum 216 #include <hildon/hildon-touch-selector.h>
32     #include <hildon/hildon-picker-button.h>
33     #include <hildon/hildon-picker-dialog.h>
34 harbaum 190 #endif
35    
36 harbaum 221 float roundf(float x);
37    
38     /* TODO: make coordinate picker support "changed" signal */
39    
40 harbaum 217 #ifdef FREMANTLE
41 harbaum 221 #define PRESET_PICKER_DIALOG
42     #define COORDINATE_PICKER
43 harbaum 217 #endif
44    
45 harbaum 1 char strlastchr(char *str) {
46     return str[strlen(str)]-1;
47     }
48    
49     /* make sure the entire path "dir" exists and create it if not */
50     int checkdir(char *dir) {
51     struct stat filestat;
52     char *p = dir, tmp;
53    
54     /* don't try to create root dir */
55     if(p[0] == '/') p++;
56    
57     do {
58     while(*p && *p != '/') p++;
59     tmp = *p;
60     *p = 0;
61    
62     int err = stat(dir, &filestat);
63     if(err) {
64     if(mkdir(dir, S_IRWXU) != 0) {
65     perror("mkdir()");
66     *p++ = tmp;
67     return -1;
68     }
69     } else {
70     if(!filestat.st_mode & S_IFDIR) {
71     printf("File %s exists and is _no_ directory\n", dir);
72     *p++ = tmp;
73     return -1;
74     }
75     }
76    
77     *p++ = tmp;
78     } while(tmp && strchr(p, '/'));
79    
80     return 0;
81     }
82    
83     void pos_lat_str(char *str, int len, float latitude) {
84     char *c = _("N");
85     float integral, fractional;
86    
87 harbaum 13 if(isnan(latitude))
88     str[0] = 0;
89     else {
90     if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
91     fractional = modff(latitude, &integral);
92 harbaum 1
93 harbaum 13 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
94     }
95 harbaum 1 }
96    
97     GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
98     char str[32];
99    
100     pos_lat_str(str, sizeof(str), latitude);
101     return gtk_label_attrib(str, size, strikethrough);
102     }
103    
104     void pos_lon_str(char *str, int len, float longitude) {
105     char *c = _("E");
106     float integral, fractional;
107    
108 harbaum 13 if(isnan(longitude))
109     str[0] = 0;
110     else {
111     if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
112     fractional = modff(longitude, &integral);
113 harbaum 1
114 harbaum 13 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
115     }
116 harbaum 1 }
117    
118     GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
119     char str[32];
120    
121     pos_lon_str(str, sizeof(str), longitude);
122     return gtk_label_attrib(str, size, strikethrough);
123     }
124    
125     float pos_parse_lat(char *str) {
126     int integral_int;
127     float fractional;
128     char c;
129    
130     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
131     c = toupper(c);
132    
133     if(c != 'S' && c != 'N')
134     return NAN;
135    
136     /* prevent -0.0 */
137     if(!integral_int && (fractional == 0.0))
138     return 0.0;
139    
140     return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
141     }
142    
143     return NAN;
144     }
145    
146     float pos_parse_lon(char *str) {
147     int integral_int;
148     float fractional;
149     char c;
150    
151     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
152     c = toupper(c);
153    
154     /* O is german "Ost" for "East" */
155     if(c != 'E' && c != 'W' && c != 'O')
156     return NAN;
157    
158     /* prevent -0.0 */
159     if(!integral_int && (fractional == 0.0))
160     return 0.0;
161    
162     return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
163     }
164    
165     return NAN;
166     }
167    
168     const char *pos_get_bearing_str(pos_t from, pos_t to) {
169     static const char *bear_str[]={
170 harbaum 185 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
171    
172     float bearing = gpx_pos_get_bearing(from, to);
173     if(!isnan(bearing)) {
174     int idx = (bearing+22.5)/45.0;
175     /* make sure we stay in icon bounds */
176     while(idx < 0) idx += 8;
177     while(idx > 7) idx -= 8;
178     return _(bear_str[idx]);
179     }
180    
181     return bear_str[8]; // empty string
182 harbaum 1 }
183    
184     /* the maemo font size is quite huge, so we adjust some fonts */
185     /* differently on maemo and non-maemo. Basically "BIG" does nothing */
186     /* on maemo and "SMALL" only does something on maemo */
187     #ifdef USE_MAEMO
188     #define MARKUP_SMALL "<span size='small'>%s</span>"
189     GtkWidget *gtk_label_small(char *str) {
190     GtkWidget *label = gtk_label_new("");
191     char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
192     gtk_label_set_markup(GTK_LABEL(label), markup);
193     g_free(markup);
194     return label;
195     }
196     #else
197     #define MARKUP_BIG "<span size='x-large'>%s</span>"
198     GtkWidget *gtk_label_big(char *str) {
199     GtkWidget *label = gtk_label_new("");
200     char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
201     gtk_label_set_markup(GTK_LABEL(label), markup);
202     g_free(markup);
203     return label;
204     }
205     #endif
206    
207     void gtk_label_attrib_set(GtkWidget *label,
208     char *str, int size, int strikethrough) {
209     char format[80];
210    
211     snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
212     #ifdef USE_MAEMO
213     (size==SIZE_SMALL)?" size='small'":"",
214     #else
215     (size==SIZE_BIG)?" size='x-large'":"",
216     #endif
217     strikethrough?" strikethrough='yes'":"",
218     (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
219    
220     char *markup = g_markup_printf_escaped(format, str);
221     // printf("markup = %s\n", markup);
222     gtk_label_set_markup(GTK_LABEL(label), markup);
223     g_free(markup);
224     }
225    
226     GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
227     GtkWidget *label = gtk_label_new("");
228     gtk_label_attrib_set(label, str, size, strikethrough);
229     return label;
230     }
231    
232     GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
233     GtkWidget *button = gtk_button_new_with_label("");
234     gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
235     str, size, strikethrough);
236     return button;
237     }
238    
239     void textbox_disable(GtkWidget *widget) {
240     gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
241     gtk_widget_set_sensitive(widget, FALSE);
242     }
243    
244     void textbox_enable(GtkWidget *widget) {
245     gtk_widget_set_sensitive(widget, TRUE);
246     gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
247     }
248    
249     pos_t *get_pos(appdata_t *appdata) {
250     pos_t *pos = &appdata->home;
251    
252     if(appdata->active_location) {
253     int i = appdata->active_location-1;
254     location_t *loc = appdata->location;
255     while(i--) loc = loc->next;
256     pos = &loc->pos;
257     }
258    
259     if(appdata->use_gps) {
260     pos = gps_get_pos(appdata);
261    
262     if(!pos) pos = &appdata->gps; /* use saved position */
263     else appdata->gps = *pos; /* save position */
264     }
265     return pos;
266     }
267    
268     void distance_str(char *str, int len, float dist, gboolean imperial) {
269 harbaum 34 if(isnan(dist))
270     snprintf(str, len, "---");
271     else if(imperial) {
272 harbaum 1 /* 1 mil = 1760 yd = 5280 ft ... */
273     if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
274     else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
275     else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
276     else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
277     else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
278     else snprintf(str, len, "%.0f mi", dist);
279     } else {
280     if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
281     else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
282     else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
283     else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
284     else snprintf(str, len, "%.0f km", dist);
285     }
286     }
287    
288     /* return distance in miles or kilometers */
289     float distance_parse(char *str, gboolean imperial) {
290     char unit[4];
291     float val = NAN;
292    
293     if(sscanf(str, "%f %3s", &val, unit) == 2) {
294     gboolean fimp = FALSE;
295    
296     if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
297     else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
298     else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
299     else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
300     else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
301     else val = NAN;
302    
303     /* found imperial and metric requested? convert miles into kilometers */
304     if(fimp & !imperial) val *= 1.609344;
305    
306     /* found metric and imperial requested? convert kilometers into miles */
307     if(!fimp & imperial) val /= 1.609344;
308     }
309     return val;
310     }
311    
312 harbaum 221 /* ------------------ coordinate picker tool --------------------------- */
313    
314 harbaum 1 static gboolean mark(GtkWidget *widget, gboolean valid) {
315     gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
316     return valid;
317     }
318    
319 harbaum 221 #ifndef COORDINATE_PICKER
320 harbaum 1 static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
321     float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
322     mark(widget, !isnan(i));
323     }
324 harbaum 221 #else
325     static GtkWidget *letter_picker_create(char *a, char *b, int sel) {
326     #ifndef FREMANTLE
327     GtkWidget *view = gtk_tree_view_new();
328     #else
329     GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
330     #endif
331 harbaum 1
332 harbaum 221 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
333     GtkTreeSelection *selection =
334     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
335    
336     /* --- "char" column --- */
337     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
338     g_object_set(renderer, "xalign", 0.5, NULL );
339     gtk_tree_view_insert_column_with_attributes(
340     GTK_TREE_VIEW(view), -1, "char", renderer, "text", 0, NULL);
341    
342     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
343    
344     /* add digits */
345     GtkTreeIter iter_a, iter_b;
346     gtk_list_store_append (store, &iter_a);
347     gtk_list_store_set(store, &iter_a, 0, _(a), 1, 0, -1);
348     gtk_list_store_append (store, &iter_b);
349     gtk_list_store_set(store, &iter_b, 0, _(b), 1, 1, -1);
350    
351     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
352     g_object_unref(store);
353    
354     /* select right character */
355     GtkTreeIter iter = (!sel)?iter_a:iter_b;
356     gtk_tree_selection_select_iter(selection, &iter);
357     GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
358     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
359     path, NULL, TRUE, 0.5, 0.5);
360     gtk_tree_path_free(path);
361    
362     /* put this inside a scrolled view */
363     #ifndef USE_PANNABLE_AREA
364     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
365     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
366     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
367     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
368     return scrolled_window;
369     #else
370     GtkWidget *pannable_area = hildon_pannable_area_new();
371     gtk_container_add(GTK_CONTAINER(pannable_area), view);
372     return pannable_area;
373     #endif
374     }
375    
376     static int picker_get(GtkWidget *widget) {
377     GtkWidget *view = gtk_bin_get_child(GTK_BIN(widget));
378    
379     GtkTreeSelection *sel =
380     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
381    
382     GtkTreeModel *model;
383     GtkTreeIter iter;
384    
385     /* there should never be an unseletced column. But if */
386     /* it is, we count it as zero */
387     if(!gtk_tree_selection_get_selected(sel, &model, &iter))
388     return 0;
389    
390     int retval = 0;
391     gtk_tree_model_get(model, &iter, 1, &retval, -1);
392     return retval;
393     }
394    
395    
396     static GtkWidget *digit_picker_create(int min, int max, int sel) {
397     #ifndef FREMANTLE
398     GtkWidget *view = gtk_tree_view_new();
399     #else
400     GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
401     #endif
402    
403     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
404     GtkTreeSelection *selection =
405     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
406    
407     /* --- "digit" column --- */
408     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
409     g_object_set(renderer, "xalign", 0.5, NULL );
410     gtk_tree_view_insert_column_with_attributes(
411     GTK_TREE_VIEW(view), -1, "digit", renderer, "text", 0, NULL);
412    
413     GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
414    
415     /* add digits */
416     int i;
417     GtkTreeIter siter;
418     for(i=min;i<=max;i++) {
419     char str[2] = { '0'+i, 0 };
420     GtkTreeIter iter;
421     /* Append a row and fill in some data */
422     gtk_list_store_append (store, &iter);
423     gtk_list_store_set(store, &iter, 0, str, 1, i, -1);
424    
425     if(i == sel) siter = iter;
426     }
427    
428     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
429     g_object_unref(store);
430    
431     gtk_tree_selection_select_iter(selection, &siter);
432     GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &siter);
433     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
434     path, NULL, TRUE, 0.5, 0.5);
435     gtk_tree_path_free(path);
436    
437     /* put this inside a scrolled view */
438     #ifndef USE_PANNABLE_AREA
439     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
440     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
441     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
442     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
443     return scrolled_window;
444     #else
445     GtkWidget *pannable_area = hildon_pannable_area_new();
446     gtk_container_add(GTK_CONTAINER(pannable_area), view);
447     return pannable_area;
448     #endif
449     }
450    
451     static gint on_lat_picker_button_press(GtkWidget *button,
452     GdkEventButton *event, gpointer data) {
453    
454     if(event->type == GDK_BUTTON_PRESS) {
455     GtkWidget *dialog =
456     gtk_dialog_new_with_buttons(_("Latitude"),
457     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
458     GTK_DIALOG_MODAL,
459     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
460     _("Done"), GTK_RESPONSE_ACCEPT,
461     NULL);
462    
463     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
464    
465     int i, lat = (int)g_object_get_data(G_OBJECT(button), "latitude");
466    
467     /* parse latitude into components */
468     int sign = (lat>=0)?0:1;
469     lat = abs(lat);
470     int deg = lat / 60000;
471     int min = (lat /1000)%60;
472     int minfrac = lat % 1000;
473    
474     GtkWidget *signw, *degw[2], *minw[2], *minfracw[3];
475    
476    
477     /* create N/S 89° 99.999 */
478     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
479     gtk_box_pack_start_defaults(GTK_BOX(hbox),
480     signw = letter_picker_create("N","S", sign));
481    
482     gtk_box_pack_start_defaults(GTK_BOX(hbox),
483     degw[0] = digit_picker_create(0,8, deg/10));
484     gtk_box_pack_start_defaults(GTK_BOX(hbox),
485     degw[1] = digit_picker_create(0,9, deg%10));
486     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
487    
488     gtk_box_pack_start_defaults(GTK_BOX(hbox),
489     minw[0] = digit_picker_create(0,5, min/10));
490     gtk_box_pack_start_defaults(GTK_BOX(hbox),
491     minw[1] = digit_picker_create(0,9, min%10));
492     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
493    
494     gtk_box_pack_start_defaults(GTK_BOX(hbox),
495     minfracw[0] = digit_picker_create(0,9, minfrac/100));
496     gtk_box_pack_start_defaults(GTK_BOX(hbox),
497     minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
498     gtk_box_pack_start_defaults(GTK_BOX(hbox),
499     minfracw[2] = digit_picker_create(0,9, minfrac%10));
500    
501     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
502    
503     gtk_widget_show_all(dialog);
504     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
505    
506     /* parse N/S */
507     sign = picker_get(signw)?-1:1;
508    
509     /* parse degrees ... */
510     for(deg=0,i=0;i<2;i++)
511     deg = 10 * deg + picker_get(degw[i]);
512    
513     /* ... minutes ... */
514     for(min=0,i=0;i<2;i++)
515     min = 10 * min + picker_get(minw[i]);
516    
517     /* ... and fractions of minutes */
518     for(minfrac=0,i=0;i<3;i++)
519     minfrac = 10 * minfrac + picker_get(minfracw[i]);
520    
521     float latitude = sign * (deg + min/60.0 + minfrac/60000.0);
522     lat_entry_set(button, latitude);
523     }
524    
525     gtk_widget_destroy(dialog);
526    
527     return TRUE;
528     }
529     return FALSE;
530     }
531     #endif
532    
533 harbaum 1 /* a entry that is colored red when being "active" */
534     GtkWidget *lat_entry_new(float lat) {
535 harbaum 221 char str[32];
536     pos_lat_str(str, sizeof(str), lat);
537    
538     #ifndef COORDINATE_PICKER
539 harbaum 1 GdkColor color;
540 harbaum 190
541 harbaum 212 GtkWidget *widget = entry_new();
542 harbaum 1 gdk_color_parse("#ff0000", &color);
543     gtk_widget_modify_text(widget, TAG_STATE, &color);
544    
545     gtk_entry_set_text(GTK_ENTRY(widget), str);
546    
547     g_signal_connect(G_OBJECT(widget), "changed",
548     G_CALLBACK(callback_modified_lat), NULL);
549    
550 harbaum 221 #else
551     GtkWidget *widget = gtk_button_new_with_label(str);
552    
553     #ifdef FREMANTLE
554     hildon_gtk_widget_set_theme_size(widget,
555     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
556     #endif
557     int lat_int = (int)roundf(lat * 60000);
558     g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
559     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
560     (GtkSignalFunc)on_lat_picker_button_press, NULL);
561     #endif
562    
563 harbaum 1 return widget;
564     }
565    
566 harbaum 221 #ifndef COORDINATE_PICKER
567 harbaum 1 static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
568     float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
569     mark(widget, !isnan(i));
570     }
571 harbaum 221 #else
572     static gint on_lon_picker_button_press(GtkWidget *button,
573     GdkEventButton *event, gpointer data) {
574 harbaum 1
575 harbaum 221 if(event->type == GDK_BUTTON_PRESS) {
576     GtkWidget *dialog =
577     gtk_dialog_new_with_buttons(_("Longitude"),
578     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
579     GTK_DIALOG_MODAL,
580     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
581     _("Done"), GTK_RESPONSE_ACCEPT,
582     NULL);
583    
584     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
585    
586     int i, lat = (int)g_object_get_data(G_OBJECT(button), "longitude");
587    
588     /* parse latitude into components */
589     int sign = (lat>=0)?0:1;
590     lat = abs(lat);
591     int deg = lat / 60000;
592     int min = (lat /1000)%60;
593     int minfrac = lat % 1000;
594    
595     GtkWidget *signw, *degw[3], *minw[2], *minfracw[3];
596    
597     /* create E/W 179° 99.999 */
598     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
599     gtk_box_pack_start_defaults(GTK_BOX(hbox),
600     signw = letter_picker_create("E","W", sign));
601    
602     gtk_box_pack_start_defaults(GTK_BOX(hbox),
603     degw[0] = digit_picker_create(0,1, deg/100));
604     gtk_box_pack_start_defaults(GTK_BOX(hbox),
605     degw[1] = digit_picker_create(0,9, (deg/10)%10));
606     gtk_box_pack_start_defaults(GTK_BOX(hbox),
607     degw[2] = digit_picker_create(0,9, deg%10));
608     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
609    
610     gtk_box_pack_start_defaults(GTK_BOX(hbox),
611     minw[0] = digit_picker_create(0,5, min/10));
612     gtk_box_pack_start_defaults(GTK_BOX(hbox),
613     minw[1] = digit_picker_create(0,9, min%10));
614     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
615    
616     gtk_box_pack_start_defaults(GTK_BOX(hbox),
617     minfracw[0] = digit_picker_create(0,9, minfrac/100));
618     gtk_box_pack_start_defaults(GTK_BOX(hbox),
619     minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
620     gtk_box_pack_start_defaults(GTK_BOX(hbox),
621     minfracw[2] = digit_picker_create(0,9, minfrac%10));
622    
623     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
624    
625     gtk_widget_show_all(dialog);
626     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
627    
628     /* parse E/W */
629     sign = picker_get(signw)?-1:1;
630    
631     /* parse degrees ... */
632     for(deg=0,i=0;i<3;i++)
633     deg = 10 * deg + picker_get(degw[i]);
634    
635     /* ... minutes ... */
636     for(min=0,i=0;i<2;i++)
637     min = 10 * min + picker_get(minw[i]);
638    
639     /* ... and fractions of minutes */
640     for(minfrac=0,i=0;i<3;i++)
641     minfrac = 10 * minfrac + picker_get(minfracw[i]);
642    
643     float longitude = sign * (deg + min/60.0 + minfrac/60000.0);
644     lon_entry_set(button, longitude);
645     }
646    
647     gtk_widget_destroy(dialog);
648    
649     return TRUE;
650     }
651     return FALSE;
652     }
653     #endif
654    
655 harbaum 1 /* a entry that is colored red when filled with invalid coordinate */
656     GtkWidget *lon_entry_new(float lon) {
657 harbaum 221 char str[32];
658     pos_lon_str(str, sizeof(str), lon);
659    
660     #ifndef COORDINATE_PICKER
661 harbaum 1 GdkColor color;
662 harbaum 190
663 harbaum 212 GtkWidget *widget = entry_new();
664 harbaum 1 gdk_color_parse("#ff0000", &color);
665     gtk_widget_modify_text(widget, TAG_STATE, &color);
666    
667     gtk_entry_set_text(GTK_ENTRY(widget), str);
668    
669     g_signal_connect(G_OBJECT(widget), "changed",
670     G_CALLBACK(callback_modified_lon), NULL);
671    
672 harbaum 221 #else
673     GtkWidget *widget = gtk_button_new_with_label(str);
674    
675     #ifdef FREMANTLE
676     hildon_gtk_widget_set_theme_size(widget,
677     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
678     #endif
679     int lon_int = (int)roundf(lon * 60000);
680     g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
681     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
682     (GtkSignalFunc)on_lon_picker_button_press, NULL);
683     #endif
684    
685 harbaum 1 return widget;
686     }
687    
688 harbaum 221 float lat_entry_get(GtkWidget *widget) {
689     #ifndef COORDINATE_PICKER
690 harbaum 1 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
691 harbaum 221 #else
692     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
693     #endif
694 harbaum 1 return pos_parse_lat(p);
695     }
696    
697 harbaum 221 float lon_entry_get(GtkWidget *widget) {
698     #ifndef COORDINATE_PICKER
699 harbaum 1 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
700 harbaum 221 #else
701     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
702     #endif
703 harbaum 1 return pos_parse_lon(p);
704     }
705    
706 harbaum 221 void lat_entry_set(GtkWidget *widget, float lat) {
707     char str[32];
708     pos_lat_str(str, sizeof(str)-1, lat);
709     #ifndef COORDINATE_PICKER
710     gtk_entry_set_text(GTK_ENTRY(widget), str);
711     #else
712     gtk_button_set_label(GTK_BUTTON(widget), str);
713     int lat_int = (int)roundf(lat * 60000);
714     g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
715     #endif
716     }
717    
718     void lon_entry_set(GtkWidget *widget, float lon) {
719     char str[32];
720     pos_lon_str(str, sizeof(str)-1, lon);
721     #ifndef COORDINATE_PICKER
722     gtk_entry_set_text(GTK_ENTRY(widget), str);
723     #else
724     gtk_button_set_label(GTK_BUTTON(widget), str);
725     int lon_int = (int)roundf(lon * 60000);
726     g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
727     #endif
728     }
729    
730     void lat_label_set(GtkWidget *widget, float lat) {
731     char str[32];
732     pos_lat_str(str, sizeof(str)-1, lat);
733     gtk_label_set(GTK_LABEL(widget), str);
734     }
735    
736     void lon_label_set(GtkWidget *widget, float lon) {
737     char str[32];
738     pos_lon_str(str, sizeof(str)-1, lon);
739     gtk_label_set(GTK_LABEL(widget), str);
740     }
741    
742     void lat_label_attrib_set(GtkWidget *widget, float lat,
743     int size, int strikethrough) {
744     char str[32];
745     pos_lat_str(str, sizeof(str)-1, lat);
746     gtk_label_attrib_set(widget, str, size, strikethrough);
747     }
748    
749     void lon_label_attrib_set(GtkWidget *widget, float lon,
750     int size, int strikethrough) {
751     char str[32];
752     pos_lon_str(str, sizeof(str)-1, lon);
753     gtk_label_attrib_set(widget, str, size, strikethrough);
754     }
755    
756 harbaum 1 static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
757     /* don't care for metric/imperial since we only want to know if this */
758     /* is parseable at all */
759     float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
760     mark(widget, !isnan(i));
761     }
762    
763     /* a entry that is colored red when filled with invalid distance */
764     GtkWidget *dist_entry_new(float dist, gboolean mil) {
765     GdkColor color;
766 harbaum 212 GtkWidget *widget = entry_new();
767 harbaum 1 gdk_color_parse("#ff0000", &color);
768     gtk_widget_modify_text(widget, TAG_STATE, &color);
769    
770     char str[32];
771     distance_str(str, sizeof(str), dist, mil);
772     gtk_entry_set_text(GTK_ENTRY(widget), str);
773    
774     g_signal_connect(G_OBJECT(widget), "changed",
775     G_CALLBACK(callback_modified_dist), NULL);
776    
777     return widget;
778     }
779    
780     float dist_get(GtkWidget *widget, gboolean mil) {
781     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
782     return distance_parse(p, mil);
783     }
784    
785     #ifndef USE_MAEMO
786     #ifdef ENABLE_BROWSER_INTERFACE
787     #include <libgnome/gnome-url.h>
788    
789     int browser_url(appdata_t *appdata, char *url) {
790     /* taken from gnome-open, part of libgnome */
791     GError *err = NULL;
792     gnome_url_show(url, &err);
793     return 0;
794     }
795     #endif
796     #endif
797 harbaum 77
798     /* recursively remove an entire file system */
799     void rmdir_recursive(char *path) {
800     GDir *dir = g_dir_open(path, 0, NULL);
801     if(dir) {
802     const char *name = g_dir_read_name(dir);
803     while(name) {
804     char *fullname = g_strdup_printf("%s/%s", path, name);
805     // printf("deleting %s\n", fullname);
806    
807     if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
808     rmdir_recursive(fullname);
809     else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
810     g_remove(fullname);
811    
812     g_free(fullname);
813     name = g_dir_read_name(dir);
814     }
815    
816     g_dir_close(dir);
817     }
818     g_rmdir(path);
819     }
820    
821 harbaum 137 #ifdef ENABLE_BROWSER_INTERFACE
822     static void on_link_clicked(GtkButton *button, gpointer data) {
823     appdata_t *appdata = (appdata_t*)data;
824     char *url = g_object_get_data(G_OBJECT(button), "url");
825     if(url) browser_url(appdata, url);
826     }
827     #endif
828    
829     /* a button containing a weblink */
830     GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
831     int size, int strikethrough) {
832    
833     #ifdef ENABLE_BROWSER_INTERFACE
834     if(url) {
835     GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
836     g_object_set_data(G_OBJECT(button), "url", url);
837     gtk_signal_connect(GTK_OBJECT(button), "clicked",
838     (GtkSignalFunc)on_link_clicked, appdata);
839    
840     return button;
841     }
842     #endif
843     return gtk_label_attrib(str, size, strikethrough);
844     }
845    
846     #ifdef ENABLE_BROWSER_INTERFACE
847     static void on_link_id_clicked(GtkButton *button, gpointer data) {
848     appdata_t *appdata = (appdata_t*)data;
849    
850     unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
851     char *type = g_object_get_data(G_OBJECT(button), "type");
852    
853     char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
854     type, id);
855    
856     if(url) {
857     browser_url(appdata, url);
858     g_free(url);
859     }
860     }
861     #endif
862    
863     GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
864     const char *type, int id) {
865    
866     #ifdef ENABLE_BROWSER_INTERFACE
867     if(id) {
868     GtkWidget *ref = gtk_button_new_with_label(str);
869     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
870     // hildon_gtk_widget_set_theme_size(ref,
871     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
872     #endif
873     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
874     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
875     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
876     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
877    
878     return ref;
879     }
880     #endif
881     return gtk_label_new(str);
882     }
883    
884 harbaum 138
885     GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
886     const char *type, int id) {
887    
888     #ifdef ENABLE_BROWSER_INTERFACE
889     if(id) {
890     GtkWidget *ref = gtk_button_new();
891     gtk_button_set_image(GTK_BUTTON(ref), icon);
892    
893     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
894     // hildon_gtk_widget_set_theme_size(ref,
895     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
896     #endif
897     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
898     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
899     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
900     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
901    
902     return ref;
903     }
904     #endif
905     return icon;
906     }
907    
908 harbaum 165 /* left aligned, word wrapped multiline widget */
909     GtkWidget *simple_text_widget(char *text) {
910     GtkWidget *label = gtk_label_new(text);
911    
912     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
913     gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
914     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
915    
916     return label;
917     }
918 harbaum 198
919    
920     /* a label that is left aligned */
921     GtkWidget *left_label_new(char *str) {
922     GtkWidget *widget = gtk_label_new(str);
923     gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
924     return widget;
925     }
926 harbaum 212
927 harbaum 221 /* ------------- preset coordinate picker tool ----------------- */
928    
929 harbaum 217 static void pos_set(GtkWidget *item, float lat, float lon) {
930 harbaum 212
931     GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
932 harbaum 221 lat_entry_set(lat_entry, lat);
933 harbaum 212
934     GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
935 harbaum 221 lon_entry_set(lon_entry, lon);
936 harbaum 212 }
937    
938 harbaum 217 static void cb_gps(GtkWidget *item, gpointer data) {
939 harbaum 212 appdata_t *appdata = (appdata_t*)data;
940 harbaum 218 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
941     pos_t *pos = NULL;
942 harbaum 212
943 harbaum 218 if(!id)
944     pos = gps_get_pos(appdata);
945     else if(id == 1)
946     pos = &appdata->home;
947     else {
948     location_t *location = appdata->location;
949     while(location && id > 2) {
950     location = location->next;
951     id--;
952     }
953    
954     if(id == 2)
955     pos = &location->pos;
956     }
957    
958     if(!pos) pos_set(item, NAN, NAN);
959     else pos_set(item, pos->lat, pos->lon);
960 harbaum 212 }
961    
962 harbaum 217 static void cb_geomath(GtkWidget *item, gpointer data) {
963 harbaum 212 appdata_t *appdata = (appdata_t*)data;
964    
965     pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
966     }
967    
968     #ifdef ENABLE_OSM_GPS_MAP
969 harbaum 217 static void cb_map(GtkWidget *item, gpointer data) {
970 harbaum 212 appdata_t *appdata = (appdata_t*)data;
971    
972     pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
973     }
974     #endif
975    
976 harbaum 217 static void cb_cache(GtkWidget *item, gpointer data) {
977 harbaum 212 appdata_t *appdata = (appdata_t*)data;
978 harbaum 217
979 harbaum 212 cache_t *cache = appdata->cur_cache;
980     g_assert(cache);
981    
982 harbaum 217 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
983    
984     if(!id)
985 harbaum 212 pos_set(item, cache->pos.lat, cache->pos.lon);
986 harbaum 221 else if(id == 1)
987     pos_set(item, cache->notes->pos.lat, cache->notes->pos.lon);
988 harbaum 212 else {
989     wpt_t *wpt = cache->wpt;
990 harbaum 221 while(wpt && id > 2) {
991 harbaum 212 wpt = wpt->next;
992 harbaum 217 id--;
993 harbaum 212 }
994 harbaum 217
995 harbaum 221 if(id == 2)
996 harbaum 217 pos_set(item, wpt->pos.lat, wpt->pos.lon);
997 harbaum 212 }
998     }
999    
1000 harbaum 221 #ifndef PRESET_PICKER_DIALOG
1001 harbaum 212 static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1002     GtkWidget *icon, char *menu_str,
1003 harbaum 217 void(*func)(GtkWidget*, gpointer), gint id,
1004 harbaum 212 GtkWidget *lon_entry, GtkWidget *lat_entry) {
1005    
1006     GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
1007    
1008     if(icon)
1009     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
1010    
1011     g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
1012     g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
1013 harbaum 217 g_object_set_data(G_OBJECT(item), "id", (gpointer)id);
1014 harbaum 212
1015     if(func)
1016     gtk_signal_connect(GTK_OBJECT(item), "activate",
1017     (GtkSignalFunc)func, appdata);
1018    
1019     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1020    
1021     return item;
1022     }
1023    
1024     static GtkWidget *popup_menu_create(appdata_t *appdata,
1025     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1026     GtkWidget *menu = gtk_menu_new();
1027    
1028 harbaum 214 menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1029 harbaum 218 _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1030    
1031     menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1032     _("Home"), cb_gps, 1, lon_entry, lat_entry);
1033    
1034     location_t *location = appdata->location;
1035     gint id = 2;
1036     while(location) {
1037     menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1038     location->name, cb_gps, id++, lon_entry, lat_entry);
1039    
1040     location = location->next;
1041     }
1042    
1043 harbaum 215 menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
1044 harbaum 217 _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
1045 harbaum 212 #ifdef ENABLE_OSM_GPS_MAP
1046 harbaum 215 menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1047 harbaum 217 _("Map position"), cb_map, 0, lon_entry, lat_entry);
1048 harbaum 212 #endif
1049 harbaum 214
1050 harbaum 212 if(appdata->cur_cache) {
1051     cache_t *cache = appdata->cur_cache;
1052    
1053 harbaum 217 char *name = cache->name;
1054     if(!name) name = cache->id;
1055    
1056 harbaum 221 /* original cache position */
1057 harbaum 212 if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
1058 harbaum 214 menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1059 harbaum 217 name, cb_cache, 0, lon_entry, lat_entry);
1060 harbaum 212 }
1061    
1062 harbaum 221 /* overwritten cache position */
1063     if(cache->notes &&
1064     !isnan(cache->notes->pos.lat) && !isnan(cache->notes->pos.lon)) {
1065     menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1066     _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1067     }
1068    
1069 harbaum 212 wpt_t *wpt = cache->wpt;
1070 harbaum 221 gint id = 2;
1071 harbaum 212 while(wpt) {
1072     GtkWidget *icon = NULL;
1073     if(wpt->sym != WPT_SYM_UNKNOWN)
1074 harbaum 213 icon = icon_get_widget(ICON_POS, wpt->sym);
1075 harbaum 212
1076 harbaum 217 char *name = wpt->desc;
1077     if(!name) name = wpt->cmt;
1078     if(!name) name = wpt->id;
1079    
1080     menu_add(menu, appdata, icon, name, cb_cache, id++,
1081 harbaum 212 lon_entry, lat_entry);
1082    
1083     wpt = wpt->next;
1084     }
1085     }
1086    
1087     gtk_widget_show_all(menu);
1088    
1089     return menu;
1090     }
1091    
1092     static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1093     gpointer data) {
1094    
1095     if(event->type == GDK_BUTTON_PRESS) {
1096     GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1097    
1098     /* draw a popup menu */
1099     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1100     event->button, event->time);
1101     return TRUE;
1102     }
1103     return FALSE;
1104     }
1105    
1106     static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1107     GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1108     gtk_widget_destroy(menu);
1109     }
1110     #endif
1111    
1112 harbaum 221 #ifdef PRESET_PICKER_DIALOG
1113 harbaum 212
1114 harbaum 217 enum {
1115 harbaum 221 PRESET_PICKER_COL_ICON = 0,
1116     PRESET_PICKER_COL_NAME,
1117     PRESET_PICKER_COL_ID,
1118     PRESET_PICKER_COL_CB,
1119     PRESET_PICKER_NUM_COLS
1120 harbaum 217 };
1121 harbaum 212
1122 harbaum 221 static void preset_picker_add(GtkListStore *store, appdata_t *appdata,
1123 harbaum 217 GdkPixbuf *icon, char *menu_str,
1124     void(*func)(GtkWidget*, gpointer), gint id) {
1125     GtkTreeIter iter;
1126 harbaum 212
1127 harbaum 217 /* Append a row and fill in some data */
1128     gtk_list_store_append (store, &iter);
1129 harbaum 212
1130 harbaum 217 gtk_list_store_set(store, &iter,
1131 harbaum 221 PRESET_PICKER_COL_ICON, icon,
1132     PRESET_PICKER_COL_NAME, menu_str,
1133     PRESET_PICKER_COL_ID, id,
1134     PRESET_PICKER_COL_CB, func,
1135 harbaum 217 -1);
1136 harbaum 212 }
1137 harbaum 214
1138 harbaum 221 static void on_preset_picker_activated(GtkTreeView *treeview,
1139 harbaum 217 GtkTreePath *path,
1140     GtkTreeViewColumn *col,
1141     gpointer userdata) {
1142     GtkTreeIter iter;
1143     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1144 harbaum 214
1145 harbaum 217 if(gtk_tree_model_get_iter(model, &iter, path)) {
1146     gint id;
1147     void(*func)(GtkWidget*, gpointer);
1148     gtk_tree_model_get(model, &iter,
1149 harbaum 221 PRESET_PICKER_COL_ID, &id,
1150     PRESET_PICKER_COL_CB, &func,
1151 harbaum 217 -1);
1152    
1153     /* set id on widget as callbacks expect it this way */
1154     g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1155     func(GTK_WIDGET(treeview), userdata);
1156 harbaum 218
1157     gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1158     GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1159    
1160 harbaum 217 }
1161 harbaum 214 }
1162 harbaum 216
1163 harbaum 221 static GtkWidget *preset_picker_create(appdata_t *appdata,
1164 harbaum 217 GtkWidget *lat_entry, GtkWidget *lon_entry) {
1165     GtkCellRenderer *renderer;
1166     GtkListStore *store;
1167    
1168     GtkWidget *view = gtk_tree_view_new();
1169 harbaum 216
1170 harbaum 217 g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1171     g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1172 harbaum 216
1173 harbaum 217 /* --- "Icon" column --- */
1174     renderer = gtk_cell_renderer_pixbuf_new();
1175     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1176 harbaum 221 -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1177 harbaum 216
1178 harbaum 217 /* --- "Name" column --- */
1179     renderer = gtk_cell_renderer_text_new();
1180     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1181     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1182 harbaum 221 "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1183 harbaum 217 gtk_tree_view_column_set_expand(column, TRUE);
1184     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1185 harbaum 216
1186 harbaum 221 store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1187 harbaum 217 GDK_TYPE_PIXBUF,
1188     G_TYPE_STRING,
1189     G_TYPE_INT,
1190     G_TYPE_POINTER);
1191 harbaum 216
1192 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1193 harbaum 218 _("GPS position"), cb_gps, 0);
1194    
1195 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1196 harbaum 218 _("Home"), cb_gps, 1);
1197    
1198     location_t *location = appdata->location;
1199     gint id = 2;
1200     while(location) {
1201 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1202 harbaum 218 location->name, cb_gps, id++);
1203    
1204     location = location->next;
1205     }
1206    
1207 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1208 harbaum 217 _("Geomath projection"), cb_geomath, 0);
1209     #ifdef ENABLE_OSM_GPS_MAP
1210 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1211 harbaum 217 _("Map position"), cb_map, 0);
1212     #endif
1213 harbaum 216
1214 harbaum 217 if(appdata->cur_cache) {
1215     cache_t *cache = appdata->cur_cache;
1216 harbaum 216
1217 harbaum 217 char *name = cache->name;
1218     if(!name) name = cache->id;
1219 harbaum 216
1220 harbaum 221 /* original cache position */
1221 harbaum 217 if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
1222 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1223 harbaum 217 name, cb_cache, 0);
1224     }
1225 harbaum 216
1226 harbaum 221 /* overwritten cache position */
1227     if(cache->notes &&
1228     !isnan(cache->notes->pos.lat) && !isnan(cache->notes->pos.lon)) {
1229     preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1230     _("Modified coordinate"), cb_cache, 1);
1231     }
1232    
1233 harbaum 217 wpt_t *wpt = cache->wpt;
1234 harbaum 221 gint id = 2;
1235 harbaum 217 while(wpt) {
1236     GdkPixbuf *icon = NULL;
1237     if(wpt->sym != WPT_SYM_UNKNOWN)
1238     icon = icon_get(ICON_POS, wpt->sym);
1239 harbaum 216
1240 harbaum 217 char *name = wpt->desc;
1241     if(!name) name = wpt->cmt;
1242     if(!name) name = wpt->id;
1243 harbaum 216
1244 harbaum 221 preset_picker_add(store, appdata, icon, name, cb_cache, id++);
1245 harbaum 217 wpt = wpt->next;
1246     }
1247     }
1248 harbaum 216
1249    
1250 harbaum 217 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1251     g_object_unref(store);
1252    
1253     /* make list react on clicks */
1254     g_signal_connect(view, "row-activated",
1255 harbaum 221 (GCallback)on_preset_picker_activated, appdata);
1256 harbaum 217
1257     /* put this inside a scrolled view */
1258     #ifndef USE_PANNABLE_AREA
1259     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1260     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1261     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1262     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1263     return scrolled_window;
1264     #else
1265     GtkWidget *pannable_area = hildon_pannable_area_new();
1266     gtk_container_add(GTK_CONTAINER(pannable_area), view);
1267     return pannable_area;
1268     #endif
1269 harbaum 216 }
1270    
1271 harbaum 221 static gint on_preset_picker_button_press(GtkWidget *button,
1272 harbaum 217 GdkEventButton *event, gpointer data) {
1273     appdata_t *appdata = (appdata_t*)data;
1274 harbaum 216
1275 harbaum 217 gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1276     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1277    
1278 harbaum 216 if(event->type == GDK_BUTTON_PRESS) {
1279 harbaum 217 GtkWidget *dialog =
1280     gtk_dialog_new_with_buttons(_("Preset coordinates"),
1281     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1282     GTK_DIALOG_MODAL,
1283     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1284     NULL);
1285 harbaum 216
1286 harbaum 217 gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
1287 harbaum 216
1288 harbaum 217 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1289 harbaum 221 preset_picker_create(appdata, lat_entry, lon_entry));
1290 harbaum 217
1291 harbaum 216 gtk_widget_show_all(dialog);
1292     gtk_dialog_run(GTK_DIALOG(dialog));
1293     gtk_widget_destroy(dialog);
1294    
1295     return TRUE;
1296     }
1297     return FALSE;
1298     }
1299 harbaum 217 #endif
1300 harbaum 216
1301 harbaum 221 void preset_coordinate_picker_update(appdata_t *appdata, GtkWidget *widget) {
1302     #ifndef PRESET_PICKER_DIALOG
1303     printf("updating popup menu\n");
1304    
1305     GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1306     g_assert(menu);
1307     gtk_widget_destroy(menu);
1308    
1309     gpointer lat_entry = g_object_get_data(G_OBJECT(widget), "lat_entry");
1310     g_assert(lat_entry);
1311     gpointer lon_entry = g_object_get_data(G_OBJECT(widget), "lon_entry");
1312     g_assert(lon_entry);
1313    
1314     menu = popup_menu_create(appdata, lat_entry, lon_entry);
1315     g_object_set_data(G_OBJECT(widget), "menu", (gpointer)menu);
1316     #endif
1317     }
1318    
1319     GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1320 harbaum 217 GtkWidget *lat_entry, GtkWidget *lon_entry) {
1321 harbaum 216
1322 harbaum 217 GtkWidget *button = gtk_button_new();
1323 harbaum 216
1324     gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));
1325 harbaum 217
1326     gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
1327    
1328 harbaum 221 g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1329     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1330    
1331     g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1332     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1333    
1334     #ifndef PRESET_PICKER_DIALOG
1335 harbaum 216 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1336 harbaum 217 (GtkSignalFunc)on_popup_button_press, appdata);
1337 harbaum 216
1338 harbaum 217 gtk_signal_connect(GTK_OBJECT(button), "destroy",
1339     (GtkSignalFunc)on_popup_destroy, appdata);
1340    
1341     g_object_set_data(G_OBJECT(button), "menu",
1342     popup_menu_create(appdata, lat_entry, lon_entry));
1343 harbaum 216 #else
1344 harbaum 217 #ifdef FREMANTLE
1345     hildon_gtk_widget_set_theme_size(button,
1346     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1347 harbaum 216 #endif
1348    
1349 harbaum 217 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1350 harbaum 221 (GtkSignalFunc)on_preset_picker_button_press, appdata);
1351 harbaum 217 #endif
1352    
1353 harbaum 216 return button;
1354     }
1355 harbaum 217
1356     GtkWidget *entry_new(void) {
1357     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1358     return gtk_entry_new();
1359     #else
1360     return hildon_entry_new(HILDON_SIZE_AUTO);
1361 harbaum 216 #endif
1362 harbaum 217 }
1363    
1364     gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
1365     int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
1366     int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
1367    
1368     return((lat1 != lat2) || (lon1 != lon2));
1369     }
1370