Source code for pymodaq.extensions.sequencer.utilities.elements.move

import dataclasses

import weakref
from typing import Any

from serializall import SerializableFactory

from qtpy import QtCore, QtWidgets

from pymodaq.control_modules.enums import MoveType
from pymodaq.control_modules.units import get_unit_to_display
from pymodaq.utils.data import DataActuator
from pymodaq.utils.managers.modules import ModuleType
from pymodaq.utils.scanner.scanner import Orientation
from pymodaq_data import DataToExport, Q_
from pymodaq_gui.parameter.pymodaq_ptypes import GroupParameter, registerParameterType
from pymodaq_gui.parameter import Parameter, ParameterTree
from pymodaq.extensions.sequencer.utilities.element_factory import SeqEltBase, SeqEltFactory, ElementError

from pymodaq.extensions.sequencer.utilities.widget_with_toolbar import WidgetWithToolbar
from qt_themes import get_theme

from pymodaq_utils.categorizing import categorize_items, find_last_index

ser_factory = SerializableFactory()


class ActuatorScalableParameter(GroupParameter):
    """
    """

    def __init__(self, **opts):
        opts['type'] = 'act_move_elt'
        opts['addText'] = 'Add'

        opts['addMenu'] = categorize_items(opts['actuators'])
        super().__init__(**opts)

    def addNew(self, typ: tuple):
        """
        """

        typ = typ[-1]  # Only need last entry here
        if typ in [child.name() for child in self.children()]:
            return
        child = {'title': f'{typ}',
                 'name': f'{typ}',
                 'type': 'float',
                 'siPrefix': True,
                 'removable': True,
                 }
        self.addChild(child)

registerParameterType('act_move_elt', ActuatorScalableParameter, override=True)


@dataclasses.dataclass
class ValueUnits:
    value: float
    units: str

    def __repr__(self):
        return f'{self.value} {self.units}'


class ActuatorsValuesUnits:

    def __init__(self):
        self._actuators: dict[str, ValueUnits] = {}

    def __len__(self):
        return len(self._actuators)

    def add_update_actuator(self, act_name: str, value: float, units: str):
        self._actuators[act_name] = ValueUnits(value=value, units=units)

    def get_value_units(self, act_name: str) -> ValueUnits:
        return self._actuators[act_name]

    @property
    def actuators(self) -> list[str]:
        return list(self._actuators.keys())

    def __repr__(self):
        repr = ''
        for act_name in self._actuators:
            repr += f'{act_name}: {self._actuators[act_name]} / '
        return repr

    def to_dict(self) -> dict[str, str]:
        return {act_name: (f'{self.get_value_units(act_name).value} '
                           f'{self.get_value_units(act_name).units}') for act_name in self._actuators}


[docs] @SerializableFactory.register_decorator() @SeqEltFactory.register_elt() class MoveElt(SeqEltBase): elt_name = 'move' children_allowed = False def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._wait_move_done = True self._actuator_and_value = ActuatorsValuesUnits() def initialize_element(self): pass def set_wait_move_done(self, not_wait=True): self._wait_move_done = not not_wait def do_things_with_dashboard(self): pass def _create_widget(self, base_widget: WidgetWithToolbar) -> WidgetWithToolbar: base_widget.settings = Parameter.create(name='settings', type='act_move_elt', actuators=self.dashboard.modules_manager.actuators_name) for act_name in self._actuator_and_value.actuators: base_widget.settings.addNew((act_name,)) base_widget.settings.child(act_name).setValue( self._actuator_and_value.get_value_units(act_name).value) base_widget.settings.child(act_name).setOpts( suffix=self._actuator_and_value.get_value_units(act_name).units) base_widget.settings.sigTreeStateChanged.connect(self._on_tree_changed) base_widget.settings_tree = ParameterTree() base_widget.settings_tree.header().setSectionResizeMode( QtWidgets.QHeaderView.ResizeMode.Interactive, ) base_widget.settings_tree.resizeColumnToContents(0) base_widget.settings_tree.setParameters(base_widget.settings, showTop=False) base_widget.insert_widget(base_widget.settings_tree) base_widget.add_action('wait_move_done', 'WaitForMoveDone', icon_name='hourglass', icon_color=get_theme().green, icon_checked='hourglass_disabled', icon_checked_color=get_theme().red, checkable=True, checked=not self._wait_move_done) base_widget.connect_action('wait_move_done', self.set_wait_move_done) if (base_widget.parent() is not None and hasattr(base_widget.parent(), 'popup_hiding')): base_widget.parent().popup_hiding.connect(self._on_editor_closing) return base_widget def _on_tree_changed(self, param_parent, changes): for param, change, data in changes: path = param_parent.childPath(param) if change == "childAdded": child: Parameter = data[0] actuator = self.dashboard.modules_manager.get_mod_from_name(child.name(), mod=ModuleType.Actuator) child.setOpts(suffix=get_unit_to_display(actuator.units)) self._actuator_and_value.add_update_actuator(child.name(), child.value(), get_unit_to_display(actuator.units),) elif change == "value": self._actuator_and_value.add_update_actuator( param.name(), data, param.opts['suffix']) elif change == "parent": pass elif change == "options": pass elif change == "limits": pass elif change == 'contextMenu': pass def _on_editor_closing(self): pass def _execute(self, dte: DataToExport=None): """ Move the Actuators to their value and wait or not depending on the wait_move_done boolean""" dte_move = DataToExport('actuators', data=[ DataActuator( act_name, data=self._actuator_and_value.get_value_units(act_name).value, units=self._actuator_and_value.get_value_units(act_name).units ) for act_name in self._actuator_and_value.actuators if act_name in self.dashboard.modules_manager.actuators_name ]) self.dashboard.modules_manager.move_actuators_with_callback( dte_move, mode=MoveType.ABS, callback=self._on_move_done, do_connect_modules=True) if not self._wait_move_done: self.done_signal.emit() def _on_move_done(self, dte: DataToExport): self.dashboard.modules_manager.forget_callback( self._on_move_done, module_type=ModuleType.Actuator, disconnect_modules=True) self.save_data(dte, done=False) # to log the data, done_signal handled below if self._wait_move_done: self.done_signal.emit()
[docs] def to_dict_custom(self) -> dict[str, Any]: """ adds attribute to a dict in order to produce a human readable representation/configuration for this element to be reimplemented """ move_dict = self._actuator_and_value.to_dict() move_dict['wait_move_done'] = self._wait_move_done return move_dict
[docs] def from_dict_custom(self, dict_config: dict[str, Any]): """ Create/set the custom part of the element to finish initialization using setters, attribute assignment or methods """ self._wait_move_done = dict_config.pop('wait_move_done', True) for act_name in dict_config: quantity = Q_(dict_config[act_name]) self._actuator_and_value.add_update_actuator(act_name, quantity.magnitude, quantity.units)
def _eq(self, other: 'MoveElt'): """ Custom method to reimplement to assert two elements are equals""" return self.to_dict() == other.to_dict() def __repr__(self): return f"{super().__repr__()} - {self._actuator_and_value}"
[docs] def check_set_is_valid(self): """ Check the validity of the element Will be called before executing the element. Try to make sure the element is valid or raise ElementError if the user may do something! """ for act_name in self._actuator_and_value.actuators: if act_name not in self.dashboard.modules_manager.actuators_name: raise ElementError(f'Actuator {act_name} not available in Dashboard')
def size_hint(self) -> QtCore.QSize: return QtCore.QSize(200, 150 + 35 * len(self._actuator_and_value))