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.ResetPanel
   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.ScriptPanel
   magscope.ui.controls.StatusPanel
   magscope.ui.controls.XYLockPanel
   magscope.ui.controls.ZLockPanel
   magscope.ui.controls.ZLUTGenerationPanel
   magscope.ui.controls.ZLUTSweepPreviewWidget
   magscope.ui.controls.ZLUTGenerationDialog
   magscope.ui.controls.ZLUTPanel


Functions
---------

.. autoapisummary::

   magscope.ui.controls.has_tweezepy_support
   magscope.ui.controls.load_tweezepy_avar


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

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

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


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


   .. py:attribute:: groupbox
      :type:  magscope.ui.widgets.CollapsibleGroupBox


   .. 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:: ResetPanel(manager: magscope.ui.ui.UIManager)

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


   Clickable panel that resets the GUI layout to defaults.


   .. py:attribute:: manager


   .. py:attribute:: title_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:: MagScopeSettingsPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   Allow importing, exporting, and editing MagScope configuration values.


   .. py:attribute:: _current_settings


   .. py:attribute:: _setting_inputs
      :type:  dict[str, magscope.ui.widgets.LabeledLineEditWithValue]


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



   .. py:attribute:: load_button


   .. py:attribute:: save_button


   .. py:attribute:: defaults_button


   .. py:attribute:: apply_button


   .. py:attribute:: status_label


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


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


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


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


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


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


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


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


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


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


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

   Bases: :py:obj:`ControlPanelBase`


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



   .. py:attribute:: acquisition_on_checkbox


   .. py:attribute:: acquisition_mode_combobox


   .. py:attribute:: acquisition_dir_on_checkbox


   .. py:attribute:: acquisition_dir_button


   .. py:attribute:: acquisition_dir_textedit


   .. 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: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:attribute:: auto_select_button


   .. 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:: 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)

   Bases: :py:obj:`ControlPanelBase`


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


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


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



   .. 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:attribute:: status_label


   .. py:method:: _parse_int(widget: magscope.ui.widgets.LabeledLineEditWithValue, fallback: int, *, minimum: int | None = None) -> int


   .. py:method:: _parse_float(widget: magscope.ui.widgets.LabeledLineEditWithValue, fallback: float, *, minimum: float | None = None) -> float


   .. 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:: _format_last_updated_text() -> str


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


   .. py:method:: _coerce_int_value(raw: Any, *, name: str, fallback: int, minimum: int | None = None, enforce_odd: bool = False) -> int


   .. py:method:: _coerce_float_value(raw: Any, *, name: str, fallback: float, minimum: float | None = None) -> float


   .. py:method:: _coerce_bool_value(raw: Any, *, fallback: bool) -> bool


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


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


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


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


   .. py:method:: reset_defaults() -> 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:: XYLockPanel(manager: magscope.ui.ui.UIManager)

   Bases: :py:obj:`ControlPanelBase`


   .. py:attribute:: enabled


   .. py:attribute:: interval


   .. py:attribute:: max


   .. py:attribute:: window


   .. 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:: enabled


   .. py:attribute:: bead


   .. py:attribute:: target


   .. py:attribute:: interval


   .. py:attribute:: max


   .. py:attribute:: window


   .. py:method:: enabled_callback()


   .. py:method:: bead_callback()


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



