Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 215 - (show annotations)
Sun Jul 12 20:01:14 2009 UTC (14 years, 10 months ago) by harbaum
File MIME type: text/plain
File size: 21965 byte(s)
Draw exact border in osm-gps-map
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 struct {
57 GtkWidget *widget;
58 GtkWidget *zoomin, *zoomout;
59 gboolean needs_redraw;
60 } map;
61
62 } context_t;
63
64 static void parse_and_set_lat(GtkWidget *src, pos_float_t *store) {
65 pos_float_t i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(src)));
66 if(pos_lat_valid(i))
67 *store = i;
68 }
69
70 static void parse_and_set_lon(GtkWidget *src, pos_float_t *store) {
71 pos_float_t i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(src)));
72 if(pos_lon_valid(i))
73 *store = i;
74 }
75
76 #define LOG2(x) (log(x) / log(2))
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 void on_area_warning_clicked(GtkButton *button, gpointer data) {
94 context_t *context = (context_t*)data;
95
96 /* compute area size */
97 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
98 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
99 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
100
101 double area = vscale * (context->max.lat - context->min.lat) *
102 hscale * (context->max.lon - context->min.lon);
103
104 warningf(context->dialog,
105 _("The currently selected area is %.02f km² (%.02f mil²) in size. "
106 "This is more than the recommended %.02f km² (%.02f mil²).\n\n"
107 "Continuing may result in a big download and low mapping performance "
108 "in a densly mapped area (e.g. cities)!"),
109 area, area/(KMPMIL*KMPMIL),
110 WARN_OVER, WARN_OVER/(KMPMIL*KMPMIL)
111 );
112
113 }
114
115 static void area_main_update(context_t *context) {
116 pos_lat_label_set(context->minlat, context->min.lat);
117 pos_lat_label_set(context->maxlat, context->max.lat);
118 pos_lon_label_set(context->minlon, context->min.lon);
119 pos_lon_label_set(context->maxlon, context->max.lon);
120
121 /* check if area size exceeds recommended values */
122 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
123 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
124 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
125
126 double area = vscale * (context->max.lat - context->min.lat) *
127 hscale * (context->max.lon - context->min.lon);
128
129 if(area > WARN_OVER)
130 gtk_widget_show(context->warning);
131 else
132 gtk_widget_hide(context->warning);
133 }
134
135 #ifdef ENABLE_OSM_GPS_MAP
136 static GSList *pos_append(GSList *list, pos_float_t lat, pos_float_t lon) {
137 coord_t *coo = g_new0(coord_t, 1);
138 coo->rlat = DEG2RAD(lat);
139 coo->rlon = DEG2RAD(lon);
140 list = g_slist_append(list, coo);
141 return list;
142 }
143
144 /* the contents of the map tab have been changed */
145 static void map_update(context_t *context, gboolean forced) {
146
147 /* map is first tab (page 0) */
148 if(!forced && !current_tab_is(context, -1, TAB_LABEL_MAP)) {
149 context->map.needs_redraw = TRUE;
150 return;
151 }
152
153 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
154 pos_float_t center_lon = (context->max.lon + context->min.lon)/2;
155
156 /* we know the widgets pixel size, we know the required real size, */
157 /* we want the zoom! */
158 double vzoom = LOG2((45.0 * context->map.widget->allocation.height)/
159 ((context->max.lat - context->min.lat)*32.0));
160
161 double hzoom = LOG2((45.0 * context->map.widget->allocation.width)/
162 ((context->max.lon - context->min.lon)*32.0));
163
164 osm_gps_map_set_center(OSM_GPS_MAP(context->map.widget),
165 center_lat, center_lon);
166
167 /* use smallest zoom, so everything fits on screen */
168 osm_gps_map_set_zoom(OSM_GPS_MAP(context->map.widget),
169 (vzoom < hzoom)?vzoom:hzoom);
170
171 /* ---------- draw border (as a gps track) -------------- */
172 osm_gps_map_clear_tracks(OSM_GPS_MAP(context->map.widget));
173
174 GSList *box = pos_append(NULL, context->min.lat, context->min.lon);
175 box = pos_append(box, context->max.lat, context->min.lon);
176 box = pos_append(box, context->max.lat, context->max.lon);
177 box = pos_append(box, context->min.lat, context->max.lon);
178 box = pos_append(box, context->min.lat, context->min.lon);
179
180 osm_gps_map_add_track(OSM_GPS_MAP(context->map.widget), box);
181
182 context->map.needs_redraw = FALSE;
183 }
184
185 static gboolean on_map_configure(GtkWidget *widget,
186 GdkEventConfigure *event,
187 context_t *context) {
188 map_update(context, FALSE);
189 return FALSE;
190 }
191 #endif
192
193 /* the contents of the direct tab have been changed */
194 static void direct_update(context_t *context) {
195 pos_lat_entry_set(context->direct.minlat, context->min.lat);
196 pos_lon_entry_set(context->direct.minlon, context->min.lon);
197 pos_lat_entry_set(context->direct.maxlat, context->max.lat);
198 pos_lon_entry_set(context->direct.maxlon, context->max.lon);
199 }
200
201 /* update the contents of the extent tab */
202 static void extent_update(context_t *context) {
203 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
204 pos_float_t center_lon = (context->max.lon + context->min.lon)/2;
205
206 pos_lat_entry_set(context->extent.lat, center_lat);
207 pos_lat_entry_set(context->extent.lon, center_lon);
208
209 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
210 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
211
212 double height = vscale * (context->max.lat - context->min.lat);
213 double width = hscale * (context->max.lon - context->min.lon);
214
215 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
216 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
217 }
218
219 static void callback_modified_direct(GtkWidget *widget, gpointer data) {
220 context_t *context = (context_t*)data;
221
222 /* direct is second tab (page 1) */
223 if(!current_tab_is(context, -1, TAB_LABEL_DIRECT))
224 return;
225
226 /* parse the fields from the direct entry pad */
227 parse_and_set_lat(context->direct.minlat, &context->min.lat);
228 parse_and_set_lon(context->direct.minlon, &context->min.lon);
229 parse_and_set_lat(context->direct.maxlat, &context->max.lat);
230 parse_and_set_lon(context->direct.maxlon, &context->max.lon);
231
232 area_main_update(context);
233
234 /* also adjust other views */
235 extent_update(context);
236 #ifdef ENABLE_OSM_GPS_MAP
237 map_update(context, FALSE);
238 #endif
239 }
240
241 static void callback_modified_extent(GtkWidget *widget, gpointer data) {
242 context_t *context = (context_t*)data;
243
244 /* extent is third tab (page 2) */
245 if(!current_tab_is(context, -1, TAB_LABEL_EXTENT))
246 return;
247
248 pos_float_t center_lat = pos_lat_get(context->extent.lat);
249 pos_float_t center_lon = pos_lon_get(context->extent.lon);
250
251 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
252 return;
253
254 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
255 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
256
257 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
258 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
259
260 height /= 2 * vscale;
261 context->min.lat = center_lat - height;
262 context->max.lat = center_lat + height;
263
264 width /= 2 * hscale;
265 context->min.lon = center_lon - width;
266 context->max.lon = center_lon + width;
267
268 area_main_update(context);
269
270 /* also update other tabs */
271 direct_update(context);
272 #ifdef ENABLE_OSM_GPS_MAP
273 map_update(context, FALSE);
274 #endif
275 }
276
277 static void callback_modified_unit(GtkWidget *widget, gpointer data) {
278 context_t *context = (context_t*)data;
279
280 /* get current values */
281 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
282 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
283
284 /* adjust unit flag */
285 context->extent.is_mil = gtk_combo_box_get_active(
286 GTK_COMBO_BOX(context->extent.mil_km)) == 0;
287
288 /* save values */
289 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
290 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
291 }
292
293 #ifdef USE_HILDON
294 static void callback_fetch_mm_clicked(GtkButton *button, gpointer data) {
295 context_t *context = (context_t*)data;
296
297 if(!dbus_mm_set_position(context->area->osso_context, NULL)) {
298 errorf(context->dialog,
299 _("Unable to communicate with Maemo Mapper. "
300 "You need to have Maemo Mapper installed "
301 "to use this feature."));
302 return;
303 }
304
305 if(!context->area->mmpos->valid) {
306 errorf(context->dialog,
307 _("No valid position received yet. You need "
308 "to scroll or zoom the Maemo Mapper view "
309 "in order to force it to send its current "
310 "view position to osm2go."));
311 return;
312 }
313
314 /* maemo mapper is fourth tab (page 3) */
315 if(!current_tab_is(context, -1, TAB_LABEL_MM))
316 return;
317
318 /* maemo mapper pos data ... */
319 pos_float_t center_lat = context->area->mmpos->pos.lat;
320 pos_float_t center_lon = context->area->mmpos->pos.lon;
321 int zoom = context->area->mmpos->zoom;
322
323 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
324 return;
325
326 double vscale = DEG2RAD(POS_EQ_RADIUS);
327 double height = 8 * (1<<zoom) / vscale;
328 context->min.lat = center_lat - height;
329 context->max.lat = center_lat + height;
330
331 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS);
332 double width = 16 * (1<<zoom) / hscale;
333 context->min.lon = center_lon - width;
334 context->max.lon = center_lon + width;
335
336 area_main_update(context);
337
338 /* also update other tabs */
339 direct_update(context);
340 extent_update(context);
341 #ifdef ENABLE_OSM_GPS_MAP
342 map_update(context, FALSE);
343 #endif
344 }
345 #endif
346
347 #ifdef ENABLE_OSM_GPS_MAP
348 /* the user has changed the map view, update other views accordingly */
349 static void map_has_changed(context_t *context) {
350 coord_t pt1, pt2;
351
352 /* get maps bounding box */
353 osm_gps_map_get_bbox(OSM_GPS_MAP(context->map.widget), &pt1, &pt2);
354
355 context->min.lat = RAD2DEG(pt2.rlat);
356 context->max.lat = RAD2DEG(pt1.rlat);
357
358 context->min.lon = RAD2DEG(pt1.rlon);
359 context->max.lon = RAD2DEG(pt2.rlon);
360
361 area_main_update(context);
362 direct_update(context);
363 extent_update(context);
364 }
365
366 static gboolean
367 on_map_button_release_event(GtkWidget *widget,
368 GdkEventButton *event, context_t *context) {
369 map_has_changed(context);
370 return FALSE;
371 }
372
373 static void map_zoom(context_t *context, int step) {
374 int zoom;
375 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
376 g_object_get(map, "zoom", &zoom, NULL);
377 zoom = osm_gps_map_set_zoom(map, zoom+step);
378
379 /* enable/disable zoom buttons as required */
380 gtk_widget_set_sensitive(context->map.zoomin, zoom<17);
381 gtk_widget_set_sensitive(context->map.zoomout, zoom>1);
382
383 map_has_changed(context);
384 }
385
386 static gboolean
387 cb_map_zoomin(GtkButton *button, context_t *context) {
388 map_zoom(context, +1);
389 return FALSE;
390 }
391
392 static gboolean
393 cb_map_zoomout(GtkButton *button, context_t *context) {
394 map_zoom(context, -1);
395 return FALSE;
396 }
397
398 static void on_page_switch(GtkNotebook *notebook, GtkNotebookPage *page,
399 guint page_num, context_t *context) {
400
401 /* updating the map while the user manually changes some coordinates */
402 /* may confuse the map. so we delay those updates until the map tab */
403 /* is becoming visible */
404 if(current_tab_is(context, page_num, TAB_LABEL_MAP) &&
405 context->map.needs_redraw)
406 map_update(context, TRUE);
407 }
408 #endif
409
410 gboolean area_edit(area_edit_t *area) {
411 GtkWidget *vbox;
412 gboolean ok = FALSE;
413
414 context_t context;
415 memset(&context, 0, sizeof(context_t));
416 context.area = area;
417 context.min.lat = area->min->lat;
418 context.min.lon = area->min->lon;
419 context.max.lat = area->max->lat;
420 context.max.lon = area->max->lon;
421
422 context.dialog =
423 misc_dialog_new(MISC_DIALOG_HIGH, _("Area editor"),
424 GTK_WINDOW(area->parent),
425 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
426 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
427 NULL);
428
429 GtkWidget *table = gtk_table_new(5, 2, FALSE); // x, y
430
431 GtkWidget *label = gtk_label_new(_("Latitude:"));
432 misc_table_attach(table, label, 0, 0);
433 context.minlat = pos_lat_label_new(area->min->lat);
434 misc_table_attach(table, context.minlat, 1, 0);
435 label = gtk_label_new(_("to"));
436 misc_table_attach(table, label, 2, 0);
437 context.maxlat = pos_lat_label_new(area->max->lat);
438 misc_table_attach(table, context.maxlat, 3, 0);
439
440 label = gtk_label_new(_("Longitude:"));
441 misc_table_attach(table, label, 0, 1);
442 context.minlon = pos_lon_label_new(area->min->lon);
443 misc_table_attach(table, context.minlon, 1, 1);
444 label = gtk_label_new(_("to"));
445 misc_table_attach(table, label, 2, 1);
446 context.maxlon = pos_lon_label_new(area->max->lon);
447 misc_table_attach(table, context.maxlon, 3, 1);
448
449 context.warning = gtk_button_new();
450 gtk_button_set_image(GTK_BUTTON(context.warning),
451 gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,
452 GTK_ICON_SIZE_BUTTON));
453 g_signal_connect(context.warning, "clicked",
454 G_CALLBACK(on_area_warning_clicked), &context);
455 gtk_table_attach_defaults(GTK_TABLE(table), context.warning, 4, 5, 0, 2);
456
457 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
458 table, FALSE, FALSE, 0);
459
460 context.notebook = gtk_notebook_new();
461
462 #ifdef ENABLE_OSM_GPS_MAP
463 /* ------------- fetch from map ------------------------ */
464
465 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
466
467 context.map.needs_redraw = FALSE;
468 context.map.widget = g_object_new(OSM_TYPE_GPS_MAP,
469 "repo-uri", MAP_SOURCE_OPENSTREETMAP,
470 "proxy-uri", misc_get_proxy_uri(area->settings),
471 NULL);
472
473 g_signal_connect(G_OBJECT(context.map.widget), "configure-event",
474 G_CALLBACK(on_map_configure), &context);
475 g_signal_connect(G_OBJECT(context.map.widget), "button-release-event",
476 G_CALLBACK(on_map_button_release_event), &context);
477
478 gtk_box_pack_start_defaults(GTK_BOX(hbox), context.map.widget);
479
480 /* zoom button box */
481 vbox = gtk_vbox_new(FALSE,0);
482
483 context.map.zoomin = gtk_button_new();
484 gtk_button_set_image(GTK_BUTTON(context.map.zoomin),
485 gtk_image_new_from_stock(GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_MENU));
486 g_signal_connect(context.map.zoomin, "clicked",
487 G_CALLBACK(cb_map_zoomin), &context);
488 gtk_box_pack_start(GTK_BOX(vbox), context.map.zoomin, FALSE, FALSE, 0);
489
490 context.map.zoomout = gtk_button_new();
491 gtk_button_set_image(GTK_BUTTON(context.map.zoomout),
492 gtk_image_new_from_stock(GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_MENU));
493 g_signal_connect(context.map.zoomout, "clicked",
494 G_CALLBACK(cb_map_zoomout), &context);
495 gtk_box_pack_start(GTK_BOX(vbox), context.map.zoomout, FALSE, FALSE, 0);
496
497 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
498
499 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
500 hbox, gtk_label_new(_(TAB_LABEL_MAP)));
501 #endif
502
503 /* ------------ direct min/max edit --------------- */
504
505 vbox = gtk_vbox_new(FALSE, 10);
506 table = gtk_table_new(3, 3, FALSE); // x, y
507 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
508 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
509
510 context.direct.minlat = pos_lat_entry_new(0.0);
511 misc_table_attach(table, context.direct.minlat, 0, 0);
512 label = gtk_label_new(_("to"));
513 misc_table_attach(table, label, 1, 0);
514 context.direct.maxlat = pos_lat_entry_new(0.0);
515 misc_table_attach(table, context.direct.maxlat, 2, 0);
516
517 context.direct.minlon = pos_lon_entry_new(area->min->lon);
518 misc_table_attach(table, context.direct.minlon, 0, 1);
519 label = gtk_label_new(_("to"));
520 misc_table_attach(table, label, 1, 1);
521 context.direct.maxlon = pos_lon_entry_new(0.0);
522 misc_table_attach(table, context.direct.maxlon, 2, 1);
523
524 /* setup this page */
525 direct_update(&context);
526
527 g_signal_connect(G_OBJECT(context.direct.minlat), "changed",
528 G_CALLBACK(callback_modified_direct), &context);
529 g_signal_connect(G_OBJECT(context.direct.minlon), "changed",
530 G_CALLBACK(callback_modified_direct), &context);
531 g_signal_connect(G_OBJECT(context.direct.maxlat), "changed",
532 G_CALLBACK(callback_modified_direct), &context);
533 g_signal_connect(G_OBJECT(context.direct.maxlon), "changed",
534 G_CALLBACK(callback_modified_direct), &context);
535
536
537 /* --- hint --- */
538 label = gtk_label_new(_("(recommended min/max diff <0.03 degrees)"));
539 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 2, 3);
540
541 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
542 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
543 vbox, gtk_label_new(_(TAB_LABEL_DIRECT)));
544
545 /* ------------- center/extent edit ------------------------ */
546
547 vbox = gtk_vbox_new(FALSE, 10);
548 table = gtk_table_new(3, 4, FALSE); // x, y
549 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
550 gtk_table_set_row_spacings(GTK_TABLE(table), 5);
551
552 label = gtk_label_new(_("Center:"));
553 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
554 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
555 context.extent.lat = pos_lat_entry_new(0.0);
556 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lat, 1, 2, 0, 1);
557 context.extent.lon = pos_lon_entry_new(0.0);
558 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lon, 2, 3, 0, 1);
559
560 gtk_table_set_row_spacing(GTK_TABLE(table), 0, 10);
561
562 label = gtk_label_new(_("Width:"));
563 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
564 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
565 context.extent.width = gtk_entry_new();
566 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.width, 1, 2, 1, 2);
567
568 label = gtk_label_new(_("Height:"));
569 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
570 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
571 context.extent.height = gtk_entry_new();
572 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.height, 1, 2, 2, 3);
573
574 context.extent.mil_km = gtk_combo_box_new_text();
575 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("mi"));
576 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("km"));
577 gtk_combo_box_set_active(GTK_COMBO_BOX(context.extent.mil_km), 1); // km
578
579 gtk_table_attach(GTK_TABLE(table), context.extent.mil_km, 2, 3, 1, 3,
580 0, 0, 0, 0);
581
582 /* setup this page */
583 extent_update(&context);
584
585 /* connect signals after inital update to avoid confusion */
586 g_signal_connect(G_OBJECT(context.extent.lat), "changed",
587 G_CALLBACK(callback_modified_extent), &context);
588 g_signal_connect(G_OBJECT(context.extent.lon), "changed",
589 G_CALLBACK(callback_modified_extent), &context);
590 g_signal_connect(G_OBJECT(context.extent.width), "changed",
591 G_CALLBACK(callback_modified_extent), &context);
592 g_signal_connect(G_OBJECT(context.extent.height), "changed",
593 G_CALLBACK(callback_modified_extent), &context);
594 g_signal_connect(G_OBJECT(context.extent.mil_km), "changed",
595 G_CALLBACK(callback_modified_unit), &context);
596
597 /* --- hint --- */
598 label = gtk_label_new(_("(recommended width/height < 2km/1.25mi)"));
599 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 3, 4);
600
601 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
602 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
603 vbox, gtk_label_new(_(TAB_LABEL_EXTENT)));
604
605 #ifdef USE_HILDON
606 /* ------------- fetch from maemo mapper ------------------------ */
607
608 vbox = gtk_vbox_new(FALSE, 8);
609 context.mmapper.fetch =
610 gtk_button_new_with_label(_("Get from Maemo Mapper"));
611 gtk_box_pack_start(GTK_BOX(vbox), context.mmapper.fetch, FALSE, FALSE, 0);
612
613 g_signal_connect(G_OBJECT(context.mmapper.fetch), "clicked",
614 G_CALLBACK(callback_fetch_mm_clicked), &context);
615
616 /* --- hint --- */
617 label = gtk_label_new(_("(recommended MM zoom level < 7)"));
618 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
619
620
621 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
622 vbox, gtk_label_new(_(TAB_LABEL_MM)));
623 #endif
624
625 /* ------------------------------------------------------ */
626
627 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
628 context.notebook);
629
630 #ifdef ENABLE_OSM_GPS_MAP
631 g_signal_connect(G_OBJECT(context.notebook), "switch-page",
632 G_CALLBACK(on_page_switch), &context);
633 #endif
634
635 gtk_widget_show_all(context.dialog);
636
637 area_main_update(&context);
638
639 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) {
640 /* copy modified values back to given storage */
641 area->min->lat = context.min.lat;
642 area->min->lon = context.min.lon;
643 area->max->lat = context.max.lat;
644 area->max->lon = context.max.lon;
645 ok = TRUE;
646 }
647
648 gtk_widget_destroy(context.dialog);
649
650 return ok;
651 }