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

Parent Directory Parent Directory | Revision Log Revision Log


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