Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 231 - (hide annotations)
Mon Dec 7 16:14:50 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 57213 byte(s)
Map set widget
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 harbaum 223 /* TODO:
21     */
22    
23 harbaum 1 #include <math.h>
24     #include <string.h>
25     #include <ctype.h>
26    
27 harbaum 77 #include <glib.h>
28     #include <glib/gstdio.h>
29    
30 harbaum 1 #include "gpxview.h"
31    
32 harbaum 231 #ifdef ENABLE_OSM_GPS_MAP
33     #include "osm-gps-map.h"
34     #endif
35    
36 harbaum 190 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
37     #include <hildon/hildon-entry.h>
38 harbaum 216 #include <hildon/hildon-touch-selector.h>
39     #include <hildon/hildon-picker-button.h>
40     #include <hildon/hildon-picker-dialog.h>
41 harbaum 190 #endif
42    
43 harbaum 221 float roundf(float x);
44    
45 harbaum 223 /* Enable special fremantle UI elements. These particular widgets */
46     /* don't use any hildon/fremantle specific parts and can thus even */
47     /* be used under plain gtk. This is mainly for testing and developemt */
48 harbaum 217 #ifdef FREMANTLE
49 harbaum 221 #define PRESET_PICKER_DIALOG
50     #define COORDINATE_PICKER
51 harbaum 217 #endif
52    
53 harbaum 1 char strlastchr(char *str) {
54     return str[strlen(str)]-1;
55     }
56    
57     /* make sure the entire path "dir" exists and create it if not */
58     int checkdir(char *dir) {
59     struct stat filestat;
60     char *p = dir, tmp;
61    
62     /* don't try to create root dir */
63     if(p[0] == '/') p++;
64    
65     do {
66     while(*p && *p != '/') p++;
67     tmp = *p;
68     *p = 0;
69    
70     int err = stat(dir, &filestat);
71     if(err) {
72     if(mkdir(dir, S_IRWXU) != 0) {
73     perror("mkdir()");
74     *p++ = tmp;
75     return -1;
76     }
77     } else {
78     if(!filestat.st_mode & S_IFDIR) {
79     printf("File %s exists and is _no_ directory\n", dir);
80     *p++ = tmp;
81     return -1;
82     }
83     }
84    
85     *p++ = tmp;
86     } while(tmp && strchr(p, '/'));
87    
88     return 0;
89     }
90    
91     void pos_lat_str(char *str, int len, float latitude) {
92     char *c = _("N");
93     float integral, fractional;
94    
95 harbaum 13 if(isnan(latitude))
96     str[0] = 0;
97     else {
98     if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
99     fractional = modff(latitude, &integral);
100 harbaum 1
101 harbaum 13 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
102     }
103 harbaum 1 }
104    
105     GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
106     char str[32];
107    
108     pos_lat_str(str, sizeof(str), latitude);
109     return gtk_label_attrib(str, size, strikethrough);
110     }
111    
112     void pos_lon_str(char *str, int len, float longitude) {
113     char *c = _("E");
114     float integral, fractional;
115    
116 harbaum 13 if(isnan(longitude))
117     str[0] = 0;
118     else {
119     if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
120     fractional = modff(longitude, &integral);
121 harbaum 1
122 harbaum 13 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
123     }
124 harbaum 1 }
125    
126     GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
127     char str[32];
128    
129     pos_lon_str(str, sizeof(str), longitude);
130     return gtk_label_attrib(str, size, strikethrough);
131     }
132    
133     float pos_parse_lat(char *str) {
134     int integral_int;
135     float fractional;
136     char c;
137    
138     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
139     c = toupper(c);
140    
141     if(c != 'S' && c != 'N')
142     return NAN;
143    
144     /* prevent -0.0 */
145     if(!integral_int && (fractional == 0.0))
146     return 0.0;
147    
148     return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
149     }
150    
151     return NAN;
152     }
153    
154     float pos_parse_lon(char *str) {
155     int integral_int;
156     float fractional;
157     char c;
158    
159     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
160     c = toupper(c);
161    
162     /* O is german "Ost" for "East" */
163     if(c != 'E' && c != 'W' && c != 'O')
164     return NAN;
165    
166     /* prevent -0.0 */
167     if(!integral_int && (fractional == 0.0))
168     return 0.0;
169    
170     return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
171     }
172    
173     return NAN;
174     }
175    
176     const char *pos_get_bearing_str(pos_t from, pos_t to) {
177     static const char *bear_str[]={
178 harbaum 185 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
179    
180     float bearing = gpx_pos_get_bearing(from, to);
181     if(!isnan(bearing)) {
182     int idx = (bearing+22.5)/45.0;
183     /* make sure we stay in icon bounds */
184     while(idx < 0) idx += 8;
185     while(idx > 7) idx -= 8;
186     return _(bear_str[idx]);
187     }
188    
189     return bear_str[8]; // empty string
190 harbaum 1 }
191    
192     /* the maemo font size is quite huge, so we adjust some fonts */
193     /* differently on maemo and non-maemo. Basically "BIG" does nothing */
194     /* on maemo and "SMALL" only does something on maemo */
195     #ifdef USE_MAEMO
196     #define MARKUP_SMALL "<span size='small'>%s</span>"
197     GtkWidget *gtk_label_small(char *str) {
198     GtkWidget *label = gtk_label_new("");
199     char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
200     gtk_label_set_markup(GTK_LABEL(label), markup);
201     g_free(markup);
202     return label;
203     }
204     #else
205     #define MARKUP_BIG "<span size='x-large'>%s</span>"
206     GtkWidget *gtk_label_big(char *str) {
207     GtkWidget *label = gtk_label_new("");
208     char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
209     gtk_label_set_markup(GTK_LABEL(label), markup);
210     g_free(markup);
211     return label;
212     }
213     #endif
214    
215     void gtk_label_attrib_set(GtkWidget *label,
216     char *str, int size, int strikethrough) {
217     char format[80];
218    
219     snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
220     #ifdef USE_MAEMO
221     (size==SIZE_SMALL)?" size='small'":"",
222     #else
223     (size==SIZE_BIG)?" size='x-large'":"",
224     #endif
225     strikethrough?" strikethrough='yes'":"",
226     (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
227    
228     char *markup = g_markup_printf_escaped(format, str);
229     // printf("markup = %s\n", markup);
230     gtk_label_set_markup(GTK_LABEL(label), markup);
231     g_free(markup);
232     }
233    
234     GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
235     GtkWidget *label = gtk_label_new("");
236     gtk_label_attrib_set(label, str, size, strikethrough);
237     return label;
238     }
239    
240     GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
241     GtkWidget *button = gtk_button_new_with_label("");
242     gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
243     str, size, strikethrough);
244     return button;
245     }
246    
247     void textbox_disable(GtkWidget *widget) {
248     gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
249     gtk_widget_set_sensitive(widget, FALSE);
250     }
251    
252     void textbox_enable(GtkWidget *widget) {
253     gtk_widget_set_sensitive(widget, TRUE);
254     gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
255     }
256    
257     pos_t *get_pos(appdata_t *appdata) {
258     pos_t *pos = &appdata->home;
259    
260     if(appdata->active_location) {
261     int i = appdata->active_location-1;
262     location_t *loc = appdata->location;
263     while(i--) loc = loc->next;
264     pos = &loc->pos;
265     }
266    
267     if(appdata->use_gps) {
268     pos = gps_get_pos(appdata);
269    
270     if(!pos) pos = &appdata->gps; /* use saved position */
271     else appdata->gps = *pos; /* save position */
272     }
273     return pos;
274     }
275    
276     void distance_str(char *str, int len, float dist, gboolean imperial) {
277 harbaum 34 if(isnan(dist))
278     snprintf(str, len, "---");
279     else if(imperial) {
280 harbaum 1 /* 1 mil = 1760 yd = 5280 ft ... */
281     if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
282     else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
283     else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
284     else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
285     else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
286     else snprintf(str, len, "%.0f mi", dist);
287     } else {
288     if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
289     else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
290     else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
291     else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
292     else snprintf(str, len, "%.0f km", dist);
293     }
294     }
295    
296     /* return distance in miles or kilometers */
297     float distance_parse(char *str, gboolean imperial) {
298     char unit[4];
299     float val = NAN;
300    
301     if(sscanf(str, "%f %3s", &val, unit) == 2) {
302     gboolean fimp = FALSE;
303    
304     if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
305     else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
306     else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
307     else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
308     else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
309     else val = NAN;
310    
311     /* found imperial and metric requested? convert miles into kilometers */
312     if(fimp & !imperial) val *= 1.609344;
313    
314     /* found metric and imperial requested? convert kilometers into miles */
315     if(!fimp & imperial) val /= 1.609344;
316     }
317     return val;
318     }
319    
320 harbaum 221 /* ------------------ coordinate picker tool --------------------------- */
321    
322 harbaum 223 #ifndef COORDINATE_PICKER
323 harbaum 1 static gboolean mark(GtkWidget *widget, gboolean valid) {
324     gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
325     return valid;
326     }
327    
328 harbaum 226 GtkWidget *red_entry_new_with_text(char *str) {
329 harbaum 223 GdkColor color;
330    
331     GtkWidget *widget = entry_new();
332     gdk_color_parse("#ff0000", &color);
333     gtk_widget_modify_text(widget, TAG_STATE, &color);
334 harbaum 226 if(str) gtk_entry_set_text(GTK_ENTRY(widget), str);
335    
336 harbaum 223 return widget;
337     }
338    
339 harbaum 1 static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
340     float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
341     mark(widget, !isnan(i));
342     }
343 harbaum 221 #else
344 harbaum 223 static void picker_center_iter(GtkWidget *view, GtkTreeIter *iter) {
345     /* select new iter */
346     GtkTreeSelection *selection =
347     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
348     GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
349     gtk_tree_selection_select_iter(selection, iter);
350     GtkTreePath *path =
351     gtk_tree_model_get_path(model, iter);
352     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
353     path, NULL, TRUE, 0.5, 0.5);
354     gtk_tree_path_free(path);
355     }
356    
357     static void on_picker_activated(GtkTreeView *treeview,
358     GtkTreePath *path,
359     GtkTreeViewColumn *col,
360     gpointer userdata) {
361     gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeview),
362     path, NULL, TRUE, 0.5, 0.5);
363     }
364    
365     #define DUMMY_NUM 1
366    
367     static void dummy_append(GtkListStore *store, int n) {
368     GtkTreeIter iter;
369    
370     while(n--) {
371     gtk_list_store_append (store, &iter);
372     gtk_list_store_set(store, &iter, 0, "", 1, -1, 2, FALSE, -1);
373     }
374     }
375    
376     static GtkWidget *string_picker_create(const char *str[], int sel) {
377 harbaum 221 #ifndef FREMANTLE
378     GtkWidget *view = gtk_tree_view_new();
379     #else
380     GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
381     #endif
382 harbaum 1
383 harbaum 221 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
384     GtkTreeSelection *selection =
385     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
386    
387     /* --- "char" column --- */
388     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
389     g_object_set(renderer, "xalign", 0.5, NULL );
390     gtk_tree_view_insert_column_with_attributes(
391 harbaum 223 GTK_TREE_VIEW(view), -1, "str", renderer,
392     "text", 0,
393     "sensitive", 2,
394     NULL);
395 harbaum 221
396 harbaum 223 GtkListStore *store =
397     gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
398 harbaum 221
399 harbaum 223 dummy_append(store, DUMMY_NUM);
400 harbaum 221
401 harbaum 223 /* add strings */
402     GtkTreeIter iter, siter;
403     int i;
404     for(i=0;*str;str++,i++) {
405     gtk_list_store_append (store, &iter);
406     gtk_list_store_set(store, &iter, 0, _(*str), 1, i, 2, TRUE, -1);
407     if(i == sel) siter = iter;
408     }
409    
410     dummy_append(store, DUMMY_NUM);
411    
412 harbaum 221 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
413     g_object_unref(store);
414    
415 harbaum 223 #ifndef FREMANTLE
416     g_signal_connect(view, "row-activated",
417     (GCallback)on_picker_activated, NULL);
418     #else
419     g_signal_connect(view, "hildon-row-tapped",
420     (GCallback)on_picker_activated, NULL);
421     #endif
422    
423 harbaum 221 /* select right character */
424 harbaum 223 gtk_tree_selection_select_iter(selection, &siter);
425     picker_center_iter(view, &siter);
426 harbaum 221
427     /* put this inside a scrolled view */
428     #ifndef USE_PANNABLE_AREA
429     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
430     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
431     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
432     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
433     return scrolled_window;
434     #else
435     GtkWidget *pannable_area = hildon_pannable_area_new();
436     gtk_container_add(GTK_CONTAINER(pannable_area), view);
437     return pannable_area;
438     #endif
439     }
440    
441     static int picker_get(GtkWidget *widget) {
442     GtkWidget *view = gtk_bin_get_child(GTK_BIN(widget));
443    
444     GtkTreeSelection *sel =
445     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
446    
447     GtkTreeModel *model;
448     GtkTreeIter iter;
449    
450     /* there should never be an unseletced column. But if */
451     /* it is, we count it as zero */
452     if(!gtk_tree_selection_get_selected(sel, &model, &iter))
453     return 0;
454    
455     int retval = 0;
456     gtk_tree_model_get(model, &iter, 1, &retval, -1);
457     return retval;
458     }
459    
460     static GtkWidget *digit_picker_create(int min, int max, int sel) {
461     #ifndef FREMANTLE
462     GtkWidget *view = gtk_tree_view_new();
463     #else
464     GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
465     #endif
466    
467     gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
468     GtkTreeSelection *selection =
469     gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
470    
471     /* --- "digit" column --- */
472     GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
473     g_object_set(renderer, "xalign", 0.5, NULL );
474     gtk_tree_view_insert_column_with_attributes(
475 harbaum 223 GTK_TREE_VIEW(view), -1, "digit", renderer,
476     "text", 0,
477     "sensitive", 2,
478     NULL);
479 harbaum 221
480 harbaum 223 GtkListStore *store =
481     gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
482 harbaum 221
483 harbaum 223 dummy_append(store, DUMMY_NUM);
484    
485 harbaum 221 /* add digits */
486     int i;
487     GtkTreeIter siter;
488     for(i=min;i<=max;i++) {
489     char str[2] = { '0'+i, 0 };
490     GtkTreeIter iter;
491     /* Append a row and fill in some data */
492     gtk_list_store_append (store, &iter);
493 harbaum 223 gtk_list_store_set(store, &iter, 0, str, 1, i, 2, TRUE, -1);
494 harbaum 221
495     if(i == sel) siter = iter;
496     }
497    
498 harbaum 223 dummy_append(store, DUMMY_NUM);
499    
500 harbaum 221 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
501     g_object_unref(store);
502    
503 harbaum 223 #ifndef FREMANTLE
504     g_signal_connect(view, "row-activated",
505     (GCallback)on_picker_activated, NULL);
506     #else
507     g_signal_connect(view, "hildon-row-tapped",
508     (GCallback)on_picker_activated, NULL);
509     #endif
510    
511 harbaum 221 gtk_tree_selection_select_iter(selection, &siter);
512 harbaum 223 picker_center_iter(view, &siter);
513 harbaum 221
514     /* put this inside a scrolled view */
515     #ifndef USE_PANNABLE_AREA
516     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
517     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
518     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
519     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
520     return scrolled_window;
521     #else
522     GtkWidget *pannable_area = hildon_pannable_area_new();
523     gtk_container_add(GTK_CONTAINER(pannable_area), view);
524     return pannable_area;
525     #endif
526     }
527    
528     static gint on_lat_picker_button_press(GtkWidget *button,
529     GdkEventButton *event, gpointer data) {
530    
531     if(event->type == GDK_BUTTON_PRESS) {
532     GtkWidget *dialog =
533     gtk_dialog_new_with_buttons(_("Latitude"),
534     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
535     GTK_DIALOG_MODAL,
536     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
537     _("Done"), GTK_RESPONSE_ACCEPT,
538     NULL);
539    
540 harbaum 223 gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
541 harbaum 221
542     int i, lat = (int)g_object_get_data(G_OBJECT(button), "latitude");
543    
544     /* parse latitude into components */
545     int sign = (lat>=0)?0:1;
546     lat = abs(lat);
547     int deg = lat / 60000;
548     int min = (lat /1000)%60;
549     int minfrac = lat % 1000;
550    
551     GtkWidget *signw, *degw[2], *minw[2], *minfracw[3];
552    
553    
554     /* create N/S 89° 99.999 */
555     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
556 harbaum 223 static const char *ns[] = { "N", "S", NULL };
557 harbaum 221 gtk_box_pack_start_defaults(GTK_BOX(hbox),
558 harbaum 223 signw = string_picker_create(ns, sign));
559 harbaum 221
560     gtk_box_pack_start_defaults(GTK_BOX(hbox),
561     degw[0] = digit_picker_create(0,8, deg/10));
562     gtk_box_pack_start_defaults(GTK_BOX(hbox),
563     degw[1] = digit_picker_create(0,9, deg%10));
564     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
565    
566     gtk_box_pack_start_defaults(GTK_BOX(hbox),
567     minw[0] = digit_picker_create(0,5, min/10));
568     gtk_box_pack_start_defaults(GTK_BOX(hbox),
569     minw[1] = digit_picker_create(0,9, min%10));
570     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
571    
572     gtk_box_pack_start_defaults(GTK_BOX(hbox),
573     minfracw[0] = digit_picker_create(0,9, minfrac/100));
574     gtk_box_pack_start_defaults(GTK_BOX(hbox),
575     minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
576     gtk_box_pack_start_defaults(GTK_BOX(hbox),
577     minfracw[2] = digit_picker_create(0,9, minfrac%10));
578    
579     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
580    
581     gtk_widget_show_all(dialog);
582     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
583    
584     /* parse degrees ... */
585     for(deg=0,i=0;i<2;i++)
586     deg = 10 * deg + picker_get(degw[i]);
587    
588     /* ... minutes ... */
589     for(min=0,i=0;i<2;i++)
590     min = 10 * min + picker_get(minw[i]);
591    
592     /* ... and fractions of minutes */
593     for(minfrac=0,i=0;i<3;i++)
594     minfrac = 10 * minfrac + picker_get(minfracw[i]);
595    
596 harbaum 223 /* parse N/S */
597     if(deg | min | minfrac)
598     sign = picker_get(signw)?-1:1;
599     else
600     sign = 1; // theres no S 00 00.000
601    
602 harbaum 221 float latitude = sign * (deg + min/60.0 + minfrac/60000.0);
603     lat_entry_set(button, latitude);
604     }
605    
606     gtk_widget_destroy(dialog);
607    
608     return TRUE;
609     }
610     return FALSE;
611     }
612     #endif
613    
614 harbaum 1 /* a entry that is colored red when being "active" */
615     GtkWidget *lat_entry_new(float lat) {
616 harbaum 221 char str[32];
617     pos_lat_str(str, sizeof(str), lat);
618    
619     #ifndef COORDINATE_PICKER
620 harbaum 226 GtkWidget *widget = red_entry_new_with_text(str);
621 harbaum 190
622 harbaum 1 g_signal_connect(G_OBJECT(widget), "changed",
623     G_CALLBACK(callback_modified_lat), NULL);
624    
625 harbaum 221 #else
626     GtkWidget *widget = gtk_button_new_with_label(str);
627    
628     #ifdef FREMANTLE
629     hildon_gtk_widget_set_theme_size(widget,
630     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
631     #endif
632     int lat_int = (int)roundf(lat * 60000);
633     g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
634     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
635     (GtkSignalFunc)on_lat_picker_button_press, NULL);
636     #endif
637 harbaum 223
638 harbaum 1 return widget;
639     }
640    
641 harbaum 221 #ifndef COORDINATE_PICKER
642 harbaum 1 static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
643     float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
644     mark(widget, !isnan(i));
645     }
646 harbaum 221 #else
647     static gint on_lon_picker_button_press(GtkWidget *button,
648     GdkEventButton *event, gpointer data) {
649 harbaum 1
650 harbaum 221 if(event->type == GDK_BUTTON_PRESS) {
651     GtkWidget *dialog =
652     gtk_dialog_new_with_buttons(_("Longitude"),
653     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
654     GTK_DIALOG_MODAL,
655     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
656     _("Done"), GTK_RESPONSE_ACCEPT,
657     NULL);
658    
659 harbaum 223 gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
660 harbaum 221
661     int i, lat = (int)g_object_get_data(G_OBJECT(button), "longitude");
662    
663     /* parse latitude into components */
664     int sign = (lat>=0)?0:1;
665     lat = abs(lat);
666     int deg = lat / 60000;
667     int min = (lat /1000)%60;
668     int minfrac = lat % 1000;
669    
670     GtkWidget *signw, *degw[3], *minw[2], *minfracw[3];
671    
672     /* create E/W 179° 99.999 */
673     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
674 harbaum 223 static const char *ew[] = { "E", "W", NULL };
675 harbaum 221 gtk_box_pack_start_defaults(GTK_BOX(hbox),
676 harbaum 223 signw = string_picker_create(ew, sign));
677 harbaum 221
678     gtk_box_pack_start_defaults(GTK_BOX(hbox),
679     degw[0] = digit_picker_create(0,1, deg/100));
680     gtk_box_pack_start_defaults(GTK_BOX(hbox),
681     degw[1] = digit_picker_create(0,9, (deg/10)%10));
682     gtk_box_pack_start_defaults(GTK_BOX(hbox),
683     degw[2] = digit_picker_create(0,9, deg%10));
684     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
685    
686     gtk_box_pack_start_defaults(GTK_BOX(hbox),
687     minw[0] = digit_picker_create(0,5, min/10));
688     gtk_box_pack_start_defaults(GTK_BOX(hbox),
689     minw[1] = digit_picker_create(0,9, min%10));
690     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
691    
692     gtk_box_pack_start_defaults(GTK_BOX(hbox),
693     minfracw[0] = digit_picker_create(0,9, minfrac/100));
694     gtk_box_pack_start_defaults(GTK_BOX(hbox),
695     minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
696     gtk_box_pack_start_defaults(GTK_BOX(hbox),
697     minfracw[2] = digit_picker_create(0,9, minfrac%10));
698    
699     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
700    
701     gtk_widget_show_all(dialog);
702     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
703    
704     /* parse degrees ... */
705     for(deg=0,i=0;i<3;i++)
706     deg = 10 * deg + picker_get(degw[i]);
707    
708     /* ... minutes ... */
709     for(min=0,i=0;i<2;i++)
710     min = 10 * min + picker_get(minw[i]);
711    
712     /* ... and fractions of minutes */
713     for(minfrac=0,i=0;i<3;i++)
714     minfrac = 10 * minfrac + picker_get(minfracw[i]);
715    
716 harbaum 223 if(deg | min | minfrac)
717     sign = picker_get(signw)?-1:1;
718     else
719     sign = 1; // theres no W 00 00.000
720    
721 harbaum 221 float longitude = sign * (deg + min/60.0 + minfrac/60000.0);
722     lon_entry_set(button, longitude);
723     }
724    
725     gtk_widget_destroy(dialog);
726    
727     return TRUE;
728     }
729     return FALSE;
730     }
731     #endif
732    
733 harbaum 1 /* a entry that is colored red when filled with invalid coordinate */
734     GtkWidget *lon_entry_new(float lon) {
735 harbaum 221 char str[32];
736     pos_lon_str(str, sizeof(str), lon);
737    
738     #ifndef COORDINATE_PICKER
739 harbaum 226 GtkWidget *widget = red_entry_new_with_text(str);
740 harbaum 1 g_signal_connect(G_OBJECT(widget), "changed",
741     G_CALLBACK(callback_modified_lon), NULL);
742    
743 harbaum 221 #else
744     GtkWidget *widget = gtk_button_new_with_label(str);
745    
746     #ifdef FREMANTLE
747     hildon_gtk_widget_set_theme_size(widget,
748     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
749     #endif
750     int lon_int = (int)roundf(lon * 60000);
751     g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
752     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
753     (GtkSignalFunc)on_lon_picker_button_press, NULL);
754     #endif
755    
756 harbaum 1 return widget;
757     }
758    
759 harbaum 221 float lat_entry_get(GtkWidget *widget) {
760     #ifndef COORDINATE_PICKER
761 harbaum 1 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
762 harbaum 221 #else
763     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
764     #endif
765 harbaum 1 return pos_parse_lat(p);
766     }
767    
768 harbaum 221 float lon_entry_get(GtkWidget *widget) {
769     #ifndef COORDINATE_PICKER
770 harbaum 1 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
771 harbaum 221 #else
772     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
773     #endif
774 harbaum 1 return pos_parse_lon(p);
775     }
776    
777 harbaum 221 void lat_entry_set(GtkWidget *widget, float lat) {
778     char str[32];
779     pos_lat_str(str, sizeof(str)-1, lat);
780     #ifndef COORDINATE_PICKER
781     gtk_entry_set_text(GTK_ENTRY(widget), str);
782     #else
783     gtk_button_set_label(GTK_BUTTON(widget), str);
784     int lat_int = (int)roundf(lat * 60000);
785     g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
786 harbaum 223 g_signal_emit_by_name(widget, "changed");
787 harbaum 221 #endif
788     }
789    
790     void lon_entry_set(GtkWidget *widget, float lon) {
791     char str[32];
792     pos_lon_str(str, sizeof(str)-1, lon);
793     #ifndef COORDINATE_PICKER
794     gtk_entry_set_text(GTK_ENTRY(widget), str);
795     #else
796     gtk_button_set_label(GTK_BUTTON(widget), str);
797     int lon_int = (int)roundf(lon * 60000);
798     g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
799 harbaum 223 g_signal_emit_by_name(widget, "changed");
800 harbaum 221 #endif
801     }
802    
803     void lat_label_set(GtkWidget *widget, float lat) {
804     char str[32];
805     pos_lat_str(str, sizeof(str)-1, lat);
806     gtk_label_set(GTK_LABEL(widget), str);
807     }
808    
809     void lon_label_set(GtkWidget *widget, float lon) {
810     char str[32];
811     pos_lon_str(str, sizeof(str)-1, lon);
812     gtk_label_set(GTK_LABEL(widget), str);
813     }
814    
815     void lat_label_attrib_set(GtkWidget *widget, float lat,
816     int size, int strikethrough) {
817     char str[32];
818     pos_lat_str(str, sizeof(str)-1, lat);
819     gtk_label_attrib_set(widget, str, size, strikethrough);
820     }
821    
822     void lon_label_attrib_set(GtkWidget *widget, float lon,
823     int size, int strikethrough) {
824     char str[32];
825     pos_lon_str(str, sizeof(str)-1, lon);
826     gtk_label_attrib_set(widget, str, size, strikethrough);
827     }
828    
829 harbaum 223 #ifndef COORDINATE_PICKER
830 harbaum 1 static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
831     /* don't care for metric/imperial since we only want to know if this */
832     /* is parseable at all */
833 harbaum 223 float i =
834     distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
835 harbaum 1 mark(widget, !isnan(i));
836     }
837 harbaum 223 #else
838     static gint on_dist_picker_button_press(GtkWidget *button,
839     GdkEventButton *event, gpointer data) {
840 harbaum 1
841 harbaum 223 if(event->type == GDK_BUTTON_PRESS) {
842     GtkWidget *dialog =
843     gtk_dialog_new_with_buttons(_("Distance"),
844     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
845     GTK_DIALOG_MODAL,
846     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
847     _("Done"), GTK_RESPONSE_ACCEPT,
848     NULL);
849    
850     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
851    
852     /* distance is given in m or ft (depending on mil) */
853     int i, dist = (int)g_object_get_data(G_OBJECT(button), "distance");
854     gboolean mil = (gboolean)g_object_get_data(G_OBJECT(button), "mil");
855     int unit = 0;
856    
857     /* parse distance into components */
858     if(mil) {
859     /* 1 mil = 1760 yd = 5280 ft. 1yd = 3 ft */
860     if(dist<95) { unit = 0; dist *= 100; }
861     else if(dist<2904) { unit = 1; dist = 100 * dist / 3; }
862     else { unit = 2; dist = 5 * dist / 264; }
863     } else {
864     if(dist<1000) { unit = 3; dist *= 100; }
865     else { unit = 4; dist /= 10; }
866     }
867    
868     GtkWidget *distw[4], *fracw[2], *unitw;
869    
870     /* create xxxx.x unit */
871     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
872    
873     gtk_box_pack_start_defaults(GTK_BOX(hbox),
874     distw[0] = digit_picker_create(0,9, (dist/100000)%10));
875     gtk_box_pack_start_defaults(GTK_BOX(hbox),
876     distw[1] = digit_picker_create(0,9, (dist/10000)%10));
877     gtk_box_pack_start_defaults(GTK_BOX(hbox),
878     distw[2] = digit_picker_create(0,9, (dist/1000)%10));
879     gtk_box_pack_start_defaults(GTK_BOX(hbox),
880     distw[3] = digit_picker_create(0,9, (dist/100)%10));
881     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
882     gtk_box_pack_start_defaults(GTK_BOX(hbox),
883     fracw[0] = digit_picker_create(0,9, (dist/10)%10));
884     gtk_box_pack_start_defaults(GTK_BOX(hbox),
885     fracw[1] = digit_picker_create(0,9, (dist/1)%10));
886    
887     static const char *units[] = { "ft", "yd", "mi", "m", "km", NULL };
888     gtk_box_pack_start_defaults(GTK_BOX(hbox),
889     unitw = string_picker_create(units, unit));
890    
891     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
892    
893     gtk_widget_show_all(dialog);
894     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
895    
896     /* parse distance */
897     for(dist=0,i=0;i<4;i++)
898     dist = 10 * dist + picker_get(distw[i]);
899    
900     for(i=0;i<2;i++)
901     dist = 10 * dist + picker_get(fracw[i]);
902    
903     unit = picker_get(unitw);
904     if(unit == 0) { dist /= 100; } // ft
905     else if(unit == 1) { dist = 3*dist/100; } // yd
906     else if(unit == 2) { dist = 528*dist/10; } // mi
907     else if(unit == 3) { dist /= 100; } // m
908     else if(unit == 4) { dist *= 10; } // km
909    
910     /* user may have switched between metric and imperial */
911     float distance;
912     if(unit <= 2) {
913     distance = dist / 5280.0;
914     if(!mil) distance *= 1.609344;
915     } else {
916     distance = dist / 1000.0;
917     if( mil) distance /= 1.609344;
918     }
919    
920     dist_entry_set(button, distance, mil);
921     }
922    
923     gtk_widget_destroy(dialog);
924    
925     return TRUE;
926     }
927     return FALSE;
928     }
929     #endif
930    
931 harbaum 1 /* a entry that is colored red when filled with invalid distance */
932     GtkWidget *dist_entry_new(float dist, gboolean mil) {
933 harbaum 223 char str[32];
934     distance_str(str, sizeof(str), dist, mil);
935    
936     #ifndef COORDINATE_PICKER
937 harbaum 226 GtkWidget *widget = red_entry_new_with_text(str);
938 harbaum 1 g_signal_connect(G_OBJECT(widget), "changed",
939     G_CALLBACK(callback_modified_dist), NULL);
940    
941 harbaum 223 #else
942     GtkWidget *widget = gtk_button_new_with_label(str);
943    
944     #ifdef FREMANTLE
945     hildon_gtk_widget_set_theme_size(widget,
946     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
947     #endif
948     int dist_int = (int)roundf(dist * 1000); // km -> m
949     if(mil) dist_int = (int)roundf(dist * 5280.0); // mi -> ft
950    
951     g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
952     g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
953     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
954     (GtkSignalFunc)on_dist_picker_button_press, NULL);
955     #endif
956    
957 harbaum 1 return widget;
958     }
959    
960 harbaum 223 float dist_entry_get(GtkWidget *widget, gboolean mil) {
961     #ifndef COORDINATE_PICKER
962 harbaum 1 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
963 harbaum 223 #else
964     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
965     #endif
966 harbaum 1 return distance_parse(p, mil);
967     }
968    
969 harbaum 223 void dist_entry_set(GtkWidget *widget, float dist, gboolean mil) {
970     char str[32];
971     distance_str(str, sizeof(str), dist, mil);
972    
973     #ifndef COORDINATE_PICKER
974     gtk_entry_set_text(GTK_ENTRY(widget), str);
975     #else
976     int dist_int = (int)roundf(dist * 1000); // km -> m
977     if(mil) dist_int = (int)roundf(dist * 5280.0); // mi -> ft
978     g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
979     g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
980     gtk_button_set_label(GTK_BUTTON(widget), str);
981     #endif
982     }
983    
984 harbaum 1 #ifndef USE_MAEMO
985     #ifdef ENABLE_BROWSER_INTERFACE
986     #include <libgnome/gnome-url.h>
987    
988     int browser_url(appdata_t *appdata, char *url) {
989     /* taken from gnome-open, part of libgnome */
990     GError *err = NULL;
991     gnome_url_show(url, &err);
992     return 0;
993     }
994     #endif
995     #endif
996 harbaum 77
997     /* recursively remove an entire file system */
998     void rmdir_recursive(char *path) {
999     GDir *dir = g_dir_open(path, 0, NULL);
1000     if(dir) {
1001     const char *name = g_dir_read_name(dir);
1002     while(name) {
1003     char *fullname = g_strdup_printf("%s/%s", path, name);
1004     // printf("deleting %s\n", fullname);
1005    
1006     if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
1007     rmdir_recursive(fullname);
1008     else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
1009     g_remove(fullname);
1010    
1011     g_free(fullname);
1012     name = g_dir_read_name(dir);
1013     }
1014    
1015     g_dir_close(dir);
1016     }
1017     g_rmdir(path);
1018     }
1019    
1020 harbaum 137 #ifdef ENABLE_BROWSER_INTERFACE
1021     static void on_link_clicked(GtkButton *button, gpointer data) {
1022     appdata_t *appdata = (appdata_t*)data;
1023     char *url = g_object_get_data(G_OBJECT(button), "url");
1024     if(url) browser_url(appdata, url);
1025     }
1026     #endif
1027    
1028     /* a button containing a weblink */
1029     GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
1030     int size, int strikethrough) {
1031    
1032     #ifdef ENABLE_BROWSER_INTERFACE
1033     if(url) {
1034     GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
1035     g_object_set_data(G_OBJECT(button), "url", url);
1036     gtk_signal_connect(GTK_OBJECT(button), "clicked",
1037     (GtkSignalFunc)on_link_clicked, appdata);
1038    
1039     return button;
1040     }
1041     #endif
1042     return gtk_label_attrib(str, size, strikethrough);
1043     }
1044    
1045     #ifdef ENABLE_BROWSER_INTERFACE
1046     static void on_link_id_clicked(GtkButton *button, gpointer data) {
1047     appdata_t *appdata = (appdata_t*)data;
1048    
1049     unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
1050     char *type = g_object_get_data(G_OBJECT(button), "type");
1051    
1052     char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
1053     type, id);
1054    
1055     if(url) {
1056     browser_url(appdata, url);
1057     g_free(url);
1058     }
1059     }
1060     #endif
1061    
1062     GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
1063     const char *type, int id) {
1064    
1065     #ifdef ENABLE_BROWSER_INTERFACE
1066     if(id) {
1067     GtkWidget *ref = gtk_button_new_with_label(str);
1068     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1069     // hildon_gtk_widget_set_theme_size(ref,
1070     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1071     #endif
1072     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1073     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1074     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1075     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1076    
1077     return ref;
1078     }
1079     #endif
1080     return gtk_label_new(str);
1081     }
1082    
1083 harbaum 138
1084     GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
1085     const char *type, int id) {
1086    
1087     #ifdef ENABLE_BROWSER_INTERFACE
1088     if(id) {
1089     GtkWidget *ref = gtk_button_new();
1090     gtk_button_set_image(GTK_BUTTON(ref), icon);
1091    
1092     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1093     // hildon_gtk_widget_set_theme_size(ref,
1094     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1095     #endif
1096     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1097     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1098     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1099     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1100    
1101     return ref;
1102     }
1103     #endif
1104     return icon;
1105     }
1106    
1107 harbaum 165 /* left aligned, word wrapped multiline widget */
1108     GtkWidget *simple_text_widget(char *text) {
1109     GtkWidget *label = gtk_label_new(text);
1110    
1111     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1112     gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
1113     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1114    
1115     return label;
1116     }
1117 harbaum 198
1118    
1119     /* a label that is left aligned */
1120     GtkWidget *left_label_new(char *str) {
1121     GtkWidget *widget = gtk_label_new(str);
1122     gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
1123     return widget;
1124     }
1125 harbaum 212
1126 harbaum 221 /* ------------- preset coordinate picker tool ----------------- */
1127    
1128 harbaum 217 static void pos_set(GtkWidget *item, float lat, float lon) {
1129 harbaum 212
1130     GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1131 harbaum 221 lat_entry_set(lat_entry, lat);
1132 harbaum 212
1133     GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1134 harbaum 221 lon_entry_set(lon_entry, lon);
1135 harbaum 212 }
1136    
1137 harbaum 217 static void cb_gps(GtkWidget *item, gpointer data) {
1138 harbaum 212 appdata_t *appdata = (appdata_t*)data;
1139 harbaum 218 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1140     pos_t *pos = NULL;
1141 harbaum 212
1142 harbaum 218 if(!id)
1143     pos = gps_get_pos(appdata);
1144     else if(id == 1)
1145     pos = &appdata->home;
1146     else {
1147     location_t *location = appdata->location;
1148     while(location && id > 2) {
1149     location = location->next;
1150     id--;
1151     }
1152    
1153     if(id == 2)
1154     pos = &location->pos;
1155     }
1156    
1157     if(!pos) pos_set(item, NAN, NAN);
1158     else pos_set(item, pos->lat, pos->lon);
1159 harbaum 212 }
1160    
1161 harbaum 217 static void cb_geomath(GtkWidget *item, gpointer data) {
1162 harbaum 212 appdata_t *appdata = (appdata_t*)data;
1163    
1164     pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
1165     }
1166    
1167     #ifdef ENABLE_OSM_GPS_MAP
1168 harbaum 217 static void cb_map(GtkWidget *item, gpointer data) {
1169 harbaum 212 appdata_t *appdata = (appdata_t*)data;
1170    
1171     pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
1172     }
1173     #endif
1174    
1175 harbaum 231 #ifdef ENABLE_MAEMO_MAPPER
1176     static void cb_mm(GtkWidget *item, gpointer data) {
1177     appdata_t *appdata = (appdata_t*)data;
1178    
1179     pos_set(item, appdata->mmpos.lat, appdata->mpos.lon);
1180     }
1181     #endif
1182    
1183 harbaum 217 static void cb_cache(GtkWidget *item, gpointer data) {
1184 harbaum 212 appdata_t *appdata = (appdata_t*)data;
1185 harbaum 217
1186 harbaum 212 cache_t *cache = appdata->cur_cache;
1187     g_assert(cache);
1188    
1189 harbaum 217 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1190    
1191     if(!id)
1192 harbaum 212 pos_set(item, cache->pos.lat, cache->pos.lon);
1193 harbaum 228 else if(id == 1) {
1194     /* fetch position out of notes dialog since they probably */
1195     /* haven't been saved yet */
1196     pos_t pos = notes_get_pos(appdata->cache_context);
1197     pos_set(item, pos.lat, pos.lon);
1198     } else {
1199 harbaum 212 wpt_t *wpt = cache->wpt;
1200 harbaum 221 while(wpt && id > 2) {
1201 harbaum 212 wpt = wpt->next;
1202 harbaum 217 id--;
1203 harbaum 212 }
1204 harbaum 217
1205 harbaum 221 if(id == 2)
1206 harbaum 217 pos_set(item, wpt->pos.lat, wpt->pos.lon);
1207 harbaum 212 }
1208     }
1209    
1210 harbaum 221 #ifndef PRESET_PICKER_DIALOG
1211 harbaum 212 static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1212     GtkWidget *icon, char *menu_str,
1213 harbaum 217 void(*func)(GtkWidget*, gpointer), gint id,
1214 harbaum 212 GtkWidget *lon_entry, GtkWidget *lat_entry) {
1215    
1216     GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
1217    
1218     if(icon)
1219     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
1220    
1221     g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
1222     g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
1223 harbaum 217 g_object_set_data(G_OBJECT(item), "id", (gpointer)id);
1224 harbaum 212
1225     if(func)
1226     gtk_signal_connect(GTK_OBJECT(item), "activate",
1227     (GtkSignalFunc)func, appdata);
1228    
1229     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1230    
1231     return item;
1232     }
1233    
1234     static GtkWidget *popup_menu_create(appdata_t *appdata,
1235     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1236     GtkWidget *menu = gtk_menu_new();
1237    
1238 harbaum 223 if(pos_valid(gps_get_pos(appdata)))
1239     menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1240     _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1241 harbaum 218
1242 harbaum 223 if(pos_valid(&appdata->home))
1243     menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1244     _("Home"), cb_gps, 1, lon_entry, lat_entry);
1245 harbaum 218
1246     location_t *location = appdata->location;
1247     gint id = 2;
1248     while(location) {
1249 harbaum 223 if(pos_valid(&location->pos))
1250 harbaum 231 menu_add(menu, appdata, icon_get_widget(ICON_POS, 17),
1251 harbaum 223 location->name, cb_gps, id, lon_entry, lat_entry);
1252 harbaum 218
1253 harbaum 223 id++;
1254 harbaum 218 location = location->next;
1255     }
1256    
1257 harbaum 223 if(pos_valid(&appdata->geomath))
1258     menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
1259     _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
1260    
1261 harbaum 212 #ifdef ENABLE_OSM_GPS_MAP
1262 harbaum 223 if(pos_valid(&appdata->map.pos))
1263     menu_add(menu, appdata, icon_get_widget(ICON_POS, 20), _("Map position"),
1264     cb_map, 0, lon_entry, lat_entry);
1265 harbaum 212 #endif
1266 harbaum 214
1267 harbaum 231 #ifdef ENABLE_MAEMO_MAPPER
1268     if(appdata->mmpos_valid) {
1269     menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1270     _("Maemo mapper position"), cb_mm, 0, lon_entry, lat_entry);
1271     }
1272     #endif
1273    
1274 harbaum 212 if(appdata->cur_cache) {
1275     cache_t *cache = appdata->cur_cache;
1276    
1277 harbaum 217 char *name = cache->name;
1278     if(!name) name = cache->id;
1279    
1280 harbaum 221 /* original cache position */
1281 harbaum 223 if(pos_valid(&cache->pos))
1282 harbaum 214 menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1283 harbaum 217 name, cb_cache, 0, lon_entry, lat_entry);
1284 harbaum 212
1285 harbaum 221 /* overwritten cache position */
1286 harbaum 228 if(appdata->cache_context && notes_get_override(appdata->cache_context))
1287 harbaum 221 menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1288     _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1289    
1290 harbaum 212 wpt_t *wpt = cache->wpt;
1291 harbaum 221 gint id = 2;
1292 harbaum 212 while(wpt) {
1293 harbaum 223 if(pos_valid(&wpt->pos)) {
1294     GtkWidget *icon = NULL;
1295     if(wpt->sym != WPT_SYM_UNKNOWN)
1296     icon = icon_get_widget(ICON_POS, wpt->sym);
1297 harbaum 212
1298 harbaum 223 char *name = wpt->desc;
1299     if(!name) name = wpt->cmt;
1300     if(!name) name = wpt->id;
1301    
1302     menu_add(menu, appdata, icon, name, cb_cache, id,
1303     lon_entry, lat_entry);
1304     }
1305 harbaum 217
1306 harbaum 223 id++;
1307 harbaum 212 wpt = wpt->next;
1308     }
1309     }
1310    
1311     gtk_widget_show_all(menu);
1312    
1313     return menu;
1314     }
1315    
1316     static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1317     gpointer data) {
1318    
1319 harbaum 223 appdata_t *appdata = (appdata_t*)data;
1320    
1321 harbaum 212 if(event->type == GDK_BUTTON_PRESS) {
1322     GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1323    
1324 harbaum 223 if(menu)
1325     gtk_widget_destroy(menu);
1326    
1327     gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1328     g_assert(lat_entry);
1329     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1330     g_assert(lon_entry);
1331    
1332     menu = popup_menu_create(appdata, lat_entry, lon_entry);
1333     g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1334    
1335 harbaum 212 /* draw a popup menu */
1336     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1337     event->button, event->time);
1338     return TRUE;
1339     }
1340     return FALSE;
1341     }
1342    
1343     static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1344     GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1345 harbaum 223 if(menu) gtk_widget_destroy(menu);
1346 harbaum 212 }
1347     #endif
1348    
1349 harbaum 221 #ifdef PRESET_PICKER_DIALOG
1350 harbaum 212
1351 harbaum 217 enum {
1352 harbaum 221 PRESET_PICKER_COL_ICON = 0,
1353     PRESET_PICKER_COL_NAME,
1354     PRESET_PICKER_COL_ID,
1355     PRESET_PICKER_COL_CB,
1356     PRESET_PICKER_NUM_COLS
1357 harbaum 217 };
1358 harbaum 212
1359 harbaum 221 static void preset_picker_add(GtkListStore *store, appdata_t *appdata,
1360 harbaum 217 GdkPixbuf *icon, char *menu_str,
1361     void(*func)(GtkWidget*, gpointer), gint id) {
1362     GtkTreeIter iter;
1363 harbaum 212
1364 harbaum 217 /* Append a row and fill in some data */
1365     gtk_list_store_append (store, &iter);
1366 harbaum 212
1367 harbaum 217 gtk_list_store_set(store, &iter,
1368 harbaum 221 PRESET_PICKER_COL_ICON, icon,
1369     PRESET_PICKER_COL_NAME, menu_str,
1370     PRESET_PICKER_COL_ID, id,
1371     PRESET_PICKER_COL_CB, func,
1372 harbaum 217 -1);
1373 harbaum 212 }
1374 harbaum 214
1375 harbaum 221 static void on_preset_picker_activated(GtkTreeView *treeview,
1376 harbaum 217 GtkTreePath *path,
1377     GtkTreeViewColumn *col,
1378     gpointer userdata) {
1379     GtkTreeIter iter;
1380     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1381 harbaum 214
1382 harbaum 217 if(gtk_tree_model_get_iter(model, &iter, path)) {
1383     gint id;
1384     void(*func)(GtkWidget*, gpointer);
1385     gtk_tree_model_get(model, &iter,
1386 harbaum 221 PRESET_PICKER_COL_ID, &id,
1387     PRESET_PICKER_COL_CB, &func,
1388 harbaum 217 -1);
1389    
1390     /* set id on widget as callbacks expect it this way */
1391     g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1392     func(GTK_WIDGET(treeview), userdata);
1393 harbaum 218
1394     gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1395     GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1396    
1397 harbaum 217 }
1398 harbaum 214 }
1399 harbaum 216
1400 harbaum 221 static GtkWidget *preset_picker_create(appdata_t *appdata,
1401 harbaum 217 GtkWidget *lat_entry, GtkWidget *lon_entry) {
1402     GtkCellRenderer *renderer;
1403     GtkListStore *store;
1404    
1405     GtkWidget *view = gtk_tree_view_new();
1406 harbaum 216
1407 harbaum 217 g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1408     g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1409 harbaum 216
1410 harbaum 217 /* --- "Icon" column --- */
1411     renderer = gtk_cell_renderer_pixbuf_new();
1412     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1413 harbaum 221 -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1414 harbaum 216
1415 harbaum 217 /* --- "Name" column --- */
1416     renderer = gtk_cell_renderer_text_new();
1417     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1418     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1419 harbaum 221 "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1420 harbaum 217 gtk_tree_view_column_set_expand(column, TRUE);
1421     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1422 harbaum 216
1423 harbaum 221 store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1424 harbaum 217 GDK_TYPE_PIXBUF,
1425     G_TYPE_STRING,
1426     G_TYPE_INT,
1427     G_TYPE_POINTER);
1428 harbaum 216
1429 harbaum 223 if(pos_valid(gps_get_pos(appdata)))
1430     preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1431     _("GPS position"), cb_gps, 0);
1432 harbaum 218
1433 harbaum 223 if(pos_valid(&appdata->home))
1434     preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1435     _("Home"), cb_gps, 1);
1436 harbaum 218
1437     location_t *location = appdata->location;
1438     gint id = 2;
1439     while(location) {
1440 harbaum 223 if(pos_valid(&location->pos))
1441 harbaum 231 preset_picker_add(store, appdata, icon_get(ICON_POS, 17),
1442 harbaum 223 location->name, cb_gps, id);
1443 harbaum 218
1444 harbaum 223 id++;
1445 harbaum 218 location = location->next;
1446     }
1447    
1448 harbaum 223 if(pos_valid(&appdata->geomath))
1449     preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1450     _("Geomath projection"), cb_geomath, 0);
1451 harbaum 231
1452 harbaum 217 #ifdef ENABLE_OSM_GPS_MAP
1453 harbaum 223 if(pos_valid(&appdata->map.pos))
1454     preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1455     _("Map position"), cb_map, 0);
1456 harbaum 217 #endif
1457 harbaum 216
1458 harbaum 231 #ifdef ENABLE_MAEMO_MAPPER
1459     if(appdata->mmpos_valid) {
1460     preset_picker_add(menu, appdata, icon_get(ICON_POS, 24),
1461     _("Maemo mapper position"), cb_mm, 0);
1462     }
1463     #endif
1464    
1465 harbaum 217 if(appdata->cur_cache) {
1466     cache_t *cache = appdata->cur_cache;
1467 harbaum 216
1468 harbaum 217 char *name = cache->name;
1469     if(!name) name = cache->id;
1470 harbaum 223
1471 harbaum 221 /* original cache position */
1472 harbaum 223 if(pos_valid(&cache->pos))
1473 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1474 harbaum 223 name, cb_cache, 0);
1475 harbaum 216
1476 harbaum 221 /* overwritten cache position */
1477 harbaum 228 if(appdata->cache_context && notes_get_override(appdata->cache_context))
1478 harbaum 221 preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1479 harbaum 223 _("Modified coordinate"), cb_cache, 1);
1480 harbaum 221
1481 harbaum 217 wpt_t *wpt = cache->wpt;
1482 harbaum 221 gint id = 2;
1483 harbaum 217 while(wpt) {
1484 harbaum 223 if(pos_valid(&wpt->pos)) {
1485     GdkPixbuf *icon = NULL;
1486     if(wpt->sym != WPT_SYM_UNKNOWN)
1487     icon = icon_get(ICON_POS, wpt->sym);
1488 harbaum 216
1489 harbaum 223 char *name = wpt->desc;
1490     if(!name) name = wpt->cmt;
1491     if(!name) name = wpt->id;
1492 harbaum 216
1493 harbaum 223 preset_picker_add(store, appdata, icon, name, cb_cache, id);
1494     }
1495     id++;
1496 harbaum 217 wpt = wpt->next;
1497     }
1498     }
1499 harbaum 216
1500 harbaum 217 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1501     g_object_unref(store);
1502    
1503     /* make list react on clicks */
1504     g_signal_connect(view, "row-activated",
1505 harbaum 221 (GCallback)on_preset_picker_activated, appdata);
1506 harbaum 217
1507     /* put this inside a scrolled view */
1508     #ifndef USE_PANNABLE_AREA
1509     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1510     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1511     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1512     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1513     return scrolled_window;
1514     #else
1515     GtkWidget *pannable_area = hildon_pannable_area_new();
1516     gtk_container_add(GTK_CONTAINER(pannable_area), view);
1517     return pannable_area;
1518     #endif
1519 harbaum 216 }
1520    
1521 harbaum 221 static gint on_preset_picker_button_press(GtkWidget *button,
1522 harbaum 217 GdkEventButton *event, gpointer data) {
1523     appdata_t *appdata = (appdata_t*)data;
1524 harbaum 216
1525 harbaum 217 gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1526     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1527    
1528 harbaum 216 if(event->type == GDK_BUTTON_PRESS) {
1529 harbaum 217 GtkWidget *dialog =
1530     gtk_dialog_new_with_buttons(_("Preset coordinates"),
1531     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1532     GTK_DIALOG_MODAL,
1533     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1534     NULL);
1535 harbaum 216
1536 harbaum 223 gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1537 harbaum 216
1538 harbaum 217 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1539 harbaum 221 preset_picker_create(appdata, lat_entry, lon_entry));
1540 harbaum 217
1541 harbaum 216 gtk_widget_show_all(dialog);
1542     gtk_dialog_run(GTK_DIALOG(dialog));
1543     gtk_widget_destroy(dialog);
1544    
1545     return TRUE;
1546     }
1547     return FALSE;
1548     }
1549 harbaum 217 #endif
1550 harbaum 216
1551 harbaum 221
1552     GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1553 harbaum 217 GtkWidget *lat_entry, GtkWidget *lon_entry) {
1554 harbaum 216
1555 harbaum 217 GtkWidget *button = gtk_button_new();
1556 harbaum 216
1557 harbaum 231 gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 22));
1558 harbaum 217
1559     gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
1560    
1561 harbaum 221 g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1562     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1563    
1564     #ifndef PRESET_PICKER_DIALOG
1565 harbaum 216 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1566 harbaum 217 (GtkSignalFunc)on_popup_button_press, appdata);
1567 harbaum 216
1568 harbaum 217 gtk_signal_connect(GTK_OBJECT(button), "destroy",
1569     (GtkSignalFunc)on_popup_destroy, appdata);
1570 harbaum 216 #else
1571 harbaum 217 #ifdef FREMANTLE
1572     hildon_gtk_widget_set_theme_size(button,
1573     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1574 harbaum 216 #endif
1575    
1576 harbaum 217 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1577 harbaum 221 (GtkSignalFunc)on_preset_picker_button_press, appdata);
1578 harbaum 217 #endif
1579    
1580 harbaum 216 return button;
1581     }
1582 harbaum 217
1583 harbaum 231 #if defined(ENABLE_MAEMO_MAPPER) || defined(ENABLE_OSM_GPS_MAP)
1584     static pos_t goto_pos_get(GtkWidget *item) {
1585     pos_t pos;
1586    
1587     GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1588     pos.lat = lat_entry_get(lat_entry);
1589    
1590     GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1591     pos.lon = lon_entry_get(lon_entry);
1592    
1593     return pos;
1594     }
1595    
1596     #ifdef ENABLE_MAEMO_MAPPER
1597     static void cb_mm_set(GtkWidget *item, gpointer data) {
1598     appdata_t *appdata = (appdata_t*)data;
1599    
1600     pos_t pos = goto_pos_get(item);
1601     if(!isnan(pos.lat) && !isnan(pos.lon))
1602     dbus_mm_set_position(appdata, &pos);
1603     }
1604     #endif
1605    
1606     static void cb_map_set(GtkWidget *item, gpointer data) {
1607     appdata_t *appdata = (appdata_t*)data;
1608    
1609     pos_t pos = goto_pos_get(item);
1610     if(!isnan(pos.lat) && !isnan(pos.lon)) {
1611     map(appdata);
1612     osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1613     pos.lat, pos.lon);
1614     }
1615     }
1616    
1617     #ifndef PRESET_PICKER_DIALOG
1618     static GtkWidget *goto_popup_menu_create(appdata_t *appdata,
1619     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1620     GtkWidget *menu = gtk_menu_new();
1621    
1622     #if defined(ENABLE_OSM_GPS_MAP)
1623     menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1624     _("Map position"), cb_map_set, 0, lon_entry, lat_entry);
1625     #endif
1626    
1627     #if defined(ENABLE_MAEMO_MAPPER)
1628     menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1629     _("Maemo mapper position"), cb_mm_set, 0, lon_entry, lat_entry);
1630     #endif
1631    
1632     gtk_widget_show_all(menu);
1633    
1634     return menu;
1635     }
1636     #else
1637     static GtkWidget *goto_picker_create(appdata_t *appdata,
1638     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1639     GtkCellRenderer *renderer;
1640     GtkListStore *store;
1641    
1642     GtkWidget *view = gtk_tree_view_new();
1643    
1644     g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1645     g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1646    
1647     /* --- "Icon" column --- */
1648     renderer = gtk_cell_renderer_pixbuf_new();
1649     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1650     -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1651    
1652     /* --- "Name" column --- */
1653     renderer = gtk_cell_renderer_text_new();
1654     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1655     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1656     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1657     gtk_tree_view_column_set_expand(column, TRUE);
1658     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1659    
1660     store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1661     GDK_TYPE_PIXBUF,
1662     G_TYPE_STRING,
1663     G_TYPE_INT,
1664     G_TYPE_POINTER);
1665    
1666     #if defined(ENABLE_OSM_GPS_MAP)
1667     preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1668     _("Map position"), cb_map_set, 0);
1669     #endif
1670    
1671     #if defined(ENABLE_MAEMO_MAPPER)
1672     preset_picker_add(store, appdata, icon_get(ICON_POS, 24),
1673     _("Maemo mapper position"), cb_mm_set, 0);
1674     #endif
1675    
1676     gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1677     g_object_unref(store);
1678    
1679     /* make list react on clicks */
1680     g_signal_connect(view, "row-activated",
1681     (GCallback)on_preset_picker_activated, appdata);
1682    
1683     /* put this inside a scrolled view */
1684     #ifndef USE_PANNABLE_AREA
1685     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1686     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1687     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1688     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1689     return scrolled_window;
1690     #else
1691     GtkWidget *pannable_area = hildon_pannable_area_new();
1692     gtk_container_add(GTK_CONTAINER(pannable_area), view);
1693     return pannable_area;
1694     #endif
1695     }
1696     #endif
1697    
1698     static gint on_goto_button_press(GtkWidget *button,
1699     GdkEventButton *event, gpointer data) {
1700     appdata_t *appdata = (appdata_t*)data;
1701    
1702     if(event->type == GDK_BUTTON_PRESS) {
1703    
1704     #if defined(ENABLE_MAEMO_MAPPER) && !defined(ENABLE_OSM_GPS_MAP)
1705     /* only maemo mapper is being used */
1706     pos_t pos = goto_pos_get(button);
1707     if(!isnan(pos.lat) && !isnan(pos.lon)) {
1708     dbus_mm_set_position(appdata, &pos);
1709     #elif !defined(ENABLE_MAEMO_MAPPER) && defined(ENABLE_OSM_GPS_MAP)
1710     /* only internal map is being used */
1711     pos_t pos = goto_pos_get(button);
1712     if(!isnan(pos.lat) && !isnan(pos.lon)) {
1713     map(appdata);
1714     osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1715     pos.lat, pos.lon);
1716     }
1717     #else
1718    
1719     gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1720     g_assert(lat_entry);
1721     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1722     g_assert(lon_entry);
1723    
1724     #ifndef PRESET_PICKER_DIALOG
1725     GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1726     if(!menu) {
1727     menu = goto_popup_menu_create(appdata, lat_entry, lon_entry);
1728     g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1729     }
1730    
1731     /* draw a popup menu */
1732     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1733     event->button, event->time);
1734     #else
1735     GtkWidget *dialog =
1736     gtk_dialog_new_with_buttons(_("Map coordinates"),
1737     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1738     GTK_DIALOG_MODAL,
1739     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1740     NULL);
1741    
1742     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1743    
1744     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1745     goto_picker_create(appdata, lat_entry, lon_entry));
1746    
1747     gtk_widget_show_all(dialog);
1748     gtk_dialog_run(GTK_DIALOG(dialog));
1749     gtk_widget_destroy(dialog);
1750     #endif
1751    
1752     #endif
1753    
1754     return TRUE;
1755     }
1756     return FALSE;
1757     }
1758    
1759     /* a button which makes the map/maemo mapper go to the associated */
1760     /* position */
1761     GtkWidget *goto_coordinate(appdata_t *appdata,
1762     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1763    
1764     GtkWidget *button = gtk_button_new();
1765    
1766     gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 23));
1767    
1768     gtk_widget_set_tooltip_text(button, _("Goto coordinates"));
1769    
1770     g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1771     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1772    
1773     gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1774     (GtkSignalFunc)on_goto_button_press, appdata);
1775    
1776     #ifndef PRESET_PICKER_DIALOG
1777     gtk_signal_connect(GTK_OBJECT(button), "destroy",
1778     (GtkSignalFunc)on_popup_destroy, appdata);
1779     #else
1780     #ifdef FREMANTLE
1781     hildon_gtk_widget_set_theme_size(button,
1782     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1783     #endif
1784     #endif
1785    
1786     return button;
1787     }
1788     #else
1789     /* no map installed */
1790     GtkWidget *goto_coordinate(appdata_t *appdata,
1791     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1792     return gtk_label_new("");
1793     }
1794     #endif
1795    
1796 harbaum 217 GtkWidget *entry_new(void) {
1797     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1798     return gtk_entry_new();
1799     #else
1800     return hildon_entry_new(HILDON_SIZE_AUTO);
1801 harbaum 216 #endif
1802 harbaum 217 }
1803    
1804     gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
1805     int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
1806     int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
1807    
1808     return((lat1 != lat2) || (lon1 != lon2));
1809     }
1810    
1811 harbaum 223 gboolean pos_valid(pos_t *pos) {
1812     if(!pos) return FALSE;
1813     return(!isnan(pos->lat) && !isnan(pos->lon));
1814     }
1815    
1816     void misc_init(void) {
1817     g_signal_new ("changed", GTK_TYPE_BUTTON,
1818     G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
1819     g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1820     }
1821    
1822     void angle_str(char *str, int len, float angle) {
1823     snprintf(str, len, _("%.1f°"), angle);
1824     }
1825    
1826     float angle_parse(char *str) {
1827     float val;
1828    
1829     if(sscanf(str, _("%f°"), &val) != 1)
1830     val = NAN;
1831    
1832     return val;
1833     }
1834    
1835     #ifndef COORDINATE_PICKER
1836     static void callback_modified_angle(GtkWidget *widget, gpointer data ) {
1837     float i = angle_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
1838     mark(widget, !isnan(i));
1839     }
1840     #else
1841     static gint on_angle_picker_button_press(GtkWidget *button,
1842     GdkEventButton *event, gpointer data) {
1843    
1844     if(event->type == GDK_BUTTON_PRESS) {
1845     GtkWidget *dialog =
1846     gtk_dialog_new_with_buttons(_("Direction"),
1847     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1848     GTK_DIALOG_MODAL,
1849     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1850     _("Done"), GTK_RESPONSE_ACCEPT,
1851     NULL);
1852    
1853     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1854    
1855     int i, angle = (int)g_object_get_data(G_OBJECT(button), "angle");
1856    
1857     GtkWidget *anglew[3], *fracw;
1858    
1859     /* create xxx.x° */
1860     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
1861    
1862     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1863     anglew[0] = digit_picker_create(0,3, (angle/1000)%10));
1864     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1865     anglew[1] = digit_picker_create(0,9, (angle/100)%10));
1866     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1867     anglew[2] = digit_picker_create(0,9, (angle/10)%10));
1868     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
1869     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1870     fracw = digit_picker_create(0,9, (angle/1)%10));
1871     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
1872    
1873     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1874    
1875     gtk_widget_show_all(dialog);
1876     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1877    
1878     /* parse angle */
1879     for(angle=0,i=0;i<3;i++)
1880     angle = 10 * angle + picker_get(anglew[i]);
1881    
1882     angle = 10 * angle + picker_get(fracw);
1883    
1884     angle_entry_set(button, angle/10.0);
1885     }
1886    
1887     gtk_widget_destroy(dialog);
1888    
1889     return TRUE;
1890     }
1891     return FALSE;
1892     }
1893     #endif
1894    
1895     GtkWidget *angle_entry_new(float angle) {
1896     char str[32];
1897     angle_str(str, sizeof(str), angle);
1898    
1899     #ifndef COORDINATE_PICKER
1900 harbaum 226 GtkWidget *widget = red_entry_new_with_text(str);
1901 harbaum 223 g_signal_connect(G_OBJECT(widget), "changed",
1902     G_CALLBACK(callback_modified_angle), NULL);
1903     #else
1904     GtkWidget *widget = gtk_button_new_with_label(str);
1905    
1906     #ifdef FREMANTLE
1907     hildon_gtk_widget_set_theme_size(widget,
1908     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1909     #endif
1910     int angle_int = (int)roundf(angle*10.0);
1911     g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1912     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
1913     (GtkSignalFunc)on_angle_picker_button_press, NULL);
1914     #endif
1915     return widget;
1916     }
1917    
1918     float angle_entry_get(GtkWidget *widget) {
1919     #ifndef COORDINATE_PICKER
1920     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
1921     #else
1922     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
1923     #endif
1924     return angle_parse(p);
1925     }
1926    
1927     void angle_entry_set(GtkWidget *widget, float angle) {
1928     char str[32];
1929     angle_str(str, sizeof(str)-1, angle);
1930     #ifndef COORDINATE_PICKER
1931     gtk_entry_set_text(GTK_ENTRY(widget), str);
1932     #else
1933     gtk_button_set_label(GTK_BUTTON(widget), str);
1934     int angle_int = (int)roundf(angle * 10.0);
1935     g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1936     g_signal_emit_by_name(widget, "changed");
1937     #endif
1938     }
1939