Contents of /trunk/src/misc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 221 - (show annotations)
Mon Nov 30 21:28:04 2009 UTC (14 years, 5 months ago) by harbaum
File MIME type: text/plain
File size: 40249 byte(s)
Fremantle coordinate picker
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 #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) {
46 return str[strlen(str)]-1;
47 }
48
49 /* make sure the entire path "dir" exists and create it if not */
50 int checkdir(char *dir) {
51 struct stat filestat;
52 char *p = dir, tmp;
53
54 /* don't try to create root dir */
55 if(p[0] == '/') p++;
56
57 do {
58 while(*p && *p != '/') p++;
59 tmp = *p;
60 *p = 0;
61
62 int err = stat(dir, &filestat);
63 if(err) {
64 if(mkdir(dir, S_IRWXU) != 0) {
65 perror("mkdir()");
66 *p++ = tmp;
67 return -1;
68 }
69 } else {
70 if(!filestat.st_mode & S_IFDIR) {
71 printf("File %s exists and is _no_ directory\n", dir);
72 *p++ = tmp;
73 return -1;
74 }
75 }
76
77 *p++ = tmp;
78 } while(tmp && strchr(p, '/'));
79
80 return 0;
81 }
82
83 void pos_lat_str(char *str, int len, float latitude) {
84 char *c = _("N");
85 float integral, fractional;
86
87 if(isnan(latitude))
88 str[0] = 0;
89 else {
90 if(latitude < 0) { latitude = fabs(latitude); c = _("S"); }
91 fractional = modff(latitude, &integral);
92
93 snprintf(str, len, "%s %02d° %06.3f'", c, (int)integral, fractional*60.0);
94 }
95 }
96
97 GtkWidget *pos_lat(float latitude, int size, int strikethrough) {
98 char str[32];
99
100 pos_lat_str(str, sizeof(str), latitude);
101 return gtk_label_attrib(str, size, strikethrough);
102 }
103
104 void pos_lon_str(char *str, int len, float longitude) {
105 char *c = _("E");
106 float integral, fractional;
107
108 if(isnan(longitude))
109 str[0] = 0;
110 else {
111 if(longitude < 0) { longitude = fabs(longitude); c = _("W"); }
112 fractional = modff(longitude, &integral);
113
114 snprintf(str, len, "%s %03d° %06.3f'", c, (int)integral, fractional*60.0);
115 }
116 }
117
118 GtkWidget *pos_lon(float longitude, int size, int strikethrough) {
119 char str[32];
120
121 pos_lon_str(str, sizeof(str), longitude);
122 return gtk_label_attrib(str, size, strikethrough);
123 }
124
125 float pos_parse_lat(char *str) {
126 int integral_int;
127 float fractional;
128 char c;
129
130 if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
131 c = toupper(c);
132
133 if(c != 'S' && c != 'N')
134 return NAN;
135
136 /* prevent -0.0 */
137 if(!integral_int && (fractional == 0.0))
138 return 0.0;
139
140 return ((c == 'S')?-1:+1) * (integral_int + fractional/60.0);
141 }
142
143 return NAN;
144 }
145
146 float pos_parse_lon(char *str) {
147 int integral_int;
148 float fractional;
149 char c;
150
151 if(sscanf(str, "%c %d° %f'", &c, &integral_int, &fractional) == 3) {
152 c = toupper(c);
153
154 /* O is german "Ost" for "East" */
155 if(c != 'E' && c != 'W' && c != 'O')
156 return NAN;
157
158 /* prevent -0.0 */
159 if(!integral_int && (fractional == 0.0))
160 return 0.0;
161
162 return ((c == 'W')?-1:+1) * (integral_int + fractional/60.0);
163 }
164
165 return NAN;
166 }
167
168 const char *pos_get_bearing_str(pos_t from, pos_t to) {
169 static const char *bear_str[]={
170 "N", "NE", "E", "SE", "S", "SW", "W", "NW", "" };
171
172 float bearing = gpx_pos_get_bearing(from, to);
173 if(!isnan(bearing)) {
174 int idx = (bearing+22.5)/45.0;
175 /* 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 */
185 /* differently on maemo and non-maemo. Basically "BIG" does nothing */
186 /* on maemo and "SMALL" only does something on maemo */
187 #ifdef USE_MAEMO
188 #define MARKUP_SMALL "<span size='small'>%s</span>"
189 GtkWidget *gtk_label_small(char *str) {
190 GtkWidget *label = gtk_label_new("");
191 char *markup = g_markup_printf_escaped(MARKUP_SMALL, str);
192 gtk_label_set_markup(GTK_LABEL(label), markup);
193 g_free(markup);
194 return label;
195 }
196 #else
197 #define MARKUP_BIG "<span size='x-large'>%s</span>"
198 GtkWidget *gtk_label_big(char *str) {
199 GtkWidget *label = gtk_label_new("");
200 char *markup = g_markup_printf_escaped(MARKUP_BIG, str);
201 gtk_label_set_markup(GTK_LABEL(label), markup);
202 g_free(markup);
203 return label;
204 }
205 #endif
206
207 void gtk_label_attrib_set(GtkWidget *label,
208 char *str, int size, int strikethrough) {
209 char format[80];
210
211 snprintf(format, sizeof(format), "<span%s%s%s>%%s</span>",
212 #ifdef USE_MAEMO
213 (size==SIZE_SMALL)?" size='small'":"",
214 #else
215 (size==SIZE_BIG)?" size='x-large'":"",
216 #endif
217 strikethrough?" strikethrough='yes'":"",
218 (strikethrough==STRIKETHROUGH_RED)?" strikethrough_color='red'":"");
219
220 char *markup = g_markup_printf_escaped(format, str);
221 // printf("markup = %s\n", markup);
222 gtk_label_set_markup(GTK_LABEL(label), markup);
223 g_free(markup);
224 }
225
226 GtkWidget *gtk_label_attrib(char *str, int size, int strikethrough) {
227 GtkWidget *label = gtk_label_new("");
228 gtk_label_attrib_set(label, str, size, strikethrough);
229 return label;
230 }
231
232 GtkWidget *gtk_button_attrib(char *str, int size, int strikethrough) {
233 GtkWidget *button = gtk_button_new_with_label("");
234 gtk_label_attrib_set(gtk_bin_get_child(GTK_BIN(button)),
235 str, size, strikethrough);
236 return button;
237 }
238
239 void textbox_disable(GtkWidget *widget) {
240 gtk_editable_set_editable(GTK_EDITABLE(widget), FALSE);
241 gtk_widget_set_sensitive(widget, FALSE);
242 }
243
244 void textbox_enable(GtkWidget *widget) {
245 gtk_widget_set_sensitive(widget, TRUE);
246 gtk_editable_set_editable(GTK_EDITABLE(widget), TRUE);
247 }
248
249 pos_t *get_pos(appdata_t *appdata) {
250 pos_t *pos = &appdata->home;
251
252 if(appdata->active_location) {
253 int i = appdata->active_location-1;
254 location_t *loc = appdata->location;
255 while(i--) loc = loc->next;
256 pos = &loc->pos;
257 }
258
259 if(appdata->use_gps) {
260 pos = gps_get_pos(appdata);
261
262 if(!pos) pos = &appdata->gps; /* use saved position */
263 else appdata->gps = *pos; /* save position */
264 }
265 return pos;
266 }
267
268 void distance_str(char *str, int len, float dist, gboolean imperial) {
269 if(isnan(dist))
270 snprintf(str, len, "---");
271 else if(imperial) {
272 /* 1 mil = 1760 yd = 5280 ft ... */
273 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);
275 else if(dist<0.55) snprintf(str, len, "%.0f yd", dist*1760.0);
276 else if(dist<10.0) snprintf(str, len, "%.2f mi", dist);
277 else if(dist<100.0) snprintf(str, len, "%.1f mi", dist);
278 else snprintf(str, len, "%.0f mi", dist);
279 } else {
280 if(dist<0.01) snprintf(str, len, "%.2f m", dist*1000.0);
281 else if(dist<0.1) snprintf(str, len, "%.1f m", dist*1000.0);
282 else if(dist<1.0) snprintf(str, len, "%.0f m", dist*1000.0);
283 else if(dist<100.0) snprintf(str, len, "%.1f km", dist);
284 else snprintf(str, len, "%.0f km", dist);
285 }
286 }
287
288 /* return distance in miles or kilometers */
289 float distance_parse(char *str, gboolean imperial) {
290 char unit[4];
291 float val = NAN;
292
293 if(sscanf(str, "%f %3s", &val, unit) == 2) {
294 gboolean fimp = FALSE;
295
296 if(strcasecmp(unit, "ft") == 0) { fimp = TRUE; val /= 5280.0; }
297 else if(strcasecmp(unit, "yd") == 0) { fimp = TRUE; val /= 1760.0; }
298 else if(strcasecmp(unit, "mi") == 0) { fimp = TRUE; }
299 else if(strcasecmp(unit, "m") == 0) { fimp = FALSE; val /= 1000.0; }
300 else if(strcasecmp(unit, "km") == 0) { fimp = FALSE; }
301 else val = NAN;
302
303 /* found imperial and metric requested? convert miles into kilometers */
304 if(fimp & !imperial) val *= 1.609344;
305
306 /* found metric and imperial requested? convert kilometers into miles */
307 if(!fimp & imperial) val /= 1.609344;
308 }
309 return val;
310 }
311
312 /* ------------------ coordinate picker tool --------------------------- */
313
314 static gboolean mark(GtkWidget *widget, gboolean valid) {
315 gtk_widget_set_state(widget, valid?GTK_STATE_NORMAL:TAG_STATE);
316 return valid;
317 }
318
319 #ifndef COORDINATE_PICKER
320 static void callback_modified_lat(GtkWidget *widget, gpointer data ) {
321 float i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
322 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" */
534 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;
540
541 GtkWidget *widget = entry_new();
542 gdk_color_parse("#ff0000", &color);
543 gtk_widget_modify_text(widget, TAG_STATE, &color);
544
545 gtk_entry_set_text(GTK_ENTRY(widget), str);
546
547 g_signal_connect(G_OBJECT(widget), "changed",
548 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;
564 }
565
566 #ifndef COORDINATE_PICKER
567 static void callback_modified_lon(GtkWidget *widget, gpointer data ) {
568 float i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(widget)));
569 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 */
656 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;
662
663 GtkWidget *widget = entry_new();
664 gdk_color_parse("#ff0000", &color);
665 gtk_widget_modify_text(widget, TAG_STATE, &color);
666
667 gtk_entry_set_text(GTK_ENTRY(widget), str);
668
669 g_signal_connect(G_OBJECT(widget), "changed",
670 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;
686 }
687
688 float lat_entry_get(GtkWidget *widget) {
689 #ifndef COORDINATE_PICKER
690 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);
695 }
696
697 float lon_entry_get(GtkWidget *widget) {
698 #ifndef COORDINATE_PICKER
699 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);
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 ) {
757 /* don't care for metric/imperial since we only want to know if this */
758 /* is parseable at all */
759 float i = distance_parse((char*)gtk_entry_get_text(GTK_ENTRY(widget)), FALSE);
760 mark(widget, !isnan(i));
761 }
762
763 /* a entry that is colored red when filled with invalid distance */
764 GtkWidget *dist_entry_new(float dist, gboolean mil) {
765 GdkColor color;
766 GtkWidget *widget = entry_new();
767 gdk_color_parse("#ff0000", &color);
768 gtk_widget_modify_text(widget, TAG_STATE, &color);
769
770 char str[32];
771 distance_str(str, sizeof(str), dist, mil);
772 gtk_entry_set_text(GTK_ENTRY(widget), str);
773
774 g_signal_connect(G_OBJECT(widget), "changed",
775 G_CALLBACK(callback_modified_dist), NULL);
776
777 return widget;
778 }
779
780 float dist_get(GtkWidget *widget, gboolean mil) {
781 char *p = (char*)gtk_entry_get_text(GTK_ENTRY(widget));
782 return distance_parse(p, mil);
783 }
784
785 #ifndef USE_MAEMO
786 #ifdef ENABLE_BROWSER_INTERFACE
787 #include <libgnome/gnome-url.h>
788
789 int browser_url(appdata_t *appdata, char *url) {
790 /* taken from gnome-open, part of libgnome */
791 GError *err = NULL;
792 gnome_url_show(url, &err);
793 return 0;
794 }
795 #endif
796 #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