diff --git a/BlocksScreen/lib/panels/controlTab.py b/BlocksScreen/lib/panels/controlTab.py index 398fe844..17c48f9e 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 b33ba7ee..e40019ef 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 483419e7..ab114198 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 @@ -225,10 +224,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 @@ -1276,20 +1271,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) @@ -1301,56 +1292,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" @@ -1362,8 +1325,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) @@ -1373,154 +1334,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, + + 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", ) - 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.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.QPixmap(blocked), 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_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 ) @@ -1541,7 +1416,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" @@ -1551,26 +1425,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)) @@ -1578,75 +1447,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)) @@ -1654,6 +1488,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, @@ -1662,38 +1497,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 df8c2a95..a0162d28 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -501,7 +501,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( @@ -612,7 +612,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 b05db099..4ba60c84 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 25271694..3369d2d1 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 d55fc229..bae636da 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 96d33103..f845456c 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 968d8988..e2895ac1 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 140f0afb..2b52b56e 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 c167fc2d..08aba9e1 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 28d08bea..0fd58b23 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 db4666bb..2ae19625 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 8c792aa9..234cff0a 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 08a80020..48083b90 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 a3b81682..a3cd4b84 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 00000000..cac0e7e3 --- /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 75fc409e..4a751713 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 413c3895..13c02af0 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 5caf8d13..8db9ca4d 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 348eb3ea..35b959c4 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():