Man this refactor has been hurting my head
This commit is contained in:
parent
a86461ac6b
commit
dac34a46a2
4 changed files with 329 additions and 141 deletions
|
@ -11,7 +11,7 @@ from hexagram.speedo import Speedo
|
||||||
from hexagram.tacho import Tacho
|
from hexagram.tacho import Tacho
|
||||||
from hexagram.fuel import FuelGauge
|
from hexagram.fuel import FuelGauge
|
||||||
from hexagram.thermo import Thermometer
|
from hexagram.thermo import Thermometer
|
||||||
from hexagram.status import VehicleStatus, StatusIcon, StatusIconBox
|
from hexagram.status import StatusIconBox, ColdStatus, ColdIcon
|
||||||
|
|
||||||
class ShiftIndicator(Gauge):
|
class ShiftIndicator(Gauge):
|
||||||
__slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max',
|
__slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max',
|
||||||
|
@ -100,7 +100,6 @@ class AmbientTemp(TextGauge):
|
||||||
ICON_WIDTH = 40
|
ICON_WIDTH = 40
|
||||||
ICON_HEIGHT = 40
|
ICON_HEIGHT = 40
|
||||||
ICON_PADDING = 16
|
ICON_PADDING = 16
|
||||||
ICON_COLOR = '#fff'
|
|
||||||
|
|
||||||
COLD_THRESHOLD = 4.0 # °C
|
COLD_THRESHOLD = 4.0 # °C
|
||||||
|
|
||||||
|
@ -108,12 +107,7 @@ class AmbientTemp(TextGauge):
|
||||||
super().__init__(x, y, -100, 100, align)
|
super().__init__(x, y, -100, 100, align)
|
||||||
|
|
||||||
self.value = 0
|
self.value = 0
|
||||||
self.icon = StatusIcon(VehicleStatus.COLD,
|
self.icon = ColdIcon(self.ICON_WIDTH, self.ICON_HEIGHT)
|
||||||
'cold',
|
|
||||||
self.ICON_WIDTH,
|
|
||||||
self.ICON_HEIGHT,
|
|
||||||
self.ICON_COLOR,
|
|
||||||
'path {stroke: %(s)s;stroke-width: 8}')
|
|
||||||
|
|
||||||
def format_text(self):
|
def format_text(self):
|
||||||
return "%.1f°C" % self.value
|
return "%.1f°C" % self.value
|
||||||
|
@ -149,7 +143,8 @@ class AmbientTemp(TextGauge):
|
||||||
|
|
||||||
self.icon.draw(cr,
|
self.icon.draw(cr,
|
||||||
text_x_offset + width - self.icon.width,
|
text_x_offset + width - self.icon.width,
|
||||||
self.y - icon_y_offset)
|
self.y - icon_y_offset,
|
||||||
|
ColdStatus.ON)
|
||||||
|
|
||||||
class Clock(TextGauge):
|
class Clock(TextGauge):
|
||||||
def __init__(self, x: float, y: float, align: Align):
|
def __init__(self, x: float, y: float, align: Align):
|
||||||
|
|
64
py/hexagram/icon.py
Normal file
64
py/hexagram/icon.py
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
import os
|
||||||
|
import enum
|
||||||
|
import cairo
|
||||||
|
|
||||||
|
from hexagram.svg import render_to_image
|
||||||
|
|
||||||
|
class Icon():
|
||||||
|
__slots__ = 'name', 'width', 'height', 'style', 'variants', \
|
||||||
|
'_path', '_surfaces',
|
||||||
|
|
||||||
|
__dirs__ = ('./icons',
|
||||||
|
'/usr/local/share/hexagram/icons'
|
||||||
|
'/usr/share/hexagram/icons')
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _locate(name: str):
|
||||||
|
for dir in Icon.__dirs__:
|
||||||
|
path = "%s/%s.svg" % (dir, name)
|
||||||
|
|
||||||
|
if os.path.exists(path):
|
||||||
|
return path
|
||||||
|
|
||||||
|
raise FileNotFoundError(name + '.svg')
|
||||||
|
|
||||||
|
STYLE = 'rect,path,circle{stroke:%(s)s;}'
|
||||||
|
|
||||||
|
def __init__(self, name: str, width: float, height: float, variants: dict, style: str=STYLE):
|
||||||
|
self.name = name
|
||||||
|
self.width = width
|
||||||
|
self.height = height
|
||||||
|
self.style = style
|
||||||
|
self.variants = variants
|
||||||
|
self._path = Icon._locate(name)
|
||||||
|
self._surfaces: dict[enum.Enum, cairo.ImageSurface] = dict()
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
for key in self._surfaces:
|
||||||
|
self._surfaces[key].finish()
|
||||||
|
|
||||||
|
def _surface(self, status) -> cairo.ImageSurface:
|
||||||
|
surface = self._surfaces.get(status)
|
||||||
|
|
||||||
|
if surface is not None:
|
||||||
|
return surface
|
||||||
|
|
||||||
|
color = self.variants[status]
|
||||||
|
surface = render_to_image(self._path,
|
||||||
|
self.width,
|
||||||
|
self.height,
|
||||||
|
self.style % {'s': color})
|
||||||
|
|
||||||
|
self._surfaces[status] = surface
|
||||||
|
|
||||||
|
return surface
|
||||||
|
|
||||||
|
def drawable(self, status: enum.Enum):
|
||||||
|
return status in self.variants
|
||||||
|
|
||||||
|
def draw(self, cr: cairo.Context, x: float, y: float, status):
|
||||||
|
surface = self._surface(status)
|
||||||
|
|
||||||
|
cr.set_source_surface(surface, x, y)
|
||||||
|
cr.rectangle(x, y, self.width, self.height)
|
||||||
|
cr.fill()
|
|
@ -4,147 +4,285 @@ import cairo
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from hexagram.svg import render_to_image
|
|
||||||
from hexagram.gauge import Gauge
|
from hexagram.gauge import Gauge
|
||||||
|
from hexagram.icon import Icon
|
||||||
|
|
||||||
class VehicleStatus(enum.Enum):
|
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
|
OK = 0
|
||||||
ABS_FAULT = 1 << 0
|
DETECTED = 1
|
||||||
AIRBAG_FAULT = 1 << 1
|
|
||||||
BATTERY_FAULT = 1 << 2
|
|
||||||
BEAMS_FOG = 1 << 3
|
|
||||||
BEAMS_HIGH = 1 << 4
|
|
||||||
BEAMS_LOW = 1 << 5
|
|
||||||
BEAMS_PARKING = 1 << 6
|
|
||||||
BELT = 1 << 7
|
|
||||||
CAUTION = 1 << 8
|
|
||||||
COLD = 1 << 9
|
|
||||||
COLLISION = 1 << 10
|
|
||||||
COOLANT_LOW = 1 << 11
|
|
||||||
COOLANT_OVERHEAT = 1 << 12
|
|
||||||
CRUISE = 1 << 13
|
|
||||||
FUEL_LOW = 1 << 14
|
|
||||||
LANEKEEP_OFF = 1 << 15
|
|
||||||
ENGINE_FAULT = 1 << 16
|
|
||||||
OIL_LOW = 1 << 17
|
|
||||||
OIL_OVERHEAT = 1 << 18
|
|
||||||
PARKING_BRAKE_ON = 1 << 19
|
|
||||||
PARKING_BRAKE_FAULT = 1 << 20
|
|
||||||
STABILITY_OFF = 1 << 21
|
|
||||||
TPMS_WARNING = 1 << 22
|
|
||||||
TPMS_FAULT = 1 << 23
|
|
||||||
TRACTION_OFF = 1 << 24
|
|
||||||
TRACTION_FAULT = 1 << 25
|
|
||||||
WARNING = 1 << 26
|
|
||||||
WIPER_WASHER_LOW = 1 << 27
|
|
||||||
|
|
||||||
__strings__ = {
|
class CollisionIcon(StatusIcon):
|
||||||
OK: 'OK', ABS_FAULT: "ABS fault", AIRBAG_FAULT: "airbag fault",
|
TYPE = CollisionStatus
|
||||||
BATTERY_FAULT: "low battery voltage", BEAMS_FOG: "foglights on",
|
NAME = 'collision'
|
||||||
BEAMS_HIGH: "highbeams on", BEAMS_LOW: "lowbeams on",
|
STYLE = 'path {stroke-width: 10px; stroke: %(s)s}'
|
||||||
BEAMS_PARKING: "parking beams on", BELT: "warning: fasten seatbelt",
|
VARIANTS = {
|
||||||
CAUTION: "caution", COLLISION: "collision detected", COLD: "outside temperatures cold",
|
CollisionStatus.DETECTED: '#f00'
|
||||||
COOLANT_LOW: "coolant low", COOLANT_OVERHEAT: "engine overheating",
|
|
||||||
CRUISE: "cruise control on", FUEL_LOW: "fuel low",
|
|
||||||
LANEKEEP_OFF: "lane assist deactivated", ENGINE_FAULT: "check engine",
|
|
||||||
OIL_LOW: "oil level low", OIL_OVERHEAT: "oil overheating",
|
|
||||||
PARKING_BRAKE_ON: "parking brake on", PARKING_BRAKE_FAULT: "parking brake malfunction",
|
|
||||||
STABILITY_OFF: "stability control off", TPMS_WARNING: "check tire pressures",
|
|
||||||
TPMS_FAULT: "tire pressure monitoring system fault",
|
|
||||||
TRACTION_OFF: "traction control off", WARNING: "warning, drive with caution",
|
|
||||||
WIPER_WASHER_LOW: "wiper washer fluid low"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def __str__(self):
|
class FuelStatus(enum.Enum):
|
||||||
return self.__strings__.get(self.value, "unknown")
|
OK = 0
|
||||||
|
LOW = 1
|
||||||
|
FAULT = 2
|
||||||
|
|
||||||
class StatusIcon():
|
class FuelIcon(StatusIcon):
|
||||||
__slots__ = 'status', 'name', 'width', 'height', 'color', 'surface',
|
TYPE = FuelStatus
|
||||||
|
NAME = 'fuel'
|
||||||
|
STYLE = '#g9 * {stroke: %(s)s} #path9 {fill: %(s)s}'
|
||||||
|
VARIANTS = {
|
||||||
|
FuelStatus.LOW: '#fa0',
|
||||||
|
FuelStatus.FAULT: '#f00'
|
||||||
|
}
|
||||||
|
|
||||||
__dirs__ = ('./icons',
|
class SeatBeltStatus(enum.Enum):
|
||||||
'/usr/local/share/hexagram/icons'
|
OK = 0
|
||||||
'/usr/share/hexagram/icons')
|
UNFASTENED = 1
|
||||||
|
FAULT = 2
|
||||||
|
|
||||||
@staticmethod
|
class SeatBeltIcon(StatusIcon):
|
||||||
def _locate(name: str):
|
TYPE = SeatBeltStatus
|
||||||
for dir in StatusIcon.__dirs__:
|
NAME = 'belt'
|
||||||
path = "%s/%s.svg" % (dir, name)
|
STYLE = 'path {fill: %(s)s}'
|
||||||
|
VARIANTS = {
|
||||||
|
SeatBeltStatus.UNFASTENED: '#f00'
|
||||||
|
}
|
||||||
|
|
||||||
if os.path.exists(path):
|
class CoolantStatus(enum.Enum):
|
||||||
return path
|
OK = 0
|
||||||
|
LOW = 1
|
||||||
|
OVERHEAT = 2
|
||||||
|
FAULT = 3
|
||||||
|
|
||||||
raise FileNotFoundError(name + '.svg')
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, status: VehicleStatus, name: str, width: float, height: float, color: str, style: Optional[str]=None):
|
class OilStatus(enum.Enum):
|
||||||
self.status = status
|
OK = 0
|
||||||
self.name = name
|
LOW = 1
|
||||||
self.width = width
|
OVERHEAT = 2
|
||||||
self.height = height
|
FAULT = 3
|
||||||
self.color = color
|
|
||||||
|
|
||||||
if style is None:
|
class OilIcon(StatusIcon):
|
||||||
style = 'rect,path,circle{stroke:%(s)s;}'
|
TYPE = OilStatus
|
||||||
|
NAME = 'oil'
|
||||||
|
STYLE ='path {fill: %(s)s; stroke: %(s)s}'
|
||||||
|
VARIANTS = {
|
||||||
|
OilStatus.LOW: '#fa0',
|
||||||
|
OilStatus.OVERHEAT: '#f00'
|
||||||
|
}
|
||||||
|
|
||||||
path = StatusIcon._locate(name)
|
class ParkingBrakeStatus(enum.Enum):
|
||||||
|
OFF = 0
|
||||||
|
ON = 1
|
||||||
|
FAULT = 2
|
||||||
|
|
||||||
self.surface = render_to_image(path, width, height, style % {'s': color})
|
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'
|
||||||
|
}
|
||||||
|
|
||||||
def __del__(self):
|
class WiperWasherStatus(enum.Enum):
|
||||||
if self.surface is not None:
|
OK = 0
|
||||||
self.surface.finish()
|
LOW = 1
|
||||||
|
FAULT = 2
|
||||||
|
|
||||||
def draw(self, cr: cairo.Context, x: float, y: float):
|
class WiperWasherIcon(StatusIcon):
|
||||||
cr.set_source_surface(self.surface, x, y)
|
TYPE = WiperWasherStatus
|
||||||
cr.rectangle(x, y, self.width, self.height)
|
NAME = 'wiper-washer'
|
||||||
cr.fill()
|
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):
|
class StatusIconBox(Gauge):
|
||||||
__slots__ = 'x', 'y', 'width', 'height', 'value', 'surface', 'icons', '_redraw'
|
__slots__ = 'x', 'y', 'width', 'height', 'surface', 'statuses', 'icons', \
|
||||||
|
'_redraw'
|
||||||
__icons__ = (
|
|
||||||
(VehicleStatus.BATTERY_FAULT, 'battery', '#f00', '#rect5, #rect6 {fill: %(s)s} #rect4, path {stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.BEAMS_FOG, 'beams-fog', '#0f0', '#g9 path {fill: %(s)s} #g5 path {stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.BEAMS_HIGH, 'beams-high', '#00f', 'path {fill: %(s)s; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.BEAMS_LOW, 'beams-low', '#0f0', 'path {fill: %(s)s; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.BEAMS_PARKING, 'beams-parking', '#ff0', 'path {stroke: %(s)s; stroke-width: 12}'),
|
|
||||||
(VehicleStatus.BELT, 'belt', '#f00', 'path {fill: %(s)s}'),
|
|
||||||
(VehicleStatus.COLLISION, 'collision', '#f00', 'path {stroke-width: 10px; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.COOLANT_LOW, 'coolant', '#fa0', 'path, circle, rect {fill: %(s)s} #g9 path {stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.COOLANT_OVERHEAT, 'coolant', '#f00', 'path, circle, rect {fill: %(s)s} #g9 path {stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.CRUISE, 'cruise', '#0f0', 'path, circle {fill: %(s)s; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.FUEL_LOW, 'fuel', '#fa0', '#g9 * {stroke: %(s)s} #path9 {fill: %(s)s}'),
|
|
||||||
(VehicleStatus.LANEKEEP_OFF, 'lane-departure', '#fa0', 'path {stroke: %(s)s; stroke-width: 8}'),
|
|
||||||
(VehicleStatus.OIL_LOW, 'oil', '#fa0', 'path {fill: %(s)s; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.OIL_OVERHEAT, 'oil', '#f00', 'path {fill: %(s)s; stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.PARKING_BRAKE_ON, 'parking', '#fa0', '#path6, #path5 {stroke: %(s)s} circle {stroke: %(s)s} #path7 {fill: %(s)s}'),
|
|
||||||
(VehicleStatus.PARKING_BRAKE_FAULT, 'parking', '#f00', '#path6, #path5 {stroke: %(s)s} circle {stroke: %(s)s} #path7 {fill: %(s)s}'),
|
|
||||||
(VehicleStatus.STABILITY_OFF, 'stability', '#fa0', '#path9, #path8, #path7, #path6, #path5 {fill: %(s)s} #path10 {stroke: %(s)s}'),
|
|
||||||
(VehicleStatus.TPMS_WARNING, 'tpms', '#fa0', 'path, circle {fill: %(s)s}'),
|
|
||||||
(VehicleStatus.WIPER_WASHER_LOW, 'wiper-washer', '#fa0'),
|
|
||||||
)
|
|
||||||
|
|
||||||
ICON_WIDTH = 48
|
ICON_WIDTH = 48
|
||||||
ICON_HEIGHT = 48
|
ICON_HEIGHT = 48
|
||||||
|
|
||||||
|
ICONS = (
|
||||||
|
CollisionIcon, FuelIcon, SeatBeltIcon, CoolantIcon, OilIcon,
|
||||||
|
ParkingBrakeIcon, WiperWasherIcon, LaneKeepIcon, StabilityControlIcon,
|
||||||
|
TPMSIcon, FogBeamIcon, ParkingBeamIcon, LowBeamIcon, HighBeamIcon
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, x: float, y: float, width: float, height: float):
|
def __init__(self, x: float, y: float, width: float, height: float):
|
||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
self.value = VehicleStatus.OK.value
|
|
||||||
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(width), int(height))
|
self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32,int(width), int(height))
|
||||||
self._redraw = False
|
self._redraw = False
|
||||||
|
|
||||||
self.icons: dict[int, StatusIcon] = dict()
|
self.statuses: dict[enum.EnumType, enum.Enum] = dict()
|
||||||
|
self.icons: dict[enum.EnumType, StatusIcon] = dict()
|
||||||
|
|
||||||
for item in self.__icons__:
|
for icon_type in self.ICONS:
|
||||||
status, name, color = item[0:3]
|
self.icons[icon_type.TYPE] = icon_type(self.ICON_WIDTH, self.ICON_HEIGHT)
|
||||||
style = 'rect,path,circle{stroke:%(s)s;}' if len(item) < 4 else item[3]
|
|
||||||
|
|
||||||
self.icons[status.value] = StatusIcon(status, name,
|
|
||||||
self.ICON_WIDTH,
|
|
||||||
self.ICON_HEIGHT,
|
|
||||||
color, style)
|
|
||||||
|
|
||||||
def __del__(self):
|
def __del__(self):
|
||||||
self.surface.finish()
|
self.surface.finish()
|
||||||
|
@ -161,11 +299,11 @@ class StatusIconBox(Gauge):
|
||||||
|
|
||||||
x, y = 0, self.height - self.ICON_HEIGHT
|
x, y = 0, self.height - self.ICON_HEIGHT
|
||||||
|
|
||||||
for status_value in self.icons:
|
for typeof in self.statuses:
|
||||||
icon = self.icons[status_value]
|
status = self.statuses[typeof]
|
||||||
|
icon = self.icons[typeof]
|
||||||
|
|
||||||
if self.value & status_value:
|
if icon.drawable(status):
|
||||||
if icon is not None:
|
|
||||||
icon.draw(cr, x, y)
|
icon.draw(cr, x, y)
|
||||||
|
|
||||||
x += self.ICON_WIDTH
|
x += self.ICON_WIDTH
|
||||||
|
@ -183,14 +321,5 @@ class StatusIconBox(Gauge):
|
||||||
cr.rectangle(self.x, self.y, self.width, self.height)
|
cr.rectangle(self.x, self.y, self.width, self.height)
|
||||||
cr.fill()
|
cr.fill()
|
||||||
|
|
||||||
def reset(self):
|
def set(self, status: enum.Enum):
|
||||||
self.value = VehicleStatus.OK.value
|
self.statuses[type(status)] = status
|
||||||
self._redraw = True
|
|
||||||
|
|
||||||
def set_status(self, status: VehicleStatus):
|
|
||||||
self.value |= status.value
|
|
||||||
self._redraw = True
|
|
||||||
|
|
||||||
def clear_status(self, status: VehicleStatus):
|
|
||||||
self.value &= ~status.value
|
|
||||||
self._redraw = True
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ def render_to_surface(path: str, surface: cairo.Surface, width: float, height: f
|
||||||
|
|
||||||
svg.render_layer(cr, None, rect)
|
svg.render_layer(cr, None, rect)
|
||||||
|
|
||||||
def render_to_image(path: str, width: float, height: float, style: Optional[str]=None) -> cairo.Surface:
|
def render_to_image(path: str, width: float, height: float, style: Optional[str]=None) -> cairo.ImageSurface:
|
||||||
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
|
||||||
|
|
||||||
render_to_surface(path, surface, width, height, style)
|
render_to_surface(path, surface, width, height, style)
|
||||||
|
|
Loading…
Add table
Reference in a new issue