Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 218 - (hide annotations)
Fri Nov 27 08:58:48 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 26552 byte(s)
More unified coordinate sources
1 harbaum 1 /*
2     * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3     *
4     * This file is part of GPXView.
5     *
6     * GPXView is free software: you can redistribute it and/or modify
7     * it under the terms of the GNU General Public License as published by
8     * the Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * GPXView is distributed in the hope that it will be useful,
12     * but WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14     * GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License
17     * along with GPXView. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20     #include <math.h>
21     #include <string.h>
22     #include <ctype.h>
23    
24 harbaum 77 #include <glib.h>
25     #include <glib/gstdio.h>
26    
27 harbaum 1 #include "gpxview.h"
28    
29 harbaum 190 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
30     #include <hildon/hildon-entry.h>
31 harbaum 216 #include <hildon/hildon-touch-selector.h>
32     #include <hildon/hildon-picker-button.h>
33     #include <hildon/hildon-picker-dialog.h>
34 harbaum 190 #endif
35    
36 harbaum 217 #ifdef FREMANTLE
37     #define PICKER_DIALOG
38     #endif
39    
40 harbaum 1 char strlastchr(char *str) {
41     return str[strlen(str)]-1;
42     }
43    
44     /* make sure the entire path "dir" exists and create it if not */
45     int checkdir(char *dir) {
46     struct stat filestat;
47     char *p = dir, tmp;
48    
49     /* don't try to create root dir */
50     if(p[0] == '/') p++;
51    
52     do {
53     while(*p && *p != '/') p++;
54     tmp = *p;
55     *p = 0;
56    
57     int err = stat(dir, &filestat);
58     if(err) {
59     if(mkdir(dir, S_IRWXU) != 0) {
60     perror("mkdir()");
61     *p++ = tmp;
62     return -1;
63     }
64     } else {
65     if(!filestat.st_mode & S_IFDIR) {
66     printf("File %s exists and is _no_ directory\n", dir);
67     *p++ = tmp;
68     return -1;
69     }
70     }
71    
72     *p++ = tmp;
73     } while(tmp && strchr(p, '/'));
74    
75     return 0;
76     }
77    
78     void pos_lat_str(char *str, int len, float latitude) {
79     char *c = _("N");
80     float integral, fractional;
81    
82 harbaum 13 if(isnan(latitude))
83     str[0] = 0;
84     else {
85     if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
86     fractional = modff(latitude, &integral);
87 harbaum 1
88 harbaum 13 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
89     }
90 harbaum 1 }
91    
92     GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
93     char str[32];
94    
95     pos_lat_str(str, sizeof(str), latitude);
96     return gtk_label_attrib(str, size, strikethrough);
97     }
98    
99     void pos_lon_str(char *str, int len, float longitude) {
100     char *c = _("E");
101     float integral, fractional;
102    
103 harbaum 13 if(isnan(longitude))
104     str[0] = 0;
105     else {
106     if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
107     fractional = modff(longitude, &integral);
108 harbaum 1
109 harbaum 13 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
110     }
111 harbaum 1 }
112    
113     GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
114     char str[32];
115    
116     pos_lon_str(str, sizeof(str), longitude);
117     return gtk_label_attrib(str, size, strikethrough);
118     }
119    
120     float pos_parse_lat(char *str) {
121     int integral_int;
122     float fractional;
123     char c;
124    
125     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
126     c = toupper(c);
127    
128     if(c != 'S' && c != 'N')
129     return NAN;
130    
131     /* prevent -0.0 */
132     if(!integral_int && (fractional == 0.0))
133     return 0.0;
134    
135     return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
136     }
137    
138     return NAN;
139     }
140    
141     float pos_parse_lon(char *str) {
142     int integral_int;
143     float fractional;
144     char c;
145    
146     if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
147     c = toupper(c);
148    
149     /* O is german "Ost" for "East" */
150     if(c != 'E' && c != 'W' && c != 'O')
151     return NAN;
152    
153     /* prevent -0.0 */
154     if(!integral_int && (fractional == 0.0))
155     return 0.0;
156    
157     return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
158     }
159    
160     return NAN;
161     }
162    
163     const char *pos_get_bearing_str(pos_t from, pos_t to) {
164     static const char *bear_str[]={
165 harbaum 185 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
166    
167     float bearing = gpx_pos_get_bearing(from, to);
168     if(!isnan(bearing)) {
169     int idx = (bearing+22.5)/45.0;
170     /* make sure we stay in icon bounds */
171     while(idx < 0) idx += 8;
172     while(idx > 7) idx -= 8;
173     return _(bear_str[idx]);
174     }
175    
176     return bear_str[8]; // empty string
177 harbaum 1 }
178    
179     /* the maemo font size is quite huge, so we adjust some fonts */
180     /* differently on maemo and non-maemo. Basically "BIG" does nothing */
181     /* on maemo and "SMALL" only does something on maemo */
182     #ifdef USE_MAEMO
183     #define MARKUP_SMALL "<span size='small'>%s</span>"
184     GtkWidget *gtk_label_small(char *str) {
185     GtkWidget *label = gtk_label_new("");
186     char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
187     gtk_label_set_markup(GTK_LABEL(label), markup);
188     g_free(markup);
189     return label;
190     }
191     #else
192     #define MARKUP_BIG "<span size='x-large'>%s</span>"
193     GtkWidget *gtk_label_big(char *str) {
194     GtkWidget *label = gtk_label_new("");
195     char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
196     gtk_label_set_markup(GTK_LABEL(label), markup);
197     g_free(markup);
198     return label;
199     }
200     #endif
201    
202     void gtk_label_attrib_set(GtkWidget *label,
203     char *str, int size, int strikethrough) {
204     char format[80];
205    
206     snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
207     #ifdef USE_MAEMO
208     (size==SIZE_SMALL)?" size='small'":"",
209     #else
210     (size==SIZE_BIG)?" size='x-large'":"",
211     #endif
212     strikethrough?" strikethrough='yes'":"",
213     (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
214    
215     char *markup = g_markup_printf_escaped(format, str);
216     // printf("markup = %s\n", markup);
217     gtk_label_set_markup(GTK_LABEL(label), markup);
218     g_free(markup);
219     }
220    
221     GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
222     GtkWidget *label = gtk_label_new("");
223     gtk_label_attrib_set(label, str, size, strikethrough);
224     return label;
225     }
226    
227     GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
228     GtkWidget *button = gtk_button_new_with_label("");
229     gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
230     str, size, strikethrough);
231     return button;
232     }
233    
234     void textbox_disable(GtkWidget *widget) {
235     gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
236     gtk_widget_set_sensitive(widget, FALSE);
237     }
238    
239     void textbox_enable(GtkWidget *widget) {
240     gtk_widget_set_sensitive(widget, TRUE);
241     gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
242     }
243    
244     pos_t *get_pos(appdata_t *appdata) {
245     pos_t *pos = &appdata->home;
246    
247     if(appdata->active_location) {
248     int i = appdata->active_location-1;
249     location_t *loc = appdata->location;
250     while(i--) loc = loc->next;
251     pos = &loc->pos;
252     }
253    
254     if(appdata->use_gps) {
255     pos = gps_get_pos(appdata);
256    
257     if(!pos) pos = &appdata->gps; /* use saved position */
258     else appdata->gps = *pos; /* save position */
259     }
260     return pos;
261     }
262    
263     void distance_str(char *str, int len, float dist, gboolean imperial) {
264 harbaum 34 if(isnan(dist))
265     snprintf(str, len, "---");
266     else if(imperial) {
267 harbaum 1 /* 1 mil = 1760 yd = 5280 ft ... */
268     if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
269     else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
270     else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
271     else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
272     else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
273     else snprintf(str, len, "%.0f mi", dist);
274     } else {
275     if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
276     else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
277     else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
278     else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
279     else snprintf(str, len, "%.0f km", dist);
280     }
281     }
282    
283     /* return distance in miles or kilometers */
284     float distance_parse(char *str, gboolean imperial) {
285     char unit[4];
286     float val = NAN;
287    
288     if(sscanf(str, "%f %3s", &val, unit) == 2) {
289     gboolean fimp = FALSE;
290    
291     if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
292     else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
293     else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
294     else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
295     else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
296     else val = NAN;
297    
298     /* found imperial and metric requested? convert miles into kilometers */
299     if(fimp & !imperial) val *= 1.609344;
300    
301     /* found metric and imperial requested? convert kilometers into miles */
302     if(!fimp & imperial) val /= 1.609344;
303     }
304     return val;
305     }
306    
307     static gboolean mark(GtkWidget *widget, gboolean valid) {
308     gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
309     return valid;
310     }
311    
312     static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
313     float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
314     mark(widget, !isnan(i));
315     }
316    
317     /* a entry that is colored red when being "active" */
318     GtkWidget *lat_entry_new(float lat) {
319     GdkColor color;
320 harbaum 190
321 harbaum 212 GtkWidget *widget = entry_new();
322 harbaum 1 gdk_color_parse("#ff0000", &color);
323     gtk_widget_modify_text(widget, TAG_STATE, &color);
324    
325     char str[32];
326     pos_lat_str(str, sizeof(str), lat);
327     gtk_entry_set_text(GTK_ENTRY(widget), str);
328    
329     g_signal_connect(G_OBJECT(widget), "changed",
330     G_CALLBACK(callback_modified_lat), NULL);
331    
332     return widget;
333     }
334    
335     static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
336     float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
337     mark(widget, !isnan(i));
338     }
339    
340     /* a entry that is colored red when filled with invalid coordinate */
341     GtkWidget *lon_entry_new(float lon) {
342     GdkColor color;
343 harbaum 190
344 harbaum 212 GtkWidget *widget = entry_new();
345 harbaum 190 // gtk_entry_set_width_chars(GTK_ENTRY(widget), 14);
346    
347 harbaum 1 gdk_color_parse("#ff0000", &color);
348     gtk_widget_modify_text(widget, TAG_STATE, &color);
349    
350     char str[32];
351     pos_lon_str(str, sizeof(str), lon);
352     gtk_entry_set_text(GTK_ENTRY(widget), str);
353    
354     g_signal_connect(G_OBJECT(widget), "changed",
355     G_CALLBACK(callback_modified_lon), NULL);
356    
357     return widget;
358     }
359    
360    
361     float lat_get(GtkWidget *widget) {
362     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
363     return pos_parse_lat(p);
364     }
365    
366     float lon_get(GtkWidget *widget) {
367     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
368     return pos_parse_lon(p);
369     }
370    
371     static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
372     /* don't care for metric/imperial since we only want to know if this */
373     /* is parseable at all */
374     float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
375     mark(widget, !isnan(i));
376     }
377    
378     /* a entry that is colored red when filled with invalid distance */
379     GtkWidget *dist_entry_new(float dist, gboolean mil) {
380     GdkColor color;
381 harbaum 212 GtkWidget *widget = entry_new();
382 harbaum 1 gdk_color_parse("#ff0000", &color);
383     gtk_widget_modify_text(widget, TAG_STATE, &color);
384    
385     char str[32];
386     distance_str(str, sizeof(str), dist, mil);
387     gtk_entry_set_text(GTK_ENTRY(widget), str);
388    
389     g_signal_connect(G_OBJECT(widget), "changed",
390     G_CALLBACK(callback_modified_dist), NULL);
391    
392     return widget;
393     }
394    
395     float dist_get(GtkWidget *widget, gboolean mil) {
396     char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
397     return distance_parse(p, mil);
398     }
399    
400     #ifndef USE_MAEMO
401     #ifdef ENABLE_BROWSER_INTERFACE
402     #include <libgnome/gnome-url.h>
403    
404     int browser_url(appdata_t *appdata, char *url) {
405     /* taken from gnome-open, part of libgnome */
406     GError *err = NULL;
407     gnome_url_show(url, &err);
408     return 0;
409     }
410     #endif
411     #endif
412 harbaum 77
413     /* recursively remove an entire file system */
414     void rmdir_recursive(char *path) {
415     GDir *dir = g_dir_open(path, 0, NULL);
416     if(dir) {
417     const char *name = g_dir_read_name(dir);
418     while(name) {
419     char *fullname = g_strdup_printf("%s/%s", path, name);
420     // printf("deleting %s\n", fullname);
421    
422     if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
423     rmdir_recursive(fullname);
424     else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
425     g_remove(fullname);
426    
427     g_free(fullname);
428     name = g_dir_read_name(dir);
429     }
430    
431     g_dir_close(dir);
432     }
433     g_rmdir(path);
434     }
435    
436 harbaum 137 #ifdef ENABLE_BROWSER_INTERFACE
437     static void on_link_clicked(GtkButton *button, gpointer data) {
438     appdata_t *appdata = (appdata_t*)data;
439     char *url = g_object_get_data(G_OBJECT(button), "url");
440     if(url) browser_url(appdata, url);
441     }
442     #endif
443    
444     /* a button containing a weblink */
445     GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
446     int size, int strikethrough) {
447    
448     #ifdef ENABLE_BROWSER_INTERFACE
449     if(url) {
450     GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
451     g_object_set_data(G_OBJECT(button), "url", url);
452     gtk_signal_connect(GTK_OBJECT(button), "clicked",
453     (GtkSignalFunc)on_link_clicked, appdata);
454    
455     return button;
456     }
457     #endif
458     return gtk_label_attrib(str, size, strikethrough);
459     }
460    
461     #ifdef ENABLE_BROWSER_INTERFACE
462     static void on_link_id_clicked(GtkButton *button, gpointer data) {
463     appdata_t *appdata = (appdata_t*)data;
464    
465     unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
466     char *type = g_object_get_data(G_OBJECT(button), "type");
467    
468     char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
469     type, id);
470    
471     if(url) {
472     browser_url(appdata, url);
473     g_free(url);
474     }
475     }
476     #endif
477    
478     GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
479     const char *type, int id) {
480    
481     #ifdef ENABLE_BROWSER_INTERFACE
482     if(id) {
483     GtkWidget *ref = gtk_button_new_with_label(str);
484     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
485     // hildon_gtk_widget_set_theme_size(ref,
486     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
487     #endif
488     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
489     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
490     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
491     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
492    
493     return ref;
494     }
495     #endif
496     return gtk_label_new(str);
497     }
498    
499 harbaum 138
500     GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
501     const char *type, int id) {
502    
503     #ifdef ENABLE_BROWSER_INTERFACE
504     if(id) {
505     GtkWidget *ref = gtk_button_new();
506     gtk_button_set_image(GTK_BUTTON(ref), icon);
507    
508     #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
509     // hildon_gtk_widget_set_theme_size(ref,
510     // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
511     #endif
512     g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
513     g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
514     gtk_signal_connect(GTK_OBJECT(ref), "clicked",
515     GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
516    
517     return ref;
518     }
519     #endif
520     return icon;
521     }
522    
523 harbaum 165 /* left aligned, word wrapped multiline widget */
524     GtkWidget *simple_text_widget(char *text) {
525     GtkWidget *label = gtk_label_new(text);
526    
527     gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
528     gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
529     gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
530    
531     return label;
532     }
533 harbaum 198
534    
535     /* a label that is left aligned */
536     GtkWidget *left_label_new(char *str) {
537     GtkWidget *widget = gtk_label_new(str);
538     gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
539     return widget;
540     }
541 harbaum 212
542 harbaum 217 static void pos_set(GtkWidget *item, float lat, float lon) {
543 harbaum 212 char str[32];
544    
545     pos_lat_str(str, sizeof(str)-1, lat);
546     GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
547     gtk_entry_set_text(GTK_ENTRY(lat_entry), str);
548    
549     pos_lon_str(str, sizeof(str)-1, lon);
550     GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
551     gtk_entry_set_text(GTK_ENTRY(lon_entry), str);
552     }
553    
554 harbaum 217 static void cb_gps(GtkWidget *item, gpointer data) {
555 harbaum 212 appdata_t *appdata = (appdata_t*)data;
556 harbaum 218 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
557     pos_t *pos = NULL;
558 harbaum 212
559 harbaum 218 if(!id)
560     pos = gps_get_pos(appdata);
561     else if(id == 1)
562     pos = &appdata->home;
563     else {
564     location_t *location = appdata->location;
565     while(location && id > 2) {
566     location = location->next;
567     id--;
568     }
569    
570     if(id == 2)
571     pos = &location->pos;
572     }
573    
574     if(!pos) pos_set(item, NAN, NAN);
575     else pos_set(item, pos->lat, pos->lon);
576 harbaum 212 }
577    
578 harbaum 217 static void cb_geomath(GtkWidget *item, gpointer data) {
579 harbaum 212 appdata_t *appdata = (appdata_t*)data;
580    
581     pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
582     }
583    
584     #ifdef ENABLE_OSM_GPS_MAP
585 harbaum 217 static void cb_map(GtkWidget *item, gpointer data) {
586 harbaum 212 appdata_t *appdata = (appdata_t*)data;
587    
588     pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
589     }
590     #endif
591    
592 harbaum 217 static void cb_cache(GtkWidget *item, gpointer data) {
593 harbaum 212 appdata_t *appdata = (appdata_t*)data;
594 harbaum 217
595 harbaum 212 cache_t *cache = appdata->cur_cache;
596     g_assert(cache);
597    
598 harbaum 217 gint id = (gint)g_object_get_data(G_OBJECT(item), "id");
599    
600     if(!id)
601 harbaum 212 pos_set(item, cache->pos.lat, cache->pos.lon);
602     else {
603     wpt_t *wpt = cache->wpt;
604 harbaum 217 while(wpt && id > 1) {
605 harbaum 212 wpt = wpt->next;
606 harbaum 217 id--;
607 harbaum 212 }
608 harbaum 217
609     if(id == 1)
610     pos_set(item, wpt->pos.lat, wpt->pos.lon);
611 harbaum 212 }
612     }
613    
614 harbaum 217 #ifndef PICKER_DIALOG
615 harbaum 212 static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
616     GtkWidget *icon, char *menu_str,
617 harbaum 217 void(*func)(GtkWidget*, gpointer), gint id,
618 harbaum 212 GtkWidget *lon_entry, GtkWidget *lat_entry) {
619    
620     GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
621    
622     if(icon)
623     gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
624    
625     g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
626     g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
627 harbaum 217 g_object_set_data(G_OBJECT(item), "id", (gpointer)id);
628 harbaum 212
629     if(func)
630     gtk_signal_connect(GTK_OBJECT(item), "activate",
631     (GtkSignalFunc)func, appdata);
632    
633     gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
634    
635     return item;
636     }
637    
638     static GtkWidget *popup_menu_create(appdata_t *appdata,
639     GtkWidget *lat_entry, GtkWidget *lon_entry) {
640     GtkWidget *menu = gtk_menu_new();
641    
642 harbaum 214 menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
643 harbaum 218 _("GPS position"), cb_gps, 0, lon_entry, lat_entry);
644    
645     menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
646     _("Home"), cb_gps, 1, lon_entry, lat_entry);
647    
648     location_t *location = appdata->location;
649     gint id = 2;
650     while(location) {
651     menu_add(menu, appdata, icon_get_widget(ICON_POS, 21),
652     location->name, cb_gps, id++, lon_entry, lat_entry);
653    
654     location = location->next;
655     }
656    
657 harbaum 215 menu_add(menu, appdata, icon_get_widget(ICON_POS, 19),
658 harbaum 217 _("Geomath projection"), cb_geomath, 0, lon_entry, lat_entry);
659 harbaum 212 #ifdef ENABLE_OSM_GPS_MAP
660 harbaum 215 menu_add(menu, appdata, icon_get_widget(ICON_POS, 20),
661 harbaum 217 _("Map position"), cb_map, 0, lon_entry, lat_entry);
662 harbaum 212 #endif
663 harbaum 214
664 harbaum 212 if(appdata->cur_cache) {
665     cache_t *cache = appdata->cur_cache;
666    
667 harbaum 217 char *name = cache->name;
668     if(!name) name = cache->id;
669    
670 harbaum 212 if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
671 harbaum 214 menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
672 harbaum 217 name, cb_cache, 0, lon_entry, lat_entry);
673 harbaum 212 }
674    
675     wpt_t *wpt = cache->wpt;
676 harbaum 217 gint id = 1;
677 harbaum 212 while(wpt) {
678     GtkWidget *icon = NULL;
679     if(wpt->sym != WPT_SYM_UNKNOWN)
680 harbaum 213 icon = icon_get_widget(ICON_POS, wpt->sym);
681 harbaum 212
682 harbaum 217 char *name = wpt->desc;
683     if(!name) name = wpt->cmt;
684     if(!name) name = wpt->id;
685    
686     menu_add(menu, appdata, icon, name, cb_cache, id++,
687 harbaum 212 lon_entry, lat_entry);
688    
689     wpt = wpt->next;
690     }
691     }
692    
693     gtk_widget_show_all(menu);
694    
695     return menu;
696     }
697    
698     static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
699     gpointer data) {
700    
701     if(event->type == GDK_BUTTON_PRESS) {
702     GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
703    
704     /* draw a popup menu */
705     gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
706     event->button, event->time);
707     return TRUE;
708     }
709     return FALSE;
710     }
711    
712     static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
713     GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
714     gtk_widget_destroy(menu);
715     }
716     #endif
717    
718 harbaum 217 #ifdef PICKER_DIALOG
719 harbaum 212
720 harbaum 217 enum {
721     PICKER_COL_ICON = 0,
722     PICKER_COL_NAME,
723     PICKER_COL_ID,
724     PICKER_COL_CB,
725     PICKER_NUM_COLS
726     };
727 harbaum 212
728 harbaum 217 static void picker_add(GtkListStore *store, appdata_t *appdata,
729     GdkPixbuf *icon, char *menu_str,
730     void(*func)(GtkWidget*, gpointer), gint id) {
731     GtkTreeIter iter;
732 harbaum 212
733 harbaum 217 /* Append a row and fill in some data */
734     gtk_list_store_append (store, &iter);
735 harbaum 212
736 harbaum 217 gtk_list_store_set(store, &iter,
737     PICKER_COL_ICON, icon,
738     PICKER_COL_NAME, menu_str,
739     PICKER_COL_ID, id,
740     PICKER_COL_CB, func,
741     -1);
742 harbaum 212 }
743 harbaum 214
744 harbaum 217 static void on_picker_activated(GtkTreeView *treeview,
745     GtkTreePath *path,
746     GtkTreeViewColumn *col,
747     gpointer userdata) {
748     GtkTreeIter iter;
749     GtkTreeModel *model = gtk_tree_view_get_model(treeview);
750 harbaum 214
751 harbaum 217 if(gtk_tree_model_get_iter(model, &iter, path)) {
752     gint id;
753     void(*func)(GtkWidget*, gpointer);
754     gtk_tree_model_get(model, &iter,
755     PICKER_COL_ID, &id,
756     PICKER_COL_CB, &func,
757     -1);
758    
759     /* set id on widget as callbacks expect it this way */
760     g_object_set_data(G_OBJECT(treeview), "id", (gpointer)id);
761     func(GTK_WIDGET(treeview), userdata);
762 harbaum 218
763     /* xyz */
764     gtk_dialog_response(GTK_DIALOG(gtk_widget_get_toplevel(
765     GTK_WIDGET(treeview))), GTK_RESPONSE_ACCEPT);
766    
767 harbaum 217 }
768 harbaum 214 }
769 harbaum 216
770 harbaum 217 static GtkWidget *picker_create(appdata_t *appdata,
771     GtkWidget *lat_entry, GtkWidget *lon_entry) {
772     GtkCellRenderer *renderer;
773     GtkListStore *store;
774    
775     GtkWidget *view = gtk_tree_view_new();
776 harbaum 216
777 harbaum 217 g_object_set_data(G_OBJECT(view), "lat_entry", (gpointer)lat_entry);
778     g_object_set_data(G_OBJECT(view), "lon_entry", (gpointer)lon_entry);
779 harbaum 216
780 harbaum 217 /* --- "Icon" column --- */
781     renderer = gtk_cell_renderer_pixbuf_new();
782     gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
783     -1, "Icon", renderer, "pixbuf", PICKER_COL_ICON, NULL);
784 harbaum 216
785 harbaum 217 /* --- "Name" column --- */
786     renderer = gtk_cell_renderer_text_new();
787     g_object_set(renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL );
788     GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
789     "Name", renderer, "text", PICKER_COL_NAME, NULL);
790     gtk_tree_view_column_set_expand(column, TRUE);
791     gtk_tree_view_insert_column(GTK_TREE_VIEW(view), column, -1);
792 harbaum 216
793 harbaum 217 store = gtk_list_store_new(PICKER_NUM_COLS,
794     GDK_TYPE_PIXBUF,
795     G_TYPE_STRING,
796     G_TYPE_INT,
797     G_TYPE_POINTER);
798 harbaum 216
799 harbaum 217 picker_add(store, appdata, icon_get(ICON_POS, 18),
800 harbaum 218 _("GPS position"), cb_gps, 0);
801    
802     picker_add(store, appdata, icon_get(ICON_POS, 21),
803     _("Home"), cb_gps, 1);
804    
805     location_t *location = appdata->location;
806     gint id = 2;
807     while(location) {
808     picker_add(store, appdata, icon_get(ICON_POS, 21),
809     location->name, cb_gps, id++);
810    
811     location = location->next;
812     }
813    
814 harbaum 217 picker_add(store, appdata, icon_get(ICON_POS, 19),
815     _("Geomath projection"), cb_geomath, 0);
816     #ifdef ENABLE_OSM_GPS_MAP
817     picker_add(store, appdata, icon_get(ICON_POS, 20),
818     _("Map position"), cb_map, 0);
819     #endif
820 harbaum 216
821 harbaum 217 if(appdata->cur_cache) {
822     cache_t *cache = appdata->cur_cache;
823 harbaum 216
824 harbaum 217 char *name = cache->name;
825     if(!name) name = cache->id;
826 harbaum 216
827 harbaum 217 if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
828     picker_add(store, appdata, icon_get(ICON_POS, cache->type + 6),
829     name, cb_cache, 0);
830     }
831 harbaum 216
832 harbaum 217 wpt_t *wpt = cache->wpt;
833     gint id = 1;
834     while(wpt) {
835     GdkPixbuf *icon = NULL;
836     if(wpt->sym != WPT_SYM_UNKNOWN)
837     icon = icon_get(ICON_POS, wpt->sym);
838 harbaum 216
839 harbaum 217 char *name = wpt->desc;
840     if(!name) name = wpt->cmt;
841     if(!name) name = wpt->id;
842 harbaum 216
843 harbaum 217 picker_add(store, appdata, icon, name, cb_cache, id++);
844     wpt = wpt->next;
845     }
846     }
847 harbaum 216
848    
849 harbaum 217 gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store));
850     g_object_unref(store);
851    
852     /* make list react on clicks */
853     g_signal_connect(view, "row-activated",
854     (GCallback)on_picker_activated, appdata);
855    
856     #if 0
857     g_signal_connect(view, "destroy",
858     (GCallback)cachelist_destroy, ce);
859     #endif
860    
861     /* put this inside a scrolled view */
862     #ifndef USE_PANNABLE_AREA
863     GtkWidget *scrolled_window = gtk_scrolled_window_new (NULL, NULL);
864     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window),
865     GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
866     gtk_container_add(GTK_CONTAINER(scrolled_window), view);
867     return scrolled_window;
868     #else
869     GtkWidget *pannable_area = hildon_pannable_area_new();
870     gtk_container_add(GTK_CONTAINER(pannable_area), view);
871     return pannable_area;
872     #endif
873 harbaum 216 }
874    
875 harbaum 217 static gint on_picker_button_press(GtkWidget *button,
876     GdkEventButton *event, gpointer data) {
877     appdata_t *appdata = (appdata_t*)data;
878 harbaum 216
879 harbaum 217 gpointer lat_entry = g_object_get_data(G_OBJECT(button), "lat_entry");
880     gpointer lon_entry = g_object_get_data(G_OBJECT(button), "lon_entry");
881    
882 harbaum 216 if(event->type == GDK_BUTTON_PRESS) {
883 harbaum 217 GtkWidget *dialog =
884     gtk_dialog_new_with_buttons(_("Preset coordinates"),
885     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))),
886     GTK_DIALOG_MODAL,
887     GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
888     NULL);
889 harbaum 216
890 harbaum 217 gtk_window_set_default_size(GTK_WINDOW(dialog), 400, 200);
891 harbaum 216
892 harbaum 217 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox),
893     picker_create(appdata, lat_entry, lon_entry));
894    
895 harbaum 216 gtk_widget_show_all(dialog);
896     gtk_dialog_run(GTK_DIALOG(dialog));
897     gtk_widget_destroy(dialog);
898    
899     return TRUE;
900     }
901     return FALSE;
902     }
903 harbaum 217 #endif
904 harbaum 216
905 harbaum 217 GtkWidget *coo_popup(appdata_t *appdata,
906     GtkWidget *lat_entry, GtkWidget *lon_entry) {
907 harbaum 216
908 harbaum 217 GtkWidget *button = gtk_button_new();
909 harbaum 216
910     gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));
911 harbaum 217
912     gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
913    
914     #ifndef PICKER_DIALOG
915 harbaum 216 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
916 harbaum 217 (GtkSignalFunc)on_popup_button_press, appdata);
917 harbaum 216
918 harbaum 217 gtk_signal_connect(GTK_OBJECT(button), "destroy",
919     (GtkSignalFunc)on_popup_destroy, appdata);
920    
921     g_object_set_data(G_OBJECT(button), "menu",
922     popup_menu_create(appdata, lat_entry, lon_entry));
923 harbaum 216 #else
924 harbaum 217 #ifdef FREMANTLE
925     hildon_gtk_widget_set_theme_size(button,
926     (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
927 harbaum 216 #endif
928    
929 harbaum 217 g_object_set_data(G_OBJECT(button), "lat_entry", (gpointer)lat_entry);
930     g_object_set_data(G_OBJECT(button), "lon_entry", (gpointer)lon_entry);
931    
932     gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
933     (GtkSignalFunc)on_picker_button_press, appdata);
934     #endif
935    
936 harbaum 216 return button;
937     }
938 harbaum 217
939     GtkWidget *entry_new(void) {
940     #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
941     return gtk_entry_new();
942     #else
943     return hildon_entry_new(HILDON_SIZE_AUTO);
944 harbaum 216 #endif
945 harbaum 217 }
946    
947     gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
948     int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
949     int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
950    
951     return((lat1 != lat2) || (lon1 != lon2));
952     }
953