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

Parent Directory Parent Directory | Revision Log Revision Log


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