Diff of /trunk/src/misc.c

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

revision 216 by harbaum, Thu Nov 26 14:32:41 2009 UTC revision 223 by harbaum, Tue Dec 1 20:03:51 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 33  Line 36 
36  #include <hildon/hildon-picker-dialog.h>  #include <hildon/hildon-picker-dialog.h>
37  #endif  #endif
38    
39    float roundf(float x);
40    
41    /* Enable special fremantle UI elements. These particular widgets */
42    /* don't use any hildon/fremantle specific parts and can thus even */
43    /* be used under plain gtk. This is mainly for testing and developemt */
44    #ifdef FREMANTLE
45    #define PRESET_PICKER_DIALOG
46    #define COORDINATE_PICKER
47    #endif
48    
49  char strlastchr(char *str) {  char strlastchr(char *str) {
50    return str[strlen(str)]-1;    return str[strlen(str)]-1;
51  }  }
# Line 300  float distance_parse(char *str, gboolean Line 313  float distance_parse(char *str, gboolean
313    return val;    return val;
314  }  }
315    
316    /* ------------------ coordinate picker tool --------------------------- */
317    
318    #ifndef COORDINATE_PICKER
319  static gboolean mark(GtkWidget *widget, gboolean valid) {  static gboolean mark(GtkWidget *widget, gboolean valid) {
320    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
321    return valid;    return valid;
322  }  }
323    
324    GtkWidget *red_entry_new(void) {
325      GdkColor color;
326    
327      GtkWidget *widget = entry_new();
328      gdk_color_parse("#ff0000", &color);
329      gtk_widget_modify_text(widget, TAG_STATE, &color);
330      return widget;
331    }
332    
333  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
334    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)));
335    mark(widget, !isnan(i));    mark(widget, !isnan(i));
336  }  }
337    #else
338    static void picker_center_iter(GtkWidget *view, GtkTreeIter *iter) {
339      /* select new iter */
340      GtkTreeSelection *selection =
341        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
342      GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(view));
343      gtk_tree_selection_select_iter(selection, iter);
344      GtkTreePath *path =
345        gtk_tree_model_get_path(model, iter);
346      gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
347                                   path, NULL, TRUE, 0.5, 0.5);
348      gtk_tree_path_free(path);
349    }
350    
351    static void on_picker_activated(GtkTreeView        *treeview,
352                                    GtkTreePath        *path,
353                                    GtkTreeViewColumn  *col,
354                                    gpointer            userdata) {
355      gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(treeview),
356                                   path, NULL, TRUE, 0.5, 0.5);
357    }
358    
359    #define DUMMY_NUM  1
360    
361    static void dummy_append(GtkListStore *store, int n) {
362      GtkTreeIter iter;
363    
364      while(n--) {
365        gtk_list_store_append (store, &iter);
366        gtk_list_store_set(store, &iter, 0, "", 1, -1, 2, FALSE, -1);
367      }
368    }
369    
370    static GtkWidget *string_picker_create(const char *str[], int sel) {
371    #ifndef FREMANTLE
372      GtkWidget *view = gtk_tree_view_new();
373    #else
374      GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
375    #endif
376    
377      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
378      GtkTreeSelection *selection =
379        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
380    
381      /* --- "char" column --- */
382      GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
383      g_object_set(renderer, "xalign", 0.5, NULL );
384      gtk_tree_view_insert_column_with_attributes(
385          GTK_TREE_VIEW(view), -1, "str", renderer,
386          "text", 0,
387          "sensitive", 2,
388          NULL);
389    
390      GtkListStore *store =
391        gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
392    
393      dummy_append(store, DUMMY_NUM);
394    
395      /* add strings */
396      GtkTreeIter iter, siter;
397      int i;
398      for(i=0;*str;str++,i++) {
399        gtk_list_store_append (store, &iter);
400        gtk_list_store_set(store, &iter, 0, _(*str), 1, i, 2, TRUE, -1);
401        if(i == sel) siter = iter;
402      }
403    
404      dummy_append(store, DUMMY_NUM);
405    
406      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
407      g_object_unref(store);
408    
409    #ifndef FREMANTLE
410      g_signal_connect(view, "row-activated",
411                       (GCallback)on_picker_activated, NULL);
412    #else
413      g_signal_connect(view, "hildon-row-tapped",
414                       (GCallback)on_picker_activated, NULL);
415    #endif
416    
417      /* select right character */
418      gtk_tree_selection_select_iter(selection, &siter);
419      picker_center_iter(view, &siter);
420    
421      /* put this inside a scrolled view */
422    #ifndef USE_PANNABLE_AREA
423      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
424      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
425                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
426      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
427      return scrolled_window;
428    #else
429      GtkWidget *pannable_area = hildon_pannable_area_new();
430      gtk_container_add(GTK_CONTAINER(pannable_area), view);
431      return pannable_area;
432    #endif
433    }
434    
435    static int picker_get(GtkWidget *widget) {
436      GtkWidget *view = gtk_bin_get_child(GTK_BIN(widget));
437    
438      GtkTreeSelection *sel =
439        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
440    
441      GtkTreeModel *model;
442      GtkTreeIter iter;
443    
444      /* there should never be an unseletced column. But if */
445      /* it is, we count it as zero */
446      if(!gtk_tree_selection_get_selected(sel, &model, &iter))
447        return 0;
448    
449      int retval = 0;
450      gtk_tree_model_get(model, &iter, 1, &retval, -1);
451      return retval;
452    }
453    
454    static GtkWidget *digit_picker_create(int min, int max, int sel) {
455    #ifndef FREMANTLE
456      GtkWidget *view = gtk_tree_view_new();
457    #else
458      GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
459    #endif
460    
461      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
462      GtkTreeSelection *selection =
463        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
464    
465      /* --- "digit" column --- */
466      GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
467      g_object_set(renderer, "xalign", 0.5, NULL );
468      gtk_tree_view_insert_column_with_attributes(
469          GTK_TREE_VIEW(view), -1, "digit", renderer,
470          "text", 0,
471          "sensitive", 2,
472          NULL);
473    
474      GtkListStore *store =
475        gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_BOOLEAN);
476    
477      dummy_append(store, DUMMY_NUM);
478    
479      /* add digits */
480      int i;
481      GtkTreeIter siter;
482      for(i=min;i<=max;i++) {
483        char str[2] = { '0'+i, 0 };
484        GtkTreeIter     iter;
485        /* Append a row and fill in some data */
486        gtk_list_store_append (store, &iter);
487        gtk_list_store_set(store, &iter, 0, str, 1, i, 2, TRUE, -1);
488    
489        if(i == sel) siter = iter;
490      }
491    
492      dummy_append(store, DUMMY_NUM);
493    
494      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
495      g_object_unref(store);
496    
497    #ifndef FREMANTLE
498      g_signal_connect(view, "row-activated",
499                       (GCallback)on_picker_activated, NULL);
500    #else
501      g_signal_connect(view, "hildon-row-tapped",
502                       (GCallback)on_picker_activated, NULL);
503    #endif
504    
505      gtk_tree_selection_select_iter(selection, &siter);
506      picker_center_iter(view, &siter);
507    
508      /* put this inside a scrolled view */
509    #ifndef USE_PANNABLE_AREA
510      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
511      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
512                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
513      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
514      return scrolled_window;
515    #else
516      GtkWidget *pannable_area = hildon_pannable_area_new();
517      gtk_container_add(GTK_CONTAINER(pannable_area), view);
518      return pannable_area;
519    #endif
520    }
521    
522    static gint on_lat_picker_button_press(GtkWidget *button,
523                       GdkEventButton *event, gpointer data) {
524    
525      if(event->type == GDK_BUTTON_PRESS) {
526        GtkWidget *dialog =
527          gtk_dialog_new_with_buttons(_("Latitude"),
528              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
529                                      GTK_DIALOG_MODAL,
530              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
531              _("Done"),        GTK_RESPONSE_ACCEPT,
532              NULL);
533    
534        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
535    
536        int i, lat = (int)g_object_get_data(G_OBJECT(button), "latitude");
537    
538        /* parse latitude into components */
539        int sign = (lat>=0)?0:1;
540        lat = abs(lat);
541        int deg = lat / 60000;
542        int min = (lat /1000)%60;
543        int minfrac = lat % 1000;
544    
545        GtkWidget *signw, *degw[2], *minw[2], *minfracw[3];
546    
547    
548        /* create N/S 89° 99.999 */
549        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
550        static const char *ns[] = { "N", "S", NULL };
551        gtk_box_pack_start_defaults(GTK_BOX(hbox),
552                    signw = string_picker_create(ns, sign));
553    
554        gtk_box_pack_start_defaults(GTK_BOX(hbox),
555                    degw[0] = digit_picker_create(0,8, deg/10));
556        gtk_box_pack_start_defaults(GTK_BOX(hbox),
557                    degw[1] = digit_picker_create(0,9, deg%10));
558        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
559    
560        gtk_box_pack_start_defaults(GTK_BOX(hbox),
561                    minw[0] = digit_picker_create(0,5, min/10));
562        gtk_box_pack_start_defaults(GTK_BOX(hbox),
563                    minw[1] = digit_picker_create(0,9, min%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                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
568        gtk_box_pack_start_defaults(GTK_BOX(hbox),
569                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
570        gtk_box_pack_start_defaults(GTK_BOX(hbox),
571                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
572    
573        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
574    
575        gtk_widget_show_all(dialog);
576        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
577    
578          /* parse degrees ... */
579          for(deg=0,i=0;i<2;i++)
580            deg = 10 * deg + picker_get(degw[i]);
581    
582          /* ... minutes ... */
583          for(min=0,i=0;i<2;i++)
584            min = 10 * min + picker_get(minw[i]);
585    
586          /* ... and fractions of minutes */
587          for(minfrac=0,i=0;i<3;i++)
588            minfrac = 10 * minfrac + picker_get(minfracw[i]);
589    
590          /* parse N/S */
591          if(deg | min | minfrac)
592            sign = picker_get(signw)?-1:1;
593          else
594            sign = 1;   // theres no S 00 00.000
595    
596          float latitude = sign * (deg + min/60.0 + minfrac/60000.0);
597          lat_entry_set(button, latitude);
598        }
599    
600        gtk_widget_destroy(dialog);
601    
602        return TRUE;
603      }
604      return FALSE;
605    }
606    #endif
607    
608  /* a entry that is colored red when being "active" */  /* a entry that is colored red when being "active" */
609  GtkWidget *lat_entry_new(float lat) {  GtkWidget *lat_entry_new(float lat) {
610      char str[32];
611      pos_lat_str(str, sizeof(str), lat);
612    
613    #ifndef COORDINATE_PICKER
614    GdkColor color;    GdkColor color;
615    
616    GtkWidget *widget = entry_new();    GtkWidget *widget = entry_new();
617    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
618    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
619    
   char str[32];  
   pos_lat_str(str, sizeof(str), lat);  
620    gtk_entry_set_text(GTK_ENTRY(widget), str);    gtk_entry_set_text(GTK_ENTRY(widget), str);
621    
622    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
623                     G_CALLBACK(callback_modified_lat), NULL);                     G_CALLBACK(callback_modified_lat), NULL);
624    
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;    return widget;
639  }  }
640    
641    #ifndef COORDINATE_PICKER
642  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
643    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)));
644    mark(widget, !isnan(i));    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 */  /* a entry that is colored red when filled with invalid coordinate */
734  GtkWidget *lon_entry_new(float lon) {  GtkWidget *lon_entry_new(float lon) {
735      char str[32];
736      pos_lon_str(str, sizeof(str), lon);
737    
738    #ifndef COORDINATE_PICKER
739    GdkColor color;    GdkColor color;
740    
741    GtkWidget *widget = entry_new();    GtkWidget *widget = entry_new();
   //  gtk_entry_set_width_chars(GTK_ENTRY(widget), 14);  
   
742    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
743    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
744    
   char str[32];  
   pos_lon_str(str, sizeof(str), lon);  
745    gtk_entry_set_text(GTK_ENTRY(widget), str);    gtk_entry_set_text(GTK_ENTRY(widget), str);
746    
747    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
748                     G_CALLBACK(callback_modified_lon), NULL);                     G_CALLBACK(callback_modified_lon), NULL);
749    
750    #else
751      GtkWidget *widget = gtk_button_new_with_label(str);
752    
753    #ifdef FREMANTLE
754      hildon_gtk_widget_set_theme_size(widget,
755            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
756    #endif
757      int lon_int = (int)roundf(lon * 60000);
758      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
759      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
760                         (GtkSignalFunc)on_lon_picker_button_press, NULL);
761    #endif
762    
763    return widget;    return widget;
764  }  }
765    
766    float lat_entry_get(GtkWidget *widget) {
767  float lat_get(GtkWidget *widget) {  #ifndef COORDINATE_PICKER
768    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
769    #else
770      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
771    #endif
772    return pos_parse_lat(p);    return pos_parse_lat(p);
773  }  }
774    
775  float lon_get(GtkWidget *widget) {  float lon_entry_get(GtkWidget *widget) {
776    #ifndef COORDINATE_PICKER
777    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
778    #else
779      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
780    #endif
781    return pos_parse_lon(p);    return pos_parse_lon(p);
782  }  }
783    
784    void lat_entry_set(GtkWidget *widget, float lat) {
785      char str[32];
786      pos_lat_str(str, sizeof(str)-1, lat);
787    #ifndef COORDINATE_PICKER
788      gtk_entry_set_text(GTK_ENTRY(widget), str);
789    #else
790      gtk_button_set_label(GTK_BUTTON(widget), str);
791      int lat_int = (int)roundf(lat * 60000);
792      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
793      g_signal_emit_by_name(widget, "changed");
794    #endif
795    }
796    
797    void lon_entry_set(GtkWidget *widget, float lon) {
798      char str[32];
799      pos_lon_str(str, sizeof(str)-1, lon);
800    #ifndef COORDINATE_PICKER
801      gtk_entry_set_text(GTK_ENTRY(widget), str);
802    #else
803      gtk_button_set_label(GTK_BUTTON(widget), str);
804      int lon_int = (int)roundf(lon * 60000);
805      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
806      g_signal_emit_by_name(widget, "changed");
807    #endif
808    }
809    
810    void lat_label_set(GtkWidget *widget, float lat) {
811      char str[32];
812      pos_lat_str(str, sizeof(str)-1, lat);
813      gtk_label_set(GTK_LABEL(widget), str);
814    }
815    
816    void lon_label_set(GtkWidget *widget, float lon) {
817      char str[32];
818      pos_lon_str(str, sizeof(str)-1, lon);
819      gtk_label_set(GTK_LABEL(widget), str);
820    }
821    
822    void lat_label_attrib_set(GtkWidget *widget, float lat,
823                              int size, int strikethrough) {
824      char str[32];
825      pos_lat_str(str, sizeof(str)-1, lat);
826      gtk_label_attrib_set(widget, str, size, strikethrough);
827    }
828    
829    void lon_label_attrib_set(GtkWidget *widget, float lon,
830                              int size, int strikethrough) {
831      char str[32];
832      pos_lon_str(str, sizeof(str)-1, lon);
833      gtk_label_attrib_set(widget, str, size, strikethrough);
834    }
835    
836    #ifndef COORDINATE_PICKER
837  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
838    /* 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 */
839    /* is parseable at all */    /* is parseable at all */
840    float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);    float i =
841        distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
842    mark(widget, !isnan(i));    mark(widget, !isnan(i));
843  }  }
844    #else
845    static gint on_dist_picker_button_press(GtkWidget *button,
846                       GdkEventButton *event, gpointer data) {
847    
848      if(event->type == GDK_BUTTON_PRESS) {
849        GtkWidget *dialog =
850          gtk_dialog_new_with_buttons(_("Distance"),
851              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
852                                      GTK_DIALOG_MODAL,
853              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
854              _("Done"),        GTK_RESPONSE_ACCEPT,
855              NULL);
856    
857        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
858    
859        /* distance is given in m or ft (depending on mil) */
860        int i, dist = (int)g_object_get_data(G_OBJECT(button), "distance");
861        gboolean mil = (gboolean)g_object_get_data(G_OBJECT(button), "mil");
862        int unit = 0;
863    
864        /* parse distance into components */
865        if(mil) {
866          /* 1 mil = 1760 yd = 5280 ft. 1yd = 3 ft */
867          if(dist<95)        { unit = 0; dist *= 100;  }
868          else if(dist<2904) { unit = 1; dist = 100 * dist / 3;  }
869          else               { unit = 2; dist = 5 * dist / 264; }
870        } else {
871          if(dist<1000)      { unit = 3; dist *= 100;  }
872          else               { unit = 4; dist /= 10; }
873        }
874    
875        GtkWidget *distw[4], *fracw[2], *unitw;
876    
877        /* create xxxx.x unit */
878        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
879    
880        gtk_box_pack_start_defaults(GTK_BOX(hbox),
881                    distw[0] = digit_picker_create(0,9, (dist/100000)%10));
882        gtk_box_pack_start_defaults(GTK_BOX(hbox),
883                    distw[1] = digit_picker_create(0,9, (dist/10000)%10));
884        gtk_box_pack_start_defaults(GTK_BOX(hbox),
885                    distw[2] = digit_picker_create(0,9, (dist/1000)%10));
886        gtk_box_pack_start_defaults(GTK_BOX(hbox),
887                    distw[3] = digit_picker_create(0,9, (dist/100)%10));
888        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
889        gtk_box_pack_start_defaults(GTK_BOX(hbox),
890                    fracw[0] = digit_picker_create(0,9, (dist/10)%10));
891        gtk_box_pack_start_defaults(GTK_BOX(hbox),
892                    fracw[1] = digit_picker_create(0,9, (dist/1)%10));
893    
894        static const char *units[] = { "ft", "yd", "mi", "m", "km", NULL };
895        gtk_box_pack_start_defaults(GTK_BOX(hbox),
896                    unitw = string_picker_create(units, unit));
897    
898        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
899    
900        gtk_widget_show_all(dialog);
901        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
902    
903          /* parse distance */
904          for(dist=0,i=0;i<4;i++)
905            dist = 10 * dist + picker_get(distw[i]);
906    
907          for(i=0;i<2;i++)
908            dist = 10 * dist + picker_get(fracw[i]);
909    
910          unit = picker_get(unitw);
911          if(unit == 0)      { dist /= 100; }         // ft
912          else if(unit == 1) { dist = 3*dist/100; }   // yd
913          else if(unit == 2) { dist = 528*dist/10; }  // mi
914          else if(unit == 3) { dist /= 100; }         // m
915          else if(unit == 4) { dist *= 10; }          // km
916    
917          /* user may have switched between metric and imperial */
918          float distance;
919          if(unit <= 2) {
920            distance = dist / 5280.0;
921            if(!mil) distance *=  1.609344;
922          } else {
923            distance = dist / 1000.0;
924            if( mil) distance /=  1.609344;
925          }
926    
927          dist_entry_set(button, distance, mil);
928        }
929    
930        gtk_widget_destroy(dialog);
931    
932        return TRUE;
933      }
934      return FALSE;
935    }
936    #endif
937    
938  /* a entry that is colored red when filled with invalid distance */  /* a entry that is colored red when filled with invalid distance */
939  GtkWidget *dist_entry_new(float dist, gboolean mil) {  GtkWidget *dist_entry_new(float dist, gboolean mil) {
940      char str[32];
941      distance_str(str, sizeof(str), dist, mil);
942    
943    #ifndef COORDINATE_PICKER
944    GdkColor color;    GdkColor color;
945    GtkWidget *widget = entry_new();    GtkWidget *widget = entry_new();
946    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
947    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
948    
   char str[32];  
   distance_str(str, sizeof(str), dist, mil);  
949    gtk_entry_set_text(GTK_ENTRY(widget), str);    gtk_entry_set_text(GTK_ENTRY(widget), str);
950    
951    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
952                     G_CALLBACK(callback_modified_dist), NULL);                     G_CALLBACK(callback_modified_dist), NULL);
953    
954    #else
955      GtkWidget *widget = gtk_button_new_with_label(str);
956    
957    #ifdef FREMANTLE
958      hildon_gtk_widget_set_theme_size(widget,
959            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
960    #endif
961      int dist_int = (int)roundf(dist * 1000);        // km -> m
962      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
963    
964      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
965      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
966      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
967                         (GtkSignalFunc)on_dist_picker_button_press, NULL);
968    #endif
969    
970    return widget;    return widget;
971  }  }
972    
973  float dist_get(GtkWidget *widget, gboolean mil) {  float dist_entry_get(GtkWidget *widget, gboolean mil) {
974    #ifndef COORDINATE_PICKER
975    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
976    #else
977      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
978    #endif
979    return distance_parse(p, mil);    return distance_parse(p, mil);
980  }  }
981    
982    void dist_entry_set(GtkWidget *widget, float dist, gboolean mil) {
983      char str[32];
984      distance_str(str, sizeof(str), dist, mil);
985    
986    #ifndef COORDINATE_PICKER
987      gtk_entry_set_text(GTK_ENTRY(widget), str);
988    #else
989      int dist_int = (int)roundf(dist * 1000);        // km -> m
990      if(mil) dist_int = (int)roundf(dist * 5280.0);  // mi -> ft
991      g_object_set_data(G_OBJECT(widget), "distance", (gpointer)dist_int);
992      g_object_set_data(G_OBJECT(widget), "mil", (gpointer)mil);
993      gtk_button_set_label(GTK_BUTTON(widget), str);
994    #endif
995    }
996    
997  #ifndef USE_MAEMO  #ifndef USE_MAEMO
998  #ifdef ENABLE_BROWSER_INTERFACE  #ifdef ENABLE_BROWSER_INTERFACE
999  #include <libgnome/gnome-url.h>  #include <libgnome/gnome-url.h>
# Line 535  GtkWidget *left_label_new(char *str) { Line 1136  GtkWidget *left_label_new(char *str) {
1136    return widget;    return widget;
1137  }  }
1138    
1139  static void pos_set(GtkMenuItem *item, float lat, float lon) {  /* ------------- preset coordinate picker tool ----------------- */
1140    char str[32];  
1141    static void pos_set(GtkWidget *item, float lat, float lon) {
1142    
   pos_lat_str(str, sizeof(str)-1, lat);  
1143    GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");    GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
1144    gtk_entry_set_text(GTK_ENTRY(lat_entry), str);    lat_entry_set(lat_entry, lat);
1145    
   pos_lon_str(str, sizeof(str)-1, lon);  
1146    GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");    GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
1147    gtk_entry_set_text(GTK_ENTRY(lon_entry), str);    lon_entry_set(lon_entry, lon);
1148  }  }
1149    
1150  static void cb_gps(GtkMenuItem *item, gpointer data) {  static void cb_gps(GtkWidget *item, gpointer data) {
1151    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1152      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1153      pos_t *pos = NULL;
1154    
1155    pos_t *refpos = get_pos(appdata);    if(!id)
1156    if(!refpos) pos_set(item, NAN, NAN);      pos = gps_get_pos(appdata);
1157    else        pos_set(item, refpos->lat, refpos->lon);    else if(id == 1)
1158        pos = &appdata->home;
1159      else {
1160        location_t *location = appdata->location;
1161        while(location && id > 2) {
1162          location = location->next;
1163          id--;
1164        }
1165    
1166        if(id == 2)
1167          pos = &location->pos;
1168      }
1169    
1170      if(!pos) pos_set(item, NAN, NAN);
1171      else     pos_set(item, pos->lat, pos->lon);
1172  }  }
1173    
1174  static void cb_geomath(GtkMenuItem *item, gpointer data) {  static void cb_geomath(GtkWidget *item, gpointer data) {
1175    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1176    
1177    pos_set(item, appdata->geomath.lat, appdata->geomath.lon);    pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
1178  }  }
1179    
1180  #ifdef ENABLE_OSM_GPS_MAP  #ifdef ENABLE_OSM_GPS_MAP
1181  static void cb_map(GtkMenuItem *item, gpointer data) {  static void cb_map(GtkWidget *item, gpointer data) {
1182    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1183    
1184    pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);    pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
1185  }  }
1186  #endif  #endif
1187    
1188  static const gchar *menu_item_get_label(GtkMenuItem *menu_item) {  static void cb_cache(GtkWidget *item, gpointer data) {
   GList *children, *l;  
   GtkWidget *child;  
   children = gtk_container_get_children (GTK_CONTAINER (menu_item));  
   for (l = g_list_first (children); l != NULL;  
        l = g_list_next (l)) {  
     child = (GtkWidget *)l->data;  
     if (GTK_IS_LABEL (child)) {  
       return gtk_label_get_label (GTK_LABEL (child));  
     }  
   }  
   return NULL;  
 }  
   
 static void cb_cache(GtkMenuItem *item, gpointer data) {  
   const char *label = menu_item_get_label(item);  
1189    appdata_t *appdata = (appdata_t*)data;    appdata_t *appdata = (appdata_t*)data;
1190    
1191    cache_t *cache = appdata->cur_cache;    cache_t *cache = appdata->cur_cache;
1192    g_assert(cache);    g_assert(cache);
1193    
1194    if(!strcmp(label, cache->id))    gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
1195    
1196      if(!id)
1197      pos_set(item, cache->pos.lat, cache->pos.lon);      pos_set(item, cache->pos.lat, cache->pos.lon);
1198      else if(id == 1)
1199        pos_set(item, cache->notes->pos.lat, cache->notes->pos.lon);
1200    else {    else {
1201      wpt_t *wpt = cache->wpt;      wpt_t *wpt = cache->wpt;
1202      while(wpt) {      while(wpt && id > 2) {
       if(!strcmp(label, wpt->id)) {  
         pos_set(item, wpt->pos.lat, wpt->pos.lon);  
         return;  
       }  
   
1203        wpt = wpt->next;        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,  static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1214                             GtkWidget *icon, char *menu_str,                             GtkWidget *icon, char *menu_str,
1215                             void(*func)(GtkMenuItem*, gpointer),                             void(*func)(GtkWidget*, gpointer), gint id,
1216                             GtkWidget *lon_entry, GtkWidget *lat_entry) {                             GtkWidget *lon_entry, GtkWidget *lat_entry) {
1217    
1218    GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);    GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
# Line 617  static GtkWidget *menu_add(GtkWidget *me Line 1222  static GtkWidget *menu_add(GtkWidget *me
1222    
1223    g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);    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);    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)    if(func)
1228      gtk_signal_connect(GTK_OBJECT(item), "activate",      gtk_signal_connect(GTK_OBJECT(item), "activate",
# Line 631  static GtkWidget *popup_menu_create(appd Line 1237  static GtkWidget *popup_menu_create(appd
1237                      GtkWidget *lat_entry, GtkWidget *lon_entry) {                      GtkWidget *lat_entry, GtkWidget *lon_entry) {
1238    GtkWidget *menu = gtk_menu_new();    GtkWidget *menu = gtk_menu_new();
1239    
1240    menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),    if(pos_valid(gps_get_pos(appdata)))
1241             _("Current position (GPS)"), cb_gps, lon_entry, lat_entry);      menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1242    menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),               _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1243             _("Geomath projection"), cb_geomath, lon_entry, lat_entry);  
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, 21),
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  #ifdef ENABLE_OSM_GPS_MAP
1264    menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),    if(pos_valid(&appdata->map.pos))
1265             _("Map position"), cb_map, lon_entry, lat_entry);      menu_add(menu, appdata, icon_get_widget(ICON_POS, 20), _("Map position"),
1266                 cb_map, 0, lon_entry, lat_entry);
1267  #endif  #endif
1268    
   printf("popup cache present: %s\n", appdata->cur_cache?"Yes":"No");  
   
1269    if(appdata->cur_cache) {    if(appdata->cur_cache) {
1270      cache_t *cache = appdata->cur_cache;      cache_t *cache = appdata->cur_cache;
1271    
1272      if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {      char *name = cache->name;
1273        if(!name) name = cache->id;
1274    
1275        /* original cache position */
1276        if(pos_valid(&cache->pos))
1277        menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),        menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1278                 cache->id, cb_cache, lon_entry, lat_entry);                 name, cb_cache, 0, lon_entry, lat_entry);
1279      }  
1280        /* overwritten cache position */
1281        if(cache->notes && pos_valid(&cache->notes->pos))
1282          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1283                   _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1284    
     printf("appending cache waypoints\n");  
1285      wpt_t *wpt = cache->wpt;      wpt_t *wpt = cache->wpt;
1286        gint id = 2;
1287      while(wpt) {      while(wpt) {
1288        GtkWidget *icon = NULL;        if(pos_valid(&wpt->pos)) {
1289        if(wpt->sym != WPT_SYM_UNKNOWN)          GtkWidget *icon = NULL;
1290          icon = icon_get_widget(ICON_POS, wpt->sym);          if(wpt->sym != WPT_SYM_UNKNOWN)
1291              icon = icon_get_widget(ICON_POS, wpt->sym);
1292        menu_add(menu, appdata, icon, wpt->id, cb_cache,  
1293                 lon_entry, lat_entry);          char *name = wpt->desc;
1294            if(!name) name = wpt->cmt;
1295            if(!name) name = wpt->id;
1296    
1297            menu_add(menu, appdata, icon, name, cb_cache, id,
1298                     lon_entry, lat_entry);
1299          }
1300    
1301          id++;
1302        wpt = wpt->next;        wpt = wpt->next;
1303      }      }
1304    }    }
# Line 672  static GtkWidget *popup_menu_create(appd Line 1311  static GtkWidget *popup_menu_create(appd
1311  static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,  static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1312                                    gpointer data) {                                    gpointer data) {
1313    
1314      appdata_t *appdata = (appdata_t*)data;
1315    
1316    if(event->type == GDK_BUTTON_PRESS) {    if(event->type == GDK_BUTTON_PRESS) {
1317      GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");      GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1318    
1319        if(menu)
1320          gtk_widget_destroy(menu);
1321    
1322        gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1323        g_assert(lat_entry);
1324        gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1325        g_assert(lon_entry);
1326    
1327        menu = popup_menu_create(appdata, lat_entry, lon_entry);
1328        g_object_set_data(G_OBJECT(button), "menu", (gpointer)menu);
1329    
1330      /* draw a popup menu */      /* draw a popup menu */
1331      gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,      gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1332                     event->button, event->time);                     event->button, event->time);
# Line 685  static gint on_popup_button_press(GtkWid Line 1337  static gint on_popup_button_press(GtkWid
1337    
1338  static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {  static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1339    GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");    GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1340    gtk_widget_destroy(menu);    if(menu) gtk_widget_destroy(menu);
1341    }
1342    #endif
1343    
1344    #ifdef PRESET_PICKER_DIALOG
1345    
1346    enum {
1347      PRESET_PICKER_COL_ICON = 0,
1348      PRESET_PICKER_COL_NAME,
1349      PRESET_PICKER_COL_ID,
1350      PRESET_PICKER_COL_CB,
1351      PRESET_PICKER_NUM_COLS
1352    };
1353    
1354    static void preset_picker_add(GtkListStore *store,  appdata_t *appdata,
1355                           GdkPixbuf *icon, char *menu_str,
1356                           void(*func)(GtkWidget*, gpointer), gint id) {
1357      GtkTreeIter     iter;
1358    
1359      /* Append a row and fill in some data */
1360      gtk_list_store_append (store, &iter);
1361    
1362      gtk_list_store_set(store, &iter,
1363                         PRESET_PICKER_COL_ICON, icon,
1364                         PRESET_PICKER_COL_NAME, menu_str,
1365                         PRESET_PICKER_COL_ID, id,
1366                         PRESET_PICKER_COL_CB, func,
1367                         -1);
1368    }
1369    
1370    static void on_preset_picker_activated(GtkTreeView        *treeview,
1371                                    GtkTreePath        *path,
1372                                    GtkTreeViewColumn  *col,
1373                                    gpointer            userdata) {
1374      GtkTreeIter   iter;
1375      GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1376    
1377      if(gtk_tree_model_get_iter(model, &iter, path)) {
1378        gint id;
1379        void(*func)(GtkWidget*, gpointer);
1380        gtk_tree_model_get(model, &iter,
1381                           PRESET_PICKER_COL_ID, &id,
1382                           PRESET_PICKER_COL_CB, &func,
1383                           -1);
1384    
1385        /* set id on widget as callbacks expect it this way */
1386        g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1387        func(GTK_WIDGET(treeview), userdata);
1388    
1389        gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1390                        GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1391    
1392      }
1393    }
1394    
1395    static GtkWidget *preset_picker_create(appdata_t *appdata,
1396                                    GtkWidget *lat_entry, GtkWidget *lon_entry) {
1397      GtkCellRenderer *renderer;
1398      GtkListStore    *store;
1399    
1400      GtkWidget *view = gtk_tree_view_new();
1401    
1402      g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1403      g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1404    
1405      /* --- "Icon" column --- */
1406      renderer = gtk_cell_renderer_pixbuf_new();
1407      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1408          -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1409    
1410      /* --- "Name" column --- */
1411      renderer = gtk_cell_renderer_text_new();
1412      g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1413      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1414                     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1415      gtk_tree_view_column_set_expand(column, TRUE);
1416      gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1417    
1418      store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1419                                 GDK_TYPE_PIXBUF,
1420                                 G_TYPE_STRING,
1421                                 G_TYPE_INT,
1422                                 G_TYPE_POINTER);
1423    
1424      if(pos_valid(gps_get_pos(appdata)))
1425        preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1426                          _("GPS position"), cb_gps, 0);
1427    
1428      if(pos_valid(&appdata->home))
1429        preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1430                          _("Home"), cb_gps, 1);
1431    
1432      location_t *location = appdata->location;
1433      gint id = 2;
1434      while(location) {
1435        if(pos_valid(&location->pos))
1436          preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1437                            location->name, cb_gps, id);
1438    
1439        id++;
1440        location = location->next;
1441      }
1442    
1443      if(pos_valid(&appdata->geomath))
1444        preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1445                          _("Geomath projection"), cb_geomath, 0);
1446    #ifdef ENABLE_OSM_GPS_MAP
1447      if(pos_valid(&appdata->map.pos))
1448        preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1449                          _("Map position"), cb_map, 0);
1450    #endif
1451    
1452      if(appdata->cur_cache) {
1453        cache_t *cache = appdata->cur_cache;
1454    
1455        char *name = cache->name;
1456        if(!name) name = cache->id;
1457    
1458        /* original cache position */
1459        if(pos_valid(&cache->pos))
1460          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1461                            name, cb_cache, 0);
1462    
1463        /* overwritten cache position */
1464        if(cache->notes && pos_valid(&cache->notes->pos))
1465          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1466                            _("Modified coordinate"), cb_cache, 1);
1467    
1468        wpt_t *wpt = cache->wpt;
1469        gint id = 2;
1470        while(wpt) {
1471          if(pos_valid(&wpt->pos)) {
1472            GdkPixbuf *icon = NULL;
1473            if(wpt->sym != WPT_SYM_UNKNOWN)
1474              icon = icon_get(ICON_POS, wpt->sym);
1475    
1476            char *name = wpt->desc;
1477            if(!name) name = wpt->cmt;
1478            if(!name) name = wpt->id;
1479    
1480            preset_picker_add(store, appdata, icon, name, cb_cache, id);
1481          }
1482          id++;
1483          wpt = wpt->next;
1484        }
1485      }
1486    
1487      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1488      g_object_unref(store);
1489    
1490      /* make list react on clicks */
1491      g_signal_connect(view, "row-activated",
1492                       (GCallback)on_preset_picker_activated, appdata);
1493    
1494      /* put this inside a scrolled view */
1495    #ifndef USE_PANNABLE_AREA
1496      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1497      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1498                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1499      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1500      return scrolled_window;
1501    #else
1502      GtkWidget *pannable_area = hildon_pannable_area_new();
1503      gtk_container_add(GTK_CONTAINER(pannable_area), view);
1504      return pannable_area;
1505    #endif
1506  }  }
1507    
1508  GtkWidget *coo_popup(appdata_t *appdata,  static gint on_preset_picker_button_press(GtkWidget *button,
1509                       GdkEventButton *event, gpointer data) {
1510      appdata_t *appdata = (appdata_t*)data;
1511    
1512      gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1513      gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1514    
1515      if(event->type == GDK_BUTTON_PRESS) {
1516        GtkWidget *dialog =
1517          gtk_dialog_new_with_buttons(_("Preset coordinates"),
1518              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1519                                      GTK_DIALOG_MODAL,
1520              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1521              NULL);
1522    
1523        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1524    
1525        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1526                            preset_picker_create(appdata, lat_entry, lon_entry));
1527    
1528        gtk_widget_show_all(dialog);
1529        gtk_dialog_run(GTK_DIALOG(dialog));
1530        gtk_widget_destroy(dialog);
1531    
1532        return TRUE;
1533      }
1534      return FALSE;
1535    }
1536    #endif
1537    
1538    
1539    GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1540                       GtkWidget *lat_entry, GtkWidget *lon_entry) {                       GtkWidget *lat_entry, GtkWidget *lon_entry) {
1541    
1542    GtkWidget *button = gtk_button_new();    GtkWidget *button = gtk_button_new();
 #ifdef FREMANTLE  
   hildon_gtk_widget_set_theme_size(button,  
           (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));  
 #endif  
1543    
1544    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, 17));
1545    
1546    gtk_widget_set_tooltip_text(button, _("Preset coordinates"));    gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
1547    
1548      g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1549      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1550    
1551    #ifndef PRESET_PICKER_DIALOG
1552    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1553                       (GtkSignalFunc)on_popup_button_press, appdata);                       (GtkSignalFunc)on_popup_button_press, appdata);
1554    
# Line 709  GtkWidget *coo_popup(appdata_t *appdata, Line 1557  GtkWidget *coo_popup(appdata_t *appdata,
1557    
1558    g_object_set_data(G_OBJECT(button), "menu",    g_object_set_data(G_OBJECT(button), "menu",
1559                      popup_menu_create(appdata, lat_entry, lon_entry));                      popup_menu_create(appdata, lat_entry, lon_entry));
1560    #else
1561    #ifdef FREMANTLE
1562      hildon_gtk_widget_set_theme_size(button,
1563            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1564    #endif
1565    
1566      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1567                         (GtkSignalFunc)on_preset_picker_button_press, appdata);
1568    #endif
1569    
1570    return button;    return button;
1571  }  }
# Line 728  gboolean pos_differ(pos_t *pos1, pos_t * Line 1585  gboolean pos_differ(pos_t *pos1, pos_t *
1585    return((lat1 != lat2) || (lon1 != lon2));    return((lat1 != lat2) || (lon1 != lon2));
1586  }  }
1587    
1588  #ifdef FREMANTLE  gboolean pos_valid(pos_t *pos) {
1589  void selection_changed (HildonTouchSelector * selector,    if(!pos) return FALSE;
1590                     gpointer *user_data) {    return(!isnan(pos->lat) && !isnan(pos->lon));
   gchar *current_selection = NULL;  
   
   current_selection = hildon_touch_selector_get_current_text (selector);  
   g_debug ("Current selection : %s", current_selection);  
1591  }  }
1592    
1593  static GtkWidget *create_customized_selector() {  void misc_init(void) {
1594    GtkWidget *selector = NULL;    g_signal_new ("changed", GTK_TYPE_BUTTON,
1595    GSList *icon_list = NULL;                  G_SIGNAL_RUN_FIRST, 0, NULL, NULL,
1596    GtkListStore *store_icons = NULL;                  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
1597    GSList *item = NULL;  }
   GtkCellRenderer *renderer = NULL;  
   HildonTouchSelectorColumn *column = NULL;  
   
   selector = hildon_touch_selector_new ();  
   
   icon_list = gtk_stock_list_ids ();  
   
   store_icons = gtk_list_store_new (1, G_TYPE_STRING);  
   for (item = icon_list; item; item = g_slist_next (item)) {  
     GtkTreeIter iter;  
     gchar *label = item->data;  
1598    
1599      gtk_list_store_append (store_icons, &iter);  void angle_str(char *str, int len, float angle) {
1600      gtk_list_store_set (store_icons, &iter, 0, label, -1);    snprintf(str, len, _("%.1f°"), angle);
1601      g_free (label);  }
   }  
   g_slist_free (icon_list);  
1602    
1603    renderer = gtk_cell_renderer_pixbuf_new ();  float angle_parse(char *str) {
1604    gtk_cell_renderer_set_fixed_size (renderer, -1, 100);    float val;
1605    
1606    column = hildon_touch_selector_append_column (HILDON_TOUCH_SELECTOR (selector),    if(sscanf(str, _("%f°"), &val) != 1)
1607                                                  GTK_TREE_MODEL (store_icons),      val = NAN;
1608                                                  renderer, "stock-id", 0, NULL);  
1609      return val;
1610    }
1611    
1612    g_object_set (G_OBJECT (column), "text-column", 0, NULL);  #ifndef COORDINATE_PICKER
1613    static void callback_modified_angle(GtkWidget *widget, gpointer data ) {
1614      float i = angle_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
1615      mark(widget, !isnan(i));
1616    }
1617    #else
1618    static gint on_angle_picker_button_press(GtkWidget *button,
1619                       GdkEventButton *event, gpointer data) {
1620    
1621    hildon_touch_selector_set_column_selection_mode (HILDON_TOUCH_SELECTOR (selector),    if(event->type == GDK_BUTTON_PRESS) {
1622                                                     HILDON_TOUCH_SELECTOR_SELECTION_MODE_SINGLE);      GtkWidget *dialog =
1623          gtk_dialog_new_with_buttons(_("Direction"),
1624              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1625                                      GTK_DIALOG_MODAL,
1626              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1627              _("Done"),        GTK_RESPONSE_ACCEPT,
1628              NULL);
1629    
1630        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 210);
1631    
1632        int i, angle = (int)g_object_get_data(G_OBJECT(button), "angle");
1633    
1634        GtkWidget *anglew[3], *fracw;
1635    
1636        /* create xxx.x° */
1637        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
1638    
1639        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1640                    anglew[0] = digit_picker_create(0,3, (angle/1000)%10));
1641        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1642                    anglew[1] = digit_picker_create(0,9, (angle/100)%10));
1643        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1644                    anglew[2] = digit_picker_create(0,9, (angle/10)%10));
1645        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new(" . "), FALSE, FALSE, 0);
1646        gtk_box_pack_start_defaults(GTK_BOX(hbox),
1647                    fracw = digit_picker_create(0,9, (angle/1)%10));
1648        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
1649    
1650        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
1651    
1652    g_signal_connect (G_OBJECT (selector), "changed",      gtk_widget_show_all(dialog);
1653                      G_CALLBACK (selection_changed), NULL);      if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
1654    
1655    return selector;        /* parse angle */
1656  }        for(angle=0,i=0;i<3;i++)
1657            angle = 10 * angle + picker_get(anglew[i]);
1658    
1659  static gint on_picker_request(GtkWidget *button, GdkEventButton *event,        angle = 10 * angle + picker_get(fracw);
                               gpointer data) {  
   
   if(event->type == GDK_BUTTON_PRESS) {  
     GtkWidget *dialog = hildon_picker_dialog_new(NULL);  
     GtkWidget *selector = create_customized_selector();  
     hildon_picker_dialog_set_selector(HILDON_PICKER_DIALOG(dialog),  
                       HILDON_TOUCH_SELECTOR(selector));  
1660    
1661      hildon_touch_selector_set_active(HILDON_TOUCH_SELECTOR (selector), 1, -1);        angle_entry_set(button, angle/10.0);
1662        }
1663    
     gtk_widget_show_all(dialog);  
     gtk_dialog_run(GTK_DIALOG(dialog));  
1664      gtk_widget_destroy(dialog);      gtk_widget_destroy(dialog);
1665    
1666      return TRUE;      return TRUE;
1667    }    }
1668    return FALSE;    return FALSE;
1669  }  }
1670    #endif
1671    
1672  GtkWidget *picker_button_new(void) {  GtkWidget *angle_entry_new(float angle) {
1673    GtkWidget *button;    char str[32];
1674      angle_str(str, sizeof(str), angle);
 #if 1  
   button = gtk_button_new();  
   hildon_gtk_widget_set_theme_size(button,  
           (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));  
1675    
1676    gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));  #ifndef COORDINATE_PICKER
1677      GtkWidget *widget = red_entry_new();
1678    gtk_signal_connect(GTK_OBJECT(button), "button-press-event",    gtk_entry_set_text(GTK_ENTRY(widget), str);
                      (GtkSignalFunc)on_picker_request, NULL);  
1679    
1680      g_signal_connect(G_OBJECT(widget), "changed",
1681                       G_CALLBACK(callback_modified_angle), NULL);
1682  #else  #else
1683    button = hildon_picker_button_new(HILDON_SIZE_AUTO,    GtkWidget *widget = gtk_button_new_with_label(str);
1684                                      HILDON_BUTTON_ARRANGEMENT_VERTICAL);  
1685    #ifdef FREMANTLE
1686    hildon_button_set_title(HILDON_BUTTON(button), "Test");    hildon_gtk_widget_set_theme_size(widget,
1687    hildon_picker_button_set_selector(HILDON_PICKER_BUTTON(button),          (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1688                      HILDON_TOUCH_SELECTOR(create_customized_selector()));  #endif
1689      int angle_int = (int)roundf(angle*10.0);
1690      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1691      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
1692                         (GtkSignalFunc)on_angle_picker_button_press, NULL);
1693  #endif  #endif
1694      return widget;
1695    }
1696    
1697    return button;  float angle_entry_get(GtkWidget *widget) {
1698    #ifndef COORDINATE_PICKER
1699      char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
1700    #else
1701      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
1702    #endif
1703      return angle_parse(p);
1704  }  }
1705    
1706    void angle_entry_set(GtkWidget *widget, float angle) {
1707      char str[32];
1708      angle_str(str, sizeof(str)-1, angle);
1709    #ifndef COORDINATE_PICKER
1710      gtk_entry_set_text(GTK_ENTRY(widget), str);
1711    #else
1712      gtk_button_set_label(GTK_BUTTON(widget), str);
1713      int angle_int = (int)roundf(angle * 10.0);
1714      g_object_set_data(G_OBJECT(widget), "angle", (gpointer)angle_int);
1715      g_signal_emit_by_name(widget, "changed");
1716  #endif  #endif
1717    }
1718    

Legend:
Removed from v.216  
changed lines
  Added in v.223