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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 112 - (hide annotations)
Tue Sep 15 13:52:04 2009 UTC (14 years, 7 months ago) by harbaum
File MIME type: text/plain
File size: 52422 byte(s)
Balloon to OSD migration started
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 112 #include "converter.h"
36 harbaum 73 #include "osm-gps-map-osd-classic.h"
37 harbaum 71
38 harbaum 70 //the osd controls
39     typedef struct {
40 harbaum 74 /* the offscreen representation of the OSD */
41 harbaum 108 struct {
42     cairo_surface_t *surface;
43     gboolean rendered;
44     #ifdef OSD_GPS_BUTTON
45     gboolean gps_enabled;
46     #endif
47     } controls;
48 harbaum 86
49 harbaum 112 #ifdef OSD_BALLOON
50     //a balloon with additional info
51     struct {
52     cairo_surface_t *surface;
53    
54     float lat, lon;
55     gboolean valid;
56     OsmGpsMapRect_t rect;
57    
58     /* function called to have the user app draw the contents */
59     OsmGpsMapBalloonCallback cb;
60     gpointer data;
61     } balloon;
62     #endif
63    
64 harbaum 98 #ifdef OSD_SCALE
65 harbaum 110 struct {
66     cairo_surface_t *surface;
67     int zoom;
68     } scale;
69 harbaum 98 #endif
70 harbaum 110
71 harbaum 105 #ifdef OSD_CROSSHAIR
72 harbaum 110 struct {
73     cairo_surface_t *surface;
74     gboolean rendered;
75     } crosshair;
76 harbaum 105 #endif
77    
78 harbaum 106 #ifdef OSD_COORDINATES
79 harbaum 110 struct {
80     cairo_surface_t *surface;
81     float lat, lon;
82     } coordinates;
83 harbaum 106 #endif
84    
85 harbaum 88 #ifdef OSD_SOURCE_SEL
86 harbaum 110 struct {
87     /* values to handle the "source" menu */
88     cairo_surface_t *surface;
89     gboolean expanded;
90     gint shift, dir, count;
91     gint handler_id;
92     gint width, height;
93 harbaum 111 gboolean rendered;
94 harbaum 110 } source_sel;
95 harbaum 88 #endif
96 harbaum 87
97 harbaum 70 } osd_priv_t;
98    
99 harbaum 112 #ifdef OSD_BALLOON
100     /* most visual effects are hardcoded by now, but may be made */
101     /* available via properties later */
102     #ifndef BALLOON_AREA_WIDTH
103     #define BALLOON_AREA_WIDTH 290
104     #endif
105     #ifndef BALLOON_AREA_HEIGHT
106     #define BALLOON_AREA_HEIGHT 75
107     #endif
108     #ifndef BALLOON_CORNER_RADIUS
109     #define BALLOON_CORNER_RADIUS 10
110     #endif
111    
112     #define BALLOON_BORDER (BALLOON_CORNER_RADIUS/2)
113     #define BALLOON_WIDTH (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)
114     #define BALLOON_HEIGHT (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)
115     #define BALLOON_TRANSPARENCY 0.8
116     #define POINTER_HEIGHT 20
117     #define POINTER_FOOT_WIDTH 20
118     #define POINTER_OFFSET (BALLOON_CORNER_RADIUS*3/4)
119     #define BALLOON_SHADOW (BALLOON_CORNER_RADIUS/2)
120     #define BALLOON_SHADOW_TRANSPARENCY 0.2
121    
122     #define CLOSE_BUTTON_RADIUS (BALLOON_CORNER_RADIUS)
123    
124    
125     /* draw the bubble shape. this is used twice, once for the shape and once */
126     /* for the shadow */
127     static void
128     osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,
129     gboolean bottom, int px, int py, int px0, int px1) {
130    
131     cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);
132     cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
133     BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);
134     if(!bottom) {
135     /* insert top pointer */
136     cairo_line_to (cr, px1, y0);
137     cairo_line_to (cr, px, py);
138     cairo_line_to (cr, px0, y0);
139     }
140    
141     cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);
142     cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
143     BALLOON_CORNER_RADIUS, -M_PI/2, 0);
144     cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);
145     cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
146     BALLOON_CORNER_RADIUS, 0, M_PI/2);
147     if(bottom) {
148     /* insert bottom pointer */
149     cairo_line_to (cr, px0, y1);
150     cairo_line_to (cr, px, py);
151     cairo_line_to (cr, px1, y1);
152     }
153    
154     cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);
155     cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
156     BALLOON_CORNER_RADIUS, M_PI/2, M_PI);
157    
158     cairo_close_path (cr);
159     }
160    
161     /* xyz */
162    
163     static void
164     osd_render_balloon(osm_gps_map_osd_t *osd) {
165     osd_priv_t *priv = (osd_priv_t*)osd->priv;
166    
167     /* get zoom */
168     gint zoom;
169     g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
170    
171     /* ------- convert given coordinate into screen position --------- */
172     gint x0, y0;
173     osm_gps_map_geographic_to_screen (OSM_GPS_MAP(osd->widget),
174     priv->balloon.lat, priv->balloon.lon,
175     &x0, &y0);
176    
177     /* check position of this relative to screen center to determine */
178     /* pointer direction ... */
179     int pointer_x = x0, pointer_x0, pointer_x1;
180     int pointer_y = y0;
181    
182     /* ... and calculate position */
183     if(x0 > osd->widget->allocation.width/2) {
184     x0 += POINTER_OFFSET;
185     pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
186     pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;
187     } else {
188     x0 -= POINTER_OFFSET;
189     pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
190     pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;
191     }
192    
193     gboolean bottom = FALSE;
194     if(y0 > osd->widget->allocation.height/2) {
195     bottom = TRUE;
196     y0 -= BALLOON_HEIGHT + POINTER_HEIGHT;
197     } else
198     y0 += POINTER_HEIGHT;
199    
200     /* calculate bottom/right of box */
201     int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;
202    
203     /* save balloon screen coordinates for later use */
204     priv->balloon.rect.x = x0 + BALLOON_BORDER;
205     priv->balloon.rect.y = y0 + BALLOON_BORDER;
206     priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;
207     priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;
208    
209     cairo_t *cr = cairo_create(priv->balloon.surface);
210    
211     /* --------- draw shadow --------------- */
212     osm_gps_map_draw_balloon_shape (cr,
213     x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,
214     x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,
215     bottom, pointer_x, pointer_y,
216     pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);
217    
218     cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);
219     cairo_fill_preserve (cr);
220     cairo_set_source_rgba (cr, 1, 0, 0, 1.0);
221     cairo_set_line_width (cr, 0);
222     cairo_stroke (cr);
223    
224     /* --------- draw main shape ----------- */
225     osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,
226     bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);
227    
228     cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);
229     cairo_fill_preserve (cr);
230     cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);
231     cairo_set_line_width (cr, 1);
232     cairo_stroke (cr);
233    
234    
235     /* ---------- draw close button --------- */
236    
237     int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS;
238     int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS;
239     int crad = CLOSE_BUTTON_RADIUS;
240    
241     cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI);
242     cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0);
243     cairo_fill_preserve (cr);
244     cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0);
245     cairo_set_line_width (cr, 2);
246     cairo_stroke(cr);
247    
248     cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
249     cairo_set_line_width (cr, BALLOON_CORNER_RADIUS/3.3);
250     cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
251     cairo_move_to (cr, cx - crad/2, cy - crad/2);
252     cairo_line_to (cr, cx + crad/2, cy + crad/2);
253     cairo_stroke (cr);
254     cairo_move_to (cr, cx + crad/2, cy - crad/2);
255     cairo_line_to (cr, cx - crad/2, cy + crad/2);
256     cairo_stroke (cr);
257    
258     if (priv->balloon.cb) {
259     /* clip in case application tries to draw in */
260     /* exceed of the balloon */
261     cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,
262     priv->balloon.rect.w, priv->balloon.rect.h);
263     cairo_clip (cr);
264     cairo_new_path (cr); /* current path is not
265     consumed by cairo_clip() */
266    
267     priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);
268     }
269    
270     cairo_destroy(cr);
271     }
272    
273     #if 0
274     /* the user clicked into the balloons main area. handle this */
275     static void
276     osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y)
277     {
278     OsmGpsMapPrivate *priv = map->priv;
279    
280     if (!priv->balloon.valid)
281     return;
282    
283     /* check if the close button was clicked */
284     if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&
285     (x < priv->balloon.rect.w) &&
286     (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {
287    
288     priv->balloon.valid = FALSE;
289     osm_gps_map_map_redraw_idle(map);
290     }
291     }
292    
293     /* return true if balloon is being displayed and if */
294     /* the given coordinate is within this balloon */
295     static gboolean
296     osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)
297     {
298     return (priv->balloon.valid &&
299     (x > priv->balloon.rect.x) &&
300     (x < priv->balloon.rect.x + priv->balloon.rect.w) &&
301     (y > priv->balloon.rect.y) &&
302     (y < priv->balloon.rect.y + priv->balloon.rect.h));
303     }
304    
305     #if 0
306     /* don't drag if the user clicked within the balloon */
307     if (osm_gps_map_in_balloon(priv,
308     event->x + EXTRA_BORDER,
309     event->y + EXTRA_BORDER))
310     {
311     priv->drag_counter = -1;
312     return FALSE;
313     }
314    
315     #ifdef ENABLE_BALLOON
316     /* released inside the balloon? */
317     if (osm_gps_map_in_balloon(priv,
318     event->x + EXTRA_BORDER,
319     event->y + EXTRA_BORDER))
320     {
321     osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),
322     event->x - priv->balloon.rect.x + EXTRA_BORDER,
323     event->y - priv->balloon.rect.y + EXTRA_BORDER);
324     }
325     #endif
326    
327     #endif
328    
329     void
330     osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
331     OsmGpsMapBalloonCallback cb, gpointer data)
332     {
333     OsmGpsMapPrivate *priv;
334    
335     /* remove and previously installed balloon */
336     osm_gps_map_clear_balloon (map);
337    
338     g_return_if_fail (OSM_IS_GPS_MAP (map));
339     priv = map->priv;
340    
341     priv->balloon.lat = latitude;
342     priv->balloon.lon = longitude;
343     priv->balloon.valid = TRUE;
344    
345     priv->balloon.cb = cb;
346     priv->balloon.data = data;
347    
348     // this redraws the map
349     osm_gps_map_map_redraw_idle(map);
350     }
351    
352     void
353     osm_gps_map_clear_balloon (OsmGpsMap *map)
354     {
355     OsmGpsMapPrivate *priv;
356    
357     g_return_if_fail (OSM_IS_GPS_MAP (map));
358     priv = map->priv;
359    
360     priv->balloon.valid = FALSE;
361    
362     osm_gps_map_map_redraw_idle(map);
363     }
364     #endif
365    
366     void osm_gps_map_osd_clear_balloon (OsmGpsMap *map) {
367     printf("request to clear balloon\n");
368     }
369    
370     void
371     osm_gps_map_osd_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
372     OsmGpsMapBalloonCallback cb, gpointer data)
373     {
374     printf("request to draw balloon at %f %f\n", latitude, longitude);
375     }
376    
377     #endif // OSD_BALLOON
378    
379 harbaum 70 /* position and extent of bounding box */
380 harbaum 77 #ifndef OSD_X
381 harbaum 70 #define OSD_X (10)
382 harbaum 77 #endif
383    
384     #ifndef OSD_Y
385 harbaum 70 #define OSD_Y (10)
386 harbaum 77 #endif
387 harbaum 70
388     /* parameters of the direction shape */
389 harbaum 77 #ifndef OSD_DIAMETER
390 harbaum 70 #define D_RAD (30) // diameter of dpad
391     #else
392 harbaum 77 #define D_RAD (OSD_DIAMETER)
393 harbaum 70 #endif
394     #define D_TIP (4*D_RAD/5) // distance of arrow tip from dpad center
395     #define D_LEN (D_RAD/4) // length of arrow
396     #define D_WID (D_LEN) // width of arrow
397    
398     /* parameters of the "zoom" pad */
399     #define Z_STEP (D_RAD/4) // distance between dpad and zoom
400     #define Z_RAD (D_RAD/2) // radius of "caps" of zoom bar
401    
402 harbaum 74 #ifdef OSD_SHADOW_ENABLE
403 harbaum 70 /* shadow also depends on control size */
404     #define OSD_SHADOW (D_RAD/6)
405 harbaum 74 #else
406     #define OSD_SHADOW (0)
407     #endif
408 harbaum 70
409 harbaum 77 /* normally the GPS button is in the center of the dpad. if there's */
410     /* no dpad it will go into the zoom area */
411     #if defined(OSD_GPS_BUTTON) && defined(OSD_NO_DPAD)
412     #define Z_GPS 1
413     #else
414     #define Z_GPS 0
415     #endif
416    
417 harbaum 70 /* total width and height of controls incl. shadow */
418 harbaum 77 #define OSD_W (2*D_RAD + OSD_SHADOW + Z_GPS * 2 * Z_RAD)
419     #if !Z_GPS
420 harbaum 70 #define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)
421 harbaum 77 #else
422     #define OSD_H (2*Z_RAD + OSD_SHADOW)
423     #endif
424 harbaum 70
425 harbaum 74 #ifdef OSD_SHADOW_ENABLE
426 harbaum 70 #define OSD_LBL_SHADOW (OSD_SHADOW/2)
427 harbaum 74 #endif
428 harbaum 70
429 harbaum 77 #define Z_TOP ((1-Z_GPS) * (2 * D_RAD + Z_STEP))
430    
431 harbaum 70 #define Z_MID (Z_TOP + Z_RAD)
432     #define Z_BOT (Z_MID + Z_RAD)
433     #define Z_LEFT (Z_RAD)
434 harbaum 77 #define Z_RIGHT (2 * D_RAD - Z_RAD + Z_GPS * 2 * Z_RAD)
435     #define Z_CENTER ((Z_RIGHT + Z_LEFT)/2)
436 harbaum 70
437     /* create the cairo shape used for the zoom buttons */
438     static void
439 harbaum 86 osd_zoom_shape(cairo_t *cr, gint x, gint y)
440 harbaum 71 {
441 harbaum 70 cairo_move_to (cr, x+Z_LEFT, y+Z_TOP);
442     cairo_line_to (cr, x+Z_RIGHT, y+Z_TOP);
443     cairo_arc (cr, x+Z_RIGHT, y+Z_MID, Z_RAD, -M_PI/2, M_PI/2);
444     cairo_line_to (cr, x+Z_LEFT, y+Z_BOT);
445     cairo_arc (cr, x+Z_LEFT, y+Z_MID, Z_RAD, M_PI/2, -M_PI/2);
446     }
447    
448 harbaum 86 /* ------------------- color/shadow functions ----------------- */
449    
450     #ifndef OSD_COLOR
451     /* if no color has been specified we just use the gdks default colors */
452     static void
453     osd_labels(cairo_t *cr, gint width, gboolean enabled,
454     GdkColor *fg, GdkColor *disabled) {
455     if(enabled) gdk_cairo_set_source_color(cr, fg);
456     else gdk_cairo_set_source_color(cr, disabled);
457     cairo_set_line_width (cr, width);
458     }
459     #else
460     static void
461     osd_labels(cairo_t *cr, gint width, gboolean enabled) {
462     if(enabled) cairo_set_source_rgb (cr, OSD_COLOR);
463     else cairo_set_source_rgb (cr, OSD_COLOR_DISABLED);
464     cairo_set_line_width (cr, width);
465     }
466     #endif
467    
468     #ifdef OSD_SHADOW_ENABLE
469     static void
470     osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) {
471     cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15);
472     cairo_set_line_width (cr, width);
473     }
474     #endif
475    
476 harbaum 76 #ifndef OSD_NO_DPAD
477 harbaum 70 /* create the cairo shape used for the dpad */
478     static void
479 harbaum 86 osd_dpad_shape(cairo_t *cr, gint x, gint y)
480 harbaum 71 {
481 harbaum 70 cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);
482     }
483 harbaum 76 #endif
484 harbaum 70
485 harbaum 86 #ifdef OSD_SHADOW_ENABLE
486     static void
487     osd_shape_shadow(cairo_t *cr) {
488     cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
489     cairo_fill (cr);
490     cairo_stroke (cr);
491     }
492     #endif
493    
494     #ifndef OSD_COLOR
495     /* if no color has been specified we just use the gdks default colors */
496     static void
497     osd_shape(cairo_t *cr, GdkColor *bg, GdkColor *fg) {
498     gdk_cairo_set_source_color(cr, bg);
499     cairo_fill_preserve (cr);
500     gdk_cairo_set_source_color(cr, fg);
501     cairo_set_line_width (cr, 1);
502     cairo_stroke (cr);
503     }
504     #else
505     static void
506     osd_shape(cairo_t *cr) {
507     cairo_set_source_rgb (cr, OSD_COLOR_BG);
508     cairo_fill_preserve (cr);
509     cairo_set_source_rgb (cr, OSD_COLOR);
510     cairo_set_line_width (cr, 1);
511     cairo_stroke (cr);
512     }
513     #endif
514    
515    
516 harbaum 70 static gboolean
517     osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)
518     {
519     return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);
520     }
521    
522 harbaum 76 #ifndef OSD_NO_DPAD
523 harbaum 70 /* check whether x/y is within the dpad */
524     static osd_button_t
525 harbaum 86 osd_check_dpad(gint x, gint y)
526 harbaum 70 {
527     /* within entire dpad circle */
528 harbaum 77 if( osm_gps_map_in_circle(x, y, D_RAD, D_RAD, D_RAD))
529 harbaum 70 {
530     /* convert into position relative to dpads centre */
531 harbaum 77 x -= D_RAD;
532     y -= D_RAD;
533 harbaum 70
534 harbaum 76 #ifdef OSD_GPS_BUTTON
535 harbaum 70 /* check for dpad center goes here! */
536     if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3))
537     return OSD_GPS;
538 harbaum 76 #endif
539 harbaum 70
540     if( y < 0 && abs(x) < abs(y))
541     return OSD_UP;
542    
543     if( y > 0 && abs(x) < abs(y))
544     return OSD_DOWN;
545    
546     if( x < 0 && abs(y) < abs(x))
547     return OSD_LEFT;
548    
549     if( x > 0 && abs(y) < abs(x))
550     return OSD_RIGHT;
551    
552     return OSD_BG;
553     }
554     return OSD_NONE;
555     }
556 harbaum 76 #endif
557 harbaum 70
558     /* check whether x/y is within the zoom pads */
559     static osd_button_t
560 harbaum 86 osd_check_zoom(gint x, gint y) {
561 harbaum 77 if( x > 0 && x < OSD_W && y > Z_TOP && y < Z_BOT) {
562 harbaum 70
563     /* within circle around (-) label */
564 harbaum 77 if( osm_gps_map_in_circle(x, y, Z_LEFT, Z_MID, Z_RAD))
565 harbaum 70 return OSD_OUT;
566    
567 harbaum 77 /* within circle around (+) label */
568     if( osm_gps_map_in_circle(x, y, Z_RIGHT, Z_MID, Z_RAD))
569     return OSD_IN;
570    
571     #if Z_GPS == 1
572     /* within square around center */
573     if( x > Z_CENTER - Z_RAD && x < Z_CENTER + Z_RAD)
574     return OSD_GPS;
575     #endif
576    
577 harbaum 70 /* between center of (-) button and center of entire zoom control area */
578 harbaum 77 if(x > OSD_LEFT && x < D_RAD)
579 harbaum 70 return OSD_OUT;
580    
581     /* between center of (+) button and center of entire zoom control area */
582 harbaum 77 if(x < OSD_RIGHT && x > D_RAD)
583 harbaum 70 return OSD_IN;
584     }
585    
586     return OSD_NONE;
587     }
588    
589 harbaum 88 #ifdef OSD_SOURCE_SEL
590    
591 harbaum 86 /* place source selection at right border */
592     #define OSD_S_RAD (Z_RAD)
593     #define OSD_S_X (-OSD_X)
594     #define OSD_S_Y (OSD_Y)
595     #define OSD_S_PW (2 * Z_RAD)
596     #define OSD_S_W (OSD_S_PW)
597     #define OSD_S_PH (2 * Z_RAD)
598     #define OSD_S_H (OSD_S_PH + OSD_SHADOW)
599    
600 harbaum 87 /* size of usable area when expanded */
601 harbaum 110 #define OSD_S_AREA_W (priv->source_sel.width)
602     #define OSD_S_AREA_H (priv->source_sel.height)
603 harbaum 86 #define OSD_S_EXP_W (OSD_S_PW + OSD_S_AREA_W + OSD_SHADOW)
604     #define OSD_S_EXP_H (OSD_S_AREA_H + OSD_SHADOW)
605    
606     /* internal value to draw the arrow on the "puller" */
607     #define OSD_S_D0 (OSD_S_RAD/2)
608 harbaum 87 #ifndef OSD_FONT_SIZE
609     #define OSD_FONT_SIZE 16.0
610     #endif
611     #define OSD_TEXT_BORDER (OSD_FONT_SIZE/2)
612     #define OSD_TEXT_SKIP (OSD_FONT_SIZE/8)
613 harbaum 86
614 harbaum 88 /* draw the shape of the source selection OSD, either only the puller (not expanded) */
615     /* or the entire menu incl. the puller (expanded) */
616 harbaum 86 static void
617     osd_source_shape(osd_priv_t *priv, cairo_t *cr, gint x, gint y) {
618 harbaum 110 if(!priv->source_sel.expanded) {
619 harbaum 86 /* just draw the puller */
620     cairo_move_to (cr, x + OSD_S_PW, y + OSD_S_PH);
621     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
622     cairo_line_to (cr, x + OSD_S_PW, y);
623     } else {
624     /* draw the puller and the area itself */
625     cairo_move_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y + OSD_S_AREA_H);
626     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H);
627     if(OSD_S_Y > 0) {
628     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_PH);
629     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
630     } else {
631     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_AREA_H-OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
632     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H - OSD_S_PH);
633     cairo_line_to (cr, x + OSD_S_PW, y);
634     }
635     cairo_line_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y);
636     cairo_close_path (cr);
637     }
638     }
639    
640     static void
641 harbaum 87 osd_source_content(osm_gps_map_osd_t *osd, cairo_t *cr, gint offset) {
642     osd_priv_t *priv = (osd_priv_t*)osd->priv;
643 harbaum 86
644 harbaum 87 int py = offset + OSD_S_RAD - OSD_S_D0;
645    
646 harbaum 110 if(!priv->source_sel.expanded) {
647 harbaum 86 /* draw the "puller" open (<) arrow */
648 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD + OSD_S_D0/2, py);
649 harbaum 86 cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
650     cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
651     } else {
652     if(OSD_S_Y < 0)
653 harbaum 87 py += OSD_S_AREA_H - OSD_S_PH;
654 harbaum 86
655     /* draw the "puller" close (>) arrow */
656 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD - OSD_S_D0/2, py);
657 harbaum 86 cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
658     cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
659 harbaum 87 cairo_stroke(cr);
660    
661     /* don't draw a shadow for the text content */
662     if(offset == 1) {
663     gint source;
664     g_object_get(osd->widget, "map-source", &source, NULL);
665    
666     cairo_select_font_face (cr, "Sans",
667     CAIRO_FONT_SLANT_NORMAL,
668     CAIRO_FONT_WEIGHT_BOLD);
669     cairo_set_font_size (cr, OSD_FONT_SIZE);
670    
671 harbaum 110 int i, step = (priv->source_sel.height - 2*OSD_TEXT_BORDER) /
672 harbaum 89 OSM_GPS_MAP_SOURCE_LAST;
673 harbaum 87 for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
674     cairo_text_extents_t extents;
675     const char *src = osm_gps_map_source_get_friendly_name(i);
676     cairo_text_extents (cr, src, &extents);
677    
678     int x = offset + OSD_S_PW + OSD_TEXT_BORDER;
679     int y = offset + step * (i-1) + OSD_TEXT_BORDER;
680    
681     /* draw filled rectangle if selected */
682     if(source == i) {
683     cairo_rectangle(cr, x - OSD_TEXT_BORDER/2,
684     y - OSD_TEXT_SKIP,
685 harbaum 110 priv->source_sel.width - OSD_TEXT_BORDER,
686 harbaum 87 step + OSD_TEXT_SKIP);
687     cairo_fill(cr);
688    
689     /* temprarily draw with background color */
690     #ifndef OSD_COLOR
691     GdkColor bg = osd->widget->style->bg[GTK_STATE_NORMAL];
692     gdk_cairo_set_source_color(cr, &bg);
693     #else
694     cairo_set_source_rgb (cr, OSD_COLOR_BG);
695     #endif
696     }
697    
698     cairo_move_to (cr, x, y + OSD_TEXT_SKIP - extents.y_bearing);
699     cairo_show_text (cr, src);
700    
701     /* restore color */
702     if(source == i) {
703     #ifndef OSD_COLOR
704     GdkColor fg = osd->widget->style->fg[GTK_STATE_NORMAL];
705     gdk_cairo_set_source_color(cr, &fg);
706     #else
707     cairo_set_source_rgb (cr, OSD_COLOR);
708     #endif
709     }
710     }
711     }
712 harbaum 86 }
713     }
714    
715     static void
716 harbaum 111 osd_render_source_sel(osm_gps_map_osd_t *osd, gboolean force_rerender) {
717 harbaum 86 osd_priv_t *priv = (osd_priv_t*)osd->priv;
718    
719 harbaum 111 if(priv->source_sel.rendered && !force_rerender)
720     return;
721    
722     priv->source_sel.rendered = TRUE;
723    
724 harbaum 86 #ifndef OSD_COLOR
725     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
726     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
727     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
728     #endif
729    
730     /* draw source selector */
731 harbaum 110 cairo_t *cr = cairo_create(priv->source_sel.surface);
732 harbaum 86 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
733     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
734     cairo_paint(cr);
735     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
736    
737     #ifdef OSD_SHADOW_ENABLE
738     osd_source_shape(priv, cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
739     osd_shape_shadow(cr);
740     #endif
741    
742     osd_source_shape(priv, cr, 1, 1);
743     #ifndef OSD_COLOR
744     osd_shape(cr, &bg, &fg);
745     #else
746     osd_shape(cr);
747     #endif
748    
749     #ifdef OSD_SHADOW_ENABLE
750     osd_labels_shadow(cr, Z_RAD/3, TRUE);
751 harbaum 87 osd_source_content(osd, cr, 1+OSD_LBL_SHADOW);
752     cairo_stroke (cr);
753 harbaum 86 #endif
754     #ifndef OSD_COLOR
755     osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
756     #else
757     osd_labels(cr, Z_RAD/3, TRUE);
758     #endif
759 harbaum 87 osd_source_content(osd, cr, 1);
760     cairo_stroke (cr);
761 harbaum 86
762     cairo_destroy(cr);
763     }
764    
765 harbaum 89 /* re-allocate the buffer used to draw the menu. This is used */
766     /* to collapse/expand the buffer */
767 harbaum 86 static void
768     osd_source_reallocate(osm_gps_map_osd_t *osd) {
769     osd_priv_t *priv = (osd_priv_t*)osd->priv;
770    
771     /* re-allocate offscreen bitmap */
772 harbaum 110 g_assert (priv->source_sel.surface);
773 harbaum 86
774     int w = OSD_S_W, h = OSD_S_H;
775 harbaum 110 if(priv->source_sel.expanded) {
776 harbaum 87 cairo_text_extents_t extents;
777    
778     /* determine content size */
779 harbaum 110 cairo_t *cr = cairo_create(priv->source_sel.surface);
780 harbaum 87 cairo_select_font_face (cr, "Sans",
781     CAIRO_FONT_SLANT_NORMAL,
782     CAIRO_FONT_WEIGHT_BOLD);
783     cairo_set_font_size (cr, OSD_FONT_SIZE);
784    
785     /* calculate menu size */
786     int i, max_h = 0, max_w = 0;
787     for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
788     const char *src = osm_gps_map_source_get_friendly_name(i);
789     cairo_text_extents (cr, src, &extents);
790    
791     if(extents.width > max_w) max_w = extents.width;
792     if(extents.height > max_h) max_h = extents.height;
793     }
794     cairo_destroy(cr);
795    
796 harbaum 110 priv->source_sel.width = max_w + 2*OSD_TEXT_BORDER;
797     priv->source_sel.height = OSM_GPS_MAP_SOURCE_LAST *
798 harbaum 87 (max_h + 2*OSD_TEXT_SKIP) + 2*OSD_TEXT_BORDER;
799    
800 harbaum 86 w = OSD_S_EXP_W;
801     h = OSD_S_EXP_H;
802     }
803    
804 harbaum 110 cairo_surface_destroy(priv->source_sel.surface);
805     priv->source_sel.surface =
806 harbaum 86 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w+2, h+2);
807    
808 harbaum 111 osd_render_source_sel(osd, TRUE);
809 harbaum 86 }
810    
811     #define OSD_HZ 15
812 harbaum 87 #define OSD_TIME 500
813 harbaum 86
814     static gboolean osd_source_animate(gpointer data) {
815     osm_gps_map_osd_t *osd = (osm_gps_map_osd_t*)data;
816     osd_priv_t *priv = (osd_priv_t*)osd->priv;
817     int diff = OSD_S_EXP_W - OSD_S_W - OSD_S_X;
818     gboolean done = FALSE;
819 harbaum 110 priv->source_sel.count += priv->source_sel.dir;
820 harbaum 86
821     /* shifting in */
822 harbaum 110 if(priv->source_sel.dir < 0) {
823     if(priv->source_sel.count <= 0) {
824     priv->source_sel.count = 0;
825 harbaum 86 done = TRUE;
826     }
827     } else {
828 harbaum 110 if(priv->source_sel.count >= 1000) {
829     priv->source_sel.expanded = FALSE;
830 harbaum 86 osd_source_reallocate(osd);
831    
832 harbaum 110 priv->source_sel.count = 1000;
833 harbaum 86 done = TRUE;
834     }
835     }
836    
837    
838     /* count runs linearly from 0 to 1000, map this nicely onto a position */
839    
840 harbaum 111 /* nice sinoid mapping */
841 harbaum 110 float m = 0.5-cos(priv->source_sel.count * M_PI / 1000.0)/2;
842 harbaum 111 priv->source_sel.shift =
843     (osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X) +
844 harbaum 86 m * diff;
845    
846 harbaum 111 /* make sure the screen is updated */
847 harbaum 86 osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
848    
849 harbaum 111 /* stop animation if done */
850 harbaum 86 if(done)
851 harbaum 110 priv->source_sel.handler_id = 0;
852 harbaum 86
853     return !done;
854     }
855    
856     /* switch between expand and collapse mode of source selection */
857     static void
858     osd_source_toggle(osm_gps_map_osd_t *osd)
859     {
860     osd_priv_t *priv = (osd_priv_t*)osd->priv;
861    
862     /* ignore clicks while animation is running */
863 harbaum 110 if(priv->source_sel.handler_id)
864 harbaum 86 return;
865    
866 harbaum 111 /* expand immediately, collapse is handle at the end of the */
867     /* collapse animation */
868 harbaum 110 if(!priv->source_sel.expanded) {
869     priv->source_sel.expanded = TRUE;
870 harbaum 86 osd_source_reallocate(osd);
871    
872 harbaum 110 priv->source_sel.count = 1000;
873     priv->source_sel.shift = osd->widget->allocation.width - OSD_S_W;
874     priv->source_sel.dir = -1000/OSD_HZ;
875 harbaum 86 } else {
876 harbaum 110 priv->source_sel.count = 0;
877 harbaum 111 priv->source_sel.shift = osd->widget->allocation.width -
878     OSD_S_EXP_W + OSD_S_X;
879 harbaum 110 priv->source_sel.dir = +1000/OSD_HZ;
880 harbaum 86 }
881    
882 harbaum 111 /* start timer to handle animation */
883     priv->source_sel.handler_id = gtk_timeout_add(OSD_TIME/OSD_HZ,
884     osd_source_animate, osd);
885 harbaum 86 }
886    
887 harbaum 89 /* check if the user clicked inside the source selection area */
888 harbaum 70 static osd_button_t
889 harbaum 86 osd_source_check(osm_gps_map_osd_t *osd, gint x, gint y) {
890     osd_priv_t *priv = (osd_priv_t*)osd->priv;
891    
892 harbaum 110 if(!priv->source_sel.expanded)
893 harbaum 86 x -= osd->widget->allocation.width - OSD_S_W;
894     else
895     x -= osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
896    
897     if(OSD_S_Y > 0)
898     y -= OSD_S_Y;
899     else
900     y -= osd->widget->allocation.height - OSD_S_PH + OSD_S_Y;
901    
902     /* within square around puller? */
903     if(y > 0 && y < OSD_S_PH && x > 0 && x < OSD_S_PW) {
904     /* really within puller shape? */
905     if(x > Z_RAD || osm_gps_map_in_circle(x, y, Z_RAD, Z_RAD, Z_RAD)) {
906     /* expand source selector */
907     osd_source_toggle(osd);
908    
909     /* tell upper layers that user clicked some background element */
910     /* of the OSD */
911     return OSD_BG;
912     }
913     }
914 harbaum 88
915     /* check for clicks into data area */
916 harbaum 110 if(priv->source_sel.expanded && !priv->source_sel.handler_id) {
917 harbaum 94 /* re-adjust from puller top to content top */
918     if(OSD_S_Y < 0)
919     y += OSD_S_EXP_H - OSD_S_PH;
920    
921 harbaum 88 if(x > OSD_S_PW &&
922     x < OSD_S_PW + OSD_S_EXP_W &&
923     y > 0 &&
924     y < OSD_S_EXP_H) {
925 harbaum 94
926 harbaum 110 int step = (priv->source_sel.height - 2*OSD_TEXT_BORDER)
927 harbaum 89 / OSM_GPS_MAP_SOURCE_LAST;
928 harbaum 88
929 harbaum 89 y -= OSD_TEXT_BORDER - OSD_TEXT_SKIP;
930     y /= step;
931     y += 1;
932    
933     gint old = 0;
934     g_object_get(osd->widget, "map-source", &old, NULL);
935    
936     if(y > OSM_GPS_MAP_SOURCE_NULL &&
937     y <= OSM_GPS_MAP_SOURCE_LAST &&
938     old != y) {
939     g_object_set(osd->widget, "map-source", y, NULL);
940    
941 harbaum 111 osd_render_source_sel(osd, TRUE);
942 harbaum 89 osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
943     }
944    
945     /* return "clicked in OSD background" to prevent further */
946     /* processing by application */
947 harbaum 88 return OSD_BG;
948     }
949     }
950    
951 harbaum 86 return OSD_NONE;
952     }
953 harbaum 88 #endif // OSD_SOURCE_SEL
954 harbaum 86
955     static osd_button_t
956     osd_check(osm_gps_map_osd_t *osd, gint x, gint y) {
957 harbaum 70 osd_button_t but = OSD_NONE;
958    
959 harbaum 86 #ifdef OSD_SOURCE_SEL
960     /* the source selection area is handles internally */
961     but = osd_source_check(osd, x, y);
962     if(but != OSD_NONE)
963     return but;
964     #endif
965    
966 harbaum 77 x -= OSD_X;
967     y -= OSD_Y;
968    
969     if(OSD_X < 0)
970     x -= (osd->widget->allocation.width - OSD_W);
971    
972     if(OSD_Y < 0)
973     y -= (osd->widget->allocation.height - OSD_H);
974    
975 harbaum 70 /* first do a rough test for the OSD area. */
976     /* this is just to avoid an unnecessary detailed test */
977 harbaum 77 if(x > 0 && x < OSD_W && y > 0 && y < OSD_H) {
978 harbaum 76 #ifndef OSD_NO_DPAD
979 harbaum 86 but = osd_check_dpad(x, y);
980 harbaum 76 #endif
981 harbaum 70
982     if(but == OSD_NONE)
983 harbaum 86 but = osd_check_zoom(x, y);
984 harbaum 70 }
985    
986     return but;
987     }
988    
989 harbaum 76 #ifndef OSD_NO_DPAD
990 harbaum 70 static void
991 harbaum 86 osd_dpad_labels(cairo_t *cr, gint x, gint y) {
992 harbaum 70 /* move reference to dpad center */
993     x += D_RAD;
994     y += D_RAD;
995    
996     const static gint offset[][3][2] = {
997     /* left arrow/triangle */
998     { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } },
999     /* right arrow/triangle */
1000     { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } },
1001     /* top arrow/triangle */
1002     { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } },
1003     /* bottom arrow/triangle */
1004     { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } }
1005     };
1006    
1007     int i;
1008     for(i=0;i<4;i++) {
1009     cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]);
1010     cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]);
1011     cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]);
1012     }
1013     }
1014 harbaum 76 #endif
1015 harbaum 70
1016 harbaum 76 #ifdef OSD_GPS_BUTTON
1017     /* draw the satellite dish icon in the center of the dpad */
1018 harbaum 77 #define GPS_V0 (D_RAD/7)
1019 harbaum 70 #define GPS_V1 (D_RAD/10)
1020     #define GPS_V2 (D_RAD/5)
1021    
1022     /* draw a satellite receiver dish */
1023 harbaum 77 /* this is either drawn in the center of the dpad (if present) */
1024     /* or in the middle of the zoom area */
1025 harbaum 70 static void
1026 harbaum 86 osd_dpad_gps(cairo_t *cr, gint x, gint y) {
1027 harbaum 70 /* move reference to dpad center */
1028 harbaum 77 x += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD * 3;
1029     y += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD + GPS_V0;
1030 harbaum 70
1031     cairo_move_to (cr, x-GPS_V0, y+GPS_V0);
1032     cairo_rel_line_to (cr, +GPS_V0, -GPS_V0);
1033     cairo_rel_line_to (cr, +GPS_V0, +GPS_V0);
1034     cairo_close_path (cr);
1035    
1036     cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2);
1037     cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y);
1038     cairo_close_path (cr);
1039    
1040     x += GPS_V1;
1041     cairo_move_to (cr, x, y-GPS_V2);
1042     cairo_rel_line_to (cr, +GPS_V1, -GPS_V1);
1043     }
1044 harbaum 76 #endif
1045 harbaum 70
1046     #define Z_LEN (2*Z_RAD/3)
1047    
1048     static void
1049 harbaum 86 osd_zoom_labels(cairo_t *cr, gint x, gint y) {
1050 harbaum 70 cairo_move_to (cr, x + Z_LEFT - Z_LEN, y + Z_MID);
1051     cairo_line_to (cr, x + Z_LEFT + Z_LEN, y + Z_MID);
1052    
1053     cairo_move_to (cr, x + Z_RIGHT, y + Z_MID - Z_LEN);
1054     cairo_line_to (cr, x + Z_RIGHT, y + Z_MID + Z_LEN);
1055     cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID);
1056     cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID);
1057     }
1058    
1059 harbaum 106 #ifdef OSD_COORDINATES
1060    
1061 harbaum 107 #ifndef OSD_COORDINATES_FONT_SIZE
1062     #define OSD_COORDINATES_FONT_SIZE 12
1063     #endif
1064    
1065 harbaum 108 #define OSD_COORDINATES_OFFSET (OSD_COORDINATES_FONT_SIZE/6)
1066 harbaum 107
1067 harbaum 108 #define OSD_COORDINATES_W (8*OSD_COORDINATES_FONT_SIZE+2*OSD_COORDINATES_OFFSET)
1068     #define OSD_COORDINATES_H (2*OSD_COORDINATES_FONT_SIZE+OSD_COORDINATES_OFFSET)
1069    
1070 harbaum 107 /* these can be overwritten with versions that support */
1071     /* localization */
1072     #ifndef OSD_COORDINATES_CHR_N
1073     #define OSD_COORDINATES_CHR_N "N"
1074     #endif
1075     #ifndef OSD_COORDINATES_CHR_S
1076     #define OSD_COORDINATES_CHR_S "S"
1077     #endif
1078     #ifndef OSD_COORDINATES_CHR_E
1079     #define OSD_COORDINATES_CHR_E "E"
1080     #endif
1081     #ifndef OSD_COORDINATES_CHR_W
1082     #define OSD_COORDINATES_CHR_W "W"
1083     #endif
1084    
1085    
1086    
1087     /* this is the classic geocaching notation */
1088     static char
1089     *osd_latitude_str(float latitude) {
1090     char *c = OSD_COORDINATES_CHR_N;
1091     float integral, fractional;
1092    
1093     if(isnan(latitude))
1094     return NULL;
1095    
1096     if(latitude < 0) {
1097     latitude = fabs(latitude);
1098     c = OSD_COORDINATES_CHR_S;
1099     }
1100    
1101     fractional = modff(latitude, &integral);
1102    
1103     return g_strdup_printf("%s %02d° %06.3f'",
1104     c, (int)integral, fractional*60.0);
1105     }
1106    
1107     static char
1108     *osd_longitude_str(float longitude) {
1109     char *c = OSD_COORDINATES_CHR_E;
1110     float integral, fractional;
1111    
1112     if(isnan(longitude))
1113     return NULL;
1114    
1115     if(longitude < 0) {
1116     longitude = fabs(longitude);
1117     c = OSD_COORDINATES_CHR_W;
1118     }
1119    
1120     fractional = modff(longitude, &integral);
1121    
1122     return g_strdup_printf("%s %03d° %06.3f'",
1123     c, (int)integral, fractional*60.0);
1124     }
1125    
1126 harbaum 106 static void
1127     osd_render_coordinates(osm_gps_map_osd_t *osd)
1128     {
1129     osd_priv_t *priv = (osd_priv_t*)osd->priv;
1130    
1131 harbaum 107 /* get current map position */
1132     gfloat lat, lon;
1133     g_object_get(osd->widget, "latitude", &lat, "longitude", &lon, NULL);
1134    
1135 harbaum 108 /* check if position has changed enough to require redraw */
1136 harbaum 110 if(!isnan(priv->coordinates.lat) && !isnan(priv->coordinates.lon))
1137     /* 1/60000 == 1/1000 minute */
1138     if((fabsf(lat - priv->coordinates.lat) < 1/60000) &&
1139     (fabsf(lon - priv->coordinates.lon) < 1/60000))
1140 harbaum 108 return;
1141    
1142 harbaum 110 priv->coordinates.lat = lat;
1143     priv->coordinates.lon = lon;
1144 harbaum 108
1145 harbaum 111 /* first fill with transparency */
1146 harbaum 110 cairo_t *cr = cairo_create(priv->coordinates.surface);
1147 harbaum 106 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1148 harbaum 111 // cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 0.5);
1149     cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
1150 harbaum 106 cairo_paint(cr);
1151     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1152    
1153 harbaum 107 cairo_select_font_face (cr, "Sans",
1154     CAIRO_FONT_SLANT_NORMAL,
1155     CAIRO_FONT_WEIGHT_BOLD);
1156     cairo_set_font_size (cr, OSD_COORDINATES_FONT_SIZE);
1157    
1158     char *latitude = osd_latitude_str(lat);
1159     char *longitude = osd_longitude_str(lon);
1160    
1161     cairo_text_extents_t lat_extents, lon_extents;
1162     cairo_text_extents (cr, latitude, &lat_extents);
1163     cairo_text_extents (cr, longitude, &lon_extents);
1164    
1165     cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1166     cairo_set_line_width (cr, OSD_COORDINATES_FONT_SIZE/6);
1167 harbaum 108 cairo_move_to (cr,
1168     (OSD_COORDINATES_W - lat_extents.width)/2,
1169 harbaum 107 OSD_COORDINATES_OFFSET - lat_extents.y_bearing);
1170     cairo_text_path (cr, latitude);
1171     cairo_move_to (cr,
1172 harbaum 108 (OSD_COORDINATES_W - lon_extents.width)/2,
1173 harbaum 107 OSD_COORDINATES_OFFSET - lon_extents.y_bearing +
1174     OSD_COORDINATES_FONT_SIZE);
1175     cairo_text_path (cr, longitude);
1176     cairo_stroke (cr);
1177    
1178     cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
1179     cairo_move_to (cr,
1180 harbaum 108 (OSD_COORDINATES_W - lat_extents.width)/2,
1181 harbaum 107 OSD_COORDINATES_OFFSET - lat_extents.y_bearing);
1182     cairo_show_text (cr, latitude);
1183     cairo_move_to (cr,
1184 harbaum 108 (OSD_COORDINATES_W - lon_extents.width)/2,
1185 harbaum 107 OSD_COORDINATES_OFFSET - lon_extents.y_bearing +
1186     OSD_COORDINATES_FONT_SIZE);
1187     cairo_show_text (cr, longitude);
1188    
1189     g_free(latitude);
1190     g_free(longitude);
1191    
1192 harbaum 106 cairo_destroy(cr);
1193     }
1194     #endif // OSD_COORDINATES
1195    
1196 harbaum 105 #ifdef OSD_CROSSHAIR
1197    
1198     #ifndef OSD_CROSSHAIR_RADIUS
1199 harbaum 106 #define OSD_CROSSHAIR_RADIUS 10
1200 harbaum 105 #endif
1201    
1202 harbaum 106 #define OSD_CROSSHAIR_TICK (OSD_CROSSHAIR_RADIUS/2)
1203     #define OSD_CROSSHAIR_BORDER (OSD_CROSSHAIR_TICK + OSD_CROSSHAIR_RADIUS/4)
1204     #define OSD_CROSSHAIR_W ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2)
1205     #define OSD_CROSSHAIR_H ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2)
1206 harbaum 105
1207     static void
1208 harbaum 106 osd_render_crosshair_shape(cairo_t *cr) {
1209     cairo_arc (cr, OSD_CROSSHAIR_W/2, OSD_CROSSHAIR_H/2,
1210     OSD_CROSSHAIR_RADIUS, 0, 2*M_PI);
1211    
1212     cairo_move_to (cr, OSD_CROSSHAIR_W/2 - OSD_CROSSHAIR_RADIUS,
1213     OSD_CROSSHAIR_H/2);
1214     cairo_rel_line_to (cr, -OSD_CROSSHAIR_TICK, 0);
1215     cairo_move_to (cr, OSD_CROSSHAIR_W/2 + OSD_CROSSHAIR_RADIUS,
1216     OSD_CROSSHAIR_H/2);
1217     cairo_rel_line_to (cr, OSD_CROSSHAIR_TICK, 0);
1218    
1219     cairo_move_to (cr, OSD_CROSSHAIR_W/2,
1220     OSD_CROSSHAIR_H/2 - OSD_CROSSHAIR_RADIUS);
1221     cairo_rel_line_to (cr, 0, -OSD_CROSSHAIR_TICK);
1222     cairo_move_to (cr, OSD_CROSSHAIR_W/2,
1223     OSD_CROSSHAIR_H/2 + OSD_CROSSHAIR_RADIUS);
1224     cairo_rel_line_to (cr, 0, OSD_CROSSHAIR_TICK);
1225    
1226     cairo_stroke (cr);
1227     }
1228    
1229     static void
1230 harbaum 105 osd_render_crosshair(osm_gps_map_osd_t *osd)
1231     {
1232     osd_priv_t *priv = (osd_priv_t*)osd->priv;
1233    
1234 harbaum 110 if(priv->crosshair.rendered)
1235     return;
1236    
1237     priv->crosshair.rendered = TRUE;
1238    
1239 harbaum 105 /* first fill with transparency */
1240 harbaum 110 cairo_t *cr = cairo_create(priv->crosshair.surface);
1241 harbaum 105 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1242 harbaum 106 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
1243 harbaum 105 cairo_paint(cr);
1244     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1245    
1246 harbaum 106 cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
1247    
1248     cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5);
1249     cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/2);
1250     osd_render_crosshair_shape(cr);
1251    
1252     cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
1253     cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/4);
1254     osd_render_crosshair_shape(cr);
1255    
1256 harbaum 105 cairo_destroy(cr);
1257     }
1258     #endif
1259    
1260     #ifdef OSD_SCALE
1261    
1262     #ifndef OSD_SCALE_FONT_SIZE
1263     #define OSD_SCALE_FONT_SIZE 12
1264     #endif
1265     #define OSD_SCALE_W (10*OSD_SCALE_FONT_SIZE)
1266     #define OSD_SCALE_H (5*OSD_SCALE_FONT_SIZE/2)
1267    
1268 harbaum 103 /* various parameters used to create the scale */
1269     #define OSD_SCALE_H2 (OSD_SCALE_H/2)
1270     #define OSD_SCALE_TICK (2*OSD_SCALE_FONT_SIZE/3)
1271     #define OSD_SCALE_M (OSD_SCALE_H2 - OSD_SCALE_TICK)
1272     #define OSD_SCALE_I (OSD_SCALE_H2 + OSD_SCALE_TICK)
1273     #define OSD_SCALE_FD (OSD_SCALE_FONT_SIZE/4)
1274 harbaum 99
1275 harbaum 70 static void
1276 harbaum 98 osd_render_scale(osm_gps_map_osd_t *osd)
1277     {
1278 harbaum 86 osd_priv_t *priv = (osd_priv_t*)osd->priv;
1279 harbaum 103
1280     /* this only needs to be rendered if the zoom has changed */
1281     gint zoom;
1282     g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
1283 harbaum 110 if(zoom == priv->scale.zoom)
1284 harbaum 103 return;
1285    
1286 harbaum 110 priv->scale.zoom = zoom;
1287 harbaum 103
1288 harbaum 99 float m_per_pix = osm_gps_map_get_scale(OSM_GPS_MAP(osd->widget));
1289 harbaum 70
1290 harbaum 98 /* first fill with transparency */
1291 harbaum 110 cairo_t *cr = cairo_create(priv->scale.surface);
1292 harbaum 98 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1293 harbaum 100 cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
1294 harbaum 103 // pink for testing: cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2);
1295 harbaum 98 cairo_paint(cr);
1296     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1297    
1298     /* determine the size of the scale width in meters */
1299 harbaum 103 float width = (OSD_SCALE_W-OSD_SCALE_FONT_SIZE/6) * m_per_pix;
1300 harbaum 102
1301 harbaum 98 /* scale this to useful values */
1302     int exp = logf(width)*M_LOG10E;
1303     int mant = width/pow(10,exp);
1304 harbaum 99 int width_metric = mant * pow(10,exp);
1305 harbaum 103 char *dist_str = NULL;
1306     if(width_metric<1000)
1307     dist_str = g_strdup_printf("%u m", width_metric);
1308     else
1309     dist_str = g_strdup_printf("%u km", width_metric/1000);
1310 harbaum 99 width_metric /= m_per_pix;
1311    
1312 harbaum 102 /* and now the hard part: scale for useful imperial values :-( */
1313     /* try to convert to feet, 1ft == 0.3048 m */
1314     width /= 0.3048;
1315     float imp_scale = 0.3048;
1316     char *dist_imp_unit = "ft";
1317 harbaum 99
1318 harbaum 102 if(width >= 100) {
1319     /* 1yd == 3 feet */
1320     width /= 3.0;
1321     imp_scale *= 3.0;
1322     dist_imp_unit = "yd";
1323    
1324     if(width >= 1760.0) {
1325     /* 1mi == 1760 yd */
1326     width /= 1760.0;
1327     imp_scale *= 1760.0;
1328     dist_imp_unit = "mi";
1329     }
1330     }
1331    
1332 harbaum 103 /* also convert this to full tens/hundreds */
1333     exp = logf(width)*M_LOG10E;
1334     mant = width/pow(10,exp);
1335     int width_imp = mant * pow(10,exp);
1336     char *dist_str_imp = g_strdup_printf("%u %s", width_imp, dist_imp_unit);
1337 harbaum 102
1338 harbaum 103 /* convert back to pixels */
1339     width_imp *= imp_scale;
1340     width_imp /= m_per_pix;
1341    
1342 harbaum 99 cairo_select_font_face (cr, "Sans",
1343     CAIRO_FONT_SLANT_NORMAL,
1344     CAIRO_FONT_WEIGHT_BOLD);
1345 harbaum 102 cairo_set_font_size (cr, OSD_SCALE_FONT_SIZE);
1346 harbaum 99 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
1347    
1348     cairo_text_extents_t extents;
1349     cairo_text_extents (cr, dist_str, &extents);
1350    
1351 harbaum 100 cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1352 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6);
1353     cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD);
1354 harbaum 100 cairo_text_path (cr, dist_str);
1355     cairo_stroke (cr);
1356 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD,
1357     OSD_SCALE_H2+OSD_SCALE_FD + extents.height);
1358     cairo_text_path (cr, dist_str_imp);
1359     cairo_stroke (cr);
1360 harbaum 100
1361     cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
1362 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD);
1363 harbaum 99 cairo_show_text (cr, dist_str);
1364 harbaum 103 cairo_move_to (cr, 2*OSD_SCALE_FD,
1365     OSD_SCALE_H2+OSD_SCALE_FD + extents.height);
1366     cairo_show_text (cr, dist_str_imp);
1367 harbaum 99
1368 harbaum 103 g_free(dist_str);
1369     g_free(dist_str_imp);
1370    
1371 harbaum 99 /* draw white line */
1372     cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
1373     cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
1374 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/3);
1375     cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M);
1376     cairo_rel_line_to (cr, 0, OSD_SCALE_TICK);
1377 harbaum 99 cairo_rel_line_to (cr, width_metric, 0);
1378 harbaum 103 cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1379 harbaum 99 cairo_stroke(cr);
1380 harbaum 103 cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I);
1381     cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1382     cairo_rel_line_to (cr, width_imp, 0);
1383     cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK);
1384     cairo_stroke(cr);
1385 harbaum 99
1386     /* draw black line */
1387     cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
1388 harbaum 103 cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6);
1389     cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M);
1390     cairo_rel_line_to (cr, 0, OSD_SCALE_TICK);
1391 harbaum 99 cairo_rel_line_to (cr, width_metric, 0);
1392 harbaum 103 cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1393 harbaum 99 cairo_stroke(cr);
1394 harbaum 103 cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I);
1395     cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK);
1396     cairo_rel_line_to (cr, width_imp, 0);
1397     cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK);
1398     cairo_stroke(cr);
1399 harbaum 99
1400 harbaum 98 cairo_destroy(cr);
1401     }
1402 harbaum 105 #endif
1403 harbaum 98
1404     static void
1405 harbaum 108 osd_render_controls(osm_gps_map_osd_t *osd)
1406 harbaum 98 {
1407     osd_priv_t *priv = (osd_priv_t*)osd->priv;
1408    
1409 harbaum 108 if(priv->controls.rendered
1410     #ifdef OSD_GPS_BUTTON
1411     && (priv->controls.gps_enabled == (osd->cb != NULL))
1412     #endif
1413     )
1414     return;
1415    
1416     #ifdef OSD_GPS_BUTTON
1417     priv->controls.gps_enabled = (osd->cb != NULL);
1418     #endif
1419 harbaum 110 priv->controls.rendered = TRUE;
1420 harbaum 108
1421 harbaum 86 #ifndef OSD_COLOR
1422     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
1423     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
1424     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
1425 harbaum 74 #endif
1426 harbaum 70
1427     /* first fill with transparency */
1428 harbaum 108 cairo_t *cr = cairo_create(priv->controls.surface);
1429 harbaum 70 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1430     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
1431     cairo_paint(cr);
1432     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1433    
1434     /* --------- draw zoom and dpad shape shadow ----------- */
1435 harbaum 74 #ifdef OSD_SHADOW_ENABLE
1436 harbaum 86 osd_zoom_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
1437     osd_shape_shadow(cr);
1438 harbaum 76 #ifndef OSD_NO_DPAD
1439 harbaum 86 osd_dpad_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
1440     osd_shape_shadow(cr);
1441 harbaum 74 #endif
1442 harbaum 76 #endif
1443 harbaum 70
1444     /* --------- draw zoom and dpad shape ----------- */
1445    
1446 harbaum 86 osd_zoom_shape(cr, 1, 1);
1447 harbaum 74 #ifndef OSD_COLOR
1448 harbaum 86 osd_shape(cr, &bg, &fg);
1449 harbaum 74 #else
1450 harbaum 86 osd_shape(cr);
1451 harbaum 74 #endif
1452 harbaum 76 #ifndef OSD_NO_DPAD
1453 harbaum 86 osd_dpad_shape(cr, 1, 1);
1454 harbaum 74 #ifndef OSD_COLOR
1455 harbaum 86 osd_shape(cr, &bg, &fg);
1456 harbaum 74 #else
1457 harbaum 86 osd_shape(cr);
1458 harbaum 74 #endif
1459 harbaum 76 #endif
1460 harbaum 70
1461     /* --------- draw zoom and dpad labels --------- */
1462    
1463 harbaum 74 #ifdef OSD_SHADOW_ENABLE
1464 harbaum 87 osd_labels_shadow(cr, Z_RAD/3, TRUE);
1465 harbaum 86 osd_zoom_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1466 harbaum 76 #ifndef OSD_NO_DPAD
1467 harbaum 86 osd_dpad_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1468 harbaum 76 #endif
1469 harbaum 87 cairo_stroke(cr);
1470 harbaum 76 #ifdef OSD_GPS_BUTTON
1471 harbaum 87 osd_labels_shadow(cr, Z_RAD/6, osd->cb != NULL);
1472 harbaum 86 osd_dpad_gps(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
1473 harbaum 87 cairo_stroke(cr);
1474 harbaum 74 #endif
1475 harbaum 76 #endif
1476 harbaum 70
1477 harbaum 74 #ifndef OSD_COLOR
1478 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
1479 harbaum 74 #else
1480 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE);
1481 harbaum 74 #endif
1482 harbaum 87 osd_zoom_labels(cr, 1, 1);
1483     #ifndef OSD_NO_DPAD
1484     osd_dpad_labels(cr, 1, 1);
1485     #endif
1486     cairo_stroke(cr);
1487    
1488 harbaum 74 #ifndef OSD_COLOR
1489 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL, &fg, &da);
1490 harbaum 74 #else
1491 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL);
1492 harbaum 74 #endif
1493 harbaum 87 #ifdef OSD_GPS_BUTTON
1494     osd_dpad_gps(cr, 1, 1);
1495 harbaum 76 #endif
1496 harbaum 87 cairo_stroke(cr);
1497 harbaum 70
1498     cairo_destroy(cr);
1499 harbaum 108 }
1500 harbaum 86
1501 harbaum 108 static void
1502     osd_render(osm_gps_map_osd_t *osd)
1503     {
1504 harbaum 111 /* this function is actually called pretty often since the */
1505     /* OSD contents may have changed (due to a coordinate/zoom change). */
1506     /* The different OSD parts have to make sure that they don't */
1507     /* render unneccessarily often and thus waste CPU power */
1508    
1509 harbaum 108 osd_render_controls(osd);
1510    
1511 harbaum 88 #ifdef OSD_SOURCE_SEL
1512 harbaum 111 osd_render_source_sel(osd, FALSE);
1513 harbaum 88 #endif
1514 harbaum 98
1515     #ifdef OSD_SCALE
1516     osd_render_scale(osd);
1517     #endif
1518 harbaum 105
1519     #ifdef OSD_CROSSHAIR
1520     osd_render_crosshair(osd);
1521     #endif
1522 harbaum 106
1523     #ifdef OSD_COORDINATES
1524     osd_render_coordinates(osd);
1525     #endif
1526 harbaum 70 }
1527    
1528     static void
1529 harbaum 86 osd_draw(osm_gps_map_osd_t *osd, GdkDrawable *drawable)
1530 harbaum 70 {
1531 harbaum 73 osd_priv_t *priv = (osd_priv_t*)osd->priv;
1532 harbaum 70
1533     /* OSD itself uses some off-screen rendering, so check if the */
1534     /* offscreen buffer is present and create it if not */
1535 harbaum 108 if(!priv->controls.surface) {
1536 harbaum 70 /* create overlay ... */
1537 harbaum 108 priv->controls.surface =
1538 harbaum 86 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W+2, OSD_H+2);
1539    
1540 harbaum 108 priv->controls.rendered = FALSE;
1541     #ifdef OSD_GPS_BUTTON
1542     priv->controls.gps_enabled = FALSE;
1543     #endif
1544    
1545 harbaum 88 #ifdef OSD_SOURCE_SEL
1546 harbaum 86 /* the initial OSD state is alway not-expanded */
1547 harbaum 110 priv->source_sel.surface =
1548 harbaum 86 cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1549     OSD_S_W+2, OSD_S_H+2);
1550 harbaum 111 priv->source_sel.rendered = FALSE;
1551 harbaum 88 #endif
1552 harbaum 86
1553 harbaum 98 #ifdef OSD_SCALE
1554 harbaum 110 priv->scale.surface =
1555 harbaum 98 cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1556 harbaum 103 OSD_SCALE_W, OSD_SCALE_H);
1557 harbaum 110 priv->scale.zoom = -1;
1558 harbaum 98 #endif
1559    
1560 harbaum 105 #ifdef OSD_CROSSHAIR
1561 harbaum 110 priv->crosshair.surface =
1562 harbaum 105 cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1563     OSD_CROSSHAIR_W, OSD_CROSSHAIR_H);
1564 harbaum 110 priv->crosshair.rendered = FALSE;
1565 harbaum 105 #endif
1566    
1567 harbaum 106 #ifdef OSD_COORDINATES
1568 harbaum 110 priv->coordinates.surface =
1569 harbaum 106 cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1570     OSD_COORDINATES_W, OSD_COORDINATES_H);
1571 harbaum 108
1572 harbaum 110 priv->coordinates.lat = priv->coordinates.lon = OSM_GPS_MAP_INVALID;
1573 harbaum 106 #endif
1574    
1575 harbaum 70 /* ... and render it */
1576 harbaum 86 osd_render(osd);
1577 harbaum 70 }
1578    
1579     // now draw this onto the original context
1580 harbaum 75 cairo_t *cr = gdk_cairo_create(drawable);
1581 harbaum 77
1582 harbaum 106 int x, y;
1583 harbaum 77
1584 harbaum 106 #ifdef OSD_SCALE
1585     x = OSD_X;
1586     y = -OSD_Y;
1587     if(x < 0) x += osd->widget->allocation.width - OSD_SCALE_W;
1588     if(y < 0) y += osd->widget->allocation.height - OSD_SCALE_H;
1589 harbaum 77
1590 harbaum 110 cairo_set_source_surface(cr, priv->scale.surface, x, y);
1591 harbaum 106 cairo_paint(cr);
1592     #endif
1593    
1594     #ifdef OSD_CROSSHAIR
1595     x = (osd->widget->allocation.width - OSD_CROSSHAIR_W)/2;
1596     y = (osd->widget->allocation.height - OSD_CROSSHAIR_H)/2;
1597    
1598 harbaum 110 cairo_set_source_surface(cr, priv->crosshair.surface, x, y);
1599 harbaum 106 cairo_paint(cr);
1600     #endif
1601    
1602     #ifdef OSD_COORDINATES
1603     x = -OSD_X;
1604     y = -OSD_Y;
1605     if(x < 0) x += osd->widget->allocation.width - OSD_COORDINATES_W;
1606     if(y < 0) y += osd->widget->allocation.height - OSD_COORDINATES_H;
1607    
1608 harbaum 110 cairo_set_source_surface(cr, priv->coordinates.surface, x, y);
1609 harbaum 106 cairo_paint(cr);
1610     #endif
1611    
1612     x = OSD_X;
1613     if(x < 0)
1614     x += osd->widget->allocation.width - OSD_W;
1615    
1616     y = OSD_Y;
1617     if(y < 0)
1618     y += osd->widget->allocation.height - OSD_H;
1619    
1620 harbaum 108 cairo_set_source_surface(cr, priv->controls.surface, x, y);
1621 harbaum 70 cairo_paint(cr);
1622 harbaum 86
1623     #ifdef OSD_SOURCE_SEL
1624 harbaum 110 if(!priv->source_sel.handler_id) {
1625 harbaum 86 /* the OSD source selection is not being animated */
1626 harbaum 110 if(!priv->source_sel.expanded)
1627 harbaum 86 x = osd->widget->allocation.width - OSD_S_W;
1628     else
1629     x = osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
1630     } else
1631 harbaum 110 x = priv->source_sel.shift;
1632 harbaum 86
1633     y = OSD_S_Y;
1634     if(OSD_S_Y < 0) {
1635 harbaum 110 if(!priv->source_sel.expanded)
1636 harbaum 86 y = osd->widget->allocation.height - OSD_S_H + OSD_S_Y;
1637     else
1638     y = osd->widget->allocation.height - OSD_S_EXP_H + OSD_S_Y;
1639     }
1640    
1641 harbaum 110 cairo_set_source_surface(cr, priv->source_sel.surface, x, y);
1642 harbaum 86 cairo_paint(cr);
1643     #endif
1644    
1645 harbaum 70 cairo_destroy(cr);
1646     }
1647    
1648     static void
1649 harbaum 86 osd_free(osm_gps_map_osd_t *osd)
1650 harbaum 70 {
1651 harbaum 73 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
1652 harbaum 70
1653 harbaum 108 if (priv->controls.surface)
1654     cairo_surface_destroy(priv->controls.surface);
1655 harbaum 88
1656     #ifdef OSD_SOURCE_SEL
1657 harbaum 110 if(priv->source_sel.handler_id)
1658     gtk_timeout_remove(priv->source_sel.handler_id);
1659 harbaum 86
1660 harbaum 110 if (priv->source_sel.surface)
1661     cairo_surface_destroy(priv->source_sel.surface);
1662 harbaum 88 #endif
1663 harbaum 86
1664 harbaum 98 #ifdef OSD_SCALE
1665 harbaum 110 if (priv->scale.surface)
1666     cairo_surface_destroy(priv->scale.surface);
1667 harbaum 98 #endif
1668    
1669 harbaum 105 #ifdef OSD_CROSSHAIR
1670 harbaum 110 if (priv->crosshair.surface)
1671     cairo_surface_destroy(priv->crosshair.surface);
1672 harbaum 105 #endif
1673    
1674 harbaum 106 #ifdef OSD_COORDINATES
1675 harbaum 110 if (priv->coordinates.surface)
1676     cairo_surface_destroy(priv->coordinates.surface);
1677 harbaum 106 #endif
1678    
1679 harbaum 112 #ifdef OSD_BALLOON
1680     if (priv->balloon.surface)
1681     cairo_surface_destroy(priv->balloon.surface);
1682     #endif
1683    
1684 harbaum 73 g_free(priv);
1685     }
1686    
1687 harbaum 87 static gboolean
1688     osd_busy(osm_gps_map_osd_t *osd)
1689     {
1690 harbaum 88 #ifdef OSD_SOURCE_SEL
1691 harbaum 87 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
1692 harbaum 110 return (priv->source_sel.handler_id != 0);
1693 harbaum 88 #else
1694     return FALSE;
1695     #endif
1696 harbaum 87 }
1697    
1698 harbaum 73 static osm_gps_map_osd_t osd_classic = {
1699 harbaum 88 .widget = NULL,
1700    
1701 harbaum 86 .draw = osd_draw,
1702     .check = osd_check,
1703     .render = osd_render,
1704     .free = osd_free,
1705 harbaum 87 .busy = osd_busy,
1706 harbaum 73
1707     .cb = NULL,
1708     .data = NULL,
1709    
1710     .priv = NULL
1711     };
1712    
1713     /* this is the only function that's externally visible */
1714     void
1715     osm_gps_map_osd_classic_init(OsmGpsMap *map)
1716     {
1717     osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);
1718    
1719 harbaum 112 #ifdef OSD_BALLOON
1720     priv->balloon.lat = OSM_GPS_MAP_INVALID;
1721     priv->balloon.lon = OSM_GPS_MAP_INVALID;
1722     #endif
1723    
1724 harbaum 73 osd_classic.priv = priv;
1725    
1726     osm_gps_map_register_osd(map, &osd_classic);
1727     }
1728    
1729 harbaum 76 #ifdef OSD_GPS_BUTTON
1730 harbaum 74 /* below are osd specific functions which aren't used by osm-gps-map */
1731     /* but instead are to be used by the main application */
1732 harbaum 76 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,
1733     gpointer data) {
1734 harbaum 73 osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
1735     g_return_if_fail (osd);
1736    
1737     osd->cb = cb;
1738     osd->data = data;
1739    
1740 harbaum 70 /* this may have changed the state of the gps button */
1741     /* we thus re-render the overlay */
1742 harbaum 73 osd->render(osd);
1743 harbaum 70
1744 harbaum 73 osm_gps_map_redraw(map);
1745 harbaum 70 }
1746 harbaum 76 #endif
1747 harbaum 86
1748     osd_button_t
1749     osm_gps_map_osd_check(OsmGpsMap *map, gint x, gint y) {
1750     osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
1751     g_return_val_if_fail (osd, OSD_NONE);
1752    
1753     return osd_check(osd, x, y);
1754     }