Port Python to C
This commit is contained in:
parent
25664644bf
commit
1bda9eda26
38 changed files with 2859 additions and 578 deletions
|
@ -15,10 +15,10 @@ RM = rm
|
|||
all: $(EXAMPLES)
|
||||
|
||||
cluster: cluster.c $(STATIC)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(STATIC) $(shell pkg-config --cflags --libs cairo x11) -lXext -lm
|
||||
$(CC) $(CFLAGS) $< -o $@ $(STATIC) $(shell pkg-config --cflags --libs cairo x11 librsvg-2.0) -lXext -lm
|
||||
|
||||
svg: svg.c $(STATIC)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(STATIC) $(shell pkg-config --cflags --libs cairo) -lm
|
||||
$(CC) $(CFLAGS) $< -o $@ $(STATIC) $(shell pkg-config --cflags --libs cairo librsvg-2.0) -lm
|
||||
|
||||
view: view.c $(STATIC)
|
||||
$(CC) $(CFLAGS) $< -o $@ $(STATIC) -lncurses
|
||||
|
|
|
@ -45,9 +45,9 @@ static void cluster_update(hexagram_cluster *cluster,
|
|||
struct timeval *last) {
|
||||
struct timeval now;
|
||||
|
||||
if (!hexagram_cluster_update(cluster, frame)) {
|
||||
return;
|
||||
}
|
||||
//if (!hexagram_cluster_update(cluster, frame)) {
|
||||
// return;
|
||||
//}
|
||||
|
||||
gettimeofday(&now, NULL);
|
||||
|
||||
|
@ -84,7 +84,7 @@ int main(int argc, char **argv) {
|
|||
hexagram_cluster *cluster;
|
||||
|
||||
int fd, fd2,
|
||||
width = 1024,
|
||||
width = 1280,
|
||||
height = 480;
|
||||
|
||||
cairo_t *fg, *bg;
|
||||
|
@ -110,7 +110,7 @@ int main(int argc, char **argv) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if ((cluster = hexagram_cluster_new(width, height)) == NULL) {
|
||||
if ((cluster = hexagram_cluster_new(1200, 6500, 8000)) == NULL) {
|
||||
perror("hexagram_cluster_new()");
|
||||
|
||||
return 1;
|
||||
|
|
|
@ -8,7 +8,47 @@
|
|||
|
||||
#include <cairo-svg.h>
|
||||
|
||||
#include <hexagram/cluster.h>
|
||||
#include <hexagram/path.h>
|
||||
|
||||
static char *path_data =
|
||||
"M 23.246093 0,"
|
||||
" 0 13.382812,"
|
||||
"V 44.689453"
|
||||
"L 0.0839844 44.640625,"
|
||||
" 24.033203 58.505859,"
|
||||
" 24.001953 86.332031,"
|
||||
" 22.841796 87"
|
||||
"h 4.478516"
|
||||
"L 26.068359 86.275391,"
|
||||
" 26.099609 58.449219,"
|
||||
" 50.083984 44.640625,"
|
||||
" 74.033203 58.505859,"
|
||||
" 74.001953 86.332031,"
|
||||
" 72.841796 87"
|
||||
"h 4.478516"
|
||||
"L 76.068359 86.275391,"
|
||||
" 76.099609 58.449219,"
|
||||
" 100 44.689453,"
|
||||
"V 13.365234"
|
||||
"L 76.919921 0"
|
||||
"H 73.246093"
|
||||
"L 50.015625 13.373047,"
|
||||
" 26.919921 0"
|
||||
"Z"
|
||||
"M 25.083984 1.25,"
|
||||
" 49.033203 15.115234,"
|
||||
" 49.001953, 42.941406,"
|
||||
" 25.017578 56.75,"
|
||||
" 1.0019531 42.845703,"
|
||||
"l 0.033203 -27.75"
|
||||
"z"
|
||||
"m 50 0,"
|
||||
" 24.017576 13.904297,"
|
||||
" -0.0352 27.75"
|
||||
"L 75.017578 56.75,"
|
||||
" 51.068359 42.884766,"
|
||||
" 51.099609 15.058594"
|
||||
"Z";
|
||||
|
||||
static int usage(int argc, char **argv, const char *message, ...) {
|
||||
if (message) {
|
||||
|
@ -26,9 +66,7 @@ static int usage(int argc, char **argv, const char *message, ...) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
hexagram_cluster *cluster;
|
||||
|
||||
int width = 1024,
|
||||
int width = 1280,
|
||||
height = 480;
|
||||
|
||||
cairo_surface_t *surface;
|
||||
|
@ -39,10 +77,6 @@ int main(int argc, char **argv) {
|
|||
return usage(argc, argv, "No output SVG file specified");
|
||||
}
|
||||
|
||||
if ((cluster = hexagram_cluster_new(width, height)) == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
surface = cairo_svg_surface_create(argv[1], width, height);
|
||||
|
||||
/*
|
||||
|
@ -53,11 +87,19 @@ int main(int argc, char **argv) {
|
|||
/*
|
||||
* Draw the background layer
|
||||
*/
|
||||
hexagram_cluster_draw_bg(cluster, bg);
|
||||
if (hexagram_path_run(bg, path_data, strlen(path_data)) < 0) {
|
||||
printf("Oh noes!\n");
|
||||
goto error_path_run;
|
||||
}
|
||||
|
||||
cairo_stroke(bg);
|
||||
|
||||
cairo_destroy(bg);
|
||||
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
return 0;
|
||||
|
||||
error_path_run:
|
||||
return -1;
|
||||
}
|
||||
|
|
32
include/hexagram/clock.h
Normal file
32
include/hexagram/clock.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
#ifndef _HEXAGRAM_CLOCK_H
|
||||
#define _HEXAGRAM_CLOCK_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <hexagram/text.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_CLOCK_24H,
|
||||
HEXAGRAM_CLOCK_12H
|
||||
} hexagram_clock_format;
|
||||
|
||||
typedef struct _hexagram_clock_time {
|
||||
uint16_t hour, minute;
|
||||
} hexagram_clock_time;
|
||||
|
||||
typedef struct _hexagram_clock {
|
||||
hexagram_text text;
|
||||
hexagram_clock_format format;
|
||||
hexagram_clock_time time;
|
||||
} hexagram_clock;
|
||||
|
||||
int hexagram_clock_init(hexagram_clock *clock,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_clock_format format);
|
||||
|
||||
void hexagram_clock_set(hexagram_clock *clock, time_t now);
|
||||
|
||||
#endif /* _HEXAGRAM_CLOCK_H */
|
|
@ -3,48 +3,56 @@
|
|||
|
||||
#include <cairo.h>
|
||||
|
||||
#include <hexagram/list.h>
|
||||
#include <hexagram/can.h>
|
||||
#include <hexagram/tacho.h>
|
||||
#include <hexagram/pattern.h>
|
||||
#include <hexagram/speedo.h>
|
||||
#include <hexagram/thermo.h>
|
||||
#include <hexagram/fuel.h>
|
||||
#include <hexagram/mfd.h>
|
||||
#include <hexagram/tacho.h>
|
||||
#include <hexagram/thermo.h>
|
||||
#include <hexagram/odo.h>
|
||||
#include <hexagram/temp.h>
|
||||
#include <hexagram/clock.h>
|
||||
#include <hexagram/status.h>
|
||||
|
||||
#define HEXAGRAM_CLUSTER_GAUGE_COUNT 9
|
||||
|
||||
typedef struct _hexagram_cluster {
|
||||
hexagram_tacho tacho;
|
||||
hexagram_speedo speedo;
|
||||
hexagram_thermo thermo;
|
||||
hexagram_fuel fuel;
|
||||
hexagram_mfd mfd;
|
||||
|
||||
double width,
|
||||
height;
|
||||
|
||||
struct {
|
||||
double rpm, rps, temp, fuel;
|
||||
} state;
|
||||
hexagram_pattern pattern;
|
||||
|
||||
hexagram_speedo speedo;
|
||||
hexagram_fuel fuel;
|
||||
hexagram_tacho tacho;
|
||||
hexagram_thermo thermo;
|
||||
hexagram_odo odo;
|
||||
hexagram_temp temp;
|
||||
hexagram_clock clock;
|
||||
hexagram_status_icon_box status;
|
||||
hexagram_tacho_shift_indicator shift_indicator;
|
||||
|
||||
hexagram_gauge *gauges[HEXAGRAM_CLUSTER_GAUGE_COUNT];
|
||||
} hexagram_cluster;
|
||||
|
||||
void hexagram_cluster_resize(hexagram_cluster *cluster,
|
||||
double width,
|
||||
double height);
|
||||
int hexagram_cluster_init(hexagram_cluster *cluster,
|
||||
double rpm_min,
|
||||
double rpm_redline,
|
||||
double rpm_max);
|
||||
|
||||
void hexagram_cluster_init(hexagram_cluster *cluster,
|
||||
double width,
|
||||
double height);
|
||||
void hexagram_cluster_cleanup(hexagram_cluster *cluster);
|
||||
|
||||
hexagram_cluster *hexagram_cluster_new(double width,
|
||||
double height);
|
||||
hexagram_cluster *hexagram_cluster_new(double rpm_min,
|
||||
double rpm_redline,
|
||||
double rpm_max);
|
||||
|
||||
void hexagram_cluster_destroy(hexagram_cluster *cluster);
|
||||
|
||||
int hexagram_cluster_filter_can_if(hexagram_can_if *can_if);
|
||||
|
||||
int hexagram_cluster_update(hexagram_cluster *cluster,
|
||||
struct can_frame *frame);
|
||||
void hexagram_cluster_draw_bg(hexagram_cluster *cluster, cairo_t *cr);
|
||||
|
||||
void hexagram_cluster_draw_bg(hexagram_cluster *cluster,
|
||||
cairo_t *cr);
|
||||
|
||||
void hexagram_cluster_draw_fg(hexagram_cluster *cluster,
|
||||
cairo_t *cr);
|
||||
void hexagram_cluster_draw_fg(hexagram_cluster *cluster, cairo_t *cr);
|
||||
|
||||
#endif /* _HEXAGRAM_CLUSTER_H */
|
||||
|
|
73
include/hexagram/dial.h
Normal file
73
include/hexagram/dial.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
#ifndef _HEXAGRAM_DIAL_H
|
||||
#define _HEXAGRAM_DIAL_H
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_DIAL_MAIN,
|
||||
HEXAGRAM_DIAL_BOTTOM
|
||||
} hexagram_dial_type;
|
||||
|
||||
typedef struct _hexagram_dial {
|
||||
hexagram_gauge gauge;
|
||||
hexagram_dial_type type;
|
||||
|
||||
double radius,
|
||||
min_angle,
|
||||
max_angle,
|
||||
min_value,
|
||||
max_value;
|
||||
|
||||
double needle_min_radius,
|
||||
needle_max_radius;
|
||||
|
||||
double mark_min_radius,
|
||||
mark_max_radius;
|
||||
|
||||
double value;
|
||||
cairo_pattern_t *gradient;
|
||||
} hexagram_dial;
|
||||
|
||||
int hexagram_dial_init(hexagram_dial *dial,
|
||||
hexagram_dial_type type,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double min_angle,
|
||||
double max_angle,
|
||||
double min_value,
|
||||
double max_value);
|
||||
|
||||
double hexagram_dial_angle(hexagram_dial *dial, double value);
|
||||
|
||||
int hexagram_dial_draw_legend(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
char *text);
|
||||
|
||||
int hexagram_dial_draw_legend_offset(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
char *text,
|
||||
double x_offset,
|
||||
double y_offset);
|
||||
|
||||
int hexagram_dial_draw_mark(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value);
|
||||
|
||||
int hexagram_dial_draw_needle(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value);
|
||||
|
||||
int hexagram_dial_draw_bg(hexagram_dial *dial, cairo_t *cr);
|
||||
|
||||
int hexagram_dial_draw_fg(hexagram_dial *dial, cairo_t *cr);
|
||||
|
||||
#endif /* _HEXAGRAM_DIAL_H */
|
|
@ -1,26 +1,16 @@
|
|||
#ifndef _HEXAGRAM_FUEL_H
|
||||
#define _HEXAGRAM_FUEL_H
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/dial.h>
|
||||
|
||||
typedef struct _hexagram_fuel {
|
||||
hexagram_gauge gauge;
|
||||
double redline;
|
||||
hexagram_dial dial;
|
||||
double warn_level;
|
||||
} hexagram_fuel;
|
||||
|
||||
void hexagram_fuel_init(hexagram_fuel *fuel,
|
||||
int hexagram_fuel_init(hexagram_fuel *fuel,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline);
|
||||
|
||||
void hexagram_fuel_draw_face(hexagram_fuel *fuel,
|
||||
cairo_t *cr);
|
||||
|
||||
void hexagram_fuel_draw_needle(hexagram_fuel *fuel,
|
||||
cairo_t *cr,
|
||||
double level);
|
||||
double radius);
|
||||
|
||||
#endif /* _HEXAGRAM_FUEL_H */
|
||||
|
|
|
@ -3,35 +3,26 @@
|
|||
|
||||
#include <cairo.h>
|
||||
|
||||
typedef struct _hexagram_gauge hexagram_gauge;
|
||||
|
||||
typedef int (hexagram_gauge_draw_callback)(hexagram_gauge *,
|
||||
cairo_t *);
|
||||
|
||||
typedef struct _hexagram_gauge {
|
||||
double x, y;
|
||||
double radius;
|
||||
double min_angle;
|
||||
double max_angle;
|
||||
|
||||
hexagram_gauge_draw_callback *draw_bg,
|
||||
*draw_fg;
|
||||
} hexagram_gauge;
|
||||
|
||||
void hexagram_gauge_init(hexagram_gauge *gauge,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double min_angle,
|
||||
double max_angle);
|
||||
hexagram_gauge_draw_callback *draw_bg,
|
||||
hexagram_gauge_draw_callback *draw_fg);
|
||||
|
||||
void hexagram_gauge_draw_number(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
const char *text);
|
||||
int hexagram_gauge_draw_fg(hexagram_gauge *gauge, cairo_t *cr);
|
||||
|
||||
void hexagram_gauge_draw_mark(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value);
|
||||
|
||||
void hexagram_gauge_draw_needle(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value);
|
||||
int hexagram_gauge_draw_bg(hexagram_gauge *gauge, cairo_t *cr);
|
||||
|
||||
#endif /* _HEXAGRAM_GAUGE_H */
|
||||
|
|
47
include/hexagram/icon.h
Normal file
47
include/hexagram/icon.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
#ifndef _HEXAGRAM_ICON_H
|
||||
#define _HEXAGRAM_ICON_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#define HEXAGRAM_ICON_COLOR_COUNT 6
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_ICON_COLOR_RED,
|
||||
HEXAGRAM_ICON_COLOR_ORANGE,
|
||||
HEXAGRAM_ICON_COLOR_YELLOW,
|
||||
HEXAGRAM_ICON_COLOR_GREEN,
|
||||
HEXAGRAM_ICON_COLOR_BLUE,
|
||||
HEXAGRAM_ICON_COLOR_WHITE
|
||||
} hexagram_icon_color;
|
||||
|
||||
typedef struct _hexagram_icon {
|
||||
int id;
|
||||
const char *name,
|
||||
*style_format;
|
||||
|
||||
union {
|
||||
struct {
|
||||
int red, orange, yellow, green, blue, white;
|
||||
};
|
||||
|
||||
int colors[HEXAGRAM_ICON_COLOR_COUNT];
|
||||
};
|
||||
|
||||
double width, height;
|
||||
cairo_surface_t *surfaces[HEXAGRAM_ICON_COLOR_COUNT];
|
||||
} hexagram_icon;
|
||||
|
||||
int hexagram_icon_init(hexagram_icon *icon, double width, double height);
|
||||
|
||||
void hexagram_icon_cleanup(hexagram_icon *icon);
|
||||
|
||||
int hexagram_icon_drawable(hexagram_icon *icon, int status);
|
||||
|
||||
int hexagram_icon_draw(hexagram_icon *icon,
|
||||
cairo_t *cr,
|
||||
double x,
|
||||
double y,
|
||||
int status);
|
||||
|
||||
#endif /* _HEXAGRAM_ICON_H */
|
23
include/hexagram/odo.h
Normal file
23
include/hexagram/odo.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef _HEXAGRAM_ODO_H
|
||||
#define _HEXAGRAM_ODO_H
|
||||
|
||||
#include <hexagram/text.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_ODO_KILOMETERS,
|
||||
HEXAGRAM_ODO_MILES
|
||||
} hexagram_odo_units;
|
||||
|
||||
typedef struct _hexagram_odo {
|
||||
hexagram_text text;
|
||||
hexagram_odo_units units;
|
||||
double value;
|
||||
} hexagram_odo;
|
||||
|
||||
int hexagram_odo_init(hexagram_odo *odo,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_odo_units units);
|
||||
|
||||
#endif /* _HEXAGRAM_ODO_H */
|
21
include/hexagram/path.h
Normal file
21
include/hexagram/path.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#ifndef _HEXAGRAM_PATH_H
|
||||
#define _HEXAGRAM_PATH_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cairo.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_PATH_STATE_NONE,
|
||||
HEXAGRAM_PATH_STATE_COMMAND,
|
||||
HEXAGRAM_PATH_STATE_ARG
|
||||
} hexagram_path_state;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_PATH_ARG_NONE,
|
||||
HEXAGRAM_PATH_ARG_INT,
|
||||
HEXAGRAM_PATH_ARG_FLOAT
|
||||
} hexagram_path_arg_type;
|
||||
|
||||
int hexagram_path_run(cairo_t *cr, const char *data, size_t len);
|
||||
|
||||
#endif /* _HEXAGRAM_PATH_H */
|
34
include/hexagram/pattern.h
Normal file
34
include/hexagram/pattern.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef _HEXAGRAM_PATTERN_H
|
||||
#define _HEXAGRAM_PATTERN_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cairo.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_PATTERN_STROKE,
|
||||
HEXAGRAM_PATTERN_FILL
|
||||
} hexagram_pattern_op;
|
||||
|
||||
typedef struct _hexagram_pattern {
|
||||
double width, height;
|
||||
double color[3];
|
||||
|
||||
cairo_surface_t *surface;
|
||||
} hexagram_pattern;
|
||||
|
||||
int hexagram_pattern_init(hexagram_pattern *pattern,
|
||||
double width,
|
||||
double height,
|
||||
const double color[3],
|
||||
hexagram_pattern_op op,
|
||||
const char *pathdata,
|
||||
size_t len);
|
||||
|
||||
void hexagram_pattern_cleanup(hexagram_pattern *pattern);
|
||||
|
||||
void hexagram_pattern_fill(hexagram_pattern *pattern,
|
||||
cairo_t *cr,
|
||||
const double matrix[6],
|
||||
const double scale[2]);
|
||||
|
||||
#endif /* _HEXAGRAM_PATTERN_H */
|
|
@ -1,27 +1,25 @@
|
|||
#ifndef _HEXAGRAM_SPEEDO_H
|
||||
#define _HEXAGRAM_SPEEDO_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/dial.h>
|
||||
|
||||
#define HEXAGRAM_SPEEDO_MAX_KPH 289.682
|
||||
#define HEXAGRAM_SPEEDO_MAX_MPH 180.000
|
||||
typedef enum {
|
||||
HEXAGRAM_SPEEDO_KPH,
|
||||
HEXAGRAM_SPEEDO_MPH
|
||||
} hexagram_speedo_units;
|
||||
|
||||
typedef struct _hexagram_speedo {
|
||||
hexagram_gauge gauge;
|
||||
hexagram_dial dial;
|
||||
hexagram_speedo_units units;
|
||||
} hexagram_speedo;
|
||||
|
||||
void hexagram_speedo_init(hexagram_speedo *speedo,
|
||||
int hexagram_speedo_init(hexagram_speedo *speedo,
|
||||
double x,
|
||||
double y,
|
||||
double radius);
|
||||
|
||||
void hexagram_speedo_draw_face(hexagram_speedo *speedo,
|
||||
cairo_t *cr);
|
||||
|
||||
void hexagram_speedo_draw_needle(hexagram_speedo *speedo,
|
||||
cairo_t *cr,
|
||||
double kph);
|
||||
double radius,
|
||||
double max_value,
|
||||
hexagram_speedo_units units);
|
||||
|
||||
#endif /* _HEXAGRAM_SPEEDO_H */
|
||||
|
|
173
include/hexagram/status.h
Normal file
173
include/hexagram/status.h
Normal file
|
@ -0,0 +1,173 @@
|
|||
#ifndef _HEXAGRAM_STATUS_H
|
||||
#define _HEXAGRAM_STATUS_H
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
#include <hexagram/icon.h>
|
||||
#include <hexagram/gauge.h>
|
||||
|
||||
#define HEXAGRAM_STATUS_ICON_WIDTH 48
|
||||
#define HEXAGRAM_STATUS_ICON_HEIGHT 48
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_CAUTION,
|
||||
HEXAGRAM_STATUS_COLLISION,
|
||||
HEXAGRAM_STATUS_FUEL,
|
||||
HEXAGRAM_STATUS_SEATBELT,
|
||||
HEXAGRAM_STATUS_COOLANT,
|
||||
HEXAGRAM_STATUS_OIL,
|
||||
HEXAGRAM_STATUS_PARKING_BRAKE,
|
||||
HEXAGRAM_STATUS_WIPER_WASHER,
|
||||
HEXAGRAM_STATUS_LANE_ASSIST,
|
||||
HEXAGRAM_STATUS_STABILITY_CONTROL,
|
||||
HEXAGRAM_STATUS_TRACTION_CONTROL,
|
||||
HEXAGRAM_STATUS_TPMS,
|
||||
HEXAGRAM_STATUS_ABS,
|
||||
HEXAGRAM_STATUS_AIRBAG,
|
||||
HEXAGRAM_STATUS_BATTERY,
|
||||
HEXAGRAM_STATUS_ENGINE,
|
||||
HEXAGRAM_STATUS_FOG_BEAM,
|
||||
HEXAGRAM_STATUS_PARKING_BEAM,
|
||||
HEXAGRAM_STATUS_LOW_BEAM,
|
||||
HEXAGRAM_STATUS_HIGH_BEAM,
|
||||
HEXAGRAM_STATUS_COLD,
|
||||
HEXAGRAM_STATUS_COUNT
|
||||
} hexagram_status_type;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_CAUTION_OFF,
|
||||
HEXAGRAM_STATUS_CAUTION_ON,
|
||||
HEXAGRAM_STATUS_CAUTION_WARNING
|
||||
} hexagram_status_caution;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_COLLISION_OK,
|
||||
HEXAGRAM_STATUS_COLLISION_DETECTED
|
||||
} hexagram_status_collision;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_FUEL_OK,
|
||||
HEXAGRAM_STATUS_FUEL_LOW,
|
||||
HEXAGRAM_STATUS_FUEL_FAULT
|
||||
} hexagram_status_fuel;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_SEATBELT_OK,
|
||||
HEXAGRAM_STATUS_SEATBELT_UNFASTENED,
|
||||
HEXAGRAM_STATUS_SEATBELT_FAULT
|
||||
} hexagram_status_seatbelt;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_COOLANT_OK,
|
||||
HEXAGRAM_STATUS_COOLANT_LOW,
|
||||
HEXAGRAM_STATUS_COOLANT_OVERHEAT,
|
||||
HEXAGRAM_STATUS_COOLANT_FAULT
|
||||
} hexagram_status_coolant;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_OIL_OK,
|
||||
HEXAGRAM_STATUS_OIL_LOW,
|
||||
HEXAGRAM_STATUS_OIL_OVERHEAT,
|
||||
HEXAGRAM_STATUS_OIL_FAULT
|
||||
} hexagram_status_oil;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_PARKING_BRAKE_OFF,
|
||||
HEXAGRAM_STATUS_PARKING_BRAKE_ON,
|
||||
HEXAGRAM_STATUS_PARKING_BRAKE_FAULT
|
||||
} hexagram_status_parking_brake;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_WIPER_WASHER_OK,
|
||||
HEXAGRAM_STATUS_WIPER_WASHER_LOW,
|
||||
HEXAGRAM_STATUS_WIPER_WASHER_FAULT
|
||||
} hexagram_status_wiper_washer;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_LANE_ASSIST_ON,
|
||||
HEXAGRAM_STATUS_LANE_ASSIST_OFF,
|
||||
HEXAGRAM_STATUS_LANE_ASSIST_FAULT
|
||||
} hexagram_status_lane_assist;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_STABILITY_CONTROL_ON,
|
||||
HEXAGRAM_STATUS_STABILITY_CONTROL_OFF,
|
||||
HEXAGRAM_STATUS_STABILITY_CONTROL_FAULT
|
||||
} hexagram_status_stability_control;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_TRACTION_CONTROL_ON,
|
||||
HEXAGRAM_STATUS_TRACTION_CONTROL_OFF,
|
||||
HEXAGRAM_STATUS_TRACTION_CONTROL_FAULT
|
||||
} hexagram_status_traction_control;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_TPMS_OK,
|
||||
HEXAGRAM_STATUS_TPMS_WARNING,
|
||||
HEXAGRAM_STATUS_TPMS_FAULT
|
||||
} hexagram_status_tpms;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_AIRBAG_ON,
|
||||
HEXAGRAM_STATUS_AIRBAG_OFF,
|
||||
HEXAGRAM_STATUS_AIRBAG_DEPLOYED,
|
||||
HEXAGRAM_STATUS_AIRBAG_FAULT
|
||||
} hexagram_status_airbag;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_BATTERY_OK,
|
||||
HEXAGRAM_STATUS_BATTERY_FAULT
|
||||
} hexagram_status_battery;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_ENGINE_OK,
|
||||
HEXAGRAM_STATUS_ENGINE_FAULT
|
||||
} hexagram_status_engine;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_FOG_BEAM_OFF,
|
||||
HEXAGRAM_STATUS_FOG_BEAM_ON,
|
||||
HEXAGRAM_STATUS_FOG_BEAM_FAULT
|
||||
} hexagram_status_fog_beam;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_PARKING_BEAM_OFF,
|
||||
HEXAGRAM_STATUS_PARKING_BEAM_ON,
|
||||
HEXAGRAM_STATUS_PARKING_BEAM_FAULT
|
||||
} hexagram_status_parking_beam;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_LOW_BEAM_OFF,
|
||||
HEXAGRAM_STATUS_LOW_BEAM_ON,
|
||||
HEXAGRAM_STATUS_LOW_BEAM_FAULT
|
||||
} hexagram_status_low_beam;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_STATUS_HIGH_BEAM_OFF,
|
||||
HEXAGRAM_STATUS_HIGH_BEAM_ON,
|
||||
HEXAGRAM_STATUS_HIGH_BEAM_FAULT
|
||||
} hexagram_status_high_beam;
|
||||
|
||||
typedef struct _hexagram_status_icon_box {
|
||||
hexagram_gauge gauge;
|
||||
double width, height;
|
||||
|
||||
hexagram_icon *icons;
|
||||
int state[HEXAGRAM_STATUS_COUNT];
|
||||
cairo_surface_t *surface;
|
||||
int dirty;
|
||||
} hexagram_status_icon_box;
|
||||
|
||||
int hexagram_status_icon_box_init(hexagram_status_icon_box *box,
|
||||
double x,
|
||||
double y,
|
||||
double width,
|
||||
double height);
|
||||
|
||||
void hexagram_status_icon_box_cleanup(hexagram_status_icon_box *box);
|
||||
|
||||
void hexagram_status_icon_set(hexagram_status_icon_box *box,
|
||||
hexagram_status_type type,
|
||||
int status);
|
||||
|
||||
#endif /* _HEXAGRAM_STATUS_H */
|
17
include/hexagram/svg.h
Normal file
17
include/hexagram/svg.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef _HEXAGRAM_SVG_H
|
||||
#define _HEXAGRAM_SVG_H
|
||||
|
||||
#include <cairo.h>
|
||||
|
||||
int hexagram_svg_render_to_surface(const char *path,
|
||||
cairo_surface_t *surface,
|
||||
double width,
|
||||
double height,
|
||||
const char *style);
|
||||
|
||||
cairo_surface_t *hexagram_svg_render_to_image(const char *path,
|
||||
double width,
|
||||
double height,
|
||||
const char *style);
|
||||
|
||||
#endif /* _HEXAGRAM_SVG_H */
|
|
@ -1,26 +1,38 @@
|
|||
#ifndef _HEXAGRAM_TACHO_H
|
||||
#define _HEXAGRAM_TACHO_H
|
||||
|
||||
#include <cairo.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <hexagram/trans.h>
|
||||
#include <hexagram/dial.h>
|
||||
#include <hexagram/gauge.h>
|
||||
|
||||
typedef struct _hexagram_tacho {
|
||||
hexagram_gauge gauge;
|
||||
hexagram_dial dial;
|
||||
double redline;
|
||||
hexagram_trans_gear gear;
|
||||
hexagram_trans_shift_mode shift_mode;
|
||||
} hexagram_tacho;
|
||||
|
||||
void hexagram_tacho_init(hexagram_tacho *tacho,
|
||||
typedef struct _hexagram_tacho_shift_indicator {
|
||||
hexagram_gauge gauge;
|
||||
|
||||
double rpm_min,
|
||||
rpm_shift,
|
||||
rpm;
|
||||
} hexagram_tacho_shift_indicator;
|
||||
|
||||
int hexagram_tacho_init(hexagram_tacho *tacho,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline);
|
||||
double redline,
|
||||
double rpm_max);
|
||||
|
||||
void hexagram_tacho_draw_face(hexagram_tacho *tacho,
|
||||
cairo_t *cr);
|
||||
|
||||
void hexagram_tacho_draw_needle(hexagram_tacho *tacho,
|
||||
cairo_t *cr,
|
||||
double rpm);
|
||||
int hexagram_tacho_shift_indicator_init(hexagram_tacho_shift_indicator *shift,
|
||||
double x,
|
||||
double y,
|
||||
double rpm_min,
|
||||
double rpm_shift);
|
||||
|
||||
#endif /* _HEXAGRAM_TACHO_H */
|
||||
|
|
27
include/hexagram/temp.h
Normal file
27
include/hexagram/temp.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef _HEXAGRAM_TEMP_H
|
||||
#define _HEXAGRAM_TEMP_H
|
||||
|
||||
#include <hexagram/text.h>
|
||||
#include <hexagram/icon.h>
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_TEMP_CELSIUS,
|
||||
HEXAGRAM_TEMP_FAHRENHEIT
|
||||
} hexagram_temp_units;
|
||||
|
||||
typedef struct _hexagram_temp {
|
||||
hexagram_text text;
|
||||
hexagram_icon icon;
|
||||
hexagram_temp_units units;
|
||||
double value;
|
||||
} hexagram_temp;
|
||||
|
||||
int hexagram_temp_init(hexagram_temp *temp,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_temp_units units);
|
||||
|
||||
void hexagram_temp_cleanup(hexagram_temp *temp);
|
||||
|
||||
#endif /* _HEXAGRAM_TEMP_H */
|
37
include/hexagram/text.h
Normal file
37
include/hexagram/text.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef _HEXAGRAM_TEXT_H
|
||||
#define _HEXAGRAM_TEXT_H
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <cairo.h>
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
|
||||
#define HEXAGRAM_TEXT_FONT_FACE "Muli"
|
||||
#define HEXAGRAM_TEXT_FONT_SLANT CAIRO_FONT_SLANT_NORMAL
|
||||
#define HEXAGRAM_TEXT_FONT_WEIGHT CAIRO_FONT_WEIGHT_BOLD
|
||||
#define HEXAGRAM_TEXT_FONT_SIZE 24
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_TEXT_LEFT,
|
||||
HEXAGRAM_TEXT_MIDDLE,
|
||||
HEXAGRAM_TEXT_RIGHT
|
||||
} hexagram_text_align;
|
||||
|
||||
typedef struct _hexagram_text hexagram_text;
|
||||
|
||||
typedef ssize_t (hexagram_text_format_callback)(hexagram_text *, char *, size_t);
|
||||
|
||||
typedef struct _hexagram_text {
|
||||
hexagram_gauge gauge;
|
||||
hexagram_text_align align;
|
||||
hexagram_text_format_callback *format_text;
|
||||
char buf[128];
|
||||
} hexagram_text;
|
||||
|
||||
int hexagram_text_init(hexagram_text *text,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_text_format_callback *format_text);
|
||||
|
||||
#endif /* _HEXAGRAM_TEXT_H */
|
|
@ -3,24 +3,18 @@
|
|||
|
||||
#include <cairo.h>
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/dial.h>
|
||||
#include <hexagram/temp.h>
|
||||
|
||||
typedef struct _hexagram_thermo {
|
||||
hexagram_gauge gauge;
|
||||
double redline;
|
||||
hexagram_dial dial;
|
||||
hexagram_temp_units units;
|
||||
double level_warn;
|
||||
} hexagram_thermo;
|
||||
|
||||
void hexagram_thermo_init(hexagram_thermo *thermo,
|
||||
int hexagram_thermo_init(hexagram_thermo *thermo,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline);
|
||||
|
||||
void hexagram_thermo_draw_face(hexagram_thermo *thermo,
|
||||
cairo_t *cr);
|
||||
|
||||
void hexagram_thermo_draw_needle(hexagram_thermo *thermo,
|
||||
cairo_t *cr,
|
||||
double temp);
|
||||
double radius);
|
||||
|
||||
#endif /* _HEXAGRAM_THERMO_H */
|
||||
|
|
35
include/hexagram/trans.h
Normal file
35
include/hexagram/trans.h
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef _HEXAGRAM_TRANS_H
|
||||
#define _HEXAGRAM_TRANS_H
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_TRANS_GEAR_S = -4,
|
||||
HEXAGRAM_TRANS_GEAR_D = -3,
|
||||
HEXAGRAM_TRANS_GEAR_P = -2,
|
||||
HEXAGRAM_TRANS_GEAR_R = -1,
|
||||
HEXAGRAM_TRANS_GEAR_N = 0,
|
||||
HEXAGRAM_TRANS_GEAR_1 = 1,
|
||||
HEXAGRAM_TRANS_GEAR_2 = 2,
|
||||
HEXAGRAM_TRANS_GEAR_3 = 3,
|
||||
HEXAGRAM_TRANS_GEAR_4 = 4,
|
||||
HEXAGRAM_TRANS_GEAR_5 = 5,
|
||||
HEXAGRAM_TRANS_GEAR_6 = 6,
|
||||
HEXAGRAM_TRANS_GEAR_7 = 7,
|
||||
HEXAGRAM_TRANS_GEAR_8 = 8,
|
||||
HEXAGRAM_TRANS_GEAR_9 = 9,
|
||||
HEXAGRAM_TRANS_GEAR_10 = 10
|
||||
} hexagram_trans_gear;
|
||||
|
||||
typedef enum {
|
||||
HEXAGRAM_TRANS_SHIFT_NORMAL,
|
||||
HEXAGRAM_TRANS_SHIFT_COMFORT,
|
||||
HEXAGRAM_TRANS_SHIFT_ECO,
|
||||
HEXAGRAM_TRANS_SHIFT_SPORT,
|
||||
HEXAGRAM_TRANS_SHIFT_RACE,
|
||||
HEXAGRAM_TRANS_SHIFT_MANUAL,
|
||||
} hexagram_trans_shift_mode;
|
||||
|
||||
char *hexagram_trans_gear_str(hexagram_trans_gear gear);
|
||||
|
||||
char *hexagram_trans_shift_mode_str(hexagram_trans_shift_mode mode);
|
||||
|
||||
#endif /* _HEXAGRAM_TRANS_H */
|
14
src/Makefile
14
src/Makefile
|
@ -4,18 +4,20 @@ INCLUDE_PATH = ../include
|
|||
HEADER_SUBDIR = hexagram
|
||||
|
||||
CC = $(CROSS)cc
|
||||
CFLAGS += -fPIC -I$(INCLUDE_PATH) $(shell pkg-config --cflags cairo x11)
|
||||
LDFLAGS = $(shell pkg-config --libs cairo x11) -lXext
|
||||
CFLAGS += -fPIC -I$(INCLUDE_PATH) $(shell pkg-config --cflags cairo x11 librsvg-2.0)
|
||||
LDFLAGS = $(shell pkg-config --libs cairo x11 librsvg-2.0) -lXext
|
||||
|
||||
HEADERS = list.h dict.h hash.h can.h capture.h pcapng.h module.h \
|
||||
window.h gauge.h tacho.h speedo.h thermo.h fuel.h mfd.h \
|
||||
cluster.h sim.h schedule.h
|
||||
window.h path.h pattern.h gauge.h dial.h text.h odo.h clock.h \
|
||||
temp.h trans.h tacho.h speedo.h thermo.h fuel.h mfd.h \
|
||||
cluster.h sim.h schedule.h svg.h icon.h status.h
|
||||
|
||||
HEADERS_LOCAL = util.h
|
||||
|
||||
OBJS = list.o dict.o hash.o can.o capture.o pcapng.o module.o \
|
||||
window.o gauge.o tacho.o speedo.o thermo.o fuel.o mfd.o \
|
||||
cluster.o sim.o schedule.o
|
||||
window.o path.o pattern.o gauge.o dial.o text.o odo.o clock.o \
|
||||
temp.o trans.o tacho.o speedo.o thermo.o fuel.o mfd.o \
|
||||
cluster.o sim.o schedule.o svg.o icon.o status.o
|
||||
|
||||
VERSION_MAJOR = 0
|
||||
VERSION_MINOR = 0.1
|
||||
|
|
54
src/clock.c
Normal file
54
src/clock.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <hexagram/clock.h>
|
||||
|
||||
static ssize_t format_text(hexagram_text *text, char *buf, size_t len) {
|
||||
hexagram_clock *clock = (hexagram_clock *)text;
|
||||
switch (clock->format) {
|
||||
case HEXAGRAM_CLOCK_24H:
|
||||
return snprintf(buf, len, "%d:%02d",
|
||||
clock->time.hour, clock->time.minute);
|
||||
|
||||
case HEXAGRAM_CLOCK_12H:
|
||||
return snprintf(buf, len, "%d:%02d %s",
|
||||
clock->time.hour, clock->time.minute,
|
||||
clock->time.hour < 12? "am": "pm");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_clock_init(hexagram_clock *clock,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_clock_format format) {
|
||||
if (hexagram_text_init(&clock->text,
|
||||
x,
|
||||
y,
|
||||
align,
|
||||
format_text) < 0) {
|
||||
goto error_text_init;
|
||||
}
|
||||
|
||||
clock->format = format;
|
||||
clock->time.hour = 0;
|
||||
clock->time.minute = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
error_text_init:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_clock_set(hexagram_clock *clock, time_t now) {
|
||||
struct tm *now_tm;
|
||||
|
||||
if ((now_tm = localtime(&now)) == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
clock->time.hour = now_tm->tm_hour;
|
||||
clock->time.minute = now_tm->tm_min;
|
||||
}
|
335
src/cluster.c
335
src/cluster.c
|
@ -3,74 +3,68 @@
|
|||
|
||||
#include <hexagram/cluster.h>
|
||||
|
||||
void hexagram_cluster_resize(hexagram_cluster *cluster,
|
||||
double width,
|
||||
double height) {
|
||||
/*
|
||||
* Ensure correct cluster aspect ratio
|
||||
*/
|
||||
if (width / height > 32.0 / 15.0) {
|
||||
width = height * (32.0 / 15.0);
|
||||
} else {
|
||||
height = width * (15.0 / 32.0);
|
||||
}
|
||||
#define CLUSTER_WIDTH 1280
|
||||
#define CLUSTER_HEIGHT 480
|
||||
|
||||
hexagram_tacho_init(&cluster->tacho,
|
||||
width * 0.2,
|
||||
height * 0.5,
|
||||
height * 0.4,
|
||||
6500.0);
|
||||
#define SHIFT_INDICATOR_X 392
|
||||
#define SHIFT_INDICATOR_Y 24
|
||||
|
||||
hexagram_speedo_init(&cluster->speedo,
|
||||
width * 0.8,
|
||||
height * 0.5,
|
||||
height * 0.4);
|
||||
#define SECTION_HEIGHT_TOP 64
|
||||
#define SECTION_HEIGHT_BOTTOM 52
|
||||
|
||||
hexagram_thermo_init(&cluster->thermo,
|
||||
width * 0.43,
|
||||
height * 0.76,
|
||||
height * 0.13,
|
||||
230.0);
|
||||
#define SPEEDO_MAX 200.0
|
||||
#define SPEEDO_UNITS HEXAGRAM_SPEEDO_MPH
|
||||
|
||||
hexagram_fuel_init(&cluster->fuel,
|
||||
width * 0.57,
|
||||
height * 0.76,
|
||||
height * 0.13,
|
||||
0.14);
|
||||
#define PATTERN_WIDTH 100
|
||||
#define PATTERN_HEIGHT 87
|
||||
|
||||
hexagram_mfd_init(&cluster->mfd,
|
||||
width * 0.42,
|
||||
height * 0.10,
|
||||
width * 0.16,
|
||||
height * 0.50);
|
||||
static const double hexagon_pattern_color[3] = { 0.3, 0.1, 0.3 };
|
||||
|
||||
cluster->width = width;
|
||||
cluster->height = height;
|
||||
}
|
||||
static const double hexagon_pattern_matrix[6] = {
|
||||
0.21213203, 0.21213203, 0.21213203, -0.21213203, 1, 1
|
||||
};
|
||||
|
||||
void hexagram_cluster_init(hexagram_cluster *cluster,
|
||||
double width,
|
||||
double height) {
|
||||
hexagram_cluster_resize(cluster, width, height);
|
||||
static const double hexagon_pattern_scale[2] = { 3, 3 };
|
||||
|
||||
memset(&cluster->state, '\0', sizeof(cluster->state));
|
||||
}
|
||||
|
||||
hexagram_cluster *hexagram_cluster_new(double width,
|
||||
double height) {
|
||||
hexagram_cluster *cluster;
|
||||
|
||||
if ((cluster = malloc(sizeof(*cluster))) == NULL) {
|
||||
goto error_malloc_cluster;
|
||||
}
|
||||
|
||||
hexagram_cluster_init(cluster, width, height);
|
||||
|
||||
return cluster;
|
||||
|
||||
error_malloc_cluster:
|
||||
return NULL;
|
||||
}
|
||||
static const char *hexagon_pattern =
|
||||
"M 23.246093 0,"
|
||||
" 0 13.382812,"
|
||||
"V 44.689453"
|
||||
"L 0.0839844 44.640625,"
|
||||
" 24.033203 58.505859,"
|
||||
" 24.001953 86.332031,"
|
||||
" 22.841796 87"
|
||||
"h 4.478516"
|
||||
"L 26.068359 86.275391,"
|
||||
" 26.099609 58.449219,"
|
||||
" 50.083984 44.640625,"
|
||||
" 74.033203 58.505859,"
|
||||
" 74.001953 86.332031,"
|
||||
" 72.841796 87"
|
||||
"h 4.478516"
|
||||
"L 76.068359 86.275391,"
|
||||
" 76.099609 58.449219,"
|
||||
" 100 44.689453,"
|
||||
"V 13.365234"
|
||||
"L 76.919921 0"
|
||||
"H 73.246093"
|
||||
"L 50.015625 13.373047,"
|
||||
" 26.919921 0"
|
||||
"Z"
|
||||
"M 25.083984 1.25,"
|
||||
" 49.033203 15.115234,"
|
||||
" 49.001953, 42.941406,"
|
||||
" 25.017578 56.75,"
|
||||
" 1.0019531 42.845703,"
|
||||
"l 0.033203 -27.75"
|
||||
"z"
|
||||
"m 50 0,"
|
||||
" 24.017576 13.904297,"
|
||||
" -0.0352 27.75"
|
||||
"L 75.017578 56.75,"
|
||||
" 51.068359 42.884766,"
|
||||
" 51.099609 15.058594"
|
||||
"Z";
|
||||
|
||||
int hexagram_cluster_filter_can_if(hexagram_can_if *can_if) {
|
||||
struct can_filter filters[4] = {
|
||||
|
@ -87,65 +81,202 @@ int hexagram_cluster_filter_can_if(hexagram_can_if *can_if) {
|
|||
sizeof(filters));
|
||||
}
|
||||
|
||||
int hexagram_cluster_update(hexagram_cluster *cluster,
|
||||
struct can_frame *frame) {
|
||||
switch (frame->can_id) {
|
||||
case 0x280: {
|
||||
cluster->state.rpm = 0.25 *
|
||||
(double)(frame->data[2] | (frame->data[3] << 8));
|
||||
int hexagram_cluster_init(hexagram_cluster *cluster,
|
||||
double rpm_min,
|
||||
double rpm_redline,
|
||||
double rpm_max) {
|
||||
cluster->width = CLUSTER_WIDTH;
|
||||
cluster->height = CLUSTER_HEIGHT;
|
||||
|
||||
return 1;
|
||||
if (hexagram_pattern_init(&cluster->pattern,
|
||||
PATTERN_WIDTH,
|
||||
PATTERN_HEIGHT,
|
||||
hexagon_pattern_color,
|
||||
HEXAGRAM_PATTERN_STROKE,
|
||||
hexagon_pattern,
|
||||
strlen(hexagon_pattern)) < 0) {
|
||||
goto error_pattern_init;
|
||||
}
|
||||
|
||||
case 0x288: {
|
||||
cluster->state.temp = 0.75 * (double)(frame->data[1] - 48);
|
||||
|
||||
return 1;
|
||||
if (hexagram_speedo_init(&cluster->speedo,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
SPEEDO_MAX,
|
||||
SPEEDO_UNITS) < 0) {
|
||||
goto error_speedo_init;
|
||||
}
|
||||
|
||||
case 0x320: {
|
||||
cluster->state.fuel = (double)(frame->data[2] & 0xf) / 15.0;
|
||||
|
||||
return 1;
|
||||
if (hexagram_fuel_init(&cluster->fuel,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2) < 0) {
|
||||
goto error_fuel_init;
|
||||
}
|
||||
|
||||
case 0x5a0: {
|
||||
cluster->state.rps = 0.001 * (double)(frame->data[1]
|
||||
| (frame->data[2] << 8));
|
||||
if (hexagram_tacho_init(&cluster->tacho,
|
||||
CLUSTER_WIDTH - CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
rpm_redline,
|
||||
rpm_max) < 0) {
|
||||
goto error_tacho_init;
|
||||
}
|
||||
|
||||
return 1;
|
||||
if (hexagram_thermo_init(&cluster->thermo,
|
||||
CLUSTER_WIDTH - CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2,
|
||||
CLUSTER_HEIGHT / 2) < 0) {
|
||||
goto error_thermo_init;
|
||||
}
|
||||
|
||||
if (hexagram_odo_init(&cluster->odo,
|
||||
0.8 * CLUSTER_HEIGHT,
|
||||
CLUSTER_HEIGHT - 16,
|
||||
HEXAGRAM_TEXT_LEFT,
|
||||
HEXAGRAM_ODO_MILES) < 0) {
|
||||
goto error_odo_init;
|
||||
}
|
||||
|
||||
if (hexagram_clock_init(&cluster->clock,
|
||||
CLUSTER_WIDTH / 2,
|
||||
CLUSTER_HEIGHT - 16,
|
||||
HEXAGRAM_TEXT_MIDDLE,
|
||||
HEXAGRAM_CLOCK_24H) < 0) {
|
||||
goto error_clock_init;
|
||||
}
|
||||
|
||||
if (hexagram_temp_init(&cluster->temp,
|
||||
CLUSTER_WIDTH - 0.8 * CLUSTER_HEIGHT,
|
||||
CLUSTER_HEIGHT - 16,
|
||||
HEXAGRAM_TEXT_RIGHT,
|
||||
HEXAGRAM_TEMP_CELSIUS) < 0) {
|
||||
goto error_temp_init;
|
||||
}
|
||||
|
||||
if (hexagram_tacho_shift_indicator_init(&cluster->shift_indicator,
|
||||
SHIFT_INDICATOR_X,
|
||||
SHIFT_INDICATOR_Y,
|
||||
rpm_min,
|
||||
rpm_redline) < 0) {
|
||||
goto error_tacho_shift_indicator_init;
|
||||
}
|
||||
|
||||
if (hexagram_status_icon_box_init(&cluster->status,
|
||||
CLUSTER_WIDTH / 2 - HEXAGRAM_STATUS_ICON_WIDTH * 3.5,
|
||||
CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM - 16 - HEXAGRAM_STATUS_ICON_HEIGHT * 3,
|
||||
HEXAGRAM_STATUS_ICON_WIDTH * 7,
|
||||
HEXAGRAM_STATUS_ICON_HEIGHT * 3) < 0) {
|
||||
goto error_status_icon_box_init;
|
||||
}
|
||||
|
||||
cluster->gauges[0] = &cluster->speedo.dial.gauge;
|
||||
cluster->gauges[1] = &cluster->fuel.dial.gauge;
|
||||
cluster->gauges[2] = &cluster->tacho.dial.gauge;
|
||||
cluster->gauges[3] = &cluster->thermo.dial.gauge;
|
||||
cluster->gauges[4] = &cluster->odo.text.gauge;
|
||||
cluster->gauges[5] = &cluster->temp.text.gauge;
|
||||
cluster->gauges[6] = &cluster->clock.text.gauge;
|
||||
cluster->gauges[7] = &cluster->status.gauge;
|
||||
cluster->gauges[8] = &cluster->shift_indicator.gauge;
|
||||
|
||||
return 0;
|
||||
|
||||
error_status_icon_box_init:
|
||||
error_tacho_shift_indicator_init:
|
||||
hexagram_temp_cleanup(&cluster->temp);
|
||||
|
||||
error_temp_init:
|
||||
error_clock_init:
|
||||
error_odo_init:
|
||||
error_thermo_init:
|
||||
error_tacho_init:
|
||||
error_fuel_init:
|
||||
error_speedo_init:
|
||||
hexagram_pattern_cleanup(&cluster->pattern);
|
||||
|
||||
error_pattern_init:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_cluster_draw_bg(hexagram_cluster *cluster,
|
||||
cairo_t *cr) {
|
||||
/*
|
||||
* Paint canvas black
|
||||
*/
|
||||
cairo_set_source_rgb(cr, 0, 0, 0);
|
||||
cairo_paint(cr);
|
||||
|
||||
hexagram_tacho_draw_face(&cluster->tacho, cr);
|
||||
hexagram_speedo_draw_face(&cluster->speedo, cr);
|
||||
hexagram_thermo_draw_face(&cluster->thermo, cr);
|
||||
hexagram_fuel_draw_face(&cluster->fuel, cr);
|
||||
hexagram_mfd_draw(&cluster->mfd, cr);
|
||||
void hexagram_cluster_cleanup(hexagram_cluster *cluster) {
|
||||
hexagram_status_icon_box_cleanup(&cluster->status);
|
||||
hexagram_temp_cleanup(&cluster->temp);
|
||||
hexagram_pattern_cleanup(&cluster->pattern);
|
||||
}
|
||||
|
||||
void hexagram_cluster_draw_fg(hexagram_cluster *cluster,
|
||||
cairo_t *cr) {
|
||||
hexagram_tacho_draw_needle(&cluster->tacho, cr,
|
||||
cluster->state.rpm);
|
||||
hexagram_cluster *hexagram_cluster_new(double rpm_min,
|
||||
double rpm_redline,
|
||||
double rpm_max) {
|
||||
hexagram_cluster *cluster;
|
||||
|
||||
hexagram_speedo_draw_needle(&cluster->speedo, cr,
|
||||
cluster->state.rps);
|
||||
if ((cluster = malloc(sizeof(*cluster))) == NULL) {
|
||||
goto error_malloc_cluster;
|
||||
}
|
||||
|
||||
hexagram_thermo_draw_needle(&cluster->thermo, cr,
|
||||
cluster->state.temp);
|
||||
hexagram_cluster_init(cluster, rpm_min, rpm_redline, rpm_max);
|
||||
|
||||
hexagram_fuel_draw_needle(&cluster->fuel, cr,
|
||||
cluster->state.fuel);
|
||||
return cluster;
|
||||
|
||||
error_malloc_cluster:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void hexagram_cluster_destroy(hexagram_cluster *cluster) {
|
||||
hexagram_cluster_cleanup(cluster);
|
||||
free(cluster);
|
||||
}
|
||||
|
||||
void hexagram_cluster_draw_bg(hexagram_cluster *cluster, cairo_t *cr) {
|
||||
int i;
|
||||
|
||||
cairo_set_source_rgb(cr, 0.1, 0.1, 0.1);
|
||||
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, CLUSTER_HEIGHT);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, CLUSTER_HEIGHT);
|
||||
hexagram_pattern_fill(&cluster->pattern,
|
||||
cr,
|
||||
hexagon_pattern_matrix,
|
||||
hexagon_pattern_scale);
|
||||
|
||||
/* Top dark area */
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
|
||||
cairo_rectangle(cr, 0, 0, CLUSTER_WIDTH, SECTION_HEIGHT_TOP);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_set_source_rgba(cr, 1, 1, 1, 0.25);
|
||||
cairo_move_to(cr, 0, SECTION_HEIGHT_TOP);
|
||||
cairo_line_to(cr, CLUSTER_WIDTH, SECTION_HEIGHT_TOP);
|
||||
cairo_stroke(cr);
|
||||
|
||||
/* Bottom dark area */
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 0.5);
|
||||
cairo_rectangle(cr,
|
||||
0,
|
||||
CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM,
|
||||
CLUSTER_WIDTH,
|
||||
SECTION_HEIGHT_BOTTOM);
|
||||
cairo_fill(cr);
|
||||
|
||||
cairo_set_source_rgba(cr, 1, 1, 1, 0.25);
|
||||
cairo_move_to(cr, 0, CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM);
|
||||
cairo_line_to(cr, CLUSTER_WIDTH, CLUSTER_HEIGHT - SECTION_HEIGHT_BOTTOM);
|
||||
cairo_stroke(cr);
|
||||
|
||||
for (i=0; i<HEXAGRAM_CLUSTER_GAUGE_COUNT; i++) {
|
||||
if (cluster->gauges[i]->draw_bg) {
|
||||
cluster->gauges[i]->draw_bg(cluster->gauges[i], cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void hexagram_cluster_draw_fg(hexagram_cluster *cluster, cairo_t *cr) {
|
||||
int i;
|
||||
|
||||
for (i=0; i<HEXAGRAM_CLUSTER_GAUGE_COUNT; i++) {
|
||||
if (cluster->gauges[i]->draw_fg) {
|
||||
cluster->gauges[i]->draw_fg(cluster->gauges[i], cr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
305
src/dial.c
Normal file
305
src/dial.c
Normal file
|
@ -0,0 +1,305 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <hexagram/dial.h>
|
||||
|
||||
#define RAD (M_PI / 180.0)
|
||||
#define ANGLE_OFFSET (M_PI / 2.0)
|
||||
|
||||
#define DIAL_MAIN_BEZEL_WIDTH 16
|
||||
|
||||
#define DIAL_MAIN_MARK_RADIUS_MIN
|
||||
#define DIAL_MAIN_MARK_RADIUS_MAX
|
||||
|
||||
static inline double _min(double a, double b) {
|
||||
return a < b?
|
||||
a: b;
|
||||
}
|
||||
|
||||
static cairo_pattern_t *gradient_create(hexagram_dial *dial) {
|
||||
const double stops[2][5] = {
|
||||
{ 0, 1.0, 0.4, 1.0, 1.0 },
|
||||
{ 1, 0.4, 0.0, 0.4, 0.0 }
|
||||
};
|
||||
|
||||
cairo_pattern_t *pattern;
|
||||
|
||||
size_t i;
|
||||
|
||||
if ((pattern = cairo_pattern_create_linear(dial->gauge.x - dial->radius,
|
||||
dial->gauge.y - dial->radius,
|
||||
dial->gauge.x + dial->radius,
|
||||
dial->gauge.y + dial->radius)) == NULL) {
|
||||
goto error_cairo_pattern_create_linear;
|
||||
}
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
cairo_pattern_add_color_stop_rgba(pattern,
|
||||
stops[i][0],
|
||||
stops[i][1],
|
||||
stops[i][2],
|
||||
stops[i][3],
|
||||
stops[i][4]);
|
||||
}
|
||||
|
||||
return pattern;
|
||||
|
||||
error_cairo_pattern_create_linear:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int main_draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_dial *dial = (hexagram_dial *)gauge;
|
||||
|
||||
double arc[5] = {
|
||||
dial->gauge.x,
|
||||
dial->gauge.y,
|
||||
dial->radius - DIAL_MAIN_BEZEL_WIDTH,
|
||||
0,
|
||||
2.0 * M_PI
|
||||
};
|
||||
|
||||
/* Gauge face */
|
||||
cairo_set_source_rgba(cr, 0, 0, 0, 1);
|
||||
cairo_arc(cr, arc[0], arc[1], arc[2], arc[3], arc[4]);
|
||||
cairo_fill(cr);
|
||||
|
||||
/* Gauge bezel */
|
||||
cairo_set_source(cr, dial->gradient);
|
||||
cairo_set_line_width(cr, DIAL_MAIN_BEZEL_WIDTH);
|
||||
cairo_arc(cr, arc[0], arc[1], arc[2], arc[3], arc[4]);
|
||||
cairo_stroke(cr);
|
||||
|
||||
/* Gauge centre bezel */
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
cairo_set_line_width(cr, DIAL_MAIN_BEZEL_WIDTH / 3.0);
|
||||
cairo_arc(cr, dial->gauge.x, dial->gauge.y, dial->radius / 2, 0, 2.0 * M_PI);
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int main_draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_dial *dial = (hexagram_dial *)gauge;
|
||||
|
||||
double angle = hexagram_dial_angle(dial, dial->value);
|
||||
|
||||
cairo_set_line_width(cr, dial->radius * 0.375);
|
||||
cairo_set_source_rgba(cr, 1, 0.4, 1, 0.25);
|
||||
|
||||
cairo_arc(cr,
|
||||
dial->gauge.x,
|
||||
dial->gauge.y,
|
||||
dial->radius * 0.713,
|
||||
dial->min_angle - ANGLE_OFFSET - RAD * 1.5,
|
||||
angle);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
hexagram_dial_draw_needle(dial, cr, 0.5, 0.89, dial->value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bottom_draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_dial *dial = (hexagram_dial *)gauge;
|
||||
|
||||
cairo_set_line_width(cr, 24);
|
||||
cairo_set_source_rgb(cr, 0.2, 0.2, 0.2);
|
||||
|
||||
cairo_arc(cr,
|
||||
dial->gauge.x,
|
||||
dial->gauge.y,
|
||||
dial->radius - 36,
|
||||
dial->min_angle - ANGLE_OFFSET - 4 * RAD,
|
||||
dial->max_angle - ANGLE_OFFSET + 4 * RAD);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bottom_draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_dial *dial = (hexagram_dial *)gauge;
|
||||
|
||||
double min_radius = 0.8,
|
||||
max_radius = 0.9;
|
||||
|
||||
return hexagram_dial_draw_needle(dial, cr, min_radius, max_radius, dial->value);
|
||||
}
|
||||
|
||||
int hexagram_dial_init(hexagram_dial *dial,
|
||||
hexagram_dial_type type,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double min_angle,
|
||||
double max_angle,
|
||||
double min_value,
|
||||
double max_value) {
|
||||
dial->gauge.x = x;
|
||||
dial->gauge.y = y;
|
||||
dial->type = type;
|
||||
dial->radius = radius;
|
||||
dial->min_angle = min_angle;
|
||||
dial->max_angle = max_angle;
|
||||
dial->min_value = min_value;
|
||||
dial->max_value = max_value;
|
||||
|
||||
dial->needle_min_radius = 0;
|
||||
dial->needle_max_radius = 0;
|
||||
|
||||
dial->mark_min_radius = 0;
|
||||
dial->mark_max_radius = 0;
|
||||
|
||||
dial->value = min_value;
|
||||
|
||||
switch (type) {
|
||||
case HEXAGRAM_DIAL_MAIN:
|
||||
if ((dial->gradient = gradient_create(dial)) == NULL) {
|
||||
goto error_gradient_create;
|
||||
}
|
||||
|
||||
dial->gauge.draw_bg = main_draw_bg;
|
||||
dial->gauge.draw_fg = main_draw_fg;
|
||||
|
||||
break;
|
||||
|
||||
case HEXAGRAM_DIAL_BOTTOM:
|
||||
dial->gradient = NULL;
|
||||
|
||||
dial->gauge.draw_bg = bottom_draw_bg;
|
||||
dial->gauge.draw_fg = bottom_draw_fg;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_gradient_create:
|
||||
return -1;
|
||||
}
|
||||
|
||||
double hexagram_dial_angle(hexagram_dial *dial, double value) {
|
||||
double adj_max = dial->max_value - dial->min_value,
|
||||
adj = _min(adj_max, value - dial->min_value);
|
||||
|
||||
double angle = dial->min_angle +
|
||||
(dial->max_angle - dial->min_angle) * (adj / adj_max) - ANGLE_OFFSET;
|
||||
|
||||
switch (dial->type) {
|
||||
case HEXAGRAM_DIAL_MAIN:
|
||||
return angle;
|
||||
|
||||
case HEXAGRAM_DIAL_BOTTOM:
|
||||
return (dial->max_angle - angle) + dial->min_angle + M_PI;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_legend(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
char *text) {
|
||||
double angle = hexagram_dial_angle(dial, value);
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
cairo_text_extents(cr, text, &extents);
|
||||
|
||||
cairo_move_to(cr,
|
||||
dial->gauge.x + radius * dial->radius * cos(angle) - extents.width / 1.5,
|
||||
dial->gauge.y + radius * dial->radius * sin(angle) + extents.height / 4);
|
||||
|
||||
cairo_show_text(cr, text);
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_legend_offset(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
char *text,
|
||||
double x_offset,
|
||||
double y_offset) {
|
||||
double angle = hexagram_dial_angle(dial, value);
|
||||
|
||||
cairo_move_to(cr,
|
||||
dial->gauge.x + radius * dial->radius * cos(angle) + x_offset,
|
||||
dial->gauge.y + radius * dial->radius * sin(angle) + y_offset);
|
||||
|
||||
cairo_show_text(cr, text);
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_mark(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value) {
|
||||
double angle = hexagram_dial_angle(dial, value);
|
||||
|
||||
cairo_move_to(cr,
|
||||
dial->gauge.x + min_radius * dial->radius * cos(angle),
|
||||
dial->gauge.y + min_radius * dial->radius * sin(angle));
|
||||
|
||||
cairo_line_to(cr,
|
||||
dial->gauge.x + max_radius * dial->radius * cos(angle),
|
||||
dial->gauge.y + max_radius * dial->radius * sin(angle));
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_needle(hexagram_dial *dial,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value) {
|
||||
double angle = hexagram_dial_angle(dial, value);
|
||||
|
||||
cairo_set_source_rgba(cr, 1, 0.4, 1, 0.75);
|
||||
cairo_set_line_width(cr, 8);
|
||||
|
||||
cairo_move_to(cr,
|
||||
dial->gauge.x + min_radius * dial->radius * cos(angle),
|
||||
dial->gauge.y + min_radius * dial->radius * sin(angle));
|
||||
|
||||
cairo_line_to(cr,
|
||||
dial->gauge.x + (max_radius * dial->radius) * cos(angle),
|
||||
dial->gauge.y + (max_radius * dial->radius) * sin(angle));
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_bg(hexagram_dial *dial, cairo_t *cr) {
|
||||
switch (dial->type) {
|
||||
case HEXAGRAM_DIAL_MAIN:
|
||||
return main_draw_bg(&dial->gauge, cr);
|
||||
|
||||
case HEXAGRAM_DIAL_BOTTOM:
|
||||
return bottom_draw_bg(&dial->gauge, cr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_dial_draw_fg(hexagram_dial *dial, cairo_t *cr) {
|
||||
switch (dial->type) {
|
||||
case HEXAGRAM_DIAL_MAIN:
|
||||
return main_draw_fg(&dial->gauge, cr);
|
||||
|
||||
case HEXAGRAM_DIAL_BOTTOM:
|
||||
return bottom_draw_fg(&dial->gauge, cr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
133
src/fuel.c
133
src/fuel.c
|
@ -1,88 +1,87 @@
|
|||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/fuel.h>
|
||||
|
||||
void hexagram_fuel_init(hexagram_fuel *fuel,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline) {
|
||||
hexagram_gauge_init(&fuel->gauge, x, y, radius,
|
||||
300.0 * (M_PI / 180.0),
|
||||
420.0 * (M_PI / 180.0));
|
||||
#define RAD (M_PI / 180.0)
|
||||
|
||||
fuel->redline = redline;
|
||||
}
|
||||
#define LEVEL_MIN 0
|
||||
#define LEVEL_WARN 2
|
||||
#define LEVEL_MAX 15
|
||||
|
||||
void hexagram_fuel_draw_face(hexagram_fuel *fuel,
|
||||
cairo_t *cr) {
|
||||
int i;
|
||||
#define ANGLE_MIN (144.0 * RAD)
|
||||
#define ANGLE_MAX (216.0 * RAD)
|
||||
|
||||
#define FONT_FACE "Muli"
|
||||
|
||||
static int draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_fuel *fuel = (hexagram_fuel *)gauge;
|
||||
int level;
|
||||
|
||||
if (hexagram_dial_draw_bg(&fuel->dial, cr) < 0) {
|
||||
goto error_dial_draw_bg;
|
||||
}
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
FONT_FACE,
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_font_size(cr, fuel->dial.radius * 0.1);
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 0, 0);
|
||||
hexagram_dial_draw_legend_offset(&fuel->dial, cr, 0.75, 0, "0", -5, 5);
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
hexagram_dial_draw_legend_offset(&fuel->dial, cr, 0.75, fuel->dial.max_value, "1", -10, 5);
|
||||
|
||||
cairo_arc(cr,
|
||||
fuel->gauge.x,
|
||||
fuel->gauge.y,
|
||||
fuel->gauge.radius,
|
||||
0,
|
||||
2.0 * M_PI);
|
||||
cairo_set_line_width(cr, 6.0);
|
||||
|
||||
cairo_stroke(cr);
|
||||
for (level=0; level<=LEVEL_MAX; level++) {
|
||||
double min_radius;
|
||||
|
||||
cairo_move_to(cr,
|
||||
fuel->gauge.x - 0.8 * fuel->gauge.radius,
|
||||
fuel->gauge.y - 0.1 * fuel->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "0");
|
||||
|
||||
cairo_move_to(cr,
|
||||
fuel->gauge.x - 0.15 * fuel->gauge.radius,
|
||||
fuel->gauge.y - 0.50 * fuel->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "1/2");
|
||||
|
||||
cairo_move_to(cr,
|
||||
fuel->gauge.x + 0.65 * fuel->gauge.radius,
|
||||
fuel->gauge.y - 0.10 * fuel->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "1");
|
||||
|
||||
/*
|
||||
* Draw gauge graduations
|
||||
*/
|
||||
for (i=0; i<=16; i++) {
|
||||
double min_radius = (i <= 4)?
|
||||
(i % 2? 0.8: 0.7):
|
||||
(i % 4? 0.8: 0.7);
|
||||
|
||||
if (i <= (16.0 * fuel->redline)) {
|
||||
if (level < 2) {
|
||||
min_radius = 0.84;
|
||||
cairo_set_source_rgb(cr, 1, 0, 0);
|
||||
} else if (level < 4) {
|
||||
min_radius = 0.82;
|
||||
cairo_set_source_rgb(cr, 1, 0, 0);
|
||||
} else {
|
||||
min_radius = 0.82;
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_mark(&fuel->gauge,
|
||||
cr,
|
||||
min_radius,
|
||||
0.9,
|
||||
(double)i / 16.0);
|
||||
}
|
||||
}
|
||||
|
||||
void hexagram_fuel_draw_needle(hexagram_fuel *fuel,
|
||||
cairo_t *cr,
|
||||
double level) {
|
||||
if (level < 0.0) {
|
||||
level = 0.0;
|
||||
} else if (level > 1.0) {
|
||||
level = 1.0;
|
||||
hexagram_dial_draw_mark(&fuel->dial, cr, min_radius, 0.87, level);
|
||||
}
|
||||
|
||||
cairo_stroke(cr);
|
||||
return 0;
|
||||
|
||||
hexagram_gauge_draw_needle(&fuel->gauge,
|
||||
cr,
|
||||
0.9,
|
||||
level);
|
||||
error_dial_draw_bg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hexagram_fuel_init(hexagram_fuel *fuel,
|
||||
double x,
|
||||
double y,
|
||||
double radius) {
|
||||
if (hexagram_dial_init(&fuel->dial,
|
||||
HEXAGRAM_DIAL_BOTTOM,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
ANGLE_MIN,
|
||||
ANGLE_MAX,
|
||||
LEVEL_MIN,
|
||||
LEVEL_MAX) < 0) {
|
||||
goto error_dial_init;
|
||||
}
|
||||
|
||||
fuel->dial.gauge.draw_bg = draw_bg;
|
||||
fuel->dial.value = LEVEL_MIN;
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_init:
|
||||
return -1;
|
||||
}
|
||||
|
|
85
src/gauge.c
85
src/gauge.c
|
@ -6,87 +6,10 @@
|
|||
void hexagram_gauge_init(hexagram_gauge *gauge,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double min_angle,
|
||||
double max_angle) {
|
||||
hexagram_gauge_draw_callback *draw_bg,
|
||||
hexagram_gauge_draw_callback *draw_fg) {
|
||||
gauge->x = x;
|
||||
gauge->y = y;
|
||||
gauge->radius = radius;
|
||||
gauge->min_angle = min_angle;
|
||||
gauge->max_angle = max_angle;
|
||||
}
|
||||
|
||||
void hexagram_gauge_draw_number(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value,
|
||||
const char *text) {
|
||||
double angle = gauge->min_angle
|
||||
+ ((gauge->max_angle - gauge->min_angle) * value) - 1.658;
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
|
||||
cairo_move_to(cr,
|
||||
gauge->x + (radius * gauge->radius) * cos(angle),
|
||||
gauge->y + (radius * gauge->radius) * sin(angle));
|
||||
|
||||
cairo_save(cr);
|
||||
cairo_rotate(cr, angle + 1.658);
|
||||
cairo_show_text(cr, text);
|
||||
cairo_stroke(cr);
|
||||
cairo_restore(cr);
|
||||
}
|
||||
|
||||
void hexagram_gauge_draw_mark(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double min_radius,
|
||||
double max_radius,
|
||||
double value) {
|
||||
double angle = gauge->min_angle
|
||||
+ ((gauge->max_angle - gauge->min_angle) * value) - (M_PI / 2.0);
|
||||
|
||||
cairo_move_to(cr,
|
||||
gauge->x + (min_radius * gauge->radius) * cos(angle),
|
||||
gauge->y + (min_radius * gauge->radius) * sin(angle));
|
||||
|
||||
cairo_line_to(cr,
|
||||
gauge->x + (max_radius * gauge->radius) * cos(angle),
|
||||
gauge->y + (max_radius * gauge->radius) * sin(angle));
|
||||
|
||||
cairo_stroke(cr);
|
||||
}
|
||||
|
||||
void hexagram_gauge_draw_needle(hexagram_gauge *gauge,
|
||||
cairo_t *cr,
|
||||
double radius,
|
||||
double value) {
|
||||
double angle = gauge->min_angle
|
||||
+ ((gauge->max_angle - gauge->min_angle) * value) - (M_PI / 2.0);
|
||||
|
||||
/*
|
||||
* Draw the gauge pivot
|
||||
*/
|
||||
cairo_set_source_rgb(cr, 0.4, 0.4, 0.4);
|
||||
|
||||
cairo_arc(cr,
|
||||
gauge->x,
|
||||
gauge->y,
|
||||
gauge->radius * 0.08,
|
||||
0,
|
||||
2.0 * M_PI);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
/*
|
||||
* Draw the needle above the pivot
|
||||
*/
|
||||
cairo_move_to(cr, gauge->x, gauge->y);
|
||||
|
||||
cairo_set_source_rgb(cr, 0, 0.25, 1.0);
|
||||
|
||||
cairo_line_to(cr,
|
||||
gauge->x + (radius * gauge->radius) * cos(angle),
|
||||
gauge->y + (radius * gauge->radius) * sin(angle));
|
||||
|
||||
cairo_stroke(cr);
|
||||
gauge->draw_bg = draw_bg;
|
||||
gauge->draw_fg = draw_fg;
|
||||
}
|
||||
|
|
151
src/icon.c
Normal file
151
src/icon.c
Normal file
|
@ -0,0 +1,151 @@
|
|||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <hexagram/svg.h>
|
||||
#include <hexagram/icon.h>
|
||||
|
||||
#define ICON_DIR_COUNT 3
|
||||
|
||||
static const char *icon_dirs[ICON_DIR_COUNT] = {
|
||||
"./icons",
|
||||
"/usr/local/share/hexagram/icons",
|
||||
"/usr/share/hexagram/icons"
|
||||
};
|
||||
|
||||
static const char *icon_colors[HEXAGRAM_ICON_COLOR_COUNT] = {
|
||||
"#f00", "#fa0", "#ff0", "#0f0", "#00f", "#fff"
|
||||
};
|
||||
|
||||
static cairo_surface_t *load_to_surface(const char *path,
|
||||
const char *style_format,
|
||||
const char *color,
|
||||
double width,
|
||||
double height) {
|
||||
cairo_surface_t *surface;
|
||||
char *style;
|
||||
|
||||
if (asprintf(&style, style_format, color) < 0) {
|
||||
goto error_asprintf_style;
|
||||
}
|
||||
|
||||
if ((surface = hexagram_svg_render_to_image(path,
|
||||
width,
|
||||
height,
|
||||
style)) == NULL) {
|
||||
goto error_svg_render_to_image;
|
||||
}
|
||||
|
||||
free(style);
|
||||
|
||||
return surface;
|
||||
|
||||
error_svg_render_to_image:
|
||||
free(style);
|
||||
|
||||
error_asprintf_style:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hexagram_icon_init(hexagram_icon *icon, double width, double height) {
|
||||
char path[128];
|
||||
ssize_t i, c;
|
||||
|
||||
icon->width = width;
|
||||
icon->height = height;
|
||||
|
||||
for (c=0; c<HEXAGRAM_ICON_COLOR_COUNT; c++) {
|
||||
icon->surfaces[c] = NULL;
|
||||
}
|
||||
|
||||
for (i=0; i<ICON_DIR_COUNT; i++) {
|
||||
size_t len = strlen(icon_dirs[i]) + 1 + strlen(icon->name) + 5;
|
||||
struct stat st;
|
||||
|
||||
if (len > sizeof(path)) {
|
||||
errno = ENAMETOOLONG;
|
||||
|
||||
goto error_nametoolong;
|
||||
}
|
||||
|
||||
if (snprintf(path, len, "%s/%s.svg", icon_dirs[i], icon->name) < 0) {
|
||||
goto error_snprintf;
|
||||
}
|
||||
|
||||
if (stat(path, &st) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (c=0; c<HEXAGRAM_ICON_COLOR_COUNT; c++) {
|
||||
if (!icon->colors[c]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((icon->surfaces[c] = load_to_surface(path,
|
||||
icon->style_format,
|
||||
icon_colors[c],
|
||||
width,
|
||||
height)) == NULL) {
|
||||
goto error_load_to_surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_load_to_surface:
|
||||
error_snprintf:
|
||||
error_nametoolong:
|
||||
while (--c >= 0) {
|
||||
cairo_surface_destroy(icon->surfaces[c]);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_icon_cleanup(hexagram_icon *icon) {
|
||||
size_t c;
|
||||
|
||||
for (c=0; c<HEXAGRAM_ICON_COLOR_COUNT; c++) {
|
||||
if (icon->surfaces[c]) {
|
||||
cairo_surface_destroy(icon->surfaces[c]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int hexagram_icon_drawable(hexagram_icon *icon, int status) {
|
||||
int color;
|
||||
|
||||
for (color=0; color<HEXAGRAM_ICON_COLOR_COUNT; color++) {
|
||||
if (icon->colors[color] == status && icon->surfaces[color] != NULL) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_icon_draw(hexagram_icon *icon,
|
||||
cairo_t *cr,
|
||||
double x,
|
||||
double y,
|
||||
int status) {
|
||||
int color;
|
||||
|
||||
for (color=0; color<HEXAGRAM_ICON_COLOR_COUNT; color++) {
|
||||
if (icon->colors[color] == status && icon->surfaces[color] != NULL) {
|
||||
cairo_set_source_surface(cr, icon->surfaces[color], x, y);
|
||||
cairo_rectangle(cr, x, y, icon->width, icon->height);
|
||||
cairo_fill(cr);
|
||||
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
done:
|
||||
return 0;
|
||||
}
|
31
src/odo.c
Normal file
31
src/odo.c
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <hexagram/odo.h>
|
||||
|
||||
static ssize_t format_text(hexagram_text *text, char *buf, size_t len) {
|
||||
hexagram_odo *odo = (hexagram_odo *)text;
|
||||
|
||||
return snprintf(buf, len, "%.1f mi", odo->value);
|
||||
}
|
||||
|
||||
int hexagram_odo_init(hexagram_odo *odo,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_odo_units units) {
|
||||
if (hexagram_text_init(&odo->text,
|
||||
x,
|
||||
y,
|
||||
align,
|
||||
format_text) < 0) {
|
||||
goto error_text_init;
|
||||
}
|
||||
|
||||
odo->units = units;
|
||||
odo->value = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
error_text_init:
|
||||
return -1;
|
||||
}
|
286
src/path.c
Normal file
286
src/path.c
Normal file
|
@ -0,0 +1,286 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hexagram/path.h>
|
||||
|
||||
static inline int is_alpha(char c) {
|
||||
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
|
||||
}
|
||||
|
||||
static inline int is_num(char c) {
|
||||
return c >= '0' && c <= '9';
|
||||
}
|
||||
|
||||
static inline int is_num_start(char c) {
|
||||
return is_num(c) || c == '-';
|
||||
}
|
||||
|
||||
static inline int is_sep(char c) {
|
||||
return c == ',' || c == ' ' || c == '\t' || c == '\n';
|
||||
}
|
||||
|
||||
struct arg {
|
||||
ssize_t start, end;
|
||||
hexagram_path_arg_type type;
|
||||
char buf[32];
|
||||
};
|
||||
|
||||
struct command {
|
||||
char c;
|
||||
int stride, first, argc;
|
||||
double argv[8];
|
||||
};
|
||||
|
||||
static void horiz_to(cairo_t *cr, double x2) {
|
||||
double x1, y1;
|
||||
|
||||
cairo_get_current_point(cr, &x1, &y1);
|
||||
cairo_line_to(cr, x2, y1);
|
||||
}
|
||||
|
||||
static void rel_horiz_to(cairo_t *cr, double x2) {
|
||||
double x1, y1;
|
||||
|
||||
cairo_get_current_point(cr, &x1, &y1);
|
||||
cairo_line_to(cr, x1 + x2, y1);
|
||||
}
|
||||
|
||||
static void vert_to(cairo_t *cr, double y2) {
|
||||
double x1, y1;
|
||||
|
||||
cairo_get_current_point(cr, &x1, &y1);
|
||||
cairo_line_to(cr, x1, y2);
|
||||
}
|
||||
|
||||
static void rel_vert_to(cairo_t *cr, double y2) {
|
||||
double x1, y1;
|
||||
|
||||
cairo_get_current_point(cr, &x1, &y1);
|
||||
cairo_line_to(cr, x1, y1 + y2);
|
||||
}
|
||||
|
||||
static int command_init(struct command *cmd, char c) {
|
||||
memset(cmd, '\0', sizeof(*cmd));
|
||||
|
||||
switch (c) {
|
||||
case 'C': case 'c': cmd->stride = 6; break;
|
||||
case 'Q': case 'q':
|
||||
case 'S': case 's': cmd->stride = 4; break;
|
||||
case 'M': case 'm':
|
||||
case 'T': case 't':
|
||||
case 'L': case 'l': cmd->stride = 2; break;
|
||||
case 'H': case 'h':
|
||||
case 'V': case 'v': cmd->stride = 1; break;
|
||||
case 'Z': case 'z': cmd->stride = 0; break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
cmd->c = c;
|
||||
cmd->first = 1;
|
||||
cmd->argc = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int command_run(struct command *cmd, cairo_t *cr) {
|
||||
if (cmd->stride == 0) {
|
||||
if (cmd->argc > 0) {
|
||||
goto error;
|
||||
}
|
||||
} else if (cmd->argc % cmd->stride != 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch (cmd->c) {
|
||||
case 'M':
|
||||
if (cmd->first) {
|
||||
cairo_move_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
} else {
|
||||
cairo_line_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
if (cmd->first) {
|
||||
cairo_rel_move_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
} else {
|
||||
cairo_rel_line_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
cairo_line_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
cairo_rel_line_to(cr, cmd->argv[0], cmd->argv[1]);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
horiz_to(cr, cmd->argv[0]);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
rel_horiz_to(cr, cmd->argv[0]);
|
||||
break;
|
||||
|
||||
case 'V':
|
||||
vert_to(cr, cmd->argv[0]);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
rel_vert_to(cr, cmd->argv[0]);
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
cairo_curve_to(cr,
|
||||
cmd->argv[0], cmd->argv[1], cmd->argv[2],
|
||||
cmd->argv[3], cmd->argv[4], cmd->argv[5]);
|
||||
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
cairo_rel_curve_to(cr,
|
||||
cmd->argv[0], cmd->argv[1], cmd->argv[2],
|
||||
cmd->argv[3], cmd->argv[4], cmd->argv[5]);
|
||||
|
||||
break;
|
||||
|
||||
case 'Z': case 'z':
|
||||
cairo_close_path(cr);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void arg_init(struct arg *arg, size_t start, hexagram_path_arg_type type) {
|
||||
memset(arg, '\0', sizeof(*arg));
|
||||
|
||||
arg->start = start;
|
||||
arg->type = type;
|
||||
}
|
||||
|
||||
static int arg_end(struct arg *arg, struct command *cmd, size_t end, const char *buf, cairo_t *cr) {
|
||||
if (end - arg->start >= sizeof(arg->buf)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
strncpy(arg->buf, &buf[arg->start], end - arg->start);
|
||||
|
||||
cmd->argv[cmd->argc++] = atof(arg->buf);
|
||||
|
||||
if (cmd->argc == cmd->stride) {
|
||||
if (command_run(cmd, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
cmd->first = 0;
|
||||
cmd->argc = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hexagram_path_run(cairo_t *cr, const char *data, size_t len) {
|
||||
size_t i;
|
||||
hexagram_path_state state = HEXAGRAM_PATH_STATE_NONE;
|
||||
|
||||
struct command cmd = { .c = '\0', .argc = 0 };
|
||||
struct arg arg = { -1, -1, HEXAGRAM_PATH_ARG_NONE, "" };
|
||||
|
||||
for (i=0; i<len; i++) {
|
||||
char c = data[i];
|
||||
|
||||
switch (state) {
|
||||
case HEXAGRAM_PATH_STATE_NONE:
|
||||
if (is_alpha(c)) {
|
||||
command_init(&cmd, c);
|
||||
state = HEXAGRAM_PATH_STATE_COMMAND;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HEXAGRAM_PATH_STATE_COMMAND:
|
||||
if (is_alpha(c)) {
|
||||
if (command_run(&cmd, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
command_init(&cmd, c);
|
||||
} else if (is_num_start(c)) {
|
||||
arg_init(&arg, i, HEXAGRAM_PATH_ARG_INT);
|
||||
state = HEXAGRAM_PATH_STATE_ARG;
|
||||
} else if (c == '.') {
|
||||
arg_init(&arg, i, HEXAGRAM_PATH_ARG_FLOAT);
|
||||
state = HEXAGRAM_PATH_STATE_ARG;
|
||||
} else if (!is_sep(c)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case HEXAGRAM_PATH_STATE_ARG:
|
||||
if (is_alpha(c)) {
|
||||
if (arg_end(&arg, &cmd, i, data, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
command_init(&cmd, c);
|
||||
state = HEXAGRAM_PATH_STATE_COMMAND;
|
||||
} else if (is_num(c)) {
|
||||
arg.end = i;
|
||||
} else if (is_sep(c)) {
|
||||
if (arg_end(&arg, &cmd, i, data, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
state = HEXAGRAM_PATH_STATE_COMMAND;
|
||||
} else if (c == '-') {
|
||||
arg_init(&arg, i, HEXAGRAM_PATH_ARG_INT);
|
||||
} else if (c == '.') {
|
||||
if (arg.type == HEXAGRAM_PATH_ARG_FLOAT) {
|
||||
goto error;
|
||||
} else {
|
||||
arg.type = HEXAGRAM_PATH_ARG_FLOAT;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state == HEXAGRAM_PATH_STATE_ARG) {
|
||||
if (arg_end(&arg, &cmd, i, data, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
} else if (state == HEXAGRAM_PATH_STATE_COMMAND) {
|
||||
if (command_run(&cmd, cr) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
85
src/pattern.c
Normal file
85
src/pattern.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <hexagram/path.h>
|
||||
#include <hexagram/pattern.h>
|
||||
|
||||
int hexagram_pattern_init(hexagram_pattern *pattern,
|
||||
double width,
|
||||
double height,
|
||||
const double color[3],
|
||||
hexagram_pattern_op op,
|
||||
const char *pathdata,
|
||||
size_t len) {
|
||||
cairo_t *cr;
|
||||
|
||||
pattern->width = width;
|
||||
pattern->height = height;
|
||||
pattern->color[0] = color[0];
|
||||
pattern->color[1] = color[1];
|
||||
pattern->color[2] = color[2];
|
||||
|
||||
if ((pattern->surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
||||
width,
|
||||
height)) == NULL) {
|
||||
goto error_cairo_image_surface_create;
|
||||
}
|
||||
|
||||
if ((cr = cairo_create(pattern->surface)) == NULL) {
|
||||
goto error_cairo_create;
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(cr, color[0], color[1], color[2]);
|
||||
|
||||
if (hexagram_path_run(cr, pathdata, len) < 0) {
|
||||
goto error_path_run;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case HEXAGRAM_PATTERN_STROKE:
|
||||
cairo_stroke(cr);
|
||||
break;
|
||||
|
||||
case HEXAGRAM_PATTERN_FILL:
|
||||
cairo_fill(cr);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_destroy(cr);
|
||||
|
||||
return 0;
|
||||
|
||||
error_path_run:
|
||||
cairo_destroy(cr);
|
||||
|
||||
error_cairo_create:
|
||||
cairo_surface_destroy(pattern->surface);
|
||||
|
||||
error_cairo_image_surface_create:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_pattern_cleanup(hexagram_pattern *pattern) {
|
||||
cairo_surface_destroy(pattern->surface);
|
||||
}
|
||||
|
||||
void hexagram_pattern_fill(hexagram_pattern *pattern,
|
||||
cairo_t *cr,
|
||||
const double matrix[6],
|
||||
const double scale[2]) {
|
||||
cairo_matrix_t m;
|
||||
cairo_pattern_t *source;
|
||||
|
||||
cairo_matrix_init(&m,
|
||||
matrix[0], matrix[1], matrix[2],
|
||||
matrix[3], matrix[4], matrix[5]);
|
||||
|
||||
cairo_matrix_scale(&m, scale[0], scale[1]);
|
||||
|
||||
cairo_set_source_surface(cr, pattern->surface, 0, 0);
|
||||
|
||||
source = cairo_get_source(cr);
|
||||
cairo_pattern_set_matrix(source, &m);
|
||||
cairo_pattern_set_extend(source, CAIRO_EXTEND_REPEAT);
|
||||
|
||||
cairo_fill(cr);
|
||||
}
|
168
src/speedo.c
168
src/speedo.c
|
@ -4,74 +4,126 @@
|
|||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/speedo.h>
|
||||
|
||||
void hexagram_speedo_init(hexagram_speedo *speedo,
|
||||
#define SPEEDO_ANGLE_MIN 232.0 * (M_PI / 180.0)
|
||||
#define SPEEDO_ANGLE_MAX 488.0 * (M_PI / 180.0)
|
||||
|
||||
#define SPEEDO_FONT_FACE "Muli"
|
||||
|
||||
static int draw_text(hexagram_speedo *speedo,
|
||||
cairo_t *cr,
|
||||
double x,
|
||||
double y,
|
||||
double radius) {
|
||||
hexagram_gauge_init(&speedo->gauge, x, y, radius,
|
||||
232.0 * (M_PI / 180.0),
|
||||
488.0 * (M_PI / 180.0));
|
||||
const char *text,
|
||||
double size) {
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
SPEEDO_FONT_FACE,
|
||||
CAIRO_FONT_SLANT_ITALIC,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_font_size(cr, speedo->dial.radius * size);
|
||||
cairo_set_source_rgb(cr, 1, 0.4, 1);
|
||||
|
||||
cairo_text_extents(cr, text, &extents);
|
||||
|
||||
cairo_move_to(cr,
|
||||
x - extents.width / 2,
|
||||
y + extents.height / 4);
|
||||
|
||||
cairo_show_text(cr, text);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hexagram_speedo_draw_face(hexagram_speedo *speedo,
|
||||
cairo_t *cr) {
|
||||
int i;
|
||||
static int draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_speedo *speedo = (hexagram_speedo *)gauge;
|
||||
|
||||
cairo_select_font_face(cr, "Helvetica",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
int speed;
|
||||
|
||||
cairo_set_font_size(cr, speedo->gauge.radius * 0.125);
|
||||
if (hexagram_dial_draw_bg(&speedo->dial, cr) < 0) {
|
||||
goto error_dial_draw_bg;
|
||||
}
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
SPEEDO_FONT_FACE,
|
||||
CAIRO_FONT_SLANT_ITALIC,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_font_size(cr, speedo->dial.radius * 0.1);
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
|
||||
cairo_arc(cr,
|
||||
speedo->gauge.x,
|
||||
speedo->gauge.y,
|
||||
speedo->gauge.radius,
|
||||
for (speed=0; speed<=(int)speedo->dial.max_value; speed += 5) {
|
||||
double min_radius = speed % 10 == 0? 0.81: 0.82;
|
||||
|
||||
cairo_set_line_width(cr, speed % 10 == 0? 6.0: 2.0);
|
||||
hexagram_dial_draw_mark(&speedo->dial, cr, min_radius, 0.87, (double)speed);
|
||||
}
|
||||
|
||||
for (speed=0; speed<=(int)speedo->dial.max_value; speed += 20) {
|
||||
char buf[8];
|
||||
|
||||
if (snprintf(buf, 8, "%d", speed) < 0) {
|
||||
goto error_snprintf;
|
||||
}
|
||||
|
||||
hexagram_dial_draw_legend(&speedo->dial, cr, 0.68, speed, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_snprintf:
|
||||
error_dial_draw_bg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_speedo *speedo = (hexagram_speedo *)gauge;
|
||||
char buf[8];
|
||||
|
||||
if (hexagram_dial_draw_fg(&speedo->dial, cr) < 0) {
|
||||
goto error_dial_draw_fg;
|
||||
}
|
||||
|
||||
if (snprintf(buf, 8, "%d", (int)speedo->dial.value) < 0) {
|
||||
goto error_snprintf;
|
||||
}
|
||||
|
||||
draw_text(speedo, cr, gauge->x, gauge->y - speedo->dial.radius * 0.01, buf, 0.32);
|
||||
|
||||
draw_text(speedo, cr, gauge->x, gauge->y + speedo->dial.radius * 0.2, "mph", 0.1);
|
||||
|
||||
return 0;
|
||||
|
||||
error_snprintf:
|
||||
error_dial_draw_fg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hexagram_speedo_init(hexagram_speedo *speedo,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double max_value,
|
||||
hexagram_speedo_units units) {
|
||||
if (hexagram_dial_init(&speedo->dial,
|
||||
HEXAGRAM_DIAL_MAIN,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
SPEEDO_ANGLE_MIN,
|
||||
SPEEDO_ANGLE_MAX,
|
||||
0,
|
||||
2.0 * M_PI);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
/*
|
||||
* Draw face numbers
|
||||
*/
|
||||
for (i=0; i<=180; i+=20) {
|
||||
char text[5];
|
||||
|
||||
snprintf(text, 4, "%02d", i);
|
||||
|
||||
hexagram_gauge_draw_number(&speedo->gauge,
|
||||
cr,
|
||||
0.85,
|
||||
i / 180.0,
|
||||
text);
|
||||
max_value) < 0) {
|
||||
goto error_dial_init;
|
||||
}
|
||||
|
||||
for (i=0; i<=180; i+=2) {
|
||||
hexagram_gauge_draw_mark(&speedo->gauge,
|
||||
cr,
|
||||
(i % 10)? 0.75: 0.7,
|
||||
0.8,
|
||||
i / 180.0);
|
||||
}
|
||||
}
|
||||
|
||||
void hexagram_speedo_draw_needle(hexagram_speedo *speedo,
|
||||
cairo_t *cr,
|
||||
double rps) {
|
||||
double kph = (2.00152 * rps * 3600) / 1000.0,
|
||||
mph = kph * 0.621371;
|
||||
|
||||
if (mph < 0) {
|
||||
mph = 0;
|
||||
} else if (mph > HEXAGRAM_SPEEDO_MAX_MPH) {
|
||||
mph = HEXAGRAM_SPEEDO_MAX_MPH;
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_needle(&speedo->gauge,
|
||||
cr,
|
||||
0.8,
|
||||
mph / HEXAGRAM_SPEEDO_MAX_MPH);
|
||||
speedo->dial.gauge.draw_bg = draw_bg;
|
||||
speedo->dial.gauge.draw_fg = draw_fg;
|
||||
speedo->units = units;
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_init:
|
||||
return -1;
|
||||
}
|
||||
|
|
242
src/status.c
Normal file
242
src/status.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
#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;
|
||||
}
|
70
src/svg.c
Normal file
70
src/svg.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
#include <librsvg/rsvg.h>
|
||||
|
||||
#include <hexagram/svg.h>
|
||||
|
||||
int hexagram_svg_render_to_surface(const char *path,
|
||||
cairo_surface_t *surface,
|
||||
double width,
|
||||
double height,
|
||||
const char *style) {
|
||||
cairo_t *cr;
|
||||
RsvgHandle *svg;
|
||||
RsvgRectangle rect = {0, 0, width, height};
|
||||
GError *err = NULL;
|
||||
|
||||
if ((cr = cairo_create(surface)) == NULL) {
|
||||
goto error_cairo_create;
|
||||
}
|
||||
|
||||
if ((svg = rsvg_handle_new_from_file(path, &err)) == NULL) {
|
||||
goto error_rsvg_handle_new_from_file;
|
||||
}
|
||||
|
||||
if (style) {
|
||||
if (rsvg_handle_set_stylesheet(svg, (guint8 *)style, strlen(style), &err) != TRUE) {
|
||||
goto error_rsvg_handle_set_stylesheet;
|
||||
}
|
||||
}
|
||||
|
||||
if (rsvg_handle_render_layer(svg, cr, NULL, &rect, &err) != TRUE) {
|
||||
goto error_rsvg_handle_render_layer;
|
||||
}
|
||||
|
||||
g_object_unref(svg);
|
||||
cairo_destroy(cr);
|
||||
|
||||
return 0;
|
||||
|
||||
error_rsvg_handle_render_layer:
|
||||
error_rsvg_handle_set_stylesheet:
|
||||
g_object_unref(svg);
|
||||
|
||||
error_rsvg_handle_new_from_file:
|
||||
cairo_destroy(cr);
|
||||
|
||||
error_cairo_create:
|
||||
return -1;
|
||||
}
|
||||
|
||||
cairo_surface_t *hexagram_svg_render_to_image(const char *path,
|
||||
double width,
|
||||
double height,
|
||||
const char *style) {
|
||||
cairo_surface_t *surface;
|
||||
|
||||
if ((surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height)) == NULL) {
|
||||
goto error_cairo_image_surface_create;
|
||||
}
|
||||
|
||||
if (hexagram_svg_render_to_surface(path, surface, width, height, style) < 0) {
|
||||
goto error_render_to_surface;
|
||||
}
|
||||
|
||||
return surface;
|
||||
|
||||
error_render_to_surface:
|
||||
cairo_surface_destroy(surface);
|
||||
|
||||
error_cairo_image_surface_create:
|
||||
return NULL;
|
||||
}
|
313
src/tacho.c
313
src/tacho.c
|
@ -4,79 +4,274 @@
|
|||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/tacho.h>
|
||||
|
||||
void hexagram_tacho_init(hexagram_tacho *tacho,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline) {
|
||||
hexagram_gauge_init(&tacho->gauge,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
232.0 * (M_PI / 180.0),
|
||||
488.0 * (M_PI / 180.0));
|
||||
#define TACHO_ANGLE_MIN (232.0 * (M_PI / 180.0))
|
||||
#define TACHO_ANGLE_MAX (488.0 * (M_PI / 180.0))
|
||||
|
||||
tacho->redline = redline;
|
||||
}
|
||||
#define TACHO_INTERVAL_MARK 500
|
||||
#define TACHO_INTERVAL_LEGEND 1000
|
||||
|
||||
void hexagram_tacho_draw_face(hexagram_tacho *tacho,
|
||||
cairo_t *cr) {
|
||||
int i;
|
||||
#define TACHO_FONT_FACE_LEGEND "Muli"
|
||||
#define TACHO_FONT_FACE_GEAR "HEX:gon Bold Italic"
|
||||
|
||||
cairo_select_font_face(cr, "Helvetica",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
static int draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_tacho *tacho = (hexagram_tacho *)gauge;
|
||||
int rpm;
|
||||
|
||||
cairo_set_font_size(cr, tacho->gauge.radius * 0.125);
|
||||
if (hexagram_dial_draw_bg(&tacho->dial, cr) < 0) {
|
||||
goto error_dial_draw_bg;
|
||||
}
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
TACHO_FONT_FACE_LEGEND,
|
||||
CAIRO_FONT_SLANT_ITALIC,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_font_size(cr, tacho->dial.radius * 0.15);
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
|
||||
for (rpm=0; rpm<=(int)tacho->dial.max_value; rpm+=TACHO_INTERVAL_MARK) {
|
||||
double min_radius = (rpm % TACHO_INTERVAL_LEGEND) == 0? 0.81: 0.82;
|
||||
|
||||
if (rpm >= tacho->redline) {
|
||||
cairo_set_source_rgb(cr, 0.6, 0.1, 0.1);
|
||||
}
|
||||
|
||||
cairo_set_line_width(cr, (rpm % TACHO_INTERVAL_LEGEND) == 0? 6.0: 2.0);
|
||||
|
||||
hexagram_dial_draw_mark(&tacho->dial, cr, min_radius, 0.87, rpm);
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
|
||||
cairo_arc(cr,
|
||||
tacho->gauge.x,
|
||||
tacho->gauge.y,
|
||||
tacho->gauge.radius,
|
||||
for (rpm=0; rpm<=(int)tacho->dial.max_value; rpm+=TACHO_INTERVAL_LEGEND) {
|
||||
char buf[8];
|
||||
|
||||
if (rpm >= tacho->redline) {
|
||||
cairo_set_source_rgb(cr, 1.0, 0.1, 0.1);
|
||||
}
|
||||
|
||||
snprintf(buf, sizeof(buf), "%d", (int)(rpm / TACHO_INTERVAL_LEGEND));
|
||||
|
||||
hexagram_dial_draw_legend(&tacho->dial, cr, 0.675, rpm, buf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_draw_bg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int gear_text(hexagram_tacho *tacho, char *buf, size_t len) {
|
||||
const char *formats[3] = {
|
||||
"S%s",
|
||||
"M%s",
|
||||
"%s"
|
||||
};
|
||||
|
||||
const char *format;
|
||||
|
||||
if (tacho->gear < HEXAGRAM_TRANS_GEAR_S || tacho->gear > HEXAGRAM_TRANS_GEAR_10) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tacho->gear >= HEXAGRAM_TRANS_GEAR_1) {
|
||||
switch (tacho->shift_mode) {
|
||||
case HEXAGRAM_TRANS_SHIFT_SPORT:
|
||||
case HEXAGRAM_TRANS_SHIFT_RACE:
|
||||
format = formats[0];
|
||||
break;
|
||||
|
||||
case HEXAGRAM_TRANS_SHIFT_MANUAL:
|
||||
format = formats[1];
|
||||
break;
|
||||
|
||||
default:
|
||||
format = formats[2];
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
format = formats[2];
|
||||
}
|
||||
|
||||
return snprintf(buf, len, format, hexagram_trans_gear_str(tacho->gear));
|
||||
}
|
||||
|
||||
static int draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_tacho *tacho = (hexagram_tacho *)gauge;
|
||||
cairo_text_extents_t extents;
|
||||
char buf[8];
|
||||
|
||||
if (hexagram_dial_draw_fg(&tacho->dial, cr) < 0) {
|
||||
goto error_dial_draw_fg;
|
||||
}
|
||||
|
||||
if (gear_text(tacho, buf, sizeof(buf)) < 0) {
|
||||
goto error_gear_text;
|
||||
}
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
TACHO_FONT_FACE_GEAR,
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
|
||||
cairo_set_font_size(cr, tacho->dial.radius * 0.4);
|
||||
cairo_set_source_rgb(cr, 1, 0.4, 1);
|
||||
|
||||
cairo_text_extents(cr, buf, &extents);
|
||||
|
||||
cairo_move_to(cr,
|
||||
gauge->x - extents.width / 2,
|
||||
gauge->y + extents.height / 2);
|
||||
|
||||
cairo_show_text(cr, buf);
|
||||
|
||||
return 0;
|
||||
|
||||
error_gear_text:
|
||||
error_dial_draw_fg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hexagram_tacho_init(hexagram_tacho *tacho,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline,
|
||||
double max_rpm) {
|
||||
if (hexagram_dial_init(&tacho->dial,
|
||||
HEXAGRAM_DIAL_MAIN,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
TACHO_ANGLE_MIN,
|
||||
TACHO_ANGLE_MAX,
|
||||
0,
|
||||
2.0 * M_PI);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
/*
|
||||
* Draw face numbers
|
||||
*/
|
||||
for (i=0; i<=80; i+=10) {
|
||||
char text[4];
|
||||
|
||||
snprintf(text, 3, "%02d", i);
|
||||
|
||||
hexagram_gauge_draw_number(&tacho->gauge,
|
||||
cr,
|
||||
0.85,
|
||||
i / 80.0,
|
||||
text);
|
||||
max_rpm) < 0) {
|
||||
goto error_dial_init;
|
||||
}
|
||||
|
||||
for (i=0; i<=80; i++) {
|
||||
if (i * 100 >= tacho->redline) {
|
||||
cairo_set_source_rgb(cr, 1, 0, 0);
|
||||
}
|
||||
tacho->dial.gauge.draw_bg = draw_bg;
|
||||
tacho->dial.gauge.draw_fg = draw_fg;
|
||||
|
||||
hexagram_gauge_draw_mark(&tacho->gauge,
|
||||
cr,
|
||||
i % 5? 0.75: 0.7,
|
||||
0.8,
|
||||
i / 80.0);
|
||||
}
|
||||
tacho->redline = redline;
|
||||
tacho->shift_mode = HEXAGRAM_TRANS_SHIFT_NORMAL;
|
||||
tacho->gear = HEXAGRAM_TRANS_GEAR_N;
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_init:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_tacho_draw_needle(hexagram_tacho *tacho,
|
||||
#define LIGHT_LEVEL_COUNT 5
|
||||
#define LIGHT_WIDTH 48
|
||||
#define LIGHT_HEIGHT 12
|
||||
#define LIGHT_SPACING 8
|
||||
#define LIGHT_LOW 0.25
|
||||
|
||||
static double light_colors[LIGHT_LEVEL_COUNT][3] = {
|
||||
{ 0.0, 1.0, 0.0 },
|
||||
{ 0.6, 1.0, 0.0 },
|
||||
{ 1.0, 1.0, 0.0 },
|
||||
{ 1.0, 0.6, 0.0 },
|
||||
{ 1.0, 0.0, 0.0 }
|
||||
};
|
||||
|
||||
static int light_levels[LIGHT_LEVEL_COUNT][2] = {
|
||||
{ 0, 8 },
|
||||
{ 1, 7 },
|
||||
{ 2, 6 },
|
||||
{ 3, 5 },
|
||||
{ 4, 4 }
|
||||
};
|
||||
|
||||
static int shift_indicator_draw_level(hexagram_tacho_shift_indicator *shift,
|
||||
cairo_t *cr,
|
||||
double rpm) {
|
||||
if (rpm > 8000) {
|
||||
rpm = 8000;
|
||||
int level,
|
||||
int on) {
|
||||
int max_level = LIGHT_LEVEL_COUNT - 1;
|
||||
double r, g, b;
|
||||
int i;
|
||||
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
} else if (level >= max_level) {
|
||||
level = max_level;
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_needle(&tacho->gauge,
|
||||
cr,
|
||||
0.8,
|
||||
rpm / 8000);
|
||||
r = light_colors[level][0];
|
||||
g = light_colors[level][1];
|
||||
b = light_colors[level][2];
|
||||
|
||||
if (!on) {
|
||||
r *= LIGHT_LOW;
|
||||
g *= LIGHT_LOW;
|
||||
b *= LIGHT_LOW;
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(cr, r, g, b);
|
||||
|
||||
for (i=0; i<2; i++) {
|
||||
int l = light_levels[level][i];
|
||||
double x = l * (LIGHT_WIDTH + LIGHT_SPACING);
|
||||
|
||||
cairo_rectangle(cr,
|
||||
shift->gauge.x + x,
|
||||
shift->gauge.y,
|
||||
LIGHT_WIDTH,
|
||||
LIGHT_HEIGHT);
|
||||
|
||||
cairo_fill(cr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shift_indicator_draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_tacho_shift_indicator *shift = (hexagram_tacho_shift_indicator *)gauge;
|
||||
int level;
|
||||
|
||||
for (level=0; level<LIGHT_LEVEL_COUNT; level++) {
|
||||
shift_indicator_draw_level(shift, cr, level, 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shift_indicator_draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_tacho_shift_indicator *shift = (hexagram_tacho_shift_indicator *)gauge;
|
||||
|
||||
double adj = shift->rpm - shift->rpm_min,
|
||||
adj_max = shift->rpm_shift - shift->rpm_min;
|
||||
|
||||
int level = (int)((adj / adj_max) * LIGHT_LEVEL_COUNT),
|
||||
i;
|
||||
|
||||
if (shift->rpm < shift->rpm_min) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i=0; i<LIGHT_LEVEL_COUNT; i++) {
|
||||
shift_indicator_draw_level(shift, cr, i, level >= i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_tacho_shift_indicator_init(hexagram_tacho_shift_indicator *shift,
|
||||
double x,
|
||||
double y,
|
||||
double rpm_min,
|
||||
double rpm_shift) {
|
||||
hexagram_gauge_init(&shift->gauge,
|
||||
x,
|
||||
y,
|
||||
shift_indicator_draw_bg,
|
||||
shift_indicator_draw_fg);
|
||||
|
||||
shift->rpm_min = rpm_min;
|
||||
shift->rpm_shift = rpm_shift;
|
||||
shift->rpm = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
117
src/temp.c
Normal file
117
src/temp.c
Normal file
|
@ -0,0 +1,117 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hexagram/temp.h>
|
||||
#include <hexagram/status.h>
|
||||
|
||||
#define ICON_ID HEXAGRAM_STATUS_COLD
|
||||
#define ICON_NAME "cold"
|
||||
#define ICON_STYLE "path {stroke: %1$s; stroke-width: 8}"
|
||||
#define ICON_WIDTH 40
|
||||
#define ICON_HEIGHT 40
|
||||
#define ICON_PADDING 16
|
||||
|
||||
#define COLD 1
|
||||
#define COLD_THRESHOLD 4.0 /* °C */
|
||||
|
||||
static ssize_t format_text(hexagram_text *text, char *buf, size_t len) {
|
||||
hexagram_temp *temp = (hexagram_temp *)text;
|
||||
|
||||
return snprintf(buf, len, "%.1f°C", temp->value);
|
||||
}
|
||||
|
||||
static int draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_temp *temp = (hexagram_temp *)gauge;
|
||||
cairo_text_extents_t extents;
|
||||
double text_x_offset = 0.0;
|
||||
|
||||
if (temp->text.format_text(&temp->text, temp->text.buf, sizeof(temp->text.buf)) < 0) {
|
||||
goto error_format_text;
|
||||
}
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
HEXAGRAM_TEXT_FONT_FACE,
|
||||
HEXAGRAM_TEXT_FONT_SLANT,
|
||||
HEXAGRAM_TEXT_FONT_WEIGHT);
|
||||
|
||||
cairo_text_extents(cr, temp->text.buf, &extents);
|
||||
|
||||
if (temp->value <= COLD_THRESHOLD) {
|
||||
extents.width += ICON_WIDTH + ICON_PADDING;
|
||||
}
|
||||
|
||||
switch (temp->text.align) {
|
||||
case HEXAGRAM_TEXT_LEFT:
|
||||
break;
|
||||
|
||||
case HEXAGRAM_TEXT_MIDDLE:
|
||||
text_x_offset = gauge->x - extents.width / 2.0;
|
||||
break;
|
||||
|
||||
case HEXAGRAM_TEXT_RIGHT:
|
||||
text_x_offset = gauge->x - extents.width;
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
cairo_move_to(cr, text_x_offset, gauge->y);
|
||||
cairo_show_text(cr, temp->text.buf);
|
||||
|
||||
if (temp->value <= COLD_THRESHOLD) {
|
||||
int icon_y_offset = abs(ICON_HEIGHT - HEXAGRAM_TEXT_FONT_SIZE) * 2;
|
||||
|
||||
if (hexagram_icon_draw(&temp->icon,
|
||||
cr,
|
||||
text_x_offset + extents.width - ICON_WIDTH,
|
||||
gauge->y - icon_y_offset,
|
||||
COLD) < 0) {
|
||||
goto error_icon_draw;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_icon_draw:
|
||||
error_format_text:
|
||||
return -1;
|
||||
}
|
||||
|
||||
int hexagram_temp_init(hexagram_temp *temp,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_temp_units units) {
|
||||
if (hexagram_text_init(&temp->text,
|
||||
x,
|
||||
y,
|
||||
align,
|
||||
format_text) < 0) {
|
||||
goto error_text_init;
|
||||
}
|
||||
|
||||
memset(&temp->icon, '\0', sizeof(hexagram_icon));
|
||||
|
||||
temp->text.gauge.draw_fg = draw_fg;
|
||||
temp->icon.id = ICON_ID;
|
||||
temp->icon.name = ICON_NAME;
|
||||
temp->icon.style_format = ICON_STYLE;
|
||||
temp->icon.white = COLD;
|
||||
|
||||
if (hexagram_icon_init(&temp->icon, ICON_WIDTH, ICON_HEIGHT) < 0) {
|
||||
goto error_icon_init;
|
||||
}
|
||||
|
||||
temp->units = units;
|
||||
temp->value = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
error_icon_init:
|
||||
error_text_init:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_temp_cleanup(hexagram_temp *temp) {
|
||||
hexagram_icon_cleanup(&temp->icon);
|
||||
}
|
64
src/text.c
Normal file
64
src/text.c
Normal file
|
@ -0,0 +1,64 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <hexagram/text.h>
|
||||
|
||||
#define FONT_FACE "Muli"
|
||||
#define FONT_SLANT CAIRO_FONT_SLANT_NORMAL
|
||||
#define FONT_WEIGHT CAIRO_FONT_WEIGHT_BOLD
|
||||
#define FONT_SIZE 24
|
||||
|
||||
static int draw_fg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_text *text = (hexagram_text *)gauge;
|
||||
cairo_text_extents_t extents;
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
|
||||
cairo_select_font_face(cr,
|
||||
FONT_FACE,
|
||||
FONT_SLANT,
|
||||
FONT_WEIGHT);
|
||||
|
||||
text->format_text(text, text->buf, sizeof(text->buf));
|
||||
|
||||
cairo_set_font_size(cr, FONT_SIZE);
|
||||
|
||||
cairo_text_extents(cr, text->buf, &extents);
|
||||
|
||||
switch (text->align) {
|
||||
case HEXAGRAM_TEXT_LEFT:
|
||||
cairo_move_to(cr, text->gauge.x, text->gauge.y);
|
||||
break;
|
||||
|
||||
case HEXAGRAM_TEXT_MIDDLE:
|
||||
cairo_move_to(cr, text->gauge.x - extents.width / 2, text->gauge.y);
|
||||
break;
|
||||
|
||||
case HEXAGRAM_TEXT_RIGHT:
|
||||
cairo_move_to(cr, text->gauge.x - extents.width, text->gauge.y);
|
||||
break;
|
||||
}
|
||||
|
||||
cairo_show_text(cr, text->buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hexagram_text_init(hexagram_text *text,
|
||||
double x,
|
||||
double y,
|
||||
hexagram_text_align align,
|
||||
hexagram_text_format_callback *format_text) {
|
||||
hexagram_gauge_init(&text->gauge,
|
||||
x,
|
||||
y,
|
||||
NULL,
|
||||
draw_fg);
|
||||
|
||||
text->align = align;
|
||||
text->format_text = format_text;
|
||||
|
||||
memset(text->buf, '\0', sizeof(text->buf));
|
||||
|
||||
return 0;
|
||||
}
|
138
src/thermo.c
138
src/thermo.c
|
@ -3,93 +3,85 @@
|
|||
#include <hexagram/gauge.h>
|
||||
#include <hexagram/thermo.h>
|
||||
|
||||
void hexagram_thermo_init(hexagram_thermo *thermo,
|
||||
double x,
|
||||
double y,
|
||||
double radius,
|
||||
double redline) {
|
||||
hexagram_gauge_init(&thermo->gauge, x, y, radius,
|
||||
300.0 * (M_PI / 180.0),
|
||||
420.0 * (M_PI / 180.0));
|
||||
#define RAD (M_PI / 180.0)
|
||||
|
||||
thermo->redline = redline;
|
||||
}
|
||||
#define ANGLE_MIN (144.0 * RAD)
|
||||
#define ANGLE_MAX (216.0 * RAD)
|
||||
|
||||
void hexagram_thermo_draw_face(hexagram_thermo *thermo,
|
||||
cairo_t *cr) {
|
||||
#define LEVEL_MIN 48
|
||||
#define LEVEL_WARN 116
|
||||
#define LEVEL_MAX 127
|
||||
|
||||
#define FONT_FACE "Muli"
|
||||
|
||||
static int draw_bg(hexagram_gauge *gauge, cairo_t *cr) {
|
||||
hexagram_thermo *thermo = (hexagram_thermo *)gauge;
|
||||
double incr;
|
||||
int i;
|
||||
|
||||
cairo_select_font_face(cr, "Helvetica",
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_NORMAL);
|
||||
if (hexagram_dial_draw_bg(&thermo->dial, cr) < 0) {
|
||||
goto error_dial_draw_bg;
|
||||
}
|
||||
|
||||
cairo_set_font_size(cr, thermo->gauge.radius * 0.2);
|
||||
cairo_select_font_face(cr,
|
||||
FONT_FACE,
|
||||
CAIRO_FONT_SLANT_NORMAL,
|
||||
CAIRO_FONT_WEIGHT_BOLD);
|
||||
|
||||
cairo_set_font_size(cr, thermo->dial.radius * 0.1);
|
||||
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
hexagram_dial_draw_legend(&thermo->dial, cr, 0.75, thermo->dial.min_value, "C");
|
||||
|
||||
cairo_arc(cr,
|
||||
thermo->gauge.x,
|
||||
thermo->gauge.y,
|
||||
thermo->gauge.radius,
|
||||
0,
|
||||
2.0 * M_PI);
|
||||
|
||||
cairo_stroke(cr);
|
||||
|
||||
/*
|
||||
* Draw face numbers
|
||||
*/
|
||||
cairo_move_to(cr,
|
||||
thermo->gauge.x - 0.8 * thermo->gauge.radius,
|
||||
thermo->gauge.y - 0.1 * thermo->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "120");
|
||||
|
||||
cairo_move_to(cr,
|
||||
thermo->gauge.x - 0.15 * thermo->gauge.radius,
|
||||
thermo->gauge.y - 0.5 * thermo->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "190");
|
||||
|
||||
cairo_move_to(cr,
|
||||
thermo->gauge.x + 0.5 * thermo->gauge.radius,
|
||||
thermo->gauge.y - 0.1 * thermo->gauge.radius);
|
||||
|
||||
cairo_show_text(cr, "260");
|
||||
|
||||
/*
|
||||
* Draw gauge graduations
|
||||
*/
|
||||
for (i=0; i<=16; i++) {
|
||||
double min_radius = (i >= 14)?
|
||||
(i % 2? 0.8: 0.7):
|
||||
(i % 4? 0.8: 0.7);
|
||||
|
||||
if ((i * 8.23529411) + 120 >= thermo->redline) {
|
||||
cairo_set_source_rgb(cr, 1, 0, 0);
|
||||
hexagram_dial_draw_legend(&thermo->dial, cr, 0.75, thermo->dial.max_value, "H");
|
||||
|
||||
cairo_set_line_width(cr, 6.0);
|
||||
|
||||
incr = (thermo->dial.max_value - thermo->dial.min_value) / 8.0;
|
||||
|
||||
for (i=0; i<9; i++) {
|
||||
double level = thermo->dial.min_value + i * incr;
|
||||
|
||||
if (level >= LEVEL_WARN) {
|
||||
cairo_set_source_rgb(cr, 0.8, 0, 0);
|
||||
} else {
|
||||
cairo_set_source_rgb(cr, 1, 1, 1);
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_mark(&thermo->gauge,
|
||||
cr,
|
||||
min_radius,
|
||||
0.90,
|
||||
i / 16.0);
|
||||
hexagram_dial_draw_mark(&thermo->dial, cr, 0.83, 0.87, level);
|
||||
|
||||
level += incr;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_draw_bg:
|
||||
return -1;
|
||||
}
|
||||
|
||||
void hexagram_thermo_draw_needle(hexagram_thermo *thermo,
|
||||
cairo_t *cr,
|
||||
double temp) {
|
||||
double fahrenheit = temp * (9.0 / 5.0) + 32.0;
|
||||
|
||||
if (fahrenheit < 120) {
|
||||
fahrenheit = 120;
|
||||
} else if (fahrenheit > 260) {
|
||||
fahrenheit = 260;
|
||||
int hexagram_thermo_init(hexagram_thermo *thermo,
|
||||
double x,
|
||||
double y,
|
||||
double radius) {
|
||||
if (hexagram_dial_init(&thermo->dial,
|
||||
HEXAGRAM_DIAL_BOTTOM,
|
||||
x,
|
||||
y,
|
||||
radius,
|
||||
ANGLE_MIN,
|
||||
ANGLE_MAX,
|
||||
LEVEL_MIN,
|
||||
LEVEL_MAX) < 0) {
|
||||
goto error_dial_init;
|
||||
}
|
||||
|
||||
hexagram_gauge_draw_needle(&thermo->gauge,
|
||||
cr,
|
||||
0.9,
|
||||
(fahrenheit - 120) / 140.0);
|
||||
thermo->dial.gauge.draw_bg = draw_bg;
|
||||
thermo->dial.value = LEVEL_MIN;
|
||||
thermo->level_warn = LEVEL_WARN;
|
||||
|
||||
return 0;
|
||||
|
||||
error_dial_init:
|
||||
return -1;
|
||||
}
|
||||
|
|
28
src/trans.c
Normal file
28
src/trans.c
Normal file
|
@ -0,0 +1,28 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include <hexagram/trans.h>
|
||||
|
||||
char *hexagram_trans_gear_str(hexagram_trans_gear gear) {
|
||||
static char *gears[15] = {
|
||||
"S", "D", "P", "R", "N", "1", "2", "3", "4", "5",
|
||||
"6", "7", "8", "9", "10"
|
||||
};
|
||||
|
||||
if (gear < HEXAGRAM_TRANS_GEAR_S || gear > HEXAGRAM_TRANS_GEAR_10) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gears[gear + 4];
|
||||
}
|
||||
|
||||
char *hexagram_trans_shift_mode_str(hexagram_trans_shift_mode mode) {
|
||||
static char *modes[6] = {
|
||||
"normal", "comfort", "eco", "sport", "race", "manual"
|
||||
};
|
||||
|
||||
if (mode < HEXAGRAM_TRANS_SHIFT_NORMAL || mode > HEXAGRAM_TRANS_SHIFT_MANUAL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return modes[mode];
|
||||
}
|
Loading…
Add table
Reference in a new issue