From e3703f7bb3dc69139ee9a37e731d088cd77f56e4 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Wed, 12 Aug 2026 14:30:57 +0100 Subject: [PATCH 01/18] Refactor: separated mainwindow widget --- BlocksScreen/lib/panels/mainWindow.py | 686 ++++++++++++--- .../panels/widgets/MainWindow/cancelPage.py | 273 ++++++ .../widgets/MainWindow/connectionPage.py | 555 ++++++++++++ .../widgets/MainWindow/notificationPage.py | 407 +++++++++ .../panels/widgets/MainWindow/updatePage.py | 638 ++++++++++++++ BlocksScreen/lib/ui/mainWindow.ui | 807 ------------------ BlocksScreen/lib/ui/mainWindow_ui.py | 325 ------- 7 files changed, 2458 insertions(+), 1233 deletions(-) create mode 100644 BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py create mode 100644 BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py create mode 100644 BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py create mode 100644 BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py delete mode 100644 BlocksScreen/lib/ui/mainWindow.ui delete mode 100644 BlocksScreen/lib/ui/mainWindow_ui.py diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index 646b7c107..5b5f739ee 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -23,13 +23,12 @@ from lib.panels.printTab import PrintTab from lib.panels.utilitiesTab import UtilitiesTab from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.cancelPage import CancelPage -from lib.panels.widgets.connectionPage import ConnectionPage +from lib.panels.widgets.MainWindow.cancelPage import CancelPage +from lib.panels.widgets.MainWindow.connectionPage import ConnectionPage from lib.panels.widgets.loadWidget import LoadingOverlayWidget -from lib.panels.widgets.notificationPage import NotificationPage -from lib.panels.widgets.updatePage import UpdatePage +from lib.panels.widgets.MainWindow.notificationPage import NotificationPage +from lib.panels.widgets.MainWindow.updatePage import UpdatePage from lib.printer import Printer -from lib.ui.mainWindow_ui import Ui_MainWindow # With header from lib.ui.resources.background_resources_rc import * from lib.ui.resources.font_rc import * from lib.ui.resources.graphic_resources_rc import * @@ -38,6 +37,9 @@ from lib.ui.resources.system_resources_rc import * from lib.ui.resources.top_bar_resources_rc import * from lib.updater_worker import UpdaterWorker +from lib.utils.blocks_tabwidget import NotificationQTabWidget +from lib.utils.display_button import DisplayButton +from lib.utils.icon_button import IconButton from PyQt6 import QtCore, QtGui, QtWidgets from screensaver import ScreenSaver @@ -122,8 +124,7 @@ def __init__(self): """Set up UI, instantiate subsystems, and wire all inter-component signals.""" super().__init__() self.config: BlocksScreenConfig = get_configparser() - self.ui = Ui_MainWindow() - self.ui.setupUi(self) + self._setup_ui() self.screensaver = ScreenSaver(self) self._popup_toggle: bool = False self._update_in_progress: bool = False @@ -139,7 +140,7 @@ def __init__(self): self._klipper_restart_timeout.setSingleShot(True) self._klipper_restart_timeout.setInterval(30_000) self._klipper_restart_timeout.timeout.connect(self._on_klipper_restart_timeout) - self.ui.main_content_widget.setCurrentIndex(0) + self.main_content_widget.setCurrentIndex(0) usb_config = self.config.get_section("usb_manager", fallback=None) gdir = None @@ -170,9 +171,7 @@ def __init__(self): self.update_page.hide() self.conn_window.call_cancel_panel.connect(self.handle_cancel_print) self.installEventFilter(self.conn_window) - self.printPanel = PrintTab( - self.ui.printTab, self.file_data, self.ws, self.printer - ) + self.printPanel = PrintTab(self.printTab, self.file_data, self.ws, self.printer) self.usb_manager.usb_mounted.connect( self.printPanel.filesPage_widget.on_usb_added ) @@ -183,10 +182,10 @@ def __init__(self): if not os.environ.get("BLOCKSCREEN_DEV"): QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.CursorShape.BlankCursor) self.filamentPanel = FilamentTab( - self.ui.filamentTab, self.printer, self.ws, self.config, self.amu_manager + self.filamentTab, self.printer, self.ws, self.config, self.amu_manager ) - self.controlPanel = ControlTab(self.ui.controlTab, self.ws, self.printer) - self.utilitiesPanel = UtilitiesTab(self.ui.utilitiesTab, self.ws, self.printer) + self.controlPanel = ControlTab(self.controlTab, self.ws, self.printer) + self.utilitiesPanel = UtilitiesTab(self.utilitiesTab, self.ws, self.printer) self.networkPanel = NetworkControlWindow(self) self.bo_ws_startup.connect(slot=self.bo_start_websocket_connection) @@ -214,30 +213,29 @@ def __init__(self): self.utilitiesPanel.request_back.connect(slot=self.global_back) self.utilitiesPanel.request_change_page.connect(slot=self.global_change_page) self.utilitiesPanel.update_available.connect(self.on_update_available) - - self.ui.notification_btn.clicked.connect(self.notiPage.show_notification_panel) - self.ui.extruder_temp_display.clicked.connect( + self.notification_btn.clicked.connect(self.notiPage.show_notification_panel) + self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) - self.ui.bed_temp_display.clicked.connect( + self.bed_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) - self.ui.filament_type_icon.clicked.connect( + self.filament_type_icon.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.filamentTab), + self.main_content_widget.indexOf(self.filamentTab), 2, ) ) - self.ui.filament_type_icon.setText("PLA") - self.ui.filament_type_icon.update() - self.ui.nozzle_size_icon.setText("0.4mm") - self.ui.nozzle_size_icon.update() + self.filament_type_icon.setText("PLA") + self.filament_type_icon.update() + self.nozzle_size_icon.setText("0.4mm") + self.nozzle_size_icon.update() self.conn_window.retry_connection_clicked.connect(slot=self.ws.retry_wb_conn) self.conn_window.firmware_restart_clicked.connect( slot=self.mc.restart_klipper_mcu_service @@ -263,7 +261,7 @@ def __init__(self): self.amu_manager.run_gcode_signal.connect(self.ws.api.run_gcode) self.run_gcode_signal.connect(self.ws.api.run_gcode) - self.ui.main_content_widget.currentChanged.connect(slot=self.reset_tab_indexes) + self.main_content_widget.currentChanged.connect(slot=self.reset_tab_indexes) self.call_network_panel.connect(self.networkPanel.show_network_panel) self.call_notification_panel.connect(self.notiPage.show_notification_panel) self.networkPanel.update_wifi_icon.connect(self.change_wifi_icon) @@ -271,7 +269,7 @@ def __init__(self): self.conn_window.notification_button_clicked.connect( self.call_notification_panel.emit ) - self.ui.wifi_button.clicked.connect(self.call_network_panel.emit) + self.wifi_button.clicked.connect(self.call_network_panel.emit) self.handle_error_response.connect( self.controlPanel.probe_helper_page.handle_error_response ) @@ -310,8 +308,8 @@ def __init__(self): self.ws.klippy_state_signal.connect(self._on_klippy_state) self.utilitiesPanel.show_update_page.connect(self.show_update_page) self.conn_window.update_button_clicked.connect(self.show_update_page) - self.ui.extruder_temp_display.display_format = "upper_downer" - self.ui.bed_temp_display.display_format = "upper_downer" + self.extruder_temp_display.display_format = "upper_downer" + self.bed_temp_display.display_format = "upper_downer" self.controlPanel.call_load_panel.connect(self.show_loadscreen) self.filamentPanel.call_load_panel.connect(self.show_loadscreen) @@ -353,7 +351,7 @@ def __init__(self): self.printer.print_stats_update[str, str].connect(self._track_print_state) self.print_status = "idle" - self.ui.chamber_temp_display.hide() + self.chamber_temp_display.hide() if self.config.has_section("server"): self.bo_ws_startup.emit() @@ -429,9 +427,9 @@ def show_loadscreen( def show_update_page(self, fullscreen: bool): """Slot for displaying update Panel""" if not fullscreen: - self.update_page.setParent(self.ui.main_content_widget) - current_index = self.ui.main_content_widget.currentIndex() - tab_rect = self.ui.main_content_widget.tabBar().tabRect(current_index) + self.update_page.setParent(self.main_content_widget) + current_index = self.main_content_widget.currentIndex() + tab_rect = self.main_content_widget.tabBar().tabRect(current_index) width = tab_rect.width() _parent_size = self.update_page.parent().size() self.update_page.setGeometry( @@ -502,19 +500,19 @@ def on_cancel_print(self): """Slot for cancel print signal""" self.enable_tab_bar() try: - self.ui.extruder_temp_display.clicked.disconnect() - self.ui.bed_temp_display.clicked.disconnect() + self.extruder_temp_display.clicked.disconnect() + self.bed_temp_display.clicked.disconnect() except TypeError: pass - self.ui.extruder_temp_display.clicked.connect( + self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) - self.ui.bed_temp_display.clicked.connect( + self.bed_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) @@ -599,7 +597,7 @@ def _on_moonraker_connected_post_update(self) -> None: @QtCore.pyqtSlot(bool, name="update-available") def on_update_available(self, state: bool = False): """Signal render for red dot on utilities tab icon and Update button""" - self.ui.main_content_widget.setNotification(3, state) + self.main_content_widget.setNotification(3, state) self.utilitiesPanel.panel.update_btn.setShowNotification(state) self.repaint() @@ -612,22 +610,22 @@ def enable_tab_bar(self) -> bool: bool: True if the TabBar was disabled """ - self.ui.main_content_widget.setTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.controlTab), True + self.main_content_widget.setTabEnabled( + self.main_content_widget.indexOf(self.controlTab), True ) - self.ui.main_content_widget.setTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.utilitiesTab), True + self.main_content_widget.setTabEnabled( + self.main_content_widget.indexOf(self.utilitiesTab), True ) - self.ui.header_main_layout.setEnabled(True) + self.header_main_layout.setEnabled(True) return all( [ - not self.ui.main_content_widget.isTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.controlTab) + not self.main_content_widget.isTabEnabled( + self.main_content_widget.indexOf(self.controlTab) ), - not self.ui.main_content_widget.isTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.utilitiesTab) + not self.main_content_widget.isTabEnabled( + self.main_content_widget.indexOf(self.utilitiesTab) ), - not self.ui.header_main_layout.isEnabled(), + not self.header_main_layout.isEnabled(), ] ) @@ -642,22 +640,22 @@ def disable_tab_bar(self) -> bool: Returns: boolean: True if the TabBar was disabled """ - self.ui.main_content_widget.setTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.controlTab), False + self.main_content_widget.setTabEnabled( + self.main_content_widget.indexOf(self.controlTab), False ) - self.ui.main_content_widget.setTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.utilitiesTab), False + self.main_content_widget.setTabEnabled( + self.main_content_widget.indexOf(self.utilitiesTab), False ) - self.ui.header_main_layout.setEnabled(False) + self.header_main_layout.setEnabled(False) return all( [ - not self.ui.main_content_widget.isTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.controlTab) + not self.main_content_widget.isTabEnabled( + self.main_content_widget.indexOf(self.controlTab) ), - not self.ui.main_content_widget.isTabEnabled( - self.ui.main_content_widget.indexOf(self.ui.utilitiesTab) + not self.main_content_widget.isTabEnabled( + self.main_content_widget.indexOf(self.utilitiesTab) ), - not self.ui.header_main_layout.isEnabled(), + not self.header_main_layout.isEnabled(), ] ) @@ -674,14 +672,14 @@ def set_ui_lock(self, locked: bool) -> None: the header, so the user cannot navigate away mid-calibration. """ for tab in ( - self.ui.printTab, - self.ui.filamentTab, - self.ui.utilitiesTab, + self.printTab, + self.filamentTab, + self.utilitiesTab, ): - self.ui.main_content_widget.setTabEnabled( - self.ui.main_content_widget.indexOf(tab), not locked + self.main_content_widget.setTabEnabled( + self.main_content_widget.indexOf(tab), not locked ) - self.ui.header_main_layout.setEnabled(not locked) + self.header_main_layout.setEnabled(not locked) @QtCore.pyqtSlot(str, str, name="track_print_state") def _track_print_state(self, field: str, value: str) -> None: @@ -695,7 +693,7 @@ def _is_job_active(self) -> bool: def _print_tab_index(self) -> int: """Tab index of the print tab in the main content widget.""" - return self.ui.main_content_widget.indexOf(self.ui.printTab) + return self.main_content_widget.indexOf(self.printTab) def _job_status_index(self) -> int: """Panel index of the job-status page inside the print tab.""" @@ -737,7 +735,7 @@ def current_panel_index(self) -> int: Returns: int: The index os the page """ - match self.ui.main_content_widget.currentIndex(): + match self.main_content_widget.currentIndex(): case 0: return self.printPanel.currentIndex() case 1: @@ -754,7 +752,7 @@ def set_current_panel_index(self, panel_index: int) -> None: Args: panel_index (int): The index of the page we want to go to """ - match self.ui.main_content_widget.currentIndex(): + match self.main_content_widget.currentIndex(): case 0: self.printPanel.setCurrentIndex(panel_index) case 1: @@ -771,7 +769,7 @@ def change_wifi_icon(self, icon_key: int) -> None: Args: icon_key (int): WifiIconKey mapping for the current network state """ - self.ui.wifi_button.setPixmap(HeaderWifiIconProvider.get_pixmap(icon_key)) + self.wifi_button.setPixmap(HeaderWifiIconProvider.get_pixmap(icon_key)) @QtCore.pyqtSlot(int, int, name="request-change-page") def global_change_page(self, tab_index: int, panel_index: int) -> None: @@ -793,7 +791,7 @@ def global_change_page(self, tab_index: int, panel_index: int) -> None: self.show_loadscreen(False) panel_index = self._guard_print_panel(tab_index, panel_index) current_page = [ - self.ui.main_content_widget.currentIndex(), + self.main_content_widget.currentIndex(), self.current_panel_index(), ] requested_page = [tab_index, panel_index] @@ -801,7 +799,7 @@ def global_change_page(self, tab_index: int, panel_index: int) -> None: _logger.debug("User is already on the requested page") return self.index_stack.append(current_page) - self.ui.main_content_widget.setCurrentIndex(tab_index) + self.main_content_widget.setCurrentIndex(tab_index) self.set_current_panel_index(panel_index) _logger.debug( f"Requested page change -> Tab index : {requested_page[0]} | panel index : {requested_page[1]}", @@ -818,7 +816,7 @@ def global_change_tab(self, tab_index: int) -> None: "Tab index argument expected type int, got %s", str(type(tab_index)) ) return - self.ui.main_content_widget.setCurrentIndex(tab_index) + self.main_content_widget.setCurrentIndex(tab_index) _logger.debug( f"Requested tab change -> Tab index : {tab_index}", ) @@ -831,7 +829,7 @@ def global_back(self) -> None: return _tab, _panel = self.index_stack[-1] _panel = self._guard_print_panel(_tab, _panel) - self.ui.main_content_widget.setCurrentIndex(_tab) + self.main_content_widget.setCurrentIndex(_tab) self.set_current_panel_index(_panel) self.index_stack.pop() # Remove the last position. _logger.debug("Successfully went back a page.") @@ -1169,9 +1167,9 @@ def on_extruder_update( """Handles extruder printer object updates""" if extruder_name == "extruder": if field == "temperature": - self.ui.extruder_temp_display.setText(f"{new_value:.0f}") + self.extruder_temp_display.setText(f"{new_value:.0f}") elif field == "target": - self.ui.extruder_temp_display.secondary_text = ( + self.extruder_temp_display.secondary_text = ( f"{round(int(new_value)):.0f}°C" ) @@ -1179,34 +1177,32 @@ def on_extruder_update( def on_heater_bed_update(self, name: str, field: str, new_value: float) -> None: """Handles heater_bed printer object updates""" if field == "temperature": - self.ui.bed_temp_display.setText(f"{new_value:.0f}") + self.bed_temp_display.setText(f"{new_value:.0f}") elif field == "target": - self.ui.bed_temp_display.secondary_text = f"{round(int(new_value)):.0f}°C" + self.bed_temp_display.secondary_text = f"{round(int(new_value)):.0f}°C" @QtCore.pyqtSlot(str, str, float, name="sensor_update") def on_temp_sensor_update(self, name: str, field: str, value: float) -> None: """Handles Chamber temperature if a sensor with that name exists""" if name == "Chamber": - if self.ui.chamber_temp_display.isHidden(): - self.ui.chamber_temp_display.show() + if self.chamber_temp_display.isHidden(): + self.chamber_temp_display.show() if field == "temperature": - self.ui.chamber_temp_display.setText(f"{round(int(value)):.0f}°C") + self.chamber_temp_display.setText(f"{round(int(value)):.0f}°C") elif field == "humidity": - self.ui.chamber_temp_display.setSecondaryText( - f"{round(int(value)):.0f}%" - ) + self.chamber_temp_display.setSecondaryText(f"{round(int(value)):.0f}%") @QtCore.pyqtSlot(str, name="set-header-filament-type") def set_header_filament_type(self, type: str): """Sets header filament text label""" - self.ui.filament_type_icon.setText(f"{type}") - self.ui.filament_type_icon.update() + self.filament_type_icon.setText(f"{type}") + self.filament_type_icon.update() @QtCore.pyqtSlot(str, name="set-header-nozzle-diameter") def set_header_nozzle_diameter(self, diam: str): """Sets header nozzle diameter text label""" - self.ui.nozzle_size_icon.setText(f"{diam}mm") - self.ui.nozzle_size_icon.update() + self.nozzle_size_icon.setText(f"{diam}mm") + self.nozzle_size_icon.update() def closeEvent(self, a0: QtGui.QCloseEvent | None) -> None: """Handles GUI closing""" @@ -1233,19 +1229,19 @@ def event(self, event: QtCore.QEvent) -> bool: self.print_status = "printing" self.disable_tab_bar() try: - self.ui.extruder_temp_display.clicked.disconnect() - self.ui.bed_temp_display.clicked.disconnect() + self.extruder_temp_display.clicked.disconnect() + self.bed_temp_display.clicked.disconnect() except TypeError: pass - self.ui.extruder_temp_display.clicked.connect( + self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.printTab), + self.main_content_widget.indexOf(self.printTab), self.printPanel.indexOf(self.printPanel.tune_page), ) ) - self.ui.bed_temp_display.clicked.connect( + self.bed_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.printTab), + self.main_content_widget.indexOf(self.printTab), self.printPanel.indexOf(self.printPanel.tune_page), ) ) @@ -1261,19 +1257,19 @@ def event(self, event: QtCore.QEvent) -> bool: self.handle_cancel_print() self.enable_tab_bar() try: - self.ui.extruder_temp_display.clicked.disconnect() - self.ui.bed_temp_display.clicked.disconnect() + self.extruder_temp_display.clicked.disconnect() + self.bed_temp_display.clicked.disconnect() except TypeError: pass - self.ui.extruder_temp_display.clicked.connect( + self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) - self.ui.bed_temp_display.clicked.connect( + self.bed_temp_display.clicked.connect( lambda: self.global_change_page( - self.ui.main_content_widget.indexOf(self.ui.controlTab), + self.main_content_widget.indexOf(self.controlTab), self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), ) ) @@ -1284,3 +1280,491 @@ def sizeHint(self) -> QtCore.QSize: """Sets default size for the widget""" self.adjustSize() return QtCore.QSize(800, 480) + + def _setup_ui(self) -> None: + """Build the main window chrome: header bar, tab widget, and tab pages.""" + self.setObjectName("MainWindow") + self.resize(800, 480) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + self.setSizePolicy(sizePolicy) + self.setMinimumSize(QtCore.QSize(800, 480)) + self.setMaximumSize(QtCore.QSize(1024, 600)) + self.setSizeIncrement(QtCore.QSize(1, 1)) + self.setBaseSize(QtCore.QSize(800, 480)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush + ) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush + ) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Inactive, + QtGui.QPalette.ColorRole.WindowText, + brush, + ) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Inactive, + QtGui.QPalette.ColorRole.ButtonText, + brush, + ) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Disabled, + QtGui.QPalette.ColorRole.WindowText, + brush, + ) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Disabled, + QtGui.QPalette.ColorRole.ButtonText, + brush, + ) + self.setPalette(palette) + self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.setTabletTracking(True) + icon = QtGui.QIcon.fromTheme("applications-other") + self.setWindowIcon(icon) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.setStyleSheet( + "MainWindow > {\n url(:/font/media/fonts for text/Momcake-Thin.ttf);\n}" + ) + self.setAnimated(False) + self.main_widget = QtWidgets.QWidget(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.main_widget.sizePolicy().hasHeightForWidth()) + self.main_widget.setSizePolicy(sizePolicy) + self.main_widget.setMinimumSize(QtCore.QSize(800, 480)) + self.main_widget.setMaximumSize(QtCore.QSize(1024, 600)) + self.main_widget.setSizeIncrement(QtCore.QSize(1, 1)) + self.main_widget.setBaseSize(QtCore.QSize(800, 480)) + self.main_widget.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.main_widget.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.main_widget.setStyleSheet( + "#main_widget{background-image: url(:/background/media/1st_background.png);}\n" + "" + ) + self.main_widget.setObjectName("main_widget") + self.main_content_widget = NotificationQTabWidget(parent=self.main_widget) + self.main_content_widget.setEnabled(True) + self.main_content_widget.setGeometry(QtCore.QRect(0, 60, 800, 420)) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth( + self.main_content_widget.sizePolicy().hasHeightForWidth() + ) + self.main_content_widget.setSizePolicy(sizePolicy) + self.main_content_widget.setMinimumSize(QtCore.QSize(800, 400)) + self.main_content_widget.setMaximumSize(QtCore.QSize(1024, 720)) + self.main_content_widget.setBaseSize(QtCore.QSize(800, 400)) + self.main_content_widget.setCursor( + QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) + ) + self.main_content_widget.setLayoutDirection( + QtCore.Qt.LayoutDirection.RightToLeft + ) + self.main_content_widget.setAutoFillBackground(False) + self.main_content_widget.setStyleSheet( + "#main_content_widget{\n" + "background-image: url(:/background/media/1st_background.png);\n" + "}\n" + "QTabBar::tab{\n" + " min-width: 80px;\n" + " max-width: 80px;\n" + " min-height: 100px;\n" + " max-height: 100px;\n" + " background: transparent;\n" + "}\n" + "\n" + "" + ) + self.main_content_widget.setTabPosition(QtWidgets.QTabWidget.TabPosition.West) + self.main_content_widget.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded) + self.main_content_widget.setIconSize(QtCore.QSize(60, 60)) + self.main_content_widget.setElideMode(QtCore.Qt.TextElideMode.ElideLeft) + self.main_content_widget.setUsesScrollButtons(False) + self.main_content_widget.setDocumentMode(True) + self.main_content_widget.setTabsClosable(False) + self.main_content_widget.setMovable(False) + self.main_content_widget.setObjectName("main_content_widget") + self.printTab = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.printTab.sizePolicy().hasHeightForWidth()) + self.printTab.setSizePolicy(sizePolicy) + self.printTab.setMinimumSize(QtCore.QSize(720, 420)) + self.printTab.setMaximumSize(QtCore.QSize(1024, 720)) + self.printTab.setBaseSize(QtCore.QSize(1024, 420)) + self.printTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.printTab.setObjectName("printTab") + icon = QtGui.QIcon() + icon.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_home.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) + icon.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_home_pressed.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.On, + ) + icon.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_home_blocked.png"), + QtGui.QIcon.Mode.Disabled, + QtGui.QIcon.State.On, + ) + self.main_content_widget.addTab(self.printTab, icon, "") + self.filamentTab = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.filamentTab.sizePolicy().hasHeightForWidth()) + self.filamentTab.setSizePolicy(sizePolicy) + self.filamentTab.setMinimumSize(QtCore.QSize(720, 420)) + self.filamentTab.setMaximumSize(QtCore.QSize(1024, 720)) + self.filamentTab.setBaseSize(QtCore.QSize(1024, 420)) + self.filamentTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.filamentTab.setObjectName("filamentTab") + icon1 = QtGui.QIcon() + icon1.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_filament.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) + icon1.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_filament_pressed.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.On, + ) + icon1.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_filamente_blocked.png"), + QtGui.QIcon.Mode.Disabled, + QtGui.QIcon.State.On, + ) + self.main_content_widget.addTab(self.filamentTab, icon1, "") + self.controlTab = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.controlTab.sizePolicy().hasHeightForWidth()) + self.controlTab.setSizePolicy(sizePolicy) + self.controlTab.setMinimumSize(QtCore.QSize(720, 420)) + self.controlTab.setMaximumSize(QtCore.QSize(1024, 720)) + self.controlTab.setBaseSize(QtCore.QSize(720, 420)) + self.controlTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.controlTab.setObjectName("controlTab") + icon2 = QtGui.QIcon() + icon2.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_control.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) + icon2.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_control_pressed.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.On, + ) + icon2.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_control_blocked.png"), + QtGui.QIcon.Mode.Disabled, + QtGui.QIcon.State.On, + ) + self.main_content_widget.addTab(self.controlTab, icon2, "") + self.utilitiesTab = QtWidgets.QWidget() + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.utilitiesTab.sizePolicy().hasHeightForWidth()) + self.utilitiesTab.setSizePolicy(sizePolicy) + self.utilitiesTab.setMinimumSize(QtCore.QSize(720, 420)) + self.utilitiesTab.setMaximumSize(QtCore.QSize(1024, 720)) + self.utilitiesTab.setBaseSize(QtCore.QSize(1024, 420)) + self.utilitiesTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) + self.utilitiesTab.setObjectName("utilitiesTab") + icon3 = QtGui.QIcon() + icon3.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.Off, + ) + icon3.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_pressed.png"), + QtGui.QIcon.Mode.Normal, + QtGui.QIcon.State.On, + ) + icon3.addPixmap( + QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_blocked.png"), + QtGui.QIcon.Mode.Disabled, + QtGui.QIcon.State.On, + ) + self.main_content_widget.addTab(self.utilitiesTab, icon3, "") + self.main_header_layout = QtWidgets.QGroupBox(parent=self.main_widget) + self.main_header_layout.setEnabled(True) + self.main_header_layout.setGeometry(QtCore.QRect(0, 0, 800, 60)) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(2) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth( + self.main_header_layout.sizePolicy().hasHeightForWidth() + ) + self.main_header_layout.setSizePolicy(sizePolicy) + self.main_header_layout.setMinimumSize(QtCore.QSize(800, 60)) + self.main_header_layout.setMaximumSize(QtCore.QSize(1024, 80)) + self.main_header_layout.setSizeIncrement(QtCore.QSize(1, 1)) + self.main_header_layout.setBaseSize(QtCore.QSize(800, 60)) + font = QtGui.QFont() + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + self.main_header_layout.setFont(font) + self.main_header_layout.setCursor( + QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) + ) + self.main_header_layout.setLayoutDirection( + QtCore.Qt.LayoutDirection.LeftToRight + ) + self.main_header_layout.setStyleSheet( + "QWidget {\n" + " background-color: rgb(50,50,50);\n" + " color:rgb(255,255,255);\n" + " border-color : rgb(60,60,60);\n" + " selection-background-color: rgb(60,60,60);\n" + " gridline-color:rgb(60,60,60);\n" + " selection-color:rgb(60,60,60);\n" + "}\n" + "\n" + "QGroupBox{\n" + " background-color: rgb(50,50,50);\n" + " border: none; \n" + " border-color : rgb(60,60,60);\n" + " selection-background-color: rgb(60,60,60);\n" + " gridline-color:rgb(60,60,60);\n" + " selection-color:rgb(60,60,60);\n" + " \n" + "}\n" + "\n" + "QFrame > *{\n" + " background-color: rgb(50, 50, 50);\n" + " selection-background-color: rgb(60, 60, 60);\n" + " gridline-color: rgb(60, 60, 60);\n" + " color: rgb(255, 255, 255); \n" + " selection-color: rgb(60, 60, 60);\n" + " border-bottom-color: rgb(60, 60, 60);\n" + " \n" + "}\n" + "\n" + "\n" + "QPushButton:pressed{\n" + " border: none;\n" + " background: transparent;\n" + "}" + ) + self.main_header_layout.setTitle("") + self.main_header_layout.setAlignment( + QtCore.Qt.AlignmentFlag.AlignJustify | QtCore.Qt.AlignmentFlag.AlignVCenter + ) + self.main_header_layout.setFlat(True) + self.main_header_layout.setCheckable(False) + self.main_header_layout.setObjectName("main_header_layout") + self.header_main_layout = QtWidgets.QHBoxLayout(self.main_header_layout) + self.header_main_layout.setSizeConstraint( + QtWidgets.QLayout.SizeConstraint.SetMinimumSize + ) + self.header_main_layout.setContentsMargins(5, 0, 5, 0) + self.header_main_layout.setSpacing(10) + self.header_main_layout.setObjectName("header_main_layout") + self.notification_btn = IconButton(parent=self.main_header_layout) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth( + self.notification_btn.sizePolicy().hasHeightForWidth() + ) + self.notification_btn.setSizePolicy(sizePolicy) + self.notification_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.notification_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.notification_btn.setText("") + self.notification_btn.setIconSize(QtCore.QSize(60, 60)) + self.notification_btn.setFlat(True) + self.notification_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg") + ) + self.notification_btn.setObjectName("notification_btn") + self.header_main_layout.addWidget( + self.notification_btn, 0, QtCore.Qt.AlignmentFlag.AlignLeft + ) + self.extruder_temp_display = DisplayButton(parent=self.main_header_layout) + self.extruder_temp_display.setMinimumSize(QtCore.QSize(140, 60)) + self.extruder_temp_display.setMaximumSize(QtCore.QSize(160, 60)) + self.extruder_temp_display.setFlat(True) + self.extruder_temp_display.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle_topbar.svg"), + ) + self.extruder_temp_display.setObjectName("extruder_temp_display") + self.header_main_layout.addWidget( + self.extruder_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.bed_temp_display = DisplayButton(parent=self.main_header_layout) + self.bed_temp_display.setMinimumSize(QtCore.QSize(140, 60)) + self.bed_temp_display.setMaximumSize(QtCore.QSize(160, 60)) + self.bed_temp_display.setFlat(True) + self.bed_temp_display.setProperty( + "icon_pixmap", + QtGui.QPixmap( + ":/temperature_related/media/btn_icons/temperature_plate.svg" + ), + ) + self.bed_temp_display.setObjectName("bed_temp_display") + self.header_main_layout.addWidget( + self.bed_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.chamber_temp_display = DisplayButton(parent=self.main_header_layout) + self.chamber_temp_display.setMinimumSize(QtCore.QSize(140, 60)) + self.chamber_temp_display.setMaximumSize(QtCore.QSize(160, 60)) + self.chamber_temp_display.setFlat(True) + self.chamber_temp_display.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/top_bar_icons/media/topbar/chamber_temp_topbar.svg"), + ) + self.chamber_temp_display.setProperty( + "secondary_pixmap", + QtGui.QPixmap(":/temperature_related/media/btn_icons/humidity.svg"), + ) + self.chamber_temp_display.setObjectName("chamber_temp_display") + self.header_main_layout.addWidget( + self.chamber_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.filament_type_icon = IconButton(parent=self.main_header_layout) + self.filament_type_icon.setMinimumSize(QtCore.QSize(60, 60)) + self.filament_type_icon.setMaximumSize(QtCore.QSize(60, 60)) + self.filament_type_icon.setFlat(True) + self.filament_type_icon.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/filament_related/media/btn_icons/load_filament.svg"), + ) + self.filament_type_icon.setObjectName("filament_type_icon") + self.header_main_layout.addWidget( + self.filament_type_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.nozzle_size_icon = IconButton(parent=self.main_header_layout) + self.nozzle_size_icon.setMinimumSize(QtCore.QSize(60, 60)) + self.nozzle_size_icon.setMaximumSize(QtCore.QSize(60, 60)) + self.nozzle_size_icon.setFlat(True) + self.nozzle_size_icon.setProperty( + "icon_pixmap", + QtGui.QPixmap( + ":/temperature_related/media/btn_icons/standart_temperature.svg" + ), + ) + self.nozzle_size_icon.setObjectName("nozzle_size_icon") + self.header_main_layout.addWidget( + self.nozzle_size_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.wifi_button = IconButton(parent=self.main_header_layout) + self.wifi_button.setEnabled(True) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.wifi_button.sizePolicy().hasHeightForWidth()) + self.wifi_button.setSizePolicy(sizePolicy) + self.wifi_button.setMinimumSize(QtCore.QSize(60, 60)) + self.wifi_button.setMaximumSize(QtCore.QSize(60, 60)) + self.wifi_button.setStyleSheet("") + self.wifi_button.setText("") + self.wifi_button.setIconSize(QtCore.QSize(16, 16)) + self.wifi_button.setCheckable(False) + self.wifi_button.setChecked(False) + self.wifi_button.setFlat(True) + self.wifi_button.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/network/media/btn_icons/network/3bar_wifi.svg"), + ) + self.wifi_button.setObjectName("wifi_button") + self.header_main_layout.addWidget( + self.wifi_button, + 0, + QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignTop, + ) + self.header_main_layout.setStretch(1, 1) + self.header_main_layout.setStretch(2, 1) + self.header_main_layout.setStretch(3, 1) + self.setCentralWidget(self.main_widget) + + _translate = QtCore.QCoreApplication.translate + self.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.notification_btn.setProperty( + "button_type", _translate("MainWindow", "icon_text") + ) + self.extruder_temp_display.setText(_translate("MainWindow", "extruder")) + self.extruder_temp_display.setProperty( + "button_type", _translate("MainWindow", "secondary_display") + ) + self.extruder_temp_display.setProperty( + "name", _translate("MainWindow", "extruder_temperature_display") + ) + self.bed_temp_display.setText(_translate("MainWindow", "bed")) + self.bed_temp_display.setProperty( + "button_type", _translate("MainWindow", "secondary_display") + ) + self.chamber_temp_display.setText(_translate("MainWindow", "chamber")) + self.chamber_temp_display.setProperty( + "display_format", _translate("MainWindow", "dual") + ) + self.chamber_temp_display.setProperty( + "button_type", _translate("MainWindow", "display_secondary") + ) + self.filament_type_icon.setText(_translate("MainWindow", "Filament")) + self.filament_type_icon.setProperty( + "button_type", _translate("MainWindow", "icon_text") + ) + self.nozzle_size_icon.setText(_translate("MainWindow", "nozzle")) + self.nozzle_size_icon.setProperty( + "button_type", _translate("MainWindow", "icon_text") + ) + self.wifi_button.setProperty("button_type", _translate("MainWindow", "icon")) + self.main_content_widget.setCurrentIndex(3) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py new file mode 100644 index 000000000..dd33b52e9 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -0,0 +1,273 @@ +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.blocks_label import BlocksLabel +from PyQt6 import QtCore, QtGui, QtWidgets +import typing + +from lib.moonrakerComm import MoonWebSocket + + +class CancelPage(QtWidgets.QWidget): + """Update GUI Page, + retrieves from moonraker available clients and adds functionality + for updating or recovering them + """ + + request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="request_file_info" + ) + reprint_start: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="reprint_start" + ) + run_gcode: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run_gcode" + ) + + def __init__(self, parent: QtWidgets.QWidget, ws: MoonWebSocket) -> None: + super().__init__(parent) + self.ws: MoonWebSocket = ws + self._setupUI() + self.filename = "" + + self.confirm_button.clicked.connect(lambda: self._handle_accept()) + + self.refuse_button.clicked.connect(lambda: self._handle_refuse()) + + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) + + def _handle_accept(self): + self.run_gcode.emit("SDCARD_RESET_FILE") + self.reprint_start.emit(self.filename) + self.close() + + def _handle_refuse(self): + self.close() + self.run_gcode.emit("SDCARD_RESET_FILE") + + _REASON_HEADERS: typing.ClassVar[dict[str, str]] = { + "complete": "Print Completed", + "error": "Print Error", + "cancelled": "Print job was\ncancelled", + } + + @QtCore.pyqtSlot(str, dict, name="on_print_stats_update") + @QtCore.pyqtSlot(str, float, name="on_print_stats_update") + @QtCore.pyqtSlot(str, str, name="on_print_stats_update") + def on_print_stats_update(self, field: str, value: dict | float | str) -> None: + if isinstance(value, str): + if "filename" in field: + self.filename = value + if self.isVisible: + self.set_file_name(value) + elif "state" in field and value in self._REASON_HEADERS: + self.cf_info_tf.setText(self._REASON_HEADERS[value]) + + def show(self): + self.request_file_info.emit(self.filename) + + super().show() + + def set_pixmap(self, pixmap: QtGui.QPixmap) -> None: + if not hasattr(self, "_scene"): + self._scene = QtWidgets.QGraphicsScene(self) + self.cf_thumbnail.setScene(self._scene) + + # Scene rectangle (available display area) + graphics_rect = self.cf_thumbnail.rect().toRectF() + + # Scale pixmap preserving aspect ratio + pixmap = pixmap.scaled( + graphics_rect.size().toSize(), + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + QtCore.Qt.TransformationMode.SmoothTransformation, + ) + + adjusted_x = (graphics_rect.width() - pixmap.width()) / 2.0 + adjusted_y = (graphics_rect.height() - pixmap.height()) / 2.0 + + if not hasattr(self, "_pixmap_item"): + self._pixmap_item = QtWidgets.QGraphicsPixmapItem(pixmap) + self._scene.addItem(self._pixmap_item) + else: + self._pixmap_item.setPixmap(pixmap) + + self._pixmap_item.setPos(adjusted_x, adjusted_y) + self._scene.setSceneRect(graphics_rect) + + def set_file_name(self, file_name: str) -> None: + self.cf_file_name.setText(file_name) + + def _show_screen_thumbnail(self, dict): + try: + thumbnails = dict["thumbnail_images"] + + last_thumb = QtGui.QPixmap.fromImage(thumbnails[-1]) + + if last_thumb.isNull(): + last_thumb = QtGui.QPixmap( + "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" + ) + except Exception as e: + print(e) + last_thumb = QtGui.QPixmap( + "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" + ) + self.set_pixmap(last_thumb) + + def _setupUI(self) -> None: + """Setup widget ui""" + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + self.setSizePolicy(sizePolicy) + self.setObjectName("cancelPage") + self.setStyleSheet( + """#cancelPage { + background-image: url(:/background/media/1st_background.png); + }""" + ) + self.setMinimumSize(QtCore.QSize(800, 480)) + self.setMaximumSize(QtCore.QSize(800, 480)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.cf_header_title = QtWidgets.QHBoxLayout() + self.cf_header_title.setObjectName("cf_header_title") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.cf_file_name = BlocksLabel(parent=self) + self.cf_file_name.setMinimumSize(QtCore.QSize(0, 60)) + self.cf_file_name.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.cf_file_name.setFont(font) + self.cf_file_name.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.cf_file_name.setSizePolicy(sizePolicy) + self.cf_file_name.setStyleSheet("background: transparent; color: white;") + self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_file_name.setObjectName("cf_file_name") + self.cf_header_title.addWidget(self.cf_file_name) + + self.verticalLayout_4.addLayout(self.cf_header_title) + self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() + self.cf_content_vertical_layout.setObjectName("cf_content_vertical_layout") + self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() + self.cf_content_horizontal_layout.setObjectName("cf_content_horizontal_layout") + self.info_frame = BlocksCustomFrame(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.info_frame.setSizePolicy(sizePolicy) + + self.info_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + + self.info_layout = QtWidgets.QVBoxLayout(self.info_frame) + + self.cf_info_tf = QtWidgets.QLabel(parent=self.info_frame) + self.cf_info_tf.setText("Print job was\ncancelled") + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + + self.cf_info_tf.setFont(font) + self.cf_info_tf.setStyleSheet("background: transparent; color: white;") + + self.cf_info_tf.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_layout.addWidget(self.cf_info_tf) + + self.cf_info_tr = QtWidgets.QLabel(parent=self.info_frame) + font = QtGui.QFont() + font.setPointSize(15) + self.cf_info_tr.setFont(font) + self.cf_info_tr.setStyleSheet("background: transparent; color: white;") + self.cf_info_tr.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_info_tr.setText("Do you want to reprint?") + self.info_layout.addWidget(self.cf_info_tr) + + self.cf_confirm_layout = QtWidgets.QVBoxLayout() + self.cf_confirm_layout.setSpacing(15) + + self.confirm_button = BlocksCustomButton(parent=self.info_frame) + self.confirm_button.setMinimumSize(QtCore.QSize(250, 70)) + self.confirm_button.setMaximumSize(QtCore.QSize(250, 70)) + font = QtGui.QFont("Momcake", 18) + self.confirm_button.setFont(font) + self.confirm_button.setFlat(True) + self.confirm_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") + ) + self.confirm_button.setText("Reprint") + # 2. Align buttons to the right + self.cf_confirm_layout.addWidget( + self.confirm_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.refuse_button = BlocksCustomButton(parent=self.info_frame) + self.refuse_button.setMinimumSize(QtCore.QSize(250, 70)) + self.refuse_button.setMaximumSize(QtCore.QSize(250, 70)) + self.refuse_button.setFont(font) + self.refuse_button.setFlat(True) + self.refuse_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") + ) + self.refuse_button.setText("Ignore") + # 2. Align buttons to the right + self.cf_confirm_layout.addWidget( + self.refuse_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.info_layout.addLayout(self.cf_confirm_layout) + + self.cf_content_horizontal_layout.addWidget(self.info_frame) + + self.cf_content_vertical_layout.addLayout(self.cf_content_horizontal_layout) + self.cf_thumbnail = QtWidgets.QGraphicsView(self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.cf_thumbnail.sizePolicy().hasHeightForWidth()) + self.cf_thumbnail.setSizePolicy(sizePolicy) + self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setStyleSheet( + "QGraphicsView{\nbackground-color: transparent;\n}" + ) + self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) + self.cf_thumbnail.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setSizeAdjustPolicy( + QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored + ) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + self.cf_thumbnail.setBackgroundBrush(brush) + self.cf_thumbnail.setRenderHints( + QtGui.QPainter.RenderHint.Antialiasing + | QtGui.QPainter.RenderHint.SmoothPixmapTransform + | QtGui.QPainter.RenderHint.TextAntialiasing + ) + self.cf_thumbnail.setViewportUpdateMode( + QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate + ) + self.cf_thumbnail.setObjectName("cf_thumbnail") + self.cf_content_vertical_layout.addWidget( + self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py new file mode 100644 index 000000000..5921446e8 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py @@ -0,0 +1,555 @@ +import enum +import logging +import re +import typing + +from events import KlippyDisconnected, KlippyReady +from lib.moonrakerComm import MoonWebSocket +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + +logger = logging.getLogger(__name__) + + +class ConnectionState(enum.StrEnum): + DISCONNECTED = "disconnected" + CONNECTING = "connecting" + WEBSOCKET_LOST = "websocket_lost" + MOONRAKER_CONNECTED = "moonraker_connected" + KLIPPER_STARTUP = "klipper_startup" + KLIPPER_READY = "klipper_ready" + KLIPPER_DISCONNECTED = "klipper_disconnected" + KLIPPER_ERROR = "klipper_error" + KLIPPER_SHUTDOWN = "klipper_shutdown" + + +class ConnectionPage(QtWidgets.QFrame): + _SHUTDOWN_FALLBACK_CONTEXT: typing.Final[str] = ( + "Press 'Firmware Restart' to recover." + ) + + _MESSAGES: typing.ClassVar[dict[ConnectionState, str]] = { + ConnectionState.DISCONNECTED: "The printer is offline.\nReconnecting automatically…", + ConnectionState.CONNECTING: "Connecting to the printer\nAttempt {n}", + ConnectionState.WEBSOCKET_LOST: "Connection interrupted.\nAttempting to reconnect…", + ConnectionState.MOONRAKER_CONNECTED: "Connection established.\nWaiting for the printer to initialise…", + ConnectionState.KLIPPER_STARTUP: "The printer is starting up.\nPlease wait…", + ConnectionState.KLIPPER_READY: "The printer is ready.", + ConnectionState.KLIPPER_DISCONNECTED: "The printer is not responding.\nPress 'Restart Printer' to reconnect.", + ConnectionState.KLIPPER_ERROR: "A printer error has occurred.\nPress 'Firmware Restart' to recover.", + ConnectionState.KLIPPER_SHUTDOWN: "The printer has shut down.\n{message}", + } + + _AUTO_RECOVER_CONTEXTS: typing.ClassVar[frozenset[str]] = frozenset( + { + "m112 command", + "printers emergency button pressed", + "printer emergency button pressed", + } + ) + + _SHUTDOWN_REASON_MAP: typing.ClassVar[dict[str, str]] = { + "m112 command": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", + "printers emergency button pressed": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", + "printer emergency button pressed": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", + "webhooks request": "Emergency stop activated.", + "lost communication with mcu": "Lost communication with the MCU.", + "timer too close": "MCU overload\nCommunication timing failure.\nPress 'Firmware Restart' to recover.", + "adc out of range": "Temperature sensor fault.", + "no next step": "Communication failure with the MCU.", + "rescheduled timer in the past": "Motion rate exceeded\nReduce speed or acceleration.\nPress 'Firmware Restart' to recover.", + "stepper too far in past": "Stepper timing failure\nReduce speed or acceleration.\nPress 'Firmware Restart' to recover.", + "communication timeout during homing": "Communication timeout during homing.", + "protocol error": "MCU communication protocol error.", + "config error": "Configuration error\nCheck printer.cfg.\nPress 'Firmware Restart' to recover.", + "mcu error during connect": "Failed to connect to the MCU.", + } + + _FIRMWARE_RESTART_STATES: typing.ClassVar[frozenset[ConnectionState]] = frozenset( + { + ConnectionState.KLIPPER_ERROR, + ConnectionState.KLIPPER_SHUTDOWN, + } + ) + + _SHUTDOWN_NOISE: typing.ClassVar[frozenset[str]] = frozenset( + {"forced shutdown command", "forced shutdown", "shutdown", "none", ""} + ) + + _RESTART_LABELS: typing.ClassVar[dict[ConnectionState, str]] = { + ConnectionState.KLIPPER_ERROR: "Firmware Restart", + ConnectionState.KLIPPER_SHUTDOWN: "Firmware Restart", + ConnectionState.WEBSOCKET_LOST: "Retry Connection", + } + + _KLIPPY_STATE_MAP: typing.ClassVar[dict[str, ConnectionState]] = { + "error": ConnectionState.KLIPPER_ERROR, + "disconnected": ConnectionState.KLIPPER_DISCONNECTED, + "shutdown": ConnectionState.KLIPPER_SHUTDOWN, + "startup": ConnectionState.KLIPPER_STARTUP, + "ready": ConnectionState.KLIPPER_READY, + } + + retry_connection_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="retry_connection_clicked" + ) + wifi_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="call_network_page" + ) + reboot_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="reboot_clicked" + ) + restart_klipper_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="restart_klipper_clicked" + ) + firmware_restart_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="firmware_restart_clicked" + ) + update_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="show-update-page" + ) + notification_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="notification_button_clicked" + ) + call_load_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, str, bool, name="call-load-panel" + ) + call_cancel_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="call-cancel-panel" + ) + + def __init__(self, parent: QtWidgets.QWidget, ws: MoonWebSocket, /) -> None: + super().__init__(parent) + self.ws = ws + self._setupUI() + + self._state: ConnectionState = ConnectionState.DISCONNECTED + self.base_text: str = "" + self.dot_count: int = 0 + self.conn_toggle: bool = True + self._shutdown_confirmed: bool = ( + False # prevents fallback from overwriting shutdown reason + ) + self._last_shutdown_context: str = "" + self._firmware_restarting_pending: bool = False + self._last_restart_was_firmware: bool = False + self._escalated_to_klipper_restart: bool = False + + self.dot_timer = QtCore.QTimer(self) + self.dot_timer.setInterval(1000) + self.dot_timer.timeout.connect(self._add_dot) + + self._restart_10s_timer = QtCore.QTimer(self) + self._restart_10s_timer.setSingleShot(True) + self._restart_10s_timer.setInterval(10_000) + self._restart_10s_timer.timeout.connect(self._on_restart_10s_elapsed) + + self._restart_30s_timer = QtCore.QTimer(self) + self._restart_30s_timer.setSingleShot(True) + self._restart_30s_timer.setInterval(30_000) + self._restart_30s_timer.timeout.connect(self._on_restart_30s_elapsed) + + self.restart_klipper_button.clicked.connect(self._on_restart_clicked) + self.reboot_system_button.clicked.connect(self.reboot_clicked.emit) + self.notification_button.clicked.connect(self.notification_button_clicked.emit) + self.update_page_button.clicked.connect(self._on_update_page_clicked) + self.wifi_button.clicked.connect(self.wifi_button_clicked.emit) + + @property + def manual_restart_pending(self) -> bool: + """True while a user-initiated restart (firmware or printer) is in flight.""" + return self._firmware_restarting_pending + + def _apply_shutdown_guard(self, state: ConnectionState, context: str) -> bool: + if ( + self._state == ConnectionState.KLIPPER_SHUTDOWN + and state != ConnectionState.KLIPPER_SHUTDOWN + ): + self._shutdown_confirmed = False + elif state == ConnectionState.KLIPPER_SHUTDOWN: + _is_real = context and context != ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT + if _is_real: + self._shutdown_confirmed = True + self._last_shutdown_context = context + elif self._shutdown_confirmed or ( + self._state == ConnectionState.KLIPPER_SHUTDOWN and not context + ): + return False + return True + + def _handle_pending_restart(self, state: ConnectionState) -> bool: + if self._firmware_restarting_pending and state in ( + ConnectionState.KLIPPER_SHUTDOWN, + ConnectionState.KLIPPER_ERROR, + ConnectionState.WEBSOCKET_LOST, + ): + self._stop_restart_overlay() + return state == ConnectionState.KLIPPER_DISCONNECTED and ( + self._firmware_restarting_pending + or self._state == ConnectionState.KLIPPER_SHUTDOWN + ) + + def _set_state(self, state: ConnectionState, context: str = "") -> None: + """Update connection state and refresh the UI accordingly.""" + if state == ConnectionState.KLIPPER_SHUTDOWN and not context: + context = ( + self._last_shutdown_context or ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT + ) + if not self._apply_shutdown_guard(state, context): + return + if self._handle_pending_restart(state): + return + self.dot_timer.stop() + self._state = state + message = self._MESSAGES[state].format(n=context, message=context) + self.status_label.setText(message) + if state == ConnectionState.CONNECTING: + self.base_text = message + self.dot_count = 0 + self.dot_timer.start() + elif state == ConnectionState.KLIPPER_READY: + self._stop_restart_overlay() + self._last_shutdown_context = "" + self.hide() + return + if not self.isVisible() and self.conn_toggle: + self.show() + self._update_restart_label(state) + + def _stop_restart_overlay(self) -> None: + self._firmware_restarting_pending = False + self._restart_10s_timer.stop() + self._restart_30s_timer.stop() + self.call_load_panel.emit(False, "", False) + + def _add_dot(self) -> None: + self.dot_count += 1 + if self.dot_count > 3: + self.dot_count = 0 + dots = "." * self.dot_count + self.status_label.setText(f"{self.base_text}{dots}") + + def _update_restart_label(self, state: ConnectionState) -> None: + """Set restart_klipper_button label based on current state.""" + self.restart_klipper_button.setText( + self._RESTART_LABELS.get(state, "Restart Printer") + ) + + @staticmethod + def _strip_shutdown_prefix(raw: str) -> str: + return re.sub( + r"^(?:Shutdown due to |MCU '[^']*' shutdown[:.]\s*)", + "", + raw.split("\n")[0].strip(), + ) + + @staticmethod + def _normalize_shutdown_lines(raw: str) -> str: + line = ConnectionPage._strip_shutdown_prefix(raw) + return line.lower().replace("'", "").replace("’", "") + + @staticmethod + def _clean_shutdown_context(raw: str) -> str: + line = ConnectionPage._strip_shutdown_prefix(raw) + lower = ConnectionPage._normalize_shutdown_lines(line) + if lower in ConnectionPage._SHUTDOWN_NOISE: + return "" + for key, display in ConnectionPage._SHUTDOWN_REASON_MAP.items(): + if lower.startswith(key): + return display + return line.capitalize() + + @staticmethod + def _build_shutdown_context(raw: str) -> str: + reason = ConnectionPage._clean_shutdown_context(raw) + if not reason: + return ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT + if "\n" in reason: + return reason + return f"{reason}\nPress 'Firmware Restart' to recover." + + @staticmethod + def _is_auto_recovering_context(raw: str) -> bool: + lower = ConnectionPage._normalize_shutdown_lines(raw) + return any( + lower.startswith(key) for key in ConnectionPage._AUTO_RECOVER_CONTEXTS + ) + + def _on_restart_clicked(self) -> None: + if self._state == ConnectionState.WEBSOCKET_LOST: + self.retry_connection_clicked.emit() + return + is_firmware = self._state in self._FIRMWARE_RESTART_STATES + self._last_restart_was_firmware = is_firmware + self._escalated_to_klipper_restart = False + self._firmware_restarting_pending = True + self.call_load_panel.emit( + True, + "Restarting firmware…" if is_firmware else "Restarting printer…", + False, + ) + self._restart_10s_timer.start() + self._restart_30s_timer.start() + if is_firmware: + self.firmware_restart_clicked.emit() + else: + self.restart_klipper_clicked.emit() + + def _on_restart_10s_elapsed(self) -> None: + self.call_load_panel.emit(True, "Still restarting, please wait…", False) + + def _on_restart_30s_elapsed(self) -> None: + if self._last_restart_was_firmware and not self._escalated_to_klipper_restart: + self._escalated_to_klipper_restart = True + self.call_load_panel.emit(True, "Restarting printer...", False) + self.restart_klipper_clicked.emit() + self._restart_30s_timer.start() + return + self._stop_restart_overlay() + + def _on_update_page_clicked(self) -> None: + self.update_button_clicked.emit(True) + + @QtCore.pyqtSlot(bool, name="toggle_connection_page") + def set_toggle(self, toggle: bool) -> None: + """Enable or disable auto-show behaviour.""" + self.conn_toggle = toggle + + @QtCore.pyqtSlot(str, name="on_klippy_state") + def on_klippy_state(self, state: str) -> None: + """Handle Klipper state string changes.""" + if (mapped := self._KLIPPY_STATE_MAP.get(state)) is not None: + self._set_state(mapped) + else: + logger.warning("Unknown Klipper state: %s", state) + + @QtCore.pyqtSlot(int, name="on_websocket_connecting") + def on_websocket_connecting(self, attempt: int) -> None: + """Handle websocket reconnection attempts.""" + self._set_state(ConnectionState.CONNECTING, context=str(attempt)) + + @QtCore.pyqtSlot(name="on_websocket_connection_achieved") + def on_websocket_connection_achieved(self) -> None: + """Handle websocket connection established.""" + self._set_state(ConnectionState.MOONRAKER_CONNECTED) + + @QtCore.pyqtSlot(name="on_websocket_connection_lost") + def on_websocket_connection_lost(self) -> None: + """Handle websocket connection lost.""" + self._set_state(ConnectionState.WEBSOCKET_LOST) + + @QtCore.pyqtSlot(str, str, name="webhooks_update") + def webhook_update(self, state: str, message: str) -> None: + """Handle Moonraker websocket state updates.""" + if state == "shutdown": + should_auto_recover = ( + self._state != ConnectionState.KLIPPER_SHUTDOWN + and not self._firmware_restarting_pending + and self._is_auto_recovering_context(message) + ) + self._set_state( + ConnectionState.KLIPPER_SHUTDOWN, + context=self._build_shutdown_context(message), + ) + if should_auto_recover: + self._last_restart_was_firmware = True + self._escalated_to_klipper_restart = False + self._firmware_restarting_pending = True + self._restart_10s_timer.start() + self._restart_30s_timer.start() + + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: # noqa: N802 + if self.conn_toggle: + self.ws.api.refresh_update_status() + self.call_load_panel.emit(False, "", False) + self.call_cancel_panel.emit(False) + super().showEvent(a0) + + def eventFilter(self, a0: QtCore.QObject | None, a1: QtCore.QEvent | None) -> bool: # noqa: N802 + """Route Klipper custom events to _set_state""" + if a1 is None: + return super().eventFilter(a0, a1) + if a1.type() == KlippyDisconnected.type(): + if not self._firmware_restarting_pending: + self._set_state(ConnectionState.KLIPPER_DISCONNECTED) + elif a1.type() == KlippyReady.type(): + self._set_state(ConnectionState.KLIPPER_READY) + return super().eventFilter(a0, a1) + + def _setupUI(self) -> None: + self.setMinimumSize(QtCore.QSize(800, 480)) + self.setMaximumSize(QtCore.QSize(800, 480)) + self.setObjectName("ConnectionPage") + self.setStyleSheet( + "#ConnectionPage{background-image: url(:/background/media/1st_background.png);}" + ) + self.button_frame = BlocksCustomFrame(parent=self) + self.button_frame.setGeometry(QtCore.QRect(10, 365, 780, 140)) + self.button_frame.setMinimumSize(QtCore.QSize(780, 140)) + self.button_frame.setMaximumSize(QtCore.QSize(780, 160)) + self.button_frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.button_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) + self.button_frame.setLineWidth(0) + self.button_frame.setObjectName("button_frame") + + self.button_layout = QtWidgets.QHBoxLayout(self.button_frame) + self.button_layout.setContentsMargins(0, 5, 0, 0) + self.button_layout.setSpacing(0) + self.button_layout.setObjectName("button_layout") + + _btn_policy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.Fixed, + ) + + self.reboot_system_button = IconButton(parent=self.button_frame) + self.reboot_system_button.setSizePolicy(_btn_policy) + self.reboot_system_button.setMinimumSize(QtCore.QSize(115, 92)) + self.reboot_system_button.setMaximumSize(QtCore.QSize(115, 92)) + self.reboot_system_button.setCursor( + QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) + ) + self.reboot_system_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.reboot_system_button.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.NoContextMenu + ) + self.reboot_system_button.setFlat(True) + self.reboot_system_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/system/media/btn_icons/reboot.svg") + ) + self.reboot_system_button.setProperty("has_text", True) + self.reboot_system_button.setProperty("text_formatting", "bottom") + self.reboot_system_button.setText("Reboot") + self.reboot_system_button.setObjectName("reboot_system_button") + self.button_layout.addWidget( + self.reboot_system_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, + ) + + self.restart_klipper_button = IconButton(parent=self.button_frame) + self.restart_klipper_button.setSizePolicy(_btn_policy) + self.restart_klipper_button.setMinimumSize(QtCore.QSize(115, 92)) + self.restart_klipper_button.setMaximumSize(QtCore.QSize(115, 92)) + self.restart_klipper_button.setCursor( + QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) + ) + self.restart_klipper_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.restart_klipper_button.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.NoContextMenu + ) + self.restart_klipper_button.setFlat(True) + self.restart_klipper_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/system/media/btn_icons/restart_klipper.svg") + ) + self.restart_klipper_button.setProperty("has_text", True) + self.restart_klipper_button.setProperty("text_formatting", "bottom") + self.restart_klipper_button.setText("Restart Printer") + self.restart_klipper_button.setObjectName("restart_klipper_button") + self.button_layout.addWidget( + self.restart_klipper_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, + ) + + self.notification_button = IconButton(parent=self.button_frame) + self.notification_button.setSizePolicy(_btn_policy) + self.notification_button.setMinimumSize(QtCore.QSize(115, 92)) + self.notification_button.setMaximumSize(QtCore.QSize(115, 92)) + self.notification_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.notification_button.setFlat(True) + self.notification_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg") + ) + self.notification_button.setProperty("has_text", True) + self.notification_button.setProperty("text_formatting", "bottom") + self.notification_button.setText("Notifications") + self.notification_button.setObjectName("notification_button") + self.button_layout.addWidget( + self.notification_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, + ) + + self.update_page_button = IconButton(parent=self.button_frame) + self.update_page_button.setSizePolicy(_btn_policy) + self.update_page_button.setMinimumSize(QtCore.QSize(115, 92)) + self.update_page_button.setMaximumSize(QtCore.QSize(115, 92)) + self.update_page_button.setCursor( + QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) + ) + self.update_page_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.update_page_button.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.NoContextMenu + ) + self.update_page_button.setFlat(True) + self.update_page_button.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg"), + ) + self.update_page_button.setProperty("has_text", True) + self.update_page_button.setProperty("text_formatting", "bottom") + self.update_page_button.setText("Updates") + self.update_page_button.setObjectName("update_page_button") + self.button_layout.addWidget( + self.update_page_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, + ) + + self.wifi_button = IconButton(parent=self.button_frame) + self.wifi_button.setSizePolicy(_btn_policy) + self.wifi_button.setMinimumSize(QtCore.QSize(115, 92)) + self.wifi_button.setMaximumSize(QtCore.QSize(115, 92)) + self.wifi_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.wifi_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) + self.wifi_button.setFlat(True) + self.wifi_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/wifi_config.svg") + ) + self.wifi_button.setProperty("has_text", True) + self.wifi_button.setProperty("text_formatting", "bottom") + self.wifi_button.setProperty("class", "system_control_btn") + self.wifi_button.setText("Wi-Fi Settings") + self.wifi_button.setObjectName("wifi_button") + self.button_layout.addWidget( + self.wifi_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, + ) + + self.content_frame = QtWidgets.QFrame(parent=self) + self.content_frame.setGeometry(QtCore.QRect(0, 0, 800, 365)) + self.content_frame.setMinimumSize(QtCore.QSize(800, 365)) + self.content_frame.setMaximumSize(QtCore.QSize(800, 365)) + self.content_frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.content_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.content_frame.setObjectName("content_frame") + + self.content_layout = QtWidgets.QVBoxLayout(self.content_frame) + self.content_layout.setObjectName("content_layout") + + spacerItem = QtWidgets.QSpacerItem( + 775, + 70, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.content_layout.addItem(spacerItem) + + self.status_label = QtWidgets.QLabel(parent=self.content_frame) + self.status_label.setMaximumSize(QtCore.QSize(800, 380)) + _font = QtGui.QFont() + _font.setFamily("Momcake") + _font.setPointSize(17) + + self.status_label.setFont(_font) + self.status_label.setStyleSheet("color:white") + self.status_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.status_label.setWordWrap(True) + self.status_label.setTextInteractionFlags( + QtCore.Qt.TextInteractionFlag.NoTextInteraction + ) + self.status_label.setObjectName("status_label") + self.content_layout.addWidget(self.status_label) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py new file mode 100644 index 000000000..d21de8b91 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py @@ -0,0 +1,407 @@ +from collections import deque +from typing import ClassVar + +from lib.panels.widgets.popupDialogWidget import Popup +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.icon_button import IconButton +from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem +from PyQt6 import QtCore, QtGui, QtWidgets + + +class NotificationPage(QtWidgets.QWidget): + """Update GUI Page, + retrieves from moonraker available clients and adds functionality + for updating or recovering them + """ + + on_update_message: ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + dict, name="on-update-message" + ) + + def __init__(self, parent=None) -> None: + super().__init__(parent) + self._ICON_INFO = QtGui.QPixmap(":/ui/media/btn_icons/info.svg") + self._ICON_WARN = QtGui.QPixmap(":/ui/media/btn_icons/troubleshoot.svg") + self._ICON_ERROR = QtGui.QPixmap(":/ui/media/btn_icons/error.svg") + self._setupUI() + self.cli_tracking: deque = deque() + self.selected_item: ListItem | None = None + self.popup = Popup(self) + + self.model = EntryListModel() + self.model.setParent(self.update_buttons_list_widget) + self.entry_delegate = EntryDelegate() + self.update_buttons_list_widget.setModel(self.model) + self.update_buttons_list_widget.setItemDelegate(self.entry_delegate) + self.entry_delegate.item_selected.connect(self.on_item_clicked) + + self.update_back_btn.clicked.connect(self.hide) + self.delete_btn.clicked.connect(self.delete_selected_item) + self.delete_all_btn.clicked.connect(self.reset_view_model) + + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) + self.hide() + + @QtCore.pyqtSlot(name="call-notification-panel") + def show_notification_panel( + self, + ) -> None: + """Slot for displaying notification Panel""" + if not self.parent(): + return + _parent_size = self.parent().size() # type: ignore + self.setGeometry(0, 0, _parent_size.width(), _parent_size.height()) + self.updateGeometry() + self.update() + self.show() + self.raise_() + + def delete_selected_item(self) -> None: + """Deletes currently selected item from the list view""" + if self.selected_item is None: + return + self.model.remove_item(self.selected_item) + self.delete_btn.setEnabled(False) + self.selected_item = None + + def reset_view_model(self) -> None: + """Clears items from ListView + (Resets `QAbstractListModel` by clearing entries) + """ + self.model.clear() + self.entry_delegate.clear() + + def build_model_list(self) -> None: + """Builds the model list (`self.model`) containing updatable clients""" + self.update_buttons_list_widget.blockSignals(True) + try: + message, _, priority = self.cli_tracking.popleft() + match priority: + case 1: + self._add_notif_entry(message, "#1A8FBF", self._ICON_INFO) + case 2: + self._add_notif_entry(message, "#E7E147", self._ICON_WARN) + case 3: + self._add_notif_entry(message, "#CA4949", self._ICON_ERROR) + case _: + self._add_notif_entry(message, "#a4a4a4", self._ICON_INFO) + self.model.setData(self.model.index(0), True, EntryListModel.EnableRole) + finally: + self.update_buttons_list_widget.blockSignals(False) + + @QtCore.pyqtSlot(ListItem, name="on-item-clicked") + def on_item_clicked(self, item: ListItem) -> None: + """Setup information for the currently clicked list item on the info box. + Keeps track of the list item + """ + self.delete_btn.setEnabled(True) + + match item.color: + case "#1A8FBF": + self.type_label.setText("Info") + case "#E7E147": + self.type_label.setText("Warning") + case "#CA4949": + self.type_label.setText("Error") + case _: + self.type_label.setText("Unknown") + + self.time_label.setText(item._cache.get(-1, "N/A")) + self.selected_item = item + + @QtCore.pyqtSlot(str, str, int, bool, name="new-notication") + def new_notication( + self, + origin: str | None = None, + message: str = "", + priority: int = 0, + popup: bool = False, + ): + """ + :param message: sets notification message + :type message: str + :param priority: sets notification priority from 0 to 3 + :type priority: int + :param popup: sets if notification should appear as popup + :type popup: bool + """ + self.cli_tracking.append((message, origin, priority)) + self.model.delete_duplicates() + + if popup: + match priority: + case 3: + msg_type = Popup.MessageType.ERROR + case 2: + msg_type = Popup.MessageType.WARNING + case 1: + msg_type = Popup.MessageType.INFO + case _: + msg_type = Popup.MessageType.UNKNOWN + + self.popup.new_message(message_type=msg_type, message=message, timeout=3000) + + self.build_model_list() + + def _add_notif_entry( + self, + message: str, + color: str = "#dfdfdf", + right_icon: QtGui.QPixmap | None = None, + ) -> None: + """Adds a new item to the list model""" + item = ListItem( + text=message, + left_icon=right_icon, + selected=False, + _lfontsize=17, + _rfontsize=12, + color=color, + height=80, + allow_expand=True, + notificate=False, + color_left_icon=True, + ) + time = QtCore.QDateTime.currentDateTime().toString("hh:mm:ss") + item._cache[-1] = time + self.model.add_item(item) + + def _setupUI(self) -> None: + """Setup UI for updatePage""" + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + font = QtGui.QFont() + font.setPointSize(20) + self.setSizePolicy(sizePolicy) + self.setObjectName("updatePage") + self.setStyleSheet( + """#updatePage { + background-image: url(:/background/media/1st_background.png); + }""" + ) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.update_page_content_layout = QtWidgets.QVBoxLayout() + self.setMinimumSize(800, 480) + self.update_page_content_layout.setContentsMargins(15, 15, 15, 15) + + self.header_content_layout = QtWidgets.QHBoxLayout() + self.header_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) + self.spacer = QtWidgets.QSpacerItem( + 60, + 60, + QtWidgets.QSizePolicy.Policy.Fixed, + QtWidgets.QSizePolicy.Policy.Fixed, + ) + self.header_content_layout.addItem(self.spacer) + + self.header_title = QtWidgets.QLabel(self) + self.header_title.setMinimumSize(QtCore.QSize(100, 60)) + self.header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + palette = self.header_title.palette() + palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) + self.header_title.setFont(font) + font.setPointSize(15) + self.header_title.setPalette(palette) + self.header_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.header_title.setObjectName("header-title") + self.header_title.setText("Notification") + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.header_title.setSizePolicy(sizePolicy) + self.header_content_layout.addWidget( + self.header_title, alignment=QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.update_back_btn = IconButton(self) + self.update_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.update_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.update_back_btn.setFlat(True) + self.update_back_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.header_content_layout.addWidget( + self.update_back_btn + ) # alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.update_page_content_layout.addLayout(self.header_content_layout, 0) + + self.main_content_layout = QtWidgets.QHBoxLayout() + self.main_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + + self.update_buttons_frame = BlocksCustomFrame(self) + + self.update_buttons_frame.setMinimumSize(QtCore.QSize(500, 380)) + self.update_buttons_frame.setMaximumSize(QtCore.QSize(560, 500)) + + self.update_buttons_list_widget = QtWidgets.QListView(self.update_buttons_frame) + self.update_buttons_list_widget.setMouseTracking(True) + self.update_buttons_list_widget.setTabletTracking(True) + + self.update_buttons_list_widget.setPalette(palette) + self.update_buttons_list_widget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.update_buttons_list_widget.setStyleSheet("background-color:transparent") + self.update_buttons_list_widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.update_buttons_list_widget.setMinimumSize(self.update_buttons_frame.size()) + self.update_buttons_list_widget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.update_buttons_list_widget.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.update_buttons_list_widget.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.update_buttons_list_widget.setSizeAdjustPolicy( + QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents + ) + self.update_buttons_list_widget.setAutoScroll(False) + self.update_buttons_list_widget.setProperty("showDropIndicator", False) + self.update_buttons_list_widget.setDefaultDropAction( + QtCore.Qt.DropAction.IgnoreAction + ) + self.update_buttons_list_widget.setAlternatingRowColors(False) + self.update_buttons_list_widget.setSelectionMode( + QtWidgets.QAbstractItemView.SelectionMode.NoSelection + ) + self.update_buttons_list_widget.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems + ) + self.update_buttons_list_widget.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + ) + self.update_buttons_list_widget.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + ) + QtWidgets.QScroller.grabGesture( + self.update_buttons_list_widget, + QtWidgets.QScroller.ScrollerGestureType.TouchGesture, + ) + QtWidgets.QScroller.grabGesture( + self.update_buttons_list_widget, + QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, + ) + self.update_buttons_layout = QtWidgets.QVBoxLayout() + self.update_buttons_layout.setContentsMargins(0, 0, 0, 0) + self.update_buttons_layout.addWidget(self.update_buttons_list_widget, 0) + self.update_buttons_frame.setLayout(self.update_buttons_layout) + + self.main_content_layout.addWidget(self.update_buttons_frame) + + self.vlayout = QtWidgets.QVBoxLayout() + self.vlayout.setContentsMargins(5, 5, 5, 5) + + self.info_frame = BlocksCustomFrame() + self.info_frame.setMinimumSize(QtCore.QSize(200, 150)) + + self.info_box_layout = QtWidgets.QGridLayout(self.info_frame) + self.info_box_layout.setContentsMargins(0, 0, 0, 0) + + self.info_box_layout.addItem( + QtWidgets.QSpacerItem( + 20, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ), + 0, + 0, + ) + + self.type_title = QtWidgets.QLabel(self.info_frame) + self.type_title.setText("Type:") + self.type_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_box_layout.addWidget(self.type_title, 1, 0) + + self.type_label = QtWidgets.QLabel(self.info_frame) + self.type_label.setText("N/A") + self.type_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_box_layout.addWidget(self.type_label, 1, 1) + + self.time_title = QtWidgets.QLabel(self.info_frame) + self.time_title.setText("Time:") + self.time_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_box_layout.addWidget(self.time_title, 2, 0) + + self.time_label = QtWidgets.QLabel(self.info_frame) + self.time_label.setText("N/A") + self.time_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_box_layout.addWidget(self.time_label, 2, 1) + + self.type_title.setFont(font) + self.type_title.setStyleSheet("color:#FFFFFF") + + self.time_title.setFont(font) + self.time_title.setStyleSheet("color:#FFFFFF") + + self.type_label.setFont(font) + self.type_label.setStyleSheet("color:#FFFFFF") + + self.time_label.setFont(font) + self.time_label.setStyleSheet("color:#FFFFFF") + + self.info_frame.setLayout(self.info_box_layout) + + self.buttons_frame = BlocksCustomFrame() + self.buttons_frame.setMinimumSize(QtCore.QSize(200, 200)) + self.buttons_frame.setMaximumSize(QtCore.QSize(300, 200)) + + self.button_box_layout = QtWidgets.QVBoxLayout() + self.button_box_layout.setContentsMargins(10, 10, 10, 10) + self.buttons_frame.setLayout(self.button_box_layout) + + self.button_box = QtWidgets.QVBoxLayout() + self.button_box.setContentsMargins(0, 0, 0, 0) + + self.button_box.addItem( + QtWidgets.QSpacerItem( + 20, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + ) + + self.delete_btn = BlocksCustomButton() + self.delete_btn.setMinimumSize(QtCore.QSize(200, 60)) + self.delete_btn.setMaximumSize(QtCore.QSize(300, 60)) + font.setPointSize(15) + + self.delete_btn.setFont(font) + self.delete_btn.setPalette(palette) + self.delete_btn.setSizePolicy(sizePolicy) + self.delete_btn.setText("Delete") + self.delete_btn.setEnabled(False) + self.delete_btn.setPixmap( + QtGui.QPixmap(":/ui/media/btn_icons/garbage-icon.svg") + ) + self.button_box.addWidget( + self.delete_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.delete_all_btn = BlocksCustomButton() + self.delete_all_btn.setMinimumSize(QtCore.QSize(200, 60)) + self.delete_all_btn.setMaximumSize(QtCore.QSize(300, 60)) + font.setPointSize(15) + self.delete_all_btn.setFont(font) + self.delete_all_btn.setPalette(palette) + self.delete_all_btn.setSizePolicy(sizePolicy) + self.delete_all_btn.setText("Delete all") + self.delete_all_btn.setPixmap( + QtGui.QPixmap(":/ui/media/btn_icons/garbage-icon.svg") + ) + self.button_box.addWidget( + self.delete_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.button_box_layout.addLayout( + self.button_box, + 0, + ) + + self.vlayout.addWidget(self.info_frame) + self.vlayout.addWidget(self.buttons_frame) + + self.main_content_layout.addLayout(self.vlayout) + self.update_page_content_layout.addLayout(self.main_content_layout, 1) + self.setLayout(self.update_page_content_layout) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py b/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py new file mode 100644 index 000000000..d08404fba --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py @@ -0,0 +1,638 @@ +"""Update page widget - displays component status from the D-Bus updater daemon.""" + +import json +import logging +import typing +from types import MappingProxyType + +from PyQt6 import QtCore, QtGui, QtWidgets + +from BlocksScreen.lib.panels.widgets.basePopup import BasePopup +from BlocksScreen.lib.panels.widgets.loadWidget import LoadingOverlayWidget +from BlocksScreen.lib.utils.blocks_button import BlocksCustomButton +from BlocksScreen.lib.utils.blocks_Scrollbar import CustomScrollBar +from BlocksScreen.lib.utils.icon_button import IconButton +from updater.models import ComponentStatus + +_log = logging.getLogger(__name__) + + +class UpdatePage(QtWidgets.QWidget): + request_update: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="request-update" + ) + request_status: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="request-status" + ) + request_cancel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="request-cancel" + ) + update_available: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="update-available" + ) + call_load_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, str, bool, name="call-load-panel" + ) + disable_popups: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="disable-popups" + ) + + _STEP_LABELS: typing.ClassVar[MappingProxyType[int, str]] = MappingProxyType( + { + 1: "fetching", + 2: "pulling", + 3: "installing deps", + 4: "restarting", + } + ) + + _APT_STEP_LABELS: typing.ClassVar[MappingProxyType[int, str]] = MappingProxyType( + {1: "updating packages", 2: "upgrading packages"} + ) + + def __init__(self) -> None: + super().__init__() + self._chevron_right: QtGui.QPixmap = QtGui.QPixmap() + self._chevron_down: QtGui.QPixmap = QtGui.QPixmap() + self._setupUI() + self._statuses: dict[str, ComponentStatus] = {} + self._font_cache: dict[int, QtGui.QFont] = {} + self._chevron_btn: IconButton | None = None + self._details_widget: QtWidgets.QWidget | None = None + self.update_all_btn.clicked.connect(self.on_update_all_clicked) + self.update_back_btn.clicked.connect(self._request_status_debounced) + self._status_debounce: QtCore.QTimer = QtCore.QTimer(self) + self._status_debounce.setSingleShot(True) + self._status_debounce.timeout.connect(self.request_status.emit) + self.reload_btn.clicked.connect(self._request_status_debounced) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) + self._busy: bool = False + self._printing_state: str = "" + self._heaters: dict[str, float] = {} + self._update_avail: bool = False + self._post_update_status_pending: bool = False + self._overlay_shown: bool = False + self._elapsed_time_seconds: int = 0 + self._elapsed_timer: QtCore.QTimer = QtCore.QTimer(self) + self._elapsed_timer.setSingleShot(False) + self._elapsed_timer.setInterval(1000) + self._elapsed_timer.timeout.connect(self._update_elapsed_time) + self._busy_timeout_timer: QtCore.QTimer = QtCore.QTimer(self) + self._busy_timeout_timer.setSingleShot(True) + self._busy_timeout_timer.setInterval(400_000) # 400s > 360s watchdog + self._busy_timeout_timer.timeout.connect(self._on_busy_timeout) + self._update_confirm_popup: BasePopup | None = None + self.show_loading(True) + + def _request_status_debounced(self) -> None: + self._status_debounce.start(500) + + def set_printing_state(self, key: str, value: str) -> None: + """Cache the printer state so update safety checks can block mid-print updates.""" + if key == "state": + self._printing_state = value + + def set_heater_target(self, name: str, prop: str, value: float) -> None: + """Track heater targets; update is blocked if any heater is above 40 °C.""" + if prop == "target": + self._heaters[name] = value + + def _update_elapsed_time(self) -> None: + """Update and display elapsed time counter.""" + self._elapsed_time_seconds += 1 + minutes = self._elapsed_time_seconds // 60 + seconds = self._elapsed_time_seconds % 60 + self._elapsed_time_label.setText(f"{minutes:02d}:{seconds:02d}") + + def _on_busy_timeout(self) -> None: + """Force-dismiss overlay if update takes longer than 400s (safety net).""" + if self._busy: + _log.warning("busy timeout: force-dismissing overlay after 400s") + self._busy = False + self._overlay_shown = False + self.show_loading(False) + self.call_load_panel.emit(False, "", False) + self._show_toast( + "Update is taking longer than expected - tap refresh to check status" + ) + + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: + """Rebuild cards and request a fresh status poll each time the page becomes visible.""" + self.build_cards() + self._post_update_status_pending = True + self._request_status_debounced() + return super().showEvent(a0) + + def resizeEvent(self, a0: QtGui.QResizeEvent | None) -> None: + """Position elapsed time label and cancel button within the load widget area.""" + if self._loadwidget.isVisible(): + load_widget_height = self._loadwidget.height() + load_widget_width = self._loadwidget.width() + elapsed_y = int(load_widget_height * 0.65) + elapsed_x = (load_widget_width - 200) // 2 + self._elapsed_time_label.setGeometry(elapsed_x, elapsed_y, 200, 40) + progress_y = int(load_widget_height * 0.72) + progress_x = (load_widget_width - 200) // 2 + self._progress_label.setGeometry(progress_x, progress_y, 200, 30) + cancel_y = int(load_widget_height * 0.81) + cancel_x = (load_widget_width - 280) // 2 + self._cancel_btn.setGeometry(cancel_x, cancel_y, 280, 60) + return super().resizeEvent(a0) + + def _needs_update(self, status: ComponentStatus) -> bool: + # Mirrors daemon dirty-set: errored git repos self-heal; apt errors don't. + return bool( + status.commits_behind + or status.packages_upgradable > 0 + or status.has_local_changes + or status.branch_mismatch + or status.needs_install + or (status.error is not None and status.kind != "apt") + ) + + def _version_string(self, status: ComponentStatus) -> str: + if status.error: + return "status error" + if status.kind in ("system", "apt"): + return "updates available" + current = status.current_version or status.current_hash[:8] + return f"{current} → {status.remote_version or 'unknown'}" + + def _make_white_label( + self, + text: str, + size: int, + align: QtCore.Qt.AlignmentFlag = ( + QtCore.Qt.AlignmentFlag.AlignVCenter | QtCore.Qt.AlignmentFlag.AlignLeft + ), + ) -> QtWidgets.QLabel: + label = QtWidgets.QLabel(text, self) + if size not in self._font_cache: + self._font_cache[size] = QtGui.QFont(self._font_family, size) + label.setFont(self._font_cache[size]) + label.setStyleSheet("color: #FFFFFF;") + label.setAlignment(align) + return label + + def _status_color(self, status: ComponentStatus) -> str: + return "#ffd54f" if status.has_local_changes else "#ef5350" + + def build_cards(self) -> None: + """Tear down and rebuild component cards from the current ``_statuses`` snapshot.""" + self._chevron_btn = None + self._details_widget = None + while self._cards_layout.count(): + item = self._cards_layout.takeAt(0) + if item is not None: + widget = item.widget() + if widget is not None: + widget.deleteLater() + + updatable = {n: s for n, s in self._statuses.items() if self._needs_update(s)} + errored = { + n: s + for n, s in self._statuses.items() + if s.error and not self._needs_update(s) + } + self._update_avail = bool(updatable) + self.update_all_btn.setVisible(self._update_avail) + + if not updatable: + if not self._statuses: + text = "No update information available\nTap refresh to retry" + elif errored: + text = ( + f"Status check failed for {len(errored)} " + f"component{'s' if len(errored) != 1 else ''}\nTap refresh to retry" + ) + else: + text = "All systems up to date" + label = self._make_white_label( + text, + 22, + QtCore.Qt.AlignmentFlag.AlignCenter, + ) + label.setStyleSheet("color: rgba(255, 255, 255, 160);") + self._cards_layout.addStretch(1) + self._cards_layout.addWidget( + label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter + ) + self._cards_layout.addStretch(1) + return + + self._cards_layout.addWidget(self._make_summary_row(updatable)) + self._details_widget = self._make_details_widget({**updatable, **errored}) + self._details_widget.setVisible(False) + self._cards_layout.addWidget(self._details_widget) + self._cards_layout.addStretch(1) + + def _make_summary_row( + self, updatable: dict[str, ComponentStatus] + ) -> QtWidgets.QFrame: + card = QtWidgets.QFrame() + card.setFixedHeight(68) + card.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + card.setObjectName("updateCard") + card.setStyleSheet( + "QFrame#updateCard {" + " background: qlineargradient(x1:0, y1:0, x2:1, y2:0," + " stop:0 rgba(255,255,255,0.13), stop:1 rgba(255,255,255,0.04));" + " border: 1px solid rgba(255,255,255,0.22); border-radius: 10px; }" + ) + row = QtWidgets.QHBoxLayout(card) + row.setContentsMargins(16, 0, 16, 0) + row.setSpacing(12) + row.addWidget(self._make_white_label("BlocksScreen", 22), 1) + n = len(updatable) + row.addWidget( + self._make_white_label( + f"{n} update{'s' if n != 1 else ''}", + 16, + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ), + 0, + ) + self._chevron_btn = IconButton(card) + self._chevron_btn.setFixedSize(50, 50) + self._chevron_btn.setFlat(True) + self._chevron_btn.setPixmap(self._chevron_right) + self._chevron_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) + self._chevron_btn.clicked.connect(self._toggle_details) + row.addWidget(self._chevron_btn) + return card + + def _make_details_widget( + self, updatable: dict[str, ComponentStatus] + ) -> QtWidgets.QWidget: + container = QtWidgets.QWidget() + container.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + container.setStyleSheet("background: transparent;") + vbox = QtWidgets.QVBoxLayout(container) + vbox.setContentsMargins(8, 4, 8, 4) + vbox.setSpacing(4) + for name, status in updatable.items(): + if status.kind == "system": + continue + row_w = QtWidgets.QWidget() + row_w.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + row_w.setFixedHeight(36) + row = QtWidgets.QHBoxLayout(row_w) + row.setContentsMargins(12, 0, 8, 0) + row.setSpacing(10) + dot = QtWidgets.QLabel(row_w) + dot.setFixedSize(10, 10) + dot.setStyleSheet( + f"background: {self._status_color(status)}; border-radius: 5px;" + ) + row.addWidget(dot, 0, QtCore.Qt.AlignmentFlag.AlignVCenter) + row.addWidget(self._make_white_label(name.title(), 13), 1) + row.addWidget( + self._make_white_label( + self._version_string(status), + 11, + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ), + 0, + ) + vbox.addWidget(row_w) + return container + + @QtCore.pyqtSlot(name="toggle-details") + def _toggle_details(self) -> None: + if self._details_widget is None or self._chevron_btn is None: + return + visible = not self._details_widget.isVisible() + self._details_widget.setVisible(visible) + self._chevron_btn.setPixmap( + self._chevron_down if visible else self._chevron_right + ) + + def handle_status_ready(self, json_str: str) -> None: + """Update component statuses from a JSON payload and refresh the list.""" + self.update_all_btn.setEnabled(True) + _log.debug("handle_status_ready: busy=%s", self._busy) + try: + data: dict[str, dict] = json.loads(json_str) + except (json.JSONDecodeError, TypeError) as exc: + _log.error("handle_status_ready: bad payload '%s'", exc) + _log.debug(json_str) + # Keep the last good list but tell the user it may be stale. + self._show_toast("Status update failed - tap refresh to retry") + return + # Build per-component so one malformed entry can't blank the whole list. + self._statuses = {} + for name, fields in data.items(): + try: + self._statuses[name] = ComponentStatus(**fields) + except (TypeError, ValueError) as exc: + _log.error("handle_status_ready: skipping %r - %s", name, exc) + self._statuses[name] = ComponentStatus( + name=name, kind="unknown", error="malformed status" + ) + _update_avail = any(self._needs_update(s) for s in self._statuses.values()) + self._update_avail = _update_avail + if not self._busy: + self.show_loading(False) + if self._post_update_status_pending: + _log.debug("status_ready: emitting call_load_panel(False)") + self.call_load_panel.emit(False, "", False) + self._post_update_status_pending = False + else: + _log.debug("status_ready: skipping loadscreen dismiss (busy=True)") + self.build_cards() + self.update_available.emit(_update_avail) + + def handle_busy_changed(self, busy: bool) -> None: + """Show loading overlay while an update is in progress; poll for fresh status when done.""" + _log.info("handle_busy_changed: %s", busy) + self._busy = busy + self.show_loading(busy) + if busy: + self._elapsed_time_seconds = 0 + self._elapsed_timer.start() + self._busy_timeout_timer.start() + self._elapsed_time_label.show() + self._progress_label.setText("") + self._progress_label.show() + self._cancel_btn.show() + else: + self._elapsed_timer.stop() + self._busy_timeout_timer.stop() + self._elapsed_time_label.hide() + self._progress_label.hide() + self._cancel_btn.hide() + self.update_all_btn.setEnabled(True) + if self._overlay_shown: + self._overlay_shown = False + self.call_load_panel.emit(False, "", False) + self._request_status_debounced() + + @QtCore.pyqtSlot(name="on-update-all-clicked") + def on_update_all_clicked(self) -> None: + """Guard against updates during a print or with hot heaters; otherwise show confirm dialog.""" + _SAFE_STATES = {"standby", "complete", "cancelled", "error", ""} + if self._printing_state not in _SAFE_STATES: + self._show_toast(f"Printer {self._printing_state} - update deferred") + return + hot = [n for n, t in self._heaters.items() if t > 40.0] + if hot: + self._show_toast( + f"Heaters active ({', '.join(hot)}) - let it cool before updating" + ) + return + self._show_update_confirm() + + def _show_update_confirm(self) -> None: + # Dialogs parented to the page outlive close(); drop the previous one. + if self._update_confirm_popup is not None: + self._update_confirm_popup.deleteLater() + popup = BasePopup(self, floating=True) + popup.set_message( + "The printer will restart.\n" + "Do not turn off the printer.\n" + "The update may take a few minutes." + ) + popup.confirm_button_text("Update") + popup.cancel_button_text("Cancel") + popup.accepted.connect(self._do_update) + self._update_confirm_popup = popup + popup.open() + + @QtCore.pyqtSlot(name="on-cancel-clicked") + def _on_cancel_clicked(self) -> None: + """Emit cancel signal when user clicks cancel button.""" + _log.info("Cancel button clicked") + self.request_cancel.emit() + + @QtCore.pyqtSlot(name="do-update") + def _do_update(self) -> None: + self._overlay_shown = True + self.request_update.emit("") + self.call_load_panel.emit(True, "Updating all components ...", False) + + @QtCore.pyqtSlot(str, int, int, name="handle-step-complete") + def handle_step_complete(self, name: str, step: int, total: int) -> None: + """Forward step progress to the load panel overlay with a human-readable label.""" + status = self._statuses.get(name) + if status and status.kind == "apt": + label = self._APT_STEP_LABELS.get(step, "working") + else: + label = self._STEP_LABELS.get(step, "working") + _log.info("step_complete: %s %d/%d (%s)", name, step, total, label) + # Progress = daemon liveness; push the force-dismiss deadline out. + if self._busy_timeout_timer.isActive(): + self._busy_timeout_timer.start() + self._overlay_shown = True + overlay_msg = f"{name}: {label}" + self._progress_label.setText(f"Step {step}/{total}") + self.call_load_panel.emit(True, overlay_msg, False) + + def _show_toast(self, message: str, *, success: bool = False) -> None: + color = "#4caf50" if success else "#ef5350" + self._toast.setStyleSheet( + f"background: {color}; color: #fff; padding: 4px 12px; border-radius: 8px;" + ) + self._toast.setText(message) + self._toast.show() + self._toast.raise_() + self._toast_timer.start() + + def handle_error_occurred(self, name: str, reason: str) -> None: + """Show a toast with the error reason and prompt the user to refresh.""" + error_msg = f"{name} update failed: {reason}. Tap refresh to retry." + self._show_toast(error_msg) + + def handle_update_rejected(self) -> None: + """Daemon refused the request (already busy): drop the optimistic overlay and toast.""" + self._busy = False + self._overlay_shown = False + self.show_loading(False) + self.call_load_panel.emit(False, "", False) + self._show_toast("Another update is already in progress") + + def handle_rollback_done(self, name: str, success: bool) -> None: + """Show a success or failure toast after an automatic rollback completes.""" + self._show_toast( + f"{name}: {'rolled back' if success else 'rollback failed'}", + success=success, + ) + + def handle_recover_done(self, name: str, success: bool) -> None: + """Show a success or failure toast after a manual recovery action completes.""" + self._show_toast( + f"{name}: recovery {'complete' if success else 'failed'}", success=success + ) + + @QtCore.pyqtSlot(name="handle-daemon-unavailable") + def handle_daemon_unavailable(self) -> None: + """Show critical error when D-Bus daemon is unreachable.""" + self._busy = False + self._busy_timeout_timer.stop() + self._elapsed_timer.stop() + self._elapsed_time_label.hide() + self._progress_label.hide() + self._cancel_btn.hide() + self.show_loading(False) + self._show_toast( + "Updater unavailable. Check system logs or restart BlocksScreen.", + success=False, + ) + self.update_all_btn.setEnabled(False) + self.reload_btn.setEnabled(True) + + def show_loading(self, loading: bool = False) -> None: + """Toggle between the spinner overlay and the scrollable component list.""" + self.setUpdatesEnabled(False) + self._loadwidget.setVisible(loading) + self._scroll_area.setVisible(not loading) + self.update_all_btn.setVisible(not loading and self._update_avail) + self.setUpdatesEnabled(True) + self.disable_popups.emit(loading) + + def _setupUI(self) -> None: + bold_id = QtGui.QFontDatabase.addApplicationFont( + ":/font/media/fonts for text/Momcake-Bold.ttf" + ) + self._font_family = QtGui.QFontDatabase.applicationFontFamilies(bold_id)[0] + thin_id = QtGui.QFontDatabase.addApplicationFont( + ":/font/media/fonts for text/Momcake-Thin.ttf" + ) + thin_families = QtGui.QFontDatabase.applicationFontFamilies(thin_id) + _title_family = thin_families[0] if thin_families else "" + + self.setObjectName("updatePage") + self.setStyleSheet( + "#updatePage { background-image: url(:/background/media/1st_background.png); }" + ) + self.setMinimumSize(QtCore.QSize(600, 360)) + sp = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sp.setHorizontalStretch(1) + sp.setVerticalStretch(1) + self.setSizePolicy(sp) + + content = QtWidgets.QVBoxLayout(self) + content.setContentsMargins(15, 15, 15, 15) + + header = QtWidgets.QHBoxLayout() + header.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) + + self.update_back_btn = IconButton(self) + self.update_back_btn.setFixedSize(QtCore.QSize(66, 66)) + self.update_back_btn.setFlat(True) + self.update_back_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + header.addWidget(self.update_back_btn) + + title = QtWidgets.QLabel("Update Manager", self) + _title_font = QtGui.QFont(_title_family, 24) + title.setFont(_title_font) + title.setMinimumSize(QtCore.QSize(100, 60)) + title.setMaximumSize(QtCore.QSize(16777215, 60)) + title.setSizePolicy( + QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Preferred, + ) + ) + pal = title.palette() + pal.setColor(pal.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) + title.setPalette(pal) + title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + header.addWidget(title) + + self.reload_btn = IconButton(self) + self.reload_btn.setFixedSize(QtCore.QSize(66, 66)) + self.reload_btn.setFlat(True) + self.reload_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/refresh.svg")) + header.addWidget(self.reload_btn) + + content.addLayout(header, 0) + + self._scroll_area = QtWidgets.QScrollArea(self) + self._scroll_area.setWidgetResizable(True) + self._scroll_area.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self._scroll_area.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self._scroll_area.setStyleSheet("background: transparent;") + self._scroll_area.setVerticalScrollBar(CustomScrollBar()) + QtWidgets.QScroller.grabGesture( + self._scroll_area.viewport(), + QtWidgets.QScroller.ScrollerGestureType.TouchGesture, + ) + + self._scroll_content = QtWidgets.QWidget() + self._scroll_content.setStyleSheet("background: transparent;") + self._cards_layout = QtWidgets.QVBoxLayout(self._scroll_content) + self._cards_layout.setContentsMargins(8, 8, 8, 8) + self._cards_layout.setSpacing(8) + self._cards_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) + self._scroll_area.setWidget(self._scroll_content) + content.addWidget(self._scroll_area, 1) + + self._loadwidget = LoadingOverlayWidget( + self, LoadingOverlayWidget.AnimationGIF.DEFAULT + ) + content.addWidget(self._loadwidget, 1) + + self._elapsed_time_label = QtWidgets.QLabel("00:00", self._loadwidget) + self._elapsed_time_label.setStyleSheet( + "color: rgba(255, 255, 255, 200); background: transparent;" + ) + self._elapsed_time_label.setFont(QtGui.QFont(self._font_family, 16)) + self._elapsed_time_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self._elapsed_time_label.setFixedWidth(100) + self._elapsed_time_label.hide() + + self._progress_label = QtWidgets.QLabel("", self._loadwidget) + self._progress_label.setStyleSheet( + "color: rgba(255, 255, 255, 180); background: transparent;" + ) + self._progress_label.setFont(QtGui.QFont(self._font_family, 12)) + self._progress_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self._progress_label.setWordWrap(True) + self._progress_label.hide() + + # Touch target size: minimum 44×44 px per WCAG; set to 60px tall for comfort + self._cancel_btn = BlocksCustomButton(self._loadwidget) + self._cancel_btn.setMinimumSize(QtCore.QSize(240, 60)) + self._cancel_btn.setMaximumSize(QtCore.QSize(320, 60)) + self._cancel_btn.setFont(QtGui.QFont(self._font_family, 18)) + self._cancel_btn.setText("Cancel") + self._cancel_btn.clicked.connect(self._on_cancel_clicked) + self._cancel_btn.hide() + + self.update_all_btn = BlocksCustomButton(self) + self.update_all_btn.setMinimumSize(QtCore.QSize(240, 70)) + self.update_all_btn.setMaximumSize(QtCore.QSize(360, 70)) + self.update_all_btn.setFont(QtGui.QFont(self._font_family, 22)) + self.update_all_btn.setText("Update") + self.update_all_btn.setPixmap( + QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg") + ) + content.addWidget(self.update_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter) + self.update_all_btn.hide() + + self._toast = QtWidgets.QLabel(self) + self._toast.setWordWrap(True) + self._toast.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self._toast.setFont(QtGui.QFont(self._font_family, 13)) + self._toast.setFixedHeight(46) + self._toast.hide() + content.addWidget(self._toast, 0) + self._toast_timer = QtCore.QTimer(self) + self._toast_timer.setSingleShot(True) + self._toast_timer.setInterval(12000) + self._toast_timer.timeout.connect(self._toast.hide) + + _arrow = QtGui.QPixmap(":/arrow_icons/media/btn_icons/arrow_right.svg") + self._chevron_right: QtGui.QPixmap = _arrow + self._chevron_down: QtGui.QPixmap = _arrow.transformed( + QtGui.QTransform().rotate(90), + QtCore.Qt.TransformationMode.SmoothTransformation, + ) diff --git a/BlocksScreen/lib/ui/mainWindow.ui b/BlocksScreen/lib/ui/mainWindow.ui deleted file mode 100644 index 451677f2c..000000000 --- a/BlocksScreen/lib/ui/mainWindow.ui +++ /dev/null @@ -1,807 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 800 - 480 - - - - - 1 - 1 - - - - - 800 - 480 - - - - - 1024 - 600 - - - - - 1 - 1 - - - - - 800 - 480 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - BlankCursor - - - true - - - MainWindow - - - - :/background/logoblocks.png:/background/logoblocks.png - - - Qt::LeftToRight - - - MainWindow > { - url(:/font/media/fonts for text/Momcake-Thin.ttf); -} - - - false - - - - - 1 - 1 - - - - - 800 - 480 - - - - - 1024 - 600 - - - - - 1 - 1 - - - - - 800 - 480 - - - - BlankCursor - - - Qt::LeftToRight - - - #main_widget{background-image: url(:/background/media/1st_background.png);} - - - - - true - - - - 0 - 60 - 800 - 420 - - - - - 1 - 1 - - - - - 800 - 400 - - - - - 1024 - 720 - - - - - 800 - 400 - - - - BlankCursor - - - Qt::RightToLeft - - - false - - - #main_content_widget{ -background-image: url(:/background/media/1st_background.png); -} -QTabBar::tab{ - min-width: 80px; - max-width: 80px; - min-height: 100px; - max-height: 100px; - background: transparent; -} - - - - - QTabWidget::West - - - QTabWidget::Rounded - - - 3 - - - - 60 - 60 - - - - Qt::ElideLeft - - - false - - - true - - - false - - - false - - - - - 1 - 1 - - - - - 720 - 420 - - - - - 1024 - 720 - - - - - 1024 - 420 - - - - BlankCursor - - - - :/icons/media/main_menu/ICON_home.png - :/icons/media/main_menu/ICON_home_pressed.png - :/icons/media/main_menu/ICON_home_blocked.png:/icons/media/main_menu/ICON_home.png - - - - - - - - - 1 - 1 - - - - - 720 - 420 - - - - - 1024 - 720 - - - - - 1024 - 420 - - - - BlankCursor - - - - :/icons/media/main_menu/ICON_filament.png - :/icons/media/main_menu/ICON_filament_pressed.png - :/icons/media/main_menu/ICON_filamente_blocked.png:/icons/media/main_menu/ICON_filament.png - - - - - - - - - 1 - 1 - - - - - 720 - 420 - - - - - 1024 - 720 - - - - - 720 - 420 - - - - BlankCursor - - - - :/icons/media/main_menu/ICON_control.png - :/icons/media/main_menu/ICON_control_pressed.png - :/icons/media/main_menu/ICON_control_blocked.png:/icons/media/main_menu/ICON_control.png - - - - - - - - - 1 - 1 - - - - - 720 - 420 - - - - - 1024 - 720 - - - - - 1024 - 420 - - - - BlankCursor - - - - :/icons/media/main_menu/ICON_utilities.png - :/icons/media/main_menu/ICON_utilities_pressed.png - :/icons/media/main_menu/ICON_utilities_blocked.png:/icons/media/main_menu/ICON_utilities.png - - - - - - - - - true - - - - 0 - 0 - 800 - 60 - - - - - 2 - 1 - - - - - 800 - 60 - - - - - 1024 - 80 - - - - - 1 - 1 - - - - - 800 - 60 - - - - - PreferAntialias - - - - BlankCursor - - - Qt::LeftToRight - - - QWidget { - background-color: rgb(50,50,50); - color:rgb(255,255,255); - border-color : rgb(60,60,60); - selection-background-color: rgb(60,60,60); - gridline-color:rgb(60,60,60); - selection-color:rgb(60,60,60); -} - -QGroupBox{ - background-color: rgb(50,50,50); - border: none; - border-color : rgb(60,60,60); - selection-background-color: rgb(60,60,60); - gridline-color:rgb(60,60,60); - selection-color:rgb(60,60,60); - -} - -QFrame > *{ - background-color: rgb(50, 50, 50); - selection-background-color: rgb(60, 60, 60); - gridline-color: rgb(60, 60, 60); - color: rgb(255, 255, 255); - selection-color: rgb(60, 60, 60); - border-bottom-color: rgb(60, 60, 60); - -} - - -QPushButton:pressed{ - border: none; - background: transparent; -} - - - - - - Qt::AlignJustify|Qt::AlignVCenter - - - true - - - false - - - - 10 - - - QLayout::SetMinimumSize - - - 5 - - - 0 - - - 5 - - - 0 - - - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - 60 - 60 - - - - true - - - :/ui/media/btn_icons/notification.svg - - - icon_text - - - - - - - - 140 - 60 - - - - - 160 - 60 - - - - extruder - - - true - - - secondary_display - - - :/extruder_related/media/btn_icons/nozzle_topbar.svg - - - extruder_temperature_display - - - - - - - - 140 - 60 - - - - - 160 - 60 - - - - bed - - - true - - - secondary_display - - - :/temperature_related/media/btn_icons/temperature_plate.svg - - - - - - - - 140 - 60 - - - - - 160 - 60 - - - - chamber - - - true - - - :/top_bar_icons/media/topbar/chamber_temp_topbar.svg - - - dual - - - display_secondary - - - :/temperature_related/media/btn_icons/humidity.svg - - - - - - - - 60 - 60 - - - - - 60 - 60 - - - - Filament - - - true - - - :/filament_related/media/btn_icons/load_filament.svg - - - icon_text - - - - - - - - 60 - 60 - - - - - 60 - 60 - - - - nozzle - - - true - - - icon_text - - - :/temperature_related/media/btn_icons/standart_temperature.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/network/media/btn_icons/network/3bar_wifi.svg - - - - - - - - - - IconButton - QPushButton -
lib.utils.icon_button
-
- - DisplayButton - QPushButton -
lib.utils.display_button
-
- - NotificationQTabWidget - QTabWidget -
lib.utils.blocks_tabwidget
- 1 -
-
- - - - - - - - - - -
diff --git a/BlocksScreen/lib/ui/mainWindow_ui.py b/BlocksScreen/lib/ui/mainWindow_ui.py deleted file mode 100644 index e467dacf4..000000000 --- a/BlocksScreen/lib/ui/mainWindow_ui.py +++ /dev/null @@ -1,325 +0,0 @@ -# Form implementation generated from reading ui file 'BlocksScreen/lib/ui/mainWindow.ui' -# -# Created by: PyQt6 UI code generator 6.10.0 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_MainWindow(object): - def setupUi(self, MainWindow): - MainWindow.setObjectName("MainWindow") - MainWindow.resize(800, 480) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth()) - MainWindow.setSizePolicy(sizePolicy) - MainWindow.setMinimumSize(QtCore.QSize(800, 480)) - MainWindow.setMaximumSize(QtCore.QSize(1024, 600)) - MainWindow.setSizeIncrement(QtCore.QSize(1, 1)) - MainWindow.setBaseSize(QtCore.QSize(800, 480)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - MainWindow.setPalette(palette) - MainWindow.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - MainWindow.setTabletTracking(True) - icon = QtGui.QIcon.fromTheme("applications-other") - MainWindow.setWindowIcon(icon) - MainWindow.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - MainWindow.setStyleSheet("MainWindow > {\n" -" url(:/font/media/fonts for text/Momcake-Thin.ttf);\n" -"}") - MainWindow.setAnimated(False) - self.main_widget = QtWidgets.QWidget(parent=MainWindow) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.main_widget.sizePolicy().hasHeightForWidth()) - self.main_widget.setSizePolicy(sizePolicy) - self.main_widget.setMinimumSize(QtCore.QSize(800, 480)) - self.main_widget.setMaximumSize(QtCore.QSize(1024, 600)) - self.main_widget.setSizeIncrement(QtCore.QSize(1, 1)) - self.main_widget.setBaseSize(QtCore.QSize(800, 480)) - self.main_widget.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.main_widget.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.main_widget.setStyleSheet("#main_widget{background-image: url(:/background/media/1st_background.png);}\n" -"") - self.main_widget.setObjectName("main_widget") - self.main_content_widget = NotificationQTabWidget(parent=self.main_widget) - self.main_content_widget.setEnabled(True) - self.main_content_widget.setGeometry(QtCore.QRect(0, 60, 800, 420)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.main_content_widget.sizePolicy().hasHeightForWidth()) - self.main_content_widget.setSizePolicy(sizePolicy) - self.main_content_widget.setMinimumSize(QtCore.QSize(800, 400)) - self.main_content_widget.setMaximumSize(QtCore.QSize(1024, 720)) - self.main_content_widget.setBaseSize(QtCore.QSize(800, 400)) - self.main_content_widget.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.main_content_widget.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.main_content_widget.setAutoFillBackground(False) - self.main_content_widget.setStyleSheet("#main_content_widget{\n" -"background-image: url(:/background/media/1st_background.png);\n" -"}\n" -"QTabBar::tab{\n" -" min-width: 80px;\n" -" max-width: 80px;\n" -" min-height: 100px;\n" -" max-height: 100px;\n" -" background: transparent;\n" -"}\n" -"\n" -"") - self.main_content_widget.setTabPosition(QtWidgets.QTabWidget.TabPosition.West) - self.main_content_widget.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded) - self.main_content_widget.setIconSize(QtCore.QSize(60, 60)) - self.main_content_widget.setElideMode(QtCore.Qt.TextElideMode.ElideLeft) - self.main_content_widget.setUsesScrollButtons(False) - self.main_content_widget.setDocumentMode(True) - self.main_content_widget.setTabsClosable(False) - self.main_content_widget.setMovable(False) - self.main_content_widget.setObjectName("main_content_widget") - self.printTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.printTab.sizePolicy().hasHeightForWidth()) - self.printTab.setSizePolicy(sizePolicy) - self.printTab.setMinimumSize(QtCore.QSize(720, 420)) - self.printTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.printTab.setBaseSize(QtCore.QSize(1024, 420)) - self.printTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.printTab.setObjectName("printTab") - icon = QtGui.QIcon() - icon.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_home.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - icon.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_home_pressed.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) - icon.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_home_blocked.png"), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.On) - self.main_content_widget.addTab(self.printTab, icon, "") - self.filamentTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.filamentTab.sizePolicy().hasHeightForWidth()) - self.filamentTab.setSizePolicy(sizePolicy) - self.filamentTab.setMinimumSize(QtCore.QSize(720, 420)) - self.filamentTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.filamentTab.setBaseSize(QtCore.QSize(1024, 420)) - self.filamentTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.filamentTab.setObjectName("filamentTab") - icon1 = QtGui.QIcon() - icon1.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_filament.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - icon1.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_filament_pressed.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) - icon1.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_filamente_blocked.png"), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.On) - self.main_content_widget.addTab(self.filamentTab, icon1, "") - self.controlTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.controlTab.sizePolicy().hasHeightForWidth()) - self.controlTab.setSizePolicy(sizePolicy) - self.controlTab.setMinimumSize(QtCore.QSize(720, 420)) - self.controlTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.controlTab.setBaseSize(QtCore.QSize(720, 420)) - self.controlTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.controlTab.setObjectName("controlTab") - icon2 = QtGui.QIcon() - icon2.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_control.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - icon2.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_control_pressed.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) - icon2.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_control_blocked.png"), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.On) - self.main_content_widget.addTab(self.controlTab, icon2, "") - self.utilitiesTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.utilitiesTab.sizePolicy().hasHeightForWidth()) - self.utilitiesTab.setSizePolicy(sizePolicy) - self.utilitiesTab.setMinimumSize(QtCore.QSize(720, 420)) - self.utilitiesTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.utilitiesTab.setBaseSize(QtCore.QSize(1024, 420)) - self.utilitiesTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.utilitiesTab.setObjectName("utilitiesTab") - icon3 = QtGui.QIcon() - icon3.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off) - icon3.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_pressed.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On) - icon3.addPixmap(QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_blocked.png"), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.On) - self.main_content_widget.addTab(self.utilitiesTab, icon3, "") - self.main_header_layout = QtWidgets.QGroupBox(parent=self.main_widget) - self.main_header_layout.setEnabled(True) - self.main_header_layout.setGeometry(QtCore.QRect(0, 0, 800, 60)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(2) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.main_header_layout.sizePolicy().hasHeightForWidth()) - self.main_header_layout.setSizePolicy(sizePolicy) - self.main_header_layout.setMinimumSize(QtCore.QSize(800, 60)) - self.main_header_layout.setMaximumSize(QtCore.QSize(1024, 80)) - self.main_header_layout.setSizeIncrement(QtCore.QSize(1, 1)) - self.main_header_layout.setBaseSize(QtCore.QSize(800, 60)) - font = QtGui.QFont() - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.main_header_layout.setFont(font) - self.main_header_layout.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.main_header_layout.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.main_header_layout.setStyleSheet("QWidget {\n" -" background-color: rgb(50,50,50);\n" -" color:rgb(255,255,255);\n" -" border-color : rgb(60,60,60);\n" -" selection-background-color: rgb(60,60,60);\n" -" gridline-color:rgb(60,60,60);\n" -" selection-color:rgb(60,60,60);\n" -"}\n" -"\n" -"QGroupBox{\n" -" background-color: rgb(50,50,50);\n" -" border: none; \n" -" border-color : rgb(60,60,60);\n" -" selection-background-color: rgb(60,60,60);\n" -" gridline-color:rgb(60,60,60);\n" -" selection-color:rgb(60,60,60);\n" -" \n" -"}\n" -"\n" -"QFrame > *{\n" -" background-color: rgb(50, 50, 50);\n" -" selection-background-color: rgb(60, 60, 60);\n" -" gridline-color: rgb(60, 60, 60);\n" -" color: rgb(255, 255, 255); \n" -" selection-color: rgb(60, 60, 60);\n" -" border-bottom-color: rgb(60, 60, 60);\n" -" \n" -"}\n" -"\n" -"\n" -"QPushButton:pressed{\n" -" border: none;\n" -" background: transparent;\n" -"}") - self.main_header_layout.setTitle("") - self.main_header_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignJustify|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.main_header_layout.setFlat(True) - self.main_header_layout.setCheckable(False) - self.main_header_layout.setObjectName("main_header_layout") - self.header_main_layout = QtWidgets.QHBoxLayout(self.main_header_layout) - self.header_main_layout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinimumSize) - self.header_main_layout.setContentsMargins(5, 0, 5, 0) - self.header_main_layout.setSpacing(10) - self.header_main_layout.setObjectName("header_main_layout") - self.notification_btn = IconButton(parent=self.main_header_layout) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.notification_btn.sizePolicy().hasHeightForWidth()) - self.notification_btn.setSizePolicy(sizePolicy) - self.notification_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.notification_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.notification_btn.setText("") - self.notification_btn.setIconSize(QtCore.QSize(60, 60)) - self.notification_btn.setFlat(True) - self.notification_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg")) - self.notification_btn.setObjectName("notification_btn") - self.header_main_layout.addWidget(self.notification_btn, 0, QtCore.Qt.AlignmentFlag.AlignLeft) - self.extruder_temp_display = DisplayButton(parent=self.main_header_layout) - self.extruder_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.extruder_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.extruder_temp_display.setFlat(True) - self.extruder_temp_display.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle_topbar.svg")) - self.extruder_temp_display.setObjectName("extruder_temp_display") - self.header_main_layout.addWidget(self.extruder_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.bed_temp_display = DisplayButton(parent=self.main_header_layout) - self.bed_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.bed_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.bed_temp_display.setFlat(True) - self.bed_temp_display.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature_plate.svg")) - self.bed_temp_display.setObjectName("bed_temp_display") - self.header_main_layout.addWidget(self.bed_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.chamber_temp_display = DisplayButton(parent=self.main_header_layout) - self.chamber_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.chamber_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.chamber_temp_display.setFlat(True) - self.chamber_temp_display.setProperty("icon_pixmap", QtGui.QPixmap(":/top_bar_icons/media/topbar/chamber_temp_topbar.svg")) - self.chamber_temp_display.setProperty("secondary_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/humidity.svg")) - self.chamber_temp_display.setObjectName("chamber_temp_display") - self.header_main_layout.addWidget(self.chamber_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.filament_type_icon = IconButton(parent=self.main_header_layout) - self.filament_type_icon.setMinimumSize(QtCore.QSize(60, 60)) - self.filament_type_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.filament_type_icon.setFlat(True) - self.filament_type_icon.setProperty("icon_pixmap", QtGui.QPixmap(":/filament_related/media/btn_icons/load_filament.svg")) - self.filament_type_icon.setObjectName("filament_type_icon") - self.header_main_layout.addWidget(self.filament_type_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.nozzle_size_icon = IconButton(parent=self.main_header_layout) - self.nozzle_size_icon.setMinimumSize(QtCore.QSize(60, 60)) - self.nozzle_size_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.nozzle_size_icon.setFlat(True) - self.nozzle_size_icon.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/standart_temperature.svg")) - self.nozzle_size_icon.setObjectName("nozzle_size_icon") - self.header_main_layout.addWidget(self.nozzle_size_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.wifi_button = IconButton(parent=self.main_header_layout) - self.wifi_button.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.wifi_button.sizePolicy().hasHeightForWidth()) - self.wifi_button.setSizePolicy(sizePolicy) - self.wifi_button.setMinimumSize(QtCore.QSize(60, 60)) - self.wifi_button.setMaximumSize(QtCore.QSize(60, 60)) - self.wifi_button.setStyleSheet("") - self.wifi_button.setText("") - self.wifi_button.setIconSize(QtCore.QSize(16, 16)) - self.wifi_button.setCheckable(False) - self.wifi_button.setChecked(False) - self.wifi_button.setFlat(True) - self.wifi_button.setProperty("icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/network/3bar_wifi.svg")) - self.wifi_button.setObjectName("wifi_button") - self.header_main_layout.addWidget(self.wifi_button, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignTop) - self.header_main_layout.setStretch(1, 1) - self.header_main_layout.setStretch(2, 1) - self.header_main_layout.setStretch(3, 1) - MainWindow.setCentralWidget(self.main_widget) - - self.retranslateUi(MainWindow) - self.main_content_widget.setCurrentIndex(3) - QtCore.QMetaObject.connectSlotsByName(MainWindow) - - def retranslateUi(self, MainWindow): - _translate = QtCore.QCoreApplication.translate - MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.notification_btn.setProperty("button_type", _translate("MainWindow", "icon_text")) - self.extruder_temp_display.setText(_translate("MainWindow", "extruder")) - self.extruder_temp_display.setProperty("button_type", _translate("MainWindow", "secondary_display")) - self.extruder_temp_display.setProperty("name", _translate("MainWindow", "extruder_temperature_display")) - self.bed_temp_display.setText(_translate("MainWindow", "bed")) - self.bed_temp_display.setProperty("button_type", _translate("MainWindow", "secondary_display")) - self.chamber_temp_display.setText(_translate("MainWindow", "chamber")) - self.chamber_temp_display.setProperty("display_format", _translate("MainWindow", "dual")) - self.chamber_temp_display.setProperty("button_type", _translate("MainWindow", "display_secondary")) - self.filament_type_icon.setText(_translate("MainWindow", "Filament")) - self.filament_type_icon.setProperty("button_type", _translate("MainWindow", "icon_text")) - self.nozzle_size_icon.setText(_translate("MainWindow", "nozzle")) - self.nozzle_size_icon.setProperty("button_type", _translate("MainWindow", "icon_text")) - self.wifi_button.setProperty("button_type", _translate("MainWindow", "icon")) -from lib.utils.blocks_tabwidget import NotificationQTabWidget -from lib.utils.display_button import DisplayButton -from lib.utils.icon_button import IconButton From 45abdcdd935541c9a44c54e23559e90577369c43 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Wed, 12 Aug 2026 15:33:08 +0100 Subject: [PATCH 02/18] refactor: otimized setupUI --- BlocksScreen/lib/panels/mainWindow.py | 66 +-------------------------- 1 file changed, 1 insertion(+), 65 deletions(-) diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index 5b5f739ee..5a3364a43 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -1298,37 +1298,6 @@ def _setup_ui(self) -> None: self.setSizeIncrement(QtCore.QSize(1, 1)) self.setBaseSize(QtCore.QSize(800, 480)) palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush( @@ -1598,12 +1567,9 @@ def _setup_ui(self) -> None: " background: transparent;\n" "}" ) - self.main_header_layout.setTitle("") self.main_header_layout.setAlignment( QtCore.Qt.AlignmentFlag.AlignJustify | QtCore.Qt.AlignmentFlag.AlignVCenter ) - self.main_header_layout.setFlat(True) - self.main_header_layout.setCheckable(False) self.main_header_layout.setObjectName("main_header_layout") self.header_main_layout = QtWidgets.QHBoxLayout(self.main_header_layout) self.header_main_layout.setSizeConstraint( @@ -1613,57 +1579,40 @@ def _setup_ui(self) -> None: self.header_main_layout.setSpacing(10) self.header_main_layout.setObjectName("header_main_layout") self.notification_btn = IconButton(parent=self.main_header_layout) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth( - self.notification_btn.sizePolicy().hasHeightForWidth() - ) - self.notification_btn.setSizePolicy(sizePolicy) self.notification_btn.setMinimumSize(QtCore.QSize(60, 60)) self.notification_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.notification_btn.setText("") self.notification_btn.setIconSize(QtCore.QSize(60, 60)) - self.notification_btn.setFlat(True) self.notification_btn.setProperty( "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg") ) - self.notification_btn.setObjectName("notification_btn") self.header_main_layout.addWidget( self.notification_btn, 0, QtCore.Qt.AlignmentFlag.AlignLeft ) self.extruder_temp_display = DisplayButton(parent=self.main_header_layout) self.extruder_temp_display.setMinimumSize(QtCore.QSize(140, 60)) self.extruder_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.extruder_temp_display.setFlat(True) self.extruder_temp_display.setProperty( "icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle_topbar.svg"), ) - self.extruder_temp_display.setObjectName("extruder_temp_display") self.header_main_layout.addWidget( self.extruder_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter ) self.bed_temp_display = DisplayButton(parent=self.main_header_layout) self.bed_temp_display.setMinimumSize(QtCore.QSize(140, 60)) self.bed_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.bed_temp_display.setFlat(True) self.bed_temp_display.setProperty( "icon_pixmap", QtGui.QPixmap( ":/temperature_related/media/btn_icons/temperature_plate.svg" ), ) - self.bed_temp_display.setObjectName("bed_temp_display") self.header_main_layout.addWidget( self.bed_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter ) self.chamber_temp_display = DisplayButton(parent=self.main_header_layout) self.chamber_temp_display.setMinimumSize(QtCore.QSize(140, 60)) self.chamber_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.chamber_temp_display.setFlat(True) self.chamber_temp_display.setProperty( "icon_pixmap", QtGui.QPixmap(":/top_bar_icons/media/topbar/chamber_temp_topbar.svg"), @@ -1672,59 +1621,46 @@ def _setup_ui(self) -> None: "secondary_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/humidity.svg"), ) - self.chamber_temp_display.setObjectName("chamber_temp_display") self.header_main_layout.addWidget( self.chamber_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter ) self.filament_type_icon = IconButton(parent=self.main_header_layout) self.filament_type_icon.setMinimumSize(QtCore.QSize(60, 60)) self.filament_type_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.filament_type_icon.setFlat(True) self.filament_type_icon.setProperty( "icon_pixmap", QtGui.QPixmap(":/filament_related/media/btn_icons/load_filament.svg"), ) - self.filament_type_icon.setObjectName("filament_type_icon") self.header_main_layout.addWidget( self.filament_type_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter ) self.nozzle_size_icon = IconButton(parent=self.main_header_layout) self.nozzle_size_icon.setMinimumSize(QtCore.QSize(60, 60)) self.nozzle_size_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.nozzle_size_icon.setFlat(True) self.nozzle_size_icon.setProperty( "icon_pixmap", QtGui.QPixmap( ":/temperature_related/media/btn_icons/standart_temperature.svg" ), ) - self.nozzle_size_icon.setObjectName("nozzle_size_icon") self.header_main_layout.addWidget( self.nozzle_size_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter ) - self.wifi_button = IconButton(parent=self.main_header_layout) - self.wifi_button.setEnabled(True) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, ) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.wifi_button.sizePolicy().hasHeightForWidth()) + self.wifi_button = IconButton(parent=self.main_header_layout) self.wifi_button.setSizePolicy(sizePolicy) self.wifi_button.setMinimumSize(QtCore.QSize(60, 60)) self.wifi_button.setMaximumSize(QtCore.QSize(60, 60)) - self.wifi_button.setStyleSheet("") - self.wifi_button.setText("") self.wifi_button.setIconSize(QtCore.QSize(16, 16)) - self.wifi_button.setCheckable(False) - self.wifi_button.setChecked(False) - self.wifi_button.setFlat(True) self.wifi_button.setProperty( "icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/network/3bar_wifi.svg"), ) - self.wifi_button.setObjectName("wifi_button") self.header_main_layout.addWidget( self.wifi_button, 0, From 79c6bed9dec95117eab12d86da7d08efa65421ba Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Wed, 12 Aug 2026 17:22:32 +0100 Subject: [PATCH 03/18] del : delerted copied files --- .../panels/widgets/MainWindow/cancelPage.py | 56 +- .../widgets/MainWindow/connectionPage.py | 4 +- BlocksScreen/lib/panels/widgets/cancelPage.py | 278 -------- .../lib/panels/widgets/connectionPage.py | 555 --------------- .../lib/panels/widgets/notificationPage.py | 407 ----------- BlocksScreen/lib/panels/widgets/updatePage.py | 638 ------------------ 6 files changed, 29 insertions(+), 1909 deletions(-) delete mode 100644 BlocksScreen/lib/panels/widgets/cancelPage.py delete mode 100644 BlocksScreen/lib/panels/widgets/connectionPage.py delete mode 100644 BlocksScreen/lib/panels/widgets/notificationPage.py delete mode 100644 BlocksScreen/lib/panels/widgets/updatePage.py diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index dd33b52e9..c50bef4b8 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -1,17 +1,16 @@ +import logging +import typing + from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.blocks_label import BlocksLabel from PyQt6 import QtCore, QtGui, QtWidgets -import typing -from lib.moonrakerComm import MoonWebSocket +logger = logging.getLogger(__name__) class CancelPage(QtWidgets.QWidget): - """Update GUI Page, - retrieves from moonraker available clients and adds functionality - for updating or recovering them - """ + """Displayed when a print is cancelled; offers reprint or ignore.""" request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="request_file_info" @@ -23,14 +22,12 @@ class CancelPage(QtWidgets.QWidget): str, name="run_gcode" ) - def __init__(self, parent: QtWidgets.QWidget, ws: MoonWebSocket) -> None: + def __init__(self, parent: QtWidgets.QWidget) -> None: super().__init__(parent) - self.ws: MoonWebSocket = ws self._setupUI() self.filename = "" self.confirm_button.clicked.connect(lambda: self._handle_accept()) - self.refuse_button.clicked.connect(lambda: self._handle_refuse()) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) @@ -57,7 +54,7 @@ def on_print_stats_update(self, field: str, value: dict | float | str) -> None: if isinstance(value, str): if "filename" in field: self.filename = value - if self.isVisible: + if self.isVisible(): self.set_file_name(value) elif "state" in field and value in self._REASON_HEADERS: self.cf_info_tf.setText(self._REASON_HEADERS[value]) @@ -97,22 +94,25 @@ def set_pixmap(self, pixmap: QtGui.QPixmap) -> None: def set_file_name(self, file_name: str) -> None: self.cf_file_name.setText(file_name) - def _show_screen_thumbnail(self, dict): - try: - thumbnails = dict["thumbnail_images"] + def _show_screen_thumbnail(self, metadata: dict | None) -> None: + """Display the largest thumbnail from file metadata. - last_thumb = QtGui.QPixmap.fromImage(thumbnails[-1]) - - if last_thumb.isNull(): - last_thumb = QtGui.QPixmap( - "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" - ) - except Exception as e: - print(e) - last_thumb = QtGui.QPixmap( - "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" - ) - self.set_pixmap(last_thumb) + ``thumbnail_images`` values are pre-loaded ``QImage`` + objects produced by ``Files._process_metadata``. + """ + fallback = QtGui.QPixmap( + "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" + ) + thumbnails = metadata.get("thumbnail_images", []) if metadata else [] + if not thumbnails: + self.set_pixmap(fallback) + return + + last_thumb = thumbnails[-1] + if isinstance(last_thumb, QtGui.QImage) and not last_thumb.isNull(): + self.set_pixmap(QtGui.QPixmap.fromImage(last_thumb)) + else: + self.set_pixmap(fallback) def _setupUI(self) -> None: """Setup widget ui""" @@ -125,11 +125,9 @@ def _setupUI(self) -> None: sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.setObjectName("cancelPage") - self.setStyleSheet( - """#cancelPage { + self.setStyleSheet("""#cancelPage { background-image: url(:/background/media/1st_background.png); - }""" - ) + }""") self.setMinimumSize(QtCore.QSize(800, 480)) self.setMaximumSize(QtCore.QSize(800, 480)) self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py index 5921446e8..2f41e8950 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py @@ -359,14 +359,14 @@ def webhook_update(self, state: str, message: str) -> None: self._restart_10s_timer.start() self._restart_30s_timer.start() - def showEvent(self, a0: QtGui.QShowEvent | None) -> None: # noqa: N802 + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: if self.conn_toggle: self.ws.api.refresh_update_status() self.call_load_panel.emit(False, "", False) self.call_cancel_panel.emit(False) super().showEvent(a0) - def eventFilter(self, a0: QtCore.QObject | None, a1: QtCore.QEvent | None) -> bool: # noqa: N802 + def eventFilter(self, a0: QtCore.QObject | None, a1: QtCore.QEvent | None) -> bool: """Route Klipper custom events to _set_state""" if a1 is None: return super().eventFilter(a0, a1) diff --git a/BlocksScreen/lib/panels/widgets/cancelPage.py b/BlocksScreen/lib/panels/widgets/cancelPage.py deleted file mode 100644 index 6bebc5a81..000000000 --- a/BlocksScreen/lib/panels/widgets/cancelPage.py +++ /dev/null @@ -1,278 +0,0 @@ -import logging -import typing - -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_frame import BlocksCustomFrame -from lib.utils import gcode_loader -from lib.utils.blocks_label import BlocksLabel -from PyQt6 import QtCore, QtGui, QtWidgets - -logger = logging.getLogger(__name__) - - -class CancelPage(QtWidgets.QWidget): - """Displayed when a print is cancelled; offers reprint or ignore.""" - - request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="request_file_info" - ) - reprint_start: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="reprint_start" - ) - run_gcode: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="run_gcode" - ) - - def __init__(self, parent: QtWidgets.QWidget) -> None: - super().__init__(parent) - self._setupUI() - self.filename = "" - - self.confirm_button.clicked.connect(lambda: self._handle_accept()) - self.refuse_button.clicked.connect(lambda: self._handle_refuse()) - - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) - - def _handle_accept(self): - self.run_gcode.emit("SDCARD_RESET_FILE") - self.reprint_start.emit(self.filename) - self.close() - - def _handle_refuse(self): - self.close() - self.run_gcode.emit("SDCARD_RESET_FILE") - - _REASON_HEADERS: typing.ClassVar[dict[str, str]] = { - "complete": "Print Finished", - "error": "Print Error", - "cancelled": "Print Cancelled", - } - - @QtCore.pyqtSlot(str, dict, name="on_print_stats_update") - @QtCore.pyqtSlot(str, float, name="on_print_stats_update") - @QtCore.pyqtSlot(str, str, name="on_print_stats_update") - def on_print_stats_update(self, field: str, value: dict | float | str) -> None: - if isinstance(value, str): - if "filename" in field: - self.filename = value - if self.isVisible(): - self.set_file_name(value) - elif "state" in field: - if value in self._REASON_HEADERS: - self.cf_info_tf.setText(self._REASON_HEADERS[value]) - elif value == "printing": - # New job: drop the previous job's reason so it cannot leak. - self.cf_info_tf.clear() - - def show(self): - self.request_file_info.emit(self.filename) - - super().show() - - def set_pixmap(self, pixmap: QtGui.QPixmap) -> None: - if not hasattr(self, "_scene"): - self._scene = QtWidgets.QGraphicsScene(self) - self.cf_thumbnail.setScene(self._scene) - - # Scene rectangle (available display area) - graphics_rect = self.cf_thumbnail.rect().toRectF() - - # Scale pixmap preserving aspect ratio - pixmap = pixmap.scaled( - graphics_rect.size().toSize(), - QtCore.Qt.AspectRatioMode.KeepAspectRatio, - QtCore.Qt.TransformationMode.SmoothTransformation, - ) - - adjusted_x = (graphics_rect.width() - pixmap.width()) / 2.0 - adjusted_y = (graphics_rect.height() - pixmap.height()) / 2.0 - - if not hasattr(self, "_pixmap_item"): - self._pixmap_item = QtWidgets.QGraphicsPixmapItem(pixmap) - self._scene.addItem(self._pixmap_item) - else: - self._pixmap_item.setPixmap(pixmap) - - self._pixmap_item.setPos(adjusted_x, adjusted_y) - self._scene.setSceneRect(graphics_rect) - - def set_file_name(self, file_name: str) -> None: - self.cf_file_name.setText(file_name) - - def _show_screen_thumbnail(self, metadata: dict | None) -> None: - """Show the largest thumbnail, else the embedded one or the logo.""" - metadata = metadata or {} - meta_file = metadata.get("filename", "") - # fileinfo is global, every listed file emits it: decode only ours. - if meta_file.removeprefix("/") != self.filename.removeprefix("/"): - return - thumbnails = metadata.get("thumbnail_paths") or [] - last_thumb = QtGui.QPixmap(thumbnails[-1]) if thumbnails else QtGui.QPixmap() - if last_thumb.isNull(): - last_thumb = self._embedded_pixmap(meta_file) - self.set_pixmap(last_thumb) - - def _embedded_pixmap(self, gcode_path: str) -> QtGui.QPixmap: - """Cached embedded thumbnail, else the logo.""" - pixmap = gcode_loader.cached_pixmap(gcode_path) - if pixmap is not None: - return pixmap - return QtGui.QPixmap( - "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" - ) - - def _setupUI(self) -> None: - """Setup widget ui""" - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) - self.setSizePolicy(sizePolicy) - self.setObjectName("cancelPage") - self.setStyleSheet("""#cancelPage { - background-image: url(:/background/media/1st_background.png); - }""") - self.setMinimumSize(QtCore.QSize(800, 480)) - self.setMaximumSize(QtCore.QSize(800, 480)) - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) - self.verticalLayout_4.setObjectName("verticalLayout_4") - self.cf_header_title = QtWidgets.QHBoxLayout() - self.cf_header_title.setObjectName("cf_header_title") - - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.cf_file_name = BlocksLabel(parent=self) - self.cf_file_name.setMinimumSize(QtCore.QSize(0, 60)) - self.cf_file_name.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.cf_file_name.setFont(font) - self.cf_file_name.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.cf_file_name.setSizePolicy(sizePolicy) - self.cf_file_name.setStyleSheet("background: transparent; color: white;") - self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_file_name.setObjectName("cf_file_name") - self.cf_header_title.addWidget(self.cf_file_name) - - self.verticalLayout_4.addLayout(self.cf_header_title) - self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() - self.cf_content_vertical_layout.setObjectName("cf_content_vertical_layout") - self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() - self.cf_content_horizontal_layout.setObjectName("cf_content_horizontal_layout") - self.info_frame = BlocksCustomFrame(parent=self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.info_frame.setSizePolicy(sizePolicy) - - self.info_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - - self.info_layout = QtWidgets.QVBoxLayout(self.info_frame) - - self.cf_info_tf = QtWidgets.QLabel(parent=self.info_frame) - self.cf_info_tf.setText(self._REASON_HEADERS["cancelled"]) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - - self.cf_info_tf.setFont(font) - self.cf_info_tf.setStyleSheet("background: transparent; color: white;") - - self.cf_info_tf.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_layout.addWidget(self.cf_info_tf) - - self.cf_info_tr = QtWidgets.QLabel(parent=self.info_frame) - font = QtGui.QFont() - font.setPointSize(15) - self.cf_info_tr.setFont(font) - self.cf_info_tr.setStyleSheet("background: transparent; color: white;") - self.cf_info_tr.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_info_tr.setText("Do you want to reprint?") - self.info_layout.addWidget(self.cf_info_tr) - - self.cf_confirm_layout = QtWidgets.QVBoxLayout() - self.cf_confirm_layout.setSpacing(15) - - self.confirm_button = BlocksCustomButton(parent=self.info_frame) - self.confirm_button.setMinimumSize(QtCore.QSize(250, 70)) - self.confirm_button.setMaximumSize(QtCore.QSize(250, 70)) - font = QtGui.QFont("Momcake", 18) - self.confirm_button.setFont(font) - self.confirm_button.setFlat(True) - self.confirm_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") - ) - self.confirm_button.setText("Reprint") - # 2. Align buttons to the right - self.cf_confirm_layout.addWidget( - self.confirm_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.refuse_button = BlocksCustomButton(parent=self.info_frame) - self.refuse_button.setMinimumSize(QtCore.QSize(250, 70)) - self.refuse_button.setMaximumSize(QtCore.QSize(250, 70)) - self.refuse_button.setFont(font) - self.refuse_button.setFlat(True) - self.refuse_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") - ) - self.refuse_button.setText("Ignore") - # 2. Align buttons to the right - self.cf_confirm_layout.addWidget( - self.refuse_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.info_layout.addLayout(self.cf_confirm_layout) - - self.cf_content_horizontal_layout.addWidget(self.info_frame) - - self.cf_content_vertical_layout.addLayout(self.cf_content_horizontal_layout) - self.cf_thumbnail = QtWidgets.QGraphicsView(self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.cf_thumbnail.sizePolicy().hasHeightForWidth()) - self.cf_thumbnail.setSizePolicy(sizePolicy) - self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setStyleSheet( - "QGraphicsView{\nbackground-color: transparent;\n}" - ) - self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) - self.cf_thumbnail.setVerticalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setSizeAdjustPolicy( - QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - self.cf_thumbnail.setBackgroundBrush(brush) - self.cf_thumbnail.setRenderHints( - QtGui.QPainter.RenderHint.Antialiasing - | QtGui.QPainter.RenderHint.SmoothPixmapTransform - | QtGui.QPainter.RenderHint.TextAntialiasing - ) - self.cf_thumbnail.setViewportUpdateMode( - QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate - ) - self.cf_thumbnail.setObjectName("cf_thumbnail") - self.cf_content_vertical_layout.addWidget( - self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/connectionPage.py b/BlocksScreen/lib/panels/widgets/connectionPage.py deleted file mode 100644 index 2f41e8950..000000000 --- a/BlocksScreen/lib/panels/widgets/connectionPage.py +++ /dev/null @@ -1,555 +0,0 @@ -import enum -import logging -import re -import typing - -from events import KlippyDisconnected, KlippyReady -from lib.moonrakerComm import MoonWebSocket -from lib.utils.blocks_frame import BlocksCustomFrame -from lib.utils.icon_button import IconButton -from PyQt6 import QtCore, QtGui, QtWidgets - -logger = logging.getLogger(__name__) - - -class ConnectionState(enum.StrEnum): - DISCONNECTED = "disconnected" - CONNECTING = "connecting" - WEBSOCKET_LOST = "websocket_lost" - MOONRAKER_CONNECTED = "moonraker_connected" - KLIPPER_STARTUP = "klipper_startup" - KLIPPER_READY = "klipper_ready" - KLIPPER_DISCONNECTED = "klipper_disconnected" - KLIPPER_ERROR = "klipper_error" - KLIPPER_SHUTDOWN = "klipper_shutdown" - - -class ConnectionPage(QtWidgets.QFrame): - _SHUTDOWN_FALLBACK_CONTEXT: typing.Final[str] = ( - "Press 'Firmware Restart' to recover." - ) - - _MESSAGES: typing.ClassVar[dict[ConnectionState, str]] = { - ConnectionState.DISCONNECTED: "The printer is offline.\nReconnecting automatically…", - ConnectionState.CONNECTING: "Connecting to the printer\nAttempt {n}", - ConnectionState.WEBSOCKET_LOST: "Connection interrupted.\nAttempting to reconnect…", - ConnectionState.MOONRAKER_CONNECTED: "Connection established.\nWaiting for the printer to initialise…", - ConnectionState.KLIPPER_STARTUP: "The printer is starting up.\nPlease wait…", - ConnectionState.KLIPPER_READY: "The printer is ready.", - ConnectionState.KLIPPER_DISCONNECTED: "The printer is not responding.\nPress 'Restart Printer' to reconnect.", - ConnectionState.KLIPPER_ERROR: "A printer error has occurred.\nPress 'Firmware Restart' to recover.", - ConnectionState.KLIPPER_SHUTDOWN: "The printer has shut down.\n{message}", - } - - _AUTO_RECOVER_CONTEXTS: typing.ClassVar[frozenset[str]] = frozenset( - { - "m112 command", - "printers emergency button pressed", - "printer emergency button pressed", - } - ) - - _SHUTDOWN_REASON_MAP: typing.ClassVar[dict[str, str]] = { - "m112 command": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", - "printers emergency button pressed": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", - "printer emergency button pressed": "Emergency stop activated.\nRelease the emergency button, then\npress 'Firmware Restart' to recover.", - "webhooks request": "Emergency stop activated.", - "lost communication with mcu": "Lost communication with the MCU.", - "timer too close": "MCU overload\nCommunication timing failure.\nPress 'Firmware Restart' to recover.", - "adc out of range": "Temperature sensor fault.", - "no next step": "Communication failure with the MCU.", - "rescheduled timer in the past": "Motion rate exceeded\nReduce speed or acceleration.\nPress 'Firmware Restart' to recover.", - "stepper too far in past": "Stepper timing failure\nReduce speed or acceleration.\nPress 'Firmware Restart' to recover.", - "communication timeout during homing": "Communication timeout during homing.", - "protocol error": "MCU communication protocol error.", - "config error": "Configuration error\nCheck printer.cfg.\nPress 'Firmware Restart' to recover.", - "mcu error during connect": "Failed to connect to the MCU.", - } - - _FIRMWARE_RESTART_STATES: typing.ClassVar[frozenset[ConnectionState]] = frozenset( - { - ConnectionState.KLIPPER_ERROR, - ConnectionState.KLIPPER_SHUTDOWN, - } - ) - - _SHUTDOWN_NOISE: typing.ClassVar[frozenset[str]] = frozenset( - {"forced shutdown command", "forced shutdown", "shutdown", "none", ""} - ) - - _RESTART_LABELS: typing.ClassVar[dict[ConnectionState, str]] = { - ConnectionState.KLIPPER_ERROR: "Firmware Restart", - ConnectionState.KLIPPER_SHUTDOWN: "Firmware Restart", - ConnectionState.WEBSOCKET_LOST: "Retry Connection", - } - - _KLIPPY_STATE_MAP: typing.ClassVar[dict[str, ConnectionState]] = { - "error": ConnectionState.KLIPPER_ERROR, - "disconnected": ConnectionState.KLIPPER_DISCONNECTED, - "shutdown": ConnectionState.KLIPPER_SHUTDOWN, - "startup": ConnectionState.KLIPPER_STARTUP, - "ready": ConnectionState.KLIPPER_READY, - } - - retry_connection_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="retry_connection_clicked" - ) - wifi_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="call_network_page" - ) - reboot_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="reboot_clicked" - ) - restart_klipper_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="restart_klipper_clicked" - ) - firmware_restart_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="firmware_restart_clicked" - ) - update_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="show-update-page" - ) - notification_button_clicked: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="notification_button_clicked" - ) - call_load_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, str, bool, name="call-load-panel" - ) - call_cancel_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="call-cancel-panel" - ) - - def __init__(self, parent: QtWidgets.QWidget, ws: MoonWebSocket, /) -> None: - super().__init__(parent) - self.ws = ws - self._setupUI() - - self._state: ConnectionState = ConnectionState.DISCONNECTED - self.base_text: str = "" - self.dot_count: int = 0 - self.conn_toggle: bool = True - self._shutdown_confirmed: bool = ( - False # prevents fallback from overwriting shutdown reason - ) - self._last_shutdown_context: str = "" - self._firmware_restarting_pending: bool = False - self._last_restart_was_firmware: bool = False - self._escalated_to_klipper_restart: bool = False - - self.dot_timer = QtCore.QTimer(self) - self.dot_timer.setInterval(1000) - self.dot_timer.timeout.connect(self._add_dot) - - self._restart_10s_timer = QtCore.QTimer(self) - self._restart_10s_timer.setSingleShot(True) - self._restart_10s_timer.setInterval(10_000) - self._restart_10s_timer.timeout.connect(self._on_restart_10s_elapsed) - - self._restart_30s_timer = QtCore.QTimer(self) - self._restart_30s_timer.setSingleShot(True) - self._restart_30s_timer.setInterval(30_000) - self._restart_30s_timer.timeout.connect(self._on_restart_30s_elapsed) - - self.restart_klipper_button.clicked.connect(self._on_restart_clicked) - self.reboot_system_button.clicked.connect(self.reboot_clicked.emit) - self.notification_button.clicked.connect(self.notification_button_clicked.emit) - self.update_page_button.clicked.connect(self._on_update_page_clicked) - self.wifi_button.clicked.connect(self.wifi_button_clicked.emit) - - @property - def manual_restart_pending(self) -> bool: - """True while a user-initiated restart (firmware or printer) is in flight.""" - return self._firmware_restarting_pending - - def _apply_shutdown_guard(self, state: ConnectionState, context: str) -> bool: - if ( - self._state == ConnectionState.KLIPPER_SHUTDOWN - and state != ConnectionState.KLIPPER_SHUTDOWN - ): - self._shutdown_confirmed = False - elif state == ConnectionState.KLIPPER_SHUTDOWN: - _is_real = context and context != ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT - if _is_real: - self._shutdown_confirmed = True - self._last_shutdown_context = context - elif self._shutdown_confirmed or ( - self._state == ConnectionState.KLIPPER_SHUTDOWN and not context - ): - return False - return True - - def _handle_pending_restart(self, state: ConnectionState) -> bool: - if self._firmware_restarting_pending and state in ( - ConnectionState.KLIPPER_SHUTDOWN, - ConnectionState.KLIPPER_ERROR, - ConnectionState.WEBSOCKET_LOST, - ): - self._stop_restart_overlay() - return state == ConnectionState.KLIPPER_DISCONNECTED and ( - self._firmware_restarting_pending - or self._state == ConnectionState.KLIPPER_SHUTDOWN - ) - - def _set_state(self, state: ConnectionState, context: str = "") -> None: - """Update connection state and refresh the UI accordingly.""" - if state == ConnectionState.KLIPPER_SHUTDOWN and not context: - context = ( - self._last_shutdown_context or ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT - ) - if not self._apply_shutdown_guard(state, context): - return - if self._handle_pending_restart(state): - return - self.dot_timer.stop() - self._state = state - message = self._MESSAGES[state].format(n=context, message=context) - self.status_label.setText(message) - if state == ConnectionState.CONNECTING: - self.base_text = message - self.dot_count = 0 - self.dot_timer.start() - elif state == ConnectionState.KLIPPER_READY: - self._stop_restart_overlay() - self._last_shutdown_context = "" - self.hide() - return - if not self.isVisible() and self.conn_toggle: - self.show() - self._update_restart_label(state) - - def _stop_restart_overlay(self) -> None: - self._firmware_restarting_pending = False - self._restart_10s_timer.stop() - self._restart_30s_timer.stop() - self.call_load_panel.emit(False, "", False) - - def _add_dot(self) -> None: - self.dot_count += 1 - if self.dot_count > 3: - self.dot_count = 0 - dots = "." * self.dot_count - self.status_label.setText(f"{self.base_text}{dots}") - - def _update_restart_label(self, state: ConnectionState) -> None: - """Set restart_klipper_button label based on current state.""" - self.restart_klipper_button.setText( - self._RESTART_LABELS.get(state, "Restart Printer") - ) - - @staticmethod - def _strip_shutdown_prefix(raw: str) -> str: - return re.sub( - r"^(?:Shutdown due to |MCU '[^']*' shutdown[:.]\s*)", - "", - raw.split("\n")[0].strip(), - ) - - @staticmethod - def _normalize_shutdown_lines(raw: str) -> str: - line = ConnectionPage._strip_shutdown_prefix(raw) - return line.lower().replace("'", "").replace("’", "") - - @staticmethod - def _clean_shutdown_context(raw: str) -> str: - line = ConnectionPage._strip_shutdown_prefix(raw) - lower = ConnectionPage._normalize_shutdown_lines(line) - if lower in ConnectionPage._SHUTDOWN_NOISE: - return "" - for key, display in ConnectionPage._SHUTDOWN_REASON_MAP.items(): - if lower.startswith(key): - return display - return line.capitalize() - - @staticmethod - def _build_shutdown_context(raw: str) -> str: - reason = ConnectionPage._clean_shutdown_context(raw) - if not reason: - return ConnectionPage._SHUTDOWN_FALLBACK_CONTEXT - if "\n" in reason: - return reason - return f"{reason}\nPress 'Firmware Restart' to recover." - - @staticmethod - def _is_auto_recovering_context(raw: str) -> bool: - lower = ConnectionPage._normalize_shutdown_lines(raw) - return any( - lower.startswith(key) for key in ConnectionPage._AUTO_RECOVER_CONTEXTS - ) - - def _on_restart_clicked(self) -> None: - if self._state == ConnectionState.WEBSOCKET_LOST: - self.retry_connection_clicked.emit() - return - is_firmware = self._state in self._FIRMWARE_RESTART_STATES - self._last_restart_was_firmware = is_firmware - self._escalated_to_klipper_restart = False - self._firmware_restarting_pending = True - self.call_load_panel.emit( - True, - "Restarting firmware…" if is_firmware else "Restarting printer…", - False, - ) - self._restart_10s_timer.start() - self._restart_30s_timer.start() - if is_firmware: - self.firmware_restart_clicked.emit() - else: - self.restart_klipper_clicked.emit() - - def _on_restart_10s_elapsed(self) -> None: - self.call_load_panel.emit(True, "Still restarting, please wait…", False) - - def _on_restart_30s_elapsed(self) -> None: - if self._last_restart_was_firmware and not self._escalated_to_klipper_restart: - self._escalated_to_klipper_restart = True - self.call_load_panel.emit(True, "Restarting printer...", False) - self.restart_klipper_clicked.emit() - self._restart_30s_timer.start() - return - self._stop_restart_overlay() - - def _on_update_page_clicked(self) -> None: - self.update_button_clicked.emit(True) - - @QtCore.pyqtSlot(bool, name="toggle_connection_page") - def set_toggle(self, toggle: bool) -> None: - """Enable or disable auto-show behaviour.""" - self.conn_toggle = toggle - - @QtCore.pyqtSlot(str, name="on_klippy_state") - def on_klippy_state(self, state: str) -> None: - """Handle Klipper state string changes.""" - if (mapped := self._KLIPPY_STATE_MAP.get(state)) is not None: - self._set_state(mapped) - else: - logger.warning("Unknown Klipper state: %s", state) - - @QtCore.pyqtSlot(int, name="on_websocket_connecting") - def on_websocket_connecting(self, attempt: int) -> None: - """Handle websocket reconnection attempts.""" - self._set_state(ConnectionState.CONNECTING, context=str(attempt)) - - @QtCore.pyqtSlot(name="on_websocket_connection_achieved") - def on_websocket_connection_achieved(self) -> None: - """Handle websocket connection established.""" - self._set_state(ConnectionState.MOONRAKER_CONNECTED) - - @QtCore.pyqtSlot(name="on_websocket_connection_lost") - def on_websocket_connection_lost(self) -> None: - """Handle websocket connection lost.""" - self._set_state(ConnectionState.WEBSOCKET_LOST) - - @QtCore.pyqtSlot(str, str, name="webhooks_update") - def webhook_update(self, state: str, message: str) -> None: - """Handle Moonraker websocket state updates.""" - if state == "shutdown": - should_auto_recover = ( - self._state != ConnectionState.KLIPPER_SHUTDOWN - and not self._firmware_restarting_pending - and self._is_auto_recovering_context(message) - ) - self._set_state( - ConnectionState.KLIPPER_SHUTDOWN, - context=self._build_shutdown_context(message), - ) - if should_auto_recover: - self._last_restart_was_firmware = True - self._escalated_to_klipper_restart = False - self._firmware_restarting_pending = True - self._restart_10s_timer.start() - self._restart_30s_timer.start() - - def showEvent(self, a0: QtGui.QShowEvent | None) -> None: - if self.conn_toggle: - self.ws.api.refresh_update_status() - self.call_load_panel.emit(False, "", False) - self.call_cancel_panel.emit(False) - super().showEvent(a0) - - def eventFilter(self, a0: QtCore.QObject | None, a1: QtCore.QEvent | None) -> bool: - """Route Klipper custom events to _set_state""" - if a1 is None: - return super().eventFilter(a0, a1) - if a1.type() == KlippyDisconnected.type(): - if not self._firmware_restarting_pending: - self._set_state(ConnectionState.KLIPPER_DISCONNECTED) - elif a1.type() == KlippyReady.type(): - self._set_state(ConnectionState.KLIPPER_READY) - return super().eventFilter(a0, a1) - - def _setupUI(self) -> None: - self.setMinimumSize(QtCore.QSize(800, 480)) - self.setMaximumSize(QtCore.QSize(800, 480)) - self.setObjectName("ConnectionPage") - self.setStyleSheet( - "#ConnectionPage{background-image: url(:/background/media/1st_background.png);}" - ) - self.button_frame = BlocksCustomFrame(parent=self) - self.button_frame.setGeometry(QtCore.QRect(10, 365, 780, 140)) - self.button_frame.setMinimumSize(QtCore.QSize(780, 140)) - self.button_frame.setMaximumSize(QtCore.QSize(780, 160)) - self.button_frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.button_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) - self.button_frame.setLineWidth(0) - self.button_frame.setObjectName("button_frame") - - self.button_layout = QtWidgets.QHBoxLayout(self.button_frame) - self.button_layout.setContentsMargins(0, 5, 0, 0) - self.button_layout.setSpacing(0) - self.button_layout.setObjectName("button_layout") - - _btn_policy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.Fixed, - ) - - self.reboot_system_button = IconButton(parent=self.button_frame) - self.reboot_system_button.setSizePolicy(_btn_policy) - self.reboot_system_button.setMinimumSize(QtCore.QSize(115, 92)) - self.reboot_system_button.setMaximumSize(QtCore.QSize(115, 92)) - self.reboot_system_button.setCursor( - QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) - ) - self.reboot_system_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.reboot_system_button.setContextMenuPolicy( - QtCore.Qt.ContextMenuPolicy.NoContextMenu - ) - self.reboot_system_button.setFlat(True) - self.reboot_system_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/system/media/btn_icons/reboot.svg") - ) - self.reboot_system_button.setProperty("has_text", True) - self.reboot_system_button.setProperty("text_formatting", "bottom") - self.reboot_system_button.setText("Reboot") - self.reboot_system_button.setObjectName("reboot_system_button") - self.button_layout.addWidget( - self.reboot_system_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, - ) - - self.restart_klipper_button = IconButton(parent=self.button_frame) - self.restart_klipper_button.setSizePolicy(_btn_policy) - self.restart_klipper_button.setMinimumSize(QtCore.QSize(115, 92)) - self.restart_klipper_button.setMaximumSize(QtCore.QSize(115, 92)) - self.restart_klipper_button.setCursor( - QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) - ) - self.restart_klipper_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.restart_klipper_button.setContextMenuPolicy( - QtCore.Qt.ContextMenuPolicy.NoContextMenu - ) - self.restart_klipper_button.setFlat(True) - self.restart_klipper_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/system/media/btn_icons/restart_klipper.svg") - ) - self.restart_klipper_button.setProperty("has_text", True) - self.restart_klipper_button.setProperty("text_formatting", "bottom") - self.restart_klipper_button.setText("Restart Printer") - self.restart_klipper_button.setObjectName("restart_klipper_button") - self.button_layout.addWidget( - self.restart_klipper_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, - ) - - self.notification_button = IconButton(parent=self.button_frame) - self.notification_button.setSizePolicy(_btn_policy) - self.notification_button.setMinimumSize(QtCore.QSize(115, 92)) - self.notification_button.setMaximumSize(QtCore.QSize(115, 92)) - self.notification_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.notification_button.setFlat(True) - self.notification_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg") - ) - self.notification_button.setProperty("has_text", True) - self.notification_button.setProperty("text_formatting", "bottom") - self.notification_button.setText("Notifications") - self.notification_button.setObjectName("notification_button") - self.button_layout.addWidget( - self.notification_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, - ) - - self.update_page_button = IconButton(parent=self.button_frame) - self.update_page_button.setSizePolicy(_btn_policy) - self.update_page_button.setMinimumSize(QtCore.QSize(115, 92)) - self.update_page_button.setMaximumSize(QtCore.QSize(115, 92)) - self.update_page_button.setCursor( - QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) - ) - self.update_page_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.update_page_button.setContextMenuPolicy( - QtCore.Qt.ContextMenuPolicy.NoContextMenu - ) - self.update_page_button.setFlat(True) - self.update_page_button.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg"), - ) - self.update_page_button.setProperty("has_text", True) - self.update_page_button.setProperty("text_formatting", "bottom") - self.update_page_button.setText("Updates") - self.update_page_button.setObjectName("update_page_button") - self.button_layout.addWidget( - self.update_page_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, - ) - - self.wifi_button = IconButton(parent=self.button_frame) - self.wifi_button.setSizePolicy(_btn_policy) - self.wifi_button.setMinimumSize(QtCore.QSize(115, 92)) - self.wifi_button.setMaximumSize(QtCore.QSize(115, 92)) - self.wifi_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.wifi_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.wifi_button.setFlat(True) - self.wifi_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/wifi_config.svg") - ) - self.wifi_button.setProperty("has_text", True) - self.wifi_button.setProperty("text_formatting", "bottom") - self.wifi_button.setProperty("class", "system_control_btn") - self.wifi_button.setText("Wi-Fi Settings") - self.wifi_button.setObjectName("wifi_button") - self.button_layout.addWidget( - self.wifi_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignTop, - ) - - self.content_frame = QtWidgets.QFrame(parent=self) - self.content_frame.setGeometry(QtCore.QRect(0, 0, 800, 365)) - self.content_frame.setMinimumSize(QtCore.QSize(800, 365)) - self.content_frame.setMaximumSize(QtCore.QSize(800, 365)) - self.content_frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.content_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.content_frame.setObjectName("content_frame") - - self.content_layout = QtWidgets.QVBoxLayout(self.content_frame) - self.content_layout.setObjectName("content_layout") - - spacerItem = QtWidgets.QSpacerItem( - 775, - 70, - QtWidgets.QSizePolicy.Policy.Minimum, - QtWidgets.QSizePolicy.Policy.Minimum, - ) - self.content_layout.addItem(spacerItem) - - self.status_label = QtWidgets.QLabel(parent=self.content_frame) - self.status_label.setMaximumSize(QtCore.QSize(800, 380)) - _font = QtGui.QFont() - _font.setFamily("Momcake") - _font.setPointSize(17) - - self.status_label.setFont(_font) - self.status_label.setStyleSheet("color:white") - self.status_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.status_label.setWordWrap(True) - self.status_label.setTextInteractionFlags( - QtCore.Qt.TextInteractionFlag.NoTextInteraction - ) - self.status_label.setObjectName("status_label") - self.content_layout.addWidget(self.status_label) diff --git a/BlocksScreen/lib/panels/widgets/notificationPage.py b/BlocksScreen/lib/panels/widgets/notificationPage.py deleted file mode 100644 index d21de8b91..000000000 --- a/BlocksScreen/lib/panels/widgets/notificationPage.py +++ /dev/null @@ -1,407 +0,0 @@ -from collections import deque -from typing import ClassVar - -from lib.panels.widgets.popupDialogWidget import Popup -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_frame import BlocksCustomFrame -from lib.utils.icon_button import IconButton -from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem -from PyQt6 import QtCore, QtGui, QtWidgets - - -class NotificationPage(QtWidgets.QWidget): - """Update GUI Page, - retrieves from moonraker available clients and adds functionality - for updating or recovering them - """ - - on_update_message: ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - dict, name="on-update-message" - ) - - def __init__(self, parent=None) -> None: - super().__init__(parent) - self._ICON_INFO = QtGui.QPixmap(":/ui/media/btn_icons/info.svg") - self._ICON_WARN = QtGui.QPixmap(":/ui/media/btn_icons/troubleshoot.svg") - self._ICON_ERROR = QtGui.QPixmap(":/ui/media/btn_icons/error.svg") - self._setupUI() - self.cli_tracking: deque = deque() - self.selected_item: ListItem | None = None - self.popup = Popup(self) - - self.model = EntryListModel() - self.model.setParent(self.update_buttons_list_widget) - self.entry_delegate = EntryDelegate() - self.update_buttons_list_widget.setModel(self.model) - self.update_buttons_list_widget.setItemDelegate(self.entry_delegate) - self.entry_delegate.item_selected.connect(self.on_item_clicked) - - self.update_back_btn.clicked.connect(self.hide) - self.delete_btn.clicked.connect(self.delete_selected_item) - self.delete_all_btn.clicked.connect(self.reset_view_model) - - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) - self.hide() - - @QtCore.pyqtSlot(name="call-notification-panel") - def show_notification_panel( - self, - ) -> None: - """Slot for displaying notification Panel""" - if not self.parent(): - return - _parent_size = self.parent().size() # type: ignore - self.setGeometry(0, 0, _parent_size.width(), _parent_size.height()) - self.updateGeometry() - self.update() - self.show() - self.raise_() - - def delete_selected_item(self) -> None: - """Deletes currently selected item from the list view""" - if self.selected_item is None: - return - self.model.remove_item(self.selected_item) - self.delete_btn.setEnabled(False) - self.selected_item = None - - def reset_view_model(self) -> None: - """Clears items from ListView - (Resets `QAbstractListModel` by clearing entries) - """ - self.model.clear() - self.entry_delegate.clear() - - def build_model_list(self) -> None: - """Builds the model list (`self.model`) containing updatable clients""" - self.update_buttons_list_widget.blockSignals(True) - try: - message, _, priority = self.cli_tracking.popleft() - match priority: - case 1: - self._add_notif_entry(message, "#1A8FBF", self._ICON_INFO) - case 2: - self._add_notif_entry(message, "#E7E147", self._ICON_WARN) - case 3: - self._add_notif_entry(message, "#CA4949", self._ICON_ERROR) - case _: - self._add_notif_entry(message, "#a4a4a4", self._ICON_INFO) - self.model.setData(self.model.index(0), True, EntryListModel.EnableRole) - finally: - self.update_buttons_list_widget.blockSignals(False) - - @QtCore.pyqtSlot(ListItem, name="on-item-clicked") - def on_item_clicked(self, item: ListItem) -> None: - """Setup information for the currently clicked list item on the info box. - Keeps track of the list item - """ - self.delete_btn.setEnabled(True) - - match item.color: - case "#1A8FBF": - self.type_label.setText("Info") - case "#E7E147": - self.type_label.setText("Warning") - case "#CA4949": - self.type_label.setText("Error") - case _: - self.type_label.setText("Unknown") - - self.time_label.setText(item._cache.get(-1, "N/A")) - self.selected_item = item - - @QtCore.pyqtSlot(str, str, int, bool, name="new-notication") - def new_notication( - self, - origin: str | None = None, - message: str = "", - priority: int = 0, - popup: bool = False, - ): - """ - :param message: sets notification message - :type message: str - :param priority: sets notification priority from 0 to 3 - :type priority: int - :param popup: sets if notification should appear as popup - :type popup: bool - """ - self.cli_tracking.append((message, origin, priority)) - self.model.delete_duplicates() - - if popup: - match priority: - case 3: - msg_type = Popup.MessageType.ERROR - case 2: - msg_type = Popup.MessageType.WARNING - case 1: - msg_type = Popup.MessageType.INFO - case _: - msg_type = Popup.MessageType.UNKNOWN - - self.popup.new_message(message_type=msg_type, message=message, timeout=3000) - - self.build_model_list() - - def _add_notif_entry( - self, - message: str, - color: str = "#dfdfdf", - right_icon: QtGui.QPixmap | None = None, - ) -> None: - """Adds a new item to the list model""" - item = ListItem( - text=message, - left_icon=right_icon, - selected=False, - _lfontsize=17, - _rfontsize=12, - color=color, - height=80, - allow_expand=True, - notificate=False, - color_left_icon=True, - ) - time = QtCore.QDateTime.currentDateTime().toString("hh:mm:ss") - item._cache[-1] = time - self.model.add_item(item) - - def _setupUI(self) -> None: - """Setup UI for updatePage""" - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - font = QtGui.QFont() - font.setPointSize(20) - self.setSizePolicy(sizePolicy) - self.setObjectName("updatePage") - self.setStyleSheet( - """#updatePage { - background-image: url(:/background/media/1st_background.png); - }""" - ) - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.update_page_content_layout = QtWidgets.QVBoxLayout() - self.setMinimumSize(800, 480) - self.update_page_content_layout.setContentsMargins(15, 15, 15, 15) - - self.header_content_layout = QtWidgets.QHBoxLayout() - self.header_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) - self.spacer = QtWidgets.QSpacerItem( - 60, - 60, - QtWidgets.QSizePolicy.Policy.Fixed, - QtWidgets.QSizePolicy.Policy.Fixed, - ) - self.header_content_layout.addItem(self.spacer) - - self.header_title = QtWidgets.QLabel(self) - self.header_title.setMinimumSize(QtCore.QSize(100, 60)) - self.header_title.setMaximumSize(QtCore.QSize(16777215, 60)) - palette = self.header_title.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) - self.header_title.setFont(font) - font.setPointSize(15) - self.header_title.setPalette(palette) - self.header_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.header_title.setObjectName("header-title") - self.header_title.setText("Notification") - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.header_title.setSizePolicy(sizePolicy) - self.header_content_layout.addWidget( - self.header_title, alignment=QtCore.Qt.AlignmentFlag.AlignCenter - ) - self.update_back_btn = IconButton(self) - self.update_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.update_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.update_back_btn.setFlat(True) - self.update_back_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.header_content_layout.addWidget( - self.update_back_btn - ) # alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.update_page_content_layout.addLayout(self.header_content_layout, 0) - - self.main_content_layout = QtWidgets.QHBoxLayout() - self.main_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - - self.update_buttons_frame = BlocksCustomFrame(self) - - self.update_buttons_frame.setMinimumSize(QtCore.QSize(500, 380)) - self.update_buttons_frame.setMaximumSize(QtCore.QSize(560, 500)) - - self.update_buttons_list_widget = QtWidgets.QListView(self.update_buttons_frame) - self.update_buttons_list_widget.setMouseTracking(True) - self.update_buttons_list_widget.setTabletTracking(True) - - self.update_buttons_list_widget.setPalette(palette) - self.update_buttons_list_widget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.update_buttons_list_widget.setStyleSheet("background-color:transparent") - self.update_buttons_list_widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.update_buttons_list_widget.setMinimumSize(self.update_buttons_frame.size()) - self.update_buttons_list_widget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.update_buttons_list_widget.setVerticalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.update_buttons_list_widget.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.update_buttons_list_widget.setSizeAdjustPolicy( - QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents - ) - self.update_buttons_list_widget.setAutoScroll(False) - self.update_buttons_list_widget.setProperty("showDropIndicator", False) - self.update_buttons_list_widget.setDefaultDropAction( - QtCore.Qt.DropAction.IgnoreAction - ) - self.update_buttons_list_widget.setAlternatingRowColors(False) - self.update_buttons_list_widget.setSelectionMode( - QtWidgets.QAbstractItemView.SelectionMode.NoSelection - ) - self.update_buttons_list_widget.setSelectionBehavior( - QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems - ) - self.update_buttons_list_widget.setVerticalScrollMode( - QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel - ) - self.update_buttons_list_widget.setHorizontalScrollMode( - QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel - ) - QtWidgets.QScroller.grabGesture( - self.update_buttons_list_widget, - QtWidgets.QScroller.ScrollerGestureType.TouchGesture, - ) - QtWidgets.QScroller.grabGesture( - self.update_buttons_list_widget, - QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, - ) - self.update_buttons_layout = QtWidgets.QVBoxLayout() - self.update_buttons_layout.setContentsMargins(0, 0, 0, 0) - self.update_buttons_layout.addWidget(self.update_buttons_list_widget, 0) - self.update_buttons_frame.setLayout(self.update_buttons_layout) - - self.main_content_layout.addWidget(self.update_buttons_frame) - - self.vlayout = QtWidgets.QVBoxLayout() - self.vlayout.setContentsMargins(5, 5, 5, 5) - - self.info_frame = BlocksCustomFrame() - self.info_frame.setMinimumSize(QtCore.QSize(200, 150)) - - self.info_box_layout = QtWidgets.QGridLayout(self.info_frame) - self.info_box_layout.setContentsMargins(0, 0, 0, 0) - - self.info_box_layout.addItem( - QtWidgets.QSpacerItem( - 20, - 20, - QtWidgets.QSizePolicy.Policy.Minimum, - QtWidgets.QSizePolicy.Policy.Minimum, - ), - 0, - 0, - ) - - self.type_title = QtWidgets.QLabel(self.info_frame) - self.type_title.setText("Type:") - self.type_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_box_layout.addWidget(self.type_title, 1, 0) - - self.type_label = QtWidgets.QLabel(self.info_frame) - self.type_label.setText("N/A") - self.type_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_box_layout.addWidget(self.type_label, 1, 1) - - self.time_title = QtWidgets.QLabel(self.info_frame) - self.time_title.setText("Time:") - self.time_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_box_layout.addWidget(self.time_title, 2, 0) - - self.time_label = QtWidgets.QLabel(self.info_frame) - self.time_label.setText("N/A") - self.time_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_box_layout.addWidget(self.time_label, 2, 1) - - self.type_title.setFont(font) - self.type_title.setStyleSheet("color:#FFFFFF") - - self.time_title.setFont(font) - self.time_title.setStyleSheet("color:#FFFFFF") - - self.type_label.setFont(font) - self.type_label.setStyleSheet("color:#FFFFFF") - - self.time_label.setFont(font) - self.time_label.setStyleSheet("color:#FFFFFF") - - self.info_frame.setLayout(self.info_box_layout) - - self.buttons_frame = BlocksCustomFrame() - self.buttons_frame.setMinimumSize(QtCore.QSize(200, 200)) - self.buttons_frame.setMaximumSize(QtCore.QSize(300, 200)) - - self.button_box_layout = QtWidgets.QVBoxLayout() - self.button_box_layout.setContentsMargins(10, 10, 10, 10) - self.buttons_frame.setLayout(self.button_box_layout) - - self.button_box = QtWidgets.QVBoxLayout() - self.button_box.setContentsMargins(0, 0, 0, 0) - - self.button_box.addItem( - QtWidgets.QSpacerItem( - 20, - 20, - QtWidgets.QSizePolicy.Policy.Minimum, - QtWidgets.QSizePolicy.Policy.Minimum, - ) - ) - - self.delete_btn = BlocksCustomButton() - self.delete_btn.setMinimumSize(QtCore.QSize(200, 60)) - self.delete_btn.setMaximumSize(QtCore.QSize(300, 60)) - font.setPointSize(15) - - self.delete_btn.setFont(font) - self.delete_btn.setPalette(palette) - self.delete_btn.setSizePolicy(sizePolicy) - self.delete_btn.setText("Delete") - self.delete_btn.setEnabled(False) - self.delete_btn.setPixmap( - QtGui.QPixmap(":/ui/media/btn_icons/garbage-icon.svg") - ) - self.button_box.addWidget( - self.delete_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.delete_all_btn = BlocksCustomButton() - self.delete_all_btn.setMinimumSize(QtCore.QSize(200, 60)) - self.delete_all_btn.setMaximumSize(QtCore.QSize(300, 60)) - font.setPointSize(15) - self.delete_all_btn.setFont(font) - self.delete_all_btn.setPalette(palette) - self.delete_all_btn.setSizePolicy(sizePolicy) - self.delete_all_btn.setText("Delete all") - self.delete_all_btn.setPixmap( - QtGui.QPixmap(":/ui/media/btn_icons/garbage-icon.svg") - ) - self.button_box.addWidget( - self.delete_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.button_box_layout.addLayout( - self.button_box, - 0, - ) - - self.vlayout.addWidget(self.info_frame) - self.vlayout.addWidget(self.buttons_frame) - - self.main_content_layout.addLayout(self.vlayout) - self.update_page_content_layout.addLayout(self.main_content_layout, 1) - self.setLayout(self.update_page_content_layout) diff --git a/BlocksScreen/lib/panels/widgets/updatePage.py b/BlocksScreen/lib/panels/widgets/updatePage.py deleted file mode 100644 index d08404fba..000000000 --- a/BlocksScreen/lib/panels/widgets/updatePage.py +++ /dev/null @@ -1,638 +0,0 @@ -"""Update page widget - displays component status from the D-Bus updater daemon.""" - -import json -import logging -import typing -from types import MappingProxyType - -from PyQt6 import QtCore, QtGui, QtWidgets - -from BlocksScreen.lib.panels.widgets.basePopup import BasePopup -from BlocksScreen.lib.panels.widgets.loadWidget import LoadingOverlayWidget -from BlocksScreen.lib.utils.blocks_button import BlocksCustomButton -from BlocksScreen.lib.utils.blocks_Scrollbar import CustomScrollBar -from BlocksScreen.lib.utils.icon_button import IconButton -from updater.models import ComponentStatus - -_log = logging.getLogger(__name__) - - -class UpdatePage(QtWidgets.QWidget): - request_update: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="request-update" - ) - request_status: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="request-status" - ) - request_cancel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="request-cancel" - ) - update_available: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="update-available" - ) - call_load_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, str, bool, name="call-load-panel" - ) - disable_popups: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="disable-popups" - ) - - _STEP_LABELS: typing.ClassVar[MappingProxyType[int, str]] = MappingProxyType( - { - 1: "fetching", - 2: "pulling", - 3: "installing deps", - 4: "restarting", - } - ) - - _APT_STEP_LABELS: typing.ClassVar[MappingProxyType[int, str]] = MappingProxyType( - {1: "updating packages", 2: "upgrading packages"} - ) - - def __init__(self) -> None: - super().__init__() - self._chevron_right: QtGui.QPixmap = QtGui.QPixmap() - self._chevron_down: QtGui.QPixmap = QtGui.QPixmap() - self._setupUI() - self._statuses: dict[str, ComponentStatus] = {} - self._font_cache: dict[int, QtGui.QFont] = {} - self._chevron_btn: IconButton | None = None - self._details_widget: QtWidgets.QWidget | None = None - self.update_all_btn.clicked.connect(self.on_update_all_clicked) - self.update_back_btn.clicked.connect(self._request_status_debounced) - self._status_debounce: QtCore.QTimer = QtCore.QTimer(self) - self._status_debounce.setSingleShot(True) - self._status_debounce.timeout.connect(self.request_status.emit) - self.reload_btn.clicked.connect(self._request_status_debounced) - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) - self._busy: bool = False - self._printing_state: str = "" - self._heaters: dict[str, float] = {} - self._update_avail: bool = False - self._post_update_status_pending: bool = False - self._overlay_shown: bool = False - self._elapsed_time_seconds: int = 0 - self._elapsed_timer: QtCore.QTimer = QtCore.QTimer(self) - self._elapsed_timer.setSingleShot(False) - self._elapsed_timer.setInterval(1000) - self._elapsed_timer.timeout.connect(self._update_elapsed_time) - self._busy_timeout_timer: QtCore.QTimer = QtCore.QTimer(self) - self._busy_timeout_timer.setSingleShot(True) - self._busy_timeout_timer.setInterval(400_000) # 400s > 360s watchdog - self._busy_timeout_timer.timeout.connect(self._on_busy_timeout) - self._update_confirm_popup: BasePopup | None = None - self.show_loading(True) - - def _request_status_debounced(self) -> None: - self._status_debounce.start(500) - - def set_printing_state(self, key: str, value: str) -> None: - """Cache the printer state so update safety checks can block mid-print updates.""" - if key == "state": - self._printing_state = value - - def set_heater_target(self, name: str, prop: str, value: float) -> None: - """Track heater targets; update is blocked if any heater is above 40 °C.""" - if prop == "target": - self._heaters[name] = value - - def _update_elapsed_time(self) -> None: - """Update and display elapsed time counter.""" - self._elapsed_time_seconds += 1 - minutes = self._elapsed_time_seconds // 60 - seconds = self._elapsed_time_seconds % 60 - self._elapsed_time_label.setText(f"{minutes:02d}:{seconds:02d}") - - def _on_busy_timeout(self) -> None: - """Force-dismiss overlay if update takes longer than 400s (safety net).""" - if self._busy: - _log.warning("busy timeout: force-dismissing overlay after 400s") - self._busy = False - self._overlay_shown = False - self.show_loading(False) - self.call_load_panel.emit(False, "", False) - self._show_toast( - "Update is taking longer than expected - tap refresh to check status" - ) - - def showEvent(self, a0: QtGui.QShowEvent | None) -> None: - """Rebuild cards and request a fresh status poll each time the page becomes visible.""" - self.build_cards() - self._post_update_status_pending = True - self._request_status_debounced() - return super().showEvent(a0) - - def resizeEvent(self, a0: QtGui.QResizeEvent | None) -> None: - """Position elapsed time label and cancel button within the load widget area.""" - if self._loadwidget.isVisible(): - load_widget_height = self._loadwidget.height() - load_widget_width = self._loadwidget.width() - elapsed_y = int(load_widget_height * 0.65) - elapsed_x = (load_widget_width - 200) // 2 - self._elapsed_time_label.setGeometry(elapsed_x, elapsed_y, 200, 40) - progress_y = int(load_widget_height * 0.72) - progress_x = (load_widget_width - 200) // 2 - self._progress_label.setGeometry(progress_x, progress_y, 200, 30) - cancel_y = int(load_widget_height * 0.81) - cancel_x = (load_widget_width - 280) // 2 - self._cancel_btn.setGeometry(cancel_x, cancel_y, 280, 60) - return super().resizeEvent(a0) - - def _needs_update(self, status: ComponentStatus) -> bool: - # Mirrors daemon dirty-set: errored git repos self-heal; apt errors don't. - return bool( - status.commits_behind - or status.packages_upgradable > 0 - or status.has_local_changes - or status.branch_mismatch - or status.needs_install - or (status.error is not None and status.kind != "apt") - ) - - def _version_string(self, status: ComponentStatus) -> str: - if status.error: - return "status error" - if status.kind in ("system", "apt"): - return "updates available" - current = status.current_version or status.current_hash[:8] - return f"{current} → {status.remote_version or 'unknown'}" - - def _make_white_label( - self, - text: str, - size: int, - align: QtCore.Qt.AlignmentFlag = ( - QtCore.Qt.AlignmentFlag.AlignVCenter | QtCore.Qt.AlignmentFlag.AlignLeft - ), - ) -> QtWidgets.QLabel: - label = QtWidgets.QLabel(text, self) - if size not in self._font_cache: - self._font_cache[size] = QtGui.QFont(self._font_family, size) - label.setFont(self._font_cache[size]) - label.setStyleSheet("color: #FFFFFF;") - label.setAlignment(align) - return label - - def _status_color(self, status: ComponentStatus) -> str: - return "#ffd54f" if status.has_local_changes else "#ef5350" - - def build_cards(self) -> None: - """Tear down and rebuild component cards from the current ``_statuses`` snapshot.""" - self._chevron_btn = None - self._details_widget = None - while self._cards_layout.count(): - item = self._cards_layout.takeAt(0) - if item is not None: - widget = item.widget() - if widget is not None: - widget.deleteLater() - - updatable = {n: s for n, s in self._statuses.items() if self._needs_update(s)} - errored = { - n: s - for n, s in self._statuses.items() - if s.error and not self._needs_update(s) - } - self._update_avail = bool(updatable) - self.update_all_btn.setVisible(self._update_avail) - - if not updatable: - if not self._statuses: - text = "No update information available\nTap refresh to retry" - elif errored: - text = ( - f"Status check failed for {len(errored)} " - f"component{'s' if len(errored) != 1 else ''}\nTap refresh to retry" - ) - else: - text = "All systems up to date" - label = self._make_white_label( - text, - 22, - QtCore.Qt.AlignmentFlag.AlignCenter, - ) - label.setStyleSheet("color: rgba(255, 255, 255, 160);") - self._cards_layout.addStretch(1) - self._cards_layout.addWidget( - label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter - ) - self._cards_layout.addStretch(1) - return - - self._cards_layout.addWidget(self._make_summary_row(updatable)) - self._details_widget = self._make_details_widget({**updatable, **errored}) - self._details_widget.setVisible(False) - self._cards_layout.addWidget(self._details_widget) - self._cards_layout.addStretch(1) - - def _make_summary_row( - self, updatable: dict[str, ComponentStatus] - ) -> QtWidgets.QFrame: - card = QtWidgets.QFrame() - card.setFixedHeight(68) - card.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - card.setObjectName("updateCard") - card.setStyleSheet( - "QFrame#updateCard {" - " background: qlineargradient(x1:0, y1:0, x2:1, y2:0," - " stop:0 rgba(255,255,255,0.13), stop:1 rgba(255,255,255,0.04));" - " border: 1px solid rgba(255,255,255,0.22); border-radius: 10px; }" - ) - row = QtWidgets.QHBoxLayout(card) - row.setContentsMargins(16, 0, 16, 0) - row.setSpacing(12) - row.addWidget(self._make_white_label("BlocksScreen", 22), 1) - n = len(updatable) - row.addWidget( - self._make_white_label( - f"{n} update{'s' if n != 1 else ''}", - 16, - QtCore.Qt.AlignmentFlag.AlignRight - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ), - 0, - ) - self._chevron_btn = IconButton(card) - self._chevron_btn.setFixedSize(50, 50) - self._chevron_btn.setFlat(True) - self._chevron_btn.setPixmap(self._chevron_right) - self._chevron_btn.setCursor(QtCore.Qt.CursorShape.PointingHandCursor) - self._chevron_btn.clicked.connect(self._toggle_details) - row.addWidget(self._chevron_btn) - return card - - def _make_details_widget( - self, updatable: dict[str, ComponentStatus] - ) -> QtWidgets.QWidget: - container = QtWidgets.QWidget() - container.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - container.setStyleSheet("background: transparent;") - vbox = QtWidgets.QVBoxLayout(container) - vbox.setContentsMargins(8, 4, 8, 4) - vbox.setSpacing(4) - for name, status in updatable.items(): - if status.kind == "system": - continue - row_w = QtWidgets.QWidget() - row_w.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - row_w.setFixedHeight(36) - row = QtWidgets.QHBoxLayout(row_w) - row.setContentsMargins(12, 0, 8, 0) - row.setSpacing(10) - dot = QtWidgets.QLabel(row_w) - dot.setFixedSize(10, 10) - dot.setStyleSheet( - f"background: {self._status_color(status)}; border-radius: 5px;" - ) - row.addWidget(dot, 0, QtCore.Qt.AlignmentFlag.AlignVCenter) - row.addWidget(self._make_white_label(name.title(), 13), 1) - row.addWidget( - self._make_white_label( - self._version_string(status), - 11, - QtCore.Qt.AlignmentFlag.AlignRight - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ), - 0, - ) - vbox.addWidget(row_w) - return container - - @QtCore.pyqtSlot(name="toggle-details") - def _toggle_details(self) -> None: - if self._details_widget is None or self._chevron_btn is None: - return - visible = not self._details_widget.isVisible() - self._details_widget.setVisible(visible) - self._chevron_btn.setPixmap( - self._chevron_down if visible else self._chevron_right - ) - - def handle_status_ready(self, json_str: str) -> None: - """Update component statuses from a JSON payload and refresh the list.""" - self.update_all_btn.setEnabled(True) - _log.debug("handle_status_ready: busy=%s", self._busy) - try: - data: dict[str, dict] = json.loads(json_str) - except (json.JSONDecodeError, TypeError) as exc: - _log.error("handle_status_ready: bad payload '%s'", exc) - _log.debug(json_str) - # Keep the last good list but tell the user it may be stale. - self._show_toast("Status update failed - tap refresh to retry") - return - # Build per-component so one malformed entry can't blank the whole list. - self._statuses = {} - for name, fields in data.items(): - try: - self._statuses[name] = ComponentStatus(**fields) - except (TypeError, ValueError) as exc: - _log.error("handle_status_ready: skipping %r - %s", name, exc) - self._statuses[name] = ComponentStatus( - name=name, kind="unknown", error="malformed status" - ) - _update_avail = any(self._needs_update(s) for s in self._statuses.values()) - self._update_avail = _update_avail - if not self._busy: - self.show_loading(False) - if self._post_update_status_pending: - _log.debug("status_ready: emitting call_load_panel(False)") - self.call_load_panel.emit(False, "", False) - self._post_update_status_pending = False - else: - _log.debug("status_ready: skipping loadscreen dismiss (busy=True)") - self.build_cards() - self.update_available.emit(_update_avail) - - def handle_busy_changed(self, busy: bool) -> None: - """Show loading overlay while an update is in progress; poll for fresh status when done.""" - _log.info("handle_busy_changed: %s", busy) - self._busy = busy - self.show_loading(busy) - if busy: - self._elapsed_time_seconds = 0 - self._elapsed_timer.start() - self._busy_timeout_timer.start() - self._elapsed_time_label.show() - self._progress_label.setText("") - self._progress_label.show() - self._cancel_btn.show() - else: - self._elapsed_timer.stop() - self._busy_timeout_timer.stop() - self._elapsed_time_label.hide() - self._progress_label.hide() - self._cancel_btn.hide() - self.update_all_btn.setEnabled(True) - if self._overlay_shown: - self._overlay_shown = False - self.call_load_panel.emit(False, "", False) - self._request_status_debounced() - - @QtCore.pyqtSlot(name="on-update-all-clicked") - def on_update_all_clicked(self) -> None: - """Guard against updates during a print or with hot heaters; otherwise show confirm dialog.""" - _SAFE_STATES = {"standby", "complete", "cancelled", "error", ""} - if self._printing_state not in _SAFE_STATES: - self._show_toast(f"Printer {self._printing_state} - update deferred") - return - hot = [n for n, t in self._heaters.items() if t > 40.0] - if hot: - self._show_toast( - f"Heaters active ({', '.join(hot)}) - let it cool before updating" - ) - return - self._show_update_confirm() - - def _show_update_confirm(self) -> None: - # Dialogs parented to the page outlive close(); drop the previous one. - if self._update_confirm_popup is not None: - self._update_confirm_popup.deleteLater() - popup = BasePopup(self, floating=True) - popup.set_message( - "The printer will restart.\n" - "Do not turn off the printer.\n" - "The update may take a few minutes." - ) - popup.confirm_button_text("Update") - popup.cancel_button_text("Cancel") - popup.accepted.connect(self._do_update) - self._update_confirm_popup = popup - popup.open() - - @QtCore.pyqtSlot(name="on-cancel-clicked") - def _on_cancel_clicked(self) -> None: - """Emit cancel signal when user clicks cancel button.""" - _log.info("Cancel button clicked") - self.request_cancel.emit() - - @QtCore.pyqtSlot(name="do-update") - def _do_update(self) -> None: - self._overlay_shown = True - self.request_update.emit("") - self.call_load_panel.emit(True, "Updating all components ...", False) - - @QtCore.pyqtSlot(str, int, int, name="handle-step-complete") - def handle_step_complete(self, name: str, step: int, total: int) -> None: - """Forward step progress to the load panel overlay with a human-readable label.""" - status = self._statuses.get(name) - if status and status.kind == "apt": - label = self._APT_STEP_LABELS.get(step, "working") - else: - label = self._STEP_LABELS.get(step, "working") - _log.info("step_complete: %s %d/%d (%s)", name, step, total, label) - # Progress = daemon liveness; push the force-dismiss deadline out. - if self._busy_timeout_timer.isActive(): - self._busy_timeout_timer.start() - self._overlay_shown = True - overlay_msg = f"{name}: {label}" - self._progress_label.setText(f"Step {step}/{total}") - self.call_load_panel.emit(True, overlay_msg, False) - - def _show_toast(self, message: str, *, success: bool = False) -> None: - color = "#4caf50" if success else "#ef5350" - self._toast.setStyleSheet( - f"background: {color}; color: #fff; padding: 4px 12px; border-radius: 8px;" - ) - self._toast.setText(message) - self._toast.show() - self._toast.raise_() - self._toast_timer.start() - - def handle_error_occurred(self, name: str, reason: str) -> None: - """Show a toast with the error reason and prompt the user to refresh.""" - error_msg = f"{name} update failed: {reason}. Tap refresh to retry." - self._show_toast(error_msg) - - def handle_update_rejected(self) -> None: - """Daemon refused the request (already busy): drop the optimistic overlay and toast.""" - self._busy = False - self._overlay_shown = False - self.show_loading(False) - self.call_load_panel.emit(False, "", False) - self._show_toast("Another update is already in progress") - - def handle_rollback_done(self, name: str, success: bool) -> None: - """Show a success or failure toast after an automatic rollback completes.""" - self._show_toast( - f"{name}: {'rolled back' if success else 'rollback failed'}", - success=success, - ) - - def handle_recover_done(self, name: str, success: bool) -> None: - """Show a success or failure toast after a manual recovery action completes.""" - self._show_toast( - f"{name}: recovery {'complete' if success else 'failed'}", success=success - ) - - @QtCore.pyqtSlot(name="handle-daemon-unavailable") - def handle_daemon_unavailable(self) -> None: - """Show critical error when D-Bus daemon is unreachable.""" - self._busy = False - self._busy_timeout_timer.stop() - self._elapsed_timer.stop() - self._elapsed_time_label.hide() - self._progress_label.hide() - self._cancel_btn.hide() - self.show_loading(False) - self._show_toast( - "Updater unavailable. Check system logs or restart BlocksScreen.", - success=False, - ) - self.update_all_btn.setEnabled(False) - self.reload_btn.setEnabled(True) - - def show_loading(self, loading: bool = False) -> None: - """Toggle between the spinner overlay and the scrollable component list.""" - self.setUpdatesEnabled(False) - self._loadwidget.setVisible(loading) - self._scroll_area.setVisible(not loading) - self.update_all_btn.setVisible(not loading and self._update_avail) - self.setUpdatesEnabled(True) - self.disable_popups.emit(loading) - - def _setupUI(self) -> None: - bold_id = QtGui.QFontDatabase.addApplicationFont( - ":/font/media/fonts for text/Momcake-Bold.ttf" - ) - self._font_family = QtGui.QFontDatabase.applicationFontFamilies(bold_id)[0] - thin_id = QtGui.QFontDatabase.addApplicationFont( - ":/font/media/fonts for text/Momcake-Thin.ttf" - ) - thin_families = QtGui.QFontDatabase.applicationFontFamilies(thin_id) - _title_family = thin_families[0] if thin_families else "" - - self.setObjectName("updatePage") - self.setStyleSheet( - "#updatePage { background-image: url(:/background/media/1st_background.png); }" - ) - self.setMinimumSize(QtCore.QSize(600, 360)) - sp = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sp.setHorizontalStretch(1) - sp.setVerticalStretch(1) - self.setSizePolicy(sp) - - content = QtWidgets.QVBoxLayout(self) - content.setContentsMargins(15, 15, 15, 15) - - header = QtWidgets.QHBoxLayout() - header.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) - - self.update_back_btn = IconButton(self) - self.update_back_btn.setFixedSize(QtCore.QSize(66, 66)) - self.update_back_btn.setFlat(True) - self.update_back_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - header.addWidget(self.update_back_btn) - - title = QtWidgets.QLabel("Update Manager", self) - _title_font = QtGui.QFont(_title_family, 24) - title.setFont(_title_font) - title.setMinimumSize(QtCore.QSize(100, 60)) - title.setMaximumSize(QtCore.QSize(16777215, 60)) - title.setSizePolicy( - QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Preferred, - ) - ) - pal = title.palette() - pal.setColor(pal.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) - title.setPalette(pal) - title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - header.addWidget(title) - - self.reload_btn = IconButton(self) - self.reload_btn.setFixedSize(QtCore.QSize(66, 66)) - self.reload_btn.setFlat(True) - self.reload_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/refresh.svg")) - header.addWidget(self.reload_btn) - - content.addLayout(header, 0) - - self._scroll_area = QtWidgets.QScrollArea(self) - self._scroll_area.setWidgetResizable(True) - self._scroll_area.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self._scroll_area.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self._scroll_area.setStyleSheet("background: transparent;") - self._scroll_area.setVerticalScrollBar(CustomScrollBar()) - QtWidgets.QScroller.grabGesture( - self._scroll_area.viewport(), - QtWidgets.QScroller.ScrollerGestureType.TouchGesture, - ) - - self._scroll_content = QtWidgets.QWidget() - self._scroll_content.setStyleSheet("background: transparent;") - self._cards_layout = QtWidgets.QVBoxLayout(self._scroll_content) - self._cards_layout.setContentsMargins(8, 8, 8, 8) - self._cards_layout.setSpacing(8) - self._cards_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) - self._scroll_area.setWidget(self._scroll_content) - content.addWidget(self._scroll_area, 1) - - self._loadwidget = LoadingOverlayWidget( - self, LoadingOverlayWidget.AnimationGIF.DEFAULT - ) - content.addWidget(self._loadwidget, 1) - - self._elapsed_time_label = QtWidgets.QLabel("00:00", self._loadwidget) - self._elapsed_time_label.setStyleSheet( - "color: rgba(255, 255, 255, 200); background: transparent;" - ) - self._elapsed_time_label.setFont(QtGui.QFont(self._font_family, 16)) - self._elapsed_time_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self._elapsed_time_label.setFixedWidth(100) - self._elapsed_time_label.hide() - - self._progress_label = QtWidgets.QLabel("", self._loadwidget) - self._progress_label.setStyleSheet( - "color: rgba(255, 255, 255, 180); background: transparent;" - ) - self._progress_label.setFont(QtGui.QFont(self._font_family, 12)) - self._progress_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self._progress_label.setWordWrap(True) - self._progress_label.hide() - - # Touch target size: minimum 44×44 px per WCAG; set to 60px tall for comfort - self._cancel_btn = BlocksCustomButton(self._loadwidget) - self._cancel_btn.setMinimumSize(QtCore.QSize(240, 60)) - self._cancel_btn.setMaximumSize(QtCore.QSize(320, 60)) - self._cancel_btn.setFont(QtGui.QFont(self._font_family, 18)) - self._cancel_btn.setText("Cancel") - self._cancel_btn.clicked.connect(self._on_cancel_clicked) - self._cancel_btn.hide() - - self.update_all_btn = BlocksCustomButton(self) - self.update_all_btn.setMinimumSize(QtCore.QSize(240, 70)) - self.update_all_btn.setMaximumSize(QtCore.QSize(360, 70)) - self.update_all_btn.setFont(QtGui.QFont(self._font_family, 22)) - self.update_all_btn.setText("Update") - self.update_all_btn.setPixmap( - QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg") - ) - content.addWidget(self.update_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignCenter) - self.update_all_btn.hide() - - self._toast = QtWidgets.QLabel(self) - self._toast.setWordWrap(True) - self._toast.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self._toast.setFont(QtGui.QFont(self._font_family, 13)) - self._toast.setFixedHeight(46) - self._toast.hide() - content.addWidget(self._toast, 0) - self._toast_timer = QtCore.QTimer(self) - self._toast_timer.setSingleShot(True) - self._toast_timer.setInterval(12000) - self._toast_timer.timeout.connect(self._toast.hide) - - _arrow = QtGui.QPixmap(":/arrow_icons/media/btn_icons/arrow_right.svg") - self._chevron_right: QtGui.QPixmap = _arrow - self._chevron_down: QtGui.QPixmap = _arrow.transformed( - QtGui.QTransform().rotate(90), - QtCore.Qt.TransformationMode.SmoothTransformation, - ) From 57e95f0c3a6c613e86f32668d2d6e24a4beb2616 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Thu, 13 Aug 2026 10:18:43 +0100 Subject: [PATCH 04/18] upd: updated test --- tests/panels/conftest.py | 16 ++++++++-------- tests/widgets/test_connection_page.py | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/panels/conftest.py b/tests/panels/conftest.py index 2c53f7ac5..4e11ef4f1 100644 --- a/tests/panels/conftest.py +++ b/tests/panels/conftest.py @@ -31,11 +31,11 @@ "lib.panels.utilitiesTab", "lib.panels.widgets", "lib.panels.widgets.basePopup", - "lib.panels.widgets.cancelPage", - "lib.panels.widgets.connectionPage", + "lib.panels.widgets.MainWindow.cancelPage", + "lib.panels.widgets.MainWindow.connectionPage", "lib.panels.widgets.loadWidget", - "lib.panels.widgets.notificationPage", - "lib.panels.widgets.updatePage", + "lib.panels.widgets.MainWindow.notificationPage", + "lib.panels.widgets.MainWindow.updatePage", "lib.printer", "lib.ui", "lib.ui.mainWindow_ui", @@ -79,11 +79,11 @@ sys.modules["lib.panels.printTab"].PrintTab = MagicMock sys.modules["lib.panels.utilitiesTab"].UtilitiesTab = MagicMock sys.modules["lib.panels.widgets.basePopup"].BasePopup = MagicMock -sys.modules["lib.panels.widgets.cancelPage"].CancelPage = MagicMock -sys.modules["lib.panels.widgets.connectionPage"].ConnectionPage = MagicMock +sys.modules["lib.panels.widgets.MainWindow.cancelPage"].CancelPage = MagicMock +sys.modules["lib.panels.widgets.MainWindow.connectionPage"].ConnectionPage = MagicMock sys.modules["lib.panels.widgets.loadWidget"].LoadingOverlayWidget = MagicMock -sys.modules["lib.panels.widgets.notificationPage"].NotificationPage = MagicMock -sys.modules["lib.panels.widgets.updatePage"].UpdatePage = MagicMock +sys.modules["lib.panels.widgets.MainWindow.notificationPage"].NotificationPage = MagicMock +sys.modules["lib.panels.widgets.MainWindow.updatePage"].UpdatePage = MagicMock sys.modules["lib.printer"].Printer = MagicMock sys.modules["lib.ui.mainWindow_ui"].Ui_MainWindow = MagicMock sys.modules["lib.updater_worker"].UpdaterWorker = MagicMock diff --git a/tests/widgets/test_connection_page.py b/tests/widgets/test_connection_page.py index 7b4c98dd0..bcfe7932b 100644 --- a/tests/widgets/test_connection_page.py +++ b/tests/widgets/test_connection_page.py @@ -1,7 +1,7 @@ import pytest from unittest.mock import MagicMock from events import KlippyDisconnected, KlippyReady -from BlocksScreen.lib.panels.widgets.connectionPage import ( +from BlocksScreen.lib.panels.widgets.MainWindow.connectionPage import ( ConnectionState, ConnectionPage, ) From defef529574af46ad09a64335089e6e102c1118f Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Thu, 13 Aug 2026 10:55:56 +0100 Subject: [PATCH 05/18] upd : updated test --- tests/panels/test_main_window_unit.py | 3 ++- tests/widgets/test_update_page_unit.py | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/panels/test_main_window_unit.py b/tests/panels/test_main_window_unit.py index 2668f3736..260c8067e 100644 --- a/tests/panels/test_main_window_unit.py +++ b/tests/panels/test_main_window_unit.py @@ -62,7 +62,8 @@ def _make_nav_window(print_state: str) -> SimpleNamespace: _print_state=print_state, printPanel=print_panel, filamentPanel=MagicMock(), - ui=SimpleNamespace(main_content_widget=main_content, printTab=print_tab), + main_content_widget=main_content, + printTab=print_tab, ) for name in ( "_is_job_active", diff --git a/tests/widgets/test_update_page_unit.py b/tests/widgets/test_update_page_unit.py index 2a35e7cdf..5ab72bf7b 100644 --- a/tests/widgets/test_update_page_unit.py +++ b/tests/widgets/test_update_page_unit.py @@ -11,14 +11,14 @@ def page(qapp): """UpdatePage instance with all heavy UI deps mocked.""" patches = [ - patch("BlocksScreen.lib.panels.widgets.updatePage.LoadingOverlayWidget"), - patch("BlocksScreen.lib.panels.widgets.updatePage.BlocksCustomButton"), - patch("BlocksScreen.lib.panels.widgets.updatePage.IconButton"), + patch("BlocksScreen.lib.panels.widgets.MainWindow.updatePage.LoadingOverlayWidget"), + patch("BlocksScreen.lib.panels.widgets.MainWindow.updatePage.BlocksCustomButton"), + patch("BlocksScreen.lib.panels.widgets.MainWindow.updatePage.IconButton"), ] for p in patches: p.start() - from BlocksScreen.lib.panels.widgets.updatePage import UpdatePage + from BlocksScreen.lib.panels.widgets.MainWindow.updatePage import UpdatePage def _mock_setup(self): for attr in ( @@ -498,7 +498,7 @@ def test_bad_payload_keeps_statuses_and_toasts(self, page): class TestConfirmPopupCleanup: def test_second_confirm_deletes_previous_popup(self, page): - with patch("BlocksScreen.lib.panels.widgets.updatePage.BasePopup") as popup_cls: + with patch("BlocksScreen.lib.panels.widgets.MainWindow.updatePage.BasePopup") as popup_cls: first = MagicMock() second = MagicMock() popup_cls.side_effect = [first, second] From 0440208ef07ee6a4b50965184883df73e18a014b Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Thu, 13 Aug 2026 11:03:24 +0100 Subject: [PATCH 06/18] fix: stop lib.utils stub leak breaking mainWindow tests --- tests/panels/conftest.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/panels/conftest.py b/tests/panels/conftest.py index 4e11ef4f1..69e6bbf8e 100644 --- a/tests/panels/conftest.py +++ b/tests/panels/conftest.py @@ -9,8 +9,19 @@ import sys import types +from pathlib import Path from unittest.mock import MagicMock +_project_root = Path(__file__).resolve().parent.parent.parent + +# Other test directories (e.g. tests/lib/conftest.py) leak a bare +# ``MagicMock()`` stub for "lib.utils" into sys.modules with no teardown, +# which breaks the real ``lib.utils.*`` imports below on a full-suite run. +# Clear any stale "lib"/"lib.*" entries before rebuilding our own stubs. +for _stale in list(sys.modules): + if _stale == "lib" or _stale.startswith("lib."): + del sys.modules[_stale] + _STUB_MODULES = ( "events", "configfile", @@ -56,6 +67,11 @@ _mod.__path__ = [] # marks it as a package so submodule imports resolve sys.modules[_name] = _mod +# "lib.utils" is deliberately NOT in _STUB_MODULES: blocks_tabwidget, +# display_button, and icon_button are plain PyQt6 widgets with no heavy +# deps, so let them load for real from disk instead of stubbing them. +sys.modules["lib"].__path__ = [str(_project_root / "BlocksScreen" / "lib")] + # events.* is referenced as a bare attribute in type annotations # (e.g. ``event: events.WebSocketMessageReceived``), evaluated eagerly at # class-definition time — needs to resolve any attribute, not just a fixed set. From e8912bcf70e01bec51ebe4c35c3404792880e467 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Thu, 13 Aug 2026 14:24:03 +0100 Subject: [PATCH 07/18] add :added missing requirement --- scripts/requirements-dev.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/requirements-dev.txt b/scripts/requirements-dev.txt index 184499394..a43d9bd24 100644 --- a/scripts/requirements-dev.txt +++ b/scripts/requirements-dev.txt @@ -7,6 +7,7 @@ pytest-timeout pytest-qt pytest-asyncio PyQt6 +numpy==2.1.0 docstr_coverage bandit requests>=2.32.5 From e8dc14a1be36ab1560aced440a58b28b88ee3c14 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Mon, 28 Sep 2026 10:58:05 +0100 Subject: [PATCH 08/18] fix : brought back dev cancel page --- .../lib/panels/widgets/MainWindow/cancelPage.py | 14 +++++++++----- tests/widgets/test_cancel_page_unit.py | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index c50bef4b8..8592e578d 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -42,9 +42,9 @@ def _handle_refuse(self): self.run_gcode.emit("SDCARD_RESET_FILE") _REASON_HEADERS: typing.ClassVar[dict[str, str]] = { - "complete": "Print Completed", + "complete": "Print Finished", "error": "Print Error", - "cancelled": "Print job was\ncancelled", + "cancelled": "Print Cancelled", } @QtCore.pyqtSlot(str, dict, name="on_print_stats_update") @@ -56,8 +56,12 @@ def on_print_stats_update(self, field: str, value: dict | float | str) -> None: self.filename = value if self.isVisible(): self.set_file_name(value) - elif "state" in field and value in self._REASON_HEADERS: - self.cf_info_tf.setText(self._REASON_HEADERS[value]) + elif "state" in field: + if value in self._REASON_HEADERS: + self.cf_info_tf.setText(self._REASON_HEADERS[value]) + elif value == "printing": + # New job: drop the previous job's reason so it cannot leak. + self.cf_info_tf.clear() def show(self): self.request_file_info.emit(self.filename) @@ -171,7 +175,7 @@ def _setupUI(self) -> None: self.info_layout = QtWidgets.QVBoxLayout(self.info_frame) self.cf_info_tf = QtWidgets.QLabel(parent=self.info_frame) - self.cf_info_tf.setText("Print job was\ncancelled") + self.cf_info_tf.setText(self._REASON_HEADERS["cancelled"]) font = QtGui.QFont() font.setFamily("Momcake") font.setPointSize(20) diff --git a/tests/widgets/test_cancel_page_unit.py b/tests/widgets/test_cancel_page_unit.py index f5ab7577a..44bfbbd66 100644 --- a/tests/widgets/test_cancel_page_unit.py +++ b/tests/widgets/test_cancel_page_unit.py @@ -3,7 +3,7 @@ import pytest from PyQt6 import QtWidgets -from BlocksScreen.lib.panels.widgets.cancelPage import CancelPage +from BlocksScreen.lib.panels.widgets.MainWindow.cancelPage import CancelPage @pytest.fixture From 0a3484842cb1bb2dfe863e5fccf78f7715320130 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Thu, 13 Aug 2026 14:51:01 +0100 Subject: [PATCH 09/18] refactor: separated control stacked widget into pages --- BlocksScreen/lib/panels/controlTab.py | 817 +-- BlocksScreen/lib/panels/mainWindow.py | 12 +- .../lib/panels/widgets/ControlTab/axisPage.py | 581 ++ .../panels/widgets/ControlTab/extruderPage.py | 512 ++ .../lib/panels/widgets/ControlTab/fansPage.py | 212 + .../widgets/{ => ControlTab}/printcorePage.py | 0 .../{ => ControlTab}/probeHelperPage.py | 4 +- .../widgets/ControlTab/temperaturePage.py | 310 + BlocksScreen/lib/ui/controlStackedWidget.ui | 5781 ----------------- .../lib/ui/controlStackedWidget_ui.py | 2186 ------- 10 files changed, 1958 insertions(+), 8457 deletions(-) create mode 100644 BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py create mode 100644 BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py create mode 100644 BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py rename BlocksScreen/lib/panels/widgets/{ => ControlTab}/printcorePage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => ControlTab}/probeHelperPage.py (99%) create mode 100644 BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py delete mode 100644 BlocksScreen/lib/ui/controlStackedWidget.ui delete mode 100644 BlocksScreen/lib/ui/controlStackedWidget_ui.py diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index 9e81d3237..c3ff12133 100644 --- a/BlocksScreen/lib/panels/controlTab.py +++ b/BlocksScreen/lib/panels/controlTab.py @@ -4,19 +4,20 @@ import logging import re import typing -from functools import partial from lib.moonrakerComm import MoonWebSocket from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.ControlTab.axisPage import AxisPage +from lib.panels.widgets.ControlTab.extruderPage import ExtruderPage +from lib.panels.widgets.ControlTab.fansPage import FansPage +from lib.panels.widgets.ControlTab.printcorePage import SwapPrintcorePage +from lib.panels.widgets.ControlTab.probeHelperPage import ProbeHelper +from lib.panels.widgets.ControlTab.temperaturePage import TemperaturePage from lib.panels.widgets.numpadPage import CustomNumpad -from lib.panels.widgets.optionCardWidget import OptionCard -from lib.panels.widgets.printcorePage import SwapPrintcorePage -from lib.panels.widgets.probeHelperPage import ProbeHelper from lib.panels.widgets.slider_selector_page import SliderPage from lib.printer import Printer -from lib.ui.controlStackedWidget_ui import Ui_controlStackedWidget -from lib.utils.display_button import DisplayButton -from lib.utils.gcode import fan_speed_gcode +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.icon_button import IconButton from PyQt6 import QtCore, QtGui, QtWidgets _logger = logging.getLogger(__name__) @@ -63,43 +64,72 @@ def __init__( /, ) -> None: super().__init__(parent) - self.panel = Ui_controlStackedWidget() - self.panel.setupUi(self) + self._setup_ui() + + self.back_button.clicked.connect(lambda: self._button_change(False)) self.ws: MoonWebSocket = ws self.printer: Printer = printer self._true_zero_state: bool | None = None + self._motion_active: bool = False self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) self.timers = [] - self.extruder_info: dict = {} - self.bed_info: dict = {} - self.toolhead_info: dict = {} - self.tune_display_buttons: dict = {} - self.card_options: dict = {} - self.extrude_length: int = 10 - self.extrude_feedrate: int = 2 - self.extrude_page_message: str = "" - self.move_length: float = 1.0 - self.move_speed: float = 25.0 + self.ztilt_state = False self.ztilt_result_screen = BasePopup(self, False, False) + self.ztilt_result_screen_timer = QtCore.QTimer() + self.ztilt_result_screen_timer.setSingleShot(True) + self.ztilt_result_screen_timer.setInterval(5000) + self.ztilt_result_screen_timer.timeout.connect(self.ztilt_result_screen.hide) self.probe_helper_page = ProbeHelper(self) + self.addWidget(self.probe_helper_page) self.probe_helper_page.toggle_conn_page.connect(self.toggle_conn_page) self.probe_helper_page.disable_popups.connect(self.disable_popups) self.probe_helper_page.lock_ui.connect(self.lock_ui) - self.addWidget(self.probe_helper_page) self.probe_helper_page.call_load_panel.connect(self.call_load_panel) + self.printcores_page = SwapPrintcorePage(self) self.addWidget(self.printcores_page) + self.fans_page = FansPage(self) + self.addWidget(self.fans_page) + self.fans_page.request_back_button.connect(self.request_back_button) + self.fans_page.run_gcode_signal.connect(self.run_gcode_signal) + self.fans_page.request_slider_page.connect(self.on_slidePage_request) + self.sliderPage = SliderPage(self) self.addWidget(self.sliderPage) - self.sliderPage.request_back.connect(self.back_button) + self.sliderPage.request_back.connect(self.request_back_button) + + self.axis_page = AxisPage(self) + self.addWidget(self.axis_page) + self.axis_page.request_back.connect(self.request_back_button) + self.axis_page.run_gcode_signal.connect(self.run_gcode_signal) + self.axis_page.call_load_panel.connect(self.call_load_panel) + self.printer.toolhead_update[str, list].connect( + self.axis_page.on_toolhead_update + ) + + self.extruder_page = ExtruderPage(self, printer) + self.addWidget(self.extruder_page) + self.extruder_page.request_back.connect(self.request_back_button) + self.extruder_page.run_gcode_signal.connect(self.run_gcode_signal) + + self.temperature_page = TemperaturePage(self) + self.addWidget(self.temperature_page) + self.temperature_page.request_back.connect(self.request_back_button) + self.temperature_page.request_numpad.connect(self.on_numpad_request) + self.temperature_page.run_gcode_signal.connect(self.run_gcode_signal) + + self.numpadPage = CustomNumpad(self) + self.numpadPage.setMaximumHeight(400) + self.numpadPage.request_back.connect(self.request_back_button) + self.addWidget(self.numpadPage) self.probe_helper_page.request_page_view.connect( - partial(self.change_page, self.indexOf(self.probe_helper_page)) + lambda: self.change_page(self.indexOf(self.probe_helper_page)) ) self.probe_helper_page.query_printer_object.connect(self.ws.api.object_query) self.probe_helper_page.run_gcode_signal.connect(self.ws.api.run_gcode) - self.probe_helper_page.request_back.connect(self.back_button) + self.probe_helper_page.request_back.connect(self.request_back_button) self.printer.print_stats_update[str, str].connect( self.probe_helper_page.on_print_stats_update ) @@ -129,178 +159,135 @@ def __init__( self.printer.gcode_response.connect( self.probe_helper_page.handle_gcode_response ) - self.printer.toolhead_update[str, list].connect(self.on_toolhead_update) - self.printer.extruder_update.connect(self.on_extruder_update) - self.printer.heater_bed_update.connect(self.on_heater_bed_update) - self.panel.cp_motion_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.panel.motion_page)) - ) - self.panel.cp_temperature_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.panel.temperature_page)) - ) - self.panel.cp_fans_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.panel.fans_page)) - ) - self.panel.fans_back_btn.clicked.connect(self.back_button) - self.panel.cp_switch_print_core_btn.clicked.connect(self.show_swapcore) - self.panel.cp_nozzles_calibration_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.probe_helper_page)) - ) - self.panel.motion_extrude_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.panel.extrude_page)) - ) - self.panel.motion_move_axis_btn.clicked.connect( - partial(self.change_page, self.indexOf(self.panel.move_axis_page)) - ) - self.panel.mp_back_btn.clicked.connect(self.back_button) - self.panel.motion_auto_home_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "G28\nM400") - ) - self.panel.motion_disable_steppers_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "M84\nM400") + self.printer.extruder_update.connect(self.temperature_page.on_extruder_update) + self.printer.heater_bed_update.connect( + self.temperature_page.on_heater_bed_update ) - self.panel.exp_back_btn.clicked.connect(self.back_button) - self.panel.extrude_select_length_10_btn.toggled.connect( - partial( - self.handle_toggle_extrude_length, - caller=self.panel.extrude_select_length_10_btn, - value=10, + + self.printer.printer_config.connect(self.temperature_page.on_printer_config) + self.printer.request_object_subscription_signal.connect(self._on_object_list) + self.run_gcode_signal.connect(self.ws.api.run_gcode) + # # @ object temperature change clicked + self.printcores_page.pc_accept.clicked.connect(self.handle_swapcore) + + self.ws.klippy_state_signal.connect(self.on_klippy_status) + self.ws.klippy_state_signal.connect(self.probe_helper_page.on_klippy_status) + self.printer.on_printcore_update.connect(self.handle_printcoreupdate) + self.printer.gcode_response.connect(self._handle_gcode_response) + self.printer.z_tilt_update.connect(self._handle_z_tilt_object_update) + + self.cp_button_6.hide() + + self.printer.fan_update[str, str, float].connect( + self.fans_page.on_fan_object_update + ) + self.printer.fan_update[str, str, int].connect( + self.fans_page.on_fan_object_update + ) + self._button_change(False) + + def _button_change(self, active: bool): + self._motion_active = active + for btn in [ + self.cp_button_1, + self.cp_button_2, + self.cp_button_3, + self.cp_button_4, + self.cp_button_5, + self.cp_button_6, + ]: + with contextlib.suppress(RuntimeError, TypeError): + btn.clicked.disconnect() + if active: + self.cp_header_title.setText("Montion") + self.cp_button_1.setText("Auto Home") + + self.cp_button_1.setPixmap( + QtGui.QPixmap(":/motion/media/btn_icons/home_all.svg") ) - ) - self.panel.extrude_select_length_50_btn.toggled.connect( - partial( - self.handle_toggle_extrude_length, - caller=self.panel.extrude_select_length_50_btn, - value=50, + self.cp_button_1.clicked.connect( + lambda: self.run_gcode_signal.emit("G28\nM400") ) - ) - self.panel.extrude_select_length_100_btn.toggled.connect( - partial( - self.handle_toggle_extrude_length, - caller=self.panel.extrude_select_length_100_btn, - value=100, + self.cp_button_2.setText("Disable\nSteppers") + self.cp_button_2.clicked.connect( + lambda: self.run_gcode_signal.emit("M84\nM400") ) - ) - - self.extrude_list = [2, 4, 8] - self.panel.extrude_select_feedrate_low_btn.toggled.connect( - partial( - self.handle_toggle_extrude_feedrate, - caller=self.panel.extrude_select_feedrate_low_btn, - value=self.extrude_list[0], + self.cp_button_2.setPixmap( + QtGui.QPixmap(":/motion/media/btn_icons/disable_steppers.svg") ) - ) - self.panel.extrude_select_feedrate_middle_btn.toggled.connect( - partial( - self.handle_toggle_extrude_feedrate, - caller=self.panel.extrude_select_feedrate_middle_btn, - value=self.extrude_list[1], + self.cp_button_3.setText("Axis") + self.cp_button_3.clicked.connect( + lambda: self.change_page(self.indexOf(self.axis_page)) ) - ) - self.panel.extrude_select_feedrate_high_btn.toggled.connect( - partial( - self.handle_toggle_extrude_feedrate, - caller=self.panel.extrude_select_feedrate_high_btn, - value=self.extrude_list[2], + self.cp_button_3.setPixmap( + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg") + ) + self.cp_button_4.setText("Extruder") + self.cp_button_4.setPixmap( + QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg") + ) + self.cp_button_4.clicked.connect( + lambda: self.change_page(self.indexOf(self.extruder_page)) ) - ) - self.panel.mva_select_length_1_btn.toggled.connect( - partial(self.handle_select_move_length, value=1.0) - ) - self.panel.mva_select_length_10_btn.toggled.connect( - partial(self.handle_select_move_length, value=10.0) - ) - self.panel.mva_select_length_100_btn.toggled.connect( - partial(self.handle_select_move_length, value=100.0) - ) - self.panel.mva_select_speed_25_btn.toggled.connect( - partial(self.handle_select_move_speed, value=25.0) - ) - self.panel.mva_select_speed_50_btn.toggled.connect( - partial(self.handle_select_move_speed, value=50.0) - ) - self.panel.mva_select_speed_100_btn.toggled.connect( - partial(self.handle_select_move_speed, value=100.0) - ) - self.panel.exp_extrude_btn.clicked.connect( - partial(self.handle_extrusion, True) - ) # True for extrusion - self.panel.exp_unextrude_btn.clicked.connect( - partial(self.handle_extrusion, False) - ) # False for retraction - # Move Axis - self.panel.mva_back_btn.clicked.connect(self.back_button) - self.panel.mva_home_x_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "G28 X\nM400") - ) - self.panel.mva_home_y_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "G28 Y\nM400") - ) - self.panel.mva_home_z_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "G28 Z\nM400") - ) - self.panel.mva_home_all_btn.clicked.connect( - partial(self.run_gcode_signal.emit, "G28\nM400") - ) - self.panel.mva_up_btn.clicked.connect(partial(self.handle_move_axis, "Y")) - self.panel.mva_down_btn.clicked.connect(partial(self.handle_move_axis, "Y-")) - self.panel.mva_right_btn.clicked.connect(partial(self.handle_move_axis, "X")) - self.panel.mva_left_btn.clicked.connect(partial(self.handle_move_axis, "X-")) - self.panel.mva_z_up.clicked.connect( - partial(self.handle_move_axis, "Z-") # Move nozzle closer to bed - ) - self.panel.mva_z_down.clicked.connect( - partial(self.handle_move_axis, "Z") # Move nozzle away from bed - ) - self.panel.temp_back_button.clicked.connect(self.back_button) - self.panel.printer_settings_back_btn.clicked.connect(self.back_button) - self.run_gcode_signal.connect(self.ws.api.run_gcode) - # @ object temperature change clicked - self.numpadPage = CustomNumpad(self) - self.numpadPage.setMaximumHeight(400) - self.numpadPage.request_back.connect(self.request_back_button) - self.addWidget(self.numpadPage) - self.request_numpad[str, int, "PyQt_PyObject", int, int].connect( - self.on_numpad_request - ) + self.back_button.show() + self.Hblank.show() + + self.cp_content_layout.addWidget(self.blank, 2, 0, 1, 1) + self.cp_button_5.hide() + self.blank.show() + else: + self.cp_header_title.setText("Control") - self.panel.cooldown_btn.clicked.connect( - lambda: self.run_gcode_signal.emit( - "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=0\n\ - SET_HEATER_TEMPERATURE HEATER=extruder TARGET=0" + self.cp_button_1.setText("Motion\nControl") + self.cp_button_1.setPixmap( + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg") ) - ) + self.cp_button_1.clicked.connect(lambda: self._button_change(True)) - self.path = { - "fan_cage": QtGui.QPixmap(":/fan_related/media/btn_icons/fan_cage.svg"), - "blower": QtGui.QPixmap(":/fan_related/media/btn_icons/blower.svg"), - "fan": QtGui.QPixmap(":/fan_related/media/btn_icons/fan.svg"), - } + self.cp_button_2.setText("Temp.\nControl") + self.cp_button_2.setPixmap( + QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature.svg") + ) + self.cp_button_2.clicked.connect( + lambda: self.change_page(self.indexOf(self.temperature_page)) + ) - self.panel.cp_z_tilt_btn.clicked.connect(lambda: self.handle_ztilt()) + self.cp_button_3.setText("Nozzle\nCalibration") + self.cp_button_3.setPixmap( + QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg") + ) + self.cp_button_3.clicked.connect( + lambda: self.change_page(self.indexOf(self.probe_helper_page)) + ) - self.printcores_page.pc_accept.clicked.connect(self.handle_swapcore) + self.cp_button_4.setText("Z-Tilt") + self.cp_button_4.setPixmap( + QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg") + ) + self.cp_button_4.clicked.connect(lambda: self.handle_ztilt()) - self.ws.klippy_state_signal.connect(self.on_klippy_status) - self.ws.klippy_state_signal.connect(self.probe_helper_page.on_klippy_status) - self.printer.on_printcore_update.connect(self.handle_printcoreupdate) - self.printer.gcode_response.connect(self._handle_gcode_response) - self.printer.z_tilt_update.connect(self._handle_z_tilt_object_update) - # self.panel.cp_printer_settings_btn.hide() - self.panel.temperature_cooldown_btn.hide() - self.panel.cooldown_btn.hide() - self.panel.cp_switch_print_core_btn.hide() + self.cp_button_5.setText("Fans") + self.cp_button_5.setPixmap( + QtGui.QPixmap(":/temperature_related/media/btn_icons/fan.svg") + ) + self.cp_button_5.clicked.connect( + lambda: self.change_page(self.indexOf(self.fans_page)) + ) - self.printer.fan_update[str, str, float].connect(self.on_fan_object_update) - self.printer.fan_update[str, str, int].connect(self.on_fan_object_update) + self.cp_button_6.clicked.connect(self.show_swapcore) - self.printer.printer_config.connect(self.on_printer_config) - self.printer.request_object_subscription_signal.connect(self._on_object_list) - self.ztilt_result_screen_timer = QtCore.QTimer() - self.ztilt_result_screen_timer.setSingleShot(True) - self.ztilt_result_screen_timer.setInterval(5000) - self.ztilt_result_screen_timer.timeout.connect(self.ztilt_result_screen.hide) + self.back_button.hide() + self.Hblank.hide() + self.cp_button_5.show() + self.cp_content_layout.removeWidget(self.blank) + self.blank.hide() + self._apply_true_zero_layout() + self.repaint() + + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: + self._button_change(False) + return super().showEvent(a0) def _handle_z_tilt_object_update(self, value, state): if not self.isVisible(): @@ -311,74 +298,6 @@ def _handle_z_tilt_object_update(self, value, state): self.ztilt_result_screen.show() self.ztilt_result_screen_timer.start() - @QtCore.pyqtSlot(str, str, float, name="on_fan_update") - @QtCore.pyqtSlot(str, str, int, name="on_fan_update") - def on_fan_object_update( - self, name: str, field: str, new_value: int | float - ) -> None: - """Slot that receives updates from fan objects. - - Args: - name (str): Fan object name - field (str): Field name - new_value (int | float): New value for the field - """ - if "speed" not in field: - return - - fields = name.split() - first_field = fields[0] - second_field = fields[1] if len(fields) > 1 else None - name = second_field.replace("_", " ") if second_field else name - - fan_card = self.tune_display_buttons.get(name) - if fan_card is None and first_field in ( - "fan", - "fan_generic", - ): - icon = self.path.get("fan") - if second_field: - second_field = second_field.lower() - pattern_blower = r"(?:^|_)(?:blower|auxiliary)(?:_|$)" - pattern_exhaust = r"(?:^|_)exhaust(?:_|$)" - if re.search(pattern_blower, second_field): - icon = self.path.get("blower") - elif re.search(pattern_exhaust, second_field): - icon = self.path.get("fan_cage") - - card = OptionCard(self, name, str(name), icon) # type: ignore - card.setObjectName(str(name)) - - # Add card to layout and record reference - self.card_options[name] = card - self.panel.fans_content_layout.addWidget(card) - - # If the card doesn't have expected UI properties, discard it - if not hasattr(card, "continue_clicked"): - del card - self.card_options.pop(name, None) - return - - card.setMode(True) - card.secondtext.setText(f"{new_value}%") - card.continue_clicked.connect( - lambda: self.on_slidePage_request( - str(name), - card.secondtext.text().replace("%", ""), - self.on_slider_change, - 0, - 100, - ) - ) - - self.tune_display_buttons[name] = card - self.update() - fan_card = card - - if fan_card: - value_percent = new_value * 100 if new_value <= 1 else new_value - fan_card.secondtext.setText(f"{value_percent:.0f}%") - @QtCore.pyqtSlot(str, int, "PyQt_PyObject", name="on_slidePage_request") @QtCore.pyqtSlot(str, int, "PyQt_PyObject", int, int, name="on_slidePage_request") def on_slidePage_request( @@ -389,7 +308,6 @@ def on_slidePage_request( min_value: int = 0, max_value: int = 100, ) -> None: - with contextlib.suppress(RuntimeError, TypeError): self.sliderPage.value_selected.disconnect() self.sliderPage.value_selected.connect(callback) @@ -399,29 +317,6 @@ def on_slidePage_request( self.sliderPage.set_slider_position(int(current_value)) self.change_page(self.indexOf(self.sliderPage)) - @QtCore.pyqtSlot(str, int, name="on_slider_change") - def on_slider_change(self, name: str, new_value: int) -> None: - """Handle fan slider value change.""" - self.run_gcode_signal.emit(fan_speed_gcode(name, new_value)) - - def create_display_button(self, name: str) -> DisplayButton: - """Create and return a DisplayButton - - Args: - name (str): Name for the display button - - Returns: - DisplayButton: The created DisplayButton object - """ - display_button = DisplayButton() - display_button.setObjectName(str(name + "_display")) - display_button.setMinimumSize(QtCore.QSize(150, 50)) - display_button.setMaximumSize(QtCore.QSize(150, 80)) - font = QtGui.QFont() - font.setPointSize(16) - display_button.setFont(font) - return display_button - def handle_printcoreupdate(self, value: dict): _swapping = value.get("swapping") if _swapping is None or _swapping == "idle": @@ -475,44 +370,6 @@ def _handle_gcode_response(self, messages: list): False, ) - @QtCore.pyqtSlot(dict, name="printer_config") - def on_printer_config(self, config: dict) -> None: - """Slot that receives the full printer configuration, - - Additionally, this method configures the signal connections - between controllable heaters and numpad calls - """ - try: - self.panel.extruder_temp_display.clicked.disconnect() - self.panel.bed_temp_display.clicked.disconnect() - except Exception: - _logger.debug("Signals were not connected") - extruder = config.get("extruder") or {} - bed = config.get("heater_bed") or {} - e_min_temp = extruder.get("min_temp", 0) - e_max_temp = extruder.get("max_temp", 300) - b_max_temp = bed.get("max_temp", 100) - b_min_temp = bed.get("min_temp", 0) - # Configure numpads - self.panel.extruder_temp_display.clicked.connect( - lambda: self.request_numpad[str, int, "PyQt_PyObject", int, int].emit( - "Extruder Temperature", - round(float(self.panel.extruder_temp_display.secondary_text)), - self.on_numpad_change, - int(e_min_temp), - int(e_max_temp), - ) - ) - self.panel.bed_temp_display.clicked.connect( - lambda: self.request_numpad[str, int, "PyQt_PyObject", int, int].emit( - "Bed Temperature", - round(float(self.panel.bed_temp_display.secondary_text)), - self.on_numpad_change, - int(b_min_temp), - int(b_max_temp), - ) - ) - def handle_ztilt(self): """Handle Z-Tilt Adjustment""" self.call_load_panel.emit( @@ -532,25 +389,50 @@ def on_klippy_status(self, state: str): self.printcores_page.setText("Almost done \n be patient") return self._true_zero_state = None - self.panel.cp_nozzles_calibration_btn.setVisible(True) - self._place_fans_btn(row=2) + self._apply_true_zero_layout() @QtCore.pyqtSlot(dict, name="_on_object_list") def _on_object_list(self, objects: dict) -> None: + """Track whether the printer reports a true zero offset probe""" has_true_zero = self.printer.uses_true_zero_offset if has_true_zero == self._true_zero_state: return self._true_zero_state = has_true_zero - self.panel.cp_nozzles_calibration_btn.setVisible(not has_true_zero) - self._place_fans_btn(row=1 if has_true_zero else 2) - - def _place_fans_btn(self, row: int) -> None: - layout = self.panel.cp_content_layout - layout.removeWidget(self.panel.cp_fans_btn) - layout.addWidget(self.panel.cp_fans_btn, row, 0, 1, 1) - # When fans moves to row 1, row 2 is empty — pin its height so the - # grid doesn't shrink and shift the "Control" header. - layout.setRowMinimumHeight(2, 80 if row == 1 else 0) + self._apply_true_zero_layout() + + def _apply_true_zero_layout(self) -> None: + """When true zero is used, repurpose the nozzle-calibration slot as a + second Fans button and hide the dedicated one, instead of moving + widgets between grid cells (QGridLayout doesn't fully forget a + widget's old cell after removeWidget/addWidget, which shifts the + whole page by a few px).""" + if self._motion_active: + return + has_true_zero = bool(self._true_zero_state) + with contextlib.suppress(RuntimeError, TypeError): + self.cp_button_3.clicked.disconnect() + if has_true_zero: + self.cp_button_3.setText("Fans") + self.cp_button_3.setPixmap( + QtGui.QPixmap(":/temperature_related/media/btn_icons/fan.svg") + ) + self.cp_button_3.clicked.connect( + lambda: self.change_page(self.indexOf(self.fans_page)) + ) + self.cp_button_5.hide() + self.cp_content_layout.addWidget(self.blank, 2, 0, 1, 1) + self.blank.show() + else: + self.cp_button_3.setText("Nozzle\nCalibration") + self.cp_button_3.setPixmap( + QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg") + ) + self.cp_button_3.clicked.connect( + lambda: self.change_page(self.indexOf(self.probe_helper_page)) + ) + self.cp_content_layout.removeWidget(self.blank) + self.blank.hide() + self.cp_button_5.show() def show_swapcore(self): """Show swap printcore""" @@ -583,179 +465,150 @@ def on_numpad_request( self.numpadPage.set_max_value(max_value) self.change_page(self.indexOf(self.numpadPage)) - @QtCore.pyqtSlot(str, int, name="on-numpad-change") - def on_numpad_change(self, name: str, new_value: int) -> None: - """Handles inputted numpad values""" - if "bed" in name.lower(): - name = "heater_bed" - elif "extruder" in name.lower(): - name = "extruder" - self.run_gcode_signal.emit( - f"SET_HEATER_TEMPERATURE HEATER={name} TARGET={new_value}" - ) - def change_page(self, index): """Handles changing page""" self.request_change_page.emit(2, index) - def back_button(self): - """Handle back button click""" - self.request_back_button.emit() - - def register_timed_callback(self, time: int, callback: callable) -> None: - """Registers timed callback and starts the timeout""" - _timer = QtCore.QTimer() - _timer.setSingleShot(True) - _timer.timeout.connect(callback) - _timer.start(int(time)) - self.timers.append(_timer) - - @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-feedrate") - def handle_toggle_extrude_feedrate(self, checked: bool, caller, value: int) -> None: - """Slot to change the extruder feedrate, mainly used for toggle buttons - - Args: - checked (bool): Button checked state - caller (PyQtObject): The button that called this slot - value (int): New value for the extruder feedrate - """ - if value == self.extrude_feedrate: - return - self.extrude_feedrate = value - - @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-length") - def handle_toggle_extrude_length(self, checked: bool, caller, value: int) -> None: - """Slot that changes the extrude length, mainly used for toggle buttons - - Args: - checked (bool): Button checked state - caller (PyQtObject): The button that called this slot - value (int): New value for the extrude length - """ - if self.extrude_length == value: - return - self.extrude_length = value - - @QtCore.pyqtSlot(bool, float, name="handle-select-move-speed") - def handle_select_move_speed(self, checked: bool, value: float) -> None: - """Slot that changes the move speed of manual move commands, mainly used - for toggle buttons - - Args: - checked (bool): Button checked state - value (float): New move speed value - """ - if self.move_speed == value: - return - self.move_speed = value + def _setup_ui(self) -> None: + """Build the control tab page: header, back button, and option grid.""" + self.resize(710, 410) + root = QtWidgets.QWidget() + root.setObjectName("control_page") + root.setMinimumSize(QtCore.QSize(710, 410)) + root.setMaximumSize(QtCore.QSize(710, 410)) - @QtCore.pyqtSlot(bool, float, name="handle-select-move-length") - def handle_select_move_length(self, checked: bool, value: float) -> None: - """Slot that changes the move length of manual move commands, - mainly used for toggle buttons + self.blank = QtWidgets.QWidget() + self.blank.setMinimumSize(QtCore.QSize(250, 80)) + self.blank.setMaximumSize(QtCore.QSize(250, 80)) + self.Hblank = QtWidgets.QWidget() + self.Hblank.setMinimumSize(QtCore.QSize(60, 60)) + self.Hblank.setMaximumSize(QtCore.QSize(60, 60)) - Args: - checked (bool): Button checked state - value (float): New length value - """ - if self.move_length == value: - return - self.move_length = value - - @QtCore.pyqtSlot(str, name="handle-extrusion") - def handle_extrusion(self, extrude: bool) -> None: - """Slot that requests an extrusion/unextrusion move - - Args: - extrude (bool): If True extrudes otherwise unextrudes. - """ - can_extrude = bool(self.printer.heaters_object["extruder"]["can_extrude"]) - if not can_extrude: - self.extrude_page_message = "Temperature too cold to extrude" - self.panel.exp_info_label.setText(self.extrude_page_message) - return - if extrude: - self.run_gcode_signal.emit( - f"M83\nG1 E{self.extrude_length}" - f" F{self.extrude_feedrate * 60}\nM82\nM400" - ) - self.extrude_page_message = "Extruding" - self.panel.exp_info_label.setText(self.extrude_page_message) - else: - self.run_gcode_signal.emit( - f"M83\nG1 E-{self.extrude_length}" - f" F{self.extrude_feedrate * 60}\nM82\nM400" - ) - self.extrude_page_message = "Retracting" - self.panel.exp_info_label.setText(self.extrude_page_message) - # This block of code schedules a method to be called in x amount of milliseconds - _sch_time_s = float( - self.extrude_length / self.extrude_feedrate - ) # calculate the amount of time it'll take for the operation - self.extrude_page_message = "Ready" - self.register_timed_callback( - int(_sch_time_s + 2.0) * 1000, # In milliseconds - lambda: self.panel.exp_info_label.setText(self.extrude_page_message), - ) + self.verticalLayout = QtWidgets.QVBoxLayout(root) + self.verticalLayout.setObjectName("verticalLayout") - @QtCore.pyqtSlot(str, name="handle-move-axis") - def handle_move_axis(self, axis: str) -> None: - """Slot that requests manual move command + self.cp_header_layout = QtWidgets.QHBoxLayout() + self.cp_header_layout.setObjectName("cp_header_layout") - Args: - axis (str): String that contains one of the following axis ` - ['X', - 'X-' - ,'Y' - ,'Y-' - ,'Z' - ,'Z-']`. [^1] + self.cp_header_layout.addWidget(self.Hblank) - --- + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.cp_header_title = QtWidgets.QLabel(parent=root) + self.cp_header_title.setSizePolicy(sizePolicy) + self.cp_header_title.setMinimumSize(QtCore.QSize(0, 60)) + self.cp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + self.cp_header_title.setFont(font) + self.cp_header_title.setStyleSheet("background: transparent; color: white;") + self.cp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cp_header_layout.addWidget(self.cp_header_title) - [^1]: The **-** symbol indicates the negative direction for that axis + self.back_button = IconButton(parent=self) + self.back_button.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.back_button.setMinimumSize(QtCore.QSize(60, 60)) + self.back_button.setMaximumSize(QtCore.QSize(60, 60)) + self.cp_header_layout.addWidget(self.back_button) - """ - if axis not in ["X", "X-", "Y", "Y-", "Z", "Z-"]: - return - self.run_gcode_signal.emit( - f"G91\nG0 {axis}{float(self.move_length)}" - f" F{float(self.move_speed * 60)}\nG90\nM400" - ) + self.verticalLayout.addLayout(self.cp_header_layout) - @QtCore.pyqtSlot(str, list, name="on-toolhead-update") - def on_toolhead_update(self, field: str, values: list) -> None: - """Handles updated from toolhead printer object""" - if field == "position": - self.panel.mva_x_value_label.setText(f"{values[0]:.2f}") - self.panel.mva_y_value_label.setText(f"{values[1]:.2f}") - self.panel.mva_z_value_label.setText(f"{values[2]:.3f}") + self.cp_content_layout = QtWidgets.QGridLayout() + self.cp_content_layout.setObjectName("cp_content_layout") - self.toolhead_info.update({f"{field}": values}) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) - @QtCore.pyqtSlot(str, str, float, name="on-extruder-update") - def on_extruder_update( - self, extruder_name: str, field: str, new_value: float - ) -> None: - """Handles updates from extruder printer object""" - if extruder_name == "extruder" and field == "temperature": - self.panel.extruder_temp_display.setText(f"{new_value:.1f}") - if extruder_name == "extruder" and field == "target": - self.panel.extruder_temp_display.secondary_text = f"{new_value:.1f}" - self.extruder_info.update({f"{extruder_name}": {f"{field}": new_value}}) - - @QtCore.pyqtSlot(str, str, float, name="on-heater-bed-update") - def on_heater_bed_update(self, name: str, field: str, new_value: float) -> None: - """Handles updated from heater_bed printer object""" - if field == "temperature": - self.panel.bed_temp_display.setText(f"{new_value:.1f}") - if field == "target": - self.panel.bed_temp_display.secondary_text = f"{new_value:.1f}" - self.bed_info.update({f"{name}": {f"{field}": new_value}}) - - def paintEvent(self, a0: QtGui.QPaintEvent) -> None: - """Handles ControlTab Widget painting""" - if self.panel.extrude_page.isVisible(): - self.panel.exp_info_label.setText(self.extrude_page_message) - return super().paintEvent(a0) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + + self.cp_button_1 = BlocksCustomButton(parent=root) + self.cp_button_1.setSizePolicy(sizePolicy) + self.cp_button_1.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_1.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_1.setFont(font) + self.cp_button_1.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), + ) + self.cp_content_layout.addWidget(self.cp_button_1, 0, 0, 1, 1) + + self.cp_button_2 = BlocksCustomButton(parent=root) + self.cp_button_2.setSizePolicy(sizePolicy) + self.cp_button_2.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_2.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_2.setFont(font) + self.cp_content_layout.addWidget(self.cp_button_2, 0, 1, 1, 1) + + self.cp_button_3 = BlocksCustomButton(parent=root) + self.cp_button_3.setSizePolicy(sizePolicy) + self.cp_button_3.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_3.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_3.setFont(font) + self.cp_button_3.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg") + ) + self.cp_content_layout.addWidget(self.cp_button_3, 1, 0, 1, 1) + + self.cp_button_4 = BlocksCustomButton(parent=root) + self.cp_button_4.setSizePolicy(sizePolicy) + self.cp_button_4.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_4.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_4.setFont(font) + self.cp_button_4.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg"), + ) + self.cp_content_layout.addWidget(self.cp_button_4, 1, 1, 1, 1) + + self.cp_button_5 = BlocksCustomButton(parent=root) + self.cp_button_5.setSizePolicy(sizePolicy) + self.cp_button_5.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_5.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_5.setFont(font) + self.cp_button_5.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg") + ) + self.cp_content_layout.addWidget(self.cp_button_5, 2, 0, 1, 1) + + self.cp_button_6 = BlocksCustomButton(parent=root) + self.cp_button_6.setSizePolicy(sizePolicy) + self.cp_button_6.setMinimumSize(QtCore.QSize(250, 80)) + self.cp_button_6.setMaximumSize(QtCore.QSize(250, 80)) + self.cp_button_6.setFont(font) + self.cp_button_6.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") + ) + self.cp_content_layout.addWidget(self.cp_button_6, 2, 1, 1, 1) + self.cp_content_layout.setRowMinimumHeight(0, 80) + self.cp_content_layout.setRowMinimumHeight(1, 80) + self.cp_content_layout.setRowMinimumHeight(2, 80) + + content_widget = QtWidgets.QWidget(parent=root) + content_widget.setLayout(self.cp_content_layout) + content_widget.setSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + self.cp_content_layout.setContentsMargins(0, 0, 0, 0) + content_widget.setFixedHeight(self.cp_content_layout.sizeHint().height()) + self.verticalLayout.addWidget(content_widget) + + _translate = QtCore.QCoreApplication.translate + self.setWindowTitle(_translate("controlStackedWidget", "StackedWidget")) + self.cp_header_title.setText(_translate("controlStackedWidget", "Control")) + + self.cp_button_1.setText(_translate("controlStackedWidget", "Motion\nControl")) + self.cp_button_2.setText(_translate("controlStackedWidget", "Temp.\nControl")) + self.cp_button_3.setText( + _translate("controlStackedWidget", "Nozzle\nCalibration") + ) + self.cp_button_4.setText(_translate("controlStackedWidget", "Z-Tilt")) + self.cp_button_5.setText(_translate("controlStackedWidget", "Fans")) + self.cp_button_6.setText(_translate("controlStackedWidget", "Swap\nPrint Core")) + self.addWidget(root) diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index 5a3364a43..8b7f007d3 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -217,13 +217,13 @@ def __init__(self): self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) self.bed_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) self.filament_type_icon.clicked.connect( @@ -507,13 +507,13 @@ def on_cancel_print(self): self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) self.bed_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) @@ -1264,13 +1264,13 @@ def event(self, event: QtCore.QEvent) -> bool: self.extruder_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) self.bed_temp_display.clicked.connect( lambda: self.global_change_page( self.main_content_widget.indexOf(self.controlTab), - self.controlPanel.indexOf(self.controlPanel.panel.temperature_page), + self.controlPanel.indexOf(self.controlPanel.temperature_page), ) ) return False diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py new file mode 100644 index 000000000..026915fdb --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py @@ -0,0 +1,581 @@ +"""Control tab axis page: jog XYZ, pick move length/speed, home and disable steppers.""" + +import typing + +from lib.utils.check_button import BlocksCustomCheckButton +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class AxisPage(QtWidgets.QWidget): + """Axis movement page of the control tab.""" + + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run_gcode" + ) + request_back = QtCore.pyqtSignal(name="request_back") + + call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") + + def __init__(self, parent: QtWidgets.QWidget) -> None: + super().__init__(parent) + + self.setObjectName("axis_page") + self._setup_ui() + + self.update() + + self.move_length: float = 1.0 + self.move_speed: float = 25.0 + + self.mva_back_btn.clicked.connect(self.request_back.emit) + self.mva_home_x_btn.clicked.connect( + lambda: self.run_gcode_signal.emit("G28 X\nM400") + ) + self.mva_home_y_btn.clicked.connect( + lambda: self.run_gcode_signal.emit("G28 Y\nM400") + ) + self.mva_home_z_btn.clicked.connect( + lambda: self.run_gcode_signal.emit("G28 Z\nM400") + ) + self.mva_home_all_btn.clicked.connect( + lambda: self.run_gcode_signal.emit("G28\nM400") + ) + + self.mva_up_btn.clicked.connect(lambda: self.handle_move_axis("Y")) + self.mva_down_btn.clicked.connect(lambda: self.handle_move_axis("Y-")) + self.mva_right_btn.clicked.connect(lambda: self.handle_move_axis("X")) + self.mva_left_btn.clicked.connect(lambda: self.handle_move_axis("X-")) + self.mva_z_up.clicked.connect( + lambda: self.handle_move_axis("Z-") # Move nozzle closer to bed + ) + self.mva_z_down.clicked.connect( + lambda: self.handle_move_axis("Z") # Move nozzle away from bed + ) + + self.mva_select_length_1_btn.toggled.connect( + lambda checked: self.handle_select_move_length(checked, value=1.0) + ) + self.mva_select_length_10_btn.toggled.connect( + lambda checked: self.handle_select_move_length(checked, value=10.0) + ) + self.mva_select_length_100_btn.toggled.connect( + lambda checked: self.handle_select_move_length(checked, value=100.0) + ) + self.mva_select_speed_25_btn.toggled.connect( + lambda checked: self.handle_select_move_speed(checked, value=25.0) + ) + self.mva_select_speed_50_btn.toggled.connect( + lambda checked: self.handle_select_move_speed(checked, value=50.0) + ) + self.mva_select_speed_100_btn.toggled.connect( + lambda checked: self.handle_select_move_speed(checked, value=100.0) + ) + + @QtCore.pyqtSlot(bool, float, name="handle-select-move-speed") + def handle_select_move_speed(self, checked: bool, value: float) -> None: + """Slot that changes the move speed of manual move commands, mainly used + for toggle buttons + + Args: + checked (bool): Button checked state + value (float): New move speed value + """ + if self.move_speed == value: + return + self.move_speed = value + + @QtCore.pyqtSlot(bool, float, name="handle-select-move-length") + def handle_select_move_length(self, checked: bool, value: float) -> None: + """Slot that changes the move length of manual move commands, + mainly used for toggle buttons + + + Args: + checked (bool): Button checked state + value (float): New length value + """ + if self.move_length == value: + return + self.move_length = value + + @QtCore.pyqtSlot(str, name="handle-move-axis") + def handle_move_axis(self, axis: str) -> None: + """Slot that requests manual move command + + Args: + axis (str): String that contains one of the following axis ` + ['X', + 'X-' + ,'Y' + ,'Y-' + ,'Z' + ,'Z-']`. [^1] + + --- + + [^1]: The **-** symbol indicates the negative direction for that axis + + """ + if axis not in ["X", "X-", "Y", "Y-", "Z", "Z-"]: + return + self.run_gcode_signal.emit( + f"G91\nG0 {axis}{float(self.move_length)} F{float(self.move_speed * 60)}\nG90\nM400" + ) + + @QtCore.pyqtSlot(str, list, name="on-toolhead-update") + def on_toolhead_update(self, field: str, values: list) -> None: + """Handles updated from toolhead printer object""" + if field == "position": + self.mva_x_value_label.setText(f"{values[0]:.2f}") + self.mva_y_value_label.setText(f"{values[1]:.2f}") + self.mva_z_value_label.setText(f"{values[2]:.3f}") + + if values[0] == "252,50" and values[1] == "250" and values[2] == "50": + self.call_load_panel.emit(False, "", False) + + def _setup_ui(self) -> None: + """Build the axis page: jog pads, step selector, and status labels.""" + widget = QtWidgets.QWidget(parent=self) + widget.setMinimumSize(QtCore.QSize(710, 410)) + widget.setMaximumSize(QtCore.QSize(710, 410)) + self.setObjectName("move_axis_page") + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setObjectName("verticalLayout") + self.mva_header_layout = QtWidgets.QHBoxLayout() + self.mva_header_layout.setObjectName("mva_header_layout") + spacerItem2 = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.mva_header_layout.addItem(spacerItem2) + self.mva_title_label = QtWidgets.QLabel(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth( + self.mva_title_label.sizePolicy().hasHeightForWidth() + ) + self.mva_title_label.setSizePolicy(sizePolicy) + self.mva_title_label.setMinimumSize(QtCore.QSize(0, 0)) + self.mva_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.mva_title_label.setFont(font) + self.mva_title_label.setStyleSheet("background: transparent; color: white;") + self.mva_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.mva_title_label.setObjectName("mva_title_label") + self.mva_header_layout.addWidget(self.mva_title_label) + + self.mva_back_btn = IconButton(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed + ) + self.mva_back_btn.setSizePolicy(sizePolicy) + self.mva_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.mva_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.mva_back_btn.setObjectName("mva_back_btn") + self.mva_header_layout.addWidget( + self.mva_back_btn, + 0, + QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + + self.verticalLayout.addLayout(self.mva_header_layout) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.mva_home_axis_layout = QtWidgets.QVBoxLayout() + self.mva_home_axis_layout.setContentsMargins(5, 5, 5, 5) + self.mva_home_axis_layout.setObjectName("mva_home_axis_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + + self.mva_home_x_btn = IconButton(parent=self) + self.mva_home_x_btn.setSizePolicy(sizePolicy) + self.mva_home_x_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_home_x_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_home_x_btn.setObjectName("mva_home_x_btn") + self.mva_home_x_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_x.svg") + ) + self.mva_home_axis_layout.addWidget( + self.mva_home_x_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.mva_home_y_btn = IconButton(parent=self) + self.mva_home_y_btn.setSizePolicy(sizePolicy) + self.mva_home_y_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_home_y_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_home_y_btn.setObjectName("mva_home_y_btn") + self.mva_home_y_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_y.svg") + ) + self.mva_home_axis_layout.addWidget( + self.mva_home_y_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.mva_home_z_btn = IconButton(parent=self) + self.mva_home_z_btn.setSizePolicy(sizePolicy) + self.mva_home_z_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_home_z_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_home_z_btn.setObjectName("mva_home_z_btn") + self.mva_home_z_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_z.svg") + ) + self.mva_home_axis_layout.addWidget( + self.mva_home_z_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.mva_home_all_btn = IconButton(parent=self) + self.mva_home_all_btn.setSizePolicy(sizePolicy) + self.mva_home_all_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_home_all_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_home_all_btn.setObjectName("mva_home_all_btn") + self.mva_home_all_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_all.svg") + ) + self.mva_home_axis_layout.addWidget( + self.mva_home_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.horizontalLayout_2.addLayout(self.mva_home_axis_layout) + self.verticalLayout_6 = QtWidgets.QVBoxLayout() + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.label_2 = QtWidgets.QLabel(parent=self) + self.label_2.setMaximumSize(QtCore.QSize(16777215, 20)) + font = QtGui.QFont() + font.setPointSize(14) + self.label_2.setFont(font) + self.label_2.setStyleSheet("color:white") + self.label_2.setObjectName("label_2") + self.verticalLayout_6.addWidget(self.label_2) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + + self.axis_select_length_group = QtWidgets.QButtonGroup(self) + self.axis_select_length_group.setObjectName("extrude_select_length_group") + + self.mva_select_length_1_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_length_1_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_length_1_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_length_1_btn.setFont(font) + self.mva_select_length_1_btn.setCheckable(True) + self.mva_select_length_1_btn.setChecked(True) + self.mva_select_length_1_btn.setAutoExclusive(True) + self.mva_select_length_1_btn.setObjectName("mva_select_length_1_btn") + self.axis_select_length_group.addButton(self.mva_select_length_1_btn) + self.horizontalLayout_3.addWidget(self.mva_select_length_1_btn) + + self.mva_select_length_10_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_length_10_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_length_10_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_length_10_btn.setFont(font) + self.mva_select_length_10_btn.setCheckable(True) + self.mva_select_length_10_btn.setAutoExclusive(True) + self.mva_select_length_10_btn.setObjectName("mva_select_length_10_btn") + self.axis_select_length_group.addButton(self.mva_select_length_10_btn) + self.horizontalLayout_3.addWidget(self.mva_select_length_10_btn) + + self.mva_select_length_100_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_length_100_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_length_100_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_length_100_btn.setFont(font) + self.mva_select_length_100_btn.setAutoExclusive(True) + self.mva_select_length_100_btn.setCheckable(True) + self.mva_select_length_100_btn.setObjectName("mva_select_length_100_btn") + self.axis_select_length_group.addButton(self.mva_select_length_100_btn) + self.horizontalLayout_3.addWidget(self.mva_select_length_100_btn) + + self.verticalLayout_6.addLayout(self.horizontalLayout_3) + self.label = QtWidgets.QLabel(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) + self.label.setSizePolicy(sizePolicy) + self.label.setMaximumSize(QtCore.QSize(16777215, 20)) + + self.label.setFont(font) + self.label.setStyleSheet("color:white") + self.label.setObjectName("label") + self.verticalLayout_6.addWidget(self.label) + self.horizontalLayout_4 = QtWidgets.QHBoxLayout() + self.horizontalLayout_4.setObjectName("horizontalLayout_4") + + self.axis_select_speed_group = QtWidgets.QButtonGroup(self) + self.axis_select_speed_group.setObjectName("extrude_select_length_group") + + self.mva_select_speed_25_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_speed_25_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_25_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_25_btn.setFont(font) + self.mva_select_speed_25_btn.setCheckable(True) + self.mva_select_speed_25_btn.setChecked(True) + self.mva_select_speed_25_btn.setAutoExclusive(True) + self.mva_select_speed_25_btn.setObjectName("mva_select_speed_25_btn") + self.axis_select_speed_group.addButton(self.mva_select_speed_25_btn) + self.horizontalLayout_4.addWidget(self.mva_select_speed_25_btn) + + self.mva_select_speed_50_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_speed_50_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_50_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_50_btn.setFont(font) + self.mva_select_speed_50_btn.setCheckable(True) + self.mva_select_speed_50_btn.setAutoExclusive(True) + self.mva_select_speed_50_btn.setObjectName("mva_select_speed_50_btn") + self.axis_select_speed_group.addButton(self.mva_select_speed_50_btn) + self.horizontalLayout_4.addWidget(self.mva_select_speed_50_btn) + + self.mva_select_speed_100_btn = BlocksCustomCheckButton(parent=self) + self.mva_select_speed_100_btn.setMinimumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_100_btn.setMaximumSize(QtCore.QSize(90, 90)) + self.mva_select_speed_100_btn.setFont(font) + self.mva_select_speed_100_btn.setCheckable(True) + self.mva_select_speed_100_btn.setAutoExclusive(True) + self.mva_select_speed_100_btn.setObjectName("mva_select_speed_100_btn") + self.axis_select_speed_group.addButton(self.mva_select_speed_100_btn) + self.horizontalLayout_4.addWidget(self.mva_select_speed_100_btn) + + self.verticalLayout_6.addLayout(self.horizontalLayout_4) + self.horizontalLayout_2.addLayout(self.verticalLayout_6) + self.horizontalLayout_5 = QtWidgets.QHBoxLayout() + self.horizontalLayout_5.setObjectName("horizontalLayout_5") + self.gridLayout_2 = QtWidgets.QGridLayout() + self.gridLayout_2.setContentsMargins(0, 5, 0, 5) + self.gridLayout_2.setObjectName("gridLayout_2") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + + self.mva_left_btn = IconButton(parent=self) + self.mva_left_btn.setSizePolicy(sizePolicy) + self.mva_left_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_left_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_left_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/left_arrow.svg") + ) + self.mva_left_btn.setObjectName("mva_left_btn") + self.gridLayout_2.addWidget( + self.mva_left_btn, 1, 0, 1, 1, QtCore.Qt.AlignmentFlag.AlignRight + ) + + self.mva_right_btn = IconButton(parent=self) + self.mva_right_btn.setSizePolicy(sizePolicy) + self.mva_right_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_right_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_right_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg"), + ) + self.mva_right_btn.setObjectName("mva_right_btn") + self.gridLayout_2.addWidget( + self.mva_right_btn, 1, 2, 1, 1, QtCore.Qt.AlignmentFlag.AlignLeft + ) + + self.mva_down_btn = IconButton(parent=self) + self.mva_down_btn.setSizePolicy(sizePolicy) + self.mva_down_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_down_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_down_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg") + ) + self.mva_down_btn.setObjectName("mva_down_btn") + self.gridLayout_2.addWidget( + self.mva_down_btn, 2, 1, 1, 1, QtCore.Qt.AlignmentFlag.AlignTop + ) + + self.mva_up_btn = IconButton(parent=self) + self.mva_up_btn.setSizePolicy(sizePolicy) + self.mva_up_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_up_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_up_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg") + ) + self.mva_up_btn.setObjectName("mva_up_btn") + self.gridLayout_2.addWidget( + self.mva_up_btn, 0, 1, 1, 1, QtCore.Qt.AlignmentFlag.AlignBottom + ) + + self.mva_middle = IconButton(parent=self) + self.mva_middle.setSizePolicy(sizePolicy) + self.mva_middle.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_middle.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_middle.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/center_arrows.svg") + ) + self.mva_middle.setObjectName("mva_middle") + + self.gridLayout_2.addWidget(self.mva_middle, 1, 1, 1, 1) + self.horizontalLayout_5.addLayout(self.gridLayout_2) + + self.mva_z_layout = QtWidgets.QVBoxLayout() + self.mva_z_layout.setObjectName("mva_z_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + + self.mva_z_up = IconButton(parent=self) + self.mva_z_up.setSizePolicy(sizePolicy) + self.mva_z_up.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_z_up.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_z_up.setIconSize(QtCore.QSize(16, 16)) + self.mva_z_up.setProperty( + "icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg") + ) + self.mva_z_up.setObjectName("mva_z_up") + self.mva_z_layout.addWidget( + self.mva_z_up, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.mva_z_down = IconButton(parent=self) + self.mva_z_down.setSizePolicy(sizePolicy) + self.mva_z_down.setMinimumSize(QtCore.QSize(60, 60)) + self.mva_z_down.setMaximumSize(QtCore.QSize(60, 60)) + self.mva_z_down.setProperty( + "icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg") + ) + self.mva_z_down.setObjectName("mva_z_down") + self.mva_z_layout.addWidget( + self.mva_z_down, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.horizontalLayout_5.addLayout(self.mva_z_layout) + self.horizontalLayout_2.addLayout(self.horizontalLayout_5) + self.verticalLayout.addLayout(self.horizontalLayout_2) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.mva_x_label = QtWidgets.QLabel(parent=self) + self.mva_x_label.setEnabled(True) + + self.mva_x_label.setFont(font) + self.mva_x_label.setStyleSheet("background: transparent; color: white;") + self.mva_x_label.setObjectName("mva_x_label") + self.horizontalLayout_6.addWidget( + self.mva_x_label, 0, QtCore.Qt.AlignmentFlag.AlignRight + ) + self.mva_x_value_label = QtWidgets.QLabel(parent=self) + self.mva_x_value_label.setEnabled(True) + + self.mva_x_value_label.setFont(font) + self.mva_x_value_label.setStyleSheet("background: transparent; color: white;") + self.mva_x_value_label.setObjectName("mva_x_value_label") + self.horizontalLayout_6.addWidget(self.mva_x_value_label) + self.mva_y_label = QtWidgets.QLabel(parent=self) + self.mva_y_label.setEnabled(True) + + self.mva_y_label.setFont(font) + self.mva_y_label.setStyleSheet("background: transparent; color: white;") + self.mva_y_label.setObjectName("mva_y_label") + self.horizontalLayout_6.addWidget( + self.mva_y_label, 0, QtCore.Qt.AlignmentFlag.AlignRight + ) + self.mva_y_value_label = QtWidgets.QLabel(parent=self) + self.mva_y_value_label.setEnabled(True) + + self.mva_y_value_label.setFont(font) + self.mva_y_value_label.setStyleSheet("background: transparent; color: white;") + self.mva_y_value_label.setObjectName("mva_y_value_label") + self.horizontalLayout_6.addWidget(self.mva_y_value_label) + self.mva_z_label = QtWidgets.QLabel(parent=self) + self.mva_z_label.setEnabled(True) + + self.mva_z_label.setFont(font) + self.mva_z_label.setStyleSheet("background: transparent; color: white;") + self.mva_z_label.setObjectName("mva_z_label") + self.horizontalLayout_6.addWidget( + self.mva_z_label, 0, QtCore.Qt.AlignmentFlag.AlignRight + ) + self.mva_z_value_label = QtWidgets.QLabel(parent=self) + self.mva_z_value_label.setEnabled(True) + + self.mva_z_value_label.setFont(font) + self.mva_z_value_label.setStyleSheet("background: transparent; color: white;") + self.mva_z_value_label.setObjectName("mva_z_value_label") + self.horizontalLayout_6.addWidget(self.mva_z_value_label) + self.verticalLayout.addLayout(self.horizontalLayout_6) + widget.setLayout(self.verticalLayout) + + _translate = QtCore.QCoreApplication.translate + self.mva_x_label.setText(_translate("controlStackedWidget", "X:")) + self.mva_y_label.setText(_translate("controlStackedWidget", "Y:")) + self.mva_z_label.setText(_translate("controlStackedWidget", "Z:")) + self.mva_z_value_label.setText(_translate("controlStackedWidget", "0")) + self.mva_y_value_label.setText(_translate("controlStackedWidget", "0")) + self.mva_x_value_label.setText(_translate("controlStackedWidget", "0")) + self.mva_title_label.setText(_translate("controlStackedWidget", "Move Axis")) + self.mva_title_label.setProperty( + "class", _translate("controlStackedWidget", "title_text") + ) + self.mva_back_btn.setText(_translate("controlStackedWidget", "Back")) + self.mva_back_btn.setProperty( + "class", _translate("controlStackedWidget", "menu_btn") + ) + self.mva_back_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_z_up.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_z_down.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_home_x_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_home_y_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_home_z_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_home_all_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_select_speed_25_btn.setText(_translate("controlStackedWidget", "25")) + self.mva_select_speed_50_btn.setText(_translate("controlStackedWidget", "50")) + self.mva_select_speed_100_btn.setText(_translate("controlStackedWidget", "100")) + self.label.setText(_translate("controlStackedWidget", "Move Speed mm/s")) + self.mva_select_length_1_btn.setText(_translate("controlStackedWidget", "1")) + self.mva_select_length_10_btn.setText(_translate("controlStackedWidget", "10")) + self.mva_select_length_100_btn.setText( + _translate("controlStackedWidget", "100") + ) + self.label_2.setText(_translate("controlStackedWidget", "Move Length mm")) + self.mva_left_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_right_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_down_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_up_btn.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) + self.mva_middle.setProperty( + "button_type", _translate("controlStackedWidget", "icon") + ) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py new file mode 100644 index 000000000..1a058896c --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py @@ -0,0 +1,512 @@ +"""Control tab extruder page: manual extrude/retract with feedrate and length picks.""" + +import typing + +from lib.printer import Printer +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_label import BlocksLabel +from lib.utils.check_button import BlocksCustomCheckButton +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class ExtruderPage(QtWidgets.QWidget): + """Filament extrude/retract page of the control tab.""" + + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run_gcode" + ) + + request_back = QtCore.pyqtSignal(name="request-back-button") + + def __init__( + self, + parent: QtWidgets.QWidget, + printer: Printer, + ) -> None: + super().__init__(parent) + + self.setObjectName("extruder_page") + self.extrude_list: list[int] = [2, 4, 8] + self._setup_ui() + + self.update() + + self.printer: Printer = printer + self.timers = [] + self.extrude_length: int = 10 + self.extrude_feedrate: int = 2 + self.extrude_page_message: str = "" + + self.exp_extrude_btn.clicked.connect( + lambda: self.handle_extrusion(True) + ) # True for extrusion + self.exp_unextrude_btn.clicked.connect( + lambda: self.handle_extrusion(False) + ) # False for retraction + + self.exp_back_btn.clicked.connect(self.request_back.emit) + self.extrude_select_length_10_btn.toggled.connect( + lambda: self.handle_toggle_extrude_length( + caller=self.extrude_select_length_10_btn, value=10 + ) + ) + self.extrude_select_length_50_btn.toggled.connect( + lambda: self.handle_toggle_extrude_length( + caller=self.extrude_select_length_50_btn, value=50 + ) + ) + self.extrude_select_length_100_btn.toggled.connect( + lambda: self.handle_toggle_extrude_length( + caller=self.extrude_select_length_100_btn, value=100 + ) + ) + self.extrude_select_feedrate_low_btn.toggled.connect( + lambda: self.handle_toggle_extrude_feedrate( + caller=self.extrude_select_feedrate_low_btn, + value=self.extrude_list[0], + ) + ) + self.extrude_select_feedrate_middle_btn.toggled.connect( + lambda: self.handle_toggle_extrude_feedrate( + caller=self.extrude_select_feedrate_middle_btn, + value=self.extrude_list[1], + ) + ) + self.extrude_select_feedrate_high_btn.toggled.connect( + lambda: self.handle_toggle_extrude_feedrate( + caller=self.extrude_select_feedrate_high_btn, + value=self.extrude_list[2], + ) + ) + + @QtCore.pyqtSlot(str, name="handle-extrusion") + def handle_extrusion(self, extrude: bool) -> None: + """Slot that requests an extrusion/unextrusion move + + Args: + extrude (bool): If True extrudes otherwise unextrudes. + """ + can_extrude = bool(self.printer.heaters_object["extruder"]["can_extrude"]) + if not can_extrude: + self.extrude_page_message = "Temperature too cold to extrude" + self.exp_info_label.setText(self.extrude_page_message) + return + if extrude: + self.run_gcode_signal.emit( + f"M83\nG1 E{self.extrude_length} F{self.extrude_feedrate * 60}\nM82\nM400" + ) + self.extrude_page_message = "Extruding" + self.exp_info_label.setText(self.extrude_page_message) + else: + self.run_gcode_signal.emit( + f"M83\nG1 E-{self.extrude_length} F{self.extrude_feedrate * 60}\nM82\nM400" + ) + self.extrude_page_message = "Retracting" + self.exp_info_label.setText(self.extrude_page_message) + # This block of code schedules a method to be called in x amount of milliseconds + _sch_time_s = float( + self.extrude_length / self.extrude_feedrate + ) # calculate the amount of time it'll take for the operation + self.extrude_page_message = "Ready" + self.register_timed_callback( + int(_sch_time_s + 2.0) * 1000, # In milliseconds + lambda: self.exp_info_label.setText(self.extrude_page_message), + ) + + def register_timed_callback(self, time: int, callback: callable) -> None: + """Registers timed callback and starts the timeout""" + _timer = QtCore.QTimer() + _timer.setSingleShot(True) + _timer.timeout.connect(callback) + _timer.start(int(time)) + self.timers.append(_timer) + + @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-feedrate") + def handle_toggle_extrude_feedrate(self, caller, value: int) -> None: + """Slot to change the extruder feedrate, mainly used for toggle buttons + + Args: + checked (bool): Button checked state + caller (PyQtObject): The button that called this slot + value (int): New value for the extruder feedrate + """ + if value == self.extrude_feedrate: + return + self.extrude_feedrate = value + + @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-length") + def handle_toggle_extrude_length(self, caller, value: int) -> None: + """Slot that changes the extrude length, mainly used for toggle buttons + + Args: + checked (bool): Button checked state + caller (PyQtObject): The button that called this slot + value (int): New value for the extrude length + """ + if self.extrude_length == value: + return + self.extrude_length = value + + def paintEvent(self, a0: QtGui.QPaintEvent | None) -> None: + """Refresh the info label while the extrude page is visible.""" + if self.extrude_page.isVisible(): + self.exp_info_label.setText(self.extrude_page_message) + return super().paintEvent(a0) + + def _setup_ui(self) -> None: + """Build the extruder page: extrude/retract controls and status labels.""" + widget = QtWidgets.QWidget(parent=self) + widget.setMinimumSize(QtCore.QSize(710, 410)) + widget.setMaximumSize(QtCore.QSize(710, 410)) + self.setObjectName("fans_page") + self.extrude_page = QtWidgets.QWidget() + self.extrude_page.setMinimumSize(QtCore.QSize(710, 400)) + self.extrude_page.setMaximumSize(QtCore.QSize(720, 420)) + self.extrude_page.setObjectName("extrude_page") + self.verticalLayout = QtWidgets.QVBoxLayout(self.extrude_page) + self.verticalLayout.setObjectName("verticalLayout") + spacerItem = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout.addItem(spacerItem) + self.exp_header_layout = QtWidgets.QHBoxLayout() + self.exp_header_layout.setObjectName("exp_header_layout") + spacerItem1 = QtWidgets.QSpacerItem( + 60, + 60, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.exp_header_layout.addItem(spacerItem1) + self.exp_title_label = QtWidgets.QLabel(parent=self.extrude_page) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth( + self.exp_title_label.sizePolicy().hasHeightForWidth() + ) + self.exp_title_label.setSizePolicy(sizePolicy) + self.exp_title_label.setMinimumSize(QtCore.QSize(0, 60)) + self.exp_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.exp_title_label.setFont(font) + self.exp_title_label.setStyleSheet("background: transparent; color: white;") + self.exp_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.exp_title_label.setObjectName("exp_title_label") + self.exp_header_layout.addWidget(self.exp_title_label) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + self.exp_back_btn = IconButton(parent=self.extrude_page) + + self.exp_back_btn.setSizePolicy(sizePolicy) + self.exp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.exp_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.exp_back_btn.setFont(font) + self.exp_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.exp_back_btn.setObjectName("exp_back_btn") + + self.exp_header_layout.addWidget( + self.exp_back_btn, + 0, + QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + self.verticalLayout.addLayout(self.exp_header_layout) + self.exp_vertical_content_layout = QtWidgets.QVBoxLayout() + self.exp_vertical_content_layout.setContentsMargins(5, 5, 5, 5) + self.exp_vertical_content_layout.setObjectName("exp_vertical_content_layout") + + font = QtGui.QFont() + font.setPointSize(14) + + self.exp_length_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) + self.exp_length_group_box.setMinimumSize(QtCore.QSize(0, 80)) + self.exp_length_group_box.setMaximumSize(QtCore.QSize(16777215, 16777215)) + self.exp_length_group_box.setFont(font) + self.exp_length_group_box.setStyleSheet("color:white") + self.exp_length_group_box.setAlignment( + QtCore.Qt.AlignmentFlag.AlignLeading + | QtCore.Qt.AlignmentFlag.AlignLeft + | QtCore.Qt.AlignmentFlag.AlignVCenter + ) + self.exp_length_group_box.setFlat(True) + self.exp_length_group_box.setObjectName("exp_length_group_box") + + self.layoutWidget = QtWidgets.QWidget(parent=self.exp_length_group_box) + self.layoutWidget.setGeometry(QtCore.QRect(0, 20, 681, 61)) + self.layoutWidget.setObjectName("layoutWidget") + self.exp_length_content_layout = QtWidgets.QHBoxLayout(self.layoutWidget) + self.exp_length_content_layout.setContentsMargins(5, 5, 5, 5) + self.exp_length_content_layout.setSpacing(5) + self.exp_length_content_layout.setObjectName("exp_length_content_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setPointSize(16) + font.setWeight(50) + + self.extrude_select_length_group = QtWidgets.QButtonGroup(self) + self.extrude_select_length_group.setObjectName("extrude_select_length_group") + + self.extrude_select_length_10_btn = BlocksCustomCheckButton( + parent=self.layoutWidget + ) + self.extrude_select_length_10_btn.setSizePolicy(sizePolicy) + self.extrude_select_length_10_btn.setFont(font) + self.extrude_select_length_10_btn.setCheckable(True) + self.extrude_select_length_10_btn.setChecked(True) + self.extrude_select_length_10_btn.setObjectName("extrude_select_length_10_btn") + + self.extrude_select_length_group.addButton(self.extrude_select_length_10_btn) + self.exp_length_content_layout.addWidget(self.extrude_select_length_10_btn) + + self.extrude_select_length_50_btn = BlocksCustomCheckButton( + parent=self.layoutWidget + ) + self.extrude_select_length_50_btn.setSizePolicy(sizePolicy) + self.extrude_select_length_50_btn.setFont(font) + self.extrude_select_length_50_btn.setCheckable(True) + self.extrude_select_length_50_btn.setObjectName("extrude_select_length_50_btn") + + self.extrude_select_length_group.addButton(self.extrude_select_length_50_btn) + self.exp_length_content_layout.addWidget(self.extrude_select_length_50_btn) + + self.extrude_select_length_100_btn = BlocksCustomCheckButton( + parent=self.layoutWidget + ) + self.extrude_select_length_100_btn.setSizePolicy(sizePolicy) + self.extrude_select_length_100_btn.setFont(font) + self.extrude_select_length_100_btn.setCheckable(True) + self.extrude_select_length_100_btn.setObjectName( + "extrude_select_length_100_btn" + ) + + self.extrude_select_length_group.addButton(self.extrude_select_length_100_btn) + self.exp_length_content_layout.addWidget(self.extrude_select_length_100_btn) + self.exp_vertical_content_layout.addWidget(self.exp_length_group_box) + + font = QtGui.QFont() + font.setPointSize(14) + + self.exp_feedrate_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) + self.exp_feedrate_group_box.setMinimumSize(QtCore.QSize(0, 80)) + self.exp_feedrate_group_box.setFont(font) + self.exp_feedrate_group_box.setStyleSheet("color:white") + self.exp_feedrate_group_box.setObjectName("exp_feedrate_group_box") + + self.layoutWidget1 = QtWidgets.QWidget(parent=self.exp_feedrate_group_box) + self.layoutWidget1.setGeometry(QtCore.QRect(0, 19, 681, 61)) + self.layoutWidget1.setObjectName("layoutWidget1") + + self.exp_feedrate_content_layout = QtWidgets.QHBoxLayout(self.layoutWidget1) + self.exp_feedrate_content_layout.setContentsMargins(5, 5, 5, 5) + self.exp_feedrate_content_layout.setSpacing(5) + self.exp_feedrate_content_layout.setObjectName("exp_feedrate_content_layout") + + font = QtGui.QFont() + font.setPointSize(16) + font.setBold(False) + font.setWeight(50) + + self.extrude_select_feedrate_group = QtWidgets.QButtonGroup(self) + self.extrude_select_feedrate_group.setObjectName( + "extrude_select_feedrate_group" + ) + + self.extrude_select_feedrate_low_btn = BlocksCustomCheckButton( + parent=self.layoutWidget1 + ) + self.extrude_select_feedrate_low_btn.setSizePolicy(sizePolicy) + self.extrude_select_feedrate_low_btn.setFont(font) + self.extrude_select_feedrate_low_btn.setCheckable(True) + self.extrude_select_feedrate_low_btn.setChecked(True) + self.extrude_select_feedrate_low_btn.setObjectName( + "extrude_select_feedrate_low_btn" + ) + + self.extrude_select_feedrate_group.addButton( + self.extrude_select_feedrate_low_btn + ) + self.exp_feedrate_content_layout.addWidget(self.extrude_select_feedrate_low_btn) + + self.extrude_select_feedrate_middle_btn = BlocksCustomCheckButton( + parent=self.layoutWidget1 + ) + self.extrude_select_feedrate_middle_btn.setSizePolicy(sizePolicy) + self.extrude_select_feedrate_middle_btn.setFont(font) + self.extrude_select_feedrate_middle_btn.setCheckable(True) + self.extrude_select_feedrate_middle_btn.setObjectName( + "extrude_select_feedrate_middle_btn" + ) + + self.extrude_select_feedrate_group.addButton( + self.extrude_select_feedrate_middle_btn + ) + self.exp_feedrate_content_layout.addWidget( + self.extrude_select_feedrate_middle_btn + ) + + self.extrude_select_feedrate_high_btn = BlocksCustomCheckButton( + parent=self.layoutWidget1 + ) + self.extrude_select_feedrate_high_btn.setSizePolicy(sizePolicy) + self.extrude_select_feedrate_high_btn.setFont(font) + self.extrude_select_feedrate_high_btn.setCheckable(True) + self.extrude_select_feedrate_high_btn.setObjectName( + "extrude_select_feedrate_high_btn" + ) + self.extrude_select_feedrate_group.addButton( + self.extrude_select_feedrate_high_btn + ) + self.exp_feedrate_content_layout.addWidget( + self.extrude_select_feedrate_high_btn + ) + self.exp_vertical_content_layout.addWidget(self.exp_feedrate_group_box) + + self.exp_movement_content_layout = QtWidgets.QVBoxLayout() + self.exp_movement_content_layout.setContentsMargins(-1, 5, -1, -1) + self.exp_movement_content_layout.setSpacing(0) + self.exp_movement_content_layout.setObjectName("exp_movement_content_layout") + + self.exp_buttons_layout = QtWidgets.QHBoxLayout() + self.exp_buttons_layout.setContentsMargins(5, 5, 5, 5) + self.exp_buttons_layout.setObjectName("exp_buttons_layout") + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + self.exp_unextrude_btn = BlocksCustomButton(parent=self.extrude_page) + self.exp_unextrude_btn.setSizePolicy(sizePolicy) + self.exp_unextrude_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.exp_unextrude_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.exp_unextrude_btn.setFont(font) + self.exp_unextrude_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg"), + ) + self.exp_unextrude_btn.setObjectName("exp_unextrude_btn") + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(16) + + self.exp_buttons_layout.addWidget(self.exp_unextrude_btn) + self.exp_nozzle_icon_label = BlocksLabel(parent=self.extrude_page) + self.exp_nozzle_icon_label.setMinimumSize(QtCore.QSize(60, 60)) + self.exp_nozzle_icon_label.setMaximumSize(QtCore.QSize(60, 60)) + self.exp_nozzle_icon_label.setFont(font) + self.exp_nozzle_icon_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.exp_nozzle_icon_label.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg"), + ) + self.exp_nozzle_icon_label.setObjectName("exp_nozzle_icon_label") + self.exp_buttons_layout.addWidget(self.exp_nozzle_icon_label) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + + self.exp_extrude_btn = BlocksCustomButton(parent=self.extrude_page) + self.exp_extrude_btn.setSizePolicy(sizePolicy) + self.exp_extrude_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.exp_extrude_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.exp_extrude_btn.setFont(font) + self.exp_extrude_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg"), + ) + self.exp_extrude_btn.setObjectName("exp_extrude_btn") + + self.exp_buttons_layout.addWidget(self.exp_extrude_btn) + self.exp_movement_content_layout.addLayout(self.exp_buttons_layout) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setFamily("Montserrat") + font.setPointSize(14) + + self.exp_info_layout = QtWidgets.QHBoxLayout() + self.exp_info_layout.setContentsMargins(5, 5, 5, 5) + self.exp_info_layout.setObjectName("exp_info_layout") + + self.exp_info_label = QtWidgets.QLabel(parent=self.extrude_page) + self.exp_info_label.setSizePolicy(sizePolicy) + self.exp_info_label.setFont(font) + self.exp_info_label.setStyleSheet("background: transparent; color: white;") + self.exp_info_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignHCenter) + self.exp_info_label.setObjectName("exp_info_label") + self.exp_info_layout.addWidget(self.exp_info_label) + self.exp_movement_content_layout.addLayout(self.exp_info_layout) + self.exp_movement_content_layout.setStretch(1, 1) + self.exp_vertical_content_layout.addLayout(self.exp_movement_content_layout) + self.exp_vertical_content_layout.setStretch(2, 1) + self.verticalLayout.addLayout(self.exp_vertical_content_layout) + widget.setLayout(self.verticalLayout) + + _translate = QtCore.QCoreApplication.translate + self.exp_title_label.setText(_translate("controlStackedWidget", "Extrude")) + self.exp_back_btn.setText(_translate("controlStackedWidget", "Back")) + self.exp_length_group_box.setTitle( + _translate("controlStackedWidget", "Extrude Length (mm)") + ) + self.extrude_select_length_10_btn.setText( + _translate("controlStackedWidget", "10") + ) + self.extrude_select_length_50_btn.setText( + _translate("controlStackedWidget", "50") + ) + self.extrude_select_length_100_btn.setText( + _translate("controlStackedWidget", "100") + ) + self.exp_feedrate_group_box.setTitle( + _translate("controlStackedWidget", "Extrude Feedrate (mm/s)") + ) + self.extrude_select_feedrate_low_btn.setText( + _translate("controlStackedWidget", str(self.extrude_list[0])) + ) + self.extrude_select_feedrate_middle_btn.setText( + _translate("controlStackedWidget", str(self.extrude_list[1])) + ) + self.extrude_select_feedrate_high_btn.setText( + _translate("controlStackedWidget", str(self.extrude_list[2])) + ) + self.exp_unextrude_btn.setText(_translate("controlStackedWidget", "Retract")) + self.exp_extrude_btn.setText(_translate("controlStackedWidget", "Extrude")) + self.exp_info_label.setText(_translate("controlStackedWidget", "")) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py new file mode 100644 index 000000000..0e008c502 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py @@ -0,0 +1,212 @@ +"""Control tab fans page: one card per fan with a slider popup for speed changes.""" + +import re +import typing + +from lib.panels.widgets.optionCardWidget import OptionCard +from lib.utils.gcode import fan_speed_gcode +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class FansPage(QtWidgets.QWidget): + """Fan control page of the control tab.""" + + request_slider_page = QtCore.pyqtSignal( + str, int, "PyQt_PyObject", int, int, name="on_slidePage_request" + ) + request_back_button = QtCore.pyqtSignal(name="request-back-button") + + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + + self.tune_display_buttons: dict = {} + self.card_options: dict = {} + self._setup_ui() + self.fans_back_btn.clicked.connect(self.request_back_button.emit) + + self.path = { + "fan_cage": QtGui.QPixmap(":/fan_related/media/btn_icons/fan_cage.svg"), + "blower": QtGui.QPixmap(":/fan_related/media/btn_icons/blower.svg"), + "fan": QtGui.QPixmap(":/fan_related/media/btn_icons/fan.svg"), + } + + @QtCore.pyqtSlot(str, str, float, name="on_fan_update") + @QtCore.pyqtSlot(str, str, int, name="on_fan_update") + def on_fan_object_update(self, name: str, field: str, new_value: float) -> None: + """Slot that receives updates from fan objects. + + Args: + name (str): Fan object name + field (str): Field name + new_value (int | float): New value for the field + """ + if "speed" not in field: + return + + fields = name.split() + first_field = fields[0] + second_field = fields[1] if len(fields) > 1 else None + name = second_field.replace("_", " ") if second_field else name + + fan_card = self.tune_display_buttons.get(name) + if fan_card is None and first_field in ( + "fan", + "fan_generic", + ): + icon = self.path.get("fan") + if second_field: + second_field = second_field.lower() + pattern_blower = r"(?:^|_)(?:blower|auxiliary)(?:_|$)" + pattern_exhaust = r"(?:^|_)exhaust(?:_|$)" + if re.search(pattern_blower, second_field): + icon = self.path.get("blower") + elif re.search(pattern_exhaust, second_field): + icon = self.path.get("fan_cage") + + card = OptionCard(self, name, str(name), icon) # type: ignore + card.setObjectName(str(name)) + + # Add card to layout and record reference + self.card_options[name] = card + self.fans_content_layout.addWidget(card) + + # If the card doesn't have expected UI properties, discard it + if not hasattr(card, "continue_clicked"): + del card + self.card_options.pop(name, None) + return + + card.setMode(True) + card.secondtext.setText(f"{new_value}%") + card.continue_clicked.connect( + lambda: self.request_slider_page.emit( + str(name), + int(card.secondtext.text().replace("%", "")), + self.on_slider_change, + 0, + 100, + ) + ) + + self.tune_display_buttons[name] = card + self.update() + fan_card = card + + if fan_card: + value_percent = new_value * 100 if new_value <= 1 else new_value + fan_card.secondtext.setText(f"{value_percent:.0f}%") + + @QtCore.pyqtSlot(str, int, name="on_slider_change") + def on_slider_change(self, name: str, new_value: int) -> None: + """ + Slider change handler + Args: + name (str): fan name + new_value (int): value from 0 to 255 to set fans speed + """ + self.run_gcode_signal.emit(fan_speed_gcode(name, new_value)) + + def _setup_ui(self) -> None: + """Build the fans page: header, back button, and fan slider area.""" + self.setObjectName("fans_page") + widget = QtWidgets.QWidget(parent=self) + widget.setGeometry(QtCore.QRect(0, 0, 720, 420)) + + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setObjectName("verticalLayout") + + spacerItem9 = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout.addItem(spacerItem9) + + self.fans_header_layout = QtWidgets.QHBoxLayout() + self.fans_header_layout.setObjectName("fans_header_layout") + + spacerItem10 = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.fans_header_layout.addItem(spacerItem10) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + self.fans_title_label = QtWidgets.QLabel(parent=self) + self.fans_title_label.setSizePolicy(sizePolicy) + self.fans_title_label.setFont(font) + self.fans_title_label.setStyleSheet("background: transparent; color: white;") + self.fans_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.fans_title_label.setObjectName("fans_title_label") + self.fans_header_layout.addWidget(self.fans_title_label) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + self.fans_back_btn = IconButton(parent=self) + self.fans_back_btn.setSizePolicy(sizePolicy) + self.fans_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.fans_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.fans_back_btn.setFont(font) + self.fans_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.fans_back_btn.setObjectName("fans_back_btn") + + self.fans_header_layout.addWidget(self.fans_back_btn) + self.verticalLayout.addLayout(self.fans_header_layout) + spacerItem11 = QtWidgets.QSpacerItem( + 20, + 111, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + self.verticalLayout.addItem(spacerItem11) + + self.fans_content_layout = QtWidgets.QHBoxLayout() + self.fans_content_layout.setObjectName("fans_content_layout") + self.verticalLayout.addLayout(self.fans_content_layout) + + spacerItem12 = QtWidgets.QSpacerItem( + 20, + 111, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.verticalLayout.addItem(spacerItem12) + + widget.setLayout(self.verticalLayout) + + _translate = QtCore.QCoreApplication.translate + self.fans_title_label.setText(_translate("controlStackedWidget", "Fans")) + self.fans_back_btn.setText(_translate("controlStackedWidget", "Back")) diff --git a/BlocksScreen/lib/panels/widgets/printcorePage.py b/BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/printcorePage.py rename to BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py diff --git a/BlocksScreen/lib/panels/widgets/probeHelperPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/probeHelperPage.py rename to BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py index 0df4b50d3..55aaa9ce4 100644 --- a/BlocksScreen/lib/panels/widgets/probeHelperPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py @@ -97,7 +97,7 @@ def __init__(self, parent: QtWidgets.QWidget) -> None: self._eddy_command: str = "" self.setObjectName("probe_offset_page") - self._setupUi() + self._setup_ui() self.inductive_icon = QtGui.QPixmap( ":/z_levelling/media/btn_icons/inductive.svg" ) @@ -731,7 +731,7 @@ def _create_move_button( btn.setObjectName(obj_name) return btn - def _setupUi(self) -> None: + def _setup_ui(self) -> None: """Build and lay out all UI elements for the probe helper page.""" self.bbp_offset_value_selector_group = QtWidgets.QButtonGroup(self) self.bbp_offset_value_selector_group.setExclusive(True) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py b/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py new file mode 100644 index 000000000..968d89881 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py @@ -0,0 +1,310 @@ +"""Control tab temperature page: per-heater target display and preset selection.""" + +import contextlib +import typing + +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.display_button import DisplayButton +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class TemperaturePage(QtWidgets.QWidget): + """Heater temperature page of the control tab.""" + + request_back = QtCore.pyqtSignal(name="request-back-button") + + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + request_numpad: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, + int, + "PyQt_PyObject", + int, + int, + name="request-numpad", + ) + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + + self._setup_ui() + + self.temp_back_button.clicked.connect(self.request_back.emit) + + self.cooldown_btn.hide() + self.temperature_cooldown_btn.hide() + + self._connect_temp_displays(0, 370, 0, 120) + + @QtCore.pyqtSlot(dict, name="printer_config") + def on_printer_config(self, config: dict) -> None: + """Rewire the temperature numpads with the printer's configured limits""" + extruder = config.get("extruder") or {} + bed = config.get("heater_bed") or {} + self._connect_temp_displays( + int(extruder.get("min_temp", 0)), + int(extruder.get("max_temp", 300)), + int(bed.get("min_temp", 0)), + int(bed.get("max_temp", 100)), + ) + + def _connect_temp_displays( + self, e_min: int, e_max: int, b_min: int, b_max: int + ) -> None: + """Connect both temperature displays to the numpad with the given limits""" + with contextlib.suppress(RuntimeError, TypeError): + self.extruder_temp_display.clicked.disconnect() + with contextlib.suppress(RuntimeError, TypeError): + self.bed_temp_display.clicked.disconnect() + self.extruder_temp_display.clicked.connect( + lambda: self.request_numpad.emit( + "Extruder Temperature", + round(float(self.extruder_temp_display.secondary_text)), + self.on_numpad_change, + e_min, + e_max, + ) + ) + self.bed_temp_display.clicked.connect( + lambda: self.request_numpad.emit( + "Bed Temperature", + round(float(self.bed_temp_display.secondary_text)), + self.on_numpad_change, + b_min, + b_max, + ) + ) + + @QtCore.pyqtSlot(str, int, name="on-numpad-change") + def on_numpad_change(self, name: str, new_value: int) -> None: + """Handles inputted numpad values""" + if "bed" in name.lower(): + name = "heater_bed" + elif "extruder" in name.lower(): + name = "extruder" + self.run_gcode_signal.emit( + f"SET_HEATER_TEMPERATURE HEATER={name} TARGET={new_value}" + ) + + @QtCore.pyqtSlot(str, str, float, name="on-extruder-update") + def on_extruder_update( + self, extruder_name: str, field: str, new_value: float + ) -> None: + """Handles updates from extruder printer object""" + if extruder_name == "extruder" and field == "temperature": + self.extruder_temp_display.setText(f"{new_value:.1f}") + if extruder_name == "extruder" and field == "target": + self.extruder_temp_display.secondary_text = f"{new_value:.1f}" + + @QtCore.pyqtSlot(str, str, float, name="on-heater-bed-update") + def on_heater_bed_update(self, name: str, field: str, new_value: float) -> None: + """Handles updated from heater_bed printer object""" + if field == "temperature": + self.bed_temp_display.setText(f"{new_value:.1f}") + if field == "target": + self.bed_temp_display.secondary_text = f"{new_value:.1f}" + + def _setup_ui(self) -> None: + """Build the temperature page: heater cards and preset controls.""" + self.setObjectName("temperature_page") + widget = QtWidgets.QWidget(parent=self) + widget.setGeometry(QtCore.QRect(0, 0, 720, 420)) + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setObjectName("verticalLayout") + spacerItem3 = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout.addItem(spacerItem3) + + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + + spacerItem4 = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.horizontalLayout.addItem(spacerItem4) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + font.setBold(True) + font.setWeight(75) + + self.temp_header_title = QtWidgets.QLabel(parent=self) + self.temp_header_title.setSizePolicy(sizePolicy) + self.temp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + self.temp_header_title.setFont(font) + self.temp_header_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.temp_header_title.setStyleSheet("background: transparent; color: white;") + self.temp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.temp_header_title.setObjectName("temp_header_title") + self.horizontalLayout.addWidget(self.temp_header_title) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + self.temp_back_button = IconButton(parent=self) + self.temp_back_button.setSizePolicy(sizePolicy) + self.temp_back_button.setMinimumSize(QtCore.QSize(60, 60)) + self.temp_back_button.setMaximumSize(QtCore.QSize(60, 60)) + self.temp_back_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.temp_back_button.setObjectName("temp_back_button") + + self.horizontalLayout.addWidget(self.temp_back_button) + self.verticalLayout.addLayout(self.horizontalLayout) + + spacerItem5 = QtWidgets.QSpacerItem( + 20, + 35, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout.addItem(spacerItem5) + + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setContentsMargins(5, 5, 5, 5) + self.gridLayout.setSpacing(0) + self.gridLayout.setObjectName("gridLayout") + + self.tp_content_horizontal_layout = QtWidgets.QHBoxLayout() + self.tp_content_horizontal_layout.setSizeConstraint( + QtWidgets.QLayout.SizeConstraint.SetMinimumSize + ) + self.tp_content_horizontal_layout.setContentsMargins(5, 5, 5, 5) + self.tp_content_horizontal_layout.setSpacing(5) + self.tp_content_horizontal_layout.setObjectName("tp_content_horizontal_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + + font = QtGui.QFont() + font.setPointSize(11) + + self.extruder_temp_display = DisplayButton(parent=self) + self.extruder_temp_display.setSizePolicy(sizePolicy) + self.extruder_temp_display.setMinimumSize(QtCore.QSize(200, 60)) + self.extruder_temp_display.setMaximumSize(QtCore.QSize(120, 60)) + self.extruder_temp_display.setFont(font) + self.extruder_temp_display.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg"), + ) + self.extruder_temp_display.setObjectName("extruder_temp_display") + self.tp_content_horizontal_layout.addWidget(self.extruder_temp_display) + + self.bed_temp_display = DisplayButton(parent=self) + self.bed_temp_display.setSizePolicy(sizePolicy) + self.bed_temp_display.setMinimumSize(QtCore.QSize(200, 60)) + self.bed_temp_display.setMaximumSize(QtCore.QSize(120, 60)) + self.bed_temp_display.setFont(font) + self.bed_temp_display.setProperty( + "icon_pixmap", + QtGui.QPixmap( + ":/temperature_related/media/btn_icons/temperature_plate.svg" + ), + ) + self.bed_temp_display.setObjectName("bed_temp_display") + + self.tp_content_horizontal_layout.addWidget(self.bed_temp_display) + self.gridLayout.addLayout(self.tp_content_horizontal_layout, 0, 0, 1, 2) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + self.cooldown_btn = BlocksCustomButton(parent=self) + self.cooldown_btn.setSizePolicy(sizePolicy) + self.cooldown_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.cooldown_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.cooldown_btn.setFont(font) + self.cooldown_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.cooldown_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/temperature_related/media/btn_icons/cooldown.svg"), + ) + self.cooldown_btn.setObjectName("cooldown_btn") + + self.gridLayout.addWidget(self.cooldown_btn, 2, 1, 1, 1) + spacerItem6 = QtWidgets.QSpacerItem( + 20, + 50, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.gridLayout.addItem(spacerItem6, 1, 0, 1, 2) + + self.temperature_cooldown_btn = BlocksCustomButton(parent=self) + self.temperature_cooldown_btn.setSizePolicy(sizePolicy) + self.temperature_cooldown_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.temperature_cooldown_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.temperature_cooldown_btn.setFont(font) + self.temperature_cooldown_btn.setLayoutDirection( + QtCore.Qt.LayoutDirection.LeftToRight + ) + self.temperature_cooldown_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/temperature_related/media/btn_icons/heatsoak_icon.svg"), + ) + self.temperature_cooldown_btn.setObjectName("temperature_cooldown_btn") + self.gridLayout.addWidget(self.temperature_cooldown_btn, 2, 0, 1, 1) + + self.verticalLayout.addLayout(self.gridLayout) + spacerItem7 = QtWidgets.QSpacerItem( + 20, + 8, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout.addItem(spacerItem7) + + widget.setLayout(self.verticalLayout) + + _translate = QtCore.QCoreApplication.translate + self.temp_header_title.setText( + _translate("controlStackedWidget", "Temperature") + ) + self.temp_back_button.setText(_translate("controlStackedWidget", "Back")) + self.extruder_temp_display.setProperty( + "button_type", _translate("controlStackedWidget", "secondary_display") + ) + self.bed_temp_display.setProperty( + "button_type", _translate("controlStackedWidget", "secondary_display") + ) + self.cooldown_btn.setText(_translate("controlStackedWidget", "Cooldown")) + self.temperature_cooldown_btn.setText( + _translate("controlStackedWidget", "Heatsoak") + ) diff --git a/BlocksScreen/lib/ui/controlStackedWidget.ui b/BlocksScreen/lib/ui/controlStackedWidget.ui deleted file mode 100644 index ea27b5318..000000000 --- a/BlocksScreen/lib/ui/controlStackedWidget.ui +++ /dev/null @@ -1,5781 +0,0 @@ - - - controlStackedWidget - - - - 0 - 0 - 710 - 410 - - - - - 0 - 0 - - - - - 710 - 410 - - - - - 710 - 410 - - - - StackedWidget - - - 2 - - - - - 0 - 0 - - - - - 710 - 400 - - - - - 720 - 420 - - - - - - - - - - 0 - 0 - - - - - 300 - 60 - - - - - 16777215 - 60 - - - - - Momcake - 24 - true - - - - background: transparent; color: white; - - - Control - - - Qt::AlignCenter - - - title_text - - - - - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Z-Tilt - - - false - - - true - - - menu_btn - - - :/z_levelling/media/btn_icons/bed_levelling.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Temp. -Control - - - false - - - true - - - menu_btn - - - :/temperature_related/media/btn_icons/temperature.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Nozzle -Calibration - - - false - - - true - - - menu_btn - - - :/z_levelling/media/btn_icons/bed_levelling.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Motion -Control - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/axis_maintenance.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Fans - - - false - - - true - - - menu_btn - - - :/temperature_related/media/btn_icons/fan.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Swap -Print Core - - - false - - - true - - - menu_btn - - - :/extruder_related/media/btn_icons/switch_print_core.svg - - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Motion - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Axis - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/axis_maintenance.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Disable -Steppers - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/disable_steppers.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Extrude - - - false - - - true - - - menu_btn - - - :/extruder_related/media/btn_icons/extrude.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Auto -Home - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/home_all.svg - - - - - - - - 0 - 0 - - - - - 10 - 80 - - - - - 250 - 80 - - - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 60 - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Extrude - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - 80 - - - - - 16777215 - 16777215 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - Extrude Length (mm) - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - true - - - - - 0 - 20 - 681 - 61 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 10 - - - true - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_length_group - - - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 50 - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_length_group - - - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 100 - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_length_group - - - - - - - - - - - - 0 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - Extrude Feedrate (mm/s) - - - true - - - - - 0 - 19 - 681 - 61 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 2 - - - true - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_feedrate_group - - - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 4 - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_feedrate_group - - - - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 255 - 255 - - - - - - - 120 - 120 - 120 - - - - - - - 0 - 0 - 0 - - - - - - - - - 16 - false - - - - 8 - - - true - - - false - - - false - - - true - - - normal - - - extrude_select_feedrate_group - - - - - - - - - - - 0 - - - 5 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Retract - - - false - - - true - - - menu_btn - - - :/extruder_related/media/btn_icons/extrude.svg - - - - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 16 - - - - - - - - - - Qt::AlignCenter - - - :/extruder_related/media/btn_icons/nozzle.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Extrude - - - false - - - true - - - menu_btn - - - :/extruder_related/media/btn_icons/extrude.svg - - - - - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - true - - - - 0 - 0 - - - - - 0 - 0 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - Nozzle heating to extrude - - - Qt::AlignCenter - - - - - - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - true - - - - 160 - 350 - 51 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - X: - - - - - true - - - - 340 - 350 - 51 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - Y: - - - - - true - - - - 500 - 350 - 51 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - Z: - - - - - true - - - - 550 - 350 - 91 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - 0 - - - - - true - - - - 370 - 350 - 91 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - 0 - - - - - true - - - - 190 - 350 - 81 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - 0 - - - - - - 10 - 23 - 691 - 81 - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Move Axis - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - 630 - 130 - 71 - 201 - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/up_arrow.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/down_arrow.svg - - - - - - - - - 10 - 90 - 81 - 301 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/motion/media/btn_icons/home_x.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/motion/media/btn_icons/home_y.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/motion/media/btn_icons/home_z.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/motion/media/btn_icons/home_all.svg - - - - - - - - - 96 - 240 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 25 - - - true - - - true - - - true - - - axis_select_speed_group - - - - - - 205 - 240 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 50 - - - true - - - false - - - axis_select_speed_group - - - - - - 315 - 240 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 100 - - - true - - - false - - - axis_select_speed_group - - - - - - 109 - 216 - 261 - 21 - - - - - 14 - - - - color:white - - - Move Speed mm/s - - - - - - 96 - 110 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 1 - - - true - - - true - - - true - - - axis_select_length_group - - - - - - 204 - 110 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 10 - - - true - - - false - - - axis_select_length_group - - - - - - 315 - 110 - 100 - 100 - - - - - 60 - 60 - - - - - 100 - 100 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 14 - - - - 100 - - - true - - - false - - - axis_select_length_group - - - - - - 109 - 85 - 261 - 21 - - - - - 14 - - - - color:white - - - Move Length mm - - - - - - 440 - 128 - 196 - 204 - - - - - 0 - - - 5 - - - 0 - - - 5 - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/left_arrow.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 16 - 16 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/right_arrow.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 60 - 60 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/down_arrow.svg - - - - - - - true - - - - 1 - 1 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - - - - - 60 - 60 - - - - false - - - false - - - true - - - icon - - - :/arrow_icons/media/btn_icons/up_arrow.svg - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - true - - - icon - - - :/ui/media/btn_icons/center_arrows.svg - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - Momcake - 24 - true - - - - Qt::LayoutDirection::RightToLeft - - - background: transparent; color: white; - - - Temperature - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 35 - - - - - - - - 5 - - - 5 - - - 5 - - - 5 - - - 0 - - - - - 5 - - - QLayout::SizeConstraint::SetMinimumSize - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 1 - 1 - - - - - 200 - 60 - - - - - 120 - 60 - - - - - 11 - - - - false - - - - - - true - - - :/extruder_related/media/btn_icons/nozzle.svg - - - extruder_temperature_display - - - secondary_display - - - - - - - - 1 - 1 - - - - - 200 - 60 - - - - - 120 - 60 - - - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 50 - 50 - 50 - - - - - - - 60 - 60 - 60 - - - - - - - 60 - 60 - 60 - - - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 50 - 50 - 50 - - - - - - - 60 - 60 - 60 - - - - - - - 60 - 60 - 60 - - - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 50 - 50 - 50 - - - - - - - 50 - 50 - 50 - - - - - - - 60 - 60 - 60 - - - - - - - 60 - 60 - 60 - - - - - - - - - 11 - - - - - - - false - - - false - - - true - - - :/temperature_related/media/btn_icons/temperature_plate.svg - - - bed_temperature_display - - - secondary_display - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Cooldown - - - false - - - true - - - menu_btn - - - :/temperature_related/media/btn_icons/cooldown.svg - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 50 - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Heatsoak - - - false - - - true - - - menu_btn - - - :/temperature_related/media/btn_icons/heatsoak_icon.svg - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 8 - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - true - - - - 290 - 210 - 31 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - Z - - - - - true - - - - 340 - 210 - 31 - 41 - - - - - Montserrat - 14 - - - - background: transparent; color: white; - - - 0 - - - - - - 10 - 10 - 681 - 62 - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Z Adjustment - - - Qt::AlignCenter - - - title_text - - - - - - - - 60 - 60 - - - - - 60 - 60 - - - - - - - true - - - :/button_borders/media/btn_icons/back.svg - - - icon - - - - - - - - - 600 - 110 - 90 - 177 - - - - - 5 - - - 5 - - - 5 - - - 5 - - - - - - 80 - 80 - - - - - 80 - 80 - - - - - Momcake - 36 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - ^ - - - false - - - true - - - menu_btn - - - icon - - - :/arrow_icons/media/btn_icons/up_arrow.svg - - - - - - - - 80 - 80 - - - - - 80 - 80 - - - - - Momcake - 26 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - v - - - false - - - true - - - menu_btn - - - icon - - - :/arrow_icons/media/btn_icons/down_arrow.svg - - - - - - - - - 170 - 80 - 371 - 51 - - - - - 10 - 10 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - select length - - - false - - - true - - - menu_btn - - - - - - - - - - - - normal - - - - - - 20 - 320 - 671 - 71 - - - - - - - - 0 - 0 - - - - - 10 - 0 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Confirm - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/yes.svg - - - - - - - - 0 - 0 - - - - - 10 - 0 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Cancel - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/no.svg - - - - - - - - - - 710 - 400 - - - - - 720 - 420 - - - - - - 10 - 11 - 691 - 71 - - - - - - - - 0 - 0 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - PRINTER SETTINGS - - - Qt::AlignCenter - - - title_text - - - - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - 10 - 90 - 691 - 301 - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Fans - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 111 - - - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 111 - - - - - - - - - - BlocksCustomButton - QPushButton -
lib.utils.blocks_button
-
- - IconButton - QPushButton -
lib.utils.icon_button
-
- - GroupButton - QPushButton -
lib.utils.group_button
-
- - DisplayButton - QPushButton -
lib.utils.display_button
-
- - BlocksLabel - QLabel -
lib.utils.blocks_label
-
-
- - - - - - - - - - - - - - - -
diff --git a/BlocksScreen/lib/ui/controlStackedWidget_ui.py b/BlocksScreen/lib/ui/controlStackedWidget_ui.py deleted file mode 100644 index 95417c09a..000000000 --- a/BlocksScreen/lib/ui/controlStackedWidget_ui.py +++ /dev/null @@ -1,2186 +0,0 @@ -# Form implementation generated from reading ui file 'BlocksScreen/lib/ui/controlStackedWidget.ui' -# -# Created by: PyQt6 UI code generator 6.7.1 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_controlStackedWidget(object): - def setupUi(self, controlStackedWidget): - controlStackedWidget.setObjectName("controlStackedWidget") - controlStackedWidget.resize(710, 410) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(controlStackedWidget.sizePolicy().hasHeightForWidth()) - controlStackedWidget.setSizePolicy(sizePolicy) - controlStackedWidget.setMinimumSize(QtCore.QSize(710, 410)) - controlStackedWidget.setMaximumSize(QtCore.QSize(710, 410)) - self.control_page = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.control_page.sizePolicy().hasHeightForWidth()) - self.control_page.setSizePolicy(sizePolicy) - self.control_page.setMinimumSize(QtCore.QSize(710, 400)) - self.control_page.setMaximumSize(QtCore.QSize(720, 420)) - self.control_page.setObjectName("control_page") - self.verticalLayout = QtWidgets.QVBoxLayout(self.control_page) - self.verticalLayout.setObjectName("verticalLayout") - self.cp_header_layout = QtWidgets.QHBoxLayout() - self.cp_header_layout.setObjectName("cp_header_layout") - self.cp_header_title = QtWidgets.QLabel(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_header_title.sizePolicy().hasHeightForWidth()) - self.cp_header_title.setSizePolicy(sizePolicy) - self.cp_header_title.setMinimumSize(QtCore.QSize(300, 60)) - self.cp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - font.setBold(True) - self.cp_header_title.setFont(font) - self.cp_header_title.setStyleSheet("background: transparent; color: white;") - self.cp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cp_header_title.setObjectName("cp_header_title") - self.cp_header_layout.addWidget(self.cp_header_title) - self.verticalLayout.addLayout(self.cp_header_layout) - self.cp_content_layout = QtWidgets.QGridLayout() - self.cp_content_layout.setObjectName("cp_content_layout") - self.cp_z_tilt_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_z_tilt_btn.sizePolicy().hasHeightForWidth()) - self.cp_z_tilt_btn.setSizePolicy(sizePolicy) - self.cp_z_tilt_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_z_tilt_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_z_tilt_btn.setFont(font) - self.cp_z_tilt_btn.setMouseTracking(False) - self.cp_z_tilt_btn.setTabletTracking(True) - self.cp_z_tilt_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_z_tilt_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_z_tilt_btn.setStyleSheet("") - self.cp_z_tilt_btn.setAutoDefault(False) - self.cp_z_tilt_btn.setFlat(True) - self.cp_z_tilt_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg")) - self.cp_z_tilt_btn.setObjectName("cp_z_tilt_btn") - self.cp_content_layout.addWidget(self.cp_z_tilt_btn, 1, 1, 1, 1) - self.cp_temperature_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_temperature_btn.sizePolicy().hasHeightForWidth()) - self.cp_temperature_btn.setSizePolicy(sizePolicy) - self.cp_temperature_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_temperature_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_temperature_btn.setFont(font) - self.cp_temperature_btn.setMouseTracking(False) - self.cp_temperature_btn.setTabletTracking(True) - self.cp_temperature_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_temperature_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_temperature_btn.setStyleSheet("") - self.cp_temperature_btn.setAutoDefault(False) - self.cp_temperature_btn.setFlat(True) - self.cp_temperature_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature.svg")) - self.cp_temperature_btn.setObjectName("cp_temperature_btn") - self.cp_content_layout.addWidget(self.cp_temperature_btn, 0, 1, 1, 1) - self.cp_nozzles_calibration_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_nozzles_calibration_btn.sizePolicy().hasHeightForWidth()) - self.cp_nozzles_calibration_btn.setSizePolicy(sizePolicy) - self.cp_nozzles_calibration_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_nozzles_calibration_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_nozzles_calibration_btn.setFont(font) - self.cp_nozzles_calibration_btn.setMouseTracking(False) - self.cp_nozzles_calibration_btn.setTabletTracking(True) - self.cp_nozzles_calibration_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_nozzles_calibration_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_nozzles_calibration_btn.setStyleSheet("") - self.cp_nozzles_calibration_btn.setAutoDefault(False) - self.cp_nozzles_calibration_btn.setFlat(True) - self.cp_nozzles_calibration_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg")) - self.cp_nozzles_calibration_btn.setObjectName("cp_nozzles_calibration_btn") - self.cp_content_layout.addWidget(self.cp_nozzles_calibration_btn, 1, 0, 1, 1) - self.cp_motion_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_motion_btn.sizePolicy().hasHeightForWidth()) - self.cp_motion_btn.setSizePolicy(sizePolicy) - self.cp_motion_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_motion_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_motion_btn.setFont(font) - self.cp_motion_btn.setMouseTracking(False) - self.cp_motion_btn.setTabletTracking(True) - self.cp_motion_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_motion_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_motion_btn.setStyleSheet("") - self.cp_motion_btn.setAutoDefault(False) - self.cp_motion_btn.setFlat(True) - self.cp_motion_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg")) - self.cp_motion_btn.setObjectName("cp_motion_btn") - self.cp_content_layout.addWidget(self.cp_motion_btn, 0, 0, 1, 1) - self.cp_fans_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_fans_btn.sizePolicy().hasHeightForWidth()) - self.cp_fans_btn.setSizePolicy(sizePolicy) - self.cp_fans_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_fans_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_fans_btn.setFont(font) - self.cp_fans_btn.setMouseTracking(False) - self.cp_fans_btn.setTabletTracking(True) - self.cp_fans_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_fans_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_fans_btn.setStyleSheet("") - self.cp_fans_btn.setAutoDefault(False) - self.cp_fans_btn.setFlat(True) - self.cp_fans_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/fan.svg")) - self.cp_fans_btn.setObjectName("cp_fans_btn") - self.cp_content_layout.addWidget(self.cp_fans_btn, 2, 0, 1, 1) - self.cp_switch_print_core_btn = BlocksCustomButton(parent=self.control_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cp_switch_print_core_btn.sizePolicy().hasHeightForWidth()) - self.cp_switch_print_core_btn.setSizePolicy(sizePolicy) - self.cp_switch_print_core_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.cp_switch_print_core_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cp_switch_print_core_btn.setFont(font) - self.cp_switch_print_core_btn.setMouseTracking(False) - self.cp_switch_print_core_btn.setTabletTracking(True) - self.cp_switch_print_core_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cp_switch_print_core_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cp_switch_print_core_btn.setStyleSheet("") - self.cp_switch_print_core_btn.setAutoDefault(False) - self.cp_switch_print_core_btn.setFlat(True) - self.cp_switch_print_core_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/switch_print_core.svg")) - self.cp_switch_print_core_btn.setObjectName("cp_switch_print_core_btn") - self.cp_content_layout.addWidget(self.cp_switch_print_core_btn, 2, 1, 1, 1) - self.verticalLayout.addLayout(self.cp_content_layout) - controlStackedWidget.addWidget(self.control_page) - self.motion_page = QtWidgets.QWidget() - self.motion_page.setMinimumSize(QtCore.QSize(710, 400)) - self.motion_page.setMaximumSize(QtCore.QSize(720, 420)) - self.motion_page.setObjectName("motion_page") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.motion_page) - self.verticalLayout_2.setObjectName("verticalLayout_2") - self.mp_header_layout = QtWidgets.QHBoxLayout() - self.mp_header_layout.setObjectName("mp_header_layout") - self.widget = QtWidgets.QWidget(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth()) - self.widget.setSizePolicy(sizePolicy) - self.widget.setMinimumSize(QtCore.QSize(60, 60)) - self.widget.setMaximumSize(QtCore.QSize(60, 60)) - self.widget.setObjectName("widget") - self.mp_header_layout.addWidget(self.widget) - self.mp_header_title = QtWidgets.QLabel(parent=self.motion_page) - self.mp_header_title.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mp_header_title.sizePolicy().hasHeightForWidth()) - self.mp_header_title.setSizePolicy(sizePolicy) - self.mp_header_title.setMinimumSize(QtCore.QSize(0, 0)) - self.mp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.mp_header_title.setFont(font) - self.mp_header_title.setStyleSheet("background: transparent; color: white;") - self.mp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.mp_header_title.setObjectName("mp_header_title") - self.mp_header_layout.addWidget(self.mp_header_title) - self.mp_back_btn = IconButton(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mp_back_btn.sizePolicy().hasHeightForWidth()) - self.mp_back_btn.setSizePolicy(sizePolicy) - self.mp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mp_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.mp_back_btn.setFont(font) - self.mp_back_btn.setMouseTracking(False) - self.mp_back_btn.setTabletTracking(True) - self.mp_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.mp_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.mp_back_btn.setStyleSheet("") - self.mp_back_btn.setAutoDefault(False) - self.mp_back_btn.setFlat(True) - self.mp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.mp_back_btn.setObjectName("mp_back_btn") - self.mp_header_layout.addWidget(self.mp_back_btn) - self.verticalLayout_2.addLayout(self.mp_header_layout) - self.cp_content_layout_2 = QtWidgets.QGridLayout() - self.cp_content_layout_2.setObjectName("cp_content_layout_2") - self.motion_move_axis_btn = BlocksCustomButton(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.motion_move_axis_btn.sizePolicy().hasHeightForWidth()) - self.motion_move_axis_btn.setSizePolicy(sizePolicy) - self.motion_move_axis_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.motion_move_axis_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.motion_move_axis_btn.setFont(font) - self.motion_move_axis_btn.setMouseTracking(False) - self.motion_move_axis_btn.setTabletTracking(True) - self.motion_move_axis_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.motion_move_axis_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.motion_move_axis_btn.setStyleSheet("") - self.motion_move_axis_btn.setAutoDefault(False) - self.motion_move_axis_btn.setFlat(True) - self.motion_move_axis_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg")) - self.motion_move_axis_btn.setObjectName("motion_move_axis_btn") - self.cp_content_layout_2.addWidget(self.motion_move_axis_btn, 1, 0, 1, 1) - self.motion_disable_steppers_btn = BlocksCustomButton(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.motion_disable_steppers_btn.sizePolicy().hasHeightForWidth()) - self.motion_disable_steppers_btn.setSizePolicy(sizePolicy) - self.motion_disable_steppers_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.motion_disable_steppers_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.motion_disable_steppers_btn.setFont(font) - self.motion_disable_steppers_btn.setMouseTracking(False) - self.motion_disable_steppers_btn.setTabletTracking(True) - self.motion_disable_steppers_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.motion_disable_steppers_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.motion_disable_steppers_btn.setStyleSheet("") - self.motion_disable_steppers_btn.setAutoDefault(False) - self.motion_disable_steppers_btn.setFlat(True) - self.motion_disable_steppers_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/disable_steppers.svg")) - self.motion_disable_steppers_btn.setObjectName("motion_disable_steppers_btn") - self.cp_content_layout_2.addWidget(self.motion_disable_steppers_btn, 0, 1, 1, 1) - self.motion_extrude_btn = BlocksCustomButton(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.motion_extrude_btn.sizePolicy().hasHeightForWidth()) - self.motion_extrude_btn.setSizePolicy(sizePolicy) - self.motion_extrude_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.motion_extrude_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.motion_extrude_btn.setFont(font) - self.motion_extrude_btn.setMouseTracking(False) - self.motion_extrude_btn.setTabletTracking(True) - self.motion_extrude_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.motion_extrude_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.motion_extrude_btn.setStyleSheet("") - self.motion_extrude_btn.setAutoDefault(False) - self.motion_extrude_btn.setFlat(True) - self.motion_extrude_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg")) - self.motion_extrude_btn.setObjectName("motion_extrude_btn") - self.cp_content_layout_2.addWidget(self.motion_extrude_btn, 1, 1, 1, 1) - self.motion_auto_home_btn = BlocksCustomButton(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.motion_auto_home_btn.sizePolicy().hasHeightForWidth()) - self.motion_auto_home_btn.setSizePolicy(sizePolicy) - self.motion_auto_home_btn.setMinimumSize(QtCore.QSize(10, 80)) - self.motion_auto_home_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.motion_auto_home_btn.setFont(font) - self.motion_auto_home_btn.setMouseTracking(False) - self.motion_auto_home_btn.setTabletTracking(True) - self.motion_auto_home_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.motion_auto_home_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.motion_auto_home_btn.setStyleSheet("") - self.motion_auto_home_btn.setAutoDefault(False) - self.motion_auto_home_btn.setFlat(True) - self.motion_auto_home_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_all.svg")) - self.motion_auto_home_btn.setObjectName("motion_auto_home_btn") - self.cp_content_layout_2.addWidget(self.motion_auto_home_btn, 0, 0, 1, 1) - self.blank = QtWidgets.QWidget(parent=self.motion_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.blank.sizePolicy().hasHeightForWidth()) - self.blank.setSizePolicy(sizePolicy) - self.blank.setMinimumSize(QtCore.QSize(10, 80)) - self.blank.setMaximumSize(QtCore.QSize(250, 80)) - self.blank.setObjectName("blank") - self.cp_content_layout_2.addWidget(self.blank, 2, 0, 1, 1) - self.verticalLayout_2.addLayout(self.cp_content_layout_2) - controlStackedWidget.addWidget(self.motion_page) - self.extrude_page = QtWidgets.QWidget() - self.extrude_page.setMinimumSize(QtCore.QSize(710, 400)) - self.extrude_page.setMaximumSize(QtCore.QSize(720, 420)) - self.extrude_page.setObjectName("extrude_page") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.extrude_page) - self.verticalLayout_3.setObjectName("verticalLayout_3") - spacerItem = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_3.addItem(spacerItem) - self.exp_header_layout = QtWidgets.QHBoxLayout() - self.exp_header_layout.setObjectName("exp_header_layout") - spacerItem1 = QtWidgets.QSpacerItem(60, 60, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.exp_header_layout.addItem(spacerItem1) - self.exp_title_label = QtWidgets.QLabel(parent=self.extrude_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.exp_title_label.sizePolicy().hasHeightForWidth()) - self.exp_title_label.setSizePolicy(sizePolicy) - self.exp_title_label.setMinimumSize(QtCore.QSize(0, 60)) - self.exp_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.exp_title_label.setFont(font) - self.exp_title_label.setStyleSheet("background: transparent; color: white;") - self.exp_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.exp_title_label.setObjectName("exp_title_label") - self.exp_header_layout.addWidget(self.exp_title_label) - self.exp_back_btn = IconButton(parent=self.extrude_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.exp_back_btn.sizePolicy().hasHeightForWidth()) - self.exp_back_btn.setSizePolicy(sizePolicy) - self.exp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.exp_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.exp_back_btn.setFont(font) - self.exp_back_btn.setMouseTracking(False) - self.exp_back_btn.setTabletTracking(True) - self.exp_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.exp_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.exp_back_btn.setStyleSheet("") - self.exp_back_btn.setAutoDefault(False) - self.exp_back_btn.setFlat(True) - self.exp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.exp_back_btn.setObjectName("exp_back_btn") - self.exp_header_layout.addWidget(self.exp_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.verticalLayout_3.addLayout(self.exp_header_layout) - self.exp_vertical_content_layout = QtWidgets.QVBoxLayout() - self.exp_vertical_content_layout.setContentsMargins(5, 5, 5, 5) - self.exp_vertical_content_layout.setObjectName("exp_vertical_content_layout") - self.exp_length_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) - self.exp_length_group_box.setMinimumSize(QtCore.QSize(0, 80)) - self.exp_length_group_box.setMaximumSize(QtCore.QSize(16777215, 16777215)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - self.exp_length_group_box.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.exp_length_group_box.setFont(font) - self.exp_length_group_box.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.exp_length_group_box.setFlat(True) - self.exp_length_group_box.setObjectName("exp_length_group_box") - self.layoutWidget = QtWidgets.QWidget(parent=self.exp_length_group_box) - self.layoutWidget.setGeometry(QtCore.QRect(0, 20, 681, 61)) - self.layoutWidget.setObjectName("layoutWidget") - self.exp_length_content_layout = QtWidgets.QHBoxLayout(self.layoutWidget) - self.exp_length_content_layout.setContentsMargins(5, 5, 5, 5) - self.exp_length_content_layout.setSpacing(5) - self.exp_length_content_layout.setObjectName("exp_length_content_layout") - self.extrude_select_length_10_btn = BlocksCustomCheckButton(parent=self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_length_10_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_length_10_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_length_10_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_length_10_btn.setFont(font) - self.extrude_select_length_10_btn.setCheckable(True) - self.extrude_select_length_10_btn.setChecked(True) - self.extrude_select_length_10_btn.setAutoRepeat(False) - self.extrude_select_length_10_btn.setAutoExclusive(False) - self.extrude_select_length_10_btn.setFlat(True) - self.extrude_select_length_10_btn.setObjectName("extrude_select_length_10_btn") - self.extrude_select_length_group = QtWidgets.QButtonGroup(controlStackedWidget) - self.extrude_select_length_group.setObjectName("extrude_select_length_group") - self.extrude_select_length_group.addButton(self.extrude_select_length_10_btn) - self.exp_length_content_layout.addWidget(self.extrude_select_length_10_btn) - self.extrude_select_length_50_btn = BlocksCustomCheckButton(parent=self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_length_50_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_length_50_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_length_50_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_length_50_btn.setFont(font) - self.extrude_select_length_50_btn.setCheckable(True) - self.extrude_select_length_50_btn.setAutoRepeat(False) - self.extrude_select_length_50_btn.setAutoExclusive(False) - self.extrude_select_length_50_btn.setFlat(True) - self.extrude_select_length_50_btn.setObjectName("extrude_select_length_50_btn") - self.extrude_select_length_group.addButton(self.extrude_select_length_50_btn) - self.exp_length_content_layout.addWidget(self.extrude_select_length_50_btn) - self.extrude_select_length_100_btn = BlocksCustomCheckButton(parent=self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_length_100_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_length_100_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_length_100_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_length_100_btn.setFont(font) - self.extrude_select_length_100_btn.setCheckable(True) - self.extrude_select_length_100_btn.setAutoRepeat(False) - self.extrude_select_length_100_btn.setAutoExclusive(False) - self.extrude_select_length_100_btn.setFlat(True) - self.extrude_select_length_100_btn.setObjectName("extrude_select_length_100_btn") - self.extrude_select_length_group.addButton(self.extrude_select_length_100_btn) - self.exp_length_content_layout.addWidget(self.extrude_select_length_100_btn) - self.exp_vertical_content_layout.addWidget(self.exp_length_group_box) - self.exp_feedrate_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) - self.exp_feedrate_group_box.setMinimumSize(QtCore.QSize(0, 80)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - self.exp_feedrate_group_box.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.exp_feedrate_group_box.setFont(font) - self.exp_feedrate_group_box.setFlat(True) - self.exp_feedrate_group_box.setObjectName("exp_feedrate_group_box") - self.layoutWidget1 = QtWidgets.QWidget(parent=self.exp_feedrate_group_box) - self.layoutWidget1.setGeometry(QtCore.QRect(0, 19, 681, 61)) - self.layoutWidget1.setObjectName("layoutWidget1") - self.exp_feedrate_content_layout = QtWidgets.QHBoxLayout(self.layoutWidget1) - self.exp_feedrate_content_layout.setContentsMargins(5, 5, 5, 5) - self.exp_feedrate_content_layout.setSpacing(5) - self.exp_feedrate_content_layout.setObjectName("exp_feedrate_content_layout") - self.extrude_select_feedrate_low_btn = BlocksCustomCheckButton(parent=self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_feedrate_low_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_feedrate_low_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_feedrate_low_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_feedrate_low_btn.setFont(font) - self.extrude_select_feedrate_low_btn.setCheckable(True) - self.extrude_select_feedrate_low_btn.setChecked(True) - self.extrude_select_feedrate_low_btn.setAutoRepeat(False) - self.extrude_select_feedrate_low_btn.setAutoExclusive(False) - self.extrude_select_feedrate_low_btn.setFlat(True) - self.extrude_select_feedrate_low_btn.setObjectName("extrude_select_feedrate_low_btn") - self.extrude_select_feedrate_group = QtWidgets.QButtonGroup(controlStackedWidget) - self.extrude_select_feedrate_group.setObjectName("extrude_select_feedrate_group") - self.extrude_select_feedrate_group.addButton(self.extrude_select_feedrate_low_btn) - self.exp_feedrate_content_layout.addWidget(self.extrude_select_feedrate_low_btn) - self.extrude_select_feedrate_middle_btn = BlocksCustomCheckButton(parent=self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_feedrate_middle_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_feedrate_middle_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_feedrate_middle_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_feedrate_middle_btn.setFont(font) - self.extrude_select_feedrate_middle_btn.setCheckable(True) - self.extrude_select_feedrate_middle_btn.setAutoRepeat(False) - self.extrude_select_feedrate_middle_btn.setAutoExclusive(False) - self.extrude_select_feedrate_middle_btn.setFlat(True) - self.extrude_select_feedrate_middle_btn.setObjectName("extrude_select_feedrate_middle_btn") - self.extrude_select_feedrate_group.addButton(self.extrude_select_feedrate_middle_btn) - self.exp_feedrate_content_layout.addWidget(self.extrude_select_feedrate_middle_btn) - self.extrude_select_feedrate_high_btn = BlocksCustomCheckButton(parent=self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.extrude_select_feedrate_high_btn.sizePolicy().hasHeightForWidth()) - self.extrude_select_feedrate_high_btn.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.BrightText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.extrude_select_feedrate_high_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(16) - font.setBold(False) - self.extrude_select_feedrate_high_btn.setFont(font) - self.extrude_select_feedrate_high_btn.setCheckable(True) - self.extrude_select_feedrate_high_btn.setAutoRepeat(False) - self.extrude_select_feedrate_high_btn.setAutoExclusive(False) - self.extrude_select_feedrate_high_btn.setFlat(True) - self.extrude_select_feedrate_high_btn.setObjectName("extrude_select_feedrate_high_btn") - self.extrude_select_feedrate_group.addButton(self.extrude_select_feedrate_high_btn) - self.exp_feedrate_content_layout.addWidget(self.extrude_select_feedrate_high_btn) - self.exp_vertical_content_layout.addWidget(self.exp_feedrate_group_box) - self.exp_movement_content_layout = QtWidgets.QVBoxLayout() - self.exp_movement_content_layout.setContentsMargins(-1, 5, -1, -1) - self.exp_movement_content_layout.setSpacing(0) - self.exp_movement_content_layout.setObjectName("exp_movement_content_layout") - self.exp_buttons_layout = QtWidgets.QHBoxLayout() - self.exp_buttons_layout.setContentsMargins(5, 5, 5, 5) - self.exp_buttons_layout.setObjectName("exp_buttons_layout") - self.exp_unextrude_btn = BlocksCustomButton(parent=self.extrude_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.exp_unextrude_btn.sizePolicy().hasHeightForWidth()) - self.exp_unextrude_btn.setSizePolicy(sizePolicy) - self.exp_unextrude_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.exp_unextrude_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.exp_unextrude_btn.setFont(font) - self.exp_unextrude_btn.setMouseTracking(False) - self.exp_unextrude_btn.setTabletTracking(True) - self.exp_unextrude_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.exp_unextrude_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.exp_unextrude_btn.setStyleSheet("") - self.exp_unextrude_btn.setAutoDefault(False) - self.exp_unextrude_btn.setFlat(True) - self.exp_unextrude_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg")) - self.exp_unextrude_btn.setObjectName("exp_unextrude_btn") - self.exp_buttons_layout.addWidget(self.exp_unextrude_btn) - self.exp_nozzle_icon_label = BlocksLabel(parent=self.extrude_page) - self.exp_nozzle_icon_label.setMinimumSize(QtCore.QSize(60, 60)) - self.exp_nozzle_icon_label.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(16) - self.exp_nozzle_icon_label.setFont(font) - self.exp_nozzle_icon_label.setStyleSheet("") - self.exp_nozzle_icon_label.setText("") - self.exp_nozzle_icon_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.exp_nozzle_icon_label.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg")) - self.exp_nozzle_icon_label.setObjectName("exp_nozzle_icon_label") - self.exp_buttons_layout.addWidget(self.exp_nozzle_icon_label) - self.exp_extrude_btn = BlocksCustomButton(parent=self.extrude_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.exp_extrude_btn.sizePolicy().hasHeightForWidth()) - self.exp_extrude_btn.setSizePolicy(sizePolicy) - self.exp_extrude_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.exp_extrude_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.exp_extrude_btn.setFont(font) - self.exp_extrude_btn.setMouseTracking(False) - self.exp_extrude_btn.setTabletTracking(True) - self.exp_extrude_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.exp_extrude_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.exp_extrude_btn.setStyleSheet("") - self.exp_extrude_btn.setAutoDefault(False) - self.exp_extrude_btn.setFlat(True) - self.exp_extrude_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg")) - self.exp_extrude_btn.setObjectName("exp_extrude_btn") - self.exp_buttons_layout.addWidget(self.exp_extrude_btn) - self.exp_movement_content_layout.addLayout(self.exp_buttons_layout) - self.exp_info_layout = QtWidgets.QHBoxLayout() - self.exp_info_layout.setContentsMargins(5, 5, 5, 5) - self.exp_info_layout.setObjectName("exp_info_layout") - self.exp_info_label = QtWidgets.QLabel(parent=self.extrude_page) - self.exp_info_label.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.exp_info_label.sizePolicy().hasHeightForWidth()) - self.exp_info_label.setSizePolicy(sizePolicy) - self.exp_info_label.setMinimumSize(QtCore.QSize(0, 0)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.exp_info_label.setFont(font) - self.exp_info_label.setStyleSheet("background: transparent; color: white;") - self.exp_info_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.exp_info_label.setObjectName("exp_info_label") - self.exp_info_layout.addWidget(self.exp_info_label) - self.exp_movement_content_layout.addLayout(self.exp_info_layout) - self.exp_movement_content_layout.setStretch(1, 1) - self.exp_vertical_content_layout.addLayout(self.exp_movement_content_layout) - self.exp_vertical_content_layout.setStretch(2, 1) - self.verticalLayout_3.addLayout(self.exp_vertical_content_layout) - controlStackedWidget.addWidget(self.extrude_page) - self.move_axis_page = QtWidgets.QWidget() - self.move_axis_page.setMinimumSize(QtCore.QSize(710, 400)) - self.move_axis_page.setMaximumSize(QtCore.QSize(720, 420)) - self.move_axis_page.setObjectName("move_axis_page") - self.mva_x_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_x_label.setEnabled(True) - self.mva_x_label.setGeometry(QtCore.QRect(160, 350, 51, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_x_label.setFont(font) - self.mva_x_label.setStyleSheet("background: transparent; color: white;") - self.mva_x_label.setObjectName("mva_x_label") - self.mva_y_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_y_label.setEnabled(True) - self.mva_y_label.setGeometry(QtCore.QRect(340, 350, 51, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_y_label.setFont(font) - self.mva_y_label.setStyleSheet("background: transparent; color: white;") - self.mva_y_label.setObjectName("mva_y_label") - self.mva_z_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_z_label.setEnabled(True) - self.mva_z_label.setGeometry(QtCore.QRect(500, 350, 51, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_z_label.setFont(font) - self.mva_z_label.setStyleSheet("background: transparent; color: white;") - self.mva_z_label.setObjectName("mva_z_label") - self.mva_z_value_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_z_value_label.setEnabled(True) - self.mva_z_value_label.setGeometry(QtCore.QRect(550, 350, 91, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_z_value_label.setFont(font) - self.mva_z_value_label.setStyleSheet("background: transparent; color: white;") - self.mva_z_value_label.setObjectName("mva_z_value_label") - self.mva_y_value_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_y_value_label.setEnabled(True) - self.mva_y_value_label.setGeometry(QtCore.QRect(370, 350, 91, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_y_value_label.setFont(font) - self.mva_y_value_label.setStyleSheet("background: transparent; color: white;") - self.mva_y_value_label.setObjectName("mva_y_value_label") - self.mva_x_value_label = QtWidgets.QLabel(parent=self.move_axis_page) - self.mva_x_value_label.setEnabled(True) - self.mva_x_value_label.setGeometry(QtCore.QRect(190, 350, 81, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.mva_x_value_label.setFont(font) - self.mva_x_value_label.setStyleSheet("background: transparent; color: white;") - self.mva_x_value_label.setObjectName("mva_x_value_label") - self.horizontalLayoutWidget_3 = QtWidgets.QWidget(parent=self.move_axis_page) - self.horizontalLayoutWidget_3.setGeometry(QtCore.QRect(10, 23, 691, 81)) - self.horizontalLayoutWidget_3.setObjectName("horizontalLayoutWidget_3") - self.mva_header_layout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_3) - self.mva_header_layout.setContentsMargins(0, 0, 0, 0) - self.mva_header_layout.setObjectName("mva_header_layout") - spacerItem2 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.mva_header_layout.addItem(spacerItem2) - self.mva_title_label = QtWidgets.QLabel(parent=self.horizontalLayoutWidget_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mva_title_label.sizePolicy().hasHeightForWidth()) - self.mva_title_label.setSizePolicy(sizePolicy) - self.mva_title_label.setMinimumSize(QtCore.QSize(0, 0)) - self.mva_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.mva_title_label.setFont(font) - self.mva_title_label.setStyleSheet("background: transparent; color: white;") - self.mva_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.mva_title_label.setObjectName("mva_title_label") - self.mva_header_layout.addWidget(self.mva_title_label) - self.mva_back_btn = IconButton(parent=self.horizontalLayoutWidget_3) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mva_back_btn.sizePolicy().hasHeightForWidth()) - self.mva_back_btn.setSizePolicy(sizePolicy) - self.mva_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.mva_back_btn.setFont(font) - self.mva_back_btn.setMouseTracking(False) - self.mva_back_btn.setTabletTracking(True) - self.mva_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.mva_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.mva_back_btn.setStyleSheet("") - self.mva_back_btn.setAutoDefault(False) - self.mva_back_btn.setFlat(True) - self.mva_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.mva_back_btn.setObjectName("mva_back_btn") - self.mva_header_layout.addWidget(self.mva_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.verticalLayoutWidget_2 = QtWidgets.QWidget(parent=self.move_axis_page) - self.verticalLayoutWidget_2.setGeometry(QtCore.QRect(630, 130, 71, 201)) - self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2") - self.mva_z_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_2) - self.mva_z_layout.setContentsMargins(0, 0, 0, 0) - self.mva_z_layout.setObjectName("mva_z_layout") - self.mva_z_up = IconButton(parent=self.verticalLayoutWidget_2) - self.mva_z_up.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_z_up.sizePolicy().hasHeightForWidth()) - self.mva_z_up.setSizePolicy(sizePolicy) - self.mva_z_up.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_z_up.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_z_up.setStyleSheet("") - self.mva_z_up.setText("") - self.mva_z_up.setIconSize(QtCore.QSize(16, 16)) - self.mva_z_up.setCheckable(False) - self.mva_z_up.setChecked(False) - self.mva_z_up.setFlat(True) - self.mva_z_up.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg")) - self.mva_z_up.setObjectName("mva_z_up") - self.mva_z_layout.addWidget(self.mva_z_up, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.mva_z_down = IconButton(parent=self.verticalLayoutWidget_2) - self.mva_z_down.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_z_down.sizePolicy().hasHeightForWidth()) - self.mva_z_down.setSizePolicy(sizePolicy) - self.mva_z_down.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_z_down.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_z_down.setStyleSheet("") - self.mva_z_down.setText("") - self.mva_z_down.setIconSize(QtCore.QSize(16, 16)) - self.mva_z_down.setCheckable(False) - self.mva_z_down.setChecked(False) - self.mva_z_down.setFlat(True) - self.mva_z_down.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg")) - self.mva_z_down.setObjectName("mva_z_down") - self.mva_z_layout.addWidget(self.mva_z_down, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.verticalLayoutWidget_3 = QtWidgets.QWidget(parent=self.move_axis_page) - self.verticalLayoutWidget_3.setGeometry(QtCore.QRect(10, 90, 81, 301)) - self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3") - self.mva_home_axis_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_3) - self.mva_home_axis_layout.setContentsMargins(5, 5, 5, 5) - self.mva_home_axis_layout.setObjectName("mva_home_axis_layout") - self.mva_home_x_btn = IconButton(parent=self.verticalLayoutWidget_3) - self.mva_home_x_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_home_x_btn.sizePolicy().hasHeightForWidth()) - self.mva_home_x_btn.setSizePolicy(sizePolicy) - self.mva_home_x_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_home_x_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_home_x_btn.setStyleSheet("") - self.mva_home_x_btn.setText("") - self.mva_home_x_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_home_x_btn.setCheckable(False) - self.mva_home_x_btn.setChecked(False) - self.mva_home_x_btn.setFlat(True) - self.mva_home_x_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_x.svg")) - self.mva_home_x_btn.setObjectName("mva_home_x_btn") - self.mva_home_axis_layout.addWidget(self.mva_home_x_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.mva_home_y_btn = IconButton(parent=self.verticalLayoutWidget_3) - self.mva_home_y_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_home_y_btn.sizePolicy().hasHeightForWidth()) - self.mva_home_y_btn.setSizePolicy(sizePolicy) - self.mva_home_y_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_home_y_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_home_y_btn.setStyleSheet("") - self.mva_home_y_btn.setText("") - self.mva_home_y_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_home_y_btn.setCheckable(False) - self.mva_home_y_btn.setChecked(False) - self.mva_home_y_btn.setFlat(True) - self.mva_home_y_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_y.svg")) - self.mva_home_y_btn.setObjectName("mva_home_y_btn") - self.mva_home_axis_layout.addWidget(self.mva_home_y_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.mva_home_z_btn = IconButton(parent=self.verticalLayoutWidget_3) - self.mva_home_z_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_home_z_btn.sizePolicy().hasHeightForWidth()) - self.mva_home_z_btn.setSizePolicy(sizePolicy) - self.mva_home_z_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_home_z_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_home_z_btn.setStyleSheet("") - self.mva_home_z_btn.setText("") - self.mva_home_z_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_home_z_btn.setCheckable(False) - self.mva_home_z_btn.setChecked(False) - self.mva_home_z_btn.setFlat(True) - self.mva_home_z_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_z.svg")) - self.mva_home_z_btn.setObjectName("mva_home_z_btn") - self.mva_home_axis_layout.addWidget(self.mva_home_z_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.mva_home_all_btn = IconButton(parent=self.verticalLayoutWidget_3) - self.mva_home_all_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_home_all_btn.sizePolicy().hasHeightForWidth()) - self.mva_home_all_btn.setSizePolicy(sizePolicy) - self.mva_home_all_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_home_all_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_home_all_btn.setStyleSheet("") - self.mva_home_all_btn.setText("") - self.mva_home_all_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_home_all_btn.setCheckable(False) - self.mva_home_all_btn.setChecked(False) - self.mva_home_all_btn.setFlat(True) - self.mva_home_all_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/home_all.svg")) - self.mva_home_all_btn.setObjectName("mva_home_all_btn") - self.mva_home_axis_layout.addWidget(self.mva_home_all_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.mva_select_speed_25_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_speed_25_btn.setGeometry(QtCore.QRect(96, 240, 100, 100)) - self.mva_select_speed_25_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_speed_25_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_speed_25_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_speed_25_btn.setFont(font) - self.mva_select_speed_25_btn.setCheckable(True) - self.mva_select_speed_25_btn.setChecked(True) - self.mva_select_speed_25_btn.setFlat(True) - self.mva_select_speed_25_btn.setObjectName("mva_select_speed_25_btn") - self.axis_select_speed_group = QtWidgets.QButtonGroup(controlStackedWidget) - self.axis_select_speed_group.setObjectName("axis_select_speed_group") - self.axis_select_speed_group.addButton(self.mva_select_speed_25_btn) - self.mva_select_speed_50_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_speed_50_btn.setGeometry(QtCore.QRect(205, 240, 100, 100)) - self.mva_select_speed_50_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_speed_50_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_speed_50_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_speed_50_btn.setFont(font) - self.mva_select_speed_50_btn.setCheckable(True) - self.mva_select_speed_50_btn.setFlat(False) - self.mva_select_speed_50_btn.setObjectName("mva_select_speed_50_btn") - self.axis_select_speed_group.addButton(self.mva_select_speed_50_btn) - self.mva_select_speed_100_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_speed_100_btn.setGeometry(QtCore.QRect(315, 240, 100, 100)) - self.mva_select_speed_100_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_speed_100_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_speed_100_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_speed_100_btn.setFont(font) - self.mva_select_speed_100_btn.setCheckable(True) - self.mva_select_speed_100_btn.setFlat(False) - self.mva_select_speed_100_btn.setObjectName("mva_select_speed_100_btn") - self.axis_select_speed_group.addButton(self.mva_select_speed_100_btn) - self.label = QtWidgets.QLabel(parent=self.move_axis_page) - self.label.setGeometry(QtCore.QRect(109, 216, 261, 21)) - font = QtGui.QFont() - font.setPointSize(14) - self.label.setFont(font) - self.label.setStyleSheet("color:white") - self.label.setObjectName("label") - self.mva_select_length_1_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_length_1_btn.setGeometry(QtCore.QRect(96, 110, 100, 100)) - self.mva_select_length_1_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_length_1_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_length_1_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_length_1_btn.setFont(font) - self.mva_select_length_1_btn.setCheckable(True) - self.mva_select_length_1_btn.setChecked(True) - self.mva_select_length_1_btn.setFlat(True) - self.mva_select_length_1_btn.setObjectName("mva_select_length_1_btn") - self.axis_select_length_group = QtWidgets.QButtonGroup(controlStackedWidget) - self.axis_select_length_group.setObjectName("axis_select_length_group") - self.axis_select_length_group.addButton(self.mva_select_length_1_btn) - self.mva_select_length_10_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_length_10_btn.setGeometry(QtCore.QRect(204, 110, 100, 100)) - self.mva_select_length_10_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_length_10_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_length_10_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_length_10_btn.setFont(font) - self.mva_select_length_10_btn.setCheckable(True) - self.mva_select_length_10_btn.setFlat(False) - self.mva_select_length_10_btn.setObjectName("mva_select_length_10_btn") - self.axis_select_length_group.addButton(self.mva_select_length_10_btn) - self.mva_select_length_100_btn = BlocksCustomCheckButton(parent=self.move_axis_page) - self.mva_select_length_100_btn.setGeometry(QtCore.QRect(315, 110, 100, 100)) - self.mva_select_length_100_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_select_length_100_btn.setMaximumSize(QtCore.QSize(100, 100)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.mva_select_length_100_btn.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.mva_select_length_100_btn.setFont(font) - self.mva_select_length_100_btn.setCheckable(True) - self.mva_select_length_100_btn.setFlat(False) - self.mva_select_length_100_btn.setObjectName("mva_select_length_100_btn") - self.axis_select_length_group.addButton(self.mva_select_length_100_btn) - self.label_2 = QtWidgets.QLabel(parent=self.move_axis_page) - self.label_2.setGeometry(QtCore.QRect(109, 85, 261, 21)) - font = QtGui.QFont() - font.setPointSize(14) - self.label_2.setFont(font) - self.label_2.setStyleSheet("color:white") - self.label_2.setObjectName("label_2") - self.verticalLayoutWidget = QtWidgets.QWidget(parent=self.move_axis_page) - self.verticalLayoutWidget.setGeometry(QtCore.QRect(440, 128, 196, 204)) - self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - self.gridLayout_2 = QtWidgets.QGridLayout(self.verticalLayoutWidget) - self.gridLayout_2.setContentsMargins(0, 5, 0, 5) - self.gridLayout_2.setObjectName("gridLayout_2") - self.mva_left_btn = IconButton(parent=self.verticalLayoutWidget) - self.mva_left_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_left_btn.sizePolicy().hasHeightForWidth()) - self.mva_left_btn.setSizePolicy(sizePolicy) - self.mva_left_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_left_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_left_btn.setStyleSheet("") - self.mva_left_btn.setText("") - self.mva_left_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_left_btn.setCheckable(False) - self.mva_left_btn.setChecked(False) - self.mva_left_btn.setFlat(True) - self.mva_left_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/left_arrow.svg")) - self.mva_left_btn.setObjectName("mva_left_btn") - self.gridLayout_2.addWidget(self.mva_left_btn, 1, 0, 1, 1) - self.mva_right_btn = IconButton(parent=self.verticalLayoutWidget) - self.mva_right_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_right_btn.sizePolicy().hasHeightForWidth()) - self.mva_right_btn.setSizePolicy(sizePolicy) - self.mva_right_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_right_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_right_btn.setStyleSheet("") - self.mva_right_btn.setText("") - self.mva_right_btn.setIconSize(QtCore.QSize(16, 16)) - self.mva_right_btn.setCheckable(False) - self.mva_right_btn.setChecked(False) - self.mva_right_btn.setFlat(True) - self.mva_right_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg")) - self.mva_right_btn.setObjectName("mva_right_btn") - self.gridLayout_2.addWidget(self.mva_right_btn, 1, 2, 1, 1) - self.mva_down_btn = IconButton(parent=self.verticalLayoutWidget) - self.mva_down_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_down_btn.sizePolicy().hasHeightForWidth()) - self.mva_down_btn.setSizePolicy(sizePolicy) - self.mva_down_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_down_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_down_btn.setStyleSheet("") - self.mva_down_btn.setText("") - self.mva_down_btn.setIconSize(QtCore.QSize(60, 60)) - self.mva_down_btn.setCheckable(False) - self.mva_down_btn.setChecked(False) - self.mva_down_btn.setFlat(True) - self.mva_down_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg")) - self.mva_down_btn.setObjectName("mva_down_btn") - self.gridLayout_2.addWidget(self.mva_down_btn, 2, 1, 1, 1) - self.mva_up_btn = IconButton(parent=self.verticalLayoutWidget) - self.mva_up_btn.setEnabled(True) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.mva_up_btn.sizePolicy().hasHeightForWidth()) - self.mva_up_btn.setSizePolicy(sizePolicy) - self.mva_up_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_up_btn.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_up_btn.setStyleSheet("") - self.mva_up_btn.setText("") - self.mva_up_btn.setIconSize(QtCore.QSize(60, 60)) - self.mva_up_btn.setCheckable(False) - self.mva_up_btn.setChecked(False) - self.mva_up_btn.setFlat(True) - self.mva_up_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg")) - self.mva_up_btn.setObjectName("mva_up_btn") - self.gridLayout_2.addWidget(self.mva_up_btn, 0, 1, 1, 1) - self.mva_middle = IconButton(parent=self.verticalLayoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.mva_middle.sizePolicy().hasHeightForWidth()) - self.mva_middle.setSizePolicy(sizePolicy) - self.mva_middle.setMinimumSize(QtCore.QSize(60, 60)) - self.mva_middle.setMaximumSize(QtCore.QSize(60, 60)) - self.mva_middle.setText("") - self.mva_middle.setFlat(True) - self.mva_middle.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/center_arrows.svg")) - self.mva_middle.setObjectName("mva_middle") - self.gridLayout_2.addWidget(self.mva_middle, 1, 1, 1, 1) - controlStackedWidget.addWidget(self.move_axis_page) - self.temperature_page = QtWidgets.QWidget() - self.temperature_page.setMinimumSize(QtCore.QSize(710, 400)) - self.temperature_page.setMaximumSize(QtCore.QSize(720, 420)) - self.temperature_page.setObjectName("temperature_page") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.temperature_page) - self.verticalLayout_4.setObjectName("verticalLayout_4") - spacerItem3 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_4.addItem(spacerItem3) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem4 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout.addItem(spacerItem4) - self.temp_header_title = QtWidgets.QLabel(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.temp_header_title.sizePolicy().hasHeightForWidth()) - self.temp_header_title.setSizePolicy(sizePolicy) - self.temp_header_title.setMinimumSize(QtCore.QSize(0, 60)) - self.temp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - font.setBold(True) - self.temp_header_title.setFont(font) - self.temp_header_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.temp_header_title.setStyleSheet("background: transparent; color: white;") - self.temp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.temp_header_title.setObjectName("temp_header_title") - self.horizontalLayout.addWidget(self.temp_header_title) - self.temp_back_button = IconButton(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.temp_back_button.sizePolicy().hasHeightForWidth()) - self.temp_back_button.setSizePolicy(sizePolicy) - self.temp_back_button.setMinimumSize(QtCore.QSize(60, 60)) - self.temp_back_button.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.temp_back_button.setFont(font) - self.temp_back_button.setMouseTracking(False) - self.temp_back_button.setTabletTracking(True) - self.temp_back_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.temp_back_button.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.temp_back_button.setStyleSheet("") - self.temp_back_button.setAutoDefault(False) - self.temp_back_button.setFlat(True) - self.temp_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.temp_back_button.setObjectName("temp_back_button") - self.horizontalLayout.addWidget(self.temp_back_button) - self.verticalLayout_4.addLayout(self.horizontalLayout) - spacerItem5 = QtWidgets.QSpacerItem(20, 35, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_4.addItem(spacerItem5) - self.gridLayout = QtWidgets.QGridLayout() - self.gridLayout.setContentsMargins(5, 5, 5, 5) - self.gridLayout.setSpacing(0) - self.gridLayout.setObjectName("gridLayout") - self.tp_content_horizontal_layout = QtWidgets.QHBoxLayout() - self.tp_content_horizontal_layout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinimumSize) - self.tp_content_horizontal_layout.setContentsMargins(5, 5, 5, 5) - self.tp_content_horizontal_layout.setSpacing(5) - self.tp_content_horizontal_layout.setObjectName("tp_content_horizontal_layout") - self.extruder_temp_display = DisplayButton(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.extruder_temp_display.sizePolicy().hasHeightForWidth()) - self.extruder_temp_display.setSizePolicy(sizePolicy) - self.extruder_temp_display.setMinimumSize(QtCore.QSize(200, 60)) - self.extruder_temp_display.setMaximumSize(QtCore.QSize(120, 60)) - font = QtGui.QFont() - font.setPointSize(11) - self.extruder_temp_display.setFont(font) - self.extruder_temp_display.setAutoFillBackground(False) - self.extruder_temp_display.setText("") - self.extruder_temp_display.setFlat(True) - self.extruder_temp_display.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg")) - self.extruder_temp_display.setObjectName("extruder_temp_display") - self.tp_content_horizontal_layout.addWidget(self.extruder_temp_display) - self.bed_temp_display = DisplayButton(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.bed_temp_display.sizePolicy().hasHeightForWidth()) - self.bed_temp_display.setSizePolicy(sizePolicy) - self.bed_temp_display.setMinimumSize(QtCore.QSize(200, 60)) - self.bed_temp_display.setMaximumSize(QtCore.QSize(120, 60)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Window, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Highlight, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Window, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Highlight, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.HighlightedText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Base, brush) - brush = QtGui.QBrush(QtGui.QColor(50, 50, 50)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Window, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Highlight, brush) - brush = QtGui.QBrush(QtGui.QColor(60, 60, 60)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.HighlightedText, brush) - self.bed_temp_display.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(11) - self.bed_temp_display.setFont(font) - self.bed_temp_display.setText("") - self.bed_temp_display.setCheckable(False) - self.bed_temp_display.setDefault(False) - self.bed_temp_display.setFlat(True) - self.bed_temp_display.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature_plate.svg")) - self.bed_temp_display.setObjectName("bed_temp_display") - self.tp_content_horizontal_layout.addWidget(self.bed_temp_display) - self.gridLayout.addLayout(self.tp_content_horizontal_layout, 0, 0, 1, 2) - self.cooldown_btn = BlocksCustomButton(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.cooldown_btn.sizePolicy().hasHeightForWidth()) - self.cooldown_btn.setSizePolicy(sizePolicy) - self.cooldown_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.cooldown_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.cooldown_btn.setFont(font) - self.cooldown_btn.setMouseTracking(False) - self.cooldown_btn.setTabletTracking(True) - self.cooldown_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.cooldown_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.cooldown_btn.setStyleSheet("") - self.cooldown_btn.setAutoDefault(False) - self.cooldown_btn.setFlat(True) - self.cooldown_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/cooldown.svg")) - self.cooldown_btn.setObjectName("cooldown_btn") - self.gridLayout.addWidget(self.cooldown_btn, 2, 1, 1, 1) - spacerItem6 = QtWidgets.QSpacerItem(20, 50, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.gridLayout.addItem(spacerItem6, 1, 0, 1, 2) - self.temperature_cooldown_btn = BlocksCustomButton(parent=self.temperature_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.temperature_cooldown_btn.sizePolicy().hasHeightForWidth()) - self.temperature_cooldown_btn.setSizePolicy(sizePolicy) - self.temperature_cooldown_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.temperature_cooldown_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.temperature_cooldown_btn.setFont(font) - self.temperature_cooldown_btn.setMouseTracking(False) - self.temperature_cooldown_btn.setTabletTracking(True) - self.temperature_cooldown_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.temperature_cooldown_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.temperature_cooldown_btn.setStyleSheet("") - self.temperature_cooldown_btn.setAutoDefault(False) - self.temperature_cooldown_btn.setFlat(True) - self.temperature_cooldown_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/heatsoak_icon.svg")) - self.temperature_cooldown_btn.setObjectName("temperature_cooldown_btn") - self.gridLayout.addWidget(self.temperature_cooldown_btn, 2, 0, 1, 1) - self.verticalLayout_4.addLayout(self.gridLayout) - spacerItem7 = QtWidgets.QSpacerItem(20, 8, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_4.addItem(spacerItem7) - controlStackedWidget.addWidget(self.temperature_page) - self.z_adjustment_page = QtWidgets.QWidget() - self.z_adjustment_page.setMinimumSize(QtCore.QSize(710, 400)) - self.z_adjustment_page.setMaximumSize(QtCore.QSize(720, 420)) - self.z_adjustment_page.setObjectName("z_adjustment_page") - self.z_adjust_icon = QtWidgets.QLabel(parent=self.z_adjustment_page) - self.z_adjust_icon.setEnabled(True) - self.z_adjust_icon.setGeometry(QtCore.QRect(290, 210, 31, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.z_adjust_icon.setFont(font) - self.z_adjust_icon.setStyleSheet("background: transparent; color: white;") - self.z_adjust_icon.setObjectName("z_adjust_icon") - self.z_adjust_offset_value = QtWidgets.QLabel(parent=self.z_adjustment_page) - self.z_adjust_offset_value.setEnabled(True) - self.z_adjust_offset_value.setGeometry(QtCore.QRect(340, 210, 31, 41)) - font = QtGui.QFont() - font.setFamily("Montserrat") - font.setPointSize(14) - self.z_adjust_offset_value.setFont(font) - self.z_adjust_offset_value.setStyleSheet("background: transparent; color: white;") - self.z_adjust_offset_value.setObjectName("z_adjust_offset_value") - self.horizontalLayoutWidget_10 = QtWidgets.QWidget(parent=self.z_adjustment_page) - self.horizontalLayoutWidget_10.setGeometry(QtCore.QRect(10, 10, 681, 62)) - self.horizontalLayoutWidget_10.setObjectName("horizontalLayoutWidget_10") - self.z_adjustment_header_layout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_10) - self.z_adjustment_header_layout.setContentsMargins(0, 0, 0, 0) - self.z_adjustment_header_layout.setObjectName("z_adjustment_header_layout") - spacerItem8 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.z_adjustment_header_layout.addItem(spacerItem8) - self.z_adjust_header_title = QtWidgets.QLabel(parent=self.horizontalLayoutWidget_10) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.z_adjust_header_title.sizePolicy().hasHeightForWidth()) - self.z_adjust_header_title.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.z_adjust_header_title.setFont(font) - self.z_adjust_header_title.setStyleSheet("background: transparent; color: white;") - self.z_adjust_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.z_adjust_header_title.setObjectName("z_adjust_header_title") - self.z_adjustment_header_layout.addWidget(self.z_adjust_header_title) - self.z_adjust_back_button = BlocksCustomButton(parent=self.horizontalLayoutWidget_10) - self.z_adjust_back_button.setMinimumSize(QtCore.QSize(60, 60)) - self.z_adjust_back_button.setMaximumSize(QtCore.QSize(60, 60)) - self.z_adjust_back_button.setText("") - self.z_adjust_back_button.setFlat(True) - self.z_adjust_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) - self.z_adjust_back_button.setObjectName("z_adjust_back_button") - self.z_adjustment_header_layout.addWidget(self.z_adjust_back_button) - self.verticalLayoutWidget_8 = QtWidgets.QWidget(parent=self.z_adjustment_page) - self.verticalLayoutWidget_8.setGeometry(QtCore.QRect(600, 110, 90, 177)) - self.verticalLayoutWidget_8.setObjectName("verticalLayoutWidget_8") - self.z_adjust_move_buttons_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_8) - self.z_adjust_move_buttons_layout.setContentsMargins(5, 5, 5, 5) - self.z_adjust_move_buttons_layout.setObjectName("z_adjust_move_buttons_layout") - self.z_adjust_up_btn = IconButton(parent=self.verticalLayoutWidget_8) - self.z_adjust_up_btn.setMinimumSize(QtCore.QSize(80, 80)) - self.z_adjust_up_btn.setMaximumSize(QtCore.QSize(80, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(36) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.z_adjust_up_btn.setFont(font) - self.z_adjust_up_btn.setMouseTracking(False) - self.z_adjust_up_btn.setTabletTracking(True) - self.z_adjust_up_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.z_adjust_up_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.z_adjust_up_btn.setStyleSheet("") - self.z_adjust_up_btn.setAutoDefault(False) - self.z_adjust_up_btn.setFlat(True) - self.z_adjust_up_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg")) - self.z_adjust_up_btn.setObjectName("z_adjust_up_btn") - self.z_adjust_move_buttons_layout.addWidget(self.z_adjust_up_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.z_adjust_down_btn = IconButton(parent=self.verticalLayoutWidget_8) - self.z_adjust_down_btn.setMinimumSize(QtCore.QSize(80, 80)) - self.z_adjust_down_btn.setMaximumSize(QtCore.QSize(80, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(26) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.z_adjust_down_btn.setFont(font) - self.z_adjust_down_btn.setMouseTracking(False) - self.z_adjust_down_btn.setTabletTracking(True) - self.z_adjust_down_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.z_adjust_down_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.z_adjust_down_btn.setStyleSheet("") - self.z_adjust_down_btn.setAutoDefault(False) - self.z_adjust_down_btn.setFlat(True) - self.z_adjust_down_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg")) - self.z_adjust_down_btn.setObjectName("z_adjust_down_btn") - self.z_adjust_move_buttons_layout.addWidget(self.z_adjust_down_btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.z_adjust_title = BlocksCustomButton(parent=self.z_adjustment_page) - self.z_adjust_title.setGeometry(QtCore.QRect(170, 80, 371, 51)) - self.z_adjust_title.setMinimumSize(QtCore.QSize(10, 10)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.z_adjust_title.setFont(font) - self.z_adjust_title.setMouseTracking(False) - self.z_adjust_title.setTabletTracking(True) - self.z_adjust_title.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.z_adjust_title.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.z_adjust_title.setStyleSheet("") - self.z_adjust_title.setAutoDefault(False) - self.z_adjust_title.setFlat(True) - self.z_adjust_title.setObjectName("z_adjust_title") - self.horizontalLayoutWidget_11 = QtWidgets.QWidget(parent=self.z_adjustment_page) - self.horizontalLayoutWidget_11.setGeometry(QtCore.QRect(20, 320, 671, 71)) - self.horizontalLayoutWidget_11.setObjectName("horizontalLayoutWidget_11") - self.z_adjust_buttons_layout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_11) - self.z_adjust_buttons_layout.setContentsMargins(0, 0, 0, 0) - self.z_adjust_buttons_layout.setObjectName("z_adjust_buttons_layout") - self.z_adjust_confirm_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_11) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.z_adjust_confirm_btn.sizePolicy().hasHeightForWidth()) - self.z_adjust_confirm_btn.setSizePolicy(sizePolicy) - self.z_adjust_confirm_btn.setMinimumSize(QtCore.QSize(10, 0)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.z_adjust_confirm_btn.setFont(font) - self.z_adjust_confirm_btn.setMouseTracking(False) - self.z_adjust_confirm_btn.setTabletTracking(True) - self.z_adjust_confirm_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.z_adjust_confirm_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.z_adjust_confirm_btn.setStyleSheet("") - self.z_adjust_confirm_btn.setAutoDefault(False) - self.z_adjust_confirm_btn.setFlat(True) - self.z_adjust_confirm_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) - self.z_adjust_confirm_btn.setObjectName("z_adjust_confirm_btn") - self.z_adjust_buttons_layout.addWidget(self.z_adjust_confirm_btn) - self.z_adjust_cancel_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_11) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.z_adjust_cancel_btn.sizePolicy().hasHeightForWidth()) - self.z_adjust_cancel_btn.setSizePolicy(sizePolicy) - self.z_adjust_cancel_btn.setMinimumSize(QtCore.QSize(10, 0)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.z_adjust_cancel_btn.setFont(font) - self.z_adjust_cancel_btn.setMouseTracking(False) - self.z_adjust_cancel_btn.setTabletTracking(True) - self.z_adjust_cancel_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.z_adjust_cancel_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.z_adjust_cancel_btn.setStyleSheet("") - self.z_adjust_cancel_btn.setAutoDefault(False) - self.z_adjust_cancel_btn.setFlat(True) - self.z_adjust_cancel_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg")) - self.z_adjust_cancel_btn.setObjectName("z_adjust_cancel_btn") - self.z_adjust_buttons_layout.addWidget(self.z_adjust_cancel_btn) - controlStackedWidget.addWidget(self.z_adjustment_page) - self.printer_settings_page = QtWidgets.QWidget() - self.printer_settings_page.setMinimumSize(QtCore.QSize(710, 400)) - self.printer_settings_page.setMaximumSize(QtCore.QSize(720, 420)) - self.printer_settings_page.setObjectName("printer_settings_page") - self.horizontalLayoutWidget_12 = QtWidgets.QWidget(parent=self.printer_settings_page) - self.horizontalLayoutWidget_12.setGeometry(QtCore.QRect(10, 11, 691, 71)) - self.horizontalLayoutWidget_12.setObjectName("horizontalLayoutWidget_12") - self.printer_setting_header_layout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_12) - self.printer_setting_header_layout.setContentsMargins(0, 0, 0, 0) - self.printer_setting_header_layout.setObjectName("printer_setting_header_layout") - self.printer_settings_title_label = QtWidgets.QLabel(parent=self.horizontalLayoutWidget_12) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.printer_settings_title_label.sizePolicy().hasHeightForWidth()) - self.printer_settings_title_label.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.printer_settings_title_label.setFont(font) - self.printer_settings_title_label.setStyleSheet("background: transparent; color: white;") - self.printer_settings_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.printer_settings_title_label.setObjectName("printer_settings_title_label") - self.printer_setting_header_layout.addWidget(self.printer_settings_title_label) - self.printer_settings_back_btn = IconButton(parent=self.horizontalLayoutWidget_12) - self.printer_settings_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.printer_settings_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.printer_settings_back_btn.setFont(font) - self.printer_settings_back_btn.setMouseTracking(False) - self.printer_settings_back_btn.setTabletTracking(True) - self.printer_settings_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.printer_settings_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.printer_settings_back_btn.setStyleSheet("") - self.printer_settings_back_btn.setAutoDefault(False) - self.printer_settings_back_btn.setFlat(True) - self.printer_settings_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.printer_settings_back_btn.setObjectName("printer_settings_back_btn") - self.printer_setting_header_layout.addWidget(self.printer_settings_back_btn) - self.gridLayoutWidget_3 = QtWidgets.QWidget(parent=self.printer_settings_page) - self.gridLayoutWidget_3.setGeometry(QtCore.QRect(10, 90, 691, 301)) - self.gridLayoutWidget_3.setObjectName("gridLayoutWidget_3") - self.printer_setting_content_layout = QtWidgets.QGridLayout(self.gridLayoutWidget_3) - self.printer_setting_content_layout.setContentsMargins(0, 0, 0, 0) - self.printer_setting_content_layout.setObjectName("printer_setting_content_layout") - controlStackedWidget.addWidget(self.printer_settings_page) - self.fans_page = QtWidgets.QWidget() - self.fans_page.setObjectName("fans_page") - self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.fans_page) - self.verticalLayout_5.setObjectName("verticalLayout_5") - spacerItem9 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_5.addItem(spacerItem9) - self.fans_header_layout = QtWidgets.QHBoxLayout() - self.fans_header_layout.setObjectName("fans_header_layout") - spacerItem10 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.fans_header_layout.addItem(spacerItem10) - self.fans_title_label = QtWidgets.QLabel(parent=self.fans_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.fans_title_label.sizePolicy().hasHeightForWidth()) - self.fans_title_label.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.fans_title_label.setFont(font) - self.fans_title_label.setStyleSheet("background: transparent; color: white;") - self.fans_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.fans_title_label.setObjectName("fans_title_label") - self.fans_header_layout.addWidget(self.fans_title_label) - self.fans_back_btn = IconButton(parent=self.fans_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.fans_back_btn.sizePolicy().hasHeightForWidth()) - self.fans_back_btn.setSizePolicy(sizePolicy) - self.fans_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.fans_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.fans_back_btn.setFont(font) - self.fans_back_btn.setMouseTracking(False) - self.fans_back_btn.setTabletTracking(True) - self.fans_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.fans_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.fans_back_btn.setStyleSheet("") - self.fans_back_btn.setAutoDefault(False) - self.fans_back_btn.setFlat(True) - self.fans_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.fans_back_btn.setObjectName("fans_back_btn") - self.fans_header_layout.addWidget(self.fans_back_btn) - self.verticalLayout_5.addLayout(self.fans_header_layout) - spacerItem11 = QtWidgets.QSpacerItem(20, 111, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_5.addItem(spacerItem11) - self.fans_content_layout = QtWidgets.QHBoxLayout() - self.fans_content_layout.setObjectName("fans_content_layout") - self.verticalLayout_5.addLayout(self.fans_content_layout) - spacerItem12 = QtWidgets.QSpacerItem(20, 111, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_5.addItem(spacerItem12) - controlStackedWidget.addWidget(self.fans_page) - - self.retranslateUi(controlStackedWidget) - controlStackedWidget.setCurrentIndex(2) - QtCore.QMetaObject.connectSlotsByName(controlStackedWidget) - - def retranslateUi(self, controlStackedWidget): - _translate = QtCore.QCoreApplication.translate - controlStackedWidget.setWindowTitle(_translate("controlStackedWidget", "StackedWidget")) - self.cp_header_title.setText(_translate("controlStackedWidget", "Control")) - self.cp_header_title.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.cp_z_tilt_btn.setText(_translate("controlStackedWidget", "Z-Tilt")) - self.cp_z_tilt_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.cp_temperature_btn.setText(_translate("controlStackedWidget", "Temp.\n" -"Control")) - self.cp_temperature_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.cp_nozzles_calibration_btn.setText(_translate("controlStackedWidget", "Nozzle\n" -"Calibration")) - self.cp_nozzles_calibration_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.cp_motion_btn.setText(_translate("controlStackedWidget", "Motion\n" -"Control")) - self.cp_motion_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.cp_fans_btn.setText(_translate("controlStackedWidget", "Fans")) - self.cp_fans_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.cp_switch_print_core_btn.setText(_translate("controlStackedWidget", "Swap\n" -"Print Core")) - self.cp_switch_print_core_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.mp_header_title.setText(_translate("controlStackedWidget", "Motion")) - self.mp_header_title.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.mp_back_btn.setText(_translate("controlStackedWidget", "Back")) - self.mp_back_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.mp_back_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.motion_move_axis_btn.setText(_translate("controlStackedWidget", "Axis")) - self.motion_move_axis_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.motion_disable_steppers_btn.setText(_translate("controlStackedWidget", "Disable\n" -"Steppers")) - self.motion_disable_steppers_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.motion_extrude_btn.setText(_translate("controlStackedWidget", "Extrude")) - self.motion_extrude_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.motion_auto_home_btn.setText(_translate("controlStackedWidget", "Auto\n" -"Home")) - self.motion_auto_home_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.exp_title_label.setText(_translate("controlStackedWidget", "Extrude")) - self.exp_title_label.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.exp_back_btn.setText(_translate("controlStackedWidget", "Back")) - self.exp_back_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.exp_back_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.exp_length_group_box.setTitle(_translate("controlStackedWidget", "Extrude Length (mm)")) - self.extrude_select_length_10_btn.setText(_translate("controlStackedWidget", "10")) - self.extrude_select_length_10_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.extrude_select_length_50_btn.setText(_translate("controlStackedWidget", "50")) - self.extrude_select_length_50_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.extrude_select_length_100_btn.setText(_translate("controlStackedWidget", "100")) - self.extrude_select_length_100_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.exp_feedrate_group_box.setTitle(_translate("controlStackedWidget", "Extrude Feedrate (mm/s)")) - self.extrude_select_feedrate_low_btn.setText(_translate("controlStackedWidget", "2")) - self.extrude_select_feedrate_low_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.extrude_select_feedrate_middle_btn.setText(_translate("controlStackedWidget", "4")) - self.extrude_select_feedrate_middle_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.extrude_select_feedrate_high_btn.setText(_translate("controlStackedWidget", "8")) - self.extrude_select_feedrate_high_btn.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.exp_unextrude_btn.setText(_translate("controlStackedWidget", "Retract")) - self.exp_unextrude_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.exp_extrude_btn.setText(_translate("controlStackedWidget", "Extrude")) - self.exp_extrude_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.exp_info_label.setText(_translate("controlStackedWidget", "Nozzle heating to extrude")) - self.mva_x_label.setText(_translate("controlStackedWidget", "X:")) - self.mva_y_label.setText(_translate("controlStackedWidget", "Y:")) - self.mva_z_label.setText(_translate("controlStackedWidget", "Z:")) - self.mva_z_value_label.setText(_translate("controlStackedWidget", "0")) - self.mva_y_value_label.setText(_translate("controlStackedWidget", "0")) - self.mva_x_value_label.setText(_translate("controlStackedWidget", "0")) - self.mva_title_label.setText(_translate("controlStackedWidget", "Move Axis")) - self.mva_title_label.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.mva_back_btn.setText(_translate("controlStackedWidget", "Back")) - self.mva_back_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.mva_back_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_z_up.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_z_down.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_home_x_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_home_y_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_home_z_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_home_all_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_select_speed_25_btn.setText(_translate("controlStackedWidget", "25")) - self.mva_select_speed_50_btn.setText(_translate("controlStackedWidget", "50")) - self.mva_select_speed_100_btn.setText(_translate("controlStackedWidget", "100")) - self.label.setText(_translate("controlStackedWidget", "Move Speed mm/s")) - self.mva_select_length_1_btn.setText(_translate("controlStackedWidget", "1")) - self.mva_select_length_10_btn.setText(_translate("controlStackedWidget", "10")) - self.mva_select_length_100_btn.setText(_translate("controlStackedWidget", "100")) - self.label_2.setText(_translate("controlStackedWidget", "Move Length mm")) - self.mva_left_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_right_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_down_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_up_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.mva_middle.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.temp_header_title.setText(_translate("controlStackedWidget", "Temperature")) - self.temp_header_title.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.temp_back_button.setText(_translate("controlStackedWidget", "Back")) - self.temp_back_button.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.extruder_temp_display.setProperty("name", _translate("controlStackedWidget", "extruder_temperature_display")) - self.extruder_temp_display.setProperty("button_type", _translate("controlStackedWidget", "secondary_display")) - self.bed_temp_display.setProperty("name", _translate("controlStackedWidget", "bed_temperature_display")) - self.bed_temp_display.setProperty("button_type", _translate("controlStackedWidget", "secondary_display")) - self.cooldown_btn.setText(_translate("controlStackedWidget", "Cooldown")) - self.cooldown_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.temperature_cooldown_btn.setText(_translate("controlStackedWidget", "Heatsoak")) - self.temperature_cooldown_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.z_adjust_icon.setText(_translate("controlStackedWidget", "Z")) - self.z_adjust_offset_value.setText(_translate("controlStackedWidget", "0")) - self.z_adjust_header_title.setText(_translate("controlStackedWidget", "Z Adjustment")) - self.z_adjust_header_title.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.z_adjust_back_button.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.z_adjust_up_btn.setText(_translate("controlStackedWidget", "^")) - self.z_adjust_up_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.z_adjust_up_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.z_adjust_down_btn.setText(_translate("controlStackedWidget", "v")) - self.z_adjust_down_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.z_adjust_down_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.z_adjust_title.setText(_translate("controlStackedWidget", "select length")) - self.z_adjust_title.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.z_adjust_title.setProperty("button_type", _translate("controlStackedWidget", "normal")) - self.z_adjust_confirm_btn.setText(_translate("controlStackedWidget", "Confirm")) - self.z_adjust_confirm_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.z_adjust_cancel_btn.setText(_translate("controlStackedWidget", "Cancel")) - self.z_adjust_cancel_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.printer_settings_title_label.setText(_translate("controlStackedWidget", "PRINTER SETTINGS")) - self.printer_settings_title_label.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.printer_settings_back_btn.setText(_translate("controlStackedWidget", "Back")) - self.printer_settings_back_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.printer_settings_back_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) - self.fans_title_label.setText(_translate("controlStackedWidget", "Fans")) - self.fans_title_label.setProperty("class", _translate("controlStackedWidget", "title_text")) - self.fans_back_btn.setText(_translate("controlStackedWidget", "Back")) - self.fans_back_btn.setProperty("class", _translate("controlStackedWidget", "menu_btn")) - self.fans_back_btn.setProperty("button_type", _translate("controlStackedWidget", "icon")) -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_label import BlocksLabel -from lib.utils.display_button import DisplayButton -from lib.utils.check_button import BlocksCustomCheckButton -from lib.utils.icon_button import IconButton From c6b974c6b8b646e7e0fbb85d113637454389ed02 Mon Sep 17 00:00:00 2001 From: Robert0Mart Date: Mon, 7 Sep 2026 15:08:28 +0100 Subject: [PATCH 10/18] bugfix: small bugfixes --- BlocksScreen/lib/panels/controlTab.py | 1 - BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py | 5 ----- BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index c3ff12133..bf881866e 100644 --- a/BlocksScreen/lib/panels/controlTab.py +++ b/BlocksScreen/lib/panels/controlTab.py @@ -103,7 +103,6 @@ def __init__( self.addWidget(self.axis_page) self.axis_page.request_back.connect(self.request_back_button) self.axis_page.run_gcode_signal.connect(self.run_gcode_signal) - self.axis_page.call_load_panel.connect(self.call_load_panel) self.printer.toolhead_update[str, list].connect( self.axis_page.on_toolhead_update ) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py index 026915fdb..252716941 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py @@ -15,8 +15,6 @@ class AxisPage(QtWidgets.QWidget): ) request_back = QtCore.pyqtSignal(name="request_back") - call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") - def __init__(self, parent: QtWidgets.QWidget) -> None: super().__init__(parent) @@ -131,9 +129,6 @@ def on_toolhead_update(self, field: str, values: list) -> None: self.mva_y_value_label.setText(f"{values[1]:.2f}") self.mva_z_value_label.setText(f"{values[2]:.3f}") - if values[0] == "252,50" and values[1] == "250" and values[2] == "50": - self.call_load_panel.emit(False, "", False) - def _setup_ui(self) -> None: """Build the axis page: jog pads, step selector, and status labels.""" widget = QtWidgets.QWidget(parent=self) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py index 1a058896c..d55fc229f 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py @@ -159,7 +159,7 @@ def _setup_ui(self) -> None: widget = QtWidgets.QWidget(parent=self) widget.setMinimumSize(QtCore.QSize(710, 410)) widget.setMaximumSize(QtCore.QSize(710, 410)) - self.setObjectName("fans_page") + self.setObjectName("extruder_page") self.extrude_page = QtWidgets.QWidget() self.extrude_page.setMinimumSize(QtCore.QSize(710, 400)) self.extrude_page.setMaximumSize(QtCore.QSize(720, 420)) From f53742c868e274074f2c2463ce3d6ca972d24009 Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 28 Sep 2026 12:05:53 +0100 Subject: [PATCH 11/18] Refator: filament tab pages organisation (#302) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Stacked PR — merge order This PR is stacked on top of: 1. #298 2. #299 **Do not merge until #298 and #299 are merged first.** CI won't run here until the base becomes `dev` (after the parents merge). ## Description - [x] Refactor **BlocksScreen/lib/panels/filamentTab.py** - aligned main button to the rest of the tabs - updated import **BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py** **BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py** **BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py** **BlocksScreen/lib/panels/widgets/FilamentTab/amuWidgets.py** **BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py** **BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py** - moved pages to their own folder for better organisation **BlocksScreen/lib/ui/filamentSensorsPage.ui** **BlocksScreen/lib/ui/filamentSensorsPage_ui.py** **BlocksScreen/lib/ui/filamentStackedWidget.ui** **BlocksScreen/lib/ui/filamentStackedWidget_ui.py** - deleted unused ui files --- BlocksScreen/lib/panels/filamentTab.py | 76 +++-- .../{ => FilamentTab}/addFilamentPage.py | 0 .../widgets/{ => FilamentTab}/addSpoolPage.py | 0 .../widgets/{ => FilamentTab}/amuPage.py | 2 +- .../widgets/{ => FilamentTab}/amuWidgets.py | 0 .../{ => FilamentTab}/basicFilamentPanel.py | 5 +- .../widgets/{ => FilamentTab}/spoolmanPage.py | 4 +- .../panels/widgets/MainWindow/cancelPage.py | 277 ++++++++++++++++++ BlocksScreen/lib/panels/widgets/fansPage.py | 14 - tests/widgets/test_basic_filament_panel.py | 2 +- 10 files changed, 317 insertions(+), 63 deletions(-) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/addFilamentPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/addSpoolPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/amuPage.py (99%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/amuWidgets.py (100%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/basicFilamentPanel.py (99%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/spoolmanPage.py (99%) delete mode 100644 BlocksScreen/lib/panels/widgets/fansPage.py diff --git a/BlocksScreen/lib/panels/filamentTab.py b/BlocksScreen/lib/panels/filamentTab.py index f8d472e23..3dd67a116 100644 --- a/BlocksScreen/lib/panels/filamentTab.py +++ b/BlocksScreen/lib/panels/filamentTab.py @@ -4,16 +4,16 @@ from devices.amu import AMUManager from devices.amu.models import GateStatus -from lib.panels.widgets.addFilamentPage import AddFilamentPage -from lib.panels.widgets.addSpoolPage import AddSpoolPage -from lib.panels.widgets.amuPage import AMUpage from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.basicFilamentPanel import BasicFilamentPanel from lib.panels.widgets.colorWheelWidget import ColorWheelWidget +from lib.panels.widgets.FilamentTab.addFilamentPage import AddFilamentPage +from lib.panels.widgets.FilamentTab.addSpoolPage import AddSpoolPage +from lib.panels.widgets.FilamentTab.amuPage import AMUpage +from lib.panels.widgets.FilamentTab.basicFilamentPanel import BasicFilamentPanel +from lib.panels.widgets.FilamentTab.spoolmanPage import SpoolmanPage from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard from lib.panels.widgets.loadWidget import LoadingOverlayWidget from lib.panels.widgets.numpadPage import CustomNumpad -from lib.panels.widgets.spoolmanPage import SpoolmanPage from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame @@ -48,8 +48,8 @@ def __init__( self.amu_manager: AMUManager = amu_manager self.amu_configured = False self._popup_callback = None - self.ui = self.setupUi() - self.change_page(self.indexOf(self.ui)) + self._setup_ui() + self.change_page(self.indexOf(self.filament_control_page)) self._previous_gate_states: dict[int, bool] = {} self.pre_gate_idx = {} @@ -1033,51 +1033,37 @@ def setupUi(self): widget.setMinimumSize(QtCore.QSize(710, 410)) widget.setMaximumSize(QtCore.QSize(710, 410)) self.setObjectName("filament_page") - self.verticalLayout = QtWidgets.QVBoxLayout() + self.verticalLayout = QtWidgets.QVBoxLayout(widget) self.verticalLayout.setObjectName("verticalLayout") self.fp_header_layout = QtWidgets.QHBoxLayout() self.fp_header_layout.setObjectName("fp_header_layout") - self.fp_header_layout.addItem( - QtWidgets.QSpacerItem( - 60, - 60, - QtWidgets.QSizePolicy.Policy.Fixed, - QtWidgets.QSizePolicy.Policy.Minimum, - ) - ) - self.fp_header_title = QtWidgets.QLabel(parent=self) + self.fp_hblank_left = QtWidgets.QWidget() + self.fp_hblank_left.setMinimumSize(QtCore.QSize(60, 55)) + self.fp_hblank_left.setMaximumSize(QtCore.QSize(60, 55)) + self.fp_header_layout.addWidget(self.fp_hblank_left) + + self.fp_header_title = QtWidgets.QLabel(parent=widget) sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.Fixed, - ) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.fp_header_title.sizePolicy().hasHeightForWidth() + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, ) self.fp_header_title.setSizePolicy(sizePolicy) - self.fp_header_title.setMinimumSize(QtCore.QSize(300, 60)) + self.fp_header_title.setMinimumSize(QtCore.QSize(0, 60)) self.fp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) font = QtGui.QFont() font.setFamily("Momcake") font.setPointSize(24) - font.setBold(True) - font.setWeight(75) self.fp_header_title.setFont(font) self.fp_header_title.setStyleSheet("background: transparent; color: white;") self.fp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.fp_header_title.setObjectName("fp_header_title") self.fp_header_layout.addWidget(self.fp_header_title) - self.fp_header_layout.addItem( - QtWidgets.QSpacerItem( - 60, - 60, - QtWidgets.QSizePolicy.Policy.Fixed, - QtWidgets.QSizePolicy.Policy.Minimum, - ) - ) + self.fp_hblank_right = QtWidgets.QWidget() + self.fp_hblank_right.setMinimumSize(QtCore.QSize(60, 55)) + self.fp_hblank_right.setMaximumSize(QtCore.QSize(60, 55)) + self.fp_header_layout.addWidget(self.fp_hblank_right) self.verticalLayout.addLayout(self.fp_header_layout) self.fp_content_layout = QtWidgets.QGridLayout() @@ -1124,16 +1110,20 @@ def setupUi(self): self.fp_content_layout.addWidget(self.fp_button_2, 1, 1, 1, 1) - self.verticalLayout.addLayout(self.fp_content_layout) - widget.setLayout(self.verticalLayout) + self.fp_content_layout.setRowMinimumHeight(0, 80) + self.fp_content_layout.setRowMinimumHeight(1, 80) + self.fp_content_layout.setRowMinimumHeight(2, 80) + self.fp_content_layout.setContentsMargins(0, 0, 0, 0) - self.fp_content_layout.setRowMinimumHeight( - 0, int(87.5) - ) # 87.5 to compensate for not having margin on the rest of the buttons - self.fp_content_layout.setRowMinimumHeight( - 2, int(87.5) - ) # dont ask how i got this value , it was try and repeat + fp_content_widget = QtWidgets.QWidget(parent=widget) + fp_content_widget.setLayout(self.fp_content_layout) + fp_content_widget.setSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + fp_content_widget.setFixedHeight(80 * 3 + self.fp_content_layout.spacing() * 2) + self.verticalLayout.addWidget(fp_content_widget) + self.filament_control_page = widget self.addWidget(widget) self.fp_header_title.setText("Filament") self.fp_button_1.setText("Filament\nControl") diff --git a/BlocksScreen/lib/panels/widgets/addFilamentPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/addFilamentPage.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py diff --git a/BlocksScreen/lib/panels/widgets/addSpoolPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/addSpoolPage.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py diff --git a/BlocksScreen/lib/panels/widgets/amuPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/amuPage.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py index 3648aaf96..140f0afb4 100644 --- a/BlocksScreen/lib/panels/widgets/amuPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py @@ -1,7 +1,7 @@ import typing from devices.amu import AMUManager -from lib.panels.widgets.amuWidgets import SpoolCarousel, SpoolInfoPanel +from lib.panels.widgets.FilamentTab.amuWidgets import SpoolCarousel, SpoolInfoPanel from lib.panels.widgets.basePopup import BasePopup from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton diff --git a/BlocksScreen/lib/panels/widgets/amuWidgets.py b/BlocksScreen/lib/panels/widgets/FilamentTab/amuWidgets.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/amuWidgets.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/amuWidgets.py diff --git a/BlocksScreen/lib/panels/widgets/basicFilamentPanel.py b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/basicFilamentPanel.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py index 9dc0c8d21..0340b0739 100644 --- a/BlocksScreen/lib/panels/widgets/basicFilamentPanel.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py @@ -57,7 +57,7 @@ def __init__( self.mmu_configured = False self.load_popup = load_popup self._mmu_state = None - self._setupUi() + self._setup_ui() self.filament_state = self.FilamentStates.UNKNOWN self.setCurrentIndex(0) @@ -368,7 +368,8 @@ def _setupInfoBox(self): return root - def _setupUi(self): + def _setup_ui(self) -> None: + """Build the basic filament panel: load/unload controls and status labels.""" self.setObjectName("self") self.resize(710, 411) diff --git a/BlocksScreen/lib/panels/widgets/spoolmanPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/spoolmanPage.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py index 3166c27f1..a50d1e80c 100644 --- a/BlocksScreen/lib/panels/widgets/spoolmanPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py @@ -1,8 +1,8 @@ import logging import typing -from lib.panels.widgets.addFilamentPage import AddFilamentPage -from lib.panels.widgets.addSpoolPage import AddSpoolPage +from lib.panels.widgets.FilamentTab.addFilamentPage import AddFilamentPage +from lib.panels.widgets.FilamentTab.addSpoolPage import AddSpoolPage from lib.panels.widgets.basePopup import BasePopup from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index 8592e578d..d05ec9c53 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -273,3 +273,280 @@ def _setupUI(self) -> None: self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter ) self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) + + +import logging +import typing + +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.blocks_label import BlocksLabel +from PyQt6 import QtCore, QtGui, QtWidgets + +logger = logging.getLogger(__name__) + + +class CancelPage(QtWidgets.QWidget): + """Displayed when a print is cancelled; offers reprint or ignore.""" + + request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="request_file_info" + ) + reprint_start: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="reprint_start" + ) + run_gcode: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run_gcode" + ) + + def __init__(self, parent: QtWidgets.QWidget) -> None: + super().__init__(parent) + self._setupUI() + self.filename = "" + + self.confirm_button.clicked.connect(lambda: self._handle_accept()) + self.refuse_button.clicked.connect(lambda: self._handle_refuse()) + + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) + + def _handle_accept(self): + self.run_gcode.emit("SDCARD_RESET_FILE") + self.reprint_start.emit(self.filename) + self.close() + + def _handle_refuse(self): + self.close() + self.run_gcode.emit("SDCARD_RESET_FILE") + + _REASON_HEADERS: typing.ClassVar[dict[str, str]] = { + "complete": "Print Finished", + "error": "Print Error", + "cancelled": "Print Cancelled", + } + + @QtCore.pyqtSlot(str, dict, name="on_print_stats_update") + @QtCore.pyqtSlot(str, float, name="on_print_stats_update") + @QtCore.pyqtSlot(str, str, name="on_print_stats_update") + def on_print_stats_update(self, field: str, value: dict | float | str) -> None: + if isinstance(value, str): + if "filename" in field: + self.filename = value + if self.isVisible(): + self.set_file_name(value) + elif "state" in field: + if value in self._REASON_HEADERS: + self.cf_info_tf.setText(self._REASON_HEADERS[value]) + elif value == "printing": + # New job: drop the previous job's reason so it cannot leak. + self.cf_info_tf.clear() + + def show(self): + self.request_file_info.emit(self.filename) + + super().show() + + def set_pixmap(self, pixmap: QtGui.QPixmap) -> None: + if not hasattr(self, "_scene"): + self._scene = QtWidgets.QGraphicsScene(self) + self.cf_thumbnail.setScene(self._scene) + + # Scene rectangle (available display area) + graphics_rect = self.cf_thumbnail.rect().toRectF() + + # Scale pixmap preserving aspect ratio + pixmap = pixmap.scaled( + graphics_rect.size().toSize(), + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + QtCore.Qt.TransformationMode.SmoothTransformation, + ) + + adjusted_x = (graphics_rect.width() - pixmap.width()) / 2.0 + adjusted_y = (graphics_rect.height() - pixmap.height()) / 2.0 + + if not hasattr(self, "_pixmap_item"): + self._pixmap_item = QtWidgets.QGraphicsPixmapItem(pixmap) + self._scene.addItem(self._pixmap_item) + else: + self._pixmap_item.setPixmap(pixmap) + + self._pixmap_item.setPos(adjusted_x, adjusted_y) + self._scene.setSceneRect(graphics_rect) + + def set_file_name(self, file_name: str) -> None: + self.cf_file_name.setText(file_name) + + def _show_screen_thumbnail(self, metadata: dict | None) -> None: + """Display the largest thumbnail from file metadata. + + ``thumbnail_images`` values are pre-loaded ``QImage`` + objects produced by ``Files._process_metadata``. + """ + fallback = QtGui.QPixmap( + "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" + ) + thumbnails = metadata.get("thumbnail_images", []) if metadata else [] + if not thumbnails: + self.set_pixmap(fallback) + return + + last_thumb = thumbnails[-1] + if isinstance(last_thumb, QtGui.QImage) and not last_thumb.isNull(): + self.set_pixmap(QtGui.QPixmap.fromImage(last_thumb)) + else: + self.set_pixmap(fallback) + + def _setupUI(self) -> None: + """Setup widget ui""" + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + self.setSizePolicy(sizePolicy) + self.setObjectName("cancelPage") + self.setStyleSheet("""#cancelPage { + background-image: url(:/background/media/1st_background.png); + }""") + self.setMinimumSize(QtCore.QSize(800, 480)) + self.setMaximumSize(QtCore.QSize(800, 480)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.cf_header_title = QtWidgets.QHBoxLayout() + self.cf_header_title.setObjectName("cf_header_title") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.cf_file_name = BlocksLabel(parent=self) + self.cf_file_name.setMinimumSize(QtCore.QSize(0, 60)) + self.cf_file_name.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.cf_file_name.setFont(font) + self.cf_file_name.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.cf_file_name.setSizePolicy(sizePolicy) + self.cf_file_name.setStyleSheet("background: transparent; color: white;") + self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_file_name.setObjectName("cf_file_name") + self.cf_header_title.addWidget(self.cf_file_name) + + self.verticalLayout_4.addLayout(self.cf_header_title) + self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() + self.cf_content_vertical_layout.setObjectName("cf_content_vertical_layout") + self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() + self.cf_content_horizontal_layout.setObjectName("cf_content_horizontal_layout") + self.info_frame = BlocksCustomFrame(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + self.info_frame.setSizePolicy(sizePolicy) + + self.info_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + + self.info_layout = QtWidgets.QVBoxLayout(self.info_frame) + + self.cf_info_tf = QtWidgets.QLabel(parent=self.info_frame) + self.cf_info_tf.setText(self._REASON_HEADERS["cancelled"]) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(20) + + self.cf_info_tf.setFont(font) + self.cf_info_tf.setStyleSheet("background: transparent; color: white;") + + self.cf_info_tf.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_layout.addWidget(self.cf_info_tf) + + self.cf_info_tr = QtWidgets.QLabel(parent=self.info_frame) + font = QtGui.QFont() + font.setPointSize(15) + self.cf_info_tr.setFont(font) + self.cf_info_tr.setStyleSheet("background: transparent; color: white;") + self.cf_info_tr.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_info_tr.setText("Do you want to reprint?") + self.info_layout.addWidget(self.cf_info_tr) + + self.cf_confirm_layout = QtWidgets.QVBoxLayout() + self.cf_confirm_layout.setSpacing(15) + + self.confirm_button = BlocksCustomButton(parent=self.info_frame) + self.confirm_button.setMinimumSize(QtCore.QSize(250, 70)) + self.confirm_button.setMaximumSize(QtCore.QSize(250, 70)) + font = QtGui.QFont("Momcake", 18) + self.confirm_button.setFont(font) + self.confirm_button.setFlat(True) + self.confirm_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") + ) + self.confirm_button.setText("Reprint") + # 2. Align buttons to the right + self.cf_confirm_layout.addWidget( + self.confirm_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.refuse_button = BlocksCustomButton(parent=self.info_frame) + self.refuse_button.setMinimumSize(QtCore.QSize(250, 70)) + self.refuse_button.setMaximumSize(QtCore.QSize(250, 70)) + self.refuse_button.setFont(font) + self.refuse_button.setFlat(True) + self.refuse_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") + ) + self.refuse_button.setText("Ignore") + # 2. Align buttons to the right + self.cf_confirm_layout.addWidget( + self.refuse_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + + self.info_layout.addLayout(self.cf_confirm_layout) + + self.cf_content_horizontal_layout.addWidget(self.info_frame) + + self.cf_content_vertical_layout.addLayout(self.cf_content_horizontal_layout) + self.cf_thumbnail = QtWidgets.QGraphicsView(self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.cf_thumbnail.sizePolicy().hasHeightForWidth()) + self.cf_thumbnail.setSizePolicy(sizePolicy) + self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setStyleSheet( + "QGraphicsView{\nbackground-color: transparent;\n}" + ) + self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) + self.cf_thumbnail.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setSizeAdjustPolicy( + QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored + ) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + self.cf_thumbnail.setBackgroundBrush(brush) + self.cf_thumbnail.setRenderHints( + QtGui.QPainter.RenderHint.Antialiasing + | QtGui.QPainter.RenderHint.SmoothPixmapTransform + | QtGui.QPainter.RenderHint.TextAntialiasing + ) + self.cf_thumbnail.setViewportUpdateMode( + QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate + ) + self.cf_thumbnail.setObjectName("cf_thumbnail") + self.cf_content_vertical_layout.addWidget( + self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/fansPage.py b/BlocksScreen/lib/panels/widgets/fansPage.py deleted file mode 100644 index c31a8600b..000000000 --- a/BlocksScreen/lib/panels/widgets/fansPage.py +++ /dev/null @@ -1,14 +0,0 @@ -from PyQt6 import QtCore, QtWidgets - - -class FansPage(QtWidgets.QWidget): - def __init__( - self, - parent: QtWidgets.QWidget | None, - flags: QtCore.Qt.WindowType | None, - ) -> None: - if parent is not None and flags is not None: - super().__init__(parent, flags) - - else: - super().__init__() diff --git a/tests/widgets/test_basic_filament_panel.py b/tests/widgets/test_basic_filament_panel.py index 6a7f616fc..420b36b40 100644 --- a/tests/widgets/test_basic_filament_panel.py +++ b/tests/widgets/test_basic_filament_panel.py @@ -40,7 +40,7 @@ def __init__(self, name="", temperature=0): import pytest # noqa: E402 -from BlocksScreen.lib.panels.widgets.basicFilamentPanel import ( # noqa: E402 +from BlocksScreen.lib.panels.widgets.FilamentTab.basicFilamentPanel import ( # noqa: E402 BasicFilamentPanel, ) From cb356362762f8e302715666c0c336224aa1e0719 Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 28 Sep 2026 12:05:54 +0100 Subject: [PATCH 12/18] refactor: organized pages (#303) This PR is stacked on top of: 1. #298 2. #299 **Do not merge until #298 and #299 are merged first.** CI won't run here until the base becomes `dev` (after the parents merge). - [x] refactor **BlocksScreen/lib/panels/printTab.py** - updated paths **BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py** **BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py** **BlocksScreen/lib/panels/widgets/PrintTab/filesPage.py** **BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py** **BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py** **BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py** **BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py** - organized pages into a single folder **BlocksScreen/lib/ui/printStackedWidget.ui** **BlocksScreen/lib/ui/printStackedWidget_ui.py** - deleted unused UI files --- BlocksScreen/lib/panels/printTab.py | 12 ++++++------ .../panels/widgets/{ => PrintTab}/babystepPage.py | 0 .../lib/panels/widgets/{ => PrintTab}/confirmPage.py | 0 .../lib/panels/widgets/{ => PrintTab}/filesPage.py | 0 .../panels/widgets/{ => PrintTab}/jobStatusPage.py | 0 .../panels/widgets/{ => PrintTab}/sensorWidget.py | 0 .../panels/widgets/{ => PrintTab}/sensorsPanel.py | 2 +- .../lib/panels/widgets/{ => PrintTab}/tunePage.py | 0 tests/widgets/test_job_status_page_unit.py | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/babystepPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/confirmPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/filesPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/jobStatusPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/sensorWidget.py (100%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/sensorsPanel.py (99%) rename BlocksScreen/lib/panels/widgets/{ => PrintTab}/tunePage.py (100%) diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index d2c9ec0b3..6c64a2bcd 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -6,16 +6,16 @@ from configfile import BlocksScreenConfig, get_configparser from lib.files import Files from lib.moonrakerComm import MoonWebSocket -from lib.panels.widgets.babystepPage import BabystepPage from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.confirmPage import ConfirmWidget -from lib.panels.widgets.filesPage import FilesPage -from lib.panels.widgets.jobStatusPage import JobStatusWidget from lib.panels.widgets.metadataPage import FileMetadataWidget from lib.panels.widgets.numpadPage import CustomNumpad -from lib.panels.widgets.sensorsPanel import SensorsWindow +from lib.panels.widgets.PrintTab.babystepPage import BabystepPage +from lib.panels.widgets.PrintTab.confirmPage import ConfirmWidget +from lib.panels.widgets.PrintTab.filesPage import FilesPage +from lib.panels.widgets.PrintTab.jobStatusPage import JobStatusWidget +from lib.panels.widgets.PrintTab.sensorsPanel import SensorsWindow +from lib.panels.widgets.PrintTab.tunePage import TuneWidget from lib.panels.widgets.slider_selector_page import SliderPage -from lib.panels.widgets.tunePage import TuneWidget from lib.printer import Printer from lib.utils import gcode_loader from lib.utils.blocks_button import BlocksCustomButton diff --git a/BlocksScreen/lib/panels/widgets/babystepPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/babystepPage.py rename to BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/confirmPage.py rename to BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/filesPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/filesPage.py rename to BlocksScreen/lib/panels/widgets/PrintTab/filesPage.py diff --git a/BlocksScreen/lib/panels/widgets/jobStatusPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/jobStatusPage.py rename to BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/sensorWidget.py rename to BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/sensorsPanel.py rename to BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py index 0f79fe979..e38800766 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py @@ -1,6 +1,6 @@ import typing -from lib.panels.widgets.sensorWidget import SensorWidget +from lib.panels.widgets.PrintTab.sensorWidget import SensorWidget from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem diff --git a/BlocksScreen/lib/panels/widgets/tunePage.py b/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/tunePage.py rename to BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py diff --git a/tests/widgets/test_job_status_page_unit.py b/tests/widgets/test_job_status_page_unit.py index 9d35e66d6..9e9182276 100644 --- a/tests/widgets/test_job_status_page_unit.py +++ b/tests/widgets/test_job_status_page_unit.py @@ -57,7 +57,7 @@ def set_progress(self, *a): # real CustomProgressBar takes a 0-1 float sys.modules[_name] = _mod # force-set so network conftest stubs don't win import events # noqa: F401, E402 # ensure events is importable before jobStatusPage loads -from lib.panels.widgets.jobStatusPage import JobStatusWidget # noqa: E402 +from lib.panels.widgets.PrintTab.jobStatusPage import JobStatusWidget # noqa: E402 @pytest.fixture() From c83cc25c067185f9a8d49369fbf9496ba8957e07 Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 28 Sep 2026 12:05:54 +0100 Subject: [PATCH 13/18] refactor: reorganize panel/widget file structure and standardize UI setup (#315) This PR is stacked on top of: 1. #298 2. #299 **Do not merge until #298 and #299 are merged first.** CI won't run here until the base becomes `dev` (after the parents merge). - [x] refactor - organized the rest of the widgets into a common folder - standardized setup UI cross files - updated tests based on the changes (paths and comments) by : @gmmcosta15 - lib/panels/ : mainWindow.py, controlTab.py, filamentTab.py, printTab.py, utilitiesTab.py, networkWindow.py - lib/panels/widgets/ - bannerPopup.py - common/ : basePopup.py, popupDialogWidget.py, keyboardPage.py, numpadPage.py, slider_selector_page.py, loadWidget.py, optionCardWidget.py - ControlTab/ : axisPage.py, extruderPage.py, fansPage.py, printcorePage.py, probeHelperPage.py, temperaturePage.py - FilamentTab/ : addFilamentPage.py, addSpoolPage.py, colorWheelWidget.py, amuPage.py, amuWidgets.py, basicFilamentPanel.py, spoolmanPage.py - MainWindow/ : cancelPage.py, connectionPage.py, notificationPage.py, updatePage.py - PrintTab/ : babystepPage.py, confirmPage.py, filesPage.py, jobStatusPage.py, sensorsPanel.py, sensorWidget.py, tunePage.py - UtilitiesTab/ : inputshaperPage.py, troubleshootPage.py --- BlocksScreen/devices/storage/usb_controller.py | 2 +- BlocksScreen/lib/panels/controlTab.py | 6 +++--- BlocksScreen/lib/panels/filamentTab.py | 10 +++++----- BlocksScreen/lib/panels/mainWindow.py | 4 ++-- BlocksScreen/lib/panels/networkWindow.py | 10 +++++----- BlocksScreen/lib/panels/printTab.py | 6 +++--- BlocksScreen/lib/panels/utilitiesTab.py | 8 ++++---- .../lib/panels/widgets/{ => Common}/bannerPopup.py | 4 ++-- .../lib/panels/widgets/{ => Common}/basePopup.py | 0 .../panels/widgets/{ => Common}/keyboardPage.py | 0 .../lib/panels/widgets/{ => Common}/loadWidget.py | 4 ++-- .../lib/panels/widgets/{ => Common}/numpadPage.py | 4 ++-- .../widgets/{ => Common}/optionCardWidget.py | 4 ++-- .../widgets/{ => Common}/popupDialogWidget.py | 4 ++-- .../widgets/{ => Common}/slider_selector_page.py | 4 ++-- .../lib/panels/widgets/ControlTab/fansPage.py | 2 +- .../lib/panels/widgets/ControlTab/printcorePage.py | 4 ++-- .../panels/widgets/ControlTab/probeHelperPage.py | 2 +- .../panels/widgets/FilamentTab/addFilamentPage.py | 8 ++++---- .../lib/panels/widgets/FilamentTab/addSpoolPage.py | 8 ++++---- .../widgets/FilamentTab/basicFilamentPanel.py | 4 ++-- .../widgets/{ => FilamentTab}/colorWheelWidget.py | 0 .../lib/panels/widgets/FilamentTab/spoolmanPage.py | 6 +++--- .../lib/panels/widgets/MainWindow/cancelPage.py | 4 ++-- .../panels/widgets/MainWindow/connectionPage.py | 4 ++-- .../panels/widgets/MainWindow/notificationPage.py | 6 +++--- .../lib/panels/widgets/MainWindow/updatePage.py | 14 +++++++------- .../lib/panels/widgets/PrintTab/babystepPage.py | 4 ++-- .../lib/panels/widgets/PrintTab/confirmPage.py | 4 ++-- .../lib/panels/widgets/PrintTab/jobStatusPage.py | 6 +++--- .../lib/panels/widgets/PrintTab/sensorWidget.py | 4 ++-- .../lib/panels/widgets/PrintTab/sensorsPanel.py | 4 ++-- .../lib/panels/widgets/PrintTab/tunePage.py | 4 ++-- .../widgets/{ => UtilitiesTab}/inputshaperPage.py | 5 ++--- .../widgets/{ => UtilitiesTab}/troubleshootPage.py | 4 ++-- BlocksScreen/lib/utils/blocks_togglebutton.py | 4 ++-- tests/network/conftest.py | 8 ++++---- tests/network/test_network_ui.py | 6 +++--- tests/panels/conftest.py | 8 ++++---- tests/util/test_keyboard_page_unit.py | 6 +++--- tests/widgets/conftest.py | 2 +- tests/widgets/test_job_status_page_unit.py | 4 ++-- tests/widgets/test_slider_page_request_unit.py | 5 +++-- tests/widgets/test_update_page_unit.py | 2 +- 44 files changed, 106 insertions(+), 106 deletions(-) rename BlocksScreen/lib/panels/widgets/{ => Common}/bannerPopup.py (99%) rename BlocksScreen/lib/panels/widgets/{ => Common}/basePopup.py (100%) rename BlocksScreen/lib/panels/widgets/{ => Common}/keyboardPage.py (100%) rename BlocksScreen/lib/panels/widgets/{ => Common}/loadWidget.py (99%) rename BlocksScreen/lib/panels/widgets/{ => Common}/numpadPage.py (99%) rename BlocksScreen/lib/panels/widgets/{ => Common}/optionCardWidget.py (99%) rename BlocksScreen/lib/panels/widgets/{ => Common}/popupDialogWidget.py (99%) rename BlocksScreen/lib/panels/widgets/{ => Common}/slider_selector_page.py (99%) rename BlocksScreen/lib/panels/widgets/{ => FilamentTab}/colorWheelWidget.py (100%) rename BlocksScreen/lib/panels/widgets/{ => UtilitiesTab}/inputshaperPage.py (99%) rename BlocksScreen/lib/panels/widgets/{ => UtilitiesTab}/troubleshootPage.py (99%) diff --git a/BlocksScreen/devices/storage/usb_controller.py b/BlocksScreen/devices/storage/usb_controller.py index a39ac100f..ac27b3957 100644 --- a/BlocksScreen/devices/storage/usb_controller.py +++ b/BlocksScreen/devices/storage/usb_controller.py @@ -4,7 +4,7 @@ from PyQt6 import QtCore from .udisks2 import UDisksDBusAsync -from lib.panels.widgets.bannerPopup import BannerPopup +from lib.panels.widgets.Common.bannerPopup import BannerPopup ResType: typing.TypeAlias = typing.Literal["always", "none"] diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index bf881866e..398fe8449 100644 --- a/BlocksScreen/lib/panels/controlTab.py +++ b/BlocksScreen/lib/panels/controlTab.py @@ -6,15 +6,15 @@ import typing from lib.moonrakerComm import MoonWebSocket -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.panels.widgets.ControlTab.axisPage import AxisPage from lib.panels.widgets.ControlTab.extruderPage import ExtruderPage from lib.panels.widgets.ControlTab.fansPage import FansPage from lib.panels.widgets.ControlTab.printcorePage import SwapPrintcorePage from lib.panels.widgets.ControlTab.probeHelperPage import ProbeHelper from lib.panels.widgets.ControlTab.temperaturePage import TemperaturePage -from lib.panels.widgets.numpadPage import CustomNumpad -from lib.panels.widgets.slider_selector_page import SliderPage +from lib.panels.widgets.Common.numpadPage import CustomNumpad +from lib.panels.widgets.Common.slider_selector_page import SliderPage from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.icon_button import IconButton diff --git a/BlocksScreen/lib/panels/filamentTab.py b/BlocksScreen/lib/panels/filamentTab.py index 3dd67a116..b33ba7ee9 100644 --- a/BlocksScreen/lib/panels/filamentTab.py +++ b/BlocksScreen/lib/panels/filamentTab.py @@ -4,16 +4,16 @@ from devices.amu import AMUManager from devices.amu.models import GateStatus -from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.colorWheelWidget import ColorWheelWidget +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.FilamentTab.colorWheelWidget import ColorWheelWidget from lib.panels.widgets.FilamentTab.addFilamentPage import AddFilamentPage from lib.panels.widgets.FilamentTab.addSpoolPage import AddSpoolPage from lib.panels.widgets.FilamentTab.amuPage import AMUpage from lib.panels.widgets.FilamentTab.basicFilamentPanel import BasicFilamentPanel from lib.panels.widgets.FilamentTab.spoolmanPage import SpoolmanPage -from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard -from lib.panels.widgets.loadWidget import LoadingOverlayWidget -from lib.panels.widgets.numpadPage import CustomNumpad +from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget +from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index 8b7f007d3..a3d42a85e 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -22,10 +22,10 @@ from lib.panels.networkWindow import NetworkControlWindow, PixmapCache from lib.panels.printTab import PrintTab from lib.panels.utilitiesTab import UtilitiesTab -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.panels.widgets.MainWindow.cancelPage import CancelPage from lib.panels.widgets.MainWindow.connectionPage import ConnectionPage -from lib.panels.widgets.loadWidget import LoadingOverlayWidget +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget from lib.panels.widgets.MainWindow.notificationPage import NotificationPage from lib.panels.widgets.MainWindow.updatePage import UpdatePage from lib.printer import Printer diff --git a/BlocksScreen/lib/panels/networkWindow.py b/BlocksScreen/lib/panels/networkWindow.py index 2763564d5..b127039bc 100644 --- a/BlocksScreen/lib/panels/networkWindow.py +++ b/BlocksScreen/lib/panels/networkWindow.py @@ -23,9 +23,9 @@ is_hidden_ssid, signal_to_bars, ) -from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard -from lib.panels.widgets.loadWidget import LoadingOverlayWidget -from lib.panels.widgets.popupDialogWidget import Popup +from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget +from lib.panels.widgets.Common.popupDialogWidget import Popup from lib.qrcode_gen import generate_wifi_qrcode from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame @@ -187,7 +187,7 @@ def __init__(self, parent: QtWidgets.QWidget | None = None) -> None: super().__init__(parent) if parent else super().__init__() self._init_instance_variables() - self._setupUI() + self._setup_ui() self._init_timers() self._init_model_view() self._init_network_manager() @@ -1651,7 +1651,7 @@ def showEvent(self, event: QtGui.QShowEvent | None) -> None: self._nm.refresh_state() super().showEvent(event) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Build and lay out the entire stacked-widget UI tree.""" self.setObjectName("wifi_stacked_page") self.resize(800, 480) diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index 6c64a2bcd..b7aa701f4 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -6,16 +6,16 @@ from configfile import BlocksScreenConfig, get_configparser from lib.files import Files from lib.moonrakerComm import MoonWebSocket -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.panels.widgets.metadataPage import FileMetadataWidget -from lib.panels.widgets.numpadPage import CustomNumpad +from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.panels.widgets.PrintTab.babystepPage import BabystepPage from lib.panels.widgets.PrintTab.confirmPage import ConfirmWidget from lib.panels.widgets.PrintTab.filesPage import FilesPage from lib.panels.widgets.PrintTab.jobStatusPage import JobStatusWidget from lib.panels.widgets.PrintTab.sensorsPanel import SensorsWindow from lib.panels.widgets.PrintTab.tunePage import TuneWidget -from lib.panels.widgets.slider_selector_page import SliderPage +from lib.panels.widgets.Common.slider_selector_page import SliderPage from lib.printer import Printer from lib.utils import gcode_loader from lib.utils.blocks_button import BlocksCustomButton diff --git a/BlocksScreen/lib/panels/utilitiesTab.py b/BlocksScreen/lib/panels/utilitiesTab.py index 37bfcbe85..2d7382be1 100644 --- a/BlocksScreen/lib/panels/utilitiesTab.py +++ b/BlocksScreen/lib/panels/utilitiesTab.py @@ -6,10 +6,10 @@ from functools import partial from lib.moonrakerComm import MoonWebSocket -from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.inputshaperPage import InputShaperPage -from lib.panels.widgets.optionCardWidget import OptionCard -from lib.panels.widgets.troubleshootPage import TroubleshootPage +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.UtilitiesTab.inputshaperPage import InputShaperPage +from lib.panels.widgets.Common.optionCardWidget import OptionCard +from lib.panels.widgets.UtilitiesTab.troubleshootPage import TroubleshootPage from lib.printer import Printer from lib.ui.utilitiesStackedWidget_ui import Ui_utilitiesStackedWidget from lib.utils.blocks_button import BlocksCustomButton diff --git a/BlocksScreen/lib/panels/widgets/bannerPopup.py b/BlocksScreen/lib/panels/widgets/Common/bannerPopup.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/bannerPopup.py rename to BlocksScreen/lib/panels/widgets/Common/bannerPopup.py index 990775390..90aed3e50 100644 --- a/BlocksScreen/lib/panels/widgets/bannerPopup.py +++ b/BlocksScreen/lib/panels/widgets/Common/bannerPopup.py @@ -31,7 +31,7 @@ def __init__(self, parent=None) -> None: | QtCore.Qt.WindowType.Tool | QtCore.Qt.WindowType.X11BypassWindowManagerHint ) - self._setupUI() + self._setup_ui() self.slide_in_animation = QtCore.QPropertyAnimation(self, b"geometry") self.slide_in_animation.setDuration(1000) self.slide_in_animation.setEasingCurve(QtCore.QEasingCurve.Type.OutCubic) @@ -193,7 +193,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: painter.setPen(QtCore.Qt.PenStyle.NoPen) painter.drawRoundedRect(self.rect(), 50, 70) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.horizontal_layout = QtWidgets.QHBoxLayout(self) self.horizontal_layout.setContentsMargins(5, 5, 5, 5) diff --git a/BlocksScreen/lib/panels/widgets/basePopup.py b/BlocksScreen/lib/panels/widgets/Common/basePopup.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/basePopup.py rename to BlocksScreen/lib/panels/widgets/Common/basePopup.py diff --git a/BlocksScreen/lib/panels/widgets/keyboardPage.py b/BlocksScreen/lib/panels/widgets/Common/keyboardPage.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/keyboardPage.py rename to BlocksScreen/lib/panels/widgets/Common/keyboardPage.py diff --git a/BlocksScreen/lib/panels/widgets/loadWidget.py b/BlocksScreen/lib/panels/widgets/Common/loadWidget.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/loadWidget.py rename to BlocksScreen/lib/panels/widgets/Common/loadWidget.py index 5a54dd89d..173dba0c0 100644 --- a/BlocksScreen/lib/panels/widgets/loadWidget.py +++ b/BlocksScreen/lib/panels/widgets/Common/loadWidget.py @@ -29,7 +29,7 @@ def __init__( self.max_length = 150.0 self.length_step = 2.5 - self._setupUI() + self._setup_ui() config: BlocksScreenConfig = get_configparser() animation_path = None @@ -175,7 +175,7 @@ def show(self) -> None: self.repaint() return super().show() - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True) self.gifshow = QtWidgets.QLabel("", self) self.gifshow.setObjectName("gifshow") diff --git a/BlocksScreen/lib/panels/widgets/numpadPage.py b/BlocksScreen/lib/panels/widgets/Common/numpadPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/numpadPage.py rename to BlocksScreen/lib/panels/widgets/Common/numpadPage.py index 1cc9299a3..dcd36f81c 100644 --- a/BlocksScreen/lib/panels/widgets/numpadPage.py +++ b/BlocksScreen/lib/panels/widgets/Common/numpadPage.py @@ -16,7 +16,7 @@ def __init__( parent, ) -> None: super().__init__(parent) - self._setupUI() + self._setup_ui() self.current_value: str = "0" self.name: str = "" self.min_value: int = 0 @@ -118,7 +118,7 @@ def update_min_max_label(self) -> None: self.enforce_range = True self.min_max_label.setText(f"Range: {self.min_value} - {self.max_value}") - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) diff --git a/BlocksScreen/lib/panels/widgets/optionCardWidget.py b/BlocksScreen/lib/panels/widgets/Common/optionCardWidget.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/optionCardWidget.py rename to BlocksScreen/lib/panels/widgets/Common/optionCardWidget.py index e331049d2..11f0dcf66 100644 --- a/BlocksScreen/lib/panels/widgets/optionCardWidget.py +++ b/BlocksScreen/lib/panels/widgets/Common/optionCardWidget.py @@ -25,7 +25,7 @@ def __init__( self.name = name self.card_text = text self.doubleT: bool = False - self._setupUi(self) + self._setup_ui(self) self.option_icon.setAttribute( QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents ) @@ -200,7 +200,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: painter.end() - def _setupUi(self, option_card): + def _setup_ui(self, option_card): option_card.setObjectName("option_card") option_card.resize(200, 300) sizePolicy = QtWidgets.QSizePolicy( diff --git a/BlocksScreen/lib/panels/widgets/popupDialogWidget.py b/BlocksScreen/lib/panels/widgets/Common/popupDialogWidget.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/popupDialogWidget.py rename to BlocksScreen/lib/panels/widgets/Common/popupDialogWidget.py index 371372a45..b07cae204 100644 --- a/BlocksScreen/lib/panels/widgets/popupDialogWidget.py +++ b/BlocksScreen/lib/panels/widgets/Common/popupDialogWidget.py @@ -40,7 +40,7 @@ def __init__(self, parent) -> None: | QtCore.Qt.WindowType.FramelessWindowHint | QtCore.Qt.WindowType.X11BypassWindowManagerHint ) - self._setupUI() + self._setup_ui() self.slide_in_animation = QtCore.QPropertyAnimation(self, b"geometry") self.slide_in_animation.setDuration(1000) self.slide_in_animation.setEasingCurve(QtCore.QEasingCurve.Type.OutCubic) @@ -231,7 +231,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: painter.setPen(QtCore.Qt.PenStyle.NoPen) painter.drawRoundedRect(self.rect(), 10, 10) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.horizontal_layout = QtWidgets.QHBoxLayout(self) self.horizontal_layout.setContentsMargins(5, 5, 5, 5) diff --git a/BlocksScreen/lib/panels/widgets/slider_selector_page.py b/BlocksScreen/lib/panels/widgets/Common/slider_selector_page.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/slider_selector_page.py rename to BlocksScreen/lib/panels/widgets/Common/slider_selector_page.py index 2f6c89f72..8d4ca926c 100644 --- a/BlocksScreen/lib/panels/widgets/slider_selector_page.py +++ b/BlocksScreen/lib/panels/widgets/Common/slider_selector_page.py @@ -32,7 +32,7 @@ def __init__(self, parent) -> None: "#SliderPage{background-image: url(:/background/media/1st_background.png);}\n" ) self.setObjectName("SliderPage") - self._setupUI() + self._setup_ui() self.back_button.clicked.connect(self.request_back.emit) self.back_button.clicked.connect(self.value_selected.disconnect) self.slider.sliderReleased.connect(self.on_slider_value_change) @@ -83,7 +83,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: self.object_name_label.setText(str(self.name)) painter.end() - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup the components for the widget""" self.setMinimumSize(QtCore.QSize(700, 410)) self.setMaximumSize(QtCore.QSize(720, 420)) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py index 0e008c502..96d331030 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py @@ -3,7 +3,7 @@ import re import typing -from lib.panels.widgets.optionCardWidget import OptionCard +from lib.panels.widgets.Common.optionCardWidget import OptionCard from lib.utils.gcode import fan_speed_gcode from lib.utils.icon_button import IconButton from PyQt6 import QtCore, QtGui, QtWidgets diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py b/BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py index b5942e549..cb1754019 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/printcorePage.py @@ -14,7 +14,7 @@ def __init__( self.setWindowFlags( QtCore.Qt.WindowType.Popup | QtCore.Qt.WindowType.FramelessWindowHint ) - self._setupUI() + self._setup_ui() self.repaint() def setText(self, text: str) -> None: @@ -83,7 +83,7 @@ def show(self) -> None: self.repaint() return super().show() - def _setupUI(self) -> None: + def _setup_ui(self) -> None: font = QtGui.QFont() font.setPointSize(20) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py index 55aaa9ce4..76c8d28d2 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/probeHelperPage.py @@ -2,7 +2,7 @@ import logging import typing -from lib.panels.widgets.optionCardWidget import OptionCard +from lib.panels.widgets.Common.optionCardWidget import OptionCard from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_label import BlocksLabel from lib.utils.check_button import BlocksCustomCheckButton diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py index 4ac867a99..7f530c8c6 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/addFilamentPage.py @@ -1,9 +1,9 @@ import typing -from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.colorWheelWidget import ColorWheelWidget -from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard -from lib.panels.widgets.numpadPage import CustomNumpad +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.FilamentTab.colorWheelWidget import ColorWheelWidget +from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard +from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.blocks_linedit import BlocksCustomLinEdit diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py index ecadd5c3f..7a9e3296b 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/addSpoolPage.py @@ -1,9 +1,9 @@ import typing -from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.keyboardPage import CustomQwertyKeyboard -from lib.panels.widgets.loadWidget import LoadingOverlayWidget -from lib.panels.widgets.numpadPage import CustomNumpad +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget +from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.blocks_linedit import BlocksCustomLinEdit diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py index 0340b0739..c167fc2df 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py @@ -4,8 +4,8 @@ from devices.amu.models import FilamentPos, GateStatus from lib.filament import Filament -from lib.panels.widgets.basePopup import BasePopup -from lib.panels.widgets.popupDialogWidget import Popup +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.Common.popupDialogWidget import Popup from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame diff --git a/BlocksScreen/lib/panels/widgets/colorWheelWidget.py b/BlocksScreen/lib/panels/widgets/FilamentTab/colorWheelWidget.py similarity index 100% rename from BlocksScreen/lib/panels/widgets/colorWheelWidget.py rename to BlocksScreen/lib/panels/widgets/FilamentTab/colorWheelWidget.py diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py index a50d1e80c..0233f8f6c 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/spoolmanPage.py @@ -3,7 +3,7 @@ from lib.panels.widgets.FilamentTab.addFilamentPage import AddFilamentPage from lib.panels.widgets.FilamentTab.addSpoolPage import AddSpoolPage -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem @@ -45,7 +45,7 @@ def __init__(self, parent=None) -> None: self._selected_spool: dict | None = None self._display_name_to_spool: dict[str, dict] = {} - self._setupUI() + self._setup_ui() self._setup_add_popup() self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) @@ -325,7 +325,7 @@ def showEvent(self, event: QtGui.QShowEvent | None) -> None: # noqa: N802 self._on_reload_clicked() return super().showEvent(event) - def _setupUI(self) -> None: # noqa: N802 + def _setup_ui(self) -> None: # noqa: N802 self.setMaximumHeight(470) size_policy = QtWidgets.QSizePolicy( diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index d05ec9c53..e4c290a13 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -24,7 +24,7 @@ class CancelPage(QtWidgets.QWidget): def __init__(self, parent: QtWidgets.QWidget) -> None: super().__init__(parent) - self._setupUI() + self._setup_ui() self.filename = "" self.confirm_button.clicked.connect(lambda: self._handle_accept()) @@ -118,7 +118,7 @@ def _show_screen_thumbnail(self, metadata: dict | None) -> None: else: self.set_pixmap(fallback) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup widget ui""" sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py index 2f41e8950..bc8aa8d21 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/connectionPage.py @@ -122,7 +122,7 @@ class ConnectionPage(QtWidgets.QFrame): def __init__(self, parent: QtWidgets.QWidget, ws: MoonWebSocket, /) -> None: super().__init__(parent) self.ws = ws - self._setupUI() + self._setup_ui() self._state: ConnectionState = ConnectionState.DISCONNECTED self.base_text: str = "" @@ -377,7 +377,7 @@ def eventFilter(self, a0: QtCore.QObject | None, a1: QtCore.QEvent | None) -> bo self._set_state(ConnectionState.KLIPPER_READY) return super().eventFilter(a0, a1) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.setMinimumSize(QtCore.QSize(800, 480)) self.setMaximumSize(QtCore.QSize(800, 480)) self.setObjectName("ConnectionPage") diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py index d21de8b91..bb0d81ae9 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/notificationPage.py @@ -1,7 +1,7 @@ from collections import deque from typing import ClassVar -from lib.panels.widgets.popupDialogWidget import Popup +from lib.panels.widgets.Common.popupDialogWidget import Popup from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton @@ -24,7 +24,7 @@ def __init__(self, parent=None) -> None: self._ICON_INFO = QtGui.QPixmap(":/ui/media/btn_icons/info.svg") self._ICON_WARN = QtGui.QPixmap(":/ui/media/btn_icons/troubleshoot.svg") self._ICON_ERROR = QtGui.QPixmap(":/ui/media/btn_icons/error.svg") - self._setupUI() + self._setup_ui() self.cli_tracking: deque = deque() self.selected_item: ListItem | None = None self.popup = Popup(self) @@ -167,7 +167,7 @@ def _add_notif_entry( item._cache[-1] = time self.model.add_item(item) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup UI for updatePage""" sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py b/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py index d08404fba..825bd013e 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/updatePage.py @@ -7,11 +7,11 @@ from PyQt6 import QtCore, QtGui, QtWidgets -from BlocksScreen.lib.panels.widgets.basePopup import BasePopup -from BlocksScreen.lib.panels.widgets.loadWidget import LoadingOverlayWidget -from BlocksScreen.lib.utils.blocks_button import BlocksCustomButton -from BlocksScreen.lib.utils.blocks_Scrollbar import CustomScrollBar -from BlocksScreen.lib.utils.icon_button import IconButton +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_Scrollbar import CustomScrollBar +from lib.utils.icon_button import IconButton from updater.models import ComponentStatus _log = logging.getLogger(__name__) @@ -54,7 +54,7 @@ def __init__(self) -> None: super().__init__() self._chevron_right: QtGui.QPixmap = QtGui.QPixmap() self._chevron_down: QtGui.QPixmap = QtGui.QPixmap() - self._setupUI() + self._setup_ui() self._statuses: dict[str, ComponentStatus] = {} self._font_cache: dict[int, QtGui.QFont] = {} self._chevron_btn: IconButton | None = None @@ -491,7 +491,7 @@ def show_loading(self, loading: bool = False) -> None: self.setUpdatesEnabled(True) self.disable_popups.emit(loading) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: bold_id = QtGui.QFontDatabase.addApplicationFont( ":/font/media/fonts for text/Momcake-Bold.ttf" ) diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py index 1b632c178..f06a8411d 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/babystepPage.py @@ -40,7 +40,7 @@ def __init__(self, parent) -> None: self._z_offset_text: float = 0.0 self._pending_z_offset: float = 0.0 - self._setupUI() + self._setup_ui() self.bbp_mvup.clicked.connect(self.on_move_nozzle_close) self.bbp_mvdown.clicked.connect(self.on_move_nozzle_away) self.bbp_mvup.setEnabled(False) @@ -129,7 +129,7 @@ def _create_offset_button( btn.setObjectName(obj_name) return btn - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup babystep page UI.""" btn_group = QtWidgets.QButtonGroup(self) btn_group.setExclusive(True) diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py index 5d7f40ebc..aa9ae8290 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/confirmPage.py @@ -28,7 +28,7 @@ class ConfirmWidget(QtWidgets.QWidget): def __init__(self, parent) -> None: super().__init__(parent) - self._setupUI() + self._setup_ui() self.setMouseTracking(True) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) self.thumbnail: QtGui.QImage = self._blocksthumbnail @@ -171,7 +171,7 @@ def showEvent(self, a0: QtGui.QShowEvent) -> None: self.cf_thumbnail.hide() return super().showEvent(a0) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup widget ui""" sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py b/BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py index 91891b265..8f9758a59 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/jobStatusPage.py @@ -8,7 +8,7 @@ calculate_max_layers, estimate_print_time, ) -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_label import BlocksLabel from lib.utils.blocks_progressbar import CustomProgressBar @@ -96,7 +96,7 @@ def __init__(self, parent) -> None: self._layer_frozen = False self._awaiting_resume = False self._resume_baseline = 0.0 - self._setupUI() + self._setup_ui() self.cancel_print_dialog = BasePopup(self, floating=True) self.tune_menu_btn.clicked.connect(self.tune_clicked.emit) self.js_file_name_icon.clicked.connect(self._on_file_info_clicked) @@ -508,7 +508,7 @@ def _compute_progress(self) -> float: return (self._file_position - start) / (end - start) return self._raw_progress - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup widget ui""" sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.Expanding, diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py b/BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py index 14aa0a43e..74f41e07b 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/sensorWidget.py @@ -65,7 +65,7 @@ def __init__(self, parent, sensor_name: str): self.icon_pixmap_fnp: QtGui.QPixmap = QtGui.QPixmap( ":/filament_related/media/btn_icons/filament_sensor_off.svg" ) - self._setupUI() + self._setup_ui() self.toggle_button.stateChange.connect(self.toggle_sensor_state) @property @@ -189,7 +189,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ) style_painter.end() - def _setupUI(self): + def _setup_ui(self): _policy = QtWidgets.QSizePolicy.Policy.MinimumExpanding size_policy = QtWidgets.QSizePolicy(_policy, _policy) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py index e38800766..b77ee6b3e 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/sensorsPanel.py @@ -22,7 +22,7 @@ def __init__(self, parent): self.sensor_tracking_widget = {} self.current_widget = None self.sensor_list: list[SensorWidget] = [] - self._setupUi() + self._setup_ui() self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) self.setTabletTracking(True) @@ -128,7 +128,7 @@ def create_sensor_widget(self, name: str) -> SensorWidget: return _item_widget - def _setupUi(self) -> None: + def _setup_ui(self) -> None: """Setup UI for updatePage""" font_id = QtGui.QFontDatabase.addApplicationFont( ":/font/media/fonts for text/Momcake-Bold.ttf" diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py b/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py index 039973151..28d08bea5 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py @@ -45,7 +45,7 @@ def __init__(self, parent) -> None: super().__init__(parent) self.tune_display_buttons: dict = {} self.setObjectName("tune_page") - self._setupUI() + self._setup_ui() self.sensors_menu_btn.clicked.connect(self.request_sensorsPage.emit) self.tune_babystep_menu_btn.clicked.connect(self.request_bbpPage.emit) self.tune_back_btn.clicked.connect(self.request_back) @@ -242,7 +242,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: if self.isVisible(): self.speed_display.setText(str(f"{int(self.speed_factor_override * 100)}%")) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, diff --git a/BlocksScreen/lib/panels/widgets/inputshaperPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/inputshaperPage.py rename to BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py index bf9209bb8..462538901 100644 --- a/BlocksScreen/lib/panels/widgets/inputshaperPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py @@ -23,8 +23,7 @@ def __init__(self, parent=None) -> None: super().__init__(parent) else: super().__init__() - self._setupUI() - self.currentItem: ListItem | None = None + self._setup_ui() self.selected_item: ListItem | None = None self.ongoing_update: bool = False self.type_dict: dict = {} @@ -139,7 +138,7 @@ def add_type_entry(self, cli_name: str, recommended: str = "") -> None: ) self.model.add_item(item) - def _setupUI(self) -> None: + def _setup_ui(self) -> None: """Setup UI for updatePage""" font_id = QtGui.QFontDatabase.addApplicationFont( ":/font/media/fonts for text/Momcake-Bold.ttf" diff --git a/BlocksScreen/lib/panels/widgets/troubleshootPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py similarity index 99% rename from BlocksScreen/lib/panels/widgets/troubleshootPage.py rename to BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py index 8673f0457..11e3c6135 100644 --- a/BlocksScreen/lib/panels/widgets/troubleshootPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py @@ -17,7 +17,7 @@ def __init__( self.setWindowFlags( QtCore.Qt.WindowType.Popup | QtCore.Qt.WindowType.FramelessWindowHint ) - self._setupUI() + self._setup_ui() self.label_4.setText( "For more information check our website \n www.blockstec.com \n or \nsupport@blockstec.com" ) @@ -44,7 +44,7 @@ def show(self) -> None: self.repaint() return super().show() - def _setupUI(self) -> None: + def _setup_ui(self) -> None: self.setObjectName("troubleshoot_page") self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") diff --git a/BlocksScreen/lib/utils/blocks_togglebutton.py b/BlocksScreen/lib/utils/blocks_togglebutton.py index e95194d9d..cf3f66724 100644 --- a/BlocksScreen/lib/utils/blocks_togglebutton.py +++ b/BlocksScreen/lib/utils/blocks_togglebutton.py @@ -17,7 +17,7 @@ def __init__(self, parent): ":/filament_related/media/btn_icons/filament_sensor_turn_on.svg" ) - self._setupUI() + self._setup_ui() self.tb = self.toggle_button def text(self) -> str: @@ -84,7 +84,7 @@ def setDisabled(self, a0: bool) -> None: self.toggle_button.repaint() return super().setDisabled(a0) - def _setupUI(self): + def _setup_ui(self): _policy = QtWidgets.QSizePolicy.Policy.MinimumExpanding size_policy = QtWidgets.QSizePolicy(_policy, _policy) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) diff --git a/tests/network/conftest.py b/tests/network/conftest.py index f8d2d371e..cee3ce758 100644 --- a/tests/network/conftest.py +++ b/tests/network/conftest.py @@ -202,7 +202,7 @@ def setFlat(self, v: bool) -> None: class _BlocksCustomCheckButtonStub(QtWidgets.QCheckBox): - """BlocksCustomCheckButton stand-in: adds setFlat() used in _setupUI.""" + """BlocksCustomCheckButton stand-in — adds setFlat() used in _setup_ui.""" def setFlat(self, v: bool) -> None: pass @@ -272,13 +272,13 @@ def setNumericOnly(self, enabled): "EntryListModel": _EntryListModelStub, "ListItem": _ListItemStub, }, - "lib.panels.widgets.keyboardPage": { + "lib.panels.widgets.Common.keyboardPage": { "CustomQwertyKeyboard": _KeyboardStub, }, - "lib.panels.widgets.loadWidget": { + "lib.panels.widgets.Common.loadWidget": { "LoadingOverlayWidget": _LoadingOverlayStub, }, - "lib.panels.widgets.popupDialogWidget": { + "lib.panels.widgets.Common.popupDialogWidget": { "Popup": _PopupStub, }, } diff --git a/tests/network/test_network_ui.py b/tests/network/test_network_ui.py index 15b3d8864..fc02a4cee 100644 --- a/tests/network/test_network_ui.py +++ b/tests/network/test_network_ui.py @@ -1020,13 +1020,13 @@ def test_clears_loading(self, win): # ───────────────────────────────────────────────────────────────────────────── -# _setupUI smoke test: covers ~1 200 statements in _setupUI + page helpers +# _setup_ui smoke test — covers ~1 200 statements in _setup_ui + page helpers # ───────────────────────────────────────────────────────────────────────────── @pytest.mark.unit class TestSetupUIRunsWithoutError: - """Calling _setupUI() must not raise: covers the entire UI construction path.""" + """Calling _setup_ui() must not raise — covers the entire UI construction path.""" def test_setup_ui_completes(self, qapp): from unittest.mock import patch @@ -1041,7 +1041,7 @@ def _stub_init(self, *_a, **_kw): with patch.object(NetworkControlWindow, "__init__", _stub_init): w = NetworkControlWindow() - w._setupUI() + w._setup_ui() assert w.main_network_page is not None assert w.network_list_page is not None assert w.add_network_page is not None diff --git a/tests/panels/conftest.py b/tests/panels/conftest.py index 69e6bbf8e..75fc409eb 100644 --- a/tests/panels/conftest.py +++ b/tests/panels/conftest.py @@ -41,10 +41,10 @@ "lib.panels.printTab", "lib.panels.utilitiesTab", "lib.panels.widgets", - "lib.panels.widgets.basePopup", + "lib.panels.widgets.Common.basePopup", "lib.panels.widgets.MainWindow.cancelPage", "lib.panels.widgets.MainWindow.connectionPage", - "lib.panels.widgets.loadWidget", + "lib.panels.widgets.Common.loadWidget", "lib.panels.widgets.MainWindow.notificationPage", "lib.panels.widgets.MainWindow.updatePage", "lib.printer", @@ -94,10 +94,10 @@ sys.modules["lib.panels.networkWindow"].PixmapCache = MagicMock sys.modules["lib.panels.printTab"].PrintTab = MagicMock sys.modules["lib.panels.utilitiesTab"].UtilitiesTab = MagicMock -sys.modules["lib.panels.widgets.basePopup"].BasePopup = MagicMock +sys.modules["lib.panels.widgets.Common.basePopup"].BasePopup = MagicMock sys.modules["lib.panels.widgets.MainWindow.cancelPage"].CancelPage = MagicMock sys.modules["lib.panels.widgets.MainWindow.connectionPage"].ConnectionPage = MagicMock -sys.modules["lib.panels.widgets.loadWidget"].LoadingOverlayWidget = MagicMock +sys.modules["lib.panels.widgets.Common.loadWidget"].LoadingOverlayWidget = MagicMock sys.modules["lib.panels.widgets.MainWindow.notificationPage"].NotificationPage = MagicMock sys.modules["lib.panels.widgets.MainWindow.updatePage"].UpdatePage = MagicMock sys.modules["lib.printer"].Printer = MagicMock diff --git a/tests/util/test_keyboard_page_unit.py b/tests/util/test_keyboard_page_unit.py index 5d96d8176..dedb99604 100644 --- a/tests/util/test_keyboard_page_unit.py +++ b/tests/util/test_keyboard_page_unit.py @@ -29,12 +29,12 @@ # Force-reload the real module: the network conftest registers a stub # that lacks the layout constants we need. for _key in [ - "lib.panels.widgets.keyboardPage", - "BlocksScreen.lib.panels.widgets.keyboardPage", + "lib.panels.widgets.Common.keyboardPage", + "BlocksScreen.lib.panels.widgets.Common.keyboardPage", ]: sys.modules.pop(_key, None) -from BlocksScreen.lib.panels.widgets.keyboardPage import ( # noqa: E402 +from BlocksScreen.lib.panels.widgets.Common.keyboardPage import ( # noqa: E402 _LOWERCASE, _NUM_KEYS, _NUMBERS, diff --git a/tests/widgets/conftest.py b/tests/widgets/conftest.py index 8c6a31030..647627a36 100644 --- a/tests/widgets/conftest.py +++ b/tests/widgets/conftest.py @@ -57,7 +57,7 @@ @pytest.fixture(scope="module", autouse=True) def mock_heavy_deps(): with pytest.MonkeyPatch.context() as mp: - for key in ("configfile", "BlocksScreen.lib.panels.widgets.loadWidget"): + for key in ("configfile", "BlocksScreen.lib.panels.widgets.Common.loadWidget"): mp.delitem(sys.modules, key, raising=False) mp.setitem(sys.modules, "configfile", MagicMock()) yield diff --git a/tests/widgets/test_job_status_page_unit.py b/tests/widgets/test_job_status_page_unit.py index 9e9182276..534784fec 100644 --- a/tests/widgets/test_job_status_page_unit.py +++ b/tests/widgets/test_job_status_page_unit.py @@ -39,7 +39,7 @@ def set_progress(self, *a): # real CustomProgressBar takes a 0-1 float _blocks_label = types.ModuleType("lib.utils.blocks_label") _display_button = types.ModuleType("lib.utils.display_button") _progress_bar = types.ModuleType("lib.utils.blocks_progressbar") -_base_popup = types.ModuleType("lib.panels.widgets.basePopup") +_base_popup = types.ModuleType("lib.panels.widgets.Common.basePopup") _blocks_button.BlocksCustomButton = _make_stub(QtWidgets.QPushButton) _blocks_label.BlocksLabel = _make_stub(QtWidgets.QLabel) @@ -52,7 +52,7 @@ def set_progress(self, *a): # real CustomProgressBar takes a 0-1 float ("lib.utils.blocks_label", _blocks_label), ("lib.utils.display_button", _display_button), ("lib.utils.blocks_progressbar", _progress_bar), - ("lib.panels.widgets.basePopup", _base_popup), + ("lib.panels.widgets.Common.basePopup", _base_popup), ]: sys.modules[_name] = _mod # force-set so network conftest stubs don't win diff --git a/tests/widgets/test_slider_page_request_unit.py b/tests/widgets/test_slider_page_request_unit.py index ed1f5e8b8..65f9f8824 100644 --- a/tests/widgets/test_slider_page_request_unit.py +++ b/tests/widgets/test_slider_page_request_unit.py @@ -39,11 +39,12 @@ sys.modules.pop("lib.panels.printTab", None) sys.modules.pop("lib.panels.controlTab", None) sys.modules.pop("lib.ui", None) -sys.modules.pop("lib.ui.controlStackedWidget_ui", None) +for _stubbed in [_m for _m in sys.modules if _m.startswith("lib.panels.widgets")]: + sys.modules.pop(_stubbed, None) from lib.panels.controlTab import ControlTab # noqa: E402 from lib.panels.printTab import PrintTab # noqa: E402 -from lib.panels.widgets.slider_selector_page import SliderPage # noqa: E402 +from lib.panels.widgets.Common.slider_selector_page import SliderPage # noqa: E402 @pytest.fixture diff --git a/tests/widgets/test_update_page_unit.py b/tests/widgets/test_update_page_unit.py index 5ab72bf7b..26980da09 100644 --- a/tests/widgets/test_update_page_unit.py +++ b/tests/widgets/test_update_page_unit.py @@ -40,7 +40,7 @@ def _mock_setup(self): self._chevron_right = MagicMock() self._chevron_down = MagicMock() - setup_patch = patch.object(UpdatePage, "_setupUI", _mock_setup) + setup_patch = patch.object(UpdatePage, "_setup_ui", _mock_setup) setup_patch.start() pg = UpdatePage() setup_patch.stop() From 3bc6398e560eb81a2a9485751c05f7be5d10a42b Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 28 Sep 2026 12:05:55 +0100 Subject: [PATCH 14/18] feat: separated utilities ui into pages (#332) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Stacked PR — merge order This PR is stacked on top of: 1. #298 2. #299 **Do not merge until #298 , #299 are merged first.** CI won't run here until the base becomes `dev` (after the parents merge). ## Descirption - [x] Refactor ### Separated utitliesStacked.ui into pages - BlocksScreen/lib/panels/widgets/UtilitiesTab/InputShaPage.py - BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py - BlocksScreen/lib/panels/widgets/UtilitiesTab/infoPage.py - BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py - BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py - BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py (cleaned setupUi) ### deleted old UI - BlocksScreen/lib/ui/utilitiesStackedWidget.ui - BlocksScreen/lib/ui/utilitiesStackedWidget_ui.py --- BlocksScreen/lib/panels/mainWindow.py | 2 +- BlocksScreen/lib/panels/utilitiesTab.py | 834 ++--- .../widgets/UtilitiesTab/axisMaintPage.py | 215 ++ .../panels/widgets/UtilitiesTab/infoPage.py | 123 + .../widgets/UtilitiesTab/inputshaperPage.py | 534 +-- .../panels/widgets/UtilitiesTab/ledsPage.py | 364 ++ .../widgets/UtilitiesTab/routinePage.py | 494 +++ .../widgets/UtilitiesTab/troubleshootPage.py | 67 +- BlocksScreen/lib/ui/utilitiesStackedWidget.ui | 3072 ----------------- .../lib/ui/utilitiesStackedWidget_ui.py | 1282 ------- 10 files changed, 1774 insertions(+), 5213 deletions(-) create mode 100644 BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py create mode 100644 BlocksScreen/lib/panels/widgets/UtilitiesTab/infoPage.py create mode 100644 BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py create mode 100644 BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py delete mode 100644 BlocksScreen/lib/ui/utilitiesStackedWidget.ui delete mode 100644 BlocksScreen/lib/ui/utilitiesStackedWidget_ui.py diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index a3d42a85e..7b037ff8c 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -598,7 +598,7 @@ def _on_moonraker_connected_post_update(self) -> None: def on_update_available(self, state: bool = False): """Signal render for red dot on utilities tab icon and Update button""" self.main_content_widget.setNotification(3, state) - self.utilitiesPanel.panel.update_btn.setShowNotification(state) + self.utilitiesPanel.up_update_btn.setShowNotification(state) self.repaint() def enable_tab_bar(self) -> bool: diff --git a/BlocksScreen/lib/panels/utilitiesTab.py b/BlocksScreen/lib/panels/utilitiesTab.py index 2d7382be1..b05db099c 100644 --- a/BlocksScreen/lib/panels/utilitiesTab.py +++ b/BlocksScreen/lib/panels/utilitiesTab.py @@ -1,60 +1,26 @@ import logging import re import typing -from dataclasses import dataclass from enum import Enum, auto -from functools import partial from lib.moonrakerComm import MoonWebSocket from lib.panels.widgets.Common.basePopup import BasePopup -from lib.panels.widgets.UtilitiesTab.inputshaperPage import InputShaperPage -from lib.panels.widgets.Common.optionCardWidget import OptionCard +from lib.panels.widgets.UtilitiesTab.axisMaintPage import AxisMaintPage +from lib.panels.widgets.UtilitiesTab.infoPage import InfoPage +from lib.panels.widgets.UtilitiesTab.InputShaPage import InputShaperPage +from lib.panels.widgets.UtilitiesTab.ledsPage import LedsPage +from lib.panels.widgets.UtilitiesTab.routinePage import RoutineCheckPage from lib.panels.widgets.UtilitiesTab.troubleshootPage import TroubleshootPage from lib.printer import Printer -from lib.ui.utilitiesStackedWidget_ui import Ui_utilitiesStackedWidget from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.toggleAnimatedButton import ToggleAnimatedButton from PyQt6 import QtCore, QtGui, QtWidgets -logger = logging.getLogger(__name__) - - -@dataclass -class LedState: - """Represents the state of an LED light.""" - - led_type: str - red: int = 0 - green: int = 0 - blue: int = 0 - white: int = 255 - state: str = "on" - - def get_gcode(self, name: str) -> str: - """Generates the G-code command for the current state.""" - if self.state == "off": - return f"SET_LED LED={name} RED=0 GREEN=0 BLUE=0 WHITE=0" - if self.led_type == "white": - return f"SET_LED LED={name} WHITE={self.white / 255:.2f}" - # Default to RGB - return ( - f"SET_LED LED={name} RED={self.red / 255:.2f} " - f"GREEN={self.green / 255:.2f} BLUE={self.blue / 255:.2f} " - f"WHITE={self.white / 255:.2f}" - ) - class Process(Enum): - FAN = auto() AXIS = auto() - BED_HEATER = auto() - EXTRUDER = auto() - AXIS_MAINTENANCE = auto() class UtilitiesTab(QtWidgets.QStackedWidget): - _LED_TYPES: frozenset[str] = frozenset({"led", "neopixel", "dotstar"}) - request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( name="request-back" ) @@ -93,636 +59,282 @@ class UtilitiesTab(QtWidgets.QStackedWidget): ) call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") + on_object_list = QtCore.pyqtSignal(list, name="on-object-list") + def __init__( self, parent: QtWidgets.QWidget, ws: MoonWebSocket, printer: Printer ) -> None: super().__init__(parent) - self.panel = Ui_utilitiesStackedWidget() - self.panel.setupUi(self) + self.info_page: InfoPage = InfoPage(self) + self.leds_page: LedsPage = LedsPage(self) + self.axes_page: AxisMaintPage = AxisMaintPage(self) + self.routines_page: RoutineCheckPage = RoutineCheckPage(self) + self.troubleshoot_page: TroubleshootPage = TroubleshootPage(self) + + # currently using the logic only so theres no duplicate (logic flag disables render/update Ui) + self.is_page: InputShaperPage = InputShaperPage(self, logic=True) + self.is_page.hide() + + self.setupUi() self.ws = ws self.printer: Printer = printer - self.troubleshoot_page: TroubleshootPage = TroubleshootPage(self) - # --- State Variables --- - self.objects: dict = { - "fans": {}, - "axis": {"x": "indf", "y": "indf", "z": "indf"}, - "bheat": {"Bed_Heater": "indf"}, - "extrude": {"extruder": "indf"}, - "leds": {}, - } - self.x_inputshaper: dict = {} - self.stepper_limits: dict = {} - - self.current_object: str | None = None - self.current_process: Process | None = None - self.axis_in: str = "x" - self.amount: int = 1 - self.tb: bool = False - self.cg = None - self.aut: bool = False - - self._is_timeout_timer: QtCore.QTimer = QtCore.QTimer(self) - self._is_timeout_timer.setSingleShot(True) - self._is_timeout_timer.setInterval(300_000) # 5 min: longest plausible IS run - self._is_timeout_timer.timeout.connect(self._on_is_timeout) - - # --- PixMap --- - self._led_pixmap = QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") # --- UI Setup --- self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.panel.update_btn.clicked.connect( + self.up_update_btn.clicked.connect( lambda: self.show_update_page[bool].emit(False) ) - self.is_page = InputShaperPage(self) - self.is_page.call_load_panel.connect(self.call_load_panel) - self.addWidget(self.is_page) - - self.dialog_page = BasePopup(self, dialog=True, floating=True) - self.addWidget(self.dialog_page) - - # --- Back Buttons --- - for button in ( - self.panel.leds_back_btn, - self.panel.info_back_btn, - self.panel.leds_slider_back_btn, - self.panel.input_shaper_back_btn, - self.panel.routine_check_back_btn, - self.is_page.update_back_btn, - ): - button.clicked.connect(self.back_button) - # --- Page Navigation --- - self._connect_page_change(self.panel.utilities_axes_btn, self.panel.axes_page) - self._connect_page_change( - self.panel.utilities_input_shaper_btn, self.panel.input_shaper_page + self.up_input_shaper_btn.clicked.connect(self.ask_input_shaper) + + self.up_leds_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.leds_page)) ) - self._connect_page_change(self.panel.utilities_info_btn, self.panel.info_page) - self._connect_page_change( - self.panel.utilities_routine_check_btn, self.panel.routines_page + self.up_axes_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.axes_page)) ) - self._connect_page_change(self.panel.am_cancel, self.panel.utilities_page) - - self._connect_page_change(self.panel.axes_back_btn, self.panel.utilities_page) - self._connect_page_change( - self.troubleshoot_page.tb_back_btn, self.panel.utilities_page + self.up_info_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.info_page)) + ) + self.up_routine_check_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.routines_page)) + ) + self.axes_page.axes_back_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.utilitiesPage)) + ) + self.troubleshoot_page.tb_back_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.utilitiesPage)) ) + # --- Info --- + self.info_page.request_back_button.connect(self.request_back) + + # --- LEDs --- + self.leds_page.request_back_button.connect(self.request_back) + self.leds_page.run_gcode_signal.connect(self.run_gcode_signal) + self.on_object_list.connect(self.leds_page.on_object_list) + # --- Routines --- - self.panel.rc_fans.clicked.connect(partial(self.run_routine, Process.FAN)) - self.panel.rc_bheat.clicked.connect( - partial(self.run_routine, Process.BED_HEATER) + self.routines_page.run_gcode_signal.connect(self.run_gcode_signal) + self.routines_page.request_back.connect(self.request_back) + self.routines_page.call_load_panel.connect(self.call_load_panel) + self.routines_page.request_tb_page.connect(self.troubleshoot_request) + self.printer.toolhead_update[str, str].connect( + self.routines_page.on_toolhead_update + ) + self.printer.printer_config.connect( + self.routines_page.on_printer_config_received ) - self.panel.rc_ext.clicked.connect(partial(self.run_routine, Process.EXTRUDER)) - self.panel.rc_axis.clicked.connect(partial(self.run_routine, Process.AXIS)) - self.panel.rc_no.clicked.connect(self.on_routine_answer) - self.panel.rc_yes.clicked.connect(self.on_routine_answer) + self.routines_page.subscribe_config.connect(self.subscribe_config) + self.on_object_list.connect(self.routines_page.on_object_list) # --- Axis Maintenance --- - self.panel.am_execute.clicked.connect(self.axis_maintenance) - self.panel.toggle_led_button.state = ToggleAnimatedButton.State.ON + self.axes_page.run_gcode_signal.connect(self.run_gcode_signal) + self.axes_page.call_load_panel.connect(self.call_load_panel) + self.axes_page.request_back.connect(self.request_back) - # --- LEDs --- - # self.panel.leds_r_slider.sliderReleased.connect(self.update_led_values) - # self.panel.leds_g_slider.sliderReleased.connect(self.update_led_values) - # self.panel.leds_b_slider.sliderReleased.connect(self.update_led_values) - self.panel.leds_w_slider.sliderReleased.connect(self.update_led_values) - self.panel.toggle_led_button.clicked.connect(self.toggle_led_state) + # ---- Input Shaper ---- + self.is_popup: BasePopup = BasePopup(self, dialog=True, floating=True) + self.is_popup.set_message( + "Run the automatic input shaper?\n\nThe printer will calibrate both axes." + ) + self.is_popup.confirm_button_text("Yes") + self.is_popup.cancel_button_text("No") + self.is_popup.confirm_button.clicked.connect(self.run_input_shaper) + self.is_page.run_gcode_signal.connect(self.run_gcode_signal) + self.is_page.call_load_panel.connect(self.call_load_panel) + self.printer.gcode_response.connect(self.is_page.handle_gcode_response) # --- Websocket/Printer Signals --- self.run_gcode_signal.connect(self.ws.api.run_gcode) - self.is_page.run_gcode_signal.connect(self.ws.api.run_gcode) + self.subscribe_config[str, "PyQt_PyObject"].connect( self.printer.on_subscribe_config ) self.subscribe_config[list, "PyQt_PyObject"].connect( self.printer.on_subscribe_config ) - self.printer.gcode_response.connect(self.handle_gcode_response) - # --- Initialize Printer Communication --- - self.printer.printer_config.connect(self.on_printer_config_received) - self.printer.gcode_move_update.connect(self.on_gcode_move_update) + def ask_input_shaper(self) -> None: + """Ask whether to run the automatic input shaper.""" + self.is_popup.show() - self.panel.update_btn.setPixmap( - QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg") - ) + def run_input_shaper(self) -> None: + """Start the automatic input shaper calibration.""" + self.is_popup.hide() + self.is_page.handle_is("SHAPER_CALIBRATE") - # ---- Input Shaper ---- - self.automatic_is = OptionCard( - self, - "Automatic\nInput Shaper", - "Automatic Input Shaper", - QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper_auto.svg"), - ) # type: ignore - self.automatic_is.setObjectName("Automatic_IS_Card") - self.panel.is_content_layout.addWidget( - self.automatic_is, alignment=QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.automatic_is.continue_clicked.connect( - lambda: self.handle_is("SHAPER_CALIBRATE") - ) + def troubleshoot_request(self) -> None: + """Show troubleshoot page""" + self.troubleshoot_page.show() - self.manual_is = OptionCard( - self, - "Manual\nInput Shaper", - "Manual Input Shaper", - QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper_manual.svg"), - ) # type: ignore - self.manual_is.setObjectName("Manual_IS_Card") - self.panel.is_content_layout.addWidget( - self.manual_is, alignment=QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.manual_is.continue_clicked.connect(lambda: self.handle_is("")) + def change_page(self, index: int): + """Request change page by index""" + self.call_load_panel.emit(False, "", False) + self.troubleshoot_page.hide() + if index < self.count(): + self.request_change_page.emit(3, index) - self.is_types: dict = {} - self.is_aut_types: dict = {} - self.dialog_page.accepted.connect( - lambda: self.handle_is("SHAPER_CALIBRATE AXIS=Y") - ) - self.dialog_page.rejected.connect( - lambda: self.handle_is("SHAPER_CALIBRATE AXIS=X") - ) + @QtCore.pyqtSlot(name="request-back") + def back_button(self) -> None: + """Request back""" + self.request_back.emit() + + def setupUi(self): + + self.setObjectName("utilitiesTab") - self.is_page.action_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.panel.input_shaper_page)) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum ) - def handle_gcode_response(self, data: list[str]) -> None: - """ - Parses a Klipper Input Shaper console message and updates self.is_types. - """ + self.resize(710, 410) + self.setSizePolicy(sizePolicy) + self.setMinimumSize(QtCore.QSize(710, 410)) + self.setMaximumSize(QtCore.QSize(710, 410)) + self.utilitiesPage = QtWidgets.QWidget() + self.utilitiesPage.setObjectName("utilitiesPage") - if not isinstance(data, list) or len(data) != 1 or not isinstance(data[0], str): - logger.warning( - "handle_gcode_response: invalid input format. Expected list[str], received: %r", - data, - ) - return + self.verticalLayout = QtWidgets.QVBoxLayout(self.utilitiesPage) + self.verticalLayout.setObjectName("verticalLayout") - message = data[0] + self.up_header_layout = QtWidgets.QHBoxLayout() + self.up_header_layout.setObjectName("up_header_layout") - pattern_fitted = re.compile( - r"Fitted shaper '(?P\w+)' frequency = (?P[\d\.]+) Hz \(vibrations = (?P[\d\.]+)%" + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum ) - match_fitted = pattern_fitted.search(message) - - if match_fitted: - name = match_fitted.group("name") - freq = float(match_fitted.group("freq")) - vib = float(match_fitted.group("vib")) - current_data = self.is_types.get(name, {}) - current_data.update( - { - "frequency": freq, - "vibration": vib, - "max_accel": current_data.get("max_accel", 0.0), - } - ) - self.is_types[name] = current_data - - return - pattern_accel = re.compile( - r"To avoid too much smoothing with '(?P\w+)', suggested max_accel <= (?P[\d\.]+) mm/sec\^2" + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + self.up_title_label = QtWidgets.QLabel(parent=self.utilitiesPage) + self.up_title_label.setSizePolicy(sizePolicy) + self.up_title_label.setMinimumSize(QtCore.QSize(0, 60)) + self.up_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + self.up_title_label.setFont(font) + self.up_title_label.setStyleSheet("background: transparent; color: white;") + self.up_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.up_title_label.setObjectName("up_title_label") + self.up_header_layout.addWidget(self.up_title_label) + self.verticalLayout.addLayout(self.up_header_layout) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, ) - match_accel = pattern_accel.search(message) - if match_accel: - name = match_accel.group("name") - accel = float(match_accel.group("accel")) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) - if name in self.is_types and isinstance(self.is_types[name], dict): - self.is_types[name]["max_accel"] = accel - else: - self.is_types[name] = self.is_types.get(name, {}) - self.is_types[name]["max_accel"] = accel - return + self.up_content_layout = QtWidgets.QGridLayout() + self.up_content_layout.setObjectName("up_content_layout") - pattern_recommended = re.compile( - r"Recommended shaper_type_(?P[xy]) = (?P\w+), shaper_freq_(?P=axis) = (?P[\d\.]+) Hz" + self.up_info_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_info_btn.setSizePolicy(sizePolicy) + self.up_info_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_info_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_info_btn.setFont(font) + self.up_info_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg") ) - match_recommended = pattern_recommended.search(message) - if match_recommended: - axis = match_recommended.group("axis") - recommended_type = match_recommended.group("type") - self.is_types["Axis"] = axis - if self.aut: - self.is_aut_types[axis] = recommended_type - if len(self.is_aut_types) == 2: - self.run_gcode_signal.emit("SAVE_CONFIG") - self._is_timeout_timer.stop() - self.call_load_panel.emit(False, "", False) - self.aut = False - return - return - - reordered = {recommended_type: self.is_types[recommended_type]} - for key, value in self.is_types.items(): - if key not in ("suggested_type", recommended_type, "Axis"): - reordered[key] = value - - self.is_page.set_type_dictionary(self.is_types) - first_key = next(iter(reordered.keys()), None) - for key in reordered: - if key == first_key: - self.is_page.add_type_entry(key, "Recommended type") - else: - self.is_page.add_type_entry(key) - - self.is_page.build_model_list() - self._is_timeout_timer.stop() - self.call_load_panel.emit(False, "", False) - return - - def handle_is(self, gcode: str) -> None: - if gcode == "SHAPER_CALIBRATE": - self.run_gcode_signal.emit("G28\nM400") - self.aut = True - self.run_gcode_signal.emit(gcode) - elif gcode == "": - self.dialog_page.confirm_background_color("#dfdfdf") - self.dialog_page.cancel_background_color("#dfdfdf") - self.dialog_page.cancel_font_color("#000000") - self.dialog_page.confirm_font_color("#000000") - self.dialog_page.cancel_button_text("X axis") - self.dialog_page.confirm_button_text("Y axis") - self.dialog_page.set_message( - "Select the axis you want to execute the input shaper on:" - ) - self.dialog_page.show() - return - else: - self.run_gcode_signal.emit("G28\nM400") - self.run_gcode_signal.emit(gcode) - self.change_page(self.indexOf(self.is_page)) - - self._is_timeout_timer.start() - self.call_load_panel.emit(True, "Running Input Shaper...", False) - - def _on_is_timeout(self) -> None: - self.call_load_panel.emit(False, "", False) - - @QtCore.pyqtSlot(list, name="on_object_list") - def on_object_list(self, object_list: list) -> None: - """Handle receiving printer object list""" - self.cg = object_list - for obj in self.cg: - base_name = obj.split()[0] - - # Only accept 'fan_generic' or 'fan' - if base_name == "fan_generic" or base_name == "fan": - self.objects["fans"][obj.removeprefix(base_name + " ")] = "indef" - self._update_leds_from_config() - - @QtCore.pyqtSlot(dict, name="on_object_config") - @QtCore.pyqtSlot(list, name="on_object_config") - def on_object_config(self, config: dict | list) -> None: - """Handle receiving printer object configurations""" - if not config: - return - config_items = [config] if isinstance(config, dict) else config - for item in config_items: - for key, value in item.items(): - if ( - key.startswith("stepper_") - and isinstance(value, dict) - and key not in self.stepper_limits - ): - pos_min = value.get("position_min") - pos_max = value.get("position_max") - if pos_min is not None or pos_max is not None: - min_val = ( - float(pos_min) if pos_min is not None else -float("inf") - ) - max_val = ( - float(pos_max) if pos_max is not None else float("inf") - ) - endstop_raw = value.get("position_endstop") - endstop = float(endstop_raw) if endstop_raw is not None else 0.0 - homes_at_min = abs(endstop - min_val) <= abs(endstop - max_val) - self.stepper_limits[key] = { - "min": min_val, - "max": max_val, - "homes_at_min": homes_at_min, - } - - def on_printer_config_received(self, config: dict) -> None: - """Handle printer configuration""" - for axis in ("x", "y", "z"): - self.subscribe_config[str, "PyQt_PyObject"].emit( - f"stepper_{axis}", self.on_object_config - ) - - @QtCore.pyqtSlot(str, list, name="on_gcode_move_update") - def on_gcode_move_update(self, name: str, value: list) -> None: - """Handle gcode move""" - if not value: - return - if name == "gcode_position": - ... - - def run_routine(self, process: Process): - """Run check routine for available processes""" - self.current_process = process - routine_configs = { - Process.FAN: ("fans", "fan is spinning"), - Process.AXIS: ("axis", "axis is moving"), - Process.BED_HEATER: ("bheat", "bed is heating"), - Process.EXTRUDER: ("extrude", "extruder is being tested"), - } - if process not in routine_configs: - return - obj_key, message = routine_configs[process] - obj_list = list(self.objects.get(obj_key, {}).keys()) - if not self._advance_routine_object(obj_list): - if self.tb: - self.troubleshoot_request() - self.tb = False - else: - self.change_page(self.indexOf(self.panel.utilities_page)) - - return - if self.tb: - self.troubleshoot_request() - self.tb = False - self.current_object = None - self.current_process = None - return - message = ( - f"Please check if the {self.current_object}\nis functioning correctly." + self.up_info_btn.setObjectName("up_info_btn") + self.up_content_layout.addWidget(self.up_info_btn, 0, 0, 1, 1) + + self.up_leds_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_leds_btn.setSizePolicy(sizePolicy) + self.up_leds_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_leds_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_leds_btn.setFont(font) + self.up_leds_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") ) - if process == Process.AXIS: - message = f"Please ensure the {self.current_object} axis moves correctly." - elif process in [Process.BED_HEATER, Process.EXTRUDER]: - message = "Please check if the temperature reaches 60°C. \n it may take a few moments." - - self.set_routine_check_page( - f"Running routine for: {self.current_object}", message + self.up_leds_btn.setObjectName("up_leds_btn") + self.up_content_layout.addWidget(self.up_leds_btn, 0, 1, 1, 1) + + self.up_routine_check_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_routine_check_btn.setSizePolicy(sizePolicy) + self.up_routine_check_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_routine_check_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_routine_check_btn.setFont(font) + self.up_routine_check_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg") ) - self.show_waiting_page( - self.indexOf(self.panel.rc_page), - message, - 20000 if process == Process.AXIS else 0, + self.up_routine_check_btn.setObjectName("up_routine_check_btn") + self.up_content_layout.addWidget(self.up_routine_check_btn, 1, 0, 1, 1) + + self.up_axes_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_axes_btn.setSizePolicy(sizePolicy) + self.up_axes_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_axes_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_axes_btn.setFont(font) + self.up_axes_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), ) - self._send_routine_gcode() - - def _advance_routine_object(self, obj_list: list) -> bool: - if not obj_list: - is_first_run = self.current_object is None - self.current_object = obj_list[0] if is_first_run and obj_list else "done" - return is_first_run - if self.current_object not in obj_list: - if self.current_process == Process.AXIS: - self.run_gcode_signal.emit("G28") - self.current_object = obj_list[0] - return True - try: - current_index = obj_list.index(self.current_object) - if current_index + 1 < len(obj_list): - self.current_object = obj_list[current_index + 1] - return True - else: - self.current_object = None - return False - except ValueError: - self.current_object = obj_list[0] - return True - - def on_routine_answer(self) -> None: - """Handle routine ongoing process""" - if self.current_process is None or self.current_object is None: - return - if self.sender() == self.panel.rc_yes: - answer = "yes" - else: - answer = "no" - self.tb = True - process_map = { - Process.FAN: ("fans", self.current_object), - Process.AXIS: ("axis", self.current_object), - Process.BED_HEATER: ("bheat", "Bed_Heater"), - Process.EXTRUDER: ("extrude", "extruder"), - } - if self.current_process in process_map: - obj_key, item_key = process_map[self.current_process] - self.objects[obj_key][item_key] = answer - if self.current_process in [Process.BED_HEATER, Process.EXTRUDER]: - self.run_gcode_signal.emit("TURN_OFF_HEATERS") - - if self.current_process == Process.FAN: - self.run_gcode_signal.emit("M107") - for i in self.objects["fans"]: - self.run_gcode_signal.emit( - f"SET_FAN_SPEED FAN={i.removeprefix('fan_generic ')} SPEED=0\nM400" - ) - - self.run_routine(self.current_process) - elif self.current_process == Process.AXIS_MAINTENANCE: - if answer == "yes": - self._run_AXIS_MAINTENANCE_gcode(self.current_object) - else: - self.change_page(self.indexOf(self.panel.axes_page)) - - def _send_routine_gcode(self): - """Send the correct G-code for the current process and object.""" - if self.current_process == Process.FAN: - fan_name = self.current_object or next(iter(self.objects["fans"]), None) - if fan_name: - if fan_name == "fan": - self.run_gcode_signal.emit("M106 S255\nM400") - else: - self.run_gcode_signal.emit( - f"SET_FAN_SPEED FAN={fan_name.removeprefix('fan_generic ')} SPEED=0.8\nM400" - ) - - return - - if self.current_process == Process.AXIS: - if gcode := self._routine_check_axis_gcode(self.current_object): - self.run_gcode_signal.emit(f"{gcode}\nM400") - return - - gcode_map = { - Process.BED_HEATER: "SET_HEATER_TEMPERATURE HEATER=heater_bed TARGET=60", - Process.EXTRUDER: "SET_HEATER_TEMPERATURE HEATER=extruder TARGET=60", - } - - if gcode := gcode_map.get(self.current_process): - self.run_gcode_signal.emit(f"{gcode}\nM400") - - def _routine_check_axis_gcode(self, axis: str, margin: float = 70.0) -> str: - limits = self.stepper_limits.get(f"stepper_{axis}") - if not limits: - return "" - - span = limits["max"] - limits["min"] - if span <= 0: - return "" - - effective_margin = margin - if span - (2 * margin) <= 0: - effective_margin = span * 0.1 - - distance = span - (2 * effective_margin) - if distance <= 0: - return "" - - sign = 1 if limits.get("homes_at_min", True) else -1 - axis_upper = axis.upper() - - out = f"G1 {axis_upper}{sign * distance:.2f} F6000" - back = f"G1 {axis_upper}{-sign * (distance - 10):.2f} F6000" - moves = f"{out}\n{back}" - if axis == "x": - moves += "\nG90\nG1 X250 F6000" - - return f"G91\n{moves}" - - def set_routine_check_page(self, title: str, label: str): - """Set text on routine page""" - self.panel.rc_tittle.setText(title) - self.panel.rc_label.setText(label) - - def update_led_values(self) -> None: - """Update led state and color values""" - if self.current_object not in self.objects["leds"]: - return - led_state: LedState = self.objects["leds"][self.current_object] - led_state.white = int(self.panel.leds_w_slider.value() * 255 / 100) - self.save_led_state() - - def _update_leds_from_config(self): - layout = self.panel.leds_content_layout - - while layout.count(): - if (child := layout.takeAt(0)) and child.widget(): - child.widget().deleteLater() # type: ignore - - led_names = [] - if not self.cg: - return - - # Collect LED names - match Klipper LED hardware types only - for obj in self.cg: - parts = obj.split() - if len(parts) >= 2 and parts[0] in self._LED_TYPES: - name = parts[1] - led_names.append(name) - self.objects["leds"][name] = LedState(led_type="white") - - max_columns = 3 - buttons = [] # store references to created buttons - - # Create LED buttons - for i, name in enumerate(led_names): - if self.panel.leds_widget: - button = BlocksCustomButton() - button.setFixedSize(200, 70) - button.setText(name) - button.setProperty("class", "menu_btn") - button.setPixmap(self._led_pixmap) - row, col = divmod(i, max_columns) - layout.addWidget(button, row, col) - button.clicked.connect(partial(self.handle_led_button, name)) - buttons.append(button) - - try: - self.panel.utilities_leds_btn.clicked.disconnect() - except (RuntimeError, TypeError): - pass - if len(buttons) == 1: - self.panel.utilities_leds_btn.clicked.connect( - partial(self.handle_led_button, led_names[0]) - ) - elif len(buttons) > 1: - self._connect_page_change( - self.panel.utilities_leds_btn, self.panel.leds_page - ) - - def toggle_led_state(self) -> None: - """Toggle leds""" - if self.current_object not in self.objects["leds"]: - return - led_state: LedState = self.objects["leds"][self.current_object] - if led_state.state == "off": - led_state.state = "on" - self.panel.toggle_led_button.state = ToggleAnimatedButton.State.ON - else: - led_state.state = "off" - self.panel.toggle_led_button.state = ToggleAnimatedButton.State.OFF - self.save_led_state() - - def handle_led_button(self, name: str) -> None: - """Handle led button clicked""" - self.current_object = name - led_state: LedState = self.objects["leds"].get(name) - if not led_state: - return - is_rgb = led_state.led_type == "rgb" - self.panel.leds_w_slider.setVisible(not is_rgb) - self.panel.leds_w_slider.setValue(led_state.white) - self.change_page(self.indexOf(self.panel.leds_slider_page)) - - def save_led_state(self): - """Save led state""" - if self.current_object: - if self.current_object in self.objects["leds"]: - led_state: LedState = self.objects["leds"][self.current_object] - self.run_gcode_signal.emit(led_state.get_gcode(self.current_object)) - - def axis_maintenance(self) -> None: - """Routine, checks axis movement for printer debugging""" - self.current_process = Process.AXIS_MAINTENANCE - self.current_object = ( - self.panel.axis_maintenance_gb.checkedButton().text().lower() - ) - self.run_gcode_signal.emit(f"AXIS_MAINTENANCE_{self.current_object}\nM400") - self.set_routine_check_page( - "Axis Maintenance", - f"Insert oil on the {self.current_object.upper()} axis before confirming.", + self.up_content_layout.addWidget(self.up_axes_btn, 1, 1, 1, 1) + + self.up_update_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_update_btn.setSizePolicy(sizePolicy) + self.up_update_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_update_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_update_btn.setFont(font) + self.up_update_btn.setPixmap( + QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg") ) - self.show_waiting_page( - self.indexOf(self.panel.rc_page), - f"Homing {self.current_object.upper()} axis...", - 20000, + + self.up_update_btn.setObjectName("up_update_btn") + self.up_content_layout.addWidget(self.up_update_btn, 2, 0, 1, 1) + + self.up_input_shaper_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_input_shaper_btn.setSizePolicy(sizePolicy) + self.up_input_shaper_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_input_shaper_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_input_shaper_btn.setFont(font) + self.up_input_shaper_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg"), ) + self.up_content_layout.addWidget(self.up_input_shaper_btn, 2, 1, 1, 1) - def _run_AXIS_MAINTENANCE_gcode(self, axis: str): - stepper_key = f"stepper_{axis}" - if stepper_key in self.stepper_limits: - self.run_gcode_signal.emit(f"AXIS_MAINTENANCE_FINISH_{axis}\nM400") - self.show_waiting_page( - self.indexOf(self.panel.axes_page), - f"Running maintenance cycle on {axis.upper()} axis...", - 5000, - ) - else: - self.change_page(self.indexOf(self.panel.axes_page)) + self.verticalLayout.addLayout(self.up_content_layout) + self.addWidget(self.utilitiesPage) - def troubleshoot_request(self) -> None: - """Show troubleshoot page""" - self.troubleshoot_page.show() + # Info - def show_waiting_page(self, page_to_go_to: int, label: str, time_ms: int): - """Show placeholder page""" - self.call_load_panel.emit(True, label, False) - QtCore.QTimer.singleShot(time_ms, lambda: self.change_page(page_to_go_to)) + self.addWidget(self.info_page) - def _connect_page_change(self, button: QtWidgets.QWidget, page: QtWidgets.QWidget): - if isinstance(button, QtWidgets.QAbstractButton): - button.clicked.connect(lambda: self.change_page(self.indexOf(page))) + # Leds Page - def change_page(self, index: int): - """Request change page by index""" - self.call_load_panel.emit(False, "", False) - self.troubleshoot_page.hide() - if index < self.count(): - self.request_change_page.emit(3, index) + self.addWidget(self.leds_page) - @QtCore.pyqtSlot(name="request-back") - def back_button(self) -> None: - """Request back""" - self.request_back.emit() + # Routine Page + + self.addWidget(self.routines_page) + + # Axis maintenance Page + + self.addWidget(self.axes_page) + + # Input Shaper Page + + # self.addWidget(self.is_page) + + self.setCurrentIndex(0) + + _translate = QtCore.QCoreApplication.translate + + self.up_title_label.setText(_translate("self", "Utilities")) + self.up_info_btn.setText(_translate("self", "Info")) + self.up_leds_btn.setText(_translate("self", "LED's")) + self.up_routine_check_btn.setText(_translate("self", "Routine\nCheck")) + self.up_axes_btn.setText(_translate("self", "Axis\nMaint.")) + self.up_update_btn.setText(_translate("self", "Update")) + self.up_input_shaper_btn.setText(_translate("self", "Input\nShaper")) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py new file mode 100644 index 000000000..db4666bba --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py @@ -0,0 +1,215 @@ +import typing + +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.check_button import BlocksCustomCheckButton +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class AxisMaintPage(QtWidgets.QWidget): + """Axis Maintenance page of the utilities tab.""" + + request_back = QtCore.pyqtSignal(name="request-back-button") + + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + + self.answerPage = BasePopup(self, False, True) + self.answerPage.accepted.connect(self._run_AXIS_MAINTENANCE_gcode) + + self._setup_ui() + self.axes_back_btn.clicked.connect(self.request_back.emit) + self.am_execute.clicked.connect(self.axis_maintenance) + + def _run_AXIS_MAINTENANCE_gcode(self): + if self.current_object: + self.run_gcode_signal.emit( + f"AXIS_MAINTENANCE_FINISH_{self.current_object}\nM400" + ) + + self.call_load_panel.emit( + True, + f"Running maintenance cycle on {self.current_object.upper()} axis...", + False, + ) + + QtCore.QTimer.singleShot( + 50000, lambda: self.call_load_panel.emit(False, "", False) + ) + + else: + self.answerPage.hide() + + def axis_maintenance(self) -> None: + """Routine, checks axis movement for printer debugging""" + self.current_object = self.axis_maintenance_gb.checkedButton().text().lower() + self.run_gcode_signal.emit(f"AXIS_MAINTENANCE_{self.current_object}\nM400") + + self.answerPage.set_message( + f"Apply oil to the {self.current_object.upper()} axis, then press Confirm.", + ) + + self.answerPage.show() + self.call_load_panel.emit( + True, f"Homing {self.current_object.upper()} axis...", False + ) + + QtCore.QTimer.singleShot( + 10000, + lambda: { + self.call_load_panel.emit(False, "", False), + self.answerPage.show(), + }, + ) + + def _setup_ui(self) -> None: + self.setObjectName("axes_page") + + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self) + self.verticalLayout_7.setObjectName("verticalLayout_7") + spacerItem12 = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout_7.addItem(spacerItem12) + self.lcd_settings_header_layout = QtWidgets.QHBoxLayout() + self.lcd_settings_header_layout.setObjectName("lcd_settings_header_layout") + spacerItem13 = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.lcd_settings_header_layout.addItem(spacerItem13) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + + self.lcd_settings_title_label = QtWidgets.QLabel(parent=self) + self.lcd_settings_title_label.setSizePolicy(sizePolicy) + self.lcd_settings_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + self.lcd_settings_title_label.setFont(font) + self.lcd_settings_title_label.setStyleSheet( + "background: transparent; color: white;" + ) + self.lcd_settings_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.lcd_settings_header_layout.addWidget(self.lcd_settings_title_label) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + self.axes_back_btn = IconButton(parent=self) + self.axes_back_btn.setSizePolicy(sizePolicy) + self.axes_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.axes_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.axes_back_btn.setFont(font) + self.axes_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.axes_back_btn.setObjectName("axes_back_btn") + + self.lcd_settings_header_layout.addWidget(self.axes_back_btn) + self.verticalLayout_7.addLayout(self.lcd_settings_header_layout) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + self.frame_2 = BlocksCustomFrame(parent=self) + self.frame_2.setSizePolicy(sizePolicy) + self.frame_2.setMinimumSize(QtCore.QSize(650, 0)) + self.frame_2.setObjectName("frame_2") + + self.gridLayout = QtWidgets.QGridLayout(self.frame_2) + self.gridLayout.setObjectName("gridLayout") + + self.axis_maintenance_gb = QtWidgets.QButtonGroup(self) + self.axis_maintenance_gb.setObjectName("axis_maintenance_gb") + + self.am_execute = BlocksCustomButton(parent=self.frame_2) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + + self.am_execute.setSizePolicy(sizePolicy) + self.am_execute.setMinimumSize(QtCore.QSize(250, 80)) + self.am_execute.setMaximumSize(QtCore.QSize(250, 80)) + self.am_execute.setFont(font) + self.am_execute.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") + ) + self.am_execute.setObjectName("am_execute") + self.gridLayout.addWidget(self.am_execute, 2, 1, 1, 1) + + font = QtGui.QFont() + font.setPointSize(20) + + self.am_y = BlocksCustomCheckButton(parent=self.frame_2) + self.am_y.setMinimumSize(QtCore.QSize(60, 80)) + self.am_y.setMaximumSize(QtCore.QSize(250, 80)) + self.am_y.setFont(font) + self.am_y.setCheckable(True) + self.am_y.setChecked(True) + self.am_y.setAutoExclusive(True) + self.am_y.setFlat(True) + self.am_y.setObjectName("am_y") + self.axis_maintenance_gb.addButton(self.am_y) + + self.gridLayout.addWidget(self.am_y, 1, 0, 1, 1) + + self.am_z = BlocksCustomCheckButton(parent=self.frame_2) + self.am_z.setMinimumSize(QtCore.QSize(60, 80)) + self.am_z.setMaximumSize(QtCore.QSize(250, 80)) + self.am_z.setFont(font) + self.am_z.setCheckable(True) + self.am_z.setAutoExclusive(True) + self.axis_maintenance_gb.addButton(self.am_z) + self.gridLayout.addWidget(self.am_z, 2, 0, 1, 1) + + self.am_x = BlocksCustomCheckButton(parent=self.frame_2) + self.am_x.setMinimumSize(QtCore.QSize(250, 80)) + self.am_x.setMaximumSize(QtCore.QSize(250, 80)) + self.am_x.setFont(font) + self.am_x.setCheckable(True) + self.am_x.setAutoExclusive(True) + self.axis_maintenance_gb.addButton(self.am_x) + self.gridLayout.addWidget(self.am_x, 0, 0, 1, 1) + + self.verticalLayout_7.addWidget( + self.frame_2, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.lcd_settings_title_label.setText("Axis Maintenance") + + self.axes_back_btn.setText("Back") + self.am_execute.setText("Execute") + + self.am_z.setText("Z") + self.am_x.setText("X") + self.am_y.setText("Y") diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/infoPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/infoPage.py new file mode 100644 index 000000000..0f4ef130f --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/infoPage.py @@ -0,0 +1,123 @@ +import typing + +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class InfoPage(QtWidgets.QWidget): + """Info page of the utilities tab.""" + + request_back_button = QtCore.pyqtSignal(name="request-back-button") + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + + self._setup_ui() + self.info_back_btn.clicked.connect(self.request_back_button.emit) + + def _setup_ui(self) -> None: + self.setObjectName("info_page") + + spacerItem = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + spacerItem1 = QtWidgets.QSpacerItem( + 60, + 60, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.verticalLayout_2.addItem(spacerItem) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + self.info_header_layout = QtWidgets.QHBoxLayout() + self.info_header_layout.setObjectName("info_header_layout") + self.info_header_layout.addItem(spacerItem1) + + self.info_title_label = QtWidgets.QLabel(parent=self) + self.info_title_label.setSizePolicy(sizePolicy) + self.info_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + self.info_title_label.setFont(font) + self.info_title_label.setStyleSheet("background: transparent; color: white;") + self.info_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_header_layout.addWidget(self.info_title_label) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + + self.info_back_btn = IconButton(parent=self) + self.info_back_btn.setSizePolicy(sizePolicy) + self.info_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.info_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.info_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.info_header_layout.addWidget(self.info_back_btn) + self.verticalLayout_2.addLayout(self.info_header_layout) + + self.info_content_layout = QtWidgets.QVBoxLayout() + self.info_content_layout.setObjectName("info_content_layout") + + self.frame = BlocksCustomFrame(parent=self) + self.frame.setMinimumSize(QtCore.QSize(350, 260)) + self.frame.setMaximumSize(QtCore.QSize(350, 290)) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Preferred, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + font = QtGui.QFont() + font.setPointSize(20) + + self.kv_label = QtWidgets.QLabel(parent=self.frame) + self.kv_label.setGeometry(QtCore.QRect(0, 10, 351, 81)) + self.kv_label.setSizePolicy(sizePolicy) + self.kv_label.setFont(font) + self.kv_label.setStyleSheet("color:white") + self.kv_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.kv_label.setObjectName("kv_label") + + font = QtGui.QFont() + font.setPointSize(20) + + self.smth_label = QtWidgets.QLabel(parent=self.frame) + self.smth_label.setGeometry(QtCore.QRect(0, 110, 351, 81)) + self.smth_label.setSizePolicy(sizePolicy) + self.smth_label.setFont(font) + self.smth_label.setStyleSheet("color:white") + self.smth_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_content_layout.addWidget( + self.frame, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.verticalLayout_2.addLayout(self.info_content_layout) + + _translate = QtCore.QCoreApplication.translate + + self.info_title_label.setText(_translate("self", "Info")) + self.info_title_label.setProperty("class", _translate("self", "title_text")) + self.info_back_btn.setText(_translate("self", "Back")) + self.info_back_btn.setProperty("class", _translate("self", "menu_btn")) + self.info_back_btn.setProperty("button_type", _translate("self", "icon")) + self.kv_label.setText(_translate("self", "Model: Blocks RF50")) + self.smth_label.setText(_translate("self", "www.blockstec.com ")) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py index 462538901..8c792aa9b 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py @@ -1,5 +1,8 @@ +import re import typing +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.Common.optionCardWidget import OptionCard from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton @@ -7,28 +10,38 @@ from PyQt6 import QtCore, QtGui, QtWidgets -class InputShaperPage(QtWidgets.QWidget): - """Update GUI Page, - retrieves from moonraker available clients and adds functionality - for updating or recovering them - """ - +class InputShaperPage(QtWidgets.QStackedWidget): run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run-gcode" ) call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") + request_back_button = QtCore.pyqtSignal(name="request-back-button") - def __init__(self, parent=None) -> None: + def __init__(self, parent=None, logic: bool = False) -> None: if parent: super().__init__(parent) else: super().__init__() - self._setup_ui() - self.selected_item: ListItem | None = None - self.ongoing_update: bool = False + + # flag that disable all UI usage (headless per say) <- current use on utilities tab + self.logic: bool = logic + + self.currentItem: ListItem | None = None self.type_dict: dict = {} - self.repeated_request_status = QtCore.QTimer() - self.repeated_request_status.setInterval(2000) # every 2 seconds + self.is_types: dict = {} + self.is_aut_types: dict = {} + self.aut: bool = False + + self._is_timeout_timer: QtCore.QTimer = QtCore.QTimer(self) + self._is_timeout_timer.setSingleShot(True) + self._is_timeout_timer.setInterval(300_000) # 5 min: longest plausible IS run + self._is_timeout_timer.timeout.connect(self._on_is_timeout) + + if self.logic: + return + + self._setup_ui() + self.model = EntryListModel() self.model.setParent(self.update_buttons_list_widget) self.entry_delegate = EntryDelegate() @@ -37,27 +50,176 @@ def __init__(self, parent=None) -> None: self.entry_delegate.item_selected.connect(self.on_item_clicked) self.update_back_btn.clicked.connect(self.reset_view_model) + self.is_back_btn.clicked.connect(self.request_back_button) + + self.dialog_page = BasePopup(self, dialog=True, floating=True) + self.addWidget(self.dialog_page) + self.dialog_page.confirm_button.clicked.connect( + lambda: self.handle_is("SHAPER_CALIBRATE AXIS=Y") + ) + self.dialog_page.cancel_button.clicked.connect( + lambda: self.handle_is("SHAPER_CALIBRATE AXIS=X") + ) + self.action_btn.clicked.connect(self.handle_ism_confirm) - def handle_update_end(self) -> None: - """Handles update end signal - (closes loading page, returns to normal operation) - """ - self.call_load_panel.emit(False, "Updating...", False) - self.repeated_request_status.stop() - self.build_model_list() + self.automatic_card_is = OptionCard( + self, + "Automatic\nInput Shaper", + "Automatic Input Shaper", + QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper_auto.svg"), + ) # type: ignore + self.automatic_card_is.setObjectName("Automatic_IS_Card") + self.is_content_layout.addWidget( + self.automatic_card_is, alignment=QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.automatic_card_is.clicked.connect( + lambda: self.handle_is("SHAPER_CALIBRATE") + ) + + self.manual__card_is = OptionCard( + self, + "Manual\nInput Shaper", + "Manual Input Shaper", + QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper_manual.svg"), + ) # type: ignore + self.manual__card_is.setObjectName("Manual_IS_Card") + self.is_content_layout.addWidget( + self.manual__card_is, alignment=QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.manual__card_is.clicked.connect(lambda: self.handle_is("")) - def handle_ongoing_update(self) -> None: - """Handled ongoing update signal, - calls loading page (blocks user interaction) + self.setCurrentIndex(self.indexOf(self.manual_is)) + + def handle_gcode_response(self, data: list[str]) -> None: + """ + Parses a Klipper Input Shaper console message and updates self.is_types. """ - self.call_load_panel.emit(True, "Updating...", False) - self.repeated_request_status.start(2000) + + if not isinstance(data, list) or len(data) != 1 or not isinstance(data[0], str): + print( + f"WARNING: Invalid input format. Expected a list with one string. Received: {data}" + ) + return + + message = data[0] + + pattern_fitted = re.compile( + r"Fitted shaper '(?P\w+)' frequency = (?P[\d\.]+) Hz \(vibrations = (?P[\d\.]+)%" + ) + match_fitted = pattern_fitted.search(message) + + if match_fitted: + name = match_fitted.group("name") + freq = float(match_fitted.group("freq")) + vib = float(match_fitted.group("vib")) + current_data = self.is_types.get(name, {}) + current_data.update( + { + "frequency": freq, + "vibration": vib, + "max_accel": current_data.get("max_accel", 0.0), + } + ) + self.is_types[name] = current_data + + return + pattern_accel = re.compile( + r"To avoid too much smoothing with '(?P\w+)', suggested max_accel <= (?P[\d\.]+) mm/sec\^2" + ) + match_accel = pattern_accel.search(message) + + if match_accel: + name = match_accel.group("name") + accel = float(match_accel.group("accel")) + + if name in self.is_types and isinstance(self.is_types[name], dict): + self.is_types[name]["max_accel"] = accel + else: + self.is_types[name] = self.is_types.get(name, {}) + self.is_types[name]["max_accel"] = accel + return + + pattern_recommended = re.compile( + r"Recommended shaper_type_(?P[xy]) = (?P\w+), shaper_freq_(?P=axis) = (?P[\d\.]+) Hz" + ) + match_recommended = pattern_recommended.search(message) + if match_recommended: + axis = match_recommended.group("axis") + recommended_type = match_recommended.group("type") + self.is_types["Axis"] = axis + if self.aut: + self.is_aut_types[axis] = recommended_type + if len(self.is_aut_types) == 2: + self.run_gcode_signal.emit("SAVE_CONFIG") + self._is_timeout_timer.stop() + self.call_load_panel.emit(False, "", False) + self.aut = False + return + return + + reordered = {} + if recommended_type in self.is_types: + reordered[recommended_type] = self.is_types[recommended_type] + for key, value in self.is_types.items(): + if key not in ("suggested_type", recommended_type, "Axis"): + reordered[key] = value + + self.set_type_dictionary(self.is_types) + first_key = next(iter(reordered.keys()), None) + for key in reordered: + if key == first_key: + self.add_type_entry(key, "Recommended type") + else: + self.add_type_entry(key) + + self.build_model_list() + self._is_timeout_timer.stop() + self.call_load_panel.emit(False, "", False) + return + + def set_type_dictionary(self, types: dict) -> None: + """Receives the dictionary of input shaper types from the utilities tab""" + self.type_dict = types + + def _on_is_timeout(self) -> None: + self.call_load_panel.emit(False, "", False) + + def handle_is(self, gcode: str) -> None: + if gcode == "SHAPER_CALIBRATE": + self.run_gcode_signal.emit("G28\nM400") + self.aut = True + self.run_gcode_signal.emit(gcode) + elif gcode == "": + # Picking an axis needs the dialog, which logic-only mode never built. + if self.logic: + return + self.dialog_page.confirm_background_color("#dfdfdf") + self.dialog_page.cancel_background_color("#dfdfdf") + self.dialog_page.cancel_font_color("#000000") + self.dialog_page.confirm_font_color("#000000") + self.dialog_page.cancel_button_text("X axis") + self.dialog_page.confirm_button_text("Y axis") + self.dialog_page.set_message( + "Select the axis you want to execute the input shaper on:" + ) + self.dialog_page.show() + return + else: + self.run_gcode_signal.emit("G28\nM400") + self.run_gcode_signal.emit(gcode) + if not self.logic: + self.setCurrentIndex(self.indexOf(self.manual_is)) + + self._is_timeout_timer.start() + self.call_load_panel.emit(True, "Running Input Shaper...", False) def reset_view_model(self) -> None: """Clears items from ListView (Resets `QAbstractListModel` by clearing entries) """ + if self.logic: + return self.model.clear() self.entry_delegate.clear() @@ -72,6 +234,8 @@ def showEvent(self, a0: QtGui.QShowEvent | None) -> None: def build_model_list(self) -> None: """Builds the model list (`self.model`) containing updatable clients""" + if self.logic: + return self.update_buttons_list_widget.blockSignals(True) self.model.setData(self.model.index(0), True, EntryListModel.EnableRole) self.on_item_clicked( @@ -79,52 +243,56 @@ def build_model_list(self) -> None: ) self.update_buttons_list_widget.blockSignals(False) - def set_type_dictionary(self, dict) -> None: - """Receives the dictionary of input shaper types from the utilities tab""" - self.type_dict = dict - return - @QtCore.pyqtSlot(ListItem, name="on-item-clicked") def on_item_clicked(self, item: ListItem) -> None: """Setup information for the currently clicked list item on the info box. Keeps track of the list item """ - self.currentItem: ListItem = item + if self.logic: + return + self.currentItem = item if not item: return - current_info = self.type_dict.get(self.currentItem.text, {}) + current_info = self.type_dict.get(item.text, {}) if not current_info: return - _vib = current_info.get("vibration") - self.vib_label.setText(f"{float(_vib):.0f}%" if _vib is not None else "N/A%") - _accel = current_info.get("max_accel") + self.vib_label.setText(self._measurement(current_info.get("vibration"), "%")) self.sug_accel_label.setText( - f"{float(_accel):.0f}mm/s²" if _accel is not None else "N/Amm/s²" + self._measurement(current_info.get("max_accel"), "mm/s²") ) self.action_btn.show() + @staticmethod + def _measurement(value: object, unit: str) -> str: + if not isinstance(value, (int, float)) or isinstance(value, bool): + return "N/A" + return f"{value:.0f}{unit}" + def handle_ism_confirm(self) -> None: - """Apply the selected input shaper type to the printer and save the config.""" - if self.currentItem is None: + """Apply the selected shaper to the axis that was calibrated, and save.""" + if self.logic: return + axis = self.type_dict.get("Axis") + if self.currentItem is None or axis not in ("x", "y"): + return + current_info = self.type_dict.get(self.currentItem.text, {}) frequency = current_info.get("frequency", "N/A") - if self.type_dict.get("Axis") == "x": - self.run_gcode_signal.emit( - f"SET_INPUT_SHAPER SHAPER_TYPE_X={self.currentItem.text} SHAPER_FREQ_X={frequency}" - ) - elif self.type_dict.get("Axis") == "y": - self.run_gcode_signal.emit( - f"SET_INPUT_SHAPER SHAPER_TYPE_Y={self.currentItem.text} SHAPER_FREQ_Y={frequency}" - ) + self.run_gcode_signal.emit( + f"SET_INPUT_SHAPER SHAPER_TYPE_{axis.upper()}={self.currentItem.text} " + f"SHAPER_FREQ_{axis.upper()}={frequency}" + ) self.run_gcode_signal.emit("SAVE_CONFIG") self.reset_view_model() + self.setCurrentIndex(self.indexOf(self.is_page)) def add_type_entry(self, cli_name: str, recommended: str = "") -> None: """Adds a new item to the list model""" + if self.logic: + return item = ListItem( text=cli_name, right_text=recommended, @@ -140,176 +308,122 @@ def add_type_entry(self, cli_name: str, recommended: str = "") -> None: def _setup_ui(self) -> None: """Setup UI for updatePage""" - font_id = QtGui.QFontDatabase.addApplicationFont( - ":/font/media/fonts for text/Momcake-Bold.ttf" - ) - _families = QtGui.QFontDatabase.applicationFontFamilies(font_id) - font_family = _families[0] if _families else "" sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) + self.setSizePolicy(sizePolicy) self.setMinimumSize(QtCore.QSize(710, 400)) self.setMaximumSize(QtCore.QSize(720, 420)) + + self.is_page = QtWidgets.QWidget() + self.is_page.setObjectName("is_page") + self.verticalLayout_13 = QtWidgets.QVBoxLayout(self.is_page) + self.verticalLayout_13.setObjectName("verticalLayout_13") + + spacerItem14 = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.verticalLayout_13.addItem(spacerItem14) + self.is_header_layout = QtWidgets.QHBoxLayout() + self.is_header_layout.setObjectName("is_header_layout") + spacerItem15 = QtWidgets.QSpacerItem( + 60, + 0, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.is_header_layout.addItem(spacerItem15) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + + self.is_header_title = QtWidgets.QLabel(parent=self.is_page) + self.is_header_title.setSizePolicy(sizePolicy) + self.is_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + self.is_header_title.setFont(font) + self.is_header_title.setStyleSheet("background: transparent; color: white;") + self.is_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.is_header_layout.addWidget(self.is_header_title) + + self.is_back_btn = IconButton(parent=self.is_page) + self.is_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.is_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.is_back_btn.setStyleSheet("") + self.is_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.is_header_layout.addWidget(self.is_back_btn) + + self.verticalLayout_13.addLayout(self.is_header_layout) + + self.is_content_layout = QtWidgets.QHBoxLayout() + self.is_content_layout.setObjectName("is_content_layout") + self.verticalLayout_13.addLayout(self.is_content_layout) + + self.addWidget(self.is_page) + + self.is_header_title.setText("Input Shaper") + self.is_back_btn.setText("Back") + + # MANUAL INPUT SHAPPER PAGE DOWN HERE DONT TOUCH . thx :D + + self.manual_is = QtWidgets.QWidget(self) + self.manual_is.setSizePolicy(sizePolicy) + self.manual_is.setMinimumSize(QtCore.QSize(710, 400)) + self.manual_is.setMaximumSize(QtCore.QSize(720, 420)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.update_page_content_layout = QtWidgets.QVBoxLayout() + self.update_page_content_layout = QtWidgets.QVBoxLayout(self.manual_is) self.update_page_content_layout.setContentsMargins(15, 15, 2, 2) - self.header_content_layout = QtWidgets.QHBoxLayout() + self.header_content_layout = QtWidgets.QHBoxLayout(self.manual_is) self.header_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) - self.spacer_left = QtWidgets.QLabel(self) + self.spacer_left = QtWidgets.QLabel(self.manual_is) self.spacer_left.setMinimumSize(QtCore.QSize(60, 60)) self.spacer_left.setMaximumSize(QtCore.QSize(60, 60)) self.header_content_layout.addWidget(self.spacer_left, 0) - self.header_title = QtWidgets.QLabel(self) - self.header_title.setMinimumSize(QtCore.QSize(100, 60)) - self.header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() - font.setFamily(font_family) font.setPointSize(24) - palette = self.header_title.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) + + self.header_title = QtWidgets.QLabel(self.manual_is) + self.header_title.setMinimumSize(QtCore.QSize(100, 60)) + self.header_title.setMaximumSize(QtCore.QSize(16777215, 60)) self.header_title.setFont(font) - self.header_title.setPalette(palette) - self.header_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) self.header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.header_title.setObjectName("header-title") + self.header_title.setStyleSheet("color:white") self.header_title.setText("Input Shaper") self.header_content_layout.addWidget(self.header_title, 0) - self.update_back_btn = IconButton(self) + + self.update_back_btn = IconButton(self.manual_is) self.update_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.update_back_btn.setMaximumSize(QtCore.QSize(60, 60)) self.update_back_btn.setFlat(True) self.update_back_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.header_content_layout.addWidget(self.update_back_btn, 0) self.update_page_content_layout.addLayout(self.header_content_layout, 0) - self.main_content_layout = QtWidgets.QHBoxLayout() + self.main_content_layout = QtWidgets.QHBoxLayout(self.manual_is) self.main_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.update_buttons_frame = BlocksCustomFrame(self) - - self.update_buttons_frame.setMinimumSize(QtCore.QSize(300, 300)) - self.update_buttons_frame.setMaximumSize(QtCore.QSize(350, 500)) - - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Link, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Link, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Highlight, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Link, - brush, - ) + self.update_buttons_frame = BlocksCustomFrame(self.manual_is) + self.update_buttons_list_widget = QtWidgets.QListView(self.update_buttons_frame) self.update_buttons_list_widget.setMouseTracking(True) - self.update_buttons_list_widget.setTabletTracking(True) - - self.update_buttons_list_widget.setPalette(palette) self.update_buttons_list_widget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) self.update_buttons_list_widget.setStyleSheet("background-color:transparent") - self.update_buttons_list_widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.update_buttons_list_widget.setMinimumSize(self.update_buttons_frame.size()) self.update_buttons_list_widget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) self.update_buttons_list_widget.setVerticalScrollBarPolicy( @@ -347,99 +461,92 @@ def _setup_ui(self) -> None: self.update_buttons_list_widget, QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, ) - self.update_buttons_layout = QtWidgets.QVBoxLayout() - self.update_buttons_layout.setContentsMargins(15, 20, 20, 5) + + self.update_buttons_layout = QtWidgets.QVBoxLayout(self.manual_is) + # self.update_buttons_layout.setContentsMargins(15, 20, 20, 5) self.update_buttons_layout.addWidget(self.update_buttons_list_widget, 0) + self.update_buttons_frame.setLayout(self.update_buttons_layout) self.main_content_layout.addWidget(self.update_buttons_frame, 0) - self.infobox_frame = BlocksCustomFrame() - self.infobox_frame.setMinimumSize(QtCore.QSize(250, 300)) + self.infobox_frame = BlocksCustomFrame(self.manual_is) + self.infobox_frame.setMaximumWidth(250) self.info_box_layout = QtWidgets.QVBoxLayout() self.info_box_layout.setContentsMargins(10, 10, 10, 10) font = QtGui.QFont() - font.setFamily(font_family) font.setPointSize(20) - self.info_box = QtWidgets.QGridLayout() + + self.info_box = QtWidgets.QGridLayout(self.manual_is) self.info_box.setContentsMargins(0, 0, 0, 0) - self.vib_title_label = QtWidgets.QLabel(self) + font.setPointSize(12) + + self.vib_title_label = QtWidgets.QLabel(self.manual_is) self.vib_title_label.setText("Vibrations: ") self.vib_title_label.setMinimumSize(QtCore.QSize(60, 60)) self.vib_title_label.setMaximumSize( QtCore.QSize(int(self.infobox_frame.size().width() * 0.40), 9999) ) - palette = self.vib_title_label.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) + self.vib_title_label.setStyleSheet("color:white") self.vib_title_label.setAlignment( QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter ) self.vib_title_label.setFont(font) - self.vib_title_label.setPalette(palette) self.vib_title_label.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.vib_label = QtWidgets.QLabel(self) + + self.vib_label = QtWidgets.QLabel(self.manual_is) self.vib_label.setMinimumSize(QtCore.QSize(100, 60)) - self.vib_label.setMaximumSize(QtCore.QSize(16777215, 9999)) - palette = self.vib_label.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) self.vib_label.setFont(font) - self.vib_label.setPalette(palette) + self.vib_label.setStyleSheet("color:white") + self.vib_label.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) self.vib_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.vib_label.setObjectName("version-tracking") self.info_box.addWidget(self.vib_title_label, 0, 0) self.info_box.addWidget(self.vib_label, 0, 1) - self.sug_accel_title_label = QtWidgets.QLabel(self) + self.sug_accel_title_label = QtWidgets.QLabel(self.manual_is) self.sug_accel_title_label.setText("Sugested Max\nAcceleration:") self.sug_accel_title_label.setMinimumSize(QtCore.QSize(60, 60)) self.sug_accel_title_label.setMaximumSize( QtCore.QSize(int(self.infobox_frame.size().width() * 0.40), 9999) ) - palette = self.sug_accel_title_label.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) self.sug_accel_title_label.setAlignment( QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter ) self.sug_accel_title_label.setFont(font) - self.sug_accel_title_label.setPalette(palette) - self.sug_accel_title_label.setLayoutDirection( - QtCore.Qt.LayoutDirection.RightToLeft - ) + self.sug_accel_title_label.setStyleSheet("color:white") - self.sug_accel_label = QtWidgets.QLabel(self) + self.sug_accel_label = QtWidgets.QLabel(self.manual_is) self.sug_accel_label.setMinimumSize(QtCore.QSize(100, 60)) self.sug_accel_label.setMaximumSize( QtCore.QSize(int(self.infobox_frame.size().width() * 0.60), 9999) ) - palette = self.sug_accel_label.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) + self.sug_accel_label.setStyleSheet("color:white") + self.sug_accel_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.sug_accel_label.setFont(font) - self.sug_accel_label.setPalette(palette) self.info_box.addWidget(self.sug_accel_title_label, 1, 0) self.info_box.addWidget(self.sug_accel_label, 1, 1) self.info_box_layout.addLayout(self.info_box, 1) - self.button_box = QtWidgets.QVBoxLayout() + self.button_box = QtWidgets.QVBoxLayout(self.manual_is) self.button_box.setContentsMargins(0, 0, 0, 0) self.button_box.addSpacing(-1) - self.action_btn = BlocksCustomButton() + self.action_btn = BlocksCustomButton(self.manual_is) self.action_btn.setMinimumSize(QtCore.QSize(200, 60)) self.action_btn.setMaximumSize(QtCore.QSize(250, 60)) - font.setPointSize(20) self.action_btn.setFont(font) - self.action_btn.setPalette(palette) self.action_btn.setSizePolicy(sizePolicy) self.action_btn.setText("Confirm") self.action_btn.setPixmap(QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) + self.action_btn.hide() self.button_box.addWidget( self.action_btn, 0, @@ -452,5 +559,8 @@ def _setup_ui(self) -> None: ) self.infobox_frame.setLayout(self.info_box_layout) self.main_content_layout.addWidget(self.infobox_frame, 1) + self.update_page_content_layout.addLayout(self.main_content_layout, 1) self.setLayout(self.update_page_content_layout) + + self.addWidget(self.manual_is) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py new file mode 100644 index 000000000..08a800209 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py @@ -0,0 +1,364 @@ +import typing +from dataclasses import dataclass +from functools import partial + +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_slider import BlocksSlider +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +@dataclass +class LedState: + """Represents the state of an LED light.""" + + led_type: str + red: int = 0 + green: int = 0 + blue: int = 0 + white: int = 255 + state: bool = True + + def get_gcode(self, name: str) -> str: + """Generates the G-code command for the current state.""" + if not self.state: + return f"SET_LED LED={name} RED=0 GREEN=0 BLUE=0 WHITE=0" + if self.led_type == "white": + return f"SET_LED LED={name} WHITE={self.white / 255:.2f}" + return ( + f"SET_LED LED={name} RED={self.red / 255:.2f} " + f"GREEN={self.green / 255:.2f} BLUE={self.blue / 255:.2f} " + f"WHITE={self.white / 255:.2f}" + ) + + +class LedsPage(QtWidgets.QStackedWidget): + """Leds page of the utilities tab.""" + + _LED_TYPES: frozenset[str] = frozenset({"led", "neopixel", "dotstar"}) + + request_back_button = QtCore.pyqtSignal(name="request-back-button") + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + + self.singleled: bool = False + self.leds: dict[str, LedState] = {} + self.current_led: str | None = None + + self._led_pixmap = QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") + + self._setup_ui() + self.leds_back_btn.clicked.connect(self.request_back_button.emit) + + self.leds_w_slider.sliderReleased.connect(self.update_led_values) + self.leds_slider_back_btn.clicked.connect(self._slider_back) + self.leds_on_btn.clicked.connect(partial(self.set_led_state, True)) + self.leds_off_btn.clicked.connect(partial(self.set_led_state, False)) + + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: + if self.singleled and self.leds: + self.handle_led_button(next(iter(self.leds))) + else: + self.setCurrentIndex(self.indexOf(self.main_page)) + + return super().showEvent(a0) + + def _slider_back(self) -> None: + if self.singleled: + self.request_back_button.emit() + else: + self.setCurrentIndex(self.indexOf(self.main_page)) + + def update_led_values(self) -> None: + """Update led state and color values""" + led_state: LedState = self.leds[str(self.current_led)] + led_state.white = int(self.leds_w_slider.value() * 255 / 100) + self.save_led_state() + + def on_object_list(self, config_file) -> bool: + layout = self.leds_content_layout + cg = config_file + + while layout.count(): + if (child := layout.takeAt(0)) and child.widget(): + child.widget().deleteLater() # type: ignore + + led_names = [] + self.leds.clear() + + for obj in cg: + parts = obj.split() + if len(parts) >= 2 and parts[0] in self._LED_TYPES: + name = parts[1] + led_names.append(name) + self.leds[name] = LedState(led_type="white") + + max_columns = 3 + self.singleled = len(led_names) == 1 + + for i, name in enumerate(led_names): + button = BlocksCustomButton() + button.setFixedSize(250, 80) + button.setText(name) + button.setProperty("class", "menu_btn") + button.setPixmap(self._led_pixmap) + row, col = divmod(i, max_columns) + layout.addWidget(button, row, col, QtCore.Qt.AlignmentFlag.AlignCenter) + button.clicked.connect(partial(self.handle_led_button, name)) + + return True + + def handle_led_button(self, name: str): + self.current_led = name + led_state = self.leds.get(name) + if not led_state: + return + is_rgb = led_state.led_type == "rgb" + self.leds_w_slider.setVisible(not is_rgb) + self.leds_w_slider.setValue(round(led_state.white * 100 / 255)) + self._sync_state_buttons(led_state.state) + self.leds_slider_tittle_label.setText(name.replace("_", " ")) + self.setCurrentIndex(self.indexOf(self.leds_slider_page)) + + def set_led_state(self, state: bool) -> None: + """Turn the current led on or off""" + led_state = self.leds.get(str(self.current_led)) + if not led_state or led_state.state == state: + return + led_state.state = state + self._sync_state_buttons(state) + self.save_led_state() + + def _sync_state_buttons(self, state: bool) -> None: + # Whichever button matches the state the led is already in has nothing + # left to do, so it is the one that greys out. + self.leds_on_btn.setEnabled(not state) + self.leds_off_btn.setEnabled(state) + + def save_led_state(self): + """Save led state""" + if self.current_led and self.current_led in self.leds: + led_state: LedState = self.leds[self.current_led] + self.run_gcode_signal.emit(led_state.get_gcode(self.current_led)) + + def _setup_ui(self) -> None: + self.setObjectName("leds_page") + + self.main_page = QtWidgets.QWidget() + self.main_page.setObjectName("leds_main_page") + spacerItem3 = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + spacerItem2 = QtWidgets.QSpacerItem( + 20, + 24, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + spacerItem4 = QtWidgets.QSpacerItem( + 20, + 40, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + spacerItem5 = QtWidgets.QSpacerItem( + 20, + 40, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.main_page) + self.verticalLayout_4.addItem(spacerItem2) + + self.leds_header_layout = QtWidgets.QHBoxLayout() + self.leds_header_layout.setContentsMargins(0, 0, 0, 0) + self.leds_header_layout.setObjectName("leds_header_layout") + self.leds_header_layout.addItem(spacerItem3) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + self.leds_title_label = QtWidgets.QLabel(parent=self.main_page) + self.leds_title_label.setSizePolicy(sizePolicy) + self.leds_title_label.setFont(font) + self.leds_title_label.setStyleSheet("background: transparent; color: white;") + self.leds_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.leds_title_label.setFixedHeight(60) + self.leds_header_layout.addWidget(self.leds_title_label) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + + self.leds_back_btn = IconButton(parent=self.main_page) + self.leds_back_btn.setSizePolicy(sizePolicy) + self.leds_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.leds_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.leds_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.leds_header_layout.addWidget(self.leds_back_btn) + + self.verticalLayout_4.addLayout(self.leds_header_layout) + self.verticalLayout_4.addItem(spacerItem4) + + self.leds_content_layout = QtWidgets.QGridLayout() + self.leds_content_layout.setObjectName("leds_content_layout") + + self.verticalLayout_4.addLayout(self.leds_content_layout) + self.verticalLayout_4.addItem(spacerItem5) + + self.addWidget(self.main_page) + + # --- LED slider page ------------------------------------------------- + + self.leds_slider_page = QtWidgets.QWidget() + self.leds_slider_page.setObjectName("leds_slider_page") + + self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.leds_slider_page) + self.verticalLayout_12.setObjectName("verticalLayout_12") + self.verticalLayout_12.setContentsMargins(10, 30, 9, 9) + self.verticalLayout_12.setSpacing(0) + + self.leds_slider_header_layout = QtWidgets.QHBoxLayout() + self.leds_slider_header_layout.setObjectName("leds_slider_header_layout") + self.leds_slider_header_layout.setContentsMargins(0, 10, 0, 11) + self.leds_slider_header_layout.setSpacing(6) + self.leds_slider_header_layout.addItem( + QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Minimum, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + ) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Preferred, + ) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + self.leds_slider_tittle_label = QtWidgets.QLabel(parent=self.leds_slider_page) + self.leds_slider_tittle_label.setSizePolicy(sizePolicy) + self.leds_slider_tittle_label.setMinimumSize(QtCore.QSize(0, 60)) + self.leds_slider_tittle_label.setMaximumSize(QtCore.QSize(16777215, 60)) + self.leds_slider_tittle_label.setFont(font) + self.leds_slider_tittle_label.setStyleSheet( + "background: transparent; color: white;" + ) + self.leds_slider_tittle_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.leds_slider_tittle_label.setObjectName("leds_slider_tittle_label") + self.leds_slider_header_layout.addWidget(self.leds_slider_tittle_label) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + QtWidgets.QSizePolicy.Policy.MinimumExpanding, + ) + + self.leds_slider_back_btn = IconButton(parent=self.leds_slider_page) + self.leds_slider_back_btn.setSizePolicy(sizePolicy) + self.leds_slider_back_btn.setMinimumSize(QtCore.QSize(60, 60)) + self.leds_slider_back_btn.setMaximumSize(QtCore.QSize(60, 60)) + self.leds_slider_back_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") + ) + self.leds_slider_back_btn.setObjectName("leds_slider_back_btn") + self.leds_slider_header_layout.addWidget(self.leds_slider_back_btn) + + self.verticalLayout_12.addLayout(self.leds_slider_header_layout) + + self.verticalLayout_12.addSpacing(50) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed + ) + + self.leds_slider_content_layout = QtWidgets.QVBoxLayout() + self.leds_slider_content_layout.setObjectName("leds_slider_content_layout") + self.leds_slider_content_layout.setContentsMargins(0, 5, 0, 30) + + self.leds_w_slider = BlocksSlider(parent=self.leds_slider_page) + self.leds_w_slider.setSizePolicy(sizePolicy) + self.leds_w_slider.setMinimumSize(QtCore.QSize(600, 90)) + self.leds_w_slider.setMaximumSize(QtCore.QSize(600, 90)) + self.leds_w_slider.setMaximum(100) + self.leds_w_slider.setProperty("value", 100) + self.leds_w_slider.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.leds_slider_content_layout.addWidget( + self.leds_w_slider, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + + self.verticalLayout_12.addLayout(self.leds_slider_content_layout) + self.verticalLayout_12.addSpacing(20) + + # The on/off pair that replaced the toggle. Only one of them is ever + # enabled -- see _sync_state_buttons. + self.leds_buttons_layout = QtWidgets.QHBoxLayout() + self.leds_buttons_layout.setObjectName("leds_buttons_layout") + self.leds_buttons_layout.setContentsMargins(0, 0, 0, 0) + self.leds_buttons_layout.setSpacing(50) + self.leds_buttons_layout.addStretch(1) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + + self.leds_on_btn = BlocksCustomButton(parent=self.leds_slider_page) + self.leds_on_btn.setFixedSize(QtCore.QSize(250, 80)) + self.leds_on_btn.setFont(font) + self.leds_on_btn.setProperty("class", "menu_btn") + self.leds_on_btn.setPixmap(self._led_pixmap) + self.leds_on_btn.setObjectName("leds_on_btn") + self.leds_on_btn.setText("ON") + self.leds_buttons_layout.addWidget(self.leds_on_btn) + + self.leds_off_btn = BlocksCustomButton(parent=self.leds_slider_page) + self.leds_off_btn.setFixedSize(QtCore.QSize(250, 80)) + self.leds_off_btn.setFont(font) + self.leds_off_btn.setProperty("class", "menu_btn") + self.leds_off_btn.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/LEDs_off.svg")) + self.leds_off_btn.setObjectName("leds_off_btn") + self.leds_off_btn.setText("OFF") + self.leds_buttons_layout.addWidget(self.leds_off_btn) + + self.leds_buttons_layout.addStretch(1) + + # LedState defaults to on, and so does the pair until a led is opened. + self._sync_state_buttons(True) + + self.verticalLayout_12.addLayout(self.leds_buttons_layout) + self.verticalLayout_12.addStretch(1) + + self.addWidget(self.leds_slider_page) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) + + _translate = QtCore.QCoreApplication.translate + + self.leds_title_label.setText(_translate("self", "LED's")) + self.leds_back_btn.setText(_translate("self", "Back")) + self.leds_slider_back_btn.setText(_translate("self", "Back")) + self.leds_slider_tittle_label.setText(_translate("self", "LED's")) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py new file mode 100644 index 000000000..a3b816827 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py @@ -0,0 +1,494 @@ +import math +import typing +from dataclasses import dataclass, replace + +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.icon_button import IconButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class RoutineCheckPage(QtWidgets.QWidget): + """Routine check page of the utilities tab.""" + + request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="request-back" + ) + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + call_load_panel: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, str, bool, name="call-load-panel" + ) + request_tb_page: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="request-tb-page" + ) + subscribe_config: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + [list, "PyQt_PyObject"], + [str, "PyQt_PyObject"], + name="on-subscribe-config", + ) + + HOMED_AXES = frozenset("xyz") + + @dataclass(frozen=True) + class Step: + label: str + prompt: str + gcode: str + cleanup: str = "" + + @dataclass(frozen=True) + class AxisLimits: + """Travel range of one stepper, as reported by the printer config.""" + + min: float + max: float + homes_at_min: bool + + @property + def span(self) -> float: + """How far the axis can travel end to end.""" + return self.max - self.min + + def __init__( + self, + parent: typing.Optional["QtWidgets.QWidget"], + ) -> None: + super().__init__(parent) + self._setup_ui() + + self.fans: list[str] = [] + self.axis_limits: dict[str, RoutineCheckPage.AxisLimits] = {} + + self._steps: list[RoutineCheckPage.Step] = [] + self._index: int = -1 + self._awaiting: bool = False + + self._homing: bool = False + self._home_dropped: bool = False + self._pending: RoutineCheckPage.Step | None = None + + self._home_settle: QtCore.QTimer = QtCore.QTimer(self) + self._home_settle.setSingleShot(True) + self._home_settle.setInterval(10_000) + self._home_settle.timeout.connect(self._home_finished) + + self._home_guard: QtCore.QTimer = QtCore.QTimer(self) + self._home_guard.setSingleShot(True) + self._home_guard.setInterval(180_000) + self._home_guard.timeout.connect(self._home_finished) + + self.answerPopup: BasePopup = BasePopup(self) + self.answerPopup.accepted.connect(lambda: self.on_answer(True)) + self.answerPopup.rejected.connect(lambda: self.on_answer(False)) + + self.rp_button_1.clicked.connect(self.start_fan) + self.rp_button_2.clicked.connect(self.start_axis) + self.rp_button_3.clicked.connect(self.start_extruder) + self.rp_button_4.clicked.connect(self.start_bed) + self.back_button.clicked.connect(self.abort) + self.back_button.clicked.connect(self.request_back) + + def on_object_list(self, object_list: list): + """Collect the fans this printer reports, dropping any earlier list.""" + self.fans = [] + for obj in object_list: + base_name = obj.split()[0] + + if base_name == "fan_generic" or base_name == "fan": + self.fans.append(obj.removeprefix(base_name + " ")) + + @QtCore.pyqtSlot(dict, name="on_object_config") + @QtCore.pyqtSlot(list, name="on_object_config") + def on_object_config(self, config: dict | list) -> None: + """Handle receiving printer object configurations""" + if not config: + return + self.axis_limits.update(self.parse_axis_limits(config)) + + def on_printer_config_received(self, config: dict) -> None: + """Handle printer configuration""" + for axis in ("x", "y", "z"): + self.subscribe_config[str, "PyQt_PyObject"].emit( + f"stepper_{axis}", self.on_object_config + ) + + @QtCore.pyqtSlot(str, str, name="on_toolhead_update") + def on_toolhead_update(self, field: str, value: str) -> None: + """Watch homed_axes so the homing screen knows when to come down.""" + if field != "homed_axes" or not self._homing: + return + + if not self.HOMED_AXES <= set(str(value).lower()): + self._home_dropped = True + return + + if self._home_dropped and not self._home_settle.isActive(): + self._home_settle.start() + + def start_fan(self) -> None: + """Check every fan this printer reports, one at a time.""" + self.start_routine(self.fan_steps(self.fans)) + + def start_axis(self) -> None: + """Home, then move each axis out and back so the user can watch it.""" + self.start_routine(self.axis_steps(self.axis_limits)) + + def start_extruder(self) -> None: + """Check the extruder heater.""" + self.start_routine(self.heater_steps(["extruder"])) + + def start_bed(self) -> None: + """Check the bed heater.""" + self.start_routine(self.heater_steps(["heater_bed"])) + + def start_routine(self, steps: list[Step]) -> None: + """Begin a routine, asking about each step in turn.""" + self.abort() + self._steps = steps + self._index = -1 + self.next_step() + + def next_step(self) -> None: + """Advance to the next step, or finish when they have all been checked.""" + self._index += 1 + if self._index >= len(self._steps): + self._reset() + return + self._awaiting = True + step = self._steps[self._index] + self.send_gcode(step.gcode) + if self._homing: + self._pending = step + else: + self._ask(step) + + def on_answer(self, ok: bool) -> None: + """Continue to the next step, or hand over to troubleshoot on a no.""" + if not self._awaiting: + return + self._awaiting = False + cleanup = self._steps[self._index].cleanup + if cleanup: + self.send_gcode(cleanup) + if ok: + self.next_step() + return + self._reset() + self.request_tb_page.emit() + + def abort(self) -> None: + """Cancel a running routine and undo anything it left running.""" + if not self._steps: + return + self.answerPopup.hide() + + seen: set[str] = set() + for step in self._steps: + if step.cleanup and step.cleanup not in seen: + seen.add(step.cleanup) + self.send_gcode(step.cleanup) + + self._reset() + + def _reset(self) -> None: + self._steps = [] + self._index = -1 + self._awaiting = False + self._pending = None + + def send_gcode(self, gcode: str) -> None: + """Run a g-code block, raising the homing screen if it homes.""" + if "G28" in gcode: + self._await_home() + self.run_gcode_signal.emit(gcode) + + def _await_home(self) -> None: + self._homing = True + self._home_dropped = False + self._home_settle.stop() + self._home_guard.start() + self.answerPopup.hide() + self.call_load_panel.emit(True, "Homing...\nPlease wait", False) + + def _home_finished(self) -> None: + self._home_settle.stop() + self._home_guard.stop() + self._homing = False + self._home_dropped = False + self.call_load_panel.emit(False, "", False) + + step, self._pending = self._pending, None + if step is not None: + self._ask(step) + + def _ask(self, step: Step) -> None: + self.answerPopup.set_message(step.prompt) + self.answerPopup.show() + + @classmethod + def fan_steps(cls, fans: list[str]) -> list[Step]: + steps = [] + for fan in fans: + if fan == "fan": + label = "part cooling fan" + on, off = "M106 S255", "M107" + else: + label = fan + on = f"SET_FAN_SPEED FAN={fan} SPEED=0.8" + off = f"SET_FAN_SPEED FAN={fan} SPEED=0" + steps.append( + cls.Step( + label=label, + prompt=f"Please check if the {label} is spinning.", + gcode=f"{on}\nM400", + cleanup=off, + ) + ) + return steps + + @classmethod + def heater_steps(cls, heaters: list[str]) -> list[Step]: + """Build one check step per heater, warming each to 60 degrees.""" + steps = [] + for heater in heaters: + label = "bed heater" if heater == "heater_bed" else heater + steps.append( + cls.Step( + label=label, + prompt=( + f"Please check if the {label} reaches 60ºC.\n" + "It may take a few moments." + ), + gcode=f"SET_HEATER_TEMPERATURE HEATER={heater} TARGET=60\nM400", + cleanup="TURN_OFF_HEATERS", + ) + ) + return steps + + @classmethod + def parse_axis_limits( + cls, + config: dict | list | None, + ) -> dict[str, AxisLimits]: + """Pull the travel range of every stepper out of a printer config reply.""" + if not config: + return {} + + limits = {} + for item in [config] if isinstance(config, dict) else config: + for key, value in item.items(): + if not key.startswith("stepper_") or not isinstance(value, dict): + continue + + pos_min = value.get("position_min") + pos_max = value.get("position_max") + if pos_min is None and pos_max is None: + continue + + low = float(pos_min) if pos_min is not None else -math.inf + high = float(pos_max) if pos_max is not None else math.inf + + endstop_raw = value.get("position_endstop") + endstop = float(endstop_raw) if endstop_raw is not None else 0.0 + homes_at_min = abs(endstop - low) <= abs(endstop - high) + + limits[key.removeprefix("stepper_")] = cls.AxisLimits( + min=low, max=high, homes_at_min=homes_at_min + ) + return limits + + @staticmethod + def axis_move_gcode( + axis: str, + limits: AxisLimits, + margin: float = 70.0, + park: float | None = None, + ) -> str: + """Move the axis most of the way out and back, in absolute coordinates.""" + span = limits.span + if not math.isfinite(span) or span <= 0: + return "" + + if span - (2 * margin) <= 0: + margin = span * 0.1 + + far = limits.max - margin if limits.homes_at_min else limits.min + margin + middle = (limits.min + limits.max) / 2 + + name = axis.upper() + moves = [ + "G90", + f"G1 {name}{far:.2f} F{6000}", + f"G1 {name}{middle:.2f} F{6000}", + ] + if park is not None: + parked = min(max(park, limits.min), limits.max) + if abs(parked - middle) >= 0.01: + moves.append(f"G1 {name}{parked:.2f} F{6000}") + + return "\n".join(moves) + + @classmethod + def axis_steps( + cls, + limits: dict[str, AxisLimits], + axes: typing.Sequence[str] = ("x", "y", "z"), + ) -> list[Step]: + """Build one check step per axis, homing once before the first of them.""" + y = limits.get("y") + park_x = ( + (y.min + y.max) / 2 if y is not None and math.isfinite(y.span) else None + ) + + steps = [] + for axis in ["x", "y", "z"]: + limit = limits.get(axis) + if limit is None: + continue + + moves = cls.axis_move_gcode( + axis, limit, park=park_x if axis == "x" else None + ) + if not moves: + continue + + prologue = "" if steps else "G28\nM400\n" + steps.append( + cls.Step( + label=f"{axis.upper()} axis", + prompt=f"Please ensure the {axis.upper()} axis moves correctly.", + gcode=f"{prologue}{moves}\nM400", + ) + ) + + if steps: + steps[-1] = replace(steps[-1], cleanup="G28") + return steps + + def _setup_ui(self) -> None: + + self.blank = QtWidgets.QWidget() + self.blank.setMinimumSize(QtCore.QSize(250, 80)) + self.blank.setMaximumSize(QtCore.QSize(250, 80)) + + self.Hblank = QtWidgets.QWidget() + self.Hblank.setMinimumSize(QtCore.QSize(60, 60)) + self.Hblank.setMaximumSize(QtCore.QSize(60, 60)) + + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setObjectName("verticalLayout") + + self.rp_header_layout = QtWidgets.QHBoxLayout() + self.rp_header_layout.setObjectName("rp_header_layout") + + self.rp_header_layout.addWidget(self.Hblank) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.rp_header_title = QtWidgets.QLabel(parent=self) + self.rp_header_title.setSizePolicy(sizePolicy) + self.rp_header_title.setMinimumSize(QtCore.QSize(0, 60)) + self.rp_header_title.setMaximumSize(QtCore.QSize(16777215, 60)) + self.rp_header_title.setFont(font) + self.rp_header_title.setStyleSheet("background: transparent; color: white;") + self.rp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.rp_header_layout.addWidget(self.rp_header_title) + + self.back_button = IconButton(parent=self) + self.back_button.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.back_button.setMinimumSize(QtCore.QSize(60, 60)) + self.back_button.setMaximumSize(QtCore.QSize(60, 60)) + self.rp_header_layout.addWidget(self.back_button) + + self.verticalLayout.addLayout(self.rp_header_layout) + + self.rp_content_layout = QtWidgets.QGridLayout() + self.rp_content_layout.setObjectName("rp_content_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + + self.rp_button_1 = BlocksCustomButton(parent=self) + self.rp_button_1.setSizePolicy(sizePolicy) + self.rp_button_1.setMinimumSize(QtCore.QSize(250, 80)) + self.rp_button_1.setMaximumSize(QtCore.QSize(250, 80)) + self.rp_button_1.setFont(font) + self.rp_button_1.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/fan_related/media/btn_icons/fan_cage.svg"), + ) + self.rp_content_layout.addWidget(self.rp_button_1, 0, 0, 1, 1) + + self.rp_button_2 = BlocksCustomButton(parent=self) + self.rp_button_2.setSizePolicy(sizePolicy) + self.rp_button_2.setMinimumSize(QtCore.QSize(250, 80)) + self.rp_button_2.setMaximumSize(QtCore.QSize(250, 80)) + self.rp_button_2.setFont(font) + self.rp_button_2.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), + ) + self.rp_content_layout.addWidget(self.rp_button_2, 0, 1, 1, 1) + + self.rp_button_3 = BlocksCustomButton(parent=self) + self.rp_button_3.setSizePolicy(sizePolicy) + self.rp_button_3.setMinimumSize(QtCore.QSize(250, 80)) + self.rp_button_3.setMaximumSize(QtCore.QSize(250, 80)) + self.rp_button_3.setFont(font) + self.rp_button_3.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg"), + ) + self.rp_content_layout.addWidget(self.rp_button_3, 1, 0, 1, 1) + + self.rp_button_4 = BlocksCustomButton(parent=self) + self.rp_button_4.setSizePolicy(sizePolicy) + self.rp_button_4.setMinimumSize(QtCore.QSize(250, 80)) + self.rp_button_4.setMaximumSize(QtCore.QSize(250, 80)) + self.rp_button_4.setFont(font) + self.rp_button_4.setProperty( + "icon_pixmap", + QtGui.QPixmap( + ":/temperature_related/media/btn_icons/temperature_plate.svg" + ), + ) + self.rp_content_layout.addWidget(self.rp_button_4, 1, 1, 1, 1) + + self.rp_content_layout.addWidget(self.blank, 2, 0, 1, 1) + + self.rp_content_layout.setRowMinimumHeight(0, 80) + self.rp_content_layout.setRowMinimumHeight(1, 80) + self.rp_content_layout.setRowMinimumHeight(2, 80) + + content_widget = QtWidgets.QWidget(parent=self) + content_widget.setLayout(self.rp_content_layout) + content_widget.setSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + self.rp_content_layout.setContentsMargins(0, 0, 0, 0) + content_widget.setFixedHeight(80 * 3 + self.rp_content_layout.spacing() * 2) + + self.verticalLayout.addWidget(content_widget) + + _translate = QtCore.QCoreApplication.translate + self.setWindowTitle(_translate("controlStackedWidget", "StackedWidget")) + self.rp_header_title.setText( + _translate("controlStackedWidget", "Routine Check") + ) + + self.rp_button_1.setText(_translate("controlStackedWidget", "Fans")) + self.rp_button_2.setText(_translate("controlStackedWidget", "Axis")) + self.rp_button_3.setText(_translate("controlStackedWidget", "extruder")) + self.rp_button_4.setText(_translate("controlStackedWidget", "Bed Heater")) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py index 11e3c6135..944e24aa1 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/troubleshootPage.py @@ -45,85 +45,82 @@ def show(self) -> None: return super().show() def _setup_ui(self) -> None: + self.setObjectName("troubleshoot_page") + self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") - self.leds_slider_header_layout_2 = QtWidgets.QHBoxLayout() - self.leds_slider_header_layout_2.setObjectName("leds_slider_header_layout_2") spacerItem18 = QtWidgets.QSpacerItem( 60, 60, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum, ) - self.leds_slider_header_layout_2.addItem(spacerItem18) spacerItem19 = QtWidgets.QSpacerItem( 181, 60, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum, ) + + spacerItem20 = QtWidgets.QSpacerItem( + 0, + 60, + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + + self.leds_slider_header_layout_2 = QtWidgets.QHBoxLayout() + self.leds_slider_header_layout_2.setObjectName("leds_slider_header_layout_2") + + self.leds_slider_header_layout_2.addItem(spacerItem18) self.leds_slider_header_layout_2.addItem(spacerItem19) - self.tb_tittle_label = QtWidgets.QLabel("Troubleshoot", parent=self) - self.tb_tittle_label.setMinimumSize(QtCore.QSize(0, 60)) - self.tb_tittle_label.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() font.setFamily("Momcake") font.setPointSize(24) + + self.tb_tittle_label = QtWidgets.QLabel("Troubleshoot", parent=self) + self.tb_tittle_label.setMinimumSize(QtCore.QSize(0, 60)) + self.tb_tittle_label.setMaximumSize(QtCore.QSize(16777215, 60)) self.tb_tittle_label.setFont(font) self.tb_tittle_label.setStyleSheet("background: transparent; color: white;") self.tb_tittle_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.tb_tittle_label.setObjectName("tb_tittle_label") + self.leds_slider_header_layout_2.addWidget(self.tb_tittle_label) - spacerItem20 = QtWidgets.QSpacerItem( - 0, - 60, - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Minimum, - ) self.leds_slider_header_layout_2.addItem(spacerItem20) - self.tb_back_btn = IconButton(parent=self) + sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, ) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.tb_back_btn.sizePolicy().hasHeightForWidth()) + + self.tb_back_btn = IconButton(parent=self) self.tb_back_btn.setSizePolicy(sizePolicy) self.tb_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.tb_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.tb_back_btn.setFont(font) - self.tb_back_btn.setMouseTracking(False) - self.tb_back_btn.setTabletTracking(True) - self.tb_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.tb_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.tb_back_btn.setStyleSheet("") - self.tb_back_btn.setAutoDefault(False) - self.tb_back_btn.setFlat(True) self.tb_back_btn.setProperty( "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg") ) - self.tb_back_btn.setObjectName("tb_back_btn") + self.leds_slider_header_layout_2.addWidget(self.tb_back_btn) + self.verticalLayout.addLayout(self.leds_slider_header_layout_2) + self.horizontalLayout = QtWidgets.QHBoxLayout() self.horizontalLayout.setObjectName("horizontalLayout") + self.verticalLayout_10 = QtWidgets.QVBoxLayout() self.verticalLayout_10.setObjectName("verticalLayout_10") - self.label_4 = QtWidgets.QLabel("idk whar to type this", parent=self) + sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding, ) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4 = QtWidgets.QLabel( + "For more information check our website \n www.blockstec.com \n or \nsupport@blockstec.com", + parent=self, + ) self.label_4.setSizePolicy(sizePolicy) font = QtGui.QFont() font.setPointSize(24) diff --git a/BlocksScreen/lib/ui/utilitiesStackedWidget.ui b/BlocksScreen/lib/ui/utilitiesStackedWidget.ui deleted file mode 100644 index 3df1f8fc2..000000000 --- a/BlocksScreen/lib/ui/utilitiesStackedWidget.ui +++ /dev/null @@ -1,3072 +0,0 @@ - - - utilitiesStackedWidget - - - - 0 - 0 - 710 - 410 - - - - - 0 - 0 - - - - - 710 - 410 - - - - - 710 - 410 - - - - StackedWidget - - - 5 - - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - Momcake - 24 - true - - - - background: transparent; color: white; - - - Utilities - - - Qt::AlignCenter - - - title_text - - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Axis -Maint. - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/axis_maintenance.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - - - - Update - - - true - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Routine -Check - - - false - - - true - - - menu_btn - - - :/ui/media/btn_icons/routine.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Input -Shaper - - - false - - - true - - - menu_btn - - - :/input_shaper/media/btn_icons/input_shaper.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Info - - - false - - - true - - - menu_btn - - - :/ui/media/btn_icons/info.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - LED's - - - false - - - true - - - menu_btn - - - :/ui/media/btn_icons/LEDs.svg - - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 60 - - - - - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Info - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - - - - 350 - 260 - - - - - 350 - 290 - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - - 0 - 10 - 351 - 81 - - - - - 0 - 0 - - - - - 20 - - - - color:white - - - Model: Blocks RF50 - - - Qt::AlignCenter - - - - - - 0 - 110 - 351 - 81 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 20 - - - - color:white - - - www.blockstec.com - - - Qt::AlignCenter - - - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - LED's - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - Qt::Orientation::Vertical - - - - - - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - QLayout::SizeConstraint::SetMinimumSize - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Routine Check - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 60 - - - - - - - - 20 - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Bed Heater - - - false - - - true - - - menu_btn - - - :/temperature_related/media/btn_icons/temperature_plate.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Fans - - - false - - - true - - - menu_btn - - - :/fan_related/media/btn_icons/fan_cage.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Axis - - - false - - - true - - - menu_btn - - - :/motion/media/btn_icons/axis_maintenance.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Extruder - - - false - - - true - - - menu_btn - - - :/extruder_related/media/btn_icons/nozzle.svg - - - - - - - - - Qt::Orientation::Vertical - - - - 20 - 40 - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - label - - - Qt::AlignCenter - - - title_text - - - - - - - - - 0 - - - - - - 0 - 0 - - - - - 15 - - - - color:white - - - TextLabel - - - Qt::AlignCenter - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Yes - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/yes.svg - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 40 - 20 - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - No - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/no.svg - - - - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Axis Maintenance - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - - 0 - 0 - - - - - 650 - 0 - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - - - - 60 - 80 - - - - - 250 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 20 - - - - Y - - - true - - - true - - - true - - - true - - - axis_maintenance_gb - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Execute - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/yes.svg - - - - - - - - 60 - 80 - - - - - 250 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 20 - - - - Z - - - true - - - false - - - true - - - true - - - axis_maintenance_gb - - - - - - - - 250 - 80 - - - - - 250 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 20 - - - - X - - - true - - - false - - - true - - - true - - - axis_maintenance_gb - - - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 0 - - - - - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - Input Shaper - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 16777215 - 60 - - - - - 20 - - - - color:white - - - Input Shaper - - - Qt::AlignCenter - - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - MZV - - - true - - - false - - - true - - - menu_btn - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - EI - - - true - - - false - - - true - - - menu_btn - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - 3hump_ei - - - true - - - false - - - true - - - menu_btn - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - ZV - - - true - - - false - - - true - - - menu_btn - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - 2hump_ei - - - true - - - false - - - true - - - menu_btn - - - - - - - - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Cancel - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/no.svg - - - - - - - - 0 - 0 - - - - - 250 - 80 - - - - - 250 - 80 - - - - - Momcake - 19 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Confirm - - - false - - - true - - - menu_btn - - - :/dialog/media/btn_icons/yes.svg - - - - - - - - - - - - - Qt::Orientation::Vertical - - - QSizePolicy::Policy::Minimum - - - - 20 - 24 - - - - - - - - - - - 0 - 0 - - - - - 16777215 - 60 - - - - User Input - - - Qt::AlignCenter - - - - - - - - - - - - 0 - 0 - - - - QFrame::Shape::StyledPanel - - - QFrame::Shadow::Raised - - - - - - - - - - - - 70 - 120 - 100 - 50 - - - - - 100 - 50 - - - - - 100 - 16777215 - - - - PushButton - - - - - - 170 - 150 - 31 - 16 - - - - - Momcake - 11 - - - - color:white - - - On - - - Qt::AlignCenter - - - - - - 40 - 150 - 31 - 16 - - - - - Momcake - 11 - - - - color:white - - - Off - - - Qt::AlignCenter - - - - - - 10 - 30 - 691 - 81 - - - - - - - Qt::Orientation::Horizontal - - - QSizePolicy::Policy::Minimum - - - - 60 - 20 - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - - 16777215 - 60 - - - - - Momcake - 24 - - - - background: transparent; color: white; - - - LED's - - - Qt::AlignCenter - - - title_text - - - - - - - - 0 - 0 - - - - - 60 - 60 - - - - - 60 - 60 - - - - - Momcake - 20 - false - PreferAntialias - - - - false - - - true - - - Qt::ContextMenuPolicy::NoContextMenu - - - Qt::LayoutDirection::LeftToRight - - - - - - Back - - - false - - - true - - - menu_btn - - - icon - - - :/ui/media/btn_icons/back.svg - - - - - - - - - 10 - 200 - 688 - 101 - - - - - - - - 0 - 0 - - - - - 600 - 90 - - - - - 600 - 90 - - - - 100 - - - 100 - - - Qt::Orientation::Horizontal - - - - - - - - - - BlocksCustomButton - QPushButton -
lib.utils.blocks_button
-
- - IconButton - QPushButton -
lib.utils.icon_button
-
- - GroupButton - QPushButton -
lib.utils.group_button
-
- - BlocksSlider - QSlider -
lib.utils.blocks_slider
-
- - ToggleAnimatedButton - QPushButton -
lib.utils.toggleAnimatedButton
-
- - BlocksCustomFrame - QFrame -
lib.utils.blocks_frame
- 1 -
-
- - - - - - - - - - - - - - - - -
diff --git a/BlocksScreen/lib/ui/utilitiesStackedWidget_ui.py b/BlocksScreen/lib/ui/utilitiesStackedWidget_ui.py deleted file mode 100644 index 2874603ac..000000000 --- a/BlocksScreen/lib/ui/utilitiesStackedWidget_ui.py +++ /dev/null @@ -1,1282 +0,0 @@ -# Form implementation generated from reading ui file 'BlocksScreen/lib/ui/utilitiesStackedWidget.ui' -# -# Created by: PyQt6 UI code generator 6.7.1 -# -# WARNING: Any manual changes made to this file will be lost when pyuic6 is -# run again. Do not edit this file unless you know what you are doing. - - -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Ui_utilitiesStackedWidget(object): - def setupUi(self, utilitiesStackedWidget): - utilitiesStackedWidget.setObjectName("utilitiesStackedWidget") - utilitiesStackedWidget.resize(710, 410) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(utilitiesStackedWidget.sizePolicy().hasHeightForWidth()) - utilitiesStackedWidget.setSizePolicy(sizePolicy) - utilitiesStackedWidget.setMinimumSize(QtCore.QSize(710, 410)) - utilitiesStackedWidget.setMaximumSize(QtCore.QSize(710, 410)) - self.utilities_page = QtWidgets.QWidget() - self.utilities_page.setObjectName("utilities_page") - self.verticalLayout = QtWidgets.QVBoxLayout(self.utilities_page) - self.verticalLayout.setObjectName("verticalLayout") - self.utilities_header_layout = QtWidgets.QHBoxLayout() - self.utilities_header_layout.setObjectName("utilities_header_layout") - self.utilities_title_label = QtWidgets.QLabel(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_title_label.sizePolicy().hasHeightForWidth()) - self.utilities_title_label.setSizePolicy(sizePolicy) - self.utilities_title_label.setMinimumSize(QtCore.QSize(0, 60)) - self.utilities_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - font.setBold(True) - self.utilities_title_label.setFont(font) - self.utilities_title_label.setStyleSheet("background: transparent; color: white;") - self.utilities_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.utilities_title_label.setObjectName("utilities_title_label") - self.utilities_header_layout.addWidget(self.utilities_title_label) - self.verticalLayout.addLayout(self.utilities_header_layout) - self.utilities_content_layout = QtWidgets.QGridLayout() - self.utilities_content_layout.setObjectName("utilities_content_layout") - self.utilities_axes_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_axes_btn.sizePolicy().hasHeightForWidth()) - self.utilities_axes_btn.setSizePolicy(sizePolicy) - self.utilities_axes_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.utilities_axes_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.utilities_axes_btn.setFont(font) - self.utilities_axes_btn.setMouseTracking(False) - self.utilities_axes_btn.setTabletTracking(True) - self.utilities_axes_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.utilities_axes_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.utilities_axes_btn.setStyleSheet("") - self.utilities_axes_btn.setAutoDefault(False) - self.utilities_axes_btn.setFlat(True) - self.utilities_axes_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg")) - self.utilities_axes_btn.setObjectName("utilities_axes_btn") - self.utilities_content_layout.addWidget(self.utilities_axes_btn, 1, 1, 1, 1) - self.update_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.update_btn.sizePolicy().hasHeightForWidth()) - self.update_btn.setSizePolicy(sizePolicy) - self.update_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.update_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setBold(False) - self.update_btn.setFont(font) - self.update_btn.setFlat(True) - self.update_btn.setObjectName("update_btn") - self.utilities_content_layout.addWidget(self.update_btn, 2, 0, 1, 1) - self.utilities_routine_check_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_routine_check_btn.sizePolicy().hasHeightForWidth()) - self.utilities_routine_check_btn.setSizePolicy(sizePolicy) - self.utilities_routine_check_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.utilities_routine_check_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.utilities_routine_check_btn.setFont(font) - self.utilities_routine_check_btn.setMouseTracking(False) - self.utilities_routine_check_btn.setTabletTracking(True) - self.utilities_routine_check_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.utilities_routine_check_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.utilities_routine_check_btn.setStyleSheet("") - self.utilities_routine_check_btn.setAutoDefault(False) - self.utilities_routine_check_btn.setFlat(True) - self.utilities_routine_check_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg")) - self.utilities_routine_check_btn.setObjectName("utilities_routine_check_btn") - self.utilities_content_layout.addWidget(self.utilities_routine_check_btn, 1, 0, 1, 1) - self.utilities_input_shaper_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_input_shaper_btn.sizePolicy().hasHeightForWidth()) - self.utilities_input_shaper_btn.setSizePolicy(sizePolicy) - self.utilities_input_shaper_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.utilities_input_shaper_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.utilities_input_shaper_btn.setFont(font) - self.utilities_input_shaper_btn.setMouseTracking(False) - self.utilities_input_shaper_btn.setTabletTracking(True) - self.utilities_input_shaper_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.utilities_input_shaper_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.utilities_input_shaper_btn.setStyleSheet("") - self.utilities_input_shaper_btn.setAutoDefault(False) - self.utilities_input_shaper_btn.setFlat(True) - self.utilities_input_shaper_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg")) - self.utilities_input_shaper_btn.setObjectName("utilities_input_shaper_btn") - self.utilities_content_layout.addWidget(self.utilities_input_shaper_btn, 2, 1, 1, 1) - self.utilities_info_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_info_btn.sizePolicy().hasHeightForWidth()) - self.utilities_info_btn.setSizePolicy(sizePolicy) - self.utilities_info_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.utilities_info_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.utilities_info_btn.setFont(font) - self.utilities_info_btn.setMouseTracking(False) - self.utilities_info_btn.setTabletTracking(True) - self.utilities_info_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.utilities_info_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.utilities_info_btn.setStyleSheet("") - self.utilities_info_btn.setAutoDefault(False) - self.utilities_info_btn.setFlat(True) - self.utilities_info_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg")) - self.utilities_info_btn.setObjectName("utilities_info_btn") - self.utilities_content_layout.addWidget(self.utilities_info_btn, 0, 0, 1, 1) - self.utilities_leds_btn = BlocksCustomButton(parent=self.utilities_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.utilities_leds_btn.sizePolicy().hasHeightForWidth()) - self.utilities_leds_btn.setSizePolicy(sizePolicy) - self.utilities_leds_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.utilities_leds_btn.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.utilities_leds_btn.setFont(font) - self.utilities_leds_btn.setMouseTracking(False) - self.utilities_leds_btn.setTabletTracking(True) - self.utilities_leds_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.utilities_leds_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.utilities_leds_btn.setStyleSheet("") - self.utilities_leds_btn.setAutoDefault(False) - self.utilities_leds_btn.setFlat(True) - self.utilities_leds_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg")) - self.utilities_leds_btn.setObjectName("utilities_leds_btn") - self.utilities_content_layout.addWidget(self.utilities_leds_btn, 0, 1, 1, 1) - self.verticalLayout.addLayout(self.utilities_content_layout) - utilitiesStackedWidget.addWidget(self.utilities_page) - self.info_page = QtWidgets.QWidget() - self.info_page.setObjectName("info_page") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.info_page) - self.verticalLayout_2.setObjectName("verticalLayout_2") - spacerItem = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_2.addItem(spacerItem) - self.info_header_layout = QtWidgets.QHBoxLayout() - self.info_header_layout.setObjectName("info_header_layout") - spacerItem1 = QtWidgets.QSpacerItem(60, 60, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.info_header_layout.addItem(spacerItem1) - self.info_title_label = QtWidgets.QLabel(parent=self.info_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.info_title_label.sizePolicy().hasHeightForWidth()) - self.info_title_label.setSizePolicy(sizePolicy) - self.info_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.info_title_label.setFont(font) - self.info_title_label.setStyleSheet("background: transparent; color: white;") - self.info_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_title_label.setObjectName("info_title_label") - self.info_header_layout.addWidget(self.info_title_label) - self.info_back_btn = IconButton(parent=self.info_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.info_back_btn.sizePolicy().hasHeightForWidth()) - self.info_back_btn.setSizePolicy(sizePolicy) - self.info_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.info_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.info_back_btn.setFont(font) - self.info_back_btn.setMouseTracking(False) - self.info_back_btn.setTabletTracking(True) - self.info_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.info_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.info_back_btn.setStyleSheet("") - self.info_back_btn.setAutoDefault(False) - self.info_back_btn.setFlat(True) - self.info_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.info_back_btn.setObjectName("info_back_btn") - self.info_header_layout.addWidget(self.info_back_btn) - self.verticalLayout_2.addLayout(self.info_header_layout) - self.info_content_layout = QtWidgets.QVBoxLayout() - self.info_content_layout.setObjectName("info_content_layout") - self.frame = BlocksCustomFrame(parent=self.info_page) - self.frame.setMinimumSize(QtCore.QSize(350, 260)) - self.frame.setMaximumSize(QtCore.QSize(350, 290)) - self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.frame.setObjectName("frame") - self.kv_label = QtWidgets.QLabel(parent=self.frame) - self.kv_label.setGeometry(QtCore.QRect(0, 10, 351, 81)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.kv_label.sizePolicy().hasHeightForWidth()) - self.kv_label.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setPointSize(20) - self.kv_label.setFont(font) - self.kv_label.setStyleSheet("color:white") - self.kv_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.kv_label.setObjectName("kv_label") - self.smth_label = QtWidgets.QLabel(parent=self.frame) - self.smth_label.setGeometry(QtCore.QRect(0, 110, 351, 81)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.smth_label.sizePolicy().hasHeightForWidth()) - self.smth_label.setSizePolicy(sizePolicy) - self.smth_label.setMinimumSize(QtCore.QSize(0, 0)) - font = QtGui.QFont() - font.setPointSize(20) - self.smth_label.setFont(font) - self.smth_label.setStyleSheet("color:white") - self.smth_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.smth_label.setObjectName("smth_label") - self.info_content_layout.addWidget(self.frame, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.verticalLayout_2.addLayout(self.info_content_layout) - utilitiesStackedWidget.addWidget(self.info_page) - self.leds_page = QtWidgets.QWidget() - self.leds_page.setObjectName("leds_page") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.leds_page) - self.verticalLayout_4.setObjectName("verticalLayout_4") - spacerItem2 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_4.addItem(spacerItem2) - self.leds_header_layout = QtWidgets.QHBoxLayout() - self.leds_header_layout.setObjectName("leds_header_layout") - spacerItem3 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.leds_header_layout.addItem(spacerItem3) - self.leds_title_label = QtWidgets.QLabel(parent=self.leds_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.leds_title_label.sizePolicy().hasHeightForWidth()) - self.leds_title_label.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.leds_title_label.setFont(font) - self.leds_title_label.setStyleSheet("background: transparent; color: white;") - self.leds_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.leds_title_label.setObjectName("leds_title_label") - self.leds_header_layout.addWidget(self.leds_title_label) - self.leds_back_btn = IconButton(parent=self.leds_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.leds_back_btn.sizePolicy().hasHeightForWidth()) - self.leds_back_btn.setSizePolicy(sizePolicy) - self.leds_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.leds_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.leds_back_btn.setFont(font) - self.leds_back_btn.setMouseTracking(False) - self.leds_back_btn.setTabletTracking(True) - self.leds_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.leds_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.leds_back_btn.setStyleSheet("") - self.leds_back_btn.setAutoDefault(False) - self.leds_back_btn.setFlat(True) - self.leds_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.leds_back_btn.setObjectName("leds_back_btn") - self.leds_header_layout.addWidget(self.leds_back_btn) - self.verticalLayout_4.addLayout(self.leds_header_layout) - spacerItem4 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_4.addItem(spacerItem4) - self.verticalScrollBar = QtWidgets.QScrollBar(parent=self.leds_page) - self.verticalScrollBar.setOrientation(QtCore.Qt.Orientation.Vertical) - self.verticalScrollBar.setObjectName("verticalScrollBar") - self.verticalLayout_4.addWidget(self.verticalScrollBar) - self.leds_content_layout = QtWidgets.QGridLayout() - self.leds_content_layout.setObjectName("leds_content_layout") - self.leds_widget = QtWidgets.QWidget(parent=self.leds_page) - self.leds_widget.setObjectName("leds_widget") - self.leds_content_layout.addWidget(self.leds_widget, 0, 0, 1, 1) - self.verticalLayout_4.addLayout(self.leds_content_layout) - spacerItem5 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_4.addItem(spacerItem5) - utilitiesStackedWidget.addWidget(self.leds_page) - self.routines_page = QtWidgets.QWidget() - self.routines_page.setObjectName("routines_page") - self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.routines_page) - self.verticalLayout_5.setObjectName("verticalLayout_5") - spacerItem6 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_5.addItem(spacerItem6) - self.routines_header_layout = QtWidgets.QHBoxLayout() - self.routines_header_layout.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetMinimumSize) - self.routines_header_layout.setObjectName("routines_header_layout") - spacerItem7 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.routines_header_layout.addItem(spacerItem7) - self.routines_page_title = QtWidgets.QLabel(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.routines_page_title.sizePolicy().hasHeightForWidth()) - self.routines_page_title.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.routines_page_title.setFont(font) - self.routines_page_title.setStyleSheet("background: transparent; color: white;") - self.routines_page_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.routines_page_title.setObjectName("routines_page_title") - self.routines_header_layout.addWidget(self.routines_page_title) - self.routine_check_back_btn = IconButton(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.routine_check_back_btn.sizePolicy().hasHeightForWidth()) - self.routine_check_back_btn.setSizePolicy(sizePolicy) - self.routine_check_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.routine_check_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.routine_check_back_btn.setFont(font) - self.routine_check_back_btn.setMouseTracking(False) - self.routine_check_back_btn.setTabletTracking(True) - self.routine_check_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.routine_check_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.routine_check_back_btn.setStyleSheet("") - self.routine_check_back_btn.setAutoDefault(False) - self.routine_check_back_btn.setFlat(True) - self.routine_check_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.routine_check_back_btn.setObjectName("routine_check_back_btn") - self.routines_header_layout.addWidget(self.routine_check_back_btn) - self.verticalLayout_5.addLayout(self.routines_header_layout) - spacerItem8 = QtWidgets.QSpacerItem(20, 60, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_5.addItem(spacerItem8) - self.routines_content_layout = QtWidgets.QGridLayout() - self.routines_content_layout.setVerticalSpacing(20) - self.routines_content_layout.setObjectName("routines_content_layout") - self.rc_bheat = BlocksCustomButton(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_bheat.sizePolicy().hasHeightForWidth()) - self.rc_bheat.setSizePolicy(sizePolicy) - self.rc_bheat.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_bheat.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_bheat.setFont(font) - self.rc_bheat.setMouseTracking(False) - self.rc_bheat.setTabletTracking(True) - self.rc_bheat.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_bheat.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_bheat.setStyleSheet("") - self.rc_bheat.setAutoDefault(False) - self.rc_bheat.setFlat(True) - self.rc_bheat.setProperty("icon_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature_plate.svg")) - self.rc_bheat.setObjectName("rc_bheat") - self.routines_content_layout.addWidget(self.rc_bheat, 0, 1, 1, 1) - self.rc_fans = BlocksCustomButton(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_fans.sizePolicy().hasHeightForWidth()) - self.rc_fans.setSizePolicy(sizePolicy) - self.rc_fans.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_fans.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_fans.setFont(font) - self.rc_fans.setMouseTracking(False) - self.rc_fans.setTabletTracking(True) - self.rc_fans.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_fans.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_fans.setStyleSheet("") - self.rc_fans.setAutoDefault(False) - self.rc_fans.setFlat(True) - self.rc_fans.setProperty("icon_pixmap", QtGui.QPixmap(":/fan_related/media/btn_icons/fan_cage.svg")) - self.rc_fans.setObjectName("rc_fans") - self.routines_content_layout.addWidget(self.rc_fans, 0, 0, 1, 1) - self.rc_axis = BlocksCustomButton(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_axis.sizePolicy().hasHeightForWidth()) - self.rc_axis.setSizePolicy(sizePolicy) - self.rc_axis.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_axis.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_axis.setFont(font) - self.rc_axis.setMouseTracking(False) - self.rc_axis.setTabletTracking(True) - self.rc_axis.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_axis.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_axis.setStyleSheet("") - self.rc_axis.setAutoDefault(False) - self.rc_axis.setFlat(True) - self.rc_axis.setProperty("icon_pixmap", QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg")) - self.rc_axis.setObjectName("rc_axis") - self.routines_content_layout.addWidget(self.rc_axis, 1, 1, 1, 1) - self.rc_ext = BlocksCustomButton(parent=self.routines_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_ext.sizePolicy().hasHeightForWidth()) - self.rc_ext.setSizePolicy(sizePolicy) - self.rc_ext.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_ext.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_ext.setFont(font) - self.rc_ext.setMouseTracking(False) - self.rc_ext.setTabletTracking(True) - self.rc_ext.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_ext.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_ext.setStyleSheet("") - self.rc_ext.setAutoDefault(False) - self.rc_ext.setFlat(True) - self.rc_ext.setProperty("icon_pixmap", QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle.svg")) - self.rc_ext.setObjectName("rc_ext") - self.routines_content_layout.addWidget(self.rc_ext, 1, 0, 1, 1) - self.verticalLayout_5.addLayout(self.routines_content_layout) - spacerItem9 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - self.verticalLayout_5.addItem(spacerItem9) - utilitiesStackedWidget.addWidget(self.routines_page) - self.rc_page = QtWidgets.QWidget() - self.rc_page.setObjectName("rc_page") - self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.rc_page) - self.verticalLayout_6.setObjectName("verticalLayout_6") - spacerItem10 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_6.addItem(spacerItem10) - self.rc_header_layout = QtWidgets.QHBoxLayout() - self.rc_header_layout.setObjectName("rc_header_layout") - self.rc_tittle = QtWidgets.QLabel(parent=self.rc_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_tittle.sizePolicy().hasHeightForWidth()) - self.rc_tittle.setSizePolicy(sizePolicy) - self.rc_tittle.setMinimumSize(QtCore.QSize(0, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.rc_tittle.setFont(font) - self.rc_tittle.setStyleSheet("background: transparent; color: white;") - self.rc_tittle.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.rc_tittle.setObjectName("rc_tittle") - self.rc_header_layout.addWidget(self.rc_tittle) - self.verticalLayout_6.addLayout(self.rc_header_layout) - self.rc_content_layout = QtWidgets.QGridLayout() - self.rc_content_layout.setVerticalSpacing(0) - self.rc_content_layout.setObjectName("rc_content_layout") - self.rc_label = QtWidgets.QLabel(parent=self.rc_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_label.sizePolicy().hasHeightForWidth()) - self.rc_label.setSizePolicy(sizePolicy) - font = QtGui.QFont() - font.setPointSize(15) - self.rc_label.setFont(font) - self.rc_label.setStyleSheet("color:white") - self.rc_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.rc_label.setObjectName("rc_label") - self.rc_content_layout.addWidget(self.rc_label, 0, 0, 1, 1) - self.horizontalLayout_3 = QtWidgets.QHBoxLayout() - self.horizontalLayout_3.setObjectName("horizontalLayout_3") - self.rc_yes = BlocksCustomButton(parent=self.rc_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_yes.sizePolicy().hasHeightForWidth()) - self.rc_yes.setSizePolicy(sizePolicy) - self.rc_yes.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_yes.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_yes.setFont(font) - self.rc_yes.setMouseTracking(False) - self.rc_yes.setTabletTracking(True) - self.rc_yes.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_yes.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_yes.setStyleSheet("") - self.rc_yes.setAutoDefault(False) - self.rc_yes.setFlat(True) - self.rc_yes.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) - self.rc_yes.setObjectName("rc_yes") - self.horizontalLayout_3.addWidget(self.rc_yes) - spacerItem11 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.horizontalLayout_3.addItem(spacerItem11) - self.rc_no = BlocksCustomButton(parent=self.rc_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.rc_no.sizePolicy().hasHeightForWidth()) - self.rc_no.setSizePolicy(sizePolicy) - self.rc_no.setMinimumSize(QtCore.QSize(250, 80)) - self.rc_no.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.rc_no.setFont(font) - self.rc_no.setMouseTracking(False) - self.rc_no.setTabletTracking(True) - self.rc_no.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.rc_no.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.rc_no.setStyleSheet("") - self.rc_no.setAutoDefault(False) - self.rc_no.setFlat(True) - self.rc_no.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg")) - self.rc_no.setObjectName("rc_no") - self.horizontalLayout_3.addWidget(self.rc_no) - self.rc_content_layout.addLayout(self.horizontalLayout_3, 1, 0, 1, 1) - self.verticalLayout_6.addLayout(self.rc_content_layout) - utilitiesStackedWidget.addWidget(self.rc_page) - self.axes_page = QtWidgets.QWidget() - self.axes_page.setObjectName("axes_page") - self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.axes_page) - self.verticalLayout_7.setObjectName("verticalLayout_7") - spacerItem12 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_7.addItem(spacerItem12) - self.lcd_settings_header_layout = QtWidgets.QHBoxLayout() - self.lcd_settings_header_layout.setObjectName("lcd_settings_header_layout") - spacerItem13 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.lcd_settings_header_layout.addItem(spacerItem13) - self.lcd_settings_title_label = QtWidgets.QLabel(parent=self.axes_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lcd_settings_title_label.sizePolicy().hasHeightForWidth()) - self.lcd_settings_title_label.setSizePolicy(sizePolicy) - self.lcd_settings_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.lcd_settings_title_label.setFont(font) - self.lcd_settings_title_label.setStyleSheet("background: transparent; color: white;") - self.lcd_settings_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.lcd_settings_title_label.setObjectName("lcd_settings_title_label") - self.lcd_settings_header_layout.addWidget(self.lcd_settings_title_label) - self.axes_back_btn = IconButton(parent=self.axes_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.axes_back_btn.sizePolicy().hasHeightForWidth()) - self.axes_back_btn.setSizePolicy(sizePolicy) - self.axes_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.axes_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.axes_back_btn.setFont(font) - self.axes_back_btn.setMouseTracking(False) - self.axes_back_btn.setTabletTracking(True) - self.axes_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.axes_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.axes_back_btn.setStyleSheet("") - self.axes_back_btn.setAutoDefault(False) - self.axes_back_btn.setFlat(True) - self.axes_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.axes_back_btn.setObjectName("axes_back_btn") - self.lcd_settings_header_layout.addWidget(self.axes_back_btn) - self.verticalLayout_7.addLayout(self.lcd_settings_header_layout) - self.frame_2 = BlocksCustomFrame(parent=self.axes_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) - self.frame_2.setSizePolicy(sizePolicy) - self.frame_2.setMinimumSize(QtCore.QSize(650, 0)) - self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.frame_2.setObjectName("frame_2") - self.gridLayout = QtWidgets.QGridLayout(self.frame_2) - self.gridLayout.setObjectName("gridLayout") - self.am_y = BlocksCustomCheckButton(parent=self.frame_2) - self.am_y.setMinimumSize(QtCore.QSize(60, 80)) - self.am_y.setMaximumSize(QtCore.QSize(250, 80)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.am_y.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(20) - self.am_y.setFont(font) - self.am_y.setCheckable(True) - self.am_y.setChecked(True) - self.am_y.setAutoExclusive(True) - self.am_y.setFlat(True) - self.am_y.setObjectName("am_y") - self.axis_maintenance_gb = QtWidgets.QButtonGroup(utilitiesStackedWidget) - self.axis_maintenance_gb.setObjectName("axis_maintenance_gb") - self.axis_maintenance_gb.addButton(self.am_y) - self.gridLayout.addWidget(self.am_y, 1, 0, 1, 1) - self.am_execute = BlocksCustomButton(parent=self.frame_2) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_execute.sizePolicy().hasHeightForWidth()) - self.am_execute.setSizePolicy(sizePolicy) - self.am_execute.setMinimumSize(QtCore.QSize(250, 80)) - self.am_execute.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_execute.setFont(font) - self.am_execute.setMouseTracking(False) - self.am_execute.setTabletTracking(True) - self.am_execute.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_execute.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_execute.setStyleSheet("") - self.am_execute.setAutoDefault(False) - self.am_execute.setFlat(True) - self.am_execute.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) - self.am_execute.setObjectName("am_execute") - self.gridLayout.addWidget(self.am_execute, 2, 1, 1, 1) - self.am_z = BlocksCustomCheckButton(parent=self.frame_2) - self.am_z.setMinimumSize(QtCore.QSize(60, 80)) - self.am_z.setMaximumSize(QtCore.QSize(250, 80)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.am_z.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(20) - self.am_z.setFont(font) - self.am_z.setCheckable(True) - self.am_z.setChecked(False) - self.am_z.setAutoExclusive(True) - self.am_z.setFlat(True) - self.am_z.setObjectName("am_z") - self.axis_maintenance_gb.addButton(self.am_z) - self.gridLayout.addWidget(self.am_z, 2, 0, 1, 1) - self.am_x = BlocksCustomCheckButton(parent=self.frame_2) - self.am_x.setMinimumSize(QtCore.QSize(250, 80)) - self.am_x.setMaximumSize(QtCore.QSize(250, 80)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.ButtonText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.am_x.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(20) - self.am_x.setFont(font) - self.am_x.setCheckable(True) - self.am_x.setChecked(False) - self.am_x.setAutoExclusive(True) - self.am_x.setFlat(True) - self.am_x.setObjectName("am_x") - self.axis_maintenance_gb.addButton(self.am_x) - self.gridLayout.addWidget(self.am_x, 0, 0, 1, 1) - self.verticalLayout_7.addWidget(self.frame_2, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - utilitiesStackedWidget.addWidget(self.axes_page) - self.input_shaper_page = QtWidgets.QWidget() - self.input_shaper_page.setObjectName("input_shaper_page") - self.verticalLayout_13 = QtWidgets.QVBoxLayout(self.input_shaper_page) - self.verticalLayout_13.setObjectName("verticalLayout_13") - spacerItem14 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_13.addItem(spacerItem14) - self.is_header_layout = QtWidgets.QHBoxLayout() - self.is_header_layout.setObjectName("is_header_layout") - spacerItem15 = QtWidgets.QSpacerItem(60, 0, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.is_header_layout.addItem(spacerItem15) - self.label_2 = QtWidgets.QLabel(parent=self.input_shaper_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label_2.sizePolicy().hasHeightForWidth()) - self.label_2.setSizePolicy(sizePolicy) - self.label_2.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.label_2.setFont(font) - self.label_2.setStyleSheet("background: transparent; color: white;") - self.label_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_2.setObjectName("label_2") - self.is_header_layout.addWidget(self.label_2) - self.input_shaper_back_btn = IconButton(parent=self.input_shaper_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.input_shaper_back_btn.sizePolicy().hasHeightForWidth()) - self.input_shaper_back_btn.setSizePolicy(sizePolicy) - self.input_shaper_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.input_shaper_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.input_shaper_back_btn.setFont(font) - self.input_shaper_back_btn.setMouseTracking(False) - self.input_shaper_back_btn.setTabletTracking(True) - self.input_shaper_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.input_shaper_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.input_shaper_back_btn.setStyleSheet("") - self.input_shaper_back_btn.setAutoDefault(False) - self.input_shaper_back_btn.setFlat(True) - self.input_shaper_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.input_shaper_back_btn.setObjectName("input_shaper_back_btn") - self.is_header_layout.addWidget(self.input_shaper_back_btn) - self.verticalLayout_13.addLayout(self.is_header_layout) - self.is_content_layout = QtWidgets.QHBoxLayout() - self.is_content_layout.setObjectName("is_content_layout") - self.verticalLayout_13.addLayout(self.is_content_layout) - utilitiesStackedWidget.addWidget(self.input_shaper_page) - self.manual_is_res_page = QtWidgets.QWidget() - self.manual_is_res_page.setObjectName("manual_is_res_page") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.manual_is_res_page) - self.verticalLayout_3.setObjectName("verticalLayout_3") - self.horizontalLayout_4 = QtWidgets.QHBoxLayout() - self.horizontalLayout_4.setObjectName("horizontalLayout_4") - self.label_3 = QtWidgets.QLabel(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) - self.label_3.setSizePolicy(sizePolicy) - self.label_3.setMinimumSize(QtCore.QSize(60, 60)) - self.label_3.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setPointSize(20) - self.label_3.setFont(font) - self.label_3.setStyleSheet("color:white") - self.label_3.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_3.setObjectName("label_3") - self.horizontalLayout_4.addWidget(self.label_3, 0, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.verticalLayout_3.addLayout(self.horizontalLayout_4) - self.gridLayout_3 = QtWidgets.QGridLayout() - self.gridLayout_3.setObjectName("gridLayout_3") - self.am_mzv_2 = BlocksCustomCheckButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_mzv_2.sizePolicy().hasHeightForWidth()) - self.am_mzv_2.setSizePolicy(sizePolicy) - self.am_mzv_2.setMinimumSize(QtCore.QSize(250, 80)) - self.am_mzv_2.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_mzv_2.setFont(font) - self.am_mzv_2.setMouseTracking(False) - self.am_mzv_2.setTabletTracking(True) - self.am_mzv_2.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_mzv_2.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_mzv_2.setStyleSheet("") - self.am_mzv_2.setCheckable(True) - self.am_mzv_2.setAutoDefault(False) - self.am_mzv_2.setFlat(True) - self.am_mzv_2.setObjectName("am_mzv_2") - self.gridLayout_3.addWidget(self.am_mzv_2, 0, 1, 1, 1) - self.am_ei_2 = BlocksCustomCheckButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_ei_2.sizePolicy().hasHeightForWidth()) - self.am_ei_2.setSizePolicy(sizePolicy) - self.am_ei_2.setMinimumSize(QtCore.QSize(250, 80)) - self.am_ei_2.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_ei_2.setFont(font) - self.am_ei_2.setMouseTracking(False) - self.am_ei_2.setTabletTracking(True) - self.am_ei_2.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_ei_2.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_ei_2.setStyleSheet("") - self.am_ei_2.setCheckable(True) - self.am_ei_2.setAutoDefault(False) - self.am_ei_2.setFlat(True) - self.am_ei_2.setObjectName("am_ei_2") - self.gridLayout_3.addWidget(self.am_ei_2, 1, 0, 1, 1) - self.am_3hump_ei_2 = BlocksCustomCheckButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_3hump_ei_2.sizePolicy().hasHeightForWidth()) - self.am_3hump_ei_2.setSizePolicy(sizePolicy) - self.am_3hump_ei_2.setMinimumSize(QtCore.QSize(250, 80)) - self.am_3hump_ei_2.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_3hump_ei_2.setFont(font) - self.am_3hump_ei_2.setMouseTracking(False) - self.am_3hump_ei_2.setTabletTracking(True) - self.am_3hump_ei_2.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_3hump_ei_2.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_3hump_ei_2.setStyleSheet("") - self.am_3hump_ei_2.setCheckable(True) - self.am_3hump_ei_2.setAutoDefault(False) - self.am_3hump_ei_2.setFlat(True) - self.am_3hump_ei_2.setObjectName("am_3hump_ei_2") - self.gridLayout_3.addWidget(self.am_3hump_ei_2, 2, 0, 1, 2, QtCore.Qt.AlignmentFlag.AlignHCenter) - self.am_zv_2 = BlocksCustomCheckButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_zv_2.sizePolicy().hasHeightForWidth()) - self.am_zv_2.setSizePolicy(sizePolicy) - self.am_zv_2.setMinimumSize(QtCore.QSize(250, 80)) - self.am_zv_2.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_zv_2.setFont(font) - self.am_zv_2.setMouseTracking(False) - self.am_zv_2.setTabletTracking(True) - self.am_zv_2.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_zv_2.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_zv_2.setStyleSheet("") - self.am_zv_2.setCheckable(True) - self.am_zv_2.setAutoDefault(False) - self.am_zv_2.setFlat(True) - self.am_zv_2.setObjectName("am_zv_2") - self.gridLayout_3.addWidget(self.am_zv_2, 0, 0, 1, 1) - self.am_2hump_ei_2 = BlocksCustomCheckButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_2hump_ei_2.sizePolicy().hasHeightForWidth()) - self.am_2hump_ei_2.setSizePolicy(sizePolicy) - self.am_2hump_ei_2.setMinimumSize(QtCore.QSize(250, 80)) - self.am_2hump_ei_2.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_2hump_ei_2.setFont(font) - self.am_2hump_ei_2.setMouseTracking(False) - self.am_2hump_ei_2.setTabletTracking(True) - self.am_2hump_ei_2.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_2hump_ei_2.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_2hump_ei_2.setStyleSheet("") - self.am_2hump_ei_2.setCheckable(True) - self.am_2hump_ei_2.setAutoDefault(False) - self.am_2hump_ei_2.setFlat(True) - self.am_2hump_ei_2.setObjectName("am_2hump_ei_2") - self.gridLayout_3.addWidget(self.am_2hump_ei_2, 1, 1, 1, 1) - self.verticalLayout_3.addLayout(self.gridLayout_3) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - self.am_cancel = BlocksCustomButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_cancel.sizePolicy().hasHeightForWidth()) - self.am_cancel.setSizePolicy(sizePolicy) - self.am_cancel.setMinimumSize(QtCore.QSize(250, 80)) - self.am_cancel.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_cancel.setFont(font) - self.am_cancel.setMouseTracking(False) - self.am_cancel.setTabletTracking(True) - self.am_cancel.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_cancel.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_cancel.setStyleSheet("") - self.am_cancel.setAutoDefault(False) - self.am_cancel.setFlat(True) - self.am_cancel.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg")) - self.am_cancel.setObjectName("am_cancel") - self.horizontalLayout.addWidget(self.am_cancel) - self.am_confirm = BlocksCustomButton(parent=self.manual_is_res_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.am_confirm.sizePolicy().hasHeightForWidth()) - self.am_confirm.setSizePolicy(sizePolicy) - self.am_confirm.setMinimumSize(QtCore.QSize(250, 80)) - self.am_confirm.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.am_confirm.setFont(font) - self.am_confirm.setMouseTracking(False) - self.am_confirm.setTabletTracking(True) - self.am_confirm.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.am_confirm.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.am_confirm.setStyleSheet("") - self.am_confirm.setAutoDefault(False) - self.am_confirm.setFlat(True) - self.am_confirm.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) - self.am_confirm.setObjectName("am_confirm") - self.horizontalLayout.addWidget(self.am_confirm) - self.verticalLayout_3.addLayout(self.horizontalLayout) - utilitiesStackedWidget.addWidget(self.manual_is_res_page) - self.user_input_page = QtWidgets.QWidget() - self.user_input_page.setObjectName("user_input_page") - self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.user_input_page) - self.verticalLayout_9.setObjectName("verticalLayout_9") - spacerItem16 = QtWidgets.QSpacerItem(20, 24, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.verticalLayout_9.addItem(spacerItem16) - self.horizontalLayout_5 = QtWidgets.QHBoxLayout() - self.horizontalLayout_5.setObjectName("horizontalLayout_5") - self.label_8 = QtWidgets.QLabel(parent=self.user_input_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label_8.sizePolicy().hasHeightForWidth()) - self.label_8.setSizePolicy(sizePolicy) - self.label_8.setMaximumSize(QtCore.QSize(16777215, 60)) - self.label_8.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_8.setObjectName("label_8") - self.horizontalLayout_5.addWidget(self.label_8) - self.verticalLayout_9.addLayout(self.horizontalLayout_5) - self.verticalLayout_10 = QtWidgets.QVBoxLayout() - self.verticalLayout_10.setObjectName("verticalLayout_10") - self.frame_4 = QtWidgets.QFrame(parent=self.user_input_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_4.sizePolicy().hasHeightForWidth()) - self.frame_4.setSizePolicy(sizePolicy) - self.frame_4.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.frame_4.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.frame_4.setObjectName("frame_4") - self.verticalLayout_10.addWidget(self.frame_4) - self.verticalLayout_9.addLayout(self.verticalLayout_10) - utilitiesStackedWidget.addWidget(self.user_input_page) - self.leds_slider_page = QtWidgets.QWidget() - self.leds_slider_page.setObjectName("leds_slider_page") - self.toggle_led_button = ToggleAnimatedButton(parent=self.leds_slider_page) - self.toggle_led_button.setGeometry(QtCore.QRect(70, 120, 100, 50)) - self.toggle_led_button.setMinimumSize(QtCore.QSize(100, 50)) - self.toggle_led_button.setMaximumSize(QtCore.QSize(100, 16777215)) - self.toggle_led_button.setObjectName("toggle_led_button") - self.label_4 = QtWidgets.QLabel(parent=self.leds_slider_page) - self.label_4.setGeometry(QtCore.QRect(170, 150, 31, 16)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(11) - self.label_4.setFont(font) - self.label_4.setStyleSheet("color:white") - self.label_4.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_4.setObjectName("label_4") - self.label_5 = QtWidgets.QLabel(parent=self.leds_slider_page) - self.label_5.setGeometry(QtCore.QRect(40, 150, 31, 16)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(11) - self.label_5.setFont(font) - self.label_5.setStyleSheet("color:white") - self.label_5.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label_5.setObjectName("label_5") - self.layoutWidget = QtWidgets.QWidget(parent=self.leds_slider_page) - self.layoutWidget.setGeometry(QtCore.QRect(10, 30, 691, 81)) - self.layoutWidget.setObjectName("layoutWidget") - self.leds_slider_header_layout = QtWidgets.QHBoxLayout(self.layoutWidget) - self.leds_slider_header_layout.setContentsMargins(0, 0, 0, 0) - self.leds_slider_header_layout.setObjectName("leds_slider_header_layout") - spacerItem17 = QtWidgets.QSpacerItem(60, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) - self.leds_slider_header_layout.addItem(spacerItem17) - self.leds_slider_tittle_label = QtWidgets.QLabel(parent=self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.leds_slider_tittle_label.sizePolicy().hasHeightForWidth()) - self.leds_slider_tittle_label.setSizePolicy(sizePolicy) - self.leds_slider_tittle_label.setMinimumSize(QtCore.QSize(0, 60)) - self.leds_slider_tittle_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.leds_slider_tittle_label.setFont(font) - self.leds_slider_tittle_label.setStyleSheet("background: transparent; color: white;") - self.leds_slider_tittle_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.leds_slider_tittle_label.setObjectName("leds_slider_tittle_label") - self.leds_slider_header_layout.addWidget(self.leds_slider_tittle_label) - self.leds_slider_back_btn = IconButton(parent=self.layoutWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.leds_slider_back_btn.sizePolicy().hasHeightForWidth()) - self.leds_slider_back_btn.setSizePolicy(sizePolicy) - self.leds_slider_back_btn.setMinimumSize(QtCore.QSize(60, 60)) - self.leds_slider_back_btn.setMaximumSize(QtCore.QSize(60, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.leds_slider_back_btn.setFont(font) - self.leds_slider_back_btn.setMouseTracking(False) - self.leds_slider_back_btn.setTabletTracking(True) - self.leds_slider_back_btn.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) - self.leds_slider_back_btn.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.leds_slider_back_btn.setStyleSheet("") - self.leds_slider_back_btn.setAutoDefault(False) - self.leds_slider_back_btn.setFlat(True) - self.leds_slider_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.leds_slider_back_btn.setObjectName("leds_slider_back_btn") - self.leds_slider_header_layout.addWidget(self.leds_slider_back_btn) - self.layoutWidget1 = QtWidgets.QWidget(parent=self.leds_slider_page) - self.layoutWidget1.setGeometry(QtCore.QRect(10, 200, 688, 101)) - self.layoutWidget1.setObjectName("layoutWidget1") - self.verticalLayout_12 = QtWidgets.QVBoxLayout(self.layoutWidget1) - self.verticalLayout_12.setContentsMargins(0, 0, 0, 0) - self.verticalLayout_12.setObjectName("verticalLayout_12") - self.leds_w_slider = BlocksSlider(parent=self.layoutWidget1) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.leds_w_slider.sizePolicy().hasHeightForWidth()) - self.leds_w_slider.setSizePolicy(sizePolicy) - self.leds_w_slider.setMinimumSize(QtCore.QSize(600, 90)) - self.leds_w_slider.setMaximumSize(QtCore.QSize(600, 90)) - self.leds_w_slider.setMaximum(100) - self.leds_w_slider.setProperty("value", 100) - self.leds_w_slider.setOrientation(QtCore.Qt.Orientation.Horizontal) - self.leds_w_slider.setObjectName("leds_w_slider") - self.verticalLayout_12.addWidget(self.leds_w_slider, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) - utilitiesStackedWidget.addWidget(self.leds_slider_page) - - self.retranslateUi(utilitiesStackedWidget) - utilitiesStackedWidget.setCurrentIndex(5) - QtCore.QMetaObject.connectSlotsByName(utilitiesStackedWidget) - - def retranslateUi(self, utilitiesStackedWidget): - _translate = QtCore.QCoreApplication.translate - utilitiesStackedWidget.setWindowTitle(_translate("utilitiesStackedWidget", "StackedWidget")) - self.utilities_title_label.setText(_translate("utilitiesStackedWidget", "Utilities")) - self.utilities_title_label.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.utilities_axes_btn.setText(_translate("utilitiesStackedWidget", "Axis\n" -"Maint.")) - self.utilities_axes_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.update_btn.setText(_translate("utilitiesStackedWidget", "Update")) - self.utilities_routine_check_btn.setText(_translate("utilitiesStackedWidget", "Routine\n" -"Check")) - self.utilities_routine_check_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.utilities_input_shaper_btn.setText(_translate("utilitiesStackedWidget", "Input\n" -"Shaper")) - self.utilities_input_shaper_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.utilities_info_btn.setText(_translate("utilitiesStackedWidget", "Info")) - self.utilities_info_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.utilities_leds_btn.setText(_translate("utilitiesStackedWidget", "LED\'s")) - self.utilities_leds_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.info_title_label.setText(_translate("utilitiesStackedWidget", "Info")) - self.info_title_label.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.info_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.info_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.info_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) - self.kv_label.setText(_translate("utilitiesStackedWidget", "Model: Blocks RF50")) - self.smth_label.setText(_translate("utilitiesStackedWidget", "www.blockstec.com ")) - self.leds_title_label.setText(_translate("utilitiesStackedWidget", "LED\'s")) - self.leds_title_label.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.leds_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.leds_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.leds_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) - self.routines_page_title.setText(_translate("utilitiesStackedWidget", "Routine Check")) - self.routines_page_title.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.routine_check_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.routine_check_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.routine_check_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) - self.rc_bheat.setText(_translate("utilitiesStackedWidget", "Bed Heater")) - self.rc_bheat.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.rc_fans.setText(_translate("utilitiesStackedWidget", "Fans")) - self.rc_fans.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.rc_axis.setText(_translate("utilitiesStackedWidget", "Axis")) - self.rc_axis.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.rc_ext.setText(_translate("utilitiesStackedWidget", "Extruder")) - self.rc_ext.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.rc_tittle.setText(_translate("utilitiesStackedWidget", "label")) - self.rc_tittle.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.rc_label.setText(_translate("utilitiesStackedWidget", "TextLabel")) - self.rc_yes.setText(_translate("utilitiesStackedWidget", "Yes")) - self.rc_yes.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.rc_no.setText(_translate("utilitiesStackedWidget", "No")) - self.rc_no.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.lcd_settings_title_label.setText(_translate("utilitiesStackedWidget", "Axis Maintenance")) - self.lcd_settings_title_label.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.axes_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.axes_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.axes_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) - self.am_y.setText(_translate("utilitiesStackedWidget", "Y")) - self.am_execute.setText(_translate("utilitiesStackedWidget", "Execute")) - self.am_execute.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_z.setText(_translate("utilitiesStackedWidget", "Z")) - self.am_x.setText(_translate("utilitiesStackedWidget", "X")) - self.label_2.setText(_translate("utilitiesStackedWidget", "Input Shaper")) - self.label_2.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.input_shaper_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.input_shaper_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.input_shaper_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) - self.label_3.setText(_translate("utilitiesStackedWidget", "Input Shaper ")) - self.am_mzv_2.setText(_translate("utilitiesStackedWidget", "MZV")) - self.am_mzv_2.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_ei_2.setText(_translate("utilitiesStackedWidget", "EI")) - self.am_ei_2.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_3hump_ei_2.setText(_translate("utilitiesStackedWidget", "3hump_ei")) - self.am_3hump_ei_2.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_zv_2.setText(_translate("utilitiesStackedWidget", "ZV")) - self.am_zv_2.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_2hump_ei_2.setText(_translate("utilitiesStackedWidget", "2hump_ei")) - self.am_2hump_ei_2.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_cancel.setText(_translate("utilitiesStackedWidget", "Cancel")) - self.am_cancel.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.am_confirm.setText(_translate("utilitiesStackedWidget", "Confirm")) - self.am_confirm.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.label_8.setText(_translate("utilitiesStackedWidget", "User Input")) - self.toggle_led_button.setText(_translate("utilitiesStackedWidget", "PushButton")) - self.label_4.setText(_translate("utilitiesStackedWidget", "On")) - self.label_5.setText(_translate("utilitiesStackedWidget", "Off")) - self.leds_slider_tittle_label.setText(_translate("utilitiesStackedWidget", "LED\'s")) - self.leds_slider_tittle_label.setProperty("class", _translate("utilitiesStackedWidget", "title_text")) - self.leds_slider_back_btn.setText(_translate("utilitiesStackedWidget", "Back")) - self.leds_slider_back_btn.setProperty("class", _translate("utilitiesStackedWidget", "menu_btn")) - self.leds_slider_back_btn.setProperty("button_type", _translate("utilitiesStackedWidget", "icon")) -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_frame import BlocksCustomFrame -from lib.utils.blocks_slider import BlocksSlider -from lib.utils.check_button import BlocksCustomCheckButton -from lib.utils.icon_button import IconButton -from lib.utils.toggleAnimatedButton import ToggleAnimatedButton From a131bc5b7dd4026440b06d7c890f04301ed8ac68 Mon Sep 17 00:00:00 2001 From: RobeMartins Date: Mon, 28 Sep 2026 12:05:55 +0100 Subject: [PATCH 15/18] fix: address stacked widget review across tabs (#338) ## Description - [x] fix ### Changes address reviews on other pr of this stacked PR #298 #299 #302 #303 #315 #332 --------- Co-authored-by: Robert0Mart --- BlocksScreen/lib/panels/controlTab.py | 301 +++----- BlocksScreen/lib/panels/filamentTab.py | 54 +- BlocksScreen/lib/panels/mainWindow.py | 377 +++------- BlocksScreen/lib/panels/printTab.py | 3 +- BlocksScreen/lib/panels/utilitiesTab.py | 656 +++++++++--------- .../lib/panels/widgets/ControlTab/axisPage.py | 17 +- .../panels/widgets/ControlTab/extruderPage.py | 123 ++-- .../lib/panels/widgets/ControlTab/fansPage.py | 20 +- .../widgets/ControlTab/temperaturePage.py | 24 +- .../lib/panels/widgets/FilamentTab/amuPage.py | 2 +- .../widgets/FilamentTab/basicFilamentPanel.py | 3 +- .../lib/panels/widgets/PrintTab/tunePage.py | 1 - .../widgets/UtilitiesTab/axisMaintPage.py | 13 +- .../widgets/UtilitiesTab/inputshaperPage.py | 15 +- .../panels/widgets/UtilitiesTab/ledsPage.py | 24 +- .../widgets/UtilitiesTab/routinePage.py | 24 +- BlocksScreen/lib/utils/menu_grid.py | 31 + tests/panels/conftest.py | 10 +- tests/ui/test_resource_keys_unit.py | 4 - tests/widgets/test_confirm_page_unit.py | 2 +- tests/widgets/test_sensors_panel_unit.py | 2 +- 21 files changed, 684 insertions(+), 1022 deletions(-) create mode 100644 BlocksScreen/lib/utils/menu_grid.py diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index 398fe8449..17c48f9e4 100644 --- a/BlocksScreen/lib/panels/controlTab.py +++ b/BlocksScreen/lib/panels/controlTab.py @@ -18,6 +18,7 @@ from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.icon_button import IconButton +from lib.utils.menu_grid import fixed_menu_grid from PyQt6 import QtCore, QtGui, QtWidgets _logger = logging.getLogger(__name__) @@ -28,14 +29,6 @@ class ControlTab(QtWidgets.QStackedWidget): request_back_button = QtCore.pyqtSignal(name="request-back-button") request_change_page = QtCore.pyqtSignal(int, int, name="request-change-page") - request_numpad_signal = QtCore.pyqtSignal( - int, - str, - str, - "PyQt_PyObject", - QtWidgets.QStackedWidget, - name="request-numpad", - ) run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run-gcode" ) @@ -45,11 +38,6 @@ class ControlTab(QtWidgets.QStackedWidget): lock_ui: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( bool, name="lock-ui" ) - request_numpad: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - [str, int, "PyQt_PyObject"], - [str, int, "PyQt_PyObject", int, int], - name="request-numpad", - ) request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="request-file-info" ) @@ -72,7 +60,6 @@ def __init__( self._true_zero_state: bool | None = None self._motion_active: bool = False self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.timers = [] self.ztilt_state = False self.ztilt_result_screen = BasePopup(self, False, False) self.ztilt_result_screen_timer = QtCore.QTimer() @@ -91,7 +78,7 @@ def __init__( self.fans_page = FansPage(self) self.addWidget(self.fans_page) - self.fans_page.request_back_button.connect(self.request_back_button) + self.fans_page.request_back.connect(self.request_back_button) self.fans_page.run_gcode_signal.connect(self.run_gcode_signal) self.fans_page.request_slider_page.connect(self.on_slidePage_request) @@ -166,7 +153,6 @@ def __init__( self.printer.printer_config.connect(self.temperature_page.on_printer_config) self.printer.request_object_subscription_signal.connect(self._on_object_list) self.run_gcode_signal.connect(self.ws.api.run_gcode) - # # @ object temperature change clicked self.printcores_page.pc_accept.clicked.connect(self.handle_swapcore) self.ws.klippy_state_signal.connect(self.on_klippy_status) @@ -185,105 +171,84 @@ def __init__( ) self._button_change(False) + def _menu(self, active: bool) -> list[tuple[str, str, typing.Callable]]: + # (text, icon, slot) for each grid button, in grid order + if active: + return [ + ( + "Auto Home", + ":/motion/media/btn_icons/home_all.svg", + lambda: self.run_gcode_signal.emit("G28\nM400"), + ), + ( + "Disable\nSteppers", + ":/motion/media/btn_icons/disable_steppers.svg", + lambda: self.run_gcode_signal.emit("M84\nM400"), + ), + ( + "Axis", + ":/motion/media/btn_icons/axis_maintenance.svg", + lambda: self.change_page(self.indexOf(self.axis_page)), + ), + ( + "Extruder", + ":/extruder_related/media/btn_icons/extrude.svg", + lambda: self.change_page(self.indexOf(self.extruder_page)), + ), + ] + return [ + ( + "Motion\nControl", + ":/motion/media/btn_icons/axis_maintenance.svg", + lambda: self._button_change(True), + ), + ( + "Temp.\nControl", + ":/temperature_related/media/btn_icons/temperature.svg", + lambda: self.change_page(self.indexOf(self.temperature_page)), + ), + ( + "Nozzle\nCalibration", + ":/z_levelling/media/btn_icons/bed_levelling.svg", + lambda: self.change_page(self.indexOf(self.probe_helper_page)), + ), + ( + "Z-Tilt", + ":/z_levelling/media/btn_icons/bed_levelling.svg", + self.handle_ztilt, + ), + ( + "Fans", + ":/temperature_related/media/btn_icons/fan.svg", + lambda: self.change_page(self.indexOf(self.fans_page)), + ), + ( + "Swap\nPrint Core", + ":/ui/media/btn_icons/LEDs.svg", + self.show_swapcore, + ), + ] + def _button_change(self, active: bool): self._motion_active = active - for btn in [ - self.cp_button_1, - self.cp_button_2, - self.cp_button_3, - self.cp_button_4, - self.cp_button_5, - self.cp_button_6, - ]: + for btn in self.cp_buttons: with contextlib.suppress(RuntimeError, TypeError): btn.clicked.disconnect() - if active: - self.cp_header_title.setText("Montion") - self.cp_button_1.setText("Auto Home") - - self.cp_button_1.setPixmap( - QtGui.QPixmap(":/motion/media/btn_icons/home_all.svg") - ) - self.cp_button_1.clicked.connect( - lambda: self.run_gcode_signal.emit("G28\nM400") - ) - self.cp_button_2.setText("Disable\nSteppers") - self.cp_button_2.clicked.connect( - lambda: self.run_gcode_signal.emit("M84\nM400") - ) - self.cp_button_2.setPixmap( - QtGui.QPixmap(":/motion/media/btn_icons/disable_steppers.svg") - ) - self.cp_button_3.setText("Axis") - self.cp_button_3.clicked.connect( - lambda: self.change_page(self.indexOf(self.axis_page)) - ) - self.cp_button_3.setPixmap( - QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg") - ) - self.cp_button_4.setText("Extruder") - self.cp_button_4.setPixmap( - QtGui.QPixmap(":/extruder_related/media/btn_icons/extrude.svg") - ) - self.cp_button_4.clicked.connect( - lambda: self.change_page(self.indexOf(self.extruder_page)) - ) - - self.back_button.show() - self.Hblank.show() - - self.cp_content_layout.addWidget(self.blank, 2, 0, 1, 1) - self.cp_button_5.hide() - self.blank.show() - else: - self.cp_header_title.setText("Control") - - self.cp_button_1.setText("Motion\nControl") - self.cp_button_1.setPixmap( - QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg") - ) - self.cp_button_1.clicked.connect(lambda: self._button_change(True)) - - self.cp_button_2.setText("Temp.\nControl") - self.cp_button_2.setPixmap( - QtGui.QPixmap(":/temperature_related/media/btn_icons/temperature.svg") - ) - self.cp_button_2.clicked.connect( - lambda: self.change_page(self.indexOf(self.temperature_page)) - ) - - self.cp_button_3.setText("Nozzle\nCalibration") - self.cp_button_3.setPixmap( - QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg") - ) - self.cp_button_3.clicked.connect( - lambda: self.change_page(self.indexOf(self.probe_helper_page)) - ) - - self.cp_button_4.setText("Z-Tilt") - self.cp_button_4.setPixmap( - QtGui.QPixmap(":/z_levelling/media/btn_icons/bed_levelling.svg") - ) - self.cp_button_4.clicked.connect(lambda: self.handle_ztilt()) - - self.cp_button_5.setText("Fans") - self.cp_button_5.setPixmap( - QtGui.QPixmap(":/temperature_related/media/btn_icons/fan.svg") - ) - self.cp_button_5.clicked.connect( - lambda: self.change_page(self.indexOf(self.fans_page)) - ) - - self.cp_button_6.clicked.connect(self.show_swapcore) - - self.back_button.hide() - self.Hblank.hide() - self.cp_button_5.show() - self.cp_content_layout.removeWidget(self.blank) - self.blank.hide() + for btn, (text, icon, slot) in zip(self.cp_buttons, self._menu(active)): + btn.setText(text) + btn.setPixmap(QtGui.QPixmap(icon)) + btn.clicked.connect(slot) + self.cp_header_title.setText("Motion" if active else "Control") + self.back_button.setVisible(active) + self.Hblank.setVisible(active) + self._show_blank(active) self._apply_true_zero_layout() self.repaint() + def _show_blank(self, on: bool) -> None: + self.blank.setVisible(on) + self.cp_button_5.setVisible(not on) + def showEvent(self, a0: QtGui.QShowEvent | None) -> None: self._button_change(False) return super().showEvent(a0) @@ -400,11 +365,7 @@ def _on_object_list(self, objects: dict) -> None: self._apply_true_zero_layout() def _apply_true_zero_layout(self) -> None: - """When true zero is used, repurpose the nozzle-calibration slot as a - second Fans button and hide the dedicated one, instead of moving - widgets between grid cells (QGridLayout doesn't fully forget a - widget's old cell after removeWidget/addWidget, which shifts the - whole page by a few px).""" + """With true zero, show Fans in the nozzle-calibration slot instead.""" if self._motion_active: return has_true_zero = bool(self._true_zero_state) @@ -418,9 +379,7 @@ def _apply_true_zero_layout(self) -> None: self.cp_button_3.clicked.connect( lambda: self.change_page(self.indexOf(self.fans_page)) ) - self.cp_button_5.hide() - self.cp_content_layout.addWidget(self.blank, 2, 0, 1, 1) - self.blank.show() + self._show_blank(True) else: self.cp_button_3.setText("Nozzle\nCalibration") self.cp_button_3.setPixmap( @@ -429,9 +388,7 @@ def _apply_true_zero_layout(self) -> None: self.cp_button_3.clicked.connect( lambda: self.change_page(self.indexOf(self.probe_helper_page)) ) - self.cp_content_layout.removeWidget(self.blank) - self.blank.hide() - self.cp_button_5.show() + self._show_blank(False) def show_swapcore(self): """Show swap printcore""" @@ -470,7 +427,6 @@ def change_page(self, index): def _setup_ui(self) -> None: """Build the control tab page: header, back button, and option grid.""" - self.resize(710, 410) root = QtWidgets.QWidget() root.setObjectName("control_page") root.setMinimumSize(QtCore.QSize(710, 410)) @@ -522,92 +478,29 @@ def _setup_ui(self) -> None: QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding, ) - font = QtGui.QFont() font.setFamily("Momcake") font.setPointSize(19) - self.cp_button_1 = BlocksCustomButton(parent=root) - self.cp_button_1.setSizePolicy(sizePolicy) - self.cp_button_1.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_1.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_1.setFont(font) - self.cp_button_1.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), - ) - self.cp_content_layout.addWidget(self.cp_button_1, 0, 0, 1, 1) - - self.cp_button_2 = BlocksCustomButton(parent=root) - self.cp_button_2.setSizePolicy(sizePolicy) - self.cp_button_2.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_2.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_2.setFont(font) - self.cp_content_layout.addWidget(self.cp_button_2, 0, 1, 1, 1) - - self.cp_button_3 = BlocksCustomButton(parent=root) - self.cp_button_3.setSizePolicy(sizePolicy) - self.cp_button_3.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_3.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_3.setFont(font) - self.cp_button_3.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg") - ) - self.cp_content_layout.addWidget(self.cp_button_3, 1, 0, 1, 1) - - self.cp_button_4 = BlocksCustomButton(parent=root) - self.cp_button_4.setSizePolicy(sizePolicy) - self.cp_button_4.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_4.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_4.setFont(font) - self.cp_button_4.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg"), - ) - self.cp_content_layout.addWidget(self.cp_button_4, 1, 1, 1, 1) - - self.cp_button_5 = BlocksCustomButton(parent=root) - self.cp_button_5.setSizePolicy(sizePolicy) - self.cp_button_5.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_5.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_5.setFont(font) - self.cp_button_5.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg") - ) - self.cp_content_layout.addWidget(self.cp_button_5, 2, 0, 1, 1) - - self.cp_button_6 = BlocksCustomButton(parent=root) - self.cp_button_6.setSizePolicy(sizePolicy) - self.cp_button_6.setMinimumSize(QtCore.QSize(250, 80)) - self.cp_button_6.setMaximumSize(QtCore.QSize(250, 80)) - self.cp_button_6.setFont(font) - self.cp_button_6.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") - ) - self.cp_content_layout.addWidget(self.cp_button_6, 2, 1, 1, 1) - self.cp_content_layout.setRowMinimumHeight(0, 80) - self.cp_content_layout.setRowMinimumHeight(1, 80) - self.cp_content_layout.setRowMinimumHeight(2, 80) - - content_widget = QtWidgets.QWidget(parent=root) - content_widget.setLayout(self.cp_content_layout) - content_widget.setSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed - ) - self.cp_content_layout.setContentsMargins(0, 0, 0, 0) - content_widget.setFixedHeight(self.cp_content_layout.sizeHint().height()) - self.verticalLayout.addWidget(content_widget) - - _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("controlStackedWidget", "StackedWidget")) - self.cp_header_title.setText(_translate("controlStackedWidget", "Control")) - - self.cp_button_1.setText(_translate("controlStackedWidget", "Motion\nControl")) - self.cp_button_2.setText(_translate("controlStackedWidget", "Temp.\nControl")) - self.cp_button_3.setText( - _translate("controlStackedWidget", "Nozzle\nCalibration") - ) - self.cp_button_4.setText(_translate("controlStackedWidget", "Z-Tilt")) - self.cp_button_5.setText(_translate("controlStackedWidget", "Fans")) - self.cp_button_6.setText(_translate("controlStackedWidget", "Swap\nPrint Core")) + self.cp_buttons: list[BlocksCustomButton] = [] + for i in range(6): + btn = BlocksCustomButton(parent=root) + btn.setSizePolicy(sizePolicy) + btn.setFixedSize(QtCore.QSize(250, 80)) + btn.setFont(font) + self.cp_content_layout.addWidget(btn, i // 2, i % 2, 1, 1) + self.cp_buttons.append(btn) + ( + self.cp_button_1, + self.cp_button_2, + self.cp_button_3, + self.cp_button_4, + self.cp_button_5, + self.cp_button_6, + ) = self.cp_buttons + + self.cp_content_layout.addWidget(self.blank, 2, 0, 1, 1) + self.blank.hide() + + self.verticalLayout.addWidget(fixed_menu_grid(root, self.cp_content_layout)) self.addWidget(root) diff --git a/BlocksScreen/lib/panels/filamentTab.py b/BlocksScreen/lib/panels/filamentTab.py index b33ba7ee9..e40019ef2 100644 --- a/BlocksScreen/lib/panels/filamentTab.py +++ b/BlocksScreen/lib/panels/filamentTab.py @@ -5,21 +5,22 @@ from devices.amu import AMUManager from devices.amu.models import GateStatus from lib.panels.widgets.Common.basePopup import BasePopup -from lib.panels.widgets.FilamentTab.colorWheelWidget import ColorWheelWidget +from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget +from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.panels.widgets.FilamentTab.addFilamentPage import AddFilamentPage from lib.panels.widgets.FilamentTab.addSpoolPage import AddSpoolPage from lib.panels.widgets.FilamentTab.amuPage import AMUpage from lib.panels.widgets.FilamentTab.basicFilamentPanel import BasicFilamentPanel +from lib.panels.widgets.FilamentTab.colorWheelWidget import ColorWheelWidget from lib.panels.widgets.FilamentTab.spoolmanPage import SpoolmanPage -from lib.panels.widgets.Common.keyboardPage import CustomQwertyKeyboard -from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget -from lib.panels.widgets.Common.numpadPage import CustomNumpad from lib.printer import Printer from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.blocks_linedit import BlocksCustomLinEdit from lib.utils.icon_button import IconButton from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem +from lib.utils.menu_grid import fixed_menu_grid from lib.utils.toolmap import MmuToolmapWidget from PyQt6 import QtCore, QtGui, QtWidgets @@ -1025,25 +1026,25 @@ def on_mmu_state_changed(self, mmu_state): self.load_status_label.setText(mmu_state.action) - def setupUi(self): + @staticmethod + def _hblank() -> QtWidgets.QWidget: + blank = QtWidgets.QWidget() + blank.setFixedSize(60, 60) + return blank + + def _setup_ui(self): """Build the tab's landing page (title + Filament Control / Spoolman buttons).""" - self.resize(710, 410) self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - widget = QtWidgets.QWidget() - widget.setMinimumSize(QtCore.QSize(710, 410)) - widget.setMaximumSize(QtCore.QSize(710, 410)) self.setObjectName("filament_page") - self.verticalLayout = QtWidgets.QVBoxLayout(widget) + self.filament_control_page = QtWidgets.QWidget() + self.filament_control_page.setFixedSize(710, 410) + self.verticalLayout = QtWidgets.QVBoxLayout(self.filament_control_page) self.verticalLayout.setObjectName("verticalLayout") self.fp_header_layout = QtWidgets.QHBoxLayout() self.fp_header_layout.setObjectName("fp_header_layout") + self.fp_header_layout.addWidget(self._hblank()) - self.fp_hblank_left = QtWidgets.QWidget() - self.fp_hblank_left.setMinimumSize(QtCore.QSize(60, 55)) - self.fp_hblank_left.setMaximumSize(QtCore.QSize(60, 55)) - self.fp_header_layout.addWidget(self.fp_hblank_left) - - self.fp_header_title = QtWidgets.QLabel(parent=widget) + self.fp_header_title = QtWidgets.QLabel(parent=self.filament_control_page) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum, @@ -1060,10 +1061,7 @@ def setupUi(self): self.fp_header_title.setObjectName("fp_header_title") self.fp_header_layout.addWidget(self.fp_header_title) - self.fp_hblank_right = QtWidgets.QWidget() - self.fp_hblank_right.setMinimumSize(QtCore.QSize(60, 55)) - self.fp_hblank_right.setMaximumSize(QtCore.QSize(60, 55)) - self.fp_header_layout.addWidget(self.fp_hblank_right) + self.fp_header_layout.addWidget(self._hblank()) self.verticalLayout.addLayout(self.fp_header_layout) self.fp_content_layout = QtWidgets.QGridLayout() @@ -1110,21 +1108,11 @@ def setupUi(self): self.fp_content_layout.addWidget(self.fp_button_2, 1, 1, 1, 1) - self.fp_content_layout.setRowMinimumHeight(0, 80) - self.fp_content_layout.setRowMinimumHeight(1, 80) - self.fp_content_layout.setRowMinimumHeight(2, 80) - self.fp_content_layout.setContentsMargins(0, 0, 0, 0) - - fp_content_widget = QtWidgets.QWidget(parent=widget) - fp_content_widget.setLayout(self.fp_content_layout) - fp_content_widget.setSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + self.verticalLayout.addWidget( + fixed_menu_grid(self.filament_control_page, self.fp_content_layout) ) - fp_content_widget.setFixedHeight(80 * 3 + self.fp_content_layout.spacing() * 2) - self.verticalLayout.addWidget(fp_content_widget) - self.filament_control_page = widget - self.addWidget(widget) + self.addWidget(self.filament_control_page) self.fp_header_title.setText("Filament") self.fp_button_1.setText("Filament\nControl") self.fp_button_2.setText("Spoolman") diff --git a/BlocksScreen/lib/panels/mainWindow.py b/BlocksScreen/lib/panels/mainWindow.py index 7b037ff8c..6c5edb1ab 100644 --- a/BlocksScreen/lib/panels/mainWindow.py +++ b/BlocksScreen/lib/panels/mainWindow.py @@ -23,9 +23,9 @@ from lib.panels.printTab import PrintTab from lib.panels.utilitiesTab import UtilitiesTab from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget from lib.panels.widgets.MainWindow.cancelPage import CancelPage from lib.panels.widgets.MainWindow.connectionPage import ConnectionPage -from lib.panels.widgets.Common.loadWidget import LoadingOverlayWidget from lib.panels.widgets.MainWindow.notificationPage import NotificationPage from lib.panels.widgets.MainWindow.updatePage import UpdatePage from lib.printer import Printer @@ -140,7 +140,6 @@ def __init__(self): self._klipper_restart_timeout.setSingleShot(True) self._klipper_restart_timeout.setInterval(30_000) self._klipper_restart_timeout.timeout.connect(self._on_klipper_restart_timeout) - self.main_content_widget.setCurrentIndex(0) usb_config = self.config.get_section("usb_manager", fallback=None) gdir = None @@ -232,10 +231,6 @@ def __init__(self): 2, ) ) - self.filament_type_icon.setText("PLA") - self.filament_type_icon.update() - self.nozzle_size_icon.setText("0.4mm") - self.nozzle_size_icon.update() self.conn_window.retry_connection_clicked.connect(slot=self.ws.retry_wb_conn) self.conn_window.firmware_restart_clicked.connect( slot=self.mc.restart_klipper_mcu_service @@ -1283,20 +1278,16 @@ def sizeHint(self) -> QtCore.QSize: def _setup_ui(self) -> None: """Build the main window chrome: header bar, tab widget, and tab pages.""" + self._setup_window() + self._setup_tabs() + self._setup_header() + self.setCentralWidget(self.main_widget) + + def _setup_window(self) -> None: self.setObjectName("MainWindow") self.resize(800, 480) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) - self.setSizePolicy(sizePolicy) self.setMinimumSize(QtCore.QSize(800, 480)) self.setMaximumSize(QtCore.QSize(1024, 600)) - self.setSizeIncrement(QtCore.QSize(1, 1)) - self.setBaseSize(QtCore.QSize(800, 480)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -1308,56 +1299,28 @@ def _setup_ui(self) -> None: self.setPalette(palette) self.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) self.setTabletTracking(True) - icon = QtGui.QIcon.fromTheme("applications-other") - self.setWindowIcon(icon) self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.setStyleSheet( - "MainWindow > {\n url(:/font/media/fonts for text/Momcake-Thin.ttf);\n}" - ) self.setAnimated(False) + self.main_widget = QtWidgets.QWidget(parent=self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.main_widget.sizePolicy().hasHeightForWidth()) - self.main_widget.setSizePolicy(sizePolicy) + self.main_widget.setObjectName("main_widget") self.main_widget.setMinimumSize(QtCore.QSize(800, 480)) self.main_widget.setMaximumSize(QtCore.QSize(1024, 600)) - self.main_widget.setSizeIncrement(QtCore.QSize(1, 1)) - self.main_widget.setBaseSize(QtCore.QSize(800, 480)) self.main_widget.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) self.main_widget.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) self.main_widget.setStyleSheet( - "#main_widget{background-image: url(:/background/media/1st_background.png);}\n" - "" + "#main_widget{background-image: url(:/background/media/1st_background.png);}" ) - self.main_widget.setObjectName("main_widget") + + def _setup_tabs(self) -> None: self.main_content_widget = NotificationQTabWidget(parent=self.main_widget) - self.main_content_widget.setEnabled(True) + self.main_content_widget.setObjectName("main_content_widget") self.main_content_widget.setGeometry(QtCore.QRect(0, 60, 800, 420)) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth( - self.main_content_widget.sizePolicy().hasHeightForWidth() - ) - self.main_content_widget.setSizePolicy(sizePolicy) self.main_content_widget.setMinimumSize(QtCore.QSize(800, 400)) self.main_content_widget.setMaximumSize(QtCore.QSize(1024, 720)) - self.main_content_widget.setBaseSize(QtCore.QSize(800, 400)) - self.main_content_widget.setCursor( - QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) - ) self.main_content_widget.setLayoutDirection( QtCore.Qt.LayoutDirection.RightToLeft ) - self.main_content_widget.setAutoFillBackground(False) self.main_content_widget.setStyleSheet( "#main_content_widget{\n" "background-image: url(:/background/media/1st_background.png);\n" @@ -1369,8 +1332,6 @@ def _setup_ui(self) -> None: " max-height: 100px;\n" " background: transparent;\n" "}\n" - "\n" - "" ) self.main_content_widget.setTabPosition(QtWidgets.QTabWidget.TabPosition.West) self.main_content_widget.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded) @@ -1380,154 +1341,68 @@ def _setup_ui(self) -> None: self.main_content_widget.setDocumentMode(True) self.main_content_widget.setTabsClosable(False) self.main_content_widget.setMovable(False) - self.main_content_widget.setObjectName("main_content_widget") - self.printTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.printTab.sizePolicy().hasHeightForWidth()) - self.printTab.setSizePolicy(sizePolicy) - self.printTab.setMinimumSize(QtCore.QSize(720, 420)) - self.printTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.printTab.setBaseSize(QtCore.QSize(1024, 420)) - self.printTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.printTab.setObjectName("printTab") + + self.printTab = self._make_tab( + "printTab", + ":/icons/media/main_menu/ICON_home.png", + ":/icons/media/main_menu/ICON_home_pressed.png", + ":/icons/media/main_menu/ICON_home_blocked.png", + ) + self.filamentTab = self._make_tab( + "filamentTab", + ":/icons/media/main_menu/ICON_filament.png", + ":/icons/media/main_menu/ICON_filament_pressed.png", + ":/icons/media/main_menu/ICON_filamente_blocked.png", + ) + self.controlTab = self._make_tab( + "controlTab", + ":/icons/media/main_menu/ICON_control.png", + ":/icons/media/main_menu/ICON_control_pressed.png", + ":/icons/media/main_menu/ICON_control_blocked.png", + ) + self.utilitiesTab = self._make_tab( + "utilitiesTab", + ":/icons/media/main_menu/ICON_utilities.png", + ":/icons/media/main_menu/ICON_utilities_pressed.png", + ":/icons/media/main_menu/ICON_utilities_blocked.png", + ) + self.main_content_widget.setCurrentIndex(0) + + def _make_tab( + self, name: str, normal: str, pressed: str, blocked: str + ) -> QtWidgets.QWidget: + tab = QtWidgets.QWidget() + tab.setObjectName(name) + tab.setMinimumSize(QtCore.QSize(720, 420)) + tab.setMaximumSize(QtCore.QSize(1024, 720)) icon = QtGui.QIcon() icon.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_home.png"), + QtGui.QPixmap(normal), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off, ) icon.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_home_pressed.png"), + QtGui.QPixmap(pressed), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.On, ) icon.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_home_blocked.png"), - QtGui.QIcon.Mode.Disabled, - QtGui.QIcon.State.On, - ) - self.main_content_widget.addTab(self.printTab, icon, "") - self.filamentTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.filamentTab.sizePolicy().hasHeightForWidth()) - self.filamentTab.setSizePolicy(sizePolicy) - self.filamentTab.setMinimumSize(QtCore.QSize(720, 420)) - self.filamentTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.filamentTab.setBaseSize(QtCore.QSize(1024, 420)) - self.filamentTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.filamentTab.setObjectName("filamentTab") - icon1 = QtGui.QIcon() - icon1.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_filament.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.Off, - ) - icon1.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_filament_pressed.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.On, - ) - icon1.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_filamente_blocked.png"), - QtGui.QIcon.Mode.Disabled, - QtGui.QIcon.State.On, - ) - self.main_content_widget.addTab(self.filamentTab, icon1, "") - self.controlTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.controlTab.sizePolicy().hasHeightForWidth()) - self.controlTab.setSizePolicy(sizePolicy) - self.controlTab.setMinimumSize(QtCore.QSize(720, 420)) - self.controlTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.controlTab.setBaseSize(QtCore.QSize(720, 420)) - self.controlTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.controlTab.setObjectName("controlTab") - icon2 = QtGui.QIcon() - icon2.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_control.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.Off, - ) - icon2.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_control_pressed.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.On, - ) - icon2.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_control_blocked.png"), + QtGui.QPixmap(blocked), QtGui.QIcon.Mode.Disabled, QtGui.QIcon.State.On, ) - self.main_content_widget.addTab(self.controlTab, icon2, "") - self.utilitiesTab = QtWidgets.QWidget() - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.utilitiesTab.sizePolicy().hasHeightForWidth()) - self.utilitiesTab.setSizePolicy(sizePolicy) - self.utilitiesTab.setMinimumSize(QtCore.QSize(720, 420)) - self.utilitiesTab.setMaximumSize(QtCore.QSize(1024, 720)) - self.utilitiesTab.setBaseSize(QtCore.QSize(1024, 420)) - self.utilitiesTab.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor)) - self.utilitiesTab.setObjectName("utilitiesTab") - icon3 = QtGui.QIcon() - icon3.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.Off, - ) - icon3.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_pressed.png"), - QtGui.QIcon.Mode.Normal, - QtGui.QIcon.State.On, - ) - icon3.addPixmap( - QtGui.QPixmap(":/icons/media/main_menu/ICON_utilities_blocked.png"), - QtGui.QIcon.Mode.Disabled, - QtGui.QIcon.State.On, - ) - self.main_content_widget.addTab(self.utilitiesTab, icon3, "") + self.main_content_widget.addTab(tab, icon, "") + return tab + + def _setup_header(self) -> None: self.main_header_layout = QtWidgets.QGroupBox(parent=self.main_widget) - self.main_header_layout.setEnabled(True) + self.main_header_layout.setObjectName("main_header_layout") self.main_header_layout.setGeometry(QtCore.QRect(0, 0, 800, 60)) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(2) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth( - self.main_header_layout.sizePolicy().hasHeightForWidth() - ) - self.main_header_layout.setSizePolicy(sizePolicy) self.main_header_layout.setMinimumSize(QtCore.QSize(800, 60)) self.main_header_layout.setMaximumSize(QtCore.QSize(1024, 80)) - self.main_header_layout.setSizeIncrement(QtCore.QSize(1, 1)) - self.main_header_layout.setBaseSize(QtCore.QSize(800, 60)) font = QtGui.QFont() font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) self.main_header_layout.setFont(font) - self.main_header_layout.setCursor( - QtGui.QCursor(QtCore.Qt.CursorShape.BlankCursor) - ) self.main_header_layout.setLayoutDirection( QtCore.Qt.LayoutDirection.LeftToRight ) @@ -1548,7 +1423,6 @@ def _setup_ui(self) -> None: " selection-background-color: rgb(60,60,60);\n" " gridline-color:rgb(60,60,60);\n" " selection-color:rgb(60,60,60);\n" - " \n" "}\n" "\n" "QFrame > *{\n" @@ -1558,26 +1432,21 @@ def _setup_ui(self) -> None: " color: rgb(255, 255, 255); \n" " selection-color: rgb(60, 60, 60);\n" " border-bottom-color: rgb(60, 60, 60);\n" - " \n" "}\n" "\n" - "\n" "QPushButton:pressed{\n" " border: none;\n" " background: transparent;\n" "}" ) - self.main_header_layout.setAlignment( - QtCore.Qt.AlignmentFlag.AlignJustify | QtCore.Qt.AlignmentFlag.AlignVCenter - ) - self.main_header_layout.setObjectName("main_header_layout") self.header_main_layout = QtWidgets.QHBoxLayout(self.main_header_layout) + self.header_main_layout.setObjectName("header_main_layout") self.header_main_layout.setSizeConstraint( QtWidgets.QLayout.SizeConstraint.SetMinimumSize ) self.header_main_layout.setContentsMargins(5, 0, 5, 0) self.header_main_layout.setSpacing(10) - self.header_main_layout.setObjectName("header_main_layout") + self.notification_btn = IconButton(parent=self.main_header_layout) self.notification_btn.setMinimumSize(QtCore.QSize(60, 60)) self.notification_btn.setMaximumSize(QtCore.QSize(60, 60)) @@ -1585,75 +1454,40 @@ def _setup_ui(self) -> None: self.notification_btn.setProperty( "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/notification.svg") ) + self.notification_btn.setProperty("button_type", "icon_text") self.header_main_layout.addWidget( self.notification_btn, 0, QtCore.Qt.AlignmentFlag.AlignLeft ) - self.extruder_temp_display = DisplayButton(parent=self.main_header_layout) - self.extruder_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.extruder_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.extruder_temp_display.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/extruder_related/media/btn_icons/nozzle_topbar.svg"), - ) - self.header_main_layout.addWidget( - self.extruder_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.bed_temp_display = DisplayButton(parent=self.main_header_layout) - self.bed_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.bed_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.bed_temp_display.setProperty( - "icon_pixmap", - QtGui.QPixmap( - ":/temperature_related/media/btn_icons/temperature_plate.svg" - ), + + self.extruder_temp_display = self._make_temp_display( + "extruder", ":/extruder_related/media/btn_icons/nozzle_topbar.svg" ) - self.header_main_layout.addWidget( - self.bed_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + self.extruder_temp_display.setProperty("button_type", "secondary_display") + self.extruder_temp_display.setProperty("name", "extruder_temperature_display") + + self.bed_temp_display = self._make_temp_display( + "bed", ":/temperature_related/media/btn_icons/temperature_plate.svg" ) - self.chamber_temp_display = DisplayButton(parent=self.main_header_layout) - self.chamber_temp_display.setMinimumSize(QtCore.QSize(140, 60)) - self.chamber_temp_display.setMaximumSize(QtCore.QSize(160, 60)) - self.chamber_temp_display.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/top_bar_icons/media/topbar/chamber_temp_topbar.svg"), + self.bed_temp_display.setProperty("button_type", "secondary_display") + + self.chamber_temp_display = self._make_temp_display( + "chamber", ":/top_bar_icons/media/topbar/chamber_temp_topbar.svg" ) self.chamber_temp_display.setProperty( "secondary_pixmap", QtGui.QPixmap(":/temperature_related/media/btn_icons/humidity.svg"), ) - self.header_main_layout.addWidget( - self.chamber_temp_display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.filament_type_icon = IconButton(parent=self.main_header_layout) - self.filament_type_icon.setMinimumSize(QtCore.QSize(60, 60)) - self.filament_type_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.filament_type_icon.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/filament_related/media/btn_icons/load_filament.svg"), - ) - self.header_main_layout.addWidget( - self.filament_type_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.nozzle_size_icon = IconButton(parent=self.main_header_layout) - self.nozzle_size_icon.setMinimumSize(QtCore.QSize(60, 60)) - self.nozzle_size_icon.setMaximumSize(QtCore.QSize(60, 60)) - self.nozzle_size_icon.setProperty( - "icon_pixmap", - QtGui.QPixmap( - ":/temperature_related/media/btn_icons/standart_temperature.svg" - ), - ) - self.header_main_layout.addWidget( - self.nozzle_size_icon, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + self.chamber_temp_display.setProperty("display_format", "dual") + self.chamber_temp_display.setProperty("button_type", "display_secondary") + + self.filament_type_icon = self._make_header_icon( + "PLA", ":/filament_related/media/btn_icons/load_filament.svg" ) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, + self.nozzle_size_icon = self._make_header_icon( + "0.4mm", ":/temperature_related/media/btn_icons/standart_temperature.svg" ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) + self.wifi_button = IconButton(parent=self.main_header_layout) - self.wifi_button.setSizePolicy(sizePolicy) self.wifi_button.setMinimumSize(QtCore.QSize(60, 60)) self.wifi_button.setMaximumSize(QtCore.QSize(60, 60)) self.wifi_button.setIconSize(QtCore.QSize(16, 16)) @@ -1661,6 +1495,7 @@ def _setup_ui(self) -> None: "icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/network/3bar_wifi.svg"), ) + self.wifi_button.setProperty("button_type", "icon") self.header_main_layout.addWidget( self.wifi_button, 0, @@ -1669,38 +1504,24 @@ def _setup_ui(self) -> None: self.header_main_layout.setStretch(1, 1) self.header_main_layout.setStretch(2, 1) self.header_main_layout.setStretch(3, 1) - self.setCentralWidget(self.main_widget) - _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("MainWindow", "MainWindow")) - self.notification_btn.setProperty( - "button_type", _translate("MainWindow", "icon_text") - ) - self.extruder_temp_display.setText(_translate("MainWindow", "extruder")) - self.extruder_temp_display.setProperty( - "button_type", _translate("MainWindow", "secondary_display") - ) - self.extruder_temp_display.setProperty( - "name", _translate("MainWindow", "extruder_temperature_display") - ) - self.bed_temp_display.setText(_translate("MainWindow", "bed")) - self.bed_temp_display.setProperty( - "button_type", _translate("MainWindow", "secondary_display") - ) - self.chamber_temp_display.setText(_translate("MainWindow", "chamber")) - self.chamber_temp_display.setProperty( - "display_format", _translate("MainWindow", "dual") - ) - self.chamber_temp_display.setProperty( - "button_type", _translate("MainWindow", "display_secondary") - ) - self.filament_type_icon.setText(_translate("MainWindow", "Filament")) - self.filament_type_icon.setProperty( - "button_type", _translate("MainWindow", "icon_text") - ) - self.nozzle_size_icon.setText(_translate("MainWindow", "nozzle")) - self.nozzle_size_icon.setProperty( - "button_type", _translate("MainWindow", "icon_text") - ) - self.wifi_button.setProperty("button_type", _translate("MainWindow", "icon")) - self.main_content_widget.setCurrentIndex(3) + def _make_temp_display(self, text: str, icon: str) -> DisplayButton: + display = DisplayButton(parent=self.main_header_layout) + display.setMinimumSize(QtCore.QSize(140, 60)) + display.setMaximumSize(QtCore.QSize(160, 60)) + display.setProperty("icon_pixmap", QtGui.QPixmap(icon)) + display.setText(text) + self.header_main_layout.addWidget( + display, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + return display + + def _make_header_icon(self, text: str, icon: str) -> IconButton: + btn = IconButton(parent=self.main_header_layout) + btn.setMinimumSize(QtCore.QSize(60, 60)) + btn.setMaximumSize(QtCore.QSize(60, 60)) + btn.setProperty("icon_pixmap", QtGui.QPixmap(icon)) + btn.setProperty("button_type", "icon_text") + btn.setText(text) + self.header_main_layout.addWidget(btn, 0, QtCore.Qt.AlignmentFlag.AlignHCenter) + return btn diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index b7aa701f4..848abb3d5 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -480,7 +480,7 @@ def finish_print_signal(self) -> None: def setupMainPrintPage(self) -> None: """Setup UI for print page""" - self.setObjectName("printStackedWidget") + self.setObjectName("print_tab") self.setWindowModality(QtCore.Qt.WindowModality.WindowModal) self.resize(710, 410) sizePolicy = QtWidgets.QSizePolicy( @@ -591,7 +591,6 @@ def setupMainPrintPage(self) -> None: self.addWidget(self.print_page) _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("printStackedWidget", "StackedWidget")) self.main_print_btn.setText(_translate("printStackedWidget", "Print")) self.main_print_btn.setProperty( "class", _translate("printStackedWidget", "menu_btn") diff --git a/BlocksScreen/lib/panels/utilitiesTab.py b/BlocksScreen/lib/panels/utilitiesTab.py index b05db099c..4ba60c847 100644 --- a/BlocksScreen/lib/panels/utilitiesTab.py +++ b/BlocksScreen/lib/panels/utilitiesTab.py @@ -1,340 +1,316 @@ -import logging -import re -import typing -from enum import Enum, auto - -from lib.moonrakerComm import MoonWebSocket -from lib.panels.widgets.Common.basePopup import BasePopup -from lib.panels.widgets.UtilitiesTab.axisMaintPage import AxisMaintPage -from lib.panels.widgets.UtilitiesTab.infoPage import InfoPage -from lib.panels.widgets.UtilitiesTab.InputShaPage import InputShaperPage -from lib.panels.widgets.UtilitiesTab.ledsPage import LedsPage -from lib.panels.widgets.UtilitiesTab.routinePage import RoutineCheckPage -from lib.panels.widgets.UtilitiesTab.troubleshootPage import TroubleshootPage -from lib.printer import Printer -from lib.utils.blocks_button import BlocksCustomButton -from PyQt6 import QtCore, QtGui, QtWidgets - - -class Process(Enum): - AXIS = auto() - - -class UtilitiesTab(QtWidgets.QStackedWidget): - request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="request-back" - ) - request_change_page: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - int, int, name="request-change-page" - ) - request_available_objects_signal: typing.ClassVar[QtCore.pyqtSignal] = ( - QtCore.pyqtSignal(name="get-available-objects") - ) - run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="run-gcode" - ) - request_numpad_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - int, - str, - str, - "PyQt_PyObject", - QtWidgets.QStackedWidget, - name="request-numpad", - ) - subscribe_config: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - [list, "PyQt_PyObject"], - [str, "PyQt_PyObject"], - name="on-subscribe-config", - ) - on_update_message: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - dict, name="handle-update-message" - ) - - update_available: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="update-available" - ) - - show_update_page: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - bool, name="show-update-page" - ) - call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") - - on_object_list = QtCore.pyqtSignal(list, name="on-object-list") - - def __init__( - self, parent: QtWidgets.QWidget, ws: MoonWebSocket, printer: Printer - ) -> None: - super().__init__(parent) - - self.info_page: InfoPage = InfoPage(self) - self.leds_page: LedsPage = LedsPage(self) - self.axes_page: AxisMaintPage = AxisMaintPage(self) - self.routines_page: RoutineCheckPage = RoutineCheckPage(self) - self.troubleshoot_page: TroubleshootPage = TroubleshootPage(self) - - # currently using the logic only so theres no duplicate (logic flag disables render/update Ui) - self.is_page: InputShaperPage = InputShaperPage(self, logic=True) - self.is_page.hide() - - self.setupUi() - - self.ws = ws - self.printer: Printer = printer - - # --- UI Setup --- - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.up_update_btn.clicked.connect( - lambda: self.show_update_page[bool].emit(False) - ) - - # --- Page Navigation --- - self.up_input_shaper_btn.clicked.connect(self.ask_input_shaper) - - self.up_leds_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.leds_page)) - ) - self.up_axes_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.axes_page)) - ) - self.up_info_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.info_page)) - ) - self.up_routine_check_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.routines_page)) - ) - self.axes_page.axes_back_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.utilitiesPage)) - ) - self.troubleshoot_page.tb_back_btn.clicked.connect( - lambda: self.change_page(self.indexOf(self.utilitiesPage)) - ) - - # --- Info --- - self.info_page.request_back_button.connect(self.request_back) - - # --- LEDs --- - self.leds_page.request_back_button.connect(self.request_back) - self.leds_page.run_gcode_signal.connect(self.run_gcode_signal) - self.on_object_list.connect(self.leds_page.on_object_list) - - # --- Routines --- - self.routines_page.run_gcode_signal.connect(self.run_gcode_signal) - self.routines_page.request_back.connect(self.request_back) - self.routines_page.call_load_panel.connect(self.call_load_panel) - self.routines_page.request_tb_page.connect(self.troubleshoot_request) - self.printer.toolhead_update[str, str].connect( - self.routines_page.on_toolhead_update - ) - self.printer.printer_config.connect( - self.routines_page.on_printer_config_received - ) - self.routines_page.subscribe_config.connect(self.subscribe_config) - self.on_object_list.connect(self.routines_page.on_object_list) - - # --- Axis Maintenance --- - self.axes_page.run_gcode_signal.connect(self.run_gcode_signal) - self.axes_page.call_load_panel.connect(self.call_load_panel) - self.axes_page.request_back.connect(self.request_back) - - # ---- Input Shaper ---- - self.is_popup: BasePopup = BasePopup(self, dialog=True, floating=True) - self.is_popup.set_message( - "Run the automatic input shaper?\n\nThe printer will calibrate both axes." - ) - self.is_popup.confirm_button_text("Yes") - self.is_popup.cancel_button_text("No") - self.is_popup.confirm_button.clicked.connect(self.run_input_shaper) - self.is_page.run_gcode_signal.connect(self.run_gcode_signal) - self.is_page.call_load_panel.connect(self.call_load_panel) - self.printer.gcode_response.connect(self.is_page.handle_gcode_response) - - # --- Websocket/Printer Signals --- - self.run_gcode_signal.connect(self.ws.api.run_gcode) - - self.subscribe_config[str, "PyQt_PyObject"].connect( - self.printer.on_subscribe_config - ) - self.subscribe_config[list, "PyQt_PyObject"].connect( - self.printer.on_subscribe_config - ) - - def ask_input_shaper(self) -> None: - """Ask whether to run the automatic input shaper.""" - self.is_popup.show() - - def run_input_shaper(self) -> None: - """Start the automatic input shaper calibration.""" - self.is_popup.hide() - self.is_page.handle_is("SHAPER_CALIBRATE") - - def troubleshoot_request(self) -> None: - """Show troubleshoot page""" - self.troubleshoot_page.show() - - def change_page(self, index: int): - """Request change page by index""" - self.call_load_panel.emit(False, "", False) - self.troubleshoot_page.hide() - if index < self.count(): - self.request_change_page.emit(3, index) - - @QtCore.pyqtSlot(name="request-back") - def back_button(self) -> None: - """Request back""" - self.request_back.emit() - - def setupUi(self): - - self.setObjectName("utilitiesTab") - - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum - ) - - self.resize(710, 410) - self.setSizePolicy(sizePolicy) - self.setMinimumSize(QtCore.QSize(710, 410)) - self.setMaximumSize(QtCore.QSize(710, 410)) - self.utilitiesPage = QtWidgets.QWidget() - self.utilitiesPage.setObjectName("utilitiesPage") - - self.verticalLayout = QtWidgets.QVBoxLayout(self.utilitiesPage) - self.verticalLayout.setObjectName("verticalLayout") - - self.up_header_layout = QtWidgets.QHBoxLayout() - self.up_header_layout.setObjectName("up_header_layout") - - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum - ) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - - self.up_title_label = QtWidgets.QLabel(parent=self.utilitiesPage) - self.up_title_label.setSizePolicy(sizePolicy) - self.up_title_label.setMinimumSize(QtCore.QSize(0, 60)) - self.up_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - self.up_title_label.setFont(font) - self.up_title_label.setStyleSheet("background: transparent; color: white;") - self.up_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.up_title_label.setObjectName("up_title_label") - self.up_header_layout.addWidget(self.up_title_label) - self.verticalLayout.addLayout(self.up_header_layout) - - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(19) - - self.up_content_layout = QtWidgets.QGridLayout() - self.up_content_layout.setObjectName("up_content_layout") - - self.up_info_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_info_btn.setSizePolicy(sizePolicy) - self.up_info_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_info_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_info_btn.setFont(font) - self.up_info_btn.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg") - ) - self.up_info_btn.setObjectName("up_info_btn") - self.up_content_layout.addWidget(self.up_info_btn, 0, 0, 1, 1) - - self.up_leds_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_leds_btn.setSizePolicy(sizePolicy) - self.up_leds_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_leds_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_leds_btn.setFont(font) - self.up_leds_btn.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") - ) - self.up_leds_btn.setObjectName("up_leds_btn") - self.up_content_layout.addWidget(self.up_leds_btn, 0, 1, 1, 1) - - self.up_routine_check_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_routine_check_btn.setSizePolicy(sizePolicy) - self.up_routine_check_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_routine_check_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_routine_check_btn.setFont(font) - self.up_routine_check_btn.setProperty( - "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg") - ) - self.up_routine_check_btn.setObjectName("up_routine_check_btn") - self.up_content_layout.addWidget(self.up_routine_check_btn, 1, 0, 1, 1) - - self.up_axes_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_axes_btn.setSizePolicy(sizePolicy) - self.up_axes_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_axes_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_axes_btn.setFont(font) - self.up_axes_btn.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), - ) - self.up_content_layout.addWidget(self.up_axes_btn, 1, 1, 1, 1) - - self.up_update_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_update_btn.setSizePolicy(sizePolicy) - self.up_update_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_update_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_update_btn.setFont(font) - self.up_update_btn.setPixmap( - QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg") - ) - - self.up_update_btn.setObjectName("up_update_btn") - self.up_content_layout.addWidget(self.up_update_btn, 2, 0, 1, 1) - - self.up_input_shaper_btn = BlocksCustomButton(parent=self.utilitiesPage) - self.up_input_shaper_btn.setSizePolicy(sizePolicy) - self.up_input_shaper_btn.setMinimumSize(QtCore.QSize(250, 80)) - self.up_input_shaper_btn.setMaximumSize(QtCore.QSize(250, 80)) - self.up_input_shaper_btn.setFont(font) - self.up_input_shaper_btn.setProperty( - "icon_pixmap", - QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg"), - ) - self.up_content_layout.addWidget(self.up_input_shaper_btn, 2, 1, 1, 1) - - self.verticalLayout.addLayout(self.up_content_layout) - self.addWidget(self.utilitiesPage) - - # Info - - self.addWidget(self.info_page) - - # Leds Page - - self.addWidget(self.leds_page) - - # Routine Page - - self.addWidget(self.routines_page) - - # Axis maintenance Page - - self.addWidget(self.axes_page) - - # Input Shaper Page - - # self.addWidget(self.is_page) - - self.setCurrentIndex(0) - - _translate = QtCore.QCoreApplication.translate - - self.up_title_label.setText(_translate("self", "Utilities")) - self.up_info_btn.setText(_translate("self", "Info")) - self.up_leds_btn.setText(_translate("self", "LED's")) - self.up_routine_check_btn.setText(_translate("self", "Routine\nCheck")) - self.up_axes_btn.setText(_translate("self", "Axis\nMaint.")) - self.up_update_btn.setText(_translate("self", "Update")) - self.up_input_shaper_btn.setText(_translate("self", "Input\nShaper")) +import typing + +from lib.moonrakerComm import MoonWebSocket +from lib.panels.widgets.Common.basePopup import BasePopup +from lib.panels.widgets.UtilitiesTab.axisMaintPage import AxisMaintPage +from lib.panels.widgets.UtilitiesTab.infoPage import InfoPage +from lib.panels.widgets.UtilitiesTab.inputshaperPage import InputShaperPage +from lib.panels.widgets.UtilitiesTab.ledsPage import LedsPage +from lib.panels.widgets.UtilitiesTab.routinePage import RoutineCheckPage +from lib.panels.widgets.UtilitiesTab.troubleshootPage import TroubleshootPage +from lib.printer import Printer +from lib.utils.blocks_button import BlocksCustomButton +from PyQt6 import QtCore, QtGui, QtWidgets + + +class UtilitiesTab(QtWidgets.QStackedWidget): + request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="request-back" + ) + request_change_page: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + int, int, name="request-change-page" + ) + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run-gcode" + ) + subscribe_config: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + [list, "PyQt_PyObject"], + [str, "PyQt_PyObject"], + name="on-subscribe-config", + ) + update_available: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="update-available" + ) + + show_update_page: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + bool, name="show-update-page" + ) + call_load_panel = QtCore.pyqtSignal(bool, str, bool, name="call-load-panel") + + on_object_list = QtCore.pyqtSignal(list, name="on-object-list") + + def __init__( + self, parent: QtWidgets.QWidget, ws: MoonWebSocket, printer: Printer + ) -> None: + super().__init__(parent) + + self.info_page: InfoPage = InfoPage(self) + self.leds_page: LedsPage = LedsPage(self) + self.axes_page: AxisMaintPage = AxisMaintPage(self) + self.routines_page: RoutineCheckPage = RoutineCheckPage(self) + self.troubleshoot_page: TroubleshootPage = TroubleshootPage(self) + + # currently using the logic only so theres no duplicate (logic flag disables render/update Ui) + self.is_page: InputShaperPage = InputShaperPage(self, logic=True) + self.is_page.hide() + + self._setup_ui() + + self.ws = ws + self.printer: Printer = printer + + # --- UI Setup --- + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.up_update_btn.clicked.connect( + lambda: self.show_update_page[bool].emit(False) + ) + + # --- Page Navigation --- + self.up_input_shaper_btn.clicked.connect(self.ask_input_shaper) + + self.up_leds_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.leds_page)) + ) + self.up_axes_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.axes_page)) + ) + self.up_info_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.info_page)) + ) + self.up_routine_check_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.routines_page)) + ) + self.troubleshoot_page.tb_back_btn.clicked.connect( + lambda: self.change_page(self.indexOf(self.utilitiesPage)) + ) + + # --- Info --- + self.info_page.request_back_button.connect(self.request_back) + + # --- LEDs --- + self.leds_page.request_back_button.connect(self.request_back) + self.leds_page.run_gcode_signal.connect(self.run_gcode_signal) + self.on_object_list.connect(self.leds_page.on_object_list) + + # --- Routines --- + self.routines_page.run_gcode_signal.connect(self.run_gcode_signal) + self.routines_page.request_back.connect(self.request_back) + self.routines_page.call_load_panel.connect(self.call_load_panel) + self.routines_page.request_tb_page.connect(self.troubleshoot_request) + self.printer.toolhead_update[str, str].connect( + self.routines_page.on_toolhead_update + ) + self.printer.printer_config.connect( + self.routines_page.on_printer_config_received + ) + self.routines_page.subscribe_config.connect(self.subscribe_config) + self.on_object_list.connect(self.routines_page.on_object_list) + + # --- Axis Maintenance --- + self.axes_page.run_gcode_signal.connect(self.run_gcode_signal) + self.axes_page.call_load_panel.connect(self.call_load_panel) + self.axes_page.request_back.connect(self.request_back) + + # ---- Input Shaper ---- + self.is_popup: BasePopup = BasePopup(self, dialog=True, floating=True) + self.is_popup.set_message( + "Run the automatic input shaper?\n\nThe printer will calibrate both axes." + ) + self.is_popup.confirm_button_text("Yes") + self.is_popup.cancel_button_text("No") + self.is_popup.confirm_button.clicked.connect(self.run_input_shaper) + self.is_page.run_gcode_signal.connect(self.run_gcode_signal) + self.is_page.call_load_panel.connect(self.call_load_panel) + self.printer.gcode_response.connect(self.is_page.handle_gcode_response) + + # --- Websocket/Printer Signals --- + self.run_gcode_signal.connect(self.ws.api.run_gcode) + + self.subscribe_config[str, "PyQt_PyObject"].connect( + self.printer.on_subscribe_config + ) + self.subscribe_config[list, "PyQt_PyObject"].connect( + self.printer.on_subscribe_config + ) + + def ask_input_shaper(self) -> None: + """Ask whether to run the automatic input shaper.""" + self.is_popup.show() + + def run_input_shaper(self) -> None: + """Start the automatic input shaper calibration.""" + self.is_popup.hide() + self.is_page.handle_is("SHAPER_CALIBRATE") + + def troubleshoot_request(self) -> None: + """Show troubleshoot page""" + self.troubleshoot_page.show() + + def change_page(self, index: int): + """Request change page by index""" + self.call_load_panel.emit(False, "", False) + self.troubleshoot_page.hide() + if index < self.count(): + self.request_change_page.emit(3, index) + + @QtCore.pyqtSlot(name="request-back") + def back_button(self) -> None: + """Request back""" + self.request_back.emit() + + def _setup_ui(self) -> None: + self.setObjectName("utilitiesTab") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + + self.resize(710, 410) + self.setSizePolicy(sizePolicy) + self.setMinimumSize(QtCore.QSize(710, 410)) + self.setMaximumSize(QtCore.QSize(710, 410)) + self.utilitiesPage = QtWidgets.QWidget() + self.utilitiesPage.setObjectName("utilitiesPage") + + self.verticalLayout = QtWidgets.QVBoxLayout(self.utilitiesPage) + self.verticalLayout.setObjectName("verticalLayout") + + self.up_header_layout = QtWidgets.QHBoxLayout() + self.up_header_layout.setObjectName("up_header_layout") + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + + self.up_title_label = QtWidgets.QLabel(parent=self.utilitiesPage) + self.up_title_label.setSizePolicy(sizePolicy) + self.up_title_label.setMinimumSize(QtCore.QSize(0, 60)) + self.up_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + self.up_title_label.setFont(font) + self.up_title_label.setStyleSheet("background: transparent; color: white;") + self.up_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.up_title_label.setObjectName("up_title_label") + self.up_header_layout.addWidget(self.up_title_label) + self.verticalLayout.addLayout(self.up_header_layout) + + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(19) + + self.up_content_layout = QtWidgets.QGridLayout() + self.up_content_layout.setObjectName("up_content_layout") + + self.up_info_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_info_btn.setSizePolicy(sizePolicy) + self.up_info_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_info_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_info_btn.setFont(font) + self.up_info_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/info.svg") + ) + self.up_info_btn.setObjectName("up_info_btn") + self.up_content_layout.addWidget(self.up_info_btn, 0, 0, 1, 1) + + self.up_leds_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_leds_btn.setSizePolicy(sizePolicy) + self.up_leds_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_leds_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_leds_btn.setFont(font) + self.up_leds_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/LEDs.svg") + ) + self.up_leds_btn.setObjectName("up_leds_btn") + self.up_content_layout.addWidget(self.up_leds_btn, 0, 1, 1, 1) + + self.up_routine_check_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_routine_check_btn.setSizePolicy(sizePolicy) + self.up_routine_check_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_routine_check_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_routine_check_btn.setFont(font) + self.up_routine_check_btn.setProperty( + "icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/routine.svg") + ) + self.up_routine_check_btn.setObjectName("up_routine_check_btn") + self.up_content_layout.addWidget(self.up_routine_check_btn, 1, 0, 1, 1) + + self.up_axes_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_axes_btn.setSizePolicy(sizePolicy) + self.up_axes_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_axes_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_axes_btn.setFont(font) + self.up_axes_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/motion/media/btn_icons/axis_maintenance.svg"), + ) + self.up_axes_btn.setObjectName("up_axes_btn") + self.up_content_layout.addWidget(self.up_axes_btn, 1, 1, 1, 1) + + self.up_update_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_update_btn.setSizePolicy(sizePolicy) + self.up_update_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_update_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_update_btn.setFont(font) + self.up_update_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/system/media/btn_icons/update-software-icon.svg"), + ) + self.up_update_btn.setObjectName("up_update_btn") + self.up_content_layout.addWidget(self.up_update_btn, 2, 0, 1, 1) + + self.up_input_shaper_btn = BlocksCustomButton(parent=self.utilitiesPage) + self.up_input_shaper_btn.setSizePolicy(sizePolicy) + self.up_input_shaper_btn.setMinimumSize(QtCore.QSize(250, 80)) + self.up_input_shaper_btn.setMaximumSize(QtCore.QSize(250, 80)) + self.up_input_shaper_btn.setFont(font) + self.up_input_shaper_btn.setProperty( + "icon_pixmap", + QtGui.QPixmap(":/input_shaper/media/btn_icons/input_shaper.svg"), + ) + self.up_input_shaper_btn.setObjectName("up_input_shaper_btn") + self.up_content_layout.addWidget(self.up_input_shaper_btn, 2, 1, 1, 1) + + self.verticalLayout.addLayout(self.up_content_layout) + self.addWidget(self.utilitiesPage) + + # Info + + self.addWidget(self.info_page) + + # Leds Page + + self.addWidget(self.leds_page) + + # Routine Page + + self.addWidget(self.routines_page) + + # Axis maintenance Page + + self.addWidget(self.axes_page) + + # Input Shaper Page + + # self.addWidget(self.is_page) + + self.setCurrentIndex(0) + + _translate = QtCore.QCoreApplication.translate + + self.up_title_label.setText(_translate("utilitiesTab", "Utilities")) + self.up_info_btn.setText(_translate("utilitiesTab", "Info")) + self.up_leds_btn.setText(_translate("utilitiesTab", "LED's")) + self.up_routine_check_btn.setText(_translate("utilitiesTab", "Routine\nCheck")) + self.up_axes_btn.setText(_translate("utilitiesTab", "Axis\nMaint.")) + self.up_update_btn.setText(_translate("utilitiesTab", "Update")) + self.up_input_shaper_btn.setText(_translate("utilitiesTab", "Input\nShaper")) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py index 252716941..3369d2d1d 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/axisPage.py @@ -11,18 +11,15 @@ class AxisPage(QtWidgets.QWidget): """Axis movement page of the control tab.""" run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="run_gcode" + str, name="run-gcode" ) - request_back = QtCore.pyqtSignal(name="request_back") + request_back = QtCore.pyqtSignal(name="request-back") def __init__(self, parent: QtWidgets.QWidget) -> None: super().__init__(parent) - self.setObjectName("axis_page") self._setup_ui() - self.update() - self.move_length: float = 1.0 self.move_speed: float = 25.0 @@ -131,10 +128,7 @@ def on_toolhead_update(self, field: str, values: list) -> None: def _setup_ui(self) -> None: """Build the axis page: jog pads, step selector, and status labels.""" - widget = QtWidgets.QWidget(parent=self) - widget.setMinimumSize(QtCore.QSize(710, 410)) - widget.setMaximumSize(QtCore.QSize(710, 410)) - self.setObjectName("move_axis_page") + self.setObjectName("axis_page") self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") self.mva_header_layout = QtWidgets.QHBoxLayout() @@ -262,7 +256,7 @@ def _setup_ui(self) -> None: self.horizontalLayout_3.setObjectName("horizontalLayout_3") self.axis_select_length_group = QtWidgets.QButtonGroup(self) - self.axis_select_length_group.setObjectName("extrude_select_length_group") + self.axis_select_length_group.setObjectName("axis_select_length_group") self.mva_select_length_1_btn = BlocksCustomCheckButton(parent=self) self.mva_select_length_1_btn.setMinimumSize(QtCore.QSize(90, 90)) @@ -314,7 +308,7 @@ def _setup_ui(self) -> None: self.horizontalLayout_4.setObjectName("horizontalLayout_4") self.axis_select_speed_group = QtWidgets.QButtonGroup(self) - self.axis_select_speed_group.setObjectName("extrude_select_length_group") + self.axis_select_speed_group.setObjectName("axis_select_speed_group") self.mva_select_speed_25_btn = BlocksCustomCheckButton(parent=self) self.mva_select_speed_25_btn.setMinimumSize(QtCore.QSize(90, 90)) @@ -511,7 +505,6 @@ def _setup_ui(self) -> None: self.mva_z_value_label.setObjectName("mva_z_value_label") self.horizontalLayout_6.addWidget(self.mva_z_value_label) self.verticalLayout.addLayout(self.horizontalLayout_6) - widget.setLayout(self.verticalLayout) _translate = QtCore.QCoreApplication.translate self.mva_x_label.setText(_translate("controlStackedWidget", "X:")) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py index d55fc229f..bae636dae 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/extruderPage.py @@ -14,10 +14,10 @@ class ExtruderPage(QtWidgets.QWidget): """Filament extrude/retract page of the control tab.""" run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="run_gcode" + str, name="run-gcode" ) - request_back = QtCore.pyqtSignal(name="request-back-button") + request_back = QtCore.pyqtSignal(name="request-back") def __init__( self, @@ -26,17 +26,16 @@ def __init__( ) -> None: super().__init__(parent) - self.setObjectName("extruder_page") self.extrude_list: list[int] = [2, 4, 8] self._setup_ui() - self.update() - self.printer: Printer = printer - self.timers = [] self.extrude_length: int = 10 self.extrude_feedrate: int = 2 self.extrude_page_message: str = "" + self._ready_timer = QtCore.QTimer(self) + self._ready_timer.setSingleShot(True) + self._ready_timer.timeout.connect(self._on_ready) self.exp_extrude_btn.clicked.connect( lambda: self.handle_extrusion(True) @@ -46,41 +45,27 @@ def __init__( ) # False for retraction self.exp_back_btn.clicked.connect(self.request_back.emit) - self.extrude_select_length_10_btn.toggled.connect( - lambda: self.handle_toggle_extrude_length( - caller=self.extrude_select_length_10_btn, value=10 - ) - ) - self.extrude_select_length_50_btn.toggled.connect( - lambda: self.handle_toggle_extrude_length( - caller=self.extrude_select_length_50_btn, value=50 + for btn, length in ( + (self.extrude_select_length_10_btn, 10), + (self.extrude_select_length_50_btn, 50), + (self.extrude_select_length_100_btn, 100), + ): + btn.toggled.connect( + lambda on, v=length: on and self.handle_toggle_extrude_length(v) ) - ) - self.extrude_select_length_100_btn.toggled.connect( - lambda: self.handle_toggle_extrude_length( - caller=self.extrude_select_length_100_btn, value=100 - ) - ) - self.extrude_select_feedrate_low_btn.toggled.connect( - lambda: self.handle_toggle_extrude_feedrate( - caller=self.extrude_select_feedrate_low_btn, - value=self.extrude_list[0], + for btn, feedrate in zip( + ( + self.extrude_select_feedrate_low_btn, + self.extrude_select_feedrate_middle_btn, + self.extrude_select_feedrate_high_btn, + ), + self.extrude_list, + ): + btn.toggled.connect( + lambda on, v=feedrate: on and self.handle_toggle_extrude_feedrate(v) ) - ) - self.extrude_select_feedrate_middle_btn.toggled.connect( - lambda: self.handle_toggle_extrude_feedrate( - caller=self.extrude_select_feedrate_middle_btn, - value=self.extrude_list[1], - ) - ) - self.extrude_select_feedrate_high_btn.toggled.connect( - lambda: self.handle_toggle_extrude_feedrate( - caller=self.extrude_select_feedrate_high_btn, - value=self.extrude_list[2], - ) - ) - @QtCore.pyqtSlot(str, name="handle-extrusion") + @QtCore.pyqtSlot(bool, name="handle-extrusion") def handle_extrusion(self, extrude: bool) -> None: """Slot that requests an extrusion/unextrusion move @@ -104,44 +89,30 @@ def handle_extrusion(self, extrude: bool) -> None: ) self.extrude_page_message = "Retracting" self.exp_info_label.setText(self.extrude_page_message) - # This block of code schedules a method to be called in x amount of milliseconds - _sch_time_s = float( - self.extrude_length / self.extrude_feedrate - ) # calculate the amount of time it'll take for the operation - self.extrude_page_message = "Ready" - self.register_timed_callback( - int(_sch_time_s + 2.0) * 1000, # In milliseconds - lambda: self.exp_info_label.setText(self.extrude_page_message), - ) + # restart so an earlier move can't report "Ready" during this one + move_time_s = self.extrude_length / self.extrude_feedrate + self._ready_timer.start(int(move_time_s + 2.0) * 1000) - def register_timed_callback(self, time: int, callback: callable) -> None: - """Registers timed callback and starts the timeout""" - _timer = QtCore.QTimer() - _timer.setSingleShot(True) - _timer.timeout.connect(callback) - _timer.start(int(time)) - self.timers.append(_timer) + def _on_ready(self) -> None: + self.extrude_page_message = "Ready" + self.exp_info_label.setText(self.extrude_page_message) - @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-feedrate") - def handle_toggle_extrude_feedrate(self, caller, value: int) -> None: + @QtCore.pyqtSlot(int, name="select-extrude-feedrate") + def handle_toggle_extrude_feedrate(self, value: int) -> None: """Slot to change the extruder feedrate, mainly used for toggle buttons Args: - checked (bool): Button checked state - caller (PyQtObject): The button that called this slot value (int): New value for the extruder feedrate """ if value == self.extrude_feedrate: return self.extrude_feedrate = value - @QtCore.pyqtSlot(bool, "PyQt_PyObject", int, name="select-extrude-length") - def handle_toggle_extrude_length(self, caller, value: int) -> None: + @QtCore.pyqtSlot(int, name="select-extrude-length") + def handle_toggle_extrude_length(self, value: int) -> None: """Slot that changes the extrude length, mainly used for toggle buttons Args: - checked (bool): Button checked state - caller (PyQtObject): The button that called this slot value (int): New value for the extrude length """ if self.extrude_length == value: @@ -150,21 +121,14 @@ def handle_toggle_extrude_length(self, caller, value: int) -> None: def paintEvent(self, a0: QtGui.QPaintEvent | None) -> None: """Refresh the info label while the extrude page is visible.""" - if self.extrude_page.isVisible(): + if self.isVisible(): self.exp_info_label.setText(self.extrude_page_message) return super().paintEvent(a0) def _setup_ui(self) -> None: """Build the extruder page: extrude/retract controls and status labels.""" - widget = QtWidgets.QWidget(parent=self) - widget.setMinimumSize(QtCore.QSize(710, 410)) - widget.setMaximumSize(QtCore.QSize(710, 410)) self.setObjectName("extruder_page") - self.extrude_page = QtWidgets.QWidget() - self.extrude_page.setMinimumSize(QtCore.QSize(710, 400)) - self.extrude_page.setMaximumSize(QtCore.QSize(720, 420)) - self.extrude_page.setObjectName("extrude_page") - self.verticalLayout = QtWidgets.QVBoxLayout(self.extrude_page) + self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") spacerItem = QtWidgets.QSpacerItem( 20, @@ -182,7 +146,7 @@ def _setup_ui(self) -> None: QtWidgets.QSizePolicy.Policy.Minimum, ) self.exp_header_layout.addItem(spacerItem1) - self.exp_title_label = QtWidgets.QLabel(parent=self.extrude_page) + self.exp_title_label = QtWidgets.QLabel(parent=self) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum ) @@ -212,7 +176,7 @@ def _setup_ui(self) -> None: sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - self.exp_back_btn = IconButton(parent=self.extrude_page) + self.exp_back_btn = IconButton(parent=self) self.exp_back_btn.setSizePolicy(sizePolicy) self.exp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) @@ -236,7 +200,7 @@ def _setup_ui(self) -> None: font = QtGui.QFont() font.setPointSize(14) - self.exp_length_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) + self.exp_length_group_box = QtWidgets.QGroupBox(parent=self) self.exp_length_group_box.setMinimumSize(QtCore.QSize(0, 80)) self.exp_length_group_box.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.exp_length_group_box.setFont(font) @@ -310,7 +274,7 @@ def _setup_ui(self) -> None: font = QtGui.QFont() font.setPointSize(14) - self.exp_feedrate_group_box = QtWidgets.QGroupBox(parent=self.extrude_page) + self.exp_feedrate_group_box = QtWidgets.QGroupBox(parent=self) self.exp_feedrate_group_box.setMinimumSize(QtCore.QSize(0, 80)) self.exp_feedrate_group_box.setFont(font) self.exp_feedrate_group_box.setStyleSheet("color:white") @@ -404,7 +368,7 @@ def _setup_ui(self) -> None: QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.MinimumExpanding, ) - self.exp_unextrude_btn = BlocksCustomButton(parent=self.extrude_page) + self.exp_unextrude_btn = BlocksCustomButton(parent=self) self.exp_unextrude_btn.setSizePolicy(sizePolicy) self.exp_unextrude_btn.setMinimumSize(QtCore.QSize(250, 80)) self.exp_unextrude_btn.setMaximumSize(QtCore.QSize(250, 80)) @@ -420,7 +384,7 @@ def _setup_ui(self) -> None: font.setPointSize(16) self.exp_buttons_layout.addWidget(self.exp_unextrude_btn) - self.exp_nozzle_icon_label = BlocksLabel(parent=self.extrude_page) + self.exp_nozzle_icon_label = BlocksLabel(parent=self) self.exp_nozzle_icon_label.setMinimumSize(QtCore.QSize(60, 60)) self.exp_nozzle_icon_label.setMaximumSize(QtCore.QSize(60, 60)) self.exp_nozzle_icon_label.setFont(font) @@ -438,7 +402,7 @@ def _setup_ui(self) -> None: font.setItalic(False) font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.exp_extrude_btn = BlocksCustomButton(parent=self.extrude_page) + self.exp_extrude_btn = BlocksCustomButton(parent=self) self.exp_extrude_btn.setSizePolicy(sizePolicy) self.exp_extrude_btn.setMinimumSize(QtCore.QSize(250, 80)) self.exp_extrude_btn.setMaximumSize(QtCore.QSize(250, 80)) @@ -466,7 +430,7 @@ def _setup_ui(self) -> None: self.exp_info_layout.setContentsMargins(5, 5, 5, 5) self.exp_info_layout.setObjectName("exp_info_layout") - self.exp_info_label = QtWidgets.QLabel(parent=self.extrude_page) + self.exp_info_label = QtWidgets.QLabel(parent=self) self.exp_info_label.setSizePolicy(sizePolicy) self.exp_info_label.setFont(font) self.exp_info_label.setStyleSheet("background: transparent; color: white;") @@ -478,7 +442,6 @@ def _setup_ui(self) -> None: self.exp_vertical_content_layout.addLayout(self.exp_movement_content_layout) self.exp_vertical_content_layout.setStretch(2, 1) self.verticalLayout.addLayout(self.exp_vertical_content_layout) - widget.setLayout(self.verticalLayout) _translate = QtCore.QCoreApplication.translate self.exp_title_label.setText(_translate("controlStackedWidget", "Extrude")) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py index 96d331030..f845456c1 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/fansPage.py @@ -15,7 +15,7 @@ class FansPage(QtWidgets.QWidget): request_slider_page = QtCore.pyqtSignal( str, int, "PyQt_PyObject", int, int, name="on_slidePage_request" ) - request_back_button = QtCore.pyqtSignal(name="request-back-button") + request_back = QtCore.pyqtSignal(name="request-back") run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run-gcode" @@ -30,7 +30,7 @@ def __init__( self.tune_display_buttons: dict = {} self.card_options: dict = {} self._setup_ui() - self.fans_back_btn.clicked.connect(self.request_back_button.emit) + self.fans_back_btn.clicked.connect(self.request_back.emit) self.path = { "fan_cage": QtGui.QPixmap(":/fan_related/media/btn_icons/fan_cage.svg"), @@ -73,19 +73,10 @@ def on_fan_object_update(self, name: str, field: str, new_value: float) -> None: card = OptionCard(self, name, str(name), icon) # type: ignore card.setObjectName(str(name)) - - # Add card to layout and record reference self.card_options[name] = card self.fans_content_layout.addWidget(card) - # If the card doesn't have expected UI properties, discard it - if not hasattr(card, "continue_clicked"): - del card - self.card_options.pop(name, None) - return - card.setMode(True) - card.secondtext.setText(f"{new_value}%") card.continue_clicked.connect( lambda: self.request_slider_page.emit( str(name), @@ -110,16 +101,13 @@ def on_slider_change(self, name: str, new_value: int) -> None: Slider change handler Args: name (str): fan name - new_value (int): value from 0 to 255 to set fans speed + new_value (int): fan speed in percent, 0 to 100 """ self.run_gcode_signal.emit(fan_speed_gcode(name, new_value)) def _setup_ui(self) -> None: """Build the fans page: header, back button, and fan slider area.""" self.setObjectName("fans_page") - widget = QtWidgets.QWidget(parent=self) - widget.setGeometry(QtCore.QRect(0, 0, 720, 420)) - self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") @@ -205,8 +193,6 @@ def _setup_ui(self) -> None: ) self.verticalLayout.addItem(spacerItem12) - widget.setLayout(self.verticalLayout) - _translate = QtCore.QCoreApplication.translate self.fans_title_label.setText(_translate("controlStackedWidget", "Fans")) self.fans_back_btn.setText(_translate("controlStackedWidget", "Back")) diff --git a/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py b/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py index 968d89881..e2895ac14 100644 --- a/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py +++ b/BlocksScreen/lib/panels/widgets/ControlTab/temperaturePage.py @@ -12,7 +12,11 @@ class TemperaturePage(QtWidgets.QWidget): """Heater temperature page of the control tab.""" - request_back = QtCore.pyqtSignal(name="request-back-button") + # fallback (min, max) limits until printer_config reports the real ones + _E_LIMITS = (0, 300) + _B_LIMITS = (0, 100) + + request_back = QtCore.pyqtSignal(name="request-back") run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run-gcode" @@ -39,7 +43,7 @@ def __init__( self.cooldown_btn.hide() self.temperature_cooldown_btn.hide() - self._connect_temp_displays(0, 370, 0, 120) + self._connect_temp_displays(*self._E_LIMITS, *self._B_LIMITS) @QtCore.pyqtSlot(dict, name="printer_config") def on_printer_config(self, config: dict) -> None: @@ -47,10 +51,10 @@ def on_printer_config(self, config: dict) -> None: extruder = config.get("extruder") or {} bed = config.get("heater_bed") or {} self._connect_temp_displays( - int(extruder.get("min_temp", 0)), - int(extruder.get("max_temp", 300)), - int(bed.get("min_temp", 0)), - int(bed.get("max_temp", 100)), + int(extruder.get("min_temp", self._E_LIMITS[0])), + int(extruder.get("max_temp", self._E_LIMITS[1])), + int(bed.get("min_temp", self._B_LIMITS[0])), + int(bed.get("max_temp", self._B_LIMITS[1])), ) def _connect_temp_displays( @@ -64,7 +68,7 @@ def _connect_temp_displays( self.extruder_temp_display.clicked.connect( lambda: self.request_numpad.emit( "Extruder Temperature", - round(float(self.extruder_temp_display.secondary_text)), + round(float(self.extruder_temp_display.secondary_text or 0)), self.on_numpad_change, e_min, e_max, @@ -73,7 +77,7 @@ def _connect_temp_displays( self.bed_temp_display.clicked.connect( lambda: self.request_numpad.emit( "Bed Temperature", - round(float(self.bed_temp_display.secondary_text)), + round(float(self.bed_temp_display.secondary_text or 0)), self.on_numpad_change, b_min, b_max, @@ -112,8 +116,6 @@ def on_heater_bed_update(self, name: str, field: str, new_value: float) -> None: def _setup_ui(self) -> None: """Build the temperature page: heater cards and preset controls.""" self.setObjectName("temperature_page") - widget = QtWidgets.QWidget(parent=self) - widget.setGeometry(QtCore.QRect(0, 0, 720, 420)) self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") spacerItem3 = QtWidgets.QSpacerItem( @@ -291,8 +293,6 @@ def _setup_ui(self) -> None: ) self.verticalLayout.addItem(spacerItem7) - widget.setLayout(self.verticalLayout) - _translate = QtCore.QCoreApplication.translate self.temp_header_title.setText( _translate("controlStackedWidget", "Temperature") diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py b/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py index 140f0afb4..2b52b56ec 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/amuPage.py @@ -2,7 +2,7 @@ from devices.amu import AMUManager from lib.panels.widgets.FilamentTab.amuWidgets import SpoolCarousel, SpoolInfoPanel -from lib.panels.widgets.basePopup import BasePopup +from lib.panels.widgets.Common.basePopup import BasePopup from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton from PyQt6 import QtCore, QtGui, QtWidgets diff --git a/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py index c167fc2df..08aba9e19 100644 --- a/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py +++ b/BlocksScreen/lib/panels/widgets/FilamentTab/basicFilamentPanel.py @@ -370,8 +370,7 @@ def _setupInfoBox(self): def _setup_ui(self) -> None: """Build the basic filament panel: load/unload controls and status labels.""" - self.setObjectName("self") - self.resize(710, 411) + self.setObjectName("basic_filament_panel") sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, diff --git a/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py b/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py index 28d08bea5..0fd58b23d 100644 --- a/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py +++ b/BlocksScreen/lib/panels/widgets/PrintTab/tunePage.py @@ -469,7 +469,6 @@ def _setup_ui(self) -> None: def _retranslateUI(self): _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("printStackedWidget", "StackedWidget")) self.tune_title_label.setText(_translate("printStackedWidget", "Tune")) self.tune_title_label.setProperty( "class", _translate("printStackedWidget", "title_text") diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py index db4666bba..2ae19625b 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/axisMaintPage.py @@ -24,6 +24,7 @@ def __init__( ) -> None: super().__init__(parent) + self.current_object: str | None = None self.answerPage = BasePopup(self, False, True) self.answerPage.accepted.connect(self._run_AXIS_MAINTENANCE_gcode) @@ -59,18 +60,14 @@ def axis_maintenance(self) -> None: f"Apply oil to the {self.current_object.upper()} axis, then press Confirm.", ) - self.answerPage.show() self.call_load_panel.emit( True, f"Homing {self.current_object.upper()} axis...", False ) + QtCore.QTimer.singleShot(10000, self._on_homed) - QtCore.QTimer.singleShot( - 10000, - lambda: { - self.call_load_panel.emit(False, "", False), - self.answerPage.show(), - }, - ) + def _on_homed(self) -> None: + self.call_load_panel.emit(False, "", False) + self.answerPage.show() def _setup_ui(self) -> None: self.setObjectName("axes_page") diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py index 8c792aa9b..234cff0ad 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/inputshaperPage.py @@ -1,3 +1,4 @@ +import logging import re import typing @@ -9,6 +10,8 @@ from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem from PyQt6 import QtCore, QtGui, QtWidgets +_logger = logging.getLogger(__name__) + class InputShaperPage(QtWidgets.QStackedWidget): run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( @@ -97,9 +100,7 @@ def handle_gcode_response(self, data: list[str]) -> None: """ if not isinstance(data, list) or len(data) != 1 or not isinstance(data[0], str): - print( - f"WARNING: Invalid input format. Expected a list with one string. Received: {data}" - ) + _logger.warning("Invalid IS response format: %s", data) return message = data[0] @@ -186,7 +187,15 @@ def _on_is_timeout(self) -> None: self.call_load_panel.emit(False, "", False) def handle_is(self, gcode: str) -> None: + """Start an input shaper run. + + Args: + gcode: ``"SHAPER_CALIBRATE"`` for the automatic run on both axes, + ``""`` to ask which axis to calibrate, or a single-axis + ``SHAPER_CALIBRATE AXIS=...`` command to send as is. + """ if gcode == "SHAPER_CALIBRATE": + self.is_aut_types.clear() self.run_gcode_signal.emit("G28\nM400") self.aut = True self.run_gcode_signal.emit(gcode) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py index 08a800209..48083b900 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/ledsPage.py @@ -78,11 +78,20 @@ def _slider_back(self) -> None: def update_led_values(self) -> None: """Update led state and color values""" - led_state: LedState = self.leds[str(self.current_led)] + if (led_state := self.leds.get(str(self.current_led))) is None: + return led_state.white = int(self.leds_w_slider.value() * 255 / 100) self.save_led_state() def on_object_list(self, config_file) -> bool: + """Rebuild the LED buttons from the printer's object list. + + Args: + config_file: Printer object names, e.g. ``"neopixel status"``. + + Returns: + Always True. + """ layout = self.leds_content_layout cg = config_file @@ -116,6 +125,11 @@ def on_object_list(self, config_file) -> bool: return True def handle_led_button(self, name: str): + """Open the brightness/on-off page for one LED. + + Args: + name: The LED's config name. + """ self.current_led = name led_state = self.leds.get(name) if not led_state: @@ -358,7 +372,7 @@ def _setup_ui(self) -> None: _translate = QtCore.QCoreApplication.translate - self.leds_title_label.setText(_translate("self", "LED's")) - self.leds_back_btn.setText(_translate("self", "Back")) - self.leds_slider_back_btn.setText(_translate("self", "Back")) - self.leds_slider_tittle_label.setText(_translate("self", "LED's")) + self.leds_title_label.setText(_translate("ledsPage", "LED's")) + self.leds_back_btn.setText(_translate("ledsPage", "Back")) + self.leds_slider_back_btn.setText(_translate("ledsPage", "Back")) + self.leds_slider_tittle_label.setText(_translate("ledsPage", "LED's")) diff --git a/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py b/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py index a3b816827..a3cd4b845 100644 --- a/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py +++ b/BlocksScreen/lib/panels/widgets/UtilitiesTab/routinePage.py @@ -1,6 +1,6 @@ import math import typing -from dataclasses import dataclass, replace +from dataclasses import dataclass from lib.panels.widgets.Common.basePopup import BasePopup from lib.utils.blocks_button import BlocksCustomButton @@ -229,6 +229,7 @@ def _ask(self, step: Step) -> None: @classmethod def fan_steps(cls, fans: list[str]) -> list[Step]: + """Build one check step per fan, spinning it up and off again after.""" steps = [] for fan in fans: if fan == "fan": @@ -258,7 +259,7 @@ def heater_steps(cls, heaters: list[str]) -> list[Step]: cls.Step( label=label, prompt=( - f"Please check if the {label} reaches 60ºC.\n" + f"Please check if the {label} reaches 60°C.\n" "It may take a few moments." ), gcode=f"SET_HEATER_TEMPERATURE HEATER={heater} TARGET=60\nM400", @@ -337,13 +338,14 @@ def axis_steps( axes: typing.Sequence[str] = ("x", "y", "z"), ) -> list[Step]: """Build one check step per axis, homing once before the first of them.""" + y = limits.get("y") park_x = ( (y.min + y.max) / 2 if y is not None and math.isfinite(y.span) else None ) steps = [] - for axis in ["x", "y", "z"]: + for axis in axes: limit = limits.get(axis) if limit is None: continue @@ -362,9 +364,6 @@ def axis_steps( gcode=f"{prologue}{moves}\nM400", ) ) - - if steps: - steps[-1] = replace(steps[-1], cleanup="G28") return steps def _setup_ui(self) -> None: @@ -483,12 +482,9 @@ def _setup_ui(self) -> None: self.verticalLayout.addWidget(content_widget) _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("controlStackedWidget", "StackedWidget")) - self.rp_header_title.setText( - _translate("controlStackedWidget", "Routine Check") - ) + self.rp_header_title.setText(_translate("routinePage", "Routine Check")) - self.rp_button_1.setText(_translate("controlStackedWidget", "Fans")) - self.rp_button_2.setText(_translate("controlStackedWidget", "Axis")) - self.rp_button_3.setText(_translate("controlStackedWidget", "extruder")) - self.rp_button_4.setText(_translate("controlStackedWidget", "Bed Heater")) + self.rp_button_1.setText(_translate("routinePage", "Fans")) + self.rp_button_2.setText(_translate("routinePage", "Axis")) + self.rp_button_3.setText(_translate("routinePage", "extruder")) + self.rp_button_4.setText(_translate("routinePage", "Bed Heater")) diff --git a/BlocksScreen/lib/utils/menu_grid.py b/BlocksScreen/lib/utils/menu_grid.py new file mode 100644 index 000000000..cac0e7e37 --- /dev/null +++ b/BlocksScreen/lib/utils/menu_grid.py @@ -0,0 +1,31 @@ +"""Fixed-height wrapper for the 2-column menu button grids used by the tabs.""" + +from PyQt6 import QtWidgets + +MENU_ROW_H = 80 + + +def fixed_menu_grid( + parent: QtWidgets.QWidget, grid: QtWidgets.QGridLayout, rows: int = 3 +) -> QtWidgets.QWidget: + """Wrap a menu grid in a fixed-height widget so its rows never shift. + + Args: + parent: Parent widget of the returned container. + grid: The button grid to wrap. + rows: Number of rows to reserve, whether or not they are filled. + + Returns: + The container widget holding ``grid``. + """ + for r in range(rows): + grid.setRowMinimumHeight(r, MENU_ROW_H) + grid.setContentsMargins(0, 0, 0, 0) + container = QtWidgets.QWidget(parent) + container.setLayout(grid) + container.setSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed + ) + spacing = max(grid.verticalSpacing(), 0) + container.setFixedHeight(MENU_ROW_H * rows + spacing * (rows - 1)) + return container diff --git a/tests/panels/conftest.py b/tests/panels/conftest.py index 75fc409eb..4a7517132 100644 --- a/tests/panels/conftest.py +++ b/tests/panels/conftest.py @@ -19,7 +19,9 @@ # which breaks the real ``lib.utils.*`` imports below on a full-suite run. # Clear any stale "lib"/"lib.*" entries before rebuilding our own stubs. for _stale in list(sys.modules): - if _stale == "lib" or _stale.startswith("lib."): + if (_stale == "lib" or _stale.startswith("lib.")) and isinstance( + sys.modules[_stale], MagicMock + ): del sys.modules[_stale] _STUB_MODULES = ( @@ -49,7 +51,6 @@ "lib.panels.widgets.MainWindow.updatePage", "lib.printer", "lib.ui", - "lib.ui.mainWindow_ui", "lib.ui.resources", "lib.ui.resources.background_resources_rc", "lib.ui.resources.font_rc", @@ -98,9 +99,10 @@ sys.modules["lib.panels.widgets.MainWindow.cancelPage"].CancelPage = MagicMock sys.modules["lib.panels.widgets.MainWindow.connectionPage"].ConnectionPage = MagicMock sys.modules["lib.panels.widgets.Common.loadWidget"].LoadingOverlayWidget = MagicMock -sys.modules["lib.panels.widgets.MainWindow.notificationPage"].NotificationPage = MagicMock +sys.modules[ + "lib.panels.widgets.MainWindow.notificationPage" +].NotificationPage = MagicMock sys.modules["lib.panels.widgets.MainWindow.updatePage"].UpdatePage = MagicMock sys.modules["lib.printer"].Printer = MagicMock -sys.modules["lib.ui.mainWindow_ui"].Ui_MainWindow = MagicMock sys.modules["lib.updater_worker"].UpdaterWorker = MagicMock sys.modules["screensaver"].ScreenSaver = MagicMock diff --git a/tests/ui/test_resource_keys_unit.py b/tests/ui/test_resource_keys_unit.py index 413c38955..13c02af08 100644 --- a/tests/ui/test_resource_keys_unit.py +++ b/tests/ui/test_resource_keys_unit.py @@ -22,10 +22,6 @@ ":/background/media/graphics/scroll_list_window.svg": ( "asset is on disk but declared by no .qrc; retired by PR 3" ), - ":/button_borders/media/btn_icons/back.svg": ( - "wrong prefix, real key is :/ui/media/btn_icons/back.svg; " - "lives in a generated _ui.py so the .ui file is the fix; retired by PR 3" - ), ":/graphics/media/btn_icons/z_offset_adjust.svg": ( "asset deleted from the qrc in 927e43c (2025-06-04) and absent from " "disk, yet 3 call sites still request it; retired by PR 3" diff --git a/tests/widgets/test_confirm_page_unit.py b/tests/widgets/test_confirm_page_unit.py index 5caf8d132..8db9ca4df 100644 --- a/tests/widgets/test_confirm_page_unit.py +++ b/tests/widgets/test_confirm_page_unit.py @@ -3,7 +3,7 @@ from unittest.mock import MagicMock import pytest -from lib.panels.widgets.confirmPage import ConfirmWidget +from lib.panels.widgets.PrintTab.confirmPage import ConfirmWidget def _labels(metadata: dict) -> tuple[str, str]: diff --git a/tests/widgets/test_sensors_panel_unit.py b/tests/widgets/test_sensors_panel_unit.py index 348eb3ea0..35b959c4e 100644 --- a/tests/widgets/test_sensors_panel_unit.py +++ b/tests/widgets/test_sensors_panel_unit.py @@ -2,7 +2,7 @@ from unittest.mock import MagicMock -from lib.panels.widgets.sensorsPanel import SensorsWindow +from lib.panels.widgets.PrintTab.sensorsPanel import SensorsWindow def test_reset_view_model_drops_stale_sensor_widgets(): From 38e2bb9ca3ad7b3278e77b32ee58cd433f65538c Mon Sep 17 00:00:00 2001 From: RobeMartins Date: Mon, 28 Sep 2026 12:20:16 +0100 Subject: [PATCH 16/18] bugfix: controltab max size --- BlocksScreen/lib/panels/controlTab.py | 1 + 1 file changed, 1 insertion(+) diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index 17c48f9e4..7dd759859 100644 --- a/BlocksScreen/lib/panels/controlTab.py +++ b/BlocksScreen/lib/panels/controlTab.py @@ -427,6 +427,7 @@ def change_page(self, index): def _setup_ui(self) -> None: """Build the control tab page: header, back button, and option grid.""" + self.resize(710, 410) root = QtWidgets.QWidget() root.setObjectName("control_page") root.setMinimumSize(QtCore.QSize(710, 410)) From 958556eeebb426f56ce3958b5e72472f07fcb8a7 Mon Sep 17 00:00:00 2001 From: RobeMartins Date: Mon, 28 Sep 2026 12:26:28 +0100 Subject: [PATCH 17/18] fix: fixed duplicated cancel class and test wrong path --- .../panels/widgets/MainWindow/cancelPage.py | 277 ------------------ tests/widgets/test_files_page_unit.py | 2 +- 2 files changed, 1 insertion(+), 278 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index e4c290a13..783e3e4fd 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -273,280 +273,3 @@ def _setup_ui(self) -> None: self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter ) self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) - - -import logging -import typing - -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_frame import BlocksCustomFrame -from lib.utils.blocks_label import BlocksLabel -from PyQt6 import QtCore, QtGui, QtWidgets - -logger = logging.getLogger(__name__) - - -class CancelPage(QtWidgets.QWidget): - """Displayed when a print is cancelled; offers reprint or ignore.""" - - request_file_info: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="request_file_info" - ) - reprint_start: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="reprint_start" - ) - run_gcode: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="run_gcode" - ) - - def __init__(self, parent: QtWidgets.QWidget) -> None: - super().__init__(parent) - self._setupUI() - self.filename = "" - - self.confirm_button.clicked.connect(lambda: self._handle_accept()) - self.refuse_button.clicked.connect(lambda: self._handle_refuse()) - - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_StyledBackground, True) - - def _handle_accept(self): - self.run_gcode.emit("SDCARD_RESET_FILE") - self.reprint_start.emit(self.filename) - self.close() - - def _handle_refuse(self): - self.close() - self.run_gcode.emit("SDCARD_RESET_FILE") - - _REASON_HEADERS: typing.ClassVar[dict[str, str]] = { - "complete": "Print Finished", - "error": "Print Error", - "cancelled": "Print Cancelled", - } - - @QtCore.pyqtSlot(str, dict, name="on_print_stats_update") - @QtCore.pyqtSlot(str, float, name="on_print_stats_update") - @QtCore.pyqtSlot(str, str, name="on_print_stats_update") - def on_print_stats_update(self, field: str, value: dict | float | str) -> None: - if isinstance(value, str): - if "filename" in field: - self.filename = value - if self.isVisible(): - self.set_file_name(value) - elif "state" in field: - if value in self._REASON_HEADERS: - self.cf_info_tf.setText(self._REASON_HEADERS[value]) - elif value == "printing": - # New job: drop the previous job's reason so it cannot leak. - self.cf_info_tf.clear() - - def show(self): - self.request_file_info.emit(self.filename) - - super().show() - - def set_pixmap(self, pixmap: QtGui.QPixmap) -> None: - if not hasattr(self, "_scene"): - self._scene = QtWidgets.QGraphicsScene(self) - self.cf_thumbnail.setScene(self._scene) - - # Scene rectangle (available display area) - graphics_rect = self.cf_thumbnail.rect().toRectF() - - # Scale pixmap preserving aspect ratio - pixmap = pixmap.scaled( - graphics_rect.size().toSize(), - QtCore.Qt.AspectRatioMode.KeepAspectRatio, - QtCore.Qt.TransformationMode.SmoothTransformation, - ) - - adjusted_x = (graphics_rect.width() - pixmap.width()) / 2.0 - adjusted_y = (graphics_rect.height() - pixmap.height()) / 2.0 - - if not hasattr(self, "_pixmap_item"): - self._pixmap_item = QtWidgets.QGraphicsPixmapItem(pixmap) - self._scene.addItem(self._pixmap_item) - else: - self._pixmap_item.setPixmap(pixmap) - - self._pixmap_item.setPos(adjusted_x, adjusted_y) - self._scene.setSceneRect(graphics_rect) - - def set_file_name(self, file_name: str) -> None: - self.cf_file_name.setText(file_name) - - def _show_screen_thumbnail(self, metadata: dict | None) -> None: - """Display the largest thumbnail from file metadata. - - ``thumbnail_images`` values are pre-loaded ``QImage`` - objects produced by ``Files._process_metadata``. - """ - fallback = QtGui.QPixmap( - "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" - ) - thumbnails = metadata.get("thumbnail_images", []) if metadata else [] - if not thumbnails: - self.set_pixmap(fallback) - return - - last_thumb = thumbnails[-1] - if isinstance(last_thumb, QtGui.QImage) and not last_thumb.isNull(): - self.set_pixmap(QtGui.QPixmap.fromImage(last_thumb)) - else: - self.set_pixmap(fallback) - - def _setupUI(self) -> None: - """Setup widget ui""" - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) - self.setSizePolicy(sizePolicy) - self.setObjectName("cancelPage") - self.setStyleSheet("""#cancelPage { - background-image: url(:/background/media/1st_background.png); - }""") - self.setMinimumSize(QtCore.QSize(800, 480)) - self.setMaximumSize(QtCore.QSize(800, 480)) - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) - self.verticalLayout_4.setObjectName("verticalLayout_4") - self.cf_header_title = QtWidgets.QHBoxLayout() - self.cf_header_title.setObjectName("cf_header_title") - - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.cf_file_name = BlocksLabel(parent=self) - self.cf_file_name.setMinimumSize(QtCore.QSize(0, 60)) - self.cf_file_name.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.cf_file_name.setFont(font) - self.cf_file_name.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.cf_file_name.setSizePolicy(sizePolicy) - self.cf_file_name.setStyleSheet("background: transparent; color: white;") - self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_file_name.setObjectName("cf_file_name") - self.cf_header_title.addWidget(self.cf_file_name) - - self.verticalLayout_4.addLayout(self.cf_header_title) - self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() - self.cf_content_vertical_layout.setObjectName("cf_content_vertical_layout") - self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() - self.cf_content_horizontal_layout.setObjectName("cf_content_horizontal_layout") - self.info_frame = BlocksCustomFrame(parent=self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - self.info_frame.setSizePolicy(sizePolicy) - - self.info_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - - self.info_layout = QtWidgets.QVBoxLayout(self.info_frame) - - self.cf_info_tf = QtWidgets.QLabel(parent=self.info_frame) - self.cf_info_tf.setText(self._REASON_HEADERS["cancelled"]) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(20) - - self.cf_info_tf.setFont(font) - self.cf_info_tf.setStyleSheet("background: transparent; color: white;") - - self.cf_info_tf.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.info_layout.addWidget(self.cf_info_tf) - - self.cf_info_tr = QtWidgets.QLabel(parent=self.info_frame) - font = QtGui.QFont() - font.setPointSize(15) - self.cf_info_tr.setFont(font) - self.cf_info_tr.setStyleSheet("background: transparent; color: white;") - self.cf_info_tr.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_info_tr.setText("Do you want to reprint?") - self.info_layout.addWidget(self.cf_info_tr) - - self.cf_confirm_layout = QtWidgets.QVBoxLayout() - self.cf_confirm_layout.setSpacing(15) - - self.confirm_button = BlocksCustomButton(parent=self.info_frame) - self.confirm_button.setMinimumSize(QtCore.QSize(250, 70)) - self.confirm_button.setMaximumSize(QtCore.QSize(250, 70)) - font = QtGui.QFont("Momcake", 18) - self.confirm_button.setFont(font) - self.confirm_button.setFlat(True) - self.confirm_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") - ) - self.confirm_button.setText("Reprint") - # 2. Align buttons to the right - self.cf_confirm_layout.addWidget( - self.confirm_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.refuse_button = BlocksCustomButton(parent=self.info_frame) - self.refuse_button.setMinimumSize(QtCore.QSize(250, 70)) - self.refuse_button.setMaximumSize(QtCore.QSize(250, 70)) - self.refuse_button.setFont(font) - self.refuse_button.setFlat(True) - self.refuse_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") - ) - self.refuse_button.setText("Ignore") - # 2. Align buttons to the right - self.cf_confirm_layout.addWidget( - self.refuse_button, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - - self.info_layout.addLayout(self.cf_confirm_layout) - - self.cf_content_horizontal_layout.addWidget(self.info_frame) - - self.cf_content_vertical_layout.addLayout(self.cf_content_horizontal_layout) - self.cf_thumbnail = QtWidgets.QGraphicsView(self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.cf_thumbnail.sizePolicy().hasHeightForWidth()) - self.cf_thumbnail.setSizePolicy(sizePolicy) - self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setStyleSheet( - "QGraphicsView{\nbackground-color: transparent;\n}" - ) - self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) - self.cf_thumbnail.setVerticalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setSizeAdjustPolicy( - QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - self.cf_thumbnail.setBackgroundBrush(brush) - self.cf_thumbnail.setRenderHints( - QtGui.QPainter.RenderHint.Antialiasing - | QtGui.QPainter.RenderHint.SmoothPixmapTransform - | QtGui.QPainter.RenderHint.TextAntialiasing - ) - self.cf_thumbnail.setViewportUpdateMode( - QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate - ) - self.cf_thumbnail.setObjectName("cf_thumbnail") - self.cf_content_vertical_layout.addWidget( - self.cf_thumbnail, 0, QtCore.Qt.AlignmentFlag.AlignCenter - ) - self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) diff --git a/tests/widgets/test_files_page_unit.py b/tests/widgets/test_files_page_unit.py index d5c908013..fe5dba032 100644 --- a/tests/widgets/test_files_page_unit.py +++ b/tests/widgets/test_files_page_unit.py @@ -22,7 +22,7 @@ _bc_spec.loader.exec_module(_bc) sys.modules["lib.utils.blocks_combobox"] = _bc -from lib.panels.widgets.filesPage import FilesPage # noqa: E402 +from lib.panels.widgets.PrintTab.filesPage import FilesPage # noqa: E402 from lib.utils.list_model import ListItem # noqa: E402 From 61d2ba64b1b5179b56613ff0ed58a3c834bb33df Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Mon, 28 Sep 2026 12:59:33 +0100 Subject: [PATCH 18/18] chore(merge): absorb #298 squash, keep #291 cancelPage thumbnail logic --- .../panels/widgets/MainWindow/cancelPage.py | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py index 783e3e4fd..ab7819a23 100644 --- a/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py +++ b/BlocksScreen/lib/panels/widgets/MainWindow/cancelPage.py @@ -3,6 +3,7 @@ from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils import gcode_loader from lib.utils.blocks_label import BlocksLabel from PyQt6 import QtCore, QtGui, QtWidgets @@ -99,24 +100,26 @@ def set_file_name(self, file_name: str) -> None: self.cf_file_name.setText(file_name) def _show_screen_thumbnail(self, metadata: dict | None) -> None: - """Display the largest thumbnail from file metadata. - - ``thumbnail_images`` values are pre-loaded ``QImage`` - objects produced by ``Files._process_metadata``. - """ - fallback = QtGui.QPixmap( + """Show the largest thumbnail, else the embedded one or the logo.""" + metadata = metadata or {} + meta_file = metadata.get("filename", "") + # fileinfo is global, every listed file emits it: decode only ours. + if meta_file.removeprefix("/") != self.filename.removeprefix("/"): + return + thumbnails = metadata.get("thumbnail_paths") or [] + last_thumb = QtGui.QPixmap(thumbnails[-1]) if thumbnails else QtGui.QPixmap() + if last_thumb.isNull(): + last_thumb = self._embedded_pixmap(meta_file) + self.set_pixmap(last_thumb) + + def _embedded_pixmap(self, gcode_path: str) -> QtGui.QPixmap: + """Cached embedded thumbnail, else the logo.""" + pixmap = gcode_loader.cached_pixmap(gcode_path) + if pixmap is not None: + return pixmap + return QtGui.QPixmap( "BlocksScreen/lib/ui/resources/media/logoblocks400x300.png" ) - thumbnails = metadata.get("thumbnail_images", []) if metadata else [] - if not thumbnails: - self.set_pixmap(fallback) - return - - last_thumb = thumbnails[-1] - if isinstance(last_thumb, QtGui.QImage) and not last_thumb.isNull(): - self.set_pixmap(QtGui.QPixmap.fromImage(last_thumb)) - else: - self.set_pixmap(fallback) def _setup_ui(self) -> None: """Setup widget ui"""