Skip to content

Commit

Permalink
A collection of small ConfigureGUI modifications (#68)
Browse files Browse the repository at this point in the history
* use the motor signal movement_finished() to update the Axis control displays

* disable configuration controls while the probe drive is moving

* if the status of one axis changes make the other AxisControlWidgets update

* make the drive widget update its display when the configuration is changed

* fix over indent

* move all connected functions to MGWidget.configChanged into the _config_changed_handler() method

* when _update_drive_control_widget() execute _refresh_drive_control() if the drive control widget does not have the valid MG
  • Loading branch information
rocco8773 authored Jan 14, 2025
1 parent 89801f9 commit a85c735
Showing 1 changed file with 116 additions and 9 deletions.
125 changes: 116 additions & 9 deletions bapsf_motion/gui/configure/motion_group_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import asyncio
import logging
import warnings

from PySide6.QtCore import Qt, Signal, Slot, QSize
from PySide6.QtGui import QDoubleValidator
Expand Down Expand Up @@ -39,6 +40,9 @@
class AxisControlWidget(QWidget):
axisLinked = Signal()
axisUnlinked = Signal()
movementStarted = Signal(int)
movementStopped = Signal(int)
axisStatusChanged = Signal()

def __init__(self, parent=None):
super().__init__(parent)
Expand Down Expand Up @@ -255,6 +259,10 @@ def link_axis(self, mg: MotionGroup, ax_index: int):

self.axis_name_label.setText(self.axis.name)
self.axis.motor.status_changed.connect(self._update_display_of_axis_status)
self.axis.motor.status_changed.connect(self.axisStatusChanged.emit)
self.axis.motor.movement_started.connect(self._emit_movement_started)
self.axis.motor.movement_finished.connect(self._emit_movement_finished)
self.axis.motor.movement_finished.connect(self._update_display_of_axis_status)
self._update_display_of_axis_status()

self.axisLinked.emit()
Expand All @@ -263,17 +271,41 @@ def unlink_axis(self):
if self.axis is not None:
# self.axis.terminate(delay_loop_stop=True)
self.axis.motor.status_changed.disconnect(self._update_display_of_axis_status)
self.axis.motor.status_changed.connect(self.axisStatusChanged.emit)
self.axis.motor.movement_started.connect(self._emit_movement_started)
self.axis.motor.movement_finished.connect(self._emit_movement_finished)
self.axis.motor.movement_finished.disconnect(
self._update_display_of_axis_status
)

self._mg = None
self._axis_index = None
self.axisUnlinked.emit()

def _emit_movement_started(self):
self.movementStarted.emit(self.axis_index)

def _emit_movement_finished(self):
self.movementStopped.emit(self.axis_index)

def closeEvent(self, event):
self.logger.info("Closing AxisControlWidget")

if isinstance(self.axis, Axis):
self.axis.motor.status_changed.disconnect(self._update_display_of_axis_status)
self.axis.motor.status_changed.disconnect(self.axisStatusChanged.emit)
self.axis.motor.movement_started.connect(self._emit_movement_started)
self.axis.motor.movement_finished.connect(self._emit_movement_finished)
self.axis.motor.movement_finished.disconnect(
self._update_display_of_axis_status
)

event.accept()


class DriveControlWidget(QWidget):
movementStarted = Signal()
movementStopped = Signal()

def __init__(self, parent=None):
super().__init__(parent)
Expand Down Expand Up @@ -474,6 +506,9 @@ def link_motion_group(self, mg):
for ii, ax in enumerate(self.mg.drive.axes):
acw = self._axis_control_widgets[ii]
acw.link_axis(self.mg, ii)
acw.movementStarted.connect(self._drive_movement_started)
acw.movementStopped.connect(self._drive_movement_finished)
acw.axisStatusChanged.connect(self._update_all_axis_displays)
acw.show()

self.setEnabled(not self._mg.terminated)
Expand All @@ -483,12 +518,42 @@ def unlink_motion_group(self):
visible = True if ii == 0 else False

acw.unlink_axis()

with warnings.catch_warnings():
warnings.simplefilter("ignore", category=RuntimeWarning)
acw.movementStarted.disconnect(self._drive_movement_started)
acw.movementStopped.disconnect(self._drive_movement_finished)
acw.axisStatusChanged.disconnect(self._update_all_axis_displays)

acw.setVisible(visible)

# self.mg.terminate(delay_loop_stop=True)
self._mg = None
self.setEnabled(False)

def _update_all_axis_displays(self):
for acw in self._axis_control_widgets:
if acw.isHidden():
continue
elif acw.axis.is_moving:
continue

acw._update_display_of_axis_status()

@Slot(int)
def _drive_movement_started(self, axis_index):
self.movementStarted.emit()

@Slot(int)
def _drive_movement_finished(self, axis_index):
if not isinstance(self.mg, MotionGroup) or not isinstance(self.mg.drive, Drive):
return

is_moving = [ax.is_moving for ax in self.mg.drive.axes]
is_moving[axis_index] = False
if not any(is_moving):
self.movementStopped.emit()

def closeEvent(self, event):
self.logger.info("Closing DriveControlWidget")
event.accept()
Expand Down Expand Up @@ -531,7 +596,6 @@ def __init__(
"ips": deployed_ips,
}


self._logger = gui_logger

self._mg = None
Expand Down Expand Up @@ -682,8 +746,8 @@ def __init__(
# if MGWidget launched without a drive then use a default
# drive (if defined)
if (
"drive" not in self.mg_config
and self.drive_defaults[0][0] != "Custom Drive"
"drive" not in self.mg_config
and self.drive_defaults[0][0] != "Custom Drive"
):
self._mg_config["drive"] = _deepcopy_dict(self.drive_defaults[0][1])

Expand Down Expand Up @@ -734,12 +798,7 @@ def _connect_signals(self):

self.mg_name_widget.editingFinished.connect(self._rename_motion_group)

self.configChanged.connect(self._update_toml_widget)
self.configChanged.connect(self._update_mg_name_widget)
self.configChanged.connect(self._validate_motion_group)
self.configChanged.connect(self._update_drive_dropdown)
self.configChanged.connect(self._update_mb_dropdown)
self.configChanged.connect(self._update_transform_dropdown)
self.configChanged.connect(self._config_changed_handler)

self.drive_dropdown.currentIndexChanged.connect(
self._drive_dropdown_new_selection
Expand All @@ -751,6 +810,9 @@ def _connect_signals(self):
self._transform_dropdown_new_selection
)

self.drive_control_widget.movementStarted.connect(self.disable_config_controls)
self.drive_control_widget.movementStopped.connect(self.enable_config_controls)

self.done_btn.clicked.connect(self.return_and_close)
self.discard_btn.clicked.connect(self.close)

Expand Down Expand Up @@ -987,6 +1049,22 @@ def _build_transform_defaults(self):

return self._transform_defaults

def _config_changed_handler(self):
# Note: none of the methods executed here should cause a
# configChanged event
self._validate_motion_group()

# now update displays
self._update_mg_name_widget()
self._update_toml_widget()
self._update_drive_dropdown()
self._update_mb_dropdown()
self._update_transform_dropdown()

# updating the drive control widget should always be the last
# step
self._update_drive_control_widget()

def _populate_drive_dropdown(self):
for item in self.drive_defaults:
self.drive_dropdown.addItem(item[0])
Expand Down Expand Up @@ -1354,6 +1432,15 @@ def _update_toml_widget(self):
def _update_mg_name_widget(self):
self.mg_name_widget.setText(self.mg_config["name"])

def _update_drive_control_widget(self):
if not self.drive_control_widget.isEnabled():
return

if self.drive_control_widget.mg is None:
self._refresh_drive_control()
else:
self.drive_control_widget._update_all_axis_displays()

def _rename_motion_group(self):
self.logger.info("Renaming motion group")
self.mg.config["name"] = self.mg_name_widget.text()
Expand Down Expand Up @@ -1624,6 +1711,26 @@ def _transform_dropdown_new_selection(self, index):

self._change_transform(tr_default_config)

def disable_config_controls(self):
self.drive_dropdown.setEnabled(False)
self.drive_btn.setEnabled(False)

self.mb_dropdown.setEnabled(False)
self.mb_btn.setEnabled(False)

self.transform_dropdown.setEnabled(False)
self.transform_btn.setEnabled(False)

def enable_config_controls(self):
self.drive_dropdown.setEnabled(True)
self.drive_btn.setEnabled(True)

self.mb_dropdown.setEnabled(True)
self.mb_btn.setEnabled(True)

self.transform_dropdown.setEnabled(True)
self.transform_btn.setEnabled(True)

def return_and_close(self):
config = _deepcopy_dict(self.mg.config)
index = -1 if self._mg_index is None else self._mg_index
Expand Down

0 comments on commit a85c735

Please sign in to comment.