Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


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