--- trunk/src/osm-gps-map.c 2009/08/20 09:54:10 68 +++ trunk/src/osm-gps-map.c 2009/08/24 09:23:36 74 @@ -110,16 +110,10 @@ #endif #ifdef ENABLE_OSD - //the osd controls - struct { - GdkPixmap *backup; - cairo_surface_t *overlay; - gint backup_x, backup_y; - OsmGpsMapOsdGpsCallback cb; - gpointer data; - } osd; + //the osd controls (if present) + osm_gps_map_osd_t *osd; #endif - + //additional images or tracks added to the map GSList *tracks; GSList *images; @@ -1423,349 +1417,6 @@ g_hash_table_foreach_remove(priv->tile_cache, osm_gps_map_purge_cache_check, priv); } -#ifdef ENABLE_OSD -/* position and extent of bounding box */ -#define OSD_X (10) -#define OSD_Y (10) - -#define OSD_COLOR 0.5, 0.5, 1 -#define OSD_COLOR_DISABLED 0.8, 0.8, 0.8 - -/* parameters of the direction shape */ -#ifndef OSM_GPS_MAP_OSD_DIAMETER -#define D_RAD (30) // diameter of dpad -#else -#define D_RAD (OSM_GPS_MAP_OSD_DIAMETER) -#endif -#define D_TIP (4*D_RAD/5) // distance of arrow tip from dpad center -#define D_LEN (D_RAD/4) // length of arrow -#define D_WID (D_LEN) // width of arrow - -/* parameters of the "zoom" pad */ -#define Z_STEP (D_RAD/4) // distance between dpad and zoom -#define Z_RAD (D_RAD/2) // radius of "caps" of zoom bar - -/* shadow also depends on control size */ -#define OSD_SHADOW (D_RAD/6) - -/* total width and height of controls incl. shadow */ -#define OSD_W (2*D_RAD + OSD_SHADOW) -#define OSD_H (2*D_RAD + Z_STEP + 2*Z_RAD + OSD_SHADOW) - -#define OSD_LBL_SHADOW (OSD_SHADOW/2) - -#define Z_TOP (2 * D_RAD + Z_STEP) -#define Z_MID (Z_TOP + Z_RAD) -#define Z_BOT (Z_MID + Z_RAD) -#define Z_LEFT (Z_RAD) -#define Z_RIGHT (2 * D_RAD - Z_RAD) - -/* create the cairo shape used for the zoom buttons */ -static void -osm_gps_map_osd_zoom_shape(cairo_t *cr, gint x, gint y) { - cairo_move_to (cr, x+Z_LEFT, y+Z_TOP); - cairo_line_to (cr, x+Z_RIGHT, y+Z_TOP); - cairo_arc (cr, x+Z_RIGHT, y+Z_MID, Z_RAD, -M_PI/2, M_PI/2); - cairo_line_to (cr, x+Z_LEFT, y+Z_BOT); - cairo_arc (cr, x+Z_LEFT, y+Z_MID, Z_RAD, M_PI/2, -M_PI/2); -} - -/* create the cairo shape used for the dpad */ -static void -osm_gps_map_osd_dpad_shape(cairo_t *cr, gint x, gint y) { - cairo_arc (cr, x+D_RAD, y+D_RAD, D_RAD, 0, 2 * M_PI); -} - -typedef enum { - OSD_NONE = 0, - OSD_BG, - OSD_UP, - OSD_DOWN, - OSD_LEFT, - OSD_RIGHT, - OSD_IN, - OSD_OUT, - OSD_GPS -} osd_button_t; - -static gboolean -osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad) -{ - return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad); -} - -/* check whether x/y is within the dpad */ -static osd_button_t -osm_gps_map_osd_check_dpad(gint x, gint y) -{ - /* within entire dpad circle */ - if( osm_gps_map_in_circle(x, y, OSD_X + D_RAD, OSD_Y + D_RAD, D_RAD)) - { - /* convert into position relative to dpads centre */ - x -= (OSD_X + D_RAD); - y -= (OSD_Y + D_RAD); - - /* check for dpad center goes here! */ - if( osm_gps_map_in_circle(x, y, 0, 0, D_RAD/3)) - return OSD_GPS; - - if( y < 0 && abs(x) < abs(y)) - return OSD_UP; - - if( y > 0 && abs(x) < abs(y)) - return OSD_DOWN; - - if( x < 0 && abs(y) < abs(x)) - return OSD_LEFT; - - if( x > 0 && abs(y) < abs(x)) - return OSD_RIGHT; - - return OSD_BG; - } - return OSD_NONE; -} - -/* check whether x/y is within the zoom pads */ -static osd_button_t -osm_gps_map_osd_check_zoom(gint x, gint y) { - if( x > OSD_X && x < (OSD_X + OSD_W) && y > Z_TOP && y < (OSD_Y+Z_BOT)) { - - /* within circle around (-) label */ - if( osm_gps_map_in_circle(x, y, OSD_X + Z_LEFT, OSD_Y + Z_MID, Z_RAD)) - return OSD_OUT; - - /* between center of (-) button and center of entire zoom control area */ - if(x > OSD_LEFT && x < OSD_X + D_RAD) - return OSD_OUT; - - /* within circle around (+) label */ - if( osm_gps_map_in_circle(x, y, OSD_X + Z_RIGHT, OSD_Y + Z_MID, Z_RAD)) - return OSD_IN; - - /* between center of (+) button and center of entire zoom control area */ - if(x < OSD_RIGHT && x > OSD_X + D_RAD) - return OSD_IN; - } - - return OSD_NONE; -} - -static osd_button_t -osm_gps_map_osd_check(gint x, gint y) { - osd_button_t but = OSD_NONE; - - /* first do a rough test for the OSD area. */ - /* this is just to avoid an unnecessary detailed test */ - if(x > OSD_X && x < OSD_X + OSD_W && - y > OSD_Y && y < OSD_Y + OSD_H) { - but = osm_gps_map_osd_check_dpad(x, y); - - if(but == OSD_NONE) - but = osm_gps_map_osd_check_zoom(x, y); - } - - return but; -} - -static void -osm_gps_map_osd_shape_shadow(cairo_t *cr) { - cairo_set_source_rgba (cr, 0, 0, 0, 0.2); - cairo_fill (cr); - cairo_stroke (cr); -} - -static void -osm_gps_map_osd_shape(cairo_t *cr) { - cairo_set_source_rgb (cr, 1, 1, 1); - cairo_fill_preserve (cr); - cairo_set_source_rgb (cr, OSD_COLOR); - cairo_set_line_width (cr, 1); - cairo_stroke (cr); -} - -static void -osm_gps_map_osd_dpad_labels(cairo_t *cr, gint x, gint y) { - /* move reference to dpad center */ - x += D_RAD; - y += D_RAD; - - const static gint offset[][3][2] = { - /* left arrow/triangle */ - { { -D_TIP+D_LEN, -D_WID }, { -D_LEN, D_WID }, { +D_LEN, D_WID } }, - /* right arrow/triangle */ - { { +D_TIP-D_LEN, -D_WID }, { +D_LEN, D_WID }, { -D_LEN, D_WID } }, - /* top arrow/triangle */ - { { -D_WID, -D_TIP+D_LEN }, { D_WID, -D_LEN }, { D_WID, +D_LEN } }, - /* bottom arrow/triangle */ - { { -D_WID, +D_TIP-D_LEN }, { D_WID, +D_LEN }, { D_WID, -D_LEN } } - }; - - int i; - for(i=0;i<4;i++) { - cairo_move_to (cr, x + offset[i][0][0], y + offset[i][0][1]); - cairo_rel_line_to (cr, offset[i][1][0], offset[i][1][1]); - cairo_rel_line_to (cr, offset[i][2][0], offset[i][2][1]); - } -} - -/* draw the sattelite dish icon in the center of the dpad */ -#define GPS_V0 (D_RAD/8) -#define GPS_V1 (D_RAD/10) -#define GPS_V2 (D_RAD/5) - -/* draw a satellite receiver dish */ -static void -osm_gps_map_osd_dpad_gps(cairo_t *cr, gint x, gint y) { - /* move reference to dpad center */ - x += D_RAD; - y += D_RAD + GPS_V0; - - cairo_move_to (cr, x-GPS_V0, y+GPS_V0); - cairo_rel_line_to (cr, +GPS_V0, -GPS_V0); - cairo_rel_line_to (cr, +GPS_V0, +GPS_V0); - cairo_close_path (cr); - - cairo_move_to (cr, x+GPS_V1-GPS_V2, y-2*GPS_V2); - cairo_curve_to (cr, x-GPS_V2, y, x+GPS_V1, y+GPS_V1, x+GPS_V1+GPS_V2, y); - cairo_close_path (cr); - - x += GPS_V1; - cairo_move_to (cr, x, y-GPS_V2); - cairo_rel_line_to (cr, +GPS_V1, -GPS_V1); -} - -#define Z_LEN (2*Z_RAD/3) - -static void -osm_gps_map_osd_zoom_labels(cairo_t *cr, gint x, gint y) { - cairo_move_to (cr, x + Z_LEFT - Z_LEN, y + Z_MID); - cairo_line_to (cr, x + Z_LEFT + Z_LEN, y + Z_MID); - - cairo_move_to (cr, x + Z_RIGHT, y + Z_MID - Z_LEN); - cairo_line_to (cr, x + Z_RIGHT, y + Z_MID + Z_LEN); - cairo_move_to (cr, x + Z_RIGHT - Z_LEN, y + Z_MID); - cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID); -} - -static void -osm_gps_map_osd_labels(cairo_t *cr, gint width, gboolean enabled) { - if(enabled) cairo_set_source_rgb (cr, OSD_COLOR); - else cairo_set_source_rgb (cr, OSD_COLOR_DISABLED); - cairo_set_line_width (cr, width); - cairo_stroke (cr); -} - -static void -osm_gps_map_osd_labels_shadow(cairo_t *cr, gint width, gboolean enabled) { - cairo_set_source_rgba (cr, 0, 0, 0, enabled?0.3:0.15); - cairo_set_line_width (cr, width); - cairo_stroke (cr); -} - -static void -osm_gps_map_osd_render(OsmGpsMapPrivate *priv) { - - /* first fill with transparency */ - cairo_t *cr = cairo_create(priv->osd.overlay); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0); - cairo_paint(cr); - - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - - /* --------- draw zoom and dpad shape shadow ----------- */ - gint x = 0, y = 0; - - osm_gps_map_osd_zoom_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW); - osm_gps_map_osd_shape_shadow(cr); - osm_gps_map_osd_dpad_shape(cr, x + OSD_SHADOW, y + OSD_SHADOW); - osm_gps_map_osd_shape_shadow(cr); - - /* --------- draw zoom and dpad shape ----------- */ - - osm_gps_map_osd_zoom_shape(cr, x, y); - osm_gps_map_osd_shape(cr); - osm_gps_map_osd_dpad_shape(cr, x, y); - osm_gps_map_osd_shape(cr); - - /* --------- draw zoom and dpad labels --------- */ - - osm_gps_map_osd_zoom_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW); - osm_gps_map_osd_dpad_labels(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW); - osm_gps_map_osd_labels_shadow(cr, Z_RAD/3, TRUE); - osm_gps_map_osd_dpad_gps(cr, x + OSD_LBL_SHADOW, y + OSD_LBL_SHADOW); - osm_gps_map_osd_labels_shadow(cr, Z_RAD/6, priv->osd.cb != NULL); - - osm_gps_map_osd_zoom_labels(cr, x, y); - osm_gps_map_osd_dpad_labels(cr, x, y); - osm_gps_map_osd_labels(cr, Z_RAD/3, TRUE); - osm_gps_map_osd_dpad_gps(cr, x, y); - osm_gps_map_osd_labels(cr, Z_RAD/6, priv->osd.cb != NULL); - - cairo_destroy(cr); -} - -static void -osm_gps_map_osd_draw_controls (OsmGpsMap *map, gint xoffset, gint yoffset) -{ - OsmGpsMapPrivate *priv = map->priv; - - /* backup previous contents */ - if(!priv->osd.backup) - priv->osd.backup = gdk_pixmap_new(priv->pixmap, OSD_W+2, OSD_H+2, -1); - - gint x = OSD_X + EXTRA_BORDER + xoffset; - gint y = OSD_Y + EXTRA_BORDER + yoffset; - - /* create backup of background */ - gdk_draw_drawable(priv->osd.backup, - GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(GTK_WIDGET(map))], - priv->pixmap, x-1, y-1, 0, 0, OSD_W+2, OSD_H+2); - - priv->osd.backup_x = x-1; - priv->osd.backup_y = y-1; - - -#ifdef USE_CAIRO - /* OSD itself uses some off-screen rendering, so check if the */ - /* offscreen buffer is present and create it if not */ - if(!priv->osd.overlay) { - /* create overlay ... */ - priv->osd.overlay = - cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_W, OSD_H); - /* ... and render it */ - osm_gps_map_osd_render(priv); - } - - // now draw this onto the original context - cairo_t *cr = gdk_cairo_create(priv->pixmap); - cairo_set_source_surface(cr, priv->osd.overlay, x, y); - cairo_paint(cr); - cairo_destroy(cr); - -#else -#warning "OSD control display lacks a non-cairo implementation!" -#endif -} - -static void -osm_gps_map_osd_restore (OsmGpsMap *map) -{ - OsmGpsMapPrivate *priv = map->priv; - - /* restore backup of previous contents */ - if(priv->osd.backup) { - /* create backup of background */ - gdk_draw_drawable(priv->pixmap, - GTK_WIDGET(map)->style->fg_gc[GTK_WIDGET_STATE(GTK_WIDGET(map))], - priv->osd.backup, 0, 0, - priv->osd.backup_x, priv->osd.backup_y, OSD_W+2, OSD_H+2); - } -} - -#endif - static gboolean osm_gps_map_map_redraw (OsmGpsMap *map) { @@ -1799,8 +1450,10 @@ #ifdef ENABLE_BALLOON osm_gps_map_draw_balloon_int(map); #endif + #ifdef ENABLE_OSD - osm_gps_map_osd_draw_controls(map, 0, 0); + if(priv->osd) + priv->osd->draw(priv->osd, EXTRA_BORDER, EXTRA_BORDER); #endif //osm_gps_map_osd_speed(map, 1.5); @@ -1840,9 +1493,7 @@ #endif #ifdef ENABLE_OSD - priv->osd.backup = NULL; - priv->osd.overlay = NULL; - priv->osd.cb = NULL; + priv->osd = NULL; #endif priv->tracks = NULL; @@ -2009,11 +1660,8 @@ #endif #ifdef ENABLE_OSD - if (priv->osd.backup) - g_object_unref(priv->osd.backup); - - if (priv->osd.overlay) - cairo_surface_destroy(priv->osd.overlay); + if(priv->osd) + priv->osd->free(priv->osd); #endif G_OBJECT_CLASS (osm_gps_map_parent_class)->dispose (object); @@ -2246,51 +1894,52 @@ #define SCROLL_STEP 10 /* pressed inside OSD control? */ - osd_button_t but = osm_gps_map_osd_check(event->x, event->y); - if(but != OSD_NONE) - { - priv->drag_counter = -1; - - switch(but) { - case OSD_GPS: - priv->osd.cb(priv->osd.data); - break; - - case OSD_UP: - priv->map_y -= GTK_WIDGET(widget)->allocation.height/SCROLL_STEP; - priv->center_coord_set = FALSE; - break; - - case OSD_DOWN: - priv->map_y += GTK_WIDGET(widget)->allocation.height/SCROLL_STEP; - priv->center_coord_set = FALSE; - break; - - case OSD_LEFT: - priv->map_x -= GTK_WIDGET(widget)->allocation.width/SCROLL_STEP; - priv->center_coord_set = FALSE; - break; - - case OSD_RIGHT: - priv->map_x += GTK_WIDGET(widget)->allocation.width/SCROLL_STEP; - priv->center_coord_set = FALSE; - break; - - case OSD_IN: - osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1); - break; + if(priv->osd) { + osd_button_t but = priv->osd->check(event->x, event->y); + if(but != OSD_NONE) + { + priv->drag_counter = -1; + + switch(but) { + case OSD_UP: + priv->map_y -= GTK_WIDGET(widget)->allocation.height/SCROLL_STEP; + priv->center_coord_set = FALSE; + break; - case OSD_OUT: - osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1); - break; + case OSD_DOWN: + priv->map_y += GTK_WIDGET(widget)->allocation.height/SCROLL_STEP; + priv->center_coord_set = FALSE; + break; - default: - break; + case OSD_LEFT: + priv->map_x -= GTK_WIDGET(widget)->allocation.width/SCROLL_STEP; + priv->center_coord_set = FALSE; + break; + + case OSD_RIGHT: + priv->map_x += GTK_WIDGET(widget)->allocation.width/SCROLL_STEP; + priv->center_coord_set = FALSE; + break; + + case OSD_IN: + osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom+1); + break; + + case OSD_OUT: + osm_gps_map_set_zoom(OSM_GPS_MAP(widget), priv->map_zoom-1); + break; + + default: + /* all custom buttons are forwarded to the application */ + if(priv->osd->cb) + priv->osd->cb(but, priv->osd->data); + break; + } + + osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); + + return FALSE; } - - osm_gps_map_map_redraw_idle(OSM_GPS_MAP(widget)); - - return FALSE; } #endif @@ -2391,18 +2040,19 @@ priv->drag_mouse_dy = y - priv->drag_start_mouse_y; #ifdef ENABLE_OSD - /* undo OSD */ - osm_gps_map_osd_restore (OSM_GPS_MAP(widget)); - - /* draw new OSD */ - osm_gps_map_osd_draw_controls (OSM_GPS_MAP(widget), - -priv->drag_mouse_dx, - -priv->drag_mouse_dy); + if(priv->osd) { + /* undo OSD */ + priv->osd->restore (priv->osd); + + /* draw new OSD */ + priv->osd->draw (priv->osd, + EXTRA_BORDER - priv->drag_mouse_dx, + EXTRA_BORDER - priv->drag_mouse_dy); + } #endif - + osm_gps_map_expose (widget, NULL); - return FALSE; } @@ -2421,6 +2071,15 @@ widget->allocation.height + EXTRA_BORDER * 2, -1); +#ifdef ENABLE_OSD + /* the osd needs some references to map internal objects */ + if(priv->osd) + { + priv->osd->pixmap = priv->pixmap; + priv->osd->widget = widget; + } +#endif + /* and gc, used for clipping (I think......) */ if(priv->gc_map) g_object_unref(priv->gc_map); @@ -3308,19 +2967,27 @@ #endif #ifdef ENABLE_OSD -void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdGpsCallback cb, gpointer data) { + +void +osm_gps_map_redraw (OsmGpsMap *map) +{ + osm_gps_map_map_redraw_idle(map); +} + +osm_gps_map_osd_t *osm_gps_map_osd_get(OsmGpsMap *map) { + g_return_val_if_fail (OSM_IS_GPS_MAP (map), NULL); + return map->priv->osd; +} + +void osm_gps_map_register_osd(OsmGpsMap *map, osm_gps_map_osd_t *osd) { OsmGpsMapPrivate *priv; g_return_if_fail (OSM_IS_GPS_MAP (map)); - priv = map->priv; - - priv->osd.cb = cb; - priv->osd.data = data; - /* this may have changed the state of the gps button */ - /* we thus re-render the overlay */ - osm_gps_map_osd_render(priv); + priv = map->priv; + g_return_if_fail (!priv->osd); - osm_gps_map_map_redraw_idle(map); + priv->osd = osd; } + #endif