Contents of /trunk/src/goto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 282 - (hide annotations)
Wed May 26 19:21:47 2010 UTC (14 years ago) by harbaum
File MIME type: text/plain
File size: 23413 byte(s)
New gps integration
1 harbaum 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 harbaum 246 #ifdef ESPEAK
42 harbaum 249 #include <espeak/speak_lib.h>
43 harbaum 246
44 harbaum 249 #define ESPEAK_TIMEOUT (15000) // every 15 seconds
45    
46     char *espeak_make_string(float dist, gboolean imperial) {
47     char *retval = NULL;
48    
49     if(!imperial) {
50     /* distance is in kilometers */
51     if(dist < 2.0/1000.0)
52     retval = g_strdup(_("1 meter"));
53     else if(dist < 1.0)
54     retval = g_strdup_printf(_("%u meters"), (int)(dist*1000));
55     else if(dist < 2.0)
56     retval = g_strdup(_("1 kilometer"));
57     else
58     retval = g_strdup_printf(_("%u kilometers"), (int)dist);
59     } else {
60    
61     /* 1 mil = 1760 yd = 5280 ft ... */
62     if(dist < (2.0/5280.0))
63     retval = g_strdup(_("1 foot"));
64     else if(dist < (1.0/1760.0))
65     retval = g_strdup_printf(_("%u feet"), (int)(dist*5280));
66     else if(dist < (2.0/1760.0))
67     retval = g_strdup(_("1 yard"));
68     else if(dist < 1.0)
69     retval = g_strdup_printf(_("%u yard"), (int)(dist*1760));
70     else if(dist < 2.0)
71     retval = g_strdup(_("1 mile"));
72     else
73     retval = g_strdup_printf(_("%u miles"), (int)dist);
74     }
75     return retval;
76     }
77    
78     static gboolean espeak_do(gpointer data) {
79     cache_context_t *context = (cache_context_t*)data;
80    
81     pos_t *pos = gps_get_pos(context->appdata);
82     if(pos && !isnan(pos->lat) && !isnan(pos->lon) &&
83     !isnan(context->gotoc.pos.lat) && !isnan(context->gotoc.pos.lon)) {
84    
85     /* build distance */
86     float dist =
87     gpx_pos_get_distance(*pos, context->gotoc.pos,
88     context->appdata->imperial);
89    
90     char *talk = espeak_make_string(dist, context->appdata->imperial);
91    
92     unsigned int unique_identifier=0;
93     espeak_Synth(talk, strlen(talk)+1, 0, 0, 0, espeakCHARS_AUTO,
94     &unique_identifier, NULL);
95    
96     g_free(talk);
97     }
98    
99     return TRUE; // speak again
100     }
101    
102     static void espeak_enable(cache_context_t *context, gboolean enable) {
103     if(enable) {
104     g_assert(!context->gotoc.espeak_handler);
105    
106     context->gotoc.espeak_handler =
107     gtk_timeout_add(ESPEAK_TIMEOUT, espeak_do, context);
108    
109     espeak_do(context);
110    
111     } else {
112     if(context->gotoc.espeak_handler) {
113     gtk_timeout_remove(context->gotoc.espeak_handler);
114     context->gotoc.espeak_handler = 0;
115     }
116     }
117     }
118 harbaum 246 #endif
119    
120 harbaum 1 static float rad2deg(float rad) {
121     return fmodf(360.0 + (180.0/M_PI) * rad, 360.0);
122     }
123    
124     static void compass_draw(GtkWidget *widget, cache_context_t *context) {
125     float f;
126     int i;
127    
128     gint width = widget->allocation.width;
129     gint height = widget->allocation.height;
130     gint diameter = (height < width)?height:width;
131    
132     gint xcenter = width/2;
133     gint ycenter = height/2;
134     gint radius = diameter/2;
135    
136     /* erase background */
137     gdk_draw_rectangle(context->gotoc.compass_pixmap,
138     widget->style->bg_gc[GTK_STATE_NORMAL], TRUE,
139     0, 0, width, height);
140    
141     /* use white rosetta background unless the real background */
142     /* is very bright. Use bright grey then */
143    
144     if(widget->style->bg[GTK_STATE_NORMAL].red +
145     widget->style->bg[GTK_STATE_NORMAL].green +
146     widget->style->bg[GTK_STATE_NORMAL].blue < 3*60000) {
147     /* background is very bright, use white */
148     gdk_draw_arc(context->gotoc.compass_pixmap, widget->style->white_gc, TRUE,
149     (width-diameter)/2, (height-diameter)/2, diameter, diameter,
150     0, 360*64);
151     } else {
152     GdkGC *lgrey_gc = gdk_gc_new(context->gotoc.compass_pixmap);
153     gdk_gc_copy(lgrey_gc, widget->style->black_gc);
154     GdkColor lgrey_color;
155     gdk_color_parse("#DDDDDD", &lgrey_color);
156     gdk_gc_set_rgb_fg_color(lgrey_gc, &lgrey_color);
157    
158     gdk_draw_arc(context->gotoc.compass_pixmap, lgrey_gc, TRUE,
159     (width-diameter)/2, (height-diameter)/2, diameter, diameter,
160     0, 360*64);
161     }
162    
163     /* draw the locked/unlocked icon */
164     gdk_draw_pixbuf(context->gotoc.compass_pixmap,
165     widget->style->fg_gc[GTK_STATE_NORMAL],
166 harbaum 231 icon_get(ICON_MISC, context->appdata->compass_locked?0:1),
167 harbaum 1 0, 0, (width-diameter)/2 + diameter/32,
168     (height+diameter)/2 - 16 - diameter/32 , 16, 16,
169     GDK_RGB_DITHER_NONE,0,0);
170    
171     /* don't update heading if the compass is locked */
172     if(!context->appdata->compass_locked) {
173     int i, valid = 0, cnt=0;
174     double x_sum = 0.0, y_sum = 0.0;
175    
176     /* shift heading buffer up one entry and add new value at entry 0 */
177     for(i=MAX_AVERAGE-1;i>0;i--)
178     context->gotoc.head_avg[i] = context->gotoc.head_avg[i-1];
179     context->gotoc.head_avg[0] = gps_get_heading(context->appdata)*M_PI/180.0;
180    
181     // printf("Damping = %d\n", context->appdata->compass_damping);
182     // printf("add heading %f\n", rad2deg(context->gotoc.head_avg[0]));
183    
184     /* determine number of valid entries */
185     for(i=0;i<MAX_AVERAGE && valid<context->appdata->compass_damping;i++)
186     if(!isnan(context->gotoc.head_avg[i]))
187     valid++;
188    
189     /* map back to angle if at least one value has been added */
190     if(valid) {
191     /* map all valid antries onto a circle */
192     for(i=0;i<MAX_AVERAGE && cnt<context->appdata->compass_damping;i++) {
193     if(!isnan(context->gotoc.head_avg[i])) {
194     float weight = 1.0 - ((float)(cnt++)/(float)valid);
195     printf("weight = %f * %f\n",
196     weight, rad2deg(context->gotoc.head_avg[i]));
197     x_sum += weight * sin(context->gotoc.head_avg[i]);
198     y_sum += weight * cos(context->gotoc.head_avg[i]);
199     }
200     }
201    
202     printf("%d valid heading entries\n", valid);
203     context->gotoc.heading = atan2(x_sum, y_sum);
204     printf("averaged heading: %f\n",
205     rad2deg(context->gotoc.heading));
206     } else {
207     // printf("no valid heading, keeping old value heading\n");
208     }
209     }
210    
211     if(!isnan(context->gotoc.heading)) {
212    
213     for(i=0,f=0;f<2*M_PI-M_PI/8;f+=M_PI/4,i++) {
214     float ang = f - context->gotoc.heading;
215    
216     if(!(i&1)) {
217     /* draw diamonds */
218     GdkPoint diamond[4];
219    
220     #define OUT (1.0-LETTER_SPACE)
221    
222     diamond[0].x = xcenter + radius * OUT * sin(ang);
223     diamond[0].y = ycenter + radius * OUT * -cos(ang);
224    
225     diamond[1].x = xcenter + radius * (OUT-DIAMOND_HEIGHT/2) *
226     sin(ang+DIAMOND_WIDTH);
227     diamond[1].y = ycenter + radius * (OUT-DIAMOND_HEIGHT/2)*
228     -cos(ang+DIAMOND_WIDTH);
229    
230     diamond[2].x = xcenter + radius * (OUT-DIAMOND_HEIGHT) * sin(ang);
231     diamond[2].y = ycenter + radius * (OUT-DIAMOND_HEIGHT) * -cos(ang);
232    
233     diamond[3].x = xcenter + radius * (OUT-DIAMOND_HEIGHT/2) *
234     sin(ang-DIAMOND_WIDTH);
235     diamond[3].y = ycenter + radius * (OUT-DIAMOND_HEIGHT/2) *
236     -cos(ang-DIAMOND_WIDTH);
237    
238     gdk_draw_polygon(context->gotoc.compass_pixmap,
239     widget->style->black_gc, TRUE,
240     diamond, sizeof(diamond)/sizeof(GdkPoint));
241    
242     const char *str[] = { "N", "E", "S", "W" };
243     PangoLayout *layout = gtk_widget_create_pango_layout(widget, _(str[i/2]));
244     int tw, th;
245     pango_layout_get_pixel_size(layout, &tw, &th);
246    
247     gdk_draw_layout(context->gotoc.compass_pixmap, widget->style->black_gc,
248     xcenter + radius * (1.0-LETTER_SPACE/2)*sin(ang) - tw/2,
249     ycenter + radius * (1.0-LETTER_SPACE/2)*-cos(ang) - th/2,
250     layout);
251    
252     g_object_unref(layout);
253     } else
254     gdk_draw_line(context->gotoc.compass_pixmap, widget->style->black_gc,
255     xcenter + radius * 0.9 * sin(ang),
256     ycenter + radius * 0.9 * -cos(ang),
257     xcenter + radius * 1.0 * sin(ang),
258     ycenter + radius * 1.0 * -cos(ang));
259     }
260    
261     /* draw arrow */
262    
263     /* setup required colors */
264     GdkGC *arrow_gc = gdk_gc_new(context->gotoc.compass_pixmap);
265     gdk_gc_copy(arrow_gc, widget->style->black_gc);
266     GdkColor arrow_color;
267     gdk_color_parse("#800000", &arrow_color);
268     gdk_gc_set_rgb_fg_color(arrow_gc, &arrow_color);
269    
270     GdkPoint arrow[4];
271    
272     pos_t *pos = gps_get_pos(context->appdata);
273 harbaum 47 if(pos && !isnan(pos->lat) && !isnan(pos->lon)) {
274 harbaum 282 context->appdata->gps.saved = *pos; /* save position */
275 harbaum 1
276     float arot =
277     gpx_pos_get_bearing(*pos, context->gotoc.pos) *
278     M_PI/180 - context->gotoc.heading;
279    
280     arrow[0].x = xcenter + radius * ARROW_LENGTH * sin(arot);
281     arrow[0].y = ycenter + radius * ARROW_LENGTH * -cos(arot);
282    
283     arrow[1].x = xcenter + radius * -ARROW_LENGTH * sin(arot+ARROW_WIDTH);
284     arrow[1].y = ycenter + radius * -ARROW_LENGTH * -cos(arot+ARROW_WIDTH);
285    
286     arrow[2].x = xcenter + radius * -0.5 * ARROW_LENGTH * sin(arot);
287     arrow[2].y = ycenter + radius * -0.5 * ARROW_LENGTH * -cos(arot);
288    
289     arrow[3].x = xcenter + radius * -ARROW_LENGTH * sin(arot-ARROW_WIDTH);
290     arrow[3].y = ycenter + radius * -ARROW_LENGTH * -cos(arot-ARROW_WIDTH);
291    
292     gdk_draw_polygon(context->gotoc.compass_pixmap, arrow_gc, TRUE,
293     arrow, sizeof(arrow)/sizeof(GdkPoint));
294     } else {
295     PangoLayout *layout;
296    
297     if(context->appdata->use_gps)
298     layout = gtk_widget_create_pango_layout(widget, _("No fix"));
299     else
300     layout = gtk_widget_create_pango_layout(widget, _("GPS disabled"));
301    
302     int tw, th;
303     pango_layout_get_pixel_size(layout, &tw, &th);
304    
305     gdk_draw_layout(context->gotoc.compass_pixmap, widget->style->black_gc,
306     xcenter - tw/2, ycenter - th/2, layout);
307    
308     g_object_unref(layout);
309     }
310     }
311     }
312    
313     /* Create a new backing pixmap of the appropriate size */
314     static gint compass_configure_event(GtkWidget *widget,
315     GdkEventConfigure *event, gpointer data) {
316     cache_context_t *context = (cache_context_t*)data;
317    
318     if(context->gotoc.compass_pixmap)
319     gdk_pixmap_unref(context->gotoc.compass_pixmap);
320    
321     context->gotoc.compass_pixmap = gdk_pixmap_new(widget->window,
322     widget->allocation.width,
323     widget->allocation.height,
324     -1);
325     compass_draw(widget, context);
326     // goto_update(context);
327    
328     return TRUE;
329     }
330    
331     /* Redraw the screen from the backing pixmap */
332     static gint compass_expose_event(GtkWidget *widget, GdkEventExpose *event,
333     gpointer data) {
334     cache_context_t *context = (cache_context_t*)data;
335    
336     gdk_draw_pixmap(widget->window,
337     widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
338     context->gotoc.compass_pixmap,
339     event->area.x, event->area.y,
340     event->area.x, event->area.y,
341     event->area.width, event->area.height);
342    
343     return FALSE;
344     }
345    
346     static void sat_draw(GtkWidget *widget, cache_context_t *context) {
347     gint width = widget->allocation.width;
348     gint height = widget->allocation.height;
349    
350     /* erase background */
351     gdk_draw_rectangle(context->gotoc.sat_pixmap,
352     widget->style->bg_gc[GTK_STATE_NORMAL], TRUE,
353     0, 0, width, height);
354    
355     gps_sat_t *sat = gps_get_sats(context->appdata);
356 harbaum 282 gint sat_num = gps_get_satnum(context->appdata);
357    
358     if(sat && sat_num) {
359 harbaum 1 /* setup required colors */
360     GdkGC *used_gc = gdk_gc_new(context->gotoc.sat_pixmap);
361     gdk_gc_copy(used_gc, widget->style->black_gc);
362     GdkColor used_color;
363     gdk_color_parse("#008000", &used_color); // green
364     gdk_gc_set_rgb_fg_color(used_gc, &used_color);
365    
366     #define SAT_SPACING 3
367     int i, x;
368 harbaum 282 int swid = (width-SAT_SPACING*(sat_num-1))/sat_num;
369 harbaum 1
370     /* as of xgps, a ss of 40 and more is "plenty" */
371     int max_ss = 40;
372 harbaum 282 for(i=0;i<sat_num;i++)
373     if(sat[i].ss > max_ss) sat[i].ss = max_ss;
374 harbaum 1
375     if(swid > 40) {
376     swid = 40;
377 harbaum 282 x = (width-sat_num*swid)/2;
378 harbaum 1 } else
379     x = 0;
380    
381 harbaum 282 for(i=0;i<sat_num;i++) {
382 harbaum 1 char str[32];
383     #ifdef USE_MAEMO
384 harbaum 282 snprintf(str, sizeof(str), "<span size=\"small\">%d</span>", sat[i].prn);
385 harbaum 1 PangoLayout *layout = gtk_widget_create_pango_layout(widget, NULL);
386     pango_layout_set_markup(layout, str, strlen(str));
387     #else
388 harbaum 282 snprintf(str, sizeof(str), "%d", sat[i].prn);
389 harbaum 1 PangoLayout *layout = gtk_widget_create_pango_layout(widget, str);
390     #endif
391    
392     int tw, th;
393     pango_layout_get_pixel_size(layout, &tw, &th);
394 harbaum 47 gdk_draw_layout(context->gotoc.sat_pixmap,
395     widget->style->text_gc[GTK_STATE_NORMAL],
396 harbaum 1 x + swid/2 - tw/2, height - th, layout);
397    
398     g_object_unref(layout);
399    
400 harbaum 282 int h = (height-th) * sat[i].ss / max_ss;
401 harbaum 1
402     gdk_draw_rectangle(context->gotoc.sat_pixmap,
403 harbaum 282 sat[i].used?used_gc:widget->style->fg_gc[GTK_STATE_NORMAL],
404 harbaum 47 TRUE, x, height-h-th, swid, h);
405 harbaum 1
406     x += SAT_SPACING+swid;
407     }
408    
409     } else {
410 harbaum 47 PangoLayout *layout =
411     gtk_widget_create_pango_layout(widget, _("No SAT info"));
412 harbaum 1 int tw, th;
413     pango_layout_get_pixel_size(layout, &tw, &th);
414 harbaum 47 gdk_draw_layout(context->gotoc.sat_pixmap,
415     widget->style->text_gc[GTK_STATE_NORMAL],
416 harbaum 1 (width - tw)/2, (height - th)/2, layout);
417    
418     g_object_unref(layout);
419     }
420     }
421    
422     /* Create a new backing pixmap of the appropriate size */
423     static gint sat_configure_event(GtkWidget *widget, GdkEventConfigure *event,
424     gpointer data) {
425     cache_context_t *context = (cache_context_t*)data;
426    
427     if(context->gotoc.sat_pixmap)
428     gdk_pixmap_unref(context->gotoc.sat_pixmap);
429    
430     context->gotoc.sat_pixmap = gdk_pixmap_new(widget->window,
431     widget->allocation.width,
432     widget->allocation.height,
433     -1);
434     sat_draw(widget, context);
435    
436     return TRUE;
437     }
438    
439     /* Redraw the screen from the backing pixmap */
440     static gint sat_expose_event(GtkWidget *widget, GdkEventExpose *event,
441     gpointer data) {
442     cache_context_t *context = (cache_context_t*)data;
443    
444     gdk_draw_pixmap(widget->window,
445     widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
446     context->gotoc.sat_pixmap,
447     event->area.x, event->area.y,
448     event->area.x, event->area.y,
449     event->area.width, event->area.height);
450    
451     return FALSE;
452     }
453    
454     gint goto_destroy_event(GtkWidget *widget, gpointer data ) {
455     cache_context_t *context = (cache_context_t*)data;
456    
457     printf("destroying goto view\n");
458    
459 harbaum 249 #ifdef ESPEAK
460     espeak_enable(context, FALSE);
461     #endif
462    
463 harbaum 1 /* stop timer */
464     if(context->gotoc.handler_id)
465     gtk_timeout_remove(context->gotoc.handler_id);
466    
467     return FALSE;
468     }
469    
470     static gboolean goto_update(gpointer data) {
471     cache_context_t *context = (cache_context_t*)data;
472    
473     if(context->gotoc.sat_pixmap) {
474     static int sub = 0;
475    
476     if(!sub) {
477     /* draw sat view */
478     sat_draw(context->gotoc.sat_area, context);
479     gtk_widget_queue_draw_area(context->gotoc.sat_area, 0,0,
480     context->gotoc.sat_area->allocation.width,
481     context->gotoc.sat_area->allocation.height);
482     }
483    
484     if(sub++ == 5) sub = 0;
485     }
486    
487     if(context->gotoc.compass_pixmap) {
488     /* draw compass */
489     compass_draw(context->gotoc.compass_area, context);
490     gtk_widget_queue_draw_area(context->gotoc.compass_area, 0,0,
491     context->gotoc.compass_area->allocation.width,
492     context->gotoc.compass_area->allocation.height);
493     }
494    
495     pos_t *pos = gps_get_pos(context->appdata);
496 harbaum 47 if(pos && !isnan(pos->lat) && !isnan(pos->lon) &&
497     !isnan(context->gotoc.pos.lat) && !isnan(context->gotoc.pos.lon)) {
498 harbaum 1 char str[16];
499     gpx_pos_get_distance_str(str, sizeof(str),
500     *pos, context->gotoc.pos,
501     context->appdata->imperial);
502     gtk_label_set_text(GTK_LABEL(context->gotoc.distance_label), str);
503    
504     snprintf(str, sizeof(str), _("%.1f°"),
505     gpx_pos_get_bearing(*pos, context->gotoc.pos));
506     gtk_label_set_text(GTK_LABEL(context->gotoc.bearing_label), str);
507     } else {
508     gtk_label_set_text(GTK_LABEL(context->gotoc.distance_label), "-----");
509     gtk_label_set_text(GTK_LABEL(context->gotoc.bearing_label), "-----");
510     }
511    
512 harbaum 53 float eph = gps_get_eph(context->appdata);
513     if(isnan(eph))
514     gtk_label_set_text(GTK_LABEL(context->gotoc.eph_label), "-----");
515 harbaum 1 else {
516     char str[16];
517 harbaum 53 /* distance needs to be given in km */
518     if(context->appdata->imperial)
519     eph /= (6371.0/3959.0); // km to miles
520    
521     distance_str(str, sizeof(str), eph/1000.0, context->appdata->imperial);
522     gtk_label_set_text(GTK_LABEL(context->gotoc.eph_label), str);
523 harbaum 1 }
524    
525     return TRUE; // fire again
526     }
527    
528     static gboolean compass_clicked_event(GtkWidget *widget, GdkEventButton *event,
529     gpointer user_data) {
530     cache_context_t *context = (cache_context_t*)user_data;
531    
532     context->appdata->compass_locked = !context->appdata->compass_locked;
533    
534     printf("compass is now %slocked\n",
535     context->appdata->compass_locked?"":"un");
536    
537     if(context->gotoc.compass_pixmap) {
538     /* draw compass */
539     compass_draw(context->gotoc.compass_area, context);
540     gtk_widget_queue_draw_area(context->gotoc.compass_area, 0,0,
541     context->gotoc.compass_area->allocation.width,
542     context->gotoc.compass_area->allocation.height);
543     }
544     return FALSE;
545     }
546    
547 harbaum 214 static void pos_modified(GtkWidget *widget, gpointer data ) {
548     cache_context_t *context = (cache_context_t*)data;
549    
550     /* extract position from entries */
551 harbaum 221 context->gotoc.pos.lat = lat_entry_get(context->gotoc.lat_entry);
552     context->gotoc.pos.lon = lon_entry_get(context->gotoc.lon_entry);
553 harbaum 214
554     goto_update(context);
555     }
556    
557 harbaum 246 #ifdef ESPEAK
558     static void espeak_clicked(GtkWidget *widget, gpointer data) {
559 harbaum 249 cache_context_t *context = (cache_context_t*)data;
560 harbaum 246
561     GtkWidget *icon = gtk_button_get_image(GTK_BUTTON(widget));
562     gtk_widget_destroy(icon);
563 harbaum 249 context->appdata->espeak.enabled = !context->appdata->espeak.enabled;
564 harbaum 246 gtk_button_set_image(GTK_BUTTON(widget), icon_get_widget(ICON_MISC,
565 harbaum 249 context->appdata->espeak.enabled?6:7));
566    
567     espeak_enable(context, context->appdata->espeak.enabled);
568 harbaum 246 }
569     #endif
570    
571 harbaum 282 /* create "goto" tab */
572 harbaum 1 GtkWidget *goto_cache(cache_context_t *context) {
573     int i;
574    
575     /* clear list used for averaging */
576     for(i=0;i<MAX_AVERAGE;i++)
577     context->gotoc.head_avg[i] = NAN;
578    
579     context->gotoc.pos = gpx_cache_pos(context->cache);
580    
581 harbaum 229 GtkWidget *hbox = gtk_hbox_new(FALSE, 32);
582 harbaum 1
583     context->gotoc.compass_area = gtk_drawing_area_new();
584     gtk_drawing_area_size(GTK_DRAWING_AREA(context->gotoc.compass_area),
585     COMPASS_SIZE, COMPASS_SIZE);
586    
587     gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area), "expose_event",
588     (GtkSignalFunc)compass_expose_event, context);
589     gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area),"configure_event",
590     (GtkSignalFunc)compass_configure_event, context);
591     gtk_signal_connect(GTK_OBJECT(context->gotoc.compass_area),
592     "button_press_event",
593     (GtkSignalFunc)compass_clicked_event, context);
594    
595     gtk_widget_set_events(context->gotoc.compass_area, GDK_EXPOSURE_MASK);
596     gtk_widget_add_events(context->gotoc.compass_area, GDK_BUTTON_PRESS_MASK);
597     gtk_box_pack_start_defaults(GTK_BOX(hbox), context->gotoc.compass_area);
598    
599     GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
600 harbaum 214 GtkWidget *table = gtk_table_new(5, 3, FALSE);
601 harbaum 1
602 harbaum 214 /* ---------- destination coordinates ------- */
603 harbaum 1
604 harbaum 214 /* SIZE_SMALL doesn't work here as setting the label returns to normal */
605     gtk_table_attach_defaults(GTK_TABLE(table), left_label_new(_("Latitude:")), 0,1,0,1);
606     context->gotoc.lat_entry = lat_entry_new(context->gotoc.pos.lat);
607     gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.lat_entry, 1,2,0,1);
608     gtk_table_attach_defaults(GTK_TABLE(table), left_label_new(_("Longitude:")), 0,1,1,2);
609     context->gotoc.lon_entry = lon_entry_new(context->gotoc.pos.lon);
610     gtk_table_attach_defaults(GTK_TABLE(table), context->gotoc.lon_entry, 1,2,1,2);
611 harbaum 1
612 harbaum 214 g_signal_connect(G_OBJECT(context->gotoc.lat_entry), "changed",
613     G_CALLBACK(pos_modified), context);
614     g_signal_connect(G_OBJECT(context->gotoc.lon_entry), "changed",
615     G_CALLBACK(pos_modified), context);
616 harbaum 1
617 harbaum 231 gtk_table_attach_defaults(GTK_TABLE(table), preset_coordinate_picker(context->appdata,
618     context->gotoc.lat_entry, context->gotoc.lon_entry), 2,3,0,1);
619 harbaum 1
620 harbaum 231 gtk_table_attach_defaults(GTK_TABLE(table), goto_coordinate(context->appdata,
621     context->gotoc.lat_entry, context->gotoc.lon_entry), 2,3,1,2);
622    
623 harbaum 214 gtk_table_set_row_spacing(GTK_TABLE(table), 1, 16);
624     gtk_table_set_col_spacing(GTK_TABLE(table), 0, 16);
625 harbaum 1
626     /* -------------- distance label ------------------------- */
627 harbaum 214 gtk_table_attach_defaults(GTK_TABLE(table), left_label_new(_("Distance:")), 0,1,2,3);
628 harbaum 1 gtk_table_attach_defaults(GTK_TABLE(table),
629 harbaum 233 (context->gotoc.distance_label = gtk_label_new("-----")), 1,2,2,3);
630 harbaum 1
631     /* -------------- bearing label ------------------------- */
632 harbaum 214 gtk_table_attach_defaults(GTK_TABLE(table), left_label_new(_("Bearing:")), 0,1,3,4);
633 harbaum 1 gtk_table_attach_defaults(GTK_TABLE(table),
634 harbaum 233 (context->gotoc.bearing_label = gtk_label_new("-----")), 1,2,3,4);
635 harbaum 1
636     /* -------------- error label ------------------------- */
637 harbaum 214 gtk_table_attach_defaults(GTK_TABLE(table), left_label_new(_("Est. error:")), 0,1,4,5);
638 harbaum 1 gtk_table_attach_defaults(GTK_TABLE(table),
639 harbaum 233 (context->gotoc.eph_label = gtk_label_new("-----")), 1,2,4,5);
640 harbaum 1
641 harbaum 214 gtk_table_set_row_spacing(GTK_TABLE(table), 4, 16);
642 harbaum 1
643     /* -------------- sat view box ------------------------- */
644     GtkWidget *ihbox = gtk_hbox_new(FALSE,0);
645    
646     context->gotoc.sat_area = gtk_drawing_area_new();
647     gtk_drawing_area_size(GTK_DRAWING_AREA(context->gotoc.sat_area),
648     SAT_WIDTH, SAT_HEIGHT);
649    
650     gtk_signal_connect(GTK_OBJECT(context->gotoc.sat_area), "expose_event",
651     (GtkSignalFunc)sat_expose_event, context);
652     gtk_signal_connect(GTK_OBJECT(context->gotoc.sat_area),"configure_event",
653     (GtkSignalFunc)sat_configure_event, context);
654    
655     gtk_widget_set_events(context->gotoc.sat_area, GDK_EXPOSURE_MASK);
656    
657     gtk_box_pack_start(GTK_BOX(ihbox), context->gotoc.sat_area, 1,0,0);
658    
659 harbaum 246 #ifdef ESPEAK
660     GtkWidget *ivbox = gtk_vbox_new(FALSE, 0);
661     GtkWidget *button = button_new();
662     gtk_button_set_image(GTK_BUTTON(button), icon_get_widget(ICON_MISC,
663     context->appdata->espeak.enabled?6:7));
664     gtk_signal_connect (GTK_OBJECT(button), "clicked",
665 harbaum 249 GTK_SIGNAL_FUNC(espeak_clicked), context);
666 harbaum 246 if(context->appdata->espeak.sample_rate < 0)
667     gtk_widget_set_sensitive(button, FALSE);
668 harbaum 249 else
669     if(context->appdata->espeak.enabled)
670     espeak_enable(context, TRUE);
671 harbaum 246
672     gtk_box_pack_start(GTK_BOX(ivbox), button, 1,0,0);
673     gtk_box_pack_start(GTK_BOX(ihbox), ivbox, 1,0,0);
674     #endif
675    
676 harbaum 214 gtk_table_attach_defaults(GTK_TABLE(table), ihbox, 0,3,5,6);
677 harbaum 1
678     /* ------------------------------------------------------- */
679    
680 harbaum 229 gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, FALSE, 0);
681     gtk_box_pack_start(GTK_BOX(hbox), vbox, TRUE, TRUE, 0);
682 harbaum 1
683 harbaum 214 context->gotoc.handler_id =
684     gtk_timeout_add(UPDATE_MS, goto_update, context);
685 harbaum 1
686     return hbox;
687     }
688    
689     void goto_coordinate_update(cache_context_t *context) {
690 harbaum 214 static pos_t pos = { 0.0, 0.0 };
691    
692 harbaum 1 if(!context->notes.modified)
693     return;
694 harbaum 214
695     pos_t npos = notes_get_pos(context);
696     if(pos_differ(&npos, &pos)) {
697     pos = npos;
698    
699 harbaum 221 lat_entry_set(context->gotoc.lat_entry, npos.lat);
700     lon_entry_set(context->gotoc.lon_entry, npos.lon);
701 harbaum 214 }
702 harbaum 1 }