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

Parent Directory Parent Directory | Revision Log Revision Log


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