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() |
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 */ |
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; |
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 |
|
|
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 |
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 |
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); |
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); |
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 |
|
|
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! */ |
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 |
} |
} |
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 |
|
|
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); |
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, |
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 |
|
|
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); |
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; |
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) |
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 */ |
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 */ |
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 |
|
|
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; |
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; |
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 |
|
|
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 |
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 |
|
|
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 |
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 = { |
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 |
|
|
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 |
} |
} |