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

Parent Directory Parent Directory | Revision Log Revision Log


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