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 233 by harbaum, Wed Dec 9 19:45:36 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  /* a entry that is colored red when being "active" */  /* a entry that is colored red when being "active" */
616  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);  
   
617    char str[32];    char str[32];
618    pos_lat_str(str, sizeof(str), lat);    pos_lat_str(str, sizeof(str), lat);
619    gtk_entry_set_text(GTK_ENTRY(widget), str);  
620    #ifndef COORDINATE_PICKER
621      GtkWidget *widget = red_entry_new_with_text(str);
622    
623    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
624                     G_CALLBACK(callback_modified_lat), NULL);                     G_CALLBACK(callback_modified_lat), NULL);
625    
626    #else
627      GtkWidget *widget = gtk_button_new_with_label(str);
628    
629    #ifdef FREMANTLE
630      hildon_gtk_widget_set_theme_size(widget,
631            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
632    #endif
633      int lat_int = (int)roundf(lat * 60000);
634      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
635      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
636                         (GtkSignalFunc)on_lat_picker_button_press, NULL);
637    #endif
638    
639    return widget;    return widget;
640  }  }
641    
642    #ifndef COORDINATE_PICKER
643  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
644    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)));
645    mark(widget, !isnan(i));    mark(widget, !isnan(i));
646  }  }
647    #else
648    static gint on_lon_picker_button_press(GtkWidget *button,
649                       GdkEventButton *event, gpointer data) {
650    
651      if(event->type == GDK_BUTTON_PRESS) {
652        GtkWidget *dialog =
653          gtk_dialog_new_with_buttons(_("Longitude"),
654              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
655                                      GTK_DIALOG_MODAL,
656              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
657              _("Done"),        GTK_RESPONSE_ACCEPT,
658              NULL);
659    
660        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
661    
662        int i, lat = (int)g_object_get_data(G_OBJECT(button), "longitude");
663    
664        /* parse latitude into components */
665        int sign = (lat>=0)?0:1;
666        lat = abs(lat);
667        int deg = lat / 60000;
668        int min = (lat /1000)%60;
669        int minfrac = lat % 1000;
670    
671        GtkWidget *signw, *degw[3], *minw[2], *minfracw[3];
672    
673        /* create E/W 179° 99.999 */
674        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
675        static const char *ew[] = { "E", "W", NULL };
676        gtk_box_pack_start_defaults(GTK_BOX(hbox),
677                    signw = string_picker_create(ew, sign));
678    
679        gtk_box_pack_start_defaults(GTK_BOX(hbox),
680                    degw[0] = digit_picker_create(0,1, deg/100));
681        gtk_box_pack_start_defaults(GTK_BOX(hbox),
682                    degw[1] = digit_picker_create(0,9, (deg/10)%10));
683        gtk_box_pack_start_defaults(GTK_BOX(hbox),
684                    degw[2] = digit_picker_create(0,9, deg%10));
685        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
686    
687        gtk_box_pack_start_defaults(GTK_BOX(hbox),
688                    minw[0] = digit_picker_create(0,5, min/10));
689        gtk_box_pack_start_defaults(GTK_BOX(hbox),
690                    minw[1] = digit_picker_create(0,9, min%10));
691        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
692    
693        gtk_box_pack_start_defaults(GTK_BOX(hbox),
694                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
695        gtk_box_pack_start_defaults(GTK_BOX(hbox),
696                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
697        gtk_box_pack_start_defaults(GTK_BOX(hbox),
698                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
699    
700        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
701    
702        gtk_widget_show_all(dialog);
703        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
704    
705          /* parse degrees ... */
706          for(deg=0,i=0;i<3;i++)
707            deg = 10 * deg + picker_get(degw[i]);
708    
709          /* ... minutes ... */
710          for(min=0,i=0;i<2;i++)
711            min = 10 * min + picker_get(minw[i]);
712    
713          /* ... and fractions of minutes */
714          for(minfrac=0,i=0;i<3;i++)
715            minfrac = 10 * minfrac + picker_get(minfracw[i]);
716    
717          if(deg | min | minfrac)
718            sign = picker_get(signw)?-1:1;
719          else
720            sign = 1;   // theres no W 00 00.000
721    
722          float longitude = sign * (deg + min/60.0 + minfrac/60000.0);
723          lon_entry_set(button, longitude);
724        }
725    
726        gtk_widget_destroy(dialog);
727    
728        return TRUE;
729      }
730      return FALSE;
731    }
732    #endif
733    
734  /* a entry that is colored red when filled with invalid coordinate */  /* a entry that is colored red when filled with invalid coordinate */
735  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);  
   
736    char str[32];    char str[32];
737    pos_lon_str(str, sizeof(str), lon);    pos_lon_str(str, sizeof(str), lon);
   gtk_entry_set_text(GTK_ENTRY(widget), str);  
738    
739    #ifndef COORDINATE_PICKER
740      GtkWidget *widget = red_entry_new_with_text(str);
741    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
742                     G_CALLBACK(callback_modified_lon), NULL);                     G_CALLBACK(callback_modified_lon), NULL);
743    
744    #else
745      GtkWidget *widget = gtk_button_new_with_label(str);
746    
747    #ifdef FREMANTLE
748      hildon_gtk_widget_set_theme_size(widget,
749            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
750    #endif
751      int lon_int = (int)roundf(lon * 60000);
752      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
753      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
754                         (GtkSignalFunc)on_lon_picker_button_press, NULL);
755    #endif
756    
757    return widget;    return widget;
758  }  }
759    
760    float lat_entry_get(GtkWidget *widget) {
761  float lat_get(GtkWidget *widget) {  #ifndef COORDINATE_PICKER
762    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
763    #else
764      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
765    #endif
766    return pos_parse_lat(p);    return pos_parse_lat(p);
767  }  }
768    
769  float lon_get(GtkWidget *widget) {  float lon_entry_get(GtkWidget *widget) {
770    #ifndef COORDINATE_PICKER
771    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
772    #else
773      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
774    #endif
775    return pos_parse_lon(p);    return pos_parse_lon(p);
776  }  }
777    
778    void lat_entry_set(GtkWidget *widget, float lat) {
779      char str[32];
780      pos_lat_str(str, sizeof(str)-1, lat);
781    #ifndef COORDINATE_PICKER
782      gtk_entry_set_text(GTK_ENTRY(widget), str);
783    #else
784      gtk_button_set_label(GTK_BUTTON(widget), str);
785      int lat_int = (int)roundf(lat * 60000);
786      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
787      g_signal_emit_by_name(widget, "changed");
788    #endif
789    }
790    
791    void lon_entry_set(GtkWidget *widget, float lon) {
792      char str[32];
793      pos_lon_str(str, sizeof(str)-1, lon);
794    #ifndef COORDINATE_PICKER
795      gtk_entry_set_text(GTK_ENTRY(widget), str);
796    #else
797      gtk_button_set_label(GTK_BUTTON(widget), str);
798      int lon_int = (int)roundf(lon * 60000);
799      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
800      g_signal_emit_by_name(widget, "changed");
801    #endif
802    }
803    
804    void lat_label_set(GtkWidget *widget, float lat) {
805      char str[32];
806      pos_lat_str(str, sizeof(str)-1, lat);
807      gtk_label_set(GTK_LABEL(widget), str);
808    }
809    
810    void lon_label_set(GtkWidget *widget, float lon) {
811      char str[32];
812      pos_lon_str(str, sizeof(str)-1, lon);
813      gtk_label_set(GTK_LABEL(widget), str);
814    }
815    
816    void lat_label_attrib_set(GtkWidget *widget, float lat,
817                              int size, int strikethrough) {
818      char str[32];
819      pos_lat_str(str, sizeof(str)-1, lat);
820      gtk_label_attrib_set(widget, str, size, strikethrough);
821    }
822    
823    void lon_label_attrib_set(GtkWidget *widget, float lon,
824                              int size, int strikethrough) {
825      char str[32];
826      pos_lon_str(str, sizeof(str)-1, lon);
827      gtk_label_attrib_set(widget, str, size, strikethrough);
828    }
829    
830    #ifndef COORDINATE_PICKER
831  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
832    /* 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 */
833    /* is parseable at all */    /* is parseable at all */
834    float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);    float i =
835        distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
836    mark(widget, !isnan(i));    mark(widget, !isnan(i));
837  }  }
838    #else
839    static gint on_dist_picker_button_press(GtkWidget *button,
840                       GdkEventButton *event, gpointer data) {
841    
842      if(event->type == GDK_BUTTON_PRESS) {
843        GtkWidget *dialog =
844          gtk_dialog_new_with_buttons(_("Distance"),
845              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
846                                      GTK_DIALOG_MODAL,
847              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
848              _("Done"),        GTK_RESPONSE_ACCEPT,
849              NULL);
850    
851        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
852    
853        /* distance is given in m or ft (depending on mil) */
854        int i, dist = (int)g_object_get_data(G_OBJECT(button), "distance");
855        gboolean mil = (gboolean)g_object_get_data(G_OBJECT(button), "mil");
856        int unit = 0;
857    
858        /* parse distance into components */
859        if(mil) {
860          /* 1 mil = 1760 yd = 5280 ft. 1yd = 3 ft */
861          if(dist<95)        { unit = 0; dist *= 100;  }
862          else if(dist<2904) { unit = 1; dist = 100 * dist / 3;  }
863          else               { unit = 2; dist = 5 * dist / 264; }
864        } else {
865          if(dist<1000)      { unit = 3; dist *= 100;  }
866          else               { unit = 4; dist /= 10; }
867        }
868    
869        GtkWidget *distw[4], *fracw[2], *unitw;
870    
871        /* create xxxx.x unit */
872        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
873    
874        gtk_box_pack_start_defaults(GTK_BOX(hbox),
875                    distw[0] = digit_picker_create(0,9, (dist/100000)%10));
876        gtk_box_pack_start_defaults(GTK_BOX(hbox),
877                    distw[1] = digit_picker_create(0,9, (dist/10000)%10));
878        gtk_box_pack_start_defaults(GTK_BOX(hbox),
879                    distw[2] = digit_picker_create(0,9, (dist/1000)%10));
880        gtk_box_pack_start_defaults(GTK_BOX(hbox),
881                    distw[3] = digit_picker_create(0,9, (dist/100)%10));
882        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
883        gtk_box_pack_start_defaults(GTK_BOX(hbox),
884                    fracw[0] = digit_picker_create(0,9, (dist/10)%10));
885        gtk_box_pack_start_defaults(GTK_BOX(hbox),
886                    fracw[1] = digit_picker_create(0,9, (dist/1)%10));
887    
888        static const char *units[] = { "ft", "yd", "mi", "m", "km", NULL };
889        gtk_box_pack_start_defaults(GTK_BOX(hbox),
890                    unitw = string_picker_create(units, unit));
891    
892        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
893    
894        gtk_widget_show_all(dialog);
895        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
896    
897          /* parse distance */
898          for(dist=0,i=0;i<4;i++)
899            dist = 10 * dist + picker_get(distw[i]);
900    
901          for(i=0;i<2;i++)
902            dist = 10 * dist + picker_get(fracw[i]);
903    
904          unit = picker_get(unitw);
905          if(unit == 0)      { dist /= 100; }         // ft
906          else if(unit == 1) { dist = 3*dist/100; }   // yd
907          else if(unit == 2) { dist = 528*dist/10; }  // mi
908          else if(unit == 3) { dist /= 100; }         // m
909          else if(unit == 4) { dist *= 10; }          // km
910    
911          /* user may have switched between metric and imperial */
912          float distance;
913          if(unit <= 2) {
914            distance = dist / 5280.0;
915            if(!mil) distance *=  1.609344;
916          } else {
917            distance = dist / 1000.0;
918            if( mil) distance /=  1.609344;
919          }
920    
921          dist_entry_set(button, distance, mil);
922        }
923    
924        gtk_widget_destroy(dialog);
925    
926        return TRUE;
927      }
928      return FALSE;
929    }
930    #endif
931    
932  /* a entry that is colored red when filled with invalid distance */  /* a entry that is colored red when filled with invalid distance */
933  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);  
   
934    char str[32];    char str[32];
935    distance_str(str, sizeof(str), dist, mil);    distance_str(str, sizeof(str), dist, mil);
   gtk_entry_set_text(GTK_ENTRY(widget), str);  
936    
937    #ifndef COORDINATE_PICKER
938      GtkWidget *widget = red_entry_new_with_text(str);
939    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
940                     G_CALLBACK(callback_modified_dist), NULL);                     G_CALLBACK(callback_modified_dist), NULL);
941    
942    #else
943      GtkWidget *widget = gtk_button_new_with_label(str);
944    
945    #ifdef FREMANTLE
946      hildon_gtk_widget_set_theme_size(widget,
947            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
948    #endif
949      int dist_int = (int)roundf(dist * 1000);        // km -> m
950      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
951    
952      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
953      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
954      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
955                         (GtkSignalFunc)on_dist_picker_button_press, NULL);
956    #endif
957    
958    return widget;    return widget;
959  }  }
960    
961  float dist_get(GtkWidget *widget, gboolean mil) {  float dist_entry_get(GtkWidget *widget, gboolean mil) {
962    #ifndef COORDINATE_PICKER
963    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
964    #else
965      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
966    #endif
967    return distance_parse(p, mil);    return distance_parse(p, mil);
968  }  }
969    
970    void dist_entry_set(GtkWidget *widget, float dist, gboolean mil) {
971      char str[32];
972      distance_str(str, sizeof(str), dist, mil);
973    
974    #ifndef COORDINATE_PICKER
975      gtk_entry_set_text(GTK_ENTRY(widget), str);
976    #else
977      gtk_button_set_label(GTK_BUTTON(widget), str);
978      int dist_int = (int)roundf(dist * 1000);        // km -> m
979      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
980      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
981      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
982      g_signal_emit_by_name(widget, "changed");
983    #endif
984    }
985    
986  #ifndef USE_MAEMO  #ifndef USE_MAEMO
987  #ifdef ENABLE_BROWSER_INTERFACE  #ifdef ENABLE_BROWSER_INTERFACE
988  #include <libgnome/gnome-url.h>  #include <libgnome/gnome-url.h>
# Line 375  int browser_url(appdata_t *appdata, char Line 995  int browser_url(appdata_t *appdata, char
995  }  }
996  #endif  #endif
997  #endif  #endif
998    
999    /* recursively remove an entire file system */
1000    void rmdir_recursive(char *path) {
1001      GDir *dir = g_dir_open(path, 0, NULL);
1002      if(dir) {
1003        const char *name = g_dir_read_name(dir);
1004        while(name) {
1005          char *fullname = g_strdup_printf("%s/%s", path, name);
1006          //      printf("deleting %s\n", fullname);
1007    
1008          if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
1009            rmdir_recursive(fullname);
1010          else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
1011            g_remove(fullname);
1012    
1013          g_free(fullname);
1014          name = g_dir_read_name(dir);
1015        }
1016    
1017        g_dir_close(dir);
1018      }
1019      g_rmdir(path);
1020    }
1021    
1022    #ifdef ENABLE_BROWSER_INTERFACE
1023    static void on_link_clicked(GtkButton *button, gpointer data) {
1024      appdata_t *appdata = (appdata_t*)data;
1025      char *url = g_object_get_data(G_OBJECT(button), "url");
1026      if(url) browser_url(appdata, url);
1027    }
1028    #endif
1029    
1030    /* a button containing a weblink */
1031    GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
1032                           int size, int strikethrough) {
1033    
1034    #ifdef ENABLE_BROWSER_INTERFACE
1035      if(url) {
1036        GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
1037        g_object_set_data(G_OBJECT(button), "url", url);
1038        gtk_signal_connect(GTK_OBJECT(button), "clicked",
1039                           (GtkSignalFunc)on_link_clicked, appdata);
1040    
1041        return button;
1042      }
1043    #endif
1044      return gtk_label_attrib(str, size, strikethrough);
1045    }
1046    
1047    #ifdef ENABLE_BROWSER_INTERFACE
1048    static void on_link_id_clicked(GtkButton *button, gpointer data) {
1049      appdata_t *appdata = (appdata_t*)data;
1050    
1051      unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
1052      char *type = g_object_get_data(G_OBJECT(button), "type");
1053    
1054      char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
1055                                  type, id);
1056    
1057      if(url) {
1058        browser_url(appdata, url);
1059        g_free(url);
1060      }
1061    }
1062    #endif
1063    
1064    GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
1065                                 const char *type, int id) {
1066    
1067    #ifdef ENABLE_BROWSER_INTERFACE
1068      if(id) {
1069        GtkWidget *ref = gtk_button_new_with_label(str);
1070    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1071        //    hildon_gtk_widget_set_theme_size(ref,
1072        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1073    #endif
1074        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1075        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1076        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1077                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1078    
1079        return ref;
1080      }
1081    #endif
1082      return gtk_label_new(str);
1083    }
1084    
1085    
1086    GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
1087                                 const char *type, int id) {
1088    
1089    #ifdef ENABLE_BROWSER_INTERFACE
1090      if(id) {
1091        GtkWidget *ref = gtk_button_new();
1092        gtk_button_set_image(GTK_BUTTON(ref), icon);
1093    
1094    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1095        //    hildon_gtk_widget_set_theme_size(ref,
1096        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1097    #endif
1098        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1099        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1100        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1101                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1102    
1103        return ref;
1104      }
1105    #endif
1106      return icon;
1107    }
1108    
1109    /* left aligned, word wrapped multiline widget */
1110    GtkWidget *simple_text_widget(char *text) {
1111      GtkWidget *label = gtk_label_new(text);
1112    
1113      gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1114      gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
1115      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1116    
1117      return label;
1118    }
1119    
1120    
1121    /* a label that is left aligned */
1122    GtkWidget *left_label_new(char *str) {
1123      GtkWidget *widget = gtk_label_new(str);
1124      gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
1125      return widget;
1126    }
1127    
1128    /* ------------- preset coordinate picker tool ----------------- */
1129    
1130    static void pos_set(GtkWidget *item, float lat, float lon) {
1131    
1132      GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1133      lat_entry_set(lat_entry, lat);
1134    
1135      GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1136      lon_entry_set(lon_entry, lon);
1137    }
1138    
1139    static void cb_gps(GtkWidget *item, gpointer data) {
1140      appdata_t *appdata = (appdata_t*)data;
1141      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1142      pos_t *pos = NULL;
1143    
1144      if(!id)
1145        pos = gps_get_pos(appdata);
1146      else if(id == 1)
1147        pos = &appdata->home;
1148      else {
1149        location_t *location = appdata->location;
1150        while(location && id > 2) {
1151          location = location->next;
1152          id--;
1153        }
1154    
1155        if(id == 2)
1156          pos = &location->pos;
1157      }
1158    
1159      if(!pos) pos_set(item, NAN, NAN);
1160      else     pos_set(item, pos->lat, pos->lon);
1161    }
1162    
1163    static void cb_geomath(GtkWidget *item, gpointer data) {
1164      appdata_t *appdata = (appdata_t*)data;
1165    
1166      pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
1167    }
1168    
1169    #ifdef ENABLE_OSM_GPS_MAP
1170    static void cb_map(GtkWidget *item, gpointer data) {
1171      appdata_t *appdata = (appdata_t*)data;
1172    
1173      pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
1174    }
1175    #endif
1176    
1177    #ifdef ENABLE_MAEMO_MAPPER
1178    static void cb_mm(GtkWidget *item, gpointer data) {
1179      appdata_t *appdata = (appdata_t*)data;
1180    
1181      pos_set(item, appdata->mmpos.lat, appdata->mmpos.lon);
1182    }
1183    #endif
1184    
1185    static void cb_cache(GtkWidget *item, gpointer data) {
1186      appdata_t *appdata = (appdata_t*)data;
1187    
1188      cache_t *cache = appdata->cur_cache;
1189      g_assert(cache);
1190    
1191      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1192    
1193      if(!id)
1194        pos_set(item, cache->pos.lat, cache->pos.lon);
1195      else if(id == 1) {
1196        /* fetch position out of notes dialog since they probably */
1197        /* haven't been saved yet */
1198        pos_t pos = notes_get_pos(appdata->cache_context);
1199        pos_set(item, pos.lat, pos.lon);
1200      } else {
1201        wpt_t *wpt = cache->wpt;
1202        while(wpt && id > 2) {
1203          wpt = wpt->next;
1204          id--;
1205        }
1206    
1207        if(id == 2)
1208          pos_set(item, wpt->pos.lat, wpt->pos.lon);
1209      }
1210    }
1211    
1212    #ifndef PRESET_PICKER_DIALOG
1213    static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1214                               GtkWidget *icon, char *menu_str,
1215                               void(*func)(GtkWidget*, gpointer), gint id,
1216                               GtkWidget *lon_entry, GtkWidget *lat_entry) {
1217    
1218      GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
1219    
1220      if(icon)
1221        gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
1222    
1223      g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
1224      g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
1225      g_object_set_data(G_OBJECT(item), "id", (gpointer)id);
1226    
1227      if(func)
1228        gtk_signal_connect(GTK_OBJECT(item), "activate",
1229                           (GtkSignalFunc)func, appdata);
1230    
1231      gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1232    
1233      return item;
1234    }
1235    
1236    static GtkWidget *popup_menu_create(appdata_t *appdata,
1237                        GtkWidget *lat_entry, GtkWidget *lon_entry) {
1238      GtkWidget *menu = gtk_menu_new();
1239    
1240      if(pos_valid(gps_get_pos(appdata)))
1241        menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1242                 _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1243    
1244      if(pos_valid(&appdata->home))
1245        menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1246                 _("Home"), cb_gps, 1, lon_entry, lat_entry);
1247    
1248      location_t *location = appdata->location;
1249      gint id = 2;
1250      while(location) {
1251        if(pos_valid(&location->pos))
1252          menu_add(menu, appdata, icon_get_widget(ICON_POS, 17),
1253                   location->name, cb_gps, id, lon_entry, lat_entry);
1254    
1255        id++;
1256        location = location->next;
1257      }
1258    
1259      if(pos_valid(&appdata->geomath))
1260        menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
1261                 _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
1262    
1263    #ifdef ENABLE_OSM_GPS_MAP
1264      if(pos_valid(&appdata->map.pos))
1265        menu_add(menu, appdata, icon_get_widget(ICON_POS, 20), _("Map position"),
1266                 cb_map, 0, lon_entry, lat_entry);
1267    #endif
1268    
1269    #ifdef ENABLE_MAEMO_MAPPER
1270      if(appdata->mmpos_valid) {
1271        menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1272                 _("Maemo Mapper position"), cb_mm, 0, lon_entry, lat_entry);
1273      }
1274    #endif
1275    
1276      if(appdata->cur_cache) {
1277        cache_t *cache = appdata->cur_cache;
1278    
1279        char *name = cache->name;
1280        if(!name) name = cache->id;
1281    
1282        /* original cache position */
1283        if(pos_valid(&cache->pos))
1284          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1285                   name, cb_cache, 0, lon_entry, lat_entry);
1286    
1287        /* overwritten cache position */
1288        if(appdata->cache_context && notes_get_override(appdata->cache_context))
1289          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1290                   _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1291    
1292        wpt_t *wpt = cache->wpt;
1293        gint id = 2;
1294        while(wpt) {
1295          if(pos_valid(&wpt->pos)) {
1296            GtkWidget *icon = NULL;
1297            if(wpt->sym != WPT_SYM_UNKNOWN)
1298              icon = icon_get_widget(ICON_POS, wpt->sym);
1299    
1300            char *name = wpt->desc;
1301            if(!name) name = wpt->cmt;
1302            if(!name) name = wpt->id;
1303    
1304            menu_add(menu, appdata, icon, name, cb_cache, id,
1305                     lon_entry, lat_entry);
1306          }
1307    
1308          id++;
1309          wpt = wpt->next;
1310        }
1311      }
1312    
1313      gtk_widget_show_all(menu);
1314    
1315      return menu;
1316    }
1317    
1318    static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1319                                      gpointer data) {
1320    
1321      appdata_t *appdata = (appdata_t*)data;
1322    
1323      if(event->type == GDK_BUTTON_PRESS) {
1324        GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1325    
1326        if(menu)
1327          gtk_widget_destroy(menu);
1328    
1329        gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1330        g_assert(lat_entry);
1331        gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1332        g_assert(lon_entry);
1333    
1334        menu = popup_menu_create(appdata, lat_entry, lon_entry);
1335        g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1336    
1337        /* draw a popup menu */
1338        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1339                       event->button, event->time);
1340        return TRUE;
1341      }
1342      return FALSE;
1343    }
1344    
1345    static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1346      GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1347      if(menu) gtk_widget_destroy(menu);
1348    }
1349    #endif
1350    
1351    #ifdef PRESET_PICKER_DIALOG
1352    
1353    enum {
1354      PRESET_PICKER_COL_ICON = 0,
1355      PRESET_PICKER_COL_NAME,
1356      PRESET_PICKER_COL_ID,
1357      PRESET_PICKER_COL_CB,
1358      PRESET_PICKER_NUM_COLS
1359    };
1360    
1361    static void preset_picker_add(GtkListStore *store,  appdata_t *appdata,
1362                           GdkPixbuf *icon, char *menu_str,
1363                           void(*func)(GtkWidget*, gpointer), gint id) {
1364      GtkTreeIter     iter;
1365    
1366      /* Append a row and fill in some data */
1367      gtk_list_store_append (store, &iter);
1368    
1369      gtk_list_store_set(store, &iter,
1370                         PRESET_PICKER_COL_ICON, icon,
1371                         PRESET_PICKER_COL_NAME, menu_str,
1372                         PRESET_PICKER_COL_ID, id,
1373                         PRESET_PICKER_COL_CB, func,
1374                         -1);
1375    }
1376    
1377    static void on_preset_picker_activated(GtkTreeView        *treeview,
1378                                    GtkTreePath        *path,
1379                                    GtkTreeViewColumn  *col,
1380                                    gpointer            userdata) {
1381      GtkTreeIter   iter;
1382      GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1383    
1384      if(gtk_tree_model_get_iter(model, &iter, path)) {
1385        gint id;
1386        void(*func)(GtkWidget*, gpointer);
1387        gtk_tree_model_get(model, &iter,
1388                           PRESET_PICKER_COL_ID, &id,
1389                           PRESET_PICKER_COL_CB, &func,
1390                           -1);
1391    
1392        /* set id on widget as callbacks expect it this way */
1393        g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1394        func(GTK_WIDGET(treeview), userdata);
1395    
1396        gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1397                        GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1398    
1399      }
1400    }
1401    
1402    static GtkWidget *preset_picker_create(appdata_t *appdata,
1403                                    GtkWidget *lat_entry, GtkWidget *lon_entry) {
1404      GtkCellRenderer *renderer;
1405      GtkListStore    *store;
1406    
1407      GtkWidget *view = gtk_tree_view_new();
1408    
1409      g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1410      g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1411    
1412      /* --- "Icon" column --- */
1413      renderer = gtk_cell_renderer_pixbuf_new();
1414      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1415          -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1416    
1417      /* --- "Name" column --- */
1418      renderer = gtk_cell_renderer_text_new();
1419      g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1420      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1421                     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1422      gtk_tree_view_column_set_expand(column, TRUE);
1423      gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1424    
1425      store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1426                                 GDK_TYPE_PIXBUF,
1427                                 G_TYPE_STRING,
1428                                 G_TYPE_INT,
1429                                 G_TYPE_POINTER);
1430    
1431      if(pos_valid(gps_get_pos(appdata)))
1432        preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1433                          _("GPS position"), cb_gps, 0);
1434    
1435      if(pos_valid(&appdata->home))
1436        preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1437                          _("Home"), cb_gps, 1);
1438    
1439      location_t *location = appdata->location;
1440      gint id = 2;
1441      while(location) {
1442        if(pos_valid(&location->pos))
1443          preset_picker_add(store, appdata, icon_get(ICON_POS, 17),
1444                            location->name, cb_gps, id);
1445    
1446        id++;
1447        location = location->next;
1448      }
1449    
1450      if(pos_valid(&appdata->geomath))
1451        preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1452                          _("Geomath projection"), cb_geomath, 0);
1453    
1454    #ifdef ENABLE_OSM_GPS_MAP
1455      if(pos_valid(&appdata->map.pos))
1456        preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1457                          _("Map position"), cb_map, 0);
1458    #endif
1459    
1460    #ifdef ENABLE_MAEMO_MAPPER
1461      if(appdata->mmpos_valid) {
1462        preset_picker_add(store, appdata, icon_get(ICON_POS, 24),
1463                          _("Maemo Mapper position"), cb_mm, 0);
1464      }
1465    #endif
1466    
1467      if(appdata->cur_cache) {
1468        cache_t *cache = appdata->cur_cache;
1469    
1470        char *name = cache->name;
1471        if(!name) name = cache->id;
1472    
1473        /* original cache position */
1474        if(pos_valid(&cache->pos))
1475          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1476                            name, cb_cache, 0);
1477    
1478        /* overwritten cache position */
1479        if(appdata->cache_context && notes_get_override(appdata->cache_context))
1480          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1481                            _("Modified coordinate"), cb_cache, 1);
1482    
1483        wpt_t *wpt = cache->wpt;
1484        gint id = 2;
1485        while(wpt) {
1486          if(pos_valid(&wpt->pos)) {
1487            GdkPixbuf *icon = NULL;
1488            if(wpt->sym != WPT_SYM_UNKNOWN)
1489              icon = icon_get(ICON_POS, wpt->sym);
1490    
1491            char *name = wpt->desc;
1492            if(!name) name = wpt->cmt;
1493            if(!name) name = wpt->id;
1494    
1495            preset_picker_add(store, appdata, icon, name, cb_cache, id);
1496          }
1497          id++;
1498          wpt = wpt->next;
1499        }
1500      }
1501    
1502      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1503      g_object_unref(store);
1504    
1505      /* make list react on clicks */
1506      g_signal_connect(view, "row-activated",
1507                       (GCallback)on_preset_picker_activated, appdata);
1508    
1509      /* put this inside a scrolled view */
1510    #ifndef USE_PANNABLE_AREA
1511      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1512      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1513                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1514      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1515      return scrolled_window;
1516    #else
1517      GtkWidget *pannable_area = hildon_pannable_area_new();
1518      gtk_container_add(GTK_CONTAINER(pannable_area), view);
1519      return pannable_area;
1520    #endif
1521    }
1522    
1523    static gint on_preset_picker_button_press(GtkWidget *button,
1524                       GdkEventButton *event, gpointer data) {
1525      appdata_t *appdata = (appdata_t*)data;
1526    
1527      gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1528      gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1529    
1530      if(event->type == GDK_BUTTON_PRESS) {
1531        GtkWidget *dialog =
1532          gtk_dialog_new_with_buttons(_("Use coordinate"),
1533              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1534                                      GTK_DIALOG_MODAL,
1535              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1536              NULL);
1537    
1538        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1539    
1540        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1541                            preset_picker_create(appdata, lat_entry, lon_entry));
1542    
1543        gtk_widget_show_all(dialog);
1544        gtk_dialog_run(GTK_DIALOG(dialog));
1545        gtk_widget_destroy(dialog);
1546    
1547        return TRUE;
1548      }
1549      return FALSE;
1550    }
1551    #endif
1552    
1553    
1554    GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1555                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1556    
1557      GtkWidget *button = gtk_button_new();
1558    
1559      gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 22));
1560    
1561    #ifndef USE_MAEMO
1562      gtk_widget_set_tooltip_text(button, _("Use coordinate"));
1563    #endif
1564    
1565      g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1566      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1567    
1568    #ifndef PRESET_PICKER_DIALOG
1569      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1570                         (GtkSignalFunc)on_popup_button_press, appdata);
1571    
1572      gtk_signal_connect(GTK_OBJECT(button), "destroy",
1573                         (GtkSignalFunc)on_popup_destroy, appdata);
1574    #else
1575    #ifdef FREMANTLE
1576      hildon_gtk_widget_set_theme_size(button,
1577            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1578    #endif
1579    
1580      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1581                         (GtkSignalFunc)on_preset_picker_button_press, appdata);
1582    #endif
1583    
1584      return button;
1585    }
1586    
1587    #if defined(ENABLE_MAEMO_MAPPER) || defined(ENABLE_OSM_GPS_MAP)
1588    static pos_t goto_pos_get(GtkWidget *item) {
1589      pos_t pos;
1590    
1591      GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1592      pos.lat = lat_entry_get(lat_entry);
1593    
1594      GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1595      pos.lon = lon_entry_get(lon_entry);
1596    
1597      return  pos;
1598    }
1599    
1600    #if defined(ENABLE_MAEMO_MAPPER) && defined(ENABLE_OSM_GPS_MAP)
1601    #ifdef ENABLE_MAEMO_MAPPER
1602    static void cb_mm_set(GtkWidget *item, gpointer data) {
1603      appdata_t *appdata = (appdata_t*)data;
1604    
1605      pos_t pos = goto_pos_get(item);
1606      if(!isnan(pos.lat) && !isnan(pos.lon))
1607        dbus_mm_set_position(appdata, &pos);
1608    }
1609    #endif
1610    
1611    #ifdef ENABLE_OSM_GPS_MAP
1612    static void cb_map_set(GtkWidget *item, gpointer data) {
1613      appdata_t *appdata = (appdata_t*)data;
1614    
1615      pos_t pos = goto_pos_get(item);
1616      if(!isnan(pos.lat) && !isnan(pos.lon)) {
1617        map(appdata);
1618        osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1619                                 pos.lat, pos.lon);
1620      }
1621    }
1622    #endif
1623    
1624    #ifndef PRESET_PICKER_DIALOG
1625    static GtkWidget *goto_popup_menu_create(appdata_t *appdata,
1626                        GtkWidget *lat_entry, GtkWidget *lon_entry) {
1627      GtkWidget *menu = gtk_menu_new();
1628    
1629    #if defined(ENABLE_OSM_GPS_MAP)
1630      menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1631               _("Internal map"), cb_map_set, 0, lon_entry, lat_entry);
1632    #endif
1633    
1634    #if defined(ENABLE_MAEMO_MAPPER)
1635      menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1636               _("Maemo Mapper"), cb_mm_set, 0, lon_entry, lat_entry);
1637    #endif
1638    
1639      gtk_widget_show_all(menu);
1640    
1641      return menu;
1642    }
1643    #else
1644    static GtkWidget *goto_picker_create(appdata_t *appdata,
1645                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1646      GtkCellRenderer *renderer;
1647      GtkListStore    *store;
1648    
1649      GtkWidget *view = gtk_tree_view_new();
1650    
1651      g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1652      g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1653    
1654      /* --- "Icon" column --- */
1655      renderer = gtk_cell_renderer_pixbuf_new();
1656      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1657          -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1658    
1659      /* --- "Name" column --- */
1660      renderer = gtk_cell_renderer_text_new();
1661      g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1662      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1663                     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1664      gtk_tree_view_column_set_expand(column, TRUE);
1665      gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1666    
1667      store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1668                                 GDK_TYPE_PIXBUF,
1669                                 G_TYPE_STRING,
1670                                 G_TYPE_INT,
1671                                 G_TYPE_POINTER);
1672    
1673    #if defined(ENABLE_OSM_GPS_MAP)
1674      preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1675                        _("Internal map"), cb_map_set, 0);
1676    #endif
1677    
1678    #if defined(ENABLE_MAEMO_MAPPER)
1679      preset_picker_add(store, appdata, icon_get(ICON_POS, 24),
1680                        _("Maemo Mapper"), cb_mm_set, 0);
1681    #endif
1682    
1683      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1684      g_object_unref(store);
1685    
1686      /* make list react on clicks */
1687      g_signal_connect(view, "row-activated",
1688                       (GCallback)on_preset_picker_activated, appdata);
1689    
1690      /* put this inside a scrolled view */
1691    #ifndef USE_PANNABLE_AREA
1692      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1693      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1694                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1695      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1696      return scrolled_window;
1697    #else
1698      GtkWidget *pannable_area = hildon_pannable_area_new();
1699      gtk_container_add(GTK_CONTAINER(pannable_area), view);
1700      return pannable_area;
1701    #endif
1702    }
1703    #endif
1704    #endif
1705    
1706    static gint on_goto_button_press(GtkWidget *button,
1707                                     GdkEventButton *event, gpointer data) {
1708      appdata_t *appdata = (appdata_t*)data;
1709    
1710      if(event->type == GDK_BUTTON_PRESS) {
1711    
1712    #if defined(ENABLE_MAEMO_MAPPER) && !defined(ENABLE_OSM_GPS_MAP)
1713        /* only maemo mapper is being used */
1714        pos_t pos = goto_pos_get(button);
1715        if(!isnan(pos.lat) && !isnan(pos.lon))
1716          dbus_mm_set_position(appdata, &pos);
1717    #elif !defined(ENABLE_MAEMO_MAPPER) && defined(ENABLE_OSM_GPS_MAP)
1718        /* only internal map is being used */
1719        pos_t pos = goto_pos_get(button);
1720        if(!isnan(pos.lat) && !isnan(pos.lon)) {
1721          map(appdata);
1722          osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1723                                 pos.lat, pos.lon);
1724        }
1725    #else
1726    
1727        gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1728        g_assert(lat_entry);
1729        gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1730        g_assert(lon_entry);
1731    
1732    #ifndef PRESET_PICKER_DIALOG
1733        GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1734        if(!menu) {
1735          menu = goto_popup_menu_create(appdata, lat_entry, lon_entry);
1736          g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1737        }
1738    
1739        /* draw a popup menu */
1740        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1741                       event->button, event->time);
1742    #else
1743        GtkWidget *dialog =
1744          gtk_dialog_new_with_buttons(_("Show coordinate on map"),
1745              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1746                                      GTK_DIALOG_MODAL,
1747              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1748              NULL);
1749    
1750        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1751    
1752        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1753                            goto_picker_create(appdata, lat_entry, lon_entry));
1754    
1755        gtk_widget_show_all(dialog);
1756        gtk_dialog_run(GTK_DIALOG(dialog));
1757        gtk_widget_destroy(dialog);
1758    #endif
1759    
1760    #endif
1761    
1762        return TRUE;
1763      }
1764      return FALSE;
1765    }
1766    
1767    /* a button which makes the map/maemo mapper go to the associated */
1768    /* position */
1769    GtkWidget *goto_coordinate(appdata_t *appdata,
1770                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1771    
1772      GtkWidget *button = gtk_button_new();
1773    
1774      gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 23));
1775    
1776    #ifndef USE_MAEMO
1777      gtk_widget_set_tooltip_text(button, _("Show coordinate on map"));
1778    #endif
1779    
1780      g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1781      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1782    
1783      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1784                         (GtkSignalFunc)on_goto_button_press, appdata);
1785    
1786    #ifndef PRESET_PICKER_DIALOG
1787      gtk_signal_connect(GTK_OBJECT(button), "destroy",
1788                         (GtkSignalFunc)on_popup_destroy, appdata);
1789    #else
1790    #ifdef FREMANTLE
1791      hildon_gtk_widget_set_theme_size(button,
1792            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1793    #endif
1794    #endif
1795    
1796      return button;
1797    }
1798    #else
1799    /* no map installed */
1800    GtkWidget *goto_coordinate(appdata_t *appdata,
1801                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1802      return gtk_label_new("");
1803    }
1804    #endif
1805    
1806    GtkWidget *entry_new(void) {
1807    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1808      return gtk_entry_new();
1809    #else
1810      return hildon_entry_new(HILDON_SIZE_AUTO);
1811    #endif
1812    }
1813    
1814    gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
1815      int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
1816      int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
1817    
1818      return((lat1 != lat2) || (lon1 != lon2));
1819    }
1820    
1821    gboolean pos_valid(pos_t *pos) {
1822      if(!pos) return FALSE;
1823      return(!isnan(pos->lat) && !isnan(pos->lon));
1824    }
1825    
1826    void misc_init(void) {
1827      g_signal_new ("changed", GTK_TYPE_BUTTON,
1828                    G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
1829                    g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1830    }
1831    
1832    void angle_str(char *str, int len, float angle) {
1833      snprintf(str, len, _("%.1f°"), angle);
1834    }
1835    
1836    float angle_parse(char *str) {
1837      float val;
1838    
1839      if(sscanf(str, _("%f°"), &val) != 1)
1840        val = NAN;
1841    
1842      return val;
1843    }
1844    
1845    #ifndef COORDINATE_PICKER
1846    static void callback_modified_angle(GtkWidget *widget, gpointer data ) {
1847      float i = angle_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
1848      mark(widget, !isnan(i));
1849    }
1850    #else
1851    static gint on_angle_picker_button_press(GtkWidget *button,
1852                       GdkEventButton *event, gpointer data) {
1853    
1854      if(event->type == GDK_BUTTON_PRESS) {
1855        GtkWidget *dialog =
1856          gtk_dialog_new_with_buttons(_("Direction"),
1857              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1858                                      GTK_DIALOG_MODAL,
1859              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1860              _("Done"),        GTK_RESPONSE_ACCEPT,
1861              NULL);
1862    
1863        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1864    
1865        int i, angle = (int)g_object_get_data(G_OBJECT(button), "angle");
1866    
1867        GtkWidget *anglew[3], *fracw;
1868    
1869        /* create xxx.x° */
1870        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
1871    
1872        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1873                    anglew[0] = digit_picker_create(0,3, (angle/1000)%10));
1874        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1875                    anglew[1] = digit_picker_create(0,9, (angle/100)%10));
1876        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1877                    anglew[2] = digit_picker_create(0,9, (angle/10)%10));
1878        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
1879        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1880                    fracw = digit_picker_create(0,9, (angle/1)%10));
1881        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
1882    
1883        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1884    
1885        gtk_widget_show_all(dialog);
1886        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1887    
1888          /* parse angle */
1889          for(angle=0,i=0;i<3;i++)
1890            angle = 10 * angle + picker_get(anglew[i]);
1891    
1892          angle = 10 * angle + picker_get(fracw);
1893    
1894          angle_entry_set(button, angle/10.0);
1895        }
1896    
1897        gtk_widget_destroy(dialog);
1898    
1899        return TRUE;
1900      }
1901      return FALSE;
1902    }
1903    #endif
1904    
1905    GtkWidget *angle_entry_new(float angle) {
1906      char str[32];
1907      angle_str(str, sizeof(str), angle);
1908    
1909    #ifndef COORDINATE_PICKER
1910      GtkWidget *widget = red_entry_new_with_text(str);
1911      g_signal_connect(G_OBJECT(widget), "changed",
1912                       G_CALLBACK(callback_modified_angle), NULL);
1913    #else
1914      GtkWidget *widget = gtk_button_new_with_label(str);
1915    
1916    #ifdef FREMANTLE
1917      hildon_gtk_widget_set_theme_size(widget,
1918            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1919    #endif
1920      int angle_int = (int)roundf(angle*10.0);
1921      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1922      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
1923                         (GtkSignalFunc)on_angle_picker_button_press, NULL);
1924    #endif
1925      return widget;
1926    }
1927    
1928    float angle_entry_get(GtkWidget *widget) {
1929    #ifndef COORDINATE_PICKER
1930      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
1931    #else
1932      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
1933    #endif
1934      return angle_parse(p);
1935    }
1936    
1937    void angle_entry_set(GtkWidget *widget, float angle) {
1938      char str[32];
1939      angle_str(str, sizeof(str)-1, angle);
1940    #ifndef COORDINATE_PICKER
1941      gtk_entry_set_text(GTK_ENTRY(widget), str);
1942    #else
1943      gtk_button_set_label(GTK_BUTTON(widget), str);
1944      int angle_int = (int)roundf(angle * 10.0);
1945      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1946      g_signal_emit_by_name(widget, "changed");
1947    #endif
1948    }
1949    
1950    GtkWidget *toggle_button_new_with_label(char *label) {
1951    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1952      return gtk_check_button_new_with_label(label);
1953    #else
1954      GtkWidget *cbut = gtk_toggle_button_new_with_label(label);
1955      hildon_gtk_widget_set_theme_size(cbut,
1956               (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1957      gtk_toggle_button_set_mode(GTK_TOGGLE_BUTTON(cbut), FALSE);
1958      return cbut;
1959    #endif
1960    }
1961    
1962    void toggle_button_set_active(GtkWidget *button, gboolean active) {
1963      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
1964    }
1965    
1966    gboolean toggle_button_get_active(GtkWidget *button) {
1967      return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1968    }
1969    
1970    GtkWidget *check_button_new_with_label(char *label) {
1971    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1972      return gtk_check_button_new_with_label(label);
1973    #else
1974      GtkWidget *cbut =
1975        hildon_check_button_new(HILDON_SIZE_FINGER_HEIGHT |
1976                                HILDON_SIZE_AUTO_WIDTH);
1977      gtk_button_set_label(GTK_BUTTON(cbut), label);
1978      return cbut;
1979    #endif
1980    }
1981    
1982    void check_button_set_active(GtkWidget *button, gboolean active) {
1983    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1984      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), active);
1985    #else
1986      hildon_check_button_set_active(HILDON_CHECK_BUTTON(button), active);
1987    #endif
1988    }
1989    
1990    gboolean check_button_get_active(GtkWidget *button) {
1991    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1992      return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button));
1993    #else
1994      return hildon_check_button_get_active(HILDON_CHECK_BUTTON(button));
1995    #endif
1996    }
1997    
1998    GtkWidget *button_new(void) {
1999      GtkWidget *button = gtk_button_new();
2000    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
2001      hildon_gtk_widget_set_theme_size(button,
2002               (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2003    #endif
2004      return button;
2005    }
2006    
2007    GtkWidget *button_new_with_label(char *label) {
2008      GtkWidget *button = gtk_button_new_with_label(label);
2009    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
2010      hildon_gtk_widget_set_theme_size(button,
2011               (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
2012    #endif
2013      return button;
2014    }
2015    
2016    static void on_browse(GtkWidget *widget, gpointer data) {
2017      GtkWidget *dialog;
2018    
2019      char **fileptr = g_object_get_data(G_OBJECT(widget), "fileptr");
2020    
2021    #ifdef USE_MAEMO
2022      dialog = hildon_file_chooser_dialog_new(
2023                   GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))),
2024                   GTK_FILE_CHOOSER_ACTION_SAVE);
2025    #else
2026      dialog = gtk_file_chooser_dialog_new(
2027                   g_object_get_data(G_OBJECT(widget), "sel_title"),
2028                   GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(widget))),
2029                   GTK_FILE_CHOOSER_ACTION_SAVE,
2030                   GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
2031                   GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
2032                   NULL);
2033    #endif
2034    
2035      if(*fileptr) {
2036        printf("set filename <%s>\n", *fileptr);
2037    
2038        if(!g_file_test(*fileptr, G_FILE_TEST_EXISTS)) {
2039          char *last_sep = strrchr(*fileptr, '/');
2040          if(last_sep) {
2041            *last_sep = 0;  // seperate path from file
2042    
2043            /* the user just created a new document */
2044            gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog),
2045                                                *fileptr);
2046            gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
2047                                              last_sep+1);
2048    
2049            /* restore full filename */
2050            *last_sep = '/';
2051          }
2052        } else
2053          gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), *fileptr);
2054      }
2055    
2056      if (gtk_dialog_run (GTK_DIALOG(dialog)) == GTK_FM_OK) {
2057        gchar *name = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
2058        if(name) {
2059          if(*fileptr) g_free(*fileptr);
2060          *fileptr = g_strdup(name);
2061    
2062    #ifndef FREMANTLE
2063          GtkWidget *label = g_object_get_data(G_OBJECT(widget), "label");
2064          gtk_label_set_text(GTK_LABEL(label), *fileptr);
2065    #else
2066          hildon_button_set_value(HILDON_BUTTON(widget), *fileptr);
2067    #endif
2068        }
2069      }
2070    
2071      gtk_widget_destroy (dialog);
2072    }
2073    
2074    GtkWidget *export_file(char *sel_title, char **filename) {
2075      /* non-fremantle and classic gtk use a rather ugly and */
2076      /* complex layout */
2077    #ifndef FREMANTLE
2078      GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
2079      GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
2080      GtkWidget *label = gtk_label_new(_("Export to"));
2081      gtk_box_pack_start(GTK_BOX(hbox), label, TRUE, TRUE,0);
2082      gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2083      GtkWidget *button = button_new_with_label(_("Browse"));
2084      g_object_set_data(G_OBJECT(button), "sel_title", sel_title);
2085      g_object_set_data(G_OBJECT(button), "fileptr", filename);
2086      gtk_signal_connect(GTK_OBJECT(button), "clicked",
2087                         GTK_SIGNAL_FUNC(on_browse), NULL);
2088      gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE,0);
2089      gtk_box_pack_start_defaults(GTK_BOX(vbox), hbox);
2090    
2091      label = gtk_label_new((*filename)?*filename:"");
2092      g_object_set_data(G_OBJECT(button), "label", label);
2093      gtk_misc_set_alignment(GTK_MISC(label), 0.f, 0.5f);
2094      gtk_label_set_ellipsize(GTK_LABEL(label), PANGO_ELLIPSIZE_MIDDLE);
2095    
2096      gtk_box_pack_start_defaults(GTK_BOX(vbox), label);
2097      return vbox;
2098    #else
2099      GtkWidget *button = hildon_button_new_with_text(
2100              (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH),
2101              HILDON_BUTTON_ARRANGEMENT_VERTICAL,
2102              _("Export to"), *filename);
2103      hildon_button_set_title_alignment(HILDON_BUTTON(button), 0.5, 0.5);
2104      hildon_button_set_value_alignment(HILDON_BUTTON(button), 0.5, 0.5);
2105      g_object_set_data(G_OBJECT(button), "sel_title", sel_title);
2106      g_object_set_data(G_OBJECT(button), "fileptr", filename);
2107      gtk_signal_connect(GTK_OBJECT(button), "clicked",
2108                         GTK_SIGNAL_FUNC(on_browse), NULL);
2109      return button;
2110    #endif
2111    }
2112    
2113    

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