magscope.ui.controls
====================

.. py:module:: magscope.ui.controls


Classes
-------

.. autoapisummary::

   magscope.ui.controls.ControlPanelBase
   magscope.ui.controls.MatplotlibCleanupMixin
   magscope.ui.controls.ResponsivePlotCanvas
   magscope.ui.controls.HelpPanel
   magscope.ui.controls.MotorsPlaceholderPanel
   magscope.ui.controls.MagScopeSettingsPanel
   magscope.ui.controls.AcquisitionPanel
   magscope.ui.controls.BeadSelectionPanel
   magscope.ui.controls.CameraPanel
   magscope.ui.controls.HistogramPanel
   magscope.ui.controls.PlotSettingsPanel
   magscope.ui.controls.AllanDeviationPanel
   magscope.ui.controls.ProfilePanel
   magscope.ui.controls.TrackingOptionsPanel
   magscope.ui.controls.PreferencesDialog
   magscope.ui.controls.ScriptPanel
   magscope.ui.controls.StatusPanel
   magscope.ui.controls._LockInfoButton
   magscope.ui.controls._LockStatusBadge
   magscope.ui.controls._LockActivityIndicator
   magscope.ui.controls._LockNumberInput
   magscope.ui.controls.XYLockPanel
   magscope.ui.controls.ZLockPanel
   magscope.ui.controls.ZLUTGenerationPanel
   magscope.ui.controls.ZLUTGenerationSetupDialog
   magscope.ui.controls.ZLUTSweepPreviewWidget
   magscope.ui.controls.ZLUTGenerationDialog
   magscope.ui.controls.CurrentZLUTDialog
   magscope.ui.controls.ZLUTPanel


Functions
---------

.. autoapisummary::

   magscope.ui.controls._panel_control_target
   magscope.ui.controls._preference_widget_targets
   magscope.ui.controls.has_tweezepy_support
   magscope.ui.controls.load_tweezepy_avar


Module Contents
---------------

.. py:function:: _panel_control_target(label: str, panel_id: str, widget_attr: str, *, context: str, aliases: tuple[str, Ellipsis] = (), description: str = '', keywords: tuple[str, Ellipsis] = ()) -> magscope.ui.search.PanelControlTarget

.. py:function:: _preference_widget_targets(definitions: tuple[tuple[str, str, tuple[str, Ellipsis]], Ellipsis], *, tab_name: str, context: str) -> list[magscope.ui.search.SearchTarget]

.. py:class:: ControlPanelBase(manager: magscope.ui.ui.UIManager, title: str, collapsed_by_default: bool = False, collapsible: bool = False)

   Bases: :py:obj:`PyQt6.QtWidgets.QWidget`


   .. py:attribute:: manager
      :type:  magscope.ui.ui.UIManager


   .. py:attribute:: groupbox
      :type:  magscope.ui.widgets.CollapsibleGroupBox | None
      :value: None



   .. py:attribute:: _content_layout
      :type:  PyQt6.QtWidgets.QBoxLayout | None
      :value: None



   .. py:method:: set_title(text: str) -> None


   .. py:method:: setLayout(layout: PyQt6.QtWidgets.QBoxLayout) -> None


   .. py:method:: layout() -> PyQt6.QtWidgets.QBoxLayout


   .. py:method:: set_highlighted(enabled: bool) -> None


.. py:class:: MatplotlibCleanupMixin

   .. py:method:: _init_matplotlib_cleanup() -> None


   .. py:method:: _dispose_matplotlib(*_args: object) -> None


   .. py:method:: closeEvent(event) -> None


.. py:class:: ResponsivePlotCanvas(figure: matplotlib.figure.Figure, *, minimum_height: int = 210, maximum_height: int | None = 235, height_for_width: float = 0.72)

   Bases: :py:obj:`matplotlib.backends.backend_qtagg.FigureCanvasQTAgg`


   Figure canvas that grows taller when constrained to a narrow panel.


   .. py:attribute:: _minimum_height
      :value: 210



   .. py:attribute:: _maximum_height
      :value: 235



   .. py:attribute:: _height_for_width
      :value: 0.72



   .. py:attribute:: _preferred_height
      :value: 210



   .. py:method:: _apply_preferred_height(height: int) -> None


   .. py:method:: _update_preferred_height(width: int) -> None


   .. py:method:: resizeEvent(event)


   .. py:method:: sizeHint() -> PyQt6.QtCore.QSize


.. py:class:: HelpPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`PyQt6.QtWidgets.QFrame`


   Clickable panel that links to the MagScope documentation.


   .. py:attribute:: HELP_URL


   .. py:attribute:: manager


   .. py:attribute:: title_label


   .. py:attribute:: description_label


   .. py:attribute:: _is_hovered
      :value: False



   .. py:method:: mouseReleaseEvent(event)


   .. py:method:: enterEvent(event)


   .. py:method:: leaveEvent(event)


   .. py:method:: _apply_styles()


.. py:class:: MotorsPlaceholderPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   Panel shown when no user hardware managers are configured.


   .. py:attribute:: HELP_URL


.. py:class:: MagScopeSettingsPanel(manager: magscope.ui.ui.UIManager, *, collapsible: bool = True, file_status_label: PyQt6.QtWidgets.QLabel | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QWidget`


   Allow importing, exporting, and editing MagScope configuration values.


   .. py:attribute:: _SETTING_GROUPS
      :type:  tuple[tuple[str, tuple[str, Ellipsis]], Ellipsis]
      :value: (('Imaging', ('ROI', 'magnification')), ('Data Buffers', ('tracks max datapoints', 'video buffer...



   .. py:attribute:: manager


   .. py:attribute:: _current_settings


   .. py:attribute:: _setting_inputs
      :type:  dict[str, PyQt6.QtWidgets.QLineEdit]


   .. py:attribute:: _setting_value_labels
      :type:  dict[str, PyQt6.QtWidgets.QLabel]


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]
      :staticmethod:



   .. py:method:: _show_error(message: str) -> None


   .. py:method:: _push_settings(settings: magscope.settings.MagScopeSettings) -> None


   .. py:method:: _refresh_fields() -> None


   .. py:method:: _apply_setting_from_input(key: str) -> None


   .. py:method:: reset_defaults() -> None


   .. py:method:: _build_setting_group(title: str, keys: tuple[str, Ellipsis]) -> PyQt6.QtWidgets.QWidget


   .. py:method:: _update_saved_label_for_input(key: str) -> None


.. py:class:: AcquisitionPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: NO_DIRECTORY_SELECTED_TEXT
      :value: 'No save folder selected'



   .. py:attribute:: acquisition_on_checkbox


   .. py:attribute:: acquisition_mode_combobox


   .. py:attribute:: acquisition_dir_on_checkbox


   .. py:attribute:: acquisition_dir_textedit


   .. py:attribute:: acquisition_dir_button


   .. py:method:: set_acquisition_dir_text(path: str | None) -> None


   .. py:method:: callback_acquisition_on()


   .. py:method:: callback_acquisition_dir_on()


   .. py:method:: callback_acquisition_mode()


   .. py:method:: callback_acquisition_dir()


   .. py:method:: update_save_highlight(should_save: bool) -> None


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


.. py:class:: BeadSelectionPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: next_bead_id_label


   .. py:attribute:: reset_id_button


   .. py:attribute:: roi_size_label


   .. py:attribute:: clear_button


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: update_next_bead_id_label(next_bead_id: int) -> None


.. py:class:: CameraPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: _last_settings_update
      :type:  datetime.datetime | None
      :value: None



   .. py:attribute:: settings


   .. py:attribute:: refresh_button


   .. py:attribute:: last_update_label


   .. py:method:: callback_refresh()


   .. py:method:: callback_set_camera_setting(name)


   .. py:method:: update_camera_setting(name: str, value: str)


   .. py:method:: _format_last_update_text() -> str


.. py:class:: HistogramPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`MatplotlibCleanupMixin`, :py:obj:`ControlPanelBase`


   .. py:attribute:: update_interval
      :type:  float
      :value: 1



   .. py:attribute:: _update_last_time
      :type:  float
      :value: 0



   .. py:attribute:: enable_checkbox


   .. py:attribute:: only_beads_checkbox


   .. py:attribute:: n_bins
      :value: 256



   .. py:attribute:: figure


   .. py:attribute:: canvas


   .. py:attribute:: axes


   .. py:method:: enabled_callback(enabled: bool) -> None


   .. py:method:: _groupbox_toggled(expanded: bool) -> None


   .. py:method:: _apply_enabled_state(enabled: bool) -> None


   .. py:method:: update_plot(data)


   .. py:method:: clear()


.. py:class:: PlotSettingsPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: selected_bead


   .. py:attribute:: reference_bead


   .. py:attribute:: limits
      :type:  dict[str, tuple[PyQt6.QtWidgets.QLineEdit, PyQt6.QtWidgets.QLineEdit]]


   .. py:attribute:: grid_layout


   .. py:attribute:: time_mode


   .. py:attribute:: time_label


   .. py:attribute:: time_limits_absolute


   .. py:attribute:: time_relative_window


   .. py:attribute:: time_inputs_stack


   .. py:attribute:: beads_in_view_on


   .. py:attribute:: beads_in_view_count


   .. py:attribute:: beads_in_view_marker_size


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: selected_bead_callback(value)


   .. py:method:: reference_bead_callback(value)


   .. py:method:: time_mode_callback(value: str)


   .. py:method:: relative_time_window_callback(_value)


   .. py:method:: limits_callback(_)


   .. py:method:: beads_in_view_on_callback()


   .. py:method:: beads_in_view_count_callback()


   .. py:method:: beads_in_view_marker_size_callback()


.. py:function:: has_tweezepy_support() -> bool

.. py:function:: load_tweezepy_avar() -> tuple[callable | None, str | None]

.. py:class:: AllanDeviationPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`MatplotlibCleanupMixin`, :py:obj:`ControlPanelBase`


   .. py:attribute:: _SETTINGS_GROUP
      :value: 'AllanDeviationPanel'



   .. py:attribute:: refresh_button


   .. py:attribute:: history_window


   .. py:attribute:: history_window_hint


   .. py:attribute:: taus_mode


   .. py:attribute:: figure


   .. py:attribute:: canvas


   .. py:attribute:: axes


   .. py:attribute:: status_label


   .. py:method:: _settings() -> PyQt6.QtCore.QSettings


   .. py:method:: _setting_key(name: str) -> str


   .. py:method:: _load_setting(name: str, default: str) -> str


   .. py:method:: _persist_controls() -> None


   .. py:method:: _configure_axes() -> None


   .. py:method:: refresh_plot() -> None


   .. py:method:: clear(message: str = 'Click Refresh to compute Allan deviation') -> None


   .. py:method:: _parse_window_seconds(value: str) -> float | None
      :staticmethod:



   .. py:method:: _estimate_sampling_rate(timestamps: numpy.ndarray) -> float | None
      :staticmethod:



   .. py:method:: _apply_history_window(timestamps: numpy.ndarray, values: numpy.ndarray, window_seconds: float) -> tuple[numpy.ndarray, numpy.ndarray]
      :staticmethod:



   .. py:method:: _extract_axis_series(tracks: numpy.ndarray, *, axis_name: str, selected_bead: int | None, reference_bead: int | None) -> tuple[numpy.ndarray, numpy.ndarray]
      :staticmethod:



.. py:class:: ProfilePanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`MatplotlibCleanupMixin`, :py:obj:`ControlPanelBase`


   .. py:attribute:: enable


   .. py:attribute:: selected_bead_label


   .. py:attribute:: profile_length_label


   .. py:attribute:: figure


   .. py:attribute:: canvas


   .. py:attribute:: axes


   .. py:method:: enabled_callback(enabled: bool) -> None


   .. py:method:: _groupbox_toggled(expanded: bool) -> None


   .. py:method:: _apply_enabled_state(enabled: bool) -> None


   .. py:method:: update_plot()


   .. py:method:: clear()


.. py:class:: TrackingOptionsPanel(manager: magscope.ui.ui.UIManager, *, collapsible: bool = True)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: _current_options
      :type:  dict[str, Any]


   .. py:attribute:: _updating_fields
      :value: False



   .. py:attribute:: background_combo


   .. py:attribute:: iterations


   .. py:attribute:: line_ratio


   .. py:attribute:: n_local


   .. py:attribute:: use_fft


   .. py:attribute:: fft_oversample


   .. py:attribute:: fft_rmin


   .. py:attribute:: fft_rmax


   .. py:attribute:: fft_gaus_factor


   .. py:attribute:: radial_oversample


   .. py:attribute:: lookup_n_local


   .. py:method:: _build_preferences_group(title: str, parent: PyQt6.QtWidgets.QWidget) -> tuple[PyQt6.QtWidgets.QWidget, PyQt6.QtWidgets.QVBoxLayout]
      :staticmethod:



   .. py:method:: _configure_lineedit_row(widget: magscope.ui.widgets.LabeledLineEditWithValue) -> None
      :staticmethod:



   .. py:method:: _configure_checkbox_row(widget: magscope.ui.widgets.LabeledCheckbox) -> None
      :staticmethod:



   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]
      :staticmethod:



   .. py:method:: _option_line_edits() -> tuple[magscope.ui.widgets.LabeledLineEditWithValue, Ellipsis]


   .. py:method:: _update_value_labels() -> None


   .. py:method:: _sync_fft_enabled_state() -> None


   .. py:method:: _use_fft_changed(value: bool) -> None


   .. py:method:: _set_options(options: dict[str, Any], message: str | None = None, *, populate_inputs: bool = False) -> None


   .. py:method:: _populate_inputs_from_options() -> None


   .. py:method:: _load_options_from_mapping(loaded: Any) -> dict[str, Any]


   .. py:method:: _options_from_inputs() -> dict[str, Any]


   .. py:method:: _apply_options_from_inputs() -> None


   .. py:method:: reset_defaults() -> None


.. py:class:: PreferencesDialog(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`PyQt6.QtWidgets.QDialog`


   Modal dialog for global MagScope preferences.


   .. py:attribute:: _SIDEBAR_SECTIONS
      :type:  tuple[tuple[str, str], Ellipsis]
      :value: (('tune', 'MagScope'), ('ads_click', 'Tracking'), ('palette', 'Appearance/Layout'))



   .. py:attribute:: manager


   .. py:attribute:: load_preferences_button


   .. py:attribute:: save_preferences_button


   .. py:attribute:: reset_all_preferences_button


   .. py:attribute:: preferences_file_status


   .. py:attribute:: settings_panel


   .. py:attribute:: settings_scroll


   .. py:attribute:: tracking_options_panel


   .. py:attribute:: tracking_scroll


   .. py:attribute:: appearance_layout_tab


   .. py:attribute:: appearance_scroll


   .. py:attribute:: stack


   .. py:attribute:: reset_section_button


   .. py:attribute:: sidebar


   .. py:method:: _sidebar_selection_background(accent: str) -> str
      :staticmethod:



   .. py:method:: _apply_preferences_style(accent: str) -> None


   .. py:method:: _refresh_sidebar_icons(accent: str | None = None) -> None


   .. py:method:: _on_load_preferences_clicked() -> None


   .. py:method:: _on_save_preferences_clicked() -> None


   .. py:method:: _on_reset_all_preferences_clicked() -> None


   .. py:method:: _set_preferences_file_status(message: str) -> None


   .. py:method:: _create_appearance_layout_tab() -> PyQt6.QtWidgets.QWidget


   .. py:method:: _choose_accent_color() -> None


   .. py:method:: _update_accent_color_swatch(color: str) -> None


   .. py:method:: _apply_accent_color_setting() -> None


   .. py:method:: _apply_live_plot_progress_indicator_setting(checked: bool) -> None


   .. py:method:: _scrollable_tab(widget: PyQt6.QtWidgets.QWidget) -> PyQt6.QtWidgets.QScrollArea


   .. py:method:: _make_material_symbol_icon(font: PyQt6.QtGui.QFont, text: str, color: str = '#888888', size: int = 16) -> PyQt6.QtGui.QIcon
      :staticmethod:



   .. py:method:: _on_sidebar_selection(index: int) -> None


   .. py:method:: _on_reset_current_section() -> None


   .. py:method:: _stack_index_for_scroll(scroll: PyQt6.QtWidgets.QScrollArea) -> int


   .. py:method:: reveal_setting(setting_key: str) -> None


   .. py:method:: reveal_magscope_setting(setting_key: str) -> None


   .. py:method:: reveal_tracking_option(widget_attr: str) -> None


   .. py:method:: reveal_widget(tab_name: str, widget_attr: str) -> None


   .. py:method:: _reveal_widget(scroll: PyQt6.QtWidgets.QScrollArea, widget: PyQt6.QtWidgets.QWidget) -> None


   .. py:method:: _on_reset_appearance_tab_clicked() -> None


   .. py:method:: _reset_appearance_layout(*, reset_accent: bool) -> None


.. py:class:: ScriptPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: NO_SCRIPT_SELECTED_TEXT
      :value: 'No script loaded'



   .. py:attribute:: status_prefix
      :value: 'Status'



   .. py:attribute:: status_label


   .. py:attribute:: step_position_label


   .. py:attribute:: step_description_label


   .. py:attribute:: button_layout


   .. py:attribute:: load_button


   .. py:attribute:: start_button


   .. py:attribute:: pause_button


   .. py:attribute:: filepath_textedit


   .. py:method:: update_status(status: magscope.scripting.ScriptStatus)


   .. py:method:: update_step(current_step: int | None, total_steps: int, description: str | None)


   .. py:method:: callback_load()


   .. py:method:: callback_start()


   .. py:method:: callback_pause()


.. py:class:: StatusPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: dot_count
      :value: 0



   .. py:attribute:: display_rate_status


   .. py:attribute:: video_processors_status


   .. py:attribute:: video_buffer_size_status


   .. py:attribute:: video_buffer_status


   .. py:attribute:: video_buffer_status_bar


   .. py:attribute:: video_buffer_purge_label


   .. py:method:: update_display_rate(text)


   .. py:method:: update_video_processors_status(status_text: str)


   .. py:method:: update_video_buffer_status(status_text: str)


   .. py:method:: _update_video_buffer_size_label() -> None


   .. py:method:: update_video_buffer_purge(timestamp: float)


.. py:class:: _LockInfoButton(tooltip_text: str, parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QToolButton`


   Compact info icon that shows a tooltip on hover.


.. py:class:: _LockStatusBadge(text: str = '', parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QLabel`


   Compact color-coded status label with rounded background.


   .. py:attribute:: _state
      :value: ''



   .. py:method:: set_state(state: str) -> None


   .. py:method:: _apply_style() -> None


.. py:class:: _LockActivityIndicator(parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QWidget`


   Small circular ring indicator that fills over the lock interval and resets on correction.


   .. py:attribute:: _SIZE
      :value: 14



   .. py:attribute:: _RING_WIDTH
      :value: 2



   .. py:attribute:: _BACKGROUND_COLOR
      :value: '#666666'



   .. py:attribute:: _MAXIMUM
      :value: 100



   .. py:attribute:: _active
      :value: False



   .. py:attribute:: _progress
      :value: 0



   .. py:attribute:: _cycle_seconds
      :value: 10.0



   .. py:attribute:: _flash_mode
      :value: False



   .. py:attribute:: _timer


   .. py:method:: set_cycle_duration(seconds: float) -> None


   .. py:method:: reset() -> None


   .. py:method:: set_active(active: bool) -> None


   .. py:method:: trigger_once_flash() -> None


   .. py:method:: _recalc_interval() -> None


   .. py:method:: _tick() -> None


   .. py:method:: paintEvent(_event) -> None


.. py:class:: _LockNumberInput(label_text: str, default: float | int, unit: str, *, is_int: bool = False, minimum: float = 0.0, maximum: float = 999999.0, decimals: int = 1, callback: callable | None = None, show_unit_label: bool = True, parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QWidget`


   Compact row: label | spinbox | unit suffix.


   .. py:attribute:: label


   .. py:attribute:: unit_label


   .. py:attribute:: value_label


   .. py:property:: lineedit


.. py:class:: XYLockPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: _activity_indicator


   .. py:attribute:: once_button


   .. py:attribute:: enabled


   .. py:attribute:: interval


   .. py:attribute:: max


   .. py:attribute:: window


   .. py:method:: notify_correction() -> None


   .. py:method:: _update_badge() -> None


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: enabled_callback()


   .. py:method:: once_callback()


   .. py:method:: interval_callback()


   .. py:method:: max_callback()


   .. py:method:: window_callback()


   .. py:method:: update_enabled(value: bool)


   .. py:method:: update_interval(value: float)


   .. py:method:: update_max(value: float)


   .. py:method:: update_window(value: int)


.. py:class:: ZLockPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: _activity_indicator


   .. py:attribute:: _warning_label


   .. py:attribute:: _once_button


   .. py:attribute:: enabled


   .. py:attribute:: _bead_combo


   .. py:attribute:: bead


   .. py:attribute:: _target_spinbox


   .. py:attribute:: _target_unit_label


   .. py:attribute:: target


   .. py:attribute:: interval


   .. py:attribute:: max


   .. py:attribute:: window


   .. py:attribute:: _target_is_set
      :value: False



   .. py:method:: _refresh_bead_combo() -> None


   .. py:method:: _bead_combo_callback(text: str) -> None


   .. py:method:: _target_spinbox_callback() -> None


   .. py:method:: _once_callback() -> None


   .. py:method:: _update_badge() -> None


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: enabled_callback()


   .. py:method:: interval_callback()


   .. py:method:: max_callback()


   .. py:method:: window_callback()


   .. py:method:: update_enabled(value: bool)


   .. py:method:: update_bead(value: int)


   .. py:method:: _has_focus_motor() -> bool


   .. py:method:: _set_controls_enabled(enabled: bool) -> None


   .. py:method:: update_target(value: float)


   .. py:method:: update_interval(value: float)


   .. py:method:: update_max(value: float)


   .. py:method:: update_window(value: int)


.. py:class:: ZLUTGenerationPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: roi_size_label


   .. py:attribute:: start_input


   .. py:attribute:: step_input


   .. py:attribute:: stop_input


   .. py:attribute:: measurements_input


   .. py:attribute:: generate_button


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: generate_callback()


   .. py:method:: update_state(status: str, detail: str | None = None, *, running: bool = False, can_cancel: bool = False, phase: str = 'idle') -> None


   .. py:method:: update_progress(current_step: int, total_steps: int, capture_count: int, capture_capacity: int, motor_z_value: float | None = None) -> None


.. py:class:: ZLUTGenerationSetupDialog(parent: PyQt6.QtWidgets.QWidget | None = None, *, roi_size: int, default_measurements: int)

   Bases: :py:obj:`PyQt6.QtWidgets.QDialog`


   .. py:attribute:: start_input


   .. py:attribute:: step_input


   .. py:attribute:: stop_input


   .. py:attribute:: measurements_input


   .. py:attribute:: cancel_button


   .. py:attribute:: generate_button


   .. py:attribute:: _values
      :type:  tuple[float, float, float, int] | None
      :value: None



   .. py:property:: values
      :type: tuple[float, float, float, int] | None



   .. py:method:: _accept_if_valid() -> None


.. py:class:: ZLUTSweepPreviewWidget(parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`MatplotlibCleanupMixin`, :py:obj:`PyQt6.QtWidgets.QWidget`


   .. py:attribute:: _STATE_LABELS


   .. py:attribute:: summary_label


   .. py:attribute:: _preview_cmap


   .. py:attribute:: figure


   .. py:attribute:: canvas


   .. py:attribute:: axes


   .. py:attribute:: _image


   .. py:method:: clear(message: str = 'Waiting for Z-LUT sweep data...') -> None


   .. py:method:: update_preview(*, state: int, count: int, capacity: int, n_steps: int, n_beads: int, profiles_per_bead: int, profile_length: int, preview_image: numpy.ndarray | None, selected_bead_id: int | None, mode: str, motor_z_min: float | None, motor_z_max: float | None, expected_capture_count: int | None = None, x_axis_label: str = 'Z Position (nm)', x_axis_min: float | None = None, x_axis_max: float | None = None, image_x_min: float | None = None, image_x_max: float | None = None) -> None


.. py:class:: ZLUTGenerationDialog(parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`PyQt6.QtWidgets.QDialog`


   .. py:attribute:: _running
      :value: False



   .. py:attribute:: _evaluation_active
      :value: False



   .. py:attribute:: _startup_pending
      :value: False



   .. py:attribute:: _close_when_canceled
      :value: False



   .. py:attribute:: _selected_bead_id
      :type:  int | None
      :value: None



   .. py:attribute:: status_label


   .. py:attribute:: detail_label


   .. py:attribute:: progress_label


   .. py:attribute:: progress_bar


   .. py:attribute:: preview_widget


   .. py:attribute:: bead_selector


   .. py:attribute:: cancel_button


   .. py:attribute:: save_button


   .. py:attribute:: save_and_load_button


   .. py:attribute:: close_button


   .. py:attribute:: _cancel_callback
      :value: None



   .. py:attribute:: _close_callback
      :value: None



   .. py:attribute:: _save_callback
      :value: None



   .. py:attribute:: _save_and_load_callback
      :value: None



   .. py:attribute:: _select_bead_callback
      :value: None



   .. py:method:: set_cancel_callback(callback) -> None


   .. py:method:: set_save_callback(callback) -> None


   .. py:method:: set_save_and_load_callback(callback) -> None


   .. py:method:: set_close_callback(callback) -> None


   .. py:method:: set_select_bead_callback(callback) -> None


   .. py:method:: _handle_cancel_clicked() -> None


   .. py:method:: _handle_save_clicked() -> None


   .. py:method:: _handle_save_and_load_clicked() -> None


   .. py:method:: _handle_close_clicked() -> None


   .. py:method:: mark_starting() -> None


   .. py:method:: _handle_bead_selection_changed(index: int) -> None


   .. py:method:: update_state(status: str, detail: str | None = None, *, running: bool = False, can_cancel: bool = False, phase: str = 'idle') -> None


   .. py:method:: update_progress(current_step: int, total_steps: int, capture_count: int, capture_capacity: int, motor_z_value: float | None = None) -> None


   .. py:method:: update_evaluation(*, active: bool, bead_ids: list[int], selected_bead_id: int | None) -> None


   .. py:method:: force_close() -> None


   .. py:method:: closeEvent(event) -> None


.. py:class:: CurrentZLUTDialog(parent: PyQt6.QtWidgets.QWidget | None = None)

   Bases: :py:obj:`MatplotlibCleanupMixin`, :py:obj:`PyQt6.QtWidgets.QDialog`


   .. py:attribute:: preview_status_label


   .. py:attribute:: figure


   .. py:attribute:: canvas


   .. py:attribute:: axes


   .. py:attribute:: _image


   .. py:attribute:: min_value


   .. py:attribute:: max_value


   .. py:attribute:: step_value


   .. py:attribute:: profile_length_value


   .. py:attribute:: filepath_label


   .. py:method:: _add_metadata_row(layout: PyQt6.QtWidgets.QVBoxLayout, label_text: str) -> PyQt6.QtWidgets.QLabel


   .. py:method:: update_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


   .. py:method:: _clear_preview(message: str) -> None


   .. py:method:: _update_preview(filepath: str | None) -> None


   .. py:method:: _format_number(value: float | int | None, suffix: str = '') -> str
      :staticmethod:



.. py:class:: ZLUTPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: zlut_file_selected


   .. py:attribute:: zlut_clear_requested


   .. py:attribute:: NO_ZLUT_SELECTED_TEXT
      :value: 'No Z-LUT file selected'



   .. py:attribute:: select_button


   .. py:attribute:: clear_button


   .. py:attribute:: filepath_textedit


   .. py:attribute:: _metadata_layout


   .. py:attribute:: min_value


   .. py:attribute:: max_value


   .. py:attribute:: step_value


   .. py:attribute:: profile_length_value


   .. py:method:: search_targets() -> list[magscope.ui.search.SearchTarget]


   .. py:method:: _add_metadata_row(label_text: str) -> PyQt6.QtWidgets.QLabel


   .. py:method:: _select_zlut_file()


   .. py:method:: _clear_zlut()


   .. py:method:: set_filepath(path: str | None)


   .. py:method:: update_metadata(z_min: float | None = None, z_max: float | None = None, step_size: float | None = None, profile_length: int | None = None)


   .. py:method:: clear_metadata()


   .. py:method:: _format_number(value: float | int | None, suffix: str = '') -> str
      :staticmethod:



