Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


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