GUI: Add completed grid scan table

This commit is contained in:
leonarski_f committed 2025-06-29 12:19:47 +02:00
1 parent 518e3df0d6
commit 606f1b62fb
5 files changed
+190 -19

No files matched your search

+2
View File
@@ -26,6 +26,8 @@ class RasterGridRequest(BaseModel):
# omega angle
omega_deg: float = 0.0
visible: bool = True
def get_image_number(self) -> int:
return self.n_x * self.n_y
+3
View File
@@ -147,6 +147,9 @@ class MainWindow(QMainWindow):
self.beamline.smargon_panel.smargon.connect(self.daq.move_smargon)
self.camera_image.samcam_updated.connect(self.daq.samcam_settings)
self.raster.omega.connect(self.daq.set_omega)
self.raster.smargon.connect(self.daq.move_smargon)
self.beamline.omega_panel.set_omega.connect(self.daq.set_omega)
self.camera_image.set_omega.connect(self.daq.set_omega)
self.beamline.zoom_panel.zoom.connect(self.daq.zoom)
@@ -6,6 +6,7 @@ from aaredaqlib.diffraction_geometry import DiffractionGeometry
from aaregui.panels.scan_settings_panel import ScanSettingsPanel
from aaregui.scan_logic.raster_grid_manager import RasterGridManager, RasterGridMetric
from aaregui.widgets.number_line_edit import NumberLineEdit
from aaregui.widgets.raster_grid_table import RasterGridTable
class RasterDataCollectionPanel(ScanSettingsPanel):
@@ -97,15 +98,18 @@ class RasterDataCollectionPanel(ScanSettingsPanel):
slider.valueChanged.connect(lambda: self.raster_alpha_changed.emit(255 - slider.value()))
self._layout.addWidget(slider, 8, 1, 1, 3)
self._table = RasterGridTable(raster_mgr)
self._layout.addWidget(self._table, 9, 0, 1, 5)
horizontal_spacer = QSpacerItem(
40, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding
)
self._layout.addItem(horizontal_spacer, 9, 0, 1, 4)
self._layout.addItem(horizontal_spacer, 10, 0, 1, 5)
self.start_button = QPushButton("Evaluate grid")
self.start_button.setStyleSheet("color: rgb(78, 154, 6);")
self.start_button.clicked.connect(self.evaluate_grid)
self._layout.addWidget(self.start_button, 10, 0, 1, 5)
self._layout.addWidget(self.start_button, 11, 0, 1, 5)
self.update_grid_scan_size()
@@ -72,10 +72,14 @@ class RasterGridManager(QObject):
grid_updated = Signal()
grid_scan = Signal(RasterGridRequest)
grid_scan_size_changed = Signal(int, int)
completed_grid_updated = Signal()
file_ready = Signal(str)
image_selected = Signal(int)
omega = Signal(float)
smargon = Signal(SmargonCoordinate)
def __init__(self, geom: SampleGeometryModel):
super().__init__()
@@ -109,9 +113,10 @@ class RasterGridManager(QObject):
def _is_grid_visible(self, grid: RasterGridRequest):
if (
abs(normalize_angle(grid.omega_deg - self.__geom.omega_deg)) < 1.0
and abs(grid.smargon.phi_deg - self.__geom.smargon.phi_deg) < 1.0
and abs(grid.smargon.chi_deg - self.__geom.smargon.chi_deg) < 1.0
grid.visible
and abs(normalize_angle(grid.omega_deg - self.__geom.omega_deg)) < 0.2
and abs(grid.smargon.phi_deg - self.__geom.smargon.phi_deg) < 0.2
and abs(grid.smargon.chi_deg - self.__geom.smargon.chi_deg) < 0.2
and grid.n_x > 0
and grid.n_y > 0
):
@@ -182,10 +187,6 @@ class RasterGridManager(QObject):
self.__active_grid.n_y = 0
self.grid_scan_size_changed.emit(self.__active_grid.n_x, self.__active_grid.n_y)
@Slot()
def clear_completed_grids(self):
self.__completed_grids.clear()
def get_grid_coord(self, grid: RasterGridRequest, point: QPointF) -> Tuple[int, int]:
point_bl = self.__geom.picture_to_sample(Coordinate(x=point.x(), y=point.y()))
@@ -227,7 +228,7 @@ class RasterGridManager(QObject):
0 <= delta.y < self.__active_grid.n_y * self.__active_grid.grid_size_mm.y
)
def is_part_of_completed_grid(self, point: QPointF) -> str:
def is_part_of_completed_grid(self, point: QPointF) -> str | None:
for grid in self.__completed_grids:
if self._is_grid_visible(grid.request):
n_x = grid.request.n_x
@@ -259,7 +260,7 @@ class RasterGridManager(QObject):
txt += f"Mosaicity {grid.result.images[cell].mos:.2f}"
return txt
return ""
return None
@Slot(float, float)
@@ -279,14 +280,6 @@ class RasterGridManager(QObject):
grid = copy.deepcopy(self.__active_grid)
self.grid_scan.emit(grid)
@Slot(CompletedRasterGrid)
def grid_scan_completed(self, r: CompletedRasterGrid):
self.__completed_grids.append(r)
self.__active_grid.n_x = 0
self.__active_grid.n_y = 0
if r.result.file_prefix is not None:
self.file_ready.emit(r.result.file_prefix)
def draw_grid(self, painter: QPainter, alpha: int = 127):
self._draw_grid(painter, self.__active_grid)
for i in self.__completed_grids:
@@ -362,3 +355,51 @@ class RasterGridManager(QObject):
@Slot(RasterGridMetric)
def metric(self, r: RasterGridMetric):
self.__metric = r
@Slot()
def clear_completed_grids(self):
self.__completed_grids.clear()
self.completed_grid_updated.emit()
@Slot(CompletedRasterGrid)
def grid_scan_completed(self, r: CompletedRasterGrid):
self.__completed_grids.append(r)
self.__active_grid.n_x = 0
self.__active_grid.n_y = 0
if r.result.file_prefix is not None:
self.file_ready.emit(r.result.file_prefix)
self.completed_grid_updated.emit()
@Slot(int, bool)
def completed_grid_scan_toggle_visible(self, row: int, visible: bool):
if 0 <= row < len(self.__completed_grids):
self.__completed_grids[row].request.visible = visible
self.completed_grid_updated.emit()
@Slot(int)
def completed_grid_scan_delete(self, row: int):
if 0 <= row < len(self.__completed_grids):
del self.__completed_grids[row]
self.completed_grid_updated.emit()
@Slot(int)
def completed_grid_scan_goto(self, row: int):
if 0 <= row < len(self.__completed_grids):
self.omega.emit(self.__completed_grids[row].request.omega_deg)
self.smargon.emit(SmargonCoordinate(
phi_deg=self.__completed_grids[row].request.smargon.phi_deg,
chi_deg=self.__completed_grids[row].request.smargon.chi_deg,
))
@Slot(int)
def completed_grid_redo(self, row: int):
if 0 <= row < len(self.__completed_grids):
self.__active_grid = copy.deepcopy(self.__completed_grids[row].request)
self.__active_grid.visible = True
self.__completed_grids[row].request.visible = False
self.grid_scan_size_changed.emit(self.__active_grid.n_x, self.__active_grid.n_y)
self.completed_grid_updated.emit()
def get_completed_grids(self) -> List[CompletedRasterGrid]:
return self.__completed_grids
@@ -0,0 +1,121 @@
from PySide6.QtCore import Signal, Slot
from PySide6.QtWidgets import QTableWidget, QHeaderView, QTableWidgetItem, QWidget, QHBoxLayout, QPushButton
from aaredaqlib.raster_grid import RasterGridRequest
from aaregui.scan_logic.raster_grid_manager import RasterGridManager
class RasterGridTable(QTableWidget):
copy_clicked = Signal(int)
delete_clicked = Signal(int)
visible_clicked = Signal(int, bool)
goto_clicked = Signal(int)
def __init__(self, raster_mgr: RasterGridManager, parent=None):
super().__init__(parent)
self.__raster_mgr = raster_mgr
self.setColumnCount(5)
self.setHorizontalHeaderLabels(['Omega', 'Chi', 'Phi', 'Size (WxH)', 'Actions'])
self.verticalHeader().setVisible(False)
# Configure header
header = self.horizontalHeader()
for i in range(4):
header.setSectionResizeMode(i, QHeaderView.ResizeMode.ResizeToContents)
header.setSectionResizeMode(4, QHeaderView.ResizeMode.Stretch)
# Set minimum height
self.setMinimumHeight(100)
# Connect to raster manager signals
self.__raster_mgr.completed_grid_updated.connect(self.refresh_table)
self.copy_clicked.connect(self.__raster_mgr.completed_grid_redo)
self.delete_clicked.connect(self.__raster_mgr.completed_grid_scan_delete)
self.visible_clicked.connect(self.__raster_mgr.completed_grid_scan_toggle_visible)
self.goto_clicked.connect(self.__raster_mgr.completed_grid_scan_goto)
def add_rows(self):
for r in self.__raster_mgr.get_completed_grids():
req = r.request
row_position = self.rowCount()
self.insertRow(row_position)
# Add data cells
self.setItem(row_position, 0, QTableWidgetItem(f"{req.omega_deg:.1f}"))
self.setItem(row_position, 1, QTableWidgetItem(f"{req.smargon.chi_deg:.1f}"))
self.setItem(row_position, 2, QTableWidgetItem(f"{req.smargon.phi_deg:.1f}"))
self.setItem(row_position, 3, QTableWidgetItem(f"{req.n_x} x {req.n_y}"))
# Add action buttons
self.add_action_buttons(row_position, req.visible)
def add_action_buttons(self, row: int, visible: bool):
"""Create and add action buttons for the specified row."""
actions_widget = QWidget()
actions_layout = QHBoxLayout(actions_widget)
actions_layout.setContentsMargins(4, 4, 4, 4)
actions_layout.setSpacing(4)
button_style = """
QPushButton {
border: none;
background: transparent;
font-size: 14px;
}
QPushButton:hover {
background-color: #e0e0e0;
border-radius: 3px;
}
"""
# Copy button
copy_btn = QPushButton('⧉')
copy_btn.setFixedSize(24, 24)
copy_btn.setToolTip('Copy')
copy_btn.setStyleSheet(button_style)
copy_btn.clicked.connect(lambda checked, r=row: self.copy_clicked.emit(r))
actions_layout.addWidget(copy_btn)
# Redo button
goto_btn = QPushButton('🏃‍♂️') # Circular arrow for goto
goto_btn.setFixedSize(24, 24)
goto_btn.setToolTip('Goto scan')
goto_btn.setStyleSheet(button_style)
goto_btn.clicked.connect(lambda checked, r=row: self.goto_clicked.emit(r))
actions_layout.addWidget(goto_btn)
# Visible button
if visible:
visible_btn = QPushButton('👁')
else:
visible_btn = QPushButton('‍🗨')
visible_btn.setChecked(visible) # Initially visible
visible_btn.setFixedSize(24, 24)
visible_btn.setToolTip('Toggle visibility')
visible_btn.setStyleSheet(button_style)
visible_btn.setCheckable(True)
visible_btn.clicked.connect(lambda checked, r=row: self.visible_clicked.emit(r, not visible))
actions_layout.addWidget(visible_btn)
# Delete button
delete_btn = QPushButton('🗑')
delete_btn.setFixedSize(24, 24)
delete_btn.setToolTip('Delete')
delete_btn.setStyleSheet(button_style)
delete_btn.clicked.connect(lambda checked, r=row: self.delete_clicked.emit(r))
actions_layout.addWidget(delete_btn)
self.setCellWidget(row, 4, actions_widget)
@Slot()
def refresh_table(self):
"""Refresh the entire table content."""
# Clear existing rows
self.setRowCount(0)
# Repopulate with current data
self.add_rows()