Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 275 - (hide annotations)
Mon Aug 31 18:28:30 2009 UTC (14 years, 9 months ago) by harbaum
File MIME type: text/plain
File size: 27648 byte(s)
Fixed negative-extents bug in area editor
1 harbaum 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 harbaum 209
22     #ifdef ENABLE_OSM_GPS_MAP
23 harbaum 200 #include "osm-gps-map.h"
24 harbaum 273 #include "osm-gps-map-osd-classic.h"
25 harbaum 209 #endif
26 harbaum 1
27 harbaum 209 #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 harbaum 205 /* limit of square kilometers above the warning is enabled */
33     #define WARN_OVER 5.0
34    
35 harbaum 1 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 harbaum 205 GtkWidget *warning;
41 harbaum 1
42     struct {
43     GtkWidget *minlat, *maxlat, *minlon, *maxlon;
44 harbaum 275 GtkWidget *error;
45 harbaum 1 } direct;
46    
47     struct {
48     GtkWidget *lat, *lon, *height, *width, *mil_km;
49     gboolean is_mil;
50 harbaum 275 GtkWidget *error;
51 harbaum 1 } extent;
52    
53 harbaum 200 #ifdef USE_HILDON
54 harbaum 1 struct {
55     GtkWidget *fetch;
56     } mmapper;
57 harbaum 200 #endif
58 harbaum 1
59 harbaum 224 #ifdef ENABLE_OSM_GPS_MAP
60 harbaum 200 struct {
61     GtkWidget *widget;
62 harbaum 270 gboolean needs_redraw;
63 harbaum 224 gint handler_id;
64 harbaum 217 coord_t start;
65 harbaum 200 } map;
66 harbaum 224 #endif
67 harbaum 1 } context_t;
68    
69 harbaum 205 static void parse_and_set_lat(GtkWidget *src, pos_float_t *store) {
70 harbaum 9 pos_float_t i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(src)));
71 harbaum 205 if(pos_lat_valid(i))
72 harbaum 1 *store = i;
73     }
74    
75 harbaum 205 static void parse_and_set_lon(GtkWidget *src, pos_float_t *store) {
76 harbaum 9 pos_float_t i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(src)));
77 harbaum 205 if(pos_lon_valid(i))
78 harbaum 1 *store = i;
79     }
80    
81 harbaum 209 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 harbaum 249 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 harbaum 205 static void on_area_warning_clicked(GtkButton *button, gpointer data) {
116     context_t *context = (context_t*)data;
117    
118 harbaum 249 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 harbaum 205 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 harbaum 249 if(area > WARN_OVER) {
135     char *wtext = warn_text(context);
136 harbaum 205
137 harbaum 249 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 harbaum 205 }
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 harbaum 275 /* 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 harbaum 205 /* 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 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
189 harbaum 224 #define LOG2(x) (log(x) / log(2))
190    
191 harbaum 217 static GSList *pos_append_rad(GSList *list, pos_float_t lat, pos_float_t lon) {
192 harbaum 215 coord_t *coo = g_new0(coord_t, 1);
193 harbaum 217 coo->rlat = lat;
194     coo->rlon = lon;
195 harbaum 215 list = g_slist_append(list, coo);
196     return list;
197     }
198    
199 harbaum 217 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 harbaum 204 /* the contents of the map tab have been changed */
204     static void map_update(context_t *context, gboolean forced) {
205 harbaum 203
206 harbaum 204 /* map is first tab (page 0) */
207 harbaum 209 if(!forced && !current_tab_is(context, -1, TAB_LABEL_MAP)) {
208 harbaum 204 context->map.needs_redraw = TRUE;
209     return;
210     }
211 harbaum 203
212 harbaum 221 /* 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 harbaum 203
216 harbaum 221 /* 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 harbaum 203
220 harbaum 221 osm_gps_map_clear_tracks(OSM_GPS_MAP(context->map.widget));
221     } else {
222 harbaum 204
223 harbaum 221 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 harbaum 203
226 harbaum 221 /* 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 harbaum 270 ((context->max.lat - context->min.lat)*32.0)) -1;
230 harbaum 221
231     double hzoom = LOG2((45.0 * context->map.widget->allocation.width)/
232 harbaum 270 ((context->max.lon - context->min.lon)*32.0)) -1;
233 harbaum 221
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 harbaum 275
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 harbaum 221 }
255    
256 harbaum 204 context->map.needs_redraw = FALSE;
257 harbaum 203 }
258    
259     static gboolean on_map_configure(GtkWidget *widget,
260     GdkEventConfigure *event,
261     context_t *context) {
262 harbaum 204 map_update(context, FALSE);
263 harbaum 203 return FALSE;
264     }
265 harbaum 209 #endif
266 harbaum 203
267 harbaum 1 /* 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 harbaum 9 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 harbaum 1
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 harbaum 204 /* direct is second tab (page 1) */
297 harbaum 209 if(!current_tab_is(context, -1, TAB_LABEL_DIRECT))
298 harbaum 1 return;
299    
300     /* parse the fields from the direct entry pad */
301 harbaum 205 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 harbaum 1
306 harbaum 205 area_main_update(context);
307    
308 harbaum 1 /* also adjust other views */
309     extent_update(context);
310 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
311     map_update(context, FALSE);
312     #endif
313 harbaum 1 }
314    
315     static void callback_modified_extent(GtkWidget *widget, gpointer data) {
316     context_t *context = (context_t*)data;
317    
318 harbaum 204 /* extent is third tab (page 2) */
319 harbaum 209 if(!current_tab_is(context, -1, TAB_LABEL_EXTENT))
320 harbaum 1 return;
321    
322 harbaum 9 pos_float_t center_lat = pos_lat_get(context->extent.lat);
323     pos_float_t center_lon = pos_lon_get(context->extent.lon);
324 harbaum 1
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 harbaum 205
338 harbaum 1 width /= 2 * hscale;
339     context->min.lon = center_lon - width;
340     context->max.lon = center_lon + width;
341 harbaum 205
342     area_main_update(context);
343 harbaum 1
344     /* also update other tabs */
345     direct_update(context);
346 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
347 harbaum 204 map_update(context, FALSE);
348 harbaum 209 #endif
349 harbaum 1 }
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 harbaum 224 if(!dbus_mm_set_position(context->area->appdata->osso_context, NULL)) {
372 harbaum 1 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 harbaum 224 if(!context->area->appdata->mmpos.valid) {
380 harbaum 1 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 harbaum 204 /* maemo mapper is fourth tab (page 3) */
389 harbaum 209 if(!current_tab_is(context, -1, TAB_LABEL_MM))
390 harbaum 1 return;
391    
392     /* maemo mapper pos data ... */
393 harbaum 224 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 harbaum 1
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 harbaum 205 area_main_update(context);
411    
412 harbaum 1 /* also update other tabs */
413     direct_update(context);
414     extent_update(context);
415 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
416 harbaum 204 map_update(context, FALSE);
417 harbaum 209 #endif
418 harbaum 1 }
419     #endif
420    
421 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
422 harbaum 204
423 harbaum 217 static gboolean
424     on_map_button_press_event(GtkWidget *widget,
425     GdkEventButton *event, context_t *context) {
426 harbaum 270 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
427 harbaum 273 osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
428 harbaum 204
429 harbaum 270 /* osm-gps-map needs this event to handle the OSD */
430 harbaum 273 if(osd->check(osd, (int)event->x, (int)event->y))
431 harbaum 270 return FALSE;
432 harbaum 204
433 harbaum 270 /* remove existing marker */
434     osm_gps_map_clear_tracks(map);
435 harbaum 204
436 harbaum 270 /* 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 harbaum 217
440 harbaum 270 return TRUE;
441 harbaum 204 }
442    
443     static gboolean
444 harbaum 217 on_map_motion_notify_event(GtkWidget *widget,
445     GdkEventMotion *event, context_t *context) {
446 harbaum 270 if(!isnan(context->map.start.rlon) &&
447 harbaum 217 !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 harbaum 270 /* always returning true here disables dragging in osm-gps-map */
466     return TRUE;
467 harbaum 217 }
468    
469     static gboolean
470 harbaum 204 on_map_button_release_event(GtkWidget *widget,
471     GdkEventButton *event, context_t *context) {
472 harbaum 270
473 harbaum 273 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
474     osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
475    
476 harbaum 270 if(!isnan(context->map.start.rlon) &&
477 harbaum 217 !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 harbaum 270 /* osm-gps-map needs this event to handle the OSD */
514 harbaum 273 if(osd->check(osd, (int)event->x, (int)event->y))
515 harbaum 270 return FALSE;
516    
517     return TRUE;
518 harbaum 204 }
519    
520 harbaum 270 #if 0
521 harbaum 200 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 harbaum 270 #endif
528 harbaum 200
529 harbaum 270 static void
530 harbaum 273 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 harbaum 224 }
544     }
545    
546 harbaum 204 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 harbaum 209 if(current_tab_is(context, page_num, TAB_LABEL_MAP) &&
553     context->map.needs_redraw)
554 harbaum 204 map_update(context, TRUE);
555     }
556 harbaum 224
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     gboolean gps_fix = gps_on &&
565     gps_get_pos(context->area->appdata, NULL, NULL);
566    
567 harbaum 270 /* ... and enable "goto" button if it's valid */
568     osm_gps_map_osd_enable_gps(OSM_GPS_MAP(context->map.widget),
569 harbaum 273 OSM_GPS_MAP_OSD_CALLBACK(gps_fix?cb_map_gps:NULL), context);
570 harbaum 224
571 harbaum 270
572 harbaum 224 return TRUE;
573     }
574    
575     #endif
576    
577 harbaum 1 gboolean area_edit(area_edit_t *area) {
578 harbaum 209 GtkWidget *vbox;
579 harbaum 275 GdkColor color;
580     gdk_color_parse("red", &color);
581 harbaum 1
582     context_t context;
583     memset(&context, 0, sizeof(context_t));
584     context.area = area;
585     context.min.lat = area->min->lat;
586     context.min.lon = area->min->lon;
587     context.max.lat = area->max->lat;
588     context.max.lon = area->max->lon;
589    
590 harbaum 167 context.dialog =
591 harbaum 200 misc_dialog_new(MISC_DIALOG_HIGH, _("Area editor"),
592 harbaum 167 GTK_WINDOW(area->parent),
593 harbaum 1 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
594     GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
595     NULL);
596    
597 harbaum 205 GtkWidget *table = gtk_table_new(5, 2, FALSE); // x, y
598 harbaum 1
599 harbaum 203 GtkWidget *label = gtk_label_new(_("Latitude:"));
600     misc_table_attach(table, label, 0, 0);
601     context.minlat = pos_lat_label_new(area->min->lat);
602     misc_table_attach(table, context.minlat, 1, 0);
603     label = gtk_label_new(_("to"));
604     misc_table_attach(table, label, 2, 0);
605     context.maxlat = pos_lat_label_new(area->max->lat);
606     misc_table_attach(table, context.maxlat, 3, 0);
607 harbaum 1
608 harbaum 203 label = gtk_label_new(_("Longitude:"));
609     misc_table_attach(table, label, 0, 1);
610 harbaum 1 context.minlon = pos_lon_label_new(area->min->lon);
611 harbaum 203 misc_table_attach(table, context.minlon, 1, 1);
612     label = gtk_label_new(_("to"));
613     misc_table_attach(table, label, 2, 1);
614 harbaum 1 context.maxlon = pos_lon_label_new(area->max->lon);
615 harbaum 203 misc_table_attach(table, context.maxlon, 3, 1);
616 harbaum 1
617 harbaum 205 context.warning = gtk_button_new();
618     gtk_button_set_image(GTK_BUTTON(context.warning),
619 harbaum 206 gtk_image_new_from_stock(GTK_STOCK_DIALOG_WARNING,
620     GTK_ICON_SIZE_BUTTON));
621 harbaum 205 g_signal_connect(context.warning, "clicked",
622     G_CALLBACK(on_area_warning_clicked), &context);
623     gtk_table_attach_defaults(GTK_TABLE(table), context.warning, 4, 5, 0, 2);
624    
625 harbaum 200 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
626     table, FALSE, FALSE, 0);
627 harbaum 1
628     context.notebook = gtk_notebook_new();
629    
630 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
631 harbaum 203 /* ------------- fetch from map ------------------------ */
632    
633 harbaum 204 context.map.needs_redraw = FALSE;
634 harbaum 203 context.map.widget = g_object_new(OSM_TYPE_GPS_MAP,
635 harbaum 268 "map-source", OSM_GPS_MAP_SOURCE_OPENSTREETMAP,
636 harbaum 203 "proxy-uri", misc_get_proxy_uri(area->settings),
637 harbaum 248 "tile-cache", NULL,
638 harbaum 203 NULL);
639    
640 harbaum 273 osm_gps_map_osd_classic_init(OSM_GPS_MAP(context.map.widget));
641    
642 harbaum 203 g_signal_connect(G_OBJECT(context.map.widget), "configure-event",
643     G_CALLBACK(on_map_configure), &context);
644 harbaum 217 g_signal_connect(G_OBJECT(context.map.widget), "button-press-event",
645     G_CALLBACK(on_map_button_press_event), &context);
646     g_signal_connect(G_OBJECT(context.map.widget), "motion-notify-event",
647     G_CALLBACK(on_map_motion_notify_event), &context);
648 harbaum 204 g_signal_connect(G_OBJECT(context.map.widget), "button-release-event",
649     G_CALLBACK(on_map_button_release_event), &context);
650 harbaum 203
651 harbaum 224 /* install handler for timed updates of the gps button */
652     context.map.handler_id = gtk_timeout_add(1000, map_gps_update, &context);
653 harbaum 217 context.map.start.rlon = context.map.start.rlat = NAN;
654    
655 harbaum 203 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
656 harbaum 270 context.map.widget, gtk_label_new(_(TAB_LABEL_MAP)));
657 harbaum 209 #endif
658 harbaum 203
659 harbaum 1 /* ------------ direct min/max edit --------------- */
660    
661 harbaum 203 vbox = gtk_vbox_new(FALSE, 10);
662 harbaum 275 table = gtk_table_new(3, 4, FALSE); // x, y
663 harbaum 204 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
664     gtk_table_set_row_spacings(GTK_TABLE(table), 5);
665 harbaum 1
666 harbaum 203 context.direct.minlat = pos_lat_entry_new(0.0);
667     misc_table_attach(table, context.direct.minlat, 0, 0);
668     label = gtk_label_new(_("to"));
669     misc_table_attach(table, label, 1, 0);
670     context.direct.maxlat = pos_lat_entry_new(0.0);
671     misc_table_attach(table, context.direct.maxlat, 2, 0);
672    
673 harbaum 1 context.direct.minlon = pos_lon_entry_new(area->min->lon);
674 harbaum 203 misc_table_attach(table, context.direct.minlon, 0, 1);
675     label = gtk_label_new(_("to"));
676     misc_table_attach(table, label, 1, 1);
677 harbaum 1 context.direct.maxlon = pos_lon_entry_new(0.0);
678 harbaum 203 misc_table_attach(table, context.direct.maxlon, 2, 1);
679 harbaum 1
680     /* setup this page */
681     direct_update(&context);
682    
683     g_signal_connect(G_OBJECT(context.direct.minlat), "changed",
684     G_CALLBACK(callback_modified_direct), &context);
685     g_signal_connect(G_OBJECT(context.direct.minlon), "changed",
686     G_CALLBACK(callback_modified_direct), &context);
687     g_signal_connect(G_OBJECT(context.direct.maxlat), "changed",
688     G_CALLBACK(callback_modified_direct), &context);
689     g_signal_connect(G_OBJECT(context.direct.maxlon), "changed",
690     G_CALLBACK(callback_modified_direct), &context);
691    
692    
693     /* --- hint --- */
694     label = gtk_label_new(_("(recommended min/max diff <0.03 degrees)"));
695     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 2, 3);
696    
697 harbaum 275 /* error label */
698     context.direct.error = gtk_label_new("");
699     gtk_widget_modify_fg(context.direct.error, GTK_STATE_NORMAL, &color);
700     gtk_table_attach_defaults(GTK_TABLE(table), context.direct.error, 0, 3, 3, 4);
701    
702 harbaum 200 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
703 harbaum 1 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
704 harbaum 209 vbox, gtk_label_new(_(TAB_LABEL_DIRECT)));
705 harbaum 1
706     /* ------------- center/extent edit ------------------------ */
707    
708 harbaum 200 vbox = gtk_vbox_new(FALSE, 10);
709 harbaum 275 table = gtk_table_new(3, 5, FALSE); // x, y
710 harbaum 204 gtk_table_set_col_spacings(GTK_TABLE(table), 10);
711     gtk_table_set_row_spacings(GTK_TABLE(table), 5);
712 harbaum 1
713     label = gtk_label_new(_("Center:"));
714     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
715     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
716     context.extent.lat = pos_lat_entry_new(0.0);
717     gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lat, 1, 2, 0, 1);
718     context.extent.lon = pos_lon_entry_new(0.0);
719     gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lon, 2, 3, 0, 1);
720    
721 harbaum 204 gtk_table_set_row_spacing(GTK_TABLE(table), 0, 10);
722 harbaum 1
723     label = gtk_label_new(_("Width:"));
724     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
725     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
726     context.extent.width = gtk_entry_new();
727     gtk_table_attach_defaults(GTK_TABLE(table), context.extent.width, 1, 2, 1, 2);
728    
729     label = gtk_label_new(_("Height:"));
730     gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
731     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
732     context.extent.height = gtk_entry_new();
733 harbaum 218 gtk_table_attach_defaults(GTK_TABLE(table),
734     context.extent.height, 1, 2, 2, 3);
735 harbaum 1
736     context.extent.mil_km = gtk_combo_box_new_text();
737     gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("mi"));
738     gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("km"));
739     gtk_combo_box_set_active(GTK_COMBO_BOX(context.extent.mil_km), 1); // km
740    
741     gtk_table_attach(GTK_TABLE(table), context.extent.mil_km, 2, 3, 1, 3,
742     0, 0, 0, 0);
743    
744     /* setup this page */
745     extent_update(&context);
746    
747     /* connect signals after inital update to avoid confusion */
748     g_signal_connect(G_OBJECT(context.extent.lat), "changed",
749     G_CALLBACK(callback_modified_extent), &context);
750     g_signal_connect(G_OBJECT(context.extent.lon), "changed",
751     G_CALLBACK(callback_modified_extent), &context);
752     g_signal_connect(G_OBJECT(context.extent.width), "changed",
753     G_CALLBACK(callback_modified_extent), &context);
754     g_signal_connect(G_OBJECT(context.extent.height), "changed",
755     G_CALLBACK(callback_modified_extent), &context);
756     g_signal_connect(G_OBJECT(context.extent.mil_km), "changed",
757     G_CALLBACK(callback_modified_unit), &context);
758    
759     /* --- hint --- */
760     label = gtk_label_new(_("(recommended width/height < 2km/1.25mi)"));
761     gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 3, 4);
762    
763 harbaum 275 /* error label */
764     context.extent.error = gtk_label_new("");
765     gtk_widget_modify_fg(context.extent.error, GTK_STATE_NORMAL, &color);
766     gtk_table_attach_defaults(GTK_TABLE(table), context.extent.error, 0, 3, 4, 5);
767    
768 harbaum 200 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
769 harbaum 1 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
770 harbaum 209 vbox, gtk_label_new(_(TAB_LABEL_EXTENT)));
771 harbaum 1
772     #ifdef USE_HILDON
773     /* ------------- fetch from maemo mapper ------------------------ */
774    
775 harbaum 200 vbox = gtk_vbox_new(FALSE, 8);
776 harbaum 1 context.mmapper.fetch =
777     gtk_button_new_with_label(_("Get from Maemo Mapper"));
778 harbaum 200 gtk_box_pack_start(GTK_BOX(vbox), context.mmapper.fetch, FALSE, FALSE, 0);
779 harbaum 1
780     g_signal_connect(G_OBJECT(context.mmapper.fetch), "clicked",
781     G_CALLBACK(callback_fetch_mm_clicked), &context);
782    
783     /* --- hint --- */
784     label = gtk_label_new(_("(recommended MM zoom level < 7)"));
785 harbaum 200 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
786 harbaum 1
787    
788     gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
789 harbaum 209 vbox, gtk_label_new(_(TAB_LABEL_MM)));
790 harbaum 1 #endif
791    
792 harbaum 200 /* ------------------------------------------------------ */
793    
794 harbaum 1 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
795     context.notebook);
796    
797 harbaum 209 #ifdef ENABLE_OSM_GPS_MAP
798 harbaum 204 g_signal_connect(G_OBJECT(context.notebook), "switch-page",
799     G_CALLBACK(on_page_switch), &context);
800 harbaum 209 #endif
801 harbaum 1
802     gtk_widget_show_all(context.dialog);
803    
804 harbaum 205 area_main_update(&context);
805    
806 harbaum 249 gboolean leave = FALSE, ok = FALSE;
807     do {
808     if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) {
809     if(area_warning(&context)) {
810     leave = TRUE;
811     ok = TRUE;
812     }
813     } else
814     leave = TRUE;
815     } while(!leave);
816    
817     if(ok) {
818 harbaum 1 /* copy modified values back to given storage */
819     area->min->lat = context.min.lat;
820     area->min->lon = context.min.lon;
821     area->max->lat = context.max.lat;
822     area->max->lon = context.max.lon;
823     }
824    
825 harbaum 224 #ifdef ENABLE_OSM_GPS_MAP
826     gtk_timeout_remove(context.map.handler_id);
827     #endif
828    
829 harbaum 1 gtk_widget_destroy(context.dialog);
830    
831     return ok;
832     }