GUI: Add completed grid scan table
This commit is contained in:
1 parent
518e3df0d6
commit
606f1b62fb
5 files changed
+190
-19
No files matched your search
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
Reference in new issue
Block a user