127 lines
8.5 KiB
Markdown
127 lines
8.5 KiB
Markdown
# Adjustable/Detector widget views
|
|
|
|
Every {py:class}`~eco.elements.protocols.Adjustable` or
|
|
{py:class}`~eco.elements.protocols.Detector` in an assembly can be looked at
|
|
live from either front end — the Qt desktop workbench or a browser
|
|
(JupyterLab/Voila, via ipywidgets). Both build one row per item from the same
|
|
underlying `get_current_value()`/`set_target_value()` interface, but they are
|
|
two independent implementations with different capabilities, described below.
|
|
|
|
## Default per-item row
|
|
|
|
### Qt desktop (`eco.widgets.display_qt`)
|
|
|
|
The desktop app's dockable property grid ({py:class}`~eco.widgets.display_qt.DisplayQt`,
|
|
also used standalone via `make_assembly_qt_window`) shows a **name / current /
|
|
control** row per item, polled on a background thread:
|
|
|
|

|
|
|
|
- **Detector-only** items are read-only text — no controls.
|
|
- **Numeric Adjustables** get a step-size field, ▲/▼ tweak buttons (move
|
|
relative to the *live* current value, not the last-displayed one), an
|
|
absolute-value entry, and 🛑 Stop / ↺ Reset (back to the value from when the
|
|
row was built).
|
|
- **Enum-valued Adjustables** (anything exposing `enum_strs`, e.g.
|
|
`AdjustablePvEnum`) get a dropdown instead of step/absolute controls, same
|
|
Stop/Reset pair.
|
|
- Right-clicking a name label opens **"Add indicator"** — see below.
|
|
|
|
### ipywidgets (`eco.widgets.assembly_browser`)
|
|
|
|
The browser-side namespace/assembly browser used by the `lab`/`voila`
|
|
front ends builds each row as a plain ipywidgets `HBox`
|
|
({py:class}`~eco.widgets.assembly_browser._ItemWidget`):
|
|
|
|

|
|
|
|
- Name, Python type, and `repr()` of the current value are always shown.
|
|
- **Adjustables** get a free-text entry plus a **Set** button (best-effort
|
|
type coercion against the current value — bool/int/float/fallback JSON);
|
|
there is no step/tweak concept here, no Stop, and no live polling — value
|
|
updates only on explicit **Refresh** (Detectors) or after a successful
|
|
**Set** (Adjustables).
|
|
- **Detectors** get a **Refresh** button only.
|
|
|
|
This is a simpler, more manual sibling of the Qt row — it works anywhere a
|
|
kernel/comm can reach a browser (including Voila, with no desktop Qt
|
|
involved) but does not poll live and has no notion of enum dropdowns, tweak
|
|
steps, or in-flight move stopping.
|
|
|
|
## Indicator / gadget widgets
|
|
|
|
For a LabVIEW-style live panel — LEDs, gauges, dials — instead of a grid row,
|
|
eco provides small standalone gadgets, one per item. The current direction is
|
|
a **matched, as-simple-as-possible pair**, one module per backend, both built
|
|
entirely from each toolkit's own stock controls (no new dependency, no
|
|
custom-painted graphics) and sharing the same function names/signatures so
|
|
either is a drop-in for the other:
|
|
|
|
- {py:mod}`eco.widgets.indicator_widgets_ipy` — ipywidgets (`lab`/`voila`)
|
|
- `eco.widgets.indicator_widgets_qt_simple` — Qt desktop
|
|
|
|

|
|
|
|
*ipywidgets — `eco.widgets.indicator_widgets_ipy`*
|
|
|
|
![The same seven gadgets on the Qt side, built from plain QWidgets: a green circular QPushButton for shutter_open, a vertical QProgressBar for pressure, a horizontal QProgressBar for energy, a QProgressBar plus a "value [lo .. hi]" label for intensity, a large QLabel for counts, a row of checkable QPushButtons for mode's enum choices, and a QSlider for position.](images/widget_indicator_gadgets_qt_simple.png)
|
|
|
|
*Qt — `eco.widgets.indicator_widgets_qt_simple`*
|
|
|
|
| Gadget (same name, both modules) | ipywidgets control | Qt control | Notes |
|
|
|---|---|---|---|
|
|
| `led_indicator` | `Button` (`button_style`) | `QPushButton` (stylesheet) | click to toggle if settable; a plain label/HTML can't take a click back |
|
|
| `bar_gauge` | `FloatProgress` | `QProgressBar` | vertical or horizontal fill against `[vmin, vmax]` |
|
|
| `analog_gauge` | `FloatProgress` (horizontal) | `QProgressBar` (horizontal) | **approximation** — no needle; see below |
|
|
| `strip_chart` | `FloatProgress` + label | `QProgressBar` + label | **approximation** — position within the min/max seen so far, not a rolling line; see below |
|
|
| `numeric_tile` | `HTML` | `QLabel` (enlarged font) | large number, no sparkline (same reasoning as `strip_chart`) |
|
|
| `dial` | `ToggleButtons` (enum) / `FloatSlider` (numeric) | checkable `QPushButton` row (enum) / `QSlider` (numeric) | enum case shows every choice at once; dragging a value in a circle isn't idiomatic UX on either toolkit, so the numeric case reuses the slider rather than faking a knob |
|
|
| `slider` | `FloatSlider` | `QSlider` | writes on release if settable |
|
|
|
|
Five of the seven are exact stock-widget matches on both sides. The other two
|
|
(`analog_gauge`, `strip_chart`) are deliberately left as plain bar/value
|
|
approximations rather than reaching for a new dependency — see either
|
|
module's docstring. If a real needle gauge or a real rolling plot is wanted
|
|
later, the candidates worth reviewing first:
|
|
|
|
- **Plotly `go.Indicator`** (`mode="gauge+number"` for the needle gauge,
|
|
`mode="number+delta"` for a nicer KPI tile) — its `FigureWidget` is a real
|
|
`ipywidgets.DOMWidget`, so it drops straight into the same `VBox`/`HBox`
|
|
rows these gadgets already use, and updates live via
|
|
`fig.data[0].value = x`. The single-best "one new dependency, covers both
|
|
gaps" option.
|
|
- **bqplot** — a proper live-updating line plot (`Lines`/`Figure`) for
|
|
`strip_chart`; itself a real Jupyter widget, no needle-gauge support.
|
|
- **Panel** (`panel.widgets.indicators.Gauge`/`Dial`/`BooleanStatus`) — the
|
|
closest visual match to the Qt gadgets overall, but a separate framework
|
|
built on Bokeh; its `pn.ipywidget()` bridge into plain `ipywidgets`
|
|
layouts has known rough edges (no JS-linking, some nested-container
|
|
issues), and it pulls in Bokeh as a second rendering stack.
|
|
- **anywidget** — the modern, low-effort way to wrap any JS/web-component
|
|
(e.g. a real rotary-drag knob, a glowing LED) as a first-class Jupyter
|
|
widget, if a literal LabVIEW look is ever wanted beyond what the above
|
|
give. Worth knowing about, not needed for anything on this page.
|
|
|
|
Neither module has a discovery UI yet ("right-click a name → add gadget" on
|
|
Qt, or an equivalent on the notebook side) — call the function directly for
|
|
now, e.g. `eco.widgets.indicator_widgets_ipy.bar_gauge(my_assembly.pressure, vmin=0, vmax=100)`
|
|
or the equivalent `eco.widgets.indicator_widgets_qt_simple.bar_gauge(...)`.
|
|
|
|
### The older, hand-painted Qt gadgets
|
|
|
|
`eco.widgets.indicator_widgets` — the original, richer Qt-only module (real
|
|
needle gauge, a radial mode-select dial face, a live rolling strip-chart) —
|
|
still exists and is unrelated to the simple pair above, not superseded by
|
|
it. It's wired into the desktop app's right-click **"Add indicator"** menu
|
|
and a droppable {py:class}`~eco.widgets.dashboard_qt.Dashboard`, and its
|
|
gadgets double as valid Qt Designer "promoted widgets":
|
|
|
|

|
|
|
|
See its module docstring for the full gadget list and
|
|
`eco.widgets.indicator_widgets.attach_indicator_menu` for how it's wired
|
|
into `eco.widgets.display_qt`'s property grid. Reach for this one if the
|
|
simple pair's two approximations (no needle, no rolling line) actually
|
|
matter for a given panel; otherwise the matched simple pair above is the
|
|
current default recommendation for new work, on either backend.
|