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

Parent Directory Parent Directory | Revision Log Revision Log


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