Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 200 - (show annotations)
Thu Jul 9 11:44:27 2009 UTC (14 years, 10 months ago) by harbaum
File MIME type: text/plain
File size: 16399 byte(s)
Added osm-gps-map
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 #include "osm-gps-map.h"
22
23 typedef struct {
24 GtkWidget *dialog, *notebook;
25 area_edit_t *area;
26 pos_t min, max; /* local copy to work on */
27 GtkWidget *minlat, *maxlat, *minlon, *maxlon;
28
29 struct {
30 GtkWidget *minlat, *maxlat, *minlon, *maxlon;
31 } direct;
32
33 struct {
34 GtkWidget *lat, *lon, *height, *width, *mil_km;
35 gboolean is_mil;
36 } extent;
37
38 #ifdef USE_HILDON
39 struct {
40 GtkWidget *fetch;
41 } mmapper;
42 #endif
43
44 struct {
45 GtkWidget *widget;
46 GtkWidget *zoomin, *zoomout;
47 } map;
48
49 } context_t;
50
51 static void parse_and_set_lat(GtkWidget *src, GtkWidget *dst, pos_float_t *store) {
52 pos_float_t i = pos_parse_lat((char*)gtk_entry_get_text(GTK_ENTRY(src)));
53 if(pos_lat_valid(i)) {
54 *store = i;
55 pos_lat_label_set(dst, i);
56 }
57 }
58
59 static void parse_and_set_lon(GtkWidget *src, GtkWidget *dst, pos_float_t *store) {
60 pos_float_t i = pos_parse_lon((char*)gtk_entry_get_text(GTK_ENTRY(src)));
61 if(pos_lon_valid(i)) {
62 *store = i;
63 pos_lon_label_set(dst, i);
64 }
65 }
66
67 /* the contents of the direct tab have been changed */
68 static void direct_update(context_t *context) {
69 pos_lat_entry_set(context->direct.minlat, context->min.lat);
70 pos_lon_entry_set(context->direct.minlon, context->min.lon);
71 pos_lat_entry_set(context->direct.maxlat, context->max.lat);
72 pos_lon_entry_set(context->direct.maxlon, context->max.lon);
73 }
74
75 /* update the contents of the extent tab */
76 static void extent_update(context_t *context) {
77 pos_float_t center_lat = (context->max.lat + context->min.lat)/2;
78 pos_float_t center_lon = (context->max.lon + context->min.lon)/2;
79
80 pos_lat_entry_set(context->extent.lat, center_lat);
81 pos_lat_entry_set(context->extent.lon, center_lon);
82
83 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
84 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
85
86 double height = vscale * (context->max.lat - context->min.lat);
87 double width = hscale * (context->max.lon - context->min.lon);
88
89 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
90 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
91 }
92
93 static void callback_modified_direct(GtkWidget *widget, gpointer data) {
94 context_t *context = (context_t*)data;
95
96 /* direct is first tab (page 0) */
97 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(context->notebook)) != 0)
98 return;
99
100 /* parse the fields from the direct entry pad */
101 parse_and_set_lat(context->direct.minlat, context->minlat, &context->min.lat);
102 parse_and_set_lon(context->direct.minlon, context->minlon, &context->min.lon);
103 parse_and_set_lat(context->direct.maxlat, context->maxlat, &context->max.lat);
104 parse_and_set_lon(context->direct.maxlon, context->maxlon, &context->max.lon);
105
106 /* also adjust other views */
107 extent_update(context);
108 }
109
110 static void callback_modified_extent(GtkWidget *widget, gpointer data) {
111 context_t *context = (context_t*)data;
112
113 /* extent is second tab (page 1) */
114 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(context->notebook)) != 1)
115 return;
116
117 pos_float_t center_lat = pos_lat_get(context->extent.lat);
118 pos_float_t center_lon = pos_lon_get(context->extent.lon);
119
120 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
121 return;
122
123 double vscale = DEG2RAD(POS_EQ_RADIUS / 1000.0);
124 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS / 1000.0);
125
126 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
127 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
128
129 height /= 2 * vscale;
130 context->min.lat = center_lat - height;
131 pos_lat_label_set(context->minlat, context->min.lat);
132 context->max.lat = center_lat + height;
133 pos_lat_label_set(context->maxlat, context->max.lat);
134
135 width /= 2 * hscale;
136 context->min.lon = center_lon - width;
137 pos_lon_label_set(context->minlon, context->min.lon);
138 context->max.lon = center_lon + width;
139 pos_lon_label_set(context->maxlon, context->max.lon);
140
141 /* also update other tabs */
142 direct_update(context);
143 }
144
145 static void callback_modified_unit(GtkWidget *widget, gpointer data) {
146 context_t *context = (context_t*)data;
147
148 /* get current values */
149 double height = pos_dist_get(context->extent.height, context->extent.is_mil);
150 double width = pos_dist_get(context->extent.width, context->extent.is_mil);
151
152 /* adjust unit flag */
153 context->extent.is_mil = gtk_combo_box_get_active(
154 GTK_COMBO_BOX(context->extent.mil_km)) == 0;
155
156 /* save values */
157 pos_dist_entry_set(context->extent.width, width, context->extent.is_mil);
158 pos_dist_entry_set(context->extent.height, height, context->extent.is_mil);
159 }
160
161 #ifdef USE_HILDON
162 static void callback_fetch_mm_clicked(GtkButton *button, gpointer data) {
163 context_t *context = (context_t*)data;
164
165 printf("clicked fetch mm!\n");
166
167 if(!dbus_mm_set_position(context->area->osso_context, NULL)) {
168 errorf(context->dialog,
169 _("Unable to communicate with Maemo Mapper. "
170 "You need to have Maemo Mapper installed "
171 "to use this feature."));
172 return;
173 }
174
175 if(!context->area->mmpos->valid) {
176 errorf(context->dialog,
177 _("No valid position received yet. You need "
178 "to scroll or zoom the Maemo Mapper view "
179 "in order to force it to send its current "
180 "view position to osm2go."));
181 return;
182 }
183
184 /* maemo mapper is third tab (page 2) */
185 if(gtk_notebook_get_current_page(GTK_NOTEBOOK(context->notebook)) != 2)
186 return;
187
188 /* maemo mapper pos data ... */
189 pos_float_t center_lat = context->area->mmpos->pos.lat;
190 pos_float_t center_lon = context->area->mmpos->pos.lon;
191 int zoom = context->area->mmpos->zoom;
192
193 if(!pos_lat_valid(center_lat) || !pos_lon_valid(center_lon))
194 return;
195
196 double vscale = DEG2RAD(POS_EQ_RADIUS);
197 double height = 8 * (1<<zoom) / vscale;
198 context->min.lat = center_lat - height;
199 pos_lat_label_set(context->minlat, context->min.lat);
200 context->max.lat = center_lat + height;
201 pos_lat_label_set(context->maxlat, context->max.lat);
202
203 double hscale = DEG2RAD(cos(DEG2RAD(center_lat)) * POS_EQ_RADIUS);
204 double width = 16 * (1<<zoom) / hscale;
205 context->min.lon = center_lon - width;
206 pos_lon_label_set(context->minlon, context->min.lon);
207 context->max.lon = center_lon + width;
208 pos_lon_label_set(context->maxlon, context->max.lon);
209
210 /* also update other tabs */
211 direct_update(context);
212 extent_update(context);
213 }
214 #endif
215
216 static void map_zoom(context_t *context, int step) {
217 int zoom;
218 OsmGpsMap *map = OSM_GPS_MAP(context->map.widget);
219 g_object_get(map, "zoom", &zoom, NULL);
220 zoom = osm_gps_map_set_zoom(map, zoom+step);
221
222 /* enable/disable zoom buttons as required */
223 gtk_widget_set_sensitive(context->map.zoomin, zoom<17);
224 gtk_widget_set_sensitive(context->map.zoomout, zoom>1);
225 }
226
227 static gboolean
228 cb_map_zoomin(GtkButton *button, context_t *context) {
229 map_zoom(context, +1);
230 return FALSE;
231 }
232
233 static gboolean
234 cb_map_zoomout(GtkButton *button, context_t *context) {
235 map_zoom(context, -1);
236 return FALSE;
237 }
238
239 gboolean area_edit(area_edit_t *area) {
240 gboolean ok = FALSE;
241
242 context_t context;
243 memset(&context, 0, sizeof(context_t));
244 context.area = area;
245 context.min.lat = area->min->lat;
246 context.min.lon = area->min->lon;
247 context.max.lat = area->max->lat;
248 context.max.lon = area->max->lon;
249
250 context.dialog =
251 misc_dialog_new(MISC_DIALOG_HIGH, _("Area editor"),
252 GTK_WINDOW(area->parent),
253 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT,
254 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
255 NULL);
256
257 GtkWidget *table = gtk_table_new(3, 3, FALSE); // x, y
258
259 GtkWidget *label = gtk_label_new(_("Latitude"));
260 gtk_table_attach_defaults(GTK_TABLE(table), label, 1, 2, 0, 1);
261 label = gtk_label_new(_("Longitude"));
262 gtk_table_attach_defaults(GTK_TABLE(table), label, 2, 3, 0, 1);
263
264 label = gtk_label_new(_("Min:"));
265 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
266 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
267 context.minlat = pos_lat_label_new(area->min->lat);
268 gtk_table_attach_defaults(GTK_TABLE(table), context.minlat, 1, 2, 1, 2);
269 context.minlon = pos_lon_label_new(area->min->lon);
270 gtk_table_attach_defaults(GTK_TABLE(table), context.minlon, 2, 3, 1, 2);
271
272 label = gtk_label_new(_("Max:"));
273 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
274 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
275 context.maxlat = pos_lat_label_new(area->max->lat);
276 gtk_table_attach_defaults(GTK_TABLE(table), context.maxlat, 1, 2, 2, 3);
277 context.maxlon = pos_lon_label_new(area->max->lon);
278 gtk_table_attach_defaults(GTK_TABLE(table), context.maxlon, 2, 3, 2, 3);
279
280 gtk_box_pack_start(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
281 table, FALSE, FALSE, 0);
282
283 context.notebook = gtk_notebook_new();
284
285 /* ------------ direct min/max edit --------------- */
286
287 GtkWidget *vbox = gtk_vbox_new(FALSE, 10);
288 table = gtk_table_new(3, 3, FALSE); // x, y
289
290 label = gtk_label_new(_("Min:"));
291 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
292 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
293 context.direct.minlat = pos_lat_entry_new(0.);
294 gtk_table_attach_defaults(GTK_TABLE(table), context.direct.minlat, 1, 2, 0, 1);
295 context.direct.minlon = pos_lon_entry_new(area->min->lon);
296 gtk_table_attach_defaults(GTK_TABLE(table), context.direct.minlon, 2, 3, 0, 1);
297
298 label = gtk_label_new(_("Max:"));
299 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
300 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
301 context.direct.maxlat = pos_lat_entry_new(0.0);
302 gtk_table_attach_defaults(GTK_TABLE(table), context.direct.maxlat, 1, 2, 1, 2);
303 context.direct.maxlon = pos_lon_entry_new(0.0);
304 gtk_table_attach_defaults(GTK_TABLE(table), context.direct.maxlon, 2, 3, 1, 2);
305
306 /* setup this page */
307 direct_update(&context);
308
309 g_signal_connect(G_OBJECT(context.direct.minlat), "changed",
310 G_CALLBACK(callback_modified_direct), &context);
311 g_signal_connect(G_OBJECT(context.direct.minlon), "changed",
312 G_CALLBACK(callback_modified_direct), &context);
313 g_signal_connect(G_OBJECT(context.direct.maxlat), "changed",
314 G_CALLBACK(callback_modified_direct), &context);
315 g_signal_connect(G_OBJECT(context.direct.maxlon), "changed",
316 G_CALLBACK(callback_modified_direct), &context);
317
318
319 /* --- hint --- */
320 label = gtk_label_new(_("(recommended min/max diff <0.03 degrees)"));
321 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 2, 3);
322
323 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
324 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
325 vbox, gtk_label_new(_("Direct")));
326
327 /* ------------- center/extent edit ------------------------ */
328
329 vbox = gtk_vbox_new(FALSE, 10);
330 table = gtk_table_new(3, 4, FALSE); // x, y
331
332 label = gtk_label_new(_("Center:"));
333 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
334 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
335 context.extent.lat = pos_lat_entry_new(0.0);
336 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lat, 1, 2, 0, 1);
337 context.extent.lon = pos_lon_entry_new(0.0);
338 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.lon, 2, 3, 0, 1);
339
340 gtk_table_set_row_spacing(GTK_TABLE(table), 0, 8);
341
342 label = gtk_label_new(_("Width:"));
343 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
344 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
345 context.extent.width = gtk_entry_new();
346 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.width, 1, 2, 1, 2);
347
348 label = gtk_label_new(_("Height:"));
349 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
350 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 2, 3);
351 context.extent.height = gtk_entry_new();
352 gtk_table_attach_defaults(GTK_TABLE(table), context.extent.height, 1, 2, 2, 3);
353
354 context.extent.mil_km = gtk_combo_box_new_text();
355 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("mi"));
356 gtk_combo_box_append_text(GTK_COMBO_BOX(context.extent.mil_km), _("km"));
357 gtk_combo_box_set_active(GTK_COMBO_BOX(context.extent.mil_km), 1); // km
358
359 gtk_table_attach(GTK_TABLE(table), context.extent.mil_km, 2, 3, 1, 3,
360 0, 0, 0, 0);
361
362 /* setup this page */
363 extent_update(&context);
364
365 /* connect signals after inital update to avoid confusion */
366 g_signal_connect(G_OBJECT(context.extent.lat), "changed",
367 G_CALLBACK(callback_modified_extent), &context);
368 g_signal_connect(G_OBJECT(context.extent.lon), "changed",
369 G_CALLBACK(callback_modified_extent), &context);
370 g_signal_connect(G_OBJECT(context.extent.width), "changed",
371 G_CALLBACK(callback_modified_extent), &context);
372 g_signal_connect(G_OBJECT(context.extent.height), "changed",
373 G_CALLBACK(callback_modified_extent), &context);
374 g_signal_connect(G_OBJECT(context.extent.mil_km), "changed",
375 G_CALLBACK(callback_modified_unit), &context);
376
377 /* --- hint --- */
378 label = gtk_label_new(_("(recommended width/height < 2km/1.25mi)"));
379 gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 3, 3, 4);
380
381 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
382 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
383 vbox, gtk_label_new(_("Extent")));
384
385 #ifdef USE_HILDON
386 /* ------------- fetch from maemo mapper ------------------------ */
387
388 vbox = gtk_vbox_new(FALSE, 8);
389 context.mmapper.fetch =
390 gtk_button_new_with_label(_("Get from Maemo Mapper"));
391 gtk_box_pack_start(GTK_BOX(vbox), context.mmapper.fetch, FALSE, FALSE, 0);
392
393 g_signal_connect(G_OBJECT(context.mmapper.fetch), "clicked",
394 G_CALLBACK(callback_fetch_mm_clicked), &context);
395
396 /* --- hint --- */
397 label = gtk_label_new(_("(recommended MM zoom level < 7)"));
398 gtk_box_pack_start(GTK_BOX(vbox), label, FALSE, FALSE, 0);
399
400
401 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
402 vbox, gtk_label_new(_("Maemo Mapper")));
403 #endif
404
405 /* ------------- fetch from map ------------------------ */
406
407 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
408
409 context.map.widget = g_object_new(OSM_TYPE_GPS_MAP,
410 "repo-uri", MAP_SOURCE_OPENSTREETMAP,
411 "proxy-uri", misc_get_proxy_uri(area->settings),
412 NULL);
413
414 gtk_box_pack_start_defaults(GTK_BOX(hbox), context.map.widget);
415
416 /* zoom button box */
417 vbox = gtk_vbox_new(FALSE,0);
418
419 context.map.zoomin = gtk_button_new();
420 gtk_button_set_image(GTK_BUTTON(context.map.zoomin),
421 gtk_image_new_from_stock(GTK_STOCK_ZOOM_IN, GTK_ICON_SIZE_MENU));
422 g_signal_connect(context.map.zoomin, "clicked",
423 G_CALLBACK(cb_map_zoomin), &context);
424 gtk_box_pack_start(GTK_BOX(vbox), context.map.zoomin, FALSE, FALSE, 0);
425
426 context.map.zoomout = gtk_button_new();
427 gtk_button_set_image(GTK_BUTTON(context.map.zoomout),
428 gtk_image_new_from_stock(GTK_STOCK_ZOOM_OUT, GTK_ICON_SIZE_MENU));
429 g_signal_connect(context.map.zoomout, "clicked",
430 G_CALLBACK(cb_map_zoomout), &context);
431 gtk_box_pack_start(GTK_BOX(vbox), context.map.zoomout, FALSE, FALSE, 0);
432
433 gtk_box_pack_start(GTK_BOX(hbox), vbox, FALSE, FALSE, 0);
434
435 gtk_notebook_append_page(GTK_NOTEBOOK(context.notebook),
436 hbox, gtk_label_new(_("Map")));
437
438 /* ------------------------------------------------------ */
439
440 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(context.dialog)->vbox),
441 context.notebook);
442
443
444 gtk_widget_show_all(context.dialog);
445
446 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(context.dialog))) {
447 /* copy modified values back to given storage */
448 area->min->lat = context.min.lat;
449 area->min->lon = context.min.lon;
450 area->max->lat = context.max.lat;
451 area->max->lon = context.max.lon;
452 ok = TRUE;
453 }
454
455 gtk_widget_destroy(context.dialog);
456
457 return ok;
458 }