208.1.4
by Dr. Tilmann Bubeck
Add route-planning functionality |
1 |
#include <stdio.h> |
2 |
#include <stdlib.h> |
|
3 |
#include <string.h> |
|
4 |
#include <time.h> |
|
5 |
#include <errno.h> |
|
6 |
#include <math.h> |
|
7 |
||
8 |
#include <gtk/gtk.h> |
|
9 |
#include <glib.h> |
|
10 |
#include <glib/gstdio.h> |
|
11 |
||
12 |
#include <sys/types.h> |
|
13 |
#include <sys/stat.h> |
|
14 |
#include <fcntl.h> |
|
15 |
||
16 |
#include <libxml/parser.h> |
|
17 |
#include <libxml/tree.h> |
|
18 |
#include <libxml/encoding.h> |
|
19 |
#include <libxml/xmlwriter.h> |
|
20 |
||
21 |
#include "globals.h" |
|
22 |
#include "tile_management.h" |
|
23 |
#include "route.h" |
|
24 |
#include "wp.h" |
|
25 |
#include "interface.h" |
|
26 |
#include "support.h" |
|
27 |
#include "converter.h" |
|
28 |
#include "map_management.h" |
|
29 |
#include "util.h" |
|
30 |
#include "tracks.h" |
|
31 |
||
32 |
#define GPX_ENCODING "utf-8"
|
|
33 |
||
34 |
/**
|
|
35 |
* This is a GSList containing the waypoints of the route
|
|
36 |
* which we are planing. It is the central data structure for route.c
|
|
37 |
*/
|
|
38 |
static GSList *route = NULL; |
|
39 |
||
40 |
static GdkPixbuf *wp_icon = NULL; |
|
41 |
static int wp_icon_width = 0; |
|
42 |
static int wp_icon_height = 0; |
|
43 |
||
44 |
/**
|
|
45 |
* Clear the route.
|
|
46 |
*/
|
|
47 |
void
|
|
48 |
reset_route () |
|
49 |
{
|
|
50 |
route = NULL; |
|
51 |
}
|
|
52 |
||
53 |
/**
|
|
54 |
* Append a new waypoint at the end of the route.
|
|
55 |
*/
|
|
56 |
void
|
|
57 |
append_waypoint_to_route (double lat, double lon) |
|
58 |
{
|
|
59 |
waypoint_t *tp = g_new0 (waypoint_t,1); |
|
60 |
||
61 |
tp->lat = lat; |
|
62 |
tp->lon = lon; |
|
63 |
||
64 |
route = g_slist_append (route, tp); |
|
65 |
}
|
|
66 |
||
67 |
/**
|
|
68 |
* Change the position of the given waypoint to the new position.
|
|
69 |
*/
|
|
70 |
void
|
|
71 |
change_waypoint_of_route (waypoint_t *tp, double lat, double lon) |
|
72 |
{
|
|
73 |
tp->lat = lat; |
|
74 |
tp->lon = lon; |
|
75 |
}
|
|
76 |
||
77 |
/**
|
|
78 |
* Delete the given waypoint from the route.
|
|
79 |
*/
|
|
80 |
void
|
|
81 |
delete_waypoint_of_route (waypoint_t *wp) |
|
82 |
{
|
|
83 |
route = g_slist_remove (route, wp); |
|
84 |
g_free (wp); |
|
85 |
}
|
|
86 |
||
87 |
/**
|
|
88 |
* Insert a new waypoint before the given waypoint. This waypoint lies
|
|
89 |
* between the given waypoint and the waypoint before this waypoint.
|
|
90 |
*/
|
|
91 |
void
|
|
92 |
insert_waypoint_before_of_route (waypoint_t *wp) |
|
93 |
{
|
|
94 |
waypoint_t *previous_wp; |
|
95 |
int position; |
|
96 |
||
97 |
position = g_slist_index (route, wp); |
|
98 |
if (position > 0) { |
|
99 |
previous_wp = g_slist_nth_data (route, position - 1); |
|
100 |
||
101 |
waypoint_t *new_wp = g_new0 (waypoint_t,1); |
|
102 |
||
103 |
new_wp->lat = previous_wp->lat - (previous_wp->lat - wp->lat) / 2; |
|
104 |
new_wp->lon = previous_wp->lon - (previous_wp->lon - wp->lon) / 2; |
|
105 |
||
106 |
route = g_slist_insert (route, new_wp, position + 0); |
|
107 |
}
|
|
108 |
}
|
|
109 |
||
110 |
/**
|
|
111 |
* Find the waypoint which wp_icon is at the given mouse position.
|
|
112 |
* Return that waypoint or NULL if none was found.
|
|
113 |
*/
|
|
114 |
waypoint_t * |
|
115 |
find_routepoint (int mouse_x, int mouse_y) |
|
116 |
{
|
|
117 |
GSList *list; |
|
118 |
double lat; |
|
119 |
double lon; |
|
120 |
int pixel_x, pixel_y, x,y; |
|
121 |
||
122 |
for (list = route; list != NULL; list = list->next) |
|
123 |
{
|
|
124 |
waypoint_t *tp = list->data; |
|
125 |
||
126 |
lat = tp->lat; |
|
127 |
lon = tp->lon; |
|
128 |
||
129 |
pixel_x = lon2pixel (global_zoom, lon); |
|
130 |
pixel_y = lat2pixel (global_zoom, lat); |
|
131 |
||
132 |
x = pixel_x - global_x + wp_icon_width / 2; |
|
133 |
y = pixel_y - global_y - wp_icon_height / 2; |
|
134 |
||
135 |
if (abs (x - mouse_x) < wp_icon_width / 2 && |
|
136 |
abs (y - mouse_y) < wp_icon_height / 2) |
|
137 |
{
|
|
138 |
return tp; |
|
139 |
}
|
|
140 |
}
|
|
141 |
||
142 |
return NULL; |
|
143 |
}
|
|
144 |
||
145 |
static
|
|
146 |
void
|
|
147 |
draw_arrow (GdkGC *gc, int start_x, int start_y, int end_x, int end_y) |
|
148 |
{
|
|
149 |
int x1,y1,x2,y2; |
|
150 |
double angle = atan2 (end_y - start_y, end_x - start_x) + M_PI; |
|
151 |
double arrow_length = 20; |
|
152 |
double arrow_degrees = M_PI / 10; |
|
153 |
||
307
by Paul Wise
Update links |
154 |
/* https://kapo-cpp.blogspot.com/2008/10/drawing-arrows-with-cairo.html */
|
208.1.4
by Dr. Tilmann Bubeck
Add route-planning functionality |
155 |
|
156 |
x1 = end_x + arrow_length * cos (angle - arrow_degrees); |
|
157 |
y1 = end_y + arrow_length * sin (angle - arrow_degrees); |
|
158 |
x2 = end_x + arrow_length * cos (angle + arrow_degrees); |
|
159 |
y2 = end_y + arrow_length * sin (angle + arrow_degrees); |
|
160 |
||
161 |
gdk_draw_line (pixmap, gc, start_x, start_y, end_x, end_y); |
|
162 |
gdk_draw_line (pixmap, gc, end_x, end_y, x1, y1); |
|
163 |
gdk_draw_line (pixmap, gc, x1, y1, x2, y2); |
|
164 |
gdk_draw_line (pixmap, gc, x2, y2, end_x, end_y); |
|
165 |
}
|
|
166 |
||
167 |
static
|
|
168 |
void
|
|
169 |
draw_line_of_route (GdkGC *gc, int x1, int y1, int x2, int y2) |
|
170 |
{
|
|
171 |
if (abs (x1-x2) > 30 || abs (y1-y2) > 30) { |
|
172 |
/* Line is long enough. Draw arrow */
|
|
173 |
draw_arrow (gc, x1, y1, x2, y2); |
|
174 |
} else { |
|
175 |
/* short line. Omit arrow. */
|
|
176 |
gdk_draw_line (pixmap, gc, x1, y1, x2, y2); |
|
177 |
}
|
|
178 |
}
|
|
179 |
||
180 |
/**
|
|
181 |
* This function draws the current route on the screen.
|
|
182 |
*/
|
|
183 |
void
|
|
184 |
paint_route () |
|
185 |
{
|
|
186 |
GSList *list; |
|
187 |
int pixel_x, pixel_y, x,y, last_x = 0, last_y = 0; |
|
188 |
float lat, lon; |
|
189 |
GdkColor color; |
|
190 |
GdkGC *gc; |
|
191 |
gboolean is_line = FALSE; |
|
192 |
||
193 |
/* Load icon if not already loaded: */
|
|
194 |
if (!wp_icon) { |
|
195 |
wp_icon = load_wp_icon (); |
|
196 |
wp_icon_width = gdk_pixbuf_get_width (wp_icon); |
|
197 |
wp_icon_height = gdk_pixbuf_get_height (wp_icon); |
|
198 |
}
|
|
199 |
||
200 |
/* Create GC for drawing the route line */
|
|
201 |
gc = gdk_gc_new (pixmap); |
|
202 |
color.green = 0; |
|
203 |
color.blue = 0; |
|
204 |
color.red = 50000; |
|
205 |
gdk_gc_set_rgb_fg_color (gc, &color); |
|
206 |
gdk_gc_set_line_attributes (gc, 5, GDK_LINE_SOLID, |
|
207 |
GDK_CAP_ROUND, GDK_JOIN_ROUND); |
|
208 |
||
209 |
/* [1] paint line first */
|
|
210 |
for (list = route; list != NULL; list = list->next) |
|
211 |
{
|
|
212 |
waypoint_t *tp = list->data; |
|
213 |
||
214 |
lat = tp->lat; |
|
215 |
lon = tp->lon; |
|
216 |
||
217 |
pixel_x = lon2pixel (global_zoom, lon); |
|
218 |
pixel_y = lat2pixel (global_zoom, lat); |
|
219 |
||
220 |
x = pixel_x - global_x; |
|
221 |
y = pixel_y - global_y; |
|
222 |
||
223 |
if (is_line) |
|
224 |
{
|
|
225 |
draw_line_of_route (gc, last_x, last_y, x, y); |
|
226 |
gtk_widget_queue_draw_area (map_drawable, |
|
227 |
x-4, y-4, 8, 8); |
|
228 |
}
|
|
229 |
||
230 |
last_x = x; |
|
231 |
last_y = y; |
|
232 |
||
233 |
is_line = TRUE; |
|
234 |
}
|
|
235 |
||
236 |
/* [2] paint flags after line */
|
|
237 |
for (list = route; list != NULL; list = list->next) |
|
238 |
{
|
|
239 |
waypoint_t *tp = list->data; |
|
240 |
||
241 |
lat = tp->lat; |
|
242 |
lon = tp->lon; |
|
243 |
||
244 |
pixel_x = lon2pixel (global_zoom, lon); |
|
245 |
pixel_y = lat2pixel (global_zoom, lat); |
|
246 |
||
247 |
x = pixel_x - global_x; |
|
248 |
y = pixel_y - global_y; |
|
249 |
||
250 |
if (!wp_icon) { |
|
251 |
gdk_draw_arc (pixmap, |
|
252 |
gc, |
|
253 |
TRUE, |
|
254 |
x-4, y-4, |
|
255 |
8,8, |
|
256 |
0,23040); |
|
257 |
} else { |
|
258 |
gdk_draw_pixbuf (pixmap, |
|
259 |
NULL, |
|
260 |
wp_icon, |
|
261 |
0,0, |
|
262 |
x,y-wp_icon_height, |
|
263 |
wp_icon_width,wp_icon_height, |
|
264 |
GDK_RGB_DITHER_NONE, 0, 0); |
|
265 |
||
266 |
gtk_widget_queue_draw_area (map_drawable, |
|
267 |
x, y-wp_icon_height, |
|
268 |
wp_icon_width, |
|
269 |
wp_icon_height); |
|
270 |
}
|
|
271 |
}
|
|
272 |
}
|
|
273 |
||
305
by Paul Wise
Remove trailing whitespace |
274 |
/**
|
208.1.4
by Dr. Tilmann Bubeck
Add route-planning functionality |
275 |
* Find the bounding box of the given GSList containin waypoints.
|
276 |
*/
|
|
277 |
bbox_t
|
|
278 |
get_way_bbox (GSList *ways) |
|
279 |
{
|
|
280 |
GSList *list; |
|
281 |
bbox_t bbox; |
|
282 |
double lat, lon; |
|
283 |
||
284 |
bbox.lat1 = -90; |
|
285 |
bbox.lon1 = 180; |
|
286 |
bbox.lat2 = 90; |
|
287 |
bbox.lon2 = -180; |
|
288 |
||
289 |
for (list = ways; list != NULL; list = list->next) |
|
290 |
{
|
|
291 |
waypoint_t *tp = list->data; |
|
292 |
||
293 |
lat = tp->lat; |
|
294 |
lon = tp->lon; |
|
295 |
bbox.lat1 = (lat > bbox.lat1) ? lat : bbox.lat1; |
|
296 |
bbox.lat2 = (lat < bbox.lat2) ? lat : bbox.lat2; |
|
297 |
bbox.lon1 = (lon < bbox.lon1) ? lon : bbox.lon1; |
|
298 |
bbox.lon2 = (lon > bbox.lon2) ? lon : bbox.lon2; |
|
299 |
}
|
|
300 |
||
301 |
return bbox; |
|
302 |
}
|
|
208.1.5
by Dr. Tilmann Bubeck
Add choose_load_file() and choose_save_file() utility functions |
303 |
|
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
304 |
/**
|
305 |
* Write a single route point to the XML file in GPX format.
|
|
306 |
*/
|
|
307 |
static
|
|
308 |
void
|
|
309 |
write_rtept (xmlTextWriterPtr writer, waypoint_t *wp, int no) |
|
310 |
{
|
|
311 |
xmlTextWriterStartElement (writer, BAD_CAST "rtept"); |
|
312 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "lat", |
|
313 |
"%f", rad2deg (wp->lat)); |
|
314 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "lon", |
|
315 |
"%f", rad2deg (wp->lon)); |
|
316 |
xmlTextWriterEndElement (writer); /* </rtept> */ |
|
317 |
}
|
|
318 |
||
319 |
/**
|
|
320 |
* Save the route in GPX format to the given URI.
|
|
321 |
*/
|
|
322 |
void
|
|
305
by Paul Wise
Remove trailing whitespace |
323 |
save_route_as_gpx (const char *uri) |
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
324 |
{
|
325 |
int rc; |
|
326 |
xmlTextWriterPtr writer; |
|
327 |
int no; |
|
328 |
GSList *list; |
|
329 |
char now_as_string[200]; |
|
330 |
struct tm now_as_tm; |
|
331 |
time_t now; |
|
332 |
||
333 |
if (uri == NULL) return; |
|
334 |
||
335 |
bbox_t bbox = get_way_bbox (route); |
|
336 |
||
337 |
/*
|
|
338 |
* this initialize the library and check potential ABI mismatches
|
|
339 |
* between the version it was compiled for and the actual shared
|
|
340 |
* library used.
|
|
341 |
*/
|
|
342 |
LIBXML_TEST_VERSION
|
|
343 |
||
344 |
/* Create a new XmlWriter for uri, with no compression. */
|
|
345 |
writer = xmlNewTextWriterFilename (uri, 0); |
|
346 |
if (writer == NULL) { |
|
347 |
printf ("testXmlwriterFilename: Error creating the xml writer\n"); |
|
348 |
return; |
|
349 |
}
|
|
350 |
||
351 |
/* We would like to indent the elements for better readability. */
|
|
352 |
xmlTextWriterSetIndent (writer, 1); |
|
353 |
||
354 |
/* Start the document with the xml default for the version,
|
|
355 |
* encoding and the default for the standalone
|
|
356 |
* declaration. */
|
|
357 |
rc = xmlTextWriterStartDocument (writer, "1.0", GPX_ENCODING, "no"); |
|
358 |
if (rc < 0) { |
|
359 |
printf ("testXmlwriterFilename: Error at xmlTextWriterStartDocument\n"); |
|
360 |
return; |
|
361 |
}
|
|
362 |
||
363 |
xmlTextWriterStartElement (writer, BAD_CAST "gpx"); |
|
364 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "version", |
|
365 |
BAD_CAST "1.1"); |
|
366 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "creator", |
|
367 |
BAD_CAST PACKAGE_STRING); |
|
368 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns:xsi", |
|
369 |
BAD_CAST "http://www.w3.org/2001/XMLSchema-instance"); |
|
370 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns:topografix", |
|
371 |
BAD_CAST "http://www.topografix.com/GPX/Private/TopoGrafix/0/1"); |
|
372 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "xmlns", |
|
373 |
BAD_CAST "http://www.topografix.com/GPX/1/1"); |
|
374 |
xmlTextWriterWriteAttribute (writer, BAD_CAST "xsi:schemaLocation", |
|
375 |
BAD_CAST "http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"); |
|
376 |
||
377 |
xmlTextWriterStartElement (writer, BAD_CAST "metadata"); |
|
378 |
||
379 |
/* save current time into GPX file: */
|
|
380 |
time (&now); |
|
263
by Paul Wise
Use gmtime and the UTC timezone for times in GPX files. |
381 |
gmtime_r (&now, &now_as_tm); |
382 |
strftime (now_as_string, sizeof (now_as_string), "%Y-%m-%dT%H:%M:%SZ", |
|
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
383 |
&now_as_tm); |
384 |
xmlTextWriterWriteElement (writer, BAD_CAST "time", |
|
385 |
BAD_CAST now_as_string); |
|
386 |
||
387 |
xmlTextWriterStartElement (writer, BAD_CAST "bounds"); |
|
388 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "minlat", |
|
389 |
"%f", rad2deg (bbox.lat2)); |
|
390 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "minlon", |
|
391 |
"%f", rad2deg (bbox.lon1)); |
|
392 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "maxlat", |
|
393 |
"%f", rad2deg (bbox.lat1)); |
|
394 |
xmlTextWriterWriteFormatAttribute (writer, BAD_CAST "maxlon", |
|
395 |
"%f", rad2deg (bbox.lon2)); |
|
396 |
xmlTextWriterEndElement (writer); /* </bounds> */ |
|
397 |
||
398 |
xmlTextWriterEndElement (writer); /* </metadata> */ |
|
399 |
||
400 |
xmlTextWriterStartElement (writer, BAD_CAST "rte"); |
|
401 |
||
402 |
for (list = route, no = 1; list != NULL; list = list->next, no++) |
|
403 |
{
|
|
404 |
waypoint_t *wp = list->data; |
|
405 |
write_rtept (writer, wp, no); |
|
406 |
}
|
|
407 |
||
408 |
xmlTextWriterEndElement (writer); /* </rte> */ |
|
409 |
xmlTextWriterEndElement (writer); /* </gpx> */ |
|
410 |
||
411 |
xmlTextWriterEndDocument (writer); |
|
412 |
||
413 |
xmlFreeTextWriter (writer); |
|
414 |
}
|
|
415 |
||
416 |
/**
|
|
208.1.7
by Dr. Tilmann Bubeck
Support saving planned routes as TomTom ITN files. |
417 |
* Save a route to a TomTom ITN file format.
|
418 |
*/
|
|
419 |
void
|
|
420 |
save_route_as_tomtom_itn (const char *uri) |
|
421 |
{
|
|
422 |
FILE *tomtom; |
|
423 |
int no; |
|
424 |
GSList *list; |
|
425 |
||
426 |
if (uri == NULL) return; |
|
427 |
||
428 |
tomtom = fopen (uri, "w"); |
|
429 |
if (tomtom == NULL) { |
|
430 |
perror ("opening file to save tomtom."); |
|
431 |
} else { |
|
432 |
for (list = route, no = 1; |
|
433 |
list != NULL; |
|
434 |
list = list->next, no++) |
|
435 |
{
|
|
436 |
waypoint_t *wp = list->data; |
|
305
by Paul Wise
Remove trailing whitespace |
437 |
fprintf (tomtom, "%d|%d|WP%d|0\n", |
208.1.7
by Dr. Tilmann Bubeck
Support saving planned routes as TomTom ITN files. |
438 |
(int) (rad2deg (wp->lon) * 100000), |
439 |
(int) (rad2deg (wp->lat) * 100000), |
|
440 |
no); |
|
441 |
}
|
|
442 |
||
443 |
fclose (tomtom); |
|
444 |
}
|
|
445 |
}
|
|
446 |
||
447 |
/**
|
|
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
448 |
* Take all routepoints from a DOM tree containing GPX nodes.
|
449 |
*/
|
|
450 |
static
|
|
451 |
GSList * |
|
452 |
parse_gpx_routepoints (xmlNode *node) |
|
453 |
{
|
|
454 |
xmlNode *cur_node = NULL; |
|
455 |
GSList *list = NULL; |
|
456 |
||
457 |
for (cur_node = node; cur_node; cur_node = cur_node->next) |
|
458 |
{
|
|
305
by Paul Wise
Remove trailing whitespace |
459 |
if (cur_node->type == XML_ELEMENT_NODE) |
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
460 |
{
|
461 |
if (xmlStrEqual (cur_node->name, BAD_CAST "rtept")) |
|
462 |
{
|
|
463 |
double lat, lon; |
|
464 |
waypoint_t *tp = g_new0 (waypoint_t, 1); |
|
465 |
||
466 |
lat = atof ((char *) xmlGetProp (cur_node, |
|
467 |
BAD_CAST "lat")); |
|
468 |
lon = atof ((char *) xmlGetProp (cur_node, |
|
469 |
BAD_CAST "lon")); |
|
470 |
||
471 |
tp->lat = deg2rad (lat); |
|
472 |
tp->lon = deg2rad (lon); |
|
473 |
||
474 |
list = g_slist_append (list, tp); |
|
475 |
}
|
|
476 |
}
|
|
477 |
list = g_slist_concat (list, |
|
478 |
parse_gpx_routepoints (cur_node->children)); |
|
479 |
}
|
|
480 |
||
481 |
return list; |
|
482 |
}
|
|
483 |
||
484 |
/**
|
|
485 |
* Load a route from a given GPX file.
|
|
486 |
*/
|
|
487 |
GSList * |
|
305
by Paul Wise
Remove trailing whitespace |
488 |
load_route_as_gpx (const char *file) |
208.1.6
by Dr. Tilmann Bubeck
Support saving and loading of planned routes in GPX 1.1 files. |
489 |
{
|
490 |
GSList *list = NULL; |
|
491 |
xmlDoc *doc = NULL; |
|
492 |
xmlNode *root_element = NULL; |
|
493 |
||
494 |
LIBXML_TEST_VERSION
|
|
495 |
||
496 |
doc = xmlReadFile (file, NULL, 0); |
|
497 |
if (doc == NULL) |
|
498 |
{
|
|
499 |
printf ("error: could not parse file %s\n", file); |
|
500 |
}
|
|
501 |
||
502 |
root_element = xmlDocGetRootElement (doc); |
|
503 |
list = parse_gpx_routepoints (root_element); |
|
504 |
xmlFreeDoc (doc); |
|
505 |
xmlCleanupParser (); |
|
506 |
||
507 |
return list; |
|
508 |
}
|
|
509 |
||
510 |
/**
|
|
511 |
* Load a route from a file with a supported file format.
|
|
512 |
*/
|
|
513 |
void
|
|
514 |
load_route (const char *filename) |
|
515 |
{
|
|
516 |
bbox_t bbox; |
|
517 |
||
518 |
if (filename == NULL) return; |
|
519 |
||
520 |
route = load_route_as_gpx (filename); |
|
521 |
if (route != NULL) |
|
522 |
{
|
|
523 |
bbox = get_way_bbox (route); |
|
524 |
show_bbox (bbox); |
|
525 |
}
|
|
526 |
}
|
|
527 |
||
208.1.5
by Dr. Tilmann Bubeck
Add choose_load_file() and choose_save_file() utility functions |
528 |
|
529 |
char * |
|
530 |
choose_save_file (char *currentName) |
|
531 |
{
|
|
532 |
char *filename = NULL; |
|
533 |
GtkWidget *dialog; |
|
534 |
dialog = gtk_file_chooser_dialog_new ("Save File", |
|
535 |
NULL, |
|
536 |
GTK_FILE_CHOOSER_ACTION_SAVE, |
|
537 |
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
|
538 |
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, |
|
539 |
NULL); |
|
540 |
gtk_file_chooser_set_do_overwrite_confirmation
|
|
541 |
(GTK_FILE_CHOOSER (dialog), TRUE); |
|
542 |
gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dialog), |
|
543 |
currentName); |
|
544 |
||
545 |
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) |
|
546 |
{
|
|
547 |
filename = gtk_file_chooser_get_filename |
|
548 |
(GTK_FILE_CHOOSER (dialog)); |
|
549 |
}
|
|
550 |
||
551 |
gtk_widget_destroy (dialog); |
|
552 |
||
553 |
return filename; |
|
554 |
}
|
|
555 |
||
556 |
char * |
|
557 |
choose_load_file () |
|
558 |
{
|
|
559 |
char *filename = NULL; |
|
560 |
GtkWidget *dialog; |
|
561 |
dialog = gtk_file_chooser_dialog_new ("Open File", NULL, |
|
562 |
GTK_FILE_CHOOSER_ACTION_OPEN, |
|
563 |
GTK_STOCK_CANCEL, |
|
564 |
GTK_RESPONSE_CANCEL, |
|
565 |
GTK_STOCK_OPEN, |
|
566 |
GTK_RESPONSE_ACCEPT, |
|
567 |
NULL); |
|
568 |
||
569 |
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) |
|
570 |
{
|
|
571 |
filename = gtk_file_chooser_get_filename |
|
572 |
(GTK_FILE_CHOOSER (dialog)); |
|
573 |
}
|
|
574 |
gtk_widget_destroy (dialog); |
|
575 |
||
576 |
return filename; |
|
577 |
}
|