hexagram/py/hexagram/cluster.py

238 lines
6.5 KiB
Python
Raw Normal View History

import math
import cairo
2023-12-29 23:45:46 -05:00
from typing import Iterable, List
2023-12-31 19:12:19 -05:00
from hexagram.pattern import HexagonPattern
from hexagram.gauge import Gauge
from hexagram.dial import Dial
2023-12-31 19:12:19 -05:00
from hexagram.speedo import Speedo
2023-12-31 22:17:02 -05:00
from hexagram.tacho import Tacho
2024-01-01 01:47:56 -05:00
from hexagram.fuel import FuelGauge
2024-01-01 02:17:12 -05:00
from hexagram.thermo import ThermoGauge
2023-12-29 18:43:06 -05:00
class ShiftIndicator(Gauge):
__slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max',
2023-12-31 22:42:25 -05:00
2023-12-29 18:43:06 -05:00
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
2023-12-29 18:54:20 -05:00
self.x = x
self.y = y
self.rpm_min = rpm_min
2023-12-29 18:54:20 -05:00
self.rpm_redline = rpm_redline
self.rpm_max = rpm_max
2023-12-29 18:43:06 -05:00
def draw_level(self, cr: cairo.Context, level: int, on: bool=False):
r = self.LIGHT_COLORS[level][0]
g = self.LIGHT_COLORS[level][1]
b = self.LIGHT_COLORS[level][2]
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()
2023-12-29 18:43:06 -05:00
def draw_bg(self, cr: cairo.Context):
for level in range(0, len(self.LIGHT_LEVELS)):
self.draw_level(cr, level)
2023-12-29 18:43:06 -05:00
def draw_fg(self, cr: cairo.Context):
if self.value < self.rpm_min:
return
2023-12-29 18:43:06 -05:00
level = math.ceil((self.value - self.rpm_min) / self.rpm_redline)
2023-12-29 18:43:06 -05:00
for l in range(0, len(self.LIGHT_LEVELS)):
self.draw_level(cr, level, l >= level)
2023-12-29 18:43:06 -05:00
2024-01-01 23:37:56 -05:00
class Odometer(Gauge):
__slots__ = 'x', 'y',
def __init__(self, x: float, y: float):
self.value = 0
self.x = x
self.y = y
def draw_bg(self, cr: cairo.Context):
pass
def draw_fg(self, cr: cairo.Context):
cr.set_source_rgb(1, 1, 1)
cr.select_font_face("Muli",
cairo.FontSlant.NORMAL,
cairo.FontWeight.BOLD)
2024-01-01 23:54:25 -05:00
cr.set_font_size(24)
2024-01-01 23:37:56 -05:00
cr.move_to(self.x, self.y)
cr.show_text("%d mi" % self.value)
2024-01-01 23:44:04 -05:00
class AmbientTemp(Gauge):
__slots__ = 'x', 'y',
def __init__(self, x: float, y: float):
self.value = 0
self.x = x
self.y = y
def draw_bg(self, cr: cairo.Context):
pass
def draw_fg(self, cr: cairo.Context):
cr.set_source_rgb(1, 1, 1)
cr.select_font_face("Muli",
cairo.FontSlant.NORMAL,
cairo.FontWeight.BOLD)
2024-01-01 23:54:25 -05:00
cr.set_font_size(24)
2024-01-01 23:44:04 -05:00
cr.move_to(self.x, self.y)
cr.show_text("%.1f°C" % self.value)
2024-01-01 23:54:25 -05:00
class Clock(Gauge):
__slots__ = 'x', 'y',
def __init__(self, x: float, y: float):
self.value = 0
self.x = x
self.y = y
def draw_bg(self, cr: cairo.Context):
pass
def draw_fg(self, cr: cairo.Context):
cr.set_source_rgb(1, 1, 1)
cr.select_font_face("Muli",
cairo.FontSlant.NORMAL,
cairo.FontWeight.BOLD)
cr.set_font_size(24)
cr.move_to(self.x, self.y)
cr.show_text("%d:%02d" % (
(self.value - (self.value % 60)) / 60,
self.value % 60
))
2023-12-29 17:35:17 -05:00
class Cluster():
2024-01-01 23:54:25 -05:00
__slots__ = 'gauges', 'speedo', 'fuel', 'tacho', 'thermo', 'odo', \
'ambient', 'clock'
2023-12-29 17:35:17 -05:00
WIDTH = 1280
HEIGHT = 480
2023-12-29 18:43:06 -05:00
SHIFT_INDICATOR_X = 392
SHIFT_INDICATOR_Y = 24
def __init__(self, rpm_min: float, rpm_redline: float, rpm_max: float):
2023-12-29 23:45:46 -05:00
self.gauges: List[Gauge] = list()
2023-12-29 17:35:17 -05:00
2023-12-31 19:12:19 -05:00
self.speedo = Speedo(self.HEIGHT / 2,
self.HEIGHT / 2,
self.HEIGHT / 2,
2023-12-31 23:39:31 -05:00
200.0)
2023-12-31 19:12:19 -05:00
2024-01-01 02:17:12 -05:00
self.fuel = FuelGauge(self.HEIGHT / 2,
self.HEIGHT / 2,
self.HEIGHT / 2)
2023-12-31 22:17:02 -05:00
self.tacho = Tacho(self.WIDTH - self.HEIGHT / 2,
self.HEIGHT / 2,
self.HEIGHT / 2,
8000)
2023-12-31 19:12:19 -05:00
2024-01-01 02:17:12 -05:00
self.thermo = ThermoGauge(self.WIDTH - self.HEIGHT / 2,
self.HEIGHT / 2,
self.HEIGHT / 2)
2024-01-01 01:47:56 -05:00
2024-01-02 01:29:09 -05:00
self.odo = Odometer(0.8 * self.HEIGHT, self.HEIGHT - 16)
self.ambient = AmbientTemp(self.WIDTH - self.HEIGHT, self.HEIGHT - 16)
self.clock = Clock(self.WIDTH / 2 - 32, self.HEIGHT - 16)
2024-01-01 23:44:04 -05:00
2023-12-31 19:12:19 -05:00
self.gauges.append(self.speedo)
2024-01-01 01:47:56 -05:00
self.gauges.append(self.fuel)
2023-12-31 19:12:19 -05:00
self.gauges.append(self.tacho)
2024-01-01 02:17:12 -05:00
self.gauges.append(self.thermo)
2024-01-01 23:37:56 -05:00
self.gauges.append(self.odo)
2024-01-01 23:44:04 -05:00
self.gauges.append(self.ambient)
2024-01-01 23:54:25 -05:00
self.gauges.append(self.clock)
2023-12-29 18:43:06 -05:00
self.gauges.append(ShiftIndicator(self.SHIFT_INDICATOR_X,
self.SHIFT_INDICATOR_Y,
rpm_min,
2023-12-29 18:54:20 -05:00
rpm_redline,
rpm_max))
2023-12-29 17:35:17 -05:00
def draw_bg(self, cr: cairo.Context):
2023-12-31 18:39:54 -05:00
cr.set_source_rgb(0.1, 0.1, 0.1)
2023-12-30 01:23:50 -05:00
cr.rectangle(0, 0, self.WIDTH, self.HEIGHT)
cr.fill()
2023-12-30 01:22:49 -05:00
cr.rectangle(0, 0, self.WIDTH, self.HEIGHT)
2023-12-29 21:37:10 -05:00
2023-12-29 23:45:46 -05:00
pattern = HexagonPattern()
2023-12-30 01:22:49 -05:00
pattern.fill(cr)
2023-12-29 21:37:10 -05:00
2024-01-02 00:56:31 -05:00
# Top dark area
cr.set_source_rgba(0, 0, 0, 0.5)
2024-01-02 01:29:09 -05:00
cr.rectangle(0, 0, self.WIDTH, 64)
2024-01-02 00:56:31 -05:00
cr.fill()
cr.set_source_rgba(1, 1, 1, 0.25)
2024-01-02 01:29:09 -05:00
cr.move_to(0, 64)
cr.line_to(self.WIDTH, 64)
2024-01-02 00:56:31 -05:00
cr.stroke()
# Bottom dark area
cr.set_source_rgba(0, 0, 0, 0.5)
cr.rectangle(0, self.HEIGHT - 52, self.WIDTH, 52)
cr.fill()
cr.set_source_rgba(1, 1, 1, 0.25)
cr.move_to(0, self.HEIGHT - 52)
cr.line_to(self.WIDTH, self.HEIGHT - 52)
cr.stroke()
2023-12-29 17:35:17 -05:00
for gauge in self.gauges:
gauge.draw_bg(cr)
def draw_fg(self, cr: cairo.Context):
for gauge in self.gauges:
fn = getattr(gauge, 'draw_fg', None)
if fn is not None:
fn(cr)