Contents of /trunk/src/goto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 47 - (show annotations)
Thu Aug 6 20:23:12 2009 UTC (14 years, 8 months ago) by harbaum
File MIME type: text/plain
File size: 25272 byte(s)
Bearing fix and demo.gpx extended, version to 0.8.1
1 /*
2 * Copyright (C) 2008 Till Harbaum <till@harbaum.org>.
3 *
4 * This file is part of GPXView.
5 *
6 * GPXView 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 * GPXView 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 GPXView. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <math.h>
23
24 #include "gpxview.h"
25
26 #ifdef USE_MAEMO
27 #include "dbus.h"
28 #endif
29
30 #define COMPASS_SIZE 230
31 #define LETTER_SPACE 0.2
32 #define DIAMOND_WIDTH 0.05
33 #define DIAMOND_HEIGHT 0.2
34 #define ARROW_WIDTH 0.3
35 #define ARROW_LENGTH 0.7
36 #define UPDATE_MS 1000 /* gps updates are sent once a second */
37
38 #define SAT_WIDTH 330
39 #define SAT_HEIGHT 60
40
41 /* http://www.gtk.org/tutorial1.2/gtk_tut-30.html */
42 /* http://developer.gimp.org/api/2.0/gdk/gdk-Drawing-Primitives.html */
43
44
45 static float rad2deg(float rad) {
46 return fmodf(360.0 + (180.0/M_PI) * rad, 360.0);
47 }
48
49 static void compass_draw(GtkWidget *widget, cache_context_t *context) {
50 float f;
51 int i;
52
53 gint width = widget->allocation.width;
54 gint height = widget->allocation.height;
55 gint diameter = (height < width)?height:width;
56
57 gint xcenter = width/2;
58 gint ycenter = height/2;
59 gint radius = diameter/2;
60
61 /* erase background */
62 gdk_draw_rectangle(context->gotoc.compass_pixmap,
63 widget->style->bg_gc[GTK_STATE_NORMAL], TRUE,
64 0, 0, width, height);
65
66 /* use white rosetta background unless the real background */
67 /* is very bright. Use bright grey then */
68
69 if(widget->style->bg[GTK_STATE_NORMAL].red +
70 widget->style->bg[GTK_STATE_NORMAL].green +
71 widget->style->bg[GTK_STATE_NORMAL].blue < 3*60000) {
72 /* background is very bright, use white */
73 gdk_draw_arc(context->gotoc.compass_pixmap, widget->style->white_gc, TRUE,
74 (width-diameter)/2, (height-diameter)/2, diameter, diameter,
75 0, 360*64);
76 } else {
77 GdkGC *lgrey_gc = gdk_gc_new(context->gotoc.compass_pixmap);
78 gdk_gc_copy(lgrey_gc, widget->style->black_gc);
79 GdkColor lgrey_color;
80 gdk_color_parse("#DDDDDD", &lgrey_color);
81 gdk_gc_set_rgb_fg_color(lgrey_gc, &lgrey_color);
82
83 gdk_draw_arc(context->gotoc.compass_pixmap, lgrey_gc, TRUE,
84 (width-diameter)/2, (height-diameter)/2, diameter, diameter,
85 0, 360*64);
86 }
87
88 /* draw the locked/unlocked icon */
89 gdk_draw_pixbuf(context->gotoc.compass_pixmap,
90 widget->style->fg_gc[GTK_STATE_NORMAL],
91 icon_get(ICON_MISC, context->appdata->compass_locked?2:3),
92 0, 0, (width-diameter)/2 + diameter/32,
93 (height+diameter)/2 - 16 - diameter/32 , 16, 16,
94 GDK_RGB_DITHER_NONE,0,0);
95
96 /* don't update heading if the compass is locked */
97 if(!context->appdata->compass_locked) {
98 int i, valid = 0, cnt=0;
99 double x_sum = 0.0, y_sum = 0.0;
100
101 /* shift heading buffer up one entry and add new value at entry 0 */
102 for(i=MAX_AVERAGE-1;i>0;i--)
103 context->gotoc.head_avg[i] = context->gotoc.head_avg[i-1];
104 context->gotoc.head_avg[0] = gps_get_heading(context->appdata)*M_PI/180.0;
105
106 // printf("Damping = %d\n", context->appdata->compass_damping);
107 // printf("add heading %f\n", rad2deg(context->gotoc.head_avg[0]));
108
109 /* determine number of valid entries */
110 for(i=0;i<MAX_AVERAGE && valid<context->appdata->compass_damping;i++)
111 if(!isnan(context->gotoc.head_avg[i]))
112 valid++;
113
114 /* map back to angle if at least one value has been added */
115 if(valid) {
116 /* map all valid antries onto a circle */
117 for(i=0;i<MAX_AVERAGE && cnt<context->appdata->compass_damping;i++) {
118 if(!isnan(context->gotoc.head_avg[i])) {
119 float weight = 1.0 - ((float)(cnt++)/(float)valid);
120 printf("weight = %f * %f\n",
121 weight, rad2deg(context->gotoc.head_avg[i]));
122 x_sum += weight * sin(context->gotoc.head_avg[i]);
123 y_sum += weight * cos(context->gotoc.head_avg[i]);
124 }
125 }
126
127 printf("%d valid heading entries\n", valid);
128 context->gotoc.heading = atan2(x_sum, y_sum);
129 printf("averaged heading: %f\n",
130 rad2deg(context->gotoc.heading));
131 } else {
132 // printf("no valid heading, keeping old value heading\n");
133 }
134 }
135
136 if(!isnan(context->gotoc.heading)) {
137
138 for(i=0,f=0;f<2*M_PI-M_PI/8;f+=M_PI/4,i++) {
139 float ang = f - context->gotoc.heading;
140
141 if(!(i&1)) {
142 /* draw diamonds */
143 GdkPoint diamond[4];
144
145 #define OUT (1.0-LETTER_SPACE)
146
147 diamond[0].x = xcenter + radius * OUT * sin(ang);
148 diamond[0].y = ycenter + radius * OUT * -cos(ang);
149
150 diamond[1].x = xcenter + radius * (OUT-DIAMOND_HEIGHT/2) *
151 sin(ang+DIAMOND_WIDTH);
152 diamond[1].y = ycenter + radius * (OUT-DIAMOND_HEIGHT/2)*
153 -cos(ang+DIAMOND_WIDTH);
154
155 diamond[2].x = xcenter + radius * (OUT-DIAMOND_HEIGHT) * sin(ang);
156 diamond[2].y = ycenter + radius * (OUT-DIAMOND_HEIGHT) * -cos(ang);
157
158 diamond[3].x = xcenter + radius * (OUT-DIAMOND_HEIGHT/2) *
159 sin(ang-DIAMOND_WIDTH);
160 diamond[3].y = ycenter + radius * (OUT-DIAMOND_HEIGHT/2) *
161 -cos(ang-DIAMOND_WIDTH);
162
163 gdk_draw_polygon(context->gotoc.compass_pixmap,
164 widget->style->black_gc, TRUE,
165 diamond, sizeof(diamond)/sizeof(GdkPoint));
166
167 const char *str[] = { "N", "E", "S", "W" };
168 PangoLayout *layout = gtk_widget_create_pango_layout(widget, _(str[i/2]));
169 int tw, th;
170 pango_layout_get_pixel_size(layout, &tw, &th);
171
172 gdk_draw_layout(context->gotoc.compass_pixmap, widget->style->black_gc,
173 xcenter + radius * (1.0-LETTER_SPACE/2)*sin(ang) - tw/2,
174 ycenter + radius * (1.0-LETTER_SPACE/2)*-cos(ang) - th/2,
175 layout);
176
177 g_object_unref(layout);
178 } else
179 gdk_draw_line(context->gotoc.compass_pixmap, widget->style->black_gc,
180 xcenter + radius * 0.9 * sin(ang),
181 ycenter + radius * 0.9 * -cos(ang),
182 xcenter + radius * 1.0 * sin(ang),
183 ycenter + radius * 1.0 * -cos(ang));
184 }
185
186 /* draw arrow */
187
188 /* setup required colors */
189 GdkGC *arrow_gc = gdk_gc_new(context->gotoc.compass_pixmap);
190 gdk_gc_copy(arrow_gc, widget->style->black_gc);
191 GdkColor arrow_color;
192 gdk_color_parse("#800000", &arrow_color);
193 gdk_gc_set_rgb_fg_color(arrow_gc, &arrow_color);
194
195 GdkPoint arrow[4];
196
197 pos_t *pos = gps_get_pos(context->appdata);
198 if(pos && !isnan(pos->lat) && !isnan(pos->lon)) {
199 context->appdata->gps = *pos; /* save position */
200
201 float arot =
202 gpx_pos_get_bearing(*pos, context->gotoc.pos) *
203 M_PI/180 - context->gotoc.heading;
204
205 arrow[0].x = xcenter + radius * ARROW_LENGTH * sin(arot);
206 arrow[0].y = ycenter + radius * ARROW_LENGTH * -cos(arot);
207
208 arrow[1].x = xcenter + radius * -ARROW_LENGTH * sin(arot+ARROW_WIDTH);
209 arrow[1].y = ycenter + radius * -ARROW_LENGTH * -cos(arot+ARROW_WIDTH);
210
211 arrow[2].x = xcenter + radius * -0.5 * ARROW_LENGTH * sin(arot);
212 arrow[2].y = ycenter + radius * -0.5 * ARROW_LENGTH * -cos(arot);
213
214 arrow[3].x = xcenter + radius * -ARROW_LENGTH * sin(arot-ARROW_WIDTH);
215 arrow[3].y = ycenter + radius * -ARROW_LENGTH * -cos(arot-ARROW_WIDTH);
216
217 gdk_draw_polygon(context->gotoc.compass_pixmap, arrow_gc, TRUE,
218 arrow, sizeof(arrow)/sizeof(GdkPoint));
219 } else {
220 PangoLayout *layout;
221
222 if(context->appdata->use_gps)
223 layout = gtk_widget_create_pango_layout(widget, _("No fix"));
224 else
225 layout = gtk_widget_create_pango_layout(widget, _("GPS disabled"));
226
227 int tw, th;
228 pango_layout_get_pixel_size(layout, &tw, &th);
229
230 gdk_draw_layout(context->gotoc.compass_pixmap, widget->style->black_gc,
231 xcenter - tw/2, ycenter - th/2, layout);
232
233 g_object_unref(layout);
234 }
235 }
236 }
237
238 /* Create a new backing pixmap of the appropriate size */
239 static gint compass_configure_event(GtkWidget *widget,
240 GdkEventConfigure *event, gpointer data) {
241 cache_context_t *context = (cache_context_t*)data;
242
243 if(context->gotoc.compass_pixmap)
244 gdk_pixmap_unref(context->gotoc.compass_pixmap);
245
246 context->gotoc.compass_pixmap = gdk_pixmap_new(widget->window,
247 widget->allocation.width,
248 widget->allocation.height,
249 -1);
250 compass_draw(widget, context);
251 // goto_update(context);
252
253 return TRUE;
254 }
255
256 /* Redraw the screen from the backing pixmap */
257 static gint compass_expose_event(GtkWidget *widget, GdkEventExpose *event,
258 gpointer data) {
259 cache_context_t *context = (cache_context_t*)data;
260
261 gdk_draw_pixmap(widget->window,
262 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
263 context->gotoc.compass_pixmap,
264 event->area.x, event->area.y,
265 event->area.x, event->area.y,
266 event->area.width, event->area.height);
267
268 return FALSE;
269 }
270
271 static void sat_draw(GtkWidget *widget, cache_context_t *context) {
272 gint width = widget->allocation.width;
273 gint height = widget->allocation.height;
274
275 /* erase background */
276 gdk_draw_rectangle(context->gotoc.sat_pixmap,
277 widget->style->bg_gc[GTK_STATE_NORMAL], TRUE,
278 0, 0, width, height);
279
280 gps_sat_t *sat = gps_get_sats(context->appdata);
281 if(sat && sat->num) {
282 /* setup required colors */
283 GdkGC *used_gc = gdk_gc_new(context->gotoc.sat_pixmap);
284 gdk_gc_copy(used_gc, widget->style->black_gc);
285 GdkColor used_color;
286 gdk_color_parse("#008000", &used_color); // green
287 gdk_gc_set_rgb_fg_color(used_gc, &used_color);
288
289 #define SAT_SPACING 3
290 int i, x;
291 int swid = (width-SAT_SPACING*(sat->num-1))/sat->num;
292
293 /* as of xgps, a ss of 40 and more is "plenty" */
294 int max_ss = 40;
295 for(i=0;i<sat->num;i++)
296 if(sat->ss[i] > max_ss) sat->ss[i] = max_ss;
297
298 if(swid > 40) {
299 swid = 40;
300 x = (width-sat->num*swid)/2;
301 } else
302 x = 0;
303
304 for(i=0;i<sat->num;i++) {
305 char str[32];
306 #ifdef USE_MAEMO
307 snprintf(str, sizeof(str), "<span size=\"small\">%d</span>", sat->PRN[i]);
308 PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
309 pango_layout_set_markup(layout, str, strlen(str));
310 #else
311 snprintf(str, sizeof(str), "%d", sat->PRN[i]);
312 PangoLayout *layout = gtk_widget_create_pango_layout(widget, str);
313 #endif
314
315 int tw, th;
316 pango_layout_get_pixel_size(layout, &tw, &th);
317 gdk_draw_layout(context->gotoc.sat_pixmap,
318 widget->style->text_gc[GTK_STATE_NORMAL],
319 x + swid/2 - tw/2, height - th, layout);
320
321 g_object_unref(layout);
322
323 int h = (height-th) * sat->ss[i] / max_ss;
324
325 gdk_draw_rectangle(context->gotoc.sat_pixmap,
326 sat->used[i]?used_gc:widget->style->fg_gc[GTK_STATE_NORMAL],
327 TRUE, x, height-h-th, swid, h);
328
329 x += SAT_SPACING+swid;
330 }
331
332 /* free sat infos */
333 free(sat->PRN);
334 free(sat->ss);
335 free(sat->used);
336 } else {
337 PangoLayout *layout =
338 gtk_widget_create_pango_layout(widget, _("No SAT info"));
339 int tw, th;
340 pango_layout_get_pixel_size(layout, &tw, &th);
341 gdk_draw_layout(context->gotoc.sat_pixmap,
342 widget->style->text_gc[GTK_STATE_NORMAL],
343 (width - tw)/2, (height - th)/2, layout);
344
345 g_object_unref(layout);
346 }
347
348 /* free the sat structure */
349 if(sat)
350 free(sat);
351 }
352
353 /* Create a new backing pixmap of the appropriate size */
354 static gint sat_configure_event(GtkWidget *widget, GdkEventConfigure *event,
355 gpointer data) {
356 cache_context_t *context = (cache_context_t*)data;
357
358 if(context->gotoc.sat_pixmap)
359 gdk_pixmap_unref(context->gotoc.sat_pixmap);
360
361 context->gotoc.sat_pixmap = gdk_pixmap_new(widget->window,
362 widget->allocation.width,
363 widget->allocation.height,
364 -1);
365 sat_draw(widget, context);
366
367 return TRUE;
368 }
369
370 /* Redraw the screen from the backing pixmap */
371 static gint sat_expose_event(GtkWidget *widget, GdkEventExpose *event,
372 gpointer data) {
373 cache_context_t *context = (cache_context_t*)data;
374
375 gdk_draw_pixmap(widget->window,
376 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
377 context->gotoc.sat_pixmap,
378 event->area.x, event->area.y,
379 event->area.x, event->area.y,
380 event->area.width, event->area.height);
381
382 return FALSE;
383 }
384
385 gint goto_destroy_event(GtkWidget *widget, gpointer data ) {
386 cache_context_t *context = (cache_context_t*)data;
387
388 printf("destroying goto view\n");
389
390 /* stop timer */
391 if(context->gotoc.handler_id)
392 gtk_timeout_remove(context->gotoc.handler_id);
393
394 return FALSE;
395 }
396
397 static gboolean goto_update(gpointer data) {
398 cache_context_t *context = (cache_context_t*)data;
399
400 if(context->gotoc.sat_pixmap) {
401 static int sub = 0;
402
403 if(!sub) {
404 /* draw sat view */
405 sat_draw(context->gotoc.sat_area, context);
406 gtk_widget_queue_draw_area(context->gotoc.sat_area, 0,0,
407 context->gotoc.sat_area->allocation.width,
408 context->gotoc.sat_area->allocation.height);
409 }
410
411 if(sub++ == 5) sub = 0;
412 }
413
414 if(context->gotoc.compass_pixmap) {
415 /* draw compass */
416 compass_draw(context->gotoc.compass_area, context);
417 gtk_widget_queue_draw_area(context->gotoc.compass_area, 0,0,
418 context->gotoc.compass_area->allocation.width,
419 context->gotoc.compass_area->allocation.height);
420 }
421
422 pos_t *pos = gps_get_pos(context->appdata);
423 if(pos && !isnan(pos->lat) && !isnan(pos->lon) &&
424 !isnan(context->gotoc.pos.lat) && !isnan(context->gotoc.pos.lon)) {
425 char str[16];
426 gpx_pos_get_distance_str(str, sizeof(str),
427 *pos, context->gotoc.pos,
428 context->appdata->imperial);
429 gtk_label_set_text(GTK_LABEL(context->gotoc.distance_label), str);
430
431 snprintf(str, sizeof(str), _("%.1f°"),
432 gpx_pos_get_bearing(*pos, context->gotoc.pos));
433 gtk_label_set_text(GTK_LABEL(context->gotoc.bearing_label), str);
434 } else {
435 gtk_label_set_text(GTK_LABEL(context->gotoc.distance_label), "-----");
436 gtk_label_set_text(GTK_LABEL(context->gotoc.bearing_label), "-----");
437 }
438
439 float epe = gps_get_epe(context->appdata);
440 if(isnan(epe))
441 gtk_label_set_text(GTK_LABEL(context->gotoc.epe_label), "-----");
442 else {
443 char str[16];
444 if(context->appdata->imperial) {
445 epe *= 3.2808;
446 snprintf(str, sizeof(str), "%.1f ft", epe);
447 } else
448 snprintf(str, sizeof(str), "%.1f m", epe);
449
450 gtk_label_set_text(GTK_LABEL(context->gotoc.epe_label), str);
451 }
452
453 return TRUE; // fire again
454 }
455
456 static gint waypoint_changed_event(GtkWidget *widget, gpointer data ) {
457 cache_context_t *context = (cache_context_t*)data;
458 int wpt_idx = gtk_combo_box_get_active(GTK_COMBO_BOX(widget));
459
460 /* get position of selected waypoint */
461 if(wpt_idx == 0)
462 context->gotoc.pos = context->appdata->geomath;
463 else if(wpt_idx == 1)
464 // context->gotoc.pos = gpx_cache_pos(context->cache);
465 context->gotoc.pos = notes_get_pos(context);
466 else {
467 wpt_t *wpt = context->cache->wpt;
468 while(wpt_idx > 2) {
469 g_assert(wpt != NULL);
470 wpt = wpt->next;
471 wpt_idx--;
472 }
473 context->gotoc.pos = wpt->pos;
474 }
475
476 char str[32];
477 pos_lat_str(str, sizeof(str), context->gotoc.pos.lat);
478 gtk_label_set_text(GTK_LABEL(context->gotoc.lat_lbl), str);
479 pos_lon_str(str, sizeof(str), context->gotoc.pos.lon);
480 gtk_label_set_text(GTK_LABEL(context->gotoc.lon_lbl), str);
481
482 goto_update(context);
483
484 return FALSE;
485 }
486
487 static void manual_pos_update(cache_context_t *context) {
488 context->gotoc.pos.lat = context->appdata->manual_goto.lat;
489 context->gotoc.pos.lon = context->appdata->manual_goto.lon;
490
491 char str[32];
492 pos_lat_str(str, sizeof(str), context->gotoc.pos.lat);
493 gtk_label_set_text(GTK_LABEL(context->gotoc.lat_lbl), str);
494 pos_lon_str(str, sizeof(str), context->gotoc.pos.lon);
495 gtk_label_set_text(GTK_LABEL(context->gotoc.lon_lbl), str);
496
497 goto_update(context);
498 }
499
500 static void on_posedit_clicked(GtkWidget *button, gpointer data) {
501 cache_context_t *context = (cache_context_t*)data;
502
503 GtkWidget *dialog = gtk_dialog_new_with_buttons(_("Edit Position"),
504 GTK_WINDOW(context->appdata->window), GTK_DIALOG_MODAL,
505 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
506 GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL);
507
508 GtkWidget *lat, *lon, *label;
509 GtkWidget *table = gtk_table_new(2, 2, FALSE);
510
511 gtk_table_attach_defaults(GTK_TABLE(table),
512 label = gtk_label_new(_("Latitude:")), 0, 1, 0, 1);
513 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
514 gtk_table_attach_defaults(GTK_TABLE(table),
515 lat = lat_entry_new(context->appdata->manual_goto.lat),
516 1, 2, 0, 1);
517
518 gtk_table_attach_defaults(GTK_TABLE(table),
519 label = gtk_label_new(_("Longitude:")), 0, 1, 1, 2);
520 gtk_misc_set_alignment(GTK_MISC(label), 1.f, 0.5f);
521 gtk_table_attach_defaults(GTK_TABLE(table),
522 lon = lon_entry_new(context->appdata->manual_goto.lon),
523 1, 2, 1, 2);
524
525 gtk_box_pack_start_defaults(GTK_BOX(GTK_DIALOG(dialog)->vbox), table);
526
527 gtk_widget_show_all(dialog);
528
529 if(GTK_RESPONSE_ACCEPT == gtk_dialog_run(GTK_DIALOG(dialog))) {
530 if(isnan(lat_get(lat)) || isnan(lon_get(lon)))
531 errorf(_("Ignoring invalid position"));
532 else {
533 context->appdata->manual_goto.lat = lat_get(lat);
534 context->appdata->manual_goto.lon = lon_get(lon);
535
536 manual_pos_update(context);
537 }
538 }
539 gtk_widget_destroy(dialog);
540 }
541
542 static gint radio_changed_event(GtkWidget *widget, gpointer data ) {
543 cache_context_t *context = (cache_context_t*)data;
544
545 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
546 manual_pos_update(context);
547 gtk_widget_set_sensitive(context->gotoc.edit_but, TRUE);
548 } else {
549 waypoint_changed_event(context->gotoc.cbox, data);
550 gtk_widget_set_sensitive(context->gotoc.edit_but, FALSE);
551 }
552
553 return FALSE;
554 }
555
556 #ifdef USE_MAEMO
557 static void on_mm_button_clicked(GtkButton *button, gpointer data) {
558 cache_context_t *context = (cache_context_t*)data;
559
560 dbus_mm_set_position(context->appdata, &context->gotoc.pos);
561 }
562 #endif
563
564 static gboolean compass_clicked_event(GtkWidget *widget, GdkEventButton *event,
565 gpointer user_data) {
566 cache_context_t *context = (cache_context_t*)user_data;
567
568 context->appdata->compass_locked = !context->appdata->compass_locked;
569
570 printf("compass is now %slocked\n",
571 context->appdata->compass_locked?"":"un");
572
573 if(context->gotoc.compass_pixmap) {
574 /* draw compass */
575 compass_draw(context->gotoc.compass_area, context);
576 gtk_widget_queue_draw_area(context->gotoc.compass_area, 0,0,
577 context->gotoc.compass_area->allocation.width,
578 context->gotoc.compass_area->allocation.height);
579 }
580 return FALSE;
581 }
582
583 GtkWidget *goto_cache(cache_context_t *context) {
584 int i;
585
586 /* clear list used for averaging */
587 for(i=0;i<MAX_AVERAGE;i++)
588 context->gotoc.head_avg[i] = NAN;
589
590 context->gotoc.pos = gpx_cache_pos(context->cache);
591
592 GtkWidget *hbox = gtk_hbox_new(FALSE, 0);
593
594 context->gotoc.compass_area = gtk_drawing_area_new();
595 gtk_drawing_area_size(GTK_DRAWING_AREA(context->gotoc.compass_area),
596 COMPASS_SIZE, COMPASS_SIZE);
597
598 gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area), "expose_event",
599 (GtkSignalFunc)compass_expose_event, context);
600 gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area),"configure_event",
601 (GtkSignalFunc)compass_configure_event, context);
602 gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area),
603 "button_press_event",
604 (GtkSignalFunc)compass_clicked_event, context);
605
606 gtk_widget_set_events(context->gotoc.compass_area, GDK_EXPOSURE_MASK);
607 gtk_widget_add_events(context->gotoc.compass_area, GDK_BUTTON_PRESS_MASK);
608 gtk_box_pack_start_defaults(GTK_BOX(hbox), context->gotoc.compass_area);
609
610 GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
611 GtkWidget *table = gtk_table_new(8, 2, FALSE);
612
613 /* ---------- combo box containing waypoint names ------- */
614 GtkWidget *radio = gtk_radio_button_new_with_label(NULL, _("Waypoint:"));
615 gtk_table_attach_defaults(GTK_TABLE(table), radio, 0,1,0,1);
616
617 context->gotoc.cbox = gtk_combo_box_new_text();
618 gtk_combo_box_append_text(GTK_COMBO_BOX(context->gotoc.cbox), _("Geomath"));
619 gtk_combo_box_append_text(GTK_COMBO_BOX(context->gotoc.cbox),
620 context->cache->id);
621
622 wpt_t *wpt = context->cache->wpt;
623 while(wpt) {
624 gtk_combo_box_append_text(GTK_COMBO_BOX(context->gotoc.cbox), wpt->id);
625 wpt = wpt->next;
626 }
627 gtk_combo_box_set_active(GTK_COMBO_BOX(context->gotoc.cbox), 1);
628 gtk_signal_connect(GTK_OBJECT(context->gotoc.cbox), "changed",
629 (GtkSignalFunc)waypoint_changed_event, context);
630 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.cbox, 1,2,0,1);
631
632 /* -------------- manual entry field ------------------------- */
633 gtk_table_attach_defaults(GTK_TABLE(table),
634 gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(radio),
635 _("Manual:")), 0,1,1,2);
636 gtk_signal_connect(GTK_OBJECT(radio), "clicked",
637 (GtkSignalFunc)radio_changed_event, context);
638
639 context->gotoc.edit_but = gtk_button_new_with_label(_("Edit"));
640 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.edit_but, 1,2,1,2);
641 gtk_signal_connect(GTK_OBJECT(context->gotoc.edit_but), "clicked",
642 (GtkSignalFunc)on_posedit_clicked, context);
643 gtk_widget_set_sensitive(context->gotoc.edit_but, FALSE);
644
645 #if 0
646 context->gotoc.man_lat = gtk_entry_new();
647 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.man_lat, 1,2,1,2);
648 pos_lat_str(str, sizeof(str), context->appdata->manual_goto.lat);
649 gtk_entry_set_text(GTK_ENTRY(context->gotoc.man_lat), str);
650 textbox_disable(context->gotoc.man_lat);
651 context->gotoc.man_lon = gtk_entry_new();
652 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.man_lon, 1,2,2,3);
653 pos_lon_str(str, sizeof(str), context->appdata->manual_goto.lon);
654 gtk_entry_set_text(GTK_ENTRY(context->gotoc.man_lon), str);
655 textbox_disable(context->gotoc.man_lon);
656
657 gtk_signal_connect(GTK_OBJECT(context->gotoc.man_lat), "changed",
658 (GtkSignalFunc)entry_changed_event, context);
659 gtk_signal_connect(GTK_OBJECT(context->gotoc.man_lon), "changed",
660 (GtkSignalFunc)entry_changed_event, context);
661 #endif
662
663 gtk_table_set_row_spacing(GTK_TABLE(table), 2, 16);
664
665 /* -------------- waypoint coordinates ------------------------- */
666 /* SIZE_SMALL doesn't work here as setting the label returns to normal */
667 context->gotoc.lat_lbl = pos_lat(context->gotoc.pos.lat, SIZE_NORMAL,
668 STRIKETHROUGH_NONE);
669 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.lat_lbl,0,1,3,4);
670 context->gotoc.lon_lbl = pos_lon(context->gotoc.pos.lon, SIZE_NORMAL,
671 STRIKETHROUGH_NONE);
672 gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.lon_lbl,1,2,3,4);
673
674 /* -------------- distance label ------------------------- */
675 gtk_table_attach_defaults(GTK_TABLE(table),
676 gtk_label_new(_("Distance:")), 0,1,4,5);
677 gtk_table_attach_defaults(GTK_TABLE(table),
678 (context->gotoc.distance_label = gtk_label_new("-----")), 1,2,4,5);
679
680 /* -------------- bearing label ------------------------- */
681 gtk_table_attach_defaults(GTK_TABLE(table),
682 gtk_label_new(_("Bearing:")), 0,1,5,6);
683 gtk_table_attach_defaults(GTK_TABLE(table),
684 (context->gotoc.bearing_label = gtk_label_new("-----")), 1,2,5,6);
685
686 /* -------------- error label ------------------------- */
687 gtk_table_attach_defaults(GTK_TABLE(table),
688 gtk_label_new(_("Est. error:")), 0,1,6,7);
689 gtk_table_attach_defaults(GTK_TABLE(table),
690 (context->gotoc.epe_label = gtk_label_new("-----")), 1,2,6,7);
691
692 gtk_table_set_row_spacing(GTK_TABLE(table), 6, 16);
693
694 /* -------------- sat view box ------------------------- */
695 GtkWidget *ihbox = gtk_hbox_new(FALSE,0);
696
697 context->gotoc.sat_area = gtk_drawing_area_new();
698 gtk_drawing_area_size(GTK_DRAWING_AREA(context->gotoc.sat_area),
699 SAT_WIDTH, SAT_HEIGHT);
700
701 gtk_signal_connect(GTK_OBJECT(context->gotoc.sat_area), "expose_event",
702 (GtkSignalFunc)sat_expose_event, context);
703 gtk_signal_connect(GTK_OBJECT(context->gotoc.sat_area),"configure_event",
704 (GtkSignalFunc)sat_configure_event, context);
705
706 gtk_widget_set_events(context->gotoc.sat_area, GDK_EXPOSURE_MASK);
707
708 gtk_box_pack_start(GTK_BOX(ihbox), context->gotoc.sat_area, 1,0,0);
709
710 #ifdef USE_MAEMO
711 GtkWidget *mm_button = gtk_button_new();
712 gtk_button_set_image(GTK_BUTTON(mm_button), icon_get_widget(ICON_MISC, 0));
713 gtk_signal_connect(GTK_OBJECT(mm_button), "clicked",
714 (GtkSignalFunc)on_mm_button_clicked, context);
715 gtk_box_pack_start(GTK_BOX(ihbox), mm_button, 1,0,0);
716 #endif
717 gtk_table_attach_defaults(GTK_TABLE(table), ihbox, 0,2,7,8);
718
719 /* ------------------------------------------------------- */
720
721 gtk_box_pack_start(GTK_BOX(vbox), table, 1,0,0);
722 gtk_box_pack_start(GTK_BOX(hbox), vbox, 1,0,0);
723
724 context->gotoc.handler_id = gtk_timeout_add(UPDATE_MS,
725 goto_update, context);
726
727 return hbox;
728 }
729
730 void goto_coordinate_update(cache_context_t *context) {
731 if(!context->notes.modified)
732 return;
733
734 waypoint_changed_event(context->gotoc.cbox, context);
735 }