diff --git a/py/hexagram/cluster.py b/py/hexagram/cluster.py index 2269bf5..2b0e969 100644 --- a/py/hexagram/cluster.py +++ b/py/hexagram/cluster.py @@ -11,6 +11,7 @@ from hexagram.speedo import Speedo from hexagram.tacho import Tacho from hexagram.fuel import FuelGauge from hexagram.thermo import Thermometer +from hexagram.icons import StatusIconBox class ShiftIndicator(Gauge): __slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max', @@ -114,7 +115,7 @@ class Clock(TextGauge): class Cluster(): __slots__ = 'gauges', 'speedo', 'fuel', 'tacho', 'thermo', 'odo', \ - 'ambient', 'clock', 'shift_indicator', + 'ambient', 'clock', 'shift_indicator', 'status', WIDTH = 1280 HEIGHT = 480 @@ -153,6 +154,10 @@ class Cluster(): rpm_redline, rpm_max) + self.status = StatusIconBox(478, 276, + StatusIconBox.ICON_WIDTH * 10, + StatusIconBox.ICON_HEIGHT * 2) + self.gauges.append(self.speedo) self.gauges.append(self.fuel) self.gauges.append(self.tacho) @@ -161,6 +166,7 @@ class Cluster(): self.gauges.append(self.ambient) self.gauges.append(self.clock) self.gauges.append(self.shift_indicator) + self.gauges.append(self.status) def draw_bg(self, cr: cairo.Context): cr.set_source_rgb(0.1, 0.1, 0.1) diff --git a/py/hexagram/icons.py b/py/hexagram/icons.py index 2d889e6..2a950aa 100644 --- a/py/hexagram/icons.py +++ b/py/hexagram/icons.py @@ -1,57 +1,22 @@ import os import cairo +from typing import Optional + +from hexagram.gauge import Gauge from hexagram.status import VehicleStatus from hexagram.svg import render_to_image class ISO7000Icon(): - __slots__ = 'status', 'name', 'color', - - def __init__(self, status: VehicleStatus, name: str, color: str): - self.status = status - self.name = name - self.color = color - -class ISO7000(): - __slots__ = 'icons', 'width', 'height', + __slots__ = 'status', 'name', 'width', 'height', 'color', 'surface', __dirs__ = ('./icons', '/usr/local/share/hexagram/icons' '/usr/share/hexagram/icons') - __icons__ = ( - (VehicleStatus.ABS_FAULT, 'abs', '#fa0'), - (VehicleStatus.AIRBAG_FAULT, 'airbag', '#fa0'), - (VehicleStatus.BATTERY_FAULT, 'beams-fog', '#f00'), - (VehicleStatus.BEAMS_FOG, 'beams-fog', '#0f0'), - (VehicleStatus.BEAMS_HIGH, 'beams-high', '#00f'), - (VehicleStatus.BEAMS_LOW, 'beams-low', '#0f0'), - (VehicleStatus.BEAMS_PARKING, 'beams-parking', '#ff0'), - (VehicleStatus.BELT, 'belt', '#f00'), - (VehicleStatus.CAUTION, 'caution', '#fa0'), - (VehicleStatus.COLD, 'cold', '#eef'), - (VehicleStatus.COLLISION, 'coolant', '#f00'), - (VehicleStatus.COOLANT_LOW, 'coolant', '#fa0'), - (VehicleStatus.COOLANT_OVERHEAT, 'coolant', '#f00'), - (VehicleStatus.CRUISE, 'cruise', '#0f0'), - (VehicleStatus.FUEL_LOW, 'fuel', '#fa0'), - (VehicleStatus.LANEKEEP_OFF, 'lane-departure', '#fa0'), - (VehicleStatus.ENGINE_FAULT, 'mil', '#fa0'), - (VehicleStatus.OIL_LOW, 'oil', '#fa0'), - (VehicleStatus.OIL_OVERHEAT, 'oil', '#f00'), - (VehicleStatus.PARKING_BRAKE_ON, 'parking', '#fa0'), - (VehicleStatus.PARKING_BRAKE_FAULT, 'parking', '#f00'), - (VehicleStatus.STABILITY_OFF, 'stability', '#fa0'), - (VehicleStatus.TPMS_WARNING, 'tpms', '#f00'), - (VehicleStatus.TRACTION_OFF, 'traction', '#fa0'), - (VehicleStatus.TRACTION_FAULT, 'traction', '#f00'), - (VehicleStatus.WARNING, 'warning', '#f00'), - (VehicleStatus.WIPER_WASHER_LOW, 'wiper-washer', '#fa0'), - ) - @staticmethod def _locate(name: str): - for dir in ISO7000.__dirs__: + for dir in ISO7000Icon.__dirs__: path = "%s/%s.svg" % (dir, name) if os.path.exists(path): @@ -59,34 +24,103 @@ class ISO7000(): raise FileNotFoundError(name + '.svg') - def __init__(self, width: float, height: float): - self.icons = dict() + def __init__(self, status: VehicleStatus, name: str, width: float, height: float, color: str): + self.status = status + self.name = name self.width = width self.height = height + self.color = color - for item in self.__icons__: - icon = ISO7000Icon(*item) - style = 'rect,path,circle{stroke:%(s)s;fill:%(s)s}' % {'s': icon.color} - path = ISO7000._locate(icon.name) + style = 'rect,path,circle{stroke:%(s)s;fill:%(s)s}' % {'s': color} + path = ISO7000Icon._locate(name) - self.icons[icon.status.value] = render_to_image(path, width, height, style) + self.surface = render_to_image(path, width, height, style) def __del__(self): - for status_value in self.icons: - self.icons[status_value].finish() + self.surface.finish() - def draw(self, cr: cairo.Context, status: VehicleStatus, x: float, y: float): - icon = self.icons[status.value] - - cr.set_source_surface(icon, 0, 0) + def draw(self, cr: cairo.Context, x: float, y: float): + print(f"Drawing! {self.status}, {x}, {y}, {self.width}, {self.height}, {self.color}") + cr.set_source_surface(self.surface, 0, 0) cr.rectangle(x, y, self.width, self.height) cr.fill() -class StatusIconBox(): - __slots__ = 'x', 'y', 'width', 'height', +class ISO7000(): + __slots__ = 'icons', + + __icons__ = ( + (VehicleStatus.BATTERY_FAULT, 'beams-fog', '#f00'), + (VehicleStatus.BEAMS_FOG, 'beams-fog', '#0f0'), + (VehicleStatus.BEAMS_HIGH, 'beams-high', '#00f'), + (VehicleStatus.BEAMS_LOW, 'beams-low', '#0f0'), + (VehicleStatus.BEAMS_PARKING, 'beams-parking', '#ff0'), + (VehicleStatus.BELT, 'belt', '#f00'), + (VehicleStatus.COLD, 'cold', '#eef'), + (VehicleStatus.COLLISION, 'coolant', '#f00'), + (VehicleStatus.COOLANT_LOW, 'coolant', '#fa0'), + (VehicleStatus.COOLANT_OVERHEAT, 'coolant', '#f00'), + (VehicleStatus.CRUISE, 'cruise', '#0f0'), + (VehicleStatus.FUEL_LOW, 'fuel', '#fa0'), + (VehicleStatus.LANEKEEP_OFF, 'lane-departure', '#fa0'), + (VehicleStatus.OIL_LOW, 'oil', '#fa0'), + (VehicleStatus.OIL_OVERHEAT, 'oil', '#f00'), + (VehicleStatus.PARKING_BRAKE_ON, 'parking', '#fa0'), + (VehicleStatus.PARKING_BRAKE_FAULT, 'parking', '#f00'), + (VehicleStatus.STABILITY_OFF, 'stability', '#fa0'), + (VehicleStatus.TPMS_WARNING, 'tpms', '#fa0'), + (VehicleStatus.WIPER_WASHER_LOW, 'wiper-washer', '#fa0'), + ) + + def __init__(self, width: float, height: float): + self.icons = dict() + + for item in self.__icons__: + status, name, color = item + + self.icons[status.value] = ISO7000Icon(status, + name, + width, + height, + color) + +class StatusIconBox(Gauge): + __slots__ = 'x', 'y', 'width', 'height', 'iso7000', 'value', + + ICON_WIDTH = 32 + ICON_HEIGHT = 32 def __init__(self, x: float, y: float, width: float, height: float): - self.x = x - self.y = y - self.width = width - self.height = height + self.x = x + self.y = y + self.width = width + self.height = height + self.iso7000 = ISO7000(self.ICON_WIDTH, self.ICON_HEIGHT) + self.value = VehicleStatus.OK.value + + def reset(self): + self.value = VehicleStatus.OK.value + + def set_status(self, status: VehicleStatus): + self.value |= status.value + + def clear_status(self, status: VehicleStatus): + self.value &= ~status.value + + def draw_bg(self, cr: cairo.Context): + pass + + def draw_fg(self, cr: cairo.Context): + x, y = 0, 0 + + for status_value in self.iso7000.icons: + icon = self.iso7000.icons[status_value] + + if self.value & status_value: + if icon is not None: + icon.draw(cr, self.x + x, self.y + y) + + x += self.ICON_WIDTH + + if x >= self.width: + x = 0 + y += self.ICON_HEIGHT diff --git a/py/hexagram/status.py b/py/hexagram/status.py index 6255cdb..7327163 100644 --- a/py/hexagram/status.py +++ b/py/hexagram/status.py @@ -36,7 +36,7 @@ class VehicleStatus(enum.Enum): BATTERY_FAULT: "low battery voltage", BEAMS_FOG: "foglights on", BEAMS_HIGH: "highbeams on", BEAMS_LOW: "lowbeams on", BEAMS_PARKING: "parking beams on", BELT: "warning: fasten seatbelt", - CAUTION: "caution", COLLISION: "collision detected", + CAUTION: "caution", COLLISION: "collision detected", COLD: "outside temperatures cold", 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",