Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


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