Build instructions
This commit is contained in:
41
codex/AGENTS.md
Normal file
41
codex/AGENTS.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# AGENTS.md
|
||||
|
||||
## Current status
|
||||
|
||||
Project instruction set initialized.
|
||||
|
||||
## Completed steps
|
||||
|
||||
None yet.
|
||||
|
||||
## Current step
|
||||
|
||||
Step 1 - Public API contract and pure core.
|
||||
|
||||
## Design decisions
|
||||
|
||||
- Package is managed with uv.
|
||||
- Public import is `import dpg_gauges as dpgg`.
|
||||
- Package target is Python 3.11+.
|
||||
- The package is Dear PyGui-only, but pure configuration/state helpers should avoid Dear PyGui imports where practical.
|
||||
- Widget creation and Dear PyGui item operations are GUI-thread-only.
|
||||
- Runtime value/configuration updates are intended to be called from the GUI thread.
|
||||
- High-frequency updates should be smoothed/coalesced so gauges remain readable and flicker-free.
|
||||
- Out-of-range values clamp to min/max and display the clamped value.
|
||||
- Gauges are display-only for the first release.
|
||||
- Thresholds and redline zones are visual only; they do not trigger events.
|
||||
- The public API should feel like normal Dear PyGui context-manager usage.
|
||||
|
||||
## Known issues
|
||||
|
||||
None yet.
|
||||
|
||||
## Commands used
|
||||
|
||||
- Read `codex-old/README.md`, `codex-old/FEATURES.md`, `codex-old/ARCHITECTURE.md`, `codex-old/STEPS.md`, and `codex-old/AGENTS.md`.
|
||||
- Inspected `/home/hector/projects/dpg-map` package, examples, tests, docs, and pyproject structure.
|
||||
- Created the initial `codex/` instruction documents for `dpg-gauges`.
|
||||
|
||||
## Next action
|
||||
|
||||
Implement Step 1.
|
||||
444
codex/ARCHITECTURE.md
Normal file
444
codex/ARCHITECTURE.md
Normal file
@@ -0,0 +1,444 @@
|
||||
# dpg-gauges Architecture
|
||||
|
||||
This document defines the internal architecture for `dpg-gauges`.
|
||||
|
||||
The central rule is:
|
||||
|
||||
> Dear PyGui item and draw operations happen on the GUI thread. Gauge state is kept separately
|
||||
> from draw commands so high-rate value updates can redraw only the dynamic parts of a gauge.
|
||||
|
||||
`dpg-gauges` does not need the full thread-safe command architecture used by `dpg-map`; gauge
|
||||
updates are intended to be made from the GUI thread. The package still needs a clean state/render
|
||||
split so animation, smoothing, sizing, and high-rate updates stay stable.
|
||||
|
||||
## High-level architecture
|
||||
|
||||
```text
|
||||
Public API
|
||||
↓
|
||||
Validation and configuration normalization
|
||||
↓
|
||||
Gauge registry and GaugeState
|
||||
↓
|
||||
Renderer on GUI thread
|
||||
↓
|
||||
Dear PyGui child/group + drawlist/text/items
|
||||
```
|
||||
|
||||
## Critical invariants
|
||||
|
||||
### Threading invariants
|
||||
|
||||
1. Dear PyGui APIs are called only on the GUI thread.
|
||||
2. Widget creation functions are GUI-thread-only.
|
||||
3. Runtime updates are GUI-thread-only unless explicitly documented otherwise.
|
||||
4. Worker threads may produce raw data, but application code must marshal values to the GUI thread.
|
||||
5. Locks should not be needed for normal gauge updates in the first release.
|
||||
|
||||
### State invariants
|
||||
|
||||
1. Every gauge has one `GaugeState` stored in the registry.
|
||||
2. Public tags identify logical gauges and should align with Dear PyGui behaviour where practical.
|
||||
3. Raw target value, clamped value, and displayed animated value are separate concepts.
|
||||
4. Thresholds and markers are configuration, not business logic.
|
||||
5. Out-of-range values clamp before rendering.
|
||||
6. Non-finite values enter an invalid display state instead of crashing.
|
||||
|
||||
### Rendering invariants
|
||||
|
||||
1. Static geometry and dynamic geometry should be separate where practical.
|
||||
2. Value updates should not rebuild static ticks, labels, threshold bands, or frames unless needed.
|
||||
3. Configuration changes mark the smallest reasonable dirty set.
|
||||
4. Redraws must not flicker through an empty state.
|
||||
5. Hidden or zero-size layouts must not permanently collapse a gauge.
|
||||
|
||||
### Sizing invariants
|
||||
|
||||
1. Requested size and measured size are stored separately.
|
||||
2. Drawlists use concrete measured dimensions.
|
||||
3. A measured size of zero while hidden does not overwrite the last useful non-zero size.
|
||||
4. Square gauges use the smaller dimension by default.
|
||||
5. Stretchable gauges can use the full available width/height.
|
||||
|
||||
## Package layout
|
||||
|
||||
```text
|
||||
src/dpg_gauges/
|
||||
__init__.py
|
||||
api.py
|
||||
widget.py
|
||||
state.py
|
||||
renderer.py
|
||||
draw_layers.py
|
||||
sizing.py
|
||||
animation.py
|
||||
smoothing.py
|
||||
scales.py
|
||||
themes.py
|
||||
gauges.py
|
||||
diagnostics.py
|
||||
types.py
|
||||
exceptions.py
|
||||
examples/
|
||||
basic_analog.py
|
||||
basic_digital.py
|
||||
basic_bar.py
|
||||
basic_level.py
|
||||
basic_status.py
|
||||
basic_segmented.py
|
||||
basic_compass.py
|
||||
basic_thermometer.py
|
||||
basic_battery.py
|
||||
basic_multi_value.py
|
||||
thresholds_markers.py
|
||||
animations.py
|
||||
dashboard.py
|
||||
sizing.py
|
||||
live_high_rate.py
|
||||
live_worst_case.py
|
||||
tests/
|
||||
docs/
|
||||
GETTING_STARTED.md
|
||||
EXAMPLES.md
|
||||
API_REFERENCE.md
|
||||
codex/
|
||||
README.md
|
||||
FEATURES.md
|
||||
ARCHITECTURE.md
|
||||
STEPS.md
|
||||
AGENTS.md
|
||||
```
|
||||
|
||||
## Module responsibilities
|
||||
|
||||
### `__init__.py`
|
||||
|
||||
Exports the public API only.
|
||||
|
||||
No expensive Dear PyGui initialization should happen here.
|
||||
|
||||
### `api.py`
|
||||
|
||||
Contains thin public wrappers:
|
||||
|
||||
- resolve gauge tags
|
||||
- validate and normalize simple arguments
|
||||
- call creation helpers
|
||||
- call state update helpers
|
||||
- expose stable runtime functions
|
||||
|
||||
`api.py` should not contain detailed drawing code.
|
||||
|
||||
### `types.py`
|
||||
|
||||
Defines shared types and dataclasses:
|
||||
|
||||
```python
|
||||
Tag = str | int
|
||||
Color = tuple[int, int, int] | tuple[int, int, int, int]
|
||||
GaugeValue = float | int | bool | str | None
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class ThresholdBand: ...
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GaugeMarker: ...
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AnimationConfig: ...
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SmoothingConfig: ...
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GaugeStats: ...
|
||||
```
|
||||
|
||||
### `exceptions.py`
|
||||
|
||||
Public exceptions:
|
||||
|
||||
```python
|
||||
class DpgGaugesError(Exception): ...
|
||||
class GaugeNotFoundError(DpgGaugesError): ...
|
||||
class GaugeConfigError(DpgGaugesError): ...
|
||||
class GaugeValueError(DpgGaugesError): ...
|
||||
class GaugeTypeError(DpgGaugesError): ...
|
||||
class ThreadingError(DpgGaugesError): ...
|
||||
```
|
||||
|
||||
### `state.py`
|
||||
|
||||
Owns global configuration, the gauge registry, and `GaugeState`.
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DpgGaugesConfig:
|
||||
default_theme: str | GaugeTheme | None = None
|
||||
animation: AnimationConfig | bool | None = None
|
||||
smoothing: SmoothingConfig | bool | None = None
|
||||
default_width: int | None = None
|
||||
default_height: int | None = None
|
||||
frame_rate_limit: float | None = None
|
||||
debug: bool = False
|
||||
|
||||
@dataclass
|
||||
class GaugeState:
|
||||
tag: Tag
|
||||
gauge_type: str
|
||||
container_tag: Tag
|
||||
drawlist_tag: Tag | None
|
||||
text_tags: dict[str, Tag]
|
||||
config: GaugeConfig
|
||||
target_value: GaugeValue
|
||||
clamped_value: float | None
|
||||
displayed_value: float | None
|
||||
previous_displayed_value: float | None
|
||||
value_revision: int = 0
|
||||
config_revision: int = 0
|
||||
measured_width: int = 0
|
||||
measured_height: int = 0
|
||||
last_nonzero_width: int = 0
|
||||
last_nonzero_height: int = 0
|
||||
dirty: DirtyFlags = DirtyFlags.FULL
|
||||
renderer: GaugeRenderer | None = None
|
||||
```
|
||||
|
||||
### `gauges.py`
|
||||
|
||||
Defines normalized configuration dataclasses for gauge families:
|
||||
|
||||
- `GaugeConfig`
|
||||
- `AnalogGaugeConfig`
|
||||
- `DigitalGaugeConfig`
|
||||
- `BarGaugeConfig`
|
||||
- `LevelGaugeConfig`
|
||||
- `StatusLightConfig`
|
||||
- `SegmentedGaugeConfig`
|
||||
- `CompassGaugeConfig`
|
||||
- `ThermometerGaugeConfig`
|
||||
- `BatteryGaugeConfig`
|
||||
- `MultiValueGaugeConfig`
|
||||
|
||||
This module should be mostly pure and easy to test.
|
||||
|
||||
### `widget.py`
|
||||
|
||||
Creates Dear PyGui items for gauges.
|
||||
|
||||
Typical internal structure:
|
||||
|
||||
```text
|
||||
group or child_window
|
||||
drawlist
|
||||
optional text/value items
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Creation functions enter a context manager when appropriate.
|
||||
- The logical gauge is registered before yielding.
|
||||
- Raw internal draw item tags are not required as public API.
|
||||
- Callback and tooltip wiring happens here or in a small helper.
|
||||
|
||||
### `renderer.py`
|
||||
|
||||
GUI-thread-only renderer.
|
||||
|
||||
Responsibilities:
|
||||
|
||||
- measure gauge size
|
||||
- apply animation/smoothing progression
|
||||
- rebuild dirty static layer
|
||||
- rebuild dirty dynamic layer
|
||||
- update text/value items
|
||||
- avoid unnecessary static redraws
|
||||
- expose debug state
|
||||
|
||||
Gauge rendering should prefer Dear PyGui drawlists for shapes, arcs, needles, bars, and custom
|
||||
visuals. Plain Dear PyGui text items may be used when that is simpler and more reliable.
|
||||
|
||||
### `draw_layers.py`
|
||||
|
||||
Tracks draw item tags by purpose:
|
||||
|
||||
```python
|
||||
@dataclass
|
||||
class DrawLayer:
|
||||
name: str
|
||||
item_tags: set[Tag] = field(default_factory=set)
|
||||
```
|
||||
|
||||
Suggested layers:
|
||||
|
||||
- background
|
||||
- static scale
|
||||
- thresholds
|
||||
- dynamic value
|
||||
- markers
|
||||
- text/debug
|
||||
|
||||
The renderer can delete and rebuild only selected layers.
|
||||
|
||||
### `sizing.py`
|
||||
|
||||
Provides helpers for measured dimensions and aspect decisions:
|
||||
|
||||
- track requested vs measured size
|
||||
- preserve last non-zero size
|
||||
- calculate square gauge rect
|
||||
- calculate stretch rect
|
||||
- detect hidden-to-visible transitions
|
||||
|
||||
### `animation.py`
|
||||
|
||||
Provides animation interpolation:
|
||||
|
||||
- linear interpolation
|
||||
- simple easing names
|
||||
- target/displayed value separation
|
||||
- frame scheduling rules
|
||||
|
||||
Avoid an overbuilt animation framework in the first release.
|
||||
|
||||
### `smoothing.py`
|
||||
|
||||
Provides optional readability smoothing:
|
||||
|
||||
- exponential moving average via `alpha`
|
||||
- optional `max_step`
|
||||
- reset behaviour when value jumps or gauge is reconfigured
|
||||
|
||||
### `scales.py`
|
||||
|
||||
Pure math helpers:
|
||||
|
||||
- clamp and normalize values
|
||||
- map value to angle
|
||||
- map value to bar fill fraction
|
||||
- generate tick values
|
||||
- format values
|
||||
- resolve threshold geometry
|
||||
|
||||
No Dear PyGui imports.
|
||||
|
||||
### `themes.py`
|
||||
|
||||
Lightweight presets and style normalization.
|
||||
|
||||
This should complement Dear PyGui theming, not replace it.
|
||||
|
||||
Built-in presets can include:
|
||||
|
||||
- `default`
|
||||
- `dark`
|
||||
- `minimal`
|
||||
- `motorsport`
|
||||
- `industrial`
|
||||
|
||||
### `diagnostics.py`
|
||||
|
||||
Provides:
|
||||
|
||||
```python
|
||||
def get_gauge_debug_state(tag) -> dict[str, Any]: ...
|
||||
```
|
||||
|
||||
Include:
|
||||
|
||||
- gauge type
|
||||
- target value
|
||||
- clamped value
|
||||
- displayed value
|
||||
- measured size
|
||||
- last non-zero size
|
||||
- dirty flags
|
||||
- value/config revisions
|
||||
- animation state
|
||||
- smoothing state
|
||||
|
||||
## Dirty flag model
|
||||
|
||||
Use bit flags:
|
||||
|
||||
```python
|
||||
class DirtyFlags(IntFlag):
|
||||
NONE = 0
|
||||
VALUE = auto()
|
||||
STATIC = auto()
|
||||
DYNAMIC = auto()
|
||||
TEXT = auto()
|
||||
SIZE = auto()
|
||||
STYLE = auto()
|
||||
DEBUG = auto()
|
||||
FULL = VALUE | STATIC | DYNAMIC | TEXT | SIZE | STYLE | DEBUG
|
||||
```
|
||||
|
||||
Expected usage:
|
||||
|
||||
| Operation | Dirty flags |
|
||||
|---|---|
|
||||
| value update | `VALUE | DYNAMIC | TEXT` |
|
||||
| animation tick | `DYNAMIC | TEXT` |
|
||||
| threshold update | `STATIC | DYNAMIC` |
|
||||
| marker update | `STATIC | DYNAMIC` |
|
||||
| label/unit/precision update | `TEXT` |
|
||||
| min/max update | `STATIC | DYNAMIC | TEXT` |
|
||||
| resize | `SIZE | STATIC | DYNAMIC | TEXT` |
|
||||
| style/theme update | `STYLE | STATIC | DYNAMIC | TEXT` |
|
||||
|
||||
## Frame and update lifecycle
|
||||
|
||||
For each gauge update:
|
||||
|
||||
```text
|
||||
1. Public API validates value/config.
|
||||
2. State target value/config is updated.
|
||||
3. Dirty flags are marked.
|
||||
4. Renderer is scheduled if needed.
|
||||
5. Renderer measures size.
|
||||
6. Renderer advances animation/smoothing.
|
||||
7. Renderer redraws static layers only if needed.
|
||||
8. Renderer redraws dynamic/text layers as needed.
|
||||
9. Dirty flags are cleared.
|
||||
10. Renderer continues scheduling frames only while animation/smoothing is active.
|
||||
```
|
||||
|
||||
## High-rate telemetry strategy
|
||||
|
||||
The first release should not promise background-thread-safe UI calls. Instead, examples should show
|
||||
the correct Dear PyGui pattern:
|
||||
|
||||
```text
|
||||
producer thread writes latest raw value to a lock-protected variable or queue
|
||||
GUI frame callback reads the newest value
|
||||
GUI frame callback calls dpgg.set_value(...)
|
||||
gauge renderer coalesces/animates/smooths visual changes
|
||||
```
|
||||
|
||||
This preserves Dear PyGui thread rules while still covering worst-case telemetry rates.
|
||||
|
||||
## Initial setup instructions
|
||||
|
||||
```bash
|
||||
mkdir dpg-gauges
|
||||
cd dpg-gauges
|
||||
git init
|
||||
uv init --package dpg-gauges
|
||||
uv add dearpygui
|
||||
uv add --dev pytest ruff pyright
|
||||
```
|
||||
|
||||
Recommended `pyproject.toml` additions:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "I", "UP", "B", "SIM"]
|
||||
|
||||
[tool.pyright]
|
||||
typeCheckingMode = "basic"
|
||||
```
|
||||
374
codex/FEATURES.md
Normal file
374
codex/FEATURES.md
Normal file
@@ -0,0 +1,374 @@
|
||||
# dpg-gauges Feature Specification
|
||||
|
||||
This document defines the public behaviour and API contract for `dpg-gauges`.
|
||||
|
||||
`dpg-gauges` is a Python package providing easy-to-use, high-performance Dear PyGui gauge
|
||||
widgets for vehicle telemetry, dyno displays, dashboards, and general numeric/status data.
|
||||
|
||||
It should be usable as:
|
||||
|
||||
```python
|
||||
import dpg_gauges as dpgg
|
||||
```
|
||||
|
||||
The first release must be practical to use quickly, but still built cleanly enough to avoid a
|
||||
rewrite after the first real dashboard.
|
||||
|
||||
## Product goals
|
||||
|
||||
- Provide a healthy set of common gauges out of the box.
|
||||
- Feel natural in Dear PyGui code and layout containers.
|
||||
- Support high-rate telemetry updates from the GUI thread without flicker.
|
||||
- Smooth or animate rapidly changing values so humans can read them.
|
||||
- Keep public API stable once introduced.
|
||||
- Be configurable enough for vehicle and dyno dashboards without forcing users to subclass.
|
||||
- Remain display-only for the first release.
|
||||
|
||||
## Non-goals for the first release
|
||||
|
||||
Do not implement these in the first release:
|
||||
|
||||
- Non-Dear PyGui backends
|
||||
- Arbitrary image/icon rendering inside gauges
|
||||
- Historical traces or sparklines
|
||||
- Gauge-driven threshold callbacks or alarms
|
||||
- Editable knobs/sliders
|
||||
- Complex custom shader/GPU renderers
|
||||
- Theme engines that replace Dear PyGui theming
|
||||
- Background-thread Dear PyGui updates
|
||||
|
||||
## Core requirements
|
||||
|
||||
### 1. Dear PyGui-native usage
|
||||
|
||||
Gauge widgets should behave like normal Dear PyGui widgets as much as possible:
|
||||
|
||||
```python
|
||||
with dpgg.analog_gauge(tag="rpm", label="RPM", min_value=0, max_value=8000, unit="rpm"):
|
||||
pass
|
||||
|
||||
dpgg.set_value("rpm", 3250)
|
||||
```
|
||||
|
||||
Creation functions are context managers so users can write layouts naturally:
|
||||
|
||||
```python
|
||||
with dpg.window(label="Dashboard"):
|
||||
with dpgg.gauge_panel(label="Engine"):
|
||||
dpgg.analog_gauge(tag="rpm", label="RPM", max_value=8000, redline_start=6500)
|
||||
dpgg.digital_gauge(tag="speed", label="Speed", unit="km/h")
|
||||
```
|
||||
|
||||
### 2. GUI-thread update contract
|
||||
|
||||
Dear PyGui item operations must happen on the GUI thread. Public creation functions are
|
||||
GUI-thread-only. Runtime updates are also intended for the GUI thread unless a function is
|
||||
explicitly documented otherwise.
|
||||
|
||||
High-rate data may be produced in worker threads, but the app should marshal the latest values to
|
||||
the GUI thread before calling `dpgg.set_value(...)` or `dpgg.update_gauge(...)`.
|
||||
|
||||
The package should still be robust against high-rate GUI-thread calls:
|
||||
|
||||
- value updates should be cheap
|
||||
- repeated value updates may coalesce to the latest value before draw
|
||||
- animation/smoothing should be optional
|
||||
- static gauge geometry should be reused where practical
|
||||
- dynamic draw layers should be rebuilt without flickering through empty states
|
||||
|
||||
### 3. Gauge catalogue
|
||||
|
||||
Required MVP gauge types:
|
||||
|
||||
- `digital_gauge`: large numeric readout with label, unit, precision, optional sign, and state color
|
||||
- `analog_gauge`: circular or arc dial with ticks, labels, needle, thresholds, target markers, and redline
|
||||
- `bar_gauge`: horizontal or vertical fill bar with thresholds and optional target marker
|
||||
- `level_gauge`: tank/level style gauge, useful for fuel, battery, fluids, and percentages
|
||||
- `status_light`: LED/status indicator with text, colors, blink/pulse option, and simple states
|
||||
- `segmented_gauge`: segmented bar or LED strip, useful for RPM shift lights or battery cells
|
||||
- `compass_gauge`: circular heading display for degrees, direction labels, and optional bearing marker
|
||||
- `thermometer_gauge`: vertical temperature-style display with colored bands
|
||||
- `battery_gauge`: battery-specific gauge with percentage/value display and charge/discharge state styling
|
||||
- `multi_value_gauge`: compact grouped numeric readout for related values, such as AFR/lambda/fuel pressure
|
||||
|
||||
Nice-to-have after MVP stability:
|
||||
|
||||
- `shift_light_gauge`: specialized segmented RPM/shift light strip
|
||||
- `delta_gauge`: positive/negative centered bar for lap delta, trim, or correction values
|
||||
- `mini_dial_gauge`: small dial optimized for dense dashboards
|
||||
- `radial_progress_gauge`: donut-style progress/value indicator
|
||||
|
||||
### 4. Configuration model
|
||||
|
||||
Common gauge configuration should cover most needs without requiring later public API churn.
|
||||
|
||||
Shared parameters should include where applicable:
|
||||
|
||||
```python
|
||||
tag: str | int | None = None
|
||||
label: str | None = None
|
||||
value: float | int | bool | str | None = 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: Callable | 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: Callable[[float], str] | None = None
|
||||
```
|
||||
|
||||
Visual configuration should include where applicable:
|
||||
|
||||
```python
|
||||
background_color: Color | None = None
|
||||
frame_color: Color | None = None
|
||||
value_color: Color | None = None
|
||||
text_color: Color | None = None
|
||||
muted_text_color: Color | None = None
|
||||
border_color: Color | None = None
|
||||
needle_color: Color | None = None
|
||||
tick_color: Color | None = None
|
||||
thresholds: Sequence[ThresholdBand] | None = None
|
||||
markers: Sequence[GaugeMarker] | None = None
|
||||
redline_start: float | None = None
|
||||
redline_color: Color = (255, 45, 45, 255)
|
||||
```
|
||||
|
||||
Analog-specific configuration should include:
|
||||
|
||||
```python
|
||||
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
|
||||
```
|
||||
|
||||
Bar/level-specific configuration should include:
|
||||
|
||||
```python
|
||||
orientation: Literal["horizontal", "vertical"] = "horizontal"
|
||||
fill_mode: Literal["clamp", "centered"] = "clamp"
|
||||
corner_radius: float = 4.0
|
||||
show_scale: bool = True
|
||||
stretch: bool = True
|
||||
```
|
||||
|
||||
Status-specific configuration should include:
|
||||
|
||||
```python
|
||||
state: str | bool | int = False
|
||||
states: Mapping[Any, StatusState] | None = None
|
||||
blink: bool = False
|
||||
pulse: bool = False
|
||||
```
|
||||
|
||||
### 5. Thresholds and markers
|
||||
|
||||
Thresholds are visual bands only. They must not trigger callbacks or business logic.
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class ThresholdBand:
|
||||
start: float
|
||||
end: float
|
||||
color: Color
|
||||
label: str | None = None
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class GaugeMarker:
|
||||
value: float
|
||||
color: Color
|
||||
label: str | None = None
|
||||
thickness: float = 2.0
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Thresholds and markers are clamped to the gauge range for drawing.
|
||||
- Invalid threshold ordering raises during configuration.
|
||||
- Overlapping thresholds are allowed and draw in given order.
|
||||
- `redline_start` is convenience syntax for a threshold from `redline_start` to `max_value`.
|
||||
|
||||
### 6. Value behaviour
|
||||
|
||||
- Numeric values clamp to `min_value` and `max_value` by default.
|
||||
- Displayed value should match the clamped visual value.
|
||||
- Non-finite numeric values should enter an invalid display state rather than crash.
|
||||
- `None` should show an empty/unknown state if supported by the gauge.
|
||||
- Precision and formatting must be consistent across digital text and visual geometry.
|
||||
|
||||
### 7. Animation and smoothing
|
||||
|
||||
Animation should be optional per gauge and globally configurable.
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class AnimationConfig:
|
||||
enabled: bool = True
|
||||
duration: float = 0.15
|
||||
easing: str = "linear"
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SmoothingConfig:
|
||||
enabled: bool = False
|
||||
alpha: float = 0.35
|
||||
max_step: float | None = None
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- Animation changes what is drawn, not the logical target value.
|
||||
- Smoothing is for readability, not data processing.
|
||||
- Users can disable animation for exact instantaneous displays.
|
||||
- High-rate updates should converge toward the newest target value without queue buildup.
|
||||
|
||||
### 8. Layout and sizing
|
||||
|
||||
Gauges must support common Dear PyGui size behaviour:
|
||||
|
||||
- `width=0` and `height=0` preserve Dear PyGui default behaviour.
|
||||
- `width=-1` fills available width.
|
||||
- `height=-1` fills available height where Dear PyGui allows it.
|
||||
- Positive dimensions are respected.
|
||||
- `autosize_x` and `autosize_y` are supported where practical.
|
||||
- Analog/compass/radial gauges maintain square aspect by default.
|
||||
- Digital/bar/segmented gauges can stretch horizontally.
|
||||
- Widgets should work in windows, groups, child windows, tabs, tables, and hidden/show-later layouts.
|
||||
|
||||
### 9. Dashboard helpers
|
||||
|
||||
Provide light helpers, not a full layout engine:
|
||||
|
||||
```python
|
||||
with dpgg.gauge_panel(label="Engine", width=-1):
|
||||
...
|
||||
|
||||
with dpgg.gauge_grid(columns=3, width=-1):
|
||||
...
|
||||
```
|
||||
|
||||
Dashboard helpers should use normal Dear PyGui containers internally and not block users from using
|
||||
native Dear PyGui layouts directly.
|
||||
|
||||
### 10. Public API
|
||||
|
||||
Required exports:
|
||||
|
||||
```python
|
||||
configure
|
||||
|
||||
GaugeTheme
|
||||
GaugeStyle
|
||||
AnimationConfig
|
||||
SmoothingConfig
|
||||
ThresholdBand
|
||||
GaugeMarker
|
||||
StatusState
|
||||
GaugeValue
|
||||
GaugeStats
|
||||
|
||||
analog_gauge
|
||||
digital_gauge
|
||||
bar_gauge
|
||||
level_gauge
|
||||
status_light
|
||||
segmented_gauge
|
||||
compass_gauge
|
||||
thermometer_gauge
|
||||
battery_gauge
|
||||
multi_value_gauge
|
||||
|
||||
gauge_panel
|
||||
gauge_grid
|
||||
|
||||
set_value
|
||||
get_value
|
||||
update_gauge
|
||||
configure_gauge
|
||||
set_thresholds
|
||||
set_markers
|
||||
set_show
|
||||
delete_gauge
|
||||
|
||||
get_gauge_debug_state
|
||||
```
|
||||
|
||||
### 11. Global configuration
|
||||
|
||||
```python
|
||||
dpgg.configure(
|
||||
*,
|
||||
default_theme: str | GaugeTheme | None = None,
|
||||
animation: AnimationConfig | bool | None = None,
|
||||
smoothing: SmoothingConfig | bool | None = None,
|
||||
default_width: int | None = None,
|
||||
default_height: int | None = None,
|
||||
frame_rate_limit: float | None = None,
|
||||
debug: bool = False,
|
||||
) -> None
|
||||
```
|
||||
|
||||
### 12. Runtime API
|
||||
|
||||
```python
|
||||
dpgg.set_value(tag, value: GaugeValue) -> None
|
||||
dpgg.get_value(tag) -> GaugeValue
|
||||
|
||||
dpgg.update_gauge(
|
||||
tag,
|
||||
*,
|
||||
value: GaugeValue | None = None,
|
||||
label: str | None = None,
|
||||
unit: str | None = None,
|
||||
min_value: float | None = None,
|
||||
max_value: float | None = None,
|
||||
thresholds: Sequence[ThresholdBand] | None = None,
|
||||
markers: Sequence[GaugeMarker] | None = None,
|
||||
show: bool | None = None,
|
||||
) -> None
|
||||
|
||||
dpgg.configure_gauge(tag, **config) -> None
|
||||
dpgg.set_thresholds(tag, thresholds: Sequence[ThresholdBand]) -> None
|
||||
dpgg.set_markers(tag, markers: Sequence[GaugeMarker]) -> None
|
||||
dpgg.set_show(tag, show: bool) -> None
|
||||
dpgg.delete_gauge(tag) -> None
|
||||
```
|
||||
|
||||
Runtime functions are GUI-thread functions unless explicitly documented otherwise.
|
||||
|
||||
### 13. Acceptance tests
|
||||
|
||||
Before the first usable release:
|
||||
|
||||
1. Every gauge type can be created in a basic example.
|
||||
2. Analog, digital, bar, level, status, segmented, compass, thermometer, battery, and multi-value gauges render without terminal errors.
|
||||
3. Gauges update from GUI-thread frame callbacks at normal telemetry rates.
|
||||
4. Stress examples tolerate producer rates above 60 Hz by using latest-value marshalling to the GUI thread.
|
||||
5. Animation and smoothing can be enabled and disabled.
|
||||
6. Thresholds and markers render correctly and do not trigger callbacks.
|
||||
7. Out-of-range values clamp and display min/max.
|
||||
8. Hidden tab examples do not permanently collapse gauge size.
|
||||
9. Analog gauges maintain square aspect by default.
|
||||
10. Bar/digital gauges can stretch horizontally.
|
||||
11. Dashboard helpers work with grouped gauges.
|
||||
12. Local editable install works with `uv add --editable ../dpg-gauges`.
|
||||
18
codex/README.md
Normal file
18
codex/README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Codex Build Notes
|
||||
|
||||
This folder contains internal build instructions, implementation architecture notes, and the
|
||||
rolling agent log for `dpg-gauges`.
|
||||
|
||||
These files are not the final user-facing package documentation:
|
||||
|
||||
- `AGENTS.md`: rolling implementation log and current build status
|
||||
- `ARCHITECTURE.md`: internal architecture, module responsibilities, and invariants
|
||||
- `FEATURES.md`: public feature and API contract
|
||||
- `STEPS.md`: ordered implementation plan
|
||||
|
||||
User-facing documentation should live in:
|
||||
|
||||
- `../README.md`
|
||||
- `../docs/GETTING_STARTED.md`
|
||||
- `../docs/EXAMPLES.md`
|
||||
- `../docs/API_REFERENCE.md`
|
||||
503
codex/STEPS.md
Normal file
503
codex/STEPS.md
Normal file
@@ -0,0 +1,503 @@
|
||||
# dpg-gauges Build Steps
|
||||
|
||||
There is no Step 0. Initial setup is listed separately, then implementation starts at Step 1.
|
||||
|
||||
## Workflow rules
|
||||
|
||||
1. Use `uv` for all Python package and dependency management.
|
||||
2. Always read `codex/FEATURES.md`, `codex/ARCHITECTURE.md`, and `codex/AGENTS.md` before making code changes.
|
||||
3. Keep `codex/AGENTS.md` as a rolling log of what has been done, what is broken, and what comes next.
|
||||
4. Update `README.md` and `docs/` whenever public behaviour or examples change.
|
||||
5. After every step, update `codex/AGENTS.md`, run relevant checks, and commit if working in git.
|
||||
6. Do not casually change public API once introduced.
|
||||
7. Dear PyGui calls must happen on the GUI thread only.
|
||||
8. Runtime gauge updates are GUI-thread-only unless explicitly documented otherwise.
|
||||
9. Prefer stable, boring implementation over clever drawing tricks.
|
||||
10. Keep each step shippable and tested before moving to the next.
|
||||
|
||||
## Initial setup instructions
|
||||
|
||||
Run these before Step 1 when starting from a clean repository:
|
||||
|
||||
```bash
|
||||
mkdir dpg-gauges
|
||||
cd dpg-gauges
|
||||
git init
|
||||
uv init --package dpg-gauges
|
||||
uv add dearpygui
|
||||
uv add --dev pytest ruff pyright
|
||||
```
|
||||
|
||||
Create this structure:
|
||||
|
||||
```text
|
||||
src/dpg_gauges/
|
||||
__init__.py
|
||||
api.py
|
||||
widget.py
|
||||
state.py
|
||||
renderer.py
|
||||
draw_layers.py
|
||||
sizing.py
|
||||
animation.py
|
||||
smoothing.py
|
||||
scales.py
|
||||
themes.py
|
||||
gauges.py
|
||||
diagnostics.py
|
||||
types.py
|
||||
exceptions.py
|
||||
examples/
|
||||
tests/
|
||||
docs/
|
||||
codex/FEATURES.md
|
||||
codex/ARCHITECTURE.md
|
||||
codex/STEPS.md
|
||||
codex/AGENTS.md
|
||||
README.md
|
||||
```
|
||||
|
||||
Recommended `pyproject.toml` additions:
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "I", "UP", "B", "SIM"]
|
||||
|
||||
[tool.pyright]
|
||||
typeCheckingMode = "basic"
|
||||
```
|
||||
|
||||
Initial checks:
|
||||
|
||||
```bash
|
||||
uv run python -c "import dpg_gauges; print(dpg_gauges.__name__)"
|
||||
uv run ruff check .
|
||||
uv run ruff format .
|
||||
```
|
||||
|
||||
## Step 1 - Public API contract and pure core
|
||||
|
||||
Goal: lock the public API surface and implement pure non-DPG components first.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Define public exports in `__init__.py`.
|
||||
|
||||
Required API names:
|
||||
|
||||
```python
|
||||
configure
|
||||
|
||||
GaugeTheme
|
||||
GaugeStyle
|
||||
AnimationConfig
|
||||
SmoothingConfig
|
||||
ThresholdBand
|
||||
GaugeMarker
|
||||
StatusState
|
||||
GaugeStats
|
||||
|
||||
analog_gauge
|
||||
digital_gauge
|
||||
bar_gauge
|
||||
level_gauge
|
||||
status_light
|
||||
segmented_gauge
|
||||
compass_gauge
|
||||
thermometer_gauge
|
||||
battery_gauge
|
||||
multi_value_gauge
|
||||
|
||||
gauge_panel
|
||||
gauge_grid
|
||||
|
||||
set_value
|
||||
get_value
|
||||
update_gauge
|
||||
configure_gauge
|
||||
set_thresholds
|
||||
set_markers
|
||||
set_show
|
||||
delete_gauge
|
||||
|
||||
get_gauge_debug_state
|
||||
```
|
||||
|
||||
2. Add exceptions in `exceptions.py`.
|
||||
3. Add shared dataclasses and types in `types.py`.
|
||||
4. Implement configuration normalization dataclasses in `gauges.py`.
|
||||
5. Implement pure scale helpers in `scales.py`.
|
||||
6. Implement lightweight theme/style presets in `themes.py`.
|
||||
7. Stub GUI-dependent public functions so imports succeed.
|
||||
8. Add tests for imports, dataclass construction, clamp/normalize math, tick generation, threshold validation, and formatting.
|
||||
|
||||
Checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- public API imports cleanly
|
||||
- pure gauge config can be created and validated
|
||||
- value clamping and formatting are tested
|
||||
- no Dear PyGui context is required for Step 1 tests
|
||||
- API names are fixed before renderer work begins
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 1: lock public api and pure core"
|
||||
```
|
||||
|
||||
## Step 2 - State, sizing, animation, and smoothing model
|
||||
|
||||
Goal: build the logical model before rendering final visuals.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Implement `DpgGaugesConfig` and `configure(...)`.
|
||||
2. Implement `GaugeState` and global gauge registry.
|
||||
3. Implement `DirtyFlags`.
|
||||
4. Implement sizing helpers:
|
||||
- requested size vs measured size
|
||||
- last non-zero size preservation
|
||||
- square gauge rect
|
||||
- stretch gauge rect
|
||||
5. Implement animation interpolation in `animation.py`.
|
||||
6. Implement smoothing helpers in `smoothing.py`.
|
||||
7. Implement runtime state functions for `set_value`, `get_value`, `update_gauge`, `set_thresholds`, `set_markers`, `set_show`, and `delete_gauge` without final drawing complexity.
|
||||
8. Add tests for registry behaviour, value/clamped/displayed separation, dirty flags, sizing transitions, animation interpolation, smoothing progression, and invalid values.
|
||||
|
||||
Checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- values clamp to min/max
|
||||
- non-finite values do not crash pure state helpers
|
||||
- dirty flags distinguish value, static, dynamic, text, size, and style changes
|
||||
- smoothing and animation are optional and testable without Dear PyGui
|
||||
- hidden/zero-size state does not erase last non-zero size
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 2: add gauge state sizing and animation model"
|
||||
```
|
||||
|
||||
## Step 3 - Widget shell and renderer foundation
|
||||
|
||||
Goal: create stable Dear PyGui gauge shells and a renderer that can draw placeholders without flicker.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Implement gauge creation context managers in `widget.py`.
|
||||
2. Create internal group/child/drawlist structures for gauge widgets.
|
||||
3. Register each gauge before yielding from the context manager.
|
||||
4. Implement `GaugeRenderer` foundation:
|
||||
- measure size
|
||||
- schedule frame callbacks where animation is active
|
||||
- draw placeholder background/frame/value text
|
||||
- expose debug state
|
||||
5. Implement `draw_layers.py` bookkeeping.
|
||||
6. Implement `gauge_panel` and `gauge_grid` as lightweight layout helpers.
|
||||
7. Add examples:
|
||||
- `examples/basic_digital.py`
|
||||
- `examples/basic_analog.py`
|
||||
- `examples/sizing.py`
|
||||
- `examples/dashboard.py`
|
||||
8. Add Dear PyGui context smoke tests where feasible.
|
||||
|
||||
Manual checks:
|
||||
|
||||
```bash
|
||||
uv run python examples/basic_digital.py
|
||||
uv run python examples/basic_analog.py
|
||||
uv run python examples/sizing.py
|
||||
uv run python examples/dashboard.py
|
||||
```
|
||||
|
||||
Automated checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- gauge shells appear inside Dear PyGui windows
|
||||
- widgets respect basic width/height options
|
||||
- hidden/show-later layout does not permanently collapse sizes
|
||||
- debug state reports useful state
|
||||
- no flicker through empty drawlists on simple value changes
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 3: add widget shell and renderer foundation"
|
||||
```
|
||||
|
||||
## Step 4 - Digital, bar, level, and status gauges
|
||||
|
||||
Goal: implement the simplest high-value gauges first.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Implement `digital_gauge` rendering.
|
||||
2. Implement `bar_gauge` rendering with horizontal/vertical orientation.
|
||||
3. Implement `level_gauge` rendering.
|
||||
4. Implement `status_light` rendering.
|
||||
5. Implement threshold and marker drawing for bar/level where applicable.
|
||||
6. Implement optional tooltips and callbacks.
|
||||
7. Add examples:
|
||||
- `examples/basic_digital.py`
|
||||
- `examples/basic_bar.py`
|
||||
- `examples/basic_level.py`
|
||||
- `examples/basic_status.py`
|
||||
- `examples/thresholds_markers.py`
|
||||
8. Add tests for pure geometry and runtime update state.
|
||||
|
||||
Manual checks:
|
||||
|
||||
```bash
|
||||
uv run python examples/basic_digital.py
|
||||
uv run python examples/basic_bar.py
|
||||
uv run python examples/basic_level.py
|
||||
uv run python examples/basic_status.py
|
||||
uv run python examples/thresholds_markers.py
|
||||
```
|
||||
|
||||
Automated checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- digital values format correctly
|
||||
- bar/level fill fraction is correct and clamped
|
||||
- status states display configured colors/text
|
||||
- thresholds and markers render visually without events
|
||||
- stretchable gauges behave in resizable layouts
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 4: add digital bar level and status gauges"
|
||||
```
|
||||
|
||||
## Step 5 - Analog, segmented, compass, thermometer, battery, and multi-value gauges
|
||||
|
||||
Goal: complete the first-release gauge catalogue.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Implement `analog_gauge`:
|
||||
- arcs
|
||||
- ticks
|
||||
- tick labels
|
||||
- needle
|
||||
- redline
|
||||
- markers
|
||||
2. Implement `segmented_gauge`.
|
||||
3. Implement `compass_gauge`.
|
||||
4. Implement `thermometer_gauge`.
|
||||
5. Implement `battery_gauge`.
|
||||
6. Implement `multi_value_gauge`.
|
||||
7. Ensure square gauges maintain aspect ratio by default.
|
||||
8. Add examples:
|
||||
- `examples/basic_segmented.py`
|
||||
- `examples/basic_compass.py`
|
||||
- `examples/basic_thermometer.py`
|
||||
- `examples/basic_battery.py`
|
||||
- `examples/basic_multi_value.py`
|
||||
9. Add tests for value-to-angle math, tick generation, compass wraparound, segment activation, battery clamp, and multi-value config validation.
|
||||
|
||||
Manual checks:
|
||||
|
||||
```bash
|
||||
uv run python examples/basic_analog.py
|
||||
uv run python examples/basic_segmented.py
|
||||
uv run python examples/basic_compass.py
|
||||
uv run python examples/basic_thermometer.py
|
||||
uv run python examples/basic_battery.py
|
||||
uv run python examples/basic_multi_value.py
|
||||
```
|
||||
|
||||
Automated checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- all MVP gauge types render
|
||||
- analog redline and markers render correctly
|
||||
- compass wraps heading values sensibly
|
||||
- segmented gauges support dense shift-light style displays
|
||||
- square gauges do not distort in common layouts
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 5: complete first gauge catalogue"
|
||||
```
|
||||
|
||||
## Step 6 - High-rate updates, animation, and stress examples
|
||||
|
||||
Goal: prove gauges remain readable and stable under fast telemetry.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Integrate animation into renderer scheduling.
|
||||
2. Integrate optional smoothing into value rendering.
|
||||
3. Ensure repeated GUI-thread `set_value` calls coalesce naturally to the newest target.
|
||||
4. Add examples:
|
||||
- `examples/animations.py`
|
||||
- `examples/live_high_rate.py`
|
||||
- `examples/live_worst_case.py`
|
||||
5. High-rate examples should use a producer thread for data generation and GUI-thread frame callbacks for Dear PyGui updates.
|
||||
6. Add debug fields for animation/smoothing state.
|
||||
7. Add tests for animation convergence, smoothing reset behaviour, and latest-target wins.
|
||||
|
||||
Manual stress checks:
|
||||
|
||||
```bash
|
||||
uv run python examples/animations.py
|
||||
uv run python examples/live_high_rate.py
|
||||
uv run python examples/live_worst_case.py
|
||||
```
|
||||
|
||||
While examples run:
|
||||
|
||||
- drive updates above 60 Hz where possible
|
||||
- verify gauges do not flicker
|
||||
- verify values remain human-readable with smoothing enabled
|
||||
- verify animation can be disabled for immediate response
|
||||
- verify UI remains responsive
|
||||
|
||||
Automated checks:
|
||||
|
||||
```bash
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- high-rate examples remain stable
|
||||
- smoothing and animation are configurable per gauge
|
||||
- no unbounded update queue exists
|
||||
- renderer only schedules continuous frames while needed
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 6: add animation and high rate update stress tests"
|
||||
```
|
||||
|
||||
## Step 7 - Documentation, hardening, and beta release
|
||||
|
||||
Goal: make the package usable as a dependency in DataFlux and public projects.
|
||||
|
||||
Tasks:
|
||||
|
||||
1. Write `README.md` with:
|
||||
- install
|
||||
- minimal analog/digital examples
|
||||
- dashboard example
|
||||
- GUI-thread update contract
|
||||
- animation/smoothing explanation
|
||||
- threshold/marker examples
|
||||
2. Write docs:
|
||||
- `docs/GETTING_STARTED.md`
|
||||
- `docs/EXAMPLES.md`
|
||||
- `docs/API_REFERENCE.md`
|
||||
3. Add docstrings for all public functions.
|
||||
4. Review public API exports.
|
||||
5. Add hardening tests for:
|
||||
- unknown gauge
|
||||
- duplicate tag
|
||||
- invalid range
|
||||
- invalid threshold
|
||||
- invalid marker
|
||||
- non-finite value
|
||||
- deleted gauge updates
|
||||
- hidden layout sizing
|
||||
- animation disabled/enabled
|
||||
6. Run all examples manually.
|
||||
7. Test local editable install from another project:
|
||||
|
||||
```bash
|
||||
uv add --editable ../dpg-gauges
|
||||
uv run python -c "import dpg_gauges as dpgg; print(dpgg.__name__)"
|
||||
```
|
||||
|
||||
8. Bump version.
|
||||
|
||||
Suggested initial beta:
|
||||
|
||||
```text
|
||||
0.1.0b1
|
||||
```
|
||||
|
||||
Final checks:
|
||||
|
||||
```bash
|
||||
uv sync
|
||||
uv run pytest
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run pyright
|
||||
```
|
||||
|
||||
Acceptance criteria:
|
||||
|
||||
- all examples run
|
||||
- local editable dependency works
|
||||
- docs cover all public gauge types
|
||||
- high-rate examples are stable
|
||||
- README clearly documents Dear PyGui GUI-thread expectations
|
||||
- `codex/AGENTS.md` accurately describes status
|
||||
|
||||
Commit:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "step 7: harden docs and prepare beta"
|
||||
git tag v0.1.0b1
|
||||
```
|
||||
Reference in New Issue
Block a user