Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


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