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

Parent Directory Parent Directory | Revision Log Revision Log


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