Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


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