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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 74 - (hide annotations)
Mon Aug 24 09:23:36 2009 UTC (14 years, 8 months ago) by harbaum
File MIME type: text/plain
File size: 14364 byte(s)
OSD color matching
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 71 /* parameters that can be overwritten from the config file: */
25     /* OSM_GPS_MAP_OSD_DIAMETER */
26    
27     #ifndef USE_CAIRO
28     #error "OSD control display lacks a non-cairo implementation!"
29 harbaum 70 #endif
30    
31 harbaum 71 #include <cairo.h>
32    
33     #include "osm-gps-map.h"
34 harbaum 73 #include "osm-gps-map-osd-classic.h"
35 harbaum 71
36 harbaum 70 //the osd controls
37     typedef struct {
38 harbaum 74 /* the offscreen representation of the OSD */
39     cairo_surface_t *overlay;
40    
41     /* stuff required to restore the original map content */
42 harbaum 70 GdkPixmap *backup;
43     gint backup_x, backup_y;
44 harbaum 74
45     GdkColor bg, fg, da;
46    
47 harbaum 70 } osd_priv_t;
48    
49     /* position and extent of bounding box */
50     #define OSD_X (10)
51     #define OSD_Y (10)
52    
53     /* parameters of the direction shape */
54     #ifndef OSM_GPS_MAP_OSD_DIAMETER
55     #define D_RAD (30) // diameter of dpad
56     #else
57     #define D_RAD (OSM_GPS_MAP_OSD_DIAMETER)
58     #endif
59     #define D_TIP (4*D_RAD/5) // distance of arrow tip from dpad center
60     #define D_LEN (D_RAD/4) // length of arrow
61     #define D_WID (D_LEN) // width of arrow
62    
63     /* parameters of the "zoom" pad */
64     #define Z_STEP (D_RAD/4) // distance between dpad and zoom
65     #define Z_RAD (D_RAD/2) // radius of "caps" of zoom bar
66    
67 harbaum 74 #ifdef OSD_SHADOW_ENABLE
68 harbaum 70 /* shadow also depends on control size */
69     #define OSD_SHADOW (D_RAD/6)
70 harbaum 74 #else
71     #define OSD_SHADOW (0)
72     #endif
73 harbaum 70
74     /* total width and height of controls incl. shadow */
75     #define OSD_W (2*D_RAD + OSD_SHADOW)
76     #define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW)
77    
78 harbaum 74 #ifdef OSD_SHADOW_ENABLE
79 harbaum 70 #define OSD_LBL_SHADOW (OSD_SHADOW/2)
80 harbaum 74 #endif
81 harbaum 70
82     #define Z_TOP (2 * D_RAD + Z_STEP)
83     #define Z_MID (Z_TOP + Z_RAD)
84     #define Z_BOT (Z_MID + Z_RAD)
85     #define Z_LEFT (Z_RAD)
86     #define Z_RIGHT (2 * D_RAD - Z_RAD)
87    
88 harbaum 71
89 harbaum 70 /* create the cairo shape used for the zoom buttons */
90     static void
91 harbaum 71 osm_gps_map_osd_zoom_shape(cairo_t *cr, gint x, gint y)
92     {
93 harbaum 70 cairo_move_to (cr, x+Z_LEFT, y+Z_TOP);
94     cairo_line_to (cr, x+Z_RIGHT, y+Z_TOP);
95     cairo_arc (cr, x+Z_RIGHT, y+Z_MID, Z_RAD, -M_PI/2, M_PI/2);
96     cairo_line_to (cr, x+Z_LEFT, y+Z_BOT);
97     cairo_arc (cr, x+Z_LEFT, y+Z_MID, Z_RAD, M_PI/2, -M_PI/2);
98     }
99    
100     /* create the cairo shape used for the dpad */
101     static void
102 harbaum 71 osm_gps_map_osd_dpad_shape(cairo_t *cr, gint x, gint y)
103     {
104 harbaum 70 cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI);
105     }
106    
107     static gboolean
108     osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)
109     {
110     return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);
111     }
112    
113     /* check whether x/y is within the dpad */
114     static osd_button_t
115     osm_gps_map_osd_check_dpad(gint x, gint y)
116     {
117     /* within entire dpad circle */
118     if( osm_gps_map_in_circle(x, y, OSD_X + D_RAD, OSD_Y + D_RAD, D_RAD))
119     {
120     /* convert into position relative to dpads centre */
121     x -= (OSD_X + D_RAD);
122     y -= (OSD_Y + D_RAD);
123    
124     /* check for dpad center goes here! */
125     if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3))
126     return OSD_GPS;
127    
128     if( y < 0 && abs(x) < abs(y))
129     return OSD_UP;
130    
131     if( y > 0 && abs(x) < abs(y))
132     return OSD_DOWN;
133    
134     if( x < 0 && abs(y) < abs(x))
135     return OSD_LEFT;
136    
137     if( x > 0 && abs(y) < abs(x))
138     return OSD_RIGHT;
139    
140     return OSD_BG;
141     }
142     return OSD_NONE;
143     }
144    
145     /* check whether x/y is within the zoom pads */
146     static osd_button_t
147     osm_gps_map_osd_check_zoom(gint x, gint y) {
148     if( x > OSD_X && x < (OSD_X + OSD_W) && y > Z_TOP && y < (OSD_Y+Z_BOT)) {
149    
150     /* within circle around (-) label */
151     if( osm_gps_map_in_circle(x, y, OSD_X + Z_LEFT, OSD_Y + Z_MID, Z_RAD))
152     return OSD_OUT;
153    
154     /* between center of (-) button and center of entire zoom control area */
155     if(x > OSD_LEFT && x < OSD_X + D_RAD)
156     return OSD_OUT;
157    
158     /* within circle around (+) label */
159     if( osm_gps_map_in_circle(x, y, OSD_X + Z_RIGHT, OSD_Y + Z_MID, Z_RAD))
160     return OSD_IN;
161    
162     /* between center of (+) button and center of entire zoom control area */
163     if(x < OSD_RIGHT && x > OSD_X + D_RAD)
164     return OSD_IN;
165     }
166    
167     return OSD_NONE;
168     }
169    
170     static osd_button_t
171     osm_gps_map_osd_check(gint x, gint y) {
172     osd_button_t but = OSD_NONE;
173    
174     /* first do a rough test for the OSD area. */
175     /* this is just to avoid an unnecessary detailed test */
176     if(x > OSD_X && x < OSD_X + OSD_W &&
177     y > OSD_Y && y < OSD_Y + OSD_H) {
178     but = osm_gps_map_osd_check_dpad(x, y);
179    
180     if(but == OSD_NONE)
181     but = osm_gps_map_osd_check_zoom(x, y);
182     }
183    
184     return but;
185     }
186    
187 harbaum 74 #ifdef OSD_SHADOW_ENABLE
188 harbaum 70 static void
189     osm_gps_map_osd_shape_shadow(cairo_t *cr) {
190     cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
191     cairo_fill (cr);
192     cairo_stroke (cr);
193     }
194 harbaum 74 #endif
195 harbaum 70
196 harbaum 74 #ifndef OSD_COLOR
197     /* if no color has been specified we just use the gdks default colors */
198 harbaum 70 static void
199 harbaum 74 osm_gps_map_osd_shape(cairo_t *cr, GdkColor *bg, GdkColor *fg) {
200     gdk_cairo_set_source_color(cr, bg);
201     cairo_fill_preserve (cr);
202     gdk_cairo_set_source_color(cr, fg);
203     cairo_set_line_width (cr, 1);
204     cairo_stroke (cr);
205     }
206     #else
207     static void
208 harbaum 70 osm_gps_map_osd_shape(cairo_t *cr) {
209 harbaum 74 cairo_set_source_rgb (cr, OSD_COLOR_BG);
210 harbaum 70 cairo_fill_preserve (cr);
211     cairo_set_source_rgb (cr, OSD_COLOR);
212     cairo_set_line_width (cr, 1);
213     cairo_stroke (cr);
214     }
215 harbaum 74 #endif
216 harbaum 70
217     static void
218     osm_gps_map_osd_dpad_labels(cairo_t *cr, gint x, gint y) {
219     /* move reference to dpad center */
220     x += D_RAD;
221     y += D_RAD;
222    
223     const static gint offset[][3][2] = {
224     /* left arrow/triangle */
225     { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } },
226     /* right arrow/triangle */
227     { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } },
228     /* top arrow/triangle */
229     { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } },
230     /* bottom arrow/triangle */
231     { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } }
232     };
233    
234     int i;
235     for(i=0;i<4;i++) {
236     cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]);
237     cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]);
238     cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]);
239     }
240     }
241    
242     /* draw the sattelite dish icon in the center of the dpad */
243     #define GPS_V0 (D_RAD/8)
244     #define GPS_V1 (D_RAD/10)
245     #define GPS_V2 (D_RAD/5)
246    
247     /* draw a satellite receiver dish */
248     static void
249     osm_gps_map_osd_dpad_gps(cairo_t *cr, gint x, gint y) {
250     /* move reference to dpad center */
251     x += D_RAD;
252     y += D_RAD + GPS_V0;
253    
254     cairo_move_to (cr, x-GPS_V0, y+GPS_V0);
255     cairo_rel_line_to (cr, +GPS_V0, -GPS_V0);
256     cairo_rel_line_to (cr, +GPS_V0, +GPS_V0);
257     cairo_close_path (cr);
258    
259     cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2);
260     cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y);
261     cairo_close_path (cr);
262    
263     x += GPS_V1;
264     cairo_move_to (cr, x, y-GPS_V2);
265     cairo_rel_line_to (cr, +GPS_V1, -GPS_V1);
266     }
267    
268     #define Z_LEN (2*Z_RAD/3)
269    
270     static void
271     osm_gps_map_osd_zoom_labels(cairo_t *cr, gint x, gint y) {
272     cairo_move_to (cr, x + Z_LEFT - Z_LEN, y + Z_MID);
273     cairo_line_to (cr, x + Z_LEFT + Z_LEN, y + Z_MID);
274    
275     cairo_move_to (cr, x + Z_RIGHT, y + Z_MID - Z_LEN);
276     cairo_line_to (cr, x + Z_RIGHT, y + Z_MID + Z_LEN);
277     cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID);
278     cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID);
279     }
280    
281 harbaum 74 #ifndef OSD_COLOR
282     /* if no color has been specified we just use the gdks default colors */
283 harbaum 70 static void
284 harbaum 74 osm_gps_map_osd_labels(cairo_t *cr, gint width, gboolean enabled,
285     GdkColor *fg, GdkColor *disabled) {
286     if(enabled) gdk_cairo_set_source_color(cr, fg);
287     else gdk_cairo_set_source_color(cr, disabled);
288     cairo_set_line_width (cr, width);
289     cairo_stroke (cr);
290     }
291     #else
292     static void
293 harbaum 70 osm_gps_map_osd_labels(cairo_t *cr, gint width, gboolean enabled) {
294     if(enabled) cairo_set_source_rgb (cr, OSD_COLOR);
295     else cairo_set_source_rgb (cr, OSD_COLOR_DISABLED);
296     cairo_set_line_width (cr, width);
297     cairo_stroke (cr);
298     }
299 harbaum 74 #endif
300 harbaum 70
301 harbaum 74 #ifdef OSD_SHADOW_ENABLE
302 harbaum 70 static void
303     osm_gps_map_osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) {
304     cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15);
305     cairo_set_line_width (cr, width);
306     cairo_stroke (cr);
307     }
308 harbaum 74 #endif
309 harbaum 70
310     static void
311 harbaum 73 osm_gps_map_osd_render(osm_gps_map_osd_t *osd) {
312     osd_priv_t *priv = (osd_priv_t*)osd->priv;
313 harbaum 70
314     /* first fill with transparency */
315 harbaum 73 cairo_t *cr = cairo_create(priv->overlay);
316 harbaum 70 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
317     cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0);
318     cairo_paint(cr);
319    
320     cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
321    
322     /* --------- draw zoom and dpad shape shadow ----------- */
323     gint x = 0, y = 0;
324    
325 harbaum 74 #ifdef OSD_SHADOW_ENABLE
326 harbaum 70 osm_gps_map_osd_zoom_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW);
327     osm_gps_map_osd_shape_shadow(cr);
328     osm_gps_map_osd_dpad_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW);
329     osm_gps_map_osd_shape_shadow(cr);
330 harbaum 74 #endif
331 harbaum 70
332     /* --------- draw zoom and dpad shape ----------- */
333    
334     osm_gps_map_osd_zoom_shape(cr, x, y);
335 harbaum 74 #ifndef OSD_COLOR
336     osm_gps_map_osd_shape(cr, &priv->bg, &priv->fg);
337     #else
338 harbaum 70 osm_gps_map_osd_shape(cr);
339 harbaum 74 #endif
340 harbaum 70 osm_gps_map_osd_dpad_shape(cr, x, y);
341 harbaum 74 #ifndef OSD_COLOR
342     osm_gps_map_osd_shape(cr, &priv->bg, &priv->fg);
343     #else
344 harbaum 70 osm_gps_map_osd_shape(cr);
345 harbaum 74 #endif
346 harbaum 70
347     /* --------- draw zoom and dpad labels --------- */
348    
349 harbaum 74 #ifdef OSD_SHADOW_ENABLE
350 harbaum 70 osm_gps_map_osd_zoom_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);
351     osm_gps_map_osd_dpad_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);
352     osm_gps_map_osd_labels_shadow(cr, Z_RAD/3, TRUE);
353     osm_gps_map_osd_dpad_gps(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW);
354 harbaum 73 osm_gps_map_osd_labels_shadow(cr, Z_RAD/6, osd->cb != NULL);
355 harbaum 74 #endif
356 harbaum 70
357     osm_gps_map_osd_zoom_labels(cr, x, y);
358     osm_gps_map_osd_dpad_labels(cr, x, y);
359 harbaum 74 #ifndef OSD_COLOR
360     osm_gps_map_osd_labels(cr, Z_RAD/3, TRUE, &priv->fg, &priv->da);
361     #else
362 harbaum 70 osm_gps_map_osd_labels(cr, Z_RAD/3, TRUE);
363 harbaum 74 #endif
364 harbaum 70 osm_gps_map_osd_dpad_gps(cr, x, y);
365 harbaum 74 #ifndef OSD_COLOR
366     osm_gps_map_osd_labels(cr, Z_RAD/6, osd->cb != NULL, &priv->fg, &priv->da);
367     #else
368 harbaum 73 osm_gps_map_osd_labels(cr, Z_RAD/6, osd->cb != NULL);
369 harbaum 74 #endif
370 harbaum 70
371     cairo_destroy(cr);
372     }
373    
374     static void
375 harbaum 73 osm_gps_map_osd_draw(osm_gps_map_osd_t *osd, gint xoffset, gint yoffset)
376 harbaum 70 {
377 harbaum 73 osd_priv_t *priv = (osd_priv_t*)osd->priv;
378 harbaum 70
379     /* backup previous contents */
380 harbaum 73 if(!priv->backup)
381     priv->backup = gdk_pixmap_new(osd->pixmap, OSD_W+2, OSD_H+2, -1);
382 harbaum 70
383 harbaum 73 gint x = OSD_X + xoffset;
384     gint y = OSD_Y + yoffset;
385 harbaum 70
386     /* create backup of background */
387 harbaum 73 gdk_draw_drawable(priv->backup,
388     osd->widget->style->fg_gc[GTK_WIDGET_STATE(osd->widget)],
389     osd->pixmap, x-1, y-1, 0, 0, OSD_W+2, OSD_H+2);
390 harbaum 70
391 harbaum 73 priv->backup_x = x-1;
392     priv->backup_y = y-1;
393 harbaum 70
394     /* OSD itself uses some off-screen rendering, so check if the */
395     /* offscreen buffer is present and create it if not */
396 harbaum 73 if(!priv->overlay) {
397 harbaum 70 /* create overlay ... */
398 harbaum 73 priv->overlay =
399 harbaum 70 cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W, OSD_H);
400     /* ... and render it */
401 harbaum 73 osm_gps_map_osd_render(osd);
402 harbaum 70 }
403    
404     // now draw this onto the original context
405 harbaum 73 cairo_t *cr = gdk_cairo_create(osd->pixmap);
406     cairo_set_source_surface(cr, priv->overlay, x, y);
407 harbaum 70 cairo_paint(cr);
408     cairo_destroy(cr);
409     }
410    
411     static void
412 harbaum 73 osm_gps_map_osd_restore (osm_gps_map_osd_t *osd)
413 harbaum 70 {
414 harbaum 73 osd_priv_t *priv = (osd_priv_t*)osd->priv;
415 harbaum 70
416     /* restore backup of previous contents */
417 harbaum 73 if(priv->backup) {
418 harbaum 70 /* create backup of background */
419 harbaum 73 gdk_draw_drawable(osd->pixmap,
420     osd->widget->style->fg_gc[GTK_WIDGET_STATE(osd->widget)],
421     priv->backup, 0, 0,
422     priv->backup_x, priv->backup_y, OSD_W+2, OSD_H+2);
423 harbaum 70 }
424     }
425    
426 harbaum 73 static void
427     osm_gps_map_osd_free(osm_gps_map_osd_t *osd)
428 harbaum 70 {
429 harbaum 73 osd_priv_t *priv = (osd_priv_t *)(osd->priv);
430 harbaum 70
431 harbaum 73 if (priv->backup)
432     g_object_unref(priv->backup);
433 harbaum 70
434 harbaum 73 if (priv->overlay)
435     cairo_surface_destroy(priv->overlay);
436 harbaum 70
437 harbaum 73 g_free(priv);
438     }
439    
440     static osm_gps_map_osd_t osd_classic = {
441     .restore = osm_gps_map_osd_restore,
442     .draw = osm_gps_map_osd_draw,
443     .check = osm_gps_map_osd_check,
444     .render = osm_gps_map_osd_render,
445     .free = osm_gps_map_osd_free,
446    
447     .cb = NULL,
448     .data = NULL,
449    
450     .priv = NULL
451     };
452    
453     /* this is the only function that's externally visible */
454     void
455     osm_gps_map_osd_classic_init(OsmGpsMap *map)
456     {
457     osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);
458    
459     osd_classic.priv = priv;
460    
461 harbaum 74 /* extract style info from the widget */
462     priv->bg = GTK_WIDGET(map)->style->bg[GTK_STATE_NORMAL];
463     priv->fg = GTK_WIDGET(map)->style->fg[GTK_STATE_NORMAL];
464     priv->da = GTK_WIDGET(map)->style->fg[GTK_STATE_INSENSITIVE];
465    
466 harbaum 73 osm_gps_map_register_osd(map, &osd_classic);
467     }
468    
469    
470 harbaum 74 /* below are osd specific functions which aren't used by osm-gps-map */
471     /* but instead are to be used by the main application */
472 harbaum 73 void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb, gpointer data) {
473     osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
474    
475     g_return_if_fail (osd);
476    
477     osd->cb = cb;
478     osd->data = data;
479    
480 harbaum 70 /* this may have changed the state of the gps button */
481     /* we thus re-render the overlay */
482 harbaum 73 osd->render(osd);
483 harbaum 70
484 harbaum 73 osm_gps_map_redraw(map);
485 harbaum 70 }