]> err.no Git - mapper/blob - src/cb.c
35251003cc7763f1c85ee2bcaab5afbd467ac339
[mapper] / src / cb.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  * Copyright (C) 2006-2007 John Costigan.
6  *
7  * POI and GPS-Info code originally written by Cezary Jackiewicz.
8  *
9  * Default map data provided by http://www.openstreetmap.org/
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along
22  * with this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <config.h>
27
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <stddef.h>
33 #include <locale.h>
34 #include <errno.h>
35 #include <sys/wait.h>
36 #include <glib/gstdio.h>
37 #include <gtk/gtk.h>
38 #include <gdk/gdkkeysyms.h>
39 #include <fcntl.h>
40 #include <libintl.h>
41 #include <locale.h>
42
43 #include "hildon-mapper.h"
44
45 #include "utils.h"
46 #include "poi.h"
47 #include "path.h"
48 #include "route.h"
49 #include "track.h"
50 #include "settings.h"
51 #include "gps.h"
52 #include "map.h"
53 #include "mapper-types.h"
54 #include "ui-common.h"
55 #include "db.h"
56 #include "latlon.h"
57 #include "cb.h"
58 #include "poi-gui.h"
59 #include "gps-panels.h"
60 #include "gps-conn.h"
61 #include "search.h"
62 #include "help.h"
63
64 gboolean 
65 menu_cb_route_download(GtkAction * action)
66 {
67 GtkListStore *store;
68
69 route_download(NULL);
70 store=route_generate_store(&_route);
71 if (store!=NULL) {
72         gtk_tree_view_set_model(route_tree_view, store);
73         g_object_unref(G_OBJECT(store));
74 }
75 return TRUE;
76 }
77
78 gboolean 
79 menu_cb_route_open(GtkAction * action)
80 {
81 GtkListStore *store;
82
83 route_open_file();
84 store=route_generate_store(&_route);
85 if (store!=NULL) {
86         gtk_tree_view_set_model(route_tree_view, store);
87         g_object_unref(G_OBJECT(store));
88 }
89 return TRUE;
90 }
91
92 gboolean 
93 menu_cb_route_distnext(GtkAction * action)
94 {
95 route_show_distance_to_next();
96 return TRUE;
97 }
98
99 gboolean 
100 menu_cb_route_distlast(GtkAction * action)
101 {
102 route_show_distance_to_last();
103 return TRUE;
104 }
105
106 gboolean 
107 menu_cb_route_reset(GtkAction * action)
108 {
109 route_find_nearest_point();
110 map_render_data();
111 MACRO_QUEUE_DRAW_AREA();
112 return TRUE;
113 }
114
115 gboolean 
116 menu_cb_route_clear(GtkAction * action)
117 {
118 route_clear();
119 gtk_tree_view_set_model(route_tree_view, NULL);
120 return TRUE;
121 }
122
123 gboolean 
124 menu_cb_track_open(GtkAction * action)
125 {
126 track_open();
127 return TRUE;
128 }
129
130 gboolean 
131 menu_cb_track_save(GtkAction * action)
132 {
133 track_save();
134 return TRUE;
135 }
136
137 gboolean 
138 menu_cb_track_insert_break(GtkAction * action)
139 {
140 track_insert_break();
141 return TRUE;
142 }
143
144 gboolean 
145 menu_cb_track_insert_mark(GtkAction * action)
146 {
147 track_insert_mark();
148 return TRUE;
149 }
150
151 gboolean 
152 menu_cb_track_distlast(GtkAction * action)
153 {
154 track_show_distance_from_last();
155 return TRUE;
156 }
157
158 gboolean 
159 menu_cb_track_distfirst(GtkAction * action)
160 {
161 track_show_distance_from_first();
162 return TRUE;
163 }
164
165 gboolean 
166 menu_cb_route_save(GtkAction * action)
167 {
168 route_save();
169 return TRUE;
170 }
171
172 gboolean 
173 menu_cb_track_clear(GtkAction * action)
174 {
175 track_clear();
176 return TRUE;
177 }
178
179 gboolean 
180 menu_cb_track_filter(GtkAction * action)
181 {
182 filter_dialog();
183 return TRUE;
184 }
185
186 gboolean 
187 menu_cb_show_tracks(GtkAction *action)
188 {
189 _show_tracks ^= TRACKS_MASK;
190 if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
191         _show_tracks |= TRACKS_MASK;
192         map_render_paths();
193         MACRO_QUEUE_DRAW_AREA();
194         MACRO_BANNER_SHOW_INFO(_window, _("Tracks are now shown"));
195 } else {
196         _show_tracks &= ~TRACKS_MASK;
197         map_force_redraw();
198         MACRO_BANNER_SHOW_INFO(_window, _("Tracks are now hidden"));
199 }
200 return TRUE;
201 }
202
203 gboolean 
204 menu_cb_show_scale(GtkAction * action)
205 {
206 _show_scale = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
207 MACRO_QUEUE_DRAW_AREA();
208 return TRUE;
209 }
210
211 gboolean 
212 menu_cb_show_routes(GtkAction * action)
213 {
214 if (gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action))) {
215         _show_tracks |= ROUTES_MASK;
216         map_render_paths();
217         MACRO_QUEUE_DRAW_AREA();
218         MACRO_BANNER_SHOW_INFO(_window, _("Routes are now shown"));
219 } else {
220         _show_tracks &= ~ROUTES_MASK;
221         map_force_redraw();
222         MACRO_BANNER_SHOW_INFO(_window, _("Routes are now hidden"));
223 }
224 return TRUE;
225 }
226
227 gboolean 
228 menu_cb_show_velvec(GtkAction * action)
229 {
230 _show_velvec = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
231 map_move_mark();
232 return TRUE;
233 }
234
235 gboolean 
236 menu_cb_show_poi(GtkAction * action)
237 {
238 _show_poi = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
239 map_force_redraw();
240 return TRUE;
241 }
242
243 gboolean 
244 menu_cb_gps_show_info(GtkAction * action)
245 {
246 _gps_info = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action));
247 gps_show_info(_gps);
248 return TRUE;
249 }
250
251 gboolean
252 menu_cb_autocenter(GtkAction *action, GtkRadioAction *current)
253 {
254 guint new_center_unitx, new_center_unity;
255 gint value = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (current));
256
257 switch (value) {
258         case CENTER_LEAD:
259                 _center_mode = CENTER_LEAD;
260                 MACRO_BANNER_SHOW_INFO(_window, _("Auto-Center Mode: Lead"));
261         break;
262         case CENTER_LATLON:
263                 _center_mode = CENTER_LATLON;
264                 MACRO_BANNER_SHOW_INFO(_window, _("Auto-Center Mode: Lat/Lon"));
265         break;
266         case CENTER_MANUAL:
267         default:
268                 _center_mode = -_center_mode;
269                 MACRO_BANNER_SHOW_INFO(_window, _("Auto-Center Off"));
270                 return TRUE;
271         break;
272 }
273
274 MACRO_RECALC_CENTER(_gps->data, new_center_unitx, new_center_unity);
275 map_center_unit(new_center_unitx, new_center_unity);
276 return TRUE;
277 }
278
279 gboolean 
280 menu_cb_goto_latlon(GtkAction * action)
281 {
282 map_dialog_goto_latlon();
283 return TRUE;
284 }
285
286 gboolean 
287 menu_cb_goto_home(GtkAction *action)
288 {
289 if (map_goto_position(&_home)==FALSE) {
290         MACRO_BANNER_SHOW_INFO(_window, _("Home not set."));
291 } else {
292         map_set_zoom(3);
293         MACRO_BANNER_SHOW_INFO(_window, _("At home location"));
294 }
295 return TRUE;
296 }
297
298 gboolean 
299 menu_cb_goto_destination(GtkAction *action)
300 {
301 if (map_goto_position(&_dest)==FALSE) {
302         MACRO_BANNER_SHOW_INFO(_window, _("Destination not set."));
303 } else {
304         map_set_zoom(3);
305         MACRO_BANNER_SHOW_INFO(_window, _("At destination"));
306 }
307 return TRUE;
308 }
309
310 gboolean 
311 menu_cb_goto_gps(GtkAction *action)
312 {
313 _center_mode = CENTER_LATLON;
314 map_center_unit(_gps->data.unitx, _gps->data.unity);
315 map_update_location_from_center();
316 MACRO_BANNER_SHOW_INFO(_window, _("At GPS coordinates."));
317 return TRUE;
318 }
319
320 gboolean 
321 menu_cb_goto_nextway(GtkAction * action)
322 {
323 if (_next_way && _next_way->point->unity) {
324         if (_center_mode > 0)
325                 set_action_activate("autocenter_none", TRUE);
326
327         map_center_unit(_next_way->point->unitx, _next_way->point->unity);
328 } else {
329         MACRO_BANNER_SHOW_INFO(_window, _("There is no next waypoint."));
330 }
331
332 return TRUE;
333 }
334
335 gboolean 
336 menu_cb_goto_nearpoi(GtkAction * action)
337 {
338 gdouble lat, lon;
339 poi_info *p;
340
341 if (_center_mode > 0) {
342         /* Auto-Center is enabled - use the GPS position. */
343         lat=_gps->data.lat;
344         lon=_gps->data.lon;
345 } else {
346         /* Auto-Center is disabled - use the view center. */
347         unit2latlon(_center.unitx, _center.unity, lat, lon);
348 }
349
350 p=poi_find_nearest(lat, lon);
351
352 if (p) {
353         guint unitx, unity;
354         gchar *banner;
355
356         latlon2unit(p->lat, p->lon, unitx, unity);
357         banner = g_strdup_printf("%s (%s)", p->label, p->cat_label);
358         g_printf("%s\n", banner);
359         MACRO_BANNER_SHOW_INFO(_window, banner);
360         g_free(banner);
361         poi_free(p);
362
363         if (_center_mode > 0)
364                 set_action_activate("autocenter_none", TRUE);
365
366         map_center_unit(unitx, unity);
367         map_update_location_from_center();
368 } else {
369         MACRO_BANNER_SHOW_INFO(_window, _("No POIs found."));
370 }
371
372 return TRUE;
373 }
374
375 gboolean 
376 menu_cb_maps_repoman(GtkAction * action)
377 {
378 repoman_dialog();
379 return TRUE;
380 }
381
382 gboolean 
383 menu_cb_maps_select(GtkAction * action, gpointer new_repo)
384 {
385 repo_set_curr(new_repo);
386 map_force_redraw();
387 return TRUE;
388 }
389
390 gboolean 
391 cb_zoom_auto(GtkAction * action)
392 {
393 map_set_autozoom(TRUE, _gps->data.speed);
394 return TRUE;
395 }
396
397 gboolean 
398 cb_zoom_base(GtkAction * action)
399 {
400 map_set_autozoom(FALSE, 0);
401 map_set_zoom(3);
402 return TRUE;
403 }
404
405 gboolean 
406 cb_zoomin(GtkAction * action)
407 {
408 map_set_autozoom(FALSE, 0);
409 g_idle_add((GSourceFunc)map_zoom_in, NULL);
410 return TRUE;
411 }
412
413 gboolean 
414 cb_zoomout(GtkAction * action)
415 {
416 map_set_autozoom(FALSE, 0);
417 g_idle_add((GSourceFunc)map_zoom_out, NULL);
418 return TRUE;
419 }
420
421 gboolean 
422 cb_fullscreen(GtkAction * action)
423 {
424 if ((_fullscreen = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)))) {
425         gtk_window_fullscreen(GTK_WINDOW(_window));
426 } else {
427         gtk_window_unfullscreen(GTK_WINDOW(_window));
428 }
429 gtk_idle_add((GSourceFunc) window_present, NULL);
430 return TRUE;
431 }
432
433 gboolean 
434 menu_cb_enable_gps(GtkAction * action)
435 {
436 if ((_enable_gps = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)))) {
437         if (_gps->io.address) {
438                 gps_conn_set_state(_gps, RCVR_DOWN);
439                 gps_connect_now(_gps);
440         } else {
441                 popup_error(_window, _("Cannot enable GPS until a GPS Receiver has been configured in the GPS Settings dialog."));
442                 set_action_activate("gps_enabled", FALSE);
443         }
444 } else {
445         if (_gps->io.conn > RCVR_OFF)
446                 gps_conn_set_state(_gps, RCVR_OFF);
447         gps_disconnect(_gps);
448         track_add(NULL);
449         _speed_excess=FALSE;
450 }
451 if (_enable_gps==FALSE)
452         set_action_activate("autocenter_none", TRUE);
453 set_action_sensitive("goto_gps", _enable_gps);
454 set_action_sensitive("autocenter_latlon", _enable_gps);
455 set_action_sensitive("autocenter_lead", _enable_gps);
456
457 map_move_mark();
458 gps_show_info(&_gps->data);
459
460 return TRUE;
461 }
462
463 gboolean 
464 menu_cb_auto_download(GtkAction * action)
465 {
466 if ((_auto_download = gtk_toggle_action_get_active(GTK_TOGGLE_ACTION(action)) )) {
467         if (_curr_repo->url == REPOTYPE_NONE)
468                 popup_error(_window, _("NOTE: You must set a Map URI in the current repository in order to download maps."));
469         map_force_redraw();
470 }
471
472 return TRUE;
473 }
474
475 gboolean 
476 menu_cb_settings(GtkAction * action)
477 {
478 settings_dialog();
479 MACRO_RECALC_FOCUS_BASE();
480 MACRO_RECALC_FOCUS_SIZE();
481 map_force_redraw();
482 return TRUE;
483 }
484
485 gboolean 
486 menu_cb_settings_gps(GtkAction * action)
487 {
488 if (settings_dialog_gps(_gps)) {
489         /* Settings have changed - reconnect to receiver. */
490         if (_enable_gps) {
491                 gps_conn_set_state(_gps, RCVR_DOWN);
492                 gps_disconnect(_gps);
493                 gps_connect_now(_gps);
494         }
495 }
496 MACRO_RECALC_FOCUS_BASE();
497 MACRO_RECALC_FOCUS_SIZE();
498 map_force_redraw();
499 return TRUE;
500 }
501
502 gboolean 
503 menu_cb_settings_colors(GtkAction * action)
504 {
505 settings_dialog_colors();
506 map_force_redraw();
507 return TRUE;
508 }
509
510 gboolean 
511 menu_cb_settings_osm(GtkAction * action)
512 {
513 settings_dialog_osm();
514 return TRUE;
515 }
516
517 gboolean 
518 menu_cb_help(GtkAction * action)
519 {
520 help_topic_display(HELP_ID_INTRO, 0);
521 return TRUE;
522 }
523
524 gboolean 
525 menu_cb_about(GtkAction * action)
526 {
527 gchar *authors[]={
528         "Kaj-Michael Lang",
529         "John Costigan",
530         "Cezary Jackiewicz", NULL
531 };
532
533 gtk_show_about_dialog(GTK_WINDOW(_window), 
534         "name", "Mapper",
535         "version", VERSION, 
536         "copyright", "Kaj-Michael Lang",
537         "license", "GPL",
538         "authors", authors,
539         NULL);
540 return TRUE;
541 }
542
543 gboolean 
544 window_cb_key_press(GtkWidget * widget, GdkEventKey * event)
545 {
546 CustomKey custom_key;
547
548 switch (event->keyval) {
549         case HILDON_HARDKEY_UP:
550                 custom_key = CUSTOM_KEY_UP;
551         break;
552         case HILDON_HARDKEY_DOWN:
553                 custom_key = CUSTOM_KEY_DOWN;
554         break;
555         case HILDON_HARDKEY_LEFT:
556                 custom_key = CUSTOM_KEY_LEFT;
557         break;
558         case HILDON_HARDKEY_RIGHT:
559                 custom_key = CUSTOM_KEY_RIGHT;
560         break;
561         case HILDON_HARDKEY_SELECT:
562                 custom_key = CUSTOM_KEY_SELECT;
563         break;
564         case HILDON_HARDKEY_INCREASE:
565                 custom_key = CUSTOM_KEY_INCREASE;
566         break;
567         case HILDON_HARDKEY_DECREASE:
568                 custom_key = CUSTOM_KEY_DECREASE;
569         break;
570         case HILDON_HARDKEY_FULLSCREEN:
571                 custom_key = CUSTOM_KEY_FULLSCREEN;
572         break;
573         case HILDON_HARDKEY_ESC:
574                 custom_key = CUSTOM_KEY_ESC;
575         break;
576         default:
577                 return FALSE;
578 }
579
580         switch (_action[custom_key]) {
581         case CUSTOM_ACTION_PAN_NORTH:
582                 map_pan(0, -PAN_UNITS);
583         break;
584         case CUSTOM_ACTION_PAN_WEST:
585                 map_pan(-PAN_UNITS, 0);
586         break;
587         case CUSTOM_ACTION_PAN_SOUTH:
588                 map_pan(0, PAN_UNITS);
589         break;
590         case CUSTOM_ACTION_PAN_EAST:
591                 map_pan(PAN_UNITS, 0);
592         break;
593         case CUSTOM_ACTION_TOGGLE_AUTOCENTER:
594                 switch (_center_mode) {
595                 case CENTER_LATLON:
596                 case CENTER_WAS_LEAD:
597                         set_action_activate("autocenter_lead", TRUE);
598                 break;
599                 case CENTER_LEAD:
600                 case CENTER_WAS_LATLON:
601                         set_action_activate("autocenter_latlon", TRUE);
602                 break;
603                 default:
604                         set_action_activate("autocenter_latlon", TRUE);
605                 break;
606                 }
607         break;
608         case CUSTOM_ACTION_ZOOM_IN:
609         case CUSTOM_ACTION_ZOOM_OUT:
610                 if (!_key_zoom_timeout_sid) {
611                         _key_zoom_new = _zoom + (_action[custom_key] == CUSTOM_ACTION_ZOOM_IN ? -_curr_repo->view_zoom_steps : _curr_repo->view_zoom_steps);
612                         /* Remember, _key_zoom_new is unsigned. */
613                         if (_key_zoom_new < MAX_ZOOM) {
614                                 _key_zoom_timeout_sid = g_timeout_add(400, map_key_zoom_timeout, NULL);
615                         }
616                 }
617         break;
618         case CUSTOM_ACTION_TOGGLE_FULLSCREEN:
619                 set_action_activate("view_fullscreen", !_fullscreen);
620         break;
621         case CUSTOM_ACTION_TOGGLE_TRACKS:
622                 switch (_show_tracks) {
623                 case 0:
624                         /* Nothing shown, nothing saved; just set both. */
625                         _show_tracks = TRACKS_MASK | ROUTES_MASK;
626                         break;
627                 case TRACKS_MASK << 16:
628                 case ROUTES_MASK << 16:
629                 case (ROUTES_MASK | TRACKS_MASK) << 16:
630                         /* Something was saved and nothing changed since.
631                          * Restore saved. */
632                         _show_tracks = _show_tracks >> 16;
633                         break;
634                 default:
635                         /* There is no history, or they changed something
636                          * since the last historical change. Save and
637                          * clear. */
638                         _show_tracks = _show_tracks << 16;
639                 }
640                 set_action_activate("view_route", _show_tracks & ROUTES_MASK);
641                 set_action_activate("view_track", _show_tracks & TRACKS_MASK);
642         break;
643         case CUSTOM_ACTION_TOGGLE_SCALE:
644                 set_action_activate("view_scale", _show_scale);
645         break;
646         case CUSTOM_ACTION_TOGGLE_POI:
647                 set_action_activate("view_poi", _show_poi);
648         break;
649         case CUSTOM_ACTION_CHANGE_REPO: {
650                         GList *curr = g_list_find(_repo_list, _curr_repo);
651                         if (!curr)
652                                 break;
653
654                         /* Loop until we reach a next-able repo, or until we get
655                          * back to the current repo. */
656                         while ((curr = (curr->next ? curr->next : _repo_list)) && !((RepoData *) curr->data)->nextable && curr->data != _curr_repo) {
657                         }
658
659                         if (curr->data != _curr_repo) {
660                                 repo_set_curr(curr->data);
661                                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(_curr_repo->menu_item), TRUE);
662                         } else {
663                                 popup_error(_window, _("There are no other next-able repositories."));
664                         }
665                         break;
666                 }
667         break;
668         case CUSTOM_ACTION_ROUTE_DISTNEXT:
669                 route_show_distance_to_next();
670         break;
671         case CUSTOM_ACTION_ROUTE_DISTLAST:
672                 route_show_distance_to_last();
673         break;
674         case CUSTOM_ACTION_TRACK_BREAK:
675                 track_insert_break();
676         break;
677         case CUSTOM_ACTION_TRACK_DISTLAST:
678                 track_show_distance_from_last();
679         break;
680         case CUSTOM_ACTION_TRACK_DISTFIRST:
681                 track_show_distance_from_first();
682         break;
683         case CUSTOM_ACTION_TOGGLE_GPS:
684                 set_action_activate("gps_enable", !_enable_gps);
685         break;
686         case CUSTOM_ACTION_TOGGLE_GPSINFO:
687                 set_action_activate("gps_info", !_gps_info);
688         break;
689         case CUSTOM_ACTION_TOGGLE_SPEEDLIMIT:
690                 _speed_on ^= 1;
691         break;
692         default:
693                 return FALSE;
694 }
695 return TRUE;
696 }
697
698 gboolean 
699 window_cb_key_release(GtkWidget * widget, GdkEventKey * event)
700 {
701 switch (event->keyval) {
702         case HILDON_HARDKEY_INCREASE:
703         case HILDON_HARDKEY_DECREASE:
704                 if (_key_zoom_timeout_sid) {
705                         g_source_remove(_key_zoom_timeout_sid);
706                         _key_zoom_timeout_sid = 0;
707                         map_set_zoom(_key_zoom_new);
708                 }
709         return TRUE;
710         break;
711         default:
712                 return FALSE;
713 }
714 }
715
716 void 
717 cmenu_show_latlon(guint unitx, guint unity)
718 {
719 gdouble lat, lon;
720 gchar buffer[80], tmp1[16], tmp2[16];
721
722 unit2latlon(unitx, unity, lat, lon);
723 lat_format(_degformat, lat, tmp1);
724 lon_format(_degformat, lon, tmp2);
725
726 g_snprintf(buffer, sizeof(buffer),
727          "%s: %s\n"
728          "%s: %s", _("Latitude"), tmp1, _("Longitude"), tmp2);
729
730 MACRO_BANNER_SHOW_INFO(_window, buffer);
731 }
732
733 void 
734 cmenu_clip_latlon(guint unitx, guint unity)
735 {
736 gchar buffer[80];
737 gdouble lat, lon;
738
739 unit2latlon(unitx, unity, lat, lon);
740 g_snprintf(buffer, sizeof(buffer), "%.06f,%.06f", lat, lon);
741
742 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1);
743 }
744
745 void 
746 cmenu_route_to(guint unitx, guint unity)
747 {
748 gchar buffer[80];
749 gchar strlat[32];
750 gchar strlon[32];
751 gdouble lat, lon;
752
753 unit2latlon(unitx, unity, lat, lon);
754
755 g_ascii_formatd(strlat, 32, "%.06f", lat);
756 g_ascii_formatd(strlon, 32, "%.06f", lon);
757 g_snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
758
759 route_download(buffer);
760 }
761
762 void 
763 cmenu_distance_to(guint unitx, guint unity)
764 {
765 gchar buffer[80];
766 gdouble lat, lon;
767
768 unit2latlon(unitx, unity, lat, lon);
769
770 g_snprintf(buffer, sizeof(buffer), "%s: %.02lf %s", _("Distance"),
771          calculate_distance(_gps->data.lat, _gps->data.lon, lat, lon) * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
772 MACRO_BANNER_SHOW_INFO(_window, buffer);
773 }
774
775 void 
776 cmenu_add_route(guint unitx, guint unity)
777 {
778 MACRO_PATH_INCREMENT_TAIL(_route);
779 _route.tail->unitx = x2unit(_cmenu_position_x);
780 _route.tail->unity = y2unit(_cmenu_position_y);
781 route_find_nearest_point();
782 map_force_redraw();
783 }
784
785 void cmenu_route_add_way(guint unitx, guint unity)
786 {
787 gdouble lat, lon;
788 gchar tmp1[16], tmp2[16], *p_latlon;
789 GtkWidget *dialog;
790 GtkWidget *table;
791 GtkWidget *label;
792 GtkWidget *txt_scroll;
793 GtkWidget *txt_desc;
794
795 dialog = gtk_dialog_new_with_buttons(_("Add Waypoint"),
796                              GTK_WINDOW(_window),
797                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
798                              GTK_RESPONSE_ACCEPT,
799                              GTK_STOCK_CANCEL,
800                              GTK_RESPONSE_REJECT, NULL);
801
802         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
803                            table = gtk_table_new(2, 2, FALSE), TRUE, TRUE, 0);
804
805         gtk_table_attach(GTK_TABLE(table),
806                          label = gtk_label_new(_("Lat, Lon")),
807                          0, 1, 0, 1, GTK_FILL, 0, 2, 4);
808         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
809
810         unit2latlon(unitx, unity, lat, lon);
811         lat_format(_degformat, lat, tmp1);
812         lon_format(_degformat, lon, tmp2);
813         p_latlon = g_strdup_printf("%s, %s", tmp1, tmp2);
814         gtk_table_attach(GTK_TABLE(table),
815                          label = gtk_label_new(p_latlon),
816                          1, 2, 0, 1, GTK_FILL, 0, 2, 4);
817         gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
818         g_free(p_latlon);
819
820         gtk_table_attach(GTK_TABLE(table),
821                          label = gtk_label_new(_("Description")),
822                          0, 1, 1, 2, GTK_FILL, 0, 2, 4);
823         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
824
825         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
826         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
827                                             GTK_SHADOW_IN);
828         gtk_table_attach(GTK_TABLE(table),
829                          txt_scroll,
830                          1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
831
832         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
833                                        GTK_POLICY_AUTOMATIC,
834                                        GTK_POLICY_AUTOMATIC);
835
836         txt_desc = gtk_text_view_new();
837         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
838
839         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
840         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
841
842         gtk_widget_show_all(dialog);
843
844         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
845                 GtkTextBuffer *tbuf;
846                 GtkTextIter ti1, ti2;
847                 gchar *desc;
848
849                 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
850                 gtk_text_buffer_get_iter_at_offset(tbuf, &ti1, 0);
851                 gtk_text_buffer_get_end_iter(tbuf, &ti2);
852                 desc = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
853
854                 if (*desc) {
855                         /* There's a description.  Add a waypoint. */
856                         MACRO_PATH_INCREMENT_TAIL(_route);
857                         _route.tail->unitx = unitx;
858                         _route.tail->unity = unity;
859                         _route.tail->time = 0;
860                         _route.tail->altitude = NAN;
861
862                         MACRO_PATH_INCREMENT_WTAIL(_route);
863                         _route.wtail->point = _route.tail;
864                         _route.wtail->desc
865                             = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
866                 } else {
867                         GtkWidget *confirm;
868
869                         g_free(desc);
870
871                         confirm = hildon_note_new_confirmation(GTK_WINDOW(dialog),
872                                                          _("Creating a \"waypoint\" with no description actually "
873                                                           "adds a break point.  Is that what you want?"));
874
875                         if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
876                                 /* There's no description.  Add a break by adding a (0, 0)
877                                  * point (if necessary), and then the ordinary route point. */
878                                 if (_route.tail->unity) {
879                                         MACRO_PATH_INCREMENT_TAIL(_route);
880                                         *_route.tail = _point_null;
881                                 }
882
883                                 MACRO_PATH_INCREMENT_TAIL(_route);
884                                 _route.tail->unitx = unitx;
885                                 _route.tail->unity = unity;
886                                 _route.tail->time = 0;
887                                 _route.tail->altitude = NAN;
888
889                                 gtk_widget_destroy(confirm);
890                         } else {
891                                 gtk_widget_destroy(confirm);
892                                 continue;
893                         }
894                 }
895
896                 route_find_nearest_point();
897                 map_render_paths();
898                 MACRO_QUEUE_DRAW_AREA();
899                 break;
900         }
901 gtk_widget_destroy(dialog);
902 }
903
904 gboolean 
905 cmenu_cb_loc_show_latlon(GtkAction * action)
906 {
907 cmenu_show_latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
908 return TRUE;
909 }
910
911 gboolean 
912 cmenu_cb_loc_clip_latlon(GtkAction * action)
913 {
914 cmenu_clip_latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
915 return TRUE;
916 }
917
918 gboolean 
919 cmenu_cb_loc_route_to(GtkAction * action)
920 {
921 cmenu_route_to(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
922 return TRUE;
923 }
924
925 gboolean 
926 cmenu_cb_loc_distance_to(GtkAction * action)
927 {
928 cmenu_distance_to(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
929 return TRUE;
930 }
931
932 gboolean 
933 cmenu_cb_loc_add_route(GtkAction * action)
934 {
935 cmenu_add_route(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
936 return TRUE;
937 }
938
939 gboolean 
940 cmenu_cb_loc_add_way(GtkAction * action)
941 {
942 cmenu_route_add_way(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
943 return TRUE;
944 }
945
946 gboolean 
947 cmenu_cb_loc_add_poi(GtkAction * action)
948 {
949 guint ux, uy;
950 poi_info *poi;
951
952 poi=poi_new();
953 ux=x2unit(_cmenu_position_x);
954 uy=y2unit(_cmenu_position_y);
955 unit2latlon(ux, uy, poi->lat, poi->lon);
956 poi_edit_dialog(ACTION_ADD_POI, poi);
957
958 return TRUE;
959 }
960
961 gboolean
962 cb_poi_search(GtkAction *action)
963 {
964 poi_info poi;
965 gdouble lat, lon;
966
967 if (_center_mode>0) {
968         lat=_gps->data.lat;
969         lon=_gps->data.lon;
970 } else {
971         unit2latlon(_center.unitx, _center.unity, lat, lon);
972 }
973
974 mapper_search_dialog(SEARCH_TYPE_POI, lat, lon);
975 return TRUE;
976 }
977
978 gboolean 
979 cb_poi_add(GtkAction *action)
980 {
981 gdouble lat,lon;
982 const gchar *name = gtk_action_get_name(action);
983 poi_info *p;
984
985 if (_center_mode>0) {
986         lat=_gps->data.lat;
987         lon=_gps->data.lon;
988 } else {
989         unit2latlon(_center.unitx, _center.unity, lat, lon);
990 }
991
992 if (strcmp(name, "poi_add")==0) {
993         p=poi_new();
994         p->lat=lat;
995         p->lon=lon;
996         poi_edit_dialog(ACTION_ADD_POI, p);
997         map_poi_cache_clear();
998 } else if (strcmp(name, "poi_quick_add")==0) {
999         poi_quick_dialog(lat, lon);
1000         map_poi_cache_clear();
1001 } else
1002         g_assert_not_reached();
1003
1004 return TRUE;
1005 }
1006
1007 gboolean
1008 menu_cb_search_address(GtkAction *action)
1009 {
1010 gdouble lat, lon;
1011
1012 if (_center_mode>0) {
1013         lat=_gps->data.lat;
1014         lon=_gps->data.lon;
1015 } else {
1016         unit2latlon(_center.unitx, _center.unity, lat, lon);
1017 }
1018 mapper_search_dialog(SEARCH_TYPE_WAY, lat, lon);
1019 return TRUE;
1020 }
1021
1022 gboolean 
1023 cmenu_cb_loc_set_home(GtkAction * action)
1024 {
1025 guint unitx, unity;
1026
1027 unitx = x2unit(_cmenu_position_x);
1028 unity = y2unit(_cmenu_position_y);
1029 unit2latlon(unitx, unity, _home.lat, _home.lon);
1030 _home.valid=TRUE;
1031
1032 config_save_home();
1033 map_render_data();
1034 return TRUE;
1035 }
1036
1037 gboolean 
1038 cmenu_cb_loc_set_destination(GtkAction *action)
1039 {
1040 guint unitx, unity;
1041
1042 unitx = x2unit(_cmenu_position_x);
1043 unity = y2unit(_cmenu_position_y);
1044 unit2latlon(unitx, unity, _dest.lat, _dest.lon);
1045 _dest.valid=TRUE;
1046 #if 0
1047 map_update_location_from_center();
1048 #endif
1049 return TRUE;
1050 }
1051
1052 gboolean 
1053 cmenu_cb_loc_set_gps(GtkAction * action)
1054 {
1055 _gps->data.unitx = x2unit(_cmenu_position_x);
1056 _gps->data.unity = y2unit(_cmenu_position_y);
1057 unit2latlon(_gps->data.unitx, _gps->data.unity, _gps->data.lat, _gps->data.lon);
1058
1059 /* Move mark to new location. */
1060 map_refresh_mark();
1061 _gps->data.time=time(NULL);
1062 track_add(&_gps->data);
1063
1064 return TRUE;
1065 }
1066
1067 gboolean 
1068 cmenu_cb_way_show_latlon(GtkAction * action)
1069 {
1070 WayPoint *way;
1071
1072 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1073                 cmenu_show_latlon(way->point->unitx, way->point->unity);
1074
1075 return TRUE;
1076 }
1077
1078 gboolean 
1079 cmenu_cb_way_show_desc(GtkAction * action)
1080 {
1081 WayPoint *way;
1082
1083 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1084         MACRO_BANNER_SHOW_INFO(_window, way->desc);
1085 }
1086
1087 return TRUE;
1088 }
1089
1090 gboolean 
1091 cmenu_cb_way_clip_latlon(GtkAction * action)
1092 {
1093 WayPoint *way;
1094
1095 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1096                 cmenu_clip_latlon(way->point->unitx, way->point->unity);
1097 return TRUE;
1098 }
1099
1100 gboolean 
1101 cmenu_cb_way_clip_desc(GtkAction * action)
1102 {
1103 WayPoint *way;
1104
1105 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1106         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), way->desc, -1);
1107
1108 return TRUE;
1109 }
1110
1111 gboolean 
1112 cmenu_cb_way_route_to(GtkAction * action)
1113 {
1114 WayPoint *way;
1115
1116 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1117         cmenu_route_to(way->point->unitx, way->point->unity);
1118
1119 return TRUE;
1120 }
1121
1122 gboolean 
1123 cmenu_cb_way_distance_to(GtkAction * action)
1124 {
1125 WayPoint *way;
1126
1127 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1128         route_show_distance_to(way->point);
1129
1130 return TRUE;
1131 }
1132
1133 gboolean 
1134 cmenu_cb_way_delete(GtkAction * action)
1135 {
1136 WayPoint *way;
1137
1138 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1139         gchar buffer[BUFFER_SIZE];
1140         GtkWidget *confirm;
1141
1142         g_snprintf(buffer, sizeof(buffer), "%s:\n%s\n", _("Confirm delete of waypoint"), way->desc);
1143         confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
1144
1145         if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
1146                 Point *pdel_min, *pdel_max, *pdel_start, *pdel_end;
1147                 guint num_del;
1148
1149                 /* Delete surrounding route data, too. */
1150                 if (way == _route.whead)
1151                         pdel_min = _route.head;
1152                 else
1153                         pdel_min = way[-1].point;
1154
1155                 if (way == _route.wtail)
1156                         pdel_max = _route.tail;
1157                 else
1158                         pdel_max = way[1].point;
1159
1160                 /* Find largest continuous segment around the waypoint, EXCLUDING
1161                  * pdel_min and pdel_max. */
1162                 for (pdel_start = way->point - 1; pdel_start->unity
1163                      && pdel_start > pdel_min; pdel_start--) {
1164                 }
1165                 for (pdel_end = way->point + 1; pdel_end->unity
1166                      && pdel_end < pdel_max; pdel_end++) {
1167                 }
1168
1169                 /* If pdel_end is set to _route.tail, and if _route.tail is a
1170                  * non-zero point, then delete _route.tail. */
1171                 if (pdel_end == _route.tail && pdel_end->unity)
1172                         pdel_end++;     /* delete _route.tail too */
1173                 /* else, if *both* endpoints are zero points, delete one. */
1174                 else if (!pdel_start->unity && !pdel_end->unity)
1175                         pdel_start--;
1176
1177                 /* Delete BETWEEN pdel_start and pdel_end, exclusive. */
1178                 num_del = pdel_end - pdel_start - 1;
1179
1180                 memmove(pdel_start + 1, pdel_end,(_route.tail - pdel_end + 1) * sizeof(Point));
1181                 _route.tail -= num_del;
1182
1183                 /* Remove waypoint and move/adjust subsequent waypoints. */
1184                 g_free(way->desc);
1185                 while (way++ != _route.wtail) {
1186                         way[-1] = *way;
1187                         way[-1].point -= num_del;
1188                 }
1189                 _route.wtail--;
1190
1191                 route_find_nearest_point();
1192                 map_force_redraw();
1193         }
1194         gtk_widget_destroy(confirm);
1195 }
1196
1197 return TRUE;
1198 }
1199
1200 gboolean
1201 menu_cb_category(GtkAction * action)
1202 {
1203 if (poi_category_list())
1204         map_force_redraw();
1205
1206 return TRUE;
1207 }
1208
1209 gboolean 
1210 cmenu_cb_way_add_poi(GtkAction * action)
1211 {
1212 WayPoint *way;
1213
1214 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1215         poi_info *p;
1216
1217         p=poi_new();
1218         unit2latlon(way->point->unitx, way->point->unity, p->lat, p->lon);
1219         poi_edit_dialog(ACTION_ADD_POI, p);
1220 }
1221 return TRUE;
1222 }
1223
1224 gboolean 
1225 cmenu_cb_poi_route_to(GtkAction * action)
1226 {
1227 poi_info poi;
1228
1229 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1230         guint unitx, unity;
1231         latlon2unit(poi.lat, poi.lon, unitx, unity);
1232         cmenu_route_to(unitx, unity);
1233 }
1234
1235 return TRUE;
1236 }
1237
1238 gboolean 
1239 cmenu_cb_poi_distance_to(GtkAction * action)
1240 {
1241 poi_info poi;
1242
1243 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1244         guint unitx, unity;
1245         latlon2unit(poi.lat, poi.lon, unitx, unity);
1246         cmenu_distance_to(unitx, unity);
1247 }
1248
1249 return TRUE;
1250 }
1251
1252 gboolean 
1253 cmenu_cb_poi_add_route(GtkAction * action)
1254 {
1255 poi_info poi;
1256
1257 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1258         guint unitx, unity;
1259         latlon2unit(poi.lat, poi.lon, unitx, unity);
1260         cmenu_add_route(unitx, unity);
1261 }
1262
1263 return TRUE;
1264 }
1265
1266 gboolean 
1267 cmenu_cb_poi_add_way(GtkAction * action)
1268 {
1269 poi_info poi;
1270
1271 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1272         guint unitx, unity;
1273         latlon2unit(poi.lat, poi.lon, unitx, unity);
1274         cmenu_route_add_way(unitx, unity);
1275 }
1276
1277 return TRUE;
1278 }
1279
1280 gboolean
1281 cmenu_cb_poi_show_poi(GtkAction *action)
1282 {
1283 /* XXX: Write this */
1284 return TRUE;
1285 }
1286
1287 gboolean 
1288 cmenu_cb_poi_edit_poi(GtkAction * action)
1289 {
1290 poi_info *p;
1291 gdouble lat, lon;
1292
1293 unit2latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), lat, lon);
1294 p=poi_find_nearest(lat, lon);
1295 if (!p) {
1296         popup_error(_window, _("No POI found at location."));
1297         return TRUE;
1298 }
1299 poi_edit_dialog(ACTION_EDIT_POI, p);
1300 return TRUE;
1301 }