magscope.ui

Contents

magscope.ui#

Submodules#

Classes#

VideoViewer

PlotWorker

TimeSeriesPlotBase

BeadGraphic

CollapsibleGroupBox

A titled QGroupBox that can optionally collapse its content.

GripSplitter

Simple class for adding '...' to QSplitter handles.

LabeledCheckbox

Horizontally combined QLabel and QCheckbox.

LabeledLineEdit

Horizontally combined QLabel and QLineedit.

LabeledLineEditWithValue

Horizontally combined QLabel, QLineedit, and a second QLabel to show the value.

LabeledStepperLineEdit

Horizontally combined QLabel and QLineedit with a QButton to increment/decrement the value on either side.

ResizableLabel

Custom QLabel that emits a signal when it's resized.

AcquisitionPanel

AllanDeviationPanel

BeadSelectionPanel

CameraPanel

ControlPanelBase

HistogramPanel

PlotSettingsPanel

PreferencesDialog

Modal dialog for global MagScope preferences.

ScriptPanel

StatusPanel

TrackingOptionsPanel

MagScopeSettingsPanel

Allow importing, exporting, and editing MagScope configuration values.

Controls

Adaptive workflow controls with movable tabs and responsive columns.

UIManager

Abstract base class for processes in the MagScope

Package Contents#

class magscope.ui.VideoViewer(scale_factor=1.25)[source]#

Bases: PyQt6.QtWidgets.QGraphicsView

coordinatesChanged: PyQt6.QtCore.pyqtSignal#
clicked: PyQt6.QtCore.pyqtSignal#
sceneClicked: PyQt6.QtCore.pyqtSignal#
_MINIMAP_MARGIN = 12#
_MINIMAP_MIN_SIZE = 120#
_MINIMAP_MAX_SIZE = 220#
_MINIMAP_LABEL_SPACING = 6#
_MINIMAP_ZOOM_HEIGHT = 26#
_MINIMAP_BUTTON_SPACING = 6#
_mouse_start_pos#
_mouse_start_time = 0.0#
_zoom = 0#
scale_factor = 1.25#
_empty = True#
scene#
_image#
_overlay_entries: list[tuple[PyQt6.QtCore.QRectF, PyQt6.QtCore.QPointF, str, bool, str]] = []#
_visible_overlay_entries: list[tuple[PyQt6.QtCore.QRectF, str, bool]] | None = None#
_visible_label_entries: list[tuple[PyQt6.QtCore.QPointF, PyQt6.QtGui.QStaticText, bool]] | None = None#
_overlay_cache_pixmap#
_overlay_cache_dirty = True#
_overlay_cache_size#
_overlay_cache_device_pixel_ratio = 0.0#
_static_label_cache: dict[str, PyQt6.QtGui.QStaticText]#
_label_metrics#
_label_ascent#
_marker_x#
_marker_y#
_marker_size = 0#
_minimap_label#
_minimap_zoom_label#
_minimap_reset_button#
_minimap_base#
_fit_scale = 1.0#
set_bead_overlay(bead_rois: dict[int, tuple[int, int, int, int]], active_bead_id: int | None, selected_bead_id: int | None, reference_bead_id: int | None, label_overrides: dict[int, str] | None = None, state_overrides: dict[int, str] | None = None) None[source]#
_invalidate_overlay_view_cache() None[source]#
_get_static_label(label_text: str) PyQt6.QtGui.QStaticText[source]#
_rebuild_overlay_view_cache() None[source]#
_rebuild_overlay_cache_pixmap() None[source]#
_ensure_overlay_cache_pixmap() None[source]#
plot(x, y, size)[source]#
clear_crosshairs()[source]#
set_image_to_default()[source]#
has_image()[source]#
image_scene_rect() PyQt6.QtCore.QRectF[source]#
reset_view(scale=1)[source]#
clear_image()[source]#
set_pixmap(pixmap)[source]#
zoom_level()[source]#
zoom(step)[source]#
wheelEvent(event)[source]#
resizeEvent(event)[source]#
toggle_drag_mode()[source]#
update_coordinates(pos=None)[source]#
mouseMoveEvent(event)[source]#
leaveEvent(event)[source]#
mousePressEvent(event)[source]#
mouseReleaseEvent(event)[source]#
scrollContentsBy(dx, dy)[source]#
_refresh_minimap()[source]#
_layout_minimap()[source]#
_compute_highlight_rect(scaled_size, offset_x, offset_y)[source]#
_current_zoom_percent()[source]#
drawForeground(painter, rect)[source]#
class magscope.ui.PlotWorker[source]#

Bases: PyQt6.QtCore.QObject

image_signal#
limits_signal#
selected_bead_signal#
reference_bead_signal#
stop_signal#
figure_size_signal#
time_mode_signal#
relative_window_signal#
axes: matplotlib.axes.Axes#
locks: dict[str, multiprocessing.synchronize.Lock]#
figure: matplotlib.figure.Figure | None = None#
canvas: matplotlib.backends.backend_qtagg.FigureCanvasQTAgg#
_is_running: bool = False#
plots = []#
limits: dict[str, tuple[float, float]]#
selected_bead: int | None = 0#
reference_bead: int | None = None#
n_plots: int#
update_on: bool = True#
_update_last_time: float#
fig_width = 5#
fig_height = 4#
dpi = 100#
device_pixel_ratio = 1.0#
time_mode = 'absolute'#
relative_window_seconds: float | None = 300#
_tracks_snapshot: numpy.ndarray | None = None#
mutex: PyQt6.QtCore.QMutex#
figure_size_changed = True#
setup()[source]#
run()[source]#
do_main_loop()[source]#
add_plot(plot: TimeSeriesPlotBase)[source]#

Used to add plots before the process has started

_set_limits(limits: dict[str, list[float, float]])[source]#
_set_selected_bead(bead: int)[source]#
_set_reference_bead(bead: int | None)[source]#
set_locks(locks: dict[str, multiprocessing.synchronize.Lock])[source]#
_stop()[source]#
dispose() None[source]#
_update_figure_size(width: int, height: int, device_pixel_ratio: float)[source]#

Slot: update figure size based on QLabel dimensions.

_recreate_figure_if_needed()[source]#

Recreate figure and canvas if size changed.

_set_time_mode(time_mode: str)[source]#
_set_relative_window(window_seconds: float | None)[source]#
_apply_time_axis_format()[source]#
class magscope.ui.TimeSeriesPlotBase(buffer_name: str, ylabel: str)[source]#
buffer: magscope.datatypes.MatrixBuffer#
buffer_name#
parent: PlotWorker#
axes: matplotlib.axes.Axes#
ylabel#
setup()[source]#

Called after the parent process is started

set_parent(parent: PlotWorker)[source]#
set_axes(axes: matplotlib.axes.Axes)[source]#
abstractmethod update()[source]#
class magscope.ui.BeadGraphic(parent: magscope.ui.ui.UIManager, id: int, roi: tuple[int, int, int, int], view_scene)[source]#

Bases: PyQt6.QtWidgets.QGraphicsRectItem

LABEL_FONT#
LABEL_COLOR#
LABEL_OFFSET_X = 10#
LABEL_OFFSET_Y = 1#
BORDER_COLOR_DEFAULT = (0, 255, 255, 255)#
FILL_COLOR_DEFAULT = None#
BORDER_COLOR_SELECTED = (255, 0, 0, 255)#
FILL_COLOR_SELECTED = None#
BORDER_COLOR_REFERENCE = (0, 255, 0, 255)#
FILL_COLOR_REFERENCE = None#
HOVER_BORDER_COLOR = (255, 96, 96, 255)#
DRAG_BORDER_COLOR = (255, 255, 255, 255)#
IDLE_PEN_WIDTH = 0#
HOVER_PEN_WIDTH = 2#
SELECTED_PEN_WIDTH = 2#
DRAG_PEN_WIDTH = 3#
CORNER_GRIP_SIZE = 6.0#
_shared_pens: dict[str, PyQt6.QtGui.QPen] | None = None#
_shared_brushes: dict[str, PyQt6.QtGui.QBrush] | None = None#
_parent: magscope.ui.ui.UIManager#
id: int#
_initializing: bool = True#
_is_moving: bool = False#
_is_hovered: bool = False#
_locked: bool#
_color_state: str = 'default'#
_cached_roi: tuple[int, int, int, int] | None = None#
pen_width = 0#
label#
property locked#
view_scene#
remove()[source]#
classmethod roi_from_center(x: float, y: float, width: float) tuple[int, int, int, int][source]#
classmethod label_scene_position_for_roi(roi: tuple[int, int, int, int]) PyQt6.QtCore.QPointF[source]#
classmethod clamp_roi_to_scene(roi: tuple[int, int, int, int], scene_rect: PyQt6.QtCore.QRectF) tuple[int, int, int, int][source]#
classmethod move_roi(roi: tuple[int, int, int, int], dx: int, dy: int, scene_rect: PyQt6.QtCore.QRectF) tuple[int, int, int, int][source]#
set_selection_state(state: str)[source]#

Update the bead overlay color to match selection/reference state.

classmethod _ensure_shared_pens_and_brushes() None[source]#
static _create_pen(color: tuple[int, int, int, int]) PyQt6.QtGui.QPen[source]#
static _create_brush(color: tuple[int, int, int, int] | None) PyQt6.QtGui.QBrush[source]#
_apply_color()[source]#
_current_visual_state() str[source]#
_current_border_color() PyQt6.QtGui.QColor[source]#
_current_pen_width() int[source]#
_update_cursor() None[source]#
_corner_grip_rects() list[PyQt6.QtCore.QRectF][source]#
_paint_rect() PyQt6.QtCore.QRectF[source]#
_current_scene_rect() PyQt6.QtCore.QRectF[source]#
paint(painter, option, widget=None)[source]#
move(dx, dy)[source]#
validate_move(value)[source]#

Prevents the graphic from moving outside the scene border

get_label_scene_position() PyQt6.QtCore.QPointF[source]#
set_roi_bounds(roi: tuple[int, int, int, int]) None[source]#
itemChange(change, value)[source]#
hoverEnterEvent(event)[source]#
hoverLeaveEvent(event)[source]#
mousePressEvent(event)[source]#
mouseReleaseEvent(event)[source]#
on_move_completed()[source]#
get_roi_bounds() tuple[int, int, int, int][source]#
_update_cached_roi()[source]#
class magscope.ui.CollapsibleGroupBox(title='', collapsed=False, *, collapsible: bool = True)[source]#

Bases: PyQt6.QtWidgets.QGroupBox

A titled QGroupBox that can optionally collapse its content.

_DEFAULT_BORDER_COLOR = 'palette(mid)'#
_DEFAULT_BORDER_WIDTH = 1#
title = ''#
collapsible = True#
default_collapsed = False#
_border_color = 'palette(mid)'#
_border_width = 1#
_settings_key = '_Group Box Collapsed'#
toggle_button#
drag_handle#
content_area#
animation#
collapsed#
set_highlight_border(color_name: str | None) None[source]#
_apply_panel_style() None[source]#
_animation_finished() None[source]#
property settings_key: str#
toggle(checked)[source]#
reset_to_default() None[source]#
_apply_collapsed_state(collapsed: bool, *, animate: bool, persist: bool) None[source]#
setContentLayout(content_layout)[source]#
static _get_toggle_text(title, expanded, *, collapsible: bool = True)[source]#
class magscope.ui.GripSplitter(orientation, name=None, parent=None)[source]#

Bases: PyQt6.QtWidgets.QSplitter

Simple class for adding ‘…’ to QSplitter handles.

name = None#
shown_once = False#
showEvent(e)[source]#
createHandle()[source]#
handle_released()[source]#
class magscope.ui.LabeledCheckbox(*, label_text: str, widths: tuple[int, int] = (0, 0), default=False, callback: callable = None)[source]#

Bases: PyQt6.QtWidgets.QWidget

Horizontally combined QLabel and QCheckbox.

layout#
label#
checkbox#
class magscope.ui.LabeledLineEdit(*, label_text: str, widths: tuple[int, int] = (0, 0), default=None, validator: PyQt6.QtGui.QValidator = None, callback: callable = None)[source]#

Bases: PyQt6.QtWidgets.QWidget

Horizontally combined QLabel and QLineedit.

layout#
label#
lineedit#
class magscope.ui.LabeledLineEditWithValue(*, label_text: str, validator: PyQt6.QtGui.QValidator = None, widths: tuple[int, int, int] = (0, 0, 0), default=None, callback: callable = None)[source]#

Bases: PyQt6.QtWidgets.QWidget

Horizontally combined QLabel, QLineedit, and a second QLabel to show the value.

layout#
label#
lineedit#
value_label#
class magscope.ui.LabeledStepperLineEdit(*, label_text: str, left_button_text: str, right_button_text: str, widths: tuple[int, int, int, int] = (0, 0, 0, 0), default=None, validator: PyQt6.QtGui.QValidator = None, callbacks: tuple[callable, callable, callable] = (None, None, None))[source]#

Bases: PyQt6.QtWidgets.QWidget

Horizontally combined QLabel and QLineedit with a QButton to increment/decrement the value on either side.

layout#
name_label#
left_button#
lineedit#
right_button#
class magscope.ui.ResizableLabel(parent=None, *, ignore_pixmap_size_hint: bool = False)[source]#

Bases: PyQt6.QtWidgets.QLabel

Custom QLabel that emits a signal when it’s resized.

resized#
_ignore_pixmap_size_hint = False#
sizeHint() PyQt6.QtCore.QSize[source]#
minimumSizeHint() PyQt6.QtCore.QSize[source]#
resizeEvent(event)[source]#

Override resize event to emit signal with new dimensions.

class magscope.ui.AcquisitionPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

NO_DIRECTORY_SELECTED_TEXT = 'No save folder selected'#
acquisition_on_checkbox#
acquisition_mode_combobox#
acquisition_dir_on_checkbox#
acquisition_dir_textedit#
acquisition_dir_button#
set_acquisition_dir_text(path: str | None) None[source]#
callback_acquisition_on()[source]#
callback_acquisition_dir_on()[source]#
callback_acquisition_mode()[source]#
callback_acquisition_dir()[source]#
update_save_highlight(should_save: bool) None[source]#
search_targets() list[magscope.ui.search.SearchTarget][source]#
class magscope.ui.AllanDeviationPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: MatplotlibCleanupMixin, ControlPanelBase

_SETTINGS_GROUP = 'AllanDeviationPanel'#
refresh_button#
history_window#
history_window_hint#
taus_mode#
figure#
canvas#
axes#
status_label#
_settings() PyQt6.QtCore.QSettings[source]#
_setting_key(name: str) str[source]#
_load_setting(name: str, default: str) str[source]#
_persist_controls() None[source]#
_configure_axes() None[source]#
refresh_plot() None[source]#
clear(message: str = 'Click Refresh to compute Allan deviation') None[source]#
static _parse_window_seconds(value: str) float | None[source]#
static _estimate_sampling_rate(timestamps: numpy.ndarray) float | None[source]#
static _apply_history_window(timestamps: numpy.ndarray, values: numpy.ndarray, window_seconds: float) tuple[numpy.ndarray, numpy.ndarray][source]#
static _extract_axis_series(tracks: numpy.ndarray, *, axis_name: str, selected_bead: int | None, reference_bead: int | None) tuple[numpy.ndarray, numpy.ndarray][source]#
class magscope.ui.BeadSelectionPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

next_bead_id_label#
reset_id_button#
roi_size_label#
clear_button#
search_targets() list[magscope.ui.search.SearchTarget][source]#
update_next_bead_id_label(next_bead_id: int) None[source]#
class magscope.ui.CameraPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

_last_settings_update: datetime.datetime | None = None#
settings#
refresh_button#
last_update_label#
callback_refresh()[source]#
callback_set_camera_setting(name)[source]#
update_camera_setting(name: str, value: str)[source]#
_format_last_update_text() str[source]#
class magscope.ui.ControlPanelBase(manager: magscope.ui.ui.UIManager, title: str, collapsed_by_default: bool = False, collapsible: bool = False)[source]#

Bases: PyQt6.QtWidgets.QWidget

manager: magscope.ui.ui.UIManager#
groupbox: magscope.ui.widgets.CollapsibleGroupBox | None = None#
_content_layout: PyQt6.QtWidgets.QBoxLayout | None = None#
set_title(text: str) None[source]#
setLayout(layout: PyQt6.QtWidgets.QBoxLayout) None[source]#
layout() PyQt6.QtWidgets.QBoxLayout[source]#
set_highlighted(enabled: bool) None[source]#
class magscope.ui.HistogramPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: MatplotlibCleanupMixin, ControlPanelBase

update_interval: float = 1#
_update_last_time: float = 0#
enable_checkbox#
only_beads_checkbox#
n_bins = 256#
figure#
canvas#
axes#
enabled_callback(enabled: bool) None[source]#
_groupbox_toggled(expanded: bool) None[source]#
_apply_enabled_state(enabled: bool) None[source]#
update_plot(data)[source]#
clear()[source]#
class magscope.ui.PlotSettingsPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

selected_bead#
reference_bead#
limits: dict[str, tuple[PyQt6.QtWidgets.QLineEdit, PyQt6.QtWidgets.QLineEdit]]#
grid_layout#
time_mode#
time_label#
time_limits_absolute#
time_relative_window#
time_inputs_stack#
beads_in_view_on#
beads_in_view_count#
beads_in_view_marker_size#
search_targets() list[magscope.ui.search.SearchTarget][source]#
selected_bead_callback(value)[source]#
reference_bead_callback(value)[source]#
time_mode_callback(value: str)[source]#
relative_time_window_callback(_value)[source]#
limits_callback(_)[source]#
beads_in_view_on_callback()[source]#
beads_in_view_count_callback()[source]#
beads_in_view_marker_size_callback()[source]#
class magscope.ui.PreferencesDialog(manager: magscope.ui.ui.UIManager)[source]#

Bases: PyQt6.QtWidgets.QDialog

Modal dialog for global MagScope preferences.

_SIDEBAR_SECTIONS: tuple[tuple[str, str], Ellipsis] = (('tune', 'MagScope'), ('ads_click', 'Tracking'), ('palette', 'Appearance/Layout'))#
manager#
load_preferences_button#
save_preferences_button#
reset_all_preferences_button#
preferences_file_status#
settings_panel#
settings_scroll#
tracking_options_panel#
tracking_scroll#
appearance_layout_tab#
appearance_scroll#
stack#
reset_section_button#
sidebar#
static _sidebar_selection_background(accent: str) str[source]#
_apply_preferences_style(accent: str) None[source]#
_refresh_sidebar_icons(accent: str | None = None) None[source]#
_on_load_preferences_clicked() None[source]#
_on_save_preferences_clicked() None[source]#
_on_reset_all_preferences_clicked() None[source]#
_set_preferences_file_status(message: str) None[source]#
_create_appearance_layout_tab() PyQt6.QtWidgets.QWidget[source]#
_choose_accent_color() None[source]#
_update_accent_color_swatch(color: str) None[source]#
_apply_accent_color_setting() None[source]#
_apply_live_plot_progress_indicator_setting(checked: bool) None[source]#
_scrollable_tab(widget: PyQt6.QtWidgets.QWidget) PyQt6.QtWidgets.QScrollArea[source]#
static _make_material_symbol_icon(font: PyQt6.QtGui.QFont, text: str, color: str = '#888888', size: int = 16) PyQt6.QtGui.QIcon[source]#
_on_sidebar_selection(index: int) None[source]#
_on_reset_current_section() None[source]#
_stack_index_for_scroll(scroll: PyQt6.QtWidgets.QScrollArea) int[source]#
reveal_setting(setting_key: str) None[source]#
reveal_magscope_setting(setting_key: str) None[source]#
reveal_tracking_option(widget_attr: str) None[source]#
reveal_widget(tab_name: str, widget_attr: str) None[source]#
_reveal_widget(scroll: PyQt6.QtWidgets.QScrollArea, widget: PyQt6.QtWidgets.QWidget) None[source]#
_on_reset_appearance_tab_clicked() None[source]#
_reset_appearance_layout(*, reset_accent: bool) None[source]#
class magscope.ui.ScriptPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

NO_SCRIPT_SELECTED_TEXT = 'No script loaded'#
status_prefix = 'Status'#
status_label#
step_position_label#
step_description_label#
button_layout#
load_button#
start_button#
pause_button#
filepath_textedit#
update_status(status: magscope.scripting.ScriptStatus)[source]#
update_step(current_step: int | None, total_steps: int, description: str | None)[source]#
callback_load()[source]#
callback_start()[source]#
callback_pause()[source]#
class magscope.ui.StatusPanel(manager: magscope.ui.ui.UIManager)[source]#

Bases: ControlPanelBase

dot_count = 0#
display_rate_status#
video_processors_status#
video_buffer_size_status#
video_buffer_status#
video_buffer_status_bar#
video_buffer_purge_label#
update_display_rate(text)[source]#
update_video_processors_status(status_text: str)[source]#
update_video_buffer_status(status_text: str)[source]#
_update_video_buffer_size_label() None[source]#
update_video_buffer_purge(timestamp: float)[source]#
class magscope.ui.TrackingOptionsPanel(manager: magscope.ui.ui.UIManager, *, collapsible: bool = True)[source]#

Bases: ControlPanelBase

_current_options: dict[str, Any]#
_updating_fields = False#
background_combo#
iterations#
line_ratio#
n_local#
use_fft#
fft_oversample#
fft_rmin#
fft_rmax#
fft_gaus_factor#
radial_oversample#
lookup_n_local#
static _build_preferences_group(title: str, parent: PyQt6.QtWidgets.QWidget) tuple[PyQt6.QtWidgets.QWidget, PyQt6.QtWidgets.QVBoxLayout][source]#
static _configure_lineedit_row(widget: magscope.ui.widgets.LabeledLineEditWithValue) None[source]#
static _configure_checkbox_row(widget: magscope.ui.widgets.LabeledCheckbox) None[source]#
static search_targets() list[magscope.ui.search.SearchTarget][source]#
_option_line_edits() tuple[magscope.ui.widgets.LabeledLineEditWithValue, Ellipsis][source]#
_update_value_labels() None[source]#
_sync_fft_enabled_state() None[source]#
_use_fft_changed(value: bool) None[source]#
_set_options(options: dict[str, Any], message: str | None = None, *, populate_inputs: bool = False) None[source]#
_populate_inputs_from_options() None[source]#
_load_options_from_mapping(loaded: Any) dict[str, Any][source]#
_options_from_inputs() dict[str, Any][source]#
_apply_options_from_inputs() None[source]#
reset_defaults() None[source]#
class magscope.ui.MagScopeSettingsPanel(manager: magscope.ui.ui.UIManager, *, collapsible: bool = True, file_status_label: PyQt6.QtWidgets.QLabel | None = None)[source]#

Bases: PyQt6.QtWidgets.QWidget

Allow importing, exporting, and editing MagScope configuration values.

_SETTING_GROUPS: tuple[tuple[str, tuple[str, Ellipsis]], Ellipsis] = (('Imaging', ('ROI', 'magnification')), ('Data Buffers', ('tracks max datapoints', 'video buffer...#
manager#
_current_settings#
_setting_inputs: dict[str, PyQt6.QtWidgets.QLineEdit]#
_setting_value_labels: dict[str, PyQt6.QtWidgets.QLabel]#
static search_targets() list[magscope.ui.search.SearchTarget][source]#
_show_error(message: str) None[source]#
_push_settings(settings: magscope.settings.MagScopeSettings) None[source]#
_refresh_fields() None[source]#
_apply_setting_from_input(key: str) None[source]#
reset_defaults() None[source]#
_build_setting_group(title: str, keys: tuple[str, Ellipsis]) PyQt6.QtWidgets.QWidget[source]#
_update_saved_label_for_input(key: str) None[source]#
class magscope.ui.Controls(manager: UIManager)[source]#

Bases: PyQt6.QtWidgets.QWidget

Adaptive workflow controls with movable tabs and responsive columns.

LAYOUT_SETTINGS_GROUP = 'controls/layout'#
WORKFLOW_COLUMNS_SETTINGS_KEY = 'controls/workflow_columns'#
MIN_COLUMN_WIDTH = 360#
MAX_COLUMNS = 4#
WORKFLOW_ORDER = ['Run', 'Analysis', 'Locking', 'Motors']#
WORKFLOW_TAB_ALIASES#
DEFAULT_LAYOUTS#
manager#
panels: dict[str, magscope.ui.controls.ControlPanelBase | PyQt6.QtWidgets.QWidget]#
_settings#
_tab_widgets: list[WorkflowTabWidget] = []#
_tab_pages: dict[str, PyQt6.QtWidgets.QScrollArea]#
_tab_content_layouts: dict[str, PyQt6.QtWidgets.QVBoxLayout]#
_panel_to_tab: dict[str, str]#
_current_column_count = 0#
_loading_layout = False#
_columns_layout#
property settings#
_create_standard_panels() None[source]#
_create_workflow_pages() None[source]#
_populate_workflow_pages() None[source]#
_desired_column_count() int[source]#
_default_layout_for_count(count: int) list[list[str]][source]#
_load_saved_layout() list[list[str]] | None[source]#
_save_workflow_layout() None[source]#
_current_workflow_layout() list[list[str]][source]#
classmethod _canonical_workflow_tab_id(tab_id: Any) str[source]#
_layout_for_column_count(count: int) list[list[str]][source]#
_expand_layout_to_count(columns: list[list[str]], count: int) list[list[str]][source]#
_fill_empty_columns(columns: list[list[str]], preferred_layout: list[list[str]]) list[list[str]][source]#
_tabs_for_empty_column(columns: list[list[str]], preferred_layout: list[list[str]], empty_index: int) list[str][source]#
_clear_tab_widgets() None[source]#
_apply_workflow_layout(layout: list[list[str]], *, save: bool) None[source]#
_sync_column_count_to_width() None[source]#
move_workflow_tab(tab_id: str, target_column: int, target_index: int) None[source]#
export_preferences() dict[str, Any][source]#
import_preferences(preferences: Mapping[str, Any]) None[source]#
validate_preferences(preferences: Mapping[str, Any]) None[source]#
_normalise_workflow_layout(raw_layout: Any) list[list[str]][source]#
reveal_panel(panel_id: str) None[source]#
_reveal_legacy_panel(panel_id: str) None[source]#
reset_to_defaults() None[source]#
resizeEvent(event)[source]#
class magscope.ui.UIManager[source]#

Bases: magscope.processes.ManagerProcessBase

Abstract base class for processes in the MagScope

Subclass requirements: * Each subclass should have a unique name. * There should only be one instance of each subclass (singleton). * The class name is used for consistent inter-process identification.

_material_symbols_font_family: str | None = None#
VIEWER_LAYOUT_STATE_VERSION = 1#
VIEWER_GEOMETRY_SETTINGS_KEY = 'viewer/main_window_geometry'#
VIEWER_DOCK_STATE_SETTINGS_KEY = 'viewer/dock_state'#
_ZLUT_TRACKING_ACQUISITION_MODES#
_active_bead_graphic: magscope.ui.widgets.BeadGraphic | None = None#
_active_bead_id: int | None = None#
_bead_rois: dict[int, tuple[int, int, int, int]]#
_pending_bead_add_id: int | None = None#
_pending_bead_add_roi: tuple[int, int, int, int] | None = None#
_bead_next_id: int = 0#
beads_in_view_on = False#
beads_in_view_count = 1#
beads_in_view_marker_size = 20#
central_widgets: list[PyQt6.QtWidgets.QWidget] = []#
central_layouts: list[PyQt6.QtWidgets.QLayout] = []#
controls: Controls | None = None#
controls_to_add = []#
camera_dock: PyQt6.QtWidgets.QDockWidget | None = None#
camera_dock_title_bar: PyQt6.QtWidgets.QWidget | None = None#
camera_dock_header: PyQt6.QtWidgets.QWidget | None = None#
bead_toolbar: PyQt6.QtWidgets.QWidget | None = None#
bead_instructions_button: PyQt6.QtWidgets.QPushButton | None = None#
bead_roi_size_label: PyQt6.QtWidgets.QLabel | None = None#
bead_total_count_label: PyQt6.QtWidgets.QLabel | None = None#
bead_next_id_label: PyQt6.QtWidgets.QLabel | None = None#
bead_reassign_ids_button: PyQt6.QtWidgets.QPushButton | None = None#
bead_remove_all_button: PyQt6.QtWidgets.QPushButton | None = None#
_display_rate_counter: int = 0#
_display_rate_last_time: float#
_display_rate_last_rate: float = 0#
plot_worker: magscope.ui.plots.PlotWorker#
plot_thread: PyQt6.QtCore.QThread#
plots_widget: PyQt6.QtWidgets.QLabel#
plots_dock: PyQt6.QtWidgets.QDockWidget | None = None#
plots_dock_title_bar: PyQt6.QtWidgets.QWidget | None = None#
plots_dock_header: PyQt6.QtWidgets.QWidget | None = None#
plots_to_add: list[magscope.ui.plots.TimeSeriesPlotBase] = []#
plots_progress_indicator: LivePlotProgressIndicator | None = None#
_plot_progress_timer: PyQt6.QtCore.QTimer | None = None#
_plot_progress_started_at: float | None = None#
_plot_progress_last_image_time: float | None = None#
_plot_progress_interval_seconds = 1.0#
_preferences_dialog: magscope.ui.controls.PreferencesDialog | None = None#
qt_app: PyQt6.QtWidgets.QApplication | None = None#
selected_bead = 0#
reference_bead: int | None = None#
_timer: PyQt6.QtCore.QTimer | None = None#
_timer_video_view: PyQt6.QtCore.QTimer | None = None#
_video_buffer_last_index: int = 0#
_video_viewer_need_reset: bool = True#
video_viewer: magscope.ui.video_viewer.VideoViewer | None = None#
windows: list[PyQt6.QtWidgets.QMainWindow] = []#
_suppress_bead_roi_updates: bool = False#
_last_applied_roi: int | None = None#
_settings_persistence_warning_shown = False#
_bead_roi_capacity = 10000#
_auto_bead_selection_dialog: magscope.ui.auto_bead_selection_dialog.AutoBeadSelectionDialog | None = None#
_startup_ready_sent = False#
_zlut_generation_dialog: magscope.ui.controls.ZLUTGenerationDialog | None = None#
_zlut_generation_setup_dialog: magscope.ui.controls.ZLUTGenerationSetupDialog | None = None#
_current_zlut_dialog: magscope.ui.controls.CurrentZLUTDialog | None = None#
_current_zlut_filepath: str | None = None#
_current_zlut_metadata: dict[str, float | int | None]#
_zlut_generation_phase = 'idle'#
_zlut_generation_z_axis_min_nm: float | None = None#
_zlut_generation_z_axis_max_nm: float | None = None#
_zlut_generation_z_axis_descending = False#
_zlut_sweep_dataset: magscope.datatypes.ZLUTSweepDataset | None = None#
_zlut_evaluation_bead_ids: list[int] = []#
_zlut_evaluation_selected_bead_id: int | None = None#
_zlut_preview_last_poll: float = 0.0#
_shutdown_complete = False#
_search_container: PyQt6.QtWidgets.QWidget | None = None#
_search_toggle_button: PyQt6.QtWidgets.QToolButton | None = None#
_search_popup: PyQt6.QtWidgets.QWidget | None = None#
_search_popup_box: PyQt6.QtWidgets.QLineEdit | None = None#
_search_popup_escape_shortcut: PyQt6.QtGui.QShortcut | None = None#
_search_status_label: PyQt6.QtWidgets.QLabel | None = None#
_search_status_timer: PyQt6.QtCore.QTimer | None = None#
_menu_row: PyQt6.QtWidgets.QWidget | None = None#
_menu_bar: PyQt6.QtWidgets.QMenuBar | None = None#
_top_bar_menu_controls: PyQt6.QtWidgets.QWidget | None = None#
_top_bar_menu_buttons: dict[str, _TopBarActionButton]#
_top_bar_action_buttons: dict[str, _TopBarActionButton]#
_window_controls: PyQt6.QtWidgets.QWidget | None = None#
_minimize_button: PyQt6.QtWidgets.QToolButton | None = None#
_maximize_restore_button: PyQt6.QtWidgets.QToolButton | None = None#
_close_button: PyQt6.QtWidgets.QToolButton | None = None#
_caption_button_state_filter: _CaptionButtonStateFilter | None = None#
_top_bar_compact_filter: _TopBarCompactModeFilter | None = None#
_top_bar: _UnifiedTopBar | None = None#
_help_menu_action: PyQt6.QtGui.QAction | None = None#
_window_icon_label: PyQt6.QtWidgets.QLabel | None = None#
_window_title_label: PyQt6.QtWidgets.QLabel | None = None#
_title_bar_safe_area_spacer: PyQt6.QtWidgets.QWidget | None = None#
_title_bar_safe_area_window_handle: Any = None#
_layout_menu: PyQt6.QtWidgets.QMenu | None = None#
_auto_bead_selection_action: PyQt6.QtGui.QAction | None = None#
_zlut_menu: PyQt6.QtWidgets.QMenu | None = None#
_new_zlut_action: PyQt6.QtGui.QAction | None = None#
_load_zlut_action: PyQt6.QtGui.QAction | None = None#
_unload_zlut_action: PyQt6.QtGui.QAction | None = None#
_show_current_zlut_action: PyQt6.QtGui.QAction | None = None#
_menus: dict[str, PyQt6.QtWidgets.QMenu]#
_search_shortcuts: list[PyQt6.QtGui.QShortcut] = []#
_search_registry#
_search_highlighter#
classmethod _material_symbols_font(point_size: int = 18) PyQt6.QtGui.QFont[source]#
static _material_symbols_filled_stylesheet() str[source]#
static _configure_unified_top_bar_window(window: PyQt6.QtWidgets.QMainWindow) None[source]#
static _ensure_unified_top_menu_bar(window: PyQt6.QtWidgets.QMainWindow) _UnifiedTopMenuBar[source]#
static _viewer_dock_separator_stylesheet() str[source]#
_refresh_plot_progress_indicator() None[source]#
_live_plot_progress_indicator_enabled() bool[source]#
_apply_live_plot_progress_indicator_enabled() None[source]#
static _install_viewer_dock_separator_hover_delay(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_apply_viewer_dock_separator_style(window: PyQt6.QtWidgets.QMainWindow) None[source]#
static _zlut_requested_sweep_edges(z_axis_min_nm: float | None, z_axis_max_nm: float | None, n_steps: int) tuple[float | None, float | None][source]#
static _build_zlut_preview_payload(preview_snapshot: dict[str, object], *, z_axis_min_nm: float | None, z_axis_max_nm: float | None, z_axis_descending: bool) dict[str, object][source]#
setup()[source]#
_notify_startup_ready() None[source]#
set_settings(settings: magscope.settings.MagScopeSettings)[source]#

Apply new settings and clear beads if the ROI size changed.

_current_accent_color() str[source]#
_apply_accent_color(color: str) None[source]#
_show_settings_persistence_warning_if_needed() None[source]#
_show_settings_persistence_warning() None[source]#
update_plot_figure_size(w, h)[source]#
_set_plot_image(img: PyQt6.QtGui.QImage) None[source]#
_create_live_plot_progress_indicator() LivePlotProgressIndicator[source]#
_ensure_plot_progress_timer() None[source]#
_reset_plot_progress() None[source]#
_update_plot_progress() None[source]#
static _disconnect_signal(signal, callback) None[source]#
static _stop_timer(timer: PyQt6.QtCore.QTimer | None) None[source]#
static _close_widget(widget: PyQt6.QtWidgets.QWidget | None) None[source]#
_shutdown_plot_worker() None[source]#
quit()[source]#

Shutdown the process (and ask the other processes to quit too).

do_main_loop()[source]#
_handle_timer_exception(exc: BaseException) None[source]#

Surface exceptions that occur inside Qt timer callbacks.

_run_safe(callback: Callable[[], None]) None[source]#
_main_loop_tick() None[source]#
_update_view_and_hist_tick() None[source]#
set_selected_bead(bead: int)[source]#
set_live_profile_monitor_enabled(enabled: bool) None[source]#
set_reference_bead(bead: int | None)[source]#
_sync_plot_settings_selected_bead(bead: int) None[source]#
_sync_plot_settings_reference_bead(bead: int | None) None[source]#
_normalize_bead_id(bead: int | None) int | None[source]#
_get_bead_highlight_state(bead_id: int) str[source]#
_refresh_bead_overlay() None[source]#
_update_auto_bead_selection_action_state() None[source]#
_can_start_auto_bead_selection() bool[source]#
_snapshot_recent_image() numpy.ndarray | None[source]#
_current_image_display_scale() int[source]#
_current_scene_rect() PyQt6.QtCore.QRectF[source]#
_current_visible_scene_rect() PyQt6.QtCore.QRectF[source]#
_next_random_bead_roi(rng: numpy.random.Generator, visible_rect: PyQt6.QtCore.QRectF) tuple[int, int, int, int] | None[source]#
_set_active_bead(bead_id: int | None) None[source]#
on_active_bead_move_completed(bead_id: int, roi: tuple[int, int, int, int]) None[source]#
add_random_beads(count: int, seed: int | None = None) None[source]#
_add_new_bead_batch(rois: Iterable[tuple[int, int, int, int]]) dict[int, tuple[int, int, int, int]][source]#
_hit_test_bead(pos: PyQt6.QtCore.QPoint) int | None[source]#
_update_bead_highlight(bead_id: int) None[source]#
_update_bead_highlights(*, old_selected: int | None = None, old_reference: int | None = None)[source]#
_clear_live_profile_buffer() None[source]#
property n_windows#
property bead_roi_updates_suppressed: bool#
property bead_next_id: int#
_broadcast_bead_roi_update() None[source]#
_write_bead_rois_to_buffer(bead_rois: dict[int, tuple[int, int, int, int]]) None[source]#
create_central_widgets()[source]#
_create_viewer_docks(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_viewer_dock_title_bar(dock: PyQt6.QtWidgets.QDockWidget, title: str) PyQt6.QtWidgets.QWidget[source]#
_create_viewer_dock_content(dock: PyQt6.QtWidgets.QDockWidget, viewer: PyQt6.QtWidgets.QWidget, toolbar: PyQt6.QtWidgets.QWidget | None = None, viewer_margins: tuple[int, int, int, int] | None = None, viewer_overlay: PyQt6.QtWidgets.QWidget | None = None) tuple[PyQt6.QtWidgets.QWidget, PyQt6.QtWidgets.QWidget][source]#
_create_live_bead_toolbar() PyQt6.QtWidgets.QWidget[source]#
show_bead_selection_instructions() None[source]#
_dock_viewer_pane(dock: PyQt6.QtWidgets.QDockWidget) None[source]#
_set_viewer_dock_header_visible(dock: PyQt6.QtWidgets.QDockWidget, visible: bool) None[source]#
_set_viewer_dock_title_bar_visible(dock: PyQt6.QtWidgets.QDockWidget, visible: bool) None[source]#
_handle_viewer_dock_top_level_changed(dock: PyQt6.QtWidgets.QDockWidget, floating: bool) None[source]#
_schedule_floating_dock_window_configuration(dock: PyQt6.QtWidgets.QDockWidget, floating: bool) None[source]#
_configure_floating_dock_window(dock: PyQt6.QtWidgets.QDockWidget, floating: bool) None[source]#
_create_view_menu(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_tools_menu(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_zlut_menu(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_update_zlut_menu_action_state() None[source]#
_register_menu(name: str, menu: PyQt6.QtWidgets.QMenu) None[source]#
_create_preferences_menu_action(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_help_menu_action(window: PyQt6.QtWidgets.QMainWindow) None[source]#
static _title_bar_right_safe_area_width(window: PyQt6.QtWidgets.QMainWindow) int[source]#
_update_title_bar_safe_area_spacing(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_install_title_bar_safe_area_updates(window: PyQt6.QtWidgets.QMainWindow) None[source]#
static _apply_top_bar_style(menu_container: PyQt6.QtWidgets.QWidget, menu_bar_vertical_padding: int) None[source]#
_create_top_bar_menu_controls(menu_bar: PyQt6.QtWidgets.QMenuBar, parent: PyQt6.QtWidgets.QWidget, target_height: int) PyQt6.QtWidgets.QWidget[source]#
_create_caption_button(parent: PyQt6.QtWidgets.QWidget, object_name: str, icon_text: str, tooltip: str, callback: Callable[[], None], target_height: int, role: str) PyQt6.QtWidgets.QToolButton[source]#
_create_main_window_controls(window: PyQt6.QtWidgets.QMainWindow, parent: PyQt6.QtWidgets.QWidget, target_height: int) PyQt6.QtWidgets.QWidget[source]#
_toggle_main_window_maximized(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_search_menu_widget(window: PyQt6.QtWidgets.QMainWindow) None[source]#
_create_search_popup(window: PyQt6.QtWidgets.QMainWindow, target_height: int) tuple[PyQt6.QtWidgets.QWidget, PyQt6.QtWidgets.QLineEdit][source]#
_handle_search_box_text_edited(search_box: PyQt6.QtWidgets.QLineEdit, model: PyQt6.QtCore.QStringListModel, completer: PyQt6.QtWidgets.QCompleter, text: str) None[source]#
_guide_to_search_result_from_box(search_box: PyQt6.QtWidgets.QLineEdit) None[source]#
_guide_to_search_result_from_text(text: str) None[source]#
_sync_search_boxes(text: str, source: PyQt6.QtWidgets.QLineEdit | None = None) None[source]#
_show_search_popup() None[source]#
_hide_search_popup() None[source]#
_clear_search_popup_box() None[source]#
_search_container_horizontal_margins() int[source]#
_search_inline_total_width(search_box_width: int) int[source]#
_search_collapsed_total_width() int[source]#
static _widget_width_hint(widget: PyQt6.QtWidgets.QWidget | None) int[source]#
_set_menu_search_compact_state(collapsed: bool, search_box_width: int) None[source]#
_set_top_bar_menu_icon_mode(icon_only: bool) None[source]#
_update_top_bar_compact_mode() None[source]#
_refresh_search_registry() None[source]#
_ensure_search_registry() None[source]#
_menu_search_targets() list[magscope.ui.search.SearchTarget][source]#
_generic_panel_search_targets() list[magscope.ui.search.SearchTarget][source]#
_core_control_search_targets() list[magscope.ui.search.SearchTarget][source]#
static _normalize_search_text(text: str) str[source]#
_find_search_target(text: str) magscope.ui.search.SearchTarget | None[source]#
_find_exact_search_target(text: str) magscope.ui.search.SearchTarget | None[source]#
_search_completion_labels(text: str) list[str][source]#
_update_search_completion_model(model: PyQt6.QtCore.QStringListModel, completer: PyQt6.QtWidgets.QCompleter, text: str) None[source]#
_guide_to_search_result(text: str) bool[source]#
_guide_to_target(target: magscope.ui.search.SearchTarget) None[source]#
_reveal_search_target(target: magscope.ui.search.SearchTarget) None[source]#
_search_target_widget(target: magscope.ui.search.PanelControlTarget) PyQt6.QtWidgets.QWidget | None[source]#
_reveal_preference_setting(target: magscope.ui.search.PreferencesSettingTarget) None[source]#
_reveal_preference_widget(target: magscope.ui.search.PreferencesWidgetTarget) None[source]#
_reveal_menu_action(target: magscope.ui.search.MenuActionTarget) None[source]#
_highlight_search_widget(widget: PyQt6.QtWidgets.QWidget) None[source]#
_clear_search_highlight(widget: PyQt6.QtWidgets.QWidget) None[source]#
_install_search_shortcuts(window: PyQt6.QtWidgets.QMainWindow, search_box: PyQt6.QtWidgets.QLineEdit) None[source]#
_set_search_status(text: str) None[source]#
_clear_search_status_label_ref() None[source]#
_show_preferences_dialog() None[source]#
_dock_all_viewers() None[source]#
_viewer_layout_settings() PyQt6.QtCore.QSettings[source]#
_save_viewer_layout() None[source]#
_restore_viewer_layout() bool[source]#
_clear_viewer_layout() None[source]#
static _encode_qbytearray(value: PyQt6.QtCore.QByteArray) str[source]#
static _decode_qbytearray(value: str) PyQt6.QtCore.QByteArray[source]#
export_appearance_layout_preferences() dict[str, Any][source]#
import_appearance_layout_preferences(preferences: Mapping[str, Any]) None[source]#
validate_appearance_layout_preferences(preferences: Mapping[str, Any]) None[source]#
reset_appearance_layout_preferences() None[source]#
_sync_viewer_dock_headers() None[source]#
_apply_default_viewer_layout() None[source]#
_reset_viewer_layout() None[source]#
update_view_coords()[source]#
_update_view_and_hist()[source]#
callback_view_clicked(pos: PyQt6.QtCore.QPoint, button=Qt.MouseButton.LeftButton)[source]#
refresh_bead_rois()[source]#
update_bead_rois()[source]#
_add_bead_roi(bead_id: int, roi: tuple[int, int, int, int]) None[source]#
_update_bead_roi(bead_id: int, roi: tuple[int, int, int, int]) None[source]#
_update_multiple_bead_rois(bead_rois: dict[int, tuple[int, int, int, int]]) None[source]#
_remove_bead_roi(bead_id: int) None[source]#
move_beads(moves: list[tuple[int, int, int]])[source]#
add_bead(pos: PyQt6.QtCore.QPoint)[source]#
start_auto_bead_selection() None[source]#
_apply_auto_bead_selection(rois: list[tuple[int, int, int, int]]) None[source]#
_show_auto_bead_selection_capacity_warning(skipped_count: int) None[source]#
_on_auto_bead_selection_dialog_finished(_result: int) None[source]#
remove_bead(id: int)[source]#
clear_beads()[source]#
reset_bead_ids()[source]#
_update_roi_labels(roi: int) None[source]#
_update_next_bead_id_label() None[source]#
_update_bead_roi_size_label(roi: int | None = None) None[source]#
_update_bead_count_label() None[source]#
_update_live_bead_toolbar_labels() None[source]#
_clear_pending_bead_add() None[source]#
_calculate_next_bead_id() int[source]#
update_video_processors_status()[source]#
update_video_buffer_status()[source]#
_update_display_rate()[source]#
_update_beads_in_view()[source]#
update_camera_setting(name: str, value: str)[source]#
update_video_buffer_purge(t: float)[source]#
update_script_status(status: magscope.scripting.ScriptStatus)[source]#
update_script_step(current_step: int | None, total_steps: int, description: str | None)[source]#
print(text: str, details: str | None = None)[source]#
show_error(text: str, details: str | None = None)[source]#
show_warning(text: str, details: str | None = None)[source]#
set_acquisition_on(value: bool)[source]#
set_acquisition_dir(value: str | None)[source]#
set_acquisition_dir_on(value: bool)[source]#
set_acquisition_mode(mode: magscope.utils.AcquisitionMode)[source]#
update_xy_lock_enabled(value: bool)[source]#
update_xy_lock_interval(value: float)[source]#
update_xy_lock_max(value: float)[source]#
update_xy_lock_window(value: int)[source]#
update_z_lock_enabled(value: bool)[source]#
update_z_lock_bead(value: int)[source]#
update_z_lock_target(value: float)[source]#
update_z_lock_interval(value: float)[source]#
update_z_lock_max(value: float)[source]#
update_z_lock_window(value: int)[source]#
request_zlut_file(filepath: str) None[source]#
clear_zlut() None[source]#
unload_zlut() None[source]#
load_zlut_file_dialog() None[source]#
show_current_zlut_dialog() None[source]#
_clear_current_zlut_dialog_ref() None[source]#
show_new_zlut_dialog() None[source]#
_zlut_generation_preflight_error() str | None[source]#
_registered_focus_motor_names() list[str][source]#
_set_current_zlut(*, filepath: str | None, z_min: float | None = None, z_max: float | None = None, step_size: float | None = None, profile_length: int | None = None) None[source]#
_update_current_zlut_dialog() None[source]#
_clear_zlut_generation_preview(message: str = 'Waiting for Z-LUT sweep data...') None[source]#
_read_zlut_preview_snapshot(dataset: magscope.datatypes.ZLUTSweepDataset) dict[str, object][source]#
show_zlut_generation_dialog() None[source]#
start_zlut_generation(*, start_nm: float, step_nm: float, stop_nm: float, profiles_per_bead: int) None[source]#
cancel_zlut_generation() None[source]#
discard_generated_zlut_evaluation() None[source]#
select_generated_zlut_bead(bead_id: int) None[source]#
save_generated_zlut(bead_id: int, load_after_save: bool = True) None[source]#
request_profile_length() None[source]#
update_zlut_metadata(filepath: str | None = None, z_min: float | None = None, z_max: float | None = None, step_size: float | None = None, profile_length: int | None = None) None[source]#
report_profile_length(profile_length: int | None = None) None[source]#
update_zlut_generation_state(status: str, detail: str | None = None, running: bool = False, can_cancel: bool = False, phase: str = 'idle', z_axis_min_nm: float | None = None, z_axis_max_nm: float | None = None, z_axis_descending: bool = False) None[source]#
update_zlut_generation_evaluation(active: bool, bead_ids: list[int], selected_bead_id: int | None = None) None[source]#
update_zlut_generation_progress(current_step: int, total_steps: int, capture_count: int, capture_capacity: int, motor_z_value: float | None = None) None[source]#
_handle_zlut_dialog_destroyed() None[source]#
_detach_zlut_sweep_dataset() None[source]#
_update_zlut_generation_dialog() None[source]#
_refresh_zlut_preview_from_dataset() None[source]#