Diff of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.1  
changed lines
  Added in v.240