Contents of /trunk/src/osm-gps-map-osd-classic.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 107 - (hide annotations)
Fri Sep 11 12:16:50 2009 UTC (14 years, 7 months ago) by harbaum
File MIME type: text/plain
File size: 39957 byte(s)
OSD coordinates
1 harbaum 71 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
2     /* vim:set et sw=4 ts=4 cino=t0,(0: */
3 harbaum 70 /*
4     * Copyright (C) Till Harbaum 2009 <till@harbaum.org>
5     *
6     * osm-gps-map is free software: you can redistribute it and/or modify it
7     * under the terms of the GNU General Public License as published by the
8     * Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * osm-gps-map is distributed in the hope that it will be useful, but
12     * WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14     * See the GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License along
17     * with this program. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20 harbaum 73 #include "config.h"
21     #include <stdlib.h> // abs
22 harbaum 87 #include <math.h> // M_PI/cos()
23 harbaum 70
24 harbaum 71 /* parameters that can be overwritten from the config file: */
25 harbaum 77 /* OSD_DIAMETER */
26     /* OSD_X, OSD_Y */
27 harbaum 71
28     #ifndef USE_CAIRO
29     #error "OSD control display lacks a non-cairo implementation!"
30 harbaum 70 #endif
31    
32 harbaum 71 #include <cairo.h>
33    
34     #include "osm-gps-map.h"
35 harbaum 73 #include "osm-gps-map-osd-classic.h"
36 harbaum 71
37 harbaum 70 //the osd controls
38     typedef struct {
39 harbaum 74 /* the offscreen representation of the OSD */
40     cairo_surface_t *overlay;
41 harbaum 86
42 harbaum 98 #ifdef OSD_SCALE
43     cairo_surface_t *scale;
44 harbaum 103 int scale_zoom;
45 harbaum 98 #endif
46    
47 harbaum 105 #ifdef OSD_CROSSHAIR
48     cairo_surface_t *crosshair;
49     #endif
50    
51 harbaum 106 #ifdef OSD_COORDINATES
52     cairo_surface_t *coordinates;
53     #endif
54    
55 harbaum 88 #ifdef OSD_SOURCE_SEL
56 harbaum 87 /* values to handle the "source" menu */
57 harbaum 86 cairo_surface_t *map_source;
58     gboolean expanded;
59     gint shift, dir, count;
60     gint handler_id;
61 harbaum 87 gint width, height;
62 harbaum 88 #endif
63 harbaum 87
64 harbaum 70 } osd_priv_t;
65    
66     /* position and extent of bounding box */
67 harbaum 77 #ifndef OSD_X
68 harbaum 70 #define OSD_X (10)
69 harbaum 77 #endif
70    
71     #ifndef OSD_Y
72 harbaum 70 #define OSD_Y (10)
73 harbaum 77 #endif
74 harbaum 70
75     /* parameters of the direction shape */
76 harbaum 77 #ifndef OSD_DIAMETER
77 harbaum 70 #define D_RAD (30) // diameter of dpad
78     #else
79 harbaum 77 #define D_RAD (OSD_DIAMETER)
80 harbaum 70 #endif
81     #define D_TIP (4*D_RAD/5) // distance of arrow tip from dpad center
82     #define D_LEN (D_RAD/4) // length of arrow
83     #define D_WID (D_LEN) // width of arrow
84    
85     /* parameters of the "zoom" pad */
86     #define Z_STEP (D_RAD/4) // distance between dpad and zoom
87     #define Z_RAD (D_RAD/2) // radius of "caps" of zoom bar
88    
89 harbaum 74 #ifdef OSD_SHADOW_ENABLE
90 harbaum 70 /* shadow also depends on control size */
91     #define OSD_SHADOW (D_RAD/6)
92 harbaum 74 #else
93     #define OSD_SHADOW (0)
94     #endif
95 harbaum 70
96 harbaum 77 /* normally the GPS button is in the center of the dpad. if there's */
97     /* no dpad it will go into the zoom area */
98     #if defined(OSD_GPS_BUTTON) && defined(OSD_NO_DPAD)
99     #define Z_GPS 1
100     #else
101     #define Z_GPS 0
102     #endif
103    
104 harbaum 70 /* total width and height of controls incl. shadow */
105 harbaum 77 #define OSD_W (2*D_RAD + OSD_SHADOW + Z_GPS * 2 * Z_RAD)
106     #if !Z_GPS
107 harbaum 70 #define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)
108 harbaum 77 #else
109     #define OSD_H (2*Z_RAD + OSD_SHADOW)
110     #endif
111 harbaum 70
112 harbaum 74 #ifdef OSD_SHADOW_ENABLE
113 harbaum 70 #define OSD_LBL_SHADOW (OSD_SHADOW/2)
114 harbaum 74 #endif
115 harbaum 70
116 harbaum 77 #define Z_TOP ((1-Z_GPS) * (2 * D_RAD + Z_STEP))
117    
118 harbaum 70 #define Z_MID (Z_TOP + Z_RAD)
119     #define Z_BOT (Z_MID + Z_RAD)
120     #define Z_LEFT (Z_RAD)
121 harbaum 77 #define Z_RIGHT (2 * D_RAD - Z_RAD + Z_GPS * 2 * Z_RAD)
122     #define Z_CENTER ((Z_RIGHT + Z_LEFT)/2)
123 harbaum 70
124     /* create the cairo shape used for the zoom buttons */
125     static void
126 harbaum 86 osd_zoom_shape(cairo_t *cr, gint x, gint y)
127 harbaum 71 {
128 harbaum 70 cairo_move_to (cr, x+Z_LEFT, y+Z_TOP);
129     cairo_line_to (cr, x+Z_RIGHT, y+Z_TOP);
130     cairo_arc (cr, x+Z_RIGHT, y+Z_MID, Z_RAD, -M_PI/2, M_PI/2);
131     cairo_line_to (cr, x+Z_LEFT, y+Z_BOT);
132     cairo_arc (cr, x+Z_LEFT, y+Z_MID, Z_RAD, M_PI/2, -M_PI/2);
133     }
134    
135 harbaum 86 /* ------------------- color/shadow functions ----------------- */
136    
137     #ifndef OSD_COLOR
138     /* if no color has been specified we just use the gdks default colors */
139     static void
140     osd_labels(cairo_t *cr, gint width, gboolean enabled,
141     GdkColor *fg, GdkColor *disabled) {
142     if(enabled) gdk_cairo_set_source_color(cr, fg);
143     else gdk_cairo_set_source_color(cr, disabled);
144     cairo_set_line_width (cr, width);
145     }
146     #else
147     static void
148     osd_labels(cairo_t *cr, gint width, gboolean enabled) {
149     if(enabled) cairo_set_source_rgb (cr, OSD_COLOR);
150     else cairo_set_source_rgb (cr, OSD_COLOR_DISABLED);
151     cairo_set_line_width (cr, width);
152     }
153     #endif
154    
155     #ifdef OSD_SHADOW_ENABLE
156     static void
157     osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) {
158     cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15);
159     cairo_set_line_width (cr, width);
160     }
161     #endif
162    
163 harbaum 76 #ifndef OSD_NO_DPAD
164 harbaum 70 /* create the cairo shape used for the dpad */
165     static void
166 harbaum 86 osd_dpad_shape(cairo_t *cr, gint x, gint y)
167 harbaum 71 {
168 harbaum 70 cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);
169     }
170 harbaum 76 #endif
171 harbaum 70
172 harbaum 86 #ifdef OSD_SHADOW_ENABLE
173     static void
174     osd_shape_shadow(cairo_t *cr) {
175     cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
176     cairo_fill (cr);
177     cairo_stroke (cr);
178     }
179     #endif
180    
181     #ifndef OSD_COLOR
182     /* if no color has been specified we just use the gdks default colors */
183     static void
184     osd_shape(cairo_t *cr, GdkColor *bg, GdkColor *fg) {
185     gdk_cairo_set_source_color(cr, bg);
186     cairo_fill_preserve (cr);
187     gdk_cairo_set_source_color(cr, fg);
188     cairo_set_line_width (cr, 1);
189     cairo_stroke (cr);
190     }
191     #else
192     static void
193     osd_shape(cairo_t *cr) {
194     cairo_set_source_rgb (cr, OSD_COLOR_BG);
195     cairo_fill_preserve (cr);
196     cairo_set_source_rgb (cr, OSD_COLOR);
197     cairo_set_line_width (cr, 1);
198     cairo_stroke (cr);
199     }
200     #endif
201    
202    
203 harbaum 70 static gboolean
204     osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)
205     {
206     return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);
207     }
208    
209 harbaum 76 #ifndef OSD_NO_DPAD
210 harbaum 70 /* check whether x/y is within the dpad */
211     static osd_button_t
212 harbaum 86 osd_check_dpad(gint x, gint y)
213 harbaum 70 {
214     /* within entire dpad circle */
215 harbaum 77 if( osm_gps_map_in_circle(x, y, D_RAD, D_RAD, D_RAD))
216 harbaum 70 {
217     /* convert into position relative to dpads centre */
218 harbaum 77 x -= D_RAD;
219     y -= D_RAD;
220 harbaum 70
221 harbaum 76 #ifdef OSD_GPS_BUTTON
222 harbaum 70 /* check for dpad center goes here! */
223     if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3))
224     return OSD_GPS;
225 harbaum 76 #endif
226 harbaum 70
227     if( y < 0 && abs(x) < abs(y))
228     return OSD_UP;
229    
230     if( y > 0 && abs(x) < abs(y))
231     return OSD_DOWN;
232    
233     if( x < 0 && abs(y) < abs(x))
234     return OSD_LEFT;
235    
236     if( x > 0 && abs(y) < abs(x))
237     return OSD_RIGHT;
238    
239     return OSD_BG;
240     }
241     return OSD_NONE;
242     }
243 harbaum 76 #endif
244 harbaum 70
245     /* check whether x/y is within the zoom pads */
246     static osd_button_t
247 harbaum 86 osd_check_zoom(gint x, gint y) {
248 harbaum 77 if( x > 0 && x < OSD_W && y > Z_TOP && y < Z_BOT) {
249 harbaum 70
250     /* within circle around (-) label */
251 harbaum 77 if( osm_gps_map_in_circle(x, y, Z_LEFT, Z_MID, Z_RAD))
252 harbaum 70 return OSD_OUT;
253    
254 harbaum 77 /* within circle around (+) label */
255     if( osm_gps_map_in_circle(x, y, Z_RIGHT, Z_MID, Z_RAD))
256     return OSD_IN;
257    
258     #if Z_GPS == 1
259     /* within square around center */
260     if( x > Z_CENTER - Z_RAD && x < Z_CENTER + Z_RAD)
261     return OSD_GPS;
262     #endif
263    
264 harbaum 70 /* between center of (-) button and center of entire zoom control area */
265 harbaum 77 if(x > OSD_LEFT && x < D_RAD)
266 harbaum 70 return OSD_OUT;
267    
268     /* between center of (+) button and center of entire zoom control area */
269 harbaum 77 if(x < OSD_RIGHT && x > D_RAD)
270 harbaum 70 return OSD_IN;
271     }
272    
273     return OSD_NONE;
274     }
275    
276 harbaum 88 #ifdef OSD_SOURCE_SEL
277    
278 harbaum 86 /* place source selection at right border */
279     #define OSD_S_RAD (Z_RAD)
280     #define OSD_S_X (-OSD_X)
281     #define OSD_S_Y (OSD_Y)
282     #define OSD_S_PW (2 * Z_RAD)
283     #define OSD_S_W (OSD_S_PW)
284     #define OSD_S_PH (2 * Z_RAD)
285     #define OSD_S_H (OSD_S_PH + OSD_SHADOW)
286    
287 harbaum 87 /* size of usable area when expanded */
288     #define OSD_S_AREA_W (priv->width)
289     #define OSD_S_AREA_H (priv->height)
290 harbaum 86 #define OSD_S_EXP_W (OSD_S_PW + OSD_S_AREA_W + OSD_SHADOW)
291     #define OSD_S_EXP_H (OSD_S_AREA_H + OSD_SHADOW)
292    
293     /* internal value to draw the arrow on the "puller" */
294     #define OSD_S_D0 (OSD_S_RAD/2)
295 harbaum 87 #ifndef OSD_FONT_SIZE
296     #define OSD_FONT_SIZE 16.0
297     #endif
298     #define OSD_TEXT_BORDER (OSD_FONT_SIZE/2)
299     #define OSD_TEXT_SKIP (OSD_FONT_SIZE/8)
300 harbaum 86
301 harbaum 88 /* draw the shape of the source selection OSD, either only the puller (not expanded) */
302     /* or the entire menu incl. the puller (expanded) */
303 harbaum 86 static void
304     osd_source_shape(osd_priv_t *priv, cairo_t *cr, gint x, gint y) {
305     if(!priv->expanded) {
306     /* just draw the puller */
307     cairo_move_to (cr, x + OSD_S_PW, y + OSD_S_PH);
308     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
309     cairo_line_to (cr, x + OSD_S_PW, y);
310     } else {
311     /* draw the puller and the area itself */
312     cairo_move_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y + OSD_S_AREA_H);
313     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H);
314     if(OSD_S_Y > 0) {
315     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_PH);
316     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
317     } else {
318     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_AREA_H-OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
319     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H - OSD_S_PH);
320     cairo_line_to (cr, x + OSD_S_PW, y);
321     }
322     cairo_line_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y);
323     cairo_close_path (cr);
324     }
325     }
326    
327     static void
328 harbaum 87 osd_source_content(osm_gps_map_osd_t *osd, cairo_t *cr, gint offset) {
329     osd_priv_t *priv = (osd_priv_t*)osd->priv;
330 harbaum 86
331 harbaum 87 int py = offset + OSD_S_RAD - OSD_S_D0;
332    
333 harbaum 86 if(!priv->expanded) {
334     /* draw the "puller" open (<) arrow */
335 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD + OSD_S_D0/2, py);
336 harbaum 86 cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
337     cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
338     } else {
339     if(OSD_S_Y < 0)
340 harbaum 87 py += OSD_S_AREA_H - OSD_S_PH;
341 harbaum 86
342     /* draw the "puller" close (>) arrow */
343 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD - OSD_S_D0/2, py);
344 harbaum 86 cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
345     cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
346 harbaum 87 cairo_stroke(cr);
347    
348     /* don't draw a shadow for the text content */
349     if(offset == 1) {
350     gint source;
351     g_object_get(osd->widget, "map-source", &source, NULL);
352    
353     cairo_select_font_face (cr, "Sans",
354     CAIRO_FONT_SLANT_NORMAL,
355     CAIRO_FONT_WEIGHT_BOLD);
356     cairo_set_font_size (cr, OSD_FONT_SIZE);
357    
358 harbaum 89 int i, step = (priv->height - 2*OSD_TEXT_BORDER) /
359     OSM_GPS_MAP_SOURCE_LAST;
360 harbaum 87 for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
361     cairo_text_extents_t extents;
362     const char *src = osm_gps_map_source_get_friendly_name(i);
363     cairo_text_extents (cr, src, &extents);
364    
365     int x = offset + OSD_S_PW + OSD_TEXT_BORDER;
366     int y = offset + step * (i-1) + OSD_TEXT_BORDER;
367    
368     /* draw filled rectangle if selected */
369     if(source == i) {
370     cairo_rectangle(cr, x - OSD_TEXT_BORDER/2,
371     y - OSD_TEXT_SKIP,
372     priv->width - OSD_TEXT_BORDER,
373     step + OSD_TEXT_SKIP);
374     cairo_fill(cr);
375    
376     /* temprarily draw with background color */
377     #ifndef OSD_COLOR
378     GdkColor bg = osd->widget->style->bg[GTK_STATE_NORMAL];
379     gdk_cairo_set_source_color(cr, &bg);
380     #else
381     cairo_set_source_rgb (cr, OSD_COLOR_BG);
382     #endif
383     }
384    
385     cairo_move_to (cr, x, y + OSD_TEXT_SKIP - extents.y_bearing);
386     cairo_show_text (cr, src);
387    
388     /* restore color */
389     if(source == i) {
390     #ifndef OSD_COLOR
391     GdkColor fg = osd->widget->style->fg[GTK_STATE_NORMAL];
392     gdk_cairo_set_source_color(cr, &fg);
393     #else
394     cairo_set_source_rgb (cr, OSD_COLOR);
395     #endif
396     }
397     }
398     }
399 harbaum 86 }
400     }
401    
402     static void
403     osd_render_source_sel(osm_gps_map_osd_t *osd) {
404     osd_priv_t *priv = (osd_priv_t*)osd->priv;
405    
406     #ifndef OSD_COLOR
407     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
408     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
409     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
410     #endif
411    
412     /* draw source selector */
413     cairo_t *cr = cairo_create(priv->map_source);
414     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
415     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
416     cairo_paint(cr);
417     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
418    
419     #ifdef OSD_SHADOW_ENABLE
420     osd_source_shape(priv, cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
421     osd_shape_shadow(cr);
422     #endif
423    
424     osd_source_shape(priv, cr, 1, 1);
425     #ifndef OSD_COLOR
426     osd_shape(cr, &bg, &fg);
427     #else
428     osd_shape(cr);
429     #endif
430    
431     #ifdef OSD_SHADOW_ENABLE
432     osd_labels_shadow(cr, Z_RAD/3, TRUE);
433 harbaum 87 osd_source_content(osd, cr, 1+OSD_LBL_SHADOW);
434     cairo_stroke (cr);
435 harbaum 86 #endif
436     #ifndef OSD_COLOR
437     osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
438     #else
439     osd_labels(cr, Z_RAD/3, TRUE);
440     #endif
441 harbaum 87 osd_source_content(osd, cr, 1);
442     cairo_stroke (cr);
443 harbaum 86
444     cairo_destroy(cr);
445     }
446    
447 harbaum 89 /* re-allocate the buffer used to draw the menu. This is used */
448     /* to collapse/expand the buffer */
449 harbaum 86 static void
450     osd_source_reallocate(osm_gps_map_osd_t *osd) {
451     osd_priv_t *priv = (osd_priv_t*)osd->priv;
452    
453     /* re-allocate offscreen bitmap */
454     g_assert (priv->map_source);
455    
456     int w = OSD_S_W, h = OSD_S_H;
457     if(priv->expanded) {
458 harbaum 87 cairo_text_extents_t extents;
459    
460     /* determine content size */
461     cairo_t *cr = cairo_create(priv->map_source);
462     cairo_select_font_face (cr, "Sans",
463     CAIRO_FONT_SLANT_NORMAL,
464     CAIRO_FONT_WEIGHT_BOLD);
465     cairo_set_font_size (cr, OSD_FONT_SIZE);
466    
467     /* calculate menu size */
468     int i, max_h = 0, max_w = 0;
469     for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
470     const char *src = osm_gps_map_source_get_friendly_name(i);
471     cairo_text_extents (cr, src, &extents);
472    
473     if(extents.width > max_w) max_w = extents.width;
474     if(extents.height > max_h) max_h = extents.height;
475     }
476     cairo_destroy(cr);
477    
478     priv->width = max_w + 2*OSD_TEXT_BORDER;
479     priv->height = OSM_GPS_MAP_SOURCE_LAST *
480     (max_h + 2*OSD_TEXT_SKIP) + 2*OSD_TEXT_BORDER;
481    
482 harbaum 86 w = OSD_S_EXP_W;
483     h = OSD_S_EXP_H;
484     }
485    
486 harbaum 87 cairo_surface_destroy(priv->map_source);
487 harbaum 86 priv->map_source =
488     cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w+2, h+2);
489    
490     osd_render_source_sel(osd);
491     }
492    
493     #define OSD_HZ 15
494 harbaum 87 #define OSD_TIME 500
495 harbaum 86
496     static gboolean osd_source_animate(gpointer data) {
497     osm_gps_map_osd_t *osd = (osm_gps_map_osd_t*)data;
498     osd_priv_t *priv = (osd_priv_t*)osd->priv;
499     int diff = OSD_S_EXP_W - OSD_S_W - OSD_S_X;
500     gboolean done = FALSE;
501     priv->count += priv->dir;
502    
503     /* shifting in */
504     if(priv->dir < 0) {
505     if(priv->count <= 0) {
506     priv->count = 0;
507     done = TRUE;
508     }
509     } else {
510     if(priv->count >= 1000) {
511     priv->expanded = FALSE;
512     osd_source_reallocate(osd);
513    
514     priv->count = 1000;
515     done = TRUE;
516     }
517     }
518    
519    
520     /* count runs linearly from 0 to 1000, map this nicely onto a position */
521    
522     /* nicer sinoid mapping */
523     float m = 0.5-cos(priv->count * M_PI / 1000.0)/2;
524     priv->shift = (osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X) +
525     m * diff;
526    
527     osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
528    
529     if(done)
530     priv->handler_id = 0;
531    
532     return !done;
533     }
534    
535     /* switch between expand and collapse mode of source selection */
536     static void
537     osd_source_toggle(osm_gps_map_osd_t *osd)
538     {
539     osd_priv_t *priv = (osd_priv_t*)osd->priv;
540    
541     /* ignore clicks while animation is running */
542     if(priv->handler_id)
543     return;
544    
545     /* expand immediately, collapse is handle at the end of the collapse animation */
546     if(!priv->expanded) {
547     priv->expanded = TRUE;
548     osd_source_reallocate(osd);
549    
550     priv->count = 1000;
551     priv->shift = osd->widget->allocation.width - OSD_S_W;
552     priv->dir = -1000/OSD_HZ;
553     } else {
554     priv->count = 0;
555     priv->shift = osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
556     priv->dir = +1000/OSD_HZ;
557     }
558    
559     priv->handler_id = gtk_timeout_add(OSD_TIME/OSD_HZ, osd_source_animate, osd);
560     }
561    
562 harbaum 89 /* check if the user clicked inside the source selection area */
563 harbaum 70 static osd_button_t
564 harbaum 86 osd_source_check(osm_gps_map_osd_t *osd, gint x, gint y) {
565     osd_priv_t *priv = (osd_priv_t*)osd->priv;
566    
567     if(!priv->expanded)
568     x -= osd->widget->allocation.width - OSD_S_W;
569     else
570     x -= osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
571    
572     if(OSD_S_Y > 0)
573     y -= OSD_S_Y;
574     else
575     y -= osd->widget->allocation.height - OSD_S_PH + OSD_S_Y;
576    
577     /* within square around puller? */
578     if(y > 0 && y < OSD_S_PH && x > 0 && x < OSD_S_PW) {
579     /* really within puller shape? */
580     if(x > Z_RAD || osm_gps_map_in_circle(x, y, Z_RAD, Z_RAD, Z_RAD)) {
581     /* expand source selector */
582     osd_source_toggle(osd);
583    
584     /* tell upper layers that user clicked some background element */
585     /* of the OSD */
586     return OSD_BG;
587     }
588     }
589 harbaum 88
590     /* check for clicks into data area */
591 harbaum 89 if(priv->expanded && !priv->handler_id) {
592 harbaum 94 /* re-adjust from puller top to content top */
593     if(OSD_S_Y < 0)
594     y += OSD_S_EXP_H - OSD_S_PH;
595    
596 harbaum 88 if(x > OSD_S_PW &&
597     x < OSD_S_PW + OSD_S_EXP_W &&
598     y > 0 &&
599     y < OSD_S_EXP_H) {
600 harbaum 94
601 harbaum 89 int step = (priv->height - 2*OSD_TEXT_BORDER)
602     / OSM_GPS_MAP_SOURCE_LAST;
603 harbaum 88
604 harbaum 89 y -= OSD_TEXT_BORDER - OSD_TEXT_SKIP;
605     y /= step;
606     y += 1;
607    
608     gint old = 0;
609     g_object_get(osd->widget, "map-source", &old, NULL);
610    
611     if(y > OSM_GPS_MAP_SOURCE_NULL &&
612     y <= OSM_GPS_MAP_SOURCE_LAST &&
613     old != y) {
614     g_object_set(osd->widget, "map-source", y, NULL);
615    
616     osd_render_source_sel(osd);
617     osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
618     }
619    
620     /* return "clicked in OSD background" to prevent further */
621     /* processing by application */
622 harbaum 88 return OSD_BG;
623     }
624     }
625    
626 harbaum 86 return OSD_NONE;
627     }
628 harbaum 88 #endif // OSD_SOURCE_SEL
629 harbaum 86
630     static osd_button_t
631     osd_check(osm_gps_map_osd_t *osd, gint x, gint y) {
632 harbaum 70 osd_button_t but = OSD_NONE;
633    
634 harbaum 86 #ifdef OSD_SOURCE_SEL
635     /* the source selection area is handles internally */
636     but = osd_source_check(osd, x, y);
637     if(but != OSD_NONE)
638     return but;
639     #endif
640    
641 harbaum 77 x -= OSD_X;
642     y -= OSD_Y;
643    
644     if(OSD_X < 0)
645     x -= (osd->widget->allocation.width - OSD_W);
646    
647     if(OSD_Y < 0)
648     y -= (osd->widget->allocation.height - OSD_H);
649    
650 harbaum 70 /* first do a rough test for the OSD area. */
651     /* this is just to avoid an unnecessary detailed test */
652 harbaum 77 if(x > 0 && x < OSD_W && y > 0 && y < OSD_H) {
653 harbaum 76 #ifndef OSD_NO_DPAD
654 harbaum 86 but = osd_check_dpad(x, y);
655 harbaum 76 #endif
656 harbaum 70
657     if(but == OSD_NONE)
658 harbaum 86 but = osd_check_zoom(x, y);
659 harbaum 70 }
660    
661     return but;
662     }
663    
664 harbaum 76 #ifndef OSD_NO_DPAD
665 harbaum 70 static void
666 harbaum 86 osd_dpad_labels(cairo_t *cr, gint x, gint y) {
667 harbaum 70 /* move reference to dpad center */
668     x += D_RAD;
669     y += D_RAD;
670    
671     const static gint offset[][3][2] = {
672     /* left arrow/triangle */
673     { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } },
674     /* right arrow/triangle */
675     { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } },
676     /* top arrow/triangle */
677     { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } },
678     /* bottom arrow/triangle */
679     { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } }
680     };
681    
682     int i;
683     for(i=0;i<4;i++) {
684     cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]);
685     cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]);
686     cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]);
687     }
688     }
689 harbaum 76 #endif
690 harbaum 70
691 harbaum 76 #ifdef OSD_GPS_BUTTON
692     /* draw the satellite dish icon in the center of the dpad */
693 harbaum 77 #define GPS_V0 (D_RAD/7)
694 harbaum 70 #define GPS_V1 (D_RAD/10)
695     #define GPS_V2 (D_RAD/5)
696    
697     /* draw a satellite receiver dish */
698 harbaum 77 /* this is either drawn in the center of the dpad (if present) */
699     /* or in the middle of the zoom area */
700 harbaum 70 static void
701 harbaum 86 osd_dpad_gps(cairo_t *cr, gint x, gint y) {
702 harbaum 70 /* move reference to dpad center */
703 harbaum 77 x += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD * 3;
704     y += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD + GPS_V0;
705 harbaum 70
706     cairo_move_to (cr, x-GPS_V0, y+GPS_V0);
707     cairo_rel_line_to (cr, +GPS_V0, -GPS_V0);
708     cairo_rel_line_to (cr, +GPS_V0, +GPS_V0);
709     cairo_close_path (cr);
710    
711     cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2);
712     cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y);
713     cairo_close_path (cr);
714    
715     x += GPS_V1;
716     cairo_move_to (cr, x, y-GPS_V2);
717     cairo_rel_line_to (cr, +GPS_V1, -GPS_V1);
718     }
719 harbaum 76 #endif
720 harbaum 70
721     #define Z_LEN (2*Z_RAD/3)
722    
723     static void
724 harbaum 86 osd_zoom_labels(cairo_t *cr, gint x, gint y) {
725 harbaum 70 cairo_move_to (cr, x + Z_LEFT - Z_LEN, y + Z_MID);
726     cairo_line_to (cr, x + Z_LEFT + Z_LEN, y + Z_MID);
727    
728     cairo_move_to (cr, x + Z_RIGHT, y + Z_MID - Z_LEN);
729     cairo_line_to (cr, x + Z_RIGHT, y + Z_MID + Z_LEN);
730     cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID);
731     cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID);
732     }
733    
734 harbaum 106 #ifdef OSD_COORDINATES
735    
736 harbaum 107 #ifndef OSD_COORDINATES_FONT_SIZE
737     #define OSD_COORDINATES_FONT_SIZE 12
738     #endif
739    
740     #define OSD_COORDINATES_W (9*OSD_COORDINATES_FONT_SIZE)
741     #define OSD_COORDINATES_H (2*OSD_COORDINATES_FONT_SIZE)
742    
743     /* these can be overwritten with versions that support */
744     /* localization */
745     #ifndef OSD_COORDINATES_CHR_N
746     #define OSD_COORDINATES_CHR_N "N"
747     #endif
748     #ifndef OSD_COORDINATES_CHR_S
749     #define OSD_COORDINATES_CHR_S "S"
750     #endif
751     #ifndef OSD_COORDINATES_CHR_E
752     #define OSD_COORDINATES_CHR_E "E"
753     #endif
754     #ifndef OSD_COORDINATES_CHR_W
755     #define OSD_COORDINATES_CHR_W "W"
756     #endif
757    
758    
759    
760     /* this is the classic geocaching notation */
761     static char
762     *osd_latitude_str(float latitude) {
763     char *c = OSD_COORDINATES_CHR_N;
764     float integral, fractional;
765    
766     if(isnan(latitude))
767     return NULL;
768    
769     if(latitude < 0) {
770     latitude = fabs(latitude);
771     c = OSD_COORDINATES_CHR_S;
772     }
773    
774     fractional = modff(latitude, &integral);
775    
776     return g_strdup_printf("%s %02d° %06.3f'",
777     c, (int)integral, fractional*60.0);
778     }
779    
780     static char
781     *osd_longitude_str(float longitude) {
782     char *c = OSD_COORDINATES_CHR_E;
783     float integral, fractional;
784    
785     if(isnan(longitude))
786     return NULL;
787    
788     if(longitude < 0) {
789     longitude = fabs(longitude);
790     c = OSD_COORDINATES_CHR_W;
791     }
792    
793     fractional = modff(longitude, &integral);
794    
795     return g_strdup_printf("%s %03d° %06.3f'",
796     c, (int)integral, fractional*60.0);
797     }
798    
799     #define OSD_COORDINATES_OFFSET (OSD_COORDINATES_FONT_SIZE/6)
800    
801 harbaum 106 static void
802     osd_render_coordinates(osm_gps_map_osd_t *osd)
803     {
804     osd_priv_t *priv = (osd_priv_t*)osd->priv;
805    
806 harbaum 107 /* get current map position */
807     gfloat lat, lon;
808     g_object_get(osd->widget, "latitude", &lat, "longitude", &lon, NULL);
809    
810 harbaum 106 /* first fill with transparency */
811     cairo_t *cr = cairo_create(priv->coordinates);
812     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
813     // cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
814     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2);
815     cairo_paint(cr);
816     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
817    
818 harbaum 107 cairo_select_font_face (cr, "Sans",
819     CAIRO_FONT_SLANT_NORMAL,
820     CAIRO_FONT_WEIGHT_BOLD);
821     cairo_set_font_size (cr, OSD_COORDINATES_FONT_SIZE);
822    
823     char *latitude = osd_latitude_str(lat);
824     char *longitude = osd_longitude_str(lon);
825    
826     cairo_text_extents_t lat_extents, lon_extents;
827     cairo_text_extents (cr, latitude, &lat_extents);
828     cairo_text_extents (cr, longitude, &lon_extents);
829    
830     cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
831     cairo_set_line_width (cr, OSD_COORDINATES_FONT_SIZE/6);
832     cairo_move_to (cr,
833     OSD_COORDINATES_OFFSET - lat_extents.x_bearing,
834     OSD_COORDINATES_OFFSET - lat_extents.y_bearing);
835     cairo_text_path (cr, latitude);
836     cairo_move_to (cr,
837     OSD_COORDINATES_OFFSET - lon_extents.x_bearing,
838     OSD_COORDINATES_OFFSET - lon_extents.y_bearing +
839     OSD_COORDINATES_FONT_SIZE);
840     cairo_text_path (cr, longitude);
841     cairo_stroke (cr);
842    
843     cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
844     cairo_move_to (cr,
845     OSD_COORDINATES_OFFSET - lat_extents.x_bearing,
846     OSD_COORDINATES_OFFSET - lat_extents.y_bearing);
847     cairo_show_text (cr, latitude);
848     cairo_move_to (cr,
849     OSD_COORDINATES_OFFSET - lon_extents.x_bearing,
850     OSD_COORDINATES_OFFSET - lon_extents.y_bearing +
851     OSD_COORDINATES_FONT_SIZE);
852     cairo_show_text (cr, longitude);
853    
854     g_free(latitude);
855     g_free(longitude);
856    
857 harbaum 106 cairo_destroy(cr);
858     }
859     #endif // OSD_COORDINATES
860    
861 harbaum 105 #ifdef OSD_CROSSHAIR
862    
863     #ifndef OSD_CROSSHAIR_RADIUS
864 harbaum 106 #define OSD_CROSSHAIR_RADIUS 10
865 harbaum 105 #endif
866    
867 harbaum 106 #define OSD_CROSSHAIR_TICK (OSD_CROSSHAIR_RADIUS/2)
868     #define OSD_CROSSHAIR_BORDER (OSD_CROSSHAIR_TICK + OSD_CROSSHAIR_RADIUS/4)
869     #define OSD_CROSSHAIR_W ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2)
870     #define OSD_CROSSHAIR_H ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2)
871 harbaum 105
872     static void
873 harbaum 106 osd_render_crosshair_shape(cairo_t *cr) {
874     cairo_arc (cr, OSD_CROSSHAIR_W/2, OSD_CROSSHAIR_H/2,
875     OSD_CROSSHAIR_RADIUS, 0, 2*M_PI);
876    
877     cairo_move_to (cr, OSD_CROSSHAIR_W/2 - OSD_CROSSHAIR_RADIUS,
878     OSD_CROSSHAIR_H/2);
879     cairo_rel_line_to (cr, -OSD_CROSSHAIR_TICK, 0);
880     cairo_move_to (cr, OSD_CROSSHAIR_W/2 + OSD_CROSSHAIR_RADIUS,
881     OSD_CROSSHAIR_H/2);
882     cairo_rel_line_to (cr, OSD_CROSSHAIR_TICK, 0);
883    
884     cairo_move_to (cr, OSD_CROSSHAIR_W/2,
885     OSD_CROSSHAIR_H/2 - OSD_CROSSHAIR_RADIUS);
886     cairo_rel_line_to (cr, 0, -OSD_CROSSHAIR_TICK);
887     cairo_move_to (cr, OSD_CROSSHAIR_W/2,
888     OSD_CROSSHAIR_H/2 + OSD_CROSSHAIR_RADIUS);
889     cairo_rel_line_to (cr, 0, OSD_CROSSHAIR_TICK);
890    
891     cairo_stroke (cr);
892     }
893    
894     static void
895 harbaum 105 osd_render_crosshair(osm_gps_map_osd_t *osd)
896     {
897     osd_priv_t *priv = (osd_priv_t*)osd->priv;
898    
899     /* first fill with transparency */
900     cairo_t *cr = cairo_create(priv->crosshair);
901     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
902 harbaum 106 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
903     // cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2);
904 harbaum 105 cairo_paint(cr);
905     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
906    
907 harbaum 106 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
908    
909     cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5);
910     cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/2);
911     osd_render_crosshair_shape(cr);
912    
913     cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
914     cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/4);
915     osd_render_crosshair_shape(cr);
916    
917 harbaum 105 cairo_destroy(cr);
918     }
919     #endif
920    
921     #ifdef OSD_SCALE
922    
923     #ifndef OSD_SCALE_FONT_SIZE
924     #define OSD_SCALE_FONT_SIZE 12
925     #endif
926     #define OSD_SCALE_W (10*OSD_SCALE_FONT_SIZE)
927     #define OSD_SCALE_H (5*OSD_SCALE_FONT_SIZE/2)
928    
929 harbaum 103 /* various parameters used to create the scale */
930     #define OSD_SCALE_H2 (OSD_SCALE_H/2)
931     #define OSD_SCALE_TICK (2*OSD_SCALE_FONT_SIZE/3)
932     #define OSD_SCALE_M (OSD_SCALE_H2 - OSD_SCALE_TICK)
933     #define OSD_SCALE_I (OSD_SCALE_H2 + OSD_SCALE_TICK)
934     #define OSD_SCALE_FD (OSD_SCALE_FONT_SIZE/4)
935 harbaum 99
936 harbaum 70 static void
937 harbaum 98 osd_render_scale(osm_gps_map_osd_t *osd)
938     {
939 harbaum 86 osd_priv_t *priv = (osd_priv_t*)osd->priv;
940 harbaum 103
941     /* this only needs to be rendered if the zoom has changed */
942     gint zoom;
943     g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
944     if(zoom == priv->scale_zoom)
945     return;
946    
947     priv->scale_zoom = zoom;
948    
949 harbaum 99 float m_per_pix = osm_gps_map_get_scale(OSM_GPS_MAP(osd->widget));
950 harbaum 70
951 harbaum 98 /* first fill with transparency */
952     cairo_t *cr = cairo_create(priv->scale);
953     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
954 harbaum 100 cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
955 harbaum 103 // pink for testing: cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2);
956 harbaum 98 cairo_paint(cr);
957     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
958    
959     /* determine the size of the scale width in meters */
960 harbaum 103 float width = (OSD_SCALE_W-OSD_SCALE_FONT_SIZE/6) * m_per_pix;
961 harbaum 102
962 harbaum 98 /* scale this to useful values */
963     int exp = logf(width)*M_LOG10E;
964     int mant = width/pow(10,exp);
965 harbaum 99 int width_metric = mant * pow(10,exp);
966 harbaum 103 char *dist_str = NULL;
967     if(width_metric<1000)
968     dist_str = g_strdup_printf("%u m", width_metric);
969     else
970     dist_str = g_strdup_printf("%u km", width_metric/1000);
971 harbaum 99 width_metric /= m_per_pix;
972    
973 harbaum 102 /* and now the hard part: scale for useful imperial values :-( */
974     /* try to convert to feet, 1ft == 0.3048 m */
975     width /= 0.3048;
976     float imp_scale = 0.3048;
977     char *dist_imp_unit = "ft";
978 harbaum 99
979 harbaum 102 if(width >= 100) {
980     /* 1yd == 3 feet */
981     width /= 3.0;
982     imp_scale *= 3.0;
983     dist_imp_unit = "yd";
984    
985     if(width >= 1760.0) {
986     /* 1mi == 1760 yd */
987     width /= 1760.0;
988     imp_scale *= 1760.0;
989     dist_imp_unit = "mi";
990     }
991     }
992    
993 harbaum 103 /* also convert this to full tens/hundreds */
994     exp = logf(width)*M_LOG10E;
995     mant = width/pow(10,exp);
996     int width_imp = mant * pow(10,exp);
997     char *dist_str_imp = g_strdup_printf("%u %s", width_imp, dist_imp_unit);
998 harbaum 102
999 harbaum 103 /* convert back to pixels */
1000     width_imp *= imp_scale;
1001     width_imp /= m_per_pix;
1002    
1003 harbaum 99 cairo_select_font_face (cr, "Sans",
1004     CAIRO_FONT_SLANT_NORMAL,
1005     CAIRO_FONT_WEIGHT_BOLD);
1006 harbaum 102 cairo_set_font_size (cr, OSD_SCALE_FONT_SIZE);
1007 harbaum 99 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
1008    
1009     cairo_text_extents_t extents;
1010     cairo_text_extents (cr, dist_str, &extents);
1011    
1012 harbaum 100 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1013 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6);
1014     cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD);
1015 harbaum 100 cairo_text_path (cr, dist_str);
1016     cairo_stroke (cr);
1017 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD,
1018     OSD_SCALE_H2+OSD_SCALE_FD + extents.height);
1019     cairo_text_path (cr, dist_str_imp);
1020     cairo_stroke (cr);
1021 harbaum 100
1022     cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
1023 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD);
1024 harbaum 99 cairo_show_text (cr, dist_str);
1025 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD,
1026     OSD_SCALE_H2+OSD_SCALE_FD + extents.height);
1027     cairo_show_text (cr, dist_str_imp);
1028 harbaum 99
1029 harbaum 103 g_free(dist_str);
1030     g_free(dist_str_imp);
1031    
1032 harbaum 99 /* draw white line */
1033     cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
1034     cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
1035 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/3);
1036     cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M);
1037     cairo_rel_line_to (cr, 0, OSD_SCALE_TICK);
1038 harbaum 99 cairo_rel_line_to (cr, width_metric, 0);
1039 harbaum 103 cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1040 harbaum 99 cairo_stroke(cr);
1041 harbaum 103 cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I);
1042     cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1043     cairo_rel_line_to (cr, width_imp, 0);
1044     cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK);
1045     cairo_stroke(cr);
1046 harbaum 99
1047     /* draw black line */
1048     cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
1049 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6);
1050     cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M);
1051     cairo_rel_line_to (cr, 0, OSD_SCALE_TICK);
1052 harbaum 99 cairo_rel_line_to (cr, width_metric, 0);
1053 harbaum 103 cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1054 harbaum 99 cairo_stroke(cr);
1055 harbaum 103 cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I);
1056     cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1057     cairo_rel_line_to (cr, width_imp, 0);
1058     cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK);
1059     cairo_stroke(cr);
1060 harbaum 99
1061 harbaum 98 cairo_destroy(cr);
1062     }
1063 harbaum 105 #endif
1064 harbaum 98
1065     static void
1066     osd_render(osm_gps_map_osd_t *osd)
1067     {
1068     osd_priv_t *priv = (osd_priv_t*)osd->priv;
1069    
1070 harbaum 86 #ifndef OSD_COLOR
1071     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
1072     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
1073     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
1074 harbaum 74 #endif
1075 harbaum 70
1076     /* first fill with transparency */
1077 harbaum 73 cairo_t *cr = cairo_create(priv->overlay);
1078 harbaum 70 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1079     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
1080     cairo_paint(cr);
1081     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1082    
1083     /* --------- draw zoom and dpad shape shadow ----------- */
1084 harbaum 74 #ifdef OSD_SHADOW_ENABLE
1085 harbaum 86 osd_zoom_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
1086     osd_shape_shadow(cr);
1087 harbaum 76 #ifndef OSD_NO_DPAD
1088 harbaum 86 osd_dpad_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
1089     osd_shape_shadow(cr);
1090 harbaum 74 #endif
1091 harbaum 76 #endif
1092 harbaum 70
1093     /* --------- draw zoom and dpad shape ----------- */
1094    
1095 harbaum 86 osd_zoom_shape(cr, 1, 1);
1096 harbaum 74 #ifndef OSD_COLOR
1097 harbaum 86 osd_shape(cr, &bg, &fg);
1098 harbaum 74 #else
1099 harbaum 86 osd_shape(cr);
1100 harbaum 74 #endif
1101 harbaum 76 #ifndef OSD_NO_DPAD
1102 harbaum 86 osd_dpad_shape(cr, 1, 1);
1103 harbaum 74 #ifndef OSD_COLOR
1104 harbaum 86 osd_shape(cr, &bg, &fg);
1105 harbaum 74 #else
1106 harbaum 86 osd_shape(cr);
1107 harbaum 74 #endif
1108 harbaum 76 #endif
1109 harbaum 70
1110     /* --------- draw zoom and dpad labels --------- */
1111    
1112 harbaum 74 #ifdef OSD_SHADOW_ENABLE
1113 harbaum 87 osd_labels_shadow(cr, Z_RAD/3, TRUE);
1114 harbaum 86 osd_zoom_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1115 harbaum 76 #ifndef OSD_NO_DPAD
1116 harbaum 86 osd_dpad_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1117 harbaum 76 #endif
1118 harbaum 87 cairo_stroke(cr);
1119 harbaum 76 #ifdef OSD_GPS_BUTTON
1120 harbaum 87 osd_labels_shadow(cr, Z_RAD/6, osd->cb != NULL);
1121 harbaum 86 osd_dpad_gps(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1122 harbaum 87 cairo_stroke(cr);
1123 harbaum 74 #endif
1124 harbaum 76 #endif
1125 harbaum 70
1126 harbaum 74 #ifndef OSD_COLOR
1127 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
1128 harbaum 74 #else
1129 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE);
1130 harbaum 74 #endif
1131 harbaum 87 osd_zoom_labels(cr, 1, 1);
1132     #ifndef OSD_NO_DPAD
1133     osd_dpad_labels(cr, 1, 1);
1134     #endif
1135     cairo_stroke(cr);
1136    
1137 harbaum 74 #ifndef OSD_COLOR
1138 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL, &fg, &da);
1139 harbaum 74 #else
1140 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL);
1141 harbaum 74 #endif
1142 harbaum 87 #ifdef OSD_GPS_BUTTON
1143     osd_dpad_gps(cr, 1, 1);
1144 harbaum 76 #endif
1145 harbaum 87 cairo_stroke(cr);
1146 harbaum 70
1147     cairo_destroy(cr);
1148 harbaum 86
1149 harbaum 88 #ifdef OSD_SOURCE_SEL
1150 harbaum 86 osd_render_source_sel(osd);
1151 harbaum 88 #endif
1152 harbaum 98
1153     #ifdef OSD_SCALE
1154     osd_render_scale(osd);
1155     #endif
1156 harbaum 105
1157     #ifdef OSD_CROSSHAIR
1158     osd_render_crosshair(osd);
1159     #endif
1160 harbaum 106
1161     #ifdef OSD_COORDINATES
1162     osd_render_coordinates(osd);
1163     #endif
1164 harbaum 70 }
1165    
1166     static void
1167 harbaum 86 osd_draw(osm_gps_map_osd_t *osd, GdkDrawable *drawable)
1168 harbaum 70 {
1169 harbaum 73 osd_priv_t *priv = (osd_priv_t*)osd->priv;
1170 harbaum 70
1171     /* OSD itself uses some off-screen rendering, so check if the */
1172     /* offscreen buffer is present and create it if not */
1173 harbaum 73 if(!priv->overlay) {
1174 harbaum 70 /* create overlay ... */
1175 harbaum 73 priv->overlay =
1176 harbaum 86 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W+2, OSD_H+2);
1177    
1178 harbaum 88 #ifdef OSD_SOURCE_SEL
1179 harbaum 86 /* the initial OSD state is alway not-expanded */
1180     priv->map_source =
1181     cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1182     OSD_S_W+2, OSD_S_H+2);
1183 harbaum 88 #endif
1184 harbaum 86
1185 harbaum 98 #ifdef OSD_SCALE
1186     priv->scale =
1187     cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1188 harbaum 103 OSD_SCALE_W, OSD_SCALE_H);
1189     priv->scale_zoom = -1;
1190 harbaum 98 #endif
1191    
1192 harbaum 105 #ifdef OSD_CROSSHAIR
1193     priv->crosshair =
1194     cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1195     OSD_CROSSHAIR_W, OSD_CROSSHAIR_H);
1196     #endif
1197    
1198 harbaum 106 #ifdef OSD_COORDINATES
1199     priv->coordinates =
1200     cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1201     OSD_COORDINATES_W, OSD_COORDINATES_H);
1202     #endif
1203    
1204 harbaum 70 /* ... and render it */
1205 harbaum 86 osd_render(osd);
1206 harbaum 70 }
1207    
1208     // now draw this onto the original context
1209 harbaum 75 cairo_t *cr = gdk_cairo_create(drawable);
1210 harbaum 77
1211 harbaum 106 int x, y;
1212 harbaum 77
1213 harbaum 106 #ifdef OSD_SCALE
1214     x = OSD_X;
1215     y = -OSD_Y;
1216     if(x < 0) x += osd->widget->allocation.width - OSD_SCALE_W;
1217     if(y < 0) y += osd->widget->allocation.height - OSD_SCALE_H;
1218 harbaum 77
1219 harbaum 106 cairo_set_source_surface(cr, priv->scale, x, y);
1220     cairo_paint(cr);
1221     #endif
1222    
1223     #ifdef OSD_CROSSHAIR
1224     x = (osd->widget->allocation.width - OSD_CROSSHAIR_W)/2;
1225     y = (osd->widget->allocation.height - OSD_CROSSHAIR_H)/2;
1226    
1227     cairo_set_source_surface(cr, priv->crosshair, x, y);
1228     cairo_paint(cr);
1229     #endif
1230    
1231     #ifdef OSD_COORDINATES
1232     x = -OSD_X;
1233     y = -OSD_Y;
1234     if(x < 0) x += osd->widget->allocation.width - OSD_COORDINATES_W;
1235     if(y < 0) y += osd->widget->allocation.height - OSD_COORDINATES_H;
1236    
1237     cairo_set_source_surface(cr, priv->coordinates, x, y);
1238     cairo_paint(cr);
1239     #endif
1240    
1241     x = OSD_X;
1242     if(x < 0)
1243     x += osd->widget->allocation.width - OSD_W;
1244    
1245     y = OSD_Y;
1246     if(y < 0)
1247     y += osd->widget->allocation.height - OSD_H;
1248    
1249 harbaum 77 cairo_set_source_surface(cr, priv->overlay, x, y);
1250 harbaum 70 cairo_paint(cr);
1251 harbaum 86
1252     #ifdef OSD_SOURCE_SEL
1253     if(!priv->handler_id) {
1254     /* the OSD source selection is not being animated */
1255     if(!priv->expanded)
1256     x = osd->widget->allocation.width - OSD_S_W;
1257     else
1258     x = osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
1259     } else
1260     x = priv->shift;
1261    
1262     y = OSD_S_Y;
1263     if(OSD_S_Y < 0) {
1264     if(!priv->expanded)
1265     y = osd->widget->allocation.height - OSD_S_H + OSD_S_Y;
1266     else
1267     y = osd->widget->allocation.height - OSD_S_EXP_H + OSD_S_Y;
1268     }
1269    
1270     cairo_set_source_surface(cr, priv->map_source, x, y);
1271     cairo_paint(cr);
1272     #endif
1273    
1274 harbaum 70 cairo_destroy(cr);
1275     }
1276    
1277     static void
1278 harbaum 86 osd_free(osm_gps_map_osd_t *osd)
1279 harbaum 70 {
1280 harbaum 73 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
1281 harbaum 70
1282 harbaum 88 if (priv->overlay)
1283     cairo_surface_destroy(priv->overlay);
1284    
1285     #ifdef OSD_SOURCE_SEL
1286 harbaum 86 if(priv->handler_id)
1287     gtk_timeout_remove(priv->handler_id);
1288    
1289     if (priv->map_source)
1290     cairo_surface_destroy(priv->map_source);
1291 harbaum 88 #endif
1292 harbaum 86
1293 harbaum 98 #ifdef OSD_SCALE
1294     if (priv->scale)
1295     cairo_surface_destroy(priv->scale);
1296     #endif
1297    
1298 harbaum 105 #ifdef OSD_CROSSHAIR
1299     if (priv->crosshair)
1300     cairo_surface_destroy(priv->crosshair);
1301     #endif
1302    
1303 harbaum 106 #ifdef OSD_COORDINATES
1304     if (priv->coordinates)
1305     cairo_surface_destroy(priv->coordinates);
1306     #endif
1307    
1308 harbaum 73 g_free(priv);
1309     }
1310    
1311 harbaum 87 static gboolean
1312     osd_busy(osm_gps_map_osd_t *osd)
1313     {
1314 harbaum 88 #ifdef OSD_SOURCE_SEL
1315 harbaum 87 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
1316     return (priv->handler_id != 0);
1317 harbaum 88 #else
1318     return FALSE;
1319     #endif
1320 harbaum 87 }
1321    
1322 harbaum 73 static osm_gps_map_osd_t osd_classic = {
1323 harbaum 88 .widget = NULL,
1324    
1325 harbaum 86 .draw = osd_draw,
1326     .check = osd_check,
1327     .render = osd_render,
1328     .free = osd_free,
1329 harbaum 87 .busy = osd_busy,
1330 harbaum 73
1331     .cb = NULL,
1332     .data = NULL,
1333    
1334     .priv = NULL
1335     };
1336    
1337     /* this is the only function that's externally visible */
1338     void
1339     osm_gps_map_osd_classic_init(OsmGpsMap *map)
1340     {
1341     osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);
1342    
1343     osd_classic.priv = priv;
1344    
1345     osm_gps_map_register_osd(map, &osd_classic);
1346     }
1347    
1348 harbaum 76 #ifdef OSD_GPS_BUTTON
1349 harbaum 74 /* below are osd specific functions which aren't used by osm-gps-map */
1350     /* but instead are to be used by the main application */
1351 harbaum 76 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,
1352     gpointer data) {
1353 harbaum 73 osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
1354     g_return_if_fail (osd);
1355    
1356     osd->cb = cb;
1357     osd->data = data;
1358    
1359 harbaum 70 /* this may have changed the state of the gps button */
1360     /* we thus re-render the overlay */
1361 harbaum 73 osd->render(osd);
1362 harbaum 70
1363 harbaum 73 osm_gps_map_redraw(map);
1364 harbaum 70 }
1365 harbaum 76 #endif
1366 harbaum 86
1367     osd_button_t
1368     osm_gps_map_osd_check(OsmGpsMap *map, gint x, gint y) {
1369     osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
1370     g_return_val_if_fail (osd, OSD_NONE);
1371    
1372     return osd_check(osd, x, y);
1373     }