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

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 111 by harbaum, Mon Sep 14 12:16:08 2009 UTC revision 112 by harbaum, Tue Sep 15 13:52:04 2009 UTC
# Line 32  Line 32 
32  #include <cairo.h>  #include <cairo.h>
33    
34  #include "osm-gps-map.h"  #include "osm-gps-map.h"
35    #include "converter.h"
36  #include "osm-gps-map-osd-classic.h"  #include "osm-gps-map-osd-classic.h"
37    
38  //the osd controls  //the osd controls
# Line 45  typedef struct { Line 46  typedef struct {
46  #endif  #endif
47      } controls;      } controls;
48    
49    #ifdef OSD_BALLOON
50        //a balloon with additional info
51        struct {
52            cairo_surface_t *surface;
53    
54            float lat, lon;
55            gboolean valid;
56            OsmGpsMapRect_t rect;
57    
58            /* function called to have the user app draw the contents */
59            OsmGpsMapBalloonCallback cb;
60            gpointer data;
61        } balloon;
62    #endif
63    
64  #ifdef OSD_SCALE  #ifdef OSD_SCALE
65      struct {      struct {
66          cairo_surface_t *surface;          cairo_surface_t *surface;
# Line 80  typedef struct { Line 96  typedef struct {
96    
97  } osd_priv_t;  } osd_priv_t;
98    
99    #ifdef OSD_BALLOON
100    /* most visual effects are hardcoded by now, but may be made */
101    /* available via properties later */
102    #ifndef BALLOON_AREA_WIDTH
103    #define BALLOON_AREA_WIDTH           290
104    #endif
105    #ifndef BALLOON_AREA_HEIGHT
106    #define BALLOON_AREA_HEIGHT           75
107    #endif
108    #ifndef BALLOON_CORNER_RADIUS
109    #define BALLOON_CORNER_RADIUS         10
110    #endif
111    
112    #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/2)
113    #define BALLOON_WIDTH                (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)
114    #define BALLOON_HEIGHT               (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)
115    #define BALLOON_TRANSPARENCY         0.8
116    #define POINTER_HEIGHT                20
117    #define POINTER_FOOT_WIDTH            20
118    #define POINTER_OFFSET               (BALLOON_CORNER_RADIUS*3/4)
119    #define BALLOON_SHADOW               (BALLOON_CORNER_RADIUS/2)
120    #define BALLOON_SHADOW_TRANSPARENCY  0.2
121    
122    #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS)
123    
124    
125    /* draw the bubble shape. this is used twice, once for the shape and once */
126    /* for the shadow */
127    static void
128    osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,
129           gboolean bottom, int px, int py, int px0, int px1) {
130    
131        cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);
132        cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
133                   BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);
134        if(!bottom) {
135            /* insert top pointer */
136            cairo_line_to (cr, px1, y0);
137            cairo_line_to (cr, px, py);
138            cairo_line_to (cr, px0, y0);
139        }
140    
141        cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);
142        cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
143                   BALLOON_CORNER_RADIUS, -M_PI/2, 0);
144        cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);
145        cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
146                   BALLOON_CORNER_RADIUS, 0, M_PI/2);
147        if(bottom) {
148            /* insert bottom pointer */
149            cairo_line_to (cr, px0, y1);
150            cairo_line_to (cr, px, py);
151            cairo_line_to (cr, px1, y1);
152        }
153    
154        cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);
155        cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
156                   BALLOON_CORNER_RADIUS, M_PI/2, M_PI);
157    
158        cairo_close_path (cr);
159    }
160    
161    /* xyz */
162    
163    static void
164    osd_render_balloon(osm_gps_map_osd_t *osd) {
165        osd_priv_t *priv = (osd_priv_t*)osd->priv;
166    
167        /* get zoom */
168        gint zoom;
169        g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
170    
171        /* ------- convert given coordinate into screen position --------- */
172        gint x0, y0;
173        osm_gps_map_geographic_to_screen (OSM_GPS_MAP(osd->widget),
174                                          priv->balloon.lat, priv->balloon.lon,
175                                          &x0, &y0);
176    
177        /* check position of this relative to screen center to determine */
178        /* pointer direction ... */
179        int pointer_x = x0, pointer_x0, pointer_x1;
180        int pointer_y = y0;
181    
182        /* ... and calculate position */
183        if(x0 > osd->widget->allocation.width/2) {
184            x0 += POINTER_OFFSET;
185            pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
186            pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;
187        } else {
188            x0 -= POINTER_OFFSET;
189            pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
190            pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;
191        }
192    
193        gboolean bottom = FALSE;
194        if(y0 > osd->widget->allocation.height/2) {
195            bottom = TRUE;
196            y0 -= BALLOON_HEIGHT + POINTER_HEIGHT;
197        } else
198            y0 += POINTER_HEIGHT;
199    
200        /* calculate bottom/right of box */
201        int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;
202    
203        /* save balloon screen coordinates for later use */
204        priv->balloon.rect.x = x0 + BALLOON_BORDER;
205        priv->balloon.rect.y = y0 + BALLOON_BORDER;
206        priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;
207        priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;
208    
209        cairo_t *cr = cairo_create(priv->balloon.surface);
210    
211        /* --------- draw shadow --------------- */
212        osm_gps_map_draw_balloon_shape (cr,
213                     x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,
214                     x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,
215                     bottom, pointer_x, pointer_y,
216                     pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);
217    
218        cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);
219        cairo_fill_preserve (cr);
220        cairo_set_source_rgba (cr, 1, 0, 0, 1.0);
221        cairo_set_line_width (cr, 0);
222        cairo_stroke (cr);
223    
224        /* --------- draw main shape ----------- */
225        osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,
226                     bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);
227    
228        cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);
229        cairo_fill_preserve (cr);
230        cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);
231        cairo_set_line_width (cr, 1);
232        cairo_stroke (cr);
233    
234    
235        /* ---------- draw close button --------- */
236    
237        int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS;
238        int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS;
239        int crad = CLOSE_BUTTON_RADIUS;
240    
241        cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI);
242        cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0);
243        cairo_fill_preserve (cr);
244        cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0);
245        cairo_set_line_width (cr, 2);
246        cairo_stroke(cr);
247    
248        cairo_set_source_rgba (cr, 1, 1, 1, 1.0);
249        cairo_set_line_width (cr, BALLOON_CORNER_RADIUS/3.3);
250        cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND);
251        cairo_move_to (cr, cx - crad/2, cy - crad/2);
252        cairo_line_to (cr, cx + crad/2, cy + crad/2);
253        cairo_stroke (cr);
254        cairo_move_to (cr, cx + crad/2, cy - crad/2);
255        cairo_line_to (cr, cx - crad/2, cy + crad/2);
256        cairo_stroke (cr);
257    
258        if (priv->balloon.cb) {
259            /* clip in case application tries to draw in */
260                /* exceed of the balloon */
261            cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,
262                             priv->balloon.rect.w, priv->balloon.rect.h);
263            cairo_clip (cr);
264            cairo_new_path (cr);  /* current path is not
265                                     consumed by cairo_clip() */
266    
267            priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);
268        }
269    
270        cairo_destroy(cr);
271    }
272    
273    #if 0
274    /* the user clicked into the balloons main area. handle this */
275    static void
276    osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y)
277    {
278        OsmGpsMapPrivate *priv = map->priv;
279    
280        if (!priv->balloon.valid)
281            return;
282    
283        /* check if the close button was clicked */
284        if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) &&
285            (x < priv->balloon.rect.w) &&
286            (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) {
287    
288            priv->balloon.valid = FALSE;
289            osm_gps_map_map_redraw_idle(map);
290        }
291    }
292    
293    /* return true if balloon is being displayed and if */
294    /* the given coordinate is within this balloon */
295    static gboolean
296    osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y)
297    {
298        return (priv->balloon.valid &&
299                (x > priv->balloon.rect.x) &&
300                (x < priv->balloon.rect.x + priv->balloon.rect.w) &&
301                (y > priv->balloon.rect.y) &&
302                (y < priv->balloon.rect.y + priv->balloon.rect.h));
303    }
304    
305    #if 0
306        /* don't drag if the user clicked within the balloon */
307        if (osm_gps_map_in_balloon(priv,
308                       event->x + EXTRA_BORDER,
309                       event->y + EXTRA_BORDER))
310        {
311            priv->drag_counter = -1;
312            return FALSE;
313        }
314    
315    #ifdef ENABLE_BALLOON
316        /* released inside the balloon? */
317        if (osm_gps_map_in_balloon(priv,
318                       event->x + EXTRA_BORDER,
319                       event->y + EXTRA_BORDER))
320        {
321            osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget),
322                 event->x - priv->balloon.rect.x + EXTRA_BORDER,
323                 event->y - priv->balloon.rect.y + EXTRA_BORDER);
324        }
325    #endif
326    
327    #endif
328    
329    void
330    osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
331                              OsmGpsMapBalloonCallback cb, gpointer data)
332    {
333        OsmGpsMapPrivate *priv;
334    
335        /* remove and previously installed balloon */
336        osm_gps_map_clear_balloon (map);
337    
338        g_return_if_fail (OSM_IS_GPS_MAP (map));
339        priv = map->priv;
340    
341        priv->balloon.lat = latitude;
342        priv->balloon.lon = longitude;
343        priv->balloon.valid = TRUE;
344    
345        priv->balloon.cb = cb;
346        priv->balloon.data = data;
347    
348        // this redraws the map
349        osm_gps_map_map_redraw_idle(map);
350    }
351    
352    void
353    osm_gps_map_clear_balloon (OsmGpsMap *map)
354    {
355        OsmGpsMapPrivate *priv;
356    
357        g_return_if_fail (OSM_IS_GPS_MAP (map));
358        priv = map->priv;
359    
360        priv->balloon.valid = FALSE;
361    
362        osm_gps_map_map_redraw_idle(map);
363    }
364    #endif
365    
366    void osm_gps_map_osd_clear_balloon (OsmGpsMap *map) {
367        printf("request to clear balloon\n");
368    }
369    
370    void
371    osm_gps_map_osd_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
372                                  OsmGpsMapBalloonCallback cb, gpointer data)
373    {
374        printf("request to draw balloon at %f %f\n", latitude, longitude);
375    }
376    
377    #endif // OSD_BALLOON
378    
379  /* position and extent of bounding box */  /* position and extent of bounding box */
380  #ifndef OSD_X  #ifndef OSD_X
381  #define OSD_X      (10)  #define OSD_X      (10)
# Line 1380  osd_free(osm_gps_map_osd_t *osd) Line 1676  osd_free(osm_gps_map_osd_t *osd)
1676           cairo_surface_destroy(priv->coordinates.surface);           cairo_surface_destroy(priv->coordinates.surface);
1677  #endif  #endif
1678    
1679    #ifdef OSD_BALLOON
1680        if (priv->balloon.surface)
1681             cairo_surface_destroy(priv->balloon.surface);
1682    #endif
1683    
1684      g_free(priv);      g_free(priv);
1685  }  }
1686    
# Line 1415  osm_gps_map_osd_classic_init(OsmGpsMap * Line 1716  osm_gps_map_osd_classic_init(OsmGpsMap *
1716  {  {
1717      osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);      osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);
1718    
1719    #ifdef OSD_BALLOON
1720        priv->balloon.lat = OSM_GPS_MAP_INVALID;
1721        priv->balloon.lon = OSM_GPS_MAP_INVALID;
1722    #endif
1723    
1724      osd_classic.priv = priv;      osd_classic.priv = priv;
1725    
1726      osm_gps_map_register_osd(map, &osd_classic);      osm_gps_map_register_osd(map, &osd_classic);

Legend:
Removed from v.111  
changed lines
  Added in v.112