--- trunk/src/osm-gps-map-osd-classic.c 2009/09/07 13:20:37 98 +++ trunk/src/osm-gps-map-osd-classic.c 2009/09/10 13:06:16 106 @@ -25,11 +25,6 @@ /* OSD_DIAMETER */ /* OSD_X, OSD_Y */ -#define OSD_SCALE - -#define OSD_SCALE_W 100 -#define OSD_SCALE_H 20 - #ifndef USE_CAIRO #error "OSD control display lacks a non-cairo implementation!" #endif @@ -39,6 +34,8 @@ #include "osm-gps-map.h" #include "osm-gps-map-osd-classic.h" +#define OSD_COORDINATES + //the osd controls typedef struct { /* the offscreen representation of the OSD */ @@ -46,6 +43,15 @@ #ifdef OSD_SCALE cairo_surface_t *scale; + int scale_zoom; +#endif + +#ifdef OSD_CROSSHAIR + cairo_surface_t *crosshair; +#endif + +#ifdef OSD_COORDINATES + cairo_surface_t *coordinates; #endif #ifdef OSD_SOURCE_SEL @@ -451,7 +457,6 @@ int w = OSD_S_W, h = OSD_S_H; if(priv->expanded) { - /* ... and right of it the waypoint id */ cairo_text_extents_t extents; /* determine content size */ @@ -728,34 +733,230 @@ cairo_line_to (cr, x + Z_RIGHT + Z_LEN, y + Z_MID); } -static float pixel2m(OsmGpsMap *map, int pixel) { - return pixel*osm_gps_map_get_scale(OSM_GPS_MAP(map)); +#ifdef OSD_COORDINATES +#define OSD_COORDINATES_W 100 +#define OSD_COORDINATES_H 50 + +static void +osd_render_coordinates(osm_gps_map_osd_t *osd) +{ + osd_priv_t *priv = (osd_priv_t*)osd->priv; + + /* first fill with transparency */ + cairo_t *cr = cairo_create(priv->coordinates); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + // cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); + cairo_paint(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + cairo_destroy(cr); +} +#endif // OSD_COORDINATES + +#ifdef OSD_CROSSHAIR + +#ifndef OSD_CROSSHAIR_RADIUS +#define OSD_CROSSHAIR_RADIUS 10 +#endif + +#define OSD_CROSSHAIR_TICK (OSD_CROSSHAIR_RADIUS/2) +#define OSD_CROSSHAIR_BORDER (OSD_CROSSHAIR_TICK + OSD_CROSSHAIR_RADIUS/4) +#define OSD_CROSSHAIR_W ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2) +#define OSD_CROSSHAIR_H ((OSD_CROSSHAIR_RADIUS+OSD_CROSSHAIR_BORDER)*2) + +static void +osd_render_crosshair_shape(cairo_t *cr) { + cairo_arc (cr, OSD_CROSSHAIR_W/2, OSD_CROSSHAIR_H/2, + OSD_CROSSHAIR_RADIUS, 0, 2*M_PI); + + cairo_move_to (cr, OSD_CROSSHAIR_W/2 - OSD_CROSSHAIR_RADIUS, + OSD_CROSSHAIR_H/2); + cairo_rel_line_to (cr, -OSD_CROSSHAIR_TICK, 0); + cairo_move_to (cr, OSD_CROSSHAIR_W/2 + OSD_CROSSHAIR_RADIUS, + OSD_CROSSHAIR_H/2); + cairo_rel_line_to (cr, OSD_CROSSHAIR_TICK, 0); + + cairo_move_to (cr, OSD_CROSSHAIR_W/2, + OSD_CROSSHAIR_H/2 - OSD_CROSSHAIR_RADIUS); + cairo_rel_line_to (cr, 0, -OSD_CROSSHAIR_TICK); + cairo_move_to (cr, OSD_CROSSHAIR_W/2, + OSD_CROSSHAIR_H/2 + OSD_CROSSHAIR_RADIUS); + cairo_rel_line_to (cr, 0, OSD_CROSSHAIR_TICK); + + cairo_stroke (cr); +} + +static void +osd_render_crosshair(osm_gps_map_osd_t *osd) +{ + osd_priv_t *priv = (osd_priv_t*)osd->priv; + + /* first fill with transparency */ + cairo_t *cr = cairo_create(priv->crosshair); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0); + // cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); + cairo_paint(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_OVER); + + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + + cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.5); + cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/2); + osd_render_crosshair_shape(cr); + + cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5); + cairo_set_line_width (cr, OSD_CROSSHAIR_RADIUS/4); + osd_render_crosshair_shape(cr); + + cairo_destroy(cr); } +#endif + +#ifdef OSD_SCALE + +#ifndef OSD_SCALE_FONT_SIZE +#define OSD_SCALE_FONT_SIZE 12 +#endif +#define OSD_SCALE_W (10*OSD_SCALE_FONT_SIZE) +#define OSD_SCALE_H (5*OSD_SCALE_FONT_SIZE/2) + +/* various parameters used to create the scale */ +#define OSD_SCALE_H2 (OSD_SCALE_H/2) +#define OSD_SCALE_TICK (2*OSD_SCALE_FONT_SIZE/3) +#define OSD_SCALE_M (OSD_SCALE_H2 - OSD_SCALE_TICK) +#define OSD_SCALE_I (OSD_SCALE_H2 + OSD_SCALE_TICK) +#define OSD_SCALE_FD (OSD_SCALE_FONT_SIZE/4) static void osd_render_scale(osm_gps_map_osd_t *osd) { osd_priv_t *priv = (osd_priv_t*)osd->priv; + /* this only needs to be rendered if the zoom has changed */ + gint zoom; + g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL); + if(zoom == priv->scale_zoom) + return; + + priv->scale_zoom = zoom; + + float m_per_pix = osm_gps_map_get_scale(OSM_GPS_MAP(osd->widget)); + /* first fill with transparency */ cairo_t *cr = cairo_create(priv->scale); cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - // cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0); - cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); + cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.0); + // pink for testing: cairo_set_source_rgba(cr, 1.0, 0.0, 0.0, 0.2); cairo_paint(cr); cairo_set_operator(cr, CAIRO_OPERATOR_OVER); /* determine the size of the scale width in meters */ - float width = pixel2m(OSM_GPS_MAP(osd->widget), OSD_SCALE_W); - printf("width = %f meters\n", width); - + float width = (OSD_SCALE_W-OSD_SCALE_FONT_SIZE/6) * m_per_pix; + /* scale this to useful values */ int exp = logf(width)*M_LOG10E; int mant = width/pow(10,exp); - printf("mant = %d, exp = %d \n", mant, exp); + int width_metric = mant * pow(10,exp); + char *dist_str = NULL; + if(width_metric<1000) + dist_str = g_strdup_printf("%u m", width_metric); + else + dist_str = g_strdup_printf("%u km", width_metric/1000); + width_metric /= m_per_pix; + + /* and now the hard part: scale for useful imperial values :-( */ + /* try to convert to feet, 1ft == 0.3048 m */ + width /= 0.3048; + float imp_scale = 0.3048; + char *dist_imp_unit = "ft"; + + if(width >= 100) { + /* 1yd == 3 feet */ + width /= 3.0; + imp_scale *= 3.0; + dist_imp_unit = "yd"; + + if(width >= 1760.0) { + /* 1mi == 1760 yd */ + width /= 1760.0; + imp_scale *= 1760.0; + dist_imp_unit = "mi"; + } + } + + /* also convert this to full tens/hundreds */ + exp = logf(width)*M_LOG10E; + mant = width/pow(10,exp); + int width_imp = mant * pow(10,exp); + char *dist_str_imp = g_strdup_printf("%u %s", width_imp, dist_imp_unit); + + /* convert back to pixels */ + width_imp *= imp_scale; + width_imp /= m_per_pix; + + cairo_select_font_face (cr, "Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_BOLD); + cairo_set_font_size (cr, OSD_SCALE_FONT_SIZE); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + + cairo_text_extents_t extents; + cairo_text_extents (cr, dist_str, &extents); + + cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6); + cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD); + cairo_text_path (cr, dist_str); + cairo_stroke (cr); + cairo_move_to (cr, 2*OSD_SCALE_FD, + OSD_SCALE_H2+OSD_SCALE_FD + extents.height); + cairo_text_path (cr, dist_str_imp); + cairo_stroke (cr); + + cairo_set_source_rgb(cr, 0.0, 0.0, 0.0); + cairo_move_to (cr, 2*OSD_SCALE_FD, OSD_SCALE_H2-OSD_SCALE_FD); + cairo_show_text (cr, dist_str); + cairo_move_to (cr, 2*OSD_SCALE_FD, + OSD_SCALE_H2+OSD_SCALE_FD + extents.height); + cairo_show_text (cr, dist_str_imp); + + g_free(dist_str); + g_free(dist_str_imp); + + /* draw white line */ + cairo_set_line_cap (cr, CAIRO_LINE_CAP_ROUND); + cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/3); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M); + cairo_rel_line_to (cr, 0, OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_metric, 0); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_stroke(cr); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_imp, 0); + cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK); + cairo_stroke(cr); + + /* draw black line */ + cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0); + cairo_set_line_width (cr, OSD_SCALE_FONT_SIZE/6); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_M); + cairo_rel_line_to (cr, 0, OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_metric, 0); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_stroke(cr); + cairo_move_to (cr, OSD_SCALE_FONT_SIZE/6, OSD_SCALE_I); + cairo_rel_line_to (cr, 0, -OSD_SCALE_TICK); + cairo_rel_line_to (cr, width_imp, 0); + cairo_rel_line_to (cr, 0, +OSD_SCALE_TICK); + cairo_stroke(cr); cairo_destroy(cr); } +#endif static void osd_render(osm_gps_map_osd_t *osd) @@ -848,6 +1049,14 @@ #ifdef OSD_SCALE osd_render_scale(osd); #endif + +#ifdef OSD_CROSSHAIR + osd_render_crosshair(osd); +#endif + +#ifdef OSD_COORDINATES + osd_render_coordinates(osd); +#endif } static void @@ -873,6 +1082,19 @@ priv->scale = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, OSD_SCALE_W, OSD_SCALE_H); + priv->scale_zoom = -1; +#endif + +#ifdef OSD_CROSSHAIR + priv->crosshair = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + OSD_CROSSHAIR_W, OSD_CROSSHAIR_H); +#endif + +#ifdef OSD_COORDINATES + priv->coordinates = + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, + OSD_COORDINATES_W, OSD_COORDINATES_H); #endif /* ... and render it */ @@ -882,12 +1104,43 @@ // now draw this onto the original context cairo_t *cr = gdk_cairo_create(drawable); - int x = OSD_X, y = OSD_Y; - if(OSD_X < 0) - x = osd->widget->allocation.width - OSD_W + OSD_X; + int x, y; - if(OSD_Y < 0) - y = osd->widget->allocation.height - OSD_H + OSD_Y; +#ifdef OSD_SCALE + x = OSD_X; + y = -OSD_Y; + if(x < 0) x += osd->widget->allocation.width - OSD_SCALE_W; + if(y < 0) y += osd->widget->allocation.height - OSD_SCALE_H; + + cairo_set_source_surface(cr, priv->scale, x, y); + cairo_paint(cr); +#endif + +#ifdef OSD_CROSSHAIR + x = (osd->widget->allocation.width - OSD_CROSSHAIR_W)/2; + y = (osd->widget->allocation.height - OSD_CROSSHAIR_H)/2; + + cairo_set_source_surface(cr, priv->crosshair, x, y); + cairo_paint(cr); +#endif + +#ifdef OSD_COORDINATES + x = -OSD_X; + y = -OSD_Y; + if(x < 0) x += osd->widget->allocation.width - OSD_COORDINATES_W; + if(y < 0) y += osd->widget->allocation.height - OSD_COORDINATES_H; + + cairo_set_source_surface(cr, priv->coordinates, x, y); + cairo_paint(cr); +#endif + + x = OSD_X; + if(x < 0) + x += osd->widget->allocation.width - OSD_W; + + y = OSD_Y; + if(y < 0) + y += osd->widget->allocation.height - OSD_H; cairo_set_source_surface(cr, priv->overlay, x, y); cairo_paint(cr); @@ -914,16 +1167,6 @@ cairo_paint(cr); #endif -#ifdef OSD_SCALE - x = OSD_X; - y = -OSD_Y; - if(x < 0) x += osd->widget->allocation.width - OSD_SCALE_W; - if(y < 0) y += osd->widget->allocation.height - OSD_SCALE_H; - - cairo_set_source_surface(cr, priv->scale, x, y); - cairo_paint(cr); -#endif - cairo_destroy(cr); } @@ -948,6 +1191,16 @@ cairo_surface_destroy(priv->scale); #endif +#ifdef OSD_CROSSHAIR + if (priv->crosshair) + cairo_surface_destroy(priv->crosshair); +#endif + +#ifdef OSD_COORDINATES + if (priv->coordinates) + cairo_surface_destroy(priv->coordinates); +#endif + g_free(priv); }