505 lines
12 KiB
Markdown
505 lines
12 KiB
Markdown
# 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 the completed step when 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.
|
|
11. Do not start the next step while the previous completed step is still uncommitted.
|
|
|
|
## 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
|
|
```
|