Contents of /trunk/src/goto.c

Parent Directory Parent Directory | Revision Log Revision Log


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