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 113 by harbaum, Wed Sep 16 13:45:10 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            int orientation, offset_x, offset_y;
54    
55            float lat, lon;
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 BALLOON_W  (BALLOON_WIDTH + BALLOON_SHADOW)
123    #define BALLOON_H  (BALLOON_HEIGHT + POINTER_HEIGHT + BALLOON_SHADOW)
124    
125    #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS)
126    
127    
128    /* draw the bubble shape. this is used twice, once for the shape and once */
129    /* for the shadow */
130    static void
131    osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,
132           gboolean bottom, int px, int py, int px0, int px1) {
133    
134        cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);
135        cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
136                   BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);
137        if(!bottom) {
138            /* insert top pointer */
139            cairo_line_to (cr, px1, y0);
140            cairo_line_to (cr, px, py);
141            cairo_line_to (cr, px0, y0);
142        }
143    
144        cairo_line_to (cr, x1 - BALLOON_CORNER_RADIUS, y0);
145        cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
146                   BALLOON_CORNER_RADIUS, -M_PI/2, 0);
147        cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS);
148        cairo_arc (cr, x1 - BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
149                   BALLOON_CORNER_RADIUS, 0, M_PI/2);
150        if(bottom) {
151            /* insert bottom pointer */
152            cairo_line_to (cr, px0, y1);
153            cairo_line_to (cr, px, py);
154            cairo_line_to (cr, px1, y1);
155        }
156    
157        cairo_line_to (cr, x0 + BALLOON_CORNER_RADIUS, y1);
158        cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y1 - BALLOON_CORNER_RADIUS,
159                   BALLOON_CORNER_RADIUS, M_PI/2, M_PI);
160    
161        cairo_close_path (cr);
162    }
163    
164    static void
165    osd_render_balloon(osm_gps_map_osd_t *osd) {
166        osd_priv_t *priv = (osd_priv_t*)osd->priv;
167    
168        /* get zoom */
169        gint zoom;
170        g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
171    
172        /* ------- convert given coordinate into screen position --------- */
173        gint xs, ys;
174        osm_gps_map_geographic_to_screen (OSM_GPS_MAP(osd->widget),
175                                          priv->balloon.lat, priv->balloon.lon,
176                                          &xs, &ys);
177    
178        gint x0 = 1, y0 = 1;
179    
180        /* check position of this relative to screen center to determine */
181        /* pointer direction ... */
182        int pointer_x, pointer_x0, pointer_x1;
183        int pointer_y;
184    
185        /* ... and calculate position */
186        int orientation = 0;
187        if(xs > osd->widget->allocation.width/2) {
188            priv->balloon.offset_x = -BALLOON_WIDTH + POINTER_OFFSET;
189            pointer_x = x0 - priv->balloon.offset_x;
190            pointer_x0 = pointer_x - (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
191            pointer_x1 = pointer_x0 - POINTER_FOOT_WIDTH;
192            orientation |= 1;
193        } else {
194            priv->balloon.offset_x = -POINTER_OFFSET;
195            pointer_x = x0 - priv->balloon.offset_x;
196            pointer_x1 = pointer_x + (BALLOON_CORNER_RADIUS - POINTER_OFFSET);
197            pointer_x0 = pointer_x1 + POINTER_FOOT_WIDTH;
198        }
199    
200        gboolean bottom = FALSE;
201        if(ys > osd->widget->allocation.height/2) {
202            priv->balloon.offset_y = -BALLOON_HEIGHT - POINTER_HEIGHT;
203            pointer_y = y0 - priv->balloon.offset_y;
204            bottom = TRUE;
205            orientation |= 2;
206        } else {
207            priv->balloon.offset_y = 0;
208            pointer_y = y0 - priv->balloon.offset_y;
209            y0 += POINTER_HEIGHT;
210        }
211    
212        /* if required orientation equals current one, then don't render */
213        /* anything */
214        if(orientation == priv->balloon.orientation)
215            return;
216    
217        priv->balloon.orientation = orientation;
218    
219        /* calculate bottom/right of box */
220        int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;
221    
222        /* save balloon screen coordinates for later use */
223        priv->balloon.rect.x = x0 + BALLOON_BORDER;
224        priv->balloon.rect.y = y0 + BALLOON_BORDER;
225        priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER;
226        priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER;
227    
228        cairo_t *cr = cairo_create(priv->balloon.surface);
229        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
230        cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
231        cairo_paint(cr);
232        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
233    
234        /* --------- draw shadow --------------- */
235        osm_gps_map_draw_balloon_shape (cr,
236                     x0 + BALLOON_SHADOW, y0 + BALLOON_SHADOW,
237                     x1 + BALLOON_SHADOW, y1 + BALLOON_SHADOW,
238                     bottom, pointer_x, pointer_y,
239                     pointer_x0 + BALLOON_SHADOW, pointer_x1 + BALLOON_SHADOW);
240    
241        cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_SHADOW_TRANSPARENCY);
242        cairo_fill_preserve (cr);
243        cairo_set_source_rgba (cr, 1, 0, 0, 1.0);
244        cairo_set_line_width (cr, 0);
245        cairo_stroke (cr);
246    
247        /* --------- draw main shape ----------- */
248        osm_gps_map_draw_balloon_shape (cr, x0, y0, x1, y1,
249                     bottom, pointer_x, pointer_y, pointer_x0, pointer_x1);
250    
251        cairo_set_source_rgba (cr, 1, 1, 1, BALLOON_TRANSPARENCY);
252        cairo_fill_preserve (cr);
253        cairo_set_source_rgba (cr, 0, 0, 0, BALLOON_TRANSPARENCY);
254        cairo_set_line_width (cr, 1);
255        cairo_stroke (cr);
256    
257        if (priv->balloon.cb) {
258            /* clip in case application tries to draw in */
259                /* exceed of the balloon */
260            cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y,
261                             priv->balloon.rect.w, priv->balloon.rect.h);
262            cairo_clip (cr);
263            cairo_new_path (cr);  /* current path is not
264                                     consumed by cairo_clip() */
265    
266            priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data);
267        }
268    
269        cairo_destroy(cr);
270    }
271    
272    /* return true if balloon is being displayed and if */
273    /* the given coordinate is within this balloon */
274    static gboolean
275    osd_balloon_check(osm_gps_map_osd_t *osd, gint x, gint y)
276    {
277        osd_priv_t *priv = (osd_priv_t*)osd->priv;
278    
279        if(!priv->balloon.surface)
280            return FALSE;
281    
282        gint xs, ys;
283        osm_gps_map_geographic_to_screen (OSM_GPS_MAP(osd->widget),
284                                          priv->balloon.lat, priv->balloon.lon,
285                                          &xs, &ys);
286    
287        xs += priv->balloon.rect.x + priv->balloon.offset_x;
288        ys += priv->balloon.rect.y + priv->balloon.offset_y;
289    
290        return (priv->balloon.surface &&
291                (x > xs) && (x < xs + priv->balloon.rect.w) &&
292                (y > ys) && (y < ys + priv->balloon.rect.h));
293    }
294    
295    void osm_gps_map_osd_clear_balloon (OsmGpsMap *map) {
296        g_return_if_fail (OSM_IS_GPS_MAP (map));
297    
298        osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
299        g_return_if_fail (osd);
300    
301        osd_priv_t *priv = (osd_priv_t*)osd->priv;
302        g_return_if_fail (priv);
303    
304        printf("request to clear balloon\n");
305    
306        if(priv->balloon.surface) {
307            cairo_surface_destroy(priv->balloon.surface);
308            priv->balloon.surface = NULL;
309            priv->balloon.lat = OSM_GPS_MAP_INVALID;
310            priv->balloon.lon = OSM_GPS_MAP_INVALID;
311        }
312        osm_gps_map_redraw(map);
313    }
314    
315    void
316    osm_gps_map_osd_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
317                                  OsmGpsMapBalloonCallback cb, gpointer data) {
318        g_return_if_fail (OSM_IS_GPS_MAP (map));
319    
320        osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
321        g_return_if_fail (osd);
322    
323        osd_priv_t *priv = (osd_priv_t*)osd->priv;
324        g_return_if_fail (priv);
325    
326        osm_gps_map_osd_clear_balloon (map);
327    
328        printf("request to draw balloon at %f %f\n", latitude, longitude);
329    
330        /* allocate balloon surface */
331        priv->balloon.surface =
332            cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
333                                       BALLOON_W+2, BALLOON_H+2);
334    
335        priv->balloon.lat = latitude;
336        priv->balloon.lon = longitude;
337        priv->balloon.cb = cb;
338        priv->balloon.data = data;
339    
340        priv->balloon.orientation = -1;
341    
342        osd_render_balloon(osd);
343    
344        osm_gps_map_redraw(map);
345    }
346    
347    #endif // OSD_BALLOON
348    
349  /* position and extent of bounding box */  /* position and extent of bounding box */
350  #ifndef OSD_X  #ifndef OSD_X
351  #define OSD_X      (10)  #define OSD_X      (10)
# Line 660  static osd_button_t Line 926  static osd_button_t
926  osd_check(osm_gps_map_osd_t *osd, gint x, gint y) {  osd_check(osm_gps_map_osd_t *osd, gint x, gint y) {
927      osd_button_t but = OSD_NONE;      osd_button_t but = OSD_NONE;
928    
929    #ifdef OSD_BALLOON
930        /* check if user clicked into balloon */
931        if(osd_balloon_check(osd, x, y))
932            return OSD_BG;
933    #endif
934    
935  #ifdef OSD_SOURCE_SEL  #ifdef OSD_SOURCE_SEL
936      /* the source selection area is handles internally */      /* the source selection area is handles internally */
937      but = osd_source_check(osd, x, y);      but = osd_source_check(osd, x, y);
# Line 1283  osd_draw(osm_gps_map_osd_t *osd, GdkDraw Line 1555  osd_draw(osm_gps_map_osd_t *osd, GdkDraw
1555      // now draw this onto the original context      // now draw this onto the original context
1556      cairo_t *cr = gdk_cairo_create(drawable);      cairo_t *cr = gdk_cairo_create(drawable);
1557    
1558      int x, y;      gint x, y;
1559    
1560  #ifdef OSD_SCALE  #ifdef OSD_SCALE
1561      x =  OSD_X;      x =  OSD_X;
# Line 1313  osd_draw(osm_gps_map_osd_t *osd, GdkDraw Line 1585  osd_draw(osm_gps_map_osd_t *osd, GdkDraw
1585      cairo_paint(cr);      cairo_paint(cr);
1586  #endif  #endif
1587    
1588    #ifdef OSD_BALLOON
1589        if(priv->balloon.surface) {
1590    
1591            /* convert given lat lon into screen coordinates */
1592            gint x, y;
1593            osm_gps_map_geographic_to_screen (OSM_GPS_MAP(osd->widget),
1594                                          priv->balloon.lat, priv->balloon.lon,
1595                                          &x, &y);
1596    
1597            /* check if balloon needs to be rerendered */
1598            osd_render_balloon(osd);
1599    
1600            cairo_set_source_surface(cr, priv->balloon.surface,
1601                                     x + priv->balloon.offset_x,
1602                                     y + priv->balloon.offset_y);
1603            cairo_paint(cr);
1604        }
1605    #endif
1606    
1607      x = OSD_X;      x = OSD_X;
1608      if(x < 0)      if(x < 0)
1609          x += osd->widget->allocation.width - OSD_W;          x += osd->widget->allocation.width - OSD_W;
# Line 1380  osd_free(osm_gps_map_osd_t *osd) Line 1671  osd_free(osm_gps_map_osd_t *osd)
1671           cairo_surface_destroy(priv->coordinates.surface);           cairo_surface_destroy(priv->coordinates.surface);
1672  #endif  #endif
1673    
1674    #ifdef OSD_BALLOON
1675        if (priv->balloon.surface)
1676             cairo_surface_destroy(priv->balloon.surface);
1677    #endif
1678    
1679      g_free(priv);      g_free(priv);
1680  }  }
1681    
# Line 1415  osm_gps_map_osd_classic_init(OsmGpsMap * Line 1711  osm_gps_map_osd_classic_init(OsmGpsMap *
1711  {  {
1712      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);
1713    
1714    #ifdef OSD_BALLOON
1715        priv->balloon.lat = OSM_GPS_MAP_INVALID;
1716        priv->balloon.lon = OSM_GPS_MAP_INVALID;
1717    #endif
1718    
1719      osd_classic.priv = priv;      osd_classic.priv = priv;
1720    
1721      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.113