hexagram/py/hexagram/tacho.py
2024-01-09 12:57:16 -05:00

156 lines
4.2 KiB
Python

import enum
import math
import cairo
from hexagram.gauge import Gauge
from hexagram.dial import Dial
from hexagram.trans import Gear, ShiftMode
class Tacho(Dial):
__slots__ = 'redline', 'gear', 'shift_mode',
MIN_ANGLE = 232.0 * (math.pi / 180.0)
MAX_ANGLE = 488.0 * (math.pi / 180.0)
FONT_FACE = "Muli"
def __init__(self, x: float, y: float, radius: float, redline: float, max_value: float):
super().__init__(x, y, radius, self.MIN_ANGLE, self.MAX_ANGLE, 0, max_value)
self.value = 0
self.redline = redline
self.gear: Gear = Gear.N
self.shift_mode: ShiftMode = ShiftMode.NORMAL
def draw_bg(self, cr: cairo.Context):
super().draw_bg(cr)
cr.select_font_face(self.FONT_FACE,
cairo.FontSlant.ITALIC,
cairo.FontWeight.BOLD)
cr.set_font_size(self.radius * 0.15)
cr.set_source_rgb(1, 1, 1)
for speed in range(0, int(self.max_value)+1, 500):
min_radius = 0.81 if speed % 1000 == 0 else 0.82
if speed >= self.redline:
cr.set_source_rgb(0.6, 0.1, 0.1)
cr.set_line_width(6.0 if speed % 1000 == 0 else 2.0)
self.draw_mark(cr, min_radius, 0.87, speed)
cr.set_source_rgb(1.0, 1.0, 1.0)
for speed in range(0, int(self.max_value)+1, 1000):
if speed >= self.redline:
cr.set_source_rgb(1.0, 0.1, 0.1)
self.draw_legend(cr, 0.675, speed, "%d" % int(speed / 1000))
def gear_text(self):
text = ''
if self.gear.value >= Gear.GEAR_1.value:
if self.shift_mode is ShiftMode.SPORT or self.shift_mode is ShiftMode.RACE:
text += 'S'
elif self.shift_mode is ShiftMode.MANUAL:
text += 'M'
text += str(self.gear)
return text
def draw_fg(self, cr: cairo.Context):
super().draw_fg(cr)
text = self.gear_text()
cr.select_font_face("HEX:gon Bold Italic")
cr.set_font_size(self.radius * 0.4)
cr.set_source_rgb(1, 0.4, 1)
extents = cr.text_extents(text)
width = extents[2] - extents[0]
height = extents[3] - extents[1]
cr.move_to(self.x - width / 2,
self.y + height / 4)
cr.show_text(text)
class ShiftIndicator(Gauge):
__slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max',
LIGHT_WIDTH = 48
LIGHT_HEIGHT = 12
LIGHT_SPACING = 8
LIGHT_LOW = 0.25
LIGHT_COLORS = (
(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),
)
LIGHT_LEVELS = (
(0, 8),
(1, 7),
(2, 6),
(3, 5),
(4,),
)
def __init__(self, x: float, y: float, rpm_min: float, rpm_redline: float, rpm_max: float):
self.value = 0
self.x = x
self.y = y
self.rpm_min = rpm_min
self.rpm_redline = rpm_redline
self.rpm_max = rpm_max
def draw_level(self, cr: cairo.Context, level: int, on: bool=False):
max_level = len(self.LIGHT_LEVELS) - 1
if level < 0:
level = 0
elif level >= max_level:
level = max_level
r, g, b = self.LIGHT_COLORS[level]
if not on:
r *= self.LIGHT_LOW
g *= self.LIGHT_LOW
b *= self.LIGHT_LOW
cr.set_source_rgb(r, g, b)
for i in self.LIGHT_LEVELS[level]:
x = i * (self.LIGHT_WIDTH + self.LIGHT_SPACING)
cr.rectangle(self.x + x,
self.y,
self.LIGHT_WIDTH,
self.LIGHT_HEIGHT)
cr.fill()
def draw_bg(self, cr: cairo.Context):
for level in range(0, len(self.LIGHT_LEVELS)):
self.draw_level(cr, level)
def draw_fg(self, cr: cairo.Context):
if self.value < self.rpm_min:
return
adj = self.value - self.rpm_min
adj_max = self.rpm_max - self.rpm_min
level = int((adj / adj_max) * len(self.LIGHT_LEVELS))
for l in range(0, len(self.LIGHT_LEVELS)):
self.draw_level(cr, l, level >= l)