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