--- trunk/src/osm-gps-map.c 2009/08/16 19:29:01 57 +++ trunk/src/osm-gps-map.c 2009/08/17 10:51:56 58 @@ -99,8 +99,13 @@ gboolean gps_valid; //a balloon with additional info - coord_t *balloon; - gboolean balloon_valid; + struct { + coord_t *coo; + gboolean valid; + OsmGpsMapRect_t rect; + OsmGpsMapBalloonCallback cb; + gpointer data; + } balloon; //additional images or tracks added to the map GSList *tracks; @@ -639,9 +644,13 @@ /* most visual effects are hardcoded by now, but may be made */ /* available via properties later */ +#define BALLOON_AREA_WIDTH 250 +#define BALLOON_AREA_HEIGHT 75 + #define BALLOON_CORNER_RADIUS 20 -#define BALLOON_WIDTH 150 -#define BALLOON_HEIGHT 75 +#define BALLOON_BORDER (BALLOON_CORNER_RADIUS/4) +#define BALLOON_WIDTH (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER) +#define BALLOON_HEIGHT (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER) #define BALLOON_TRANSPARENCY 0.8 #define POINTER_HEIGHT 20 #define POINTER_FOOT_WIDTH 20 @@ -649,6 +658,9 @@ #define BALLOON_SHADOW 5 #define BALLOON_SHADOW_TRANSPARENCY 0.2 +#define CLOSE_BUTTON_RADIUS (BALLOON_CORNER_RADIUS/3) + + /* draw the bubble shape. this is used twice, once for the shape and once */ /* for the shadow */ static void @@ -658,7 +670,7 @@ cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS); cairo_curve_to (cr, x0 , y0, x0 , y0, x0 + BALLOON_CORNER_RADIUS, y0); if(!bottom) { - /* insert bottom/left pointer */ + /* insert top pointer */ cairo_line_to (cr, px1, y0); cairo_line_to (cr, px, py); cairo_line_to (cr, px0, y0); @@ -669,7 +681,7 @@ cairo_line_to (cr, x1 , y1 - BALLOON_CORNER_RADIUS); cairo_curve_to (cr, x1, y1, x1, y1, x1 - BALLOON_CORNER_RADIUS, y1); if(bottom) { - /* insert bottom/left pointer */ + /* insert bottom pointer */ cairo_line_to (cr, px0, y1); cairo_line_to (cr, px, py); cairo_line_to (cr, px1, y1); @@ -687,12 +699,12 @@ { OsmGpsMapPrivate *priv = map->priv; - if (priv->balloon_valid) { + if (priv->balloon.valid) { /* ------- convert given coordinate into screen position --------- */ - int x0 = lon2pixel(priv->map_zoom, priv->balloon->rlon) - + int x0 = lon2pixel(priv->map_zoom, priv->balloon.coo->rlon) - priv->map_x + EXTRA_BORDER; - int y0 = lat2pixel(priv->map_zoom, priv->balloon->rlat) - + int y0 = lat2pixel(priv->map_zoom, priv->balloon.coo->rlat) - priv->map_y + EXTRA_BORDER; /* check position of this relative to screen center to determine */ @@ -721,6 +733,12 @@ /* calculate bottom/right of box */ int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT; + /* save balloon screen coordinates for later use */ + priv->balloon.rect.x = x0 + BALLOON_BORDER; + priv->balloon.rect.y = y0 + BALLOON_BORDER; + priv->balloon.rect.w = x1 - x0 - 2*BALLOON_BORDER; + priv->balloon.rect.h = y1 - y0 - 2*BALLOON_BORDER; + #ifdef USE_CAIRO cairo_t *cr = gdk_cairo_create(priv->pixmap); @@ -750,28 +768,38 @@ /* ---------- draw close button --------- */ - int cx = x1 - BALLOON_CORNER_RADIUS*3/4; - int cy = y0 + BALLOON_CORNER_RADIUS*3/4; - int crad = BALLOON_CORNER_RADIUS/3; + int cx = x1 - BALLOON_BORDER - CLOSE_BUTTON_RADIUS; + int cy = y0 + BALLOON_BORDER + CLOSE_BUTTON_RADIUS; + int crad = CLOSE_BUTTON_RADIUS; cairo_arc (cr, cx, cy, crad, 0, 2 * M_PI); cairo_set_source_rgba (cr, 0.8, 0, 0, 1.0); cairo_fill_preserve (cr); cairo_set_source_rgba (cr, 0.3, 0, 0, 1.0); - cairo_set_line_width (cr, 1); + cairo_set_line_width (cr, 2); cairo_stroke(cr); - int cs = crad/2; cairo_set_source_rgba (cr, 1, 1, 1, 1.0); cairo_set_line_width (cr, 3); cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); - cairo_move_to (cr, cx - cs, cy - cs); - cairo_line_to (cr, cx + cs, cy + cs); + cairo_move_to (cr, cx - crad/2, cy - crad/2); + cairo_line_to (cr, cx + crad/2, cy + crad/2); cairo_stroke (cr); - cairo_move_to (cr, cx + cs, cy - cs); - cairo_line_to (cr, cx - cs, cy + cs); + cairo_move_to (cr, cx + crad/2, cy - crad/2); + cairo_line_to (cr, cx - crad/2, cy + crad/2); cairo_stroke (cr); + if (priv->balloon.cb) { + /* clip in case application tries to draw in */ + /* exceed of the balloon */ + cairo_rectangle (cr, priv->balloon.rect.x, priv->balloon.rect.y, + priv->balloon.rect.w, priv->balloon.rect.h); + cairo_clip (cr); + cairo_new_path (cr); /* current path is not + consumed by cairo_clip() */ + + priv->balloon.cb(cr, &priv->balloon.rect, priv->balloon.data); + } gtk_widget_queue_draw_area (GTK_WIDGET(map), x0, y0, BALLOON_WIDTH, @@ -782,6 +810,39 @@ } } +/* the user clicked into the balloons main area. handle this */ +static void +osm_gps_map_handle_balloon_click(OsmGpsMap *map, gint x, gint y) +{ + OsmGpsMapPrivate *priv = map->priv; + + printf("clocked at %d %d\n", x, y); + + if (!priv->balloon.valid) + return; + + /* check if the close button was clicked */ + if ((x > priv->balloon.rect.w - 2*CLOSE_BUTTON_RADIUS) && + (x < priv->balloon.rect.w) && + (y > 0) && (y < 2*CLOSE_BUTTON_RADIUS)) { + + priv->balloon.valid = FALSE; + osm_gps_map_map_redraw_idle(map); + } +} + +/* return true if balloon is being displayed and if */ +/* the given coordinate is within this balloon */ +static gboolean +osm_gps_map_in_balloon(OsmGpsMapPrivate *priv, gint x, gint y) +{ + return (priv->balloon.valid && + (x > priv->balloon.rect.x) && + (x < priv->balloon.rect.x + priv->balloon.rect.w) && + (y > priv->balloon.rect.y) && + (y < priv->balloon.rect.y + priv->balloon.rect.h)); +} + static void osm_gps_map_blit_tile(OsmGpsMap *map, GdkPixbuf *pixbuf, int offset_x, int offset_y) { @@ -1398,8 +1459,9 @@ priv->gps = g_new0(coord_t, 1); priv->gps_valid = FALSE; - priv->balloon = g_new0(coord_t, 1); - priv->balloon_valid = FALSE; + priv->balloon.coo = g_new0(coord_t, 1); + priv->balloon.valid = FALSE; + priv->balloon.cb = NULL; priv->tracks = NULL; priv->images = NULL; @@ -1559,7 +1621,7 @@ g_source_remove (priv->idle_map_redraw); g_free(priv->gps); - g_free(priv->balloon); + g_free(priv->balloon.coo); G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object); } @@ -1776,6 +1838,15 @@ { OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + /* don't drag if the user clicked within the balloon */ + if (osm_gps_map_in_balloon(priv, + event->x + EXTRA_BORDER, + event->y + EXTRA_BORDER)) + { + priv->drag_counter = -1; + return FALSE; + } + priv->drag_counter = 0; priv->drag_start_mouse_x = (int) event->x; priv->drag_start_mouse_y = (int) event->y; @@ -1790,6 +1861,20 @@ { OsmGpsMapPrivate *priv = OSM_GPS_MAP_PRIVATE(widget); + /* released inside the balloon? */ + if (osm_gps_map_in_balloon(priv, + event->x + EXTRA_BORDER, + event->y + EXTRA_BORDER)) + { + osm_gps_map_handle_balloon_click(OSM_GPS_MAP(widget), + event->x - priv->balloon.rect.x + EXTRA_BORDER, + event->y - priv->balloon.rect.y + EXTRA_BORDER); + return FALSE; + } + + if (priv->drag_counter < 0) + return FALSE; + if (priv->dragging) { priv->dragging = FALSE; @@ -1807,7 +1892,7 @@ priv->drag_mouse_dx = 0; priv->drag_mouse_dy = 0; - priv->drag_counter = 0; + priv->drag_counter = -1; return FALSE; } @@ -1832,6 +1917,9 @@ if (!(state & GDK_BUTTON1_MASK)) return FALSE; + if (priv->drag_counter < 0) + return FALSE; + priv->drag_counter++; // we havent dragged more than 6 pixels @@ -1934,7 +2022,8 @@ widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], priv->pixmap, - event->area.x + EXTRA_BORDER, event->area.y + EXTRA_BORDER, + event->area.x + EXTRA_BORDER, + event->area.y + EXTRA_BORDER, event->area.x, event->area.y, event->area.width, event->area.height); @@ -2710,7 +2799,8 @@ } void -osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude) +osm_gps_map_draw_balloon (OsmGpsMap *map, float latitude, float longitude, + OsmGpsMapBalloonCallback cb, gpointer data) { OsmGpsMapPrivate *priv; @@ -2720,9 +2810,12 @@ g_return_if_fail (OSM_IS_GPS_MAP (map)); priv = map->priv; - priv->balloon->rlat = deg2rad(latitude); - priv->balloon->rlon = deg2rad(longitude); - priv->balloon_valid = TRUE; + priv->balloon.coo->rlat = deg2rad(latitude); + priv->balloon.coo->rlon = deg2rad(longitude); + priv->balloon.valid = TRUE; + + priv->balloon.cb = cb; + priv->balloon.data = data; // this redraws the map osm_gps_map_map_redraw_idle(map); @@ -2736,7 +2829,7 @@ g_return_if_fail (OSM_IS_GPS_MAP (map)); priv = map->priv; - priv->balloon_valid = FALSE; + priv->balloon.valid = FALSE; osm_gps_map_map_redraw_idle(map); }