2 * Copyright (C) 2006, 2007 John Costigan.
4 * POI and GPS-Info code originally written by Cezary Jackiewicz.
6 * Default map data provided by http://www.openstreetmap.org/
8 * This file is part of Maemo Mapper.
10 * Maemo Mapper is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * (at your option) any later version.
15 * Maemo Mapper is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with Maemo Mapper. If not, see <http://www.gnu.org/licenses/>.
37 # include <hildon/hildon-help.h>
38 # include <hildon/hildon-note.h>
39 # include <hildon/hildon-banner.h>
40 # include <hildon/hildon-sound.h>
42 # include <osso-helplib.h>
43 # include <hildon-widgets/hildon-note.h>
44 # include <hildon-widgets/hildon-banner.h>
45 # include <hildon-widgets/hildon-system-sound.h>
46 # include <hildon-widgets/hildon-input-mode-hint.h>
54 #include "gdk-pixbuf-rotate.h"
61 typedef struct _RouteDownloadInfo RouteDownloadInfo;
62 struct _RouteDownloadInfo {
63 GtkWidget *rad_use_gps;
64 GtkWidget *rad_use_route;
65 GtkWidget *rad_use_text;
66 GtkWidget *chk_avoid_highways;
72 /* _near_point is the route point to which we are closest. */
73 static Point *_near_point = NULL;
75 /* _next_way is what we currently interpret to be the next waypoint. */
76 static WayPoint *_next_way;
77 static gint64 _next_way_dist_squared = INT64_MAX;
79 /* _next_wpt is the route point immediately following _next_way. */
80 static Point *_next_wpt = NULL;
81 static gint64 _next_wpt_dist_squared = INT64_MAX;
83 static gfloat _initial_distance_from_waypoint = -1.f;
84 static WayPoint *_initial_distance_waypoint = NULL;
86 static sqlite3 *_path_db = NULL;
87 static sqlite3_stmt *_track_stmt_select = NULL;
88 static sqlite3_stmt *_track_stmt_delete_path = NULL;
89 static sqlite3_stmt *_track_stmt_delete_way = NULL;
90 static sqlite3_stmt *_track_stmt_insert_path = NULL;
91 static sqlite3_stmt *_track_stmt_insert_way = NULL;
92 static sqlite3_stmt *_route_stmt_select = NULL;
93 static sqlite3_stmt *_route_stmt_delete_path = NULL;
94 static sqlite3_stmt *_route_stmt_delete_way = NULL;
95 static sqlite3_stmt *_route_stmt_insert_path = NULL;
96 static sqlite3_stmt *_route_stmt_insert_way = NULL;
97 static sqlite3_stmt *_path_stmt_trans_begin = NULL;
98 static sqlite3_stmt *_path_stmt_trans_commit = NULL;
99 static sqlite3_stmt *_path_stmt_trans_rollback = NULL;
101 static gchar *_last_spoken_phrase;
104 path_resize(Path *path, gint size)
106 printf("%s()\n", __PRETTY_FUNCTION__);
108 if(path->head + size != path->cap)
110 Point *old_head = path->head;
112 path->head = g_renew(Point, old_head, size);
113 path->cap = path->head + size;
114 if(path->head != old_head)
116 path->tail = path->head + (path->tail - old_head);
118 /* Adjust all of the waypoints. */
119 for(curr = path->whead - 1; curr++ != path->wtail; )
120 curr->point = path->head + (curr->point - old_head);
124 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
128 path_wresize(Path *path, gint wsize)
130 printf("%s()\n", __PRETTY_FUNCTION__);
132 if(path->whead + wsize != path->wcap)
134 WayPoint *old_whead = path->whead;
135 path->whead = g_renew(WayPoint, old_whead, wsize);
136 path->wtail = path->whead + (path->wtail - old_whead);
137 path->wcap = path->whead + wsize;
140 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
144 read_path_from_db(Path *path, sqlite3_stmt *select_stmt)
146 printf("%s()\n", __PRETTY_FUNCTION__);
148 MACRO_PATH_INIT(*path);
149 while(SQLITE_ROW == sqlite3_step(select_stmt))
153 MACRO_PATH_INCREMENT_TAIL(*path);
154 path->tail->unitx = sqlite3_column_int(select_stmt, 0);
155 path->tail->unity = sqlite3_column_int(select_stmt, 1);
156 path->tail->time = sqlite3_column_int(select_stmt, 2);
157 path->tail->altitude = sqlite3_column_int(select_stmt, 3);
159 desc = sqlite3_column_text(select_stmt, 4);
162 MACRO_PATH_INCREMENT_WTAIL(*path);
163 path->wtail->point = path->tail;
164 path->wtail->desc = g_strdup(desc);
167 sqlite3_reset(select_stmt);
169 /* If the last point isn't null, then add another null point. */
170 if(path->tail->unity)
172 MACRO_PATH_INCREMENT_TAIL(*path);
173 *path->tail = _point_null;
176 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
179 /* Returns the new next_update_index. */
181 write_path_to_db(Path *path,
182 sqlite3_stmt *delete_path_stmt,
183 sqlite3_stmt *delete_way_stmt,
184 sqlite3_stmt *insert_path_stmt,
185 sqlite3_stmt *insert_way_stmt,
186 gint index_last_saved)
191 gboolean success = TRUE;
192 printf("%s(%d)\n", __PRETTY_FUNCTION__, index_last_saved);
194 /* Start transaction. */
195 sqlite3_step(_path_stmt_trans_begin);
196 sqlite3_reset(_path_stmt_trans_begin);
198 if(index_last_saved == 0)
200 /* Replace the whole thing, so delete the table first. */
201 if(SQLITE_DONE != sqlite3_step(delete_way_stmt)
202 || SQLITE_DONE != sqlite3_step(delete_path_stmt))
204 gchar buffer[BUFFER_SIZE];
205 snprintf(buffer, sizeof(buffer), "%s\n%s",
206 _("Failed to write to path database. "
207 "Tracks and routes may not be saved."),
208 sqlite3_errmsg(_path_db));
209 popup_error(_window, buffer);
212 sqlite3_reset(delete_way_stmt);
213 sqlite3_reset(delete_path_stmt);
216 for(num = index_last_saved, curr = path->head + num, wcurr = path->whead;
217 success && ++curr <= path->tail; ++num)
219 /* If this is the last point, and it is null, don't write it. */
220 if(curr == path->tail && !curr->unity)
223 /* Insert the path point. */
224 if(SQLITE_OK != sqlite3_bind_int(insert_path_stmt, 1, curr->unitx)
225 || SQLITE_OK != sqlite3_bind_int(insert_path_stmt, 2, curr->unity)
226 || SQLITE_OK != sqlite3_bind_int(insert_path_stmt, 3, curr->time)
227 || SQLITE_OK != sqlite3_bind_int(insert_path_stmt, 4, curr->altitude)
228 || SQLITE_DONE != sqlite3_step(insert_path_stmt))
230 gchar buffer[BUFFER_SIZE];
231 snprintf(buffer, sizeof(buffer), "%s\n%s",
232 _("Failed to write to path database. "
233 "Tracks and routes may not be saved."),
234 sqlite3_errmsg(_path_db));
235 popup_error(_window, buffer);
238 sqlite3_reset(insert_path_stmt);
240 /* Now, check if curr is a waypoint. */
241 if(success && wcurr <= path->wtail && wcurr->point == curr)
243 gint num = sqlite3_last_insert_rowid(_path_db);
244 if(SQLITE_OK != sqlite3_bind_int(insert_way_stmt, 1, num)
245 || SQLITE_OK != sqlite3_bind_text(insert_way_stmt, 2, wcurr->desc,
247 || SQLITE_DONE != sqlite3_step(insert_way_stmt))
249 gchar buffer[BUFFER_SIZE];
250 snprintf(buffer, sizeof(buffer), "%s\n%s",
251 _("Failed to write to path database. "
252 "Tracks and routes may not be saved."),
253 sqlite3_errmsg(_path_db));
254 popup_error(_window, buffer);
257 sqlite3_reset(insert_way_stmt);
263 sqlite3_step(_path_stmt_trans_commit);
264 sqlite3_reset(_path_stmt_trans_commit);
265 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
270 sqlite3_step(_path_stmt_trans_rollback);
271 sqlite3_reset(_path_stmt_trans_rollback);
272 vprintf("%s(): return 0\n", __PRETTY_FUNCTION__);
273 return index_last_saved;
278 path_save_route_to_db()
282 write_path_to_db(&_route,
283 _route_stmt_delete_path,
284 _route_stmt_delete_way,
285 _route_stmt_insert_path,
286 _route_stmt_insert_way,
292 path_save_track_to_db()
296 write_path_to_db(&_track,
297 _track_stmt_delete_path,
298 _track_stmt_delete_way,
299 _track_stmt_insert_path,
300 _track_stmt_insert_way,
306 path_update_track_in_db()
310 _track_index_last_saved = write_path_to_db(&_track,
311 _track_stmt_delete_path,
312 _track_stmt_delete_way,
313 _track_stmt_insert_path,
314 _track_stmt_insert_way,
315 _track_index_last_saved);
320 * Updates _near_point, _next_way, and _next_wpt. If quick is FALSE (as
321 * it is when this function is called from route_find_nearest_point), then
322 * the entire list (starting from _near_point) is searched. Otherwise, we
323 * stop searching when we find a point that is farther away.
326 route_update_nears(gboolean quick)
328 gboolean ret = FALSE;
330 WayPoint *wcurr, *wnext;
331 gint64 near_dist_squared;
332 printf("%s(%d)\n", __PRETTY_FUNCTION__, quick);
334 /* If we have waypoints (_next_way != NULL), then determine the "next
335 * waypoint", which is defined as the waypoint after the nearest point,
336 * UNLESS we've passed that waypoint, in which case the waypoint after
337 * that waypoint becomes the "next" waypoint. */
340 /* First, set near_dist_squared with the new distance from
343 near_dist_squared = DISTANCE_SQUARED(_pos, *near);
345 /* Now, search _route for a closer point. If quick is TRUE, then we'll
346 * only search forward, only as long as we keep finding closer points.
348 for(curr = _near_point; curr++ != _route.tail; )
352 gint64 dist_squared = DISTANCE_SQUARED(_pos, *curr);
353 if(dist_squared <= near_dist_squared)
356 near_dist_squared = dist_squared;
363 /* Update _near_point. */
366 for(wnext = wcurr = _next_way; wcurr < _route.wtail; wcurr++)
368 if(wcurr->point < near
369 /* Okay, this else if expression warrants explanation. If the
370 * nearest track point happens to be a waypoint, then we want to
371 * check if we have "passed" that waypoint. To check this, we
372 * test the distance from _pos to the waypoint and from _pos to
373 * _next_wpt, and if the former is increasing and the latter is
374 * decreasing, then we have passed the waypoint, and thus we
375 * should skip it. Note that if there is no _next_wpt, then
376 * there is no next waypoint, so we do not skip it in that case. */
377 || (wcurr->point == near && quick
379 && (DISTANCE_SQUARED(_pos, *near) > _next_way_dist_squared
380 && DISTANCE_SQUARED(_pos, *_next_wpt)
381 < _next_wpt_dist_squared))))
389 if(wnext == _route.wtail && (wnext->point < near
390 || (wnext->point == near && quick
392 && (DISTANCE_SQUARED(_pos, *near) > _next_way_dist_squared
393 &&DISTANCE_SQUARED(_pos, *_next_wpt)
394 < _next_wpt_dist_squared)))))
398 _next_way_dist_squared = INT64_MAX;
399 _next_wpt_dist_squared = INT64_MAX;
402 /* Only update _next_way (and consequently _next_wpt) if _next_way is
403 * different, and record that fact for return. */
406 if(!quick || _next_way != wnext)
409 _next_wpt = wnext->point;
410 if(_next_wpt == _route.tail)
414 while(!(++_next_wpt)->unity)
416 if(_next_wpt == _route.tail)
425 _next_way_dist_squared = DISTANCE_SQUARED(_pos, *wnext->point);
427 _next_wpt_dist_squared = DISTANCE_SQUARED(_pos, *_next_wpt);
431 vprintf("%s(): return %d\n", __PRETTY_FUNCTION__, ret);
436 * Reset the _near_point data by searching the entire route for the nearest
437 * route point and waypoint.
440 route_find_nearest_point()
442 printf("%s()\n", __PRETTY_FUNCTION__);
444 /* Initialize _near_point to first non-zero point. */
445 _near_point = _route.head;
446 while(!_near_point->unity && _near_point != _route.tail)
449 /* Initialize _next_way. */
450 if(_route.wtail < _route.whead
451 || (_autoroute_data.enabled && _route.wtail == _route.whead))
454 /* We have at least one waypoint. */
455 _next_way = _autoroute_data.enabled ? _route.whead + 1 : _route.whead;
456 _next_way_dist_squared = INT64_MAX;
458 /* Initialize _next_wpt. */
460 _next_wpt_dist_squared = INT64_MAX;
462 route_update_nears(FALSE);
464 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
468 * Show the distance from the current GPS location to the given point,
469 * following the route. If point is NULL, then the distance is shown to the
473 route_show_distance_to(Point *point)
476 gdouble lat1, lon1, lat2, lon2;
478 printf("%s()\n", __PRETTY_FUNCTION__);
480 /* If point is NULL, use the next waypoint. */
481 if(point == NULL && _next_way)
482 point = _next_way->point;
484 /* If point is still NULL, return an error. */
487 printf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
491 unit2latlon(_pos.unitx, _pos.unity, lat1, lon1);
492 if(point > _near_point)
495 /* Skip _near_point in case we have already passed it. */
496 for(curr = _near_point + 1; curr <= point; ++curr)
500 unit2latlon(curr->unitx, curr->unity, lat2, lon2);
501 sum += calculate_distance(lat1, lon1, lat2, lon2);
507 else if(point < _near_point)
510 /* Skip _near_point in case we have already passed it. */
511 for(curr = _near_point - 1; curr >= point; --curr)
515 unit2latlon(curr->unitx, curr->unity, lat2, lon2);
516 sum += calculate_distance(lat1, lon1, lat2, lon2);
524 /* Waypoint _is_ the nearest point. */
525 unit2latlon(_near_point->unitx, _near_point->unity, lat2, lon2);
526 sum += calculate_distance(lat1, lon1, lat2, lon2);
529 snprintf(buffer, sizeof(buffer), "%s: %.02f %s", _("Distance"),
530 sum * UNITS_CONVERT[_units], UNITS_ENUM_TEXT[_units]);
531 MACRO_BANNER_SHOW_INFO(_window, buffer);
534 printf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
538 route_show_distance_to_next()
540 printf("%s()\n", __PRETTY_FUNCTION__);
542 if(!route_show_distance_to(NULL))
544 MACRO_BANNER_SHOW_INFO(_window, _("There is no next waypoint."));
546 printf("%s(): return\n", __PRETTY_FUNCTION__);
550 route_show_distance_to_last()
552 printf("%s()\n", __PRETTY_FUNCTION__);
554 if(_route.head != _route.tail)
556 /* Find last non-zero point. */
558 for(p = _route.tail; !p->unity; p--) { }
559 route_show_distance_to(p);
563 MACRO_BANNER_SHOW_INFO(_window, _("The current route is empty."));
565 printf("%s(): return\n", __PRETTY_FUNCTION__);
569 track_show_distance_from(Point *point)
572 gdouble lat1, lon1, lat2, lon2;
575 unit2latlon(_pos.unitx, _pos.unity, lat1, lon1);
577 /* Skip _track.tail because that should be _pos. */
578 for(curr = _track.tail; curr > point; --curr)
582 unit2latlon(curr->unitx, curr->unity, lat2, lon2);
583 sum += calculate_distance(lat1, lon1, lat2, lon2);
589 snprintf(buffer, sizeof(buffer), "%s: %.02f %s", _("Distance"),
590 sum * UNITS_CONVERT[_units], UNITS_ENUM_TEXT[_units]);
591 MACRO_BANNER_SHOW_INFO(_window, buffer);
595 track_show_distance_from_last()
597 printf("%s()\n", __PRETTY_FUNCTION__);
599 /* Find last zero point. */
600 if(_track.head != _track.tail)
603 /* Find last zero point. */
604 for(point = _track.tail; point->unity; point--) { }
605 track_show_distance_from(point);
609 MACRO_BANNER_SHOW_INFO(_window, _("The current track is empty."));
611 printf("%s(): return\n", __PRETTY_FUNCTION__);
615 track_show_distance_from_first()
617 printf("%s()\n", __PRETTY_FUNCTION__);
619 /* Find last zero point. */
620 if(_track.head != _track.tail)
621 track_show_distance_from(_track.head);
624 MACRO_BANNER_SHOW_INFO(_window, _("The current track is empty."));
626 printf("%s(): return\n", __PRETTY_FUNCTION__);
630 route_download_and_setup(GtkWidget *parent, const gchar *source_url,
631 const gchar *from, const gchar *to,
632 gboolean avoid_highways, gint replace_policy)
639 GnomeVFSResult vfs_result;
640 printf("%s(%s, %s)\n", __PRETTY_FUNCTION__, from, to);
642 from_escaped = gnome_vfs_escape_string(from);
643 to_escaped = gnome_vfs_escape_string(to);
644 buffer = g_strdup_printf(source_url, from_escaped, to_escaped);
645 g_free(from_escaped);
651 buffer = g_strconcat(old, "&avoid_highways=on", NULL);
655 /* Attempt to download the route from the server. */
656 vfs_result = gnome_vfs_read_entire_file(buffer, &size, &bytes);
659 if(vfs_result != GNOME_VFS_OK)
662 popup_error(parent, gnome_vfs_result_to_string(vfs_result));
663 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
667 if(strncmp(bytes, "<?xml", strlen("<?xml")))
669 /* Not an XML document - must be bad locations. */
671 _("Invalid source or destination."));
673 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
676 /* Else, if GPS is enabled, replace the route, otherwise append it. */
677 else if(gpx_path_parse(&_route, bytes, size, replace_policy))
679 path_save_route_to_db();
681 /* Find the nearest route point, if we're connected. */
682 route_find_nearest_point();
686 MACRO_BANNER_SHOW_INFO(_window, _("Route Downloaded"));
689 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
692 popup_error(parent, _("Error parsing GPX file."));
695 vprintf("%s(): return FALSE\n", __PRETTY_FUNCTION__);
700 * This function is periodically run to download updated auto-route data
701 * from the route source.
706 gchar latstr[32], lonstr[32], latlonstr[80];
707 printf("%s(%f, %f, %s)\n", __PRETTY_FUNCTION__,
708 _gps.lat, _gps.lon, _autoroute_data.dest);
710 g_ascii_dtostr(latstr, 32, _gps.lat);
711 g_ascii_dtostr(lonstr, 32, _gps.lon);
712 snprintf(latlonstr, sizeof(latlonstr), "%s, %s", latstr, lonstr);
714 if(!route_download_and_setup(_window, _autoroute_data.source_url, latlonstr,
715 _autoroute_data.dest, _autoroute_data.avoid_highways,0))
718 _autoroute_data.in_progress = FALSE;
720 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
727 printf("%s()\n", __PRETTY_FUNCTION__);
729 route_find_nearest_point();
730 MACRO_MAP_RENDER_DATA();
731 MACRO_QUEUE_DRAW_AREA();
733 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
737 * Add a point to the _track list. This function is slightly overloaded,
738 * since it is what houses the check for "have we moved
739 * significantly": it also initiates the re-calculation of the _near_point
740 * data, as well as calling osso_display_state_on() when we have the focus.
742 * If a non-zero time is given, then the current position (as taken from the
743 * _pos variable) is appended to _track with the given time. If time is zero,
744 * then _point_null is appended to _track with time zero (this produces a
745 * "break" in the track).
748 track_add(time_t time, gboolean newly_fixed)
750 gboolean show_directions = TRUE;
751 gint announce_thres_unsquared;
752 gboolean ret = FALSE;
753 printf("%s(%d, %d, %d, %d)\n", __PRETTY_FUNCTION__,
754 (guint)time, newly_fixed, _pos.unitx, _pos.unity);
756 gboolean moving = FALSE;
757 gboolean approaching_waypoint = FALSE;
758 gint xdiff, ydiff, dopcand;
760 announce_thres_unsquared = (20+_gps.speed) * _announce_notice_ratio*32;
762 if(!_track.tail->unity
763 || ((xdiff = _pos.unitx - _track.tail->unitx), /* comma op */
764 (ydiff = _pos.unity - _track.tail->unity), /* comma op */
765 /* Check if xdiff or ydiff are huge. */
766 ((abs(xdiff) >> 12) || (abs(ydiff) >> 12)
767 /* Okay, let's see if we've moved enough to justify adding
768 * to the track. It depends on our error. I'd like to
769 * make the threshold roughly linear with respect to the
770 * P/HDOP (completely arbitrary, I know), but I also
771 * want to keep the threshold at a minimum of 2
772 * zoom-level-4 pixel, and I want dop's of less than 2 to
773 * also have a 1-pixel threshold. I also throw in some
774 * PDOP into the mix, just for fun. */
775 || ((dopcand = 8 * (_gps.pdop - 6 +(_gps.hdop*_gps.hdop))),
776 ((xdiff * xdiff) + (ydiff * ydiff)
777 >= (MAX(2, dopcand) << 8))))))
779 /* We moved enough to actually register a move. */
782 /* Update the nearest-waypoint data. */
783 if(_route.head != _route.tail
784 && (newly_fixed ? (route_find_nearest_point(), TRUE)
785 : route_update_nears(TRUE)))
787 /* Nearest waypoint has changed - re-render paths. */
789 MACRO_QUEUE_DRAW_AREA();
794 if(_show_paths & TRACKS_MASK)
796 /* Instead of calling map_render_paths(), we'll draw the new
797 * line ourselves and call gtk_widget_queue_draw_area(). */
798 gint tx1, ty1, tx2, ty2;
799 map_render_segment(_gc[COLORABLE_TRACK],
800 _gc[COLORABLE_TRACK_BREAK],
801 _track.tail->unitx, _track.tail->unity,
802 _pos.unitx, _pos.unity);
803 if(_track.tail->unity)
805 unit2screen(_track.tail->unitx, _track.tail->unity,
807 unit2screen(_pos.unitx, _pos.unity, tx2, ty2);
808 gtk_widget_queue_draw_area(_map_widget,
809 MIN(tx1, tx2) - _draw_width,
810 MIN(ty1, ty2) - _draw_width,
811 abs(tx1 - tx2) + (2 * _draw_width),
812 abs(ty1 - ty2) + (2 * _draw_width));
816 MACRO_PATH_INCREMENT_TAIL(_track);
820 /* Calculate distance to route. (point to line) */
823 gint route_x1, route_x2, route_y1, route_y2;
824 gint64 route_dist_squared_1 = INT64_MAX;
825 gint64 route_dist_squared_2 = INT64_MAX;
828 route_x1 = _near_point->unitx;
829 route_y1 = _near_point->unity;
831 /* Try previous point first. */
832 if(_near_point != _route.head && _near_point[-1].unity)
834 route_x2 = _near_point[-1].unitx;
835 route_y2 = _near_point[-1].unity;
836 slope = (gfloat)(route_y2 - route_y1)
837 / (gfloat)(route_x2 - route_x1);
839 if(route_x1 == route_x2)
841 /* Vertical line special case. */
842 route_dist_squared_1 = (_pos.unitx - route_x1)
843 * (_pos.unitx - route_x1);
847 route_dist_squared_1 = abs((slope * _pos.unitx)
848 - _pos.unity + (route_y1 - (slope * route_x1)));
849 route_dist_squared_1 =
850 route_dist_squared_1 * route_dist_squared_1
851 / ((slope * slope) + 1);
854 if(_near_point != _route.tail && _near_point[1].unity)
856 route_x2 = _near_point[1].unitx;
857 route_y2 = _near_point[1].unity;
858 slope = (gfloat)(route_y2 - route_y1)
859 / (gfloat)(route_x2 - route_x1);
861 if(route_x1 == route_x2)
863 /* Vertical line special case. */
864 route_dist_squared_2 = (_pos.unitx - route_x1)
865 * (_pos.unitx - route_x1);
869 route_dist_squared_2 = abs((slope * _pos.unitx)
870 - _pos.unity + (route_y1 - (slope * route_x1)));
871 route_dist_squared_2 =
872 route_dist_squared_2 * route_dist_squared_2
873 / ((slope * slope) + 1);
877 /* Check if our distance from the route is large. */
878 if(MIN(route_dist_squared_1, route_dist_squared_2)
881 /* Prevent announcments from occurring. */
882 announce_thres_unsquared = INT_MAX;
884 if(_autoroute_data.enabled && !_autoroute_data.in_progress)
886 MACRO_BANNER_SHOW_INFO(_window,
887 _("Recalculating directions..."));
888 _autoroute_data.in_progress = TRUE;
889 show_directions = FALSE;
890 g_idle_add((GSourceFunc)auto_route_dl_idle, NULL);
894 /* Reset the route to try and find the nearest point.*/
900 /* Keep the display on. */
904 if(_initial_distance_waypoint
905 && (_next_way != _initial_distance_waypoint
906 || _next_way_dist_squared > (_initial_distance_from_waypoint
907 * _initial_distance_from_waypoint)))
909 /* We've moved on to the next waypoint, or we're really far from
910 * the current waypoint. */
913 gtk_widget_destroy(_waypoint_banner);
914 _waypoint_banner = NULL;
916 _initial_distance_from_waypoint = -1.f;
917 _initial_distance_waypoint = NULL;
920 /* Check if we should announce upcoming waypoints. */
922 && (_initial_distance_waypoint || _next_way_dist_squared
923 < (announce_thres_unsquared * announce_thres_unsquared)))
927 if(!_initial_distance_waypoint)
929 /* First time we're close enough to this waypoint. */
931 /* And that we haven't already announced it. */
932 && strcmp(_next_way->desc, _last_spoken_phrase))
934 g_free(_last_spoken_phrase);
935 _last_spoken_phrase = g_strdup(_next_way->desc);
938 /* We are the fork child. Synthesize the voice. */
939 hildon_play_system_sound(
940 "/usr/share/sounds/ui-information_note.wav");
942 printf("%s %s\n", _voice_synth_path,
943 _last_spoken_phrase);
944 execl(_voice_synth_path, basename(_voice_synth_path),
945 "-t", _last_spoken_phrase, (char *)NULL);
946 /* No good? Try to launch it with /bin/sh */
947 execl("/bin/sh", "sh", _voice_synth_path,
948 "-t", _last_spoken_phrase, (char *)NULL);
949 /* Still no good? Oh well... */
953 _initial_distance_from_waypoint
954 = sqrtf(_next_way_dist_squared);
955 _initial_distance_waypoint = _next_way;
956 if(_next_wpt && _next_wpt->unity != 0)
958 /* Create a banner for us the show progress. */
959 _waypoint_banner = hildon_banner_show_progress(
960 _window, NULL, _next_way->desc);
964 /* This is the last point in a segment, i.e.
965 * "Arrive at ..." - just announce. */
966 MACRO_BANNER_SHOW_INFO(_window, _next_way->desc);
969 else if(_waypoint_banner);
971 /* We're already close to this waypoint. */
972 gdouble fraction = 1.f - (sqrtf(_next_way_dist_squared)
973 / _initial_distance_from_waypoint);
974 BOUND(fraction, 0.f, 1.f);
975 hildon_banner_set_fraction(
976 HILDON_BANNER(_waypoint_banner), fraction);
979 approaching_waypoint = TRUE;
981 else if(_next_way_dist_squared > 2 * (_initial_distance_from_waypoint
982 * _initial_distance_from_waypoint))
984 /* We're too far away now - destroy the banner. */
987 UNBLANK_SCREEN(moving, approaching_waypoint);
989 /* Maybe update the track database. */
991 static time_t last_track_db_update = 0;
992 if(!time || (time - last_track_db_update > 60
993 && _track.tail - _track.head + 1 > _track_index_last_saved))
995 path_update_track_in_db();
996 last_track_db_update = time;
1000 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1009 confirm = hildon_note_new_confirmation(GTK_WINDOW(_window),
1010 _("Really clear the track?"));
1012 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm))) {
1013 MACRO_PATH_FREE(_track);
1014 MACRO_PATH_INIT(_track);
1015 path_save_track_to_db();
1019 gtk_widget_destroy(confirm);
1023 track_insert_break(gboolean temporary)
1025 printf("%s()\n", __PRETTY_FUNCTION__);
1027 if(_track.tail->unity)
1030 unit2screen(_track.tail->unitx, _track.tail->unity, x1, y1);
1032 MACRO_PATH_INCREMENT_TAIL(_track);
1033 *_track.tail = _point_null;
1035 /* To mark a "waypoint" in a track, we'll add a (0, 0) point and then
1036 * another instance of the most recent track point. */
1039 MACRO_PATH_INCREMENT_TAIL(_track);
1040 *_track.tail = _track.tail[-2];
1043 /** Instead of calling map_render_paths(), we'll just add the waypoint
1045 /* Make sure this circle will be visible. */
1046 if((x1 < _view_width_pixels) && (y1 < _view_height_pixels))
1047 gdk_draw_arc(_map_pixmap, _gc[COLORABLE_TRACK_BREAK],
1048 FALSE, /* FALSE: not filled. */
1053 0, /* start at 0 degrees. */
1057 /* Update the track database. */
1058 path_update_track_in_db();
1060 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1064 * Cancel the current auto-route.
1069 printf("%s()\n", __PRETTY_FUNCTION__);
1071 if(_autoroute_data.enabled)
1073 _autoroute_data.enabled = FALSE;
1074 g_free(_autoroute_data.source_url);
1075 _autoroute_data.source_url = NULL;
1076 g_free(_autoroute_data.dest);
1077 _autoroute_data.dest = NULL;
1078 _autoroute_data.in_progress = FALSE;
1081 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1085 find_nearest_waypoint(gint unitx, gint unity)
1089 gint64 nearest_squared;
1090 Point pos = { unitx, unity, 0, INT_MIN };
1091 printf("%s()\n", __PRETTY_FUNCTION__);
1093 wcurr = wnear = _route.whead;
1094 if(wcurr && wcurr <= _route.wtail)
1096 nearest_squared = DISTANCE_SQUARED(pos, *(wcurr->point));
1098 wnear = _route.whead;
1099 while(++wcurr <= _route.wtail)
1101 gint64 test_squared = DISTANCE_SQUARED(pos, *(wcurr->point));
1102 if(test_squared < nearest_squared)
1105 nearest_squared = test_squared;
1109 /* Only use the waypoint if it is within a 6*_draw_width square drawn
1110 * around the position. This is consistent with select_poi(). */
1111 if(abs(unitx - wnear->point->unitx) < pixel2unit(3 * _draw_width)
1112 && abs(unity - wnear->point->unity) < pixel2unit(3 * _draw_width))
1116 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1121 origin_type_selected(GtkWidget *toggle, RouteDownloadInfo *oti)
1123 printf("%s()\n", __PRETTY_FUNCTION__);
1125 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(toggle)))
1127 gtk_widget_set_sensitive(oti->txt_from, toggle == oti->rad_use_text);
1128 gtk_widget_set_sensitive(oti->chk_auto, toggle == oti->rad_use_gps);
1130 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1135 route_download_swap(GtkWidget *button, RouteDownloadInfo *oti)
1138 printf("%s()\n", __PRETTY_FUNCTION__);
1140 /* Save the old origin. */
1141 old_origin = g_strdup(gtk_entry_get_text(GTK_ENTRY(oti->txt_from)));
1143 /* Set the origin text field equal to the current destination. */
1144 gtk_entry_set_text(GTK_ENTRY(oti->txt_from),
1145 gtk_entry_get_text(GTK_ENTRY(oti->txt_to)));
1147 /* Set the contents of the destination text field. */
1148 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti->rad_use_gps)))
1150 /* "Use GPS Location" is enabled - set Destination to GPS Location */
1154 g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
1155 g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
1156 snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
1157 gtk_entry_set_text(GTK_ENTRY(oti->txt_to), buffer);
1159 else if(gtk_toggle_button_get_active(
1160 GTK_TOGGLE_BUTTON(oti->rad_use_route)))
1162 /* "Use End of Route" is enabled - set Destination to start of route */
1169 /* Use first non-zero route point. */
1170 for(p = _route.head; !p->unity; p++) { }
1172 unit2latlon(p->unitx, p->unity, lat, lon);
1173 g_ascii_formatd(strlat, 32, "%.06f", lat);
1174 g_ascii_formatd(strlon, 32, "%.06f", lon);
1175 snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
1176 gtk_entry_set_text(GTK_ENTRY(oti->txt_to), buffer);
1178 else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti->rad_use_text)))
1180 /* "Origin" is enabled - just use the text. */
1181 gtk_entry_set_text(GTK_ENTRY(oti->txt_to), old_origin);
1185 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(oti->rad_use_text), TRUE);
1187 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1192 * Display a dialog box to the user asking them to download a route. The
1193 * "From" and "To" textfields may be initialized using the first two
1194 * parameters. The third parameter, if set to TRUE, will cause the "Use GPS
1195 * Location" checkbox to be enabled, which automatically sets the "From" to the
1196 * current GPS position (this overrides any value that may have been passed as
1197 * the "To" initializer).
1198 * None of the passed strings are freed - that is left to the caller, and it is
1199 * safe to free either string as soon as this function returns.
1202 route_download(gchar *to)
1204 static GtkWidget *dialog = NULL;
1205 static GtkWidget *table = NULL;
1206 static GtkWidget *label = NULL;
1207 static GtkWidget *txt_source_url = NULL;
1208 static GtkWidget *btn_swap = NULL;
1209 static RouteDownloadInfo oti;
1210 printf("%s()\n", __PRETTY_FUNCTION__);
1212 conic_recommend_connected();
1216 GtkEntryCompletion *from_comp;
1217 GtkEntryCompletion *to_comp;
1218 dialog = gtk_dialog_new_with_buttons(_("Download Route"),
1219 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
1220 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1221 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1224 /* Enable the help button. */
1226 hildon_help_dialog_help_enable(
1228 ossohelp_dialog_help_enable(
1230 GTK_DIALOG(dialog), HELP_ID_DOWNROUTE, _osso);
1232 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1233 table = gtk_table_new(2, 5, FALSE), TRUE, TRUE, 0);
1236 gtk_table_attach(GTK_TABLE(table),
1237 label = gtk_label_new(_("Source URL")),
1238 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
1239 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1240 gtk_table_attach(GTK_TABLE(table),
1241 txt_source_url = gtk_entry_new(),
1242 1, 5, 0, 1, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1243 gtk_entry_set_width_chars(GTK_ENTRY(txt_source_url), 25);
1245 /* Use GPS Location. */
1246 gtk_table_attach(GTK_TABLE(table),
1247 oti.rad_use_gps = gtk_radio_button_new_with_label(NULL,
1248 _("Use GPS Location")),
1249 0, 2, 1, 2, GTK_FILL, 0, 2, 4);
1251 /* Use End of Route. */
1252 gtk_table_attach(GTK_TABLE(table),
1253 oti.rad_use_route = gtk_radio_button_new_with_label_from_widget(
1254 GTK_RADIO_BUTTON(oti.rad_use_gps), _("Use End of Route")),
1255 0, 2, 2, 3, GTK_FILL, 0, 2, 4);
1257 gtk_table_attach(GTK_TABLE(table),
1258 gtk_vseparator_new(),
1259 2, 3, 1, 3, GTK_FILL, GTK_FILL, 2,4);
1262 gtk_table_attach(GTK_TABLE(table),
1263 oti.chk_auto = gtk_check_button_new_with_label(
1265 3, 5, 1, 2, GTK_FILL, 0, 2, 4);
1267 /* Avoid Highways. */
1268 gtk_table_attach(GTK_TABLE(table),
1269 oti.chk_avoid_highways = gtk_check_button_new_with_label(
1270 _("Avoid Highways")),
1271 3, 5, 2, 3, GTK_FILL, 0, 2, 4);
1275 gtk_table_attach(GTK_TABLE(table),
1276 oti.rad_use_text = gtk_radio_button_new_with_label_from_widget(
1277 GTK_RADIO_BUTTON(oti.rad_use_gps), _("Origin")),
1278 0, 1, 3, 4, GTK_FILL, 0, 2, 4);
1279 gtk_table_attach(GTK_TABLE(table),
1280 oti.txt_from = gtk_entry_new(),
1281 1, 4, 3, 4, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1282 gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_from), 25);
1283 #ifdef MAEMO_CHANGES
1285 g_object_set(G_OBJECT(oti.txt_from), "hildon-input-mode",
1286 HILDON_GTK_INPUT_MODE_FULL, NULL);
1288 g_object_set(G_OBJECT(oti.txt_from), HILDON_AUTOCAP, FALSE, NULL);
1293 gtk_table_attach(GTK_TABLE(table),
1294 label = gtk_label_new(_("Destination")),
1295 0, 1, 4, 5, GTK_FILL, 0, 2, 4);
1296 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1297 gtk_table_attach(GTK_TABLE(table),
1298 oti.txt_to = gtk_entry_new(),
1299 1, 4, 4, 5, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1300 gtk_entry_set_width_chars(GTK_ENTRY(oti.txt_to), 25);
1301 #ifdef MAEMO_CHANGES
1303 g_object_set(G_OBJECT(oti.txt_to), "hildon-input-mode",
1304 HILDON_GTK_INPUT_MODE_FULL, NULL);
1306 g_object_set(G_OBJECT(oti.txt_to), HILDON_AUTOCAP, FALSE, NULL);
1311 gtk_table_attach(GTK_TABLE(table),
1312 btn_swap = gtk_button_new_with_label("Swap"),
1313 4, 5, 3, 5, GTK_FILL, GTK_FILL, 2, 4);
1315 /* Set up auto-completion. */
1316 from_comp = gtk_entry_completion_new();
1317 gtk_entry_completion_set_model(from_comp, GTK_TREE_MODEL(_loc_model));
1318 gtk_entry_completion_set_text_column(from_comp, 0);
1319 gtk_entry_set_completion(GTK_ENTRY(oti.txt_from), from_comp);
1321 to_comp = gtk_entry_completion_new();
1322 gtk_entry_completion_set_model(to_comp, GTK_TREE_MODEL(_loc_model));
1323 gtk_entry_completion_set_text_column(to_comp, 0);
1324 gtk_entry_set_completion(GTK_ENTRY(oti.txt_to), to_comp);
1327 g_signal_connect(G_OBJECT(oti.rad_use_gps), "toggled",
1328 G_CALLBACK(origin_type_selected), &oti);
1329 g_signal_connect(G_OBJECT(oti.rad_use_route), "toggled",
1330 G_CALLBACK(origin_type_selected), &oti);
1331 g_signal_connect(G_OBJECT(oti.rad_use_text), "toggled",
1332 G_CALLBACK(origin_type_selected), &oti);
1333 g_signal_connect(G_OBJECT(btn_swap), "clicked",
1334 G_CALLBACK(route_download_swap), &oti);
1336 gtk_widget_set_sensitive(oti.chk_auto, FALSE);
1339 /* Initialize fields. */
1341 gtk_entry_set_text(GTK_ENTRY(txt_source_url), _route_dl_url);
1343 gtk_entry_set_text(GTK_ENTRY(oti.txt_to), to);
1345 /* Use "End of Route" by default if they have a route. */
1346 if(_route.head != _route.tail)
1348 /* There is no route, so make it the default. */
1349 gtk_widget_set_sensitive(oti.rad_use_route, TRUE);
1350 gtk_toggle_button_set_active(
1351 GTK_TOGGLE_BUTTON(oti.rad_use_route), TRUE);
1352 gtk_widget_grab_focus(oti.rad_use_route);
1354 /* Else use "GPS Location" if they have GPS enabled. */
1357 /* There is no route, so desensitize "Use End of Route." */
1358 gtk_widget_set_sensitive(oti.rad_use_route, FALSE);
1361 gtk_toggle_button_set_active(
1362 GTK_TOGGLE_BUTTON(oti.rad_use_gps), TRUE);
1363 gtk_widget_grab_focus(oti.rad_use_gps);
1365 /* Else use text. */
1368 gtk_toggle_button_set_active(
1369 GTK_TOGGLE_BUTTON(oti.rad_use_text), TRUE);
1370 gtk_widget_grab_focus(oti.txt_from);
1374 gtk_widget_show_all(dialog);
1376 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1378 gchar buffer[BUFFER_SIZE];
1379 const gchar *source_url, *from, *to;
1380 gboolean avoid_highways;
1382 source_url = gtk_entry_get_text(GTK_ENTRY(txt_source_url));
1383 if(!strlen(source_url))
1385 popup_error(dialog, _("Please specify a source URL."));
1390 g_free(_route_dl_url);
1391 _route_dl_url = g_strdup(source_url);
1394 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.rad_use_gps)))
1398 g_ascii_formatd(strlat, 32, "%.06f", _gps.lat);
1399 g_ascii_formatd(strlon, 32, "%.06f", _gps.lon);
1400 snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
1403 else if(gtk_toggle_button_get_active(
1404 GTK_TOGGLE_BUTTON(oti.rad_use_route)))
1411 /* Use last non-zero route point. */
1412 for(p = _route.tail; !p->unity; p--) { }
1414 unit2latlon(p->unitx, p->unity, lat, lon);
1415 g_ascii_formatd(strlat, 32, "%.06f", lat);
1416 g_ascii_formatd(strlon, 32, "%.06f", lon);
1417 snprintf(buffer, sizeof(buffer), "%s, %s", strlat, strlon);
1422 from = gtk_entry_get_text(GTK_ENTRY(oti.txt_from));
1427 popup_error(dialog, _("Please specify a start location."));
1431 to = gtk_entry_get_text(GTK_ENTRY(oti.txt_to));
1434 popup_error(dialog, _("Please specify an end location."));
1438 avoid_highways = gtk_toggle_button_get_active(
1439 GTK_TOGGLE_BUTTON(oti.chk_avoid_highways));
1440 if(route_download_and_setup(dialog, source_url, from, to,
1441 gtk_toggle_button_get_active(
1442 GTK_TOGGLE_BUTTON(oti.chk_avoid_highways)),
1443 (gtk_toggle_button_get_active(
1444 GTK_TOGGLE_BUTTON(oti.rad_use_gps)) ? 0 : 1)))
1448 /* Cancel any autoroute that might be occurring. */
1451 if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(oti.chk_auto)))
1453 _autoroute_data.source_url = g_strdup(source_url);
1454 _autoroute_data.dest = g_strdup(to);
1455 _autoroute_data.avoid_highways = avoid_highways;
1456 _autoroute_data.enabled = TRUE;
1459 /* Save Origin in Route Locations list if not from GPS. */
1460 if(gtk_toggle_button_get_active(
1461 GTK_TOGGLE_BUTTON(oti.rad_use_text))
1462 && !g_slist_find_custom(_loc_list, from,
1463 (GCompareFunc)strcmp))
1465 _loc_list = g_slist_prepend(_loc_list, g_strdup(from));
1466 gtk_list_store_insert_with_values(_loc_model, &iter,
1467 INT_MAX, 0, from, -1);
1470 /* Save Destination in Route Locations list. */
1471 if(!g_slist_find_custom(_loc_list, to,
1472 (GCompareFunc)strcmp))
1474 _loc_list = g_slist_prepend(_loc_list, g_strdup(to));
1475 gtk_list_store_insert_with_values(_loc_model, &iter,
1476 INT_MAX, 0, to, -1);
1479 /* Success! Get out of the while loop. */
1482 /* else let them try again. */
1485 gtk_widget_hide(dialog); /* Destroying causes a crash (!?!?!??!) */
1487 vprintf("%s(): return TRUE\n", __PRETTY_FUNCTION__);
1492 route_add_way_dialog(gint unitx, gint unity)
1495 gchar tmp1[LL_FMT_LEN], tmp2[LL_FMT_LEN], *p_latlon;
1496 static GtkWidget *dialog = NULL;
1497 static GtkWidget *table = NULL;
1498 static GtkWidget *label = NULL;
1499 static GtkWidget *label_lat_lon = NULL;
1500 static GtkWidget *txt_scroll = NULL;
1501 static GtkWidget *txt_desc = NULL;
1502 static int last_deg_format = 0;
1504 printf("%s()\n", __PRETTY_FUNCTION__);
1506 unit2latlon(unitx, unity, lat, lon);
1508 gint fallback_deg_format = _degformat;
1510 if(!coord_system_check_lat_lon (lat, lon, &fallback_deg_format))
1512 last_deg_format = _degformat;
1513 _degformat = fallback_deg_format;
1515 if(dialog != NULL) gtk_widget_destroy(dialog);
1518 else if(_degformat != last_deg_format)
1520 last_deg_format = _degformat;
1522 if(dialog != NULL) gtk_widget_destroy(dialog);
1529 dialog = gtk_dialog_new_with_buttons(_("Add Waypoint"),
1530 GTK_WINDOW(_window), GTK_DIALOG_MODAL,
1531 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
1532 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
1535 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
1536 table = gtk_table_new(2, 2, FALSE), TRUE, TRUE, 0);
1540 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
1541 p_latlon = g_strdup_printf("%s, %s",
1542 DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1,
1543 DEG_FORMAT_ENUM_TEXT[_degformat].short_field_2);
1545 p_latlon = g_strdup_printf("%s", DEG_FORMAT_ENUM_TEXT[_degformat].short_field_1);
1547 gtk_table_attach(GTK_TABLE(table),
1548 label = gtk_label_new(p_latlon),
1549 0, 1, 0, 1, GTK_FILL, 0, 2, 4);
1550 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1554 gtk_table_attach(GTK_TABLE(table),
1555 label_lat_lon = gtk_label_new(_("") ),
1556 1, 2, 0, 1, GTK_FILL, 0, 2, 4);
1557 gtk_misc_set_alignment(GTK_MISC(label_lat_lon), 0.0f, 0.5f);
1560 gtk_table_attach(GTK_TABLE(table),
1561 label = gtk_label_new(_("Description")),
1562 0, 1, 1, 2, GTK_FILL, 0, 2, 4);
1563 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
1565 txt_scroll = gtk_scrolled_window_new(NULL, NULL);
1566 gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(txt_scroll),
1568 gtk_table_attach(GTK_TABLE(table),
1570 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, 0, 2, 4);
1572 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(txt_scroll),
1573 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1575 txt_desc = gtk_text_view_new ();
1576 gtk_text_view_set_wrap_mode(GTK_TEXT_VIEW(txt_desc), GTK_WRAP_WORD);
1578 gtk_container_add(GTK_CONTAINER(txt_scroll), txt_desc);
1579 gtk_widget_set_size_request(GTK_WIDGET(txt_scroll), 400, 60);
1582 format_lat_lon(lat, lon, tmp1, tmp2);
1584 if(DEG_FORMAT_ENUM_TEXT[_degformat].field_2_in_use)
1585 p_latlon = g_strdup_printf("%s, %s", tmp1, tmp2);
1587 p_latlon = g_strdup_printf("%s", tmp1);
1590 gtk_label_set_text(GTK_LABEL(label_lat_lon), p_latlon);
1593 gtk_text_buffer_set_text(
1594 gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc)), "", 0);
1596 gtk_widget_show_all(dialog);
1598 while(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog)))
1600 GtkTextBuffer *tbuf;
1601 GtkTextIter ti1, ti2;
1604 tbuf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(txt_desc));
1605 gtk_text_buffer_get_iter_at_offset(tbuf, &ti1, 0);
1606 gtk_text_buffer_get_end_iter(tbuf, &ti2);
1607 desc = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
1611 /* There's a description. Add a waypoint. */
1612 MACRO_PATH_INCREMENT_TAIL(_route);
1613 _route.tail->unitx = unitx;
1614 _route.tail->unity = unity;
1615 _route.tail->time = 0;
1616 _route.tail->altitude = 0;
1618 MACRO_PATH_INCREMENT_WTAIL(_route);
1619 _route.wtail->point = _route.tail;
1621 = gtk_text_buffer_get_text(tbuf, &ti1, &ti2, TRUE);
1629 confirm = hildon_note_new_confirmation(GTK_WINDOW(dialog),
1630 _("Creating a \"waypoint\" with no description actually "
1631 "adds a break point. Is that what you want?"));
1633 if(GTK_RESPONSE_OK == gtk_dialog_run(GTK_DIALOG(confirm)))
1635 /* There's no description. Add a break by adding a (0, 0)
1636 * point (if necessary), and then the ordinary route point. */
1637 if(_route.tail->unity)
1639 MACRO_PATH_INCREMENT_TAIL(_route);
1640 *_route.tail = _point_null;
1643 MACRO_PATH_INCREMENT_TAIL(_route);
1644 _route.tail->unitx = unitx;
1645 _route.tail->unity = unity;
1646 _route.tail->time = 0;
1647 _route.tail->altitude = 0;
1650 gtk_widget_destroy(confirm);
1654 gtk_widget_destroy(confirm);
1659 route_find_nearest_point();
1661 MACRO_QUEUE_DRAW_AREA();
1664 gtk_widget_hide(dialog);
1666 _degformat = last_deg_format;
1668 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1680 gchar *settings_dir;
1681 printf("%s()\n", __PRETTY_FUNCTION__);
1683 /* Initialize settings_dir. */
1684 settings_dir = gnome_vfs_expand_initial_tilde(CONFIG_DIR_NAME);
1685 g_mkdir_with_parents(settings_dir, 0700);
1687 /* Open path database. */
1689 gchar *path_db_file;
1691 path_db_file = gnome_vfs_uri_make_full_from_relative(
1692 settings_dir, CONFIG_PATH_DB_FILE);
1694 if(!path_db_file || SQLITE_OK != sqlite3_open(path_db_file, &_path_db)
1695 /* Open worked. Now create tables, failing if they already exist. */
1696 || (sqlite3_exec(_path_db,
1697 "create table route_path ("
1698 "num integer primary key, "
1704 "create table route_way ("
1705 "route_point primary key, "
1708 "create table track_path ("
1709 "num integer primary key, "
1715 "create table track_way ("
1716 "track_point primary key, "
1717 "description text)",
1718 NULL, NULL, NULL), FALSE) /* !! Comma operator !! */
1719 /* Create prepared statements - failure here is bad! */
1720 || SQLITE_OK != sqlite3_prepare(_path_db,
1721 "select unitx, unity, time, altitude, description "
1722 "from route_path left join route_way on "
1723 "route_path.num = route_way.route_point "
1724 "order by route_path.num",
1725 -1, &_route_stmt_select, NULL)
1726 || SQLITE_OK != sqlite3_prepare(_path_db,
1727 "select unitx, unity, time, altitude, description "
1728 "from track_path left join track_way on "
1729 "track_path.num = track_way.track_point "
1730 "order by track_path.num",
1731 -1, &_track_stmt_select, NULL)
1732 || SQLITE_OK != sqlite3_prepare(_path_db,
1733 "delete from route_path",
1734 -1, &_route_stmt_delete_path, NULL)
1735 || SQLITE_OK != sqlite3_prepare(_path_db,
1736 "delete from route_way",
1737 -1, &_route_stmt_delete_way, NULL)
1738 || SQLITE_OK != sqlite3_prepare(_path_db,
1739 "insert into route_path "
1740 "(num, unitx, unity, time, altitude) "
1741 "values (NULL, ?, ?, ?, ?)",
1742 -1, &_route_stmt_insert_path, NULL)
1743 || SQLITE_OK != sqlite3_prepare(_path_db,
1744 "insert into route_way (route_point, description) "
1746 -1, &_route_stmt_insert_way, NULL)
1747 || SQLITE_OK != sqlite3_prepare(_path_db,
1748 "delete from track_path",
1749 -1, &_track_stmt_delete_path, NULL)
1750 || SQLITE_OK != sqlite3_prepare(_path_db,
1751 "delete from track_way",
1752 -1, &_track_stmt_delete_way, NULL)
1753 || SQLITE_OK != sqlite3_prepare(_path_db,
1754 "insert into track_path "
1755 "(num, unitx, unity, time, altitude) "
1756 "values (NULL, ?, ?, ?, ?)",
1757 -1, &_track_stmt_insert_path, NULL)
1758 || SQLITE_OK != sqlite3_prepare(_path_db,
1759 "insert into track_way (track_point, description) "
1761 -1, &_track_stmt_insert_way, NULL)
1762 || SQLITE_OK != sqlite3_prepare(_path_db, "begin transaction",
1763 -1, &_path_stmt_trans_begin, NULL)
1764 || SQLITE_OK != sqlite3_prepare(_path_db, "commit transaction",
1765 -1, &_path_stmt_trans_commit, NULL)
1766 || SQLITE_OK != sqlite3_prepare(_path_db, "rollback transaction",
1767 -1, &_path_stmt_trans_rollback, NULL))
1769 gchar buffer[BUFFER_SIZE];
1770 snprintf(buffer, sizeof(buffer), "%s\n%s",
1771 _("Failed to open path database. "
1772 "Tracks and routes will not be saved."),
1773 sqlite3_errmsg(_path_db));
1774 sqlite3_close(_path_db);
1776 popup_error(_window, buffer);
1780 read_path_from_db(&_route, _route_stmt_select);
1781 read_path_from_db(&_track, _track_stmt_select);
1782 _track_index_last_saved = _track.tail - _track.head - 1;
1784 g_free(path_db_file);
1787 g_free(settings_dir);
1789 _last_spoken_phrase = g_strdup("");
1791 vprintf("%s(): return\n", __PRETTY_FUNCTION__);
1797 printf("%s()\n", __PRETTY_FUNCTION__);
1800 if(_track.tail->unity)
1801 track_insert_break(FALSE);
1802 path_update_track_in_db();
1803 path_save_route_to_db();
1807 sqlite3_close(_path_db);
1811 MACRO_PATH_FREE(_track);
1812 MACRO_PATH_FREE(_route);
1814 vprintf("%s(): return\n", __PRETTY_FUNCTION__);