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

Parent Directory Parent Directory | Revision Log Revision Log


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