Contents of /trunk/src/area_edit.c

Parent Directory Parent Directory | Revision Log Revision Log


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