]> err.no Git - mapper/blob - src/cb.c
Get rid of _pos, move data to gpsdata struct.
[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 <fcntl.h>
39 #include <libintl.h>
40 #include <locale.h>
41
42 #include "hildon-mapper.h"
43
44 #include "utils.h"
45 #include "poi.h"
46 #include "path.h"
47 #include "route.h"
48 #include "track.h"
49 #include "settings.h"
50 #include "gps.h"
51 #include "map.h"
52 #include "mapper-types.h"
53 #include "bt.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(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->unitx, _gps->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->lat;
344         lon=_gps->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);
394 return TRUE;
395 }
396
397 gboolean 
398 cb_zoom_base(GtkAction * action)
399 {
400 map_set_autozoom(FALSE);
401 map_set_zoom(3);
402 return TRUE;
403 }
404
405 gboolean 
406 cb_zoomin(GtkAction * action)
407 {
408 map_set_autozoom(FALSE);
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);
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 (_rcvr_mac) {
438                 gps_conn_set_state(RCVR_DOWN);
439                 rcvr_connect_now();
440         } else {
441                 popup_error(_window, _("Cannot enable GPS until a GPS Receiver MAC is set in the Settings dialog box."));
442                 set_action_activate("gps_enable", FALSE);
443         }
444 } else {
445         if (_conn_state > RCVR_OFF)
446                 gps_conn_set_state(RCVR_OFF);
447         rcvr_disconnect();
448         track_add(0, FALSE);
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);
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 if (settings_dialog()) {
479         /* Settings have changed - reconnect to receiver. */
480         if (_enable_gps) {
481                 gps_conn_set_state(RCVR_DOWN);
482                 rcvr_disconnect();
483                 rcvr_connect_now();
484         }
485 }
486 MACRO_RECALC_FOCUS_BASE();
487 MACRO_RECALC_FOCUS_SIZE();
488 map_force_redraw();
489 return TRUE;
490 }
491
492 gboolean 
493 menu_cb_help(GtkAction * action)
494 {
495 help_topic_display(HELP_ID_INTRO, 0);
496 return TRUE;
497 }
498
499 gboolean 
500 menu_cb_about(GtkAction * action)
501 {
502 gchar *authors[]={
503         "Kaj-Michael Lang",
504         "John Costigan",
505         "Cezary Jackiewicz", NULL
506 };
507
508 gtk_show_about_dialog(GTK_WINDOW(_window), 
509         "name", "Mapper",
510         "version", VERSION, 
511         "copyright", "Kaj-Michael Lang",
512         "license", "GPL",
513         "authors", authors,
514         NULL);
515 return TRUE;
516 }
517
518 gboolean 
519 window_cb_key_press(GtkWidget * widget, GdkEventKey * event)
520 {
521 CustomKey custom_key;
522
523 switch (event->keyval) {
524         case HILDON_HARDKEY_UP:
525                 custom_key = CUSTOM_KEY_UP;
526         break;
527         case HILDON_HARDKEY_DOWN:
528                 custom_key = CUSTOM_KEY_DOWN;
529         break;
530         case HILDON_HARDKEY_LEFT:
531                 custom_key = CUSTOM_KEY_LEFT;
532         break;
533         case HILDON_HARDKEY_RIGHT:
534                 custom_key = CUSTOM_KEY_RIGHT;
535         break;
536         case HILDON_HARDKEY_SELECT:
537                 custom_key = CUSTOM_KEY_SELECT;
538         break;
539         case HILDON_HARDKEY_INCREASE:
540                 custom_key = CUSTOM_KEY_INCREASE;
541         break;
542         case HILDON_HARDKEY_DECREASE:
543                 custom_key = CUSTOM_KEY_DECREASE;
544         break;
545         case HILDON_HARDKEY_FULLSCREEN:
546                 custom_key = CUSTOM_KEY_FULLSCREEN;
547         break;
548         case HILDON_HARDKEY_ESC:
549                 custom_key = CUSTOM_KEY_ESC;
550         break;
551         default:
552                 return FALSE;
553 }
554
555         switch (_action[custom_key]) {
556         case CUSTOM_ACTION_PAN_NORTH:
557                 map_pan(0, -PAN_UNITS);
558         break;
559         case CUSTOM_ACTION_PAN_WEST:
560                 map_pan(-PAN_UNITS, 0);
561         break;
562         case CUSTOM_ACTION_PAN_SOUTH:
563                 map_pan(0, PAN_UNITS);
564         break;
565         case CUSTOM_ACTION_PAN_EAST:
566                 map_pan(PAN_UNITS, 0);
567         break;
568         case CUSTOM_ACTION_TOGGLE_AUTOCENTER:
569                 switch (_center_mode) {
570                 case CENTER_LATLON:
571                 case CENTER_WAS_LEAD:
572                         set_action_activate("autocenter_lead", TRUE);
573                 break;
574                 case CENTER_LEAD:
575                 case CENTER_WAS_LATLON:
576                         set_action_activate("autocenter_latlon", TRUE);
577                 break;
578                 default:
579                         set_action_activate("autocenter_latlon", TRUE);
580                 break;
581                 }
582         break;
583         case CUSTOM_ACTION_ZOOM_IN:
584         case CUSTOM_ACTION_ZOOM_OUT:
585                 if (!_key_zoom_timeout_sid) {
586                         _key_zoom_new = _zoom + (_action[custom_key] == CUSTOM_ACTION_ZOOM_IN ? -_curr_repo->view_zoom_steps : _curr_repo->view_zoom_steps);
587                         /* Remember, _key_zoom_new is unsigned. */
588                         if (_key_zoom_new < MAX_ZOOM) {
589                                 _key_zoom_timeout_sid = g_timeout_add(400, map_key_zoom_timeout, NULL);
590                         }
591                 }
592         break;
593         case CUSTOM_ACTION_TOGGLE_FULLSCREEN:
594                 set_action_activate("view_fullscreen", !_fullscreen);
595         break;
596         case CUSTOM_ACTION_TOGGLE_TRACKS:
597                 switch (_show_tracks) {
598                 case 0:
599                         /* Nothing shown, nothing saved; just set both. */
600                         _show_tracks = TRACKS_MASK | ROUTES_MASK;
601                         break;
602                 case TRACKS_MASK << 16:
603                 case ROUTES_MASK << 16:
604                 case (ROUTES_MASK | TRACKS_MASK) << 16:
605                         /* Something was saved and nothing changed since.
606                          * Restore saved. */
607                         _show_tracks = _show_tracks >> 16;
608                         break;
609                 default:
610                         /* There is no history, or they changed something
611                          * since the last historical change. Save and
612                          * clear. */
613                         _show_tracks = _show_tracks << 16;
614                 }
615                 set_action_activate("view_route", _show_tracks & ROUTES_MASK);
616                 set_action_activate("view_track", _show_tracks & TRACKS_MASK);
617         break;
618         case CUSTOM_ACTION_TOGGLE_SCALE:
619                 set_action_activate("view_scale", _show_scale);
620         break;
621         case CUSTOM_ACTION_TOGGLE_POI:
622                 set_action_activate("view_poi", _show_poi);
623         break;
624         case CUSTOM_ACTION_CHANGE_REPO: {
625                         GList *curr = g_list_find(_repo_list, _curr_repo);
626                         if (!curr)
627                                 break;
628
629                         /* Loop until we reach a next-able repo, or until we get
630                          * back to the current repo. */
631                         while ((curr = (curr->next ? curr->next : _repo_list)) && !((RepoData *) curr->data)->nextable && curr->data != _curr_repo) {
632                         }
633
634                         if (curr->data != _curr_repo) {
635                                 repo_set_curr(curr->data);
636                                 gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(_curr_repo->menu_item), TRUE);
637                         } else {
638                                 popup_error(_window, _("There are no other next-able repositories."));
639                         }
640                         break;
641                 }
642         break;
643         case CUSTOM_ACTION_ROUTE_DISTNEXT:
644                 route_show_distance_to_next();
645         break;
646         case CUSTOM_ACTION_ROUTE_DISTLAST:
647                 route_show_distance_to_last();
648         break;
649         case CUSTOM_ACTION_TRACK_BREAK:
650                 track_insert_break();
651         break;
652         case CUSTOM_ACTION_TRACK_DISTLAST:
653                 track_show_distance_from_last();
654         break;
655         case CUSTOM_ACTION_TRACK_DISTFIRST:
656                 track_show_distance_from_first();
657         break;
658         case CUSTOM_ACTION_TOGGLE_GPS:
659                 set_action_activate("gps_enable", !_enable_gps);
660         break;
661         case CUSTOM_ACTION_TOGGLE_GPSINFO:
662                 set_action_activate("gps_info", !_gps_info);
663         break;
664         case CUSTOM_ACTION_TOGGLE_SPEEDLIMIT:
665                 _speed_on ^= 1;
666         break;
667         default:
668                 return FALSE;
669 }
670 return TRUE;
671 }
672
673 gboolean 
674 window_cb_key_release(GtkWidget * widget, GdkEventKey * event)
675 {
676 switch (event->keyval) {
677         case HILDON_HARDKEY_INCREASE:
678         case HILDON_HARDKEY_DECREASE:
679                 if (_key_zoom_timeout_sid) {
680                         g_source_remove(_key_zoom_timeout_sid);
681                         _key_zoom_timeout_sid = 0;
682                         map_set_zoom(_key_zoom_new);
683                 }
684         return TRUE;
685         break;
686         default:
687                 return FALSE;
688 }
689 }
690
691 void 
692 cmenu_show_latlon(guint unitx, guint unity)
693 {
694 gdouble lat, lon;
695 gchar buffer[80], tmp1[16], tmp2[16];
696
697 unit2latlon(unitx, unity, lat, lon);
698 lat_format(_degformat, lat, tmp1);
699 lon_format(_degformat, lon, tmp2);
700
701 g_snprintf(buffer, sizeof(buffer),
702          "%s: %s\n"
703          "%s: %s", _("Latitude"), tmp1, _("Longitude"), tmp2);
704
705 MACRO_BANNER_SHOW_INFO(_window, buffer);
706 }
707
708 void 
709 cmenu_clip_latlon(guint unitx, guint unity)
710 {
711 gchar buffer[80];
712 gdouble lat, lon;
713
714 unit2latlon(unitx, unity, lat, lon);
715 g_snprintf(buffer, sizeof(buffer), "%.06f,%.06f", lat, lon);
716
717 gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), buffer, -1);
718 }
719
720 void 
721 cmenu_route_to(guint unitx, guint unity)
722 {
723 gchar buffer[80];
724 gchar strlat[32];
725 gchar strlon[32];
726 gdouble lat, lon;
727
728 unit2latlon(unitx, unity, lat, lon);
729
730 g_ascii_formatd(strlat, 32, "%.06f", lat);
731 g_ascii_formatd(strlon, 32, "%.06f", lon);
732 g_snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
733
734 route_download(buffer);
735 }
736
737 void 
738 cmenu_distance_to(guint unitx, guint unity)
739 {
740 gchar buffer[80];
741 gdouble lat, lon;
742
743 unit2latlon(unitx, unity, lat, lon);
744
745 g_snprintf(buffer, sizeof(buffer), "%s: %.02lf %s", _("Distance"),
746          calculate_distance(_gps->lat, _gps->lon, lat, lon) * UNITS_CONVERT[_units], UNITS_TEXT[_units]);
747 MACRO_BANNER_SHOW_INFO(_window, buffer);
748 }
749
750 void 
751 cmenu_add_route(guint unitx, guint unity)
752 {
753 MACRO_PATH_INCREMENT_TAIL(_route);
754 _route.tail->unitx = x2unit(_cmenu_position_x);
755 _route.tail->unity = y2unit(_cmenu_position_y);
756 route_find_nearest_point();
757 map_force_redraw();
758 }
759
760 void cmenu_route_add_way(guint unitx, guint unity)
761 {
762 gdouble lat, lon;
763 gchar tmp1[16], tmp2[16], *p_latlon;
764 GtkWidget *dialog;
765 GtkWidget *table;
766 GtkWidget *label;
767 GtkWidget *txt_scroll;
768 GtkWidget *txt_desc;
769
770 dialog = gtk_dialog_new_with_buttons(_("Add Waypoint"),
771                              GTK_WINDOW(_window),
772                              GTK_DIALOG_MODAL, GTK_STOCK_OK,
773                              GTK_RESPONSE_ACCEPT,
774                              GTK_STOCK_CANCEL,
775                              GTK_RESPONSE_REJECT, NULL);
776
777         gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
778                            table = gtk_table_new(2, 2, FALSE), TRUE, TRUE, 0);
779
780         gtk_table_attach(GTK_TABLE(table),
781                          label = gtk_label_new(_("Lat, Lon")),
782                          0, 1, 0, 1, GTK_FILL, 0, 2, 4);
783         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
784
785         unit2latlon(unitx, unity, lat, lon);
786         lat_format(_degformat, lat, tmp1);
787         lon_format(_degformat, lon, tmp2);
788         p_latlon = g_strdup_printf("%s, %s", tmp1, tmp2);
789         gtk_table_attach(GTK_TABLE(table),
790                          label = gtk_label_new(p_latlon),
791                          1, 2, 0, 1, GTK_FILL, 0, 2, 4);
792         gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f);
793         g_free(p_latlon);
794
795         gtk_table_attach(GTK_TABLE(table),
796                          label = gtk_label_new(_("Description")),
797                          0, 1, 1, 2, GTK_FILL, 0, 2, 4);
798         gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
799
800         txt_scroll = gtk_scrolled_window_new(NULL, NULL);
801         gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
802                                             GTK_SHADOW_IN);
803         gtk_table_attach(GTK_TABLE(table),
804                          txt_scroll,
805                          1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
806
807         gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
808                                        GTK_POLICY_AUTOMATIC,
809                                        GTK_POLICY_AUTOMATIC);
810
811         txt_desc = gtk_text_view_new();
812         gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
813
814         gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
815         gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
816
817         gtk_widget_show_all(dialog);
818
819         while (GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
820                 GtkTextBuffer *tbuf;
821                 GtkTextIter ti1, ti2;
822                 gchar *desc;
823
824                 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
825                 gtk_text_buffer_get_iter_at_offset(tbuf, &ti1, 0);
826                 gtk_text_buffer_get_end_iter(tbuf, &ti2);
827                 desc = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
828
829                 if (*desc) {
830                         /* There's a description.  Add a waypoint. */
831                         MACRO_PATH_INCREMENT_TAIL(_route);
832                         _route.tail->unitx = unitx;
833                         _route.tail->unity = unity;
834                         _route.tail->time = 0;
835                         _route.tail->altitude = NAN;
836
837                         MACRO_PATH_INCREMENT_WTAIL(_route);
838                         _route.wtail->point = _route.tail;
839                         _route.wtail->desc
840                             = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
841                 } else {
842                         GtkWidget *confirm;
843
844                         g_free(desc);
845
846                         confirm = hildon_note_new_confirmation(GTK_WINDOW(dialog),
847                                                          _("Creating a \"waypoint\" with no description actually "
848                                                           "adds a break point.  Is that what you want?"));
849
850                         if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
851                                 /* There's no description.  Add a break by adding a (0, 0)
852                                  * point (if necessary), and then the ordinary route point. */
853                                 if (_route.tail->unity) {
854                                         MACRO_PATH_INCREMENT_TAIL(_route);
855                                         *_route.tail = _point_null;
856                                 }
857
858                                 MACRO_PATH_INCREMENT_TAIL(_route);
859                                 _route.tail->unitx = unitx;
860                                 _route.tail->unity = unity;
861                                 _route.tail->time = 0;
862                                 _route.tail->altitude = NAN;
863
864                                 gtk_widget_destroy(confirm);
865                         } else {
866                                 gtk_widget_destroy(confirm);
867                                 continue;
868                         }
869                 }
870
871                 route_find_nearest_point();
872                 map_render_paths();
873                 MACRO_QUEUE_DRAW_AREA();
874                 break;
875         }
876 gtk_widget_destroy(dialog);
877 }
878
879 gboolean 
880 cmenu_cb_loc_show_latlon(GtkAction * action)
881 {
882 cmenu_show_latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
883 return TRUE;
884 }
885
886 gboolean 
887 cmenu_cb_loc_clip_latlon(GtkAction * action)
888 {
889 cmenu_clip_latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
890 return TRUE;
891 }
892
893 gboolean 
894 cmenu_cb_loc_route_to(GtkAction * action)
895 {
896 cmenu_route_to(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
897 return TRUE;
898 }
899
900 gboolean 
901 cmenu_cb_loc_distance_to(GtkAction * action)
902 {
903 cmenu_distance_to(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
904 return TRUE;
905 }
906
907 gboolean 
908 cmenu_cb_loc_add_route(GtkAction * action)
909 {
910 cmenu_add_route(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
911 return TRUE;
912 }
913
914 gboolean 
915 cmenu_cb_loc_add_way(GtkAction * action)
916 {
917 cmenu_route_add_way(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y));
918 return TRUE;
919 }
920
921 gboolean 
922 cmenu_cb_loc_add_poi(GtkAction * action)
923 {
924 guint ux, uy;
925 poi_info *poi;
926
927 poi=poi_new();
928 ux=x2unit(_cmenu_position_x);
929 uy=y2unit(_cmenu_position_y);
930 unit2latlon(ux, uy, poi->lat, poi->lon);
931 poi_edit_dialog(ACTION_ADD_POI, poi);
932
933 return TRUE;
934 }
935
936 gboolean
937 cb_poi_search(GtkAction *action)
938 {
939 poi_info poi;
940 gdouble lat, lon;
941
942 if (_center_mode>0) {
943         lat=_gps->lat;
944         lon=_gps->lon;
945 } else {
946         unit2latlon(_center.unitx, _center.unity, lat, lon);
947 }
948
949 mapper_search_dialog(SEARCH_TYPE_POI, lat, lon);
950 return TRUE;
951 }
952
953 gboolean 
954 cb_poi_add(GtkAction *action)
955 {
956 gdouble lat,lon;
957 const gchar *name = gtk_action_get_name(action);
958 poi_info *p;
959
960 if (_center_mode>0) {
961         lat=_gps->lat;
962         lon=_gps->lon;
963 } else {
964         unit2latlon(_center.unitx, _center.unity, lat, lon);
965 }
966
967 if (strcmp(name, "poi_add")==0) {
968         p=poi_new();
969         p->lat=lat;
970         p->lon=lon;
971         poi_edit_dialog(ACTION_ADD_POI, p);
972         map_poi_cache_clear();
973 } else if (strcmp(name, "poi_quick_add")==0) {
974         poi_quick_dialog(lat, lon);
975         map_poi_cache_clear();
976 } else
977         g_assert_not_reached();
978
979 return TRUE;
980 }
981
982 gboolean
983 menu_cb_search_address(GtkAction *action)
984 {
985 gdouble lat, lon;
986
987 if (_center_mode>0) {
988         lat=_gps->lat;
989         lon=_gps->lon;
990 } else {
991         unit2latlon(_center.unitx, _center.unity, lat, lon);
992 }
993 mapper_search_dialog(SEARCH_TYPE_WAY, lat, lon);
994 return TRUE;
995 }
996
997 gboolean 
998 cmenu_cb_loc_set_home(GtkAction * action)
999 {
1000 guint unitx, unity;
1001
1002 unitx = x2unit(_cmenu_position_x);
1003 unity = y2unit(_cmenu_position_y);
1004 unit2latlon(unitx, unity, _home.lat, _home.lon);
1005 _home.valid=TRUE;
1006
1007 config_save_home();
1008 map_render_data();
1009 return TRUE;
1010 }
1011
1012 gboolean 
1013 cmenu_cb_loc_set_destination(GtkAction *action)
1014 {
1015 guint unitx, unity;
1016
1017 unitx = x2unit(_cmenu_position_x);
1018 unity = y2unit(_cmenu_position_y);
1019 unit2latlon(unitx, unity, _dest.lat, _dest.lon);
1020 _dest.valid=TRUE;
1021 #if 0
1022 map_update_location_from_center();
1023 #endif
1024 return TRUE;
1025 }
1026
1027 gboolean 
1028 cmenu_cb_loc_set_gps(GtkAction * action)
1029 {
1030 _gps->unitx = x2unit(_cmenu_position_x);
1031 _gps->unity = y2unit(_cmenu_position_y);
1032 unit2latlon(_gps->unitx, _gps->unity, _gps->lat, _gps->lon);
1033
1034 /* Move mark to new location. */
1035 map_refresh_mark();
1036 track_add(time(NULL), FALSE);
1037
1038 return TRUE;
1039 }
1040
1041 gboolean 
1042 cmenu_cb_way_show_latlon(GtkAction * action)
1043 {
1044 WayPoint *way;
1045
1046 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1047                 cmenu_show_latlon(way->point->unitx, way->point->unity);
1048
1049 return TRUE;
1050 }
1051
1052 gboolean 
1053 cmenu_cb_way_show_desc(GtkAction * action)
1054 {
1055 WayPoint *way;
1056
1057 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1058         MACRO_BANNER_SHOW_INFO(_window, way->desc);
1059 }
1060
1061 return TRUE;
1062 }
1063
1064 gboolean 
1065 cmenu_cb_way_clip_latlon(GtkAction * action)
1066 {
1067 WayPoint *way;
1068
1069 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1070                 cmenu_clip_latlon(way->point->unitx, way->point->unity);
1071 return TRUE;
1072 }
1073
1074 gboolean 
1075 cmenu_cb_way_clip_desc(GtkAction * action)
1076 {
1077 WayPoint *way;
1078
1079 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1080         gtk_clipboard_set_text(gtk_clipboard_get(GDK_SELECTION_CLIPBOARD), way->desc, -1);
1081
1082 return TRUE;
1083 }
1084
1085 gboolean 
1086 cmenu_cb_way_route_to(GtkAction * action)
1087 {
1088 WayPoint *way;
1089
1090 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1091         cmenu_route_to(way->point->unitx, way->point->unity);
1092
1093 return TRUE;
1094 }
1095
1096 gboolean 
1097 cmenu_cb_way_distance_to(GtkAction * action)
1098 {
1099 WayPoint *way;
1100
1101 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y))))
1102         route_show_distance_to(way->point);
1103
1104 return TRUE;
1105 }
1106
1107 gboolean 
1108 cmenu_cb_way_delete(GtkAction * action)
1109 {
1110 WayPoint *way;
1111
1112 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1113         gchar buffer[BUFFER_SIZE];
1114         GtkWidget *confirm;
1115
1116         g_snprintf(buffer, sizeof(buffer), "%s:\n%s\n", _("Confirm delete of waypoint"), way->desc);
1117         confirm = hildon_note_new_confirmation(GTK_WINDOW(_window), buffer);
1118
1119         if (GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
1120                 Point *pdel_min, *pdel_max, *pdel_start, *pdel_end;
1121                 guint num_del;
1122
1123                 /* Delete surrounding route data, too. */
1124                 if (way == _route.whead)
1125                         pdel_min = _route.head;
1126                 else
1127                         pdel_min = way[-1].point;
1128
1129                 if (way == _route.wtail)
1130                         pdel_max = _route.tail;
1131                 else
1132                         pdel_max = way[1].point;
1133
1134                 /* Find largest continuous segment around the waypoint, EXCLUDING
1135                  * pdel_min and pdel_max. */
1136                 for (pdel_start = way->point - 1; pdel_start->unity
1137                      && pdel_start > pdel_min; pdel_start--) {
1138                 }
1139                 for (pdel_end = way->point + 1; pdel_end->unity
1140                      && pdel_end < pdel_max; pdel_end++) {
1141                 }
1142
1143                 /* If pdel_end is set to _route.tail, and if _route.tail is a
1144                  * non-zero point, then delete _route.tail. */
1145                 if (pdel_end == _route.tail && pdel_end->unity)
1146                         pdel_end++;     /* delete _route.tail too */
1147                 /* else, if *both* endpoints are zero points, delete one. */
1148                 else if (!pdel_start->unity && !pdel_end->unity)
1149                         pdel_start--;
1150
1151                 /* Delete BETWEEN pdel_start and pdel_end, exclusive. */
1152                 num_del = pdel_end - pdel_start - 1;
1153
1154                 memmove(pdel_start + 1, pdel_end,(_route.tail - pdel_end + 1) * sizeof(Point));
1155                 _route.tail -= num_del;
1156
1157                 /* Remove waypoint and move/adjust subsequent waypoints. */
1158                 g_free(way->desc);
1159                 while (way++ != _route.wtail) {
1160                         way[-1] = *way;
1161                         way[-1].point -= num_del;
1162                 }
1163                 _route.wtail--;
1164
1165                 route_find_nearest_point();
1166                 map_force_redraw();
1167         }
1168         gtk_widget_destroy(confirm);
1169 }
1170
1171 return TRUE;
1172 }
1173
1174 gboolean
1175 menu_cb_category(GtkAction * action)
1176 {
1177 if (poi_category_list())
1178         map_force_redraw();
1179
1180 return TRUE;
1181 }
1182
1183 gboolean 
1184 cmenu_cb_way_add_poi(GtkAction * action)
1185 {
1186 WayPoint *way;
1187
1188 if ((way = find_nearest_waypoint(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y)))) {
1189         poi_info *p;
1190
1191         p=poi_new();
1192         unit2latlon(way->point->unitx, way->point->unity, p->lat, p->lon);
1193         poi_edit_dialog(ACTION_ADD_POI, p);
1194 }
1195 return TRUE;
1196 }
1197
1198 gboolean 
1199 cmenu_cb_poi_route_to(GtkAction * action)
1200 {
1201 poi_info poi;
1202
1203 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1204         guint unitx, unity;
1205         latlon2unit(poi.lat, poi.lon, unitx, unity);
1206         cmenu_route_to(unitx, unity);
1207 }
1208
1209 return TRUE;
1210 }
1211
1212 gboolean 
1213 cmenu_cb_poi_distance_to(GtkAction * action)
1214 {
1215 poi_info poi;
1216
1217 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1218         guint unitx, unity;
1219         latlon2unit(poi.lat, poi.lon, unitx, unity);
1220         cmenu_distance_to(unitx, unity);
1221 }
1222
1223 return TRUE;
1224 }
1225
1226 gboolean 
1227 cmenu_cb_poi_add_route(GtkAction * action)
1228 {
1229 poi_info poi;
1230
1231 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1232         guint unitx, unity;
1233         latlon2unit(poi.lat, poi.lon, unitx, unity);
1234         cmenu_add_route(unitx, unity);
1235 }
1236
1237 return TRUE;
1238 }
1239
1240 gboolean 
1241 cmenu_cb_poi_add_way(GtkAction * action)
1242 {
1243 poi_info poi;
1244
1245 if (poi_select(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), 4, &poi)) {
1246         guint unitx, unity;
1247         latlon2unit(poi.lat, poi.lon, unitx, unity);
1248         cmenu_route_add_way(unitx, unity);
1249 }
1250
1251 return TRUE;
1252 }
1253
1254 gboolean
1255 cmenu_cb_poi_show_poi(GtkAction *action)
1256 {
1257 /* XXX: Write this */
1258 return TRUE;
1259 }
1260
1261 gboolean 
1262 cmenu_cb_poi_edit_poi(GtkAction * action)
1263 {
1264 poi_info *p;
1265 gdouble lat, lon;
1266
1267 unit2latlon(x2unit(_cmenu_position_x), y2unit(_cmenu_position_y), lat, lon);
1268 p=poi_find_nearest(lat, lon);
1269 if (!p) {
1270         popup_error(_window, _("No POI found at location."));
1271         return TRUE;
1272 }
1273 poi_edit_dialog(ACTION_EDIT_POI, p);
1274 return TRUE;
1275 }