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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 87 - (hide annotations)
Mon Aug 31 12:01:28 2009 UTC (14 years, 8 months ago) by harbaum
File MIME type: text/plain
File size: 26051 byte(s)
Map source list
1 harbaum 71 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 4 -*- */
2     /* vim:set et sw=4 ts=4 cino=t0,(0: */
3 harbaum 70 /*
4     * Copyright (C) Till Harbaum 2009 <till@harbaum.org>
5     *
6     * osm-gps-map is free software: you can redistribute it and/or modify it
7     * under the terms of the GNU General Public License as published by the
8     * Free Software Foundation, either version 3 of the License, or
9     * (at your option) any later version.
10     *
11     * osm-gps-map is distributed in the hope that it will be useful, but
12     * WITHOUT ANY WARRANTY; without even the implied warranty of
13     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14     * See the GNU General Public License for more details.
15     *
16     * You should have received a copy of the GNU General Public License along
17     * with this program. If not, see <http://www.gnu.org/licenses/>.
18     */
19    
20 harbaum 73 #include "config.h"
21     #include <stdlib.h> // abs
22 harbaum 87 #include <math.h> // M_PI/cos()
23 harbaum 70
24 harbaum 71 /* parameters that can be overwritten from the config file: */
25 harbaum 77 /* OSD_DIAMETER */
26     /* OSD_X, OSD_Y */
27 harbaum 71
28     #ifndef USE_CAIRO
29     #error "OSD control display lacks a non-cairo implementation!"
30 harbaum 70 #endif
31    
32 harbaum 71 #include <cairo.h>
33    
34     #include "osm-gps-map.h"
35 harbaum 73 #include "osm-gps-map-osd-classic.h"
36 harbaum 71
37 harbaum 70 //the osd controls
38     typedef struct {
39 harbaum 74 /* the offscreen representation of the OSD */
40     cairo_surface_t *overlay;
41 harbaum 86
42 harbaum 87 /* values to handle the "source" menu */
43 harbaum 86 cairo_surface_t *map_source;
44     gboolean expanded;
45     gint shift, dir, count;
46     gint handler_id;
47 harbaum 87 gint width, height;
48    
49 harbaum 70 } osd_priv_t;
50    
51     /* position and extent of bounding box */
52 harbaum 77 #ifndef OSD_X
53 harbaum 70 #define OSD_X (10)
54 harbaum 77 #endif
55    
56     #ifndef OSD_Y
57 harbaum 70 #define OSD_Y (10)
58 harbaum 77 #endif
59 harbaum 70
60     /* parameters of the direction shape */
61 harbaum 77 #ifndef OSD_DIAMETER
62 harbaum 70 #define D_RAD (30) // diameter of dpad
63     #else
64 harbaum 77 #define D_RAD (OSD_DIAMETER)
65 harbaum 70 #endif
66     #define D_TIP (4*D_RAD/5) // distance of arrow tip from dpad center
67     #define D_LEN (D_RAD/4) // length of arrow
68     #define D_WID (D_LEN) // width of arrow
69    
70     /* parameters of the "zoom" pad */
71     #define Z_STEP (D_RAD/4) // distance between dpad and zoom
72     #define Z_RAD (D_RAD/2) // radius of "caps" of zoom bar
73    
74 harbaum 74 #ifdef OSD_SHADOW_ENABLE
75 harbaum 70 /* shadow also depends on control size */
76     #define OSD_SHADOW (D_RAD/6)
77 harbaum 74 #else
78     #define OSD_SHADOW (0)
79     #endif
80 harbaum 70
81 harbaum 77 /* normally the GPS button is in the center of the dpad. if there's */
82     /* no dpad it will go into the zoom area */
83     #if defined(OSD_GPS_BUTTON) && defined(OSD_NO_DPAD)
84     #define Z_GPS 1
85     #else
86     #define Z_GPS 0
87     #endif
88    
89 harbaum 70 /* total width and height of controls incl. shadow */
90 harbaum 77 #define OSD_W (2*D_RAD + OSD_SHADOW + Z_GPS * 2 * Z_RAD)
91     #if !Z_GPS
92 harbaum 70 #define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)
93 harbaum 77 #else
94     #define OSD_H (2*Z_RAD + OSD_SHADOW)
95     #endif
96 harbaum 70
97 harbaum 74 #ifdef OSD_SHADOW_ENABLE
98 harbaum 70 #define OSD_LBL_SHADOW (OSD_SHADOW/2)
99 harbaum 74 #endif
100 harbaum 70
101 harbaum 77 #define Z_TOP ((1-Z_GPS) * (2 * D_RAD + Z_STEP))
102    
103 harbaum 70 #define Z_MID (Z_TOP + Z_RAD)
104     #define Z_BOT (Z_MID + Z_RAD)
105     #define Z_LEFT (Z_RAD)
106 harbaum 77 #define Z_RIGHT (2 * D_RAD - Z_RAD + Z_GPS * 2 * Z_RAD)
107     #define Z_CENTER ((Z_RIGHT + Z_LEFT)/2)
108 harbaum 70
109     /* create the cairo shape used for the zoom buttons */
110     static void
111 harbaum 86 osd_zoom_shape(cairo_t *cr, gint x, gint y)
112 harbaum 71 {
113 harbaum 70 cairo_move_to (cr, x+Z_LEFT, y+Z_TOP);
114     cairo_line_to (cr, x+Z_RIGHT, y+Z_TOP);
115     cairo_arc (cr, x+Z_RIGHT, y+Z_MID, Z_RAD, -M_PI/2, M_PI/2);
116     cairo_line_to (cr, x+Z_LEFT, y+Z_BOT);
117     cairo_arc (cr, x+Z_LEFT, y+Z_MID, Z_RAD, M_PI/2, -M_PI/2);
118     }
119    
120 harbaum 86 /* ------------------- color/shadow functions ----------------- */
121    
122     #ifndef OSD_COLOR
123     /* if no color has been specified we just use the gdks default colors */
124     static void
125     osd_labels(cairo_t *cr, gint width, gboolean enabled,
126     GdkColor *fg, GdkColor *disabled) {
127     if(enabled) gdk_cairo_set_source_color(cr, fg);
128     else gdk_cairo_set_source_color(cr, disabled);
129     cairo_set_line_width (cr, width);
130     }
131     #else
132     static void
133     osd_labels(cairo_t *cr, gint width, gboolean enabled) {
134     if(enabled) cairo_set_source_rgb (cr, OSD_COLOR);
135     else cairo_set_source_rgb (cr, OSD_COLOR_DISABLED);
136     cairo_set_line_width (cr, width);
137     }
138     #endif
139    
140     #ifdef OSD_SHADOW_ENABLE
141     static void
142     osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) {
143     cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15);
144     cairo_set_line_width (cr, width);
145     }
146     #endif
147    
148 harbaum 76 #ifndef OSD_NO_DPAD
149 harbaum 70 /* create the cairo shape used for the dpad */
150     static void
151 harbaum 86 osd_dpad_shape(cairo_t *cr, gint x, gint y)
152 harbaum 71 {
153 harbaum 70 cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);
154     }
155 harbaum 76 #endif
156 harbaum 70
157 harbaum 86 #ifdef OSD_SHADOW_ENABLE
158     static void
159     osd_shape_shadow(cairo_t *cr) {
160     cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
161     cairo_fill (cr);
162     cairo_stroke (cr);
163     }
164     #endif
165    
166     #ifndef OSD_COLOR
167     /* if no color has been specified we just use the gdks default colors */
168     static void
169     osd_shape(cairo_t *cr, GdkColor *bg, GdkColor *fg) {
170     gdk_cairo_set_source_color(cr, bg);
171     cairo_fill_preserve (cr);
172     gdk_cairo_set_source_color(cr, fg);
173     cairo_set_line_width (cr, 1);
174     cairo_stroke (cr);
175     }
176     #else
177     static void
178     osd_shape(cairo_t *cr) {
179     cairo_set_source_rgb (cr, OSD_COLOR_BG);
180     cairo_fill_preserve (cr);
181     cairo_set_source_rgb (cr, OSD_COLOR);
182     cairo_set_line_width (cr, 1);
183     cairo_stroke (cr);
184     }
185     #endif
186    
187    
188 harbaum 70 static gboolean
189     osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)
190     {
191     return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);
192     }
193    
194 harbaum 76 #ifndef OSD_NO_DPAD
195 harbaum 70 /* check whether x/y is within the dpad */
196     static osd_button_t
197 harbaum 86 osd_check_dpad(gint x, gint y)
198 harbaum 70 {
199     /* within entire dpad circle */
200 harbaum 77 if( osm_gps_map_in_circle(x, y, D_RAD, D_RAD, D_RAD))
201 harbaum 70 {
202     /* convert into position relative to dpads centre */
203 harbaum 77 x -= D_RAD;
204     y -= D_RAD;
205 harbaum 70
206 harbaum 76 #ifdef OSD_GPS_BUTTON
207 harbaum 70 /* check for dpad center goes here! */
208     if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3))
209     return OSD_GPS;
210 harbaum 76 #endif
211 harbaum 70
212     if( y < 0 && abs(x) < abs(y))
213     return OSD_UP;
214    
215     if( y > 0 && abs(x) < abs(y))
216     return OSD_DOWN;
217    
218     if( x < 0 && abs(y) < abs(x))
219     return OSD_LEFT;
220    
221     if( x > 0 && abs(y) < abs(x))
222     return OSD_RIGHT;
223    
224     return OSD_BG;
225     }
226     return OSD_NONE;
227     }
228 harbaum 76 #endif
229 harbaum 70
230     /* check whether x/y is within the zoom pads */
231     static osd_button_t
232 harbaum 86 osd_check_zoom(gint x, gint y) {
233 harbaum 77 if( x > 0 && x < OSD_W && y > Z_TOP && y < Z_BOT) {
234 harbaum 70
235     /* within circle around (-) label */
236 harbaum 77 if( osm_gps_map_in_circle(x, y, Z_LEFT, Z_MID, Z_RAD))
237 harbaum 70 return OSD_OUT;
238    
239 harbaum 77 /* within circle around (+) label */
240     if( osm_gps_map_in_circle(x, y, Z_RIGHT, Z_MID, Z_RAD))
241     return OSD_IN;
242    
243     #if Z_GPS == 1
244     /* within square around center */
245     if( x > Z_CENTER - Z_RAD && x < Z_CENTER + Z_RAD)
246     return OSD_GPS;
247     #endif
248    
249 harbaum 70 /* between center of (-) button and center of entire zoom control area */
250 harbaum 77 if(x > OSD_LEFT && x < D_RAD)
251 harbaum 70 return OSD_OUT;
252    
253     /* between center of (+) button and center of entire zoom control area */
254 harbaum 77 if(x < OSD_RIGHT && x > D_RAD)
255 harbaum 70 return OSD_IN;
256     }
257    
258     return OSD_NONE;
259     }
260    
261 harbaum 86 /* place source selection at right border */
262     #define OSD_S_RAD (Z_RAD)
263     #define OSD_S_X (-OSD_X)
264     #define OSD_S_Y (OSD_Y)
265     #define OSD_S_PW (2 * Z_RAD)
266     #define OSD_S_W (OSD_S_PW)
267     #define OSD_S_PH (2 * Z_RAD)
268     #define OSD_S_H (OSD_S_PH + OSD_SHADOW)
269    
270 harbaum 87 /* size of usable area when expanded */
271     #define OSD_S_AREA_W (priv->width)
272     #define OSD_S_AREA_H (priv->height)
273 harbaum 86 #define OSD_S_EXP_W (OSD_S_PW + OSD_S_AREA_W + OSD_SHADOW)
274     #define OSD_S_EXP_H (OSD_S_AREA_H + OSD_SHADOW)
275    
276     /* internal value to draw the arrow on the "puller" */
277     #define OSD_S_D0 (OSD_S_RAD/2)
278 harbaum 87 #ifndef OSD_FONT_SIZE
279     #define OSD_FONT_SIZE 16.0
280     #endif
281     #define OSD_TEXT_BORDER (OSD_FONT_SIZE/2)
282     #define OSD_TEXT_SKIP (OSD_FONT_SIZE/8)
283 harbaum 86
284     static void
285     osd_source_shape(osd_priv_t *priv, cairo_t *cr, gint x, gint y) {
286     if(!priv->expanded) {
287     /* just draw the puller */
288     cairo_move_to (cr, x + OSD_S_PW, y + OSD_S_PH);
289     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
290     cairo_line_to (cr, x + OSD_S_PW, y);
291     } else {
292     /* draw the puller and the area itself */
293     cairo_move_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y + OSD_S_AREA_H);
294     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H);
295     if(OSD_S_Y > 0) {
296     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_PH);
297     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
298     } else {
299     cairo_arc (cr, x+OSD_S_RAD, y+OSD_S_AREA_H-OSD_S_RAD, OSD_S_RAD, M_PI/2, -M_PI/2);
300     cairo_line_to (cr, x + OSD_S_PW, y + OSD_S_AREA_H - OSD_S_PH);
301     cairo_line_to (cr, x + OSD_S_PW, y);
302     }
303     cairo_line_to (cr, x + OSD_S_PW + OSD_S_AREA_W, y);
304     cairo_close_path (cr);
305     }
306     }
307    
308     static void
309 harbaum 87 osd_source_content(osm_gps_map_osd_t *osd, cairo_t *cr, gint offset) {
310     osd_priv_t *priv = (osd_priv_t*)osd->priv;
311 harbaum 86
312 harbaum 87 int py = offset + OSD_S_RAD - OSD_S_D0;
313    
314 harbaum 86 if(!priv->expanded) {
315     /* draw the "puller" open (<) arrow */
316 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD + OSD_S_D0/2, py);
317 harbaum 86 cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
318     cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
319     } else {
320     if(OSD_S_Y < 0)
321 harbaum 87 py += OSD_S_AREA_H - OSD_S_PH;
322 harbaum 86
323     /* draw the "puller" close (>) arrow */
324 harbaum 87 cairo_move_to (cr, offset + OSD_S_RAD - OSD_S_D0/2, py);
325 harbaum 86 cairo_rel_line_to (cr, +OSD_S_D0, +OSD_S_D0);
326     cairo_rel_line_to (cr, -OSD_S_D0, +OSD_S_D0);
327 harbaum 87 cairo_stroke(cr);
328    
329     /* don't draw a shadow for the text content */
330     if(offset == 1) {
331     gint source;
332     g_object_get(osd->widget, "map-source", &source, NULL);
333    
334     cairo_select_font_face (cr, "Sans",
335     CAIRO_FONT_SLANT_NORMAL,
336     CAIRO_FONT_WEIGHT_BOLD);
337     cairo_set_font_size (cr, OSD_FONT_SIZE);
338    
339     int i, step = (priv->height - 2*OSD_TEXT_BORDER)
340     / OSM_GPS_MAP_SOURCE_LAST;
341     for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
342     cairo_text_extents_t extents;
343     const char *src = osm_gps_map_source_get_friendly_name(i);
344     cairo_text_extents (cr, src, &extents);
345    
346     int x = offset + OSD_S_PW + OSD_TEXT_BORDER;
347     int y = offset + step * (i-1) + OSD_TEXT_BORDER;
348    
349     /* draw filled rectangle if selected */
350     if(source == i) {
351     cairo_rectangle(cr, x - OSD_TEXT_BORDER/2,
352     y - OSD_TEXT_SKIP,
353     priv->width - OSD_TEXT_BORDER,
354     step + OSD_TEXT_SKIP);
355     cairo_fill(cr);
356    
357     /* temprarily draw with background color */
358     #ifndef OSD_COLOR
359     GdkColor bg = osd->widget->style->bg[GTK_STATE_NORMAL];
360     gdk_cairo_set_source_color(cr, &bg);
361     #else
362     cairo_set_source_rgb (cr, OSD_COLOR_BG);
363     #endif
364     }
365    
366     cairo_move_to (cr, x, y + OSD_TEXT_SKIP - extents.y_bearing);
367     cairo_show_text (cr, src);
368    
369     /* restore color */
370     if(source == i) {
371     #ifndef OSD_COLOR
372     GdkColor fg = osd->widget->style->fg[GTK_STATE_NORMAL];
373     gdk_cairo_set_source_color(cr, &fg);
374     #else
375     cairo_set_source_rgb (cr, OSD_COLOR);
376     #endif
377     }
378     }
379     }
380 harbaum 86 }
381     }
382    
383     static void
384     osd_render_source_sel(osm_gps_map_osd_t *osd) {
385     osd_priv_t *priv = (osd_priv_t*)osd->priv;
386    
387     #ifndef OSD_COLOR
388     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
389     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
390     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
391     #endif
392    
393     /* draw source selector */
394     cairo_t *cr = cairo_create(priv->map_source);
395     cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
396     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
397     cairo_paint(cr);
398     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
399    
400     #ifdef OSD_SHADOW_ENABLE
401     osd_source_shape(priv, cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
402     osd_shape_shadow(cr);
403     #endif
404    
405     osd_source_shape(priv, cr, 1, 1);
406     #ifndef OSD_COLOR
407     osd_shape(cr, &bg, &fg);
408     #else
409     osd_shape(cr);
410     #endif
411    
412     #ifdef OSD_SHADOW_ENABLE
413     osd_labels_shadow(cr, Z_RAD/3, TRUE);
414 harbaum 87 osd_source_content(osd, cr, 1+OSD_LBL_SHADOW);
415     cairo_stroke (cr);
416 harbaum 86 #endif
417     #ifndef OSD_COLOR
418     osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
419     #else
420     osd_labels(cr, Z_RAD/3, TRUE);
421     #endif
422 harbaum 87 osd_source_content(osd, cr, 1);
423     cairo_stroke (cr);
424 harbaum 86
425     cairo_destroy(cr);
426     }
427    
428     static void
429     osd_source_reallocate(osm_gps_map_osd_t *osd) {
430     osd_priv_t *priv = (osd_priv_t*)osd->priv;
431    
432     /* re-allocate offscreen bitmap */
433     g_assert (priv->map_source);
434    
435     int w = OSD_S_W, h = OSD_S_H;
436     if(priv->expanded) {
437 harbaum 87 /* ... and right of it the waypoint id */
438     cairo_text_extents_t extents;
439    
440     /* determine content size */
441     cairo_t *cr = cairo_create(priv->map_source);
442     cairo_select_font_face (cr, "Sans",
443     CAIRO_FONT_SLANT_NORMAL,
444     CAIRO_FONT_WEIGHT_BOLD);
445     cairo_set_font_size (cr, OSD_FONT_SIZE);
446    
447     /* calculate menu size */
448     int i, max_h = 0, max_w = 0;
449     for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {
450     const char *src = osm_gps_map_source_get_friendly_name(i);
451     cairo_text_extents (cr, src, &extents);
452    
453     // printf("Source %d: %s = %f %f\n", i, src,
454     // extents.width, extents.height);
455    
456     if(extents.width > max_w) max_w = extents.width;
457     if(extents.height > max_h) max_h = extents.height;
458     }
459     cairo_destroy(cr);
460    
461     priv->width = max_w + 2*OSD_TEXT_BORDER;
462     priv->height = OSM_GPS_MAP_SOURCE_LAST *
463     (max_h + 2*OSD_TEXT_SKIP) + 2*OSD_TEXT_BORDER;
464    
465 harbaum 86 w = OSD_S_EXP_W;
466     h = OSD_S_EXP_H;
467     }
468    
469 harbaum 87 cairo_surface_destroy(priv->map_source);
470 harbaum 86 priv->map_source =
471     cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w+2, h+2);
472    
473     osd_render_source_sel(osd);
474    
475     }
476    
477     #define OSD_HZ 15
478 harbaum 87 #define OSD_TIME 500
479 harbaum 86
480     static gboolean osd_source_animate(gpointer data) {
481     osm_gps_map_osd_t *osd = (osm_gps_map_osd_t*)data;
482     osd_priv_t *priv = (osd_priv_t*)osd->priv;
483     int diff = OSD_S_EXP_W - OSD_S_W - OSD_S_X;
484     gboolean done = FALSE;
485     priv->count += priv->dir;
486    
487     /* shifting in */
488     if(priv->dir < 0) {
489     if(priv->count <= 0) {
490     priv->count = 0;
491     done = TRUE;
492     }
493     } else {
494     if(priv->count >= 1000) {
495     priv->expanded = FALSE;
496     osd_source_reallocate(osd);
497    
498     priv->count = 1000;
499     done = TRUE;
500     }
501     }
502    
503    
504     /* count runs linearly from 0 to 1000, map this nicely onto a position */
505    
506     /* simple linear mapping */
507     // priv->shift = (osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X) +
508     // (diff * priv->count)/1000;
509    
510     /* nicer sinoid mapping */
511     float m = 0.5-cos(priv->count * M_PI / 1000.0)/2;
512     priv->shift = (osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X) +
513     m * diff;
514    
515     osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
516    
517     if(done)
518     priv->handler_id = 0;
519    
520     return !done;
521     }
522    
523     /* switch between expand and collapse mode of source selection */
524     static void
525     osd_source_toggle(osm_gps_map_osd_t *osd)
526     {
527     osd_priv_t *priv = (osd_priv_t*)osd->priv;
528    
529     /* ignore clicks while animation is running */
530     if(priv->handler_id)
531     return;
532    
533     /* expand immediately, collapse is handle at the end of the collapse animation */
534     if(!priv->expanded) {
535     priv->expanded = TRUE;
536     osd_source_reallocate(osd);
537    
538     priv->count = 1000;
539     priv->shift = osd->widget->allocation.width - OSD_S_W;
540     priv->dir = -1000/OSD_HZ;
541     } else {
542     priv->count = 0;
543     priv->shift = osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
544     priv->dir = +1000/OSD_HZ;
545     }
546    
547     priv->handler_id = gtk_timeout_add(OSD_TIME/OSD_HZ, osd_source_animate, osd);
548     }
549    
550 harbaum 70 static osd_button_t
551 harbaum 86 osd_source_check(osm_gps_map_osd_t *osd, gint x, gint y) {
552     osd_priv_t *priv = (osd_priv_t*)osd->priv;
553    
554     if(!priv->expanded)
555     x -= osd->widget->allocation.width - OSD_S_W;
556     else
557     x -= osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
558    
559     if(OSD_S_Y > 0)
560     y -= OSD_S_Y;
561     else
562     y -= osd->widget->allocation.height - OSD_S_PH + OSD_S_Y;
563    
564     /* within square around puller? */
565     if(y > 0 && y < OSD_S_PH && x > 0 && x < OSD_S_PW) {
566     /* really within puller shape? */
567     if(x > Z_RAD || osm_gps_map_in_circle(x, y, Z_RAD, Z_RAD, Z_RAD)) {
568     /* expand source selector */
569     osd_source_toggle(osd);
570    
571     /* tell upper layers that user clicked some background element */
572     /* of the OSD */
573     return OSD_BG;
574     }
575     }
576     return OSD_NONE;
577     }
578    
579     static osd_button_t
580     osd_check(osm_gps_map_osd_t *osd, gint x, gint y) {
581 harbaum 70 osd_button_t but = OSD_NONE;
582    
583 harbaum 86 #ifdef OSD_SOURCE_SEL
584     /* the source selection area is handles internally */
585     but = osd_source_check(osd, x, y);
586     if(but != OSD_NONE)
587     return but;
588     #endif
589    
590 harbaum 77 x -= OSD_X;
591     y -= OSD_Y;
592    
593     if(OSD_X < 0)
594     x -= (osd->widget->allocation.width - OSD_W);
595    
596     if(OSD_Y < 0)
597     y -= (osd->widget->allocation.height - OSD_H);
598    
599 harbaum 70 /* first do a rough test for the OSD area. */
600     /* this is just to avoid an unnecessary detailed test */
601 harbaum 77 if(x > 0 && x < OSD_W && y > 0 && y < OSD_H) {
602 harbaum 76 #ifndef OSD_NO_DPAD
603 harbaum 86 but = osd_check_dpad(x, y);
604 harbaum 76 #endif
605 harbaum 70
606     if(but == OSD_NONE)
607 harbaum 86 but = osd_check_zoom(x, y);
608 harbaum 70 }
609    
610     return but;
611     }
612    
613 harbaum 76 #ifndef OSD_NO_DPAD
614 harbaum 70 static void
615 harbaum 86 osd_dpad_labels(cairo_t *cr, gint x, gint y) {
616 harbaum 70 /* move reference to dpad center */
617     x += D_RAD;
618     y += D_RAD;
619    
620     const static gint offset[][3][2] = {
621     /* left arrow/triangle */
622     { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } },
623     /* right arrow/triangle */
624     { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } },
625     /* top arrow/triangle */
626     { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } },
627     /* bottom arrow/triangle */
628     { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } }
629     };
630    
631     int i;
632     for(i=0;i<4;i++) {
633     cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]);
634     cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]);
635     cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]);
636     }
637     }
638 harbaum 76 #endif
639 harbaum 70
640 harbaum 76 #ifdef OSD_GPS_BUTTON
641     /* draw the satellite dish icon in the center of the dpad */
642 harbaum 77 #define GPS_V0 (D_RAD/7)
643 harbaum 70 #define GPS_V1 (D_RAD/10)
644     #define GPS_V2 (D_RAD/5)
645    
646     /* draw a satellite receiver dish */
647 harbaum 77 /* this is either drawn in the center of the dpad (if present) */
648     /* or in the middle of the zoom area */
649 harbaum 70 static void
650 harbaum 86 osd_dpad_gps(cairo_t *cr, gint x, gint y) {
651 harbaum 70 /* move reference to dpad center */
652 harbaum 77 x += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD * 3;
653     y += (1-Z_GPS) * D_RAD + Z_GPS * Z_RAD + GPS_V0;
654 harbaum 70
655     cairo_move_to (cr, x-GPS_V0, y+GPS_V0);
656     cairo_rel_line_to (cr, +GPS_V0, -GPS_V0);
657     cairo_rel_line_to (cr, +GPS_V0, +GPS_V0);
658     cairo_close_path (cr);
659    
660     cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2);
661     cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y);
662     cairo_close_path (cr);
663    
664     x += GPS_V1;
665     cairo_move_to (cr, x, y-GPS_V2);
666     cairo_rel_line_to (cr, +GPS_V1, -GPS_V1);
667     }
668 harbaum 76 #endif
669 harbaum 70
670     #define Z_LEN (2*Z_RAD/3)
671    
672     static void
673 harbaum 86 osd_zoom_labels(cairo_t *cr, gint x, gint y) {
674 harbaum 70 cairo_move_to (cr, x + Z_LEFT - Z_LEN, y + Z_MID);
675     cairo_line_to (cr, x + Z_LEFT + Z_LEN, y + Z_MID);
676    
677     cairo_move_to (cr, x + Z_RIGHT, y + Z_MID - Z_LEN);
678     cairo_line_to (cr, x + Z_RIGHT, y + Z_MID + Z_LEN);
679     cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID);
680     cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID);
681     }
682    
683     static void
684 harbaum 86 osd_render(osm_gps_map_osd_t *osd) {
685     osd_priv_t *priv = (osd_priv_t*)osd->priv;
686 harbaum 70
687 harbaum 86 #ifndef OSD_COLOR
688     GdkColor bg = GTK_WIDGET(osd->widget)->style->bg[GTK_STATE_NORMAL];
689     GdkColor fg = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_NORMAL];
690     GdkColor da = GTK_WIDGET(osd->widget)->style->fg[GTK_STATE_INSENSITIVE];
691 harbaum 74 #endif
692 harbaum 70
693     /* first fill with transparency */
694 harbaum 73 cairo_t *cr = cairo_create(priv->overlay);
695 harbaum 70 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
696     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
697     cairo_paint(cr);
698     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
699    
700     /* --------- draw zoom and dpad shape shadow ----------- */
701 harbaum 74 #ifdef OSD_SHADOW_ENABLE
702 harbaum 86 osd_zoom_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
703     osd_shape_shadow(cr);
704 harbaum 76 #ifndef OSD_NO_DPAD
705 harbaum 86 osd_dpad_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
706     osd_shape_shadow(cr);
707 harbaum 74 #endif
708 harbaum 76 #endif
709 harbaum 70
710     /* --------- draw zoom and dpad shape ----------- */
711    
712 harbaum 86 osd_zoom_shape(cr, 1, 1);
713 harbaum 74 #ifndef OSD_COLOR
714 harbaum 86 osd_shape(cr, &bg, &fg);
715 harbaum 74 #else
716 harbaum 86 osd_shape(cr);
717 harbaum 74 #endif
718 harbaum 76 #ifndef OSD_NO_DPAD
719 harbaum 86 osd_dpad_shape(cr, 1, 1);
720 harbaum 74 #ifndef OSD_COLOR
721 harbaum 86 osd_shape(cr, &bg, &fg);
722 harbaum 74 #else
723 harbaum 86 osd_shape(cr);
724 harbaum 74 #endif
725 harbaum 76 #endif
726 harbaum 70
727     /* --------- draw zoom and dpad labels --------- */
728    
729 harbaum 74 #ifdef OSD_SHADOW_ENABLE
730 harbaum 87 osd_labels_shadow(cr, Z_RAD/3, TRUE);
731 harbaum 86 osd_zoom_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
732 harbaum 76 #ifndef OSD_NO_DPAD
733 harbaum 86 osd_dpad_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
734 harbaum 76 #endif
735 harbaum 87 cairo_stroke(cr);
736 harbaum 76 #ifdef OSD_GPS_BUTTON
737 harbaum 87 osd_labels_shadow(cr, Z_RAD/6, osd->cb != NULL);
738 harbaum 86 osd_dpad_gps(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
739 harbaum 87 cairo_stroke(cr);
740 harbaum 74 #endif
741 harbaum 76 #endif
742 harbaum 70
743 harbaum 74 #ifndef OSD_COLOR
744 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
745 harbaum 74 #else
746 harbaum 86 osd_labels(cr, Z_RAD/3, TRUE);
747 harbaum 74 #endif
748 harbaum 87 osd_zoom_labels(cr, 1, 1);
749     #ifndef OSD_NO_DPAD
750     osd_dpad_labels(cr, 1, 1);
751     #endif
752     cairo_stroke(cr);
753    
754 harbaum 74 #ifndef OSD_COLOR
755 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL, &fg, &da);
756 harbaum 74 #else
757 harbaum 86 osd_labels(cr, Z_RAD/6, osd->cb != NULL);
758 harbaum 74 #endif
759 harbaum 87 #ifdef OSD_GPS_BUTTON
760     osd_dpad_gps(cr, 1, 1);
761 harbaum 76 #endif
762 harbaum 87 cairo_stroke(cr);
763 harbaum 70
764     cairo_destroy(cr);
765 harbaum 86
766     osd_render_source_sel(osd);
767 harbaum 70 }
768    
769     static void
770 harbaum 86 osd_draw(osm_gps_map_osd_t *osd, GdkDrawable *drawable)
771 harbaum 70 {
772 harbaum 73 osd_priv_t *priv = (osd_priv_t*)osd->priv;
773 harbaum 70
774     /* OSD itself uses some off-screen rendering, so check if the */
775     /* offscreen buffer is present and create it if not */
776 harbaum 73 if(!priv->overlay) {
777 harbaum 70 /* create overlay ... */
778 harbaum 73 priv->overlay =
779 harbaum 86 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W+2, OSD_H+2);
780    
781     /* the initial OSD state is alway not-expanded */
782     priv->map_source =
783     cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
784     OSD_S_W+2, OSD_S_H+2);
785    
786 harbaum 70 /* ... and render it */
787 harbaum 86 osd_render(osd);
788 harbaum 70 }
789    
790     // now draw this onto the original context
791 harbaum 75 cairo_t *cr = gdk_cairo_create(drawable);
792 harbaum 77
793     int x = OSD_X, y = OSD_Y;
794     if(OSD_X < 0)
795     x = osd->widget->allocation.width - OSD_W + OSD_X;
796    
797     if(OSD_Y < 0)
798     y = osd->widget->allocation.height - OSD_H + OSD_Y;
799    
800     cairo_set_source_surface(cr, priv->overlay, x, y);
801 harbaum 70 cairo_paint(cr);
802 harbaum 86
803     #ifdef OSD_SOURCE_SEL
804     if(!priv->handler_id) {
805     /* the OSD source selection is not being animated */
806     if(!priv->expanded)
807     x = osd->widget->allocation.width - OSD_S_W;
808     else
809     x = osd->widget->allocation.width - OSD_S_EXP_W + OSD_S_X;
810     } else
811     x = priv->shift;
812    
813     y = OSD_S_Y;
814     if(OSD_S_Y < 0) {
815     if(!priv->expanded)
816     y = osd->widget->allocation.height - OSD_S_H + OSD_S_Y;
817     else
818     y = osd->widget->allocation.height - OSD_S_EXP_H + OSD_S_Y;
819     }
820    
821     cairo_set_source_surface(cr, priv->map_source, x, y);
822     cairo_paint(cr);
823     #endif
824    
825 harbaum 70 cairo_destroy(cr);
826     }
827    
828     static void
829 harbaum 86 osd_free(osm_gps_map_osd_t *osd)
830 harbaum 70 {
831 harbaum 73 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
832 harbaum 70
833 harbaum 86 if(priv->handler_id)
834     gtk_timeout_remove(priv->handler_id);
835    
836 harbaum 73 if (priv->overlay)
837     cairo_surface_destroy(priv->overlay);
838 harbaum 70
839 harbaum 86 if (priv->map_source)
840     cairo_surface_destroy(priv->map_source);
841    
842 harbaum 73 g_free(priv);
843     }
844    
845 harbaum 87 /* this is the only function that's externally visible */
846     static gboolean
847     osd_busy(osm_gps_map_osd_t *osd)
848     {
849     osd_priv_t *priv = (osd_priv_t *)(osd->priv);
850     return (priv->handler_id != 0);
851     }
852    
853 harbaum 73 static osm_gps_map_osd_t osd_classic = {
854 harbaum 86 .draw = osd_draw,
855     .check = osd_check,
856     .render = osd_render,
857     .free = osd_free,
858 harbaum 87 .busy = osd_busy,
859 harbaum 73
860     .cb = NULL,
861     .data = NULL,
862    
863     .priv = NULL
864     };
865    
866     /* this is the only function that's externally visible */
867     void
868     osm_gps_map_osd_classic_init(OsmGpsMap *map)
869     {
870     osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);
871    
872     osd_classic.priv = priv;
873    
874     osm_gps_map_register_osd(map, &osd_classic);
875     }
876    
877 harbaum 76 #ifdef OSD_GPS_BUTTON
878 harbaum 74 /* below are osd specific functions which aren't used by osm-gps-map */
879     /* but instead are to be used by the main application */
880 harbaum 76 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,
881     gpointer data) {
882 harbaum 73 osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
883     g_return_if_fail (osd);
884    
885     osd->cb = cb;
886     osd->data = data;
887    
888 harbaum 70 /* this may have changed the state of the gps button */
889     /* we thus re-render the overlay */
890 harbaum 73 osd->render(osd);
891 harbaum 70
892 harbaum 73 osm_gps_map_redraw(map);
893 harbaum 70 }
894 harbaum 76 #endif
895 harbaum 86
896     osd_button_t
897     osm_gps_map_osd_check(OsmGpsMap *map, gint x, gint y) {
898     osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
899     g_return_val_if_fail (osd, OSD_NONE);
900    
901     return osd_check(osd, x, y);
902     }