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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 86 - (show 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 /* -*- 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 /*
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 #include "config.h"
21 #include <stdlib.h> // abs
22 #include <math.h> // M_PI
23
24 #define OSD_SOURCE_SEL
25
26 #define OSD_Y (-10)
27
28 /* parameters that can be overwritten from the config file: */
29 /* OSD_DIAMETER */
30 /* OSD_X, OSD_Y */
31
32 #ifndef USE_CAIRO
33 #error "OSD control display lacks a non-cairo implementation!"
34 #endif
35
36 #include <cairo.h>
37
38 #include "osm-gps-map.h"
39 #include "osm-gps-map-osd-classic.h"
40
41 //the osd controls
42 typedef struct {
43 /* the offscreen representation of the OSD */
44 cairo_surface_t *overlay;
45
46 cairo_surface_t *map_source;
47 gboolean expanded;
48 gint shift, dir, count;
49 gint handler_id;
50 } osd_priv_t;
51
52 /* position and extent of bounding box */
53 #ifndef OSD_X
54 #define OSD_X (10)
55 #endif
56
57 #ifndef OSD_Y
58 #define OSD_Y (10)
59 #endif
60
61 /* parameters of the direction shape */
62 #ifndef OSD_DIAMETER
63 #define D_RAD (30) // diameter of dpad
64 #else
65 #define D_RAD (OSD_DIAMETER)
66 #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 #ifdef OSD_SHADOW_ENABLE
76 /* shadow also depends on control size */
77 #define OSD_SHADOW (D_RAD/6)
78 #else
79 #define OSD_SHADOW (0)
80 #endif
81
82 /* 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 /* total width and height of controls incl. shadow */
91 #define OSD_W (2*D_RAD + OSD_SHADOW + Z_GPS * 2 * Z_RAD)
92 #if !Z_GPS
93 #define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)
94 #else
95 #define OSD_H (2*Z_RAD + OSD_SHADOW)
96 #endif
97
98 #ifdef OSD_SHADOW_ENABLE
99 #define OSD_LBL_SHADOW (OSD_SHADOW/2)
100 #endif
101
102 #define Z_TOP ((1-Z_GPS) * (2 * D_RAD + Z_STEP))
103
104 #define Z_MID (Z_TOP + Z_RAD)
105 #define Z_BOT (Z_MID + Z_RAD)
106 #define Z_LEFT (Z_RAD)
107 #define Z_RIGHT (2 * D_RAD - Z_RAD + Z_GPS * 2 * Z_RAD)
108 #define Z_CENTER ((Z_RIGHT + Z_LEFT)/2)
109
110 /* create the cairo shape used for the zoom buttons */
111 static void
112 osd_zoom_shape(cairo_t *cr, gint x, gint y)
113 {
114 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 /* ------------------- 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 #ifndef OSD_NO_DPAD
153 /* create the cairo shape used for the dpad */
154 static void
155 osd_dpad_shape(cairo_t *cr, gint x, gint y)
156 {
157 cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);
158 }
159 #endif
160
161 #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 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 #ifndef OSD_NO_DPAD
199 /* check whether x/y is within the dpad */
200 static osd_button_t
201 osd_check_dpad(gint x, gint y)
202 {
203 /* within entire dpad circle */
204 if( osm_gps_map_in_circle(x, y, D_RAD, D_RAD, D_RAD))
205 {
206 /* convert into position relative to dpads centre */
207 x -= D_RAD;
208 y -= D_RAD;
209
210 #ifdef OSD_GPS_BUTTON
211 /* 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 #endif
215
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 #endif
233
234 /* check whether x/y is within the zoom pads */
235 static osd_button_t
236 osd_check_zoom(gint x, gint y) {
237 if( x > 0 && x < OSD_W && y > Z_TOP && y < Z_BOT) {
238
239 /* within circle around (-) label */
240 if( osm_gps_map_in_circle(x, y, Z_LEFT, Z_MID, Z_RAD))
241 return OSD_OUT;
242
243 /* 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 /* between center of (-) button and center of entire zoom control area */
254 if(x > OSD_LEFT && x < D_RAD)
255 return OSD_OUT;
256
257 /* between center of (+) button and center of entire zoom control area */
258 if(x < OSD_RIGHT && x > D_RAD)
259 return OSD_IN;
260 }
261
262 return OSD_NONE;
263 }
264
265 /* 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 static osd_button_t
465 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 osd_button_t but = OSD_NONE;
496
497 #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 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 /* first do a rough test for the OSD area. */
514 /* this is just to avoid an unnecessary detailed test */
515 if(x > 0 && x < OSD_W && y > 0 && y < OSD_H) {
516 #ifndef OSD_NO_DPAD
517 but = osd_check_dpad(x, y);
518 #endif
519
520 if(but == OSD_NONE)
521 but = osd_check_zoom(x, y);
522 }
523
524 return but;
525 }
526
527 #ifndef OSD_NO_DPAD
528 static void
529 osd_dpad_labels(cairo_t *cr, gint x, gint y) {
530 /* 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 #endif
553
554 #ifdef OSD_GPS_BUTTON
555 /* draw the satellite dish icon in the center of the dpad */
556 #define GPS_V0 (D_RAD/7)
557 #define GPS_V1 (D_RAD/10)
558 #define GPS_V2 (D_RAD/5)
559
560 /* draw a satellite receiver dish */
561 /* this is either drawn in the center of the dpad (if present) */
562 /* or in the middle of the zoom area */
563 static void
564 osd_dpad_gps(cairo_t *cr, gint x, gint y) {
565 /* move reference to dpad center */
566 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
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 #endif
583
584 #define Z_LEN (2*Z_RAD/3)
585
586 static void
587 osd_zoom_labels(cairo_t *cr, gint x, gint y) {
588 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 osd_render(osm_gps_map_osd_t *osd) {
599 osd_priv_t *priv = (osd_priv_t*)osd->priv;
600
601 #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 #endif
606
607 /* first fill with transparency */
608 cairo_t *cr = cairo_create(priv->overlay);
609 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 #ifdef OSD_SHADOW_ENABLE
616 osd_zoom_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
617 osd_shape_shadow(cr);
618 #ifndef OSD_NO_DPAD
619 osd_dpad_shape(cr, 1+OSD_SHADOW, 1+OSD_SHADOW);
620 osd_shape_shadow(cr);
621 #endif
622 #endif
623
624 /* --------- draw zoom and dpad shape ----------- */
625
626 osd_zoom_shape(cr, 1, 1);
627 #ifndef OSD_COLOR
628 osd_shape(cr, &bg, &fg);
629 #else
630 osd_shape(cr);
631 #endif
632 #ifndef OSD_NO_DPAD
633 osd_dpad_shape(cr, 1, 1);
634 #ifndef OSD_COLOR
635 osd_shape(cr, &bg, &fg);
636 #else
637 osd_shape(cr);
638 #endif
639 #endif
640
641 /* --------- draw zoom and dpad labels --------- */
642
643 #ifdef OSD_SHADOW_ENABLE
644 osd_zoom_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
645 #ifndef OSD_NO_DPAD
646 osd_dpad_labels(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
647 #endif
648 osd_labels_shadow(cr, Z_RAD/3, TRUE);
649 #ifdef OSD_GPS_BUTTON
650 osd_dpad_gps(cr, 1+OSD_LBL_SHADOW, 1+OSD_LBL_SHADOW);
651 osd_labels_shadow(cr, Z_RAD/6, osd->cb != NULL);
652 #endif
653 #endif
654
655 osd_zoom_labels(cr, 1, 1);
656 #ifndef OSD_NO_DPAD
657 osd_dpad_labels(cr, 1, 1);
658 #endif
659 #ifndef OSD_COLOR
660 osd_labels(cr, Z_RAD/3, TRUE, &fg, &da);
661 #else
662 osd_labels(cr, Z_RAD/3, TRUE);
663 #endif
664 #ifdef OSD_GPS_BUTTON
665 osd_dpad_gps(cr, 1, 1);
666 #ifndef OSD_COLOR
667 osd_labels(cr, Z_RAD/6, osd->cb != NULL, &fg, &da);
668 #else
669 osd_labels(cr, Z_RAD/6, osd->cb != NULL);
670 #endif
671 #endif
672
673 cairo_destroy(cr);
674
675 osd_render_source_sel(osd);
676 }
677
678 static void
679 osd_draw(osm_gps_map_osd_t *osd, GdkDrawable *drawable)
680 {
681 osd_priv_t *priv = (osd_priv_t*)osd->priv;
682
683 /* OSD itself uses some off-screen rendering, so check if the */
684 /* offscreen buffer is present and create it if not */
685 if(!priv->overlay) {
686 /* create overlay ... */
687 priv->overlay =
688 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 /* ... and render it */
696 osd_render(osd);
697 }
698
699 // now draw this onto the original context
700 cairo_t *cr = gdk_cairo_create(drawable);
701
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 cairo_paint(cr);
711
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 cairo_destroy(cr);
735 }
736
737 static void
738 osd_free(osm_gps_map_osd_t *osd)
739 {
740 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
741
742 if(priv->handler_id)
743 gtk_timeout_remove(priv->handler_id);
744
745 if (priv->overlay)
746 cairo_surface_destroy(priv->overlay);
747
748 if (priv->map_source)
749 cairo_surface_destroy(priv->map_source);
750
751 g_free(priv);
752 }
753
754 static osm_gps_map_osd_t osd_classic = {
755 .draw = osd_draw,
756 .check = osd_check,
757 .render = osd_render,
758 .free = osd_free,
759
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 #ifdef OSD_GPS_BUTTON
778 /* 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 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,
781 gpointer data) {
782 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 /* this may have changed the state of the gps button */
789 /* we thus re-render the overlay */
790 osd->render(osd);
791
792 osm_gps_map_redraw(map);
793 }
794 #endif
795
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 }