152 lines
4.3 KiB
Python
152 lines
4.3 KiB
Python
"""Pure gauge configuration dataclasses."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping, Sequence
|
|
from dataclasses import dataclass, replace
|
|
from typing import Any, Literal
|
|
|
|
from .scales import validate_markers, validate_range, validate_thresholds
|
|
from .themes import GaugeStyle, GaugeTheme, get_theme, merge_style
|
|
from .types import (
|
|
AnimationConfig,
|
|
Callback,
|
|
GaugeMarker,
|
|
GaugeValue,
|
|
SmoothingConfig,
|
|
StatusState,
|
|
Tag,
|
|
ThresholdBand,
|
|
ValueFormatter,
|
|
)
|
|
|
|
|
|
def _normalize_animation(value: AnimationConfig | bool | None) -> AnimationConfig | None:
|
|
if isinstance(value, bool):
|
|
return AnimationConfig(enabled=value)
|
|
return value
|
|
|
|
|
|
def _normalize_smoothing(value: SmoothingConfig | bool | None) -> SmoothingConfig | None:
|
|
if isinstance(value, bool):
|
|
return SmoothingConfig(enabled=value)
|
|
return value
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class GaugeConfig:
|
|
tag: Tag | None = None
|
|
parent: Tag | None = None
|
|
label: str | None = None
|
|
value: GaugeValue = None
|
|
min_value: float = 0.0
|
|
max_value: float = 100.0
|
|
unit: str = ""
|
|
precision: int = 0
|
|
width: int = 0
|
|
height: int = 0
|
|
autosize_x: bool = False
|
|
autosize_y: bool = False
|
|
show: bool = True
|
|
show_label: bool = True
|
|
show_value: bool = True
|
|
show_unit: bool = True
|
|
tooltip: str | None = None
|
|
callback: Callback | None = None
|
|
user_data: Any = None
|
|
theme: str | GaugeTheme | None = None
|
|
style: GaugeStyle | None = None
|
|
animation: AnimationConfig | bool | None = None
|
|
smoothing: SmoothingConfig | bool | None = None
|
|
clamp: bool = True
|
|
format_value: ValueFormatter | None = None
|
|
thresholds: Sequence[ThresholdBand] = ()
|
|
markers: Sequence[GaugeMarker] = ()
|
|
|
|
def __post_init__(self) -> None:
|
|
validate_range(self.min_value, self.max_value)
|
|
validate_thresholds(self.thresholds, self.min_value, self.max_value)
|
|
validate_markers(self.markers, self.min_value, self.max_value)
|
|
if self.precision < 0:
|
|
msg = "precision must be non-negative"
|
|
raise ValueError(msg)
|
|
object.__setattr__(self, "theme", get_theme(self.theme))
|
|
object.__setattr__(self, "style", self.style or get_theme(self.theme).style)
|
|
object.__setattr__(self, "animation", _normalize_animation(self.animation))
|
|
object.__setattr__(self, "smoothing", _normalize_smoothing(self.smoothing))
|
|
object.__setattr__(self, "thresholds", tuple(self.thresholds))
|
|
object.__setattr__(self, "markers", tuple(self.markers))
|
|
|
|
def with_style_overrides(self, **overrides: Any) -> GaugeConfig:
|
|
return replace(self, style=merge_style(self.style, **overrides))
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class AnalogGaugeConfig(GaugeConfig):
|
|
start_angle: float = 225.0
|
|
end_angle: float = -45.0
|
|
major_ticks: int = 8
|
|
minor_ticks: int = 4
|
|
show_tick_labels: bool = True
|
|
needle_length: float = 0.82
|
|
needle_width: float = 3.0
|
|
center_cap_radius: float = 7.0
|
|
arc_width: float = 8.0
|
|
maintain_aspect: bool = True
|
|
redline_start: float | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class DigitalGaugeConfig(GaugeConfig):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BarGaugeConfig(GaugeConfig):
|
|
orientation: Literal["horizontal", "vertical"] = "horizontal"
|
|
fill_mode: Literal["clamp", "centered"] = "clamp"
|
|
corner_radius: float = 4.0
|
|
show_scale: bool = True
|
|
stretch: bool = True
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class LevelGaugeConfig(BarGaugeConfig):
|
|
orientation: Literal["horizontal", "vertical"] = "vertical"
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class StatusLightConfig(GaugeConfig):
|
|
state: str | bool | int = False
|
|
states: Mapping[Any, StatusState] | None = None
|
|
blink: bool = False
|
|
pulse: bool = False
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SegmentedGaugeConfig(BarGaugeConfig):
|
|
segments: int = 10
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class CompassGaugeConfig(AnalogGaugeConfig):
|
|
min_value: float = 0.0
|
|
max_value: float = 360.0
|
|
start_angle: float = 90.0
|
|
end_angle: float = -270.0
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class ThermometerGaugeConfig(LevelGaugeConfig):
|
|
pass
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class BatteryGaugeConfig(LevelGaugeConfig):
|
|
charging: bool | None = None
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class MultiValueGaugeConfig(GaugeConfig):
|
|
values: Mapping[str, GaugeValue] | None = None
|