Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 288 - (hide annotations)
Mon Jun 7 19:19:50 2010 UTC (13 years, 11 months ago) by harbaum
File MIME type: text/plain
File size: 73916 byte(s)
GPS focus enable, portrait support and some attribute icon work
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 harbaum 280 while(*p && (*p != '/')) p++;
79 harbaum 1 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 harbaum 280 if(!(filestat.st_mode & S_IFDIR)) {
91 harbaum 1 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 harbaum 282 if(!pos) pos = &appdata->gps.saved; /* use saved position */
283     else appdata->gps.saved = *pos; /* save position */
284 harbaum 1 }
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 harbaum 280 if(fimp & (!imperial)) val *= 1.609344;
325 harbaum 1
326     /* found metric and imperial requested? convert kilometers into miles */
327 harbaum 280 if((!fimp) & imperial) val /= 1.609344;
328 harbaum 1 }
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 static pos_t goto_pos_get(GtkWidget *item) {
1639     pos_t pos;
1640    
1641     GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1642     pos.lat = lat_entry_get(lat_entry);
1643    
1644     GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1645     pos.lon = lon_entry_get(lon_entry);
1646    
1647     return pos;
1648     }
1649    
1650     #ifdef ENABLE_MAEMO_MAPPER
1651     static void cb_mm_set(GtkWidget *item, gpointer data) {
1652     appdata_t *appdata = (appdata_t*)data;
1653    
1654     pos_t pos = goto_pos_get(item);
1655     if(!isnan(pos.lat) && !isnan(pos.lon))
1656     dbus_mm_set_position(appdata, &pos);
1657     }
1658     #endif
1659    
1660 harbaum 233 #ifdef ENABLE_OSM_GPS_MAP
1661 harbaum 231 static void cb_map_set(GtkWidget *item, gpointer data) {
1662     appdata_t *appdata = (appdata_t*)data;
1663    
1664     pos_t pos = goto_pos_get(item);
1665     if(!isnan(pos.lat) && !isnan(pos.lon)) {
1666     map(appdata);
1667     osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1668     pos.lat, pos.lon);
1669     }
1670     }
1671 harbaum 233 #endif
1672 harbaum 231
1673 harbaum 249 static void cb_clipboard_set(GtkWidget *item, gpointer data) {
1674     appdata_t *appdata = (appdata_t*)data;
1675    
1676     pos_t pos = goto_pos_get(item);
1677     if(!isnan(pos.lat) && !isnan(pos.lon)) {
1678     char lat[32], lon[32];
1679     pos_lat_str(lat, sizeof(lat), pos.lat);
1680     pos_lon_str(lon, sizeof(lon), pos.lon);
1681    
1682     char *str = g_strdup_printf("%s %s", lat, lon);
1683     gtk_clipboard_set_text(appdata->clipboard, str, -1);
1684     g_free(str);
1685     }
1686     }
1687    
1688 harbaum 231 #ifndef PRESET_PICKER_DIALOG
1689     static GtkWidget *goto_popup_menu_create(appdata_t *appdata,
1690     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1691     GtkWidget *menu = gtk_menu_new();
1692    
1693     #if defined(ENABLE_OSM_GPS_MAP)
1694     menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1695 harbaum 233 _("Internal map"), cb_map_set, 0, lon_entry, lat_entry);
1696 harbaum 231 #endif
1697    
1698     #if defined(ENABLE_MAEMO_MAPPER)
1699     menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1700 harbaum 233 _("Maemo Mapper"), cb_mm_set, 0, lon_entry, lat_entry);
1701 harbaum 231 #endif
1702 harbaum 249
1703     menu_add(menu, appdata, icon_get_widget(ICON_POS, 25),
1704     _("Clipboard"), cb_clipboard_set, 0, lon_entry, lat_entry);
1705 harbaum 231
1706     gtk_widget_show_all(menu);
1707    
1708     return menu;
1709     }
1710     #else
1711     static GtkWidget *goto_picker_create(appdata_t *appdata,
1712     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1713     GtkCellRenderer *renderer;
1714     GtkListStore *store;
1715    
1716     GtkWidget *view = gtk_tree_view_new();
1717    
1718     g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1719     g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1720    
1721     /* --- "Icon" column --- */
1722     renderer = gtk_cell_renderer_pixbuf_new();
1723     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1724     -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1725    
1726     /* --- "Name" column --- */
1727     renderer = gtk_cell_renderer_text_new();
1728     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1729     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1730     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1731     gtk_tree_view_column_set_expand(column, TRUE);
1732     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1733    
1734     store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1735     GDK_TYPE_PIXBUF,
1736     G_TYPE_STRING,
1737     G_TYPE_INT,
1738     G_TYPE_POINTER);
1739    
1740     #if defined(ENABLE_OSM_GPS_MAP)
1741     preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1742 harbaum 233 _("Internal map"), cb_map_set, 0);
1743 harbaum 231 #endif
1744    
1745     #if defined(ENABLE_MAEMO_MAPPER)
1746     preset_picker_add(store, appdata, icon_get(ICON_POS, 24),
1747 harbaum 233 _("Maemo Mapper"), cb_mm_set, 0);
1748 harbaum 231 #endif
1749    
1750 harbaum 249 preset_picker_add(store, appdata, icon_get(ICON_POS, 25),
1751     _("Clipboard"), cb_clipboard_set, 0);
1752    
1753 harbaum 231 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1754     g_object_unref(store);
1755    
1756     /* make list react on clicks */
1757     g_signal_connect(view, "row-activated",
1758     (GCallback)on_preset_picker_activated, appdata);
1759    
1760     /* put this inside a scrolled view */
1761     #ifndef USE_PANNABLE_AREA
1762     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1763     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1764     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1765     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1766     return scrolled_window;
1767     #else
1768     GtkWidget *pannable_area = hildon_pannable_area_new();
1769     gtk_container_add(GTK_CONTAINER(pannable_area), view);
1770     return pannable_area;
1771     #endif
1772     }
1773     #endif
1774    
1775     static gint on_goto_button_press(GtkWidget *button,
1776     GdkEventButton *event, gpointer data) {
1777     appdata_t *appdata = (appdata_t*)data;
1778    
1779     if(event->type == GDK_BUTTON_PRESS) {
1780    
1781     gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1782     g_assert(lat_entry);
1783     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1784     g_assert(lon_entry);
1785    
1786     #ifndef PRESET_PICKER_DIALOG
1787     GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1788     if(!menu) {
1789     menu = goto_popup_menu_create(appdata, lat_entry, lon_entry);
1790     g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1791     }
1792    
1793     /* draw a popup menu */
1794     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1795     event->button, event->time);
1796     #else
1797     GtkWidget *dialog =
1798 harbaum 233 gtk_dialog_new_with_buttons(_("Show coordinate on map"),
1799 harbaum 231 GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1800     GTK_DIALOG_MODAL,
1801     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1802     NULL);
1803    
1804     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1805    
1806     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1807     goto_picker_create(appdata, lat_entry, lon_entry));
1808    
1809     gtk_widget_show_all(dialog);
1810     gtk_dialog_run(GTK_DIALOG(dialog));
1811     gtk_widget_destroy(dialog);
1812     #endif
1813    
1814     return TRUE;
1815     }
1816     return FALSE;
1817     }
1818    
1819     /* a button which makes the map/maemo mapper go to the associated */
1820     /* position */
1821     GtkWidget *goto_coordinate(appdata_t *appdata,
1822     GtkWidget *lat_entry, GtkWidget *lon_entry) {
1823    
1824     GtkWidget *button = gtk_button_new();
1825    
1826     gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 23));
1827    
1828 harbaum 233 #ifndef USE_MAEMO
1829     gtk_widget_set_tooltip_text(button, _("Show coordinate on map"));
1830     #endif
1831 harbaum 231
1832     g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1833     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1834    
1835     gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1836     (GtkSignalFunc)on_goto_button_press, appdata);
1837    
1838     #ifndef PRESET_PICKER_DIALOG
1839     gtk_signal_connect(GTK_OBJECT(button), "destroy",
1840     (GtkSignalFunc)on_popup_destroy, appdata);
1841     #else
1842     #ifdef FREMANTLE
1843     hildon_gtk_widget_set_theme_size(button,
1844     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1845     #endif
1846     #endif
1847    
1848     return button;
1849     }
1850    
1851 harbaum 217 GtkWidget *entry_new(void) {
1852     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1853     return gtk_entry_new();
1854     #else
1855     return hildon_entry_new(HILDON_SIZE_AUTO);
1856 harbaum 216 #endif
1857 harbaum 217 }
1858    
1859     gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
1860     int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
1861     int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
1862    
1863     return((lat1 != lat2) || (lon1 != lon2));
1864     }
1865    
1866 harbaum 223 gboolean pos_valid(pos_t *pos) {
1867     if(!pos) return FALSE;
1868     return(!isnan(pos->lat) && !isnan(pos->lon));
1869     }
1870    
1871     void misc_init(void) {
1872     g_signal_new ("changed", GTK_TYPE_BUTTON,
1873     G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
1874     g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1875     }
1876    
1877     void angle_str(char *str, int len, float angle) {
1878     snprintf(str, len, _("%.1f°"), angle);
1879     }
1880    
1881     float angle_parse(char *str) {
1882     float val;
1883    
1884     if(sscanf(str, _("%f°"), &val) != 1)
1885     val = NAN;
1886    
1887     return val;
1888     }
1889    
1890     #ifndef COORDINATE_PICKER
1891     static void callback_modified_angle(GtkWidget *widget, gpointer data ) {
1892     float i = angle_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
1893     mark(widget, !isnan(i));
1894     }
1895     #else
1896     static gint on_angle_picker_button_press(GtkWidget *button,
1897     GdkEventButton *event, gpointer data) {
1898    
1899     if(event->type == GDK_BUTTON_PRESS) {
1900     GtkWidget *dialog =
1901     gtk_dialog_new_with_buttons(_("Direction"),
1902     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1903     GTK_DIALOG_MODAL,
1904     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1905     _("Done"), GTK_RESPONSE_ACCEPT,
1906     NULL);
1907    
1908     gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1909    
1910     int i, angle = (int)g_object_get_data(G_OBJECT(button), "angle");
1911    
1912     GtkWidget *anglew[3], *fracw;
1913    
1914     /* create xxx.x° */
1915     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
1916    
1917     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1918     anglew[0] = digit_picker_create(0,3, (angle/1000)%10));
1919     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1920     anglew[1] = digit_picker_create(0,9, (angle/100)%10));
1921     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1922     anglew[2] = digit_picker_create(0,9, (angle/10)%10));
1923     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
1924     gtk_box_pack_start_defaults(GTK_BOX(hbox),
1925     fracw = digit_picker_create(0,9, (angle/1)%10));
1926     gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
1927    
1928     gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1929    
1930     gtk_widget_show_all(dialog);
1931     if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1932    
1933     /* parse angle */
1934     for(angle=0,i=0;i<3;i++)
1935     angle = 10 * angle + picker_get(anglew[i]);
1936    
1937     angle = 10 * angle + picker_get(fracw);
1938    
1939     angle_entry_set(button, angle/10.0);
1940     }
1941    
1942     gtk_widget_destroy(dialog);
1943    
1944     return TRUE;
1945     }
1946     return FALSE;
1947     }
1948     #endif
1949    
1950     GtkWidget *angle_entry_new(float angle) {
1951     char str[32];
1952     angle_str(str, sizeof(str), angle);
1953    
1954     #ifndef COORDINATE_PICKER
1955 harbaum 226 GtkWidget *widget = red_entry_new_with_text(str);
1956 harbaum 223 g_signal_connect(G_OBJECT(widget), "changed",
1957     G_CALLBACK(callback_modified_angle), NULL);
1958     #else
1959     GtkWidget *widget = gtk_button_new_with_label(str);
1960    
1961     #ifdef FREMANTLE
1962     hildon_gtk_widget_set_theme_size(widget,
1963     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1964     #endif
1965     int angle_int = (int)roundf(angle*10.0);
1966     g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1967     gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
1968     (GtkSignalFunc)on_angle_picker_button_press, NULL);
1969     #endif
1970     return widget;
1971     }
1972 harbaum 233
1973 harbaum 223 float angle_entry_get(GtkWidget *widget) {
1974     #ifndef COORDINATE_PICKER
1975     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
1976     #else
1977     char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
1978     #endif
1979     return angle_parse(p);
1980     }
1981    
1982     void angle_entry_set(GtkWidget *widget, float angle) {
1983     char str[32];
1984     angle_str(str, sizeof(str)-1, angle);
1985     #ifndef COORDINATE_PICKER
1986     gtk_entry_set_text(GTK_ENTRY(widget), str);
1987     #else
1988     gtk_button_set_label(GTK_BUTTON(widget), str);
1989     int angle_int = (int)roundf(angle * 10.0);
1990     g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1991     g_signal_emit_by_name(widget, "changed");
1992     #endif
1993     }
1994 harbaum 233
1995     GtkWidget *toggle_button_new_with_label(char *label) {
1996     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1997     return gtk_check_button_new_with_label(label);
1998     #else
1999     GtkWidget *cbut = gtk_toggle_button_new_with_label(label);
2000     hildon_gtk_widget_set_theme_size(cbut,
2001     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2002     gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(cbut), FALSE);
2003     return cbut;
2004     #endif
2005     }
2006 harbaum 223
2007 harbaum 233 void toggle_button_set_active(GtkWidget *button, gboolean active) {
2008     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
2009     }
2010    
2011     gboolean toggle_button_get_active(GtkWidget *button) {
2012     return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
2013     }
2014    
2015     GtkWidget *check_button_new_with_label(char *label) {
2016     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
2017     return gtk_check_button_new_with_label(label);
2018     #else
2019     GtkWidget *cbut =
2020     hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT |
2021     HILDON_SIZE_AUTO_WIDTH);
2022     gtk_button_set_label(GTK_BUTTON(cbut), label);
2023     return cbut;
2024     #endif
2025     }
2026    
2027     void check_button_set_active(GtkWidget *button, gboolean active) {
2028     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
2029     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
2030     #else
2031     hildon_check_button_set_active(HILDON_CHECK_BUTTON(button), active);
2032     #endif
2033     }
2034    
2035     gboolean check_button_get_active(GtkWidget *button) {
2036     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
2037     return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
2038     #else
2039     return hildon_check_button_get_active(HILDON_CHECK_BUTTON(button));
2040     #endif
2041     }
2042    
2043     GtkWidget *button_new(void) {
2044     GtkWidget *button = gtk_button_new();
2045     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
2046     hildon_gtk_widget_set_theme_size(button,
2047     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2048     #endif
2049     return button;
2050     }
2051    
2052     GtkWidget *button_new_with_label(char *label) {
2053     GtkWidget *button = gtk_button_new_with_label(label);
2054     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
2055     hildon_gtk_widget_set_theme_size(button,
2056     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2057     #endif
2058     return button;
2059     }
2060    
2061     static void on_browse(GtkWidget *widget, gpointer data) {
2062     GtkWidget *dialog;
2063    
2064     char **fileptr = g_object_get_data(G_OBJECT(widget), "fileptr");
2065    
2066     #ifdef USE_MAEMO
2067     dialog = hildon_file_chooser_dialog_new(
2068     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))),
2069     GTK_FILE_CHOOSER_ACTION_SAVE);
2070     #else
2071     dialog = gtk_file_chooser_dialog_new(
2072     g_object_get_data(G_OBJECT(widget), "sel_title"),
2073     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))),
2074     GTK_FILE_CHOOSER_ACTION_SAVE,
2075     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2076     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2077     NULL);
2078     #endif
2079    
2080     if(*fileptr) {
2081     printf("set filename <%s>\n", *fileptr);
2082    
2083     if(!g_file_test(*fileptr, G_FILE_TEST_EXISTS)) {
2084     char *last_sep = strrchr(*fileptr, '/');
2085     if(last_sep) {
2086     *last_sep = 0; // seperate path from file
2087    
2088     /* the user just created a new document */
2089     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
2090     *fileptr);
2091     gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
2092     last_sep+1);
2093    
2094     /* restore full filename */
2095     *last_sep = '/';
2096     }
2097     } else
2098     gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), *fileptr);
2099     }
2100    
2101     if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
2102     gchar *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2103     if(name) {
2104     if(*fileptr) g_free(*fileptr);
2105     *fileptr = g_strdup(name);
2106    
2107     #ifndef FREMANTLE
2108     GtkWidget *label = g_object_get_data(G_OBJECT(widget), "label");
2109     gtk_label_set_text(GTK_LABEL(label), *fileptr);
2110     #else
2111     hildon_button_set_value(HILDON_BUTTON(widget), *fileptr);
2112     #endif
2113     }
2114     }
2115    
2116     gtk_widget_destroy (dialog);
2117     }
2118    
2119     GtkWidget *export_file(char *sel_title, char **filename) {
2120     /* non-fremantle and classic gtk use a rather ugly and */
2121     /* complex layout */
2122     #ifndef FREMANTLE
2123     GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
2124     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
2125     GtkWidget *label = gtk_label_new(_("Export to"));
2126     gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE,0);
2127     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2128     GtkWidget *button = button_new_with_label(_("Browse"));
2129     g_object_set_data(G_OBJECT(button), "sel_title", sel_title);
2130     g_object_set_data(G_OBJECT(button), "fileptr", filename);
2131     gtk_signal_connect(GTK_OBJECT(button), "clicked",
2132     GTK_SIGNAL_FUNC(on_browse), NULL);
2133     gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE,0);
2134     gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox);
2135    
2136     label = gtk_label_new((*filename)?*filename:"");
2137     g_object_set_data(G_OBJECT(button), "label", label);
2138     gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2139     gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
2140    
2141     gtk_box_pack_start_defaults(GTK_BOX(vbox), label);
2142     return vbox;
2143     #else
2144     GtkWidget *button = hildon_button_new_with_text(
2145     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH),
2146     HILDON_BUTTON_ARRANGEMENT_VERTICAL,
2147     _("Export to"), *filename);
2148     hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.5, 0.5);
2149     hildon_button_set_value_alignment(HILDON_BUTTON(button), 0.5, 0.5);
2150     g_object_set_data(G_OBJECT(button), "sel_title", sel_title);
2151     g_object_set_data(G_OBJECT(button), "fileptr", filename);
2152     gtk_signal_connect(GTK_OBJECT(button), "clicked",
2153     GTK_SIGNAL_FUNC(on_browse), NULL);
2154     return button;
2155     #endif
2156     }
2157    
2158 harbaum 246 #ifdef FREMANTLE
2159 harbaum 244 static int number_editor_get(GtkWidget *widget) {
2160     GtkWidget *entry = g_object_get_data(G_OBJECT(widget), "entry");
2161     g_assert(entry);
2162     const char *str = gtk_entry_get_text(GTK_ENTRY(entry));
2163     if(!str) return 0;
2164     return atoi(str);
2165     }
2166 harbaum 233
2167 harbaum 244 static void number_editor_set(GtkWidget *widget, int num) {
2168     int min = (int)g_object_get_data(G_OBJECT(widget), "min");
2169     int max = (int)g_object_get_data(G_OBJECT(widget), "max");
2170    
2171     if(num < min) num = min;
2172     if(num > max) num = max;
2173    
2174     GtkWidget *btn_inc =
2175     (GtkWidget*)g_object_get_data(G_OBJECT(widget), "btn_inc");
2176     gtk_widget_set_sensitive(btn_inc, num < max);
2177    
2178     GtkWidget *btn_dec =
2179     (GtkWidget*)g_object_get_data(G_OBJECT(widget), "btn_dec");
2180     gtk_widget_set_sensitive(btn_dec, num > min);
2181    
2182     GtkWidget *entry = g_object_get_data(G_OBJECT(widget), "entry");
2183     g_assert(entry);
2184     char *str = g_strdup_printf("%d", num);
2185     gtk_entry_set_text(GTK_ENTRY(entry), str);
2186     g_free(str);
2187     }
2188    
2189     static void on_number_decrease(GtkWidget *widget, gpointer data) {
2190     number_editor_set(GTK_WIDGET(data),
2191     number_editor_get(GTK_WIDGET(data)) - 1);
2192     }
2193    
2194     static void on_number_increase(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_changed(GtkWidget *widget, gpointer data) {
2200     number_editor_set(GTK_WIDGET(data),
2201     number_editor_get(GTK_WIDGET(data)));
2202     }
2203 harbaum 246 #endif
2204 harbaum 244
2205     GtkWidget *number_editor_new(int current, int min, int max) {
2206     #ifndef USE_MAEMO
2207     GtkObject *adj = gtk_adjustment_new(current, min, max, 1, 10, 10);
2208     return gtk_spin_button_new(GTK_ADJUSTMENT(adj), 1, 0);
2209     #elif MAEMO_VERSION_MAJOR < 5
2210     GtkWidget *widget = hildon_number_editor_new(min, max);
2211     hildon_number_editor_set_value(HILDON_NUMBER_EDITOR(widget), current);
2212     return widget;
2213     #else
2214     GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
2215     g_object_set_data(G_OBJECT(hbox), "min", (gpointer)min);
2216     g_object_set_data(G_OBJECT(hbox), "max", (gpointer)max);
2217    
2218     GtkWidget *btn_dec = button_new_with_label(" - ");
2219     g_object_set_data(G_OBJECT(hbox), "btn_dec", btn_dec);
2220     gtk_signal_connect(GTK_OBJECT(btn_dec), "clicked",
2221     (GtkSignalFunc)on_number_decrease, hbox);
2222     gtk_box_pack_start(GTK_BOX(hbox), btn_dec, FALSE, FALSE, 0);
2223    
2224     GtkWidget *entry = hildon_entry_new(HILDON_SIZE_AUTO);
2225     g_object_set_data(G_OBJECT(hbox), "entry", entry);
2226     g_signal_connect(G_OBJECT(entry), "changed",
2227     G_CALLBACK(on_number_changed), hbox);
2228     gtk_entry_set_width_chars(GTK_ENTRY(entry), 2);
2229     hildon_gtk_entry_set_input_mode(GTK_ENTRY(entry),
2230     HILDON_GTK_INPUT_MODE_NUMERIC);
2231     gtk_box_pack_start_defaults(GTK_BOX(hbox), entry);
2232    
2233     GtkWidget *btn_inc = button_new_with_label(" + ");
2234     g_object_set_data(G_OBJECT(hbox), "btn_inc", btn_inc);
2235     gtk_signal_connect(GTK_OBJECT(btn_inc), "clicked",
2236     (GtkSignalFunc)on_number_increase, hbox);
2237     gtk_box_pack_start(GTK_BOX(hbox), btn_inc, FALSE, FALSE, 0);
2238    
2239     number_editor_set(hbox, current);
2240    
2241     return hbox;
2242     #endif
2243     }
2244    
2245     int number_editor_get_value(GtkWidget *widget) {
2246     #ifndef USE_MAEMO
2247     return gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
2248     #elif MAEMO_VERSION_MAJOR < 5
2249     return hildon_number_editor_get_value(HILDON_NUMBER_EDITOR(widget));
2250     #else
2251     return number_editor_get(widget);
2252     #endif
2253     }
2254 harbaum 288
2255     #ifdef MAEMO5
2256     gboolean is_portrait() {
2257     GdkScreen *screen = gdk_screen_get_default();
2258     return (gdk_screen_get_width(screen) < gdk_screen_get_height(screen));
2259     }
2260    
2261     static
2262     void on_orientation_changed(GdkScreen *screen, gpointer userdata) {
2263     GtkWidget *vbox = GTK_WIDGET(userdata);
2264     GtkWidget *hbox0 = g_object_get_data(G_OBJECT(vbox), "hbox0");
2265     GtkWidget *hbox1 = g_object_get_data(G_OBJECT(vbox), "hbox1");
2266    
2267     GSList *xbut = g_object_get_data(G_OBJECT(vbox), "xbut");
2268     if(!xbut) return;
2269    
2270     int i;
2271     for(i=0;i<g_slist_length(xbut);i++) {
2272     GtkWidget *but = g_slist_nth_data(xbut, i);
2273     g_object_ref(G_OBJECT(but));
2274    
2275     if(is_portrait()) {
2276     /* move button from hbox0 to hbox1 */
2277     gtk_container_remove(GTK_CONTAINER(hbox0), but);
2278     gtk_box_pack_start_defaults(GTK_BOX(hbox1), but);
2279     } else {
2280     /* move button from hbox1 to hbox0 */
2281     gtk_container_remove(GTK_CONTAINER(hbox1), but);
2282     gtk_box_pack_start_defaults(GTK_BOX(hbox0), but);
2283     }
2284     g_object_unref(G_OBJECT(but));
2285     }
2286    
2287     gtk_window_resize(GTK_WINDOW(gtk_widget_get_toplevel(vbox)), 800, 800);
2288     }
2289     #endif
2290    
2291     GtkWidget *notebook_new(void) {
2292     #ifdef MAEMO5
2293     GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
2294    
2295     GtkWidget *notebook = gtk_notebook_new();
2296    
2297     /* solution for fremantle: we use a row of ordinary buttons instead */
2298     /* of regular tabs */
2299    
2300     /* hide the regular tabs */
2301     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
2302    
2303     gtk_box_pack_start_defaults(GTK_BOX(vbox), notebook);
2304    
2305     /* store a reference to the notebook in the vbox */
2306     g_object_set_data(G_OBJECT(vbox), "notebook", (gpointer)notebook);
2307    
2308     /* create hboxes for the buttons (second hbox for portrait mode) */
2309     GtkWidget *hbox0 = gtk_hbox_new(TRUE, 0);
2310     gtk_box_pack_start(GTK_BOX(vbox), hbox0, FALSE, FALSE, 0);
2311     g_object_set_data(G_OBJECT(vbox), "hbox0", (gpointer)hbox0);
2312     GtkWidget *hbox1 = gtk_hbox_new(TRUE, 0);
2313     gtk_box_pack_start(GTK_BOX(vbox), hbox1, FALSE, FALSE, 0);
2314     g_object_set_data(G_OBJECT(vbox), "hbox1", (gpointer)hbox1);
2315    
2316     /* this box needs to be re-arranged for portrait mode */
2317     GdkScreen *screen = gdk_screen_get_default();
2318     g_signal_connect(screen, "size-changed", G_CALLBACK(on_orientation_changed), vbox);
2319    
2320     return vbox;
2321     #else
2322     return gtk_notebook_new();
2323     #endif
2324     }
2325    
2326     GtkWidget *notebook_get_gtk_notebook(GtkWidget *notebook) {
2327     #ifdef MAEMO5
2328     return GTK_WIDGET(g_object_get_data(G_OBJECT(notebook), "notebook"));
2329     #else
2330     return notebook;
2331     #endif
2332     }
2333    
2334     #ifdef MAEMO5
2335     static void on_notebook_button_clicked(GtkWidget *button, gpointer data) {
2336     GtkNotebook *nb =
2337     GTK_NOTEBOOK(g_object_get_data(G_OBJECT(data), "notebook"));
2338    
2339     gint page = (gint)g_object_get_data(G_OBJECT(button), "page");
2340     gtk_notebook_set_current_page(nb, page);
2341     }
2342     #endif
2343    
2344     void notebook_append_page(GtkWidget *notebook,
2345     GtkWidget *page, char *label) {
2346     #ifdef MAEMO5
2347     GtkNotebook *nb =
2348     GTK_NOTEBOOK(g_object_get_data(G_OBJECT(notebook), "notebook"));
2349    
2350     gint page_num = gtk_notebook_append_page(nb, page, gtk_label_new(label));
2351     GtkWidget *button = NULL;
2352    
2353     /* select button for page 0 by default */
2354     if(!page_num) {
2355     button = gtk_radio_button_new_with_label(NULL, label);
2356     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), TRUE);
2357     g_object_set_data(G_OBJECT(notebook), "group_master", (gpointer)button);
2358     } else {
2359     GtkWidget *master = g_object_get_data(G_OBJECT(notebook), "group_master");
2360     button = gtk_radio_button_new_with_label_from_widget(
2361     GTK_RADIO_BUTTON(master), label);
2362     }
2363    
2364     gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(button), FALSE);
2365     g_object_set_data(G_OBJECT(button), "page", (gpointer)page_num);
2366    
2367     gtk_signal_connect(GTK_OBJECT(button), "clicked",
2368     GTK_SIGNAL_FUNC(on_notebook_button_clicked), notebook);
2369    
2370     hildon_gtk_widget_set_theme_size(button,
2371     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2372    
2373     gtk_box_pack_start_defaults(
2374     GTK_BOX(g_object_get_data(G_OBJECT(notebook),
2375     (!is_portrait() || page_num < 3)?"hbox0":"hbox1")), button);
2376    
2377     /* update list of "buttons that need to be moved when switching orientation" */
2378     if(page_num >= 3) {
2379     GSList *xbut = g_object_get_data(G_OBJECT(notebook), "xbut");
2380     xbut = g_slist_append(xbut, button);
2381     g_object_set_data(G_OBJECT(notebook), "xbut", xbut);
2382     }
2383    
2384     #else
2385     gtk_notebook_append_page(GTK_NOTEBOOK(notebook), page, gtk_label_new(label));
2386     #endif
2387     }
2388    
2389     GtkWidget *text_wrap(char *str) {
2390     GtkTextBuffer *buffer = gtk_text_buffer_new(NULL);
2391    
2392     #ifndef MAEMO5
2393     GtkWidget *view = gtk_text_view_new_with_buffer(buffer);
2394     #else
2395     GtkWidget *view = hildon_text_view_new();
2396     hildon_text_view_set_buffer(HILDON_TEXT_VIEW(view), buffer);
2397     #endif
2398    
2399     gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(view), GTK_WRAP_WORD);
2400     gtk_text_view_set_editable(GTK_TEXT_VIEW(view), FALSE);
2401     gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(view), FALSE);
2402     gtk_text_view_set_justification(GTK_TEXT_VIEW(view), GTK_JUSTIFY_LEFT);
2403    
2404     gtk_text_buffer_set_text(buffer, str, -1);
2405    
2406     #ifdef MAEMO5
2407     /* in fremantle this is really tricky and we need to inherit the */
2408     /* style from the topmost window in the stack */
2409     HildonWindowStack *stack = hildon_window_stack_get_default();
2410     GList *list = hildon_window_stack_get_windows(stack);
2411     gtk_widget_set_style(view, GTK_WIDGET(list->data)->style);
2412     g_list_free(list);
2413     #else
2414     GtkStyle *style = gtk_widget_get_style(view);
2415     gtk_widget_modify_base(view, GTK_STATE_NORMAL, &style->bg[GTK_STATE_NORMAL]);
2416     #endif
2417    
2418     return view;
2419     }
2420    
2421     void text_set(GtkWidget *view, char *str) {
2422     GtkTextBuffer *buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(view));
2423     gtk_text_buffer_set_text(buffer, str, -1);
2424     }
2425