Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


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