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

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

revision 202 by harbaum, Sat Nov 21 20:13:13 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 82  typedef struct { Line 99  typedef struct {
99          cairo_surface_t *surface;          cairo_surface_t *surface;
100          float lat, lon;          float lat, lon;
101          char *name;          char *name;
102          gboolean imperial;    // display distance imperial/metric          gboolean imperial, mode;    // display distance imperial/metric
103            int click_sep;
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 102  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 121  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 133  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)  
   
 #if 0  
 #define FIN   printf("entering function %s\n", __func__);  
 #define FOUT  printf("leaving function %s\n", __func__);  
 #else  
 #define FIN   ;  
 #define FOUT  ;  
 #endif  
   
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
166  osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,  osm_gps_map_draw_balloon_shape (cairo_t *cr, int x0, int y0, int x1, int y1,
167         gboolean bottom, int px, int py, int px0, int px1) {         gboolean bottom, int px, int py, int px0, int px1) {
168    
     FIN;  
   
169      cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);      cairo_move_to (cr, x0, y0 + BALLOON_CORNER_RADIUS);
170      cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,      cairo_arc (cr, x0 + BALLOON_CORNER_RADIUS, y0 + BALLOON_CORNER_RADIUS,
171                 BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);                 BALLOON_CORNER_RADIUS, -M_PI, -M_PI/2);
# Line 179  osm_gps_map_draw_balloon_shape (cairo_t Line 194  osm_gps_map_draw_balloon_shape (cairo_t
194                 BALLOON_CORNER_RADIUS, M_PI/2, M_PI);                 BALLOON_CORNER_RADIUS, M_PI/2, M_PI);
195    
196      cairo_close_path (cr);      cairo_close_path (cr);
   
     FOUT;  
197  }  }
198    
199  static void  static void
200  osd_render_balloon(osm_gps_map_osd_t *osd) {  osd_render_balloon(osm_gps_map_osd_t *osd) {
     FIN;  
   
201      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
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 244  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 301  osd_render_balloon(osm_gps_map_osd_t *os Line 310  osd_render_balloon(osm_gps_map_osd_t *os
310      }      }
311    
312      cairo_destroy(cr);      cairo_destroy(cr);
   
     FOUT;  
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  {  {
     FIN;  
   
324      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
325    
326      if(!priv->balloon.surface)      if(!priv->balloon.surface)
# Line 334  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 356  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          }          }
372      }      }
     FOUT;  
373      return is_in;      return is_in;
374  }  }
375    
376  void osm_gps_map_osd_clear_balloon (OsmGpsMap *map) {  void osm_gps_map_osd_clear_balloon (OsmGpsMap *map) {
     FIN;  
   
377      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
378    
379      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
# Line 383  void osm_gps_map_osd_clear_balloon (OsmG Line 389  void osm_gps_map_osd_clear_balloon (OsmG
389          priv->balloon.lon = OSM_GPS_MAP_INVALID;          priv->balloon.lon = OSM_GPS_MAP_INVALID;
390      }      }
391      osm_gps_map_redraw(map);      osm_gps_map_redraw(map);
     FOUT;  
392  }  }
393    
394  void  void
395  osm_gps_map_osd_draw_balloon (OsmGpsMap *map, float latitude, float longitude,  osm_gps_map_osd_draw_balloon (OsmGpsMap *map, float latitude, float longitude,
396                                OsmGpsMapBalloonCallback cb, gpointer data) {                                OsmGpsMapBalloonCallback cb, gpointer data) {
     FIN;  
397      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
398    
399      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
# Line 400  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    
444      osm_gps_map_redraw(map);      osm_gps_map_redraw(map);
     FOUT;  
445  }  }
446    
447  #endif // OSD_BALLOON  #endif // OSD_BALLOON
# Line 549  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 561  osd_shape(cairo_t *cr) { Line 586  osd_shape(cairo_t *cr) {
586  static gboolean  static gboolean
587  osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)  osm_gps_map_in_circle(gint x, gint y, gint cx, gint cy, gint rad)
588  {  {
     FIN;  
589      return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);      return( pow(cx - x, 2) + pow(cy - y, 2) < rad * rad);
590  }  }
591    
# Line 713  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 737  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 745  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 760  osd_source_content(osm_gps_map_osd_t *os Line 833  osd_source_content(osm_gps_map_osd_t *os
833    
834  static void  static void
835  osd_render_source_sel(osm_gps_map_osd_t *osd, gboolean force_rerender) {  osd_render_source_sel(osm_gps_map_osd_t *osd, gboolean force_rerender) {
     FIN;  
   
836      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
837    
838      if(!priv->source_sel.surface ||      if(!priv->source_sel.surface ||
# Line 810  osd_render_source_sel(osm_gps_map_osd_t Line 881  osd_render_source_sel(osm_gps_map_osd_t
881      cairo_stroke (cr);      cairo_stroke (cr);
882    
883      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
884  }  }
885    
886  /* re-allocate the buffer used to draw the menu. This is used */  /* re-allocate the buffer used to draw the menu. This is used */
887  /* to collapse/expand the buffer */  /* to collapse/expand the buffer */
888  static void  static void
889  osd_source_reallocate(osm_gps_map_osd_t *osd) {  osd_source_reallocate(osm_gps_map_osd_t *osd) {
     FIN;  
890      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
891    
892      /* re-allocate offscreen bitmap */      /* re-allocate offscreen bitmap */
# Line 836  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 859  osd_source_reallocate(osm_gps_map_osd_t Line 929  osd_source_reallocate(osm_gps_map_osd_t
929          cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w+2, h+2);          cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w+2, h+2);
930    
931      osd_render_source_sel(osd, TRUE);      osd_render_source_sel(osd, TRUE);
     FOUT;  
932  }  }
933    
934  #define OSD_HZ      15  #define OSD_HZ      15
935  #define OSD_TIME    500  #define OSD_TIME    500
936    
937  static gboolean osd_source_animate(gpointer data) {  static gboolean osd_source_animate(gpointer data) {
     FIN;  
938      osm_gps_map_osd_t *osd = (osm_gps_map_osd_t*)data;      osm_gps_map_osd_t *osd = (osm_gps_map_osd_t*)data;
939      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
940      int diff = OSD_S_EXP_W - OSD_S_W - OSD_S_X;      int diff = OSD_S_EXP_W - OSD_S_W - OSD_S_X;
# Line 905  static gboolean osd_source_animate(gpoin Line 973  static gboolean osd_source_animate(gpoin
973      if(done)      if(done)
974          priv->source_sel.handler_id = 0;          priv->source_sel.handler_id = 0;
975    
     FOUT;  
976      return !done;      return !done;
977  }  }
978    
# Line 913  static gboolean osd_source_animate(gpoin Line 980  static gboolean osd_source_animate(gpoin
980  static void  static void
981  osd_source_toggle(osm_gps_map_osd_t *osd)  osd_source_toggle(osm_gps_map_osd_t *osd)
982  {  {
     FIN;  
983      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
984    
985      /* ignore clicks while animation is running */      /* ignore clicks while animation is running */
# Line 939  osd_source_toggle(osm_gps_map_osd_t *osd Line 1005  osd_source_toggle(osm_gps_map_osd_t *osd
1005      /* start timer to handle animation */      /* start timer to handle animation */
1006      priv->source_sel.handler_id = gtk_timeout_add(OSD_TIME/OSD_HZ,      priv->source_sel.handler_id = gtk_timeout_add(OSD_TIME/OSD_HZ,
1007                                                    osd_source_animate, osd);                                                    osd_source_animate, osd);
     FOUT;  
1008  }  }
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) {
     FIN;  
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 963  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 983  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));
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 1010  osd_source_check(osm_gps_map_osd_t *osd, Line 1089  osd_source_check(osm_gps_map_osd_t *osd,
1089          }          }
1090      }      }
1091    
     FOUT;  
1092      return OSD_NONE;      return OSD_NONE;
1093  }  }
1094  #endif // OSD_SOURCE_SEL  #endif // OSD_SOURCE_SEL
# Line 1155  static char Line 1233  static char
1233  /* render a string at the given screen position */  /* render a string at the given screen position */
1234  static int  static int
1235  osd_render_centered_text(cairo_t *cr, int y, int width, char *text) {  osd_render_centered_text(cairo_t *cr, int y, int width, char *text) {
     FIN;  
   
1236      if(!text) return y;      if(!text) return y;
1237    
1238      char *p = g_malloc(strlen(text)+4);  // space for "...\n"      char *p = g_malloc(strlen(text)+4);  // space for "...\n"
# Line 1198  osd_render_centered_text(cairo_t *cr, in Line 1274  osd_render_centered_text(cairo_t *cr, in
1274      g_free(p);      g_free(p);
1275    
1276      /* skip + 1/5 line */      /* skip + 1/5 line */
     FOUT;  
1277      return y + 6*OSD_COORDINATES_FONT_SIZE/5;      return y + 6*OSD_COORDINATES_FONT_SIZE/5;
1278  }  }
1279    
1280  static void  static void
1281  osd_render_coordinates(osm_gps_map_osd_t *osd)  osd_render_coordinates(osm_gps_map_osd_t *osd)
1282  {  {
     FIN;  
1283      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1284    
1285      if(!priv->coordinates.surface)      if(!priv->coordinates.surface)
# Line 1251  osd_render_coordinates(osm_gps_map_osd_t Line 1325  osd_render_coordinates(osm_gps_map_osd_t
1325      g_free(longitude);      g_free(longitude);
1326    
1327      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
1328  }  }
1329  #endif  // OSD_COORDINATES  #endif  // OSD_COORDINATES
1330    
# Line 1271  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    
1350  static void  static void
1351  osd_render_nav(osm_gps_map_osd_t *osd)  osd_render_nav(osm_gps_map_osd_t *osd)
1352  {  {
     FIN;  
1353      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1354    
1355      if(!priv->nav.surface || isnan(priv->nav.lat) || isnan(priv->nav.lon))      if(!priv->nav.surface || isnan(priv->nav.lat) || isnan(priv->nav.lon))
# Line 1305  osd_render_nav(osm_gps_map_osd_t *osd) Line 1375  osd_render_nav(osm_gps_map_osd_t *osd)
1375      y = osd_render_centered_text(cr, y, OSD_NAV_W, priv->nav.name);      y = osd_render_centered_text(cr, y, OSD_NAV_W, priv->nav.name);
1376      y = osd_render_centered_text(cr, y, OSD_NAV_W, latitude);      y = osd_render_centered_text(cr, y, OSD_NAV_W, latitude);
1377      y = osd_render_centered_text(cr, y, OSD_NAV_W, longitude);      y = osd_render_centered_text(cr, y, OSD_NAV_W, longitude);
1378    
1379      g_free(latitude);      g_free(latitude);
1380      g_free(longitude);      g_free(longitude);
1381    
1382        /* everything below this is the compass. we need to know this */
1383        /* to differ between coordinate clicks and compass clicks */
1384        priv->nav.click_sep = y;
1385    
1386      /* draw the compass */      /* draw the compass */
1387      int radius = (OSD_NAV_H - y - 5*OSD_COORDINATES_FONT_SIZE/4)/2;      int radius = (OSD_NAV_H - y - 5*OSD_COORDINATES_FONT_SIZE/4)/2;
1388      if(radius > OSD_NAV_W/2)      if(radius > OSD_NAV_W/2)
# Line 1331  osd_render_nav(osm_gps_map_osd_t *osd) Line 1405  osd_render_nav(osm_gps_map_osd_t *osd)
1405  #define ARROW_WIDTH     0.3  #define ARROW_WIDTH     0.3
1406  #define ARROW_LENGTH    0.7  #define ARROW_LENGTH    0.7
1407    
1408      coord_t *gps = osm_gps_map_get_gps (OSM_GPS_MAP(osd->widget));      coord_t mpos, *pos = osm_gps_map_get_gps (OSM_GPS_MAP(osd->widget));
1409      if(gps) {      if(priv->nav.mode) {
1410          float arot = get_bearing(gps->rlat, gps->rlon,          gfloat lat, lon;
1411            g_object_get(osd->widget, "latitude", &lat, "longitude", &lon, NULL);
1412            mpos.rlat = deg2rad(lat);
1413            mpos.rlon = deg2rad(lon);
1414            pos = &mpos;
1415        }
1416    
1417        if(pos) {
1418            float arot = get_bearing(pos->rlat, pos->rlon,
1419                       deg2rad(priv->nav.lat), deg2rad(priv->nav.lon));                       deg2rad(priv->nav.lat), deg2rad(priv->nav.lon));
1420    
1421          cairo_move_to(cr,          cairo_move_to(cr,
# Line 1353  osd_render_nav(osm_gps_map_osd_t *osd) Line 1435  osd_render_nav(osm_gps_map_osd_t *osd)
1435                        y + radius * -ARROW_LENGTH * -cos(arot-ARROW_WIDTH));                        y + radius * -ARROW_LENGTH * -cos(arot-ARROW_WIDTH));
1436    
1437          cairo_close_path(cr);          cairo_close_path(cr);
1438          cairo_set_source_rgb (cr, 0, 0, 0);          if(priv->nav.mode)
1439                cairo_set_source_rgb (cr, 0, 0, 0);
1440            else
1441                cairo_set_source_rgb (cr, 0, 0, 0.8);
1442    
1443          cairo_fill (cr);          cairo_fill (cr);
1444    
1445          y += radius + OSD_COORDINATES_FONT_SIZE/4;          y += radius + OSD_COORDINATES_FONT_SIZE/4;
1446    
1447          float dist = get_distance(gps->rlat, gps->rlon,          float dist = get_distance(pos->rlat, pos->rlon,
1448                          deg2rad(priv->nav.lat), deg2rad(priv->nav.lon));                          deg2rad(priv->nav.lat), deg2rad(priv->nav.lon));
1449    
1450          char *dist_str = NULL;          char *dist_str = NULL;
# Line 1385  osd_render_nav(osm_gps_map_osd_t *osd) Line 1471  osd_render_nav(osm_gps_map_osd_t *osd)
1471      }      }
1472    
1473      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
1474  }  }
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) {
     FIN;  
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 1404  osd_nav_check(osm_gps_map_osd_t *osd, gb Line 1488  osd_nav_check(osm_gps_map_osd_t *osd, gb
1488      y -= (osd->widget->allocation.height - OSD_NAV_H)/2;      y -= (osd->widget->allocation.height - OSD_NAV_H)/2;
1489    
1490      if(x >= 0 && y >= 0 && x <= OSD_NAV_W && y <= OSD_NAV_H) {      if(x >= 0 && y >= 0 && x <= OSD_NAV_W && y <= OSD_NAV_H) {
1491          osm_gps_map_set_center(OSM_GPS_MAP(osd->widget),          if(y < priv->nav.click_sep)
1492                                 priv->nav.lat, priv->nav.lon);              osm_gps_map_set_center(OSM_GPS_MAP(osd->widget),
1493                                       priv->nav.lat, priv->nav.lon);
1494            else {
1495                priv->nav.mode = !priv->nav.mode;
1496                osm_gps_map_redraw(OSM_GPS_MAP(osd->widget));
1497            }
1498      }      }
1499    
     FOUT;  
1500      return OSD_NONE;      return OSD_NONE;
1501  }  }
1502    
1503  void osm_gps_map_osd_clear_nav (OsmGpsMap *map) {  void osm_gps_map_osd_clear_nav (OsmGpsMap *map) {
     FIN;  
1504      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
1505    
1506      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
# Line 1430  void osm_gps_map_osd_clear_nav (OsmGpsMa Line 1517  void osm_gps_map_osd_clear_nav (OsmGpsMa
1517          if(priv->nav.name) g_free(priv->nav.name);          if(priv->nav.name) g_free(priv->nav.name);
1518      }      }
1519      osm_gps_map_redraw(map);      osm_gps_map_redraw(map);
     FOUT;  
1520  }  }
1521    
1522  void  void
1523  osm_gps_map_osd_draw_nav (OsmGpsMap *map, gboolean imperial,  osm_gps_map_osd_draw_nav (OsmGpsMap *map, gboolean imperial,
1524                            float latitude, float longitude, char *name) {                            float latitude, float longitude, char *name) {
     FIN;  
1525      g_return_if_fail (OSM_IS_GPS_MAP (map));      g_return_if_fail (OSM_IS_GPS_MAP (map));
1526    
1527      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
# Line 1460  osm_gps_map_osd_draw_nav (OsmGpsMap *map Line 1545  osm_gps_map_osd_draw_nav (OsmGpsMap *map
1545      osd_render_nav(osd);      osd_render_nav(osd);
1546    
1547      osm_gps_map_redraw(map);      osm_gps_map_redraw(map);
     FOUT;  
1548  }  }
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) {
     FIN;  
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 1480  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 1515  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
1731    
     FOUT;  
1732      return but;      return but;
1733  }  }
1734    
# Line 1538  osd_check_int(osm_gps_map_osd_t *osd, gb Line 1746  osd_check_int(osm_gps_map_osd_t *osd, gb
1746    
1747  static void  static void
1748  osd_render_crosshair_shape(cairo_t *cr) {  osd_render_crosshair_shape(cairo_t *cr) {
     FIN;  
1749      cairo_arc (cr, OSD_CROSSHAIR_W/2, OSD_CROSSHAIR_H/2,      cairo_arc (cr, OSD_CROSSHAIR_W/2, OSD_CROSSHAIR_H/2,
1750                 OSD_CROSSHAIR_RADIUS, 0,  2*M_PI);                 OSD_CROSSHAIR_RADIUS, 0,  2*M_PI);
1751    
# Line 1557  osd_render_crosshair_shape(cairo_t *cr) Line 1764  osd_render_crosshair_shape(cairo_t *cr)
1764      cairo_rel_line_to (cr, 0, OSD_CROSSHAIR_TICK);      cairo_rel_line_to (cr, 0, OSD_CROSSHAIR_TICK);
1765    
1766      cairo_stroke (cr);      cairo_stroke (cr);
     FOUT;  
1767  }  }
1768    
1769  static void  static void
1770  osd_render_crosshair(osm_gps_map_osd_t *osd)  osd_render_crosshair(osm_gps_map_osd_t *osd)
1771  {  {
     FIN;  
1772      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1773    
1774      if(!priv->crosshair.surface || priv->crosshair.rendered)      if(!priv->crosshair.surface || priv->crosshair.rendered)
# Line 1590  osd_render_crosshair(osm_gps_map_osd_t * Line 1795  osd_render_crosshair(osm_gps_map_osd_t *
1795      osd_render_crosshair_shape(cr);      osd_render_crosshair_shape(cr);
1796    
1797      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
1798  }  }
1799  #endif  #endif
1800    
# Line 1612  osd_render_crosshair(osm_gps_map_osd_t * Line 1816  osd_render_crosshair(osm_gps_map_osd_t *
1816  static void  static void
1817  osd_render_scale(osm_gps_map_osd_t *osd)  osd_render_scale(osm_gps_map_osd_t *osd)
1818  {  {
     FIN;  
1819      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1820    
1821      if(!priv->scale.surface)      if(!priv->scale.surface)
# Line 1740  osd_render_scale(osm_gps_map_osd_t *osd) Line 1943  osd_render_scale(osm_gps_map_osd_t *osd)
1943      cairo_stroke(cr);      cairo_stroke(cr);
1944    
1945      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
1946  }  }
1947  #endif  #endif
1948    
1949  static void  static void
1950  osd_render_controls(osm_gps_map_osd_t *osd)  osd_render_controls(osm_gps_map_osd_t *osd)
1951  {  {
     FIN;  
1952      osd_priv_t *priv = (osd_priv_t*)osd->priv;      osd_priv_t *priv = (osd_priv_t*)osd->priv;
1953    
1954      if(!priv->controls.surface)      if(!priv->controls.surface)
# Line 1972  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 2025  osd_draw(osm_gps_map_osd_t *osd, GdkDraw Line 2237  osd_draw(osm_gps_map_osd_t *osd, GdkDraw
2237  #endif  #endif
2238    
2239      cairo_destroy(cr);      cairo_destroy(cr);
     FOUT;  
2240  }  }
2241    
2242  static void  static void
2243  osd_free(osm_gps_map_osd_t *osd)  osd_free(osm_gps_map_osd_t *osd)
2244  {  {
     FIN;  
2245      osd_priv_t *priv = (osd_priv_t *)(osd->priv);      osd_priv_t *priv = (osd_priv_t *)(osd->priv);
2246    
2247      if (priv->controls.surface)      if (priv->controls.surface)
# Line 2066  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      FOUT;      osd->priv = NULL;
2290  }  }
2291    
2292  static gboolean  static gboolean
2293  osd_busy(osm_gps_map_osd_t *osd)  osd_busy(osm_gps_map_osd_t *osd)
2294  {  {
     FIN;  
2295  #ifdef OSD_SOURCE_SEL  #ifdef OSD_SOURCE_SEL
2296      osd_priv_t *priv = (osd_priv_t *)(osd->priv);      osd_priv_t *priv = (osd_priv_t *)(osd->priv);
2297      return (priv->source_sel.handler_id != 0);      return (priv->source_sel.handler_id != 0);
# Line 2088  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      FIN;      return osd_check_int(osd, TRUE, down?OSD_STATE_DOWN:OSD_STATE_UP, x, y);
     return osd_check_int(osd, TRUE, down, x, y);  
2306  }  }
2307    
2308  static osm_gps_map_osd_t osd_classic = {  static osm_gps_map_osd_t osd_classic = {
# Line 2111  static osm_gps_map_osd_t osd_classic = { Line 2324  static osm_gps_map_osd_t osd_classic = {
2324  void  void
2325  osm_gps_map_osd_classic_init(OsmGpsMap *map)  osm_gps_map_osd_classic_init(OsmGpsMap *map)
2326  {  {
2327      FIN;      osd_priv_t *priv = g_new0(osd_priv_t, 1);
2328      osd_priv_t *priv = osd_classic.priv = g_new0(osd_priv_t, 1);  
2329        /* reset entries to default value */
2330        osd_classic.widget = NULL;
2331        osd_classic.cb     = NULL;
2332        osd_classic.data   = NULL;
2333        osd_classic.priv   = priv;
2334    
2335  #ifdef OSD_BALLOON  #ifdef OSD_BALLOON
2336      priv->balloon.lat = OSM_GPS_MAP_INVALID;      priv->balloon.lat = OSM_GPS_MAP_INVALID;
2337      priv->balloon.lon = OSM_GPS_MAP_INVALID;      priv->balloon.lon = OSM_GPS_MAP_INVALID;
2338  #endif  #endif
2339    
2340      osd_classic.priv = priv;  #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);
     FOUT;  
2345  }  }
2346    
2347  #ifdef OSD_GPS_BUTTON  #ifdef OSD_GPS_BUTTON
# Line 2130  osm_gps_map_osd_classic_init(OsmGpsMap * Line 2349  osm_gps_map_osd_classic_init(OsmGpsMap *
2349  /* but instead are to be used by the main application */  /* but instead are to be used by the main application */
2350  void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,  void osm_gps_map_osd_enable_gps (OsmGpsMap *map, OsmGpsMapOsdCallback cb,
2351                                   gpointer data) {                                   gpointer data) {
     FIN;  
2352      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);      osm_gps_map_osd_t *osd = osm_gps_map_osd_get(map);
2353      g_return_if_fail (osd);      g_return_if_fail (osd);
2354    
# Line 2142  void osm_gps_map_osd_enable_gps (OsmGpsM Line 2360  void osm_gps_map_osd_enable_gps (OsmGpsM
2360      osd->render(osd);      osd->render(osd);
2361    
2362      osm_gps_map_redraw(map);      osm_gps_map_redraw(map);
     FOUT;  
2363  }  }
2364  #endif  #endif
2365    
2366  osd_button_t  osd_button_t
2367  osm_gps_map_osd_check(OsmGpsMap *map, gint x, gint y) {  osm_gps_map_osd_check(OsmGpsMap *map, gint x, gint y) {
     FIN;  
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.202  
changed lines
  Added in v.280