UI modules¶
Main window widget — assembles the tabbed layout.
- class stoner_measurement.ui.main_window.MainWindow(plugin_manager: PluginManager, parent: QWidget | None = None)[source]¶
Bases:
QWidgetCentral widget that provides the tabbed layout.
Contains two tabs:
Measurement — the three-panel layout (DockPanel | PlotWidget | ConfigPanel).
Script Editor — a Python editor and interactive console.
Layout of the Measurement tab (left → right):
DockPanel — 25 % of width, instrument / sequence control.
PlotWidget — 50 % of width, PyQtGraph plotting area.
ConfigPanel — 25 % of width, tabbed configuration.
- Args:
- plugin_manager (PluginManager):
Shared plugin manager instance.
- Keyword Parameters:
- parent (QWidget | None):
Optional parent widget.
- Attributes:
dock_panel (DockPanel): Left panel of the Measurement tab. plot_widget (PlotWidget): Central plot in the Measurement tab. config_panel (ConfigPanel): Right configuration panel. script_tab (ScriptTab): The Script Editor tab widget.
- property config_panel: ConfigPanel¶
Right configuration panel (Measurement tab).
- Returns:
- (ConfigPanel):
The configuration panel widget.
- property dock_panel: DockPanel¶
Left dock panel (Measurement tab).
- Returns:
- (DockPanel):
The dock panel widget.
- property plot_widget: PlotWidget¶
Central plot widget (Measurement tab).
- Returns:
- (PlotWidget):
The plot widget.
- property script_tab: ScriptTab¶
The Script Editor tab widget.
- Returns:
- (ScriptTab):
The script tab widget.
- property tabs: QTabWidget¶
The top-level tab widget containing all tabs.
- Returns:
- (QTabWidget):
The tab widget.
Dock panel — left 25 % of the main window.
Provides plugin listing, sequence building controls, a run button,
and a monitoring section where plugins can display live status widgets.
The sequence list is a tree widget that supports drag-and-drop reordering
and arbitrarily deep sub-sequence nesting for
SequencePlugin items
(including StateControlPlugin),
enabling multi-dimensional measurement scans. Plugins may also be dragged
directly from the Available sequence commands list into the sequence tree to
insert new steps at any position or into a sub-sequence.
- class stoner_measurement.ui.dock_panel.DockPanel(plugin_manager: PluginManager, parent: QWidget | None = None)[source]¶
Bases:
QWidgetLeft panel containing instrument, sequence controls, and monitoring widgets.
Plugins may contribute a live-status widget via
monitor_widget(). Those widgets are displayed in a dedicated Monitoring section at the bottom of this panel and are removed automatically when the plugin is unregistered.When the user clicks a step in the Sequence Steps tree, the
plugin_selectedsignal is emitted with the corresponding plugin instance so that the configuration panel can update itself accordingly.The sequence tree supports drag-and-drop:
Drag a step above or below another to reorder.
Drag any step onto a
SequencePluginitem (e.g. aStateControlPlugin) to nest it as a sub-step (shown with indentation). This includes dragging one sequence-plugin step onto another, enabling multi-dimensional measurement scans at arbitrary depth.Drag a sub-step to the top level to promote it.
Drag a plugin from the Available sequence commands list and drop it above, below, or onto any existing step (or onto the empty area below all steps) to insert a brand-new step instance at that position. Dropping onto a
SequencePluginitem adds the new step as the last child of that sub-sequence.
- Attributes:
- sequence_steps (list[_SequenceStep]):
The current sequence steps as a recursive structure. Each element is either a plugin instance (for a leaf step with no sub-steps) or a
(plugin_instance, [sub-steps…])tuple for aSequencePluginthat has nested children. The inner list follows the same_SequenceStepstructure, so nesting may be arbitrarily deep.
- Args:
- plugin_manager (PluginManager):
The application
PluginManagerinstance — used to populate the available-plugins list and to manage monitoring widgets.
- Keyword Parameters:
- parent (QWidget | None):
Optional Qt parent widget.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.sequence_steps []
- add_monitor_widget(plugin_name: str, widget: QWidget) None[source]¶
Add a monitoring widget for the named plugin.
If a monitoring widget for plugin_name is already present this call is a no-op.
- Args:
- plugin_name (str):
Unique identifier for the owning plugin.
- widget (QWidget):
The widget to display in the monitoring section.
- Examples:
>>> from PyQt6.QtWidgets import QApplication, QLabel >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.add_monitor_widget("test", QLabel("Status: OK")) >>> "test" in panel.monitor_widgets True
- copy_selected_step() bool[source]¶
Copy the currently selected sequence step(s) to the internal clipboard.
All selected steps (including any sub-steps) are serialised to JSON and stored in
_clipboard_step_json. When a selected item’s parent is also selected the child is omitted — its data is already captured inside the parent’s serialised sub-steps. ReturnsFalsewhen nothing is selected.- Returns:
- (bool):
Trueif at least one step was copied,Falseif nothing was selected.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.load_sequence([DummyPlugin()]) >>> panel._sequence_tree.setCurrentItem(panel._sequence_tree.topLevelItem(0)) >>> panel.copy_selected_step() True >>> panel.has_clipboard_step True
- cut_selected_step() bool[source]¶
Cut the currently selected sequence step(s) to the internal clipboard.
Equivalent to
copy_selected_step()followed by removing all selected steps from the tree. ReturnsFalsewhen nothing is selected.- Returns:
- (bool):
Trueif at least one step was cut,Falseif nothing was selected.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.load_sequence([DummyPlugin()]) >>> panel._sequence_tree.setCurrentItem(panel._sequence_tree.topLevelItem(0)) >>> panel.cut_selected_step() True >>> panel._sequence_tree.topLevelItemCount() 0
- disabled_action_label() str[source]¶
Return the appropriate label for the disable/enable toggle action.
Inspects the currently selected sequence steps and returns
"Enable Plugin(s)"when all selected plugins are disabled, or"Disable Plugin(s)"otherwise (including when the selection is empty). The plural suffix is omitted when exactly one item is selected.- Returns:
- (str):
The action label to display in the context menu or Edit menu.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.disabled_action_label() 'Disable Plugin'
- property has_clipboard_step: bool¶
Truewhen the internal sequence-step clipboard contains data.- Returns:
- (bool):
Whether there is a copied/cut step ready to paste.
- load_sequence(steps: list[_SequenceStep]) None[source]¶
Replace the current sequence tree with steps.
All existing steps are removed and their plugin references released before the new steps are inserted. Each plugin is added to
_step_pluginsso that it is not garbage-collected, and itsinstance_name_changedsignal (if present) is wired to the tree’s label-update handler.This method is the programmatic counterpart of the interactive drag-and-drop sequence builder. Use it when loading a sequence from a file (see
stoner_measurement.core.serializer).- Args:
- steps (list[_SequenceStep]):
Sequence steps in the same nested format returned by
sequence_steps.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> plugin = DummyPlugin() >>> panel.load_sequence([plugin]) >>> len(panel.sequence_steps) 1
- property monitor_widgets: dict[str, QWidget]¶
Mapping of plugin name → currently displayed monitoring widget.
- paste_step() bool[source]¶
Paste step(s) from the internal clipboard into the sequence tree.
All steps in the clipboard are inserted immediately after the current item (at the same level of nesting), preserving their original order. When nothing is selected every step is appended at the top level. Instance names are adjusted using
_compute_paste_name()to avoid collisions with existing names. All newly inserted items are selected after the paste.- Returns:
- (bool):
Trueif at least one step was pasted,Falsewhen the clipboard is empty.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.load_sequence([DummyPlugin()]) >>> panel._sequence_tree.setCurrentItem(panel._sequence_tree.topLevelItem(0)) >>> panel.copy_selected_step() True >>> panel.paste_step() True >>> panel._sequence_tree.topLevelItemCount() 2
- plugin_selected¶
Emitted with the plugin instance when exactly one sequence step is selected, or
Nonewhen the selection is cleared or multiple steps are selected simultaneously.
- remove_monitor_widget(plugin_name: str) None[source]¶
Remove the monitoring widget registered for plugin_name.
If no widget is registered for plugin_name this call is a no-op.
- Args:
- plugin_name (str):
Unique identifier for the owning plugin.
- Examples:
>>> from PyQt6.QtWidgets import QApplication, QLabel >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.add_monitor_widget("test", QLabel("Status: OK")) >>> panel.remove_monitor_widget("test") >>> "test" in panel.monitor_widgets False
- property sequence_steps: list[_SequenceStep]¶
Return the current sequence steps as a (possibly nested) list.
Each element is either:
a plugin instance for a step that has no sub-steps, or
a
(plugin_instance, [sub-steps…])tuple for aSequencePluginstep that has at least one nested child. The inner list follows the same structure recursively, allowing arbitrarily deep nesting for multi-dimensional measurement scans.
- Returns:
- (list[_SequenceStep]):
Ordered sequence of step descriptors.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> panel.sequence_steps []
- toggle_disable_selected_steps() None[source]¶
Toggle the disabled state of all currently selected sequence steps.
If any selected plugin is currently enabled, all selected plugins are disabled. If all selected plugins are already disabled, they are all re-enabled. The visual appearance of each affected tree item is updated immediately to reflect the new state.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = DockPanel(plugin_manager=pm) >>> plugin = DummyPlugin() >>> panel.load_sequence([plugin]) >>> panel._sequence_tree.setCurrentItem(panel._sequence_tree.topLevelItem(0)) >>> plugin.disabled False >>> panel.toggle_disable_selected_steps() >>> plugin.disabled True >>> panel.toggle_disable_selected_steps() >>> plugin.disabled False
Central PyQtGraph plotting widget — middle 50 % of the main window.
Supports multiple named traces (each with its own colour) and multiple
independent x- and y-axes implemented via linked
pyqtgraph.ViewBox instances.
- class stoner_measurement.ui.plot_widget.PlotWidget(*args: Any, **kwargs: Any)[source]¶
Bases:
QWidgetPyQtGraph-based plot area for displaying measurement data.
The widget supports:
Named traces — each trace is an independent
pyqtgraph.PlotDataItemwith its own colour. Traces are created on first use and can be updated point-by-point or in bulk.Multiple axes — additional y-axes (left or right) and x-axes (top or bottom) can be added, and individual traces can be assigned to any axis pair.
- Attributes:
- pg_widget (pg.PlotWidget):
The underlying
pyqtgraph.PlotWidget.
- Keyword Parameters:
- parent (QWidget | None):
Optional Qt parent widget.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("my_trace", 1.0, 2.0) >>> widget.x_data("my_trace") [1.0]
- add_x_axis(name: str, label: str, position: Literal['bottom', 'top'] = 'top') None[source]¶
Add a new x-axis with an independent
pyqtgraph.ViewBox.The new ViewBox is linked to the main plot’s y-axis so that panning and zooming in y remain synchronised.
- Args:
- name (str):
Unique identifier for the new axis.
- label (str):
Text label shown on the axis.
- Keyword Parameters:
- position (Literal[“bottom”, “top”]):
Position of the axis relative to the plot. Defaults to
"top".
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.add_x_axis("freq", "Frequency (Hz)", position="top") >>> "freq" in widget.axis_names True
- add_y_axis(name: str, label: str, side: Literal['left', 'right'] = 'right') None[source]¶
Add a new y-axis with an independent
pyqtgraph.ViewBox.The new ViewBox is linked to the main plot’s x-axis so that panning and zooming in x remain synchronised across all y-axes.
- Args:
- name (str):
Unique identifier for the new axis.
- label (str):
Text label shown on the axis.
- Keyword Parameters:
- side (Literal[“left”, “right”]):
Side of the plot on which the axis appears. Defaults to
"right".
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.add_y_axis("temperature", "Temperature (K)", side="right") >>> "temperature" in widget.axis_names True
- append_point(trace_name: str, x: float, y: float) None¶
Append a single (x, y) data point to the named trace.
The trace is created automatically if it does not already exist.
- Args:
- trace_name (str):
Name of the trace to update.
- x (float):
Horizontal axis value.
- y (float):
Vertical axis value.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("sig", 0.0, 1.0) >>> widget.x_data("sig") [0.0]
- assign_trace_axes(trace_name: str, x_axis: str = 'bottom', y_axis: str = 'left') None¶
Assign a trace to a specific pair of axes.
The trace is moved from its current
pyqtgraph.ViewBoxto the ViewBox associated with y_axis. This controls which axis range is used when the trace is rendered.- Args:
- trace_name (str):
Name of the trace to reassign.
- Keyword Parameters:
- x_axis (str):
Name of the x-axis to use (must have been created via
add_x_axis()or be"bottom"). Defaults to"bottom".- y_axis (str):
Name of the y-axis to use (must have been created via
add_y_axis()or be"left"). Defaults to"left".
- Raises:
- KeyError:
If trace_name, x_axis, or y_axis are not registered.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.add_y_axis("temp", "Temperature (K)") >>> widget.append_point("sig", 0.0, 300.0) >>> widget.assign_trace_axes("sig", y_axis="temp")
- property axis_names: list[str]¶
Sorted list of all registered axis names (x and y combined).
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> sorted(widget.axis_names) ['bottom', 'left']
- clear_all() None[source]¶
Remove all traces and their data.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("a", 1.0, 2.0) >>> widget.clear_all() >>> widget.trace_names []
- ensure_x_axis(name: str, label: str = '') None[source]¶
Ensure an x-axis with name exists, creating it at the top if absent.
- Args:
- name (str):
Identifier for the x-axis. One of the default
"bottom"axis names or a custom name.
- Keyword Parameters:
- label (str):
Text label shown on the axis. Defaults to name when empty.
- ensure_y_axis(name: str, label: str = '') None[source]¶
Ensure a y-axis with name exists, creating it on the right if absent.
If the axis already exists this is a no-op. If it does not exist a new right-hand y-axis is added using
add_y_axis(), with label as the displayed axis label (falling back to name when label is empty).This is intended for use by command plugins that direct trace data to a named axis — they call this method before
assign_trace_axes()so that axes are created on demand without requiring the user to add them manually first.- Args:
- name (str):
Identifier for the y-axis. One of the default
"left"axis names or a custom name.
- Keyword Parameters:
- label (str):
Text label shown on the axis. Defaults to name when empty.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.ensure_y_axis("temp", "Temperature (K)") >>> "temp" in widget.axis_names True >>> widget.ensure_y_axis("temp") # idempotent >>> widget.axis_names.count("temp") 1
- property pg_widget: pyqtgraph.PlotWidget¶
The underlying
pyqtgraph.PlotWidget.
- remove_trace(trace_name: str) None[source]¶
Remove a named trace and all its data.
If trace_name does not exist this call is a no-op.
- Args:
- trace_name (str):
Name of the trace to remove.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("sig", 0.0, 1.0) >>> widget.remove_trace("sig") >>> widget.trace_names []
- set_default_axis_labels(x_label: str, y_label: str) None¶
Update the default bottom and left axis labels.
Called by
PlotTraceCommandwhen trace metadata (names and units fromTraceData) is available so that the plot axes reflect the physical quantities being displayed.- Args:
- x_label (str):
Label for the bottom (x) axis. If empty the axis label is left unchanged.
- y_label (str):
Label for the left (y) axis. If empty the axis label is left unchanged.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.set_default_axis_labels("Current (A)", "Voltage (V)") >>> widget._pg_widget.getPlotItem().getAxis("bottom").labelText 'Current (A)'
- set_trace(trace_name: str, x_data: Sequence[float], y_data: Sequence[float]) None¶
Replace the complete data series for a named trace.
The trace is created automatically if it does not already exist.
- Args:
- trace_name (str):
Name of the trace to update.
- x_data (Sequence[float]):
New horizontal axis data.
- y_data (Sequence[float]):
New vertical axis data.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.set_trace("sig", [0.0, 1.0], [2.0, 3.0]) >>> widget.y_data("sig") [2.0, 3.0]
- set_trace_style(trace_name: str, colour: str | None = None, line_style: str | None = None, point_style: str | None = None, line_width: float | None = None, point_size: float | None = None) None[source]¶
Set visual style properties for a trace.
- Args:
- trace_name (str):
Name of the trace to style.
- Keyword Parameters:
- colour (str | None):
Colour string accepted by pyqtgraph (e.g.
"#ff0000"). IfNone, the trace’s existing colour is preserved.- line_style (str):
One of
"solid","dash","dot","dash-dot", or"none".- point_style (str):
One of
"none","circle","square","triangle","diamond","plus", or"cross".- line_width (float | None):
Width of the plotted line. If
Nonethe existing width is preserved.- point_size (float | None):
Size of plotted points. If
Nonethe existing size is preserved.
- Raises:
- ValueError:
If line_style or point_style are unknown values.
- property trace_names: list[str]¶
Sorted list of currently registered trace names.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("b", 0.0, 1.0) >>> widget.append_point("a", 0.0, 1.0) >>> widget.trace_names ['a', 'b']
- x_data(trace_name: str = 'default') list[float][source]¶
Return the horizontal axis data for trace_name.
- Args:
- trace_name (str):
Name of the trace. Defaults to
"default".
- Returns:
- (list[float]):
Copy of the x data list.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("sig", 1.0, 2.0) >>> widget.x_data("sig") [1.0]
- y_data(trace_name: str = 'default') list[float][source]¶
Return the vertical axis data for trace_name.
- Args:
- trace_name (str):
Name of the trace. Defaults to
"default".
- Returns:
- (list[float]):
Copy of the y data list.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> widget = PlotWidget() >>> widget.append_point("sig", 1.0, 2.0) >>> widget.y_data("sig") [2.0]
Configuration panel — right 25 % of the main window.
A QTabWidget that displays the configuration tabs of whichever plugin
is currently selected in the sequence editor. Tabs are shown by calling
ConfigPanel.show_plugin() and cleared when no step is selected.
- class stoner_measurement.ui.config_panel.ConfigPanel(*args: Any, **kwargs: Any)[source]¶
Bases:
QWidgetRight-hand tabbed configuration panel.
Displays the configuration tabs of the plugin that is currently selected in the sequence editor. Call
show_plugin()to load a plugin’s tabs or passNoneto return to the idle placeholder.When the plugin manager notifies that a plugin has been removed,
show_plugin()is called withNoneautomatically if the removed plugin was the one currently being displayed.- Attributes:
- tabs (QTabWidget):
The underlying tab widget.
- Args:
- plugin_manager (PluginManager):
The application
PluginManagerinstance — used to detect when the currently displayed plugin is unregistered.
- Keyword Parameters:
- parent (QWidget | None):
Optional Qt parent widget.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = ConfigPanel(plugin_manager=pm) >>> panel.tabs.count() 0
- commit_pending_changes() None[source]¶
Commit any pending edits in the currently displayed configuration tabs.
Some input widgets (e.g.
QLineEdit) only apply their value to the plugin when the widget loses focus or the user presses Return. Toolbar and menu actions that do not take keyboard focus (the default Qt behaviour for toolbar buttons) would otherwise bypass this mechanism, so unsaved text would not reach the plugin before the action executes.This method inspects the application-wide focus widget. If it is a descendant of this panel’s tab widget it is explicitly cleared of focus, which causes Qt to emit the
editingFinishedsignal on any focusedQLineEditand flush the edit to the plugin before the action proceeds.- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = ConfigPanel(plugin_manager=pm) >>> panel.commit_pending_changes() # no-op when nothing is focused
- show_placeholder() None[source]¶
Display a centred ‘no step selected’ message in the panel.
Convenience wrapper around
show_plugin(None)that also adds a single informational tab so the panel does not appear completely empty.- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> pm = PluginManager() >>> panel = ConfigPanel(plugin_manager=pm) >>> panel.show_placeholder() >>> panel.tabs.count() 1
- show_plugin(plugin: BasePlugin | None) None[source]¶
Display the configuration tabs for plugin, replacing any currently shown tabs.
Tab widgets are sourced from
config_tabs(). BecauseTracePlugincaches its tab widgets, user-edited state is preserved when a plugin is deselected and re-selected in the sequence editor.Passing
Noneremoves all tabs and shows an empty panel.- Args:
- plugin (BasePlugin | None):
The plugin whose tabs should be displayed, or
Noneto clear the panel.
- Examples:
>>> from PyQt6.QtWidgets import QApplication >>> _ = QApplication.instance() or QApplication([]) >>> from stoner_measurement.core.plugin_manager import PluginManager >>> from stoner_measurement.plugins.trace import DummyPlugin >>> pm = PluginManager() >>> panel = ConfigPanel(plugin_manager=pm) >>> plugin = DummyPlugin() >>> panel.show_plugin(plugin) >>> panel.tabs.count() 3 >>> panel.show_plugin(None) >>> panel.tabs.count() 0
- property tabs: PyQt6.QtWidgets.QTabWidget¶
The underlying
QTabWidget.