Added style sheet options - protrait style needs to be added to more places.
This commit is contained in:
+84
-27
@@ -2,7 +2,7 @@ import time
|
||||
|
||||
import jwt
|
||||
from PySide6.QtCore import Qt, Slot, Signal, QTimer, QSettings, QEvent
|
||||
from PySide6.QtGui import QAction, QPixmap, QKeySequence, QGuiApplication
|
||||
from PySide6.QtGui import QAction, QPixmap, QKeySequence, QGuiApplication, QActionGroup
|
||||
from PySide6.QtWidgets import (
|
||||
QMainWindow,
|
||||
QWidget,
|
||||
@@ -11,12 +11,11 @@ from PySide6.QtWidgets import (
|
||||
QMessageBox,
|
||||
QDockWidget,
|
||||
QTabWidget,
|
||||
QStackedWidget
|
||||
QStackedWidget,
|
||||
)
|
||||
|
||||
#Common imports
|
||||
from aare.common.auth_models import BatonStatus
|
||||
from aare.common.beamline import cfg_get
|
||||
from aare.common.coordinate import Coordinate, SmargonCoordinate
|
||||
from aare.common.diffraction_geometry import DiffractionGeometry
|
||||
from aare.common.logger_config import setup_logger
|
||||
@@ -25,6 +24,7 @@ from aare.common.sample_geometry import SampleGeometryModel
|
||||
|
||||
#Gui Models
|
||||
from aare.gui.models.gui_state_manager import UIStateManager
|
||||
from aare.gui.styles import build_app_stylesheet, THEME_ORIGINAL, THEME_PORTRAIT
|
||||
|
||||
#panels
|
||||
from aare.gui.panels.LogPanel import LogDock
|
||||
@@ -95,11 +95,17 @@ class MainWindow(QMainWindow):
|
||||
):
|
||||
super().__init__()
|
||||
|
||||
self._theme_mode = THEME_ORIGINAL
|
||||
self._theme_action_group = None
|
||||
self._use_legacy_theme_action = None
|
||||
self._use_portrait_theme_action = None
|
||||
|
||||
self.__base_url = base_url
|
||||
self.__token = token
|
||||
self.__mounting = False
|
||||
self.__samcam_feed_banner_active = False
|
||||
self.__samcam_feed_banner_message = "Sample camera feed unavailable"
|
||||
|
||||
self._automation_critical_banner_active = False
|
||||
self._dev_help_dialog = None
|
||||
self._beamline_recovery_dialog = None
|
||||
@@ -166,6 +172,7 @@ class MainWindow(QMainWindow):
|
||||
self.setStyleSheet("background-color: rgb(216, 228, 253);")
|
||||
|
||||
root_widget = QWidget(parent=self)
|
||||
root_widget.setObjectName("mainContentRoot")
|
||||
root_layout = QVBoxLayout(root_widget)
|
||||
root_layout.setContentsMargins(0, 0, 0, 0)
|
||||
root_layout.setSpacing(0)
|
||||
@@ -180,6 +187,7 @@ class MainWindow(QMainWindow):
|
||||
root_layout.addWidget(self.content_stack, 1)
|
||||
|
||||
top_widget = QWidget(parent=root_widget)
|
||||
top_widget.setObjectName("standardMainPage")
|
||||
top_widget_layout = QHBoxLayout(top_widget)
|
||||
top_widget.setLayout(top_widget_layout)
|
||||
|
||||
@@ -300,21 +308,12 @@ class MainWindow(QMainWindow):
|
||||
|
||||
self.compact_automation_page = QWidget(parent=root_widget)
|
||||
self.compact_automation_page.setObjectName("compactAutomationPage")
|
||||
self.compact_automation_page.setStyleSheet(
|
||||
"""
|
||||
QWidget#compactAutomationPage {
|
||||
background-color: rgb(216, 228, 253);
|
||||
}
|
||||
"""
|
||||
)
|
||||
self.compact_automation_page_layout = QVBoxLayout(self.compact_automation_page)
|
||||
self.compact_automation_page_layout.setContentsMargins(18, 18, 18, 18)
|
||||
self.compact_automation_page_layout.setSpacing(0)
|
||||
self.compact_automation_page_layout.addWidget(self.compact_automation_panel)
|
||||
|
||||
# ── Portrait mode page ──────────────────────────────────────────
|
||||
# Uses a dedicated SampleCameraImageLabel so the compact_sample_camera
|
||||
# remains available for the existing compact automation view.
|
||||
self.portrait_sample_camera = SampleCameraImageLabel(
|
||||
geom=geom,
|
||||
raster=self.raster,
|
||||
@@ -325,21 +324,9 @@ class MainWindow(QMainWindow):
|
||||
sample_camera_widget=self.portrait_sample_camera,
|
||||
parent=root_widget,
|
||||
)
|
||||
self.portrait_mode_panel.setObjectName("portraitModePage")
|
||||
self.portrait_mode_panel.setStyleSheet(
|
||||
self.portrait_mode_panel.styleSheet() +
|
||||
"QWidget#portraitModePage { background-color: #071018; }"
|
||||
)
|
||||
|
||||
self.portrait_mode_page = QWidget(parent=root_widget)
|
||||
self.portrait_mode_page.setObjectName("portraitModePage")
|
||||
self.portrait_mode_page.setStyleSheet(
|
||||
"""
|
||||
QWidget#portraitModePage {
|
||||
background-color: #071018;
|
||||
}
|
||||
"""
|
||||
)
|
||||
portrait_page_layout = QHBoxLayout(self.portrait_mode_page)
|
||||
portrait_page_layout.setContentsMargins(0, 0, 0, 0)
|
||||
portrait_page_layout.setSpacing(0)
|
||||
@@ -534,6 +521,8 @@ class MainWindow(QMainWindow):
|
||||
self.setCentralWidget(root_widget)
|
||||
|
||||
self.setWindowTitle("AareGUI")
|
||||
self._restore_theme_settings()
|
||||
self._apply_theme()
|
||||
self.create_menu_bar()
|
||||
self._update_view_mode_actions()
|
||||
self._setup_global_shortcuts()
|
||||
@@ -874,6 +863,23 @@ class MainWindow(QMainWindow):
|
||||
)
|
||||
self.addAction(self._shortcut_console_log)
|
||||
|
||||
def _return_to_main_view_for_shutdown(self) -> None:
|
||||
try:
|
||||
if getattr(self, "content_stack", None) is None:
|
||||
return
|
||||
|
||||
current_widget = self.content_stack.currentWidget()
|
||||
|
||||
if hasattr(self, "portrait_mode_page") and current_widget is self.portrait_mode_page:
|
||||
self._return_from_portrait_mode()
|
||||
elif bool(getattr(self, "_in_compact_automation_view", False)):
|
||||
self._return_from_compact_automation_view()
|
||||
|
||||
if hasattr(self, "content_stack") and hasattr(self, "_standard_main_page"):
|
||||
self.content_stack.setCurrentWidget(self._standard_main_page)
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to return to main view during shutdown: {e}")
|
||||
|
||||
def _restore_samcam_overlay_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
show_detections = settings.value("samcam/show_detections", True, type=bool)
|
||||
@@ -1253,9 +1259,29 @@ class MainWindow(QMainWindow):
|
||||
def start_interactive_tutorial(self) -> None:
|
||||
self.tutorial_manager.start("manual_workflow_demo")
|
||||
|
||||
def _apply_theme(self) -> None:
|
||||
self.setStyleSheet(build_app_stylesheet(self._theme_mode))
|
||||
|
||||
def _restore_theme_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
self._theme_mode = settings.value("appearance/theme", THEME_ORIGINAL, type=str)
|
||||
|
||||
def _save_theme_settings(self) -> None:
|
||||
settings = QSettings("PSI", "AareGUI")
|
||||
settings.setValue("appearance/theme", self._theme_mode)
|
||||
|
||||
@Slot()
|
||||
def use_legacy_theme(self) -> None:
|
||||
self._theme_mode = THEME_ORIGINAL
|
||||
self._apply_theme()
|
||||
|
||||
@Slot()
|
||||
def use_portrait_theme(self) -> None:
|
||||
self._theme_mode = THEME_PORTRAIT
|
||||
self._apply_theme()
|
||||
|
||||
def create_menu_bar(self):
|
||||
"""Create a menu bar with File->Quit and Help->About."""
|
||||
# Main menu bar
|
||||
menu_bar = self.menuBar()
|
||||
|
||||
file_menu = menu_bar.addMenu("File")
|
||||
@@ -1281,6 +1307,25 @@ class MainWindow(QMainWindow):
|
||||
|
||||
view_menu = menu_bar.addMenu("View")
|
||||
|
||||
self._theme_action_group = QActionGroup(self)
|
||||
self._theme_action_group.setExclusive(True)
|
||||
|
||||
self._use_legacy_theme_action = QAction("Legacy Theme", self)
|
||||
self._use_legacy_theme_action.setCheckable(True)
|
||||
self._use_legacy_theme_action.setChecked(self._theme_mode == THEME_ORIGINAL)
|
||||
self._use_legacy_theme_action.triggered.connect(self.use_legacy_theme)
|
||||
self._theme_action_group.addAction(self._use_legacy_theme_action)
|
||||
|
||||
self._use_portrait_theme_action = QAction("Portrait Theme", self)
|
||||
self._use_portrait_theme_action.setCheckable(True)
|
||||
self._use_portrait_theme_action.setChecked(self._theme_mode == THEME_PORTRAIT)
|
||||
self._use_portrait_theme_action.triggered.connect(self.use_portrait_theme)
|
||||
self._theme_action_group.addAction(self._use_portrait_theme_action)
|
||||
|
||||
view_menu.addAction(self._use_legacy_theme_action)
|
||||
view_menu.addAction(self._use_portrait_theme_action)
|
||||
view_menu.addSeparator()
|
||||
|
||||
if self._beamline_state_panel_enabled:
|
||||
self._show_beamline_state_action = QAction("Show Beamline State Panel", self)
|
||||
self._show_beamline_state_action.setCheckable(True)
|
||||
@@ -2006,16 +2051,22 @@ class MainWindow(QMainWindow):
|
||||
self._restore_panel_visibility_settings()
|
||||
|
||||
def closeEvent(self, event) -> None:
|
||||
try:
|
||||
self._return_to_main_view_for_shutdown()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to restore main view before close: {e}")
|
||||
|
||||
try:
|
||||
# TODO put all setting related handling into state_manager
|
||||
self.state_manager.save_window(self)
|
||||
self._save_samcam_overlay_settings()
|
||||
self._save_panel_visibility_settings()
|
||||
self._save_theme_settings()
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to save main window state: {e}")
|
||||
|
||||
# End session before closing so the backend removes this GUI from Redis immediately
|
||||
# End session before closing so the backend removes this GUI from Redis immediately
|
||||
try:
|
||||
self.daq.end_session_on_close()
|
||||
except Exception as e:
|
||||
@@ -2031,6 +2082,12 @@ class MainWindow(QMainWindow):
|
||||
def cleanup(self):
|
||||
if getattr(self, "_cleanup_done", False):
|
||||
return
|
||||
|
||||
try:
|
||||
self._return_to_main_view_for_shutdown()
|
||||
except Exception as e:
|
||||
logger.warning(f"Failed to restore main view during cleanup: {e}")
|
||||
|
||||
self._cleanup_done = True
|
||||
|
||||
try:
|
||||
@@ -2066,7 +2123,7 @@ class MainWindow(QMainWindow):
|
||||
self._stop_axis_camera_threads()
|
||||
|
||||
for attr_name in (
|
||||
"prediction_thread",
|
||||
"prediction_thread",
|
||||
):
|
||||
thread = getattr(self, attr_name, None)
|
||||
if thread is None:
|
||||
|
||||
@@ -12,38 +12,18 @@ class AxisVideoPanel(QWidget):
|
||||
super().__init__(parent)
|
||||
|
||||
self._title_label = QLabel(title, self)
|
||||
self._title_label.setStyleSheet("font-weight: bold;")
|
||||
|
||||
self._status_container = QWidget(self)
|
||||
self._status_container.setStyleSheet(
|
||||
"QWidget {"
|
||||
" border-radius: 12px;"
|
||||
" background-color: #d9e2f2;"
|
||||
"}"
|
||||
)
|
||||
self._status_container.setObjectName("axisVideoStatusContainer")
|
||||
self._status_container.setProperty("busyState", "idle")
|
||||
|
||||
self._status_dot = QLabel(self._status_container)
|
||||
self._status_dot.setObjectName("axisVideoStatusDot")
|
||||
self._status_dot.setFixedSize(10, 10)
|
||||
self._status_dot.setStyleSheet(
|
||||
"QLabel {"
|
||||
" min-width: 10px;"
|
||||
" max-width: 10px;"
|
||||
" min-height: 10px;"
|
||||
" max-height: 10px;"
|
||||
" border-radius: 5px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
)
|
||||
|
||||
self._status_label = QLabel("", self._status_container)
|
||||
self._status_label.setObjectName("axisVideoStatusLabel")
|
||||
self._status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self._status_label.setStyleSheet(
|
||||
"QLabel {"
|
||||
" background-color: transparent;"
|
||||
" color: #2f3b52;"
|
||||
" font-weight: bold;"
|
||||
"}"
|
||||
)
|
||||
|
||||
status_layout = QHBoxLayout(self._status_container)
|
||||
status_layout.setContentsMargins(10, 6, 12, 6)
|
||||
@@ -72,6 +52,12 @@ class AxisVideoPanel(QWidget):
|
||||
root_layout.addLayout(controls_layout)
|
||||
root_layout.addWidget(self.view)
|
||||
|
||||
def _refresh_status_style(self) -> None:
|
||||
for widget in (self._status_container, self._status_dot, self._status_label):
|
||||
widget.style().unpolish(widget)
|
||||
widget.style().polish(widget)
|
||||
widget.update()
|
||||
|
||||
def _all_video_views(self) -> list[VideoGraphicsView]:
|
||||
views: list[VideoGraphicsView] = []
|
||||
if isinstance(self.view, VideoGraphicsView):
|
||||
@@ -86,55 +72,21 @@ class AxisVideoPanel(QWidget):
|
||||
def set_busy_style(self, style: BusyOverlayStyle | None) -> None:
|
||||
if style is None:
|
||||
self._status_label.setText("")
|
||||
self._status_container.setStyleSheet(
|
||||
"QWidget {"
|
||||
" border-radius: 12px;"
|
||||
" background-color: #d9e2f2;"
|
||||
"}"
|
||||
)
|
||||
self._status_dot.setStyleSheet(
|
||||
"QLabel {"
|
||||
" min-width: 10px;"
|
||||
" max-width: 10px;"
|
||||
" min-height: 10px;"
|
||||
" max-height: 10px;"
|
||||
" border-radius: 5px;"
|
||||
" background-color: transparent;"
|
||||
"}"
|
||||
)
|
||||
self._status_label.setStyleSheet(
|
||||
"QLabel {"
|
||||
" background-color: transparent;"
|
||||
" color: #2f3b52;"
|
||||
" font-weight: bold;"
|
||||
"}"
|
||||
)
|
||||
self._status_container.setProperty("busyState", "idle")
|
||||
self._status_dot.setStyleSheet("background-color: transparent;")
|
||||
self._status_label.setStyleSheet("")
|
||||
self._refresh_status_style()
|
||||
self._status_container.hide()
|
||||
else:
|
||||
self._status_label.setText(style.text)
|
||||
self._status_container.setStyleSheet(
|
||||
"QWidget {"
|
||||
" border-radius: 12px;"
|
||||
f" background-color: {style.badge_bg};"
|
||||
"}"
|
||||
)
|
||||
self._status_container.setProperty("busyState", "active")
|
||||
self._status_dot.setStyleSheet(
|
||||
"QLabel {"
|
||||
" min-width: 10px;"
|
||||
" max-width: 10px;"
|
||||
" min-height: 10px;"
|
||||
" max-height: 10px;"
|
||||
" border-radius: 5px;"
|
||||
f" background-color: {style.accent_dot};"
|
||||
"}"
|
||||
f"background-color: {style.accent_dot};"
|
||||
)
|
||||
self._status_label.setStyleSheet(
|
||||
"QLabel {"
|
||||
" background-color: transparent;"
|
||||
f" color: {style.badge_fg};"
|
||||
" font-weight: bold;"
|
||||
"}"
|
||||
f"color: {style.badge_fg};"
|
||||
)
|
||||
self._refresh_status_style()
|
||||
self._status_container.show()
|
||||
|
||||
for view in self._all_video_views():
|
||||
|
||||
@@ -64,6 +64,7 @@ class BeamlineStatePanel(QFrame):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setObjectName("beamlineStatePanel")
|
||||
self.setFrameShape(QFrame.Shape.StyledPanel)
|
||||
self.setFrameShadow(QFrame.Shadow.Raised)
|
||||
self.setFixedWidth(self.set_width)
|
||||
@@ -87,16 +88,16 @@ class BeamlineStatePanel(QFrame):
|
||||
self._label_hover_bg = "rgba(244, 196, 48, 0.22)"
|
||||
|
||||
self._group_colors: dict[BeamlineStateEnum, QColor] = {
|
||||
BeamlineStateEnum.DewarTransfer: QColor(128, 90, 213), # Purple
|
||||
BeamlineStateEnum.SampleExchange: QColor(237, 137, 54), # Orange
|
||||
BeamlineStateEnum.RobotSampleExchange: QColor(237, 137, 54), # Orange
|
||||
BeamlineStateEnum.SampleAlignment: QColor(72, 187, 120), # Green
|
||||
BeamlineStateEnum.BeamLocation: QColor(72, 187, 120), # Green
|
||||
BeamlineStateEnum.BeamstopAlignment: QColor(72, 187, 120), # Green
|
||||
BeamlineStateEnum.FluxMeasurement: QColor(72, 187, 120), # Green
|
||||
BeamlineStateEnum.DataCollection: QColor(236, 72, 153), # Pink
|
||||
BeamlineStateEnum.XtalSnapshot: QColor(236, 72, 153), # Pink
|
||||
BeamlineStateEnum.XrayFluorescence: QColor(236, 72, 153), # Pink
|
||||
BeamlineStateEnum.DewarTransfer: QColor(128, 90, 213),
|
||||
BeamlineStateEnum.SampleExchange: QColor(237, 137, 54),
|
||||
BeamlineStateEnum.RobotSampleExchange: QColor(237, 137, 54),
|
||||
BeamlineStateEnum.SampleAlignment: QColor(72, 187, 120),
|
||||
BeamlineStateEnum.BeamLocation: QColor(72, 187, 120),
|
||||
BeamlineStateEnum.BeamstopAlignment: QColor(72, 187, 120),
|
||||
BeamlineStateEnum.FluxMeasurement: QColor(72, 187, 120),
|
||||
BeamlineStateEnum.DataCollection: QColor(236, 72, 153),
|
||||
BeamlineStateEnum.XtalSnapshot: QColor(236, 72, 153),
|
||||
BeamlineStateEnum.XrayFluorescence: QColor(236, 72, 153),
|
||||
}
|
||||
|
||||
self._group_label_colors: dict[BeamlineStateEnum, str] = {
|
||||
@@ -153,54 +154,26 @@ class BeamlineStatePanel(QFrame):
|
||||
self._station_widgets: dict[BeamlineStateEnum, QLabel | QPushButton] = {}
|
||||
|
||||
self.title = QLabel(self)
|
||||
self.title.setObjectName("beamlineStateTitle")
|
||||
self.title.setText("<H3>Beamline state</H3>")
|
||||
self.title.setStyleSheet("background-color: #4B0082; color: #ffffff;")
|
||||
self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||
self.title.setFixedHeight(self.title_height)
|
||||
self.title.setGeometry(0, 0, self.set_width, self.title_height)
|
||||
|
||||
self.toggle_button = QPushButton("−", self)
|
||||
self.toggle_button.setObjectName("beamlineStateToggleButton")
|
||||
self.toggle_button.setToolTip("Minimise beamline state panel")
|
||||
self.toggle_button.setFixedSize(28, 28)
|
||||
self.toggle_button.move(self.set_width - 36, 11)
|
||||
self.toggle_button.clicked.connect(self.toggle_collapsed)
|
||||
self.toggle_button.setStyleSheet("""
|
||||
QPushButton {
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
background-color: rgba(255, 255, 255, 0.20);
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.32);
|
||||
}
|
||||
""")
|
||||
|
||||
self.current_label = QLabel("Current: —", self)
|
||||
self.current_label.setStyleSheet("""
|
||||
QLabel {
|
||||
color: rgb(30, 41, 59);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
""")
|
||||
self.current_label.setObjectName("beamlineStateCurrentLabel")
|
||||
self.current_label.move(14, 58)
|
||||
self.current_label.adjustSize()
|
||||
|
||||
self.tell_label = QLabel("Tell: —", self)
|
||||
self.tell_label.setStyleSheet("""
|
||||
QLabel {
|
||||
color: rgb(55, 67, 87);
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
""")
|
||||
self.tell_label.setObjectName("beamlineStateTellLabel")
|
||||
self.tell_label.move(14, 86)
|
||||
self.tell_label.adjustSize()
|
||||
|
||||
@@ -580,15 +553,7 @@ class BeamlineStatePanel(QFrame):
|
||||
tell_color = "green"
|
||||
|
||||
self.tell_label.setText(tell_text)
|
||||
self.tell_label.setStyleSheet(f"""
|
||||
QLabel {{
|
||||
color: {tell_color};
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}}
|
||||
""")
|
||||
self.tell_label.setStyleSheet(f"color: {tell_color};")
|
||||
self.tell_label.adjustSize()
|
||||
|
||||
def set_current_state(self, state: BeamlineStateEnum | None) -> None:
|
||||
|
||||
@@ -34,110 +34,6 @@ class CompactAutomationPanel(QFrame):
|
||||
|
||||
self.setFrameShape(QFrame.Shape.NoFrame)
|
||||
self.setObjectName("compactAutomationPanel")
|
||||
self.setStyleSheet(
|
||||
"""
|
||||
QFrame#compactAutomationPanel {
|
||||
background: #d8e4fd;
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
QFrame#compactCameraCard,
|
||||
QFrame#compactControlsCard,
|
||||
QFrame#compactProgressCard,
|
||||
QFrame#compactQueueCard,
|
||||
QFrame#compactQueueItem {
|
||||
background: #e6eefc;
|
||||
border: 1px solid #b9ccee;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
QLabel#compactSectionTitle {
|
||||
background: transparent;
|
||||
color: #17324d;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactSectionHint {
|
||||
background: transparent;
|
||||
color: #51657d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
QLabel#compactQueueTitle {
|
||||
background: transparent;
|
||||
color: #51657d;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactQueueValue {
|
||||
background: transparent;
|
||||
color: #10263a;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton {
|
||||
background: #cbdcf8;
|
||||
color: #17324d;
|
||||
border: 1px solid #9fb9e5;
|
||||
border-radius: 14px;
|
||||
padding: 10px 14px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton:hover {
|
||||
background: #bfd4f6;
|
||||
}
|
||||
|
||||
QLabel#compactProgressSummary {
|
||||
background: transparent;
|
||||
color: #17324d;
|
||||
font-size: 13px;
|
||||
padding: 2px 2px 6px 2px;
|
||||
}
|
||||
|
||||
QLabel#compactProgressStep {
|
||||
background: #dfe9fb;
|
||||
border: 1px solid #bfd1ef;
|
||||
border-radius: 10px;
|
||||
padding: 8px 6px;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton {
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton:hover {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton,
|
||||
QToolButton#compactSecondaryButton {
|
||||
background: #dfe9fb;
|
||||
color: #17324d;
|
||||
border: 1px solid #b2c7eb;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton:hover,
|
||||
QToolButton#compactSecondaryButton:hover {
|
||||
background: #d3e1f8;
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setContentsMargins(18, 18, 18, 18)
|
||||
|
||||
@@ -26,33 +26,6 @@ BUTTON_BG = "#132131"
|
||||
LED_OFF = "#1C2E3E"
|
||||
ACTIVE_STEP = "#FFFFFF"
|
||||
|
||||
PORTRAIT_STYLE = f"""
|
||||
QWidget {{
|
||||
background: {BG};
|
||||
color: {TEXT};
|
||||
font-family: 'Inter', 'SF Pro Display', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}}
|
||||
QScrollArea {{
|
||||
border: none;
|
||||
background: transparent;
|
||||
}}
|
||||
QScrollBar:vertical {{
|
||||
background: {CARD_BG};
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
}}
|
||||
QScrollBar::handle:vertical {{
|
||||
background: {ACCENT_DIM};
|
||||
border-radius: 2px;
|
||||
min-height: 20px;
|
||||
}}
|
||||
QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical {{
|
||||
height: 0px;
|
||||
}}
|
||||
"""
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# LED step indicator
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -269,7 +242,7 @@ class PortraitModePanel(QWidget):
|
||||
|
||||
def __init__(self, sample_camera_widget: QWidget, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setStyleSheet(PORTRAIT_STYLE)
|
||||
self.setObjectName("portraitRoot")
|
||||
self.setMaximumWidth(self.PORTRAIT_WIDTH)
|
||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding)
|
||||
|
||||
|
||||
@@ -0,0 +1,493 @@
|
||||
from __future__ import annotations
|
||||
|
||||
THEME_ORIGINAL = "original"
|
||||
THEME_PORTRAIT = "portrait"
|
||||
|
||||
|
||||
def build_app_stylesheet(theme: str) -> str:
|
||||
if theme == THEME_PORTRAIT:
|
||||
return _portrait_stylesheet()
|
||||
return _original_stylesheet()
|
||||
|
||||
|
||||
def _original_stylesheet() -> str:
|
||||
return """
|
||||
QMainWindow, QWidget {
|
||||
background-color: rgb(216, 228, 253);
|
||||
color: rgb(30, 41, 59);
|
||||
}
|
||||
|
||||
QWidget#mainContentRoot,
|
||||
QWidget#standardMainPage,
|
||||
QWidget#compactAutomationPage {
|
||||
background-color: rgb(216, 228, 253);
|
||||
}
|
||||
|
||||
QWidget#portraitModePage {
|
||||
background-color: #071018;
|
||||
}
|
||||
|
||||
QFrame#compactAutomationPanel {
|
||||
background: #d8e4fd;
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
QFrame#compactCameraCard,
|
||||
QFrame#compactControlsCard,
|
||||
QFrame#compactProgressCard,
|
||||
QFrame#compactQueueCard,
|
||||
QFrame#compactQueueItem {
|
||||
background: #e6eefc;
|
||||
border: 1px solid #b9ccee;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
QLabel#compactSectionTitle {
|
||||
background: transparent;
|
||||
color: #17324d;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactSectionHint {
|
||||
background: transparent;
|
||||
color: #51657d;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
QLabel#compactQueueTitle {
|
||||
background: transparent;
|
||||
color: #51657d;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactQueueValue {
|
||||
background: transparent;
|
||||
color: #10263a;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton {
|
||||
background: #cbdcf8;
|
||||
color: #17324d;
|
||||
border: 1px solid #9fb9e5;
|
||||
border-radius: 14px;
|
||||
padding: 10px 14px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton:hover {
|
||||
background: #bfd4f6;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton {
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton:hover {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton,
|
||||
QToolButton#compactSecondaryButton {
|
||||
background: #dfe9fb;
|
||||
color: #17324d;
|
||||
border: 1px solid #b2c7eb;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton:hover,
|
||||
QToolButton#compactSecondaryButton:hover {
|
||||
background: #d3e1f8;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="error"] {
|
||||
background-color: #fbe4e6;
|
||||
border: 2px solid #d97a84;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="success"] {
|
||||
background-color: #e7f6ea;
|
||||
border: 2px solid #7bbf8e;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="waiting"] {
|
||||
background-color: #fff8e1;
|
||||
border: 2px solid #ffb300;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner QLabel {
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
padding: 2px 6px 2px 6px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="error"] QLabel {
|
||||
color: #8f1d2c;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="success"] QLabel {
|
||||
color: #1f6a3a;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="waiting"] QLabel {
|
||||
color: #e65100;
|
||||
}
|
||||
|
||||
QWidget#axisVideoStatusContainer[busyState="idle"] {
|
||||
border-radius: 12px;
|
||||
background-color: #d9e2f2;
|
||||
}
|
||||
|
||||
QWidget#axisVideoStatusContainer[busyState="active"] {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
QLabel#axisVideoStatusDot {
|
||||
min-width: 10px;
|
||||
max-width: 10px;
|
||||
min-height: 10px;
|
||||
max-height: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QLabel#axisVideoStatusLabel {
|
||||
background-color: transparent;
|
||||
color: #2f3b52;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
QFrame#beamlineStatePanel {
|
||||
background: rgb(216, 228, 253);
|
||||
border: 1px solid rgb(185, 204, 238);
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
QLabel#beamlineStateTitle {
|
||||
background-color: #4B0082;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
QPushButton#beamlineStateToggleButton {
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
background-color: rgba(255, 255, 255, 0.20);
|
||||
color: white;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#beamlineStateToggleButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.32);
|
||||
}
|
||||
|
||||
QLabel#beamlineStateCurrentLabel {
|
||||
color: rgb(30, 41, 59);
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QLabel#beamlineStateTellLabel {
|
||||
color: rgb(55, 67, 87);
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot,
|
||||
QWidget#portraitRoot QWidget {
|
||||
background: #071018;
|
||||
color: #F5F7FA;
|
||||
font-family: 'Inter', 'SF Pro Display', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollArea {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar:vertical {
|
||||
background: #0E1A26;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar::handle:vertical {
|
||||
background: #1A3A36;
|
||||
border-radius: 2px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar::add-line:vertical,
|
||||
QWidget#portraitRoot QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def _portrait_stylesheet() -> str:
|
||||
return """
|
||||
QMainWindow, QWidget {
|
||||
background: #071018;
|
||||
color: #F5F7FA;
|
||||
}
|
||||
|
||||
QWidget#mainContentRoot,
|
||||
QWidget#standardMainPage,
|
||||
QWidget#compactAutomationPage,
|
||||
QWidget#portraitModePage {
|
||||
background: #071018;
|
||||
}
|
||||
|
||||
QTabWidget::pane,
|
||||
QScrollArea,
|
||||
QDockWidget,
|
||||
QDockWidget > QWidget {
|
||||
background: #071018;
|
||||
color: #F5F7FA;
|
||||
}
|
||||
|
||||
QFrame#compactAutomationPanel {
|
||||
background: #071018;
|
||||
border: none;
|
||||
border-radius: 18px;
|
||||
}
|
||||
|
||||
QFrame#compactCameraCard,
|
||||
QFrame#compactControlsCard,
|
||||
QFrame#compactProgressCard,
|
||||
QFrame#compactQueueCard,
|
||||
QFrame#compactQueueItem {
|
||||
background: #0E1A26;
|
||||
border: 1px solid #1A3A36;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
QLabel#compactSectionTitle {
|
||||
background: transparent;
|
||||
color: #62D8C8;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactSectionHint {
|
||||
background: transparent;
|
||||
color: #8A9BB0;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
QLabel#compactQueueTitle {
|
||||
background: transparent;
|
||||
color: #8A9BB0;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QLabel#compactQueueValue {
|
||||
background: transparent;
|
||||
color: #F5F7FA;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton {
|
||||
background: #132131;
|
||||
color: #62D8C8;
|
||||
border: 1px solid #1A3A36;
|
||||
border-radius: 14px;
|
||||
padding: 10px 14px;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QToolButton#compactMenuButton:hover {
|
||||
background: #1A3A36;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton {
|
||||
background: #62D8C8;
|
||||
color: #071018;
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 15px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactPrimaryButton:hover {
|
||||
background: #7ce6d8;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton,
|
||||
QToolButton#compactSecondaryButton {
|
||||
background: #132131;
|
||||
color: #F5F7FA;
|
||||
border: 1px solid #1A3A36;
|
||||
border-radius: 14px;
|
||||
padding: 14px 18px;
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#compactSecondaryButton:hover,
|
||||
QToolButton#compactSecondaryButton:hover {
|
||||
background: #1A3A36;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="error"] {
|
||||
background: #1A0E0E;
|
||||
border: 2px solid #8f1d2c;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="success"] {
|
||||
background: #0E1A12;
|
||||
border: 2px solid #2a7a44;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="waiting"] {
|
||||
background: #2B2208;
|
||||
border: 2px solid #ffb300;
|
||||
border-radius: 12px;
|
||||
margin: 8px 12px 8px 12px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner QLabel {
|
||||
font-weight: 700;
|
||||
font-size: 20px;
|
||||
padding: 2px 6px 2px 6px;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="error"] QLabel {
|
||||
color: #ffb3bc;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="success"] QLabel {
|
||||
color: #a8f0c0;
|
||||
}
|
||||
|
||||
QFrame#alertBanner[alertKind="waiting"] QLabel {
|
||||
color: #ffd166;
|
||||
}
|
||||
|
||||
QWidget#axisVideoStatusContainer[busyState="idle"] {
|
||||
border-radius: 12px;
|
||||
background-color: #132131;
|
||||
}
|
||||
|
||||
QWidget#axisVideoStatusContainer[busyState="active"] {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
QLabel#axisVideoStatusDot {
|
||||
min-width: 10px;
|
||||
max-width: 10px;
|
||||
min-height: 10px;
|
||||
max-height: 10px;
|
||||
border-radius: 5px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
QLabel#axisVideoStatusLabel {
|
||||
background-color: transparent;
|
||||
color: #8A9BB0;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
QFrame#beamlineStatePanel {
|
||||
background: #0E1A26;
|
||||
border: 1px solid #1A3A36;
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
QLabel#beamlineStateTitle {
|
||||
background-color: #132131;
|
||||
color: #F5F7FA;
|
||||
}
|
||||
|
||||
QPushButton#beamlineStateToggleButton {
|
||||
border: none;
|
||||
border-radius: 14px;
|
||||
background-color: rgba(255, 255, 255, 0.10);
|
||||
color: #F5F7FA;
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
QPushButton#beamlineStateToggleButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
|
||||
QLabel#beamlineStateCurrentLabel {
|
||||
color: #F5F7FA;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QLabel#beamlineStateTellLabel {
|
||||
color: #8A9BB0;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
padding-left: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot,
|
||||
QWidget#portraitRoot QWidget {
|
||||
background: #071018;
|
||||
color: #F5F7FA;
|
||||
font-family: 'Inter', 'SF Pro Display', Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollArea {
|
||||
border: none;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar:vertical {
|
||||
background: #0E1A26;
|
||||
width: 4px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar::handle:vertical {
|
||||
background: #1A3A36;
|
||||
border-radius: 2px;
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
QWidget#portraitRoot QScrollBar::add-line:vertical,
|
||||
QWidget#portraitRoot QScrollBar::sub-line:vertical {
|
||||
height: 0px;
|
||||
}
|
||||
"""
|
||||
@@ -11,6 +11,9 @@ class AlertBanner(QFrame):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
self.setObjectName("alertBanner")
|
||||
self.setProperty("alertKind", "error")
|
||||
|
||||
self._current_message = None
|
||||
self._current_is_error = None
|
||||
self._clear_timer = QTimer(self)
|
||||
@@ -41,6 +44,14 @@ class AlertBanner(QFrame):
|
||||
self.setVisible(False)
|
||||
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
|
||||
def _set_alert_kind(self, kind: str) -> None:
|
||||
self.setProperty("alertKind", kind)
|
||||
self.style().unpolish(self)
|
||||
self.style().polish(self)
|
||||
self.style().unpolish(self._label)
|
||||
self.style().polish(self._label)
|
||||
self.update()
|
||||
|
||||
@Slot(str, bool)
|
||||
def show_message(self, msg: str, is_error: bool = True, auto_clear_ms: int | None = None):
|
||||
"""Show error (red) or success (green) message."""
|
||||
@@ -53,36 +64,10 @@ class AlertBanner(QFrame):
|
||||
|
||||
if is_error:
|
||||
decorated = f"🛑 {msg} 🛑"
|
||||
self.setStyleSheet(
|
||||
"QFrame {"
|
||||
" background-color: #fbe4e6;"
|
||||
" border: 2px solid #d97a84;"
|
||||
" border-radius: 12px;"
|
||||
" margin: 8px 12px 8px 12px;"
|
||||
"}"
|
||||
"QLabel {"
|
||||
" color: #8f1d2c;"
|
||||
" font-weight: 700;"
|
||||
" font-size: 20px;"
|
||||
" padding: 2px 6px 2px 6px;"
|
||||
"}"
|
||||
)
|
||||
self._set_alert_kind("error")
|
||||
else:
|
||||
decorated = f"✅ {msg} ✅"
|
||||
self.setStyleSheet(
|
||||
"QFrame {"
|
||||
" background-color: #e7f6ea;"
|
||||
" border: 2px solid #7bbf8e;"
|
||||
" border-radius: 12px;"
|
||||
" margin: 8px 12px 8px 12px;"
|
||||
"}"
|
||||
"QLabel {"
|
||||
" color: #1f6a3a;"
|
||||
" font-weight: 700;"
|
||||
" font-size: 20px;"
|
||||
" padding: 2px 6px 2px 6px;"
|
||||
"}"
|
||||
)
|
||||
self._set_alert_kind("success")
|
||||
if auto_clear_ms is None:
|
||||
timeout = 5000
|
||||
else:
|
||||
@@ -123,20 +108,7 @@ class AlertBanner(QFrame):
|
||||
|
||||
def _apply_waiting_style(self):
|
||||
"""Apply yellow/waiting style."""
|
||||
self.setStyleSheet(
|
||||
"QFrame {"
|
||||
" background-color: #fff8e1;"
|
||||
" border: 2px solid #ffb300;"
|
||||
" border-radius: 12px;"
|
||||
" margin: 8px 12px 8px 12px;"
|
||||
"}"
|
||||
"QLabel {"
|
||||
" color: #e65100;"
|
||||
" font-weight: 700;"
|
||||
" font-size: 20px;"
|
||||
" padding: 2px 6px 2px 6px;"
|
||||
"}"
|
||||
)
|
||||
self._set_alert_kind("waiting")
|
||||
|
||||
def _update_waiting_text(self):
|
||||
"""Update the waiting message text, including countdown if active."""
|
||||
@@ -167,5 +139,6 @@ class AlertBanner(QFrame):
|
||||
self._current_message = None
|
||||
self._current_is_error = None
|
||||
self._clear_timer.stop()
|
||||
self._set_alert_kind("error")
|
||||
self._label.clear()
|
||||
self.setVisible(False)
|
||||
self.setVisible(False)
|
||||
@@ -3,11 +3,13 @@ from unittest.mock import MagicMock, patch
|
||||
from PySide6.QtCore import Qt
|
||||
from aare.gui.main_window import MainWindow
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def mock_ui_state():
|
||||
with patch("aare.gui.main_window.UIStateManager") as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
def test_main_window_init(qtbot, mock_ui_state):
|
||||
with patch("requests.get") as mock_get, \
|
||||
patch("aare.gui.main_window.DAQWorker"), \
|
||||
@@ -241,4 +243,65 @@ def test_idle_timeout_does_not_close_while_automation_active(qtbot, mock_ui_stat
|
||||
with patch("aare.gui.main_window.time.time", return_value=111.0):
|
||||
win._check_idle_timeout()
|
||||
|
||||
win.close.assert_not_called()
|
||||
win.close.assert_not_called()
|
||||
|
||||
def test_cleanup_returns_from_portrait_mode(qtbot, mock_ui_state):
|
||||
with patch("requests.get"), \
|
||||
patch("aare.gui.main_window.DAQWorker"), \
|
||||
patch("aare.gui.main_window.PredictionSubscriber"), \
|
||||
patch("aare.gui.main_window.VideoThread"), \
|
||||
patch("aare.gui.main_window.JFJochDBusClient"), \
|
||||
patch("aare.gui.main_window.jwt.decode") as mock_jwt:
|
||||
|
||||
mock_jwt.return_value = {"sub": "testuser", "staff": True, "pgroups": ["p123"], "session": 15}
|
||||
fake_token = "header.payload.signature"
|
||||
|
||||
win = MainWindow(
|
||||
base_url=None,
|
||||
token=fake_token,
|
||||
default_image=None,
|
||||
zmq_addr=None,
|
||||
pred_zmq_addr=None,
|
||||
beamline_cam_addr=None,
|
||||
gonio_cam_addr=None,
|
||||
gonio_cam_id=None
|
||||
)
|
||||
qtbot.addWidget(win)
|
||||
|
||||
win.enter_portrait_mode()
|
||||
assert win.content_stack.currentWidget() is win.portrait_mode_page
|
||||
|
||||
win.cleanup()
|
||||
|
||||
assert win.content_stack.currentWidget() is win._standard_main_page
|
||||
|
||||
|
||||
def test_cleanup_returns_from_compact_automation_view(qtbot, mock_ui_state):
|
||||
with patch("requests.get"), \
|
||||
patch("aare.gui.main_window.DAQWorker"), \
|
||||
patch("aare.gui.main_window.PredictionSubscriber"), \
|
||||
patch("aare.gui.main_window.VideoThread"), \
|
||||
patch("aare.gui.main_window.JFJochDBusClient"), \
|
||||
patch("aare.gui.main_window.jwt.decode") as mock_jwt:
|
||||
|
||||
mock_jwt.return_value = {"sub": "testuser", "staff": True, "pgroups": ["p123"], "session": 15}
|
||||
fake_token = "header.payload.signature"
|
||||
|
||||
win = MainWindow(
|
||||
base_url=None,
|
||||
token=fake_token,
|
||||
default_image=None,
|
||||
zmq_addr=None,
|
||||
pred_zmq_addr=None,
|
||||
beamline_cam_addr=None,
|
||||
gonio_cam_addr=None,
|
||||
gonio_cam_id=None
|
||||
)
|
||||
qtbot.addWidget(win)
|
||||
|
||||
win.enter_compact_automation_view()
|
||||
assert win.content_stack.currentWidget() is win.compact_automation_page
|
||||
|
||||
win.cleanup()
|
||||
|
||||
assert win.content_stack.currentWidget() is win._standard_main_page
|
||||
Reference in New Issue
Block a user