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

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

revision 279 by harbaum, Wed Dec 9 19:45:36 2009 UTC revision 280 by harbaum, Fri May 21 19:28:16 2010 UTC
# Line 18  Line 18 
18   */   */
19    
20  #include "config.h"  #include "config.h"
21    
22  #include <stdlib.h>  // abs  #include <stdlib.h>  // abs
23  #include <string.h>  #include <string.h>
24  #include <math.h>    // M_PI/cos()  #include <math.h>    // M_PI/cos()
# Line 26  Line 27 
27  /* OSD_DIAMETER */  /* OSD_DIAMETER */
28  /* OSD_X, OSD_Y */  /* OSD_X, OSD_Y */
29    
 #ifndef USE_CAIRO  
 #error "OSD control display lacks a non-cairo implementation!"  
 #endif  
   
30  #include <cairo.h>  #include <cairo.h>
31    
32  #include "osm-gps-map.h"  #include "osm-gps-map.h"
33  #include "converter.h"  #include "converter.h"
34  #include "osm-gps-map-osd-classic.h"  #include "osm-gps-map-osd-classic.h"
35    
36    static OsmGpsMapSource_t map_sources[] = {
37        OSM_GPS_MAP_SOURCE_OPENSTREETMAP,
38        OSM_GPS_MAP_SOURCE_OPENSTREETMAP_RENDERER,
39        OSM_GPS_MAP_SOURCE_OPENCYCLEMAP,
40        OSM_GPS_MAP_SOURCE_OSM_PUBLIC_TRANSPORT,
41        OSM_GPS_MAP_SOURCE_GOOGLE_STREET,
42        OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_STREET,
43        OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_SATELLITE,
44        OSM_GPS_MAP_SOURCE_VIRTUAL_EARTH_HYBRID
45    };
46    static int num_map_sources = sizeof(map_sources)/sizeof(map_sources[0]);
47    
48    #ifdef OSD_DOUBLEPIXEL
49    #define OSD_DPIX_EXTRA 1
50    #define OSD_DPIX_SKIP  (OSD_FONT_SIZE/2)
51    #else
52    #define OSD_DPIX_EXTRA 0
53    #define OSD_DPIX_SKIP  0
54    #endif
55    
56  //the osd controls  //the osd controls
57  typedef struct {  typedef struct {
58      /* the offscreen representation of the OSD */      /* the offscreen representation of the OSD */
# Line 87  typedef struct { Line 104  typedef struct {
104      } nav;      } nav;
105  #endif  #endif
106    
107    #ifdef OSD_HEARTRATE
108        struct {
109            cairo_surface_t *surface;
110            gint rate;
111            gboolean ok;
112        } hr;
113    #endif
114    
115  #ifdef OSD_COORDINATES  #ifdef OSD_COORDINATES
116      struct {      struct {
117          cairo_surface_t *surface;          cairo_surface_t *surface;
# Line 103  typedef struct { Line 128  typedef struct {
128          gint handler_id;          gint handler_id;
129          gint width, height;          gint width, height;
130          gboolean rendered;          gboolean rendered;
131            gint max_h;
132      } source_sel;      } source_sel;
133  #endif  #endif
134    
# Line 122  typedef struct { Line 148  typedef struct {
148  #endif  #endif
149    
150  #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/2)  #define BALLOON_BORDER               (BALLOON_CORNER_RADIUS/2)
151  #define BALLOON_WIDTH                (BALLOON_AREA_WIDTH + 2 * BALLOON_BORDER)  #define BALLOON_WIDTH                (priv->balloon.rect.w + 2 * BALLOON_BORDER)
152  #define BALLOON_HEIGHT               (BALLOON_AREA_HEIGHT + 2 * BALLOON_BORDER)  #define BALLOON_HEIGHT               (priv->balloon.rect.h + 2 * BALLOON_BORDER)
153  #define BALLOON_TRANSPARENCY         0.8  #define BALLOON_TRANSPARENCY         0.8
154  #define POINTER_HEIGHT                20  #define POINTER_HEIGHT                20
155  #define POINTER_FOOT_WIDTH            20  #define POINTER_FOOT_WIDTH            20
# Line 134  typedef struct { Line 160  typedef struct {
160  #define BALLOON_W  (BALLOON_WIDTH + BALLOON_SHADOW)  #define BALLOON_W  (BALLOON_WIDTH + BALLOON_SHADOW)
161  #define BALLOON_H  (BALLOON_HEIGHT + POINTER_HEIGHT + BALLOON_SHADOW)  #define BALLOON_H  (BALLOON_HEIGHT + POINTER_HEIGHT + BALLOON_SHADOW)
162    
 #define CLOSE_BUTTON_RADIUS   (BALLOON_CORNER_RADIUS)  
   
163  /* draw the bubble shape. this is used twice, once for the shape and once */  /* draw the bubble shape. this is used twice, once for the shape and once */
164  /* for the shadow */  /* for the shadow */
165  static void  static void
# Line 178  osd_render_balloon(osm_gps_map_osd_t *os Line 202  osd_render_balloon(osm_gps_map_osd_t *os
202    
203      if(!priv->balloon.surface)      if(!priv->balloon.surface)
204          return;          return;
   
205      /* get zoom */      /* get zoom */
206      gint zoom;      gint zoom;
207      g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);      g_object_get(OSM_GPS_MAP(osd->widget), "zoom", &zoom, NULL);
# Line 231  osd_render_balloon(osm_gps_map_osd_t *os Line 254  osd_render_balloon(osm_gps_map_osd_t *os
254      priv->balloon.orientation = orientation;      priv->balloon.orientation = orientation;
255    
256      /* calculate bottom/right of box */      /* calculate bottom/right of box */
257      int x1 = x0 + BALLOON_WIDTH, y1 = y0 + BALLOON_HEIGHT;      int x1 = x0 + priv->balloon.rect.w + 2*BALLOON_BORDER;
258        int y1 = y0 + priv->balloon.rect.h + 2*BALLOON_BORDER;
259    
260      /* save balloon screen coordinates for later use */      /* save balloon screen coordinates for later use */
261      priv->balloon.rect.x = x0 + BALLOON_BORDER;      priv->balloon.rect.x = x0 + BALLOON_BORDER;
262      priv->balloon.rect.y = y0 + 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;  
263    
264      g_assert(priv->balloon.surface);      g_assert(priv->balloon.surface);
265      cairo_t *cr = cairo_create(priv->balloon.surface);      cairo_t *cr = cairo_create(priv->balloon.surface);
# Line 290  osd_render_balloon(osm_gps_map_osd_t *os Line 312  osd_render_balloon(osm_gps_map_osd_t *os
312      cairo_destroy(cr);      cairo_destroy(cr);
313  }  }
314    
315    #define OSD_STATE_DOWN  0
316    #define OSD_STATE_UP    1
317    #define OSD_STATE_CHECK 2
318    
319  /* return true if balloon is being displayed and if */  /* return true if balloon is being displayed and if */
320  /* the given coordinate is within this balloon */  /* the given coordinate is within this balloon */
321  static gboolean  static gboolean
322  osd_balloon_check(osm_gps_map_osd_t *osd, gboolean click, gboolean down, gint x, gint y)  osd_balloon_check(osm_gps_map_osd_t *osd, gboolean click, gint state, gint x, gint y)
323  {  {
324      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
325    
# Line 317  osd_balloon_check(osm_gps_map_osd_t *osd Line 343  osd_balloon_check(osm_gps_map_osd_t *osd
343    
344          /* handle the fact that the balloon may have been created by the */          /* handle the fact that the balloon may have been created by the */
345          /* button down event */          /* button down event */
346          if(!is_in && !down && !priv->balloon.just_created) {          if(!is_in && state == OSD_STATE_UP && !priv->balloon.just_created) {
347              /* the user actually clicked outside the balloon */              /* the user actually clicked outside the balloon */
348    
349              /* close the balloon! */              /* close the balloon! */
# Line 339  osd_balloon_check(osm_gps_map_osd_t *osd Line 365  osd_balloon_check(osm_gps_map_osd_t *osd
365              event.type = OSM_GPS_MAP_BALLOON_EVENT_TYPE_CLICK;              event.type = OSM_GPS_MAP_BALLOON_EVENT_TYPE_CLICK;
366              event.data.click.x = x - xs;              event.data.click.x = x - xs;
367              event.data.click.y = y - ys;              event.data.click.y = y - ys;
368              event.data.click.down = down;              event.data.click.down = (state == OSD_STATE_DOWN);
369    
370              priv->balloon.cb(&event, priv->balloon.data);              priv->balloon.cb(&event, priv->balloon.data);
371          }          }
# Line 378  osm_gps_map_osd_draw_balloon (OsmGpsMap Line 404  osm_gps_map_osd_draw_balloon (OsmGpsMap
404    
405      osm_gps_map_osd_clear_balloon (map);      osm_gps_map_osd_clear_balloon (map);
406    
     /* allocate balloon surface */  
     priv->balloon.surface =  
         cairo_image_surface_create(CAIRO_FORMAT_ARGB32,  
                                    BALLOON_W+2, BALLOON_H+2);  
   
407      priv->balloon.lat = latitude;      priv->balloon.lat = latitude;
408      priv->balloon.lon = longitude;      priv->balloon.lon = longitude;
409      priv->balloon.cb = cb;      priv->balloon.cb = cb;
410      priv->balloon.data = data;      priv->balloon.data = data;
411      priv->balloon.just_created = TRUE;      priv->balloon.just_created = TRUE;
   
412      priv->balloon.orientation = -1;      priv->balloon.orientation = -1;
413        priv->balloon.rect.w = 0;
414        priv->balloon.rect.h = 0;
415    
416        /* set default size and call app callback */
417        if(!priv->balloon.rect.w || !priv->balloon.rect.h) {
418            osm_gps_map_balloon_event_t event;
419    
420            priv->balloon.rect.w = BALLOON_AREA_WIDTH;
421            priv->balloon.rect.h = BALLOON_AREA_HEIGHT;
422    
423            /* create some temporary surface, so the callback can */
424            /* e.g. determine text extents etc */
425            cairo_surface_t *surface =
426                cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10,10);
427    
428            event.type = OSM_GPS_MAP_BALLOON_EVENT_TYPE_SIZE_REQUEST;
429            event.data.draw.rect = &priv->balloon.rect;
430            event.data.draw.cr = cairo_create(surface);
431            priv->balloon.cb(&event, priv->balloon.data);
432    
433            cairo_destroy(event.data.draw.cr);
434            cairo_surface_destroy(surface);
435        }
436    
437        /* allocate balloon surface */
438        priv->balloon.surface =
439            cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
440                                       BALLOON_W+2, BALLOON_H+2);
441    
442      osd_render_balloon(osd);      osd_render_balloon(osd);
443    
# Line 526  osd_shape(cairo_t *cr, GdkColor *bg, Gdk Line 574  osd_shape(cairo_t *cr, GdkColor *bg, Gdk
574  #else  #else
575  static void  static void
576  osd_shape(cairo_t *cr) {  osd_shape(cairo_t *cr) {
577      cairo_set_source_rgb (cr, OSD_COLOR_BG);      cairo_set_source_rgba (cr, OSD_COLOR_BG);
578      cairo_fill_preserve (cr);      cairo_fill_preserve (cr);
579      cairo_set_source_rgb (cr, OSD_COLOR);      cairo_set_source_rgb (cr, OSD_COLOR);
580      cairo_set_line_width (cr, 1);      cairo_set_line_width (cr, 1);
# Line 689  osd_source_content(osm_gps_map_osd_t *os Line 737  osd_source_content(osm_gps_map_osd_t *os
737                                      CAIRO_FONT_SLANT_NORMAL,                                      CAIRO_FONT_SLANT_NORMAL,
738                                      CAIRO_FONT_WEIGHT_BOLD);                                      CAIRO_FONT_WEIGHT_BOLD);
739              cairo_set_font_size (cr, OSD_FONT_SIZE);              cairo_set_font_size (cr, OSD_FONT_SIZE);
740    
741              int i, step = (priv->source_sel.height - 2*OSD_TEXT_BORDER) /              int i, step = (priv->source_sel.height - 2*OSD_TEXT_BORDER - OSD_DPIX_SKIP) /
742                  OSM_GPS_MAP_SOURCE_LAST;                  (num_map_sources + OSD_DPIX_EXTRA);
743              for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {              for(i=0;i<num_map_sources + OSD_DPIX_EXTRA;i++) {
744                  cairo_text_extents_t extents;                  cairo_text_extents_t extents;
745                  const char *src = osm_gps_map_source_get_friendly_name(i);                  const char *src = NULL;
746    #if OSD_DPIX_EXTRA > 0
747                    /* draw "double pixel" check button */
748                    const char *dpix = _("Double Pixel");
749                    if(i == num_map_sources) {
750                        src = dpix;
751                    } else
752    #endif
753                    src = osm_gps_map_source_get_friendly_name( map_sources[i] );
754    
755                  cairo_text_extents (cr, src, &extents);                  cairo_text_extents (cr, src, &extents);
756    
757                  int x = offset + OSD_S_PW + OSD_TEXT_BORDER;                  int x = offset + OSD_S_PW + OSD_TEXT_BORDER;
758                  int y = offset + step * (i-1) + OSD_TEXT_BORDER;                  int y = offset + step * i + OSD_TEXT_BORDER;
759    
760    #if OSD_DPIX_EXTRA > 0
761                    if(i == num_map_sources) {
762                        int skip3 = OSD_DPIX_SKIP/3;
763    
764                        gboolean dpix;
765                        g_object_get(osd->widget, "double-pixel", &dpix, NULL);
766    
767                        cairo_set_line_width (cr, skip3);
768    
769                        /* draw seperator line */
770                        cairo_move_to (cr, x, y + skip3);
771                        cairo_rel_line_to (cr, OSD_S_AREA_W - 2*OSD_TEXT_BORDER, 0);
772                        cairo_stroke(cr);
773    
774                        y += OSD_DPIX_SKIP;
775    
776                        /* draw check box */
777                        cairo_move_to (cr, x, y);
778                        cairo_rel_line_to (cr, OSD_FONT_SIZE, 0);
779                        cairo_rel_line_to (cr, 0, OSD_FONT_SIZE);
780                        cairo_rel_line_to (cr, -OSD_FONT_SIZE, 0);
781                        cairo_rel_line_to (cr, 0, -OSD_FONT_SIZE);
782                        cairo_stroke(cr);
783    
784                        /* draw check if needed */
785                        if(dpix) {
786                            int space = OSD_FONT_SIZE/4;
787                            cairo_move_to (cr, x + space, y + space);
788                            cairo_rel_line_to (cr, OSD_FONT_SIZE - 2*space, OSD_FONT_SIZE - 2*space);
789                            cairo_stroke(cr);
790    
791                            cairo_move_to (cr, x + OSD_FONT_SIZE - space, y + space);
792                            cairo_rel_line_to (cr, -(OSD_FONT_SIZE - 2*space), OSD_FONT_SIZE - 2*space);
793                            cairo_stroke(cr);
794                        }
795    
796                        x += 1.5 * OSD_FONT_SIZE;
797                    }
798    #endif
799    
800                  /* draw filled rectangle if selected */                  /* draw filled rectangle if selected */
801                  if(source == i) {                  if(source == map_sources[i]) {
802                      cairo_rectangle(cr, x - OSD_TEXT_BORDER/2,                      cairo_rectangle(cr, x - OSD_TEXT_BORDER/2,
803                                      y - OSD_TEXT_SKIP,                                      y - OSD_TEXT_SKIP,
804                                      priv->source_sel.width - OSD_TEXT_BORDER,                                      priv->source_sel.width - OSD_TEXT_BORDER,
# Line 713  osd_source_content(osm_gps_map_osd_t *os Line 810  osd_source_content(osm_gps_map_osd_t *os
810                      GdkColor bg = osd->widget->style->bg[GTK_STATE_NORMAL];                      GdkColor bg = osd->widget->style->bg[GTK_STATE_NORMAL];
811                      gdk_cairo_set_source_color(cr, &bg);                      gdk_cairo_set_source_color(cr, &bg);
812  #else  #else
813                      cairo_set_source_rgb (cr, OSD_COLOR_BG);                      cairo_set_source_rgba (cr, OSD_COLOR_BG);
814  #endif  #endif
815                  }                  }
816    
# Line 721  osd_source_content(osm_gps_map_osd_t *os Line 818  osd_source_content(osm_gps_map_osd_t *os
818                  cairo_show_text (cr, src);                  cairo_show_text (cr, src);
819    
820                  /* restore color */                  /* restore color */
821                  if(source == i) {                  if(source == map_sources[i]) {
822  #ifndef OSD_COLOR  #ifndef OSD_COLOR
823                      GdkColor fg = osd->widget->style->fg[GTK_STATE_NORMAL];                      GdkColor fg = osd->widget->style->fg[GTK_STATE_NORMAL];
824                      gdk_cairo_set_source_color(cr, &fg);                      gdk_cairo_set_source_color(cr, &fg);
# Line 808  osd_source_reallocate(osm_gps_map_osd_t Line 905  osd_source_reallocate(osm_gps_map_osd_t
905          cairo_set_font_size (cr, OSD_FONT_SIZE);          cairo_set_font_size (cr, OSD_FONT_SIZE);
906    
907          /* calculate menu size */          /* calculate menu size */
908          int i, max_h = 0, max_w = 0;          int i,  max_w = 0;
909          for(i=OSM_GPS_MAP_SOURCE_NULL+1;i<=OSM_GPS_MAP_SOURCE_LAST;i++) {          priv->source_sel.max_h = 0;
910              const char *src = osm_gps_map_source_get_friendly_name(i);          for(i=0;i<num_map_sources;i++) {
911                const char *src = osm_gps_map_source_get_friendly_name( map_sources[i] );
912              cairo_text_extents (cr, src, &extents);              cairo_text_extents (cr, src, &extents);
913    
914              if(extents.width > max_w) max_w = extents.width;              if(extents.width > max_w) max_w = extents.width;
915              if(extents.height > max_h) max_h = extents.height;              if(extents.height > priv->source_sel.max_h) priv->source_sel.max_h = extents.height;
916          }          }
917          cairo_destroy(cr);          cairo_destroy(cr);
918    
919          priv->source_sel.width  = max_w + 2*OSD_TEXT_BORDER;          priv->source_sel.width  = max_w + 2*OSD_TEXT_BORDER;
920          priv->source_sel.height = OSM_GPS_MAP_SOURCE_LAST *          priv->source_sel.height = (num_map_sources + OSD_DPIX_EXTRA) *
921              (max_h + 2*OSD_TEXT_SKIP) + 2*OSD_TEXT_BORDER;              (priv->source_sel.max_h + 2*OSD_TEXT_SKIP) + 2*OSD_TEXT_BORDER + OSD_DPIX_SKIP;
922    
923          w = OSD_S_EXP_W;          w = OSD_S_EXP_W;
924          h = OSD_S_EXP_H;          h = OSD_S_EXP_H;
# Line 911  osd_source_toggle(osm_gps_map_osd_t *osd Line 1009  osd_source_toggle(osm_gps_map_osd_t *osd
1009    
1010  /* check if the user clicked inside the source selection area */  /* check if the user clicked inside the source selection area */
1011  static osd_button_t  static osd_button_t
1012  osd_source_check(osm_gps_map_osd_t *osd, gboolean down, gint x, gint y) {  osd_source_check(osm_gps_map_osd_t *osd, gint state, gint x, gint y) {
1013      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1014    
1015      if(!priv->source_sel.expanded)      if(!priv->source_sel.expanded)
# Line 929  osd_source_check(osm_gps_map_osd_t *osd, Line 1027  osd_source_check(osm_gps_map_osd_t *osd,
1027          /* really within puller shape? */          /* really within puller shape? */
1028          if(x > Z_RAD || osm_gps_map_in_circle(x, y, Z_RAD, Z_RAD, Z_RAD)) {          if(x > Z_RAD || osm_gps_map_in_circle(x, y, Z_RAD, Z_RAD, Z_RAD)) {
1029              /* expand source selector */              /* expand source selector */
1030              if(down)              if(state == OSD_STATE_DOWN)
1031                  osd_source_toggle(osd);                  osd_source_toggle(osd);
1032    
1033              /* tell upper layers that user clicked some background element */              /* tell upper layers that user clicked some background element */
# Line 949  osd_source_check(osm_gps_map_osd_t *osd, Line 1047  osd_source_check(osm_gps_map_osd_t *osd,
1047             y > 0 &&             y > 0 &&
1048             y < OSD_S_EXP_H) {             y < OSD_S_EXP_H) {
1049    
1050              int step = (priv->source_sel.height - 2*OSD_TEXT_BORDER)              int step = (priv->source_sel.height - 2*OSD_TEXT_BORDER - OSD_DPIX_SKIP)
1051                  / OSM_GPS_MAP_SOURCE_LAST;                  / (num_map_sources + OSD_DPIX_EXTRA);
1052    
1053              y -= OSD_TEXT_BORDER - OSD_TEXT_SKIP;              y -= OSD_TEXT_BORDER - OSD_TEXT_SKIP;
1054              y /= step;              int py = y / step;
             y += 1;  
1055    
1056              if(down) {              if(state == OSD_STATE_DOWN) {
1057                  gint old = 0;                  gint old = 0;
1058                  g_object_get(osd->widget, "map-source", &old, NULL);                  g_object_get(osd->widget, "map-source", &old, NULL);
1059    
1060                  if(y > OSM_GPS_MAP_SOURCE_NULL &&                  if(py >= 0 &&
1061                     y <= OSM_GPS_MAP_SOURCE_LAST &&                     py < num_map_sources &&
1062                     old != y) {                     old != map_sources[py]) {
1063                      g_object_set(osd->widget, "map-source", y, NULL);                      g_object_set(osd->widget, "map-source", map_sources[py], NULL);
1064    
1065                      osd_render_source_sel(osd, TRUE);                      osd_render_source_sel(osd, TRUE);
1066                      osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));                      osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
1067                      osm_gps_map_redraw(OSM_GPS_MAP(osd->widget));                      osm_gps_map_redraw(OSM_GPS_MAP(osd->widget));
1068                  }                  }
1069    
1070    #if OSD_DPIX_EXTRA > 0
1071                    if(py >= num_map_sources) {
1072                        y -= num_map_sources * (priv->source_sel.max_h + 2*OSD_TEXT_SKIP ) +
1073                            OSD_TEXT_SKIP + OSD_DPIX_SKIP;
1074                        if(y >= 0) {
1075                            gboolean dpix = 0;
1076                            g_object_get(osd->widget, "double-pixel", &dpix, NULL);
1077                            g_object_set(osd->widget, "double-pixel", !dpix, NULL);
1078                            osd_render_source_sel(osd, TRUE);
1079                            osm_gps_map_repaint(OSM_GPS_MAP(osd->widget));
1080                            osm_gps_map_redraw(OSM_GPS_MAP(osd->widget));
1081                        }
1082                    }
1083    #endif
1084              }              }
1085    
1086              /* return "clicked in OSD background" to prevent further */              /* return "clicked in OSD background" to prevent further */
# Line 1232  static float get_distance(float lat1, fl Line 1344  static float get_distance(float lat1, fl
1344    float aob = acos(cos(lat1) * cos(lat2) * cos(lon2 - lon1) +    float aob = acos(cos(lat1) * cos(lat2) * cos(lon2 - lon1) +
1345                     sin(lat1) * sin(lat2));                     sin(lat1) * sin(lat2));
1346    
   //  return(aob * 3959.0);   /* great circle radius in miles */  
   
1347    return(aob * 6371000.0);     /* great circle radius in meters */    return(aob * 6371000.0);     /* great circle radius in meters */
1348  }  }
1349    
# Line 1365  osd_render_nav(osm_gps_map_osd_t *osd) Line 1475  osd_render_nav(osm_gps_map_osd_t *osd)
1475    
1476  /* check if the user clicked inside the source selection area */  /* check if the user clicked inside the source selection area */
1477  static osd_button_t  static osd_button_t
1478  osd_nav_check(osm_gps_map_osd_t *osd, gboolean down, gint x, gint y) {  osd_nav_check(osm_gps_map_osd_t *osd, gint state, gint x, gint y) {
1479      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1480    
1481      if(!priv->nav.surface || down)      if(!priv->nav.surface || state == OSD_STATE_DOWN)
1482          return OSD_NONE;          return OSD_NONE;
1483    
1484      x -= OSD_X;      x -= OSD_X;
# Line 1439  osm_gps_map_osd_draw_nav (OsmGpsMap *map Line 1549  osm_gps_map_osd_draw_nav (OsmGpsMap *map
1549    
1550  #endif // OSD_NAV  #endif // OSD_NAV
1551    
1552    #ifdef OSD_HEARTRATE
1553    #ifndef OSD_HR_FONT_SIZE
1554    #define OSD_HR_FONT_SIZE 60
1555    #endif
1556    #define OSD_HR_W  3*OSD_HR_FONT_SIZE
1557    #define OSD_HR_H  OSD_HR_FONT_SIZE
1558    
1559    #ifndef OSD_HR_Y
1560    #define OSD_HR_Y OSD_Y
1561    #endif
1562    
1563    static void
1564    osd_render_heart_shape(cairo_t *cr, gint x, gint y, gint s) {
1565        cairo_move_to (cr, x-s, y-s/4);
1566        cairo_curve_to (cr, x-s, y-s,     x,   y-s,     x,   y-s/4);
1567        cairo_curve_to (cr, x,   y-s,     x+s, y-s,     x+s, y-s/4);
1568        cairo_curve_to (cr, x+s, y+s/2,   x,   y+3*s/4, x,   y+s);
1569        cairo_curve_to (cr, x,   y+3*s/4, x-s, y+s/2,   x-s, y-s/4);
1570    }
1571    
1572    static void
1573    osd_render_heart(cairo_t *cr, gint x, gint y, gint s, gboolean ok) {
1574        /* xyz */
1575    
1576        cairo_set_line_join (cr, CAIRO_LINE_JOIN_ROUND);
1577    
1578        osd_render_heart_shape(cr, x, y, s);
1579        cairo_set_source_rgb (cr, 1, 1, 1);
1580        cairo_set_line_width (cr, s/2);
1581        cairo_stroke(cr);
1582    
1583        osd_render_heart_shape(cr, x, y, s);
1584        if(ok) cairo_set_source_rgb (cr, 1, 0, 0);
1585        else   cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
1586        cairo_fill_preserve (cr);
1587        cairo_set_line_width (cr, s/5);
1588    
1589        cairo_stroke(cr);
1590    }
1591    
1592    static void
1593    osd_render_hr(osm_gps_map_osd_t *osd)
1594    {
1595        osd_priv_t *priv = (osd_priv_t*)osd->priv;
1596    
1597        if(!priv->hr.surface)
1598            return;
1599    
1600        /* first fill with transparency */
1601        g_assert(priv->hr.surface);
1602        cairo_t *cr = cairo_create(priv->hr.surface);
1603        cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1604        cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
1605        cairo_paint(cr);
1606        cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1607    
1608        cairo_select_font_face (cr, "Sans",
1609                                CAIRO_FONT_SLANT_NORMAL,
1610                                CAIRO_FONT_WEIGHT_BOLD);
1611        cairo_set_font_size (cr, OSD_HR_FONT_SIZE);
1612    
1613        char str[5];
1614        if(priv->hr.rate > 0)
1615            snprintf(str, 4, "%03u", priv->hr.rate);
1616        else if(priv->hr.rate == OSD_HR_INVALID)
1617            strcpy(str, "?");
1618        else if(priv->hr.rate == OSD_HR_ERROR)
1619            strcpy(str, "Err");
1620        else
1621            g_assert(priv->hr.rate != OSD_HR_NONE);
1622    
1623        cairo_text_extents_t extents;
1624        cairo_text_extents (cr, str, &extents);
1625    
1626        cairo_set_source_rgb(cr, 1.0, 1.0, 1.0);
1627        cairo_set_line_width (cr, OSD_HR_FONT_SIZE/10);
1628    
1629        cairo_move_to (cr, OSD_HR_W/2 - extents.width/2 + OSD_HR_FONT_SIZE/4,
1630                           OSD_HR_H/2 - extents.y_bearing/2);
1631        cairo_text_path (cr, str);
1632        cairo_stroke (cr);
1633    
1634        cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
1635        cairo_move_to (cr, OSD_HR_W/2 - extents.width/2 + OSD_HR_FONT_SIZE/4,
1636                           OSD_HR_H/2 - extents.y_bearing/2);
1637        cairo_show_text (cr, str);
1638    
1639        osd_render_heart(cr, OSD_HR_W/2 - extents.width/2 - OSD_HR_FONT_SIZE/8,
1640                         OSD_HR_H/2, OSD_HR_FONT_SIZE/5, priv->hr.ok);
1641    
1642    
1643        cairo_destroy(cr);
1644    }
1645    
1646    void
1647    osm_gps_map_osd_draw_hr (OsmGpsMap *map, gboolean ok, gint rate) {
1648        g_return_if_fail (OSM_IS_GPS_MAP (map));
1649    
1650        osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
1651        g_return_if_fail (osd);
1652    
1653        osd_priv_t *priv = (osd_priv_t*)osd->priv;
1654        g_return_if_fail (priv);
1655    
1656        /* allocate heart rate surface */
1657        if(rate != OSD_HR_NONE && !priv->hr.surface)
1658            priv->hr.surface =
1659                cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
1660                                           OSD_HR_W, OSD_HR_H);
1661    
1662        if(rate == OSD_HR_NONE && priv->hr.surface) {
1663            cairo_surface_destroy(priv->hr.surface);
1664            priv->hr.surface = NULL;
1665        }
1666    
1667        if(priv->hr.rate != rate || priv->hr.ok != ok) {
1668            priv->hr.rate = rate;
1669            priv->hr.ok = ok;
1670            osd_render_hr(osd);
1671        }
1672    
1673        osm_gps_map_redraw(map);
1674    }
1675    
1676    #endif // OSD_HEARTRATE
1677    
1678  static osd_button_t  static osd_button_t
1679  osd_check_int(osm_gps_map_osd_t *osd, gboolean click, gboolean down, gint x, gint y) {  osd_check_int(osm_gps_map_osd_t *osd, gboolean click, gint state, gint x, gint y) {
1680      osd_button_t but = OSD_NONE;      osd_button_t but = OSD_NONE;
1681    
1682  #ifdef OSD_BALLOON  #ifdef OSD_BALLOON
1683      if(down) {      if(state == OSD_STATE_DOWN) {
1684          /* needed to handle balloons that are created at click */          /* needed to handle balloons that are created at click */
1685          osd_priv_t *priv = (osd_priv_t*)osd->priv;          osd_priv_t *priv = (osd_priv_t*)osd->priv;
1686          priv->balloon.just_created = FALSE;          priv->balloon.just_created = FALSE;
# Line 1453  osd_check_int(osm_gps_map_osd_t *osd, gb Line 1689  osd_check_int(osm_gps_map_osd_t *osd, gb
1689    
1690  #ifdef OSD_SOURCE_SEL  #ifdef OSD_SOURCE_SEL
1691      /* the source selection area is handles internally */      /* the source selection area is handles internally */
1692      but = osd_source_check(osd, down, x, y);      but = osd_source_check(osd, state, x, y);
1693  #endif  #endif
1694    
1695  #ifdef OSD_NAV  #ifdef OSD_NAV
1696      if(but == OSD_NONE) {      if(but == OSD_NONE) {
1697          /* the source selection area is handles internally */          /* the source selection area is handles internally */
1698          but = osd_nav_check(osd, down, x, y);          but = osd_nav_check(osd, state, x, y);
1699      }      }
1700  #endif  #endif
1701    
# Line 1488  osd_check_int(osm_gps_map_osd_t *osd, gb Line 1724  osd_check_int(osm_gps_map_osd_t *osd, gb
1724  #ifdef OSD_BALLOON  #ifdef OSD_BALLOON
1725      if(but == OSD_NONE) {      if(but == OSD_NONE) {
1726          /* check if user clicked into balloon */          /* check if user clicked into balloon */
1727          if(osd_balloon_check(osd, click, down, x, y))          if(osd_balloon_check(osd, click, state, x, y))
1728              but = OSD_BG;              but = OSD_BG;
1729      }      }
1730  #endif  #endif
# Line 1937  osd_draw(osm_gps_map_osd_t *osd, GdkDraw Line 2173  osd_draw(osm_gps_map_osd_t *osd, GdkDraw
2173      cairo_paint(cr);      cairo_paint(cr);
2174  #endif  #endif
2175    
2176    #ifdef OSD_HEARTRATE
2177        if(priv->hr.surface) {
2178            x = (osd->widget->allocation.width - OSD_HR_W)/2;
2179            y = OSD_HR_Y;
2180            if(y < 0) y += osd->widget->allocation.height - OSD_COORDINATES_H;
2181    
2182            cairo_set_source_surface(cr, priv->hr.surface, x, y);
2183            cairo_paint(cr);
2184        }
2185    #endif
2186    
2187  #ifdef OSD_BALLOON  #ifdef OSD_BALLOON
2188      if(priv->balloon.surface) {      if(priv->balloon.surface) {
2189    
# Line 2029  osd_free(osm_gps_map_osd_t *osd) Line 2276  osd_free(osm_gps_map_osd_t *osd)
2276  #endif  #endif
2277    
2278  #ifdef OSD_BALLOON  #ifdef OSD_BALLOON
2279      if (priv->balloon.surface)      if (priv->balloon.surface)
2280           cairo_surface_destroy(priv->balloon.surface);           cairo_surface_destroy(priv->balloon.surface);
2281  #endif  #endif
2282    
2283    #ifdef OSD_HEARTRATE
2284        if (priv->hr.surface)
2285             cairo_surface_destroy(priv->hr.surface);
2286    #endif
2287    
2288      g_free(priv);      g_free(priv);
2289        osd->priv = NULL;
2290  }  }
2291    
2292  static gboolean  static gboolean
# Line 2049  osd_busy(osm_gps_map_osd_t *osd) Line 2302  osd_busy(osm_gps_map_osd_t *osd)
2302    
2303  static osd_button_t  static osd_button_t
2304  osd_check(osm_gps_map_osd_t *osd, gboolean down, gint x, gint y) {  osd_check(osm_gps_map_osd_t *osd, gboolean down, gint x, gint y) {
2305      return osd_check_int(osd, TRUE, down, x, y);      return osd_check_int(osd, TRUE, down?OSD_STATE_DOWN:OSD_STATE_UP, x, y);
2306  }  }
2307    
2308  static osm_gps_map_osd_t osd_classic = {  static osm_gps_map_osd_t osd_classic = {
# Line 2084  osm_gps_map_osd_classic_init(OsmGpsMap * Line 2337  osm_gps_map_osd_classic_init(OsmGpsMap *
2337      priv->balloon.lon = OSM_GPS_MAP_INVALID;      priv->balloon.lon = OSM_GPS_MAP_INVALID;
2338  #endif  #endif
2339    
2340    #ifdef OSD_HEARTRATE
2341        priv->hr.rate = OSD_HR_NONE;
2342    #endif
2343    
2344      osm_gps_map_register_osd(map, &osd_classic);      osm_gps_map_register_osd(map, &osd_classic);
2345  }  }
2346    
# Line 2111  osm_gps_map_osd_check(OsmGpsMap *map, gi Line 2368  osm_gps_map_osd_check(OsmGpsMap *map, gi
2368      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
2369      g_return_val_if_fail (osd, OSD_NONE);      g_return_val_if_fail (osd, OSD_NONE);
2370    
2371      return osd_check_int(osd, FALSE, TRUE, x, y);      return osd_check_int(osd, FALSE, OSD_STATE_CHECK, x, y);
2372  }  }

Legend:
Removed from v.279  
changed lines
  Added in v.280