Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 214 - (show annotations)
Thu Nov 26 10:05:23 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 20274 byte(s)
Unified coo tool
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 #include <glib.h>
25 #include <glib/gstdio.h>
26
27 #include "gpxview.h"
28
29 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR >= 5)
30 #include <hildon/hildon-entry.h>
31 #endif
32
33 char strlastchr(char *str) {
34 return str[strlen(str)]-1;
35 }
36
37 /* make sure the entire path "dir" exists and create it if not */
38 int checkdir(char *dir) {
39 struct stat filestat;
40 char *p = dir, tmp;
41
42 /* don't try to create root dir */
43 if(p[0] == '/') p++;
44
45 do {
46 while(*p && *p != '/') p++;
47 tmp = *p;
48 *p = 0;
49
50 int err = stat(dir, &filestat);
51 if(err) {
52 if(mkdir(dir, S_IRWXU) != 0) {
53 perror("mkdir()");
54 *p++ = tmp;
55 return -1;
56 }
57 } else {
58 if(!filestat.st_mode & S_IFDIR) {
59 printf("File %s exists and is _no_ directory\n", dir);
60 *p++ = tmp;
61 return -1;
62 }
63 }
64
65 *p++ = tmp;
66 } while(tmp && strchr(p, '/'));
67
68 return 0;
69 }
70
71 void pos_lat_str(char *str, int len, float latitude) {
72 char *c = _("N");
73 float integral, fractional;
74
75 if(isnan(latitude))
76 str[0] = 0;
77 else {
78 if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
79 fractional = modff(latitude, &integral);
80
81 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
82 }
83 }
84
85 GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
86 char str[32];
87
88 pos_lat_str(str, sizeof(str), latitude);
89 return gtk_label_attrib(str, size, strikethrough);
90 }
91
92 void pos_lon_str(char *str, int len, float longitude) {
93 char *c = _("E");
94 float integral, fractional;
95
96 if(isnan(longitude))
97 str[0] = 0;
98 else {
99 if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
100 fractional = modff(longitude, &integral);
101
102 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
103 }
104 }
105
106 GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
107 char str[32];
108
109 pos_lon_str(str, sizeof(str), longitude);
110 return gtk_label_attrib(str, size, strikethrough);
111 }
112
113 float pos_parse_lat(char *str) {
114 int integral_int;
115 float fractional;
116 char c;
117
118 if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
119 c = toupper(c);
120
121 if(c != 'S' && c != 'N')
122 return NAN;
123
124 /* prevent -0.0 */
125 if(!integral_int && (fractional == 0.0))
126 return 0.0;
127
128 return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
129 }
130
131 return NAN;
132 }
133
134 float pos_parse_lon(char *str) {
135 int integral_int;
136 float fractional;
137 char c;
138
139 if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
140 c = toupper(c);
141
142 /* O is german "Ost" for "East" */
143 if(c != 'E' && c != 'W' && c != 'O')
144 return NAN;
145
146 /* prevent -0.0 */
147 if(!integral_int && (fractional == 0.0))
148 return 0.0;
149
150 return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
151 }
152
153 return NAN;
154 }
155
156 const char *pos_get_bearing_str(pos_t from, pos_t to) {
157 static const char *bear_str[]={
158 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
159
160 float bearing = gpx_pos_get_bearing(from, to);
161 if(!isnan(bearing)) {
162 int idx = (bearing+22.5)/45.0;
163 /* make sure we stay in icon bounds */
164 while(idx < 0) idx += 8;
165 while(idx > 7) idx -= 8;
166 return _(bear_str[idx]);
167 }
168
169 return bear_str[8]; // empty string
170 }
171
172 /* the maemo font size is quite huge, so we adjust some fonts */
173 /* differently on maemo and non-maemo. Basically "BIG" does nothing */
174 /* on maemo and "SMALL" only does something on maemo */
175 #ifdef USE_MAEMO
176 #define MARKUP_SMALL "<span size='small'>%s</span>"
177 GtkWidget *gtk_label_small(char *str) {
178 GtkWidget *label = gtk_label_new("");
179 char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
180 gtk_label_set_markup(GTK_LABEL(label), markup);
181 g_free(markup);
182 return label;
183 }
184 #else
185 #define MARKUP_BIG "<span size='x-large'>%s</span>"
186 GtkWidget *gtk_label_big(char *str) {
187 GtkWidget *label = gtk_label_new("");
188 char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
189 gtk_label_set_markup(GTK_LABEL(label), markup);
190 g_free(markup);
191 return label;
192 }
193 #endif
194
195 void gtk_label_attrib_set(GtkWidget *label,
196 char *str, int size, int strikethrough) {
197 char format[80];
198
199 snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
200 #ifdef USE_MAEMO
201 (size==SIZE_SMALL)?" size='small'":"",
202 #else
203 (size==SIZE_BIG)?" size='x-large'":"",
204 #endif
205 strikethrough?" strikethrough='yes'":"",
206 (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
207
208 char *markup = g_markup_printf_escaped(format, str);
209 // printf("markup = %s\n", markup);
210 gtk_label_set_markup(GTK_LABEL(label), markup);
211 g_free(markup);
212 }
213
214 GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
215 GtkWidget *label = gtk_label_new("");
216 gtk_label_attrib_set(label, str, size, strikethrough);
217 return label;
218 }
219
220 GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
221 GtkWidget *button = gtk_button_new_with_label("");
222 gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
223 str, size, strikethrough);
224 return button;
225 }
226
227 void textbox_disable(GtkWidget *widget) {
228 gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
229 gtk_widget_set_sensitive(widget, FALSE);
230 }
231
232 void textbox_enable(GtkWidget *widget) {
233 gtk_widget_set_sensitive(widget, TRUE);
234 gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
235 }
236
237 pos_t *get_pos(appdata_t *appdata) {
238 pos_t *pos = &appdata->home;
239
240 if(appdata->active_location) {
241 int i = appdata->active_location-1;
242 location_t *loc = appdata->location;
243 while(i--) loc = loc->next;
244 pos = &loc->pos;
245 }
246
247 if(appdata->use_gps) {
248 pos = gps_get_pos(appdata);
249
250 if(!pos) pos = &appdata->gps; /* use saved position */
251 else appdata->gps = *pos; /* save position */
252 }
253 return pos;
254 }
255
256 void distance_str(char *str, int len, float dist, gboolean imperial) {
257 if(isnan(dist))
258 snprintf(str, len, "---");
259 else if(imperial) {
260 /* 1 mil = 1760 yd = 5280 ft ... */
261 if(dist<0.018) snprintf(str, len, "%.1f ft", dist*5280.0);
262 else if(dist<0.055) snprintf(str, len, "%.1f yd", dist*1760.0);
263 else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
264 else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
265 else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
266 else snprintf(str, len, "%.0f mi", dist);
267 } else {
268 if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
269 else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
270 else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
271 else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
272 else snprintf(str, len, "%.0f km", dist);
273 }
274 }
275
276 /* return distance in miles or kilometers */
277 float distance_parse(char *str, gboolean imperial) {
278 char unit[4];
279 float val = NAN;
280
281 if(sscanf(str, "%f %3s", &val, unit) == 2) {
282 gboolean fimp = FALSE;
283
284 if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
285 else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
286 else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
287 else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
288 else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
289 else val = NAN;
290
291 /* found imperial and metric requested? convert miles into kilometers */
292 if(fimp & !imperial) val *= 1.609344;
293
294 /* found metric and imperial requested? convert kilometers into miles */
295 if(!fimp & imperial) val /= 1.609344;
296 }
297 return val;
298 }
299
300 static gboolean mark(GtkWidget *widget, gboolean valid) {
301 gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
302 return valid;
303 }
304
305 static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
306 float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
307 mark(widget, !isnan(i));
308 }
309
310 /* a entry that is colored red when being "active" */
311 GtkWidget *lat_entry_new(float lat) {
312 GdkColor color;
313
314 GtkWidget *widget = entry_new();
315 gdk_color_parse("#ff0000", &color);
316 gtk_widget_modify_text(widget, TAG_STATE, &color);
317
318 char str[32];
319 pos_lat_str(str, sizeof(str), lat);
320 gtk_entry_set_text(GTK_ENTRY(widget), str);
321
322 g_signal_connect(G_OBJECT(widget), "changed",
323 G_CALLBACK(callback_modified_lat), NULL);
324
325 return widget;
326 }
327
328 static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
329 float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
330 mark(widget, !isnan(i));
331 }
332
333 /* a entry that is colored red when filled with invalid coordinate */
334 GtkWidget *lon_entry_new(float lon) {
335 GdkColor color;
336
337 GtkWidget *widget = entry_new();
338 // gtk_entry_set_width_chars(GTK_ENTRY(widget), 14);
339
340 gdk_color_parse("#ff0000", &color);
341 gtk_widget_modify_text(widget, TAG_STATE, &color);
342
343 char str[32];
344 pos_lon_str(str, sizeof(str), lon);
345 gtk_entry_set_text(GTK_ENTRY(widget), str);
346
347 g_signal_connect(G_OBJECT(widget), "changed",
348 G_CALLBACK(callback_modified_lon), NULL);
349
350 return widget;
351 }
352
353
354 float lat_get(GtkWidget *widget) {
355 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
356 return pos_parse_lat(p);
357 }
358
359 float lon_get(GtkWidget *widget) {
360 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
361 return pos_parse_lon(p);
362 }
363
364 static void callback_modified_dist(GtkWidget *widget, gpointer data ) {
365 /* don't care for metric/imperial since we only want to know if this */
366 /* is parseable at all */
367 float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
368 mark(widget, !isnan(i));
369 }
370
371 /* a entry that is colored red when filled with invalid distance */
372 GtkWidget *dist_entry_new(float dist, gboolean mil) {
373 GdkColor color;
374 GtkWidget *widget = entry_new();
375 gdk_color_parse("#ff0000", &color);
376 gtk_widget_modify_text(widget, TAG_STATE, &color);
377
378 char str[32];
379 distance_str(str, sizeof(str), dist, mil);
380 gtk_entry_set_text(GTK_ENTRY(widget), str);
381
382 g_signal_connect(G_OBJECT(widget), "changed",
383 G_CALLBACK(callback_modified_dist), NULL);
384
385 return widget;
386 }
387
388 float dist_get(GtkWidget *widget, gboolean mil) {
389 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
390 return distance_parse(p, mil);
391 }
392
393 #ifndef USE_MAEMO
394 #ifdef ENABLE_BROWSER_INTERFACE
395 #include <libgnome/gnome-url.h>
396
397 int browser_url(appdata_t *appdata, char *url) {
398 /* taken from gnome-open, part of libgnome */
399 GError *err = NULL;
400 gnome_url_show(url, &err);
401 return 0;
402 }
403 #endif
404 #endif
405
406 /* recursively remove an entire file system */
407 void rmdir_recursive(char *path) {
408 GDir *dir = g_dir_open(path, 0, NULL);
409 if(dir) {
410 const char *name = g_dir_read_name(dir);
411 while(name) {
412 char *fullname = g_strdup_printf("%s/%s", path, name);
413 // printf("deleting %s\n", fullname);
414
415 if(g_file_test(fullname, G_FILE_TEST_IS_DIR))
416 rmdir_recursive(fullname);
417 else if(g_file_test(fullname, G_FILE_TEST_IS_REGULAR))
418 g_remove(fullname);
419
420 g_free(fullname);
421 name = g_dir_read_name(dir);
422 }
423
424 g_dir_close(dir);
425 }
426 g_rmdir(path);
427 }
428
429 #ifdef ENABLE_BROWSER_INTERFACE
430 static void on_link_clicked(GtkButton *button, gpointer data) {
431 appdata_t *appdata = (appdata_t*)data;
432 char *url = g_object_get_data(G_OBJECT(button), "url");
433 if(url) browser_url(appdata, url);
434 }
435 #endif
436
437 /* a button containing a weblink */
438 GtkWidget *link_button_attrib(appdata_t *appdata, char *str, char *url,
439 int size, int strikethrough) {
440
441 #ifdef ENABLE_BROWSER_INTERFACE
442 if(url) {
443 GtkWidget *button = gtk_button_attrib(str, size, strikethrough);
444 g_object_set_data(G_OBJECT(button), "url", url);
445 gtk_signal_connect(GTK_OBJECT(button), "clicked",
446 (GtkSignalFunc)on_link_clicked, appdata);
447
448 return button;
449 }
450 #endif
451 return gtk_label_attrib(str, size, strikethrough);
452 }
453
454 #ifdef ENABLE_BROWSER_INTERFACE
455 static void on_link_id_clicked(GtkButton *button, gpointer data) {
456 appdata_t *appdata = (appdata_t*)data;
457
458 unsigned int id = (unsigned int)g_object_get_data(G_OBJECT(button), "id");
459 char *type = g_object_get_data(G_OBJECT(button), "type");
460
461 char *url = g_strdup_printf("http://www.geocaching.com/%s?id=%u",
462 type, id);
463
464 if(url) {
465 browser_url(appdata, url);
466 g_free(url);
467 }
468 }
469 #endif
470
471 GtkWidget *link_button_by_id(appdata_t *appdata, char *str,
472 const char *type, int id) {
473
474 #ifdef ENABLE_BROWSER_INTERFACE
475 if(id) {
476 GtkWidget *ref = gtk_button_new_with_label(str);
477 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
478 // hildon_gtk_widget_set_theme_size(ref,
479 // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
480 #endif
481 g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
482 g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
483 gtk_signal_connect(GTK_OBJECT(ref), "clicked",
484 GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
485
486 return ref;
487 }
488 #endif
489 return gtk_label_new(str);
490 }
491
492
493 GtkWidget *link_icon_button_by_id(appdata_t *appdata, GtkWidget *icon,
494 const char *type, int id) {
495
496 #ifdef ENABLE_BROWSER_INTERFACE
497 if(id) {
498 GtkWidget *ref = gtk_button_new();
499 gtk_button_set_image(GTK_BUTTON(ref), icon);
500
501 #if defined(USE_MAEMO) && (MAEMO_VERSION_MAJOR == 5)
502 // hildon_gtk_widget_set_theme_size(ref,
503 // (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
504 #endif
505 g_object_set_data(G_OBJECT(ref), "id", (gpointer)id);
506 g_object_set_data(G_OBJECT(ref), "type", (gpointer)type);
507 gtk_signal_connect(GTK_OBJECT(ref), "clicked",
508 GTK_SIGNAL_FUNC(on_link_id_clicked), appdata);
509
510 return ref;
511 }
512 #endif
513 return icon;
514 }
515
516 /* left aligned, word wrapped multiline widget */
517 GtkWidget *simple_text_widget(char *text) {
518 GtkWidget *label = gtk_label_new(text);
519
520 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
521 gtk_label_set_line_wrap_mode(GTK_LABEL(label), PANGO_WRAP_WORD);
522 gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
523
524 return label;
525 }
526
527
528 /* a label that is left aligned */
529 GtkWidget *left_label_new(char *str) {
530 GtkWidget *widget = gtk_label_new(str);
531 gtk_misc_set_alignment(GTK_MISC(widget), 0.0f, 0.5f);
532 return widget;
533 }
534
535 static void pos_set(GtkMenuItem *item, float lat, float lon) {
536 char str[32];
537
538 pos_lat_str(str, sizeof(str)-1, lat);
539 GtkWidget *lat_entry = g_object_get_data(G_OBJECT(item), "lat_entry");
540 gtk_entry_set_text(GTK_ENTRY(lat_entry), str);
541
542 pos_lon_str(str, sizeof(str)-1, lon);
543 GtkWidget *lon_entry = g_object_get_data(G_OBJECT(item), "lon_entry");
544 gtk_entry_set_text(GTK_ENTRY(lon_entry), str);
545 }
546
547 static void cb_gps(GtkMenuItem *item, gpointer data) {
548 appdata_t *appdata = (appdata_t*)data;
549
550 pos_t *refpos = get_pos(appdata);
551 if(!refpos) pos_set(item, NAN, NAN);
552 else pos_set(item, refpos->lat, refpos->lon);
553 }
554
555 static void cb_geomath(GtkMenuItem *item, gpointer data) {
556 appdata_t *appdata = (appdata_t*)data;
557
558 pos_set(item, appdata->geomath.lat, appdata->geomath.lon);
559 }
560
561 #ifdef ENABLE_OSM_GPS_MAP
562 static void cb_map(GtkMenuItem *item, gpointer data) {
563 appdata_t *appdata = (appdata_t*)data;
564
565 pos_set(item, appdata->map.pos.lat, appdata->map.pos.lon);
566 }
567 #endif
568
569 static const gchar *menu_item_get_label(GtkMenuItem *menu_item) {
570 GList *children, *l;
571 GtkWidget *child;
572 children = gtk_container_get_children (GTK_CONTAINER (menu_item));
573 for (l = g_list_first (children); l != NULL;
574 l = g_list_next (l)) {
575 child = (GtkWidget *)l->data;
576 if (GTK_IS_LABEL (child)) {
577 return gtk_label_get_label (GTK_LABEL (child));
578 }
579 }
580 return NULL;
581 }
582
583 static void cb_cache(GtkMenuItem *item, gpointer data) {
584 const char *label = menu_item_get_label(item);
585 appdata_t *appdata = (appdata_t*)data;
586
587 cache_t *cache = appdata->cur_cache;
588 g_assert(cache);
589
590 if(!strcmp(label, cache->id))
591 pos_set(item, cache->pos.lat, cache->pos.lon);
592 else {
593 wpt_t *wpt = cache->wpt;
594 while(wpt) {
595 if(!strcmp(label, wpt->id)) {
596 pos_set(item, wpt->pos.lat, wpt->pos.lon);
597 return;
598 }
599
600 wpt = wpt->next;
601 }
602 }
603 }
604
605 static GtkWidget *menu_add(GtkWidget *menu, appdata_t *appdata,
606 GtkWidget *icon, char *menu_str,
607 void(*func)(GtkMenuItem*, gpointer),
608 GtkWidget *lon_entry, GtkWidget *lat_entry) {
609
610 GtkWidget *item = gtk_image_menu_item_new_with_label(menu_str);
611
612 if(icon)
613 gtk_image_menu_item_set_image(GTK_IMAGE_MENU_ITEM(item), icon);
614
615 g_object_set_data(G_OBJECT(item), "lat_entry", (gpointer)lat_entry);
616 g_object_set_data(G_OBJECT(item), "lon_entry", (gpointer)lon_entry);
617
618 if(func)
619 gtk_signal_connect(GTK_OBJECT(item), "activate",
620 (GtkSignalFunc)func, appdata);
621
622 gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
623
624 return item;
625 }
626
627 static GtkWidget *popup_menu_create(appdata_t *appdata,
628 GtkWidget *lat_entry, GtkWidget *lon_entry) {
629 GtkWidget *menu = gtk_menu_new();
630
631 menu_add(menu, appdata, icon_get_widget(ICON_POS, 18),
632 _("Current position (GPS)"), cb_gps, lon_entry, lat_entry);
633 menu_add(menu, appdata, NULL, _("Geomath projection"),
634 cb_geomath, lon_entry, lat_entry);
635 #ifdef ENABLE_OSM_GPS_MAP
636 menu_add(menu, appdata, NULL, _("Map position"),
637 cb_map, lon_entry, lat_entry);
638 #endif
639
640 printf("popup cache present: %s\n", appdata->cur_cache?"Yes":"No");
641
642 if(appdata->cur_cache) {
643 cache_t *cache = appdata->cur_cache;
644
645 if(!isnan(cache->pos.lat) && !isnan(cache->pos.lon)) {
646 menu_add(menu, appdata, icon_get_widget(ICON_POS, cache->type + 6),
647 cache->id, cb_cache, lon_entry, lat_entry);
648 }
649
650 printf("appending cache waypoints\n");
651 wpt_t *wpt = cache->wpt;
652 while(wpt) {
653 GtkWidget *icon = NULL;
654 if(wpt->sym != WPT_SYM_UNKNOWN)
655 icon = icon_get_widget(ICON_POS, wpt->sym);
656
657 menu_add(menu, appdata, icon, wpt->id, cb_cache,
658 lon_entry, lat_entry);
659
660 wpt = wpt->next;
661 }
662 }
663
664 gtk_widget_show_all(menu);
665
666 return menu;
667 }
668
669 static gint on_popup_button_press(GtkWidget *button, GdkEventButton *event,
670 gpointer data) {
671
672 if(event->type == GDK_BUTTON_PRESS) {
673 GtkWidget *menu = g_object_get_data(G_OBJECT(button), "menu");
674
675 /* draw a popup menu */
676 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL,
677 event->button, event->time);
678 return TRUE;
679 }
680 return FALSE;
681 }
682
683 static void on_popup_destroy(GtkWidget *widget, gpointer user_data ) {
684 GtkWidget *menu = g_object_get_data(G_OBJECT(widget), "menu");
685 gtk_widget_destroy(menu);
686 }
687
688 GtkWidget *coo_popup(appdata_t *appdata,
689 GtkWidget *lat_entry, GtkWidget *lon_entry) {
690
691 GtkWidget *button = gtk_button_new();
692 #ifdef FREMANTLE
693 hildon_gtk_widget_set_theme_size(button,
694 (HILDON_SIZE_FINGER_HEIGHT | HILDON_SIZE_AUTO_WIDTH));
695 #endif
696
697 gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_POS, 17));
698
699 gtk_widget_set_tooltip_text(button, _("Preset coordinates"));
700
701 gtk_signal_connect(GTK_OBJECT(button), "button-press-event",
702 (GtkSignalFunc)on_popup_button_press, appdata);
703
704 gtk_signal_connect(GTK_OBJECT(button), "destroy",
705 (GtkSignalFunc)on_popup_destroy, appdata);
706
707 g_object_set_data(G_OBJECT(button), "menu",
708 popup_menu_create(appdata, lat_entry, lon_entry));
709
710 return button;
711 }
712
713 GtkWidget *entry_new(void) {
714 #if !defined(USE_MAEMO) || (MAEMO_VERSION_MAJOR < 5)
715 return gtk_entry_new();
716 #else
717 return hildon_entry_new(HILDON_SIZE_AUTO);
718 #endif
719 }
720
721 gboolean pos_differ(pos_t *pos1, pos_t *pos2) {
722 int lat1 = (60000 * pos1->lat)+0.5, lon1 = (60000 * pos1->lon)+0.5;
723 int lat2 = (60000 * pos2->lat)+0.5, lon2 = (60000 * pos2->lon)+0.5;
724
725 return((lat1 != lat2) || (lon1 != lon2));
726 }