Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 270 - (show annotations)
Thu Aug 20 19:15:45 2009 UTC (14 years, 9 months ago) by harbaum
File MIME type: text/plain
File size: 26006 byte(s)
Released 0.7.16
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of OSM2Go.
5 *
6 * OSM2Go is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * OSM2Go is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with OSM2Go. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "appdata.h"
21
22 #ifdef ENABLE_OSM_GPS_MAP
23 #include "osm-gps-map.h"
24 #endif
25
26 #define TAB_LABEL_MAP "Map"
27 #define TAB_LABEL_DIRECT "Direct"
28 #define TAB_LABEL_EXTENT "Extent"
29 #define TAB_LABEL_MM "Maemo Mapper"
30
31 /* limit of square kilometers above the warning is enabled */
32 #define WARN_OVER 5.0
33
34 typedef struct {
35 GtkWidget *dialog, *notebook;
36 area_edit_t *area;
37 pos_t min, max; /* local copy to work on */
38 GtkWidget *minlat, *maxlat, *minlon, *maxlon;
39 GtkWidget *warning;
40
41 struct {
42 GtkWidget *minlat, *maxlat, *minlon, *maxlon;
43 } direct;
44
45 struct {
46 GtkWidget *lat, *lon, *height, *width, *mil_km;
47 gboolean is_mil;
48 } extent;
49
50 #ifdef USE_HILDON
51 struct {
52 GtkWidget *fetch;
53 } mmapper;
54 #endif
55
56 #ifdef ENABLE_OSM_GPS_MAP
57 struct {
58 GtkWidget *widget;
59 gboolean needs_redraw;
60 gint handler_id;
61 coord_t start;
62 } map;
63 #endif
64 } context_t;
65
66 static void parse_and_set_lat(GtkWidget *src, pos_float_t *store) {
67 pos_float_t i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(src)));
68 if(pos_lat_valid(i))
69 *store = i;
70 }
71
72 static void parse_and_set_lon(GtkWidget *src, pos_float_t *store) {
73 pos_float_t i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(src)));
74 if(pos_lon_valid(i))
75 *store = i;
76 }
77
78 static gboolean current_tab_is(context_t *context, gint page_num, char *str) {
79 if(page_num < 0)
80 page_num =
81 gtk_notebook_get_current_page(GTK_NOTEBOOK(context->notebook));
82
83 if(page_num < 0) return FALSE;
84
85 GtkWidget *w =
86 gtk_notebook_get_nth_page(GTK_NOTEBOOK(context->notebook), page_num);
87 const char *name =
88 gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(context->notebook), w);
89
90 return(strcasecmp(name, _(str)) == 0);
91 }
92
93 static char *warn_text(context_t *context) {
94 /* compute area size */
95 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
96 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
97 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
98
99 double area = vscale * (context->max.lat - context->min.lat) *
100 hscale * (context->max.lon - context->min.lon);
101
102 return g_strdup_printf(
103 _("The currently selected area is %.02f km² (%.02f mi²) in size. "
104 "This is more than the recommended %.02f km² (%.02f mi²).\n\n"
105 "Continuing may result in a big or failing download and low "
106 "mapping performance in a densly mapped area (e.g. cities)!"),
107 area, area/(KMPMIL*KMPMIL),
108 WARN_OVER, WARN_OVER/(KMPMIL*KMPMIL)
109 );
110 }
111
112 static void on_area_warning_clicked(GtkButton *button, gpointer data) {
113 context_t *context = (context_t*)data;
114
115 char *wtext = warn_text(context);
116 warningf(context->dialog, wtext);
117 g_free(wtext);
118 }
119
120 static gboolean area_warning(context_t *context) {
121 gboolean ret = TRUE;
122
123 /* check if area size exceeds recommended values */
124 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
125 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
126 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
127
128 double area = vscale * (context->max.lat - context->min.lat) *
129 hscale * (context->max.lon - context->min.lon);
130
131 if(area > WARN_OVER) {
132 char *wtext = warn_text(context);
133
134 ret = yes_no_f(context->dialog, context->area->appdata,
135 MISC_AGAIN_ID_AREA_TOO_BIG, MISC_AGAIN_FLAG_DONT_SAVE_NO,
136 _("Area size warning!"),
137 _("%s Do you really want to continue?"), wtext);
138
139 g_free(wtext);
140 }
141
142 return ret;
143 }
144
145 static void area_main_update(context_t *context) {
146 pos_lat_label_set(context->minlat, context->min.lat);
147 pos_lat_label_set(context->maxlat, context->max.lat);
148 pos_lon_label_set(context->minlon, context->min.lon);
149 pos_lon_label_set(context->maxlon, context->max.lon);
150
151 /* check if area size exceeds recommended values */
152 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
153 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
154 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
155
156 double area = vscale * (context->max.lat - context->min.lat) *
157 hscale * (context->max.lon - context->min.lon);
158
159 if(area > WARN_OVER)
160 gtk_widget_show(context->warning);
161 else
162 gtk_widget_hide(context->warning);
163 }
164
165 #ifdef ENABLE_OSM_GPS_MAP
166 #define LOG2(x) (log(x) / log(2))
167
168 static GSList *pos_append_rad(GSList *list, pos_float_t lat, pos_float_t lon) {
169 coord_t *coo = g_new0(coord_t, 1);
170 coo->rlat = lat;
171 coo->rlon = lon;
172 list = g_slist_append(list, coo);
173 return list;
174 }
175
176 static GSList *pos_append(GSList *list, pos_float_t lat, pos_float_t lon) {
177 return pos_append_rad(list, DEG2RAD(lat), DEG2RAD(lon));
178 }
179
180 /* the contents of the map tab have been changed */
181 static void map_update(context_t *context, gboolean forced) {
182
183 /* map is first tab (page 0) */
184 if(!forced && !current_tab_is(context, -1, TAB_LABEL_MAP)) {
185 context->map.needs_redraw = TRUE;
186 return;
187 }
188
189 /* check if the position is invalid */
190 if(isnan(context->min.lat) || isnan(context->min.lon) ||
191 isnan(context->min.lat) || isnan(context->min.lon)) {
192
193 /* no coordinates given: display the entire world */
194 osm_gps_map_set_mapcenter(OSM_GPS_MAP(context->map.widget),
195 0.0, 0.0, 1);
196
197 osm_gps_map_clear_tracks(OSM_GPS_MAP(context->map.widget));
198 } else {
199
200 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
201 pos_float_t center_lon = (context->max.lon + context->min.lon)/2;
202
203 /* we know the widgets pixel size, we know the required real size, */
204 /* we want the zoom! */
205 double vzoom = LOG2((45.0 * context->map.widget->allocation.height)/
206 ((context->max.lat - context->min.lat)*32.0)) -1;
207
208 double hzoom = LOG2((45.0 * context->map.widget->allocation.width)/
209 ((context->max.lon - context->min.lon)*32.0)) -1;
210
211 osm_gps_map_set_center(OSM_GPS_MAP(context->map.widget),
212 center_lat, center_lon);
213
214 /* use smallest zoom, so everything fits on screen */
215 osm_gps_map_set_zoom(OSM_GPS_MAP(context->map.widget),
216 (vzoom < hzoom)?vzoom:hzoom);
217
218 /* ---------- draw border (as a gps track) -------------- */
219 osm_gps_map_clear_tracks(OSM_GPS_MAP(context->map.widget));
220
221 GSList *box = pos_append(NULL, context->min.lat, context->min.lon);
222 box = pos_append(box, context->max.lat, context->min.lon);
223 box = pos_append(box, context->max.lat, context->max.lon);
224 box = pos_append(box, context->min.lat, context->max.lon);
225 box = pos_append(box, context->min.lat, context->min.lon);
226
227 osm_gps_map_add_track(OSM_GPS_MAP(context->map.widget), box);
228 }
229
230 context->map.needs_redraw = FALSE;
231 }
232
233 static gboolean on_map_configure(GtkWidget *widget,
234 GdkEventConfigure *event,
235 context_t *context) {
236 map_update(context, FALSE);
237 return FALSE;
238 }
239 #endif
240
241 /* the contents of the direct tab have been changed */
242 static void direct_update(context_t *context) {
243 pos_lat_entry_set(context->direct.minlat, context->min.lat);
244 pos_lon_entry_set(context->direct.minlon, context->min.lon);
245 pos_lat_entry_set(context->direct.maxlat, context->max.lat);
246 pos_lon_entry_set(context->direct.maxlon, context->max.lon);
247 }
248
249 /* update the contents of the extent tab */
250 static void extent_update(context_t *context) {
251 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
252 pos_float_t center_lon = (context->max.lon + context->min.lon)/2;
253
254 pos_lat_entry_set(context->extent.lat, center_lat);
255 pos_lat_entry_set(context->extent.lon, center_lon);
256
257 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
258 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
259
260 double height = vscale * (context->max.lat - context->min.lat);
261 double width = hscale * (context->max.lon - context->min.lon);
262
263 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
264 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
265 }
266
267 static void callback_modified_direct(GtkWidget *widget, gpointer data) {
268 context_t *context = (context_t*)data;
269
270 /* direct is second tab (page 1) */
271 if(!current_tab_is(context, -1, TAB_LABEL_DIRECT))
272 return;
273
274 /* parse the fields from the direct entry pad */
275 parse_and_set_lat(context->direct.minlat, &context->min.lat);
276 parse_and_set_lon(context->direct.minlon, &context->min.lon);
277 parse_and_set_lat(context->direct.maxlat, &context->max.lat);
278 parse_and_set_lon(context->direct.maxlon, &context->max.lon);
279
280 area_main_update(context);
281
282 /* also adjust other views */
283 extent_update(context);
284 #ifdef ENABLE_OSM_GPS_MAP
285 map_update(context, FALSE);
286 #endif
287 }
288
289 static void callback_modified_extent(GtkWidget *widget, gpointer data) {
290 context_t *context = (context_t*)data;
291
292 /* extent is third tab (page 2) */
293 if(!current_tab_is(context, -1, TAB_LABEL_EXTENT))
294 return;
295
296 pos_float_t center_lat = pos_lat_get(context->extent.lat);
297 pos_float_t center_lon = pos_lon_get(context->extent.lon);
298
299 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
300 return;
301
302 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
303 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
304
305 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
306 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
307
308 height /= 2 * vscale;
309 context->min.lat = center_lat - height;
310 context->max.lat = center_lat + height;
311
312 width /= 2 * hscale;
313 context->min.lon = center_lon - width;
314 context->max.lon = center_lon + width;
315
316 area_main_update(context);
317
318 /* also update other tabs */
319 direct_update(context);
320 #ifdef ENABLE_OSM_GPS_MAP
321 map_update(context, FALSE);
322 #endif
323 }
324
325 static void callback_modified_unit(GtkWidget *widget, gpointer data) {
326 context_t *context = (context_t*)data;
327
328 /* get current values */
329 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
330 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
331
332 /* adjust unit flag */
333 context->extent.is_mil = gtk_combo_box_get_active(
334 GTK_COMBO_BOX(context->extent.mil_km)) == 0;
335
336 /* save values */
337 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
338 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
339 }
340
341 #ifdef USE_HILDON
342 static void callback_fetch_mm_clicked(GtkButton *button, gpointer data) {
343 context_t *context = (context_t*)data;
344
345 if(!dbus_mm_set_position(context->area->appdata->osso_context, NULL)) {
346 errorf(context->dialog,
347 _("Unable to communicate with Maemo Mapper. "
348 "You need to have Maemo Mapper installed "
349 "to use this feature."));
350 return;
351 }
352
353 if(!context->area->appdata->mmpos.valid) {
354 errorf(context->dialog,
355 _("No valid position received yet. You need "
356 "to scroll or zoom the Maemo Mapper view "
357 "in order to force it to send its current "
358 "view position to osm2go."));
359 return;
360 }
361
362 /* maemo mapper is fourth tab (page 3) */
363 if(!current_tab_is(context, -1, TAB_LABEL_MM))
364 return;
365
366 /* maemo mapper pos data ... */
367 pos_float_t center_lat = context->area->appdata->mmpos.pos.lat;
368 pos_float_t center_lon = context->area->appdata->mmpos.pos.lon;
369 int zoom = context->area->appdata->mmpos.zoom;
370
371 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
372 return;
373
374 double vscale = DEG2RAD(POS_EQ_RADIUS);
375 double height = 8 * (1<<zoom) / vscale;
376 context->min.lat = center_lat - height;
377 context->max.lat = center_lat + height;
378
379 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS);
380 double width = 16 * (1<<zoom) / hscale;
381 context->min.lon = center_lon - width;
382 context->max.lon = center_lon + width;
383
384 area_main_update(context);
385
386 /* also update other tabs */
387 direct_update(context);
388 extent_update(context);
389 #ifdef ENABLE_OSM_GPS_MAP
390 map_update(context, FALSE);
391 #endif
392 }
393 #endif
394
395 #ifdef ENABLE_OSM_GPS_MAP
396
397 static gboolean
398 on_map_button_press_event(GtkWidget *widget,
399 GdkEventButton *event, context_t *context) {
400 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
401
402 /* osm-gps-map needs this event to handle the OSD */
403 if(osm_gps_map_osd_check((int)event->x, (int)event->y))
404 return FALSE;
405
406 /* remove existing marker */
407 osm_gps_map_clear_tracks(map);
408
409 /* and remember this location as the start */
410 context->map.start =
411 osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y);
412
413 return TRUE;
414 }
415
416 static gboolean
417 on_map_motion_notify_event(GtkWidget *widget,
418 GdkEventMotion *event, context_t *context) {
419 if(!isnan(context->map.start.rlon) &&
420 !isnan(context->map.start.rlat)) {
421 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
422
423 /* remove existing marker */
424 osm_gps_map_clear_tracks(map);
425
426 coord_t start = context->map.start, end =
427 osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y);
428
429 GSList *box = pos_append_rad(NULL, start.rlat, start.rlon);
430 box = pos_append_rad(box, end.rlat, start.rlon);
431 box = pos_append_rad(box, end.rlat, end.rlon);
432 box = pos_append_rad(box, start.rlat, end.rlon);
433 box = pos_append_rad(box, start.rlat, start.rlon);
434
435 osm_gps_map_add_track(map, box);
436 }
437
438 /* always returning true here disables dragging in osm-gps-map */
439 return TRUE;
440 }
441
442 static gboolean
443 on_map_button_release_event(GtkWidget *widget,
444 GdkEventButton *event, context_t *context) {
445
446 if(!isnan(context->map.start.rlon) &&
447 !isnan(context->map.start.rlat)) {
448 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
449
450 coord_t start = context->map.start, end =
451 osm_gps_map_get_co_ordinates(map, (int)event->x, (int)event->y);
452
453 GSList *box = pos_append_rad(NULL, start.rlat, start.rlon);
454 box = pos_append_rad(box, end.rlat, start.rlon);
455 box = pos_append_rad(box, end.rlat, end.rlon);
456 box = pos_append_rad(box, start.rlat, end.rlon);
457 box = pos_append_rad(box, start.rlat, start.rlon);
458
459 osm_gps_map_add_track(map, box);
460
461 if(start.rlat < end.rlat) {
462 context->min.lat = RAD2DEG(start.rlat);
463 context->max.lat = RAD2DEG(end.rlat);
464 } else {
465 context->min.lat = RAD2DEG(end.rlat);
466 context->max.lat = RAD2DEG(start.rlat);
467 }
468
469 if(start.rlon < end.rlon) {
470 context->min.lon = RAD2DEG(start.rlon);
471 context->max.lon = RAD2DEG(end.rlon);
472 } else {
473 context->min.lon = RAD2DEG(end.rlon);
474 context->max.lon = RAD2DEG(start.rlon);
475 }
476
477 area_main_update(context);
478 direct_update(context);
479 extent_update(context);
480
481 context->map.start.rlon = context->map.start.rlat = NAN;
482 }
483
484 /* osm-gps-map needs this event to handle the OSD */
485 if(osm_gps_map_osd_check((int)event->x, (int)event->y))
486 return FALSE;
487
488 return TRUE;
489 }
490
491 #if 0
492 static void map_zoom(context_t *context, int step) {
493 int zoom;
494 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
495 g_object_get(map, "zoom", &zoom, NULL);
496 zoom = osm_gps_map_set_zoom(map, zoom+step);
497 }
498 #endif
499
500 static void
501 cb_map_gps(context_t *context) {
502 pos_t pos;
503
504 /* user clicked "gps" button -> jump to position */
505 gboolean gps_on =
506 context->area->appdata->settings &&
507 context->area->appdata->settings->enable_gps;
508
509 if(gps_on && gps_get_pos(context->area->appdata, &pos, NULL)) {
510 osm_gps_map_set_center(OSM_GPS_MAP(context->map.widget),
511 pos.lat, pos.lon);
512 }
513 }
514
515 static void on_page_switch(GtkNotebook *notebook, GtkNotebookPage *page,
516 guint page_num, context_t *context) {
517
518 /* updating the map while the user manually changes some coordinates */
519 /* may confuse the map. so we delay those updates until the map tab */
520 /* is becoming visible */
521 if(current_tab_is(context, page_num, TAB_LABEL_MAP) &&
522 context->map.needs_redraw)
523 map_update(context, TRUE);
524 }
525
526 static gboolean map_gps_update(gpointer data) {
527 context_t *context = (context_t*)data;
528
529 gboolean gps_on =
530 context->area->appdata->settings &&
531 context->area->appdata->settings->enable_gps;
532
533 gboolean gps_fix = gps_on &&
534 gps_get_pos(context->area->appdata, NULL, NULL);
535
536 /* ... and enable "goto" button if it's valid */
537 osm_gps_map_osd_enable_gps(OSM_GPS_MAP(context->map.widget),
538 OSM_GPS_MAP_OSD_GPS_CALLBACK(gps_fix?cb_map_gps:NULL), context);
539
540
541 return TRUE;
542 }
543
544 #endif
545
546 gboolean area_edit(area_edit_t *area) {
547 GtkWidget *vbox;
548
549 context_t context;
550 memset(&context, 0, sizeof(context_t));
551 context.area = area;
552 context.min.lat = area->min->lat;
553 context.min.lon = area->min->lon;
554 context.max.lat = area->max->lat;
555 context.max.lon = area->max->lon;
556
557 context.dialog =
558 misc_dialog_new(MISC_DIALOG_HIGH, _("Area editor"),
559 GTK_WINDOW(area->parent),
560 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
561 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
562 NULL);
563
564 GtkWidget *table = gtk_table_new(5, 2, FALSE); // x, y
565
566 GtkWidget *label = gtk_label_new(_("Latitude:"));
567 misc_table_attach(table, label, 0, 0);
568 context.minlat = pos_lat_label_new(area->min->lat);
569 misc_table_attach(table, context.minlat, 1, 0);
570 label = gtk_label_new(_("to"));
571 misc_table_attach(table, label, 2, 0);
572 context.maxlat = pos_lat_label_new(area->max->lat);
573 misc_table_attach(table, context.maxlat, 3, 0);
574
575 label = gtk_label_new(_("Longitude:"));
576 misc_table_attach(table, label, 0, 1);
577 context.minlon = pos_lon_label_new(area->min->lon);
578 misc_table_attach(table, context.minlon, 1, 1);
579 label = gtk_label_new(_("to"));
580 misc_table_attach(table, label, 2, 1);
581 context.maxlon = pos_lon_label_new(area->max->lon);
582 misc_table_attach(table, context.maxlon, 3, 1);
583
584 context.warning = gtk_button_new();
585 gtk_button_set_image(GTK_BUTTON(context.warning),
586 gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,
587 GTK_ICON_SIZE_BUTTON));
588 g_signal_connect(context.warning, "clicked",
589 G_CALLBACK(on_area_warning_clicked), &context);
590 gtk_table_attach_defaults(GTK_TABLE(table), context.warning, 4, 5, 0, 2);
591
592 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
593 table, FALSE, FALSE, 0);
594
595 context.notebook = gtk_notebook_new();
596
597 #ifdef ENABLE_OSM_GPS_MAP
598 /* ------------- fetch from map ------------------------ */
599
600 context.map.needs_redraw = FALSE;
601 context.map.widget = g_object_new(OSM_TYPE_GPS_MAP,
602 "map-source", OSM_GPS_MAP_SOURCE_OPENSTREETMAP,
603 "proxy-uri", misc_get_proxy_uri(area->settings),
604 "tile-cache", NULL,
605 NULL);
606
607 g_signal_connect(G_OBJECT(context.map.widget), "configure-event",
608 G_CALLBACK(on_map_configure), &context);
609 g_signal_connect(G_OBJECT(context.map.widget), "button-press-event",
610 G_CALLBACK(on_map_button_press_event), &context);
611 g_signal_connect(G_OBJECT(context.map.widget), "motion-notify-event",
612 G_CALLBACK(on_map_motion_notify_event), &context);
613 g_signal_connect(G_OBJECT(context.map.widget), "button-release-event",
614 G_CALLBACK(on_map_button_release_event), &context);
615
616 /* install handler for timed updates of the gps button */
617 context.map.handler_id = gtk_timeout_add(1000, map_gps_update, &context);
618 context.map.start.rlon = context.map.start.rlat = NAN;
619
620 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
621 context.map.widget, gtk_label_new(_(TAB_LABEL_MAP)));
622 #endif
623
624 /* ------------ direct min/max edit --------------- */
625
626 vbox = gtk_vbox_new(FALSE, 10);
627 table = gtk_table_new(3, 3, FALSE); // x, y
628 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
629 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
630
631 context.direct.minlat = pos_lat_entry_new(0.0);
632 misc_table_attach(table, context.direct.minlat, 0, 0);
633 label = gtk_label_new(_("to"));
634 misc_table_attach(table, label, 1, 0);
635 context.direct.maxlat = pos_lat_entry_new(0.0);
636 misc_table_attach(table, context.direct.maxlat, 2, 0);
637
638 context.direct.minlon = pos_lon_entry_new(area->min->lon);
639 misc_table_attach(table, context.direct.minlon, 0, 1);
640 label = gtk_label_new(_("to"));
641 misc_table_attach(table, label, 1, 1);
642 context.direct.maxlon = pos_lon_entry_new(0.0);
643 misc_table_attach(table, context.direct.maxlon, 2, 1);
644
645 /* setup this page */
646 direct_update(&context);
647
648 g_signal_connect(G_OBJECT(context.direct.minlat), "changed",
649 G_CALLBACK(callback_modified_direct), &context);
650 g_signal_connect(G_OBJECT(context.direct.minlon), "changed",
651 G_CALLBACK(callback_modified_direct), &context);
652 g_signal_connect(G_OBJECT(context.direct.maxlat), "changed",
653 G_CALLBACK(callback_modified_direct), &context);
654 g_signal_connect(G_OBJECT(context.direct.maxlon), "changed",
655 G_CALLBACK(callback_modified_direct), &context);
656
657
658 /* --- hint --- */
659 label = gtk_label_new(_("(recommended min/max diff <0.03 degrees)"));
660 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 2, 3);
661
662 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
663 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
664 vbox, gtk_label_new(_(TAB_LABEL_DIRECT)));
665
666 /* ------------- center/extent edit ------------------------ */
667
668 vbox = gtk_vbox_new(FALSE, 10);
669 table = gtk_table_new(3, 4, FALSE); // x, y
670 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
671 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
672
673 label = gtk_label_new(_("Center:"));
674 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
675 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
676 context.extent.lat = pos_lat_entry_new(0.0);
677 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lat, 1, 2, 0, 1);
678 context.extent.lon = pos_lon_entry_new(0.0);
679 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lon, 2, 3, 0, 1);
680
681 gtk_table_set_row_spacing(GTK_TABLE(table), 0, 10);
682
683 label = gtk_label_new(_("Width:"));
684 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
685 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
686 context.extent.width = gtk_entry_new();
687 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.width, 1, 2, 1, 2);
688
689 label = gtk_label_new(_("Height:"));
690 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
691 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
692 context.extent.height = gtk_entry_new();
693 gtk_table_attach_defaults(GTK_TABLE(table),
694 context.extent.height, 1, 2, 2, 3);
695
696 context.extent.mil_km = gtk_combo_box_new_text();
697 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("mi"));
698 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("km"));
699 gtk_combo_box_set_active(GTK_COMBO_BOX(context.extent.mil_km), 1); // km
700
701 gtk_table_attach(GTK_TABLE(table), context.extent.mil_km, 2, 3, 1, 3,
702 0, 0, 0, 0);
703
704 /* setup this page */
705 extent_update(&context);
706
707 /* connect signals after inital update to avoid confusion */
708 g_signal_connect(G_OBJECT(context.extent.lat), "changed",
709 G_CALLBACK(callback_modified_extent), &context);
710 g_signal_connect(G_OBJECT(context.extent.lon), "changed",
711 G_CALLBACK(callback_modified_extent), &context);
712 g_signal_connect(G_OBJECT(context.extent.width), "changed",
713 G_CALLBACK(callback_modified_extent), &context);
714 g_signal_connect(G_OBJECT(context.extent.height), "changed",
715 G_CALLBACK(callback_modified_extent), &context);
716 g_signal_connect(G_OBJECT(context.extent.mil_km), "changed",
717 G_CALLBACK(callback_modified_unit), &context);
718
719 /* --- hint --- */
720 label = gtk_label_new(_("(recommended width/height < 2km/1.25mi)"));
721 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 3, 4);
722
723 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
724 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
725 vbox, gtk_label_new(_(TAB_LABEL_EXTENT)));
726
727 #ifdef USE_HILDON
728 /* ------------- fetch from maemo mapper ------------------------ */
729
730 vbox = gtk_vbox_new(FALSE, 8);
731 context.mmapper.fetch =
732 gtk_button_new_with_label(_("Get from Maemo Mapper"));
733 gtk_box_pack_start(GTK_BOX(vbox), context.mmapper.fetch, FALSE, FALSE, 0);
734
735 g_signal_connect(G_OBJECT(context.mmapper.fetch), "clicked",
736 G_CALLBACK(callback_fetch_mm_clicked), &context);
737
738 /* --- hint --- */
739 label = gtk_label_new(_("(recommended MM zoom level < 7)"));
740 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
741
742
743 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
744 vbox, gtk_label_new(_(TAB_LABEL_MM)));
745 #endif
746
747 /* ------------------------------------------------------ */
748
749 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
750 context.notebook);
751
752 #ifdef ENABLE_OSM_GPS_MAP
753 g_signal_connect(G_OBJECT(context.notebook), "switch-page",
754 G_CALLBACK(on_page_switch), &context);
755 #endif
756
757 gtk_widget_show_all(context.dialog);
758
759 area_main_update(&context);
760
761 gboolean leave = FALSE, ok = FALSE;
762 do {
763 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) {
764 if(area_warning(&context)) {
765 leave = TRUE;
766 ok = TRUE;
767 }
768 } else
769 leave = TRUE;
770 } while(!leave);
771
772 if(ok) {
773 /* copy modified values back to given storage */
774 area->min->lat = context.min.lat;
775 area->min->lon = context.min.lon;
776 area->max->lat = context.max.lat;
777 area->max->lon = context.max.lon;
778 }
779
780 #ifdef ENABLE_OSM_GPS_MAP
781 gtk_timeout_remove(context.map.handler_id);
782 #endif
783
784 gtk_widget_destroy(context.dialog);
785
786 return ok;
787 }