242 lines
7 KiB
C
242 lines
7 KiB
C
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <hexagram/status.h>
|
|
|
|
#define STATUS_ICON_COUNT 14
|
|
#define STATUS_ICON_WIDTH 48
|
|
#define STATUS_ICON_HEIGHT 48
|
|
|
|
static hexagram_icon icons[STATUS_ICON_COUNT] = {
|
|
{
|
|
.id = HEXAGRAM_STATUS_SEATBELT,
|
|
.name = "belt",
|
|
.style_format = "path {fill: %1$s}",
|
|
.red = HEXAGRAM_STATUS_SEATBELT_UNFASTENED
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_PARKING_BEAM,
|
|
.name = "beams-parking",
|
|
.style_format = "path {stroke: %1$s; stroke-width: 12}",
|
|
.yellow = HEXAGRAM_STATUS_PARKING_BEAM_ON,
|
|
.red = HEXAGRAM_STATUS_PARKING_BEAM_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_LOW_BEAM,
|
|
.name = "beams-low",
|
|
.style_format = "path {fill: %1$s; stroke: %1$s}",
|
|
.green = HEXAGRAM_STATUS_LOW_BEAM_ON,
|
|
.red = HEXAGRAM_STATUS_LOW_BEAM_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_HIGH_BEAM,
|
|
.name = "beams-high",
|
|
.style_format = "path {fill: %1$s; stroke: %1$s}",
|
|
.blue = HEXAGRAM_STATUS_HIGH_BEAM_ON,
|
|
.red = HEXAGRAM_STATUS_HIGH_BEAM_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_FOG_BEAM,
|
|
.name = "beams-fog",
|
|
.style_format = "#g9 path {fill: %1$s} #g5 path {stroke: %1$s}",
|
|
.green = HEXAGRAM_STATUS_FOG_BEAM_ON,
|
|
.red = HEXAGRAM_STATUS_FOG_BEAM_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_STABILITY_CONTROL,
|
|
.name = "stability",
|
|
.style_format = "#path9, #path8, #path7, #path6, #path5 {fill: %1$s} #path10 {stroke: %1$s}",
|
|
.orange = HEXAGRAM_STATUS_STABILITY_CONTROL_OFF,
|
|
.red = HEXAGRAM_STATUS_STABILITY_CONTROL_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_LANE_ASSIST,
|
|
.name = "lane-departure",
|
|
.style_format = "path {stroke: %1$s; stroke-width: 8}",
|
|
.orange = HEXAGRAM_STATUS_LANE_ASSIST_OFF,
|
|
.red = HEXAGRAM_STATUS_LANE_ASSIST_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_PARKING_BRAKE,
|
|
.name = "parking",
|
|
.style_format = "#path6, #path5 {stroke: %1$s} circle {stroke: %1$s} #path7 {fill: %1$s}",
|
|
.red = HEXAGRAM_STATUS_PARKING_BRAKE_ON
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_FUEL,
|
|
.name = "fuel",
|
|
.style_format = "#g9 * {stroke: %1$s} #path9 {fill: %1$s}",
|
|
.orange = HEXAGRAM_STATUS_FUEL_LOW,
|
|
.red = HEXAGRAM_STATUS_FUEL_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_WIPER_WASHER,
|
|
.name = "wiper-washer",
|
|
.style_format = "rect,path,circle{stroke:%1$s;}",
|
|
.orange = HEXAGRAM_STATUS_WIPER_WASHER_LOW,
|
|
.red = HEXAGRAM_STATUS_WIPER_WASHER_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_COOLANT,
|
|
.name = "coolant",
|
|
.style_format = "path, circle, rect {fill: %1$s} #g9 path {stroke: %1$s}",
|
|
.orange = HEXAGRAM_STATUS_COOLANT_LOW,
|
|
.red = HEXAGRAM_STATUS_COOLANT_OVERHEAT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_OIL,
|
|
.name = "oil",
|
|
.style_format = "path {fill: %1$s; stroke: %1$s}",
|
|
.orange = HEXAGRAM_STATUS_OIL_LOW,
|
|
.red = HEXAGRAM_STATUS_OIL_OVERHEAT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_TPMS,
|
|
.name = "tpms",
|
|
.style_format = "path, circle {fill: %1$s}",
|
|
.orange = HEXAGRAM_STATUS_TPMS_WARNING,
|
|
.red = HEXAGRAM_STATUS_TPMS_FAULT
|
|
},
|
|
{
|
|
.id = HEXAGRAM_STATUS_COLLISION,
|
|
.name = "collision",
|
|
.style_format = "path {stroke-width: 10px; stroke: %$1s}",
|
|
.red = HEXAGRAM_STATUS_COLLISION_DETECTED
|
|
}
|
|
};
|
|
|
|
static int update(hexagram_status_icon_box *box) {
|
|
cairo_t *cr;
|
|
double x, y;
|
|
size_t i;
|
|
|
|
if ((cr = cairo_create(box->surface)) == NULL) {
|
|
goto error_cairo_create;
|
|
}
|
|
|
|
cairo_set_source_rgba(cr, 0, 0, 0, 0);
|
|
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
|
|
cairo_rectangle(cr, 0, 0, box->width, box->height);
|
|
cairo_fill(cr);
|
|
|
|
x = 0;
|
|
y = box->height - STATUS_ICON_HEIGHT;
|
|
|
|
for (i=0; i<STATUS_ICON_COUNT; i++) {
|
|
hexagram_icon *icon = &box->icons[i];
|
|
int status = box->state[icon->id];
|
|
|
|
if (status && hexagram_icon_drawable(icon, status)) {
|
|
if (hexagram_icon_draw(icon, cr, x, y, status) < 0) {
|
|
goto error_icon_draw;
|
|
}
|
|
}
|
|
|
|
x += STATUS_ICON_WIDTH;
|
|
|
|
if (x >= box->width) {
|
|
x = 0;
|
|
y -= STATUS_ICON_HEIGHT;
|
|
}
|
|
}
|
|
|
|
cairo_destroy(cr);
|
|
|
|
return 0;
|
|
|
|
error_icon_draw:
|
|
cairo_destroy(cr);
|
|
|
|
error_cairo_create:
|
|
return -1;
|
|
}
|
|
|
|
static int draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
|
hexagram_status_icon_box *box = (hexagram_status_icon_box *)gauge;
|
|
|
|
if (box->dirty) {
|
|
if (update(box) < 0) {
|
|
goto error_update;
|
|
}
|
|
|
|
box->dirty = 0;
|
|
}
|
|
|
|
cairo_set_source_surface(cr, box->surface, gauge->x, gauge->y);
|
|
cairo_rectangle(cr, gauge->x, gauge->y, box->width, box->height);
|
|
cairo_fill(cr);
|
|
|
|
return 0;
|
|
|
|
error_update:
|
|
return -1;
|
|
}
|
|
|
|
int hexagram_status_icon_box_init(hexagram_status_icon_box *box,
|
|
double x,
|
|
double y,
|
|
double width,
|
|
double height) {
|
|
size_t i;
|
|
|
|
box->gauge.x = x;
|
|
box->gauge.y = y;
|
|
box->gauge.draw_bg = NULL;
|
|
box->gauge.draw_fg = draw_fg;
|
|
|
|
box->width = width;
|
|
box->height = height;
|
|
box->icons = icons;
|
|
box->dirty = 0;
|
|
|
|
memset(&box->state, '\0', sizeof(box->state));
|
|
|
|
for (i=0; i<STATUS_ICON_COUNT; i++) {
|
|
if (hexagram_icon_init(&box->icons[i],
|
|
STATUS_ICON_WIDTH,
|
|
STATUS_ICON_HEIGHT) < 0) {
|
|
goto error_icon_init;
|
|
}
|
|
}
|
|
|
|
if ((box->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
|
box->width,
|
|
box->height)) == NULL) {
|
|
goto error_cairo_image_surface_create;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error_cairo_image_surface_create:
|
|
error_icon_init:
|
|
do {
|
|
hexagram_icon_cleanup(&box->icons[i]);
|
|
} while (--i);
|
|
|
|
return -1;
|
|
}
|
|
|
|
void hexagram_status_icon_box_cleanup(hexagram_status_icon_box *box) {
|
|
size_t i;
|
|
|
|
cairo_surface_destroy(box->surface);
|
|
|
|
for (i=0; i<STATUS_ICON_COUNT; i++) {
|
|
hexagram_icon_cleanup(&box->icons[i]);
|
|
}
|
|
|
|
free(box->icons);
|
|
|
|
return;
|
|
}
|
|
|
|
void hexagram_status_icon_set(hexagram_status_icon_box *box,
|
|
hexagram_status_type type,
|
|
int status) {
|
|
if (type < 0 || type >= HEXAGRAM_STATUS_COUNT) {
|
|
return;
|
|
}
|
|
|
|
box->dirty = 1;
|
|
box->state[type] = status;
|
|
}
|