Diff of /trunk/src/misc.c

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

revision 13 by harbaum, Sat Jun 27 11:09:19 2009 UTC revision 221 by harbaum, Mon Nov 30 21:28:04 2009 UTC
# Line 21  Line 21 
21  #include <string.h>  #include <string.h>
22  #include <ctype.h>  #include <ctype.h>
23    
24    #include <glib.h>
25    #include <glib/gstdio.h>
26    
27  #include "gpxview.h"  #include "gpxview.h"
28    
29    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
30    #include <hildon/hildon-entry.h>
31    #include <hildon/hildon-touch-selector.h>
32    #include <hildon/hildon-picker-button.h>
33    #include <hildon/hildon-picker-dialog.h>
34    #endif
35    
36    float roundf(float x);
37    
38    /* TODO: make coordinate picker support "changed" signal */
39    
40    #ifdef FREMANTLE
41    #define PRESET_PICKER_DIALOG
42    #define COORDINATE_PICKER
43    #endif
44    
45  char strlastchr(char *str) {  char strlastchr(char *str) {
46    return str[strlen(str)]-1;    return str[strlen(str)]-1;
47  }  }
# Line 148  float pos_parse_lon(char *str) { Line 167  float pos_parse_lon(char *str) {
167    
168  const char *pos_get_bearing_str(pos_t from, pos_t to) {  const char *pos_get_bearing_str(pos_t from, pos_t to) {
169    static const char *bear_str[]={    static const char *bear_str[]={
170      "N", "NE", "E", "SE", "S", "SW", "W", "NW" };      "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
171    int idx = (gpx_pos_get_bearing(from, to)+22.5)/45.0;  
172    /* make sure we stay in icon bounds */    float bearing = gpx_pos_get_bearing(from, to);
173    while(idx < 0) idx += 8;    if(!isnan(bearing)) {
174    while(idx > 7) idx -= 8;      int idx = (bearing+22.5)/45.0;
175    return _(bear_str[idx]);      /* make sure we stay in icon bounds */
176        while(idx < 0) idx += 8;
177        while(idx > 7) idx -= 8;
178        return _(bear_str[idx]);
179      }
180    
181      return bear_str[8];  // empty string
182  }  }
183    
184  /* the maemo font size is quite huge, so we adjust some fonts */  /* the maemo font size is quite huge, so we adjust some fonts */
# Line 241  pos_t *get_pos(appdata_t *appdata) { Line 266  pos_t *get_pos(appdata_t *appdata) {
266  }  }
267    
268  void distance_str(char *str, int len, float dist, gboolean imperial) {  void distance_str(char *str, int len, float dist, gboolean imperial) {
269    if(imperial) {    if(isnan(dist))
270        snprintf(str, len, "---");
271      else if(imperial) {
272      /* 1 mil = 1760 yd = 5280 ft ... */      /* 1 mil = 1760 yd = 5280 ft ... */
273      if(dist<0.018)      snprintf(str, len, "%.1f ft", dist*5280.0);      if(dist<0.018)      snprintf(str, len, "%.1f ft", dist*5280.0);
274      else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);      else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
# Line 282  float distance_parse(char *str, gboolean Line 309  float distance_parse(char *str, gboolean
309    return val;    return val;
310  }  }
311    
312    /* ------------------ coordinate picker tool --------------------------- */
313    
314  static gboolean mark(GtkWidget *widget, gboolean valid) {  static gboolean mark(GtkWidget *widget, gboolean valid) {
315    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);    gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
316    return valid;    return valid;
317  }  }
318    
319    #ifndef COORDINATE_PICKER
320  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {  static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
321    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)));
322    mark(widget, !isnan(i));    mark(widget, !isnan(i));
323  }  }
324    #else
325    static GtkWidget *letter_picker_create(char *a, char *b, int sel) {
326    #ifndef FREMANTLE
327      GtkWidget *view = gtk_tree_view_new();
328    #else
329      GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
330    #endif
331    
332      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
333      GtkTreeSelection *selection =
334        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
335    
336      /* --- "char" column --- */
337      GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
338      g_object_set(renderer, "xalign", 0.5, NULL );
339      gtk_tree_view_insert_column_with_attributes(
340          GTK_TREE_VIEW(view), -1, "char", renderer, "text", 0, NULL);
341    
342      GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
343    
344      /* add digits */
345      GtkTreeIter iter_a, iter_b;
346      gtk_list_store_append (store, &iter_a);
347      gtk_list_store_set(store, &iter_a, 0, _(a), 1, 0, -1);
348      gtk_list_store_append (store, &iter_b);
349      gtk_list_store_set(store, &iter_b, 0, _(b), 1, 1, -1);
350    
351      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
352      g_object_unref(store);
353    
354      /* select right character */
355      GtkTreeIter iter = (!sel)?iter_a:iter_b;
356      gtk_tree_selection_select_iter(selection, &iter);
357      GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &iter);
358      gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
359                                   path, NULL, TRUE, 0.5, 0.5);
360      gtk_tree_path_free(path);
361    
362      /* put this inside a scrolled view */
363    #ifndef USE_PANNABLE_AREA
364      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
365      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
366                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
367      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
368      return scrolled_window;
369    #else
370      GtkWidget *pannable_area = hildon_pannable_area_new();
371      gtk_container_add(GTK_CONTAINER(pannable_area), view);
372      return pannable_area;
373    #endif
374    }
375    
376    static int picker_get(GtkWidget *widget) {
377      GtkWidget *view = gtk_bin_get_child(GTK_BIN(widget));
378    
379      GtkTreeSelection *sel =
380        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
381    
382      GtkTreeModel *model;
383      GtkTreeIter iter;
384    
385      /* there should never be an unseletced column. But if */
386      /* it is, we count it as zero */
387      if(!gtk_tree_selection_get_selected(sel, &model, &iter))
388        return 0;
389    
390      int retval = 0;
391      gtk_tree_model_get(model, &iter, 1, &retval, -1);
392      return retval;
393    }
394    
395    
396    static GtkWidget *digit_picker_create(int min, int max, int sel) {
397    #ifndef FREMANTLE
398      GtkWidget *view = gtk_tree_view_new();
399    #else
400      GtkWidget *view = hildon_gtk_tree_view_new(HILDON_UI_MODE_EDIT);
401    #endif
402    
403      gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
404      GtkTreeSelection *selection =
405        gtk_tree_view_get_selection(GTK_TREE_VIEW(view));
406    
407      /* --- "digit" column --- */
408      GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
409      g_object_set(renderer, "xalign", 0.5, NULL );
410      gtk_tree_view_insert_column_with_attributes(
411          GTK_TREE_VIEW(view), -1, "digit", renderer, "text", 0, NULL);
412    
413      GtkListStore *store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_INT);
414    
415      /* add digits */
416      int i;
417      GtkTreeIter siter;
418      for(i=min;i<=max;i++) {
419        char str[2] = { '0'+i, 0 };
420        GtkTreeIter     iter;
421        /* Append a row and fill in some data */
422        gtk_list_store_append (store, &iter);
423        gtk_list_store_set(store, &iter, 0, str, 1, i, -1);
424    
425        if(i == sel) siter = iter;
426      }
427    
428      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
429      g_object_unref(store);
430    
431      gtk_tree_selection_select_iter(selection, &siter);
432      GtkTreePath *path = gtk_tree_model_get_path(GTK_TREE_MODEL(store), &siter);
433      gtk_tree_view_scroll_to_cell(GTK_TREE_VIEW(view),
434                                   path, NULL, TRUE, 0.5, 0.5);
435      gtk_tree_path_free(path);
436    
437      /* put this inside a scrolled view */
438    #ifndef USE_PANNABLE_AREA
439      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
440      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
441                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
442      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
443      return scrolled_window;
444    #else
445      GtkWidget *pannable_area = hildon_pannable_area_new();
446      gtk_container_add(GTK_CONTAINER(pannable_area), view);
447      return pannable_area;
448    #endif
449    }
450    
451    static gint on_lat_picker_button_press(GtkWidget *button,
452                       GdkEventButton *event, gpointer data) {
453    
454      if(event->type == GDK_BUTTON_PRESS) {
455        GtkWidget *dialog =
456          gtk_dialog_new_with_buttons(_("Latitude"),
457              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
458                                      GTK_DIALOG_MODAL,
459              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
460              _("Done"),        GTK_RESPONSE_ACCEPT,
461              NULL);
462    
463        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
464    
465        int i, lat = (int)g_object_get_data(G_OBJECT(button), "latitude");
466    
467        /* parse latitude into components */
468        int sign = (lat>=0)?0:1;
469        lat = abs(lat);
470        int deg = lat / 60000;
471        int min = (lat /1000)%60;
472        int minfrac = lat % 1000;
473    
474        GtkWidget *signw, *degw[2], *minw[2], *minfracw[3];
475    
476    
477        /* create N/S 89° 99.999 */
478        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
479        gtk_box_pack_start_defaults(GTK_BOX(hbox),
480                    signw = letter_picker_create("N","S", sign));
481    
482        gtk_box_pack_start_defaults(GTK_BOX(hbox),
483                    degw[0] = digit_picker_create(0,8, deg/10));
484        gtk_box_pack_start_defaults(GTK_BOX(hbox),
485                    degw[1] = digit_picker_create(0,9, deg%10));
486        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
487    
488        gtk_box_pack_start_defaults(GTK_BOX(hbox),
489                    minw[0] = digit_picker_create(0,5, min/10));
490        gtk_box_pack_start_defaults(GTK_BOX(hbox),
491                    minw[1] = digit_picker_create(0,9, min%10));
492        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
493    
494        gtk_box_pack_start_defaults(GTK_BOX(hbox),
495                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
496        gtk_box_pack_start_defaults(GTK_BOX(hbox),
497                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
498        gtk_box_pack_start_defaults(GTK_BOX(hbox),
499                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
500    
501        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
502    
503        gtk_widget_show_all(dialog);
504        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
505    
506          /* parse N/S */
507          sign = picker_get(signw)?-1:1;
508    
509          /* parse degrees ... */
510          for(deg=0,i=0;i<2;i++)
511            deg = 10 * deg + picker_get(degw[i]);
512    
513          /* ... minutes ... */
514          for(min=0,i=0;i<2;i++)
515            min = 10 * min + picker_get(minw[i]);
516    
517          /* ... and fractions of minutes */
518          for(minfrac=0,i=0;i<3;i++)
519            minfrac = 10 * minfrac + picker_get(minfracw[i]);
520    
521          float latitude = sign * (deg + min/60.0 + minfrac/60000.0);
522          lat_entry_set(button, latitude);
523        }
524    
525        gtk_widget_destroy(dialog);
526    
527        return TRUE;
528      }
529      return FALSE;
530    }
531    #endif
532    
533  /* a entry that is colored red when being "active" */  /* a entry that is colored red when being "active" */
534  GtkWidget *lat_entry_new(float lat) {  GtkWidget *lat_entry_new(float lat) {
535      char str[32];
536      pos_lat_str(str, sizeof(str), lat);
537    
538    #ifndef COORDINATE_PICKER
539    GdkColor color;    GdkColor color;
540    GtkWidget *widget = gtk_entry_new();  
541      GtkWidget *widget = entry_new();
542    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
543    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
544    
   char str[32];  
   pos_lat_str(str, sizeof(str), lat);  
545    gtk_entry_set_text(GTK_ENTRY(widget), str);    gtk_entry_set_text(GTK_ENTRY(widget), str);
546    
547    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
548                     G_CALLBACK(callback_modified_lat), NULL);                     G_CALLBACK(callback_modified_lat), NULL);
549    
550    #else
551      GtkWidget *widget = gtk_button_new_with_label(str);
552    
553    #ifdef FREMANTLE
554      hildon_gtk_widget_set_theme_size(widget,
555            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
556    #endif
557      int lat_int = (int)roundf(lat * 60000);
558      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
559      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
560                         (GtkSignalFunc)on_lat_picker_button_press, NULL);
561    #endif
562    
563    return widget;    return widget;
564  }  }
565    
566    #ifndef COORDINATE_PICKER
567  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {  static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
568    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)));
569    mark(widget, !isnan(i));    mark(widget, !isnan(i));
570  }  }
571    #else
572    static gint on_lon_picker_button_press(GtkWidget *button,
573                       GdkEventButton *event, gpointer data) {
574    
575      if(event->type == GDK_BUTTON_PRESS) {
576        GtkWidget *dialog =
577          gtk_dialog_new_with_buttons(_("Longitude"),
578              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
579                                      GTK_DIALOG_MODAL,
580              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
581              _("Done"),        GTK_RESPONSE_ACCEPT,
582              NULL);
583    
584        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
585    
586        int i, lat = (int)g_object_get_data(G_OBJECT(button), "longitude");
587    
588        /* parse latitude into components */
589        int sign = (lat>=0)?0:1;
590        lat = abs(lat);
591        int deg = lat / 60000;
592        int min = (lat /1000)%60;
593        int minfrac = lat % 1000;
594    
595        GtkWidget *signw, *degw[3], *minw[2], *minfracw[3];
596    
597        /* create E/W 179° 99.999 */
598        GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
599        gtk_box_pack_start_defaults(GTK_BOX(hbox),
600                    signw = letter_picker_create("E","W", sign));
601    
602        gtk_box_pack_start_defaults(GTK_BOX(hbox),
603                    degw[0] = digit_picker_create(0,1, deg/100));
604        gtk_box_pack_start_defaults(GTK_BOX(hbox),
605                    degw[1] = digit_picker_create(0,9, (deg/10)%10));
606        gtk_box_pack_start_defaults(GTK_BOX(hbox),
607                    degw[2] = digit_picker_create(0,9, deg%10));
608        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("°"), FALSE, FALSE, 0);
609    
610        gtk_box_pack_start_defaults(GTK_BOX(hbox),
611                    minw[0] = digit_picker_create(0,5, min/10));
612        gtk_box_pack_start_defaults(GTK_BOX(hbox),
613                    minw[1] = digit_picker_create(0,9, min%10));
614        gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("."), FALSE, FALSE, 0);
615    
616        gtk_box_pack_start_defaults(GTK_BOX(hbox),
617                    minfracw[0] = digit_picker_create(0,9, minfrac/100));
618        gtk_box_pack_start_defaults(GTK_BOX(hbox),
619                    minfracw[1] = digit_picker_create(0,9, (minfrac/10)%10));
620        gtk_box_pack_start_defaults(GTK_BOX(hbox),
621                    minfracw[2] = digit_picker_create(0,9, minfrac%10));
622    
623        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), hbox);
624    
625        gtk_widget_show_all(dialog);
626        if(gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
627    
628          /* parse E/W */
629          sign = picker_get(signw)?-1:1;
630    
631          /* parse degrees ... */
632          for(deg=0,i=0;i<3;i++)
633            deg = 10 * deg + picker_get(degw[i]);
634    
635          /* ... minutes ... */
636          for(min=0,i=0;i<2;i++)
637            min = 10 * min + picker_get(minw[i]);
638    
639          /* ... and fractions of minutes */
640          for(minfrac=0,i=0;i<3;i++)
641            minfrac = 10 * minfrac + picker_get(minfracw[i]);
642    
643          float longitude = sign * (deg + min/60.0 + minfrac/60000.0);
644          lon_entry_set(button, longitude);
645        }
646    
647        gtk_widget_destroy(dialog);
648    
649        return TRUE;
650      }
651      return FALSE;
652    }
653    #endif
654    
655  /* a entry that is colored red when filled with invalid coordinate */  /* a entry that is colored red when filled with invalid coordinate */
656  GtkWidget *lon_entry_new(float lon) {  GtkWidget *lon_entry_new(float lon) {
657      char str[32];
658      pos_lon_str(str, sizeof(str), lon);
659    
660    #ifndef COORDINATE_PICKER
661    GdkColor color;    GdkColor color;
662    GtkWidget *widget = gtk_entry_new();  
663      GtkWidget *widget = entry_new();
664    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
665    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
666    
   char str[32];  
   pos_lon_str(str, sizeof(str), lon);  
667    gtk_entry_set_text(GTK_ENTRY(widget), str);    gtk_entry_set_text(GTK_ENTRY(widget), str);
668    
669    g_signal_connect(G_OBJECT(widget), "changed",    g_signal_connect(G_OBJECT(widget), "changed",
670                     G_CALLBACK(callback_modified_lon), NULL);                     G_CALLBACK(callback_modified_lon), NULL);
671    
672    #else
673      GtkWidget *widget = gtk_button_new_with_label(str);
674    
675    #ifdef FREMANTLE
676      hildon_gtk_widget_set_theme_size(widget,
677            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
678    #endif
679      int lon_int = (int)roundf(lon * 60000);
680      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
681      gtk_signal_connect(GTK_OBJECT(widget), "button-press-event",
682                         (GtkSignalFunc)on_lon_picker_button_press, NULL);
683    #endif
684    
685    return widget;    return widget;
686  }  }
687    
688    float lat_entry_get(GtkWidget *widget) {
689  float lat_get(GtkWidget *widget) {  #ifndef COORDINATE_PICKER
690    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
691    #else
692      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
693    #endif
694    return pos_parse_lat(p);    return pos_parse_lat(p);
695  }  }
696    
697  float lon_get(GtkWidget *widget) {  float lon_entry_get(GtkWidget *widget) {
698    #ifndef COORDINATE_PICKER
699    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));    char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
700    #else
701      char *p = (char*)gtk_button_get_label(GTK_BUTTON(widget));
702    #endif
703    return pos_parse_lon(p);    return pos_parse_lon(p);
704  }  }
705    
706    void lat_entry_set(GtkWidget *widget, float lat) {
707      char str[32];
708      pos_lat_str(str, sizeof(str)-1, lat);
709    #ifndef COORDINATE_PICKER
710      gtk_entry_set_text(GTK_ENTRY(widget), str);
711    #else
712      gtk_button_set_label(GTK_BUTTON(widget), str);
713      int lat_int = (int)roundf(lat * 60000);
714      g_object_set_data(G_OBJECT(widget), "latitude", (gpointer)lat_int);
715    #endif
716    }
717    
718    void lon_entry_set(GtkWidget *widget, float lon) {
719      char str[32];
720      pos_lon_str(str, sizeof(str)-1, lon);
721    #ifndef COORDINATE_PICKER
722      gtk_entry_set_text(GTK_ENTRY(widget), str);
723    #else
724      gtk_button_set_label(GTK_BUTTON(widget), str);
725      int lon_int = (int)roundf(lon * 60000);
726      g_object_set_data(G_OBJECT(widget), "longitude", (gpointer)lon_int);
727    #endif
728    }
729    
730    void lat_label_set(GtkWidget *widget, float lat) {
731      char str[32];
732      pos_lat_str(str, sizeof(str)-1, lat);
733      gtk_label_set(GTK_LABEL(widget), str);
734    }
735    
736    void lon_label_set(GtkWidget *widget, float lon) {
737      char str[32];
738      pos_lon_str(str, sizeof(str)-1, lon);
739      gtk_label_set(GTK_LABEL(widget), str);
740    }
741    
742    void lat_label_attrib_set(GtkWidget *widget, float lat,
743                              int size, int strikethrough) {
744      char str[32];
745      pos_lat_str(str, sizeof(str)-1, lat);
746      gtk_label_attrib_set(widget, str, size, strikethrough);
747    }
748    
749    void lon_label_attrib_set(GtkWidget *widget, float lon,
750                              int size, int strikethrough) {
751      char str[32];
752      pos_lon_str(str, sizeof(str)-1, lon);
753      gtk_label_attrib_set(widget, str, size, strikethrough);
754    }
755    
756  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {  static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
757    /* 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 */
758    /* is parseable at all */    /* is parseable at all */
# Line 352  static void callback_modified_dist(GtkWi Line 763  static void callback_modified_dist(GtkWi
763  /* a entry that is colored red when filled with invalid distance */  /* a entry that is colored red when filled with invalid distance */
764  GtkWidget *dist_entry_new(float dist, gboolean mil) {  GtkWidget *dist_entry_new(float dist, gboolean mil) {
765    GdkColor color;    GdkColor color;
766    GtkWidget *widget = gtk_entry_new();    GtkWidget *widget = entry_new();
767    gdk_color_parse("#ff0000", &color);    gdk_color_parse("#ff0000", &color);
768    gtk_widget_modify_text(widget, TAG_STATE, &color);    gtk_widget_modify_text(widget, TAG_STATE, &color);
769    
# Line 383  int browser_url(appdata_t *appdata, char Line 794  int browser_url(appdata_t *appdata, char
794  }  }
795  #endif  #endif
796  #endif  #endif
797    
798    /* recursively remove an entire file system */
799    void rmdir_recursive(char *path) {
800      GDir *dir = g_dir_open(path, 0, NULL);
801      if(dir) {
802        const char *name = g_dir_read_name(dir);
803        while(name) {
804          char *fullname = g_strdup_printf("%s/%s", path, name);
805          //      printf("deleting %s\n", fullname);
806    
807          if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
808            rmdir_recursive(fullname);
809          else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
810            g_remove(fullname);
811    
812          g_free(fullname);
813          name = g_dir_read_name(dir);
814        }
815    
816        g_dir_close(dir);
817      }
818      g_rmdir(path);
819    }
820    
821    #ifdef ENABLE_BROWSER_INTERFACE
822    static void on_link_clicked(GtkButton *button, gpointer data) {
823      appdata_t *appdata = (appdata_t*)data;
824      char *url = g_object_get_data(G_OBJECT(button), "url");
825      if(url) browser_url(appdata, url);
826    }
827    #endif
828    
829    /* a button containing a weblink */
830    GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
831                           int size, int strikethrough) {
832    
833    #ifdef ENABLE_BROWSER_INTERFACE
834      if(url) {
835        GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
836        g_object_set_data(G_OBJECT(button), "url", url);
837        gtk_signal_connect(GTK_OBJECT(button), "clicked",
838                           (GtkSignalFunc)on_link_clicked, appdata);
839    
840        return button;
841      }
842    #endif
843      return gtk_label_attrib(str, size, strikethrough);
844    }
845    
846    #ifdef ENABLE_BROWSER_INTERFACE
847    static void on_link_id_clicked(GtkButton *button, gpointer data) {
848      appdata_t *appdata = (appdata_t*)data;
849    
850      unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
851      char *type = g_object_get_data(G_OBJECT(button), "type");
852    
853      char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
854                                  type, id);
855    
856      if(url) {
857        browser_url(appdata, url);
858        g_free(url);
859      }
860    }
861    #endif
862    
863    GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
864                                 const char *type, int id) {
865    
866    #ifdef ENABLE_BROWSER_INTERFACE
867      if(id) {
868        GtkWidget *ref = gtk_button_new_with_label(str);
869    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
870        //    hildon_gtk_widget_set_theme_size(ref,
871        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
872    #endif
873        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
874        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
875        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
876                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
877    
878        return ref;
879      }
880    #endif
881      return gtk_label_new(str);
882    }
883    
884    
885    GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
886                                 const char *type, int id) {
887    
888    #ifdef ENABLE_BROWSER_INTERFACE
889      if(id) {
890        GtkWidget *ref = gtk_button_new();
891        gtk_button_set_image(GTK_BUTTON(ref), icon);
892    
893    #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
894        //    hildon_gtk_widget_set_theme_size(ref,
895        //         (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
896    #endif
897        g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
898        g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
899        gtk_signal_connect(GTK_OBJECT(ref), "clicked",
900                           GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
901    
902        return ref;
903      }
904    #endif
905      return icon;
906    }
907    
908    /* left aligned, word wrapped multiline widget */
909    GtkWidget *simple_text_widget(char *text) {
910      GtkWidget *label = gtk_label_new(text);
911    
912      gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
913      gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
914      gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
915    
916      return label;
917    }
918    
919    
920    /* a label that is left aligned */
921    GtkWidget *left_label_new(char *str) {
922      GtkWidget *widget = gtk_label_new(str);
923      gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
924      return widget;
925    }
926    
927    /* ------------- preset coordinate picker tool ----------------- */
928    
929    static void pos_set(GtkWidget *item, float lat, float lon) {
930    
931      GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
932      lat_entry_set(lat_entry, lat);
933    
934      GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
935      lon_entry_set(lon_entry, lon);
936    }
937    
938    static void cb_gps(GtkWidget *item, gpointer data) {
939      appdata_t *appdata = (appdata_t*)data;
940      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
941      pos_t *pos = NULL;
942    
943      if(!id)
944        pos = gps_get_pos(appdata);
945      else if(id == 1)
946        pos = &appdata->home;
947      else {
948        location_t *location = appdata->location;
949        while(location && id > 2) {
950          location = location->next;
951          id--;
952        }
953    
954        if(id == 2)
955          pos = &location->pos;
956      }
957    
958      if(!pos) pos_set(item, NAN, NAN);
959      else     pos_set(item, pos->lat, pos->lon);
960    }
961    
962    static void cb_geomath(GtkWidget *item, gpointer data) {
963      appdata_t *appdata = (appdata_t*)data;
964    
965      pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
966    }
967    
968    #ifdef ENABLE_OSM_GPS_MAP
969    static void cb_map(GtkWidget *item, gpointer data) {
970      appdata_t *appdata = (appdata_t*)data;
971    
972      pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
973    }
974    #endif
975    
976    static void cb_cache(GtkWidget *item, gpointer data) {
977      appdata_t *appdata = (appdata_t*)data;
978    
979      cache_t *cache = appdata->cur_cache;
980      g_assert(cache);
981    
982      gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
983    
984      if(!id)
985        pos_set(item, cache->pos.lat, cache->pos.lon);
986      else if(id == 1)
987        pos_set(item, cache->notes->pos.lat, cache->notes->pos.lon);
988      else {
989        wpt_t *wpt = cache->wpt;
990        while(wpt && id > 2) {
991          wpt = wpt->next;
992          id--;
993        }
994    
995        if(id == 2)
996          pos_set(item, wpt->pos.lat, wpt->pos.lon);
997      }
998    }
999    
1000    #ifndef PRESET_PICKER_DIALOG
1001    static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
1002                               GtkWidget *icon, char *menu_str,
1003                               void(*func)(GtkWidget*, gpointer), gint id,
1004                               GtkWidget *lon_entry, GtkWidget *lat_entry) {
1005    
1006      GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
1007    
1008      if(icon)
1009        gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
1010    
1011      g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
1012      g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
1013      g_object_set_data(G_OBJECT(item), "id", (gpointer)id);
1014    
1015      if(func)
1016        gtk_signal_connect(GTK_OBJECT(item), "activate",
1017                           (GtkSignalFunc)func, appdata);
1018    
1019      gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
1020    
1021      return item;
1022    }
1023    
1024    static GtkWidget *popup_menu_create(appdata_t *appdata,
1025                        GtkWidget *lat_entry, GtkWidget *lon_entry) {
1026      GtkWidget *menu = gtk_menu_new();
1027    
1028      menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
1029               _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
1030    
1031      menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1032               _("Home"), cb_gps, 1, lon_entry, lat_entry);
1033    
1034      location_t *location = appdata->location;
1035      gint id = 2;
1036      while(location) {
1037        menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
1038                   location->name, cb_gps, id++, lon_entry, lat_entry);
1039    
1040        location = location->next;
1041      }
1042    
1043      menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
1044               _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
1045    #ifdef ENABLE_OSM_GPS_MAP
1046      menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
1047               _("Map position"), cb_map, 0, lon_entry, lat_entry);
1048    #endif
1049    
1050      if(appdata->cur_cache) {
1051        cache_t *cache = appdata->cur_cache;
1052    
1053        char *name = cache->name;
1054        if(!name) name = cache->id;
1055    
1056        /* original cache position */
1057        if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
1058          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1059                   name, cb_cache, 0, lon_entry, lat_entry);
1060        }
1061    
1062        /* overwritten cache position */
1063        if(cache->notes &&
1064           !isnan(cache->notes->pos.lat) && !isnan(cache->notes->pos.lon)) {
1065          menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
1066                   _("Modified coordinate"), cb_cache, 1, lon_entry, lat_entry);
1067        }
1068    
1069        wpt_t *wpt = cache->wpt;
1070        gint id = 2;
1071        while(wpt) {
1072          GtkWidget *icon = NULL;
1073          if(wpt->sym != WPT_SYM_UNKNOWN)
1074            icon = icon_get_widget(ICON_POS, wpt->sym);
1075    
1076          char *name = wpt->desc;
1077          if(!name) name = wpt->cmt;
1078          if(!name) name = wpt->id;
1079    
1080          menu_add(menu, appdata, icon, name, cb_cache, id++,
1081                   lon_entry, lat_entry);
1082    
1083          wpt = wpt->next;
1084        }
1085      }
1086    
1087      gtk_widget_show_all(menu);
1088    
1089      return menu;
1090    }
1091    
1092    static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
1093                                      gpointer data) {
1094    
1095      if(event->type == GDK_BUTTON_PRESS) {
1096        GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
1097    
1098        /* draw a popup menu */
1099        gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
1100                       event->button, event->time);
1101        return TRUE;
1102      }
1103      return FALSE;
1104    }
1105    
1106    static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
1107      GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1108      gtk_widget_destroy(menu);
1109    }
1110    #endif
1111    
1112    #ifdef PRESET_PICKER_DIALOG
1113    
1114    enum {
1115      PRESET_PICKER_COL_ICON = 0,
1116      PRESET_PICKER_COL_NAME,
1117      PRESET_PICKER_COL_ID,
1118      PRESET_PICKER_COL_CB,
1119      PRESET_PICKER_NUM_COLS
1120    };
1121    
1122    static void preset_picker_add(GtkListStore *store,  appdata_t *appdata,
1123                           GdkPixbuf *icon, char *menu_str,
1124                           void(*func)(GtkWidget*, gpointer), gint id) {
1125      GtkTreeIter     iter;
1126    
1127      /* Append a row and fill in some data */
1128      gtk_list_store_append (store, &iter);
1129    
1130      gtk_list_store_set(store, &iter,
1131                         PRESET_PICKER_COL_ICON, icon,
1132                         PRESET_PICKER_COL_NAME, menu_str,
1133                         PRESET_PICKER_COL_ID, id,
1134                         PRESET_PICKER_COL_CB, func,
1135                         -1);
1136    }
1137    
1138    static void on_preset_picker_activated(GtkTreeView        *treeview,
1139                                    GtkTreePath        *path,
1140                                    GtkTreeViewColumn  *col,
1141                                    gpointer            userdata) {
1142      GtkTreeIter   iter;
1143      GtkTreeModel *model = gtk_tree_view_get_model(treeview);
1144    
1145      if(gtk_tree_model_get_iter(model, &iter, path)) {
1146        gint id;
1147        void(*func)(GtkWidget*, gpointer);
1148        gtk_tree_model_get(model, &iter,
1149                           PRESET_PICKER_COL_ID, &id,
1150                           PRESET_PICKER_COL_CB, &func,
1151                           -1);
1152    
1153        /* set id on widget as callbacks expect it this way */
1154        g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
1155        func(GTK_WIDGET(treeview), userdata);
1156    
1157        gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
1158                        GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
1159    
1160      }
1161    }
1162    
1163    static GtkWidget *preset_picker_create(appdata_t *appdata,
1164                                    GtkWidget *lat_entry, GtkWidget *lon_entry) {
1165      GtkCellRenderer *renderer;
1166      GtkListStore    *store;
1167    
1168      GtkWidget *view = gtk_tree_view_new();
1169    
1170      g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
1171      g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
1172    
1173      /* --- "Icon" column --- */
1174      renderer = gtk_cell_renderer_pixbuf_new();
1175      gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
1176          -1, "Icon", renderer, "pixbuf", PRESET_PICKER_COL_ICON, NULL);
1177    
1178      /* --- "Name" column --- */
1179      renderer = gtk_cell_renderer_text_new();
1180      g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
1181      GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
1182                     "Name", renderer, "text", PRESET_PICKER_COL_NAME, NULL);
1183      gtk_tree_view_column_set_expand(column, TRUE);
1184      gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
1185    
1186      store = gtk_list_store_new(PRESET_PICKER_NUM_COLS,
1187                                 GDK_TYPE_PIXBUF,
1188                                 G_TYPE_STRING,
1189                                 G_TYPE_INT,
1190                                 G_TYPE_POINTER);
1191    
1192      preset_picker_add(store, appdata, icon_get(ICON_POS, 18),
1193                 _("GPS position"), cb_gps, 0);
1194    
1195      preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1196                 _("Home"), cb_gps, 1);
1197    
1198      location_t *location = appdata->location;
1199      gint id = 2;
1200      while(location) {
1201        preset_picker_add(store, appdata, icon_get(ICON_POS, 21),
1202                   location->name, cb_gps, id++);
1203    
1204        location = location->next;
1205      }
1206    
1207      preset_picker_add(store, appdata, icon_get(ICON_POS, 19),
1208                 _("Geomath projection"), cb_geomath, 0);
1209    #ifdef ENABLE_OSM_GPS_MAP
1210      preset_picker_add(store, appdata, icon_get(ICON_POS, 20),
1211                 _("Map position"), cb_map, 0);
1212    #endif
1213    
1214      if(appdata->cur_cache) {
1215        cache_t *cache = appdata->cur_cache;
1216    
1217        char *name = cache->name;
1218        if(!name) name = cache->id;
1219    
1220        /* original cache position */
1221        if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
1222          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1223                     name, cb_cache, 0);
1224        }
1225    
1226        /* overwritten cache position */
1227        if(cache->notes &&
1228           !isnan(cache->notes->pos.lat) && !isnan(cache->notes->pos.lon)) {
1229          preset_picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
1230                     _("Modified coordinate"), cb_cache, 1);
1231        }
1232    
1233        wpt_t *wpt = cache->wpt;
1234        gint id = 2;
1235        while(wpt) {
1236          GdkPixbuf *icon = NULL;
1237          if(wpt->sym != WPT_SYM_UNKNOWN)
1238            icon = icon_get(ICON_POS, wpt->sym);
1239    
1240          char *name = wpt->desc;
1241          if(!name) name = wpt->cmt;
1242          if(!name) name = wpt->id;
1243    
1244          preset_picker_add(store, appdata, icon, name, cb_cache, id++);
1245          wpt = wpt->next;
1246        }
1247      }
1248    
1249    
1250      gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
1251      g_object_unref(store);
1252    
1253      /* make list react on clicks */
1254      g_signal_connect(view, "row-activated",
1255                       (GCallback)on_preset_picker_activated, appdata);
1256    
1257      /* put this inside a scrolled view */
1258    #ifndef USE_PANNABLE_AREA
1259      GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
1260      gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
1261                                     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
1262      gtk_container_add(GTK_CONTAINER(scrolled_window), view);
1263      return scrolled_window;
1264    #else
1265      GtkWidget *pannable_area = hildon_pannable_area_new();
1266      gtk_container_add(GTK_CONTAINER(pannable_area), view);
1267      return pannable_area;
1268    #endif
1269    }
1270    
1271    static gint on_preset_picker_button_press(GtkWidget *button,
1272                       GdkEventButton *event, gpointer data) {
1273      appdata_t *appdata = (appdata_t*)data;
1274    
1275      gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
1276      gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
1277    
1278      if(event->type == GDK_BUTTON_PRESS) {
1279        GtkWidget *dialog =
1280          gtk_dialog_new_with_buttons(_("Preset coordinates"),
1281              GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
1282                                      GTK_DIALOG_MODAL,
1283              GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1284              NULL);
1285    
1286        gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
1287    
1288        gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1289                            preset_picker_create(appdata, lat_entry, lon_entry));
1290    
1291        gtk_widget_show_all(dialog);
1292        gtk_dialog_run(GTK_DIALOG(dialog));
1293        gtk_widget_destroy(dialog);
1294    
1295        return TRUE;
1296      }
1297      return FALSE;
1298    }
1299    #endif
1300    
1301    void preset_coordinate_picker_update(appdata_t *appdata, GtkWidget *widget) {
1302    #ifndef PRESET_PICKER_DIALOG
1303      printf("updating popup menu\n");
1304    
1305      GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
1306      g_assert(menu);
1307      gtk_widget_destroy(menu);
1308    
1309      gpointer lat_entry = g_object_get_data(G_OBJECT(widget), "lat_entry");
1310      g_assert(lat_entry);
1311      gpointer lon_entry = g_object_get_data(G_OBJECT(widget), "lon_entry");
1312      g_assert(lon_entry);
1313    
1314      menu = popup_menu_create(appdata, lat_entry, lon_entry);
1315      g_object_set_data(G_OBJECT(widget), "menu", (gpointer)menu);
1316    #endif
1317    }
1318    
1319    GtkWidget *preset_coordinate_picker(appdata_t *appdata,
1320                         GtkWidget *lat_entry, GtkWidget *lon_entry) {
1321    
1322      GtkWidget *button = gtk_button_new();
1323    
1324      gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));
1325    
1326      gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
1327    
1328      g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1329      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1330    
1331      g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
1332      g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
1333    
1334    #ifndef PRESET_PICKER_DIALOG
1335      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1336                         (GtkSignalFunc)on_popup_button_press, appdata);
1337    
1338      gtk_signal_connect(GTK_OBJECT(button), "destroy",
1339                         (GtkSignalFunc)on_popup_destroy, appdata);
1340    
1341      g_object_set_data(G_OBJECT(button), "menu",
1342                        popup_menu_create(appdata, lat_entry, lon_entry));
1343    #else
1344    #ifdef FREMANTLE
1345      hildon_gtk_widget_set_theme_size(button,
1346            (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
1347    #endif
1348    
1349      gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
1350                         (GtkSignalFunc)on_preset_picker_button_press, appdata);
1351    #endif
1352    
1353      return button;
1354    }
1355    
1356    GtkWidget *entry_new(void) {
1357    #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
1358      return gtk_entry_new();
1359    #else
1360      return hildon_entry_new(HILDON_SIZE_AUTO);
1361    #endif
1362    }
1363    
1364    gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
1365      int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
1366      int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
1367    
1368      return((lat1 != lat2) || (lon1 != lon2));
1369    }
1370    

Legend:
Removed from v.13  
changed lines
  Added in v.221