improve gauge function signatures

This commit is contained in:
2026-07-02 15:47:12 +02:00
parent ee5b60e620
commit 451557299e

View File

@@ -2,9 +2,10 @@
from __future__ import annotations
from collections.abc import Mapping, Sequence
from dataclasses import dataclass
from types import TracebackType
from typing import Any, Generic, TypeVar, cast
from typing import Any, Generic, Literal, TypeVar, cast
import dearpygui.dearpygui as dpg
@@ -23,7 +24,18 @@ from .gauges import (
)
from .renderer import GaugeRenderer
from .state import GaugeState, register_gauge
from .types import Tag
from .themes import GaugeStyle, GaugeTheme
from .types import (
AnimationConfig,
Callback,
GaugeMarker,
GaugeValue,
SmoothingConfig,
StatusState,
Tag,
ThresholdBand,
ValueFormatter,
)
ConfigT = TypeVar("ConfigT", bound=GaugeConfig)
@@ -138,92 +150,463 @@ def create_gauge_context(gauge_type: str, config: ConfigT) -> GaugeContext[Confi
return GaugeContext(state)
def gauge_panel(**config: Any) -> LayoutContext:
def gauge_panel(
*,
tag: Tag | None = None,
label: str | None = None,
width: int = 0,
height: int = 0,
show: bool = True,
border: bool = True,
autosize_x: bool = False,
autosize_y: bool = False,
tooltip: str | None = None,
**config: Any,
) -> LayoutContext:
"""Create a lightweight child-window container for related gauges."""
if not _dpg_context_active:
return LayoutContext(None)
tag = config.pop("tag", 0)
label = config.pop("label", None)
tooltip = config.pop("tooltip", None)
container = dpg.add_child_window(
tag=tag,
label=label,
width=config.pop("width", 0),
height=config.pop("height", 0),
show=config.pop("show", True),
border=config.pop("border", True),
autosize_x=config.pop("autosize_x", False),
autosize_y=config.pop("autosize_y", False),
tag=tag or 0,
label=label or "",
width=width,
height=height,
show=show,
border=border,
autosize_x=autosize_x,
autosize_y=autosize_y,
**config,
)
_add_tooltip(container, tooltip)
return LayoutContext(container)
def gauge_grid(**config: Any) -> LayoutContext:
def gauge_grid(
*,
columns: int = 1,
tag: Tag | None = None,
width: int = 0,
height: int = 0,
show: bool = True,
**config: Any,
) -> LayoutContext:
"""Create a lightweight horizontal gauge layout container."""
if not _dpg_context_active:
return LayoutContext(None)
columns = max(int(config.pop("columns", 1)), 1)
columns = max(int(columns), 1)
container = dpg.add_group(
tag=config.pop("tag", 0),
width=config.pop("width", 0),
height=config.pop("height", 0),
show=config.pop("show", True),
tag=tag or 0,
width=width,
height=height,
show=show,
horizontal=columns > 1,
**config,
)
return LayoutContext(container)
def analog_gauge(**config: Any) -> GaugeContext[AnalogGaugeConfig]:
def analog_gauge(
*,
tag: 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] = (),
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,
**config: Any,
) -> GaugeContext[AnalogGaugeConfig]:
"""Create an analog dial gauge with ticks, needle, thresholds, and markers."""
return create_gauge_context("analog", AnalogGaugeConfig(**config))
return create_gauge_context("analog", AnalogGaugeConfig(**_config_from_locals(locals())))
def digital_gauge(**config: Any) -> GaugeContext[DigitalGaugeConfig]:
def digital_gauge(
*,
tag: 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] = (),
**config: Any,
) -> GaugeContext[DigitalGaugeConfig]:
"""Create a large numeric readout gauge."""
return create_gauge_context("digital", DigitalGaugeConfig(**config))
return create_gauge_context("digital", DigitalGaugeConfig(**_config_from_locals(locals())))
def bar_gauge(**config: Any) -> GaugeContext[BarGaugeConfig]:
def bar_gauge(
*,
tag: 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] = (),
orientation: Literal["horizontal", "vertical"] = "horizontal",
fill_mode: Literal["clamp", "centered"] = "clamp",
corner_radius: float = 4.0,
show_scale: bool = True,
stretch: bool = True,
**config: Any,
) -> GaugeContext[BarGaugeConfig]:
"""Create a horizontal or vertical fill bar gauge."""
return create_gauge_context("bar", BarGaugeConfig(**config))
return create_gauge_context("bar", BarGaugeConfig(**_config_from_locals(locals())))
def level_gauge(**config: Any) -> GaugeContext[LevelGaugeConfig]:
def level_gauge(
*,
tag: 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] = (),
orientation: Literal["horizontal", "vertical"] = "vertical",
fill_mode: Literal["clamp", "centered"] = "clamp",
corner_radius: float = 4.0,
show_scale: bool = True,
stretch: bool = True,
**config: Any,
) -> GaugeContext[LevelGaugeConfig]:
"""Create a tank or level-style vertical gauge."""
return create_gauge_context("level", LevelGaugeConfig(**config))
return create_gauge_context("level", LevelGaugeConfig(**_config_from_locals(locals())))
def status_light(**config: Any) -> GaugeContext[StatusLightConfig]:
def status_light(
*,
tag: 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] = (),
state: str | bool | int = False,
states: Mapping[Any, StatusState] | None = None,
blink: bool = False,
pulse: bool = False,
**config: Any,
) -> GaugeContext[StatusLightConfig]:
"""Create an LED-style status indicator gauge."""
return create_gauge_context("status_light", StatusLightConfig(**config))
return create_gauge_context("status_light", StatusLightConfig(**_config_from_locals(locals())))
def segmented_gauge(**config: Any) -> GaugeContext[SegmentedGaugeConfig]:
def segmented_gauge(
*,
tag: 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] = (),
orientation: Literal["horizontal", "vertical"] = "horizontal",
fill_mode: Literal["clamp", "centered"] = "clamp",
corner_radius: float = 4.0,
show_scale: bool = True,
stretch: bool = True,
segments: int = 10,
**config: Any,
) -> GaugeContext[SegmentedGaugeConfig]:
"""Create a segmented strip gauge for shift-light or cell-style displays."""
return create_gauge_context("segmented", SegmentedGaugeConfig(**config))
return create_gauge_context("segmented", SegmentedGaugeConfig(**_config_from_locals(locals())))
def compass_gauge(**config: Any) -> GaugeContext[CompassGaugeConfig]:
def compass_gauge(
*,
tag: Tag | None = None,
label: str | None = None,
value: GaugeValue = None,
min_value: float = 0.0,
max_value: float = 360.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] = (),
start_angle: float = 90.0,
end_angle: float = -270.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,
**config: Any,
) -> GaugeContext[CompassGaugeConfig]:
"""Create a compass gauge that wraps numeric headings to 0-360 degrees."""
return create_gauge_context("compass", CompassGaugeConfig(**config))
return create_gauge_context("compass", CompassGaugeConfig(**_config_from_locals(locals())))
def thermometer_gauge(**config: Any) -> GaugeContext[ThermometerGaugeConfig]:
def thermometer_gauge(
*,
tag: 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] = (),
orientation: Literal["horizontal", "vertical"] = "vertical",
fill_mode: Literal["clamp", "centered"] = "clamp",
corner_radius: float = 4.0,
show_scale: bool = True,
stretch: bool = True,
**config: Any,
) -> GaugeContext[ThermometerGaugeConfig]:
"""Create a thermometer-style temperature gauge."""
return create_gauge_context("thermometer", ThermometerGaugeConfig(**config))
return create_gauge_context(
"thermometer", ThermometerGaugeConfig(**_config_from_locals(locals()))
)
def battery_gauge(**config: Any) -> GaugeContext[BatteryGaugeConfig]:
def battery_gauge(
*,
tag: 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] = (),
orientation: Literal["horizontal", "vertical"] = "vertical",
fill_mode: Literal["clamp", "centered"] = "clamp",
corner_radius: float = 4.0,
show_scale: bool = True,
stretch: bool = True,
charging: bool | None = None,
**config: Any,
) -> GaugeContext[BatteryGaugeConfig]:
"""Create a battery-style percentage or value gauge."""
return create_gauge_context("battery", BatteryGaugeConfig(**config))
return create_gauge_context("battery", BatteryGaugeConfig(**_config_from_locals(locals())))
def multi_value_gauge(**config: Any) -> GaugeContext[MultiValueGaugeConfig]:
def multi_value_gauge(
*,
tag: 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] = (),
values: Mapping[str, GaugeValue] | None = None,
**config: Any,
) -> GaugeContext[MultiValueGaugeConfig]:
"""Create a compact grouped key/value readout gauge."""
return create_gauge_context("multi_value", MultiValueGaugeConfig(**config))
return create_gauge_context(
"multi_value", MultiValueGaugeConfig(**_config_from_locals(locals()))
)
def _config_from_locals(values: dict[str, Any]) -> dict[str, Any]:
config = dict(values.pop("config"))
config.update(values)
return config
def _default_width(gauge_type: str) -> int: