hexagram/py/hexagram/status.py

328 lines
7.7 KiB
Python

import os
import enum
import cairo
from typing import Optional
from hexagram.gauge import Gauge
from hexagram.icon import Icon
class StatusIcon(Icon):
TYPE = enum.Enum
def __init__(self, width: float, height: float):
super().__init__(self.NAME, width, height, self.VARIANTS, self.STYLE)
class CautionStatus(enum.Enum):
OFF = 0
ON = 1
WARNING = 2
class CollisionStatus(enum.Enum):
OK = 0
DETECTED = 1
class CollisionIcon(StatusIcon):
TYPE = CollisionStatus
NAME = 'collision'
STYLE = 'path {stroke-width: 10px; stroke: %(s)s}'
VARIANTS = {
CollisionStatus.DETECTED: '#f00'
}
class FuelStatus(enum.Enum):
OK = 0
LOW = 1
FAULT = 2
class FuelIcon(StatusIcon):
TYPE = FuelStatus
NAME = 'fuel'
STYLE = '#g9 * {stroke: %(s)s} #path9 {fill: %(s)s}'
VARIANTS = {
FuelStatus.LOW: '#fa0',
FuelStatus.FAULT: '#f00'
}
class SeatBeltStatus(enum.Enum):
OK = 0
UNFASTENED = 1
FAULT = 2
class SeatBeltIcon(StatusIcon):
TYPE = SeatBeltStatus
NAME = 'belt'
STYLE = 'path {fill: %(s)s}'
VARIANTS = {
SeatBeltStatus.UNFASTENED: '#f00'
}
class CoolantStatus(enum.Enum):
OK = 0
LOW = 1
OVERHEAT = 2
FAULT = 3
class CoolantIcon(StatusIcon):
TYPE = CoolantStatus
NAME = 'coolant'
STYLE = 'path, circle, rect {fill: %(s)s} #g9 path {stroke: %(s)s}'
VARIANTS = {
CoolantStatus.LOW: '#fa0',
CoolantStatus.OVERHEAT: '#f00'
}
class OilStatus(enum.Enum):
OK = 0
LOW = 1
OVERHEAT = 2
FAULT = 3
class OilIcon(StatusIcon):
TYPE = OilStatus
NAME = 'oil'
STYLE ='path {fill: %(s)s; stroke: %(s)s}'
VARIANTS = {
OilStatus.LOW: '#fa0',
OilStatus.OVERHEAT: '#f00'
}
class ParkingBrakeStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class ParkingBrakeIcon(StatusIcon):
TYPE = ParkingBrakeStatus
NAME = 'parking'
STYLE = '#path6, #path5 {stroke: %(s)s} circle {stroke: %(s)s} #path7 {fill: %(s)s}'
VARIANTS = {
ParkingBrakeStatus.ON: '#fa0'
}
class WiperWasherStatus(enum.Enum):
OK = 0
LOW = 1
FAULT = 2
class WiperWasherIcon(StatusIcon):
TYPE = WiperWasherStatus
NAME = 'wiper-washer'
STYLE = 'rect,path,circle{stroke:%(s)s;}'
VARIANTS = {
WiperWasherStatus.LOW: '#fa0',
WiperWasherStatus.FAULT: '#f00'
}
class LaneKeepStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class LaneKeepIcon(StatusIcon):
TYPE = LaneKeepStatus
NAME = 'lane-departure'
STYLE = 'path {stroke: %(s)s; stroke-width: 8}'
VARIANTS = {
LaneKeepStatus.OFF: '#fa0',
LaneKeepStatus.ON: '#0f0',
LaneKeepStatus.FAULT: '#f00'
}
class StabilityControlStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class StabilityControlIcon(StatusIcon):
TYPE = StabilityControlStatus
NAME = 'stability'
STYLE = '#path9, #path8, #path7, #path6, #path5 {fill: %(s)s} #path10 {stroke: %(s)s}'
VARIANTS = {
StabilityControlStatus.OFF: '#fa0',
StabilityControlStatus.ON: '#0f0',
StabilityControlStatus.FAULT: '#f00'
}
class TractionControlFault(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class TPMSStatus(enum.Enum):
OK = 0
WARNING = 1
FAULT = 2
class TPMSIcon(StatusIcon):
TYPE = TPMSStatus
NAME = 'tpms'
STYLE = 'path, circle {fill: %(s)s}'
VARIANTS = {
TPMSStatus.WARNING: '#fa0',
TPMSStatus.FAULT: '#f00'
}
class ABSStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class AirbagStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class BatteryStatus(enum.Enum):
OK = 0
FAULT = 1
class BatteryIcon(StatusIcon):
TYPE = BatteryStatus
NAME = 'battery',
STYLE = '#rect5, #rect6 {fill: %(s)s} #rect4, path {stroke: %(s)s}'
VARIANTS = {
BatteryStatus.FAULT: '#f00'
}
class EngineStatus(enum.Enum):
OK = 0
FAULT = 1
class FogBeamStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class FogBeamIcon(StatusIcon):
TYPE = FogBeamStatus
NAME = 'beams-fog'
STYLE = '#g9 path {fill: %(s)s} #g5 path {stroke: %(s)s}'
VARIANTS = {
FogBeamStatus.ON: '#0f0',
FogBeamStatus.FAULT: '#f00'
}
class ParkingBeamStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class ParkingBeamIcon(StatusIcon):
TYPE = ParkingBeamStatus
NAME = 'beams-parking'
STYLE = 'path {stroke: %(s)s; stroke-width: 12}'
VARIANTS = {
ParkingBeamStatus.ON: '#ff0',
ParkingBeamStatus.FAULT: '#f00'
}
class LowBeamStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class LowBeamIcon(StatusIcon):
TYPE = LowBeamStatus
NAME = 'beams-low'
STYLE = 'path {fill: %(s)s; stroke: %(s)s}'
VARIANTS = {
LowBeamStatus.ON: '#0f0',
LowBeamStatus.FAULT: '#f00'
}
class HighBeamStatus(enum.Enum):
OFF = 0
ON = 1
FAULT = 2
class HighBeamIcon(StatusIcon):
TYPE = HighBeamStatus
NAME = 'beams-high'
STYLE = 'path {fill: %(s)s; stroke: %(s)s}'
VARIANTS = {
HighBeamStatus.ON: '#00f',
HighBeamStatus.FAULT: '#f00'
}
class ColdStatus(enum.Enum):
OFF = 0
ON = 1
class ColdIcon(StatusIcon):
TYPE = ColdStatus
NAME = 'cold'
STYLE = 'path {stroke: %(s)s;stroke-width: 8}'
VARIANTS = {
ColdStatus.ON: '#fff'
}
class StatusIconBox(Gauge):
__slots__ = 'x', 'y', 'width', 'height', 'surface', 'statuses', 'icons', \
'_redraw'
ICON_WIDTH = 48
ICON_HEIGHT = 48
ICONS = (
SeatBeltIcon, ParkingBeamIcon, LowBeamIcon, HighBeamIcon, FogBeamIcon, StabilityControlIcon, LaneKeepIcon,
ParkingBrakeIcon, FuelIcon, WiperWasherIcon, CoolantIcon, OilIcon, TPMSIcon, CollisionIcon
)
def __init__(self, x: float, y: float, width: float, height: float):
self.x = x
self.y = y
self.width = width
self.height = height
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(width), int(height))
self._redraw = False
self.statuses: dict[enum.EnumType, enum.Enum] = dict()
self.icons: dict[enum.EnumType, StatusIcon] = dict()
for icon_type in self.ICONS:
self.icons[icon_type.TYPE] = icon_type(self.ICON_WIDTH, self.ICON_HEIGHT)
def __del__(self):
self.surface.finish()
def draw_bg(self, cr: cairo.Context):
pass
def _update_surface(self):
cr = cairo.Context(self.surface)
cr.set_source_rgba(0, 0, 0, 0)
cr.set_operator(cairo.OPERATOR_SOURCE)
cr.rectangle(0, 0, self.width, self.height)
cr.fill()
x, y = 0, self.height - self.ICON_HEIGHT
for icon_type in self.ICONS:
typeof = icon_type.TYPE
status = self.statuses.get(typeof)
if status is not None:
icon = self.icons[typeof]
if icon.drawable(status):
icon.draw(cr, x, y, status)
x += self.ICON_WIDTH
if x >= self.width:
x = 0
y -= self.ICON_HEIGHT
def draw_fg(self, cr: cairo.Context):
if self._redraw:
self._update_surface()
self._redraw = False
cr.set_source_surface(self.surface, self.x, self.y)
cr.rectangle(self.x, self.y, self.width, self.height)
cr.fill()
def set(self, status: enum.Enum):
self.statuses[type(status)] = status
self._redraw = True