plesty.lib.ui.qt
PySide6 backend of the PLESTY shell.
Importing this package requires the gui extra
(uv add "plesty-lib[gui]"): PySide6 and pyqtgraph. Everything above it —
Panel, Theme,
MonitorPanel — imports without a GUI
installed, so headless hosts and CI keep working.
Submodules
Classes
Draw target that renders a monitor's traces into a pyqtgraph widget. |
|
Capture a window while active; encode a video file on stop. |
|
One sub-window of the shell, wrapping a |
|
Title bar of a sub-window: state dot, title, live status, controls. |
|
Home window hosting every panel as a rearrangeable sub-window. |
Functions
|
Return the running Qt application, creating it when there is none. |
|
Create a shell hosting panels, without starting the event loop. |
|
Open a shell on panels and run it until the window is closed. |
Package Contents
- plesty.lib.ui.qt.application(name: str = 'PLESTY') PySide6.QtWidgets.QApplication
Return the running Qt application, creating it when there is none.
- Parameters:
name (str) – Application name, used by the window manager.
- Returns:
The
QApplicationinstance.- Return type:
PySide6.QtWidgets.QApplication
- plesty.lib.ui.qt.build_shell(panels: Sequence[plesty.lib.ui.panel.Panel], *, title: str = 'PLESTY', theme: plesty.lib.ui.theme.Theme | None = None, interval_ms: int = 500, layout_file: str | pathlib.Path | None = None, remember_layout: bool = True) plesty.lib.ui.qt.shell.Shell
Create a shell hosting panels, without starting the event loop.
- Parameters:
panels (Sequence[plesty.lib.ui.panel.Panel]) – Panels to add, in the order they should be docked.
title (str) – Window title and layout key.
theme (Optional[plesty.lib.ui.theme.Theme]) – Palette;
Noneloads the packaged PLESTY theme.interval_ms (int) – Panel refresh interval in milliseconds.
layout_file (Optional[str | pathlib.Path]) – Where the arrangement is stored.
remember_layout (bool) – Restore and save the arrangement.
- Returns:
The shell, ready for
start().- Return type:
- plesty.lib.ui.qt.run(panels: Sequence[plesty.lib.ui.panel.Panel], *, title: str = 'PLESTY', theme: plesty.lib.ui.theme.Theme | None = None, interval_ms: int = 500, layout_file: str | pathlib.Path | None = None, remember_layout: bool = True) int
Open a shell on panels and run it until the window is closed.
- Parameters:
panels (Sequence[plesty.lib.ui.panel.Panel]) – Panels to add, in the order they should be docked.
title (str) – Window title and layout key.
theme (Optional[plesty.lib.ui.theme.Theme]) – Palette;
Noneloads the packaged PLESTY theme.interval_ms (int) – Panel refresh interval in milliseconds.
layout_file (Optional[str | pathlib.Path]) – Where the arrangement is stored.
remember_layout (bool) – Restore and save the arrangement.
- Returns:
The Qt exit code.
- Return type:
int
- class plesty.lib.ui.qt.PlotRenderer(theme: plesty.lib.ui.theme.Theme | None = None, parent: PySide6.QtWidgets.QWidget | None = None)
Bases:
plesty.lib.monitor.base_monitor.RendererDraw target that renders a monitor’s traces into a pyqtgraph widget.
The renderer owns its widget (
widget), so a panel builds one and hands the widget to the shell:renderer = PlotRenderer(theme) monitor.attach(renderer) # builds the plot items, replays the last data shell_panel_widget = renderer.widget
Create the plot widget.
- Parameters:
theme (Optional[plesty.lib.ui.theme.Theme]) – Palette to resolve trace colours and chrome against;
Noneloads the packaged PLESTY theme.parent (Optional[PySide6.QtWidgets.QWidget]) – Parent widget.
- theme
- widget
- plot
- caption
- _items: dict[str, Any]
- _images: dict[str, pyqtgraph.ImageItem]
- _texts: dict[str, str]
- _lut
- setup(monitor: plesty.lib.monitor.base_monitor.Monitor) None
Build one plot item per declared trace.
- Parameters:
monitor (plesty.lib.monitor.base_monitor.Monitor) – The monitor that was attached.
- Return type:
None
- draw(monitor: plesty.lib.monitor.base_monitor.Monitor, data: dict[str, plesty.lib.monitor.base_monitor.TraceData]) None
Feed new payloads into the plot items.
- Parameters:
monitor (plesty.lib.monitor.base_monitor.Monitor) – The monitor that produced the update.
data (dict[str, plesty.lib.monitor.base_monitor.TraceData]) – Trace key → payload.
- Return type:
None
- clear(monitor: plesty.lib.monitor.base_monitor.Monitor) None
Empty every plot item without rebuilding them.
- Parameters:
monitor (plesty.lib.monitor.base_monitor.Monitor) – The monitor whose view is being reset.
- Return type:
None
- _style_plot() None
Apply the theme to the plot background, axes, and grid.
- Return type:
None
- _build_item(spec: plesty.lib.monitor.base_monitor.TraceSpec, index: int) None
Create the plot item declared by one trace spec.
- Parameters:
index (int)
- Return type:
None
- _draw_curve(key: str, payload: plesty.lib.monitor.base_monitor.TraceData) None
Update one line or scatter trace.
- Parameters:
key (str)
- Return type:
None
- _draw_image(key: str, payload: plesty.lib.monitor.base_monitor.TraceData) None
Update one image trace, scaling it onto its physical axes.
- Parameters:
key (str)
- Return type:
None
- _draw_text(key: str, spec: plesty.lib.monitor.base_monitor.TraceSpec, payload: plesty.lib.monitor.base_monitor.TraceData) None
Record a scalar or text trace for the caption line under the plot.
- Parameters:
key (str)
- Return type:
None
- class plesty.lib.ui.qt.Recorder(widget: PySide6.QtWidgets.QWidget, path: str | pathlib.Path, *, fps: int = DEFAULT_FPS, every: int = 1)
Capture a window while active; encode a video file on stop.
shell.start_recording("run.mp4", fps=10) ... # the shell captures on every tick path = shell.stop_recording() # → run.mp4, or run.gif without ffmpeg
Prepare a recording of widget.
- Parameters:
widget (PySide6.QtWidgets.QWidget) – The window to capture — normally the shell itself.
path (str | pathlib.Path) – Destination file; the suffix is corrected to what the available encoder can actually write.
fps (int) – Frame rate of the encoded video.
every (int) – Capture one frame per every refreshes, for a run whose rows arrive faster than a video needs them.
- Raises:
ValueError – If fps or every is not positive.
- widget
- path
- fps = 10
- every = 1
- active = False
- frames: list[numpy.ndarray] = []
- _shape: tuple[int, int] | None = None
- _seen = 0
- start() None
Begin capturing; a restart discards what was captured before.
- Return type:
None
- stop() pathlib.Path | None
Stop capturing and encode what was captured.
- Returns:
The written file, or
Nonewhen nothing was captured — a recording that never saw a frame writes no file rather than an empty one.- Return type:
Optional[pathlib.Path]
- _encode() pathlib.Path
Write the captured frames, preferring MP4 and falling back to GIF.
- Return type:
pathlib.Path
- _encode_gif() pathlib.Path
Write an animated GIF, the fallback that needs only Pillow.
- Return type:
pathlib.Path
- describe() dict[str, Any]
Return what has been captured so far.
- Returns:
Whether the recorder is active, the frame count, and the target.
- Return type:
dict[str, Any]
- class plesty.lib.ui.qt.DockPanel(panel: plesty.lib.ui.panel.Panel, shell: Shell)
Bases:
PySide6.QtWidgets.QDockWidgetOne sub-window of the shell, wrapping a
Panel.Movable, floatable, and (unless the panel says otherwise) closable — the three features that let an operator rearrange the window at will.
Wrap panel into a sub-window of shell.
- Parameters:
panel (plesty.lib.ui.panel.Panel) – The panel to host.
shell (Shell) – The home window.
- panel
- title_bar
- toggle_floating() None
Pull the panel out of the home window, or drop it back in.
- Return type:
None
- refresh() None
Tick the panel and mirror its status into the title bar.
- Return type:
None
- class plesty.lib.ui.qt.PanelTitleBar(dock: DockPanel, title: str, closable: bool = True)
Bases:
PySide6.QtWidgets.QWidgetTitle bar of a sub-window: state dot, title, live status, controls.
Replaces Qt’s default dock title bar so a panel can show what it is doing without stealing plot area — the same window-chrome language as the plesty.net hero card. Mouse presses are left unhandled on purpose, so the dock widget beneath still starts a drag: this bar is the drag handle that pulls a panel out of the home window.
Build the bar for dock.
- Parameters:
dock (DockPanel) – The sub-window this bar belongs to.
title (str) – Text shown on the left.
closable (bool) – Show the close button.
- _dock
- dot
- label
- status
- _button(glyph: str, tip: str, handler: Any) PySide6.QtWidgets.QToolButton
Create one title-bar button.
- Parameters:
glyph (str)
tip (str)
handler (Any)
- Return type:
PySide6.QtWidgets.QToolButton
- set_status(text: str, tone: str = 'idle') None
Update the status line and the state dot.
- Parameters:
text (str) – Status text shown at the right of the bar.
tone (str) – State name understood by the theme (
"running","idle","error","warning").
- Return type:
None
- set_floating(floating: bool) None
Mark the bar as belonging to a floating window.
- Parameters:
floating (bool) – Whether the sub-window is currently floating.
- Return type:
None
- mouseDoubleClickEvent(event: Any) None
Toggle floating on a double click, as a title bar conventionally does.
- Parameters:
event (Any) – The Qt mouse event.
- Return type:
None
- class plesty.lib.ui.qt.Shell(title: str = 'PLESTY', *, theme: plesty.lib.ui.theme.Theme | None = None, interval_ms: int = 500, layout_file: str | pathlib.Path | None = None, remember_layout: bool = True, parent: PySide6.QtWidgets.QWidget | None = None)
Bases:
PySide6.QtWidgets.QMainWindowHome window hosting every panel as a rearrangeable sub-window.
Create the home window.
- Parameters:
title (str) – Window title, also the key of the saved layout.
theme (Optional[plesty.lib.ui.theme.Theme]) – Palette and stylesheet;
Noneloads the packaged PLESTY theme.interval_ms (int) – Refresh interval — how often every panel is ticked. 500 ms keeps a live spectrum fluent without loading the machine that is also running the measurement.
layout_file (Optional[str | pathlib.Path]) – Where to store the arrangement;
Noneuses~/.plesty/ui/<title>.json.remember_layout (bool) – Restore the stored arrangement on open and save it on close.
parent (Optional[PySide6.QtWidgets.QWidget]) – Parent widget.
- theme
- recorder: plesty.lib.ui.qt.recorder.Recorder | None = None
- last_recording: pathlib.Path | None = None
- remember_layout = True
- layout_file
- _timer
- add(panel: plesty.lib.ui.panel.Panel, *, area: str | None = None, tabify_with: str | None = None, split_with: str | None = None) DockPanel
Add a panel as a sub-window.
A panel joining an area that already holds one is split against the last panel there rather than dropped into the area as a whole. Only a split puts a real handle between two panels: docks that merely share an area — or worse, sit in different areas — cannot be resized against each other, which is how a panel ends up as an unadjustable strip.
- Parameters:
panel (plesty.lib.ui.panel.Panel) – The panel to host.
area (Optional[str]) – Docking area override; defaults to
panel.area.tabify_with (Optional[str]) – Name of an already-added panel to tab this one with, instead of giving it its own space.
split_with (Optional[str]) – Name of the panel to split against; defaults to the last one added to the same area.
- Returns:
The created sub-window.
- Raises:
ValueError – If the panel name is already taken, or the panel named in tabify_with / split_with is unknown.
- Return type:
- _named(name: str, action: str) DockPanel
Return an already-added sub-window by panel name.
- Raises:
ValueError – If no panel of that name was added.
- Parameters:
name (str)
action (str)
- Return type:
- _last_in_area(area: str) DockPanel | None
Return the last docked sub-window of area, if it has one.
- Parameters:
area (str)
- Return type:
Optional[DockPanel]
- apply_weights() None
Size the panels of each area in proportion to their panel weights.
Qt distributes leftover space evenly, which leaves a status strip as tall as a spectrum. Weights say what each panel is worth: a plot 3, a readout 1.
- Return type:
None
- remove(name: str) None
Remove a panel and release what it holds.
- Parameters:
name (str) – Name of the panel to remove; unknown names are ignored.
- Return type:
None
- start() None
Show the window, restore the layout, and start refreshing panels.
A stored arrangement wins over the panels’ weights — it is what the operator built last time.
- Return type:
None
- stop() None
Stop refreshing panels.
- Return type:
None
- set_status(text: str, state: str = 'idle') None
Set the shell-wide status line.
- Parameters:
text (str) – Message shown in the status bar.
state (str) – State name coloring the indicator (
"running","idle","error","warning").
- Return type:
None
- _tick() None
Refresh every panel; a failing panel never stops the others.
- Return type:
None
- start_recording(path: str | pathlib.Path, *, fps: int = 10, every: int = 1) plesty.lib.ui.qt.recorder.Recorder
Capture the window after every refresh until
stop_recording().Recording belongs to the window rather than to a view, so whatever is docked is captured — including a panel added or floated halfway through a run.
- Parameters:
path (str | pathlib.Path) – Destination file; the suffix is corrected to what the available encoder can write (MP4, else animated GIF).
fps (int) – Frame rate of the encoded video.
every (int) – Capture one frame per every refreshes.
- Returns:
The recorder, already active.
- Return type:
- stop_recording() pathlib.Path | None
Encode what was captured and stop recording.
- Returns:
The written file, or
Noneif nothing was being recorded.- Return type:
Optional[pathlib.Path]
- _toggle_recording() None
Menu handler: start a recording beside the layout, or stop one.
- Return type:
None
- save_layout(path: str | pathlib.Path | None = None) pathlib.Path
Store the current arrangement.
- Parameters:
path (Optional[str | pathlib.Path]) – Destination file;
Noneuseslayout_file.- Returns:
The path written.
- Return type:
pathlib.Path
- restore_layout(path: str | pathlib.Path | None = None) bool
Restore a stored arrangement, if one exists and still fits.
Panels that were not added this time are simply absent from the restored layout; new ones keep the placement they were added with.
- Parameters:
path (Optional[str | pathlib.Path]) – Layout file;
Noneuseslayout_file.- Returns:
Whether a layout was restored.
- Return type:
bool
- reset_layout() None
Return every panel to the area it was added with, undocked from tabs.
- Return type:
None
- _build_chrome() None
Create the menus and the status bar.
- Return type:
None
- closeEvent(event: Any) None
Save the arrangement and release the panels before closing.
- Parameters:
event (Any) – The Qt close event.
- Return type:
None