Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


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