diff --git a/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst
new file mode 100644
index 00000000000..0bda41a0d97
--- /dev/null
+++ b/docs/source/upcoming_release_notes/1275-SmarAct_UI_Overhaul.rst
@@ -0,0 +1,33 @@
+1275 SmarAct UI Overhaul
+#################
+
+API Breaks
+----------
+- N/A
+
+Library Features
+----------------
+- Added SmarAct.detailed.ui screen
+- Accompanying SmarAct.detailed.py screen to handle closed loop and picoscale
+- Added SmarActTipTilt.embedded ui and py screens for operational support
+- Designed and implemented huge improvements for all the SmarAct typhos screens, a monumental win for laser folk.
+
+Device Features
+---------------
+- Added long_name fields to various SmarAct classes in pcsdevices.epics_motor
+
+New Devices
+-----------
+- N/A
+
+Bugfixes
+--------
+- N/A
+
+Maintenance
+-----------
+- N/A
+
+Contributors
+------------
+- aberges-SLAC
diff --git a/pcdsdevices/epics_motor.py b/pcdsdevices/epics_motor.py
index 1257c526019..ffbac373b85 100644
--- a/pcdsdevices/epics_motor.py
+++ b/pcdsdevices/epics_motor.py
@@ -1562,6 +1562,20 @@ class SmarActOpenLoop(Device):
module_temp = Cpt(EpicsSignalRO, ':MODTEMP', kind='normal',
doc='Temperature of the MCS2 Module in the rack')
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ # Long name shenanigans
+ self.step_voltage.long_name = 'Step Voltage'
+ self.step_freq.long_name = 'Step Frequency'
+ self.jog_step_size.long_name = 'Jog Step Size'
+ self.jog_fwd.long_name = 'Jog Forward'
+ self.jog_rev.long_name = 'Jog Backward'
+ self.total_step_count.long_name = 'Total Step Count'
+ self.step_clear_cmd.long_name = 'Clear Step Count'
+ self.scan_move.long_name = 'Scan Voltage'
+ self.channel_temp.long_name = 'Channel Temp. (°C)'
+ self.module_temp.long_name = 'Module Temp. (°C)'
+
class SmarActTipTilt(Device):
"""
@@ -1652,6 +1666,41 @@ class SmarAct(EpicsMotorInterface):
# useful
open_loop = Cpt(SmarActOpenLoop, '', kind='omitted')
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
+ # Long name shenanigans
+ # Motor Record long name overrides
+ self.velocity.long_name = 'Velocity'
+ self.velocity_base.long_name = 'Velocity Min'
+ self.velocity_max.long_name = 'Velocity Max'
+ self.acceleration.long_name = 'Acceleration'
+ self.motor_stop.long_name = 'Stop Motor'
+ self.motor_is_moving.long_name = 'Actively Moving'
+ self.dial_position.long_name = 'Dial Position'
+ self.direction_of_travel.long_name = 'Direction of Travel'
+ self.home_forward.long_name = 'Home Forward'
+ self.home_reverse.long_name = 'Home Backward'
+ self.low_limit_switch.long_name = 'Low Limit Switch'
+ self.high_limit_switch.long_name = 'High Limit Switch'
+ self.high_limit_travel.long_name = 'High Limit Travel'
+ self.low_limit_travel.long_name = 'Low Limit Travel'
+ self.user_setpoint.long_name = 'Setpoint'
+ self.user_offset.long_name = 'User Offset'
+ self.user_offset_dir.long_name = 'User Offset Direction'
+ self.motor_egu.long_name = 'EGU'
+ self.description.long_name = 'Description'
+ # SmarAct specific long names
+ self.pos_type.long_name = 'Positioner Type'
+ self.needs_calib.long_name = 'Needs Calibration?'
+ self.do_calib.long_name = 'Calibrate'
+ self.log_scale_offset.long_name = 'Logical Scale Offset'
+ self.def_range_min.long_name = 'Default Range Min.'
+ self.def_range_max.long_name = 'Default Range Max'
+ self.log_scale_inv.long_name = 'Logical Scale Inversion'
+ self.dist_code_inv.long_name = 'Distance Code Inversion'
+ self.channel_temp.long_name = 'Channel Temp. (°C)'
+ self.module_temp.long_name = 'Module Temp. (°C)'
+
class SmarActEncodedTipTilt(Device):
"""
@@ -1718,6 +1767,18 @@ class SmarActPicoscale(SmarAct):
def __init__(self, prefix, *, ioc_base, **kwargs):
self._ioc_base = ioc_base
super().__init__(prefix, **kwargs)
+ self.pico_adj_done.long_name = 'Auto Adjustment Done?'
+ self.pico_adj_state.long_name = 'Auto Adjustment State'
+ self.pico_curr_adj_prog.long_name = 'Auto Adjustment Progress'
+ self.pico_enable.long_name = 'PicoScale Enabled?'
+ self.pico_exists.long_name = 'PicoScale Exists?'
+ self.pico_name.long_name = 'PicoScale Name'
+ self.pico_present.long_name = 'PicoScale Present?'
+ self.pico_sig_qual.long_name = 'Signal Quality'
+ self.pico_valid.long_name = 'PicoScale Valid?'
+ self.pico_stable.long_name = 'PicoScale Stable?'
+ self.pico_wmax.long_name = 'Working distance (max)'
+ self.pico_wmin.long_name = 'Working distance (min)'
class PI_M824(PVPositionerIsClose):
diff --git a/pcdsdevices/ui/SmarAct.detailed.py b/pcdsdevices/ui/SmarAct.detailed.py
new file mode 100644
index 00000000000..320cfa4a05a
--- /dev/null
+++ b/pcdsdevices/ui/SmarAct.detailed.py
@@ -0,0 +1,378 @@
+from __future__ import annotations
+
+import logging
+import re
+
+import pydm
+from pydm import Display
+from qtpy import QtCore, QtWidgets
+from typhos import utils
+
+logger = logging.getLogger(__name__)
+
+
+class _SmarActDetailedUI(QtWidgets.QWidget):
+ """Annotations helper for SmarAct.detailed.ui. Do not instantiate."""
+ # Status bar
+ calibrated_bool: pydm.widgets.byte.PyDMByteIndicator
+ has_encoder_bool: pydm.widgets.byte.PyDMByteIndicator
+ referenced_bool: pydm.widgets.byte.PyDMByteIndicator
+ # Open-loop tab
+ jog_fwd_button: pydm.widgets.pushbutton.PyDMPushButton
+ jog_rev_button: pydm.widgets.pushbutton.PyDMPushButton
+ step_clear_cmd_button: pydm.widgets.pushbutton.PyDMPushButton
+ total_step_count_rbv: pydm.widgets.label.PyDMLabel
+ step_size_rbv: pydm.widgets.label.PyDMLabel
+ step_size_set: pydm.widgets.line_edit.PyDMLineEdit
+ step_volt_rbv: pydm.widgets.label.PyDMLabel
+ step_volt_set: pydm.widgets.line_edit.PyDMLineEdit
+ step_freq_rbv: pydm.widgets.label.PyDMLabel
+ step_freq_set: pydm.widgets.line_edit.PyDMLineEdit
+ scan_move_rbv: pydm.widgets.label.PyDMLabel
+ scan_move_set: pydm.widgets.line_edit.PyDMLineEdit
+ # Closed-loop tab
+ home_forward_button: pydm.widgets.pushbutton.PyDMPushButton
+ home_reverse_button: pydm.widgets.pushbutton.PyDMPushButton
+ curr_pos_rbv: pydm.widgets.label.PyDMLabel
+ curr_pos_set: pydm.widgets.line_edit.PyDMLineEdit
+ home_velocity_rbv: pydm.widgets.label.PyDMLabel
+ home_velocity_set: pydm.widgets.line_edit.PyDMLineEdit
+ velocity_rbv: pydm.widgets.label.PyDMLabel
+ velocity_set: pydm.widgets.line_edit.PyDMLineEdit
+ velocity_base_rbv: pydm.widgets.label.PyDMLabel
+ velocity_base_set: pydm.widgets.line_edit.PyDMLineEdit
+ velocity_max_rbv: pydm.widgets.label.PyDMLabel
+ velocity_max_set: pydm.widgets.line_edit.PyDMLineEdit
+ acceleration_rbv: pydm.widgets.label.PyDMLabel
+ acceleration_set: pydm.widgets.line_edit.PyDMLineEdit
+ closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel
+ closed_loop_freq_max_set: pydm.widgets.line_edit.PyDMLineEdit
+ # Diagnostics tab
+ channel_temp_rbv: pydm.widgets.label.PyDMLabel
+ module_temp_rbv: pydm.widgets.label.PyDMLabel
+ motor_load_rbv: pydm.widgets.label.PyDMLabel
+ chan_error_rbv: pydm.widgets.label.PyDMLabel
+ diag_closed_loop_freq_max_rbv: pydm.widgets.label.PyDMLabel
+ diag_closed_loop_freq_avg_rbv: pydm.widgets.label.PyDMLabel
+ diag_closed_loop_freq_timebase_rbv: pydm.widgets.label.PyDMLabel
+ channel_states: pydm.widgets.byte.PyDMByteIndicator
+ # Config tab
+ desc_rbv: pydm.widgets.label.PyDMLabel
+ desc_set: pydm.widgets.line_edit.PyDMLineEdit
+ egu_rbv: pydm.widgets.label.PyDMLabel
+ egu_set: pydm.widgets.line_edit.PyDMLineEdit
+ pos_type_rbv: pydm.widgets.label.PyDMLabel
+ pos_type_set: pydm.widgets.line_edit.PyDMLineEdit
+ needs_calib_led: pydm.widgets.byte.PyDMByteIndicator
+ do_calib_button: pydm.widgets.pushbutton.PyDMPushButton
+ low_limit_rbv: pydm.widgets.label.PyDMLabel
+ low_limit_set: pydm.widgets.line_edit.PyDMLineEdit
+ high_limit_rbv: pydm.widgets.label.PyDMLabel
+ high_limit_set: pydm.widgets.line_edit.PyDMLineEdit
+ ttzv_rbv: pydm.widgets.label.PyDMLabel
+ ttzv_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox
+ ttzv_threshold_rbv: pydm.widgets.label.PyDMLabel
+ ttzv_treshold_set: pydm.widgets.line_edit.PyDMLineEdit
+ log_scale_offset_rbv: pydm.widgets.label.PyDMLabel
+ log_scale_offset_set: pydm.widgets.line_edit.PyDMLineEdit
+ log_scale_inversion_rbv: pydm.widgets.label.PyDMLabel
+ log_scale_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox
+ def_range_min_rbv: pydm.widgets.label.PyDMLabel
+ def_range_min_set: pydm.widgets.line_edit.PyDMLineEdit
+ def_range_max_rbv: pydm.widgets.label.PyDMLabel
+ def_range_max_set: pydm.widgets.line_edit.PyDMLineEdit
+ dist_code_inversion_rbv: pydm.widgets.label.PyDMLabel
+ dist_code_inversion_set: pydm.widgets.enum_combo_box.PyDMEnumComboBox
+ # Misc
+ controls_tabs: QtWidgets.QTabWidget
+ pico_adjustment_prog_bar: QtWidgets.QProgressBar
+
+
+class SmarActDetailedWidget(Display, utils.TyphosBase):
+ """
+ Custom widget for managing the SmarAct detailed screen
+ """
+ ui: _SmarActDetailedUI
+
+ def __init__(self, parent=None, ui_filename='SmarAct.detailed.ui', **kwargs):
+ super().__init__(parent=parent, ui_filename=ui_filename)
+
+ @property
+ def device(self):
+ """The associated device."""
+ try:
+ return self.devices[0]
+ except Exception:
+ ...
+
+ def add_device(self, device):
+ """Typhos hook for adding a new device."""
+ super().add_device(device)
+ # Gotta make sure to destroy this screen if you were handed an empty device
+ if device is None:
+ self.ui.device_name_label.setText("(no device)")
+ return
+
+ self.post_typhos_init()
+
+ def post_typhos_init(self):
+ """
+ Once typhos has relinked the device and parent widget, we need to clean
+ Up some of the signals and maybe add new widgets to the display.
+ Add any other init-esque shenanigans you need here.
+ """
+ self.fix_pvs()
+ self.maybe_add_pico()
+ self.add_tool_tips()
+
+ def fix_pvs(self):
+ """
+ Fix all the channel access and signal linking to various pydm objects in the screen,
+ since the macros aren't expanded when the UI is initialized.
+ """
+ object_names = self.find_pydm_names()
+ for obj in object_names:
+ _widget = getattr(self, obj)
+ _channel = getattr(_widget, 'channel')
+ if not _channel:
+ _channel = ''
+ if re.search(r'\{prefix\}', _channel):
+ _widget.set_channel(_channel.replace('${prefix}', self.device.prefix))
+
+ # Now let's manually add the funky egu and description signals here to avoid terminal spam
+ self.desc_set.set_channel(f'sig://{self.device.name}_description')
+ self.egu_set.set_channel(f'sig://{self.device.name}_motor_egu')
+
+ def add_tool_tips(self):
+ """
+ Add hutch_python tooltips to label widgets, if they exist.
+ """
+ _signals = list(self.device.component_names)
+ # Let's deal with the subdevice signals afterwards
+ _signals.remove('open_loop')
+ _open_loop_signals = list(self.device.open_loop.component_names)
+
+ def _get_tooltip(device: any, signal: str) -> str:
+ """
+ Get the tooltip from the Ophyd.Device signal, if it exists.
+ """
+ _dotted_name = getattr(device, signal).dotted_name
+ try:
+ _tooltip = getattr(type(device), signal).doc
+ except AttributeError:
+ _tooltip = ''
+ _tooltip = (_dotted_name + '
'
+ + round(1.75*len(_dotted_name))*'-' + '
'
+ + _tooltip)
+ return _tooltip
+
+ for sig in (_signals + _open_loop_signals):
+ # Assume the QLabel's object name is standard form
+ _label_name = sig + '_label'
+ _device = self.device
+ # open_loop is a component device, nests differently
+ if sig in _open_loop_signals:
+ _device = self.device.open_loop
+ # Now let's add the tooltip for widgets that exist
+ if hasattr(self, _label_name):
+ _tooltip = _get_tooltip(_device, sig)
+ getattr(self, _label_name).setToolTip(_tooltip)
+
+ def find_pydm_names(self) -> list[str]:
+ """
+ Find the object names for all PyDM objects using findChildren
+
+ Returns
+ ------------
+ result : list[str]
+ 1D list of object names
+ """
+ _button = pydm.widgets.pushbutton.PyDMPushButton
+ _byte = pydm.widgets.byte.PyDMByteIndicator
+ _label = pydm.widgets.label.PyDMLabel
+ _line_edit = pydm.widgets.line_edit.PyDMLineEdit
+ _combo_box = pydm.widgets.enum_combo_box.PyDMEnumComboBox
+
+ result = []
+
+ for obj_type in [_button, _byte, _label, _line_edit, _combo_box]:
+ result += [obj.objectName() for obj in self.findChildren(obj_type)]
+
+ # get rid of the objects from the embedded TyphosPositioner widget
+ _omit = ['low_limit_switch', 'moving_indicator', 'high_limit_switch',
+ 'low_limit', 'user_readback', 'error_label',
+ 'high_limit', 'user_setpoint']
+
+ return [obj for obj in result if obj not in _omit]
+
+ def maybe_add_pico(self):
+ """
+ Maybe add the picoscale tab and signals _if_ they exist.
+ Sadly involves a lot of manual signal management that would normally be
+ handled in TyphosSignalPanel.
+ """
+ if hasattr(self.device, 'pico_exists'):
+ if hasattr(self, 'picoscale'):
+ # Don't add infite tabs please :]
+ return
+ # Only start this timer if PicoScale exists
+ self.adj_prog_timer = QtCore.QTimer(parent=self)
+ self.adj_prog_timer.timeout.connect(self.update_adj_prog)
+ self.adj_prog_timer.setInterval(1000)
+ self.adj_prog_timer.start()
+ self._last_adj_prog = 0
+ # Grab all the pico related signals
+ _pico_signals = [sig for sig in self.device.component_names if 'pico' in sig]
+ self.pico_signal_dict = {}
+ # Grab any usable info from the HAPPI device and rebuild the JSON
+ for sig in _pico_signals:
+ _d = {}
+ _sig = getattr(self.device, sig)
+ _d['name'] = sig
+ if hasattr(_sig, 'pvname'):
+ _d['read_pv'] = _sig.pvname
+ if hasattr(_sig, 'setpoint_pvname'):
+ _d['write_pv'] = _sig.setpoint_pvname
+ if hasattr(_sig, 'long_name'):
+ _d['label'] = _sig.long_name
+ self.pico_signal_dict[sig] = _d
+
+ # Now let's add some metadata for customizing the display
+ _byte_sigs = ['pico_present', 'pico_exists', 'pico_valid', 'pico_enable', 'pico_stable', 'pico_adj_done']
+ _enum_sigs = ['pico_adj_state']
+ for sig in _byte_sigs:
+ self.pico_signal_dict[sig]['meta'] = 'byte'
+ for sig in _enum_sigs:
+ self.pico_signal_dict[sig]['meta'] = 'enum'
+ # Some exceptions that prove the rule
+ self.pico_signal_dict['pico_curr_adj_prog']['meta'] = 'progressbar'
+
+ # Last but not least, let me manually dictate the signal order
+ _rows = ['pico_name', 'pico_present', 'pico_exists', 'pico_valid', 'pico_enable',
+ 'pico_stable', 'pico_adj_done', 'pico_wmin', 'pico_wmax', 'pico_sig_qual',
+ 'pico_adj_state', 'pico_curr_adj_prog']
+ for pos, item in enumerate(_rows):
+ self.pico_signal_dict[item]['row'] = pos
+
+ # Generate the tab
+ self.generate_pico_tab()
+
+ def generate_pico_tab(self):
+ """
+ Gather all the pico related signals from the device and format the signal panel.
+ A lot of this is recycled from TyphosSignalPanel with some alterations.
+ """
+
+ def add_signal_row(grid: QtWidgets.QGridLayout, signal_dict: dict):
+ """
+ Similar to the typhos method but allows for some manual overhauling.
+ Bundles an EpicsSignal into a row of (Label, RBV widget, Setpoint widget)
+ and adds it to a grid layout.
+
+ Parameters
+ ------------
+ grid: QtWidgets.QGridLayout
+ The layout to add the signals to
+ signal_dict: dict
+ A JSON-like dictionary of device signals, names, and metadata
+
+ Returns
+ ------------
+ None
+ """
+ # Make the row label first
+ row_label = QtWidgets.QLabel()
+ row_label.setText(signal_dict['label'])
+ # Set the object name as an attr for later shenanigans
+ setattr(self, signal_dict['name'] + '_label', row_label)
+
+ # Then set the RBV widget
+ rbv_widget = pydm.widgets.label.PyDMLabel()
+ rbv_widget.setAlignment(QtCore.Qt.AlignCenter)
+ # Unless they're special
+ if 'meta' in signal_dict:
+ if signal_dict['meta'] == 'byte':
+ rbv_widget = pydm.widgets.byte.PyDMByteIndicator()
+ rbv_widget.circles = 1
+ rbv_widget.showLabels = 0
+ if signal_dict['meta'] == 'progressbar':
+ rbv_widget = QtWidgets.QProgressBar()
+ rbv_widget.setRange(0, 100)
+ rbv_widget.hide()
+ row_label.hide()
+
+ # Add the widget as an attr for later shenanigans
+ setattr(self, signal_dict['name'] + '_rbv', rbv_widget)
+
+ if hasattr(rbv_widget, 'set_channel'):
+ rbv_widget.set_channel(signal_dict['read_pv'])
+
+ # Create setpoint widgets if they exist
+ if 'write_pv' in signal_dict:
+ # handle tricky enums
+ if 'meta' in signal_dict and signal_dict['meta'] == 'enum':
+ setpoint_widget = pydm.widgets.enum_combo_box.PyDMEnumComboBox()
+ setpoint_widget.set_channel(signal_dict['write_pv'])
+ # lean on HAPPI if possible
+ _signal_metadata = getattr(self.device, signal_dict['name']).metadata
+ if 'enum_strs' in _signal_metadata:
+ for item in _signal_metadata['enum_strs']:
+ setpoint_widget.addItem(item)
+ # Otherwise just give it some defaults
+ else:
+ for item in ['Disable', 'Enable']:
+ setpoint_widget.addItem(item)
+ # Default line edits
+ else:
+ setpoint_widget = pydm.widgets.line_edit.PyDMLineEdit()
+ setpoint_widget.set_channel(signal_dict['write_pv'])
+
+ # Add the widget as an attr for later shenanigans
+ setattr(self, signal_dict['name'] + '_set', setpoint_widget)
+
+ # Now finally add these signals
+ grid.addWidget(row_label, signal_dict['row'], 0)
+ grid.addWidget(
+ getattr(self, signal_dict['name'] + '_rbv'), signal_dict['row'], 1)
+ if 'write_pv' in signal_dict:
+ grid.addWidget(setpoint_widget, signal_dict['row'], 2)
+
+ # Make the tab
+ self.picoscale = QtWidgets.QWidget()
+ # Format the scroll area
+ pico_scroll_area = QtWidgets.QScrollArea()
+ pico_scroll_area.setFrameStyle(QtWidgets.QFrame.NoFrame)
+ pico_scroll_area.setWidget(self.picoscale)
+ # Format the tab layout
+ self.picoscale.layout = QtWidgets.QVBoxLayout()
+ # Add signals
+ self.picoscale.panel = QtWidgets.QGridLayout()
+ for _d in self.pico_signal_dict:
+ add_signal_row(self.picoscale.panel, self.pico_signal_dict[_d])
+ # Set the layout and add to the tab widget
+ self.picoscale.setLayout(self.picoscale.panel)
+ self.controls_tabs.addTab(self.picoscale, 'Picoscale')
+
+ def update_adj_prog(self):
+ """
+ Function for displaying and updating the QProgressBar when the PicoScale
+ Auto-adjustment is taking place.
+ """
+ # Check to see if the system can even enter adjustment and display the bar
+ if self.device.pico_adj_state.get():
+ self.adj_prog_timer.start()
+ if not self._last_adj_prog:
+ self.pico_curr_adj_prog_rbv.show()
+ self.pico_curr_adj_prog_label.show()
+ # Then check to see if the progress has updated
+ if self._last_adj_prog < self.device.pico_curr_adj_prog.get():
+ self.pico_curr_adj_prog_rbv.setValue(self.device.pico_curr_adj_prog.get())
+ # Now finally check to see if it is complete. Since the threaded behavior in the IOC
+ # toggles the adjustment PV for ALL stages on a PicoScale when adjustment completes,
+ # check for that state change too.
+ if self.device.pico_adj_done.get() or not self.device.pico_adj_state.get():
+ self.pico_curr_adj_prog_rbv.hide()
+ self.pico_curr_adj_prog_rbv.reset()
+ self.pico_curr_adj_prog_label.hide()
+ # reset the timer too in case you need re-adjust later on
+ self.adj_prog_timer.start()
diff --git a/pcdsdevices/ui/SmarAct.detailed.ui b/pcdsdevices/ui/SmarAct.detailed.ui
new file mode 100644
index 00000000000..a2f4af7d26f
--- /dev/null
+++ b/pcdsdevices/ui/SmarAct.detailed.ui
@@ -0,0 +1,4708 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 543
+ 577
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 543
+ 577
+
+
+
+ Form
+
+
+
+ 0
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+
+ 5
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
+ QLayout::SetMinimumSize
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STATE_RBV.B5
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+ 1
+
+
+ 0
+
+
+
+ Has Encoder
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STATE_RBV.B6
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+ 1
+
+
+ 0
+
+
+
+ Calibrated
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STATE_RBV.B7
+
+
+ true
+
+
+ false
+
+
+ false
+
+
+ 1
+
+
+ 0
+
+
+
+ Homed
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 200
+
+
+
+
+ 16777215
+ 150
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Minimum
+
+
+
+ 20
+ 15
+
+
+
+
+ -
+
+
+ true
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 200
+
+
+
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ Open-loop
+
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Qt::LeftToRight
+
+
+ QFrame::StyledPanel
+
+
+ QFrame::Sunken
+
+
+ 1
+
+
+ Qt::ScrollBarAsNeeded
+
+
+ QAbstractScrollArea::AdjustIgnored
+
+
+ true
+
+
+ Qt::AlignCenter
+
+
+
+
+ 0
+ 0
+ 509
+ 300
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 300
+
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Jog
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+
-
+
+
+ Forward
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 25
+
+
+
+
+
+
+
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:STEP_FORWARD
+
+
+ caret-square-right
+
+
+
+ 90
+ 90
+ 90
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 5
+ 25
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 100
+ 25
+
+
+
+
+
+
+
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:STEP_REVERSE.PROC
+
+
+ caret-square-left
+
+
+
+ 90
+ 90
+ 90
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ Reverse
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ QLayout::SetDefaultConstraint
+
+
+ 6
+
+
-
+
+
+ Scan Voltage
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 55
+ 31
+
+
+
+
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:CLEAR_COUNT.PROC
+
+
+ eraser
+
+
+
+ 255
+ 85
+ 255
+
+
+
+ false
+
+
+
+
+
+
+
+
+ true
+
+
+ Are you sure you want to clear the total step count?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ Clear Count
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:STEP_VOLTAGE
+
+
+
+ -
+
+
+ Step Frequency
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STEP_FREQ
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STEP_COUNT
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 5
+ 20
+
+
+
+
+ -
+
+
+ Step Size
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:SCAN_MOVE
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+ 16777215
+ 1677215
+
+
+
+ Total Step Count
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:STEP_COUNT
+
+
+
+ -
+
+
+ Step Voltage
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:STEP_FREQ
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STEP_VOLTAGE
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:TOTAL_STEP_COUNT
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 50
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Scan Voltage as a % expressed as Uint16 (i.e. 0-65535)
+
+
+ ca://${prefix}:SCAN_POS
+
+
+ false
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 20
+ 5
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Closed-loop
+
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+ Qt::AlignCenter
+
+
+
+
+ 0
+ 0
+ 527
+ 400
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 400
+
+
+
+
-
+
+
-
+
+
+
+ 0
+ 25
+
+
+
+ Home
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ QLayout::SetNoConstraint
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 5
+ 25
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 25
+
+
+
+
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.HOMR
+
+
+ fast-backward
+
+
+ false
+
+
+
+
+
+
+
+
+ true
+
+
+ Are you sure you want to proceed? This will move your stage until it reaches the next reference position
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Reverse
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Forward
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 75
+ 25
+
+
+
+
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.HOMF
+
+
+ fast-forward
+
+
+ false
+
+
+
+
+
+
+
+
+ true
+
+
+ Are you sure you want to proceed? This will move your stage until it reaches the next reference position
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Fixed
+
+
+
+ 40
+ 20
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+ 25
+
+
+
+ Acceleration
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Velocity
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Max Velocity
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Current Position
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.VELO
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.HVEL
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Velocity for closed loop moves
+
+
+ ca://${prefix}.VELO
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Closed Loop Frequency Max
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Maximum closed loop frequency in Hz. Sets an upper threshold on the velocity of a stage. Setting > 5 kHz can affect piezo health
+
+
+ ca://${prefix}:MAX_CLF_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Home Velocity
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Base Velocity
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Base (minimum) velocity
+
+
+ ca://${prefix}.VBAS
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.VMAX
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}.RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Velocity of Homing sequence
+
+
+ ca://${prefix}.HVEL
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Acceleration of the closed loop move
+
+
+ ca://${prefix}.ACCL
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 5
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.VBAS
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.VAL
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:MAX_CLF
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.ACCL
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Maximum velocity
+
+
+ ca://${prefix}.VMAX
+
+
+ false
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Diagnostics
+
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 655
+ 250
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 250
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 150
+ 200
+
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 150
+ 600
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 150
+ 600
+
+
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 125
+ 0
+
+
+
+
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:STATE_RBV
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ 21
+
+
+ 0
+
+
+
+ Actively Moving
+ Closed Loop Active
+ Calibrating
+ Referencing
+ Move Delayed
+ Sensor Present
+ Is Calibrated
+ Is Referenced
+ End Stop Reached
+ Range Limit Reached
+ Following Limit Reached
+ Movement Failed
+ Is Streaming
+ Positioner OVLD
+ Over temperature
+ Reference Mark
+ Is Phased
+ Positioner Fault
+ Amplifier Enabled
+ In Position
+ Brake Enabled
+
+
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 2
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+ Motor Load
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Avg CLF measured in 2 s interval
+
+
+ ca://${prefix}:DIAG_CLF_AVG
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Timebase for measuring CLF diagnostics
+
+
+ DCLF Timebase
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ thermal load as a %
+
+
+ ca://${prefix}:MOTOR_LOAD
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Channel Temp.
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Max CLF measured in 2 s interval
+
+
+ DCLF Max
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Max CLF measured in 2 s interval
+
+
+ ca://${prefix}:DIAG_CLF_MAX
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Most recent channel error
+
+
+ ca://${prefix}:CHAN_ERR
+
+
+ false
+
+
+ PyDMLabel::Hex
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Timebase for measuring CLF diagnostics
+
+
+ ca://${prefix}:DIAG_CLF_TIMEBASE_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Module Temp.
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:CHANTEMP
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Channel Error
+
+
+ Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Avg CLF measured in 2 s interval
+
+
+ DCLF Avg
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:MODTEMP
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Timebase for measuring CLF diagnostics
+
+
+ false
+
+
+ ca://${prefix}:DIAG_CLF_TIMEBASE
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Celsius
+
+
+
+ -
+
+
+ Celsius
+
+
+
+ -
+
+
+ %
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Configuration
+
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ true
+
+
+
+
+ 0
+ 0
+ 509
+ 478
+
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 350
+
+
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
+ 9
+
+
-
+
+
+ 6
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Closed-loop ONLY: Whether TTZV is enabled or not
+
+
+ ca://${prefix}:TTZV_MODE_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 13
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Description
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Default minimum range for logical scale. Non-volatile.
+
+
+ Default Range Min
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:SET_LSCO
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ TTZV Threshold
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Target to Zero Voltage
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ PTYPE
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
-
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::MinimumExpanding
+
+
+
+ 80
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 55
+ 25
+
+
+
+
+ 9
+
+
+
+
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:NEED_CALIB
+
+
+
+ 255
+ 255
+ 0
+
+
+
+ Qt::Horizontal
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ 1
+
+
+ 0
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+ QSizePolicy::Expanding
+
+
+
+ 90
+ 20
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.LLM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}.LLM
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}.EGU
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}.HLM
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Sets the distance code inversion flag. Non-volatile.
+
+
+ ca://${prefix}:DCIN_RBV
+
+
+ false
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ High Limit
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Invert the logical scale. Must home after changing to take effect. Non-volatile.
+
+
+ ca://${prefix}:LSCI_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Low Limit
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Sets the distance code inversion flag. Non-volatile.
+
+
+ Distance Code Inversion
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Shift the logical scale in mm. Non-volatile.
+
+
+ ca://${prefix}:LSCO
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Current TTZV position threshold in encoder ticks (pm or ndeg)
+
+
+ ca://${prefix}:TTZ_THRESHOLD_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:SET_DRMIN
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Default Range Max
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ EGU
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Default maximum range for logical scale. Non-volatile.
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Default maximum range for logical scale. Non-volatile.
+
+
+ ca://${prefix}:DRMAX
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+ 10
+ 75
+ true
+
+
+
+
+
+
+ Calibrate
+
+
+
+ 25
+ 25
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:DO_CALIB.PROC
+
+
+ sync
+
+
+
+ 0
+ 85
+ 255
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}:PTYPE_RBV
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Invert the logical scale. Must home after changing to take effect. Non-volatile.
+
+
+ Logical Scale Inversion
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+ Shift the logical scale in mm. Non-volatile.
+
+
+ false
+
+
+ Logical Scale Offset
+
+
+ false
+
+
+ Qt::AlignCenter
+
+
+ true
+
+
+ 0
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:PTYPE
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ TTZV position threshold in encoder ticks (pm or ndeg). Range: 0 - 1E7
+
+
+ false
+
+
+ ca://${prefix}:TTZ_THRESHOLD_RBV
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+ Needs Calibration
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}.DESC
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ true
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ Default minimum range for logical scale. Non-volatile.
+
+
+ ca://${prefix}:DRMIN
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ ca://${prefix}.HLM
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+ 0
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+
+
+
+ false
+
+
+ ca://${prefix}:SET_DRMAX
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 453
+ 37
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PyDMLabel
+ QLabel
+
+
+
+ PyDMByteIndicator
+ QWidget
+
+
+
+ PyDMEnumComboBox
+ QComboBox
+ pydm.widgets.enum_combo_box
+
+
+ PyDMLineEdit
+ QLineEdit
+
+
+
+ PyDMPushButton
+ QPushButton
+
+
+
+ TyphosDisplayTitle
+ QFrame
+
+
+
+ TyphosPositionerWidget
+ QWidget
+
+
+
+
+
+
diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.py b/pcdsdevices/ui/SmarActTipTilt.embedded.py
new file mode 100644
index 00000000000..f417ca5fb65
--- /dev/null
+++ b/pcdsdevices/ui/SmarActTipTilt.embedded.py
@@ -0,0 +1,298 @@
+from __future__ import annotations
+
+import logging
+from typing import Optional
+
+import ophyd
+import pydm
+from pydm import Display
+from qtpy import QtCore, QtGui, QtWidgets
+from typhos import utils
+from typhos.panel import SignalOrder, TyphosSignalPanel
+
+logger = logging.getLogger(__name__)
+
+
+class _SmarActTipTiltEmbeddedUI(QtWidgets.QWidget):
+ """Annotations helper for SmarActTipTilt.embedded.ui. Do not instantiate."""
+ dpad_label: QtWidgets.QLabel
+ tip_forward: pydm.widgets.pushbutton.PyDMPushButton
+ tip_reverse: pydm.widgets.pushbutton.PyDMPushButton
+ tip_step_count: pydm.widgets.label.PyDMLabel
+ tilt_forward: pydm.widgets.pushbutton.PyDMPushButton
+ tilt_reverse: pydm.widgets.pushbutton.PyDMPushButton
+ tilt_step_count: pydm.widgets.label.PyDMLabel
+ settings_button: pydm.widgets.pushbutton.PyDMPushButton
+
+
+class SmarActTipTiltWidget(Display, utils.TyphosBase):
+ """Custom widget for controlling a tip-tilt with d-pad buttons"""
+ ui: _SmarActTipTiltEmbeddedUI
+
+ def __init__(self, parent=None, ui_filename='SmarActTipTilt.embedded.ui', **kwargs,):
+ super().__init__(parent=parent, ui_filename=ui_filename)
+
+ self._omit_names = ['jog_fwd', 'jog_rev']
+ self.ui.extended_signal_panel = None
+
+ self.ui.settings_button.clicked.connect(self._expand_layout)
+
+ @property
+ def device(self):
+ """The associated device."""
+ try:
+ return self.devices[0]
+ except Exception:
+ ...
+
+ def add_device(self, device):
+ """Typhos hook for adding a new device."""
+ super().add_device(device)
+ # Gotta make sure to destroy this screen if you were handed an empty device
+ if device is None:
+ self.ui.device_name_label.setText("(no device)")
+ if self.ui.extended_signal_panel is not None:
+ self.layout().removeWidget(self.ui.extended_signal_panel)
+ self.ui.extended_signal_panel.destroyLater()
+ self.ui.extended_signal_panel = None
+ return
+
+ # Can't do this during init because the device doesn't exist yet!
+ self.update_pvs()
+
+ @QtCore.Property("QStringList")
+ def omitNames(self) -> list[str]:
+ """Get or set the list of names to omit in the expanded signal panel."""
+ return self._omit_names
+
+ @omitNames.setter
+ def omitNames(self, omit_names: list[str]) -> None:
+ if omit_names == self._omit_names:
+ return
+
+ self._omit_names = list(omit_names or [])
+ if self.ui.extended_signal_panel is not None:
+ self.ui.extended_signal_panel.omitNames = self._omit_names
+
+ def _create_signal_panel(self) -> Optional[TyphosSignalPanel]:
+ """Create the 'extended' TyphosSignalPanel for the device."""
+ if self.device is None:
+ return None
+
+ return SettingsPanel(mirror=self, parent=self, flags=QtCore.Qt.Window)
+
+ def _expand_layout(self) -> None:
+ """Toggle the expansion of the signal panel."""
+ if self.ui.extended_signal_panel is None:
+ self.ui.extended_signal_panel = self._create_signal_panel()
+ if self.ui.extended_signal_panel is None:
+ return
+ to_show = True
+ else:
+ to_show = not self.ui.extended_signal_panel.isVisible()
+
+ self.ui.extended_signal_panel.setVisible(to_show)
+
+ def update_pvs(self):
+ """
+ Once we have the tip-tilt device, set the TIP and TILT channels to
+ the buttons and labels.
+ """
+
+ if self.device is None:
+ print('No device set!')
+ return
+
+ self.ui.tip_forward.set_channel(f'ca://{self.device.tip.prefix}:STEP_FORWARD.PROC')
+ self.ui.tip_reverse.set_channel(f'ca://{self.device.tip.prefix}:STEP_REVERSE.PROC')
+ self.ui.tip_step_count.set_channel(f'ca://{self.device.tip.prefix}:TOTAL_STEP_COUNT')
+ self.ui.tilt_forward.set_channel(f'ca://{self.device.tilt.prefix}:STEP_FORWARD.PROC')
+ self.ui.tilt_reverse.set_channel(f'ca://{self.device.tilt.prefix}:STEP_REVERSE.PROC')
+ self.ui.tilt_step_count.set_channel(f'ca://{self.device.tilt.prefix}:TOTAL_STEP_COUNT')
+
+ def get_names_to_omit(self) -> list[str]:
+ """
+ Get a list of signal names to omit in the extended panel.
+
+ Returns
+ -------
+ list[str]
+ """
+ device: Optional[ophyd.Device] = self.device
+ if device is None:
+ return []
+
+ to_omit = set(['jog_fwd', 'jog_rev'])
+
+ # TODO: move these to a Qt designable property
+ for name in self.omitNames:
+ to_omit.add(name)
+
+ if device.name in to_omit:
+ # Don't let the renamed position signal stop us from showing any
+ # signals:
+ to_omit.remove(device.name)
+ return sorted(to_omit)
+
+
+class _StageSettingsUI():
+ """helper for the stages basic settings. Do not instantiate."""
+ tip_label: QtWidgets.QLabel
+ tilt_label: QtWidgets.QLabel
+ step_size_label: QtWidgets.QLabel
+ tip_step_size_rbv: pydm.widgets.label.PyDMLabel
+ tip_step_size_set: pydm.widgets.line_edit.PyDMLineEdit
+ tilt_step_size_rbv: pydm.widgets.label.PyDMLabel
+ tilt_step_size_set: pydm.widgets.line_edit.PyDMLineEdit
+ step_count_label: QtWidgets.QLabel
+ step_count_rbv: pydm.widgets.label.PyDMLabel
+ step_volt_label: QtWidgets.QLabel
+ tip_step_volt_rbv: pydm.widgets.label.PyDMLabel
+ tip_step_volt_set: pydm.widgets.line_edit.PyDMLineEdit
+ tilt_step_volt_rbv: pydm.widgets.label.PyDMLabel
+ tilt_step_volt_set: pydm.widgets.label.PyDMLineEdit
+
+
+class SettingsPanel(QtWidgets.QWidget):
+ """
+ Container class for basic settings that accompany open-loop movement for SmarAct tip-tilts. Largely lifted from TyphosPositionerRow
+ """
+ mirror: SmarActTipTiltWidget
+ resize_timer: QtCore.QTimer
+
+ def __init__(self, mirror: SmarActTipTiltWidget, parent: QtWidgets.QWidget | None = None, **kwargs):
+ super().__init__(parent=parent, **kwargs)
+
+ self.mirror = mirror
+ # Make the subdevice labels
+ self.tip_label = QtWidgets.QLabel()
+ self.format_label(self.tip_label, 'Tip')
+
+ self.tilt_label = QtWidgets.QLabel()
+ self.format_label(self.tilt_label, 'Tilt')
+
+ # Then add panels, widgets, devices, and scroll areas
+ self.tip_panel = TyphosSignalPanel()
+ self.tip_panel.sortBy = SignalOrder.byName
+ self.tip_panel.omitNames = mirror.get_names_to_omit()
+ self.tip_panel.add_device(mirror.device.tip)
+ self.tip_scroll_area = QtWidgets.QScrollArea()
+ self.format_scroll_area(self.tip_panel, self.tip_scroll_area)
+
+ self.tilt_panel = TyphosSignalPanel()
+ self.tilt_panel.sortBy = SignalOrder.byName
+ self.tilt_panel.omitNames = mirror.get_names_to_omit()
+ self.tilt_panel.add_device(mirror.device.tilt)
+ self.tilt_scroll_area = QtWidgets.QScrollArea()
+ self.format_scroll_area(self.tilt_panel, self.tilt_scroll_area)
+
+ # Then add them to the layout!
+ layout = QtWidgets.QVBoxLayout()
+ layout.addWidget(self.tip_label)
+ layout.addWidget(self.tip_scroll_area)
+ layout.addWidget(self.tilt_label)
+ layout.addWidget(self.tilt_scroll_area)
+
+ # Set the layout and then do some resize timer set-up
+ self.setLayout(layout)
+ self.resize_timer = QtCore.QTimer(parent=self)
+ self.resize_timer.timeout.connect(self.fix_scroll_size)
+ self.resize_timer.setInterval(1)
+ self.resize_timer.setSingleShot(True)
+
+ # Capture the initial min widths
+ for panel in [self.tip_panel, self.tilt_panel]:
+ panel.original_panel_min_width = panel.minimumWidth()
+ panel.last_resize_width = 0
+
+ self.resize_done = False
+
+ def format_label(self, label, label_text):
+ """Create and format the text for each subdevice"""
+ _label = label
+ _label.setText(label_text)
+ _font = _label.font()
+ _font.setPointSize(_font.pointSize() + 4)
+ _label.setFont(_font)
+ _label.setMaximumHeight(
+ QtGui.QFontMetrics(_font).boundingRect(_label.text()).height()
+ )
+
+ def format_scroll_area(self, panel, panel_scroll_area):
+ """Format the scroll area for each subdevice"""
+ panel_scroll_area.setFrameStyle(QtWidgets.QFrame.NoFrame)
+ panel_scroll_area.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
+ panel_scroll_area.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
+ panel_scroll_area.setWidgetResizable(True)
+ panel_scroll_area.setWidget(panel)
+
+ def hideEvent(self, event: QtGui.QHideEvent):
+ """
+ After hide, update button text, even if we were hidden via clicking the "x".
+ Shamelessly stolen from TyphosPositionerRow.
+ """
+ button = self.mirror.ui.settings_button
+ button.PyDMIcon = 'SP_ToolBarHorizontalExtensionButton'
+ return super().hideEvent(event)
+
+ def showEvent(self, event: QtGui.QShowEvent):
+ """
+ Before show, update button text and move window to just under button.
+ Shamelessly stolen from TyphosPositionerRow.
+ """
+ button = self.mirror.ui.settings_button
+ button.PyDMIcon = 'SP_ToolBarVerticalExtensionButton'
+ offset = button.mapToGlobal(QtCore.QPoint(0, 0))
+ self.move(
+ button.mapToGlobal(
+ QtCore.QPoint(
+ button.pos().x() + button.width(),
+ button.pos().y() + button.height()
+ + self.style().pixelMetric(QtWidgets.QStyle.PM_TitleBarHeight)
+ - offset.y(),
+ )
+ )
+ )
+ if not self.resize_done:
+ self.resize_timer.start()
+ return super().showEvent(event)
+
+ def fix_scroll_size(self):
+ """
+ Slot that ensures the panel gets enough space in the scroll area.
+
+ The panel, when created, has smaller sizing information than it does
+ a few moments after being shown for the first time. This might
+ update several times before settling down.
+
+ We want to watch for this resize and set the scroll area width such
+ that there's enough room to see the widget at its minimum size.
+ --------------------------------------------------------------------
+ Also shamelessly stolen from TyphosPositionerRow
+ """
+ if (self.tip_panel.minimumWidth() <= self.tip_panel.original_panel_min_width or
+ self.tilt_panel.minimumWidth() <= self.tilt_panel.original_panel_min_width):
+ # No change
+ self.resize_timer.start()
+ return
+ elif (self.tip_panel.last_resize_width != self.tip_panel.minimumWidth() or
+ self.tilt_panel.last_resize_width != self.tilt_panel.minimumWidth()):
+ # We are not stable yet!
+ self.tip_panel.last_resize_width = self.tip_panel.minimumWidth()
+ self.tilt_panel.last_resize_width = self.tilt_panel.minimumWidth()
+ self.resize_timer.start()
+ return
+
+ def make_space(self, scroll_area, panel):
+ """Generalize fixing the dimensions of the scroll areas for multiple panels"""
+ scroll_area.setMinimumWidth(
+ panel.minimumWidth()
+ + self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollBarExtent)
+ + 2 * self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollView_ScrollBarOverlap)
+ + 2 * self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollView_ScrollBarSpacing)
+ )
+
+ make_space(self, self.tip_scroll_area, self.tip_panel)
+ make_space(self, self.tilt_scroll_area, self.tilt_panel)
+
+ self.resize_done = True
diff --git a/pcdsdevices/ui/SmarActTipTilt.embedded.ui b/pcdsdevices/ui/SmarActTipTilt.embedded.ui
new file mode 100644
index 00000000000..72b73a712ca
--- /dev/null
+++ b/pcdsdevices/ui/SmarActTipTilt.embedded.ui
@@ -0,0 +1,580 @@
+
+
+ Form
+
+
+
+ 0
+ 0
+ 320
+ 323
+
+
+
+
+ 0
+ 0
+
+
+
+ Form
+
+
+
+ QLayout::SetMinimumSize
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+
+
+
+ -
+
+
-
+
+
+ Step Count
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Tilt
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+ Tip
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+ Qt::AlignCenter
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 35
+
+
+
+
+
+
+
+ 30
+ 30
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+
+
+
+ caret-right
+
+
+
+ 0
+ 0
+ 0
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 30
+ 30
+
+
+
+
+ 12
+ 75
+ true
+
+
+
+ Step
+
+
+ Qt::AlignCenter
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 35
+
+
+
+
+
+
+
+ 30
+ 30
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+
+
+
+ caret-left
+
+
+
+ 0
+ 0
+ 0
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 35
+
+
+
+
+
+
+
+ 30
+ 30
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+
+
+
+ caret-down
+
+
+
+ 0
+ 0
+ 0
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 35
+ 35
+
+
+
+
+
+
+
+ 30
+ 30
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+
+
+
+ caret-up
+
+
+
+ 0
+ 0
+ 0
+
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ 1
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+ 25
+
+
+
+
+
+
+
+
+
+ false
+
+
+ false
+
+
+
+
+
+ false
+
+
+
+
+
+ SP_ToolBarHorizontalExtensionButton
+
+
+ false
+
+
+
+
+
+
+
+
+ false
+
+
+ Are you sure you want to proceed?
+
+
+ None
+
+
+ None
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+ PyDMLabel
+ QLabel
+
+
+
+ PyDMPushButton
+ QPushButton
+
+
+
+ TyphosDisplayTitle
+ QFrame
+
+
+
+
+
+