Refactor hexagram.icons away

This commit is contained in:
XANTRONIX Development 2024-01-04 23:27:06 -05:00
parent 1255ca26f7
commit 4745176c03
3 changed files with 122 additions and 131 deletions

View file

@ -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.icons import StatusIconBox from hexagram.status import StatusIconBox
class ShiftIndicator(Gauge): class ShiftIndicator(Gauge):
__slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max', __slots__ = 'x', 'y', 'rpm_min', 'rpm_redline', 'rpm_max',

View file

@ -1,130 +0,0 @@
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', 'width', 'height', 'color', 'surface',
__dirs__ = ('./icons',
'/usr/local/share/hexagram/icons'
'/usr/share/hexagram/icons')
@staticmethod
def _locate(name: str):
for dir in ISO7000Icon.__dirs__:
path = "%s/%s.svg" % (dir, name)
if os.path.exists(path):
return path
raise FileNotFoundError(name + '.svg')
def __init__(self, status: VehicleStatus, name: str, width: float, height: float, color: str, style: Optional[str]):
self.status = status
self.name = name
self.width = width
self.height = height
self.color = color
if style is None:
style = 'rect,path,circle{stroke:%(s)s;}'
path = ISO7000Icon._locate(name)
self.surface = render_to_image(path, width, height, style % {'s': color})
def __del__(self):
if self.surface is not None:
self.surface.finish()
def draw(self, cr: cairo.Context, x: float, y: float):
cr.set_source_surface(self.surface, x, y)
cr.rectangle(x, y, self.width, self.height)
cr.fill()
class ISO7000():
__slots__ = 'icons',
__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'),
(VehicleStatus.BELT, 'belt', '#f00', 'path {fill: %(s)s}'),
(VehicleStatus.COLD, 'cold', '#eef'),
(VehicleStatus.COLLISION, 'collision', '#f00', 'path {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'),
(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'),
)
def __init__(self, width: float, height: float):
self.icons = dict()
for item in self.__icons__:
status, name, color = item[0:3]
style = 'rect,path,circle{stroke:%(s)s;}' if len(item) < 4 else item[3]
self.icons[status.value] = ISO7000Icon(status,
name,
width,
height,
color,
style)
class StatusIconBox(Gauge):
__slots__ = 'x', 'y', 'width', 'height', 'iso7000', 'value',
ICON_WIDTH = 48
ICON_HEIGHT = 48
def __init__(self, x: float, y: float, width: float, height: float):
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

View file

@ -1,4 +1,11 @@
import os
import enum import enum
import cairo
from typing import Optional
from hexagram.svg import render_to_image
from hexagram.gauge import Gauge
class VehicleStatus(enum.Enum): class VehicleStatus(enum.Enum):
OK = 0 OK = 0
@ -50,3 +57,117 @@ class VehicleStatus(enum.Enum):
def __str__(self): def __str__(self):
return self.__strings__.get(self.value, "unknown") return self.__strings__.get(self.value, "unknown")
class StatusIcon():
__slots__ = 'status', 'name', 'width', 'height', 'color', 'surface',
__dirs__ = ('./icons',
'/usr/local/share/hexagram/icons'
'/usr/share/hexagram/icons')
@staticmethod
def _locate(name: str):
for dir in StatusIcon.__dirs__:
path = "%s/%s.svg" % (dir, name)
if os.path.exists(path):
return path
raise FileNotFoundError(name + '.svg')
def __init__(self, status: VehicleStatus, name: str, width: float, height: float, color: str, style: Optional[str]):
self.status = status
self.name = name
self.width = width
self.height = height
self.color = color
if style is None:
style = 'rect,path,circle{stroke:%(s)s;}'
path = StatusIcon._locate(name)
self.surface = render_to_image(path, width, height, style % {'s': color})
def __del__(self):
if self.surface is not None:
self.surface.finish()
def draw(self, cr: cairo.Context, x: float, y: float):
cr.set_source_surface(self.surface, x, y)
cr.rectangle(x, y, self.width, self.height)
cr.fill()
class StatusIconBox(Gauge):
__slots__ = 'x', 'y', 'width', 'height', 'icons', 'value',
__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'),
(VehicleStatus.BELT, 'belt', '#f00', 'path {fill: %(s)s}'),
(VehicleStatus.COLD, 'cold', '#eef'),
(VehicleStatus.COLLISION, 'collision', '#f00', 'path {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'),
(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_HEIGHT = 48
def __init__(self, x: float, y: float, width: float, height: float):
self.x = x
self.y = y
self.width = width
self.height = height
self.value = VehicleStatus.OK.value
self.icons: dict[int, StatusIcon] = dict()
for item in self.__icons__:
status, name, color = item[0:3]
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 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.icons:
icon = self.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