Diff of /trunk/src/misc.c

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

revision 217 by harbaum, Thu Nov 26 21:21:03 2009 UTC revision 231 by harbaum, Mon Dec 7 16:14:50 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>
# Line 26  Line 29 
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)  #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
37  #include <hildon/hildon-entry.h>  #include <hildon/hildon-entry.h>
38  #include <hildon/hildon-touch-selector.h>  #include <hildon/hildon-touch-selector.h>
# Line 33  Line 40 
40  #include <hildon/hildon-picker-dialog.h>  #include <hildon/hildon-picker-dialog.h>
41  #endif  #endif
42    
43    float roundf(float x);
44    
45    /* Enable special fremantle UI elements. These particular widgets */
46    /* don't use any hildon/fremantle specific parts and can thus even */
47    /* be used under plain gtk. This is mainly for testing and developemt */
48  #ifdef FREMANTLE  #ifdef FREMANTLE
49  #define PICKER_DIALOG  #define PRESET_PICKER_DIALOG
50    #define COORDINATE_PICKER
51  #endif  #endif
52    
53  char strlastchr(char *str) {  char strlastchr(char *str) {
# Line 304  float distance_parse(char *str, gboolean Line 317  float distance_parse(char *str, gboolean
317    return val;    return val;
318  }  }
319    
320    /* ------------------ coordinate picker tool --------------------------- */
321    
322    #ifndef COORDINATE_PICKER
323  static gboolean mark(GtkWidget *widget, gboolean valid) {  static gboolean mark(GtkWidget *widget, gboolean valid) {
324    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
325    return valid;    return valid;
326  }  }
327    
328  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {  GtkWidget *red_entry_new_with_text(char *str) {
   float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));  
   mark(widget, !isnan(i));  
 }  
   
 /* a entry that is colored red when being "active" */  
 GtkWidget *lat_entry_new(float lat) {  
329    GdkColor color;    GdkColor color;
330    
331    GtkWidget *widget = entry_new();    GtkWidget *widget = entry_new();
332    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
333    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
334      if(str) gtk_entry_set_text(GTK_ENTRY(widget), str);
335    
   char str[32];  
   pos_lat_str(str, sizeof(str), lat);  
   gtk_entry_set_text(GTK_ENTRY(widget), str);  
   
   g_signal_connect(G_OBJECT(widget), "changed",  
                    G_CALLBACK(callback_modified_lat), NULL);  
   
336    return widget;    return widget;
337  }  }
338    
339  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
340    float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));    float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
341    mark(widget, !isnan(i));    mark(widget, !isnan(i));
342  }  }
343    #else
344    static void picker_center_iter(GtkWidget *view, GtkTreeIter *iter) {
345      /* select new iter */
346      GtkTreeSelection *selection =
347        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
348      GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
349      gtk_tree_selection_select_iter(selection, iter);
350      GtkTreePath *path =
351        gtk_tree_model_get_path(model, iter);
352      gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
353                                   path, NULL, TRUE, 0.5, 0.5);
354      gtk_tree_path_free(path);
355    }
356    
357  /* a entry that is colored red when filled with invalid coordinate */  static void on_picker_activated(GtkTreeView        *treeview,
358  GtkWidget *lon_entry_new(float lon) {                                  GtkTreePath        *path,
359    GdkColor color;                                  GtkTreeViewColumn  *col,
360                                    gpointer            userdata) {
361    GtkWidget *widget = entry_new();    gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeview),
362    //  gtk_entry_set_width_chars(GTK_ENTRY(widget), 14);                                 path, NULL, TRUE, 0.5, 0.5);
363    }
   gdk_color_parse("#ff0000", &color);  
   gtk_widget_modify_text(widget, TAG_STATE, &color);  
364    
365    char str[32];  #define DUMMY_NUM  1
   pos_lon_str(str, sizeof(str), lon);  
   gtk_entry_set_text(GTK_ENTRY(widget), str);  
366    
367    g_signal_connect(G_OBJECT(widget), "changed",  static void dummy_append(GtkListStore *store, int n) {
368                     G_CALLBACK(callback_modified_lon), NULL);    GtkTreeIter iter;
369    
370    return widget;    while(n--) {
371        gtk_list_store_append (store, &iter);
372        gtk_list_store_set(store, &iter, 0, "", 1, -1, 2, FALSE, -1);
373      }
374  }  }
375    
376    static GtkWidget *string_picker_create(const char *str[], int sel) {
377    #ifndef FREMANTLE
378      GtkWidget *view = gtk_tree_view_new();
379    #else
380      GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
381    #endif
382    
383  float lat_get(GtkWidget *widget) {    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
384    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    GtkTreeSelection *selection =
385    return pos_parse_lat(p);      gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
386  }  
387      /* --- "char" column --- */
388  float lon_get(GtkWidget *widget) {    GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
389    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    g_object_set(renderer, "xalign", 0.5, NULL );
390    return pos_parse_lon(p);    gtk_tree_view_insert_column_with_attributes(
391  }        GTK_TREE_VIEW(view), -1, "str", renderer,
392          "text", 0,
393          "sensitive", 2,
394          NULL);
395    
396      GtkListStore *store =
397        gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
398    
399      dummy_append(store, DUMMY_NUM);
400    
401      /* add strings */
402      GtkTreeIter iter, siter;
403      int i;
404      for(i=0;*str;str++,i++) {
405        gtk_list_store_append (store, &iter);
406        gtk_list_store_set(store, &iter, 0, _(*str), 1, i, 2, TRUE, -1);
407        if(i == sel) siter = iter;
408      }
409    
410  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {    dummy_append(store, DUMMY_NUM);
   /* don't care for metric/imperial since we only want to know if this */  
   /* is parseable at all */  
   float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);  
   mark(widget, !isnan(i));  
 }  
411    
412  /* a entry that is colored red when filled with invalid distance */    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
413  GtkWidget *dist_entry_new(float dist, gboolean mil) {    g_object_unref(store);
   GdkColor color;  
   GtkWidget *widget = entry_new();  
   gdk_color_parse("#ff0000", &color);  
   gtk_widget_modify_text(widget, TAG_STATE, &color);  
414    
415    char str[32];  #ifndef FREMANTLE
416    distance_str(str, sizeof(str), dist, mil);    g_signal_connect(view, "row-activated",
417    gtk_entry_set_text(GTK_ENTRY(widget), str);                     (GCallback)on_picker_activated, NULL);
418    #else
419      g_signal_connect(view, "hildon-row-tapped",
420                       (GCallback)on_picker_activated, NULL);
421    #endif
422    
423    g_signal_connect(G_OBJECT(widget), "changed",    /* select right character */
424                     G_CALLBACK(callback_modified_dist), NULL);    gtk_tree_selection_select_iter(selection, &siter);
425      picker_center_iter(view, &siter);
426    return widget;  
427      /* put this inside a scrolled view */
428    #ifndef USE_PANNABLE_AREA
429      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
430      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
431                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
432      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
433      return scrolled_window;
434    #else
435      GtkWidget *pannable_area = hildon_pannable_area_new();
436      gtk_container_add(GTK_CONTAINER(pannable_area), view);
437      return pannable_area;
438    #endif
439  }  }
440    
441  float dist_get(GtkWidget *widget, gboolean mil) {  static int picker_get(GtkWidget *widget) {
442    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    GtkWidget *view = gtk_bin_get_child(GTK_BIN(widget));
443    return distance_parse(p, mil);  
444  }    GtkTreeSelection *sel =
445        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
446    
447  #ifndef USE_MAEMO    GtkTreeModel *model;
448  #ifdef ENABLE_BROWSER_INTERFACE    GtkTreeIter iter;
 #include <libgnome/gnome-url.h>  
449    
450  int browser_url(appdata_t *appdata, char *url) {    /* there should never be an unseletced column. But if */
451    /* taken from gnome-open, part of libgnome */    /* it is, we count it as zero */
452    GError *err = NULL;    if(!gtk_tree_selection_get_selected(sel, &model, &iter))
453    gnome_url_show(url, &err);      return 0;
454    return 0;  
455      int retval = 0;
456      gtk_tree_model_get(model, &iter, 1, &retval, -1);
457      return retval;
458  }  }
 #endif  
 #endif  
459    
460  /* recursively remove an entire file system */  static GtkWidget *digit_picker_create(int min, int max, int sel) {
461  void rmdir_recursive(char *path) {  #ifndef FREMANTLE
462    GDir *dir = g_dir_open(path, 0, NULL);    GtkWidget *view = gtk_tree_view_new();
463    if(dir) {  #else
464      const char *name = g_dir_read_name(dir);    GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
465      while(name) {  #endif
       char *fullname = g_strdup_printf("%s/%s", path, name);  
       //      printf("deleting %s\n", fullname);  
   
       if(g_file_test(fullname, G_FILE_TEST_IS_DIR))  
         rmdir_recursive(fullname);  
       else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))  
         g_remove(fullname);  
466    
467        g_free(fullname);    gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
468        name = g_dir_read_name(dir);    GtkTreeSelection *selection =
469      }      gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
470    
471      /* --- "digit" column --- */
472      GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
473      g_object_set(renderer, "xalign", 0.5, NULL );
474      gtk_tree_view_insert_column_with_attributes(
475          GTK_TREE_VIEW(view), -1, "digit", renderer,
476          "text", 0,
477          "sensitive", 2,
478          NULL);
479    
480      GtkListStore *store =
481        gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
482    
483      dummy_append(store, DUMMY_NUM);
484    
485      /* add digits */
486      int i;
487      GtkTreeIter siter;
488      for(i=min;i<=max;i++) {
489        char str[2] = { '0'+i, 0 };
490        GtkTreeIter     iter;
491        /* Append a row and fill in some data */
492        gtk_list_store_append (store, &iter);
493        gtk_list_store_set(store, &iter, 0, str, 1, i, 2, TRUE, -1);
494    
495      g_dir_close(dir);      if(i == sel) siter = iter;
496    }    }
497    g_rmdir(path);  
498  }    dummy_append(store, DUMMY_NUM);
499    
500  #ifdef ENABLE_BROWSER_INTERFACE    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
501  static void on_link_clicked(GtkButton *button, gpointer data) {    g_object_unref(store);
   appdata_t *appdata = (appdata_t*)data;  
   char *url = g_object_get_data(G_OBJECT(button), "url");  
   if(url) browser_url(appdata, url);  
 }  
 #endif  
502    
503  /* a button containing a weblink */  #ifndef FREMANTLE
504  GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,    g_signal_connect(view, "row-activated",
505                         int size, int strikethrough) {                     (GCallback)on_picker_activated, NULL);
506    #else
507      g_signal_connect(view, "hildon-row-tapped",
508                       (GCallback)on_picker_activated, NULL);
509    #endif
510    
511  #ifdef ENABLE_BROWSER_INTERFACE    gtk_tree_selection_select_iter(selection, &siter);
512    if(url) {    picker_center_iter(view, &siter);
     GtkWidget *button = gtk_button_attrib(str, size, strikethrough);  
     g_object_set_data(G_OBJECT(button), "url", url);  
     gtk_signal_connect(GTK_OBJECT(button), "clicked",  
                        (GtkSignalFunc)on_link_clicked, appdata);  
513    
514      return button;    /* put this inside a scrolled view */
515    }  #ifndef USE_PANNABLE_AREA
516      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
517      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
518                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
519      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
520      return scrolled_window;
521    #else
522      GtkWidget *pannable_area = hildon_pannable_area_new();
523      gtk_container_add(GTK_CONTAINER(pannable_area), view);
524      return pannable_area;
525  #endif  #endif
   return gtk_label_attrib(str, size, strikethrough);  
526  }  }
527    
528  #ifdef ENABLE_BROWSER_INTERFACE  static gint on_lat_picker_button_press(GtkWidget *button,
529  static void on_link_id_clicked(GtkButton *button, gpointer data) {                     GdkEventButton *event, gpointer data) {
   appdata_t *appdata = (appdata_t*)data;  
530    
531    unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");    if(event->type == GDK_BUTTON_PRESS) {
532    char *type = g_object_get_data(G_OBJECT(button), "type");      GtkWidget *dialog =
533          gtk_dialog_new_with_buttons(_("Latitude"),
534              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
535                                      GTK_DIALOG_MODAL,
536              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
537              _("Done"),        GTK_RESPONSE_ACCEPT,
538              NULL);
539    
540    char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",      gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
                               type, id);  
541    
542    if(url) {      int i, lat = (int)g_object_get_data(G_OBJECT(button), "latitude");
     browser_url(appdata, url);  
     g_free(url);  
   }  
 }  
 #endif  
543    
544  GtkWidget *link_button_by_id(appdata_t *appdata, char *str,      /* parse latitude into components */
545                               const char *type, int id) {      int sign = (lat>=0)?0:1;
546        lat = abs(lat);
547        int deg = lat / 60000;
548        int min = (lat /1000)%60;
549        int minfrac = lat % 1000;
550    
551  #ifdef ENABLE_BROWSER_INTERFACE      GtkWidget *signw, *degw[2], *minw[2], *minfracw[3];
   if(id) {  
     GtkWidget *ref = gtk_button_new_with_label(str);  
 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)  
     //    hildon_gtk_widget_set_theme_size(ref,  
     //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));  
 #endif  
     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);  
     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);  
     gtk_signal_connect(GTK_OBJECT(ref), "clicked",  
                        GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);  
552    
     return ref;  
   }  
 #endif  
   return gtk_label_new(str);  
 }  
553    
554        /* create N/S 89° 99.999 */
555        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
556        static const char *ns[] = { "N", "S", NULL };
557        gtk_box_pack_start_defaults(GTK_BOX(hbox),
558                    signw = string_picker_create(ns, sign));
559    
560        gtk_box_pack_start_defaults(GTK_BOX(hbox),
561                    degw[0] = digit_picker_create(0,8, deg/10));
562        gtk_box_pack_start_defaults(GTK_BOX(hbox),
563                    degw[1] = digit_picker_create(0,9, deg%10));
564        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
565    
566        gtk_box_pack_start_defaults(GTK_BOX(hbox),
567                    minw[0] = digit_picker_create(0,5, min/10));
568        gtk_box_pack_start_defaults(GTK_BOX(hbox),
569                    minw[1] = digit_picker_create(0,9, min%10));
570        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
571    
572        gtk_box_pack_start_defaults(GTK_BOX(hbox),
573                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
574        gtk_box_pack_start_defaults(GTK_BOX(hbox),
575                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
576        gtk_box_pack_start_defaults(GTK_BOX(hbox),
577                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
578    
579  GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
                              const char *type, int id) {  
   
 #ifdef ENABLE_BROWSER_INTERFACE  
   if(id) {  
     GtkWidget *ref = gtk_button_new();  
     gtk_button_set_image(GTK_BUTTON(ref), icon);  
580    
581  #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)      gtk_widget_show_all(dialog);
582      //    hildon_gtk_widget_set_theme_size(ref,      if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
     //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));  
 #endif  
     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);  
     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);  
     gtk_signal_connect(GTK_OBJECT(ref), "clicked",  
                        GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);  
   
     return ref;  
   }  
 #endif  
   return icon;  
 }  
583    
584  /* left aligned, word wrapped multiline widget */        /* parse degrees ... */
585  GtkWidget *simple_text_widget(char *text) {        for(deg=0,i=0;i<2;i++)
586    GtkWidget *label = gtk_label_new(text);          deg = 10 * deg + picker_get(degw[i]);
587    
588    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);        /* ... minutes ... */
589    gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);        for(min=0,i=0;i<2;i++)
590    gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);          min = 10 * min + picker_get(minw[i]);
591    
592          /* ... and fractions of minutes */
593          for(minfrac=0,i=0;i<3;i++)
594            minfrac = 10 * minfrac + picker_get(minfracw[i]);
595    
596          /* parse N/S */
597          if(deg | min | minfrac)
598            sign = picker_get(signw)?-1:1;
599          else
600            sign = 1;   // theres no S 00 00.000
601    
602    return label;        float latitude = sign * (deg + min/60.0 + minfrac/60000.0);
603  }        lat_entry_set(button, latitude);
604        }
605    
606        gtk_widget_destroy(dialog);
607    
608  /* a label that is left aligned */      return TRUE;
609  GtkWidget *left_label_new(char *str) {    }
610    GtkWidget *widget = gtk_label_new(str);    return FALSE;
   gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);  
   return widget;  
611  }  }
612    #endif
613    
614  static void pos_set(GtkWidget *item, float lat, float lon) {  /* a entry that is colored red when being "active" */
615    GtkWidget *lat_entry_new(float lat) {
616    char str[32];    char str[32];
617      pos_lat_str(str, sizeof(str), lat);
618    
619    pos_lat_str(str, sizeof(str)-1, lat);  #ifndef COORDINATE_PICKER
620    GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");    GtkWidget *widget = red_entry_new_with_text(str);
   gtk_entry_set_text(GTK_ENTRY(lat_entry), str);  
621    
622    pos_lon_str(str, sizeof(str)-1, lon);    g_signal_connect(G_OBJECT(widget), "changed",
623    GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");                     G_CALLBACK(callback_modified_lat), NULL);
624    gtk_entry_set_text(GTK_ENTRY(lon_entry), str);  
625    #else
626      GtkWidget *widget = gtk_button_new_with_label(str);
627    
628    #ifdef FREMANTLE
629      hildon_gtk_widget_set_theme_size(widget,
630            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
631    #endif
632      int lat_int = (int)roundf(lat * 60000);
633      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
634      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
635                         (GtkSignalFunc)on_lat_picker_button_press, NULL);
636    #endif
637    
638      return widget;
639    }
640    
641    #ifndef COORDINATE_PICKER
642    static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
643      float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
644      mark(widget, !isnan(i));
645    }
646    #else
647    static gint on_lon_picker_button_press(GtkWidget *button,
648                       GdkEventButton *event, gpointer data) {
649    
650      if(event->type == GDK_BUTTON_PRESS) {
651        GtkWidget *dialog =
652          gtk_dialog_new_with_buttons(_("Longitude"),
653              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
654                                      GTK_DIALOG_MODAL,
655              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
656              _("Done"),        GTK_RESPONSE_ACCEPT,
657              NULL);
658    
659        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
660    
661        int i, lat = (int)g_object_get_data(G_OBJECT(button), "longitude");
662    
663        /* parse latitude into components */
664        int sign = (lat>=0)?0:1;
665        lat = abs(lat);
666        int deg = lat / 60000;
667        int min = (lat /1000)%60;
668        int minfrac = lat % 1000;
669    
670        GtkWidget *signw, *degw[3], *minw[2], *minfracw[3];
671    
672        /* create E/W 179° 99.999 */
673        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
674        static const char *ew[] = { "E", "W", NULL };
675        gtk_box_pack_start_defaults(GTK_BOX(hbox),
676                    signw = string_picker_create(ew, sign));
677    
678        gtk_box_pack_start_defaults(GTK_BOX(hbox),
679                    degw[0] = digit_picker_create(0,1, deg/100));
680        gtk_box_pack_start_defaults(GTK_BOX(hbox),
681                    degw[1] = digit_picker_create(0,9, (deg/10)%10));
682        gtk_box_pack_start_defaults(GTK_BOX(hbox),
683                    degw[2] = digit_picker_create(0,9, deg%10));
684        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
685    
686        gtk_box_pack_start_defaults(GTK_BOX(hbox),
687                    minw[0] = digit_picker_create(0,5, min/10));
688        gtk_box_pack_start_defaults(GTK_BOX(hbox),
689                    minw[1] = digit_picker_create(0,9, min%10));
690        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
691    
692        gtk_box_pack_start_defaults(GTK_BOX(hbox),
693                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
694        gtk_box_pack_start_defaults(GTK_BOX(hbox),
695                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
696        gtk_box_pack_start_defaults(GTK_BOX(hbox),
697                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
698    
699        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
700    
701        gtk_widget_show_all(dialog);
702        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
703    
704          /* parse degrees ... */
705          for(deg=0,i=0;i<3;i++)
706            deg = 10 * deg + picker_get(degw[i]);
707    
708          /* ... minutes ... */
709          for(min=0,i=0;i<2;i++)
710            min = 10 * min + picker_get(minw[i]);
711    
712          /* ... and fractions of minutes */
713          for(minfrac=0,i=0;i<3;i++)
714            minfrac = 10 * minfrac + picker_get(minfracw[i]);
715    
716          if(deg | min | minfrac)
717            sign = picker_get(signw)?-1:1;
718          else
719            sign = 1;   // theres no W 00 00.000
720    
721          float longitude = sign * (deg + min/60.0 + minfrac/60000.0);
722          lon_entry_set(button, longitude);
723        }
724    
725        gtk_widget_destroy(dialog);
726    
727        return TRUE;
728      }
729      return FALSE;
730    }
731    #endif
732    
733    /* a entry that is colored red when filled with invalid coordinate */
734    GtkWidget *lon_entry_new(float lon) {
735      char str[32];
736      pos_lon_str(str, sizeof(str), lon);
737    
738    #ifndef COORDINATE_PICKER
739      GtkWidget *widget = red_entry_new_with_text(str);
740      g_signal_connect(G_OBJECT(widget), "changed",
741                       G_CALLBACK(callback_modified_lon), NULL);
742    
743    #else
744      GtkWidget *widget = gtk_button_new_with_label(str);
745    
746    #ifdef FREMANTLE
747      hildon_gtk_widget_set_theme_size(widget,
748            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
749    #endif
750      int lon_int = (int)roundf(lon * 60000);
751      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
752      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
753                         (GtkSignalFunc)on_lon_picker_button_press, NULL);
754    #endif
755    
756      return widget;
757    }
758    
759    float lat_entry_get(GtkWidget *widget) {
760    #ifndef COORDINATE_PICKER
761      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
762    #else
763      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
764    #endif
765      return pos_parse_lat(p);
766    }
767    
768    float lon_entry_get(GtkWidget *widget) {
769    #ifndef COORDINATE_PICKER
770      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
771    #else
772      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
773    #endif
774      return pos_parse_lon(p);
775    }
776    
777    void lat_entry_set(GtkWidget *widget, float lat) {
778      char str[32];
779      pos_lat_str(str, sizeof(str)-1, lat);
780    #ifndef COORDINATE_PICKER
781      gtk_entry_set_text(GTK_ENTRY(widget), str);
782    #else
783      gtk_button_set_label(GTK_BUTTON(widget), str);
784      int lat_int = (int)roundf(lat * 60000);
785      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
786      g_signal_emit_by_name(widget, "changed");
787    #endif
788    }
789    
790    void lon_entry_set(GtkWidget *widget, float lon) {
791      char str[32];
792      pos_lon_str(str, sizeof(str)-1, lon);
793    #ifndef COORDINATE_PICKER
794      gtk_entry_set_text(GTK_ENTRY(widget), str);
795    #else
796      gtk_button_set_label(GTK_BUTTON(widget), str);
797      int lon_int = (int)roundf(lon * 60000);
798      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
799      g_signal_emit_by_name(widget, "changed");
800    #endif
801    }
802    
803    void lat_label_set(GtkWidget *widget, float lat) {
804      char str[32];
805      pos_lat_str(str, sizeof(str)-1, lat);
806      gtk_label_set(GTK_LABEL(widget), str);
807    }
808    
809    void lon_label_set(GtkWidget *widget, float lon) {
810      char str[32];
811      pos_lon_str(str, sizeof(str)-1, lon);
812      gtk_label_set(GTK_LABEL(widget), str);
813    }
814    
815    void lat_label_attrib_set(GtkWidget *widget, float lat,
816                              int size, int strikethrough) {
817      char str[32];
818      pos_lat_str(str, sizeof(str)-1, lat);
819      gtk_label_attrib_set(widget, str, size, strikethrough);
820    }
821    
822    void lon_label_attrib_set(GtkWidget *widget, float lon,
823                              int size, int strikethrough) {
824      char str[32];
825      pos_lon_str(str, sizeof(str)-1, lon);
826      gtk_label_attrib_set(widget, str, size, strikethrough);
827    }
828    
829    #ifndef COORDINATE_PICKER
830    static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
831      /* don't care for metric/imperial since we only want to know if this */
832      /* is parseable at all */
833      float i =
834        distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
835      mark(widget, !isnan(i));
836    }
837    #else
838    static gint on_dist_picker_button_press(GtkWidget *button,
839                       GdkEventButton *event, gpointer data) {
840    
841      if(event->type == GDK_BUTTON_PRESS) {
842        GtkWidget *dialog =
843          gtk_dialog_new_with_buttons(_("Distance"),
844              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
845                                      GTK_DIALOG_MODAL,
846              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
847              _("Done"),        GTK_RESPONSE_ACCEPT,
848              NULL);
849    
850        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
851    
852        /* distance is given in m or ft (depending on mil) */
853        int i, dist = (int)g_object_get_data(G_OBJECT(button), "distance");
854        gboolean mil = (gboolean)g_object_get_data(G_OBJECT(button), "mil");
855        int unit = 0;
856    
857        /* parse distance into components */
858        if(mil) {
859          /* 1 mil = 1760 yd = 5280 ft. 1yd = 3 ft */
860          if(dist<95)        { unit = 0; dist *= 100;  }
861          else if(dist<2904) { unit = 1; dist = 100 * dist / 3;  }
862          else               { unit = 2; dist = 5 * dist / 264; }
863        } else {
864          if(dist<1000)      { unit = 3; dist *= 100;  }
865          else               { unit = 4; dist /= 10; }
866        }
867    
868        GtkWidget *distw[4], *fracw[2], *unitw;
869    
870        /* create xxxx.x unit */
871        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
872    
873        gtk_box_pack_start_defaults(GTK_BOX(hbox),
874                    distw[0] = digit_picker_create(0,9, (dist/100000)%10));
875        gtk_box_pack_start_defaults(GTK_BOX(hbox),
876                    distw[1] = digit_picker_create(0,9, (dist/10000)%10));
877        gtk_box_pack_start_defaults(GTK_BOX(hbox),
878                    distw[2] = digit_picker_create(0,9, (dist/1000)%10));
879        gtk_box_pack_start_defaults(GTK_BOX(hbox),
880                    distw[3] = digit_picker_create(0,9, (dist/100)%10));
881        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
882        gtk_box_pack_start_defaults(GTK_BOX(hbox),
883                    fracw[0] = digit_picker_create(0,9, (dist/10)%10));
884        gtk_box_pack_start_defaults(GTK_BOX(hbox),
885                    fracw[1] = digit_picker_create(0,9, (dist/1)%10));
886    
887        static const char *units[] = { "ft", "yd", "mi", "m", "km", NULL };
888        gtk_box_pack_start_defaults(GTK_BOX(hbox),
889                    unitw = string_picker_create(units, unit));
890    
891        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
892    
893        gtk_widget_show_all(dialog);
894        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
895    
896          /* parse distance */
897          for(dist=0,i=0;i<4;i++)
898            dist = 10 * dist + picker_get(distw[i]);
899    
900          for(i=0;i<2;i++)
901            dist = 10 * dist + picker_get(fracw[i]);
902    
903          unit = picker_get(unitw);
904          if(unit == 0)      { dist /= 100; }         // ft
905          else if(unit == 1) { dist = 3*dist/100; }   // yd
906          else if(unit == 2) { dist = 528*dist/10; }  // mi
907          else if(unit == 3) { dist /= 100; }         // m
908          else if(unit == 4) { dist *= 10; }          // km
909    
910          /* user may have switched between metric and imperial */
911          float distance;
912          if(unit <= 2) {
913            distance = dist / 5280.0;
914            if(!mil) distance *=  1.609344;
915          } else {
916            distance = dist / 1000.0;
917            if( mil) distance /=  1.609344;
918          }
919    
920          dist_entry_set(button, distance, mil);
921        }
922    
923        gtk_widget_destroy(dialog);
924    
925        return TRUE;
926      }
927      return FALSE;
928    }
929    #endif
930    
931    /* a entry that is colored red when filled with invalid distance */
932    GtkWidget *dist_entry_new(float dist, gboolean mil) {
933      char str[32];
934      distance_str(str, sizeof(str), dist, mil);
935    
936    #ifndef COORDINATE_PICKER
937      GtkWidget *widget = red_entry_new_with_text(str);
938      g_signal_connect(G_OBJECT(widget), "changed",
939                       G_CALLBACK(callback_modified_dist), NULL);
940    
941    #else
942      GtkWidget *widget = gtk_button_new_with_label(str);
943    
944    #ifdef FREMANTLE
945      hildon_gtk_widget_set_theme_size(widget,
946            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
947    #endif
948      int dist_int = (int)roundf(dist * 1000);        // km -> m
949      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
950    
951      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
952      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
953      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
954                         (GtkSignalFunc)on_dist_picker_button_press, NULL);
955    #endif
956    
957      return widget;
958    }
959    
960    float dist_entry_get(GtkWidget *widget, gboolean mil) {
961    #ifndef COORDINATE_PICKER
962      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
963    #else
964      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
965    #endif
966      return distance_parse(p, mil);
967    }
968    
969    void dist_entry_set(GtkWidget *widget, float dist, gboolean mil) {
970      char str[32];
971      distance_str(str, sizeof(str), dist, mil);
972    
973    #ifndef COORDINATE_PICKER
974      gtk_entry_set_text(GTK_ENTRY(widget), str);
975    #else
976      int dist_int = (int)roundf(dist * 1000);        // km -> m
977      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
978      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
979      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
980      gtk_button_set_label(GTK_BUTTON(widget), str);
981    #endif
982    }
983    
984    #ifndef USE_MAEMO
985    #ifdef ENABLE_BROWSER_INTERFACE
986    #include <libgnome/gnome-url.h>
987    
988    int browser_url(appdata_t *appdata, char *url) {
989      /* taken from gnome-open, part of libgnome */
990      GError *err = NULL;
991      gnome_url_show(url, &err);
992      return 0;
993    }
994    #endif
995    #endif
996    
997    /* recursively remove an entire file system */
998    void rmdir_recursive(char *path) {
999      GDir *dir = g_dir_open(path, 0, NULL);
1000      if(dir) {
1001        const char *name = g_dir_read_name(dir);
1002        while(name) {
1003          char *fullname = g_strdup_printf("%s/%s", path, name);
1004          //      printf("deleting %s\n", fullname);
1005    
1006          if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
1007            rmdir_recursive(fullname);
1008          else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
1009            g_remove(fullname);
1010    
1011          g_free(fullname);
1012          name = g_dir_read_name(dir);
1013        }
1014    
1015        g_dir_close(dir);
1016      }
1017      g_rmdir(path);
1018    }
1019    
1020    #ifdef ENABLE_BROWSER_INTERFACE
1021    static void on_link_clicked(GtkButton *button, gpointer data) {
1022      appdata_t *appdata = (appdata_t*)data;
1023      char *url = g_object_get_data(G_OBJECT(button), "url");
1024      if(url) browser_url(appdata, url);
1025    }
1026    #endif
1027    
1028    /* a button containing a weblink */
1029    GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
1030                           int size, int strikethrough) {
1031    
1032    #ifdef ENABLE_BROWSER_INTERFACE
1033      if(url) {
1034        GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
1035        g_object_set_data(G_OBJECT(button), "url", url);
1036        gtk_signal_connect(GTK_OBJECT(button), "clicked",
1037                           (GtkSignalFunc)on_link_clicked, appdata);
1038    
1039        return button;
1040      }
1041    #endif
1042      return gtk_label_attrib(str, size, strikethrough);
1043    }
1044    
1045    #ifdef ENABLE_BROWSER_INTERFACE
1046    static void on_link_id_clicked(GtkButton *button, gpointer data) {
1047      appdata_t *appdata = (appdata_t*)data;
1048    
1049      unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
1050      char *type = g_object_get_data(G_OBJECT(button), "type");
1051    
1052      char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
1053                                  type, id);
1054    
1055      if(url) {
1056        browser_url(appdata, url);
1057        g_free(url);
1058      }
1059    }
1060    #endif
1061    
1062    GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
1063                                 const char *type, int id) {
1064    
1065    #ifdef ENABLE_BROWSER_INTERFACE
1066      if(id) {
1067        GtkWidget *ref = gtk_button_new_with_label(str);
1068    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1069        //    hildon_gtk_widget_set_theme_size(ref,
1070        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1071    #endif
1072        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1073        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1074        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1075                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1076    
1077        return ref;
1078      }
1079    #endif
1080      return gtk_label_new(str);
1081    }
1082    
1083    
1084    GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
1085                                 const char *type, int id) {
1086    
1087    #ifdef ENABLE_BROWSER_INTERFACE
1088      if(id) {
1089        GtkWidget *ref = gtk_button_new();
1090        gtk_button_set_image(GTK_BUTTON(ref), icon);
1091    
1092    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
1093        //    hildon_gtk_widget_set_theme_size(ref,
1094        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1095    #endif
1096        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
1097        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
1098        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
1099                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
1100    
1101        return ref;
1102      }
1103    #endif
1104      return icon;
1105    }
1106    
1107    /* left aligned, word wrapped multiline widget */
1108    GtkWidget *simple_text_widget(char *text) {
1109      GtkWidget *label = gtk_label_new(text);
1110    
1111      gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
1112      gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
1113      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1114    
1115      return label;
1116    }
1117    
1118    
1119    /* a label that is left aligned */
1120    GtkWidget *left_label_new(char *str) {
1121      GtkWidget *widget = gtk_label_new(str);
1122      gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
1123      return widget;
1124    }
1125    
1126    /* ------------- preset coordinate picker tool ----------------- */
1127    
1128    static void pos_set(GtkWidget *item, float lat, float lon) {
1129    
1130      GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1131      lat_entry_set(lat_entry, lat);
1132    
1133      GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1134      lon_entry_set(lon_entry, lon);
1135  }  }
1136    
1137  static void cb_gps(GtkWidget *item, gpointer data) {  static void cb_gps(GtkWidget *item, gpointer data) {
1138    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1139      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1140      pos_t *pos = NULL;
1141    
1142      if(!id)
1143        pos = gps_get_pos(appdata);
1144      else if(id == 1)
1145        pos = &appdata->home;
1146      else {
1147        location_t *location = appdata->location;
1148        while(location && id > 2) {
1149          location = location->next;
1150          id--;
1151        }
1152    
1153        if(id == 2)
1154          pos = &location->pos;
1155      }
1156    
1157    pos_t *refpos = get_pos(appdata);    if(!pos) pos_set(item, NAN, NAN);
1158    if(!refpos) pos_set(item, NAN, NAN);    else     pos_set(item, pos->lat, pos->lon);
   else        pos_set(item, refpos->lat, refpos->lon);  
1159  }  }
1160    
1161  static void cb_geomath(GtkWidget *item, gpointer data) {  static void cb_geomath(GtkWidget *item, gpointer data) {
# Line 573  static void cb_map(GtkWidget *item, gpoi Line 1172  static void cb_map(GtkWidget *item, gpoi
1172  }  }
1173  #endif  #endif
1174    
1175    #ifdef ENABLE_MAEMO_MAPPER
1176    static void cb_mm(GtkWidget *item, gpointer data) {
1177      appdata_t *appdata = (appdata_t*)data;
1178    
1179      pos_set(item, appdata->mmpos.lat, appdata->mpos.lon);
1180    }
1181    #endif
1182    
1183  static void cb_cache(GtkWidget *item, gpointer data) {  static void cb_cache(GtkWidget *item, gpointer data) {
1184    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1185    
# Line 583  static void cb_cache(GtkWidget *item, gp Line 1190  static void cb_cache(GtkWidget *item, gp
1190    
1191    if(!id)    if(!id)
1192      pos_set(item, cache->pos.lat, cache->pos.lon);      pos_set(item, cache->pos.lat, cache->pos.lon);
1193    else {    else if(id == 1) {
1194        /* fetch position out of notes dialog since they probably */
1195        /* haven't been saved yet */
1196        pos_t pos = notes_get_pos(appdata->cache_context);
1197        pos_set(item, pos.lat, pos.lon);
1198      } else {
1199      wpt_t *wpt = cache->wpt;      wpt_t *wpt = cache->wpt;
1200      while(wpt && id > 1) {      while(wpt && id > 2) {
1201        wpt = wpt->next;        wpt = wpt->next;
1202        id--;        id--;
1203      }      }
1204    
1205      if(id == 1)      if(id == 2)
1206        pos_set(item, wpt->pos.lat, wpt->pos.lon);        pos_set(item, wpt->pos.lat, wpt->pos.lon);
1207    }    }
1208  }  }
1209    
1210  #ifndef PICKER_DIALOG  #ifndef PRESET_PICKER_DIALOG
1211  static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,  static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1212                             GtkWidget *icon, char *menu_str,                             GtkWidget *icon, char *menu_str,
1213                             void(*func)(GtkWidget*, gpointer), gint id,                             void(*func)(GtkWidget*, gpointer), gint id,
# Line 623  static GtkWidget *popup_menu_create(appd Line 1235  static GtkWidget *popup_menu_create(appd
1235                      GtkWidget *lat_entry, GtkWidget *lon_entry) {                      GtkWidget *lat_entry, GtkWidget *lon_entry) {
1236    GtkWidget *menu = gtk_menu_new();    GtkWidget *menu = gtk_menu_new();
1237    
1238    menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),    if(pos_valid(gps_get_pos(appdata)))
1239             _("Current position (GPS)"), cb_gps, 0, lon_entry, lat_entry);      menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1240    menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),               _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1241             _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);  
1242      if(pos_valid(&appdata->home))
1243        menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1244                 _("Home"), cb_gps, 1, lon_entry, lat_entry);
1245    
1246      location_t *location = appdata->location;
1247      gint id = 2;
1248      while(location) {
1249        if(pos_valid(&location->pos))
1250          menu_add(menu, appdata, icon_get_widget(ICON_POS, 17),
1251                   location->name, cb_gps, id, lon_entry, lat_entry);
1252    
1253        id++;
1254        location = location->next;
1255      }
1256    
1257      if(pos_valid(&appdata->geomath))
1258        menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
1259                 _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
1260    
1261  #ifdef ENABLE_OSM_GPS_MAP  #ifdef ENABLE_OSM_GPS_MAP
1262    menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),    if(pos_valid(&appdata->map.pos))
1263             _("Map position"), cb_map, 0, lon_entry, lat_entry);      menu_add(menu, appdata, icon_get_widget(ICON_POS, 20), _("Map position"),
1264                 cb_map, 0, lon_entry, lat_entry);
1265    #endif
1266    
1267    #ifdef ENABLE_MAEMO_MAPPER
1268      if(appdata->mmpos_valid) {
1269        menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1270                 _("Maemo mapper position"), cb_mm, 0, lon_entry, lat_entry);
1271      }
1272  #endif  #endif
1273    
1274    if(appdata->cur_cache) {    if(appdata->cur_cache) {
# Line 638  static GtkWidget *popup_menu_create(appd Line 1277  static GtkWidget *popup_menu_create(appd
1277      char *name = cache->name;      char *name = cache->name;
1278      if(!name) name = cache->id;      if(!name) name = cache->id;
1279    
1280      if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {      /* original cache position */
1281        if(pos_valid(&cache->pos))
1282        menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),        menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1283                 name, cb_cache, 0, lon_entry, lat_entry);                 name, cb_cache, 0, lon_entry, lat_entry);
1284      }  
1285        /* overwritten cache position */
1286        if(appdata->cache_context && notes_get_override(appdata->cache_context))
1287          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1288                   _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1289    
1290      wpt_t *wpt = cache->wpt;      wpt_t *wpt = cache->wpt;
1291      gint id = 1;      gint id = 2;
1292      while(wpt) {      while(wpt) {
1293        GtkWidget *icon = NULL;        if(pos_valid(&wpt->pos)) {
1294        if(wpt->sym != WPT_SYM_UNKNOWN)          GtkWidget *icon = NULL;
1295          icon = icon_get_widget(ICON_POS, wpt->sym);          if(wpt->sym != WPT_SYM_UNKNOWN)
1296              icon = icon_get_widget(ICON_POS, wpt->sym);
1297        char *name = wpt->desc;  
1298        if(!name) name = wpt->cmt;          char *name = wpt->desc;
1299        if(!name) name = wpt->id;          if(!name) name = wpt->cmt;
1300            if(!name) name = wpt->id;
1301        menu_add(menu, appdata, icon, name, cb_cache, id++,  
1302                 lon_entry, lat_entry);          menu_add(menu, appdata, icon, name, cb_cache, id,
1303                     lon_entry, lat_entry);
1304          }
1305    
1306          id++;
1307        wpt = wpt->next;        wpt = wpt->next;
1308      }      }
1309    }    }
# Line 669  static GtkWidget *popup_menu_create(appd Line 1316  static GtkWidget *popup_menu_create(appd
1316  static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,  static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1317                                    gpointer data) {                                    gpointer data) {
1318    
1319      appdata_t *appdata = (appdata_t*)data;
1320    
1321    if(event->type == GDK_BUTTON_PRESS) {    if(event->type == GDK_BUTTON_PRESS) {
1322      GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");      GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1323    
1324        if(menu)
1325          gtk_widget_destroy(menu);
1326    
1327        gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1328        g_assert(lat_entry);
1329        gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1330        g_assert(lon_entry);
1331    
1332        menu = popup_menu_create(appdata, lat_entry, lon_entry);
1333        g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1334    
1335      /* draw a popup menu */      /* draw a popup menu */
1336      gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,      gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1337                     event->button, event->time);                     event->button, event->time);
# Line 682  static gint on_popup_button_press(GtkWid Line 1342  static gint on_popup_button_press(GtkWid
1342    
1343  static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {  static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1344    GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");    GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1345    gtk_widget_destroy(menu);    if(menu) gtk_widget_destroy(menu);
1346  }  }
1347  #endif  #endif
1348    
1349  #ifdef PICKER_DIALOG  #ifdef PRESET_PICKER_DIALOG
1350    
1351  enum {  enum {
1352    PICKER_COL_ICON = 0,    PRESET_PICKER_COL_ICON = 0,
1353    PICKER_COL_NAME,    PRESET_PICKER_COL_NAME,
1354    PICKER_COL_ID,    PRESET_PICKER_COL_ID,
1355    PICKER_COL_CB,    PRESET_PICKER_COL_CB,
1356    PICKER_NUM_COLS    PRESET_PICKER_NUM_COLS
1357  };  };
1358    
1359  static void picker_add(GtkListStore *store,  appdata_t *appdata,  static void preset_picker_add(GtkListStore *store,  appdata_t *appdata,
1360                         GdkPixbuf *icon, char *menu_str,                         GdkPixbuf *icon, char *menu_str,
1361                         void(*func)(GtkWidget*, gpointer), gint id) {                         void(*func)(GtkWidget*, gpointer), gint id) {
1362    GtkTreeIter     iter;    GtkTreeIter     iter;
# Line 705  static void picker_add(GtkListStore *sto Line 1365  static void picker_add(GtkListStore *sto
1365    gtk_list_store_append (store, &iter);    gtk_list_store_append (store, &iter);
1366    
1367    gtk_list_store_set(store, &iter,    gtk_list_store_set(store, &iter,
1368                       PICKER_COL_ICON, icon,                       PRESET_PICKER_COL_ICON, icon,
1369                       PICKER_COL_NAME, menu_str,                       PRESET_PICKER_COL_NAME, menu_str,
1370                       PICKER_COL_ID, id,                       PRESET_PICKER_COL_ID, id,
1371                       PICKER_COL_CB, func,                       PRESET_PICKER_COL_CB, func,
1372                       -1);                       -1);
1373  }  }
1374    
1375  static void on_picker_activated(GtkTreeView        *treeview,  static void on_preset_picker_activated(GtkTreeView        *treeview,
1376                                  GtkTreePath        *path,                                  GtkTreePath        *path,
1377                                  GtkTreeViewColumn  *col,                                  GtkTreeViewColumn  *col,
1378                                  gpointer            userdata) {                                  gpointer            userdata) {
# Line 723  static void on_picker_activated(GtkTreeV Line 1383  static void on_picker_activated(GtkTreeV
1383      gint id;      gint id;
1384      void(*func)(GtkWidget*, gpointer);      void(*func)(GtkWidget*, gpointer);
1385      gtk_tree_model_get(model, &iter,      gtk_tree_model_get(model, &iter,
1386                         PICKER_COL_ID, &id,                         PRESET_PICKER_COL_ID, &id,
1387                         PICKER_COL_CB, &func,                         PRESET_PICKER_COL_CB, &func,
1388                         -1);                         -1);
1389    
1390      /* set id on widget as callbacks expect it this way */      /* set id on widget as callbacks expect it this way */
1391      g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);      g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1392      func(GTK_WIDGET(treeview), userdata);      func(GTK_WIDGET(treeview), userdata);
1393    
1394        gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1395                        GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1396    
1397    }    }
1398  }  }
1399    
1400  static GtkWidget *picker_create(appdata_t *appdata,  static GtkWidget *preset_picker_create(appdata_t *appdata,
1401                                  GtkWidget *lat_entry, GtkWidget *lon_entry) {                                  GtkWidget *lat_entry, GtkWidget *lon_entry) {
1402    GtkCellRenderer *renderer;    GtkCellRenderer *renderer;
1403    GtkListStore    *store;    GtkListStore    *store;
# Line 746  static GtkWidget *picker_create(appdata_ Line 1410  static GtkWidget *picker_create(appdata_
1410    /* --- "Icon" column --- */    /* --- "Icon" column --- */
1411    renderer = gtk_cell_renderer_pixbuf_new();    renderer = gtk_cell_renderer_pixbuf_new();
1412    gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),    gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1413        -1, "Icon", renderer, "pixbuf", PICKER_COL_ICON, NULL);        -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1414    
1415    /* --- "Name" column --- */    /* --- "Name" column --- */
1416    renderer = gtk_cell_renderer_text_new();    renderer = gtk_cell_renderer_text_new();
1417    g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );    g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1418    GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(    GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1419                   "Name", renderer, "text", PICKER_COL_NAME, NULL);                   "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1420    gtk_tree_view_column_set_expand(column, TRUE);    gtk_tree_view_column_set_expand(column, TRUE);
1421    gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);    gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1422    
1423    store = gtk_list_store_new(PICKER_NUM_COLS,    store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1424                               GDK_TYPE_PIXBUF,                               GDK_TYPE_PIXBUF,
1425                               G_TYPE_STRING,                               G_TYPE_STRING,
1426                               G_TYPE_INT,                               G_TYPE_INT,
1427                               G_TYPE_POINTER);                               G_TYPE_POINTER);
1428    
1429    picker_add(store, appdata, icon_get(ICON_POS, 18),    if(pos_valid(gps_get_pos(appdata)))
1430               _("Current position (GPS)"), cb_gps, 0);      preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1431    picker_add(store, appdata, icon_get(ICON_POS, 19),                        _("GPS position"), cb_gps, 0);
1432               _("Geomath projection"), cb_geomath, 0);  
1433      if(pos_valid(&appdata->home))
1434        preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1435                          _("Home"), cb_gps, 1);
1436    
1437      location_t *location = appdata->location;
1438      gint id = 2;
1439      while(location) {
1440        if(pos_valid(&location->pos))
1441          preset_picker_add(store, appdata, icon_get(ICON_POS, 17),
1442                            location->name, cb_gps, id);
1443    
1444        id++;
1445        location = location->next;
1446      }
1447    
1448      if(pos_valid(&appdata->geomath))
1449        preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1450                          _("Geomath projection"), cb_geomath, 0);
1451    
1452  #ifdef ENABLE_OSM_GPS_MAP  #ifdef ENABLE_OSM_GPS_MAP
1453    picker_add(store, appdata, icon_get(ICON_POS, 20),    if(pos_valid(&appdata->map.pos))
1454               _("Map position"), cb_map, 0);      preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1455                          _("Map position"), cb_map, 0);
1456    #endif
1457    
1458    #ifdef ENABLE_MAEMO_MAPPER
1459      if(appdata->mmpos_valid) {
1460        preset_picker_add(menu, appdata, icon_get(ICON_POS, 24),
1461                          _("Maemo mapper position"), cb_mm, 0);
1462      }
1463  #endif  #endif
1464    
1465    if(appdata->cur_cache) {    if(appdata->cur_cache) {
# Line 776  static GtkWidget *picker_create(appdata_ Line 1467  static GtkWidget *picker_create(appdata_
1467    
1468      char *name = cache->name;      char *name = cache->name;
1469      if(!name) name = cache->id;      if(!name) name = cache->id;
1470    
1471      if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {      /* original cache position */
1472        picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),      if(pos_valid(&cache->pos))
1473                   name, cb_cache, 0);        preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1474      }                          name, cb_cache, 0);
1475    
1476        /* overwritten cache position */
1477        if(appdata->cache_context && notes_get_override(appdata->cache_context))
1478          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1479                            _("Modified coordinate"), cb_cache, 1);
1480    
1481      wpt_t *wpt = cache->wpt;      wpt_t *wpt = cache->wpt;
1482      gint id = 1;      gint id = 2;
1483      while(wpt) {      while(wpt) {
1484        GdkPixbuf *icon = NULL;        if(pos_valid(&wpt->pos)) {
1485        if(wpt->sym != WPT_SYM_UNKNOWN)          GdkPixbuf *icon = NULL;
1486          icon = icon_get(ICON_POS, wpt->sym);          if(wpt->sym != WPT_SYM_UNKNOWN)
1487              icon = icon_get(ICON_POS, wpt->sym);
1488        char *name = wpt->desc;  
1489        if(!name) name = wpt->cmt;          char *name = wpt->desc;
1490        if(!name) name = wpt->id;          if(!name) name = wpt->cmt;
1491            if(!name) name = wpt->id;
1492    
1493        picker_add(store, appdata, icon, name, cb_cache, id++);          preset_picker_add(store, appdata, icon, name, cb_cache, id);
1494          }
1495          id++;
1496        wpt = wpt->next;        wpt = wpt->next;
1497      }      }
1498    }    }
1499    
   
1500    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));    gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1501    g_object_unref(store);    g_object_unref(store);
1502    
1503    /* make list react on clicks */    /* make list react on clicks */
1504    g_signal_connect(view, "row-activated",    g_signal_connect(view, "row-activated",
1505                     (GCallback)on_picker_activated, appdata);                     (GCallback)on_preset_picker_activated, appdata);
   
 #if 0  
   g_signal_connect(view, "destroy",  
                    (GCallback)cachelist_destroy, ce);  
 #endif  
1506    
1507    /* put this inside a scrolled view */    /* put this inside a scrolled view */
1508  #ifndef USE_PANNABLE_AREA  #ifndef USE_PANNABLE_AREA
# Line 825  static GtkWidget *picker_create(appdata_ Line 1518  static GtkWidget *picker_create(appdata_
1518  #endif  #endif
1519  }  }
1520    
1521  static gint on_picker_button_press(GtkWidget *button,  static gint on_preset_picker_button_press(GtkWidget *button,
1522                     GdkEventButton *event, gpointer data) {                     GdkEventButton *event, gpointer data) {
1523    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1524    
# Line 837  static gint on_picker_button_press(GtkWi Line 1530  static gint on_picker_button_press(GtkWi
1530        gtk_dialog_new_with_buttons(_("Preset coordinates"),        gtk_dialog_new_with_buttons(_("Preset coordinates"),
1531            GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),            GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1532                                    GTK_DIALOG_MODAL,                                    GTK_DIALOG_MODAL,
           GTK_STOCK_OK,     GTK_RESPONSE_ACCEPT,  
1533            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,            GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1534            NULL);            NULL);
1535    
1536      gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);      gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1537    
1538      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),      gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1539                                  picker_create(appdata, lat_entry, lon_entry));                          preset_picker_create(appdata, lat_entry, lon_entry));
1540    
1541      gtk_widget_show_all(dialog);      gtk_widget_show_all(dialog);
1542      gtk_dialog_run(GTK_DIALOG(dialog));      gtk_dialog_run(GTK_DIALOG(dialog));
# Line 856  static gint on_picker_button_press(GtkWi Line 1548  static gint on_picker_button_press(GtkWi
1548  }  }
1549  #endif  #endif
1550    
1551  GtkWidget *coo_popup(appdata_t *appdata,  
1552    GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1553                       GtkWidget *lat_entry, GtkWidget *lon_entry) {                       GtkWidget *lat_entry, GtkWidget *lon_entry) {
1554    
1555    GtkWidget *button = gtk_button_new();    GtkWidget *button = gtk_button_new();
1556    
1557    gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));    gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 22));
1558    
1559    gtk_widget_set_tooltip_text(button, _("Preset coordinates"));    gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
1560    
1561  #ifndef PICKER_DIALOG    g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1562      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1563    
1564    #ifndef PRESET_PICKER_DIALOG
1565    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1566                       (GtkSignalFunc)on_popup_button_press, appdata);                       (GtkSignalFunc)on_popup_button_press, appdata);
1567    
1568    gtk_signal_connect(GTK_OBJECT(button), "destroy",    gtk_signal_connect(GTK_OBJECT(button), "destroy",
1569                       (GtkSignalFunc)on_popup_destroy, appdata);                       (GtkSignalFunc)on_popup_destroy, appdata);
   
   g_object_set_data(G_OBJECT(button), "menu",  
                     popup_menu_create(appdata, lat_entry, lon_entry));  
1570  #else  #else
1571  #ifdef FREMANTLE  #ifdef FREMANTLE
1572    hildon_gtk_widget_set_theme_size(button,    hildon_gtk_widget_set_theme_size(button,
1573          (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));          (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1574  #endif  #endif
1575    
1576      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1577                         (GtkSignalFunc)on_preset_picker_button_press, appdata);
1578    #endif
1579    
1580      return button;
1581    }
1582    
1583    #if defined(ENABLE_MAEMO_MAPPER) || defined(ENABLE_OSM_GPS_MAP)
1584    static pos_t goto_pos_get(GtkWidget *item) {
1585      pos_t pos;
1586    
1587      GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1588      pos.lat = lat_entry_get(lat_entry);
1589    
1590      GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1591      pos.lon = lon_entry_get(lon_entry);
1592    
1593      return  pos;
1594    }
1595    
1596    #ifdef ENABLE_MAEMO_MAPPER
1597    static void cb_mm_set(GtkWidget *item, gpointer data) {
1598      appdata_t *appdata = (appdata_t*)data;
1599    
1600      pos_t pos = goto_pos_get(item);
1601      if(!isnan(pos.lat) && !isnan(pos.lon))
1602        dbus_mm_set_position(appdata, &pos);
1603    }
1604    #endif
1605    
1606    static void cb_map_set(GtkWidget *item, gpointer data) {
1607      appdata_t *appdata = (appdata_t*)data;
1608    
1609      pos_t pos = goto_pos_get(item);
1610      if(!isnan(pos.lat) && !isnan(pos.lon)) {
1611        map(appdata);
1612        osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1613                                 pos.lat, pos.lon);
1614      }
1615    }
1616    
1617    #ifndef PRESET_PICKER_DIALOG
1618    static GtkWidget *goto_popup_menu_create(appdata_t *appdata,
1619                        GtkWidget *lat_entry, GtkWidget *lon_entry) {
1620      GtkWidget *menu = gtk_menu_new();
1621    
1622    #if defined(ENABLE_OSM_GPS_MAP)
1623      menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1624               _("Map position"), cb_map_set, 0, lon_entry, lat_entry);
1625    #endif
1626    
1627    #if defined(ENABLE_MAEMO_MAPPER)
1628      menu_add(menu, appdata, icon_get_widget(ICON_POS, 24),
1629               _("Maemo mapper position"), cb_mm_set, 0, lon_entry, lat_entry);
1630    #endif
1631    
1632      gtk_widget_show_all(menu);
1633    
1634      return menu;
1635    }
1636    #else
1637    static GtkWidget *goto_picker_create(appdata_t *appdata,
1638                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1639      GtkCellRenderer *renderer;
1640      GtkListStore    *store;
1641    
1642      GtkWidget *view = gtk_tree_view_new();
1643    
1644      g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1645      g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1646    
1647      /* --- "Icon" column --- */
1648      renderer = gtk_cell_renderer_pixbuf_new();
1649      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1650          -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1651    
1652      /* --- "Name" column --- */
1653      renderer = gtk_cell_renderer_text_new();
1654      g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1655      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1656                     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1657      gtk_tree_view_column_set_expand(column, TRUE);
1658      gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1659    
1660      store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1661                                 GDK_TYPE_PIXBUF,
1662                                 G_TYPE_STRING,
1663                                 G_TYPE_INT,
1664                                 G_TYPE_POINTER);
1665    
1666    #if defined(ENABLE_OSM_GPS_MAP)
1667      preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1668                        _("Map position"), cb_map_set, 0);
1669    #endif
1670    
1671    #if defined(ENABLE_MAEMO_MAPPER)
1672      preset_picker_add(store, appdata, icon_get(ICON_POS, 24),
1673                        _("Maemo mapper position"), cb_mm_set, 0);
1674    #endif
1675    
1676      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1677      g_object_unref(store);
1678    
1679      /* make list react on clicks */
1680      g_signal_connect(view, "row-activated",
1681                       (GCallback)on_preset_picker_activated, appdata);
1682    
1683      /* put this inside a scrolled view */
1684    #ifndef USE_PANNABLE_AREA
1685      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1686      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1687                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1688      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1689      return scrolled_window;
1690    #else
1691      GtkWidget *pannable_area = hildon_pannable_area_new();
1692      gtk_container_add(GTK_CONTAINER(pannable_area), view);
1693      return pannable_area;
1694    #endif
1695    }
1696    #endif
1697    
1698    static gint on_goto_button_press(GtkWidget *button,
1699                                     GdkEventButton *event, gpointer data) {
1700      appdata_t *appdata = (appdata_t*)data;
1701    
1702      if(event->type == GDK_BUTTON_PRESS) {
1703    
1704    #if defined(ENABLE_MAEMO_MAPPER) && !defined(ENABLE_OSM_GPS_MAP)
1705        /* only maemo mapper is being used */
1706        pos_t pos = goto_pos_get(button);
1707        if(!isnan(pos.lat) && !isnan(pos.lon)) {
1708          dbus_mm_set_position(appdata, &pos);
1709    #elif !defined(ENABLE_MAEMO_MAPPER) && defined(ENABLE_OSM_GPS_MAP)
1710        /* only internal map is being used */
1711        pos_t pos = goto_pos_get(button);
1712        if(!isnan(pos.lat) && !isnan(pos.lon)) {
1713          map(appdata);
1714          osm_gps_map_set_center(OSM_GPS_MAP(appdata->map.context->widget),
1715                                 pos.lat, pos.lon);
1716        }
1717    #else
1718    
1719        gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1720        g_assert(lat_entry);
1721        gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1722        g_assert(lon_entry);
1723    
1724    #ifndef PRESET_PICKER_DIALOG
1725        GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1726        if(!menu) {
1727          menu = goto_popup_menu_create(appdata, lat_entry, lon_entry);
1728          g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1729        }
1730    
1731        /* draw a popup menu */
1732        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1733                       event->button, event->time);
1734    #else
1735        GtkWidget *dialog =
1736          gtk_dialog_new_with_buttons(_("Map coordinates"),
1737              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1738                                      GTK_DIALOG_MODAL,
1739              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1740              NULL);
1741    
1742        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1743    
1744        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1745                            goto_picker_create(appdata, lat_entry, lon_entry));
1746    
1747        gtk_widget_show_all(dialog);
1748        gtk_dialog_run(GTK_DIALOG(dialog));
1749        gtk_widget_destroy(dialog);
1750    #endif
1751    
1752    #endif
1753    
1754        return TRUE;
1755      }
1756      return FALSE;
1757    }
1758    
1759    /* a button which makes the map/maemo mapper go to the associated */
1760    /* position */
1761    GtkWidget *goto_coordinate(appdata_t *appdata,
1762                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1763    
1764      GtkWidget *button = gtk_button_new();
1765    
1766      gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 23));
1767    
1768      gtk_widget_set_tooltip_text(button, _("Goto coordinates"));
1769    
1770    g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);    g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1771    g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);    g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1772    
1773    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1774                       (GtkSignalFunc)on_picker_button_press, appdata);                       (GtkSignalFunc)on_goto_button_press, appdata);
1775    
1776    #ifndef PRESET_PICKER_DIALOG
1777      gtk_signal_connect(GTK_OBJECT(button), "destroy",
1778                         (GtkSignalFunc)on_popup_destroy, appdata);
1779    #else
1780    #ifdef FREMANTLE
1781      hildon_gtk_widget_set_theme_size(button,
1782            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1783    #endif
1784  #endif  #endif
1785    
1786    return button;    return button;
1787  }  }
1788    #else
1789    /* no map installed */
1790    GtkWidget *goto_coordinate(appdata_t *appdata,
1791                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1792      return gtk_label_new("");
1793    }
1794    #endif
1795    
1796  GtkWidget *entry_new(void) {  GtkWidget *entry_new(void) {
1797  #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)  #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
# Line 905  gboolean pos_differ(pos_t *pos1, pos_t * Line 1808  gboolean pos_differ(pos_t *pos1, pos_t *
1808    return((lat1 != lat2) || (lon1 != lon2));    return((lat1 != lat2) || (lon1 != lon2));
1809  }  }
1810    
1811    gboolean pos_valid(pos_t *pos) {
1812      if(!pos) return FALSE;
1813      return(!isnan(pos->lat) && !isnan(pos->lon));
1814    }
1815    
1816    void misc_init(void) {
1817      g_signal_new ("changed", GTK_TYPE_BUTTON,
1818                    G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
1819                    g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1820    }
1821    
1822    void angle_str(char *str, int len, float angle) {
1823      snprintf(str, len, _("%.1f°"), angle);
1824    }
1825    
1826    float angle_parse(char *str) {
1827      float val;
1828    
1829      if(sscanf(str, _("%f°"), &val) != 1)
1830        val = NAN;
1831    
1832      return val;
1833    }
1834    
1835    #ifndef COORDINATE_PICKER
1836    static void callback_modified_angle(GtkWidget *widget, gpointer data ) {
1837      float i = angle_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
1838      mark(widget, !isnan(i));
1839    }
1840    #else
1841    static gint on_angle_picker_button_press(GtkWidget *button,
1842                       GdkEventButton *event, gpointer data) {
1843    
1844      if(event->type == GDK_BUTTON_PRESS) {
1845        GtkWidget *dialog =
1846          gtk_dialog_new_with_buttons(_("Direction"),
1847              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1848                                      GTK_DIALOG_MODAL,
1849              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1850              _("Done"),        GTK_RESPONSE_ACCEPT,
1851              NULL);
1852    
1853        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1854    
1855        int i, angle = (int)g_object_get_data(G_OBJECT(button), "angle");
1856    
1857        GtkWidget *anglew[3], *fracw;
1858    
1859        /* create xxx.x° */
1860        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
1861    
1862        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1863                    anglew[0] = digit_picker_create(0,3, (angle/1000)%10));
1864        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1865                    anglew[1] = digit_picker_create(0,9, (angle/100)%10));
1866        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1867                    anglew[2] = digit_picker_create(0,9, (angle/10)%10));
1868        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
1869        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1870                    fracw = digit_picker_create(0,9, (angle/1)%10));
1871        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
1872    
1873        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1874    
1875        gtk_widget_show_all(dialog);
1876        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1877    
1878          /* parse angle */
1879          for(angle=0,i=0;i<3;i++)
1880            angle = 10 * angle + picker_get(anglew[i]);
1881    
1882          angle = 10 * angle + picker_get(fracw);
1883    
1884          angle_entry_set(button, angle/10.0);
1885        }
1886    
1887        gtk_widget_destroy(dialog);
1888    
1889        return TRUE;
1890      }
1891      return FALSE;
1892    }
1893    #endif
1894    
1895    GtkWidget *angle_entry_new(float angle) {
1896      char str[32];
1897      angle_str(str, sizeof(str), angle);
1898    
1899    #ifndef COORDINATE_PICKER
1900      GtkWidget *widget = red_entry_new_with_text(str);
1901      g_signal_connect(G_OBJECT(widget), "changed",
1902                       G_CALLBACK(callback_modified_angle), NULL);
1903    #else
1904      GtkWidget *widget = gtk_button_new_with_label(str);
1905    
1906    #ifdef FREMANTLE
1907      hildon_gtk_widget_set_theme_size(widget,
1908            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1909    #endif
1910      int angle_int = (int)roundf(angle*10.0);
1911      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1912      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
1913                         (GtkSignalFunc)on_angle_picker_button_press, NULL);
1914    #endif
1915      return widget;
1916    }
1917    
1918    float angle_entry_get(GtkWidget *widget) {
1919    #ifndef COORDINATE_PICKER
1920      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
1921    #else
1922      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
1923    #endif
1924      return angle_parse(p);
1925    }
1926    
1927    void angle_entry_set(GtkWidget *widget, float angle) {
1928      char str[32];
1929      angle_str(str, sizeof(str)-1, angle);
1930    #ifndef COORDINATE_PICKER
1931      gtk_entry_set_text(GTK_ENTRY(widget), str);
1932    #else
1933      gtk_button_set_label(GTK_BUTTON(widget), str);
1934      int angle_int = (int)roundf(angle * 10.0);
1935      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1936      g_signal_emit_by_name(widget, "changed");
1937    #endif
1938    }
1939    

Legend:
Removed from v.217  
changed lines
  Added in v.231