0
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2025-07-14 03:31:50 +02:00

Merge branch 'cSAX-feedback'

This commit is contained in:
wyzula-jan
2023-09-12 11:43:24 +02:00
2 changed files with 234 additions and 53 deletions

View File

@ -506,6 +506,44 @@
<string>Coordinates</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Entries Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox_mode">
<item>
<property name="text">
<string>Individual</string>
</property>
</item>
<item>
<property name="text">
<string>Start/Stop</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableWidget_coordinates">
<property name="selectionMode">
@ -524,6 +562,11 @@
<string>Show</string>
</property>
</column>
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
<column>
<property name="text">
<string>X</string>
@ -534,33 +577,56 @@
<string>Y</string>
</property>
</column>
<column>
<property name="text">
<string>Tag</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_exportCSV">
<property name="text">
<string>Export CSV</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_importCSV">
<property name="text">
<string>Import CSV</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="pushButton_help">
<property name="text">
<string>Help</string>
</property>
</widget>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QPushButton" name="pushButton_exportCSV">
<property name="text">
<string>Export CSV</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="checkBox_resize_auto">
<property name="text">
<string>Resize Auto</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="pushButton_importCSV">
<property name="text">
<string>Import CSV</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QPushButton" name="pushButton_resize_table">
<property name="text">
<string>Resize Table</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="pushButton_help">
<property name="text">
<string>Help</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QPushButton" name="pushButton_duplicate">
<property name="text">
<string>Duplicate Last Entry</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>

View File

@ -23,6 +23,7 @@ from PyQt5.QtWidgets import (
)
from PyQt5.QtWidgets import QShortcut
from pyqtgraph.Qt import QtWidgets, uic, QtCore
from PyQt5.QtWidgets import QMessageBox
from bec_lib.core import MessageEndpoints, BECMessage
from bec_widgets.qt_utils import DoubleValidationDelegate
@ -84,6 +85,10 @@ class MotorApp(QWidget):
self.init_ui()
self.tag_N = 1 # position label for saved coordinates
# State tracking for entries
self.last_selected_index = -1
self.is_next_entry_end = False
# Get all motors available
self.motor_thread.retrieve_all_motors() # TODO link to combobox that it always refresh
@ -410,8 +415,9 @@ class MotorApp(QWidget):
"""Initialize the table validators for x and y coordinates and table signals"""
# Validators
self.double_delegate = DoubleValidationDelegate(self.tableWidget_coordinates)
self.tableWidget_coordinates.setItemDelegateForColumn(2, self.double_delegate)
self.tableWidget_coordinates.setItemDelegateForColumn(3, self.double_delegate)
self.update_table_header()
# self.tableWidget_coordinates.setItemDelegateForColumn(3, self.double_delegate) #TODO check where to delegate
# self.tableWidget_coordinates.setItemDelegateForColumn(4, self.double_delegate)
# Signals
self.tableWidget_coordinates.itemChanged.connect(self.update_saved_coordinates)
@ -425,8 +431,19 @@ class MotorApp(QWidget):
lambda: self.load_table_from_csv(self.tableWidget_coordinates, precision=self.precision)
)
self.pushButton_resize_table.clicked.connect(
lambda: self.resizeTable(self.tableWidget_coordinates)
)
self.pushButton_duplicate.clicked.connect(
lambda: self.duplicate_last_row(self.tableWidget_coordinates)
)
self.pushButton_help.clicked.connect(self.show_help_dialog)
# Mode switch
self.comboBox_mode.currentIndexChanged.connect(self.update_table_header)
def init_ui(self) -> None:
"""Setup all ui elements"""
@ -534,11 +551,58 @@ class MotorApp(QWidget):
self.toolButton_up.setShortcut("")
self.toolButton_down.setShortcut("")
def update_table_header(self):
current_index = self.comboBox_mode.currentIndex()
if self.tableWidget_coordinates.rowCount() > 0:
msgBox = QMessageBox()
msgBox.setIcon(QMessageBox.Warning)
msgBox.setText(
"Switching modes will delete all table entries. Do you want to continue?"
)
msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
returnValue = msgBox.exec()
if returnValue == QMessageBox.Cancel:
self.comboBox_mode.blockSignals(True) # Block signals
self.comboBox_mode.setCurrentIndex(self.last_selected_index)
self.comboBox_mode.blockSignals(False) # Unblock signals
return
self.tableWidget_coordinates.setRowCount(0) # Wipe table
if current_index == 0: # 'individual' is selected
self.tableWidget_coordinates.setColumnCount(5)
self.tableWidget_coordinates.setHorizontalHeaderLabels(
["Move", "Show", "Tag", "X", "Y"]
)
self.tableWidget_coordinates.setItemDelegateForColumn(3, self.double_delegate)
self.tableWidget_coordinates.setItemDelegateForColumn(4, self.double_delegate)
elif current_index == 1: # 'start/stop' is selected
self.tableWidget_coordinates.setColumnCount(7)
self.tableWidget_coordinates.setHorizontalHeaderLabels(
["Move", "Show", "Tag", "X [start]", "Y [start]", "X [end]", "Y [end]"]
)
self.tableWidget_coordinates.setItemDelegateForColumn(3, self.double_delegate)
self.tableWidget_coordinates.setItemDelegateForColumn(4, self.double_delegate)
self.tableWidget_coordinates.setItemDelegateForColumn(5, self.double_delegate)
self.tableWidget_coordinates.setItemDelegateForColumn(6, self.double_delegate)
self.last_selected_index = current_index # Save the last selected index
def generate_table_coordinate(
self, table: QtWidgets.QTableWidget, coordinates: tuple, tag: str = None, precision: int = 0
) -> None:
current_row_count = table.rowCount()
table.setRowCount(current_row_count + 1)
current_index = self.comboBox_mode.currentIndex()
# current_col_count = table.columnCount()
if current_index == 1 and self.is_next_entry_end:
target_row = table.rowCount() - 1 # Last row
else:
new_row_count = table.rowCount() + 1
table.setRowCount(new_row_count)
target_row = new_row_count - 1 # New row
# Create QDoubleValidator
validator = QDoubleValidator()
@ -552,8 +616,8 @@ class MotorApp(QWidget):
lambda state, widget=checkBox: self.toggle_point_visibility(state, widget)
)
table.setItem(current_row_count, 4, QtWidgets.QTableWidgetItem(str(tag)))
table.setCellWidget(current_row_count, 1, checkBox)
table.setItem(target_row, 2, QtWidgets.QTableWidgetItem(str(tag)))
table.setCellWidget(target_row, 1, checkBox)
# Apply validator to x and y coordinate QTableWidgetItem
item_x = QtWidgets.QTableWidgetItem(str(f"{coordinates[0]:.{precision}f}"))
@ -561,16 +625,22 @@ class MotorApp(QWidget):
item_x.setFlags(item_x.flags() | Qt.ItemIsEditable)
item_y.setFlags(item_y.flags() | Qt.ItemIsEditable)
table.setItem(
current_row_count, 2, QtWidgets.QTableWidgetItem(str(f"{coordinates[0]:.{precision}f}"))
)
table.setItem(
current_row_count, 3, QtWidgets.QTableWidgetItem(str(f"{coordinates[1]:.{precision}f}"))
)
if current_index == 1:
col_index = 7
if self.is_next_entry_end:
table.setItem(target_row, 5, item_x)
table.setItem(target_row, 6, item_y)
else:
table.setItem(target_row, 3, item_x)
table.setItem(target_row, 4, item_y)
self.is_next_entry_end = not self.is_next_entry_end
else:
col_index = 5
table.setItem(target_row, 3, item_x)
table.setItem(target_row, 4, item_y)
table.setCellWidget(current_row_count, 0, button)
button.clicked.connect(partial(self.move_to_row_coordinates, table, current_row_count))
table.setCellWidget(target_row, 0, button)
button.clicked.connect(partial(self.move_to_row_coordinates, table, target_row))
brushes = [
pg.mkBrush(255, 165, 0, 255) if visible else pg.mkBrush(255, 165, 0, 0)
@ -579,21 +649,20 @@ class MotorApp(QWidget):
# Adding extra columns
if self.extra_columns:
col_index = 5 # Starting index for extra columns
table.setColumnCount(col_index + len(self.extra_columns))
for col_dict in self.extra_columns:
for col_name, default_value in col_dict.items():
if current_row_count == 0:
if target_row == 0 or (current_index == 1 and not self.is_next_entry_end):
item = QtWidgets.QTableWidgetItem(str(default_value))
else:
prev_item = table.item(current_row_count - 1, col_index)
prev_item = table.item(target_row - 1, col_index)
item_text = prev_item.text() if prev_item else ""
item = QtWidgets.QTableWidgetItem(item_text)
item.setFlags(item.flags() | Qt.ItemIsEditable)
table.setItem(current_row_count, col_index, item)
table.setItem(target_row, col_index, item)
if current_row_count == 0:
if target_row == 0 or (current_index == 1 and not self.is_next_entry_end):
table.setHorizontalHeaderItem(
col_index, QtWidgets.QTableWidgetItem(col_name)
)
@ -602,17 +671,54 @@ class MotorApp(QWidget):
self.saved_motor_map.setData(pos=self.saved_motor_positions, brush=brushes)
self.align_table_center(table)
if self.checkBox_resize_auto.isChecked():
table.resizeColumnsToContents()
def duplicate_last_row(self, table: QtWidgets.QTableWidget) -> None:
last_row = table.rowCount() - 1
if last_row == -1:
return
table.setRowCount(last_row + 2)
new_row = last_row + 1
for col in range(table.columnCount()):
cell_widget = table.cellWidget(last_row, col)
cell_item = table.item(last_row, col)
if isinstance(cell_widget, QtWidgets.QCheckBox):
new_checkbox = QtWidgets.QCheckBox()
new_checkbox.setChecked(cell_widget.isChecked())
table.setCellWidget(new_row, col, new_checkbox)
elif isinstance(cell_widget, QtWidgets.QPushButton):
new_button = QtWidgets.QPushButton(cell_widget.text())
new_button.clicked.connect(partial(self.move_to_row_coordinates, table, new_row))
table.setCellWidget(new_row, col, new_button)
elif cell_item:
new_item = QtWidgets.QTableWidgetItem(cell_item.text())
new_item.setFlags(cell_item.flags())
table.setItem(new_row, col, new_item)
self.align_table_center(table)
if self.checkBox_resize_auto.isChecked():
table.resizeColumnsToContents()
@staticmethod
def align_table_center(table: QtWidgets.QTableWidget) -> None:
for row in range(table.rowCount()):
for col in range(table.columnCount()):
item = table.item(row, col)
if item:
item.setTextAlignment(Qt.AlignCenter)
table.resizeColumnsToContents()
def move_to_row_coordinates(self, table, row):
x = float(table.item(row, 2).text())
y = float(table.item(row, 3).text())
x = float(table.item(row, 3).text())
y = float(table.item(row, 4).text())
self.move_motor_absolute(x, y)
def toggle_point_visibility(self, state, checkBox_widget):
@ -654,13 +760,13 @@ class MotorApp(QWidget):
for row in range(rows):
x = (
float(self.tableWidget_coordinates.item(row, 2).text())
if self.tableWidget_coordinates.item(row, 2) is not None
float(self.tableWidget_coordinates.item(row, 3).text())
if self.tableWidget_coordinates.item(row, 3) is not None
else None
)
y = (
float(self.tableWidget_coordinates.item(row, 3).text())
if self.tableWidget_coordinates.item(row, 3) is not None
float(self.tableWidget_coordinates.item(row, 4).text())
if self.tableWidget_coordinates.item(row, 4) is not None
else None
)
@ -690,6 +796,11 @@ class MotorApp(QWidget):
self.saved_motor_positions = np.delete(self.saved_motor_positions, row_index, axis=0)
del self.saved_point_visibility[row_index]
# If in 'start/stop' mode, check if only the 'start' coordinates are present in the row being deleted
if self.comboBox_mode.currentIndex() == 1:
if self.tableWidget_coordinates.item(row_index, 5) is None:
self.is_next_entry_end = False
# Update the plot
brushes = [
pg.mkBrush(255, 165, 0, 255) if visible else pg.mkBrush(255, 165, 0, 0)
@ -708,6 +819,9 @@ class MotorApp(QWidget):
partial(self.move_to_row_coordinates, self.tableWidget_coordinates, row)
)
def resizeTable(self, table):
table.resizeColumnsToContents()
def export_table_to_csv(self, table: QtWidgets.QTableWidget):
options = QFileDialog.Options()
filePath, _ = QFileDialog.getSaveFileName(
@ -791,7 +905,8 @@ class MotorApp(QWidget):
item.setTextAlignment(Qt.AlignCenter)
table.setItem(current_row, col + 2, item)
table.resizeColumnsToContents()
if self.checkBox_resize_auto.isChecked():
table.resizeColumnsToContents()
def save_absolute_coordinates(self):
self.generate_table_coordinate(