From 8d145fb344d6e0671c595ff6c0e9df80048c22ad Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Fri, 1 Aug 2025 16:24:17 +0100 Subject: [PATCH 01/20] Add: list_button and blocks_Scrollbar , re-do of filePage Ui and its code --- BlocksScreen/BlocksScreen.py | 4 + BlocksScreen/lib/files.py | 1 - BlocksScreen/lib/moonrakerComm.py | 8 +- BlocksScreen/lib/moonrest.py | 2 +- .../lib/panels/widgets/confirmPage.py | 298 ------------------ BlocksScreen/lib/panels/widgets/filesPage.py | 261 ++++++++------- .../ui/resources/background_resources_rc.py | 6 +- BlocksScreen/lib/ui/resources/font_rc.py | 6 +- .../lib/ui/resources/graphic_resources_rc.py | 4 +- .../lib/ui/resources/icon_resources_rc.py | 274 ++++++++-------- .../ui/resources/main_menu_resources_rc.py | 26 +- .../lib/ui/resources/system_resources_rc.py | 4 +- .../lib/ui/resources/top_bar_resources_rc.py | 46 +-- BlocksScreen/lib/utils/blocks_Scrollbar.py | 78 +++++ BlocksScreen/lib/utils/list_button.py | 248 +++++++++++++++ 15 files changed, 671 insertions(+), 595 deletions(-) delete mode 100644 BlocksScreen/lib/panels/widgets/confirmPage.py create mode 100644 BlocksScreen/lib/utils/blocks_Scrollbar.py create mode 100644 BlocksScreen/lib/utils/list_button.py diff --git a/BlocksScreen/BlocksScreen.py b/BlocksScreen/BlocksScreen.py index 539e303c..bb1ae32b 100644 --- a/BlocksScreen/BlocksScreen.py +++ b/BlocksScreen/BlocksScreen.py @@ -1,3 +1,7 @@ +from importupdate import update_imports + +update_imports("BlocksScreen/lib/ui/resources") + import logging import os import sys diff --git a/BlocksScreen/lib/files.py b/BlocksScreen/lib/files.py index be3aa64c..b7524414 100644 --- a/BlocksScreen/lib/files.py +++ b/BlocksScreen/lib/files.py @@ -85,7 +85,6 @@ def on_request_fileinfo(self, filename: str) -> None: "slicer": str, } _file_metadata = self.files_metadata.get(str(filename)) - print(_file_metadata) if not _file_metadata: return _thumbnails = _file_metadata.get("thumbnails", {}) diff --git a/BlocksScreen/lib/moonrakerComm.py b/BlocksScreen/lib/moonrakerComm.py index 0b284dd5..94901d21 100644 --- a/BlocksScreen/lib/moonrakerComm.py +++ b/BlocksScreen/lib/moonrakerComm.py @@ -168,7 +168,7 @@ def connect(self) -> bool: ) return False # _url = f"ws://192.168.1.100:7125/websocket?token={_oneshot_token}" - _url = f"ws://192.168.1.109:7125/websocket?token={_oneshot_token}" + _url = f"ws://localhost:7125/websocket?token={_oneshot_token}" self.ws = websocket.WebSocketApp( _url, on_open=self.on_open, @@ -303,8 +303,8 @@ def on_message(self, *args) -> None: # request server.info in 2 seconds if not self.query_klippy_status_timer.running: self.query_klippy_status_timer.startTimer() - elif response["result"]["klippy_state"] == "disconnected": - if not self.query_klippy_status_timer.running: + elif response["result"]["klippy_state"] == "disconnected": + if not self.query_klippy_status_timer.running: self.query_klippy_status_timer.startTimer() self.klippy_connected_signal.emit( response["result"]["klippy_connected"] @@ -332,7 +332,7 @@ def on_message(self, *args) -> None: ): # Checkout for notify_klippy_disconnect self.evaluate_klippy_status() - message_event = WebSocketMessageReceived( # mainly used to pass websocket notifications + message_event = WebSocketMessageReceived( # mainly used to pass websocket notifications method=str(response["method"]), data=response, metadata=None, diff --git a/BlocksScreen/lib/moonrest.py b/BlocksScreen/lib/moonrest.py index 31a8906e..d9d50e64 100644 --- a/BlocksScreen/lib/moonrest.py +++ b/BlocksScreen/lib/moonrest.py @@ -30,7 +30,7 @@ class MoonRest: # TODO: The ip and port need to come from a configfile # def __init__(self, ip="localhost", port="7125", api_key=False): - def __init__(self, ip="192.168.1.109", port="7125", api_key=False): + def __init__(self, ip="localhost", port="7125", api_key=False): self._ip = ip self._port = port self._api_key = api_key diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/confirmPage.py deleted file mode 100644 index 0b3bffc7..00000000 --- a/BlocksScreen/lib/panels/widgets/confirmPage.py +++ /dev/null @@ -1,298 +0,0 @@ -import typing - -from lib.utils.blocks_button import BlocksCustomButton -from lib.utils.blocks_label import BlocksLabel -from PyQt6 import QtCore, QtGui, QtWidgets - - -class ConfirmWidget(QtWidgets.QWidget): - on_accept: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - str, name="on_accept" - ) - on_reject: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - name="on_reject" - ) - - def __init__(self, parent) -> None: - super().__init__(parent) - self.setupUI() - self.setMouseTracking(True) - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) - self.thumbnail: QtGui.QImage = QtGui.QImage() - self.confirm_button.clicked.connect( - lambda: self.on_accept.emit(str(self.cf_file_name._text)) - ) - self.reject_button.clicked.connect(self.on_reject.emit) - - @QtCore.pyqtSlot(str, dict, name="on_show_widget") - def on_show_widget(self, text: str, filedata: dict | None = None) -> None: - self.cf_file_name.setText(str(text)) - if not filedata: - return - _thumbnails = filedata.get("thumbnail_images") - - if _thumbnails: - _biggest_thumbnail = _thumbnails[len(_thumbnails) - 1] - self.thumbnail = QtGui.QImage(_biggest_thumbnail) - - _total_filament = filedata.get("filament_total") - _estimated_time = filedata.get("estimated_time") - self.cf_info.setText( - "Total Filament:" - + str(_total_filament) - + "\n" - + "Slicer time: " - + str(_estimated_time) - ) - self.repaint() - - def paintEvent(self, a0: QtGui.QPaintEvent) -> None: - _scene = QtWidgets.QGraphicsScene() - if not self.thumbnail.isNull(): - _graphics_rect = self.cf_thumbnail.rect().toRectF() - _image_rect = self.thumbnail.rect() - - scaled_width = _image_rect.width() - scaled_height = _image_rect.height() - adjusted_x = (_graphics_rect.width() - scaled_width) // 2.0 - adjusted_y = (_graphics_rect.height() - scaled_height) // 2.0 - - adjusted_rect = QtCore.QRectF( - _image_rect.x() + adjusted_x, - _image_rect.y() + adjusted_y, - scaled_width, - scaled_height, - ) - _scene.setSceneRect(adjusted_rect) - _item_scaled = QtWidgets.QGraphicsPixmapItem( - QtGui.QPixmap.fromImage(self.thumbnail).scaled( - int(scaled_width), - int(scaled_height), - QtCore.Qt.AspectRatioMode.KeepAspectRatio, - QtCore.Qt.TransformationMode.SmoothTransformation, - ) - ) - _scene.addItem(_item_scaled) - self.cf_thumbnail.setScene(_scene) - - else: - self.cf_thumbnail.setScene(_scene) - - def showEvent(self, a0: QtGui.QShowEvent) -> None: - if not self.thumbnail: - self.cf_thumbnail.close() - return super().showEvent(a0) - - def hideEvent(self, a0: QtGui.QHideEvent) -> None: - return super().hideEvent(a0) - - def setupUI(self) -> None: - 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(710, 400)) - self.setMaximumSize(QtCore.QSize(720, 420)) - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) - self.verticalLayout_4.setObjectName("verticalLayout_4") - self.cf_header_title = QtWidgets.QHBoxLayout() - self.cf_header_title.setObjectName("cf_header_title") - self.confirm_title_label = QtWidgets.QLabel(parent=self) - self.confirm_title_label.setMinimumSize(QtCore.QSize(0, 60)) - self.confirm_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(24) - self.confirm_title_label.setFont(font) - self.confirm_title_label.setLayoutDirection( - QtCore.Qt.LayoutDirection.RightToLeft - ) - self.confirm_title_label.setStyleSheet( - "background: transparent; color: white;" - ) - self.confirm_title_label.setAlignment( - QtCore.Qt.AlignmentFlag.AlignCenter - ) - self.confirm_title_label.setObjectName("confirm_title_label") - self.cf_header_title.addWidget(self.confirm_title_label) - self.verticalLayout_4.addLayout(self.cf_header_title) - self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() - self.cf_content_vertical_layout.setObjectName( - "cf_content_vertical_layout" - ) - self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() - self.cf_content_horizontal_layout.setObjectName( - "cf_content_horizontal_layout" - ) - self.cf_info = QtWidgets.QLabel(parent=self) - self.cf_info.setEnabled(True) - self.cf_info.setMinimumSize(QtCore.QSize(200, 60)) - self.cf_info.setMaximumSize(QtCore.QSize(250, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(14) - self.cf_info.setFont(font) - self.cf_info.setStyleSheet("background: transparent; color: white;") - self.cf_info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_info.setWordWrap(True) - self.cf_info.setObjectName("cf_info") - self.cf_content_horizontal_layout.addWidget( - self.cf_info, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ) - self.cf_file_name = BlocksLabel(parent=self) - self.cf_file_name.setEnabled(True) - self.cf_file_name.setMinimumSize(QtCore.QSize(250, 80)) - self.cf_file_name.setMaximumSize(QtCore.QSize(250, 80)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(14) - self.cf_file_name.setFont(font) - self.cf_file_name.setStyleSheet( - "background: transparent; color: white;" - ) - self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.cf_file_name.setWordWrap(True) - self.cf_file_name.setObjectName("cf_file_name") - self.cf_content_horizontal_layout.addWidget( - self.cf_file_name, 0, QtCore.Qt.AlignmentFlag.AlignHCenter - ) - self.cf_confirm_layout = QtWidgets.QVBoxLayout() - self.cf_confirm_layout.setSizeConstraint( - QtWidgets.QLayout.SizeConstraint.SetFixedSize - ) - self.cf_confirm_layout.setContentsMargins(0, 0, 0, 0) - self.cf_confirm_layout.setSpacing(2) - self.cf_confirm_layout.setObjectName("cf_confirm_layout") - self.confirm_button = BlocksCustomButton(parent=self) - self.confirm_button.setMinimumSize(QtCore.QSize(200, 60)) - self.confirm_button.setMaximumSize(QtCore.QSize(200, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(18) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - self.confirm_button.setFont(font) - self.confirm_button.setMouseTracking(False) - self.confirm_button.setTabletTracking(True) - self.confirm_button.setContextMenuPolicy( - QtCore.Qt.ContextMenuPolicy.NoContextMenu - ) - self.confirm_button.setLayoutDirection( - QtCore.Qt.LayoutDirection.LeftToRight - ) - self.confirm_button.setStyleSheet("") - self.confirm_button.setAutoDefault(False) - self.confirm_button.setFlat(True) - self.confirm_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") - ) - self.confirm_button.setObjectName("confirm_button") - self.cf_confirm_layout.addWidget( - self.confirm_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ) - self.reject_button = BlocksCustomButton(parent=self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Fixed, - QtWidgets.QSizePolicy.Policy.Fixed, - ) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth( - self.reject_button.sizePolicy().hasHeightForWidth() - ) - self.reject_button.setSizePolicy(sizePolicy) - self.reject_button.setMinimumSize(QtCore.QSize(200, 60)) - self.reject_button.setMaximumSize(QtCore.QSize(200, 60)) - font = QtGui.QFont() - font.setFamily("Momcake") - font.setPointSize(18) - font.setItalic(False) - font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - - self.reject_button.setFont(font) - self.reject_button.setMouseTracking(False) - self.reject_button.setTabletTracking(True) - self.reject_button.setContextMenuPolicy( - QtCore.Qt.ContextMenuPolicy.NoContextMenu - ) - self.reject_button.setLayoutDirection( - QtCore.Qt.LayoutDirection.LeftToRight - ) - self.reject_button.setStyleSheet("") - self.reject_button.setAutoDefault(False) - self.reject_button.setFlat(True) - self.reject_button.setProperty( - "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") - ) - self.reject_button.setObjectName("reject") - self.cf_confirm_layout.addWidget( - self.reject_button, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ) - self.cf_content_horizontal_layout.addLayout(self.cf_confirm_layout) - self.cf_content_vertical_layout.addLayout( - self.cf_content_horizontal_layout - ) - self.cf_thumbnail = QtWidgets.QGraphicsView(parent=self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.Expanding, - QtWidgets.QSizePolicy.Policy.Expanding, - ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth( - self.cf_thumbnail.sizePolicy().hasHeightForWidth() - ) - self.cf_thumbnail.setSizePolicy(sizePolicy) - self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) - self.cf_thumbnail.setStyleSheet( - "QGraphicsView{\nbackground-color: transparent;\n}" - ) - self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) - self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) - self.cf_thumbnail.setVerticalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setHorizontalScrollBarPolicy( - QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff - ) - self.cf_thumbnail.setSizeAdjustPolicy( - QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - self.cf_thumbnail.setBackgroundBrush(brush) - self.cf_thumbnail.setRenderHints( - QtGui.QPainter.RenderHint.Antialiasing - | QtGui.QPainter.RenderHint.SmoothPixmapTransform - | QtGui.QPainter.RenderHint.TextAntialiasing - ) - self.cf_thumbnail.setViewportUpdateMode( - QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate - ) - self.cf_thumbnail.setObjectName("cf_thumbnail") - self.cf_content_vertical_layout.addWidget( - self.cf_thumbnail, - 0, - QtCore.Qt.AlignmentFlag.AlignHCenter - | QtCore.Qt.AlignmentFlag.AlignVCenter, - ) - self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) - - self.confirm_title_label.setText("Print File?") - self.confirm_button.setText("Accept") - self.reject_button.setText("Cancel") diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index b17cf140..84849f51 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -1,7 +1,10 @@ +from functools import partial from PyQt6 import QtCore, QtGui, QtWidgets import typing from lib.utils.icon_button import IconButton +from lib.utils.list_button import ListCustomButton +from lib.utils.blocks_Scrollbar import CustomScrollBar class FilesPage(QtWidgets.QWidget): @@ -23,20 +26,62 @@ class FilesPage(QtWidgets.QWidget): def __init__(self, parent) -> None: super().__init__(parent) self.setupUI() - self.setMouseTracking(True) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) - self.listWidget.itemClicked.connect(self.fileItemClicked) - self.ReloadButton.clicked.connect(lambda: self.reload_list) + + self.ReloadButton.clicked.connect(lambda: self.reload_list()) + + self.listWidget.verticalScrollBar().valueChanged.connect( + self.handlescrollbar + ) + self.scrollbar.valueChanged.connect(self.handlescrollbar) + + self.scrollbar.valueChanged.connect( + lambda value: self.listWidget.verticalScrollBar().setValue(value) + ) def showEvent(self, a0: QtGui.QShowEvent) -> None: self.add_file_entries() return super().showEvent(a0) + def estimate_print_time(self, seconds: int) -> list: + num_min, seconds = divmod(seconds, 60) + num_hours, minutes = divmod(num_min, 60) + days, hours = divmod(num_hours, 24) + return [days, hours, minutes, seconds] + @QtCore.pyqtSlot(dict, name="on_fileinfo") def on_fileinfo(self, filedata: dict) -> None: - if self._current_file_name: - self.file_selected.emit(str(self._current_file_name), filedata) + if self.buttons: + estimated_time = filedata.get("estimated_time", 0) + seconds = ( + int(estimated_time) + if isinstance(estimated_time, (int, float)) + else 0 + ) + + filament_type = ( + filedata.get("filament_type", "Unknown filament") + if filedata.get("filament_type", "Unknown filament") != -1.0 + else "Unknown filament" + ) + time_str = "" + days, hours, minutes, _ = self.estimate_print_time(seconds) + if seconds <= 0: + time_str = "No time estimated" + elif seconds < 60: + time_str = "less than 1 minute" + else: + if days > 0: + time_str = f"{days}d {hours}h {minutes}m" + elif hours > 0: + time_str = f"{hours}h {minutes}m" + else: + time_str = f"{minutes}m" + + self.button.setRightText(f"{filament_type} - {time_str}") + return + self.file_selected.emit(str(self._current_file_name), filedata) @QtCore.pyqtSlot(name="reload_list") def reload_list(self) -> None: @@ -50,49 +95,79 @@ def on_file_list(self, file_list: list) -> None: self.add_file_entries() @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name="file_item_clicked") - def fileItemClicked(self, item: QtWidgets.QListWidgetItem) -> None: + def fileItemClicked(self, item: str) -> None: """Slot for List Item clicked Args: item (QListWidgetItem): Clicked item """ # * Get the filename from the list item pressed - _current_item: QtWidgets.QWidget = self.listWidget.itemWidget(item) - if _current_item is not None: - self._current_file_name = _current_item.findChild( - QtWidgets.QLabel - ).text() # type: ignore + if item is not None: + self._current_file_name = item if self._current_file_name: self.request_file_info.emit(self._current_file_name) def add_file_entries(self) -> None: """Inserts the currently available gcode files on the QListWidget""" self.listWidget.clear() + + self.listWidget.setSpacing(35) index = 0 + self.buttons = True - def _add_entry(): - _item = QtWidgets.QListWidgetItem() - _item_widget = QtWidgets.QWidget() - _item_layout = QtWidgets.QHBoxLayout() - _item_text = QtWidgets.QLabel() - _item_text.setText(str(item["path"])) - _item_text.setAlignment( - QtCore.Qt.AlignmentFlag.AlignLeft - & QtCore.Qt.AlignmentFlag.AlignVCenter + sorted_list = sorted( + self.file_list, key=lambda x: x["modified"], reverse=True + ) + + for item in sorted_list: + self.button = ListCustomButton() + self.button.setText(str(item["path"][:-6])) + self.request_file_info.emit(item["path"]) + + self.button.setPixmap( + QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg") + ) + self.button.setFixedSize(600, 80) + self.button.setLeftFontSize(17) + self.button.setRightFontSize(12) + + list_item = QtWidgets.QListWidgetItem() + list_item.setSizeHint(self.button.sizeHint()) + + self.listWidget.addItem(list_item) + self.listWidget.setItemWidget(list_item, self.button) + + namefile = str(item["path"]) + self.button.clicked.connect( + partial(self.fileItemClicked, namefile) ) - _item_layout.addWidget(_item_text) - _item_widget.setLayout(_item_layout) - _item.setSizeHint(_item_widget.sizeHint()) - _item.setFlags(~QtCore.Qt.ItemFlag.ItemIsEditable) - return _item, _item_widget - - for item in self.file_list: - # TODO: Add a file icon before the name - _item, _item_widget = _add_entry() - self.listWidget.addItem(_item) - self.listWidget.setItemWidget(_item, _item_widget) index += 1 + self.buttons = False + + spacer_item = QtWidgets.QListWidgetItem() + spacer_widget = QtWidgets.QWidget() + spacer_widget.setFixedHeight(10) + spacer_item.setSizeHint(spacer_widget.sizeHint()) + self.listWidget.addItem(spacer_item) + + self.scrollbar.setMinimum( + self.listWidget.verticalScrollBar().minimum() + ) + self.scrollbar.setMaximum( + self.listWidget.verticalScrollBar().maximum() + ) + self.scrollbar.setPageStep( + self.listWidget.verticalScrollBar().pageStep() + ) + + def handlescrollbar(self, value): + # Block signals to avoid recursion + + self.scrollbar.blockSignals(True) + self.scrollbar.setValue(value) + self.scrollbar.blockSignals(False) + def setupUI(self): sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, @@ -145,88 +220,58 @@ def setupUI(self): self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line.setObjectName("line") self.verticalLayout_5.addWidget(self.line) - self.fp_content_layout = QtWidgets.QVBoxLayout() - self.fp_content_layout.setContentsMargins(5, 5, 5, 5) + self.fp_content_layout = QtWidgets.QHBoxLayout() + self.fp_content_layout.setContentsMargins(0, 0, 0, 0) self.fp_content_layout.setObjectName("fp_content_layout") self.listWidget = QtWidgets.QListWidget(parent=self) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.Window, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Button, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Base, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.Window, - brush, - ) - self.listWidget.setPalette(palette) - self.listWidget.setStyleSheet( - "QListWidget{background-color: transparent;}\n" - "\n" - "QLabel{\n" - "color: #ffffff;\n" - "}" - ) - self.listWidget.setEditTriggers( - QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers - ) self.listWidget.setProperty("showDropIndicator", False) + self.listWidget.setProperty("selectionMode", "NoSelection") + self.listWidget.setStyleSheet("background: transparent;") self.listWidget.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) self.listWidget.setUniformItemSizes(True) self.listWidget.setObjectName("listWidget") + self.listWidget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.listWidget.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) + self.listWidget.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems + ) + self.listWidget.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + ) + self.listWidget.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + QtWidgets.QScroller.grabGesture( + self.listWidget, + QtWidgets.QScroller.ScrollerGestureType.TouchGesture, + ) + QtWidgets.QScroller.grabGesture( + self.listWidget, + QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, + ) + self.listWidget.setEditTriggers( + QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers + ) + + scroller_instance = QtWidgets.QScroller.scroller(self.listWidget) + scroller_props = scroller_instance.scrollerProperties() + scroller_props.setScrollMetric( + QtWidgets.QScrollerProperties.ScrollMetric.DragVelocitySmoothingFactor, + 0.05, # Lower = more responsive + ) + scroller_props.setScrollMetric( + QtWidgets.QScrollerProperties.ScrollMetric.DecelerationFactor, + 0.4, # higher = less inertia + ) + QtWidgets.QScroller.scroller(self.listWidget).setScrollerProperties( + scroller_props + ) + self.fp_content_layout.addWidget(self.listWidget) + self.scrollbar = CustomScrollBar() + self.fp_content_layout.addWidget(self.scrollbar) self.verticalLayout_5.addLayout(self.fp_content_layout) + self.scrollbar.setAttribute( + QtCore.Qt.WidgetAttribute.WA_TransparentForMouseEvents, True + ) + self.scroller = QtWidgets.QScroller.scroller(self.listWidget) diff --git a/BlocksScreen/lib/ui/resources/background_resources_rc.py b/BlocksScreen/lib/ui/resources/background_resources_rc.py index af33bd2a..b0d795b7 100644 --- a/BlocksScreen/lib/ui/resources/background_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/background_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -9358,9 +9358,9 @@ \x00\x00\x00\x1a\x00\x02\x00\x00\x00\x02\x00\x00\x00\x03\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x2a\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x95\x80\xac\x82\x07\ +\x00\x00\x01\x98\x51\xb9\x78\xec\ \x00\x00\x00\x4c\x00\x00\x00\x00\x00\x01\x00\x00\x1a\xfc\ -\x00\x00\x01\x95\x80\xac\x80\x2d\ +\x00\x00\x01\x98\x51\xb9\x78\x3c\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/font_rc.py b/BlocksScreen/lib/ui/resources/font_rc.py index 739e03be..01d59ae7 100644 --- a/BlocksScreen/lib/ui/resources/font_rc.py +++ b/BlocksScreen/lib/ui/resources/font_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -5066,9 +5066,9 @@ \x00\x00\x00\x1e\x00\x02\x00\x00\x00\x02\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x40\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x95\x80\xac\x96\x55\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x00\x66\x00\x00\x00\x00\x00\x01\x00\x00\x9f\x10\ -\x00\x00\x01\x95\x80\xac\x96\x79\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/graphic_resources_rc.py b/BlocksScreen/lib/ui/resources/graphic_resources_rc.py index 8130f61e..8bc7b1d3 100644 --- a/BlocksScreen/lib/ui/resources/graphic_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/graphic_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -568,7 +568,7 @@ \x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x26\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x95\x80\xac\x9b\xc7\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/icon_resources_rc.py b/BlocksScreen/lib/ui/resources/icon_resources_rc.py index 558a9252..7bb04534 100644 --- a/BlocksScreen/lib/ui/resources/icon_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/icon_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -25197,75 +25197,75 @@ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x0d\x00\x00\x00\x12\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x08\x66\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x01\xf8\x00\x00\x00\x00\x00\x01\x00\x00\x09\x52\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x02\x20\x00\x00\x00\x00\x00\x01\x00\x00\x0a\x35\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x02\x48\x00\x00\x00\x00\x00\x01\x00\x00\x0b\x18\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x02\x70\x00\x00\x00\x00\x00\x01\x00\x00\x0c\x06\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x02\xa4\x00\x00\x00\x00\x00\x01\x00\x00\x14\x42\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x02\xd0\x00\x00\x00\x00\x00\x01\x00\x00\x1d\xf7\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x02\xfa\x00\x00\x00\x00\x00\x01\x00\x00\x22\x41\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x03\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x26\x90\ -\x00\x00\x01\x96\x67\x94\xac\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x03\x36\x00\x00\x00\x00\x00\x01\x00\x00\x2c\x6e\ -\x00\x00\x01\x96\x67\x94\xac\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x03\x52\x00\x00\x00\x00\x00\x01\x00\x00\x30\xca\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x03\x7a\x00\x00\x00\x00\x00\x01\x00\x00\x32\xb1\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x20\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x04\x00\x00\x00\x21\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x03\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x3a\x55\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x03\xbe\x00\x00\x00\x00\x00\x01\x00\x00\x3c\xcf\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x03\xe0\x00\x00\x00\x00\x00\x01\x00\x00\x3f\x43\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x03\xfe\x00\x00\x00\x00\x00\x01\x00\x00\x41\xbf\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x26\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x0a\x00\x00\x00\x27\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x04\x20\x00\x00\x00\x00\x00\x01\x00\x00\x44\x3b\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x04\x3a\x00\x00\x00\x00\x00\x01\x00\x00\x45\x3c\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x04\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x4a\x54\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x04\x9a\x00\x00\x00\x00\x00\x01\x00\x00\x56\x16\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x04\xc4\x00\x00\x00\x00\x00\x01\x00\x00\x58\x86\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x04\xea\x00\x00\x00\x00\x00\x01\x00\x00\x5e\x1e\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x05\x0e\x00\x00\x00\x00\x00\x01\x00\x00\x62\x7a\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x05\x48\x00\x00\x00\x00\x00\x01\x00\x00\x69\x07\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x05\x64\x00\x00\x00\x00\x00\x01\x00\x00\x6c\x03\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x05\x8c\x00\x00\x00\x00\x00\x01\x00\x00\x6d\x01\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x32\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x02\x00\x00\x00\x33\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x05\xbe\x00\x01\x00\x00\x00\x01\x00\x00\x77\x6b\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x05\xd0\x00\x00\x00\x00\x00\x01\x00\x02\x3a\xc0\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x02\x00\x00\x00\x36\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x06\x00\x00\x00\x3f\ @@ -25273,259 +25273,259 @@ \x00\x00\x05\xe4\x00\x02\x00\x00\x00\x07\x00\x00\x00\x38\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x05\xf6\x00\x00\x00\x00\x00\x01\x00\x02\x3f\x46\ -\x00\x00\x01\x95\x80\xac\x7d\x6d\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x06\x2a\x00\x00\x00\x00\x00\x01\x00\x02\x49\xaa\ -\x00\x00\x01\x95\x80\xac\x7f\x44\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x06\x5e\x00\x00\x00\x00\x00\x01\x00\x02\x53\xd3\ -\x00\x00\x01\x95\x80\xac\x7c\xdf\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x06\x98\x00\x00\x00\x00\x00\x01\x00\x02\x5e\x2b\ -\x00\x00\x01\x95\x80\xac\x7e\xbb\ +\x00\x00\x01\x98\x51\xb9\x78\xf8\ \x00\x00\x06\xcc\x00\x00\x00\x00\x00\x01\x00\x02\x68\x43\ -\x00\x00\x01\x95\x80\xac\x7e\x0c\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x07\x02\x00\x00\x00\x00\x00\x01\x00\x02\x72\x6c\ -\x00\x00\x01\x95\x80\xac\x80\x06\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x07\x3a\x00\x00\x00\x00\x00\x01\x00\x02\x7c\x82\ -\x00\x00\x01\x95\x80\xac\x7e\xe6\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x07\x70\x00\x00\x00\x00\x00\x01\x00\x02\x86\xe8\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x07\x98\x00\x00\x00\x00\x00\x01\x00\x02\x91\x17\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x07\xc4\x00\x00\x00\x00\x00\x01\x00\x02\x9b\x5e\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x08\x00\x00\x00\x00\x00\x00\x01\x00\x02\x9d\x5f\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x08\x2c\x00\x00\x00\x00\x00\x01\x00\x02\xb8\xa4\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x08\x58\x00\x00\x00\x00\x00\x01\x00\x02\xbd\xed\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x46\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x02\x00\x00\x00\x47\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x08\x8c\x00\x00\x00\x00\x00\x01\x00\x02\xc1\x65\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x08\xaa\x00\x00\x00\x00\x00\x01\x00\x02\xca\x47\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x4a\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x0d\x00\x00\x00\x4b\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x08\xbe\x00\x00\x00\x00\x00\x01\x00\x02\xcf\x7c\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x08\xe6\x00\x00\x00\x00\x00\x01\x00\x02\xd4\x77\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x09\x1e\x00\x00\x00\x00\x00\x01\x00\x02\xdd\x4b\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x09\x56\x00\x00\x00\x00\x00\x01\x00\x02\xe5\xef\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x09\x86\x00\x00\x00\x00\x00\x01\x00\x02\xed\x8e\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x09\xaa\x00\x00\x00\x00\x00\x01\x00\x02\xf5\x6a\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x09\xce\x00\x00\x00\x00\x00\x01\x00\x02\xfd\x20\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0a\x02\x00\x00\x00\x00\x00\x01\x00\x03\x05\x2e\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0a\x36\x00\x00\x00\x00\x00\x01\x00\x03\x0d\x10\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0a\x6a\x00\x00\x00\x00\x00\x01\x00\x03\x14\xda\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0a\xa4\x00\x00\x00\x00\x00\x01\x00\x03\x1c\x41\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0a\xc8\x00\x00\x00\x00\x00\x01\x00\x03\x1f\xfe\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0a\xf6\x00\x00\x00\x00\x00\x01\x00\x03\x23\xd7\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x59\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x07\x00\x00\x00\x5a\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0b\x1c\x00\x00\x00\x00\x00\x01\x00\x03\x29\xe0\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0b\x48\x00\x00\x00\x00\x00\x01\x00\x03\x4c\x64\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0b\x76\x00\x00\x00\x00\x00\x01\x00\x03\x52\x51\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0b\xa0\x00\x00\x00\x00\x00\x01\x00\x03\x54\x71\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0b\xc8\x00\x00\x00\x00\x00\x01\x00\x03\x5d\x09\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0b\xe2\x00\x00\x00\x00\x00\x01\x00\x03\x6c\x52\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0c\x0e\x00\x00\x00\x00\x00\x01\x00\x03\x72\xd0\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x62\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x0c\x00\x00\x00\x63\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0c\x36\x00\x00\x00\x00\x00\x01\x00\x03\x7d\x4a\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0c\x64\x00\x00\x00\x00\x00\x01\x00\x03\x7f\xf1\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0c\x92\x00\x01\x00\x00\x00\x01\x00\x03\x8c\x6e\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0c\xbe\x00\x00\x00\x00\x00\x01\x00\x03\xb9\xed\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0c\xde\x00\x00\x00\x00\x00\x01\x00\x03\xbe\xa4\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0d\x10\x00\x01\x00\x00\x00\x01\x00\x04\x17\x9d\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0d\x42\x00\x00\x00\x00\x00\x01\x00\x04\x4c\x37\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0d\x5c\x00\x00\x00\x00\x00\x01\x00\x04\x51\x81\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0d\x76\x00\x00\x00\x00\x00\x01\x00\x04\x57\x10\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0d\x90\x00\x00\x00\x00\x00\x01\x00\x04\x5c\x79\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0d\xa8\x00\x00\x00\x00\x00\x01\x00\x04\x68\x57\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x0d\xc6\x00\x00\x00\x00\x00\x01\x00\x04\x6e\x5b\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x70\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x04\x00\x00\x00\x71\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0d\xee\x00\x00\x00\x00\x00\x01\x00\x04\x73\x90\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0e\x02\x00\x00\x00\x00\x00\x01\x00\x04\x79\x8d\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0e\x14\x00\x00\x00\x00\x00\x01\x00\x04\x7b\x13\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0e\x26\x00\x00\x00\x00\x00\x01\x00\x04\x81\x0d\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x76\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x02\x00\x00\x00\x77\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0e\x3a\x00\x00\x00\x00\x00\x01\x00\x04\x83\x63\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0e\x66\x00\x00\x00\x00\x00\x01\x00\x04\x8a\x4a\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x7a\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x09\x00\x00\x00\x7b\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0e\x8a\x00\x00\x00\x00\x00\x01\x00\x04\x93\xae\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x3c\ \x00\x00\x0e\xaa\x00\x01\x00\x00\x00\x01\x00\x04\x96\x5a\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x0e\xce\x00\x00\x00\x00\x00\x01\x00\x04\xa1\xab\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x0e\xf0\x00\x00\x00\x00\x00\x01\x00\x04\xa9\x50\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x0f\x0c\x00\x00\x00\x00\x00\x01\x00\x04\xba\x50\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x0f\x30\x00\x00\x00\x00\x00\x01\x00\x04\xc3\xd1\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x0f\x50\x00\x00\x00\x00\x00\x01\x00\x04\xc9\x6e\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x0f\x78\x00\x00\x00\x00\x00\x01\x00\x04\xd3\x37\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x3c\ \x00\x00\x0f\x98\x00\x00\x00\x00\x00\x01\x00\x04\xd7\x1a\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x85\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x09\x00\x00\x00\x86\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x0f\xb4\x00\x00\x00\x00\x00\x01\x00\x04\xdd\x55\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x0f\xe4\x00\x00\x00\x00\x00\x01\x00\x04\xe6\xeb\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x10\x14\x00\x00\x00\x00\x00\x01\x00\x04\xf2\xc7\ -\x00\x00\x01\x96\x90\x6d\xef\x70\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x10\x38\x00\x00\x00\x00\x00\x01\x00\x04\xf9\x0b\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x10\x62\x00\x00\x00\x00\x00\x01\x00\x05\x00\x94\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x10\x8e\x00\x00\x00\x00\x00\x01\x00\x05\x06\xf2\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x10\xc4\x00\x00\x00\x00\x00\x01\x00\x05\x0e\xe1\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x08\xaa\x00\x00\x00\x00\x00\x01\x00\x05\x1c\x84\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x10\xe2\x00\x00\x00\x00\x00\x01\x00\x05\x21\xb9\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x90\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x01\x00\x00\x00\x91\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x10\xfc\x00\x00\x00\x00\x00\x01\x00\x05\x2b\x8e\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x01\x88\x00\x02\x00\x00\x00\x01\x00\x00\x00\x93\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x01\x98\x00\x02\x00\x00\x00\x23\x00\x00\x00\x94\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x11\x1c\x00\x00\x00\x00\x00\x01\x00\x05\x30\x54\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x11\x32\x00\x00\x00\x00\x00\x01\x00\x05\x38\x08\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x11\x4a\x00\x00\x00\x00\x00\x01\x00\x05\x3a\x2d\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x11\x82\x00\x00\x00\x00\x00\x01\x00\x05\x3b\xad\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x11\x9e\x00\x00\x00\x00\x00\x01\x00\x05\x43\x5a\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x11\xbe\x00\x00\x00\x00\x00\x01\x00\x05\x48\x2f\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x11\xd4\x00\x00\x00\x00\x00\x01\x00\x05\x49\x1f\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x11\xea\x00\x00\x00\x00\x00\x01\x00\x05\x4c\x03\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x12\x10\x00\x00\x00\x00\x00\x01\x00\x05\x52\x3a\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x12\x26\x00\x00\x00\x00\x00\x01\x00\x05\x55\x39\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x12\x3c\x00\x00\x00\x00\x00\x01\x00\x05\x5b\x43\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x12\x6e\x00\x00\x00\x00\x00\x01\x00\x05\x5e\x92\ -\x00\x00\x01\x97\xa7\xa2\x2a\x9b\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x12\x86\x00\x00\x00\x00\x00\x01\x00\x05\x68\x13\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x12\x9c\x00\x00\x00\x00\x00\x01\x00\x05\x6e\x0a\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x12\xc2\x00\x00\x00\x00\x00\x01\x00\x05\x77\xbe\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x12\xec\x00\x00\x00\x00\x00\x01\x00\x05\x7b\x0c\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x13\x0e\x00\x00\x00\x00\x00\x01\x00\x05\x7e\x9a\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x13\x22\x00\x00\x00\x00\x00\x01\x00\x05\x88\x6c\ -\x00\x00\x01\x96\x90\x7a\xe7\xc0\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x13\x4e\x00\x00\x00\x00\x00\x01\x00\x05\x8d\xb6\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x13\x76\x00\x00\x00\x00\x00\x01\x00\x05\x93\xbd\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x13\x8c\x00\x00\x00\x00\x00\x01\x00\x05\x94\xa1\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x13\xb8\x00\x00\x00\x00\x00\x01\x00\x05\x96\xea\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x50\ \x00\x00\x13\xce\x00\x00\x00\x00\x00\x01\x00\x05\x9d\x9a\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x13\xea\x00\x00\x00\x00\x00\x01\x00\x05\xa0\xde\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x14\x02\x00\x00\x00\x00\x00\x01\x00\x05\xa2\x0a\ -\x00\x00\x01\x96\x90\x7a\xd4\x38\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x14\x1c\x00\x00\x00\x00\x00\x01\x00\x05\xa7\xcb\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x14\x3e\x00\x00\x00\x00\x00\x01\x00\x05\xa8\xed\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x14\x5c\x00\x00\x00\x00\x00\x01\x00\x05\xae\xe0\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x14\x7c\x00\x00\x00\x00\x00\x01\x00\x05\xb1\xe4\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x14\x9e\x00\x00\x00\x00\x00\x01\x00\x05\xb3\x05\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x14\xbe\x00\x00\x00\x00\x00\x01\x00\x05\xb5\xd9\ -\x00\x00\x01\x96\x90\x7a\xdf\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ \x00\x00\x14\xec\x00\x00\x00\x00\x00\x01\x00\x05\xbe\x45\ -\x00\x00\x01\x96\x90\x6d\xf3\x58\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ \x00\x00\x15\x10\x00\x00\x00\x00\x00\x01\x00\x05\xc6\x05\ -\x00\x00\x01\x96\x90\x7a\xdc\x08\ +\x00\x00\x01\x98\x51\xb9\x78\x48\ \x00\x00\x15\x34\x00\x00\x00\x00\x00\x01\x00\x05\xcb\x20\ -\x00\x00\x01\x96\x90\x7a\xd8\x20\ +\x00\x00\x01\x98\x51\xb9\x78\x44\ \x00\x00\x15\x5c\x00\x00\x00\x00\x00\x01\x00\x05\xcc\x73\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x40\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/main_menu_resources_rc.py b/BlocksScreen/lib/ui/resources/main_menu_resources_rc.py index c4e463df..a548aeab 100644 --- a/BlocksScreen/lib/ui/resources/main_menu_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/main_menu_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -28766,29 +28766,29 @@ \x00\x00\x00\x20\x00\x02\x00\x00\x00\x0c\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x38\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x95\x80\xac\x7c\x4b\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x00\x58\x00\x00\x00\x00\x00\x01\x00\x00\x85\x4c\ -\x00\x00\x01\x95\x80\xac\x7a\x88\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x00\x92\x00\x00\x00\x00\x00\x01\x00\x00\xd6\x9c\ -\x00\x00\x01\x95\x80\xac\x7b\x52\ +\x00\x00\x01\x98\x51\xb9\x78\xec\ \x00\x00\x00\xb8\x00\x00\x00\x00\x00\x01\x00\x01\x89\x56\ -\x00\x00\x01\x95\x80\xac\x7c\x8f\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x00\xe0\x00\x00\x00\x00\x00\x01\x00\x02\x61\x5c\ -\x00\x00\x01\x95\x80\xac\x7a\xbc\ +\x00\x00\x01\x98\x51\xb9\x78\xec\ \x00\x00\x01\x16\x00\x00\x00\x00\x00\x01\x00\x03\x01\x56\ -\x00\x00\x01\x95\x80\xac\x7a\xf4\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x01\x40\x00\x00\x00\x00\x00\x01\x00\x03\x5a\x9f\ -\x00\x00\x01\x95\x80\xac\x7b\x17\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x01\x70\x00\x00\x00\x00\x00\x01\x00\x03\xce\x01\ -\x00\x00\x01\x95\x80\xac\x7c\x04\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x01\xaa\x00\x00\x00\x00\x00\x01\x00\x04\x2d\x70\ -\x00\x00\x01\x95\x80\xac\x7c\x2c\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x01\xe2\x00\x00\x00\x00\x00\x01\x00\x05\x01\xcf\ -\x00\x00\x01\x95\x80\xac\x7b\x7f\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x05\xb6\xcc\ -\x00\x00\x01\x95\x80\xac\x7a\xd6\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ \x00\x00\x02\x52\x00\x00\x00\x00\x00\x01\x00\x06\x73\x46\ -\x00\x00\x01\x95\x80\xac\x7b\xdf\ +\x00\x00\x01\x98\x51\xb9\x78\xf0\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/system_resources_rc.py b/BlocksScreen/lib/ui/resources/system_resources_rc.py index 5df0d511..7ab9977a 100644 --- a/BlocksScreen/lib/ui/resources/system_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/system_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -603,7 +603,7 @@ \x00\x00\x00\x2e\x00\x02\x00\x00\x00\x01\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x46\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x96\x90\x7a\xe3\xd8\ +\x00\x00\x01\x98\x51\xb9\x78\x4c\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/ui/resources/top_bar_resources_rc.py b/BlocksScreen/lib/ui/resources/top_bar_resources_rc.py index 8444c31d..991a4727 100644 --- a/BlocksScreen/lib/ui/resources/top_bar_resources_rc.py +++ b/BlocksScreen/lib/ui/resources/top_bar_resources_rc.py @@ -2,7 +2,7 @@ # Resource object code # -# Created by: The Resource Compiler for PyQt5 (Qt v5.15.14) +# Created by: The Resource Compiler for PyQt6 (Qt v5.15.14) # # WARNING! All changes made in this file will be lost! @@ -2650,49 +2650,49 @@ \x00\x00\x00\x30\x00\x02\x00\x00\x00\x16\x00\x00\x00\x04\ \x00\x00\x00\x00\x00\x00\x00\x00\ \x00\x00\x00\x42\x00\x00\x00\x00\x00\x01\x00\x00\x00\x00\ -\x00\x00\x01\x95\x80\xac\x7d\xd7\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x00\x7c\x00\x00\x00\x00\x00\x01\x00\x00\x01\x4b\ -\x00\x00\x01\x95\x80\xac\x7d\xf0\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x00\xb0\x00\x00\x00\x00\x00\x01\x00\x00\x09\xc2\ -\x00\x00\x01\x95\x80\xac\x7e\x29\ +\x00\x00\x01\x98\x51\xb9\x78\xf8\ \x00\x00\x00\xec\x00\x00\x00\x00\x00\x01\x00\x00\x13\xc4\ -\x00\x00\x01\x95\x80\xac\x7e\x68\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x01\x1a\x00\x00\x00\x00\x00\x01\x00\x00\x18\xd6\ -\x00\x00\x01\x95\x80\xac\x7d\x15\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x01\x4e\x00\x00\x00\x00\x00\x01\x00\x00\x20\x7e\ -\x00\x00\x01\x95\x80\xac\x7c\xb8\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x01\x7a\x00\x00\x00\x00\x00\x01\x00\x00\x27\xbd\ -\x00\x00\x01\x95\x80\xac\x7d\x6d\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x01\xae\x00\x00\x00\x00\x00\x01\x00\x00\x32\x21\ -\x00\x00\x01\x95\x80\xac\x7f\x44\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x01\xe2\x00\x00\x00\x00\x00\x01\x00\x00\x3c\x4a\ -\x00\x00\x01\x95\x80\xac\x7c\xdf\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x02\x1c\x00\x00\x00\x00\x00\x01\x00\x00\x46\xa2\ -\x00\x00\x01\x95\x80\xac\x7e\xbb\ +\x00\x00\x01\x98\x51\xb9\x78\xf8\ \x00\x00\x02\x50\x00\x00\x00\x00\x00\x01\x00\x00\x50\xba\ -\x00\x00\x01\x95\x80\xac\x7d\x8d\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x02\x82\x00\x00\x00\x00\x00\x01\x00\x00\x51\xdf\ -\x00\x00\x01\x95\x80\xac\x7f\x65\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x02\xca\x00\x00\x00\x00\x00\x01\x00\x00\x5c\x7d\ -\x00\x00\x01\x95\x80\xac\x7f\xdb\ +\x00\x00\x01\x98\x51\xb9\x78\xf8\ \x00\x00\x02\xfc\x00\x00\x00\x00\x00\x01\x00\x00\x5e\xd4\ -\x00\x00\x01\x95\x80\xac\x7e\x0c\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x03\x32\x00\x00\x00\x00\x00\x01\x00\x00\x68\xfd\ -\x00\x00\x01\x95\x80\xac\x80\x06\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x03\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x73\x13\ -\x00\x00\x01\x95\x80\xac\x7e\xe6\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x03\xa0\x00\x00\x00\x00\x00\x01\x00\x00\x7d\x79\ -\x00\x00\x01\x95\x80\xac\x7d\xb7\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x03\xca\x00\x00\x00\x00\x00\x01\x00\x00\x83\x70\ -\x00\x00\x01\x95\x80\xac\x7f\xa6\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x04\x02\x00\x00\x00\x00\x00\x01\x00\x00\x8c\x1f\ -\x00\x00\x01\x95\x80\xac\x7d\x50\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x04\x36\x00\x00\x00\x00\x00\x01\x00\x00\x8e\x0b\ -\x00\x00\x01\x95\x80\xac\x7e\x48\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x04\x6a\x00\x00\x00\x00\x00\x01\x00\x00\x8f\x70\ -\x00\x00\x01\x95\x80\xac\x7e\x89\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ \x00\x00\x04\x9c\x00\x00\x00\x00\x00\x01\x00\x00\x92\xd2\ -\x00\x00\x01\x95\x80\xac\x7c\xfb\ +\x00\x00\x01\x98\x51\xb9\x78\xf4\ " qt_version = [int(v) for v in QtCore.qVersion().split('.')] diff --git a/BlocksScreen/lib/utils/blocks_Scrollbar.py b/BlocksScreen/lib/utils/blocks_Scrollbar.py new file mode 100644 index 00000000..08dc6b68 --- /dev/null +++ b/BlocksScreen/lib/utils/blocks_Scrollbar.py @@ -0,0 +1,78 @@ +from PyQt6 import QtCore, QtGui, QtWidgets +import numpy as np + + +class CustomScrollBar(QtWidgets.QScrollBar): + def __init__(self, parent=None): + super().__init__(parent) + self.setFixedWidth(40) + + def paintEvent(self, event): + painter = QtGui.QPainter(self) + painter.setRenderHint(painter.RenderHint.Antialiasing, True) + painter.setRenderHint(painter.RenderHint.SmoothPixmapTransform, True) + painter.setRenderHint(painter.RenderHint.LosslessImageRendering, True) + + groove = self.rect().adjusted(0, 0, -35, 0) + min_val, max_val = self.minimum(), self.maximum() + page_step = self.pageStep() + val = self.value() + + handle_width = 5 + + if max_val == min_val: + return + + handle_percentage = int((self.value() / max_val) * 100) + + if handle_percentage < 15: + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + np.interp(handle_percentage, [0, 15], [0, 40]) + ) + handle_pos = 0 + + elif handle_percentage > 85: + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + np.interp(handle_percentage, [85, 100], [40, 0]) + ) + handle_pos = int( + (groove.height() - base_handle_length) + * (max_val - min_val) + / (max_val - min_val) + ) + else: + val = ( + np.interp((handle_percentage), [15, 85], [0, 100]) + / 100 + * max_val + ) + + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + 40 + ) + handle_pos = int( + (groove.height() - base_handle_length) + * (val - min_val) + / (max_val - min_val) + ) + + handle_rect = QtCore.QRect( + groove.x(), + int(groove.y() + handle_pos), + handle_width, + base_handle_length, + ) + + gradient = QtGui.QLinearGradient( + QtCore.QPointF(handle_rect.topLeft()), + QtCore.QPointF(handle_rect.bottomLeft()), + ) + + gradient.setColorAt(0.0, QtGui.QColor(164, 164, 164, 100)) # Top + gradient.setColorAt(0.5, QtGui.QColor(164, 164, 164, 164)) # Center + gradient.setColorAt(1.0, QtGui.QColor(164, 164, 164, 100)) # Bottom + painter.setBrush(gradient) + painter.drawRoundedRect(handle_rect, 1, 1) diff --git a/BlocksScreen/lib/utils/list_button.py b/BlocksScreen/lib/utils/list_button.py new file mode 100644 index 00000000..87a1e3be --- /dev/null +++ b/BlocksScreen/lib/utils/list_button.py @@ -0,0 +1,248 @@ +from PyQt6 import QtCore, QtGui, QtWidgets + + +class ListCustomButton(QtWidgets.QPushButton): + def __init__(self) -> None: + super().__init__() + self.icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() + self.second_icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() + self.text_color: QtGui.QColor = QtGui.QColor(255, 255, 255) + self.pressed_color = "#1A8FBF" + self._text = "" + self._right_text = "" + + self._rfontsize = 15 + self._lfontsize = 11 + + self._is_pressed = False + self._is_hovered = False + + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) + self.setSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Fixed, + ) + self.setFixedHeight(48) + self.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + + def setText(self, text: str) -> None: + self._text = text + self.update() + + def setRightText(self, text: str) -> None: + self._right_text = text + self.update() + + def setLeftFontSize(self, size: int) -> None: + self._lfontsize = size + self.update() + + def setRightFontSize(self, size: int) -> None: + self._rfontsize = size + self.update() + + def setPixmap(self, pixmap: QtGui.QPixmap) -> None: + self.icon_pixmap = pixmap + self.update() + + def setSecondPixmap(self, pixmap: QtGui.QPixmap) -> None: + self.second_icon_pixmap = pixmap + self.update() + + def mousePressEvent(self, event: QtGui.QMouseEvent) -> None: + self._is_pressed = True + self.update() + super().mousePressEvent(event) + + def mouseReleaseEvent(self, event: QtGui.QMouseEvent) -> None: + self._is_pressed = False + self.update() + super().mouseReleaseEvent(event) + + def leaveEvent(self, event: QtCore.QEvent) -> None: + self._is_hovered = False + self.update() + super().leaveEvent(event) + + def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: + painter = QtGui.QPainter(self) + painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True) + + rect = self.rect() + radius = rect.height() / 5.0 + + # Main rounded rectangle path + path = QtGui.QPainterPath() + path.addRoundedRect(QtCore.QRectF(rect), radius, radius) + + # Ellipse ("hole") for the icon on the right + ellipse_margin = rect.height() * 0.05 + ellipse_size = rect.height() * 0.90 + ellipse_rect = QtCore.QRectF( + rect.right() - ellipse_margin - ellipse_size, + rect.top() + ellipse_margin, + ellipse_size, + ellipse_size, + ) + ellipse_path = QtGui.QPainterPath() + ellipse_path.addEllipse(ellipse_rect) + self.button_ellipse = ellipse_rect + + # Ellipse ("hole") for the icon on the left (only if present) + left_icon_margin = rect.height() * 0.05 + left_icon_size = rect.height() * 0.90 + left_icon_rect = QtCore.QRectF( + rect.left() + left_icon_margin, + rect.top() + left_icon_margin, + left_icon_size, + left_icon_size, + ) + left_margin = 10 # default left margin + + # Gradient background (left to right) + if not self._is_pressed: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(20) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) + else: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(100) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) + + # Draw icon inside the ellipse "hole" (on the right) + if not self.icon_pixmap.isNull(): + icon_margin = ellipse_size * 0.10 + icon_rect = QtCore.QRectF( + ellipse_rect.left() + icon_margin / 2, + ellipse_rect.top() + icon_margin / 2, + ellipse_rect.width() - icon_margin, + ellipse_rect.height() - icon_margin, + ) + icon_scaled = self.icon_pixmap.scaled( + icon_rect.size().toSize(), + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + QtCore.Qt.TransformationMode.SmoothTransformation, + ) + # Center the icon in the ellipse + adjusted_x = ( + icon_rect.x() + (icon_rect.width() - icon_scaled.width()) / 2.0 + ) + adjusted_y = ( + icon_rect.y() + + (icon_rect.height() - icon_scaled.height()) / 2.0 + ) + adjusted_icon_rect = QtCore.QRectF( + adjusted_x, + adjusted_y, + icon_scaled.width(), + icon_scaled.height(), + ) + painter.drawPixmap( + adjusted_icon_rect, icon_scaled, icon_scaled.rect().toRectF() + ) + + # Draw second icon (on the left, if present) + if not self.second_icon_pixmap.isNull(): + left_icon_scaled = self.second_icon_pixmap.scaled( + left_icon_rect.size().toSize(), + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + QtCore.Qt.TransformationMode.SmoothTransformation, + ) + # Center the icon in the rect + adjusted_x = ( + left_icon_rect.x() + + (left_icon_rect.width() - left_icon_scaled.width()) / 2.0 + ) + adjusted_y = ( + left_icon_rect.y() + + (left_icon_rect.height() - left_icon_scaled.height()) / 2.0 + ) # <-- FIXED HERE + adjusted_left_icon_rect = QtCore.QRectF( + adjusted_x, + adjusted_y, + left_icon_scaled.width(), + left_icon_scaled.height(), + ) + painter.drawPixmap( + adjusted_left_icon_rect, + left_icon_scaled, + left_icon_scaled.rect().toRectF(), + ) + left_margin = ( + left_icon_margin + left_icon_size + 8 + ) # 8px gap after icon + + # Draw text, area before the ellipse (adjusted for left icon) + text_margin = int( + rect.right() - ellipse_size - ellipse_margin - rect.height() * 0.10 + ) + text_rect = QtCore.QRectF( + rect.left() + left_margin, + rect.top(), + text_margin - rect.left() - left_margin, + rect.height(), + ) + + # Draw main text (left-aligned) + painter.setPen(self.text_color) + _font = painter.font() + _font.setPointSize(self._lfontsize) + painter.setFont(_font) + metrics = QtGui.QFontMetrics(_font) + main_text_height = metrics.height() + + # Vertically center text + text_y = ( + rect.top() + + (rect.height() + main_text_height) / 2 + - metrics.descent() + ) + + # Calculate where to start the right text: just left of the right icon ellipse + gap = 10 # gap between right text and icon ellipse + right_font = QtGui.QFont(_font) + right_font.setPointSize(self._rfontsize) + right_metrics = QtGui.QFontMetrics(right_font) + right_text_width = right_metrics.horizontalAdvance(self._right_text) + + # The right text should end at ellipse_rect.left() - gap + right_text_x = ellipse_rect.left() - gap - right_text_width + + # Draw main text (left-aligned, but don't overlap right text) + max_main_text_width = ( + right_text_x - text_rect.left() - 10 + ) # 10px gap between main and right text + elided_main_text = metrics.elidedText( + self._text, + QtCore.Qt.TextElideMode.ElideRight, + int(max_main_text_width), + ) + + painter.setFont(_font) + painter.drawText( + int(text_rect.left()), + int(text_y), + elided_main_text, + ) + + # Draw right text (smaller, grey, just left of the icon) + if self._right_text: + painter.setFont(right_font) + painter.setPen(QtGui.QColor(160, 160, 160)) # grey color + right_text_height = right_metrics.height() + right_text_y = ( + rect.top() + + (rect.height() + right_text_height) / 2 + - right_metrics.descent() + ) + painter.drawText( + int(right_text_x), + int(right_text_y), + self._right_text, + ) + + painter.end() From 1a620a00cda128a29c68584f4830d9db284d8ddb Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Fri, 22 Aug 2025 16:56:24 +0100 Subject: [PATCH 02/20] BUG FIX: centered thumbnail position --- .../lib/panels/widgets/confirmPage.py | 327 ++++++++++++++++++ 1 file changed, 327 insertions(+) create mode 100644 BlocksScreen/lib/panels/widgets/confirmPage.py diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/confirmPage.py new file mode 100644 index 00000000..7c1ee859 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/confirmPage.py @@ -0,0 +1,327 @@ +import typing + +from lib.utils.blocks_button import BlocksCustomButton +from lib.utils.blocks_label import BlocksLabel +from PyQt6 import QtCore, QtGui, QtWidgets + + +class ConfirmWidget(QtWidgets.QWidget): + on_accept: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="on_accept" + ) + on_reject: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + name="on_reject" + ) + + def __init__(self, parent) -> None: + super().__init__(parent) + self.setupUI() + self.setMouseTracking(True) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) + self.thumbnail: QtGui.QImage = QtGui.QImage() + self.confirm_button.clicked.connect( + lambda: self.on_accept.emit(str(self.cf_file_name._text)) + ) + self.reject_button.clicked.connect(self.on_reject.emit) + + @QtCore.pyqtSlot(str, dict, name="on_show_widget") + def on_show_widget(self, text: str, filedata: dict | None = None) -> None: + self.cf_file_name.setText(str(text)) + if not filedata: + return + _thumbnails = filedata.get("thumbnail_images") + + if _thumbnails: + _biggest_thumbnail = _thumbnails[len(_thumbnails) - 1] + self.thumbnail = QtGui.QImage(_biggest_thumbnail) + + _total_filament = filedata.get("filament_total") + _estimated_time = filedata.get("estimated_time") + + if isinstance(_estimated_time, str): + seconds = 0 + else: + seconds = _estimated_time + + _estimated_time = self.estimate_print_time(seconds) + + self.cf_info.setText( + "Total Filament:" + + str(_total_filament) + + "\n" + + "Slicer time: " + + str(_estimated_time[0]) + + " days " + + str(_estimated_time[1]) + + " hours " + + str(_estimated_time[2]) + + " minutes " + + str(_estimated_time[3]) + + " seconds" + ) + self.repaint() + + def estimate_print_time(self, seconds: int) -> list: + """Convert time in seconds format to days, hours, minutes, seconds. + + Args: + seconds (int): Seconds + + Returns: + list: list that contains the converted information [days, hours, minutes, seconds] + """ + num_min, seconds = divmod(seconds, 60) + num_hours, minutes = divmod(num_min, 60) + days, hours = divmod(num_hours, 24) + return [days, hours, minutes, seconds] + + def paintEvent(self, a0: QtGui.QPaintEvent) -> None: + _scene = QtWidgets.QGraphicsScene() + if not self.thumbnail.isNull(): + _graphics_rect = self.cf_thumbnail.rect().toRectF() + _image_rect = self.thumbnail.rect() + + scaled_width = _image_rect.width() + scaled_height = _image_rect.height() + adjusted_x = (_graphics_rect.width() - scaled_width) // 2.0 + adjusted_y = (_graphics_rect.height() - scaled_height) // 2.0 + + adjusted_rect = QtCore.QRectF( + _image_rect.x() + adjusted_x, + _image_rect.y() + adjusted_y, + scaled_width, + scaled_height, + ) + _scene.setSceneRect(adjusted_rect) + _item_scaled = QtWidgets.QGraphicsPixmapItem( + QtGui.QPixmap.fromImage(self.thumbnail).scaled( + int(scaled_width), + int(scaled_height), + QtCore.Qt.AspectRatioMode.KeepAspectRatio, + QtCore.Qt.TransformationMode.SmoothTransformation, + ) + ) + _scene.addItem(_item_scaled) + self.cf_thumbnail.setScene(_scene) + + else: + self.cf_thumbnail.setScene(_scene) + + def showEvent(self, a0: QtGui.QShowEvent) -> None: + if not self.thumbnail: + self.cf_thumbnail.close() + return super().showEvent(a0) + + def hideEvent(self, a0: QtGui.QHideEvent) -> None: + return super().hideEvent(a0) + + def setupUI(self) -> None: + 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(710, 400)) + self.setMaximumSize(QtCore.QSize(720, 420)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.verticalLayout_4 = QtWidgets.QVBoxLayout(self) + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.cf_header_title = QtWidgets.QHBoxLayout() + self.cf_header_title.setObjectName("cf_header_title") + self.confirm_title_label = QtWidgets.QLabel(parent=self) + self.confirm_title_label.setMinimumSize(QtCore.QSize(0, 60)) + self.confirm_title_label.setMaximumSize(QtCore.QSize(16777215, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(24) + self.confirm_title_label.setFont(font) + self.confirm_title_label.setLayoutDirection( + QtCore.Qt.LayoutDirection.RightToLeft + ) + self.confirm_title_label.setStyleSheet( + "background: transparent; color: white;" + ) + self.confirm_title_label.setAlignment( + QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.confirm_title_label.setObjectName("confirm_title_label") + self.cf_header_title.addWidget(self.confirm_title_label) + self.verticalLayout_4.addLayout(self.cf_header_title) + self.cf_content_vertical_layout = QtWidgets.QHBoxLayout() + self.cf_content_vertical_layout.setObjectName( + "cf_content_vertical_layout" + ) + self.cf_content_horizontal_layout = QtWidgets.QVBoxLayout() + self.cf_content_horizontal_layout.setObjectName( + "cf_content_horizontal_layout" + ) + self.cf_info = QtWidgets.QLabel(parent=self) + self.cf_info.setEnabled(True) + self.cf_info.setMinimumSize(QtCore.QSize(200, 60)) + self.cf_info.setMaximumSize(QtCore.QSize(250, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(14) + self.cf_info.setFont(font) + self.cf_info.setStyleSheet("background: transparent; color: white;") + self.cf_info.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_info.setWordWrap(True) + self.cf_info.setObjectName("cf_info") + self.cf_content_horizontal_layout.addWidget( + self.cf_info, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + self.cf_file_name = BlocksLabel(parent=self) + self.cf_file_name.setEnabled(True) + self.cf_file_name.setMinimumSize(QtCore.QSize(250, 80)) + self.cf_file_name.setMaximumSize(QtCore.QSize(250, 80)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(14) + self.cf_file_name.setFont(font) + self.cf_file_name.setStyleSheet( + "background: transparent; color: white;" + ) + self.cf_file_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.cf_file_name.setWordWrap(True) + self.cf_file_name.setObjectName("cf_file_name") + self.cf_content_horizontal_layout.addWidget( + self.cf_file_name, 0, QtCore.Qt.AlignmentFlag.AlignHCenter + ) + self.cf_confirm_layout = QtWidgets.QVBoxLayout() + self.cf_confirm_layout.setSizeConstraint( + QtWidgets.QLayout.SizeConstraint.SetFixedSize + ) + self.cf_confirm_layout.setContentsMargins(0, 0, 0, 0) + self.cf_confirm_layout.setSpacing(2) + self.cf_confirm_layout.setObjectName("cf_confirm_layout") + self.confirm_button = BlocksCustomButton(parent=self) + self.confirm_button.setMinimumSize(QtCore.QSize(200, 60)) + self.confirm_button.setMaximumSize(QtCore.QSize(200, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(18) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + self.confirm_button.setFont(font) + self.confirm_button.setMouseTracking(False) + self.confirm_button.setTabletTracking(True) + self.confirm_button.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.NoContextMenu + ) + self.confirm_button.setLayoutDirection( + QtCore.Qt.LayoutDirection.LeftToRight + ) + self.confirm_button.setStyleSheet("") + self.confirm_button.setAutoDefault(False) + self.confirm_button.setFlat(True) + self.confirm_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") + ) + self.confirm_button.setObjectName("confirm_button") + self.cf_confirm_layout.addWidget( + self.confirm_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + self.reject_button = BlocksCustomButton(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Fixed, + QtWidgets.QSizePolicy.Policy.Fixed, + ) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth( + self.reject_button.sizePolicy().hasHeightForWidth() + ) + self.reject_button.setSizePolicy(sizePolicy) + self.reject_button.setMinimumSize(QtCore.QSize(200, 60)) + self.reject_button.setMaximumSize(QtCore.QSize(200, 60)) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(18) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + + self.reject_button.setFont(font) + self.reject_button.setMouseTracking(False) + self.reject_button.setTabletTracking(True) + self.reject_button.setContextMenuPolicy( + QtCore.Qt.ContextMenuPolicy.NoContextMenu + ) + self.reject_button.setLayoutDirection( + QtCore.Qt.LayoutDirection.LeftToRight + ) + self.reject_button.setStyleSheet("") + self.reject_button.setAutoDefault(False) + self.reject_button.setFlat(True) + self.reject_button.setProperty( + "icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") + ) + self.reject_button.setObjectName("reject") + self.cf_confirm_layout.addWidget( + self.reject_button, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + self.cf_content_horizontal_layout.addLayout(self.cf_confirm_layout) + self.cf_content_vertical_layout.addLayout( + self.cf_content_horizontal_layout + ) + self.cf_thumbnail = QtWidgets.QGraphicsView(parent=self) + sizePolicy = QtWidgets.QSizePolicy( + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Expanding, + ) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth( + self.cf_thumbnail.sizePolicy().hasHeightForWidth() + ) + self.cf_thumbnail.setSizePolicy(sizePolicy) + self.cf_thumbnail.setMinimumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setMaximumSize(QtCore.QSize(400, 300)) + self.cf_thumbnail.setStyleSheet( + "QGraphicsView{\nbackground-color: transparent;\n}" + ) + self.cf_thumbnail.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.cf_thumbnail.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) + self.cf_thumbnail.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.cf_thumbnail.setSizeAdjustPolicy( + QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored + ) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + self.cf_thumbnail.setBackgroundBrush(brush) + self.cf_thumbnail.setRenderHints( + QtGui.QPainter.RenderHint.Antialiasing + | QtGui.QPainter.RenderHint.SmoothPixmapTransform + | QtGui.QPainter.RenderHint.TextAntialiasing + ) + self.cf_thumbnail.setViewportUpdateMode( + QtWidgets.QGraphicsView.ViewportUpdateMode.SmartViewportUpdate + ) + self.cf_thumbnail.setObjectName("cf_thumbnail") + self.cf_content_vertical_layout.addWidget( + self.cf_thumbnail, + 0, + QtCore.Qt.AlignmentFlag.AlignRight + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) + + self.confirm_title_label.setText("Print File?") + self.confirm_button.setText("Accept") + self.reject_button.setText("Cancel") From 22f5887be3e6205e4270f216a4d4219c081246f3 Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Sun, 24 Aug 2025 20:13:43 +0100 Subject: [PATCH 03/20] Refactor: Deleted unused dev debt code --- BlocksScreen/BlocksScreen.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/BlocksScreen/BlocksScreen.py b/BlocksScreen/BlocksScreen.py index bb1ae32b..f0b80620 100644 --- a/BlocksScreen/BlocksScreen.py +++ b/BlocksScreen/BlocksScreen.py @@ -1,6 +1,3 @@ -from importupdate import update_imports - -update_imports("BlocksScreen/lib/ui/resources") import logging import os From a8573432f4c68af3bdce4e913a5e9d8f07517609 Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Mon, 28 Jul 2025 17:02:30 +0100 Subject: [PATCH 04/20] Refactor: prepare for pull request --- .vscode/extensions.json | 1 + .vscode/settings.json | 12 ++++- BlocksScreen/BlocksScreen.py | 37 +++++++++------ BlocksScreen/events.py | 39 +++++++++++----- BlocksScreen/lib/moonrakerComm.py | 2 +- BlocksScreen/lib/moonrest.py | 3 +- BlocksScreen/lib/panels/filamentTab.py | 46 +++++++++---------- BlocksScreen/lib/panels/printTab.py | 4 +- .../lib/panels/widgets/sensorsPanel.py | 41 +++++++++-------- .../lib/ui/controlStackedWidget_ui.py | 24 ++++++---- BlocksScreen/lib/ui/printStackedWidget.ui | 6 +-- Blocks_Screen.code-workspace | 40 ++++++++-------- 12 files changed, 146 insertions(+), 109 deletions(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 907eba86..9154273c 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -3,4 +3,5 @@ "seanwu.vscode-qt-for-python", "aaron-bond.better-comments" ] + } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 47389c10..c44e369f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -26,15 +26,25 @@ }, "peacock.remoteColor": "#c2fb90", "cSpell.words": [ + "babystepping", "bltouch", + "decel", + "DPMS", "ENDSTOP", + "Frameless", "gcode", "klippy", "metascan", + "Momcake", + "mooncake", + "printcore", "qtobject", "Reimplementation", "sdbus", + "setdefaulttimeout", "TESTZ", + "Tickmarks", + "topbar", "unextrude" ], "todo-tree.tree.scanMode": "workspace", @@ -51,5 +61,5 @@ "workbench.list.fastScrollSensitivity": 10, "terminal.integrated.fastScrollSensitivity": 10, "workbench.list.mouseWheelScrollSensitivity": 2, - + "editor.lineHeight": 48 } \ No newline at end of file diff --git a/BlocksScreen/BlocksScreen.py b/BlocksScreen/BlocksScreen.py index f0b80620..ace0f9f4 100644 --- a/BlocksScreen/BlocksScreen.py +++ b/BlocksScreen/BlocksScreen.py @@ -1,6 +1,6 @@ import logging -import os +# import os import sys import typing @@ -10,20 +10,28 @@ from PyQt6 import QtCore, QtGui, QtWidgets from screensaver import ScreenSaver -os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1.0" -os.environ["QT_SCALE_FACTOR"] = "1.0" -os.environ["QT_DEVICE_PIXEL_RATIO"] = "1.0" -os.environ["QT_QPA_PLATFORM"] = "xcb" -os.environ["QT_STYLE_OVERRIDE"] = "fusion" +# os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1.0" +# os.environ["QT_SCALE_FACTOR"] = "1.0" +# os.environ["QT_DEVICE_PIXEL_RATIO"] = "1.0" +# os.environ["QT_QPA_PLATFORM"] = "xcb" +# os.environ["QT_STYLE_OVERRIDE"] = "fusion" _logger = logging.getLogger(name="logs/BlocksScreen.log") -QtGui.QGuiApplication.setHighDpiScaleFactorRoundingPolicy( # type: ignore - QtCore.Qt.HighDpiScaleFactorRoundingPolicy.Ceil +# QtGui.QGuiApplication.setHighDpiScaleFactorRoundingPolicy( # type: ignore +# QtCore.Qt.HighDpiScaleFactorRoundingPolicy.Ceil +# ) +# QtGui.QGuiApplication.setLayoutDirection( # type: ignore +# QtCore.Qt.LayoutDirection.LayoutDirectionAuto +# ) +QtGui.QGuiApplication.setAttribute( + QtCore.Qt.ApplicationAttribute.AA_SynthesizeMouseForUnhandledTouchEvents, + True, ) -QtGui.QGuiApplication.setLayoutDirection( # type: ignore - QtCore.Qt.LayoutDirection.LayoutDirectionAuto +QtGui.QGuiApplication.setAttribute( + QtCore.Qt.ApplicationAttribute.AA_SynthesizeTouchForUnhandledMouseEvents, + True, ) RED = "\033[31m" @@ -58,19 +66,18 @@ def run(): setup_app_loggers() BlocksScreen = QtWidgets.QApplication([]) main_window = MainWindow() - show_splash(main_window) + # show_splash(main_window) BlocksScreen.setApplicationName("BlocksScreen") BlocksScreen.setApplicationDisplayName("BlocksScreen") BlocksScreen.setDesktopFileName("BlocksScreen") - BlocksScreen.setHighDpiScaleFactorRoundingPolicy( - QtCore.Qt.HighDpiScaleFactorRoundingPolicy.Round - ) + # BlocksScreen.setHighDpiScaleFactorRoundingPolicy( + # QtCore.Qt.HighDpiScaleFactorRoundingPolicy.Round + # ) screensaver = ScreenSaver() BlocksScreen.processEvents() # main_window.setScreen(BlocksScreen.screens()[0]) # main_window.showFullScreen() - # main_window.show() main_window.show() main_window.bo_ws_startup.emit() sys.exit(BlocksScreen.exec()) diff --git a/BlocksScreen/events.py b/BlocksScreen/events.py index 7b5229e2..05c5d28f 100644 --- a/BlocksScreen/events.py +++ b/BlocksScreen/events.py @@ -48,7 +48,9 @@ def __init__( @staticmethod def type() -> QEvent.Type: - return QEvent.Type(WebSocketMessageReceived.WebsocketMessageReceivedEvent) + return QEvent.Type( + WebSocketMessageReceived.WebsocketMessageReceivedEvent + ) class WebSocketOpen(QEvent): @@ -81,7 +83,9 @@ class WebSocketError(QEvent): WebsocketErrorEvent = QEvent.Type(QEvent.registerEventType()) def __init__(self, data, *args, **kwargs): - super(WebSocketError, self).__init__(WebSocketError.WebsocketErrorEvent) + super(WebSocketError, self).__init__( + WebSocketError.WebsocketErrorEvent + ) self.data = data self.args = args self.kwargs = kwargs @@ -124,7 +128,9 @@ class WebSocketClose(QEvent): WebsocketCloseEvent = QEvent.Type(QEvent.registerEventType()) def __init__(self, data, *args, **kwargs): - super(WebSocketClose, self).__init__(WebSocketClose.WebsocketCloseEvent) + super(WebSocketClose, self).__init__( + WebSocketClose.WebsocketCloseEvent + ) self.data = data self.args = args self.kwargs = kwargs @@ -145,7 +151,9 @@ class KlippyShutdown(QEvent): def __init__(self, data, *args, **kwargs): QEvent.__instancecheck__(self) - super(KlippyShutdown, self).__init__(KlippyShutdown.KlippyShutdownEvent) + super(KlippyShutdown, self).__init__( + KlippyShutdown.KlippyShutdownEvent + ) self.data = data self.args = args self.kwargs = kwargs @@ -236,7 +244,9 @@ class ReceivedFileData(QEvent): def __init__( self, data, method, params, /, *args, **kwargs ): # Positional-only arguments "data", "method", "params", these need to be inserted in order or it wont work - super(ReceivedFileData, self).__init__(ReceivedFileData.ReceivedFileDataEvent) + super(ReceivedFileData, self).__init__( + ReceivedFileData.ReceivedFileDataEvent + ) self.data = data self.method = method self.params = params @@ -249,18 +259,19 @@ def type() -> QEvent.Type: class PrintStart(QEvent): - """Print start event + """Print Job Start event Args: - data (any): Data or message to pass onto the event + filename(any): Name of the file currently printing + **kwargs(dict): File's metadata """ PrintStartEvent = QEvent.Type(QEvent.registerEventType()) - def __init__(self, data, *args, **kwargs): + def __init__(self, filename, *args, **kwargs): super(PrintStart, self).__init__(PrintStart.PrintStartEvent) - self.data = data - self.args = args + self.file = filename + self.file_metadata = kwargs self.kwargs = kwargs @staticmethod @@ -340,7 +351,9 @@ class PrintCancelled(QEvent): PrintCancelledEvent = QEvent.Type(QEvent.registerEventType()) def __init__(self, data, *args, **kwargs): - super(PrintCancelled, self).__init__(PrintCancelled.PrintCancelledEvent) + super(PrintCancelled, self).__init__( + PrintCancelled.PrintCancelledEvent + ) self.data = data self.args = args @@ -401,7 +414,9 @@ class NetworkDeleted(QEvent): NetworkDeletedEvent = QEvent.Type(QEvent.registerEventType()) def __init__(self, data, *args, **kwargs): - super(NetworkDeleted, self).__init__(NetworkDeleted.NetworkDeletedEvent) + super(NetworkDeleted, self).__init__( + NetworkDeleted.NetworkDeletedEvent + ) self.data = data self.args = args self.kwargs = kwargs diff --git a/BlocksScreen/lib/moonrakerComm.py b/BlocksScreen/lib/moonrakerComm.py index 94901d21..8772d31c 100644 --- a/BlocksScreen/lib/moonrakerComm.py +++ b/BlocksScreen/lib/moonrakerComm.py @@ -167,7 +167,7 @@ def connect(self) -> bool: f"Unexpected error occurred when trying to acquire oneshot token: {e}" ) return False - # _url = f"ws://192.168.1.100:7125/websocket?token={_oneshot_token}" + # _url = f"ws://192.168.1.68:7125/websocket?token={_oneshot_token}" _url = f"ws://localhost:7125/websocket?token={_oneshot_token}" self.ws = websocket.WebSocketApp( _url, diff --git a/BlocksScreen/lib/moonrest.py b/BlocksScreen/lib/moonrest.py index d9d50e64..eabc10ba 100644 --- a/BlocksScreen/lib/moonrest.py +++ b/BlocksScreen/lib/moonrest.py @@ -26,10 +26,9 @@ class MoonRest: """ timeout = 3 - # TODO: The ip and port need to come from a configfile - # def __init__(self, ip="localhost", port="7125", api_key=False): + # def __init__(self, ip="192.168.1.68", port="7125", api_key=False): def __init__(self, ip="localhost", port="7125", api_key=False): self._ip = ip self._port = port diff --git a/BlocksScreen/lib/panels/filamentTab.py b/BlocksScreen/lib/panels/filamentTab.py index 1ea402c2..91eaec49 100644 --- a/BlocksScreen/lib/panels/filamentTab.py +++ b/BlocksScreen/lib/panels/filamentTab.py @@ -14,12 +14,10 @@ class FilamentTab(QStackedWidget): request_filament_change_page = pyqtSignal(name="filament_change_page") request_filament_load = pyqtSignal(name="filament_load_t1") - request_back = pyqtSignal( - name="request_back" - ) + request_back = pyqtSignal(name="request_back") request_change_page = pyqtSignal(int, int, name="request_change_page") request_toolhead_count = pyqtSignal(int, name="toolhead_number_received") - run_gcode_signal = pyqtSignal(str, name="run_gcode") + run_gcode = pyqtSignal(str, name="run_gcode") class FilamentTypes(enum.Enum): PLA = Filament(name="PLA", temperature=220) @@ -48,7 +46,7 @@ def __init__(self, parent: QWidget, printer: Printer, ws, /) -> None: self.filament_type: Filament | None = None self.panel.filament_page_load_btn.clicked.connect( - partial(self.change_page, 1) + partial(self.change_page, self.indexOf(self.panel.load_page)) ) self.panel.custom_filament_header_back_btn.clicked.connect( self.back_button @@ -79,33 +77,33 @@ def __init__(self, parent: QWidget, printer: Printer, ws, /) -> None: self.panel.filament_page_unload_btn.clicked.connect( lambda: self.unload_filament(toolhead=0, temp=250) ) - self.run_gcode_signal.connect(self.ws.api.run_gcode) + self.run_gcode.connect(self.ws.api.run_gcode) @pyqtSlot(int, int, name="load_filament") def load_filament(self, toolhead: int = 0, temp: int = 220) -> None: - if not self.has_load_unload_objects: - return # {"error": "No load/unload routines"} - if not self._filament_state == self.FilamentStates.UNLOADED: - return # {"error": "Filament already loaded"} - if toolhead == 0: - self.run_gcode_signal.emit(f"LOAD_FILAMENT TEMPERATURE={temp}") - else: - self.run_gcode_signal.emit( - f"LOAD_FILAMENT TOOLHEAD={toolhead} TEMPERATURE{temp}" - ) + # if not self.has_load_unload_objects: + # return # {"error": "No load/unload routines"} + # if not self._filament_state == self.FilamentStates.UNLOADED: + # return # {"error": "Filament already loaded"} + # if toolhead == 0: + # self.run_gcode.emit(f"LOAD_FILAMENT TEMPERATURE={temp}") + # else: + self.run_gcode.emit( + f"LOAD_FILAMENT TOOLHEAD=load_toolhead TEMPERATURE={temp}" + ) @pyqtSlot(str, int, name="unload_filament") def unload_filament(self, toolhead: str = "0", temp: int = 220) -> None: - if not self.has_load_unload_objects: - return # {"error": "No load/unload routines"} - if not self._filament_state == self.FilamentStates.LOADED: - return # {"error": "No loaded filament"} + # if not self.has_load_unload_objects: + # return # {"error": "No load/unload routines"} + # if not self._filament_state == self.FilamentStates.LOADED: + # return # {"error": "No loaded filament"} - self.find_routine_objects() + # self.find_routine_objects() if toolhead == 0: - self.run_gcode_signal.emit(f"UNLOAD_FILAMENT TEMPERATURE={temp}") + self.run_gcode.emit(f"UNLOAD_FILAMENT TEMPERATURE={temp}") else: - self.run_gcode_signal.emit( + self.run_gcode.emit( f"UNLOAD_FILAMENT TOOLHEAD={toolhead} TEMPERATURE={temp}" ) @@ -137,7 +135,7 @@ def resizeEvent(self, a0: QResizeEvent | None) -> None: return super().resizeEvent(a0) def find_routine_objects(self): - if self.printer is None: + if not self.printer: return _available_objects = self.printer.available_objects.copy() diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index 862818fa..8872d77d 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -54,7 +54,6 @@ class PrintTab(QtWidgets.QStackedWidget): run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run_gcode" ) - _z_offset: float = 0.0 def __init__( @@ -127,6 +126,9 @@ def __init__( self.file_data.fileinfo.connect(self.jobStatusPage_widget.on_fileinfo) self.jobStatusPage_widget.print_start.connect(self.ws.api.start_print) + + # self.jobStatusPage_widget.print_start.connect() + self.jobStatusPage_widget.print_cancel.connect( self.ws.api.cancel_print ) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 751e1e95..e8e21440 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -5,7 +5,6 @@ from PyQt6 import QtCore, QtGui, QtWidgets -# TODO: Add buttons that toggle on and of the available printer sensors class SensorsWindow(QtWidgets.QWidget): run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run_gcode" @@ -23,11 +22,13 @@ class SensorsWindow(QtWidgets.QWidget): def __init__(self, parent): super(SensorsWindow, self).__init__(parent) self.setupUi() - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground) - self.setWindowFlags( - self.windowFlags() | QtCore.Qt.WindowType.FramelessWindowHint + self.setAttribute( + QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True ) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) + self.setTabletTracking(True) self.fs_sensors_list.itemClicked.connect(self.handle_sensor_clicked) + self.fs_sensors_list.itemClicked self.fs_back_button.clicked.connect(self.request_back) @QtCore.pyqtSlot(dict, name="handle_available_fil_sensors") @@ -56,6 +57,7 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: def handle_fil_state_change( self, sensor_name: str, parameter: str, value: bool ) -> None: + print("on handle fil state") if sensor_name in self.sensor_list: state = SensorWidget.FilamentState(value) _split = sensor_name.split(" ") @@ -68,13 +70,18 @@ def handle_fil_state_change( if isinstance(_item, SensorWidget) and hasattr( _item, "change_fil_sensor_state" ): - self.change_fil_sensor_state.connect( - _item.change_fil_sensor_state + _item.change_fil_sensor_state( + SensorWidget.FilamentState.PRESENT + ) + _item.repaint() + elif parameter == "filament_missing": + if isinstance(_item, SensorWidget) and hasattr( + _item, "change_fil_sensor_state" + ): + _item.change_fil_sensor_state( + SensorWidget.FilamentState.MISSING ) - self.change_fil_sensor_state.emit(state) - self.change_fil_sensor_state.disconnect() _item.repaint() - elif parameter == "enabled": if _item and isinstance(_item, SensorWidget): self.run_gcode_signal.emit( @@ -84,7 +91,8 @@ def handle_fil_state_change( @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name="handle_sensor_clicked") def handle_sensor_clicked(self, sensor: QtWidgets.QListWidgetItem) -> None: _item = self.fs_sensors_list.itemWidget(sensor) - + # FIXME: This is just not working + _item.toggle_button.state = ~_item.toggle_button.state if _item and isinstance(_item, SensorWidget): self.run_gcode_signal.emit(_item.toggle_sensor_gcode_command) @@ -100,6 +108,9 @@ def create_sensor_widget(self, name: str) -> SensorWidget: _list_item.setSizeHint( QtCore.QSize(self.fs_sensors_list.contentsRect().width(), 80) ) + _item_widget.toggle_button.stateChange.connect( + lambda: self.fs_sensors_list.itemClicked.emit(_item_widget) + ) self.fs_sensors_list.setItemWidget(_list_item, _item_widget) @@ -176,7 +187,6 @@ def setupUi(self): QtCore.Qt.LayoutDirection.LeftToRight ) self.fs_sensors_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.fs_sensors_list.setAutoFillBackground(False) self.fs_sensors_list.setObjectName("fs_sensors_list") self.fs_sensors_list.setViewMode( self.fs_sensors_list.ViewMode.ListMode @@ -185,15 +195,7 @@ def setupUi(self): QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignVCenter ) - self.fs_sensors_list.setMovement(self.fs_sensors_list.Movement.Static) self.fs_sensors_list.setFlow(self.fs_sensors_list.Flow.TopToBottom) - self.fs_sensors_list.setAttribute( - QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True - ) - self.fs_sensors_list.setWindowFlags( - self.fs_sensors_list.windowFlags() - | QtCore.Qt.WindowType.FramelessWindowHint - ) self.fs_sensors_list.setFrameStyle(0) palette = self.fs_sensors_list.palette() palette.setColor( @@ -212,7 +214,6 @@ def setupUi(self): | QtCore.Qt.AlignmentFlag.AlignVCenter, ) self.content_vertical_layout.addSpacing(5) - self.setLayout(self.content_vertical_layout) self.retranslateUi() diff --git a/BlocksScreen/lib/ui/controlStackedWidget_ui.py b/BlocksScreen/lib/ui/controlStackedWidget_ui.py index 895a1987..0b5c0b31 100644 --- a/BlocksScreen/lib/ui/controlStackedWidget_ui.py +++ b/BlocksScreen/lib/ui/controlStackedWidget_ui.py @@ -216,7 +216,7 @@ def setupUi(self, controlStackedWidget): self.mp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.mp_header_title.setObjectName("mp_header_title") self.mp_header_layout.addWidget(self.mp_header_title, 0, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.mp_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_2) + self.mp_back_btn = IconButton(parent=self.horizontalLayoutWidget_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -237,7 +237,7 @@ def setupUi(self, controlStackedWidget): self.mp_back_btn.setStyleSheet("") self.mp_back_btn.setAutoDefault(False) self.mp_back_btn.setFlat(True) - self.mp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) + self.mp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.mp_back_btn.setObjectName("mp_back_btn") self.mp_header_layout.addWidget(self.mp_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) self.gridLayoutWidget_2 = QtWidgets.QWidget(parent=self.motion_page) @@ -358,7 +358,7 @@ def setupUi(self, controlStackedWidget): self.exp_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.exp_title_label.setObjectName("exp_title_label") self.exp_header_layout.addWidget(self.exp_title_label) - self.exp_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_7) + self.exp_back_btn = IconButton(parent=self.horizontalLayoutWidget_7) self.exp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.exp_back_btn.setMaximumSize(QtCore.QSize(60, 60)) font = QtGui.QFont() @@ -374,7 +374,7 @@ def setupUi(self, controlStackedWidget): self.exp_back_btn.setStyleSheet("") self.exp_back_btn.setAutoDefault(False) self.exp_back_btn.setFlat(True) - self.exp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) + self.exp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.exp_back_btn.setObjectName("exp_back_btn") self.exp_header_layout.addWidget(self.exp_back_btn) self.verticalLayoutWidget_5 = QtWidgets.QWidget(parent=self.extrude_page) @@ -1035,7 +1035,7 @@ def setupUi(self, controlStackedWidget): self.mva_back_btn.setStyleSheet("") self.mva_back_btn.setAutoDefault(False) self.mva_back_btn.setFlat(True) - self.mva_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) + self.mva_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.mva_back_btn.setObjectName("mva_back_btn") self.mva_header_layout.addWidget(self.mva_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) self.verticalLayoutWidget = QtWidgets.QWidget(parent=self.move_axis_page) @@ -1632,7 +1632,7 @@ def setupUi(self, controlStackedWidget): self.temp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.temp_header_title.setObjectName("temp_header_title") self.horizontalLayout.addWidget(self.temp_header_title) - self.temp_back_button = BlocksCustomButton(parent=self.horizontalLayoutWidget_4) + self.temp_back_button = IconButton(parent=self.horizontalLayoutWidget_4) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -1653,7 +1653,7 @@ def setupUi(self, controlStackedWidget): self.temp_back_button.setStyleSheet("") self.temp_back_button.setAutoDefault(False) self.temp_back_button.setFlat(True) - self.temp_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) + self.temp_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.temp_back_button.setObjectName("temp_back_button") self.horizontalLayout.addWidget(self.temp_back_button) self.verticalLayoutWidget_4 = QtWidgets.QWidget(parent=self.temperature_page) @@ -1668,6 +1668,9 @@ def setupUi(self, controlStackedWidget): self.tp_content_horizontal_layout.setSpacing(5) self.tp_content_horizontal_layout.setObjectName("tp_content_horizontal_layout") self.extruder_temp_display = DisplayButton(parent=self.verticalLayoutWidget_4) + font = QtGui.QFont() + font.setPointSize(18) + self.extruder_temp_display.setFont(font) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) @@ -1682,6 +1685,7 @@ def setupUi(self, controlStackedWidget): self.extruder_temp_display.setObjectName("extruder_temp_display") self.tp_content_horizontal_layout.addWidget(self.extruder_temp_display) self.bed_temp_display = DisplayButton(parent=self.verticalLayoutWidget_4) + self.bed_temp_display.setFont(font) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) @@ -1855,12 +1859,12 @@ def setupUi(self, controlStackedWidget): self.z_adjust_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.z_adjust_header_title.setObjectName("z_adjust_header_title") self.z_adjustment_header_layout.addWidget(self.z_adjust_header_title) - self.z_adjust_back_button = BlocksCustomButton(parent=self.horizontalLayoutWidget_10) + self.z_adjust_back_button = IconButton(parent=self.horizontalLayoutWidget_10) self.z_adjust_back_button.setMinimumSize(QtCore.QSize(60, 60)) self.z_adjust_back_button.setMaximumSize(QtCore.QSize(60, 60)) self.z_adjust_back_button.setText("") self.z_adjust_back_button.setFlat(True) - self.z_adjust_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) + self.z_adjust_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.z_adjust_back_button.setObjectName("z_adjust_back_button") self.z_adjustment_header_layout.addWidget(self.z_adjust_back_button) self.verticalLayoutWidget_8 = QtWidgets.QWidget(parent=self.z_adjustment_page) @@ -2001,7 +2005,7 @@ def setupUi(self, controlStackedWidget): self.printer_settings_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.printer_settings_title_label.setObjectName("printer_settings_title_label") self.printer_setting_header_layout.addWidget(self.printer_settings_title_label) - self.printer_settings_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_12) + self.printer_settings_back_btn = IconButton(parent=self.horizontalLayoutWidget_12) self.printer_settings_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.printer_settings_back_btn.setMaximumSize(QtCore.QSize(60, 60)) font = QtGui.QFont() diff --git a/BlocksScreen/lib/ui/printStackedWidget.ui b/BlocksScreen/lib/ui/printStackedWidget.ui index 4dbbd24e..01d326fb 100644 --- a/BlocksScreen/lib/ui/printStackedWidget.ui +++ b/BlocksScreen/lib/ui/printStackedWidget.ui @@ -418,7 +418,7 @@ color: #ffffff; - + --> @@ -765,7 +765,7 @@ background-color: transparent; - + --> @@ -1308,7 +1308,7 @@ background-color: transparent; - + diff --git a/Blocks_Screen.code-workspace b/Blocks_Screen.code-workspace index 92447a1b..f4f049d6 100644 --- a/Blocks_Screen.code-workspace +++ b/Blocks_Screen.code-workspace @@ -7,25 +7,25 @@ "settings": { "autoDocstring.docstringFormat": "google", "workbench.colorCustomizations": { - "activityBar.activeBackground": "#75a9bb", - "activityBar.background": "#75a9bb", - "activityBar.foreground": "#15202b", - "activityBar.inactiveForeground": "#15202b99", - "activityBarBadge.background": "#f4eaf2", + "activityBar.activeBackground": "#325665", + "activityBar.background": "#325665", + "activityBar.foreground": "#e7e7e7", + "activityBar.inactiveForeground": "#e7e7e799", + "activityBarBadge.background": "#b56a9f", "activityBarBadge.foreground": "#15202b", - "commandCenter.border": "#15202b99", - "sash.hoverBorder": "#75a9bb", - "statusBar.background": "#5493a9", - "statusBar.foreground": "#15202b", - "statusBarItem.hoverBackground": "#437587", - "statusBarItem.remoteBackground": "#5493a9", - "statusBarItem.remoteForeground": "#15202b", - "titleBar.activeBackground": "#5493a9", - "titleBar.activeForeground": "#15202b", - "titleBar.inactiveBackground": "#5493a999", - "titleBar.inactiveForeground": "#15202b99" + "commandCenter.border": "#e7e7e799", + "sash.hoverBorder": "#325665", + "statusBar.background": "#213943", + "statusBar.foreground": "#e7e7e7", + "statusBarItem.hoverBackground": "#325665", + "statusBarItem.remoteBackground": "#213943", + "statusBarItem.remoteForeground": "#e7e7e7", + "titleBar.activeBackground": "#213943", + "titleBar.activeForeground": "#e7e7e7", + "titleBar.inactiveBackground": "#21394399", + "titleBar.inactiveForeground": "#e7e7e799" }, - "peacock.remoteColor": "#5493a9", + "peacock.remoteColor": "#213943", "todo-tree.tree.scanMode": "workspace", "todo-tree.tree.showCountsInTree": true, "todo-tree.tree.showBadges": true, @@ -33,15 +33,16 @@ "cSpell.words": [ "ENDSTOP", "logoblocks", + "Momcake", "Pixmap", "qtobject", "rescanning", - "TESTZ" + "TESTZ", + "topbar" ], "[python]": { "editor.wordBasedSuggestions": "allDocuments", "editor.defaultFormatter": "charliermarsh.ruff" - }, "ruff.lineLength": 79, "ruff.organizeImports": true, @@ -50,6 +51,5 @@ "python.analysis.autoImportCompletions": true, "editor.codeLensFontSize": 0, "editor.inlayHints.fontFamily": "Source Code Pro", - } } \ No newline at end of file From 29cad89fc937137cff20ecaec04e403fb71b69e5 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Tue, 29 Jul 2025 10:36:06 +0100 Subject: [PATCH 05/20] Work babystep page (#9) * Add: group button widget * Add: added babystepPage functionality to handle Z offset changes and design updates * pull request changes --------- Co-authored-by: Roberto Martins --- BlocksScreen/lib/moonAPI.py | 41 +- BlocksScreen/lib/panels/printTab.py | 4 + .../lib/panels/widgets/babystepPage.py | 518 +++++----- BlocksScreen/lib/panels/widgets/fansPage.py | 13 + .../lib/panels/widgets/loadingPage.py | 24 + BlocksScreen/lib/rest.py | 2 +- BlocksScreen/lib/ui/controlStackedWidget.ui | 46 +- .../lib/ui/controlStackedWidget_ui.py | 32 +- BlocksScreen/lib/utils/group_button.py | 154 +++ BlocksScreen/lib/utils/loadAnimatedLabel.py | 6 + tests/button_try.py | 122 +++ tests/random.py | 955 ++++++++++++++++++ tests/test.py | 56 + 13 files changed, 1629 insertions(+), 344 deletions(-) create mode 100644 BlocksScreen/lib/panels/widgets/fansPage.py create mode 100644 BlocksScreen/lib/panels/widgets/loadingPage.py create mode 100644 BlocksScreen/lib/utils/group_button.py create mode 100644 BlocksScreen/lib/utils/loadAnimatedLabel.py create mode 100644 tests/button_try.py create mode 100644 tests/random.py create mode 100644 tests/test.py diff --git a/BlocksScreen/lib/moonAPI.py b/BlocksScreen/lib/moonAPI.py index dd668db7..47ceb5e3 100644 --- a/BlocksScreen/lib/moonAPI.py +++ b/BlocksScreen/lib/moonAPI.py @@ -26,7 +26,9 @@ class MoonAPI(QtCore.QObject): # TODO: Callbacks for each method # TODO: Finish the pyqt slots for needed requests on the API - def __init__(self, parent: typing.Optional["QObject"], ws: typing.MoonWebSocket): + def __init__( + self, parent: typing.Optional["QObject"], ws: typing.MoonWebSocket + ): super(MoonAPI, self).__init__(parent) self._ws: MoonWebSocket = ws @@ -174,7 +176,8 @@ def get_video_devices(self): def get_cabus_devices(self, interface: str = "can0"): return self._ws.send_request( - method="machine.peripherals.canbus", params={"interface": interface} + method="machine.peripherals.canbus", + params={"interface": interface}, ) @pyqtSlot(name="api_request_file_list") @@ -227,7 +230,9 @@ def download_file(self, root: str, filename: str): if not isinstance(filename, str) or not isinstance(root, str): return False - return self._ws._moonRest.get_request(f"/server/files/{root}/{filename}") + return self._ws._moonRest.get_request( + f"/server/files/{root}/{filename}" + ) # def upload_file(self, ) # TODO: Maybe this is not necessary but either way do it @@ -268,7 +273,8 @@ def move_file(self, source_dir: str, dest_dir: str): ): return False return self._ws.send_request( - method="server.files.move", params={"source": source_dir, "dest": dest_dir} + method="server.files.move", + params={"source": source_dir, "dest": dest_dir}, ) def copy_file(self, source_dir: str, dest_dir: str): @@ -280,7 +286,8 @@ def copy_file(self, source_dir: str, dest_dir: str): ): return False return self._ws.send_request( - method="server.files.copy", params={"source": source_dir, "dest": dest_dir} + method="server.files.copy", + params={"source": source_dir, "dest": dest_dir}, ) def zip_archive(self, items: list): @@ -313,14 +320,21 @@ def list_announcements_feeds(self): return self._ws.send_request(method="server.announcements.feeds") def post_announcement_feed(self, announcement_name: str): - if isinstance(announcement_name, str) is False or announcement_name is None: + if ( + isinstance(announcement_name, str) is False + or announcement_name is None + ): return False return self._ws.send_request( - method="server.announcements.post_feed", params={"name": announcement_name} + method="server.announcements.post_feed", + params={"name": announcement_name}, ) def delete_announcement_feed(self, announcement_name: str): - if isinstance(announcement_name, str) is False or announcement_name is None: + if ( + isinstance(announcement_name, str) is False + or announcement_name is None + ): return False return self._ws.send_request( method="server.announcements.delete_feed", @@ -341,7 +355,9 @@ def get_webcam_info(self, uid: str): # TODO: Can create a class that irs a URL type like i've done before to validate the links # TODO: There are more options in this section, alot more options, later see if it's worth to implement or not - def add_update_webcam(self, cam_name: str, snapshot_url: str, stream_url: str): + def add_update_webcam( + self, cam_name: str, snapshot_url: str, stream_url: str + ): if ( isinstance(cam_name, str) is False or isinstance(snapshot_url, str) is False @@ -370,7 +386,9 @@ def delete_webcam(self, uid: str): def test_webcam(self, uid: str): if isinstance(uid, str) is False or uid is None: return False - return self._ws.send_request(method="server.webcams.test", params={"uid": uid}) + return self._ws.send_request( + method="server.webcams.test", params={"uid": uid} + ) def list_notifiers(self): return self._ws.send_request(method="server.notifiers.list") @@ -410,7 +428,8 @@ def recover_corrupt_repo(self, name: str, hard: bool = False): if isinstance(name, str) is False or name is None: return False return self._ws.send_request( - method="machine.update.recover", params={"name": name, "hard": hard} + method="machine.update.recover", + params={"name": name, "hard": hard}, ) def rollback_update(self, name: str): diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index 8872d77d..cb32c89c 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -188,6 +188,9 @@ def __init__( self.printer.gcode_move_update[str, float].connect( self.tune_page.on_gcode_move_update ) + self.printer.gcode_move_update[str, list].connect( + self.babystepPage.on_gcode_move_update + ) self.tune_page.run_gcode.connect(self.ws.api.run_gcode) self.tune_page.request_sliderPage[str, int, "PyQt_PyObject"].connect( self.on_slidePage_request @@ -228,6 +231,7 @@ def __init__( self.panel.main_print_btn.clicked.connect( partial(self.change_page, self.indexOf(self.filesPage_widget)) ) + self.babystepPage.run_gcode_signal.connect(self.ws.api.run_gcode) self.run_gcode_signal.connect(self.ws.api.run_gcode) diff --git a/BlocksScreen/lib/panels/widgets/babystepPage.py b/BlocksScreen/lib/panels/widgets/babystepPage.py index f08fc591..32733b71 100644 --- a/BlocksScreen/lib/panels/widgets/babystepPage.py +++ b/BlocksScreen/lib/panels/widgets/babystepPage.py @@ -2,6 +2,7 @@ from lib.utils.blocks_label import BlocksLabel from lib.utils.icon_button import IconButton +from lib.utils.group_button import GroupButton from PyQt6 import QtCore, QtGui, QtWidgets @@ -12,6 +13,7 @@ class BabystepPage(QtWidgets.QWidget): run_gcode: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( str, name="run_gcode" ) + _z_offset: float = 0.1 def __init__(self, parent) -> None: @@ -21,6 +23,7 @@ def __init__(self, parent) -> None: self.setAttribute(QtCore.Qt.WidgetAttribute.WA_MouseTracking, True) self.setTabletTracking(True) self.setMouseTracking(True) + self.setupUI() self.bbp_away_from_bed.clicked.connect(self.on_move_nozzle_away) self.bbp_close_to_bed.clicked.connect(self.on_move_nozzle_close) @@ -36,14 +39,15 @@ def __init__(self, parent) -> None: def on_move_nozzle_close(self) -> None: """Move the nozzle closer to the print plate by the amount set in **` self._z_offset`**""" self.run_gcode.emit( - f"SET_GCODE_OFFSET Z_ADJUST=-{self._z_offset} MOVE=1" # Z_ADJUST adds the value to the existing offset + f"SET_GCODE_OFFSET Z_ADJUST=-{self._z_offset}" # Z_ADJUST adds the value to the existing offset ) @QtCore.pyqtSlot(name="on_move_nozzle_away") def on_move_nozzle_away(self) -> None: """Slot for Babystep button to get far from the bed by **` self._z_offset`** amount""" + print("Moving nozzle away from bed by:", self._z_offset, "a") self.run_gcode.emit( - f"SET_GCODE_OFFSET Z_ADJUST=+{self._z_offset} MOVE=1" # Z_ADJUST adds the value to the existing offset + f"SET_GCODE_OFFSET Z_ADJUST=+{self._z_offset}" # Z_ADJUST adds the value to the existing offset ) @QtCore.pyqtSlot(name="handle_z_offset_change") @@ -59,13 +63,23 @@ def handle_z_offset_change(self) -> None: """ _possible_z_values: typing.List = [0.01, 0.025, 0.05, 0.1] _sender: QtCore.QObject | None = self.sender() - if _sender is not None and isinstance(_sender, QtWidgets.QLabel): - if float(_sender.text()) in _possible_z_values: - if self._z_offset == float(_sender.text()): - return - self._z_offset = float(_sender.text()) + if self._z_offset == float(_sender.text()[:-3]): + return + self._z_offset = float(_sender.text()[:-3]) + + def on_gcode_move_update(self, name: str, value: list) -> None: + if not value: + return + + if name == "homing_origin": + self._z_offset = value[2] + self.bbp_z_offset_current_value.setText( + f"Z: {self._z_offset:.3f}mm" + ) def setupUI(self): + self.bbp_offset_value_selector_group = QtWidgets.QButtonGroup(self) + self.bbp_offset_value_selector_group.setExclusive(True) sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, @@ -75,10 +89,16 @@ def setupUI(self): sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(sizePolicy) self.setMinimumSize(QtCore.QSize(710, 400)) - self.setMaximumSize(QtCore.QSize(720, 420)) + self.setMaximumSize( + QtCore.QSize(720, 420) + ) # This sets the maximum width of the entire page self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + + # Main Vertical Layout for the entire page self.verticalLayout = QtWidgets.QVBoxLayout(self) self.verticalLayout.setObjectName("verticalLayout") + + # Header Layout self.bbp_header_layout = QtWidgets.QHBoxLayout() self.bbp_header_layout.setObjectName("bbp_header_layout") self.bbp_header_title = QtWidgets.QLabel(parent=self) @@ -108,6 +128,15 @@ def setupUI(self): self.bbp_header_title.setText("Babystep") self.bbp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.bbp_header_title.setObjectName("bbp_header_title") + + spacerItem = QtWidgets.QSpacerItem( + 60, + 20, + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.bbp_header_layout.addItem(spacerItem) + self.bbp_header_layout.addWidget( self.bbp_header_title, 0, @@ -126,17 +155,162 @@ def setupUI(self): QtGui.QPixmap(":/ui/media/btn_icons/back.svg") ) self.babystep_back_btn.setObjectName("babystep_back_btn") + self.bbp_header_layout.addWidget( self.babystep_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight | QtCore.Qt.AlignmentFlag.AlignVCenter, ) - self.bbp_header_layout.setStretch(0, 1) self.verticalLayout.addLayout(self.bbp_header_layout) - self.horizontalLayout_2 = QtWidgets.QHBoxLayout() - self.horizontalLayout_2.setObjectName("horizontalLayout_2") + + self.main_content_horizontal_layout = QtWidgets.QHBoxLayout() + self.main_content_horizontal_layout.setObjectName( + "main_content_horizontal_layout" + ) + + # Offset Steps Buttons Group Box (LEFT side of main_content_horizontal_layout) + self.bbp_offset_steps_buttons_group_box = QtWidgets.QGroupBox(self) + font = QtGui.QFont() + font.setPointSize(14) + self.bbp_offset_steps_buttons_group_box.setFont(font) + self.bbp_offset_steps_buttons_group_box.setFlat(True) + # Add stylesheet to explicitly remove any border from the QGroupBox + self.bbp_offset_steps_buttons_group_box.setStyleSheet( + "QGroupBox { border: none; }" + ) + self.bbp_offset_steps_buttons_group_box.setObjectName( + "bbp_offset_steps_buttons_group_box" + ) + + self.bbp_offset_steps_buttons = QtWidgets.QVBoxLayout( + self.bbp_offset_steps_buttons_group_box + ) + self.bbp_offset_steps_buttons.setContentsMargins(9, 9, 9, 9) + self.bbp_offset_steps_buttons.setObjectName("bbp_offset_steps_buttons") + + # 0.1mm button + self.bbp_nozzle_offset_1 = GroupButton( + parent=self.bbp_offset_steps_buttons_group_box + ) + self.bbp_nozzle_offset_1.setMinimumSize(QtCore.QSize(100, 70)) + self.bbp_nozzle_offset_1.setMaximumSize(QtCore.QSize(100, 70)) + self.bbp_nozzle_offset_1.setText("0.1 mm") + + font = QtGui.QFont() + font.setPointSize(14) + self.bbp_nozzle_offset_1.setFont(font) + self.bbp_nozzle_offset_1.setCheckable(True) + self.bbp_nozzle_offset_1.setChecked(True) # Set as initially checked + self.bbp_nozzle_offset_1.setFlat(True) + self.bbp_nozzle_offset_1.setProperty("button_type", "") + self.bbp_nozzle_offset_1.setObjectName("bbp_nozzle_offset_1") + self.bbp_offset_value_selector_group.addButton( + self.bbp_nozzle_offset_1 + ) + self.bbp_offset_steps_buttons.addWidget( + self.bbp_nozzle_offset_1, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + + # Line separator for 0.1mm - set size policy to expanding horizontally + + # 0.01mm button + self.bbp_nozzle_offset_01 = GroupButton( + parent=self.bbp_offset_steps_buttons_group_box + ) + self.bbp_nozzle_offset_01.setMinimumSize(QtCore.QSize(100, 70)) + self.bbp_nozzle_offset_01.setMaximumSize( + QtCore.QSize(100, 70) + ) # Increased max width by 5 pixels + self.bbp_nozzle_offset_01.setText("0.01 mm") + + font = QtGui.QFont() + font.setPointSize(14) + self.bbp_nozzle_offset_01.setFont(font) + self.bbp_nozzle_offset_01.setCheckable(True) + self.bbp_nozzle_offset_01.setFlat(True) + self.bbp_nozzle_offset_01.setProperty("button_type", "") + self.bbp_nozzle_offset_01.setObjectName("bbp_nozzle_offset_01") + self.bbp_offset_value_selector_group.addButton( + self.bbp_nozzle_offset_01 + ) + self.bbp_offset_steps_buttons.addWidget( + self.bbp_nozzle_offset_01, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + + # 0.05mm button + self.bbp_nozzle_offset_05 = GroupButton( + parent=self.bbp_offset_steps_buttons_group_box + ) + self.bbp_nozzle_offset_05.setMinimumSize(QtCore.QSize(100, 70)) + self.bbp_nozzle_offset_05.setMaximumSize( + QtCore.QSize(100, 70) + ) # Increased max width by 5 pixels + self.bbp_nozzle_offset_05.setText("0.05 mm") + + font = QtGui.QFont() + font.setPointSize(14) + self.bbp_nozzle_offset_05.setFont(font) + self.bbp_nozzle_offset_05.setCheckable(True) + self.bbp_nozzle_offset_05.setFlat(True) + self.bbp_nozzle_offset_05.setProperty("button_type", "") + self.bbp_nozzle_offset_05.setObjectName("bbp_nozzle_offset_05") + self.bbp_offset_value_selector_group.addButton( + self.bbp_nozzle_offset_05 + ) + self.bbp_offset_steps_buttons.addWidget( + self.bbp_nozzle_offset_05, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + + # 0.025mm button + self.bbp_nozzle_offset_025 = GroupButton( + parent=self.bbp_offset_steps_buttons_group_box + ) + self.bbp_nozzle_offset_025.setMinimumSize(QtCore.QSize(100, 70)) + self.bbp_nozzle_offset_025.setMaximumSize( + QtCore.QSize(100, 70) + ) # Increased max width by 5 pixels + self.bbp_nozzle_offset_025.setText("0.025 mm") + + font = QtGui.QFont() + font.setPointSize(14) + self.bbp_nozzle_offset_025.setFont(font) + self.bbp_nozzle_offset_025.setCheckable(True) + self.bbp_nozzle_offset_025.setFlat(True) + self.bbp_nozzle_offset_025.setProperty("button_type", "") + self.bbp_nozzle_offset_025.setObjectName("bbp_nozzle_offset_025") + self.bbp_offset_value_selector_group.addButton( + self.bbp_nozzle_offset_025 + ) + self.bbp_offset_steps_buttons.addWidget( + self.bbp_nozzle_offset_025, + 0, + QtCore.Qt.AlignmentFlag.AlignHCenter + | QtCore.Qt.AlignmentFlag.AlignVCenter, + ) + + # Line separator for 0.025mm - set size policy to expanding horizontally + + # Set the layout for the group box + self.bbp_offset_steps_buttons_group_box.setLayout( + self.bbp_offset_steps_buttons + ) + # Add the group box to the main content horizontal layout FIRST for left placement + self.main_content_horizontal_layout.addWidget( + self.bbp_offset_steps_buttons_group_box + ) + + # Graphic and Current Value Frame (This will now be in the MIDDLE) self.frame_2 = QtWidgets.QFrame(parent=self) sizePolicy.setHeightForWidth( self.frame_2.sizePolicy().hasHeightForWidth() @@ -162,7 +336,7 @@ def setupUI(self): self.bbp_babystep_graphic.setObjectName("bbp_babystep_graphic") self.bbp_z_offset_current_value = BlocksLabel(parent=self.frame_2) self.bbp_z_offset_current_value.setGeometry( - QtCore.QRect(130, 70, 200, 60) + QtCore.QRect(100, 70, 200, 60) ) sizePolicy.setHeightForWidth( self.bbp_z_offset_current_value.sizePolicy().hasHeightForWidth() @@ -176,7 +350,7 @@ def setupUI(self): self.bbp_z_offset_current_value.setStyleSheet( "background: transparent; color: white;" ) - self.bbp_z_offset_current_value.setText("") + self.bbp_z_offset_current_value.setText(f"Z: {self._z_offset:.2f}mm") self.bbp_z_offset_current_value.setPixmap( QtGui.QPixmap(":/graphics/media/btn_icons/z_offset_adjust.svg") ) @@ -186,12 +360,15 @@ def setupUI(self): self.bbp_z_offset_current_value.setObjectName( "bbp_z_offset_current_value" ) - self.horizontalLayout_2.addWidget( + # Add graphic frame AFTER the offset buttons group box + self.main_content_horizontal_layout.addWidget( self.frame_2, 0, QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignVCenter, ) + + # Move Buttons Layout (This will now be on the RIGHT) self.bbp_buttons_layout = QtWidgets.QVBoxLayout() self.bbp_buttons_layout.setContentsMargins(5, 5, 5, 5) self.bbp_buttons_layout.setObjectName("bbp_buttons_layout") @@ -202,6 +379,7 @@ def setupUI(self): self.bbp_away_from_bed.setSizePolicy(sizePolicy) self.bbp_away_from_bed.setMinimumSize(QtCore.QSize(80, 80)) self.bbp_away_from_bed.setMaximumSize(QtCore.QSize(80, 80)) + self.bbp_away_from_bed.setText("") self.bbp_away_from_bed.setFlat(True) self.bbp_away_from_bed.setPixmap( QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg") @@ -220,6 +398,7 @@ def setupUI(self): self.bbp_close_to_bed.setSizePolicy(sizePolicy) self.bbp_close_to_bed.setMinimumSize(QtCore.QSize(80, 80)) self.bbp_close_to_bed.setMaximumSize(QtCore.QSize(80, 80)) + self.bbp_close_to_bed.setText("") self.bbp_close_to_bed.setFlat(True) self.bbp_close_to_bed.setPixmap( QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg") @@ -229,286 +408,43 @@ def setupUI(self): self.bbp_buttons_layout.addWidget( self.bbp_close_to_bed, 0, QtCore.Qt.AlignmentFlag.AlignRight ) - self.bbp_buttons_layout.setStretch(0, 1) - self.bbp_buttons_layout.setStretch(1, 1) - self.horizontalLayout_2.addLayout(self.bbp_buttons_layout) - self.horizontalLayout_2.setStretch(0, 1) - self.verticalLayout.addLayout(self.horizontalLayout_2) - - self.bbp_offset_steps_buttons_group_box = QtWidgets.QGroupBox() + spacerItem = QtWidgets.QSpacerItem( + 40, + 20, + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, + ) + self.main_content_horizontal_layout.addItem(spacerItem) - self.bbp_offset_steps_buttons = QtWidgets.QHBoxLayout() + # Add move buttons layout LAST for right placement + self.main_content_horizontal_layout.addLayout(self.bbp_buttons_layout) - self.bbp_offset_steps_buttons.setContentsMargins(9, 9, 9, 9) - self.bbp_offset_steps_buttons.setObjectName("bbp_offset_steps_buttons") - self.bbp_nozzle_offset_01 = QtWidgets.QPushButton(parent=self) - self.bbp_nozzle_offset_01.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_01.setMaximumSize(QtCore.QSize(100, 80)) - self.bbp_nozzle_offset_01.setText("0.01") - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - self.bbp_nozzle_offset_01.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.bbp_nozzle_offset_01.setFont(font) - self.bbp_nozzle_offset_01.setCheckable(True) - self.bbp_nozzle_offset_01.setFlat(True) - self.bbp_nozzle_offset_01.setProperty("button_type", "") - self.bbp_nozzle_offset_01.setObjectName("bbp_nozzle_offset_01") - self.bbp_offset_value_selector_group = QtWidgets.QButtonGroup(self) - self.bbp_offset_value_selector_group.setObjectName( - "bbp_offset_value_selector_group" - ) - self.bbp_offset_value_selector_group.addButton( - self.bbp_nozzle_offset_01 - ) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_01) - self.line_3 = QtWidgets.QFrame(parent=self) - self.line_3.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_3.setObjectName("line_3") - self.bbp_offset_steps_buttons.addWidget(self.line_3) - self.bbp_nozzle_offset_025 = QtWidgets.QPushButton(parent=self) - self.bbp_nozzle_offset_025.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_025.setMaximumSize(QtCore.QSize(100, 80)) - self.bbp_nozzle_offset_025.setText("0.025") - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - self.bbp_nozzle_offset_025.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.bbp_nozzle_offset_025.setFont(font) - self.bbp_nozzle_offset_025.setCheckable(True) - self.bbp_nozzle_offset_025.setFlat(True) - self.bbp_nozzle_offset_025.setProperty("button_type", "") - self.bbp_nozzle_offset_025.setObjectName("bbp_nozzle_offset_025") - self.bbp_offset_value_selector_group.addButton( - self.bbp_nozzle_offset_025 - ) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_025) - self.line_4 = QtWidgets.QFrame(parent=self) - self.line_4.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_4.setObjectName("line_4") - self.bbp_offset_steps_buttons.addWidget(self.line_4) - self.bbp_nozzle_offset_05 = QtWidgets.QPushButton(parent=self) - self.bbp_nozzle_offset_05.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_05.setMaximumSize(QtCore.QSize(100, 80)) - self.bbp_nozzle_offset_05.setText("0.05") - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - self.bbp_nozzle_offset_05.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.bbp_nozzle_offset_05.setFont(font) - self.bbp_nozzle_offset_05.setCheckable(True) - self.bbp_nozzle_offset_05.setFlat(True) - self.bbp_nozzle_offset_05.setProperty("button_type", "") - self.bbp_nozzle_offset_05.setObjectName("bbp_nozzle_offset_05") - self.bbp_offset_value_selector_group.addButton( - self.bbp_nozzle_offset_05 + spacerItem = QtWidgets.QSpacerItem( + 40, + 20, + QtWidgets.QSizePolicy.Policy.Expanding, + QtWidgets.QSizePolicy.Policy.Minimum, ) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_05) - self.line_5 = QtWidgets.QFrame(parent=self) - self.line_5.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_5.setObjectName("line_5") - self.bbp_offset_steps_buttons.addWidget(self.line_5) - self.bbp_nozzle_offset_1 = QtWidgets.QPushButton(parent=self) - self.bbp_nozzle_offset_1.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_1.setMaximumSize(QtCore.QSize(100, 80)) - self.bbp_nozzle_offset_1.setText("0.1") + self.main_content_horizontal_layout.addItem(spacerItem) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Active, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Inactive, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.WindowText, - brush, - ) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush( - QtGui.QPalette.ColorGroup.Disabled, - QtGui.QPalette.ColorRole.ButtonText, - brush, - ) - self.bbp_nozzle_offset_1.setPalette(palette) - font = QtGui.QFont() - font.setPointSize(14) - self.bbp_nozzle_offset_1.setFont(font) - self.bbp_nozzle_offset_1.setCheckable(True) - self.bbp_nozzle_offset_1.setChecked(True) - self.bbp_nozzle_offset_1.setFlat(True) - self.bbp_nozzle_offset_1.setProperty("button_type", "") - self.bbp_nozzle_offset_1.setObjectName("bbp_nozzle_offset_1") + # Set stretch factors for main content horizontal layout + # This will distribute space: offset buttons, graphic frame, move buttons + self.main_content_horizontal_layout.setStretch( + 0, 1 + ) # offset_steps_buttons_group_box + self.main_content_horizontal_layout.setStretch( + 1, 2 + ) # frame_2 (graphic and current value) + self.main_content_horizontal_layout.setStretch( + 2, 0 + ) # bbp_buttons_layout (move buttons) + + # Add the main content horizontal layout to the vertical layout + self.verticalLayout.addLayout(self.main_content_horizontal_layout) + + # Set stretch factors for vertical layout (adjust as needed for overall sizing) + self.verticalLayout.setStretch( + 1, 1 + ) # This stretch applies to main_content_horizontal_layout - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_1) - self.bbp_offset_value_selector_group.addButton( - self.bbp_nozzle_offset_1 - ) - self.bbp_offset_steps_buttons_group_box.setLayout( - self.bbp_offset_steps_buttons - ) - self.bbp_offset_steps_buttons_group_box.setPalette(palette) - - font.setPointSize(14) - self.bbp_offset_steps_buttons_group_box.setFont(font) - self.bbp_offset_steps_buttons_group_box.setFlat(True) - self.bbp_offset_steps_buttons_group_box.setTitle("Move length (mm)") - self.bbp_offset_steps_buttons_group_box.adjustSize() - self.verticalLayout.addWidget(self.bbp_offset_steps_buttons_group_box) - self.verticalLayout.setStretch(1, 1) self.setLayout(self.verticalLayout) diff --git a/BlocksScreen/lib/panels/widgets/fansPage.py b/BlocksScreen/lib/panels/widgets/fansPage.py new file mode 100644 index 00000000..5dffba42 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/fansPage.py @@ -0,0 +1,13 @@ +from PyQt6 import QtCore, QtWidgets +import typing + +class FansPage(QtWidgets.QWidget): + + def __init__( + self, parent: typing.Optional["QtWidgets.QWidget"], flags: typing.Optional["QtCore.Qt.WindowType"] + ) -> None: + if parent is not None and flags is not None: + super(FansPage, self).__init__(parent, flags) + + else : + super(FansPage, self).__init__() \ No newline at end of file diff --git a/BlocksScreen/lib/panels/widgets/loadingPage.py b/BlocksScreen/lib/panels/widgets/loadingPage.py new file mode 100644 index 00000000..1d6919ce --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/loadingPage.py @@ -0,0 +1,24 @@ +from PyQt6 import QtCore, QtWidgets, QtGui + + +class LoadingPage(QtWidgets.QWidget): + def __init__(self, parent) -> None: + super().__init__(parent) + + def setupUI(self) -> None: + 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(710, 400)) + self.setMaximumSize(QtCore.QSize(720, 420)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + + + # centered_x = (self.width() - myloadingicon.width()) // 2 + # centered_y = (self.height() - myloadingicon.height()) // 2 + # myloadingicon.moveTo(QtCore.QPoint(centered_x, centered_y)) diff --git a/BlocksScreen/lib/rest.py b/BlocksScreen/lib/rest.py index 7b78cbba..ac5ad97a 100644 --- a/BlocksScreen/lib/rest.py +++ b/BlocksScreen/lib/rest.py @@ -21,7 +21,7 @@ class WebSocketClient(tornado.websocket.WebSocketClientConnection): - url = "ws://192.168.1.165:7125" + url = "ws://192.168.1.68:7125" port = 7125 def __init__(self) -> None: diff --git a/BlocksScreen/lib/ui/controlStackedWidget.ui b/BlocksScreen/lib/ui/controlStackedWidget.ui index 2be6a888..682bc810 100644 --- a/BlocksScreen/lib/ui/controlStackedWidget.ui +++ b/BlocksScreen/lib/ui/controlStackedWidget.ui @@ -32,7 +32,7 @@ StackedWidget - 3 + 2 @@ -554,7 +554,7 @@ Settings icon - :/button_borders/media/btn_icons/back.svg + :/button_borders/media/btn_icons/back.svg @@ -901,7 +901,7 @@ Steppers icon - :/button_borders/media/btn_icons/back.svg + :/button_borders/media/btn_icons/back.svg @@ -913,7 +913,7 @@ Steppers 20 80 671 - 328 + 330 @@ -2721,7 +2721,7 @@ Steppers icon - :/button_borders/media/btn_icons/back.svg + :/button_borders/media/btn_icons/back.svg @@ -3417,7 +3417,7 @@ Steppers 0 30 291 - 61 + 62 @@ -4488,7 +4488,7 @@ Steppers icon - :/button_borders/media/btn_icons/back.svg + :/button_borders/media/btn_icons/back.svg @@ -5074,7 +5074,7 @@ Steppers true - :/button_borders/media/btn_icons/back.svg + :/button_borders/media/btn_icons/back.svg icon @@ -5089,7 +5089,7 @@ Steppers 600 110 90 - 176 + 177 @@ -5506,13 +5506,13 @@ Steppers menu_btn - :/button_borders/media/buttons/btn_part1.svg + :/button_borders/media/buttons/btn_part1.svg - :/button_borders/media/buttons/btn_part2.svg + :/button_borders/media/buttons/btn_part2.svg - :/button_borders/media/buttons/btn_part3.svg + :/button_borders/media/buttons/btn_part3.svg icon @@ -5535,16 +5535,6 @@ Steppers - - BlocksCustomButton - QPushButton -
lib.utils.blocks_button
-
- - BlocksLabel - QLabel -
lib.utils.blocks_label
-
IconButton QPushButton @@ -5555,6 +5545,16 @@ Steppers QPushButton
lib.utils.display_button
+ + BlocksCustomButton + QPushButton +
lib.utils.blocks_button
+
+ + BlocksLabel + QLabel +
lib.utils.blocks_label
+
@@ -5571,8 +5571,8 @@ Steppers + - diff --git a/BlocksScreen/lib/ui/controlStackedWidget_ui.py b/BlocksScreen/lib/ui/controlStackedWidget_ui.py index 0b5c0b31..bd95e6fb 100644 --- a/BlocksScreen/lib/ui/controlStackedWidget_ui.py +++ b/BlocksScreen/lib/ui/controlStackedWidget_ui.py @@ -216,7 +216,7 @@ def setupUi(self, controlStackedWidget): self.mp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.mp_header_title.setObjectName("mp_header_title") self.mp_header_layout.addWidget(self.mp_header_title, 0, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.mp_back_btn = IconButton(parent=self.horizontalLayoutWidget_2) + self.mp_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_2) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -237,7 +237,7 @@ def setupUi(self, controlStackedWidget): self.mp_back_btn.setStyleSheet("") self.mp_back_btn.setAutoDefault(False) self.mp_back_btn.setFlat(True) - self.mp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.mp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) self.mp_back_btn.setObjectName("mp_back_btn") self.mp_header_layout.addWidget(self.mp_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) self.gridLayoutWidget_2 = QtWidgets.QWidget(parent=self.motion_page) @@ -358,7 +358,7 @@ def setupUi(self, controlStackedWidget): self.exp_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.exp_title_label.setObjectName("exp_title_label") self.exp_header_layout.addWidget(self.exp_title_label) - self.exp_back_btn = IconButton(parent=self.horizontalLayoutWidget_7) + self.exp_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_7) self.exp_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.exp_back_btn.setMaximumSize(QtCore.QSize(60, 60)) font = QtGui.QFont() @@ -374,11 +374,11 @@ def setupUi(self, controlStackedWidget): self.exp_back_btn.setStyleSheet("") self.exp_back_btn.setAutoDefault(False) self.exp_back_btn.setFlat(True) - self.exp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.exp_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) self.exp_back_btn.setObjectName("exp_back_btn") self.exp_header_layout.addWidget(self.exp_back_btn) self.verticalLayoutWidget_5 = QtWidgets.QWidget(parent=self.extrude_page) - self.verticalLayoutWidget_5.setGeometry(QtCore.QRect(20, 80, 671, 328)) + self.verticalLayoutWidget_5.setGeometry(QtCore.QRect(20, 80, 671, 330)) self.verticalLayoutWidget_5.setObjectName("verticalLayoutWidget_5") self.exp_vertical_content_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_5) self.exp_vertical_content_layout.setContentsMargins(5, 5, 5, 5) @@ -1035,7 +1035,7 @@ def setupUi(self, controlStackedWidget): self.mva_back_btn.setStyleSheet("") self.mva_back_btn.setAutoDefault(False) self.mva_back_btn.setFlat(True) - self.mva_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.mva_back_btn.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) self.mva_back_btn.setObjectName("mva_back_btn") self.mva_header_layout.addWidget(self.mva_back_btn, 0, QtCore.Qt.AlignmentFlag.AlignRight|QtCore.Qt.AlignmentFlag.AlignVCenter) self.verticalLayoutWidget = QtWidgets.QWidget(parent=self.move_axis_page) @@ -1270,7 +1270,7 @@ def setupUi(self, controlStackedWidget): self.mva_length_group_box.setFlat(True) self.mva_length_group_box.setObjectName("mva_length_group_box") self.horizontalLayoutWidget_5 = QtWidgets.QWidget(parent=self.mva_length_group_box) - self.horizontalLayoutWidget_5.setGeometry(QtCore.QRect(0, 30, 291, 61)) + self.horizontalLayoutWidget_5.setGeometry(QtCore.QRect(0, 30, 291, 62)) self.horizontalLayoutWidget_5.setObjectName("horizontalLayoutWidget_5") self.mva_length_intervals_layout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget_5) self.mva_length_intervals_layout.setContentsMargins(0, 0, 0, 0) @@ -1632,7 +1632,7 @@ def setupUi(self, controlStackedWidget): self.temp_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.temp_header_title.setObjectName("temp_header_title") self.horizontalLayout.addWidget(self.temp_header_title) - self.temp_back_button = IconButton(parent=self.horizontalLayoutWidget_4) + self.temp_back_button = BlocksCustomButton(parent=self.horizontalLayoutWidget_4) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -1653,7 +1653,7 @@ def setupUi(self, controlStackedWidget): self.temp_back_button.setStyleSheet("") self.temp_back_button.setAutoDefault(False) self.temp_back_button.setFlat(True) - self.temp_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.temp_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) self.temp_back_button.setObjectName("temp_back_button") self.horizontalLayout.addWidget(self.temp_back_button) self.verticalLayoutWidget_4 = QtWidgets.QWidget(parent=self.temperature_page) @@ -1668,9 +1668,6 @@ def setupUi(self, controlStackedWidget): self.tp_content_horizontal_layout.setSpacing(5) self.tp_content_horizontal_layout.setObjectName("tp_content_horizontal_layout") self.extruder_temp_display = DisplayButton(parent=self.verticalLayoutWidget_4) - font = QtGui.QFont() - font.setPointSize(18) - self.extruder_temp_display.setFont(font) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) @@ -1685,7 +1682,6 @@ def setupUi(self, controlStackedWidget): self.extruder_temp_display.setObjectName("extruder_temp_display") self.tp_content_horizontal_layout.addWidget(self.extruder_temp_display) self.bed_temp_display = DisplayButton(parent=self.verticalLayoutWidget_4) - self.bed_temp_display.setFont(font) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) sizePolicy.setHorizontalStretch(1) sizePolicy.setVerticalStretch(1) @@ -1859,16 +1855,16 @@ def setupUi(self, controlStackedWidget): self.z_adjust_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.z_adjust_header_title.setObjectName("z_adjust_header_title") self.z_adjustment_header_layout.addWidget(self.z_adjust_header_title) - self.z_adjust_back_button = IconButton(parent=self.horizontalLayoutWidget_10) + self.z_adjust_back_button = BlocksCustomButton(parent=self.horizontalLayoutWidget_10) self.z_adjust_back_button.setMinimumSize(QtCore.QSize(60, 60)) self.z_adjust_back_button.setMaximumSize(QtCore.QSize(60, 60)) self.z_adjust_back_button.setText("") self.z_adjust_back_button.setFlat(True) - self.z_adjust_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.z_adjust_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/button_borders/media/btn_icons/back.svg")) self.z_adjust_back_button.setObjectName("z_adjust_back_button") self.z_adjustment_header_layout.addWidget(self.z_adjust_back_button) self.verticalLayoutWidget_8 = QtWidgets.QWidget(parent=self.z_adjustment_page) - self.verticalLayoutWidget_8.setGeometry(QtCore.QRect(600, 110, 90, 176)) + self.verticalLayoutWidget_8.setGeometry(QtCore.QRect(600, 110, 90, 177)) self.verticalLayoutWidget_8.setObjectName("verticalLayoutWidget_8") self.z_adjust_move_buttons_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget_8) self.z_adjust_move_buttons_layout.setContentsMargins(5, 5, 5, 5) @@ -2005,7 +2001,7 @@ def setupUi(self, controlStackedWidget): self.printer_settings_title_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.printer_settings_title_label.setObjectName("printer_settings_title_label") self.printer_setting_header_layout.addWidget(self.printer_settings_title_label) - self.printer_settings_back_btn = IconButton(parent=self.horizontalLayoutWidget_12) + self.printer_settings_back_btn = BlocksCustomButton(parent=self.horizontalLayoutWidget_12) self.printer_settings_back_btn.setMinimumSize(QtCore.QSize(60, 60)) self.printer_settings_back_btn.setMaximumSize(QtCore.QSize(60, 60)) font = QtGui.QFont() @@ -2035,7 +2031,7 @@ def setupUi(self, controlStackedWidget): controlStackedWidget.addWidget(self.printer_settings_page) self.retranslateUi(controlStackedWidget) - controlStackedWidget.setCurrentIndex(3) + controlStackedWidget.setCurrentIndex(2) QtCore.QMetaObject.connectSlotsByName(controlStackedWidget) def retranslateUi(self, controlStackedWidget): diff --git a/BlocksScreen/lib/utils/group_button.py b/BlocksScreen/lib/utils/group_button.py new file mode 100644 index 00000000..b9af752b --- /dev/null +++ b/BlocksScreen/lib/utils/group_button.py @@ -0,0 +1,154 @@ +import typing +from PyQt6 import QtCore, QtGui, QtWidgets + + +class GroupButton(QtWidgets.QPushButton): + """Custom Blocks QPushButton + Rounded button with a hole on the left side where an icon can be inserted + + Args: + parent (QWidget): Parent of the button + """ + + def __init__( + self, + parent: QtWidgets.QWidget, + ) -> None: + super(GroupButton, self).__init__(parent) + + self.icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() + self._icon_rect: QtCore.QRectF = QtCore.QRectF() + self.button_background = None + self.button_ellipse = None + self._text: str = "" + self._name: str = "" + self.text_color: QtGui.QColor = QtGui.QColor(0, 0, 0) + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) + + @property + def name(self): + return self._name + + @name.setter + def name(self, new_name) -> None: + self._name = new_name + self.setObjectName(new_name) + + def text(self) -> str | None: + return self._text + + def setText(self, text: str) -> None: + self._text = text + self.update() # Force button update + return + + def setPixmap(self, pixmap: QtGui.QPixmap) -> None: + self.icon_pixmap = pixmap + self.repaint() + + def paintEvent(self, e: typing.Optional[QtGui.QPaintEvent]): + opt = QtWidgets.QStyleOptionButton() + self.initStyleOption(opt) + + painter = QtGui.QPainter(self) + painter.setRenderHint(painter.RenderHint.Antialiasing, True) + painter.setRenderHint(painter.RenderHint.SmoothPixmapTransform, True) + painter.setRenderHint(painter.RenderHint.LosslessImageRendering, True) + + _rect = self.rect() + _style = self.style() + + if _style is None or _rect is None: + return + + bg_color = ( + QtGui.QColor(223, 223, 223) + if self.isChecked() + else QtGui.QColor(164, 164, 164, 90) + if self.isDown() + else QtGui.QColor(0, 0, 0, 90) + ) + + path = QtGui.QPainterPath() + xRadius = self.rect().toRectF().normalized().height() / 5.0 + yRadius = self.rect().toRectF().normalized().height() / 5.0 + painter.setBackgroundMode(QtCore.Qt.BGMode.TransparentMode) + path.addRoundedRect( + 0, + 0, + self.rect().toRectF().normalized().width(), + self.rect().toRectF().normalized().height(), + xRadius, + yRadius, + QtCore.Qt.SizeMode.AbsoluteSize, + ) + + self.button_ellipse = QtCore.QRectF( + self.rect().toRectF().normalized().left() + + self.rect().toRectF().normalized().height() * 0.05, + self.rect().toRectF().normalized().top() + + self.rect().toRectF().normalized().height() * 0.05, + (self.rect().toRectF().normalized().height() * 0.40), + (self.rect().toRectF().normalized().height() * 0.40), + ) + + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(bg_color) + painter.fillPath(path, bg_color) + + if self.text(): + if self.isChecked(): + painter.setPen(QtGui.QColor(0, 0, 0)) + else: + painter.setPen(QtGui.QColor(255, 255, 255)) + _start_text_position = int(self.button_ellipse.width() / 2) + _text_rect = _rect + _pen = painter.pen() + _pen.setStyle(QtCore.Qt.PenStyle.SolidLine) + _pen.setWidth(1) + painter.setPen(_pen) + painter.setFont(QtGui.QFont("Momcake-Thin", 14)) + + painter.drawText( + _text_rect, + QtCore.Qt.AlignmentFlag.AlignCenter, + str(self.text()), + ) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + + def setProperty(self, name: str, value: typing.Any): + if name == "name": + self._name = name + elif name == "text_color": + self.text_color = QtGui.QColor(value) + # return super().setProperty(name, value) + + def handleTouchBegin(self, e: QtCore.QEvent): + ... + # if not self.button_background: + # if self.button_background.contains(e.pos()): # type: ignore + # # super().mousePressEvent(e) + # self.mousePressEvent(e) # type: ignore + # return + # else: + # e.ignore() + # return + + def handleTouchUpdate(self, e: QtCore.QEvent): ... + def handleTouchEnd(self, e: QtCore.QEvent): ... + def handleTouchCancel(self, e: QtCore.QEvent): ... + + def event(self, e: QtCore.QEvent) -> bool: + if e.type() == QtCore.QEvent.Type.TouchBegin: + self.handleTouchBegin(e) + return False + elif e.type() == QtCore.QEvent.Type.TouchUpdate: + self.handleTouchUpdate(e) + return False + elif e.type() == QtCore.QEvent.Type.TouchEnd: + self.handleTouchEnd(e) + return False + elif e.type() == QtCore.QEvent.Type.TouchCancel: + self.handleTouchCancel(e) + return False + return super().event(e) diff --git a/BlocksScreen/lib/utils/loadAnimatedLabel.py b/BlocksScreen/lib/utils/loadAnimatedLabel.py new file mode 100644 index 00000000..4e091b48 --- /dev/null +++ b/BlocksScreen/lib/utils/loadAnimatedLabel.py @@ -0,0 +1,6 @@ +from PyQt6 import QtGui, QtWidgets, QtCore + +class LoadAnimatedLabel(QtWidgets.QLabel): + def __init__(self, parent) -> None: + super().__init__(parent) + \ No newline at end of file diff --git a/tests/button_try.py b/tests/button_try.py new file mode 100644 index 00000000..dd94dc04 --- /dev/null +++ b/tests/button_try.py @@ -0,0 +1,122 @@ +import sys + + +from PyQt6 import QtCore, QtWidgets, QtGui + + +class Button(QtWidgets.QPushButton): + def __init__(self, parent) -> None: + super().__init__(parent) + self._icon_center = None + + def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: + return super().resizeEvent(a0) + + def paintEvent(self, a0: QtGui.QPaintEvent) -> None: + opt = QtWidgets.QStyleOptionButton() + self.initStyleOption(opt) + # qp = QtGui.QPainter(self) + qp= QtWidgets.QStylePainter(self) + + qp.setPen(QtCore.Qt.PenStyle.NoPen) + qp.setRenderHint(qp.RenderHint.Antialiasing) + qp.setRenderHint(qp.RenderHint.SmoothPixmapTransform) + qp.setRenderHint(qp.RenderHint.LosslessImageRendering) + + bg_color = ( + QtGui.QColor(175, 175, 175) + if not self.isDown() + else QtGui.QColor(120, 120, 120) + ) + + path = QtGui.QPainterPath() + xRadius = self.rect().toRectF().normalized().height() / 2.0 + yRadius = self.rect().toRectF().normalized().height() / 2.0 + path.addRoundedRect( + 0, + 0, + self.rect().toRectF().normalized().width(), + self.rect().toRectF().normalized().height(), + xRadius, + yRadius, + QtCore.Qt.SizeMode.AbsoluteSize, + ) + # path.addEllipse( + # (self.rect().toRectF().normalized().height() * 0.1 / 2.0), + # (self.rect().toRectF().normalized().height() * 0.1 / 2.0), + # self.rect().toRectF().normalized().height() * 0.90, + # self.rect().toRectF().normalized().height() * 0.90, + # ) + icon_path = QtGui.QPainterPath() + icon_path.addEllipse( + self.rect().toRectF().normalized().left() + + self.rect().toRectF().normalized().height() * 0.05, + self.rect().toRectF().normalized().top() + + self.rect().toRectF().normalized().height() * 0.05, + (self.rect().toRectF().normalized().height() * 0.90), + (self.rect().toRectF().normalized().height() * 0.90), + ) + self._icon_center = icon_path.boundingRect().center() + icon_path.setFillRule(QtCore.Qt.FillRule.OddEvenFill) + cutout = path.subtracted(icon_path) + path.connectPath(icon_path) + qp.fillPath(cutout, bg_color) + # mask = QtGui.QRegion(cutout.toFillPolygon().toPolygon()) + + # self.setMask(mask) + + +class MainWindow(QtWidgets.QMainWindow): + def __init__(self) -> None: + super().__init__() + + self.setMinimumSize(1000, 800) + # self.setMaximumSize(500, 800) + self.setAutoFillBackground(True) + + p = self.palette() + p.setColor(self.backgroundRole(), QtCore.Qt.GlobalColor.blue) + + self.setPalette(p) + + self.button = Button(self) + self.button.show() + + self.button.setGeometry(QtCore.QRect(50, 100, 600, 240)) + + +if __name__ == "__main__": + app = QtWidgets.QApplication([]) + main_window = MainWindow() + + app.processEvents() + main_window.showNormal() + + sys.exit(app.exec()) + + +# path.addRoundedRect( +# 0, +# 0, +# self.rect().toRectF().width(), +# self.rect().toRectF().height(), +# self.rect().toRectF().height() * 1.1 +# - self.rect().toRectF().height() / 2, +# self.rect().toRectF().height() * 1.1 +# - self.rect().toRectF().height() / 2, +# QtCore.Qt.SizeMode.AbsoluteSize, +# ) +# path.setFillRule(QtCore.Qt.FillRule.OddEvenFill) +# path.addEllipse( +# ( +# self.rect().toRectF().height() * 0.1 +# - self.rect().toRectF().height() * 0.1 / 2.0 +# ), +# ( +# self.rect().toRectF().height() * 0.1 +# - self.rect().toRectF().height() * 0.1 / 2.0 +# ), +# self.rect().toRectF().height() * 0.90, +# self.rect().toRectF().height() * 0.90, +# ) +# mask = QtGui.QRegion(path.toFillPolygon().toPolygon()) diff --git a/tests/random.py b/tests/random.py new file mode 100644 index 00000000..d33b9684 --- /dev/null +++ b/tests/random.py @@ -0,0 +1,955 @@ +from re import search +import unittest + +config = { + "config": { + "force_move": {"enable_force_move": "True"}, + "respond": {"default_type": "echo"}, + "gcode_macro G31": { + "gcode": "\nRUN_SHELL_COMMAND CMD=clear_plr\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False" + }, + "gcode_shell_command clear_plr": { + "command": "sh /home/mks/clear_plr.sh", + "timeout": "5.", + }, + "gcode_macro save_last_file": { + "gcode": "\n\n{% set svv = printer.save_variables.variables %}\n\n{% set filepath=printer.virtual_sdcard.file_path %}\n\n{% set filename=filepath.split('/')%}\n\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename[-1] }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ printer.virtual_sdcard.file_path }\"'" + }, + "gcode_macro clear_last_file": { + "gcode": "\n{% set filename='' %}\n{% set filepath='' %}\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ filepath }\"'" + }, + "gcode_shell_command POWER_LOSS_RESUME": { + "command": "/home/mks/plr.sh", + "timeout": "420.", + }, + "gcode_macro RESUME_INTERRUPTED": { + "gcode": '\nSET_KINEMATIC_POSITION X=0\nSET_KINEMATIC_POSITION Y=0\nSET_KINEMATIC_POSITION Z=0\n{% set z_height = params.Z_HEIGHT|default(printer.save_variables.variables.power_resume_z)|float %}\n{% set last_file = params.GCODE_FILE|default(printer.save_variables.variables.last_file)|string %}\nm118 {last_file}\n\nRUN_SHELL_COMMAND CMD=POWER_LOSS_RESUME PARAMS="{z_height} \\"{last_file}\\""\nSDCARD_PRINT_FILE FILENAME=plr/"{last_file}"' + }, + "gcode_macro LOG_Z": { + "gcode": '\n{% set z_pos = printer.gcode_move.gcode_position.z %}\nRESPOND MSG="Current Z is {z_pos}"\nSAVE_VARIABLE VARIABLE=power_resume_z VALUE={z_pos}' + }, + "save_variables": { + "filename": "/home/mks/printer_data/config/saved_variables.cfg" + }, + "gcode_macro CANCEL_PRINT": { + "description": "Cancel the actual running print", + "rename_existing": "CANCEL_PRINT_BASE", + "gcode": '\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file\nG31\nTURN_OFF_HEATERS\nCANCEL_PRINT_BASE\nRESPOND TYPE=echo MSG="Cancel Print Success!"\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290 F6000\nM84 X Y E', + }, + "gcode_macro PRINT_START": { + "gcode": "\n{% set temp = params.EXTRUDER | default(220) | int %}\n{% set b_temp = params.BED | default(60) | int %}\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=True\n\nM84 E\nSET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={b_temp}\nTEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={b_temp - 5} MAXIMUM={b_temp + 5}\nG28\nBED_MESH_CALIBRATE ADAPTIVE=1\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={temp}\n\n\nTEMPERATURE_WAIT SENSOR=extruder MINIMUM={temp - 5} MAXIMUM={temp + 5}\n\n\nM400\n\n\nG90\nG92 E0\nG1 E-1\nG92 E0\nM400\n\nG92 E0\nG1 Z1.0 F3000\nG1 X0.1 Y20 Z0.3 F5000.0\nG1 X0.1 Y100.0 Z0.3 F500.0 E15\nG1 X0.4 Y100.0 Z0.3 F5000.0\nG1 X0.4 Y20 Z0.3 F500.0 E30\nG92 E0\nG1 Z1.0 F3000\nM400" + }, + "gcode_macro PAUSE": { + "description": "Pause the actual running print", + "rename_existing": "PAUSE_BASE", + "gcode": '\nRESPOND TYPE=echo MSG="Pause Print!"\n\n{% set x = params.X|default(10) %}\n{% set y = params.Y|default(290) %}\n{% set z = params.Z|default(10)|float %}\n{% set e = params.E|default(1) %}\n\n{% set max_z = printer.toolhead.axis_maximum.z|float %}\n{% set act_z = printer.toolhead.position.z|float %}\n{% set lift_z = z|abs %}\n{% if act_z < (max_z - lift_z) %}\n{% set z_safe = lift_z %}\n{% else %}\n{% set z_safe = max_z - act_z %}\n{% endif %}\n\nPAUSE_BASE\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E-{e} F500\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\n{% if "xyz" in printer.toolhead.homed_axes %}\nG1 Z{z_safe}\nG90\nG1 X{x} Y{y} F6000\n{% else %}\n{action_respond_info("Printer not homed")}\n{% endif %}', + }, + "gcode_macro RESUME": { + "description": "Resume the actual running print", + "rename_existing": "RESUME_BASE", + "gcode": '\nRESPOND TYPE=echo MSG="RESUME Print!"\n\n{% if printer["filament_switch_sensor my_sensor"].filament_detected == True %}\nRESPOND TYPE=echo MSG="RESUME Print!"\n{% set e = params.E|default(1) %}\n\n{% if \'VELOCITY\' in params|upper %}\n{% set get_params = (\'VELOCITY=\' + params.VELOCITY) %}\n{%else %}\n{% set get_params = "" %}\n{% endif %}\n\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E{e} F400\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\nRESUME_BASE {get_params}\n{% else %}\nRESPOND TYPE=echo MSG="Please Insert filament in Sensor!"\n{% endif %}', + }, + "gcode_macro END_PRINT": { + "gcode": '\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 X5 Y5 F3000\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290\n\nM84 X Y E\nRESPOND TYPE=echo MSG="Finish Print!"' + }, + "gcode_macro LOAD_FILAMENT": { + "gcode": "\nSAVE_GCODE_POSITION NAME=LOAD_STATE\nG91\nG1 E30 F300\nG1 E10 F150\nG90\nRESTORE_GCODE_POSITION NAME=LOAD_STATE" + }, + "gcode_macro UNLOAD_FILAMENT": { + "gcode": "\nSAVE_GCODE_POSITION NAME=UNLOAD_STATE\nG91\nG1 E-30 F300\nG90\nRESTORE_GCODE_POSITION NAME=UNLOAD_STATE MOVE=0" + }, + "gcode_macro LED_ON": {"gcode": "\nSET_PIN PIN=my_led VALUE=1"}, + "gcode_macro LED_OFF": {"gcode": "\nSET_PIN PIN=my_led VALUE=0"}, + "gcode_macro M205": {"gcode": "\nM105"}, + "gcode_macro PRINT_END": { + "gcode": "\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file" + }, + "exclude_object": {}, + "mcu": { + "serial": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0", + "restart_method": "command", + }, + "printer": { + "kinematics": "cartesian", + "max_velocity": "300", + "max_accel": "10000", + "max_accel_to_decel": "5000", + "max_z_velocity": "15", + "max_z_accel": "100", + "square_corner_velocity": "6", + }, + "virtual_sdcard": {"path": "/home/mks/printer_data/gcodes"}, + "pause_resume": {}, + "display_status": {}, + "gcode_arcs": {"resolution": "0.8"}, + "idle_timeout": { + "gcode": '\nRESPOND TYPE=echo MSG="No operations in 10min!"', + "timeout": "600", + }, + "mcu rpi": {"serial": "/tmp/klipper_host_mcu"}, + "adxl345": {"cs_pin": "rpi:None", "spi_bus": "spidev0.0"}, + "verify_heater extruder": { + "max_error": "60", + "check_gain_time": "20", + "hysteresis": "5", + "heating_gain": "2", + }, + "verify_heater heater_bed": { + "max_error": "180", + "check_gain_time": "120", + "hysteresis": "5", + "heating_gain": "2", + }, + "resonance_tester": { + "accel_chip": "adxl345", + "probe_points": "\n150, 150, 20", + "accel_per_hz": "100", + "min_freq": "1", + "max_freq": "100", + "max_smoothing": "0.2", + "hz_per_sec": "0.5", + }, + "stepper_x": { + "step_pin": "PD15", + "dir_pin": "PD14", + "enable_pin": "!PC7", + "microsteps": "16", + "rotation_distance": "40", + "endstop_pin": "tmc2209_stepper_x: virtual_endstop", + "homing_retract_dist": "0", + "position_endstop": "-12", + "position_min": "-12", + "position_max": "302", + "homing_speed": "50", + "step_pulse_duration": "0.000002", + }, + "tmc2209 stepper_x": { + "uart_pin": "PE3", + "run_current": "1.2", + "uart_address": "3", + "interpolate": "True", + "driver_sgthrs": "95", + "stealthchop_threshold": "0", + "diag_pin": "^PD10", + }, + "stepper_y": { + "step_pin": "PB7", + "dir_pin": "PB6", + "enable_pin": "!PB9", + "microsteps": "16", + "rotation_distance": "40", + "endstop_pin": "tmc2209_stepper_y: virtual_endstop", + "homing_retract_dist": "0", + "position_endstop": "-6", + "position_min": "-6", + "position_max": "302", + "homing_speed": "50", + "step_pulse_duration": "0.000002", + }, + "tmc2209 stepper_y": { + "uart_pin": "PE4", + "run_current": "1.2", + "uart_address": "3", + "interpolate": "True", + "driver_sgthrs": "95", + "stealthchop_threshold": "0", + "diag_pin": "^PE0", + }, + "stepper_z": { + "step_pin": "PB3", + "dir_pin": "!PD7", + "enable_pin": "!PB5", + "microsteps": "16", + "rotation_distance": "8", + "endstop_pin": "probe:z_virtual_endstop", + "position_max": "355", + "position_min": "-4", + "homing_speed": "10", + }, + "stepper_z1": { + "step_pin": "PA7", + "dir_pin": "!PA6", + "enable_pin": "!PC5", + "microsteps": "16", + "rotation_distance": "8", + "endstop_pin": "probe:z_virtual_endstop", + }, + "extruder": { + "max_extrude_only_distance": "100.0", + "step_pin": "PD1", + "dir_pin": "!PD0", + "enable_pin": "!PD4", + "microsteps": "16", + "rotation_distance": "4.59", + "nozzle_diameter": "0.400", + "filament_diameter": "1.750", + "heater_pin": "PA1", + "sensor_type": "EPCOS 100K B57560G104F", + "sensor_pin": "PA4", + "control": "pid", + "pressure_advance": "0.02", + "pressure_advance_smooth_time": "0.035", + "max_extrude_cross_section": "500", + "instantaneous_corner_velocity": "10", + "max_extrude_only_velocity": "2000", + "max_extrude_only_accel": "10000", + "pid_kp": "24.522", + "pid_ki": "1.397", + "pid_kd": "107.590", + "min_temp": "0", + "max_temp": "305", + "min_extrude_temp": "150", + }, + "tmc2209 extruder": { + "uart_pin": "PE7", + "run_current": "0.6", + "uart_address": "3", + "interpolate": "True", + }, + "heater_bed": { + "heater_pin": "PA2", + "sensor_type": "EPCOS 100K B57560G104F", + "sensor_pin": "PA3", + "control": "pid", + "pid_kp": "54.027", + "pid_ki": "0.770", + "pid_kd": "948.182", + "min_temp": "0", + "max_temp": "105", + }, + "probe": { + "pin": "PD13", + "x_offset": "27", + "y_offset": "-20", + "z_offset": "2.465", + }, + "bltouch": {"#guov": 2039}, + "probe_eddy_current": {"falsk": 329}, + "filament_switch_sensor my_sensor": {"switch_pin": "PD11"}, + "safe_z_home": { + "home_xy_position": "123,170", + "speed": "80", + "z_hop": "10", + "z_hop_speed": "15", + "move_to_previous": "True", + }, + "z_tilt": { + "z_positions": "-8, 170\n260, 170", + "points": "-8, 170\n260, 170", + "speed": "200", + "horizontal_move_z": "5", + "retries": "20", + "retry_tolerance": ".005", + }, + "bed_mesh": { + "speed": "200", + "horizontal_move_z": "5", + "mesh_min": "17,15", + "mesh_max": "285,282", + "probe_count": "5,5", + "algorithm": "bicubic", + "bicubic_tension": "0.3", + "fade_start": "0.2", + "fade_end": "5.0", + "mesh_pps": "4,4", + "move_check_distance": "3", + "adaptive_margin": "5", + }, + "screws_tilt_adjust": { + "screw1": "4, 58", + "screw1_name": "front left screw", + "screw2": "243, 58", + "screw2_name": "front right screw", + "screw3": "243, 290", + "screw3_name": "rear right screw", + "screw4": "4, 290", + "screw4_name": "rear left screw", + "horizontal_move_z": "5.", + "speed": "200.", + "screw_thread": "CW-M4", + }, + "heater_fan hotend_fan": {"pin": "PE11"}, + "multi_pin fan_pins": {"pins": "PE9,PE13"}, + "fan": {"pin": "multi_pin:fan_pins"}, + "output_pin my_led": { + "pin": "PC4", + "pwm": "1", + "value": "1", + "cycle_time": "0.010", + }, + "controller_fan Fan_Board": { + "pin": "PD3", + "fan_speed": "1.0", + "idle_timeout": "120", + "heater": "heater_bed, extruder", + "stepper": "stepper_x, stepper_y, stepper_z, stepper_z1", + }, + "input_shaper": { + "damping_ratio_x": "0.05", + "damping_ratio_y": "0.1", + "shaper_type_x": "zv", + "shaper_freq_x": "48.8", + "shaper_type_y": "mzv", + "shaper_freq_y": "49.0", + }, + "bed_mesh default": { + "version": "1", + "points": "\n-0.190000, -0.125000, 0.010000, 0.095000, 0.122500\n-0.145000, -0.095000, 0.067500, 0.125000, 0.130000\n-0.040000, -0.130000, 0.055000, 0.132500, 0.115000\n0.195000, -0.150000, 0.055000, 0.320000, 0.160000\n-0.240000, -0.110000, 0.067500, 0.197500, 0.222500", + "x_count": "5", + "y_count": "5", + "mesh_x_pps": "4", + "mesh_y_pps": "4", + "algo": "bicubic", + "tension": "0.3", + "min_x": "17.0", + "max_x": "285.0", + "min_y": "15.0", + "max_y": "282.0", + }, + }, + "warnings": [ + { + "type": "deprecated_option", + "message": "Option 'max_accel_to_decel' in section 'printer' is deprecated.", + "section": "printer", + "option": "max_accel_to_decel", + } + ], + "save_config_pending": False, + "save_config_pending_items": {}, + "settings": { + "mcu": { + "serial": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0", + "baud": 250000, + "restart_method": "command", + "max_stepper_error": 2.5e-05, + }, + "mcu rpi": { + "serial": "/tmp/klipper_host_mcu", + "max_stepper_error": 2.5e-05, + }, + "force_move": {"enable_force_move": True}, + "respond": {"default_type": "echo", "default_prefix": "echo:"}, + "gcode_macro g31": { + "gcode": "\nRUN_SHELL_COMMAND CMD=clear_plr\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False", + "description": "G-Code macro", + }, + "gcode_shell_command clear_plr": { + "command": "sh /home/mks/clear_plr.sh", + "timeout": 5.0, + "verbose": True, + }, + "gcode_macro save_last_file": { + "gcode": "\n\n{% set svv = printer.save_variables.variables %}\n\n{% set filepath=printer.virtual_sdcard.file_path %}\n\n{% set filename=filepath.split('/')%}\n\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename[-1] }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ printer.virtual_sdcard.file_path }\"'", + "description": "G-Code macro", + }, + "gcode_macro clear_last_file": { + "gcode": "\n{% set filename='' %}\n{% set filepath='' %}\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ filepath }\"'", + "description": "G-Code macro", + }, + "gcode_shell_command power_loss_resume": { + "command": "/home/mks/plr.sh", + "timeout": 420.0, + "verbose": True, + }, + "gcode_macro resume_interrupted": { + "gcode": '\nSET_KINEMATIC_POSITION X=0\nSET_KINEMATIC_POSITION Y=0\nSET_KINEMATIC_POSITION Z=0\n{% set z_height = params.Z_HEIGHT|default(printer.save_variables.variables.power_resume_z)|float %}\n{% set last_file = params.GCODE_FILE|default(printer.save_variables.variables.last_file)|string %}\nm118 {last_file}\n\nRUN_SHELL_COMMAND CMD=POWER_LOSS_RESUME PARAMS="{z_height} \\"{last_file}\\""\nSDCARD_PRINT_FILE FILENAME=plr/"{last_file}"', + "description": "G-Code macro", + }, + "gcode_macro log_z": { + "gcode": '\n{% set z_pos = printer.gcode_move.gcode_position.z %}\nRESPOND MSG="Current Z is {z_pos}"\nSAVE_VARIABLE VARIABLE=power_resume_z VALUE={z_pos}', + "description": "G-Code macro", + }, + "save_variables": { + "filename": "/home/mks/printer_data/config/saved_variables.cfg" + }, + "gcode_macro cancel_print": { + "gcode": '\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file\nG31\nTURN_OFF_HEATERS\nCANCEL_PRINT_BASE\nRESPOND TYPE=echo MSG="Cancel Print Success!"\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290 F6000\nM84 X Y E', + "rename_existing": "CANCEL_PRINT_BASE", + "description": "Cancel the actual running print", + }, + "gcode_macro print_start": { + "gcode": "\n{% set temp = params.EXTRUDER | default(220) | int %}\n{% set b_temp = params.BED | default(60) | int %}\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=True\n\nM84 E\nSET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={b_temp}\nTEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={b_temp - 5} MAXIMUM={b_temp + 5}\nG28\nBED_MESH_CALIBRATE ADAPTIVE=1\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={temp}\n\n\nTEMPERATURE_WAIT SENSOR=extruder MINIMUM={temp - 5} MAXIMUM={temp + 5}\n\n\nM400\n\n\nG90\nG92 E0\nG1 E-1\nG92 E0\nM400\n\nG92 E0\nG1 Z1.0 F3000\nG1 X0.1 Y20 Z0.3 F5000.0\nG1 X0.1 Y100.0 Z0.3 F500.0 E15\nG1 X0.4 Y100.0 Z0.3 F5000.0\nG1 X0.4 Y20 Z0.3 F500.0 E30\nG92 E0\nG1 Z1.0 F3000\nM400", + "description": "G-Code macro", + }, + "gcode_macro pause": { + "gcode": '\nRESPOND TYPE=echo MSG="Pause Print!"\n\n{% set x = params.X|default(10) %}\n{% set y = params.Y|default(290) %}\n{% set z = params.Z|default(10)|float %}\n{% set e = params.E|default(1) %}\n\n{% set max_z = printer.toolhead.axis_maximum.z|float %}\n{% set act_z = printer.toolhead.position.z|float %}\n{% set lift_z = z|abs %}\n{% if act_z < (max_z - lift_z) %}\n{% set z_safe = lift_z %}\n{% else %}\n{% set z_safe = max_z - act_z %}\n{% endif %}\n\nPAUSE_BASE\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E-{e} F500\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\n{% if "xyz" in printer.toolhead.homed_axes %}\nG1 Z{z_safe}\nG90\nG1 X{x} Y{y} F6000\n{% else %}\n{action_respond_info("Printer not homed")}\n{% endif %}', + "rename_existing": "PAUSE_BASE", + "description": "Pause the actual running print", + }, + "gcode_macro resume": { + "gcode": '\nRESPOND TYPE=echo MSG="RESUME Print!"\n\n{% if printer["filament_switch_sensor my_sensor"].filament_detected == True %}\nRESPOND TYPE=echo MSG="RESUME Print!"\n{% set e = params.E|default(1) %}\n\n{% if \'VELOCITY\' in params|upper %}\n{% set get_params = (\'VELOCITY=\' + params.VELOCITY) %}\n{%else %}\n{% set get_params = "" %}\n{% endif %}\n\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E{e} F400\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\nRESUME_BASE {get_params}\n{% else %}\nRESPOND TYPE=echo MSG="Please Insert filament in Sensor!"\n{% endif %}', + "rename_existing": "RESUME_BASE", + "description": "Resume the actual running print", + }, + "gcode_macro end_print": { + "gcode": '\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 X5 Y5 F3000\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290\n\nM84 X Y E\nRESPOND TYPE=echo MSG="Finish Print!"', + "description": "G-Code macro", + }, + "gcode_macro load_filament": { + "gcode": "\nSAVE_GCODE_POSITION NAME=LOAD_STATE\nG91\nG1 E30 F300\nG1 E10 F150\nG90\nRESTORE_GCODE_POSITION NAME=LOAD_STATE", + "description": "G-Code macro", + }, + "gcode_macro unload_filament": { + "gcode": "\nSAVE_GCODE_POSITION NAME=UNLOAD_STATE\nG91\nG1 E-30 F300\nG90\nRESTORE_GCODE_POSITION NAME=UNLOAD_STATE MOVE=0", + "description": "G-Code macro", + }, + "gcode_macro led_on": { + "gcode": "\nSET_PIN PIN=my_led VALUE=1", + "description": "G-Code macro", + }, + "gcode_macro led_off": { + "gcode": "\nSET_PIN PIN=my_led VALUE=0", + "description": "G-Code macro", + }, + "gcode_macro m205": {"gcode": "\nM105", "description": "G-Code macro"}, + "gcode_macro print_end": { + "gcode": "\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file", + "description": "G-Code macro", + }, + "virtual_sdcard": { + "path": "/home/mks/printer_data/gcodes", + "on_error_gcode": "\n{% if 'heaters' in printer %}\n TURN_OFF_HEATERS\n{% endif %}\n", + }, + "pause_resume": {"recover_velocity": 50.0}, + "gcode_arcs": {"resolution": 0.8}, + "idle_timeout": { + "timeout": 600.0, + "gcode": '\nRESPOND TYPE=echo MSG="No operations in 10min!"', + }, + "adxl345": { + "axes_map": ["x", "y", "z"], + "rate": 3200, + "cs_pin": "rpi:None", + "spi_speed": 5000000, + "spi_bus": "spidev0.0", + }, + "verify_heater extruder": { + "hysteresis": 5.0, + "max_error": 60.0, + "heating_gain": 2.0, + "check_gain_time": 20.0, + }, + "verify_heater heater_bed": { + "hysteresis": 5.0, + "max_error": 180.0, + "heating_gain": 2.0, + "check_gain_time": 120.0, + }, + "resonance_tester": { + "move_speed": 50.0, + "min_freq": 1.0, + "max_freq": 100.0, + "accel_per_hz": 100.0, + "hz_per_sec": 0.5, + "sweeping_accel": 400.0, + "sweeping_period": 1.2, + "accel_chip": "adxl345", + "max_smoothing": 0.2, + "probe_points": [[150.0, 150.0, 20.0]], + }, + "tmc2209 stepper_x": { + "uart_pin": "PE3", + "uart_address": 3, + "diag_pin": "^PD10", + "run_current": 1.2, + "hold_current": 2.0, + "sense_resistor": 0.11, + "interpolate": True, + "stealthchop_threshold": 0.0, + "driver_multistep_filt": True, + "driver_toff": 3, + "driver_hstrt": 5, + "driver_hend": 0, + "driver_tbl": 2, + "driver_semin": 0, + "driver_seup": 0, + "driver_semax": 0, + "driver_sedn": 0, + "driver_seimin": 0, + "driver_iholddelay": 8, + "driver_pwm_ofs": 36, + "driver_pwm_grad": 14, + "driver_pwm_freq": 1, + "driver_pwm_autoscale": True, + "driver_pwm_autograd": True, + "driver_pwm_reg": 8, + "driver_pwm_lim": 12, + "driver_tpowerdown": 20, + "driver_sgthrs": 95, + }, + "stepper_x": { + "microsteps": 16, + "step_pin": "PD15", + "dir_pin": "PD14", + "rotation_distance": 40.0, + "full_steps_per_rotation": 200, + "gear_ratio": [], + "step_pulse_duration": 2e-06, + "enable_pin": "!PC7", + "endstop_pin": "tmc2209_stepper_x: virtual_endstop", + "position_endstop": -12.0, + "position_min": -12.0, + "position_max": 302.0, + "homing_speed": 50.0, + "second_homing_speed": 25.0, + "homing_retract_speed": 50.0, + "homing_retract_dist": 0.0, + "homing_positive_dir": False, + }, + "tmc2209 stepper_y": { + "uart_pin": "PE4", + "uart_address": 3, + "diag_pin": "^PE0", + "run_current": 1.2, + "hold_current": 2.0, + "sense_resistor": 0.11, + "interpolate": True, + "stealthchop_threshold": 0.0, + "driver_multistep_filt": True, + "driver_toff": 3, + "driver_hstrt": 5, + "driver_hend": 0, + "driver_tbl": 2, + "driver_semin": 0, + "driver_seup": 0, + "driver_semax": 0, + "driver_sedn": 0, + "driver_seimin": 0, + "driver_iholddelay": 8, + "driver_pwm_ofs": 36, + "driver_pwm_grad": 14, + "driver_pwm_freq": 1, + "driver_pwm_autoscale": True, + "driver_pwm_autograd": True, + "driver_pwm_reg": 8, + "driver_pwm_lim": 12, + "driver_tpowerdown": 20, + "driver_sgthrs": 95, + }, + "stepper_y": { + "microsteps": 16, + "step_pin": "PB7", + "dir_pin": "PB6", + "rotation_distance": 40.0, + "full_steps_per_rotation": 200, + "gear_ratio": [], + "step_pulse_duration": 2e-06, + "enable_pin": "!PB9", + "endstop_pin": "tmc2209_stepper_y: virtual_endstop", + "position_endstop": -6.0, + "position_min": -6.0, + "position_max": 302.0, + "homing_speed": 50.0, + "second_homing_speed": 25.0, + "homing_retract_speed": 50.0, + "homing_retract_dist": 0.0, + "homing_positive_dir": False, + }, + "tmc2209 extruder": { + "uart_pin": "PE7", + "uart_address": 3, + "run_current": 0.6, + "hold_current": 2.0, + "sense_resistor": 0.11, + "interpolate": True, + "driver_multistep_filt": True, + "driver_toff": 3, + "driver_hstrt": 5, + "driver_hend": 0, + "driver_tbl": 2, + "driver_semin": 0, + "driver_seup": 0, + "driver_semax": 0, + "driver_sedn": 0, + "driver_seimin": 0, + "driver_iholddelay": 8, + "driver_pwm_ofs": 36, + "driver_pwm_grad": 14, + "driver_pwm_freq": 1, + "driver_pwm_autoscale": True, + "driver_pwm_autograd": True, + "driver_pwm_reg": 8, + "driver_pwm_lim": 12, + "driver_tpowerdown": 20, + "driver_sgthrs": 0, + }, + "extruder": { + "microsteps": 16, + "sensor_type": "EPCOS 100K B57560G104F", + "pullup_resistor": 4700.0, + "inline_resistor": 0.0, + "sensor_pin": "PA4", + "min_temp": 0.0, + "max_temp": 305.0, + "min_extrude_temp": 150.0, + "max_power": 1.0, + "smooth_time": 1.0, + "control": "pid", + "pid_kp": 24.522, + "pid_ki": 1.397, + "pid_kd": 107.59, + "heater_pin": "PA1", + "pwm_cycle_time": 0.1, + "nozzle_diameter": 0.4, + "filament_diameter": 1.75, + "max_extrude_cross_section": 500.0, + "max_extrude_only_velocity": 2000.0, + "max_extrude_only_accel": 10000.0, + "max_extrude_only_distance": 100.0, + "instantaneous_corner_velocity": 10.0, + "step_pin": "PD1", + "pressure_advance": 0.02, + "pressure_advance_smooth_time": 0.035, + "dir_pin": "!PD0", + "rotation_distance": 4.59, + "full_steps_per_rotation": 200, + "gear_ratio": [], + "enable_pin": "!PD4", + }, + "heater_bed": { + "sensor_type": "EPCOS 100K B57560G104F", + "pullup_resistor": 4700.0, + "inline_resistor": 0.0, + "sensor_pin": "PA3", + "min_temp": 0.0, + "max_temp": 105.0, + "min_extrude_temp": 170.0, + "max_power": 1.0, + "smooth_time": 1.0, + "control": "pid", + "pid_kp": 54.027, + "pid_ki": 0.77, + "pid_kd": 948.182, + "heater_pin": "PA2", + "pwm_cycle_time": 0.1, + }, + "probe": { + "z_offset": 2.465, + "deactivate_on_each_sample": True, + "activate_gcode": "", + "deactivate_gcode": "", + "pin": "PD13", + "x_offset": 27.0, + "y_offset": -20.0, + "speed": 5.0, + "lift_speed": 5.0, + "samples": 1, + "sample_retract_dist": 2.0, + "samples_result": "average", + "samples_tolerance": 0.1, + "samples_tolerance_retries": 0, + }, + "filament_switch_sensor my_sensor": { + "switch_pin": "PD11", + "pause_on_runout": True, + "runout_gcode": "", + "pause_delay": 0.5, + "event_delay": 3.0, + }, + "safe_z_home": { + "home_xy_position": [123.0, 170.0], + "z_hop": 10.0, + "z_hop_speed": 15.0, + "speed": 80.0, + "move_to_previous": True, + }, + "z_tilt": { + "z_positions": [[-8.0, 170.0], [260.0, 170.0]], + "retries": 20, + "retry_tolerance": 0.005, + "points": [[-8.0, 170.0], [260.0, 170.0]], + "horizontal_move_z": 5.0, + "speed": 200.0, + }, + "bed_mesh": { + "adaptive_margin": 5.0, + "probe_count": [5, 5], + "mesh_min": [17.0, 15.0], + "mesh_max": [285.0, 282.0], + "mesh_pps": [4, 4], + "algorithm": "bicubic", + "bicubic_tension": 0.3, + "scan_overshoot": 0, + "horizontal_move_z": 5.0, + "speed": 200.0, + "fade_start": 0.2, + "fade_end": 5.0, + "split_delta_z": 0.025, + "move_check_distance": 3.0, + }, + "bed_mesh default": { + "version": 1, + "points": [ + [-0.19, -0.125, 0.01, 0.095, 0.1225], + [-0.145, -0.095, 0.0675, 0.125, 0.13], + [-0.04, -0.13, 0.055, 0.1325, 0.115], + [0.195, -0.15, 0.055, 0.32, 0.16], + [-0.24, -0.11, 0.0675, 0.1975, 0.2225], + ], + "min_x": 17.0, + "max_x": 285.0, + "min_y": 15.0, + "max_y": 282.0, + "x_count": 5, + "y_count": 5, + "mesh_x_pps": 4, + "mesh_y_pps": 4, + "algo": "bicubic", + "tension": 0.3, + }, + "screws_tilt_adjust": { + "screw1": [4.0, 58.0], + "screw1_name": "front left screw", + "screw2": [243.0, 58.0], + "screw2_name": "front right screw", + "screw3": [243.0, 290.0], + "screw3_name": "rear right screw", + "screw4": [4.0, 290.0], + "screw4_name": "rear left screw", + "screw_thread": "CW-M4", + "horizontal_move_z": 5.0, + "speed": 200.0, + }, + "heater_fan hotend_fan": { + "heater": ["extruder"], + "heater_temp": 50.0, + "max_power": 1.0, + "kick_start_time": 0.1, + "off_below": 0.0, + "cycle_time": 0.01, + "hardware_pwm": False, + "shutdown_speed": 1.0, + "pin": "PE11", + "fan_speed": 1.0, + }, + "multi_pin fan_pins": {"pins": ["PE9", "PE13"]}, + "fan": { + "max_power": 1.0, + "kick_start_time": 0.1, + "off_below": 0.0, + "cycle_time": 0.01, + "hardware_pwm": False, + "shutdown_speed": 0.0, + "pin": "multi_pin:fan_pins", + }, + "output_pin my_led": { + "pwm": True, + "pin": "PC4", + "cycle_time": 0.01, + "hardware_pwm": False, + "scale": 1.0, + "value": 1.0, + "shutdown_value": 0.0, + }, + "controller_fan fan_board": { + "stepper": ["stepper_x", "stepper_y", "stepper_z", "stepper_z1"], + "max_power": 1.0, + "kick_start_time": 0.1, + "off_below": 0.0, + "cycle_time": 0.01, + "hardware_pwm": False, + "shutdown_speed": 0.0, + "pin": "PD3", + "fan_speed": 1.0, + "idle_speed": 1.0, + "idle_timeout": 120, + "heater": ["heater_bed", "extruder"], + }, + "input_shaper": { + "shaper_type": "mzv", + "shaper_type_x": "zv", + "damping_ratio_x": 0.05, + "shaper_freq_x": 48.8, + "shaper_type_y": "mzv", + "damping_ratio_y": 0.1, + "shaper_freq_y": 49.0, + }, + "printer": { + "max_velocity": 300.0, + "max_accel": 10000.0, + "max_accel_to_decel": 5000.0, + "minimum_cruise_ratio": 0.5, + "square_corner_velocity": 6.0, + "kinematics": "cartesian", + "max_z_velocity": 15.0, + "max_z_accel": 100.0, + }, + "stepper_z": { + "step_pin": "PB3", + "dir_pin": "!PD7", + "rotation_distance": 8.0, + "microsteps": 16, + "full_steps_per_rotation": 200, + "gear_ratio": [], + "enable_pin": "!PB5", + "endstop_pin": "probe:z_virtual_endstop", + "position_min": -4.0, + "position_max": 355.0, + "homing_speed": 10.0, + "second_homing_speed": 5.0, + "homing_retract_speed": 10.0, + "homing_retract_dist": 5.0, + "homing_positive_dir": False, + }, + "stepper_z1": { + "step_pin": "PA7", + "dir_pin": "!PA6", + "rotation_distance": 8.0, + "microsteps": 16, + "full_steps_per_rotation": 200, + "gear_ratio": [], + "enable_pin": "!PC5", + "endstop_pin": "probe:z_virtual_endstop", + }, + }, +} + + +def search_config_sections(section: str) -> list: + """Retrieve a section or sections from the printers configfile + + Args: + section (str): Name of the section + name (str, optional): Name of the section object. Defaults to "". + + Returns: + dict | None: The entire section with the section as key or None if + nothing is found + """ + + if not config or not section: + return [] + + # if "config" not in config.keys(): + if not config.get("config"): + return [] + _printer_config = config.get("config") + + return [ + {key: _printer_config} + for key in config["config"].keys() + if key.startswith(section) # O(s) time per key + ] + # Iterates over every key and checks if it starts + # with the prefix -> Complexity O(n*s) + # Simple but becomes costly for large n values + # since the dictionary is not exactly big, it should be ok + + +def get_probe(config): + _probe_type = ["probe", "bltouch", "probe_eddy_current", "smart_effector"] + _add = [] + for probe in _probe_type: + hit = search_config_sections(probe) + if hit: + _add.extend(hit) + return _add + + +def search_from_list(search_list: list, _objects: list = []): + if len(search_list) == 0: + return _objects + _objects.extend(search_config_sections(search_list.pop())) + print(_objects) + return search_from_list(search_list, _objects) + + +class test_get_configs(unittest.TestCase): + # def test_search_all_no_recursion(self): + # _probe_type = ["probe", "bltouch", "probe_eddy_current", "smart_effector"] + # self.assertEqual( + # get_probe(config), + # [ + # { + # "probe": { + # "pin": "PD13", + # "x_offset": "27", + # "y_offset": "-20", + # "z_offset": "2.465", + # } + # }, + # { + # "probe2": { + # "pin": "PD13", + # "x_offset": "27", + # "y_offset": "-20", + # "z_offset": "2.465", + # } + # }, + # {"bltouch": {"#guov": 2039}}, + # ], + # ) + + def test_diff_search_one(self): + _probe_type = _probe_type = ["probe"] + self.assertEqual( + search_from_list(_probe_type), + [ + { + "probe": { + "pin": "PD13", + "x_offset": "27", + "y_offset": "-20", + "z_offset": "2.465", + } + }, + { + "probe2": { + "pin": "PD13", + "x_offset": "27", + "y_offset": "-20", + "z_offset": "2.465", + }, + }, + ], + ) + + def test_diff_search_two(self): + _probe_type = ["probe", "bltouch" , "probe_eddy_current", "smart_effector"] + search_from_list( + _probe_type, + [ + { + "probe": { + "pin": "PD13", + "x_offset": "27", + "y_offset": "-20", + "z_offset": "2.465", + } + }, + + {"bltouch": {"#guov": 2039}}, + ], + ) + + def test_search_more_than_two(self): + _list = ["stepper_x", "stepper_y", "probe", "probe_eddy_current", "smart_effector"] + # def test_diff_search_two(self): + # _probe_type = ["probe", "bltouch"] + # self.assertEqual( + # search_from_list(_probe_type), + # [ + # { + # "probe": { + # "pin": "PD13", + # "x_offset": "27", + # "y_offset": "-20", + # "z_offset": "2.465", + # } + # }, + # { + # "probe2": { + # "pin": "PD13", + # "x_offset": "27", + # "y_offset": "-20", + # "z_offset": "2.465", + # } + # }, + # {"bltouch": {"#guov": 2039}}, + # ], + # ) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test.py b/tests/test.py new file mode 100644 index 00000000..7a137cfb --- /dev/null +++ b/tests/test.py @@ -0,0 +1,56 @@ +import sys +from PyQt6.QtCore import QRectF, Qt +from PyQt6.QtGui import QPainter, QPainterPath, QColor +from PyQt6.QtWidgets import QApplication, QWidget + +class SubtractedRectanglesWindow(QWidget): + def __init__(self): + super().__init__() + self.setWindowTitle("PyQt6 QPainterPath Subtraction") + self.setGeometry(100, 100, 600, 400) # x, y, width, height + + def paintEvent(self, event): + painter = QPainter(self) + painter.setRenderHint(QPainter.RenderHint.Antialiasing) + + # 1. Define the big rectangle + big_rect = QRectF(50, 50, 500, 300) # x, y, width, height + big_rect_path = QPainterPath() + big_rect_path.addRect(big_rect) + + # 2. Define the small rectangle inside the big one + small_rect = QRectF(150, 100, 300, 200) # x, y, width, height + small_rect_path = QPainterPath() + small_rect_path.addRect(small_rect) + + # 3. Calculate the subtracted path (the space between them) + space_path = big_rect_path.subtracted(small_rect_path) + + # --- Drawing for demonstration --- + + # Draw the big rectangle (optional, for visualization) + painter.setPen(QColor(0, 0, 255, 100)) # Blue, semi-transparent + painter.setBrush(QColor(0, 0, 255, 50)) + + + painter.drawPath(big_rect_path) + # painter.drawText(big_rect.topRight().x() + 5, big_rect.topRight().y() + 15, "Big Rect") + + # Draw the small rectangle (optional, for visualization) + painter.setPen(QColor(255, 0, 0, 100)) # Red, semi-transparent + painter.setBrush(QColor(255, 0, 0, 50)) + painter.drawPath(small_rect_path) + # painter.drawText(small_rect.bottomRight().x() + 5, small_rect.bottomRight().y() + 15, "Small Rect") + + # Draw the resulting 'space_path' + painter.setPen(QColor(0, 150, 0)) # Green + painter.setBrush(QColor(0, 200, 0, 150)) # Green, semi-transparent + painter.drawPath(space_path) + painter.drawText(20, 20, "Space Path (Green)") + + +if __name__ == '__main__': + app = QApplication(sys.argv) + window = SubtractedRectanglesWindow() + window.show() + sys.exit(app.exec()) \ No newline at end of file From 5cb43aba4905e5e0eb6160296b5619bdf385bb50 Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Tue, 29 Jul 2025 11:20:59 +0100 Subject: [PATCH 06/20] del: Unused files --- BlocksScreen/configmanager.py | 27 - BlocksScreen/lib/moonAPI.py | 476 ----------------- BlocksScreen/lib/rest.py | 89 ---- BlocksScreen/lib/util.py | 0 BlocksScreen/manager.py | 121 ----- BlocksScreen/userauth.py | 4 - tests/button_try.py | 122 ----- tests/random.py | 955 ---------------------------------- tests/test.py | 56 -- 9 files changed, 1850 deletions(-) delete mode 100644 BlocksScreen/configmanager.py delete mode 100644 BlocksScreen/lib/moonAPI.py delete mode 100644 BlocksScreen/lib/rest.py delete mode 100644 BlocksScreen/lib/util.py delete mode 100644 BlocksScreen/manager.py delete mode 100644 BlocksScreen/userauth.py delete mode 100644 tests/button_try.py delete mode 100644 tests/random.py delete mode 100644 tests/test.py diff --git a/BlocksScreen/configmanager.py b/BlocksScreen/configmanager.py deleted file mode 100644 index 5336bf77..00000000 --- a/BlocksScreen/configmanager.py +++ /dev/null @@ -1,27 +0,0 @@ -import configparser -import os -import pathlib - -class ConfigManager(configparser.ConfigParser): - baseFilename = "bo_config.cfg" - dirpath_klipper_print_data = "\printer_data\config" - - def __init__(self, filename: str = baseFilename): - self.filename = filename - kpd_dirpath = os.getcwd() + self.dirpath_klipper_print_data - - super(ConfigManager, self).__init__() - - kpd - - ... - - - def read_config(self, dir, filename): - if os.access(os.path.join(dir, filename), os.X_OK): - with _file_handler as self.read(os.path.join(dir, filename)) - - - def __getitem__(self, key: str) -> configparser.SectionProxy: - return super().__getitem__(key) - diff --git a/BlocksScreen/lib/moonAPI.py b/BlocksScreen/lib/moonAPI.py deleted file mode 100644 index 47ceb5e3..00000000 --- a/BlocksScreen/lib/moonAPI.py +++ /dev/null @@ -1,476 +0,0 @@ -import typing -from PyQt6 import QtCore -from PyQt6.QtCore import pyqtSlot, pyqtsignal - - -class MoonAPI(QtCore.QObject): - """MoonAPI - Moonraker API implementation - - - Args: - QObject (_type_): _description_ - - Raises: - NotImplementedError: _description_ - NotImplementedError: _description_ - NotImplementedError: _description_ - NotImplementedError: _description_ - NotImplementedError: _description_ - NotImplementedError: _description_ - - Returns: - _type_: _description_ - """ - - # TODO: Callbacks for each method - # TODO: Finish the pyqt slots for needed requests on the API - - def __init__( - self, parent: typing.Optional["QObject"], ws: typing.MoonWebSocket - ): - super(MoonAPI, self).__init__(parent) - self._ws: MoonWebSocket = ws - - @pyqtSlot(name="query_klippy_status") - def query_server_info(self): - _logger.debug("Requested server.info") - return self._ws.send_request(method="server.info") - - def identify_connection( - self, client_name, version, type, url, access_token, api_key - ): - return self._ws.send_request( - method="server.connection.identify", - params={ - "client_name": client_name, - "version": version, - "type": type, - "url": url, - "access_token": access_token, - "api_key": api_key, - }, - ) - - def request_temperature_cached_data(self, include_monitors: bool = False): - return self._ws.send_request( - method="server.temperature_store", - params={"include_monitors": include_monitors}, - ) - - @pyqtSlot(name="query_printer_info") - def request_printer_info(self): - return self._ws.send_request(method="printer.info") - - @pyqtSlot(name="get_available_objects") - def get_available_objects(self): - return self._ws.send_request(method="printer.objects.list") - - @pyqtSlot(dict, name="query_object") - def object_query(self, objects: dict): - # TODO: Finish - # Check if the types are correct - return self._ws.send_request( - method="printer.objects.query", params={"objects": objects} - ) - - @pyqtSlot(dict, name="object_subscription") - def object_subscription(self, objects: dict): - return self._ws.send_request( - method="printer.objects.subscribe", params={"objects": objects} - ) - - def query_endstops(self): - return self._ws.send_request(method="printer.query_endstops.status") - - @pyqtSlot(str, name="run_gcode") - def run_gcode(self, gcode: str): - if isinstance(gcode, str) is False or gcode is None: - return False - return self._ws.send_request( - method="printer.gcode.script", params={"script": gcode} - ) - - def gcode_help(self): - return self._ws.send_request(method="printer.gcode.help") - - @pyqtSlot(str, name="start_print") - def start_print(self, filename): - return self._ws.send_request( - method="printer.print.start", params={"filename": filename} - ) - - @pyqtSlot(name="pause_print") - def pause_print(self): - return self._ws.send_request(method="printer.print.pause") - - @pyqtSlot(name="resume_print") - def resume_print(self): - return self._ws.send_request(method="printer.print.resume") - - @pyqtSlot(name="stop_print") - def cancel_print(self): - return self._ws.send_request(method="printer.print.cancel") - - def machine_system(self): - return self._ws.send_request(method="machine.shutdown") - - def machine_reboot(self): - return self._ws.send_request(method="machine.reboot") - - def restart_server(self): - return self._ws.send_request(method="server.restart") - - def restart_service(self, service): - if service is None or isinstance(service, str) is False: - return False - return self._ws.send_request( - method="machine.services.restart", params={"service": service} - ) - - @pyqtSlot(name="firmware_restart") - def firmware_restart(self): - """firmware_restart - - HTTP_REQUEST: POST /printer/firmware_restart - - JSON_RPC_REQUEST: printer.firmware_restart - Returns: - _type_: _description_ - """ - # REVIEW: Whether i should send a websocket request or a post with http - # return self._ws._moonRest.firmware_restart() # With HTTP - return self._ws.send_request( - method="printer.firmware_restart" - ) # With Websocket - - def stop_service(self, service): - if service is None or isinstance(service, str) is False: - return False - return self._ws.send_request( - method="machine.services.stop", params={"service": service} - ) - - def start_service(self, service): - if service is None or isinstance(service, str) is False: - return False - return self._ws.send_request( - method="machine.services.start", params={"service": service} - ) - - def get_sudo_info(self, permission: bool = False): - if isinstance(permission, bool) is False: - return False - return self._ws.send_request( - method="machine.sudo.info", params={"check_access": permission} - ) - - def get_usb_devices(self): - return self._ws.send_request(method="machine.peripherals.usb") - - def get_serial_devices(self): - return self._ws.send_request(method="machine.peripherals.serial") - - def get_video_devices(self): - return self._ws.send_request(method="machine.peripherals.video") - - def get_cabus_devices(self, interface: str = "can0"): - return self._ws.send_request( - method="machine.peripherals.canbus", - params={"interface": interface}, - ) - - @pyqtSlot(name="api_request_file_list") - def get_file_list(self, root_folder: str | None = None): - # If the root argument is omitted the request will default to the gcodes root. - if root_folder is None: - return self._ws.send_request(method="server.files.list", params={}) - return self._ws.send_request( - method="server.files.list", params={"root": root_folder} - ) - - def list_registered_roots(self): - return self._ws.send_request(method="server.files.roots") - - @pyqtSlot(str, name="api_request_file_list") - def get_gcode_metadata(self, filename_dir: str): - if isinstance(filename_dir, str) is False or filename_dir is None: - return False - return self._ws.send_request( - method="server.files.metadata", params={"filename": filename_dir} - ) - - def scan_gcode_metadata(self, filename_dir: str): - if isinstance(filename_dir, str) is False or filename_dir is None: - return False - return self._ws.send_request( - method="server.files.metascan", params={"filename": filename_dir} - ) - - @pyqtSlot(name="api_get_gcode_thumbnail") - def get_gcode_thumbnail(self, filename_dir: str): - if isinstance(filename_dir, str) is False or filename_dir is None: - return False - return self._ws.send_request( - method="server.files.thumbnails", params={"filename": filename_dir} - ) - - @pyqtSlot(str, str, name="file_download") - def download_file(self, root: str, filename: str): - """download_file Retrieves file *filename* at root *root*, the filename must include the relative path if - it is not in the root folder - - Args: - root (str): root directory where the file lies - filename (str): file to download - - Returns: - _type_: _description_ - """ - if not isinstance(filename, str) or not isinstance(root, str): - return False - - return self._ws._moonRest.get_request( - f"/server/files/{root}/{filename}" - ) - - # def upload_file(self, ) # TODO: Maybe this is not necessary but either way do it - - def get_dir_information(self, directory: str): - if isinstance(directory, str) is False or directory is None: - return False - return self._ws.send_request( - method="server.files.get_directory", - params={"path": f"gcodes/{directory}", "extended": True}, - ) - - def create_directory(self, directory: str): - if isinstance(directory, str) is False or directory is None: - return False - return self._ws.send_request( - method="server.files.post_directory", - params={ - "path": f"gcodes/{directory}", - }, - ) - - def delete_directory(self, directory: str): - if isinstance(directory, str) is False or directory is None: - return False - return self._ws.send_request( - method="server.files.delete_directory", - params={ - "path": f"gcodes/{directory}", - }, - ) - - def move_file(self, source_dir: str, dest_dir: str): - if ( - isinstance(source_dir, str) is False - or isinstance(dest_dir, str) is False - or source_dir is None - or dest_dir is False - ): - return False - return self._ws.send_request( - method="server.files.move", - params={"source": source_dir, "dest": dest_dir}, - ) - - def copy_file(self, source_dir: str, dest_dir: str): - if ( - isinstance(source_dir, str) is False - or isinstance(dest_dir, str) is False - or source_dir is None - or dest_dir is False - ): - return False - return self._ws.send_request( - method="server.files.copy", - params={"source": source_dir, "dest": dest_dir}, - ) - - def zip_archive(self, items: list): - raise NotImplementedError() - - # !Can implement a jog queueu - - def list_announcements(self, include_dismissed: bool = False): - return self._ws.send_request( - method="server.announcements.list", - params={"include_dismissed": include_dismissed}, - ) - - def update_announcements(self): - return self._ws.send_request(method="server.announcements.update") - - def dismiss_announcements(self, entry_id: str, wake_time: int = 600): - if ( - isinstance(entry_id, str) is False - or entry_id is None - or isinstance(wake_time, int) is False - ): - return False - return self._ws.send_request( - method="server.announcements.dismiss", - params={"entry_id": entry_id, "wake_time": wake_time}, - ) - - def list_announcements_feeds(self): - return self._ws.send_request(method="server.announcements.feeds") - - def post_announcement_feed(self, announcement_name: str): - if ( - isinstance(announcement_name, str) is False - or announcement_name is None - ): - return False - return self._ws.send_request( - method="server.announcements.post_feed", - params={"name": announcement_name}, - ) - - def delete_announcement_feed(self, announcement_name: str): - if ( - isinstance(announcement_name, str) is False - or announcement_name is None - ): - return False - return self._ws.send_request( - method="server.announcements.delete_feed", - params={"name": announcement_name}, - ) - - # * WEBCAM - - def list_webcams(self): - return self._ws.send_request(method="server.webcams.list") - - def get_webcam_info(self, uid: str): - if isinstance(uid, str) is False or uid is None: - return False - return self._ws.send_request( - method="server.webcams.get_info", params={"uid": uid} - ) - - # TODO: Can create a class that irs a URL type like i've done before to validate the links - # TODO: There are more options in this section, alot more options, later see if it's worth to implement or not - def add_update_webcam( - self, cam_name: str, snapshot_url: str, stream_url: str - ): - if ( - isinstance(cam_name, str) is False - or isinstance(snapshot_url, str) is False - or isinstance(stream_url, str) is False - or cam_name is None - or snapshot_url is None - or stream_url is None - ): - return False - return self._ws.send_request( - method="server.webcams.post_item", - params={ - "name": cam_name, - "snapshot_url": snapshot_url, - "stream_url": stream_url, - }, - ) - - def delete_webcam(self, uid: str): - if isinstance(uid, str) is False or uid is None: - return False - return self._ws.send_request( - method="server.webcams.delete_item", params={"uid": uid} - ) - - def test_webcam(self, uid: str): - if isinstance(uid, str) is False or uid is None: - return False - return self._ws.send_request( - method="server.webcams.test", params={"uid": uid} - ) - - def list_notifiers(self): - return self._ws.send_request(method="server.notifiers.list") - - # UPDATES - - def update_status(self, refresh: bool = False): - return self._ws.send_request( - method="machine.update.status", params={"refresh": refresh} - ) - - def refresh_update_status(self, name: str): - if isinstance(name, str) is False or name is None: - return False - return self._ws.send_request( - method="machine.update.refresh", params={"name": name} - ) - - def full_update(self): - return self._ws.send_request(method="machine.update.full") - - def update_moonraker(self): - return self._ws.send_request(method="machine.update.moonraker") - - def update_klipper(self): - return self._ws.send_request(method="machine.update.klipper") - - def update_client(self, client_name: str): - if isinstance(client_name, str) is False or client_name is None: - return False - return self._ws.send_request(method="machine.update.client") - - def update_system(self): - return self._ws.send_request(method="machine.update.system") - - def recover_corrupt_repo(self, name: str, hard: bool = False): - if isinstance(name, str) is False or name is None: - return False - return self._ws.send_request( - method="machine.update.recover", - params={"name": name, "hard": hard}, - ) - - def rollback_update(self, name: str): - if isinstance(name, str) is False or name is None: - return False - return self._ws.send_request( - method="machine,update.rollback", params={"name": name} - ) - - # If moonraker [history] is configured - def history_list(self, limit, start, since, before, order): - # TODO: - raise NotImplementedError - return self._ws.send_request( - method="server.history.list", - params={ - "limit": limit, - "start": start, - "since": since, - "before": before, - "order": order, - }, - ) - - def history_job_totals(self): - raise NotImplementedError - return self._ws.send_request(method="server.history.totals") - - def history_reset_totals(self): - raise NotImplementedError - return self._ws.send_request(method="server.history.reset_totals") - - def history_get_job(self, uid: str): - raise NotImplementedError - return self._ws.send_request( - method="server.history.get_job", params={"uid": uid} - ) - - def history_delete_job(self, uid: str): - raise NotImplementedError - # It is possible to replace the uid argument with all=true to delete all jobs in the history database. - return self._ws.send_request( - method="server.history.delete_job", params={"uid": uid} - ) diff --git a/BlocksScreen/lib/rest.py b/BlocksScreen/lib/rest.py deleted file mode 100644 index ac5ad97a..00000000 --- a/BlocksScreen/lib/rest.py +++ /dev/null @@ -1,89 +0,0 @@ -import tornado -from urllib3.util.url import Url -import pydantic -import fastapi - -import asyncio -import multiprocessing - -import concurrent.futures -import functools -import inspect -import time -import logging -import typing -import tornado.concurrent - -from fastapi import FastAPI, WebSocket - -from PyQt6 import QtCore -import tornado.websocket - - -class WebSocketClient(tornado.websocket.WebSocketClientConnection): - url = "ws://192.168.1.68:7125" - port = 7125 - - def __init__(self) -> None: - # super(WebSocketClient, self).__init__( ) - self.connect() - - tornado.ioloop.IOLoop.current().start() - - def connect(self): - tornado.websocket.websocket_connect( - self.url, - callback=self.on_connect, - ) - - def on_connect(self, future): - self.connection = future.results() - - def on_message(self, message): - print(message) - - def on_close(self): - print("websocket closed ") - - -# if __name__ == "__main__": -# client = WebSocketClient() - -# class WebSocketClientFastAPI(FastAPI): - -# def __init__(self, *args, **kwargs): -# super(WebSocketClientFastAPI, self).__init__() - - -# @FastAPI.websocket("/ws") -# async def websocket_endspoint(websocket:WebSocket): -# await websocket.accept() -# try: -# while True: -# data = await websocket.receive_text() -# # Process data and interact with Klipper -# response = {"status": "success", "data": data} -# await websocket.send_json(response) - -# except Exception as e: -# await websocket.close() - - -# if __name__ == "__main__": - -# eb = WebSocketClientFastAPI() - - -import asyncio -import uvicorn - -async def app(scope, receive, send): - ... - -async def main(): - config = uvicorn.Config("rest:app", port=5000, log_level="info") - server = uvicorn.Server(config) - await server.serve() - -if __name__ == "__main__": - asyncio.run(main()) \ No newline at end of file diff --git a/BlocksScreen/lib/util.py b/BlocksScreen/lib/util.py deleted file mode 100644 index e69de29b..00000000 diff --git a/BlocksScreen/manager.py b/BlocksScreen/manager.py deleted file mode 100644 index 609b723d..00000000 --- a/BlocksScreen/manager.py +++ /dev/null @@ -1,121 +0,0 @@ -from PyQt6.QtCore import QObject, QEvent, pyqtSignal, pyqtSlot -from enum import Enum, EnumType, IntEnum, Enum -from collections import deque -import typing - - - - -class Manager(QObject): - - class KlipperState(Enum): - KlipperKilled = 0 - KlipperError = 1 - KlipperStandby = 2 - KlipperIdle = 3 - KlipperPrinting = 4 - - def __init__(self, parent: typing.Optional[QObject], printer = None, ws = None ) -> None: - super(Manager, self).__init__(parent) - - - - - - - def add_connection(self): ... - - - - def rm_connection(self): ... - - - def register_qtobject(self, object: QObject): ... - - - - - - - - - -class PageViewManager(QObject): - - def __init__(self, parent: typing.Optional["QObject"]) -> None: - super(PageViewManager, self).__init__(parent) - - - self.index_stack = deque() - - def request_view(self, object: QObject, index: typing.Optional[int]= None) -> None: ... - - def clean_view(self) -> None: ... - - - - - - - - @pyqtSlot(name="request_back_button_pressed") - def global_back_button(self) -> None: - if not len(self.index_stack) : - _logger.debug("Index stack is empty") - - self.main_window.setCurrentIndex(self.index_stack[-1][0]) - self.set_current_panel_index( - self.index_stack[-1][1] - ) - - self.index_stack.pop() - - self.printer_object_report_signal.connect(self.printer.report_received) - self.printer_object_list_received_signal.connect( - self.printer.object_list_received - ) - - _logger.debug("Successfully went back a page") - - @pyqtSlot(int, int, name="request_change_page") - def global_change_page(self, tab_index: int, panel_index: int) -> None: - """global_change_page Changes panels pages globally - - Args: - tab_index (int): The tab index of the panel - panel_index (int): The index of the panel page - """ - if not isinstance(tab_index, int): - _logger.debug( - f"Tab index argument expected type int, got {type(tab_index)}" - ) - if not isinstance(panel_index, int): - _logger.debug(f"Panel page index expected type int, {type(panel_index)}") - current_page = [ - self.ui.mainTabWidget.currentIndex(), - self.current_panel_index(), - ] - requested_page = [tab_index, panel_index] - # * Return if user is already on the requested page - if requested_page == current_page: - _logger.debug("User is already on the requested page") - return - # * Add to the stack of indexes the indexes of current tab and page in tab to later be able to come back to them - self.index_stack.append(current_page) - # * Go to the requested tab and page - self.ui.mainTabWidget.setCurrentIndex(tab_index) - self.set_current_panel_index(panel_index) - _logger.debug( - f"Requested page change -> Tab index :{requested_page[0]}, pane panel index : {requested_page[1]}" - ) - - def event(self, a0: QEvent | None) -> bool: - return super().event(a0) - - def installEventFilter(self, a0: QObject | None) -> None: - return super().installEventFilter(a0) - - -class SearchWindow(): ... - - diff --git a/BlocksScreen/userauth.py b/BlocksScreen/userauth.py deleted file mode 100644 index 5efcf9d3..00000000 --- a/BlocksScreen/userauth.py +++ /dev/null @@ -1,4 +0,0 @@ -import logging - - -# TODO: Create User authentication for klipper diff --git a/tests/button_try.py b/tests/button_try.py deleted file mode 100644 index dd94dc04..00000000 --- a/tests/button_try.py +++ /dev/null @@ -1,122 +0,0 @@ -import sys - - -from PyQt6 import QtCore, QtWidgets, QtGui - - -class Button(QtWidgets.QPushButton): - def __init__(self, parent) -> None: - super().__init__(parent) - self._icon_center = None - - def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: - return super().resizeEvent(a0) - - def paintEvent(self, a0: QtGui.QPaintEvent) -> None: - opt = QtWidgets.QStyleOptionButton() - self.initStyleOption(opt) - # qp = QtGui.QPainter(self) - qp= QtWidgets.QStylePainter(self) - - qp.setPen(QtCore.Qt.PenStyle.NoPen) - qp.setRenderHint(qp.RenderHint.Antialiasing) - qp.setRenderHint(qp.RenderHint.SmoothPixmapTransform) - qp.setRenderHint(qp.RenderHint.LosslessImageRendering) - - bg_color = ( - QtGui.QColor(175, 175, 175) - if not self.isDown() - else QtGui.QColor(120, 120, 120) - ) - - path = QtGui.QPainterPath() - xRadius = self.rect().toRectF().normalized().height() / 2.0 - yRadius = self.rect().toRectF().normalized().height() / 2.0 - path.addRoundedRect( - 0, - 0, - self.rect().toRectF().normalized().width(), - self.rect().toRectF().normalized().height(), - xRadius, - yRadius, - QtCore.Qt.SizeMode.AbsoluteSize, - ) - # path.addEllipse( - # (self.rect().toRectF().normalized().height() * 0.1 / 2.0), - # (self.rect().toRectF().normalized().height() * 0.1 / 2.0), - # self.rect().toRectF().normalized().height() * 0.90, - # self.rect().toRectF().normalized().height() * 0.90, - # ) - icon_path = QtGui.QPainterPath() - icon_path.addEllipse( - self.rect().toRectF().normalized().left() - + self.rect().toRectF().normalized().height() * 0.05, - self.rect().toRectF().normalized().top() - + self.rect().toRectF().normalized().height() * 0.05, - (self.rect().toRectF().normalized().height() * 0.90), - (self.rect().toRectF().normalized().height() * 0.90), - ) - self._icon_center = icon_path.boundingRect().center() - icon_path.setFillRule(QtCore.Qt.FillRule.OddEvenFill) - cutout = path.subtracted(icon_path) - path.connectPath(icon_path) - qp.fillPath(cutout, bg_color) - # mask = QtGui.QRegion(cutout.toFillPolygon().toPolygon()) - - # self.setMask(mask) - - -class MainWindow(QtWidgets.QMainWindow): - def __init__(self) -> None: - super().__init__() - - self.setMinimumSize(1000, 800) - # self.setMaximumSize(500, 800) - self.setAutoFillBackground(True) - - p = self.palette() - p.setColor(self.backgroundRole(), QtCore.Qt.GlobalColor.blue) - - self.setPalette(p) - - self.button = Button(self) - self.button.show() - - self.button.setGeometry(QtCore.QRect(50, 100, 600, 240)) - - -if __name__ == "__main__": - app = QtWidgets.QApplication([]) - main_window = MainWindow() - - app.processEvents() - main_window.showNormal() - - sys.exit(app.exec()) - - -# path.addRoundedRect( -# 0, -# 0, -# self.rect().toRectF().width(), -# self.rect().toRectF().height(), -# self.rect().toRectF().height() * 1.1 -# - self.rect().toRectF().height() / 2, -# self.rect().toRectF().height() * 1.1 -# - self.rect().toRectF().height() / 2, -# QtCore.Qt.SizeMode.AbsoluteSize, -# ) -# path.setFillRule(QtCore.Qt.FillRule.OddEvenFill) -# path.addEllipse( -# ( -# self.rect().toRectF().height() * 0.1 -# - self.rect().toRectF().height() * 0.1 / 2.0 -# ), -# ( -# self.rect().toRectF().height() * 0.1 -# - self.rect().toRectF().height() * 0.1 / 2.0 -# ), -# self.rect().toRectF().height() * 0.90, -# self.rect().toRectF().height() * 0.90, -# ) -# mask = QtGui.QRegion(path.toFillPolygon().toPolygon()) diff --git a/tests/random.py b/tests/random.py deleted file mode 100644 index d33b9684..00000000 --- a/tests/random.py +++ /dev/null @@ -1,955 +0,0 @@ -from re import search -import unittest - -config = { - "config": { - "force_move": {"enable_force_move": "True"}, - "respond": {"default_type": "echo"}, - "gcode_macro G31": { - "gcode": "\nRUN_SHELL_COMMAND CMD=clear_plr\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False" - }, - "gcode_shell_command clear_plr": { - "command": "sh /home/mks/clear_plr.sh", - "timeout": "5.", - }, - "gcode_macro save_last_file": { - "gcode": "\n\n{% set svv = printer.save_variables.variables %}\n\n{% set filepath=printer.virtual_sdcard.file_path %}\n\n{% set filename=filepath.split('/')%}\n\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename[-1] }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ printer.virtual_sdcard.file_path }\"'" - }, - "gcode_macro clear_last_file": { - "gcode": "\n{% set filename='' %}\n{% set filepath='' %}\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ filepath }\"'" - }, - "gcode_shell_command POWER_LOSS_RESUME": { - "command": "/home/mks/plr.sh", - "timeout": "420.", - }, - "gcode_macro RESUME_INTERRUPTED": { - "gcode": '\nSET_KINEMATIC_POSITION X=0\nSET_KINEMATIC_POSITION Y=0\nSET_KINEMATIC_POSITION Z=0\n{% set z_height = params.Z_HEIGHT|default(printer.save_variables.variables.power_resume_z)|float %}\n{% set last_file = params.GCODE_FILE|default(printer.save_variables.variables.last_file)|string %}\nm118 {last_file}\n\nRUN_SHELL_COMMAND CMD=POWER_LOSS_RESUME PARAMS="{z_height} \\"{last_file}\\""\nSDCARD_PRINT_FILE FILENAME=plr/"{last_file}"' - }, - "gcode_macro LOG_Z": { - "gcode": '\n{% set z_pos = printer.gcode_move.gcode_position.z %}\nRESPOND MSG="Current Z is {z_pos}"\nSAVE_VARIABLE VARIABLE=power_resume_z VALUE={z_pos}' - }, - "save_variables": { - "filename": "/home/mks/printer_data/config/saved_variables.cfg" - }, - "gcode_macro CANCEL_PRINT": { - "description": "Cancel the actual running print", - "rename_existing": "CANCEL_PRINT_BASE", - "gcode": '\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file\nG31\nTURN_OFF_HEATERS\nCANCEL_PRINT_BASE\nRESPOND TYPE=echo MSG="Cancel Print Success!"\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290 F6000\nM84 X Y E', - }, - "gcode_macro PRINT_START": { - "gcode": "\n{% set temp = params.EXTRUDER | default(220) | int %}\n{% set b_temp = params.BED | default(60) | int %}\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=True\n\nM84 E\nSET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={b_temp}\nTEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={b_temp - 5} MAXIMUM={b_temp + 5}\nG28\nBED_MESH_CALIBRATE ADAPTIVE=1\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={temp}\n\n\nTEMPERATURE_WAIT SENSOR=extruder MINIMUM={temp - 5} MAXIMUM={temp + 5}\n\n\nM400\n\n\nG90\nG92 E0\nG1 E-1\nG92 E0\nM400\n\nG92 E0\nG1 Z1.0 F3000\nG1 X0.1 Y20 Z0.3 F5000.0\nG1 X0.1 Y100.0 Z0.3 F500.0 E15\nG1 X0.4 Y100.0 Z0.3 F5000.0\nG1 X0.4 Y20 Z0.3 F500.0 E30\nG92 E0\nG1 Z1.0 F3000\nM400" - }, - "gcode_macro PAUSE": { - "description": "Pause the actual running print", - "rename_existing": "PAUSE_BASE", - "gcode": '\nRESPOND TYPE=echo MSG="Pause Print!"\n\n{% set x = params.X|default(10) %}\n{% set y = params.Y|default(290) %}\n{% set z = params.Z|default(10)|float %}\n{% set e = params.E|default(1) %}\n\n{% set max_z = printer.toolhead.axis_maximum.z|float %}\n{% set act_z = printer.toolhead.position.z|float %}\n{% set lift_z = z|abs %}\n{% if act_z < (max_z - lift_z) %}\n{% set z_safe = lift_z %}\n{% else %}\n{% set z_safe = max_z - act_z %}\n{% endif %}\n\nPAUSE_BASE\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E-{e} F500\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\n{% if "xyz" in printer.toolhead.homed_axes %}\nG1 Z{z_safe}\nG90\nG1 X{x} Y{y} F6000\n{% else %}\n{action_respond_info("Printer not homed")}\n{% endif %}', - }, - "gcode_macro RESUME": { - "description": "Resume the actual running print", - "rename_existing": "RESUME_BASE", - "gcode": '\nRESPOND TYPE=echo MSG="RESUME Print!"\n\n{% if printer["filament_switch_sensor my_sensor"].filament_detected == True %}\nRESPOND TYPE=echo MSG="RESUME Print!"\n{% set e = params.E|default(1) %}\n\n{% if \'VELOCITY\' in params|upper %}\n{% set get_params = (\'VELOCITY=\' + params.VELOCITY) %}\n{%else %}\n{% set get_params = "" %}\n{% endif %}\n\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E{e} F400\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\nRESUME_BASE {get_params}\n{% else %}\nRESPOND TYPE=echo MSG="Please Insert filament in Sensor!"\n{% endif %}', - }, - "gcode_macro END_PRINT": { - "gcode": '\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 X5 Y5 F3000\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290\n\nM84 X Y E\nRESPOND TYPE=echo MSG="Finish Print!"' - }, - "gcode_macro LOAD_FILAMENT": { - "gcode": "\nSAVE_GCODE_POSITION NAME=LOAD_STATE\nG91\nG1 E30 F300\nG1 E10 F150\nG90\nRESTORE_GCODE_POSITION NAME=LOAD_STATE" - }, - "gcode_macro UNLOAD_FILAMENT": { - "gcode": "\nSAVE_GCODE_POSITION NAME=UNLOAD_STATE\nG91\nG1 E-30 F300\nG90\nRESTORE_GCODE_POSITION NAME=UNLOAD_STATE MOVE=0" - }, - "gcode_macro LED_ON": {"gcode": "\nSET_PIN PIN=my_led VALUE=1"}, - "gcode_macro LED_OFF": {"gcode": "\nSET_PIN PIN=my_led VALUE=0"}, - "gcode_macro M205": {"gcode": "\nM105"}, - "gcode_macro PRINT_END": { - "gcode": "\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file" - }, - "exclude_object": {}, - "mcu": { - "serial": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0", - "restart_method": "command", - }, - "printer": { - "kinematics": "cartesian", - "max_velocity": "300", - "max_accel": "10000", - "max_accel_to_decel": "5000", - "max_z_velocity": "15", - "max_z_accel": "100", - "square_corner_velocity": "6", - }, - "virtual_sdcard": {"path": "/home/mks/printer_data/gcodes"}, - "pause_resume": {}, - "display_status": {}, - "gcode_arcs": {"resolution": "0.8"}, - "idle_timeout": { - "gcode": '\nRESPOND TYPE=echo MSG="No operations in 10min!"', - "timeout": "600", - }, - "mcu rpi": {"serial": "/tmp/klipper_host_mcu"}, - "adxl345": {"cs_pin": "rpi:None", "spi_bus": "spidev0.0"}, - "verify_heater extruder": { - "max_error": "60", - "check_gain_time": "20", - "hysteresis": "5", - "heating_gain": "2", - }, - "verify_heater heater_bed": { - "max_error": "180", - "check_gain_time": "120", - "hysteresis": "5", - "heating_gain": "2", - }, - "resonance_tester": { - "accel_chip": "adxl345", - "probe_points": "\n150, 150, 20", - "accel_per_hz": "100", - "min_freq": "1", - "max_freq": "100", - "max_smoothing": "0.2", - "hz_per_sec": "0.5", - }, - "stepper_x": { - "step_pin": "PD15", - "dir_pin": "PD14", - "enable_pin": "!PC7", - "microsteps": "16", - "rotation_distance": "40", - "endstop_pin": "tmc2209_stepper_x: virtual_endstop", - "homing_retract_dist": "0", - "position_endstop": "-12", - "position_min": "-12", - "position_max": "302", - "homing_speed": "50", - "step_pulse_duration": "0.000002", - }, - "tmc2209 stepper_x": { - "uart_pin": "PE3", - "run_current": "1.2", - "uart_address": "3", - "interpolate": "True", - "driver_sgthrs": "95", - "stealthchop_threshold": "0", - "diag_pin": "^PD10", - }, - "stepper_y": { - "step_pin": "PB7", - "dir_pin": "PB6", - "enable_pin": "!PB9", - "microsteps": "16", - "rotation_distance": "40", - "endstop_pin": "tmc2209_stepper_y: virtual_endstop", - "homing_retract_dist": "0", - "position_endstop": "-6", - "position_min": "-6", - "position_max": "302", - "homing_speed": "50", - "step_pulse_duration": "0.000002", - }, - "tmc2209 stepper_y": { - "uart_pin": "PE4", - "run_current": "1.2", - "uart_address": "3", - "interpolate": "True", - "driver_sgthrs": "95", - "stealthchop_threshold": "0", - "diag_pin": "^PE0", - }, - "stepper_z": { - "step_pin": "PB3", - "dir_pin": "!PD7", - "enable_pin": "!PB5", - "microsteps": "16", - "rotation_distance": "8", - "endstop_pin": "probe:z_virtual_endstop", - "position_max": "355", - "position_min": "-4", - "homing_speed": "10", - }, - "stepper_z1": { - "step_pin": "PA7", - "dir_pin": "!PA6", - "enable_pin": "!PC5", - "microsteps": "16", - "rotation_distance": "8", - "endstop_pin": "probe:z_virtual_endstop", - }, - "extruder": { - "max_extrude_only_distance": "100.0", - "step_pin": "PD1", - "dir_pin": "!PD0", - "enable_pin": "!PD4", - "microsteps": "16", - "rotation_distance": "4.59", - "nozzle_diameter": "0.400", - "filament_diameter": "1.750", - "heater_pin": "PA1", - "sensor_type": "EPCOS 100K B57560G104F", - "sensor_pin": "PA4", - "control": "pid", - "pressure_advance": "0.02", - "pressure_advance_smooth_time": "0.035", - "max_extrude_cross_section": "500", - "instantaneous_corner_velocity": "10", - "max_extrude_only_velocity": "2000", - "max_extrude_only_accel": "10000", - "pid_kp": "24.522", - "pid_ki": "1.397", - "pid_kd": "107.590", - "min_temp": "0", - "max_temp": "305", - "min_extrude_temp": "150", - }, - "tmc2209 extruder": { - "uart_pin": "PE7", - "run_current": "0.6", - "uart_address": "3", - "interpolate": "True", - }, - "heater_bed": { - "heater_pin": "PA2", - "sensor_type": "EPCOS 100K B57560G104F", - "sensor_pin": "PA3", - "control": "pid", - "pid_kp": "54.027", - "pid_ki": "0.770", - "pid_kd": "948.182", - "min_temp": "0", - "max_temp": "105", - }, - "probe": { - "pin": "PD13", - "x_offset": "27", - "y_offset": "-20", - "z_offset": "2.465", - }, - "bltouch": {"#guov": 2039}, - "probe_eddy_current": {"falsk": 329}, - "filament_switch_sensor my_sensor": {"switch_pin": "PD11"}, - "safe_z_home": { - "home_xy_position": "123,170", - "speed": "80", - "z_hop": "10", - "z_hop_speed": "15", - "move_to_previous": "True", - }, - "z_tilt": { - "z_positions": "-8, 170\n260, 170", - "points": "-8, 170\n260, 170", - "speed": "200", - "horizontal_move_z": "5", - "retries": "20", - "retry_tolerance": ".005", - }, - "bed_mesh": { - "speed": "200", - "horizontal_move_z": "5", - "mesh_min": "17,15", - "mesh_max": "285,282", - "probe_count": "5,5", - "algorithm": "bicubic", - "bicubic_tension": "0.3", - "fade_start": "0.2", - "fade_end": "5.0", - "mesh_pps": "4,4", - "move_check_distance": "3", - "adaptive_margin": "5", - }, - "screws_tilt_adjust": { - "screw1": "4, 58", - "screw1_name": "front left screw", - "screw2": "243, 58", - "screw2_name": "front right screw", - "screw3": "243, 290", - "screw3_name": "rear right screw", - "screw4": "4, 290", - "screw4_name": "rear left screw", - "horizontal_move_z": "5.", - "speed": "200.", - "screw_thread": "CW-M4", - }, - "heater_fan hotend_fan": {"pin": "PE11"}, - "multi_pin fan_pins": {"pins": "PE9,PE13"}, - "fan": {"pin": "multi_pin:fan_pins"}, - "output_pin my_led": { - "pin": "PC4", - "pwm": "1", - "value": "1", - "cycle_time": "0.010", - }, - "controller_fan Fan_Board": { - "pin": "PD3", - "fan_speed": "1.0", - "idle_timeout": "120", - "heater": "heater_bed, extruder", - "stepper": "stepper_x, stepper_y, stepper_z, stepper_z1", - }, - "input_shaper": { - "damping_ratio_x": "0.05", - "damping_ratio_y": "0.1", - "shaper_type_x": "zv", - "shaper_freq_x": "48.8", - "shaper_type_y": "mzv", - "shaper_freq_y": "49.0", - }, - "bed_mesh default": { - "version": "1", - "points": "\n-0.190000, -0.125000, 0.010000, 0.095000, 0.122500\n-0.145000, -0.095000, 0.067500, 0.125000, 0.130000\n-0.040000, -0.130000, 0.055000, 0.132500, 0.115000\n0.195000, -0.150000, 0.055000, 0.320000, 0.160000\n-0.240000, -0.110000, 0.067500, 0.197500, 0.222500", - "x_count": "5", - "y_count": "5", - "mesh_x_pps": "4", - "mesh_y_pps": "4", - "algo": "bicubic", - "tension": "0.3", - "min_x": "17.0", - "max_x": "285.0", - "min_y": "15.0", - "max_y": "282.0", - }, - }, - "warnings": [ - { - "type": "deprecated_option", - "message": "Option 'max_accel_to_decel' in section 'printer' is deprecated.", - "section": "printer", - "option": "max_accel_to_decel", - } - ], - "save_config_pending": False, - "save_config_pending_items": {}, - "settings": { - "mcu": { - "serial": "/dev/serial/by-id/usb-1a86_USB_Serial-if00-port0", - "baud": 250000, - "restart_method": "command", - "max_stepper_error": 2.5e-05, - }, - "mcu rpi": { - "serial": "/tmp/klipper_host_mcu", - "max_stepper_error": 2.5e-05, - }, - "force_move": {"enable_force_move": True}, - "respond": {"default_type": "echo", "default_prefix": "echo:"}, - "gcode_macro g31": { - "gcode": "\nRUN_SHELL_COMMAND CMD=clear_plr\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False", - "description": "G-Code macro", - }, - "gcode_shell_command clear_plr": { - "command": "sh /home/mks/clear_plr.sh", - "timeout": 5.0, - "verbose": True, - }, - "gcode_macro save_last_file": { - "gcode": "\n\n{% set svv = printer.save_variables.variables %}\n\n{% set filepath=printer.virtual_sdcard.file_path %}\n\n{% set filename=filepath.split('/')%}\n\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename[-1] }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ printer.virtual_sdcard.file_path }\"'", - "description": "G-Code macro", - }, - "gcode_macro clear_last_file": { - "gcode": "\n{% set filename='' %}\n{% set filepath='' %}\nSAVE_VARIABLE VARIABLE=last_file VALUE='\"{ filename }\"'\nSAVE_VARIABLE VARIABLE=filepath VALUE='\"{ filepath }\"'", - "description": "G-Code macro", - }, - "gcode_shell_command power_loss_resume": { - "command": "/home/mks/plr.sh", - "timeout": 420.0, - "verbose": True, - }, - "gcode_macro resume_interrupted": { - "gcode": '\nSET_KINEMATIC_POSITION X=0\nSET_KINEMATIC_POSITION Y=0\nSET_KINEMATIC_POSITION Z=0\n{% set z_height = params.Z_HEIGHT|default(printer.save_variables.variables.power_resume_z)|float %}\n{% set last_file = params.GCODE_FILE|default(printer.save_variables.variables.last_file)|string %}\nm118 {last_file}\n\nRUN_SHELL_COMMAND CMD=POWER_LOSS_RESUME PARAMS="{z_height} \\"{last_file}\\""\nSDCARD_PRINT_FILE FILENAME=plr/"{last_file}"', - "description": "G-Code macro", - }, - "gcode_macro log_z": { - "gcode": '\n{% set z_pos = printer.gcode_move.gcode_position.z %}\nRESPOND MSG="Current Z is {z_pos}"\nSAVE_VARIABLE VARIABLE=power_resume_z VALUE={z_pos}', - "description": "G-Code macro", - }, - "save_variables": { - "filename": "/home/mks/printer_data/config/saved_variables.cfg" - }, - "gcode_macro cancel_print": { - "gcode": '\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file\nG31\nTURN_OFF_HEATERS\nCANCEL_PRINT_BASE\nRESPOND TYPE=echo MSG="Cancel Print Success!"\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290 F6000\nM84 X Y E', - "rename_existing": "CANCEL_PRINT_BASE", - "description": "Cancel the actual running print", - }, - "gcode_macro print_start": { - "gcode": "\n{% set temp = params.EXTRUDER | default(220) | int %}\n{% set b_temp = params.BED | default(60) | int %}\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=True\n\nM84 E\nSET_HEATER_TEMPERATURE HEATER=heater_bed TARGET={b_temp}\nTEMPERATURE_WAIT SENSOR=heater_bed MINIMUM={b_temp - 5} MAXIMUM={b_temp + 5}\nG28\nBED_MESH_CALIBRATE ADAPTIVE=1\nSET_HEATER_TEMPERATURE HEATER=extruder TARGET={temp}\n\n\nTEMPERATURE_WAIT SENSOR=extruder MINIMUM={temp - 5} MAXIMUM={temp + 5}\n\n\nM400\n\n\nG90\nG92 E0\nG1 E-1\nG92 E0\nM400\n\nG92 E0\nG1 Z1.0 F3000\nG1 X0.1 Y20 Z0.3 F5000.0\nG1 X0.1 Y100.0 Z0.3 F500.0 E15\nG1 X0.4 Y100.0 Z0.3 F5000.0\nG1 X0.4 Y20 Z0.3 F500.0 E30\nG92 E0\nG1 Z1.0 F3000\nM400", - "description": "G-Code macro", - }, - "gcode_macro pause": { - "gcode": '\nRESPOND TYPE=echo MSG="Pause Print!"\n\n{% set x = params.X|default(10) %}\n{% set y = params.Y|default(290) %}\n{% set z = params.Z|default(10)|float %}\n{% set e = params.E|default(1) %}\n\n{% set max_z = printer.toolhead.axis_maximum.z|float %}\n{% set act_z = printer.toolhead.position.z|float %}\n{% set lift_z = z|abs %}\n{% if act_z < (max_z - lift_z) %}\n{% set z_safe = lift_z %}\n{% else %}\n{% set z_safe = max_z - act_z %}\n{% endif %}\n\nPAUSE_BASE\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E-{e} F500\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\n{% if "xyz" in printer.toolhead.homed_axes %}\nG1 Z{z_safe}\nG90\nG1 X{x} Y{y} F6000\n{% else %}\n{action_respond_info("Printer not homed")}\n{% endif %}', - "rename_existing": "PAUSE_BASE", - "description": "Pause the actual running print", - }, - "gcode_macro resume": { - "gcode": '\nRESPOND TYPE=echo MSG="RESUME Print!"\n\n{% if printer["filament_switch_sensor my_sensor"].filament_detected == True %}\nRESPOND TYPE=echo MSG="RESUME Print!"\n{% set e = params.E|default(1) %}\n\n{% if \'VELOCITY\' in params|upper %}\n{% set get_params = (\'VELOCITY=\' + params.VELOCITY) %}\n{%else %}\n{% set get_params = "" %}\n{% endif %}\n\nG91\n{% if printer.extruder.can_extrude|lower == \'True\' %}\nG1 E{e} F400\n{% else %}\n{action_respond_info("Extruder not hot enough")}\n{% endif %}\nRESUME_BASE {get_params}\n{% else %}\nRESPOND TYPE=echo MSG="Please Insert filament in Sensor!"\n{% endif %}', - "rename_existing": "RESUME_BASE", - "description": "Resume the actual running print", - }, - "gcode_macro end_print": { - "gcode": '\nG91\nG1 E-2 F500\nG1 E-2 Z0.2 F200\nG1 X5 Y5 F3000\nG1 Z1\nM106 S0\nM104 S0\nM140 S0\nG90\nG1 X10 Y290\n\nM84 X Y E\nRESPOND TYPE=echo MSG="Finish Print!"', - "description": "G-Code macro", - }, - "gcode_macro load_filament": { - "gcode": "\nSAVE_GCODE_POSITION NAME=LOAD_STATE\nG91\nG1 E30 F300\nG1 E10 F150\nG90\nRESTORE_GCODE_POSITION NAME=LOAD_STATE", - "description": "G-Code macro", - }, - "gcode_macro unload_filament": { - "gcode": "\nSAVE_GCODE_POSITION NAME=UNLOAD_STATE\nG91\nG1 E-30 F300\nG90\nRESTORE_GCODE_POSITION NAME=UNLOAD_STATE MOVE=0", - "description": "G-Code macro", - }, - "gcode_macro led_on": { - "gcode": "\nSET_PIN PIN=my_led VALUE=1", - "description": "G-Code macro", - }, - "gcode_macro led_off": { - "gcode": "\nSET_PIN PIN=my_led VALUE=0", - "description": "G-Code macro", - }, - "gcode_macro m205": {"gcode": "\nM105", "description": "G-Code macro"}, - "gcode_macro print_end": { - "gcode": "\nSAVE_VARIABLE VARIABLE=was_interrupted VALUE=False\nRUN_SHELL_COMMAND CMD=clear_plr\nclear_last_file", - "description": "G-Code macro", - }, - "virtual_sdcard": { - "path": "/home/mks/printer_data/gcodes", - "on_error_gcode": "\n{% if 'heaters' in printer %}\n TURN_OFF_HEATERS\n{% endif %}\n", - }, - "pause_resume": {"recover_velocity": 50.0}, - "gcode_arcs": {"resolution": 0.8}, - "idle_timeout": { - "timeout": 600.0, - "gcode": '\nRESPOND TYPE=echo MSG="No operations in 10min!"', - }, - "adxl345": { - "axes_map": ["x", "y", "z"], - "rate": 3200, - "cs_pin": "rpi:None", - "spi_speed": 5000000, - "spi_bus": "spidev0.0", - }, - "verify_heater extruder": { - "hysteresis": 5.0, - "max_error": 60.0, - "heating_gain": 2.0, - "check_gain_time": 20.0, - }, - "verify_heater heater_bed": { - "hysteresis": 5.0, - "max_error": 180.0, - "heating_gain": 2.0, - "check_gain_time": 120.0, - }, - "resonance_tester": { - "move_speed": 50.0, - "min_freq": 1.0, - "max_freq": 100.0, - "accel_per_hz": 100.0, - "hz_per_sec": 0.5, - "sweeping_accel": 400.0, - "sweeping_period": 1.2, - "accel_chip": "adxl345", - "max_smoothing": 0.2, - "probe_points": [[150.0, 150.0, 20.0]], - }, - "tmc2209 stepper_x": { - "uart_pin": "PE3", - "uart_address": 3, - "diag_pin": "^PD10", - "run_current": 1.2, - "hold_current": 2.0, - "sense_resistor": 0.11, - "interpolate": True, - "stealthchop_threshold": 0.0, - "driver_multistep_filt": True, - "driver_toff": 3, - "driver_hstrt": 5, - "driver_hend": 0, - "driver_tbl": 2, - "driver_semin": 0, - "driver_seup": 0, - "driver_semax": 0, - "driver_sedn": 0, - "driver_seimin": 0, - "driver_iholddelay": 8, - "driver_pwm_ofs": 36, - "driver_pwm_grad": 14, - "driver_pwm_freq": 1, - "driver_pwm_autoscale": True, - "driver_pwm_autograd": True, - "driver_pwm_reg": 8, - "driver_pwm_lim": 12, - "driver_tpowerdown": 20, - "driver_sgthrs": 95, - }, - "stepper_x": { - "microsteps": 16, - "step_pin": "PD15", - "dir_pin": "PD14", - "rotation_distance": 40.0, - "full_steps_per_rotation": 200, - "gear_ratio": [], - "step_pulse_duration": 2e-06, - "enable_pin": "!PC7", - "endstop_pin": "tmc2209_stepper_x: virtual_endstop", - "position_endstop": -12.0, - "position_min": -12.0, - "position_max": 302.0, - "homing_speed": 50.0, - "second_homing_speed": 25.0, - "homing_retract_speed": 50.0, - "homing_retract_dist": 0.0, - "homing_positive_dir": False, - }, - "tmc2209 stepper_y": { - "uart_pin": "PE4", - "uart_address": 3, - "diag_pin": "^PE0", - "run_current": 1.2, - "hold_current": 2.0, - "sense_resistor": 0.11, - "interpolate": True, - "stealthchop_threshold": 0.0, - "driver_multistep_filt": True, - "driver_toff": 3, - "driver_hstrt": 5, - "driver_hend": 0, - "driver_tbl": 2, - "driver_semin": 0, - "driver_seup": 0, - "driver_semax": 0, - "driver_sedn": 0, - "driver_seimin": 0, - "driver_iholddelay": 8, - "driver_pwm_ofs": 36, - "driver_pwm_grad": 14, - "driver_pwm_freq": 1, - "driver_pwm_autoscale": True, - "driver_pwm_autograd": True, - "driver_pwm_reg": 8, - "driver_pwm_lim": 12, - "driver_tpowerdown": 20, - "driver_sgthrs": 95, - }, - "stepper_y": { - "microsteps": 16, - "step_pin": "PB7", - "dir_pin": "PB6", - "rotation_distance": 40.0, - "full_steps_per_rotation": 200, - "gear_ratio": [], - "step_pulse_duration": 2e-06, - "enable_pin": "!PB9", - "endstop_pin": "tmc2209_stepper_y: virtual_endstop", - "position_endstop": -6.0, - "position_min": -6.0, - "position_max": 302.0, - "homing_speed": 50.0, - "second_homing_speed": 25.0, - "homing_retract_speed": 50.0, - "homing_retract_dist": 0.0, - "homing_positive_dir": False, - }, - "tmc2209 extruder": { - "uart_pin": "PE7", - "uart_address": 3, - "run_current": 0.6, - "hold_current": 2.0, - "sense_resistor": 0.11, - "interpolate": True, - "driver_multistep_filt": True, - "driver_toff": 3, - "driver_hstrt": 5, - "driver_hend": 0, - "driver_tbl": 2, - "driver_semin": 0, - "driver_seup": 0, - "driver_semax": 0, - "driver_sedn": 0, - "driver_seimin": 0, - "driver_iholddelay": 8, - "driver_pwm_ofs": 36, - "driver_pwm_grad": 14, - "driver_pwm_freq": 1, - "driver_pwm_autoscale": True, - "driver_pwm_autograd": True, - "driver_pwm_reg": 8, - "driver_pwm_lim": 12, - "driver_tpowerdown": 20, - "driver_sgthrs": 0, - }, - "extruder": { - "microsteps": 16, - "sensor_type": "EPCOS 100K B57560G104F", - "pullup_resistor": 4700.0, - "inline_resistor": 0.0, - "sensor_pin": "PA4", - "min_temp": 0.0, - "max_temp": 305.0, - "min_extrude_temp": 150.0, - "max_power": 1.0, - "smooth_time": 1.0, - "control": "pid", - "pid_kp": 24.522, - "pid_ki": 1.397, - "pid_kd": 107.59, - "heater_pin": "PA1", - "pwm_cycle_time": 0.1, - "nozzle_diameter": 0.4, - "filament_diameter": 1.75, - "max_extrude_cross_section": 500.0, - "max_extrude_only_velocity": 2000.0, - "max_extrude_only_accel": 10000.0, - "max_extrude_only_distance": 100.0, - "instantaneous_corner_velocity": 10.0, - "step_pin": "PD1", - "pressure_advance": 0.02, - "pressure_advance_smooth_time": 0.035, - "dir_pin": "!PD0", - "rotation_distance": 4.59, - "full_steps_per_rotation": 200, - "gear_ratio": [], - "enable_pin": "!PD4", - }, - "heater_bed": { - "sensor_type": "EPCOS 100K B57560G104F", - "pullup_resistor": 4700.0, - "inline_resistor": 0.0, - "sensor_pin": "PA3", - "min_temp": 0.0, - "max_temp": 105.0, - "min_extrude_temp": 170.0, - "max_power": 1.0, - "smooth_time": 1.0, - "control": "pid", - "pid_kp": 54.027, - "pid_ki": 0.77, - "pid_kd": 948.182, - "heater_pin": "PA2", - "pwm_cycle_time": 0.1, - }, - "probe": { - "z_offset": 2.465, - "deactivate_on_each_sample": True, - "activate_gcode": "", - "deactivate_gcode": "", - "pin": "PD13", - "x_offset": 27.0, - "y_offset": -20.0, - "speed": 5.0, - "lift_speed": 5.0, - "samples": 1, - "sample_retract_dist": 2.0, - "samples_result": "average", - "samples_tolerance": 0.1, - "samples_tolerance_retries": 0, - }, - "filament_switch_sensor my_sensor": { - "switch_pin": "PD11", - "pause_on_runout": True, - "runout_gcode": "", - "pause_delay": 0.5, - "event_delay": 3.0, - }, - "safe_z_home": { - "home_xy_position": [123.0, 170.0], - "z_hop": 10.0, - "z_hop_speed": 15.0, - "speed": 80.0, - "move_to_previous": True, - }, - "z_tilt": { - "z_positions": [[-8.0, 170.0], [260.0, 170.0]], - "retries": 20, - "retry_tolerance": 0.005, - "points": [[-8.0, 170.0], [260.0, 170.0]], - "horizontal_move_z": 5.0, - "speed": 200.0, - }, - "bed_mesh": { - "adaptive_margin": 5.0, - "probe_count": [5, 5], - "mesh_min": [17.0, 15.0], - "mesh_max": [285.0, 282.0], - "mesh_pps": [4, 4], - "algorithm": "bicubic", - "bicubic_tension": 0.3, - "scan_overshoot": 0, - "horizontal_move_z": 5.0, - "speed": 200.0, - "fade_start": 0.2, - "fade_end": 5.0, - "split_delta_z": 0.025, - "move_check_distance": 3.0, - }, - "bed_mesh default": { - "version": 1, - "points": [ - [-0.19, -0.125, 0.01, 0.095, 0.1225], - [-0.145, -0.095, 0.0675, 0.125, 0.13], - [-0.04, -0.13, 0.055, 0.1325, 0.115], - [0.195, -0.15, 0.055, 0.32, 0.16], - [-0.24, -0.11, 0.0675, 0.1975, 0.2225], - ], - "min_x": 17.0, - "max_x": 285.0, - "min_y": 15.0, - "max_y": 282.0, - "x_count": 5, - "y_count": 5, - "mesh_x_pps": 4, - "mesh_y_pps": 4, - "algo": "bicubic", - "tension": 0.3, - }, - "screws_tilt_adjust": { - "screw1": [4.0, 58.0], - "screw1_name": "front left screw", - "screw2": [243.0, 58.0], - "screw2_name": "front right screw", - "screw3": [243.0, 290.0], - "screw3_name": "rear right screw", - "screw4": [4.0, 290.0], - "screw4_name": "rear left screw", - "screw_thread": "CW-M4", - "horizontal_move_z": 5.0, - "speed": 200.0, - }, - "heater_fan hotend_fan": { - "heater": ["extruder"], - "heater_temp": 50.0, - "max_power": 1.0, - "kick_start_time": 0.1, - "off_below": 0.0, - "cycle_time": 0.01, - "hardware_pwm": False, - "shutdown_speed": 1.0, - "pin": "PE11", - "fan_speed": 1.0, - }, - "multi_pin fan_pins": {"pins": ["PE9", "PE13"]}, - "fan": { - "max_power": 1.0, - "kick_start_time": 0.1, - "off_below": 0.0, - "cycle_time": 0.01, - "hardware_pwm": False, - "shutdown_speed": 0.0, - "pin": "multi_pin:fan_pins", - }, - "output_pin my_led": { - "pwm": True, - "pin": "PC4", - "cycle_time": 0.01, - "hardware_pwm": False, - "scale": 1.0, - "value": 1.0, - "shutdown_value": 0.0, - }, - "controller_fan fan_board": { - "stepper": ["stepper_x", "stepper_y", "stepper_z", "stepper_z1"], - "max_power": 1.0, - "kick_start_time": 0.1, - "off_below": 0.0, - "cycle_time": 0.01, - "hardware_pwm": False, - "shutdown_speed": 0.0, - "pin": "PD3", - "fan_speed": 1.0, - "idle_speed": 1.0, - "idle_timeout": 120, - "heater": ["heater_bed", "extruder"], - }, - "input_shaper": { - "shaper_type": "mzv", - "shaper_type_x": "zv", - "damping_ratio_x": 0.05, - "shaper_freq_x": 48.8, - "shaper_type_y": "mzv", - "damping_ratio_y": 0.1, - "shaper_freq_y": 49.0, - }, - "printer": { - "max_velocity": 300.0, - "max_accel": 10000.0, - "max_accel_to_decel": 5000.0, - "minimum_cruise_ratio": 0.5, - "square_corner_velocity": 6.0, - "kinematics": "cartesian", - "max_z_velocity": 15.0, - "max_z_accel": 100.0, - }, - "stepper_z": { - "step_pin": "PB3", - "dir_pin": "!PD7", - "rotation_distance": 8.0, - "microsteps": 16, - "full_steps_per_rotation": 200, - "gear_ratio": [], - "enable_pin": "!PB5", - "endstop_pin": "probe:z_virtual_endstop", - "position_min": -4.0, - "position_max": 355.0, - "homing_speed": 10.0, - "second_homing_speed": 5.0, - "homing_retract_speed": 10.0, - "homing_retract_dist": 5.0, - "homing_positive_dir": False, - }, - "stepper_z1": { - "step_pin": "PA7", - "dir_pin": "!PA6", - "rotation_distance": 8.0, - "microsteps": 16, - "full_steps_per_rotation": 200, - "gear_ratio": [], - "enable_pin": "!PC5", - "endstop_pin": "probe:z_virtual_endstop", - }, - }, -} - - -def search_config_sections(section: str) -> list: - """Retrieve a section or sections from the printers configfile - - Args: - section (str): Name of the section - name (str, optional): Name of the section object. Defaults to "". - - Returns: - dict | None: The entire section with the section as key or None if - nothing is found - """ - - if not config or not section: - return [] - - # if "config" not in config.keys(): - if not config.get("config"): - return [] - _printer_config = config.get("config") - - return [ - {key: _printer_config} - for key in config["config"].keys() - if key.startswith(section) # O(s) time per key - ] - # Iterates over every key and checks if it starts - # with the prefix -> Complexity O(n*s) - # Simple but becomes costly for large n values - # since the dictionary is not exactly big, it should be ok - - -def get_probe(config): - _probe_type = ["probe", "bltouch", "probe_eddy_current", "smart_effector"] - _add = [] - for probe in _probe_type: - hit = search_config_sections(probe) - if hit: - _add.extend(hit) - return _add - - -def search_from_list(search_list: list, _objects: list = []): - if len(search_list) == 0: - return _objects - _objects.extend(search_config_sections(search_list.pop())) - print(_objects) - return search_from_list(search_list, _objects) - - -class test_get_configs(unittest.TestCase): - # def test_search_all_no_recursion(self): - # _probe_type = ["probe", "bltouch", "probe_eddy_current", "smart_effector"] - # self.assertEqual( - # get_probe(config), - # [ - # { - # "probe": { - # "pin": "PD13", - # "x_offset": "27", - # "y_offset": "-20", - # "z_offset": "2.465", - # } - # }, - # { - # "probe2": { - # "pin": "PD13", - # "x_offset": "27", - # "y_offset": "-20", - # "z_offset": "2.465", - # } - # }, - # {"bltouch": {"#guov": 2039}}, - # ], - # ) - - def test_diff_search_one(self): - _probe_type = _probe_type = ["probe"] - self.assertEqual( - search_from_list(_probe_type), - [ - { - "probe": { - "pin": "PD13", - "x_offset": "27", - "y_offset": "-20", - "z_offset": "2.465", - } - }, - { - "probe2": { - "pin": "PD13", - "x_offset": "27", - "y_offset": "-20", - "z_offset": "2.465", - }, - }, - ], - ) - - def test_diff_search_two(self): - _probe_type = ["probe", "bltouch" , "probe_eddy_current", "smart_effector"] - search_from_list( - _probe_type, - [ - { - "probe": { - "pin": "PD13", - "x_offset": "27", - "y_offset": "-20", - "z_offset": "2.465", - } - }, - - {"bltouch": {"#guov": 2039}}, - ], - ) - - def test_search_more_than_two(self): - _list = ["stepper_x", "stepper_y", "probe", "probe_eddy_current", "smart_effector"] - # def test_diff_search_two(self): - # _probe_type = ["probe", "bltouch"] - # self.assertEqual( - # search_from_list(_probe_type), - # [ - # { - # "probe": { - # "pin": "PD13", - # "x_offset": "27", - # "y_offset": "-20", - # "z_offset": "2.465", - # } - # }, - # { - # "probe2": { - # "pin": "PD13", - # "x_offset": "27", - # "y_offset": "-20", - # "z_offset": "2.465", - # } - # }, - # {"bltouch": {"#guov": 2039}}, - # ], - # ) - - -if __name__ == "__main__": - unittest.main() diff --git a/tests/test.py b/tests/test.py deleted file mode 100644 index 7a137cfb..00000000 --- a/tests/test.py +++ /dev/null @@ -1,56 +0,0 @@ -import sys -from PyQt6.QtCore import QRectF, Qt -from PyQt6.QtGui import QPainter, QPainterPath, QColor -from PyQt6.QtWidgets import QApplication, QWidget - -class SubtractedRectanglesWindow(QWidget): - def __init__(self): - super().__init__() - self.setWindowTitle("PyQt6 QPainterPath Subtraction") - self.setGeometry(100, 100, 600, 400) # x, y, width, height - - def paintEvent(self, event): - painter = QPainter(self) - painter.setRenderHint(QPainter.RenderHint.Antialiasing) - - # 1. Define the big rectangle - big_rect = QRectF(50, 50, 500, 300) # x, y, width, height - big_rect_path = QPainterPath() - big_rect_path.addRect(big_rect) - - # 2. Define the small rectangle inside the big one - small_rect = QRectF(150, 100, 300, 200) # x, y, width, height - small_rect_path = QPainterPath() - small_rect_path.addRect(small_rect) - - # 3. Calculate the subtracted path (the space between them) - space_path = big_rect_path.subtracted(small_rect_path) - - # --- Drawing for demonstration --- - - # Draw the big rectangle (optional, for visualization) - painter.setPen(QColor(0, 0, 255, 100)) # Blue, semi-transparent - painter.setBrush(QColor(0, 0, 255, 50)) - - - painter.drawPath(big_rect_path) - # painter.drawText(big_rect.topRight().x() + 5, big_rect.topRight().y() + 15, "Big Rect") - - # Draw the small rectangle (optional, for visualization) - painter.setPen(QColor(255, 0, 0, 100)) # Red, semi-transparent - painter.setBrush(QColor(255, 0, 0, 50)) - painter.drawPath(small_rect_path) - # painter.drawText(small_rect.bottomRight().x() + 5, small_rect.bottomRight().y() + 15, "Small Rect") - - # Draw the resulting 'space_path' - painter.setPen(QColor(0, 150, 0)) # Green - painter.setBrush(QColor(0, 200, 0, 150)) # Green, semi-transparent - painter.drawPath(space_path) - painter.drawText(20, 20, "Space Path (Green)") - - -if __name__ == '__main__': - app = QApplication(sys.argv) - window = SubtractedRectanglesWindow() - window.show() - sys.exit(app.exec()) \ No newline at end of file From cb02b1677294c2d31a30517fdedbf9733542ffcf Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Tue, 29 Jul 2025 11:23:34 +0100 Subject: [PATCH 07/20] Fix: wrong signal name for runnign gcode on babystep --- BlocksScreen/lib/panels/printTab.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/BlocksScreen/lib/panels/printTab.py b/BlocksScreen/lib/panels/printTab.py index cb32c89c..9d91b03d 100644 --- a/BlocksScreen/lib/panels/printTab.py +++ b/BlocksScreen/lib/panels/printTab.py @@ -126,9 +126,9 @@ def __init__( self.file_data.fileinfo.connect(self.jobStatusPage_widget.on_fileinfo) self.jobStatusPage_widget.print_start.connect(self.ws.api.start_print) - + # self.jobStatusPage_widget.print_start.connect() - + self.jobStatusPage_widget.print_cancel.connect( self.ws.api.cancel_print ) @@ -231,7 +231,7 @@ def __init__( self.panel.main_print_btn.clicked.connect( partial(self.change_page, self.indexOf(self.filesPage_widget)) ) - self.babystepPage.run_gcode_signal.connect(self.ws.api.run_gcode) + self.babystepPage.run_gcode.connect(self.ws.api.run_gcode) self.run_gcode_signal.connect(self.ws.api.run_gcode) From bc24b7304f11c63654836226e005f73c092e8f11 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Sun, 24 Aug 2025 17:19:50 +0100 Subject: [PATCH 08/20] Work babystep page (#10) * Add: group button widget * Add: added babystepPage functionality to handle Z offset changes and design updates * FIX: fixed an problem where the variable _z_offset was getting the value of the text * ADD: added an label with the first z value before changing it * Fixed bug due to incorrect run gcode signal name * Refactor: babystep page, run gcode signal nameing --------- Co-authored-by: Roberto Martins --- BlocksScreen/lib/moonAPI.py | 476 ++++++++++++++++++ BlocksScreen/lib/moonrakerComm.py | 2 +- BlocksScreen/lib/moonrest.py | 2 +- .../lib/panels/widgets/babystepPage.py | 35 +- BlocksScreen/lib/ui/printStackedWidget_ui.py | 293 +++++------ 5 files changed, 658 insertions(+), 150 deletions(-) create mode 100644 BlocksScreen/lib/moonAPI.py diff --git a/BlocksScreen/lib/moonAPI.py b/BlocksScreen/lib/moonAPI.py new file mode 100644 index 00000000..47ceb5e3 --- /dev/null +++ b/BlocksScreen/lib/moonAPI.py @@ -0,0 +1,476 @@ +import typing +from PyQt6 import QtCore +from PyQt6.QtCore import pyqtSlot, pyqtsignal + + +class MoonAPI(QtCore.QObject): + """MoonAPI + Moonraker API implementation + + + Args: + QObject (_type_): _description_ + + Raises: + NotImplementedError: _description_ + NotImplementedError: _description_ + NotImplementedError: _description_ + NotImplementedError: _description_ + NotImplementedError: _description_ + NotImplementedError: _description_ + + Returns: + _type_: _description_ + """ + + # TODO: Callbacks for each method + # TODO: Finish the pyqt slots for needed requests on the API + + def __init__( + self, parent: typing.Optional["QObject"], ws: typing.MoonWebSocket + ): + super(MoonAPI, self).__init__(parent) + self._ws: MoonWebSocket = ws + + @pyqtSlot(name="query_klippy_status") + def query_server_info(self): + _logger.debug("Requested server.info") + return self._ws.send_request(method="server.info") + + def identify_connection( + self, client_name, version, type, url, access_token, api_key + ): + return self._ws.send_request( + method="server.connection.identify", + params={ + "client_name": client_name, + "version": version, + "type": type, + "url": url, + "access_token": access_token, + "api_key": api_key, + }, + ) + + def request_temperature_cached_data(self, include_monitors: bool = False): + return self._ws.send_request( + method="server.temperature_store", + params={"include_monitors": include_monitors}, + ) + + @pyqtSlot(name="query_printer_info") + def request_printer_info(self): + return self._ws.send_request(method="printer.info") + + @pyqtSlot(name="get_available_objects") + def get_available_objects(self): + return self._ws.send_request(method="printer.objects.list") + + @pyqtSlot(dict, name="query_object") + def object_query(self, objects: dict): + # TODO: Finish + # Check if the types are correct + return self._ws.send_request( + method="printer.objects.query", params={"objects": objects} + ) + + @pyqtSlot(dict, name="object_subscription") + def object_subscription(self, objects: dict): + return self._ws.send_request( + method="printer.objects.subscribe", params={"objects": objects} + ) + + def query_endstops(self): + return self._ws.send_request(method="printer.query_endstops.status") + + @pyqtSlot(str, name="run_gcode") + def run_gcode(self, gcode: str): + if isinstance(gcode, str) is False or gcode is None: + return False + return self._ws.send_request( + method="printer.gcode.script", params={"script": gcode} + ) + + def gcode_help(self): + return self._ws.send_request(method="printer.gcode.help") + + @pyqtSlot(str, name="start_print") + def start_print(self, filename): + return self._ws.send_request( + method="printer.print.start", params={"filename": filename} + ) + + @pyqtSlot(name="pause_print") + def pause_print(self): + return self._ws.send_request(method="printer.print.pause") + + @pyqtSlot(name="resume_print") + def resume_print(self): + return self._ws.send_request(method="printer.print.resume") + + @pyqtSlot(name="stop_print") + def cancel_print(self): + return self._ws.send_request(method="printer.print.cancel") + + def machine_system(self): + return self._ws.send_request(method="machine.shutdown") + + def machine_reboot(self): + return self._ws.send_request(method="machine.reboot") + + def restart_server(self): + return self._ws.send_request(method="server.restart") + + def restart_service(self, service): + if service is None or isinstance(service, str) is False: + return False + return self._ws.send_request( + method="machine.services.restart", params={"service": service} + ) + + @pyqtSlot(name="firmware_restart") + def firmware_restart(self): + """firmware_restart + + HTTP_REQUEST: POST /printer/firmware_restart + + JSON_RPC_REQUEST: printer.firmware_restart + Returns: + _type_: _description_ + """ + # REVIEW: Whether i should send a websocket request or a post with http + # return self._ws._moonRest.firmware_restart() # With HTTP + return self._ws.send_request( + method="printer.firmware_restart" + ) # With Websocket + + def stop_service(self, service): + if service is None or isinstance(service, str) is False: + return False + return self._ws.send_request( + method="machine.services.stop", params={"service": service} + ) + + def start_service(self, service): + if service is None or isinstance(service, str) is False: + return False + return self._ws.send_request( + method="machine.services.start", params={"service": service} + ) + + def get_sudo_info(self, permission: bool = False): + if isinstance(permission, bool) is False: + return False + return self._ws.send_request( + method="machine.sudo.info", params={"check_access": permission} + ) + + def get_usb_devices(self): + return self._ws.send_request(method="machine.peripherals.usb") + + def get_serial_devices(self): + return self._ws.send_request(method="machine.peripherals.serial") + + def get_video_devices(self): + return self._ws.send_request(method="machine.peripherals.video") + + def get_cabus_devices(self, interface: str = "can0"): + return self._ws.send_request( + method="machine.peripherals.canbus", + params={"interface": interface}, + ) + + @pyqtSlot(name="api_request_file_list") + def get_file_list(self, root_folder: str | None = None): + # If the root argument is omitted the request will default to the gcodes root. + if root_folder is None: + return self._ws.send_request(method="server.files.list", params={}) + return self._ws.send_request( + method="server.files.list", params={"root": root_folder} + ) + + def list_registered_roots(self): + return self._ws.send_request(method="server.files.roots") + + @pyqtSlot(str, name="api_request_file_list") + def get_gcode_metadata(self, filename_dir: str): + if isinstance(filename_dir, str) is False or filename_dir is None: + return False + return self._ws.send_request( + method="server.files.metadata", params={"filename": filename_dir} + ) + + def scan_gcode_metadata(self, filename_dir: str): + if isinstance(filename_dir, str) is False or filename_dir is None: + return False + return self._ws.send_request( + method="server.files.metascan", params={"filename": filename_dir} + ) + + @pyqtSlot(name="api_get_gcode_thumbnail") + def get_gcode_thumbnail(self, filename_dir: str): + if isinstance(filename_dir, str) is False or filename_dir is None: + return False + return self._ws.send_request( + method="server.files.thumbnails", params={"filename": filename_dir} + ) + + @pyqtSlot(str, str, name="file_download") + def download_file(self, root: str, filename: str): + """download_file Retrieves file *filename* at root *root*, the filename must include the relative path if + it is not in the root folder + + Args: + root (str): root directory where the file lies + filename (str): file to download + + Returns: + _type_: _description_ + """ + if not isinstance(filename, str) or not isinstance(root, str): + return False + + return self._ws._moonRest.get_request( + f"/server/files/{root}/{filename}" + ) + + # def upload_file(self, ) # TODO: Maybe this is not necessary but either way do it + + def get_dir_information(self, directory: str): + if isinstance(directory, str) is False or directory is None: + return False + return self._ws.send_request( + method="server.files.get_directory", + params={"path": f"gcodes/{directory}", "extended": True}, + ) + + def create_directory(self, directory: str): + if isinstance(directory, str) is False or directory is None: + return False + return self._ws.send_request( + method="server.files.post_directory", + params={ + "path": f"gcodes/{directory}", + }, + ) + + def delete_directory(self, directory: str): + if isinstance(directory, str) is False or directory is None: + return False + return self._ws.send_request( + method="server.files.delete_directory", + params={ + "path": f"gcodes/{directory}", + }, + ) + + def move_file(self, source_dir: str, dest_dir: str): + if ( + isinstance(source_dir, str) is False + or isinstance(dest_dir, str) is False + or source_dir is None + or dest_dir is False + ): + return False + return self._ws.send_request( + method="server.files.move", + params={"source": source_dir, "dest": dest_dir}, + ) + + def copy_file(self, source_dir: str, dest_dir: str): + if ( + isinstance(source_dir, str) is False + or isinstance(dest_dir, str) is False + or source_dir is None + or dest_dir is False + ): + return False + return self._ws.send_request( + method="server.files.copy", + params={"source": source_dir, "dest": dest_dir}, + ) + + def zip_archive(self, items: list): + raise NotImplementedError() + + # !Can implement a jog queueu + + def list_announcements(self, include_dismissed: bool = False): + return self._ws.send_request( + method="server.announcements.list", + params={"include_dismissed": include_dismissed}, + ) + + def update_announcements(self): + return self._ws.send_request(method="server.announcements.update") + + def dismiss_announcements(self, entry_id: str, wake_time: int = 600): + if ( + isinstance(entry_id, str) is False + or entry_id is None + or isinstance(wake_time, int) is False + ): + return False + return self._ws.send_request( + method="server.announcements.dismiss", + params={"entry_id": entry_id, "wake_time": wake_time}, + ) + + def list_announcements_feeds(self): + return self._ws.send_request(method="server.announcements.feeds") + + def post_announcement_feed(self, announcement_name: str): + if ( + isinstance(announcement_name, str) is False + or announcement_name is None + ): + return False + return self._ws.send_request( + method="server.announcements.post_feed", + params={"name": announcement_name}, + ) + + def delete_announcement_feed(self, announcement_name: str): + if ( + isinstance(announcement_name, str) is False + or announcement_name is None + ): + return False + return self._ws.send_request( + method="server.announcements.delete_feed", + params={"name": announcement_name}, + ) + + # * WEBCAM + + def list_webcams(self): + return self._ws.send_request(method="server.webcams.list") + + def get_webcam_info(self, uid: str): + if isinstance(uid, str) is False or uid is None: + return False + return self._ws.send_request( + method="server.webcams.get_info", params={"uid": uid} + ) + + # TODO: Can create a class that irs a URL type like i've done before to validate the links + # TODO: There are more options in this section, alot more options, later see if it's worth to implement or not + def add_update_webcam( + self, cam_name: str, snapshot_url: str, stream_url: str + ): + if ( + isinstance(cam_name, str) is False + or isinstance(snapshot_url, str) is False + or isinstance(stream_url, str) is False + or cam_name is None + or snapshot_url is None + or stream_url is None + ): + return False + return self._ws.send_request( + method="server.webcams.post_item", + params={ + "name": cam_name, + "snapshot_url": snapshot_url, + "stream_url": stream_url, + }, + ) + + def delete_webcam(self, uid: str): + if isinstance(uid, str) is False or uid is None: + return False + return self._ws.send_request( + method="server.webcams.delete_item", params={"uid": uid} + ) + + def test_webcam(self, uid: str): + if isinstance(uid, str) is False or uid is None: + return False + return self._ws.send_request( + method="server.webcams.test", params={"uid": uid} + ) + + def list_notifiers(self): + return self._ws.send_request(method="server.notifiers.list") + + # UPDATES + + def update_status(self, refresh: bool = False): + return self._ws.send_request( + method="machine.update.status", params={"refresh": refresh} + ) + + def refresh_update_status(self, name: str): + if isinstance(name, str) is False or name is None: + return False + return self._ws.send_request( + method="machine.update.refresh", params={"name": name} + ) + + def full_update(self): + return self._ws.send_request(method="machine.update.full") + + def update_moonraker(self): + return self._ws.send_request(method="machine.update.moonraker") + + def update_klipper(self): + return self._ws.send_request(method="machine.update.klipper") + + def update_client(self, client_name: str): + if isinstance(client_name, str) is False or client_name is None: + return False + return self._ws.send_request(method="machine.update.client") + + def update_system(self): + return self._ws.send_request(method="machine.update.system") + + def recover_corrupt_repo(self, name: str, hard: bool = False): + if isinstance(name, str) is False or name is None: + return False + return self._ws.send_request( + method="machine.update.recover", + params={"name": name, "hard": hard}, + ) + + def rollback_update(self, name: str): + if isinstance(name, str) is False or name is None: + return False + return self._ws.send_request( + method="machine,update.rollback", params={"name": name} + ) + + # If moonraker [history] is configured + def history_list(self, limit, start, since, before, order): + # TODO: + raise NotImplementedError + return self._ws.send_request( + method="server.history.list", + params={ + "limit": limit, + "start": start, + "since": since, + "before": before, + "order": order, + }, + ) + + def history_job_totals(self): + raise NotImplementedError + return self._ws.send_request(method="server.history.totals") + + def history_reset_totals(self): + raise NotImplementedError + return self._ws.send_request(method="server.history.reset_totals") + + def history_get_job(self, uid: str): + raise NotImplementedError + return self._ws.send_request( + method="server.history.get_job", params={"uid": uid} + ) + + def history_delete_job(self, uid: str): + raise NotImplementedError + # It is possible to replace the uid argument with all=true to delete all jobs in the history database. + return self._ws.send_request( + method="server.history.delete_job", params={"uid": uid} + ) diff --git a/BlocksScreen/lib/moonrakerComm.py b/BlocksScreen/lib/moonrakerComm.py index 8772d31c..33f45f18 100644 --- a/BlocksScreen/lib/moonrakerComm.py +++ b/BlocksScreen/lib/moonrakerComm.py @@ -167,7 +167,7 @@ def connect(self) -> bool: f"Unexpected error occurred when trying to acquire oneshot token: {e}" ) return False - # _url = f"ws://192.168.1.68:7125/websocket?token={_oneshot_token}" + _url = f"ws://localhost:7125/websocket?token={_oneshot_token}" self.ws = websocket.WebSocketApp( _url, diff --git a/BlocksScreen/lib/moonrest.py b/BlocksScreen/lib/moonrest.py index eabc10ba..a141ece4 100644 --- a/BlocksScreen/lib/moonrest.py +++ b/BlocksScreen/lib/moonrest.py @@ -28,7 +28,7 @@ class MoonRest: timeout = 3 # TODO: The ip and port need to come from a configfile - # def __init__(self, ip="192.168.1.68", port="7125", api_key=False): + def __init__(self, ip="localhost", port="7125", api_key=False): self._ip = ip self._port = port diff --git a/BlocksScreen/lib/panels/widgets/babystepPage.py b/BlocksScreen/lib/panels/widgets/babystepPage.py index 32733b71..699d5dfc 100644 --- a/BlocksScreen/lib/panels/widgets/babystepPage.py +++ b/BlocksScreen/lib/panels/widgets/babystepPage.py @@ -32,8 +32,6 @@ def __init__(self, parent) -> None: self.bbp_nozzle_offset_025.toggled.connect(self.handle_z_offset_change) self.bbp_nozzle_offset_05.toggled.connect(self.handle_z_offset_change) self.bbp_nozzle_offset_1.toggled.connect(self.handle_z_offset_change) - self.bbp_nozzle_offset_1.toggled.connect(self.handle_z_offset_change) - self.babystep_back_btn.clicked.connect(self.request_back) @QtCore.pyqtSlot(name="on_move_nozzle_close") def on_move_nozzle_close(self) -> None: @@ -64,17 +62,23 @@ def handle_z_offset_change(self) -> None: _possible_z_values: typing.List = [0.01, 0.025, 0.05, 0.1] _sender: QtCore.QObject | None = self.sender() if self._z_offset == float(_sender.text()[:-3]): + print(_sender.text()[:-3], "is already set") return self._z_offset = float(_sender.text()[:-3]) + print(_sender.text()[:-3], "is now set") def on_gcode_move_update(self, name: str, value: list) -> None: if not value: return if name == "homing_origin": - self._z_offset = value[2] + self._z_offset_text = value[2] self.bbp_z_offset_current_value.setText( - f"Z: {self._z_offset:.3f}mm" + f"Z: {self._z_offset_text:.3f}mm" + ) + if self.bbp_z_offset_title_label.text() == "smth": + self.bbp_z_offset_title_label.setText( + f"Z: {self._z_offset_text:.3f}mm" ) def setupUI(self): @@ -334,6 +338,29 @@ def setupUI(self): QtCore.Qt.AlignmentFlag.AlignCenter ) self.bbp_babystep_graphic.setObjectName("bbp_babystep_graphic") + + # === NEW LABEL ADDED HERE === + # This is the title label that appears above the red value box. + self.bbp_z_offset_title_label = QtWidgets.QLabel(parent=self) + # Position it just above the red box. Red box is at y=70, so y=40 is appropriate. + self.bbp_z_offset_title_label.setGeometry( + QtCore.QRect(100, 40, 200, 30) + ) + font = QtGui.QFont() + font.setPointSize(12) + + self.bbp_z_offset_title_label.setFont(font) + # Set color to white to be visible on the dark background + self.bbp_z_offset_title_label.setStyleSheet( + "color: gray; background: transparent;" + ) + self.bbp_z_offset_title_label.setText("Z-Offset") + self.bbp_z_offset_title_label.setObjectName("bbp_z_offset_title_label") + self.bbp_z_offset_title_label.setText("smth") + self.bbp_z_offset_title_label.setGeometry(420, 270, 200, 30) + + # === END OF NEW LABEL === + self.bbp_z_offset_current_value = BlocksLabel(parent=self.frame_2) self.bbp_z_offset_current_value.setGeometry( QtCore.QRect(100, 70, 200, 60) diff --git a/BlocksScreen/lib/ui/printStackedWidget_ui.py b/BlocksScreen/lib/ui/printStackedWidget_ui.py index 8b9f8c17..8fe619ed 100644 --- a/BlocksScreen/lib/ui/printStackedWidget_ui.py +++ b/BlocksScreen/lib/ui/printStackedWidget_ui.py @@ -1,6 +1,6 @@ -# Form implementation generated from reading ui file '/home/bugo/github/Blocks_Screen/BlocksScreen/lib/ui/printStackedWidget.ui' +# Form implementation generated from reading ui file 'printStackedWidget.ui' # -# Created by: PyQt6 UI code generator 6.4.2 +# Created by: PyQt6 UI code generator 6.9.1 # # WARNING: Any manual changes made to this file will be lost when pyuic6 is # run again. Do not edit this file unless you know what you are doing. @@ -772,85 +772,12 @@ def setupUi(self, printStackedWidget): self.verticalLayout.addLayout(self.bbp_header_layout) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setObjectName("horizontalLayout_2") - self.frame_2 = QtWidgets.QFrame(parent=self.babystep_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) - self.frame_2.setSizePolicy(sizePolicy) - self.frame_2.setMinimumSize(QtCore.QSize(350, 160)) - self.frame_2.setMaximumSize(QtCore.QSize(350, 160)) - self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.frame_2.setObjectName("frame_2") - self.bbp_babystep_graphic = QtWidgets.QLabel(parent=self.frame_2) - self.bbp_babystep_graphic.setGeometry(QtCore.QRect(0, 30, 371, 121)) - self.bbp_babystep_graphic.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) - self.bbp_babystep_graphic.setText("") - self.bbp_babystep_graphic.setPixmap(QtGui.QPixmap(":/graphics/media/graphics/babystep_graphic.png")) - self.bbp_babystep_graphic.setScaledContents(False) - self.bbp_babystep_graphic.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.bbp_babystep_graphic.setObjectName("bbp_babystep_graphic") - self.bbp_z_offset_current_value = BlocksLabel(parent=self.frame_2) - self.bbp_z_offset_current_value.setGeometry(QtCore.QRect(130, 70, 200, 60)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.bbp_z_offset_current_value.sizePolicy().hasHeightForWidth()) - self.bbp_z_offset_current_value.setSizePolicy(sizePolicy) - self.bbp_z_offset_current_value.setMinimumSize(QtCore.QSize(150, 60)) - self.bbp_z_offset_current_value.setMaximumSize(QtCore.QSize(200, 60)) - font = QtGui.QFont() - font.setPointSize(13) - self.bbp_z_offset_current_value.setFont(font) - self.bbp_z_offset_current_value.setStyleSheet("background: transparent; color: white;") - self.bbp_z_offset_current_value.setText("") - self.bbp_z_offset_current_value.setPixmap(QtGui.QPixmap(":/graphics/media/btn_icons/z_offset_adjust.svg")) - self.bbp_z_offset_current_value.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.bbp_z_offset_current_value.setObjectName("bbp_z_offset_current_value") - self.horizontalLayout_2.addWidget(self.frame_2, 0, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) - self.bbp_buttons_layout = QtWidgets.QVBoxLayout() - self.bbp_buttons_layout.setContentsMargins(5, 5, 5, 5) - self.bbp_buttons_layout.setObjectName("bbp_buttons_layout") - self.bbp_away_from_bed = BlocksCustomButton(parent=self.babystep_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.bbp_away_from_bed.sizePolicy().hasHeightForWidth()) - self.bbp_away_from_bed.setSizePolicy(sizePolicy) - self.bbp_away_from_bed.setMinimumSize(QtCore.QSize(80, 80)) - self.bbp_away_from_bed.setMaximumSize(QtCore.QSize(80, 80)) - self.bbp_away_from_bed.setFlat(True) - self.bbp_away_from_bed.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg")) - self.bbp_away_from_bed.setObjectName("bbp_away_from_bed") - self.bbp_option_button_group = QtWidgets.QButtonGroup(printStackedWidget) - self.bbp_option_button_group.setObjectName("bbp_option_button_group") - self.bbp_option_button_group.addButton(self.bbp_away_from_bed) - self.bbp_buttons_layout.addWidget(self.bbp_away_from_bed, 0, QtCore.Qt.AlignmentFlag.AlignRight) - self.bbp_close_to_bed = BlocksCustomButton(parent=self.babystep_page) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.bbp_close_to_bed.sizePolicy().hasHeightForWidth()) - self.bbp_close_to_bed.setSizePolicy(sizePolicy) - self.bbp_close_to_bed.setMinimumSize(QtCore.QSize(80, 80)) - self.bbp_close_to_bed.setMaximumSize(QtCore.QSize(80, 80)) - self.bbp_close_to_bed.setFlat(True) - self.bbp_close_to_bed.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg")) - self.bbp_close_to_bed.setObjectName("bbp_close_to_bed") - self.bbp_option_button_group.addButton(self.bbp_close_to_bed) - self.bbp_buttons_layout.addWidget(self.bbp_close_to_bed, 0, QtCore.Qt.AlignmentFlag.AlignRight) - self.bbp_buttons_layout.setStretch(0, 1) - self.bbp_buttons_layout.setStretch(1, 1) - self.horizontalLayout_2.addLayout(self.bbp_buttons_layout) - self.horizontalLayout_2.setStretch(0, 1) - self.verticalLayout.addLayout(self.horizontalLayout_2) - self.bbp_offset_steps_buttons = QtWidgets.QHBoxLayout() - self.bbp_offset_steps_buttons.setContentsMargins(9, 9, 9, 9) - self.bbp_offset_steps_buttons.setObjectName("bbp_offset_steps_buttons") - self.bbp_nozzle_offset_01 = QtWidgets.QPushButton(parent=self.babystep_page) - self.bbp_nozzle_offset_01.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_01.setMaximumSize(QtCore.QSize(100, 80)) + self.verticalLayout_6 = QtWidgets.QVBoxLayout() + self.verticalLayout_6.setContentsMargins(9, 9, 9, 9) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.bbp_nozzle_offset_1 = QtWidgets.QPushButton(parent=self.babystep_page) + self.bbp_nozzle_offset_1.setMinimumSize(QtCore.QSize(60, 60)) + self.bbp_nozzle_offset_1.setMaximumSize(QtCore.QSize(100, 80)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -870,26 +797,27 @@ def setupUi(self, printStackedWidget): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.bbp_nozzle_offset_01.setPalette(palette) + self.bbp_nozzle_offset_1.setPalette(palette) font = QtGui.QFont() font.setPointSize(14) - self.bbp_nozzle_offset_01.setFont(font) - self.bbp_nozzle_offset_01.setCheckable(True) - self.bbp_nozzle_offset_01.setFlat(True) - self.bbp_nozzle_offset_01.setProperty("button_type", "") - self.bbp_nozzle_offset_01.setObjectName("bbp_nozzle_offset_01") + self.bbp_nozzle_offset_1.setFont(font) + self.bbp_nozzle_offset_1.setCheckable(True) + self.bbp_nozzle_offset_1.setChecked(True) + self.bbp_nozzle_offset_1.setFlat(True) + self.bbp_nozzle_offset_1.setProperty("button_type", "") + self.bbp_nozzle_offset_1.setObjectName("bbp_nozzle_offset_1") self.bbp_offset_value_selector_group = QtWidgets.QButtonGroup(printStackedWidget) self.bbp_offset_value_selector_group.setObjectName("bbp_offset_value_selector_group") - self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_01) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_01) - self.line_3 = QtWidgets.QFrame(parent=self.babystep_page) - self.line_3.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_3.setObjectName("line_3") - self.bbp_offset_steps_buttons.addWidget(self.line_3) - self.bbp_nozzle_offset_025 = QtWidgets.QPushButton(parent=self.babystep_page) - self.bbp_nozzle_offset_025.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_025.setMaximumSize(QtCore.QSize(100, 80)) + self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_1) + self.verticalLayout_6.addWidget(self.bbp_nozzle_offset_1) + self.line_2 = QtWidgets.QFrame(parent=self.babystep_page) + self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_2.setObjectName("line_2") + self.verticalLayout_6.addWidget(self.line_2) + self.bbp_nozzle_offset_05 = QtWidgets.QPushButton(parent=self.babystep_page) + self.bbp_nozzle_offset_05.setMinimumSize(QtCore.QSize(60, 60)) + self.bbp_nozzle_offset_05.setMaximumSize(QtCore.QSize(100, 80)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -909,24 +837,24 @@ def setupUi(self, printStackedWidget): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.bbp_nozzle_offset_025.setPalette(palette) + self.bbp_nozzle_offset_05.setPalette(palette) font = QtGui.QFont() font.setPointSize(14) - self.bbp_nozzle_offset_025.setFont(font) - self.bbp_nozzle_offset_025.setCheckable(True) - self.bbp_nozzle_offset_025.setFlat(True) - self.bbp_nozzle_offset_025.setProperty("button_type", "") - self.bbp_nozzle_offset_025.setObjectName("bbp_nozzle_offset_025") - self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_025) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_025) - self.line_4 = QtWidgets.QFrame(parent=self.babystep_page) - self.line_4.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_4.setObjectName("line_4") - self.bbp_offset_steps_buttons.addWidget(self.line_4) - self.bbp_nozzle_offset_05 = QtWidgets.QPushButton(parent=self.babystep_page) - self.bbp_nozzle_offset_05.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_05.setMaximumSize(QtCore.QSize(100, 80)) + self.bbp_nozzle_offset_05.setFont(font) + self.bbp_nozzle_offset_05.setCheckable(True) + self.bbp_nozzle_offset_05.setFlat(True) + self.bbp_nozzle_offset_05.setProperty("button_type", "") + self.bbp_nozzle_offset_05.setObjectName("bbp_nozzle_offset_05") + self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_05) + self.verticalLayout_6.addWidget(self.bbp_nozzle_offset_05) + self.line_3 = QtWidgets.QFrame(parent=self.babystep_page) + self.line_3.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_3.setObjectName("line_3") + self.verticalLayout_6.addWidget(self.line_3) + self.bbp_nozzle_offset_025 = QtWidgets.QPushButton(parent=self.babystep_page) + self.bbp_nozzle_offset_025.setMinimumSize(QtCore.QSize(60, 60)) + self.bbp_nozzle_offset_025.setMaximumSize(QtCore.QSize(100, 80)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -946,24 +874,24 @@ def setupUi(self, printStackedWidget): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.bbp_nozzle_offset_05.setPalette(palette) + self.bbp_nozzle_offset_025.setPalette(palette) font = QtGui.QFont() font.setPointSize(14) - self.bbp_nozzle_offset_05.setFont(font) - self.bbp_nozzle_offset_05.setCheckable(True) - self.bbp_nozzle_offset_05.setFlat(True) - self.bbp_nozzle_offset_05.setProperty("button_type", "") - self.bbp_nozzle_offset_05.setObjectName("bbp_nozzle_offset_05") - self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_05) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_05) - self.line_5 = QtWidgets.QFrame(parent=self.babystep_page) - self.line_5.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_5.setObjectName("line_5") - self.bbp_offset_steps_buttons.addWidget(self.line_5) - self.bbp_nozzle_offset_1 = QtWidgets.QPushButton(parent=self.babystep_page) - self.bbp_nozzle_offset_1.setMinimumSize(QtCore.QSize(60, 60)) - self.bbp_nozzle_offset_1.setMaximumSize(QtCore.QSize(100, 80)) + self.bbp_nozzle_offset_025.setFont(font) + self.bbp_nozzle_offset_025.setCheckable(True) + self.bbp_nozzle_offset_025.setFlat(True) + self.bbp_nozzle_offset_025.setProperty("button_type", "") + self.bbp_nozzle_offset_025.setObjectName("bbp_nozzle_offset_025") + self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_025) + self.verticalLayout_6.addWidget(self.bbp_nozzle_offset_025) + self.line_4 = QtWidgets.QFrame(parent=self.babystep_page) + self.line_4.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_4.setObjectName("line_4") + self.verticalLayout_6.addWidget(self.line_4) + self.bbp_nozzle_offset_01 = QtWidgets.QPushButton(parent=self.babystep_page) + self.bbp_nozzle_offset_01.setMinimumSize(QtCore.QSize(60, 60)) + self.bbp_nozzle_offset_01.setMaximumSize(QtCore.QSize(100, 80)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -983,23 +911,100 @@ def setupUi(self, printStackedWidget): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ButtonText, brush) - self.bbp_nozzle_offset_1.setPalette(palette) + self.bbp_nozzle_offset_01.setPalette(palette) font = QtGui.QFont() font.setPointSize(14) - self.bbp_nozzle_offset_1.setFont(font) - self.bbp_nozzle_offset_1.setCheckable(True) - self.bbp_nozzle_offset_1.setChecked(True) - self.bbp_nozzle_offset_1.setFlat(True) - self.bbp_nozzle_offset_1.setProperty("button_type", "") - self.bbp_nozzle_offset_1.setObjectName("bbp_nozzle_offset_1") - self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_1) - self.bbp_offset_steps_buttons.addWidget(self.bbp_nozzle_offset_1) - self.verticalLayout.addLayout(self.bbp_offset_steps_buttons) + self.bbp_nozzle_offset_01.setFont(font) + self.bbp_nozzle_offset_01.setCheckable(True) + self.bbp_nozzle_offset_01.setFlat(True) + self.bbp_nozzle_offset_01.setProperty("button_type", "") + self.bbp_nozzle_offset_01.setObjectName("bbp_nozzle_offset_01") + self.bbp_offset_value_selector_group.addButton(self.bbp_nozzle_offset_01) + self.verticalLayout_6.addWidget(self.bbp_nozzle_offset_01) + self.horizontalLayout_2.addLayout(self.verticalLayout_6) + self.line_5 = QtWidgets.QFrame(parent=self.babystep_page) + self.line_5.setFrameShape(QtWidgets.QFrame.Shape.VLine) + self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_5.setObjectName("line_5") + self.horizontalLayout_2.addWidget(self.line_5) + self.frame_2 = QtWidgets.QFrame(parent=self.babystep_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.frame_2.sizePolicy().hasHeightForWidth()) + self.frame_2.setSizePolicy(sizePolicy) + self.frame_2.setMinimumSize(QtCore.QSize(350, 160)) + self.frame_2.setMaximumSize(QtCore.QSize(350, 160)) + self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.frame_2.setObjectName("frame_2") + self.bbp_babystep_graphic = QtWidgets.QLabel(parent=self.frame_2) + self.bbp_babystep_graphic.setGeometry(QtCore.QRect(0, 30, 371, 121)) + self.bbp_babystep_graphic.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.bbp_babystep_graphic.setText("") + self.bbp_babystep_graphic.setPixmap(QtGui.QPixmap(":/graphics/media/graphics/babystep_graphic.png")) + self.bbp_babystep_graphic.setScaledContents(False) + self.bbp_babystep_graphic.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.bbp_babystep_graphic.setObjectName("bbp_babystep_graphic") + self.bbp_z_offset_current_value = BlocksLabel(parent=self.frame_2) + self.bbp_z_offset_current_value.setGeometry(QtCore.QRect(130, 70, 200, 60)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.bbp_z_offset_current_value.sizePolicy().hasHeightForWidth()) + self.bbp_z_offset_current_value.setSizePolicy(sizePolicy) + self.bbp_z_offset_current_value.setMinimumSize(QtCore.QSize(150, 60)) + self.bbp_z_offset_current_value.setMaximumSize(QtCore.QSize(200, 60)) + font = QtGui.QFont() + font.setPointSize(13) + self.bbp_z_offset_current_value.setFont(font) + self.bbp_z_offset_current_value.setStyleSheet("background: transparent; color: white;") + self.bbp_z_offset_current_value.setText("") + self.bbp_z_offset_current_value.setPixmap(QtGui.QPixmap(":/graphics/media/btn_icons/z_offset_adjust.svg")) + self.bbp_z_offset_current_value.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.bbp_z_offset_current_value.setObjectName("bbp_z_offset_current_value") + self.horizontalLayout_2.addWidget(self.frame_2, 0, QtCore.Qt.AlignmentFlag.AlignHCenter|QtCore.Qt.AlignmentFlag.AlignVCenter) + self.bbp_buttons_layout = QtWidgets.QVBoxLayout() + self.bbp_buttons_layout.setContentsMargins(5, 5, 5, 5) + self.bbp_buttons_layout.setObjectName("bbp_buttons_layout") + self.bbp_away_from_bed = BlocksCustomButton(parent=self.babystep_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.bbp_away_from_bed.sizePolicy().hasHeightForWidth()) + self.bbp_away_from_bed.setSizePolicy(sizePolicy) + self.bbp_away_from_bed.setMinimumSize(QtCore.QSize(80, 80)) + self.bbp_away_from_bed.setMaximumSize(QtCore.QSize(80, 80)) + self.bbp_away_from_bed.setFlat(True) + self.bbp_away_from_bed.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/up_arrow.svg")) + self.bbp_away_from_bed.setObjectName("bbp_away_from_bed") + self.bbp_option_button_group = QtWidgets.QButtonGroup(printStackedWidget) + self.bbp_option_button_group.setObjectName("bbp_option_button_group") + self.bbp_option_button_group.addButton(self.bbp_away_from_bed) + self.bbp_buttons_layout.addWidget(self.bbp_away_from_bed, 0, QtCore.Qt.AlignmentFlag.AlignRight) + self.bbp_close_to_bed = BlocksCustomButton(parent=self.babystep_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.bbp_close_to_bed.sizePolicy().hasHeightForWidth()) + self.bbp_close_to_bed.setSizePolicy(sizePolicy) + self.bbp_close_to_bed.setMinimumSize(QtCore.QSize(80, 80)) + self.bbp_close_to_bed.setMaximumSize(QtCore.QSize(80, 80)) + self.bbp_close_to_bed.setFlat(True) + self.bbp_close_to_bed.setProperty("icon_pixmap", QtGui.QPixmap(":/arrow_icons/media/btn_icons/down_arrow.svg")) + self.bbp_close_to_bed.setObjectName("bbp_close_to_bed") + self.bbp_option_button_group.addButton(self.bbp_close_to_bed) + self.bbp_buttons_layout.addWidget(self.bbp_close_to_bed, 0, QtCore.Qt.AlignmentFlag.AlignRight) + self.bbp_buttons_layout.setStretch(0, 1) + self.bbp_buttons_layout.setStretch(1, 1) + self.horizontalLayout_2.addLayout(self.bbp_buttons_layout) + self.horizontalLayout_2.setStretch(2, 1) + self.verticalLayout.addLayout(self.horizontalLayout_2) self.verticalLayout.setStretch(1, 1) printStackedWidget.addWidget(self.babystep_page) self.retranslateUi(printStackedWidget) - printStackedWidget.setCurrentIndex(2) + printStackedWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(printStackedWidget) def retranslateUi(self, printStackedWidget): @@ -1060,14 +1065,14 @@ def retranslateUi(self, printStackedWidget): self.speed_display.setProperty("button_type", _translate("printStackedWidget", "display")) self.bbp_header_title.setText(_translate("printStackedWidget", "Z Babystep")) self.babystep_back_btn.setProperty("button_type", _translate("printStackedWidget", "icon")) + self.bbp_nozzle_offset_1.setText(_translate("printStackedWidget", "0.1")) + self.bbp_nozzle_offset_05.setText(_translate("printStackedWidget", "0.05")) + self.bbp_nozzle_offset_025.setText(_translate("printStackedWidget", "0.025")) + self.bbp_nozzle_offset_01.setText(_translate("printStackedWidget", "0.01")) self.bbp_away_from_bed.setText(_translate("printStackedWidget", "~^")) self.bbp_away_from_bed.setProperty("button_type", _translate("printStackedWidget", "icon")) self.bbp_close_to_bed.setText(_translate("printStackedWidget", "^")) self.bbp_close_to_bed.setProperty("button_type", _translate("printStackedWidget", "icon")) - self.bbp_nozzle_offset_01.setText(_translate("printStackedWidget", "0.01")) - self.bbp_nozzle_offset_025.setText(_translate("printStackedWidget", "0.025")) - self.bbp_nozzle_offset_05.setText(_translate("printStackedWidget", "0.05")) - self.bbp_nozzle_offset_1.setText(_translate("printStackedWidget", "0.1")) from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_label import BlocksLabel from lib.utils.display_button import DisplayButton From 8ba6400962e58631eb0cf1b8575f341921bd3091 Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Sun, 24 Aug 2025 19:08:13 +0100 Subject: [PATCH 09/20] Work loading screen (#11) * ADD: added loading screen widget * UPD: updated loadpage with the popup system (appear on top) * ADDED: added the option to load an gif into loadpage widget instead of an circle animation * ADD: enum onto LoadScreen like "LoadScreen.AnimationGIF.BEDMESH" , added the ability to use differents gifs by editing config [loading] * Refactor address for websocket and rest connections * Refactor unused imports, code, deleted print methods used for debugging * Refacto: fix the default animation type when instantiating the class --------- Co-authored-by: Roberto Martins --- BlocksScreen/lib/moonrest.py | 1 - BlocksScreen/lib/panels/widgets/loadPage.py | 188 ++++++++++++++++++++ 2 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 BlocksScreen/lib/panels/widgets/loadPage.py diff --git a/BlocksScreen/lib/moonrest.py b/BlocksScreen/lib/moonrest.py index a141ece4..a6ac58bb 100644 --- a/BlocksScreen/lib/moonrest.py +++ b/BlocksScreen/lib/moonrest.py @@ -28,7 +28,6 @@ class MoonRest: timeout = 3 # TODO: The ip and port need to come from a configfile - def __init__(self, ip="localhost", port="7125", api_key=False): self._ip = ip self._port = port diff --git a/BlocksScreen/lib/panels/widgets/loadPage.py b/BlocksScreen/lib/panels/widgets/loadPage.py new file mode 100644 index 00000000..466ebba2 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/loadPage.py @@ -0,0 +1,188 @@ +import enum + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class LoadScreen(QtWidgets.QDialog): + class AnimationGIF(enum.Enum): + # [x]: WATHERE ARE NO GIFS IN LOADSCREEN PLEASE REMEMBER THIS IM WARNING + + # TODO : add more types into LoadScreen + + DEFAULT = None + PLACEHOLDER = "" + + def __init__( + self, parent: QtWidgets.QWidget, type: AnimationGIF = AnimationGIF.DEFAULT + ) -> None: + super().__init__(parent) + + self.type = type + self._angle = 0 + self._span_angle = 90.0 + self._is_span_growing = True + self.min_length = 5.0 + self.max_length = 150.0 + self.length_step = 2.5 + + self.setStyleSheet( + "background-image: url(:/background/media/1st_background.png);" + ) + + self.setWindowFlags( + QtCore.Qt.WindowType.Popup + | QtCore.Qt.WindowType.FramelessWindowHint + ) + + self.setupUI() + + config = parent.get_config() + try: + if config is not None: + loading_config = config["loading"] + animation = loading_config.get( + str(self.type.name), self.type.value + ) + except KeyError: + self.type = LoadScreen.AnimationGIF.DEFAULT + + self.timer = QtCore.QTimer(self) + self.timer.timeout.connect(self._update_animation) + + if self.type != LoadScreen.AnimationGIF.PLACEHOLDER: + self.movie = QtGui.QMovie(animation) # Create QMovie object + self.gifshow.setMovie(self.movie) # Set QMovie to QLabel + self.movie.start() # Start the QMovie + + # Only start the animation timer if no GIF is provided + if self.type == LoadScreen.AnimationGIF.DEFAULT: + self.timer.start(16) + + self.repaint() + + def set_status_message(self, message: str) -> None: + self.label.setText(message) + + def geometry_calc(self) -> None: + # REFACTOR: find another way to get mainwindow geometry , this version consumes too much ram + app_instance = QtWidgets.QApplication.instance() + main_window = app_instance.activeWindow() if app_instance else None + if main_window is None and app_instance: + for widget in app_instance.allWidgets(): + if isinstance(widget, QtWidgets.QMainWindow): + main_window = widget + x = main_window.geometry().x() + y = main_window.geometry().y() + width = main_window.width() + height = main_window.height() + + self.setGeometry(x, y, width, height) + + def close(self) -> bool: + self.timer.stop() + self.label.setText("Loading...") + self._angle = 0 + # Stop the GIF animation if it was started + if self.type != LoadScreen.AnimationGIF.DEFAULT: + self.gifshow.movie().stop() + return super().close() + + def _update_animation(self) -> None: + self._angle = (self._angle + 5) % 360 + if self._is_span_growing: + self._span_angle += self.length_step + if self._span_angle >= self.max_length: + self._span_angle = self.max_length + self._is_span_growing = False + else: + self._span_angle -= self.length_step + if self._span_angle <= self.min_length: + self._span_angle = self.min_length + self._is_span_growing = True + self.update() + + def sizeHint(self) -> QtCore.QSize: + popup_width = int(self.geometry().width()) + popup_height = int(self.geometry().height()) + # Centering logic + + popup_x = self.x() + popup_y = self.y() + (self.height() - popup_height) // 2 + self.move(popup_x, popup_y) + self.setFixedSize(popup_width, popup_height) + self.setMinimumSize(popup_width, popup_height) + return super().sizeHint() + + def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None: + return + + def paintEvent(self, a0: QtGui.QPaintEvent) -> None: + painter = QtGui.QPainter(self) + # loading circle draw + if self.type == LoadScreen.AnimationGIF.DEFAULT: + painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True) + painter.setRenderHint( + QtGui.QPainter.RenderHint.LosslessImageRendering, True + ) + painter.setRenderHint( + QtGui.QPainter.RenderHint.SmoothPixmapTransform, True + ) + painter.setRenderHint( + QtGui.QPainter.RenderHint.TextAntialiasing, True + ) + pen = QtGui.QPen() + pen.setWidth(8) + pen.setColor(QtGui.QColor("#ffffff")) + pen.setCapStyle(QtCore.Qt.PenCapStyle.RoundCap) + painter.setPen(pen) + + center_x = self.width() // 2 + center_y = int(self.height() * 0.4) + arc_size = 150 + + painter.translate(center_x, center_y) + painter.rotate(self._angle) + + arc_rect = QtCore.QRectF( + -arc_size / 2, -arc_size / 2, arc_size, arc_size + ) + span_angle = int(self._span_angle * 16) + painter.drawArc(arc_rect, 0, span_angle) + + def resizeEvent(self, event: QtGui.QResizeEvent) -> None: + super().resizeEvent(event) + + label_width = self.width() + label_height = 100 + label_x = (self.width() - label_width) // 2 + label_y = int(self.height() * 0.65) + + margin = 20 + # Center the GIF + gifshow_width = self.width() - margin * 2 + gifshow_height = self.height() - (self.height() - label_y) - margin + + self.gifshow.setGeometry(margin, margin, gifshow_width, gifshow_height) + + self.label.setGeometry(label_x, label_y, label_width, label_height) + + def show(self) -> None: + self.geometry_calc() + # Start the animation timer only if no GIF is present + if self.type == LoadScreen.AnimationGIF.DEFAULT: + self.timer.start() + self.repaint() + return super().show() + + def setupUI(self) -> None: + self.gifshow = QtWidgets.QLabel("", self) + self.gifshow.setObjectName("gifshow") + self.gifshow.setStyleSheet("background: transparent;") + self.gifshow.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + + self.label = QtWidgets.QLabel("Test", self) + font = QtGui.QFont() + font.setPointSize(20) + self.label.setFont(font) + self.label.setStyleSheet("color: #ffffff; background: transparent;") + self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) From cc265281fc50e62b2a9044dd517554e7406d20cc Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Sun, 24 Aug 2025 19:44:11 +0100 Subject: [PATCH 10/20] Work network styling (#12) * add: networks sytle first version * ADD: add line edit , list button (new version) and ScrollBar (new version) widgets * update: updated network (small changes like remove some prints, and removing some network from the dummy list) , updated the ui from network page and added some funcionailty (W.I.P) to it * Fix: Toggle button animation bug The button's state animation was not playing when the state was changed by code. This is fixed by removing an unnecessary check for the mouse position in the animation method. * add: added funcionality and logic for network panels (bug fixes needed) * Added method for retrieving active connection ssid name, refactored some code, fixed the rescan method * Refactor: deleted unusedcode, inheritance QObject to integrate into the application * Refactor: UI button types --------- Co-authored-by: Roberto Martins --- BlocksScreen/lib/network.py | 356 +- BlocksScreen/lib/panels/networkWindow.py | 476 +- BlocksScreen/lib/ui/wifiConnectivityWindow.ui | 5482 ++++++++++------- .../lib/ui/wifiConnectivityWindow_ui.py | 948 ++- BlocksScreen/lib/utils/blocks_ScrollBar.py | 78 + BlocksScreen/lib/utils/blocks_frame.py | 28 + BlocksScreen/lib/utils/blocks_linedit.py | 71 + BlocksScreen/lib/utils/blocks_slider.py | 78 +- BlocksScreen/lib/utils/list_button.py | 59 +- .../lib/utils/toggleAnimatedButton.py | 6 +- 10 files changed, 4685 insertions(+), 2897 deletions(-) create mode 100644 BlocksScreen/lib/utils/blocks_ScrollBar.py create mode 100644 BlocksScreen/lib/utils/blocks_frame.py create mode 100644 BlocksScreen/lib/utils/blocks_linedit.py diff --git a/BlocksScreen/lib/network.py b/BlocksScreen/lib/network.py index e77cbdce..570880b9 100644 --- a/BlocksScreen/lib/network.py +++ b/BlocksScreen/lib/network.py @@ -1,4 +1,5 @@ import logging +import random import typing from uuid import uuid4 @@ -26,9 +27,6 @@ NmConnectionPropertyNotFoundError, ) -# TODO: Add Logging, separate logger in this case so i can structure it better -# TODO: Remove the statically attributed variables - class NetworkManagerRescanError(Exception): """Exception raised when rescanning the network fails.""" @@ -38,6 +36,7 @@ def __init__(self, error): self.error = error +# class SdbusNetworkManager: class SdbusNetworkManager(QObject): """Class that controls the linux NetworkManager tool using the sdbus library. @@ -50,31 +49,24 @@ class SdbusNetworkManager(QObject): """ def __init__(self, parent: typing.Optional["QObject"]): + # def __init__(self): super(SdbusNetworkManager, self).__init__() - self.system_dbus = sdbus.sd_bus_open_system() - - if self.system_dbus is None: + if not self.system_dbus: return - self.known_networks = [] - self.saved_networks_ssids: typing.List self.hotspot_ssid: str = "PrinterHotspot" self.hotspot_password: str = "123456789" - # * Test the networkmanager sdbus.set_default_bus(self.system_dbus) - try: self.nm = NetworkManager() except Exception as e: logging.debug( f"Exception occurred when getting NetworkManager, exception message: {e}" ) - self.available_wired_interfaces = self.get_wired_interfaces() self.available_wireless_interfaces = self.get_wireless_interfaces() - self.primary_wifi_interface: NetworkDeviceWireless | None = ( self.get_wireless_interfaces()[0] if len(self.get_wireless_interfaces()) > 0 @@ -109,7 +101,8 @@ def get_available_interfaces(self) -> typing.List[str]: """ return [ - NetworkDeviceGeneric(device).interface for device in self.nm.get_devices() + NetworkDeviceGeneric(device).interface + for device in self.nm.get_devices() ] def wifi_enabled(self) -> bool: @@ -203,31 +196,42 @@ def get_wireless_interfaces(self) -> typing.List[NetworkDeviceWireless]: ) ) - def get_current_ip_addr(self) -> typing.List[str] | None: + def get_current_ssid(self) -> typing.Union[str, None]: + if self.nm.primary_connection == "/": + return + try: + return ActiveConnection(self.nm.primary_connection).id + except Exception as e: + logging.info(f"Unexpected error occurred: {e}") + + def get_current_ip_addr(self) -> typing.Union[typing.List[str], None]: """get_current_ip_addr Gets the current connection ip address. Returns: str: A string containing the current ip address """ - if self.nm.primary_connection == "/": - # TODO: Logging - print("There is no NetworkManager connection. No IP Address") - return None - _device_ip4_conf_path = ActiveConnection(self.nm.primary_connection).ip4_config + logging.info("There is no NetworkManager active connection.") + return + _device_ip4_conf_path = ActiveConnection( + self.nm.primary_connection + ).ip4_config if _device_ip4_conf_path == "/": - # NetworkManager reports that there is no ipv4 config for the interface, probably there is no connection at this time. - logging.info("NetworkManager reports no IP configuration for the interface") - # TODO: Logging - return None - + logging.info( + "NetworkManager reports no IP configuration for the interface" + ) + return ip4_conf = IPv4Config(_device_ip4_conf_path) - _addrs = [address_data["address"][1] for address_data in ip4_conf.address_data] - return _addrs + return [ + address_data["address"][1] + for address_data in ip4_conf.address_data + ] def get_primary_interface( self, - ) -> NetworkDeviceWired | NetworkDeviceWireless | typing.Tuple | str: + ) -> typing.Union[ + NetworkDeviceWired, NetworkDeviceWireless, typing.Tuple, str + ]: """get_primary_interface Return the primary interface, If a there is a connection, returns the interface that is being currently used. @@ -253,14 +257,18 @@ def get_primary_interface( self.nm.primary_connection_type, ) - def rescan_networks(self) -> None: + def rescan_networks(self) -> bool: """rescan_networks Scan for available networks.""" - if self.primary_wifi_interface == "/" or self.primary_wifi_interface is None: - return + if ( + self.primary_wifi_interface == "/" + or not self.primary_wifi_interface + ): + return False try: self.primary_wifi_interface.request_scan({}) - except Exception as e: - raise NetworkManagerRescanError(f"Network rescan failed: {e}") + return True + except Exception: + raise NetworkManagerRescanError("Network scan failed") def get_available_networks(self) -> typing.Dict: """get_available_networks Scan for networks, get the information about each network. @@ -269,14 +277,17 @@ def get_available_networks(self) -> typing.Dict: typing.List[dict] | None: A list that contains the information about every available found networks. None if nothing is found or the scan failed. - Implemented with map built-in python method instead of for loops. Don't know the performance difference, but tried to not use for loops in these methods just to try. """ - # This will only work on wifi, because we can scan networks - if self.primary_wifi_interface == "/" or self.primary_wifi_interface is None: + if ( + self.primary_wifi_interface == "/" + or not self.primary_wifi_interface + ): return {"error": "No primary interface found"} - # Make sure we scan for networks first if self.rescan_networks(): - if self.primary_wifi_interface.device_type == enums.DeviceType.WIFI: - # Get information about all scanned networks. + if ( + self.primary_wifi_interface.device_type + == enums.DeviceType.WIFI + ): _aps: typing.List[AccessPoint] = list( map( lambda ap_path: AccessPoint(ap_path), @@ -299,6 +310,7 @@ def get_available_networks(self) -> typing.Dict: _aps, ) ) + return _info_networks return {"error": "No available networks"} @@ -317,8 +329,8 @@ def get_security_type(self, ap: AccessPoint) -> typing.Tuple: Check: For more information about the flags :py:class:`WpaSecurityFlags` and `ÀccessPointCapabilities` from :py:module:`python-sdbus-networkmanager.enums` """ - if ap is None: - return None + if not ap: + return _sec_rsn: typing.List[WpaSecurityFlags] = list( map(lambda sec: sec, list(WpaSecurityFlags(ap.rsn_flags))) @@ -345,15 +357,21 @@ def get_saved_networks(self) -> typing.List[typing.Dict | None]: I admit that this implementation is way to complicated, I don't even think it's great on memory and time, but i didn't use for loops so mission achieved. """ - if self.nm is None: + if not self.nm: return [{"error": "No network manager"}] - _connections: typing.List[str] = NetworkManagerSettings().list_connections() + _connections: typing.List[str] = ( + NetworkManagerSettings().list_connections() + ) - _network_settings: typing.List[NetworkManagerConnectionProperties] = list( - map( - lambda _settings: NetworkConnectionSettings(_settings).get_settings(), - iter(_connections), + _network_settings: typing.List[NetworkManagerConnectionProperties] = ( + list( + map( + lambda _settings: NetworkConnectionSettings( + _settings + ).get_settings(), + iter(_connections), + ) ) ) @@ -364,10 +382,12 @@ def get_saved_networks(self) -> typing.List[typing.Dict | None]: map( lambda network_properties: ( { - "SSID": network_properties["802-11-wireless"]["ssid"][ - 1 - ].decode(), - "UUID": network_properties["connection"]["uuid"][1], + "SSID": network_properties["802-11-wireless"][ + "ssid" + ][1].decode(), + "UUID": network_properties["connection"][ + "uuid" + ][1], # "CONNECTION_PATH": connection } if network_properties["connection"]["type"][1] @@ -392,7 +412,7 @@ def get_saved_networks_with_for(self) -> typing.List[dict]: This implementation is equal to the klipper screen implementation, this one uses for loops and is simpler. https://github.com/KlipperScreen/KlipperScreen/blob/master/ks_includes/sdbus_nm.py Alfredo Monclues (alfrix) 2024 """ - if self.nm is None: + if not self.nm: return [] known_networks = [] for connection in NetworkManagerSettings().list_connections(): @@ -403,9 +423,9 @@ def get_saved_networks_with_for(self) -> typing.List[dict]: { "SSID": conn["802-11-wireless"]["ssid"][1].decode(), "UUID": conn["connection"]["uuid"][1], - "SECURITY_TYPE": conn["802-11-wireless-security"]["key_mgmt"][ - 1 - ].decode(), + "SECURITY_TYPE": conn["802-11-wireless-security"][ + "key_mgmt" + ][1].decode(), "CONNECTION_PATH": connection, } ) @@ -437,7 +457,9 @@ def is_known(self, ssid: str) -> bool: Returns: bool: True if the network is known otherwise False """ - return any(net["SSID"] == ssid for net in self.get_saved_networks_with_for()) + return any( + net["SSID"] == ssid for net in self.get_saved_networks_with_for() + ) def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: """Add and Save a network to the device. @@ -455,7 +477,10 @@ def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: On the returned dictionary a key value "error" can appear if an error occurred, the value will say what the error was. "exception" """ - if self.primary_wifi_interface is None or self.primary_wifi_interface == "/": + if ( + not self.primary_wifi_interface + or self.primary_wifi_interface == "/" + ): return {"status": "error", "msg": "No Available interface"} # Connections with the same if result in failure, so get ids first. @@ -480,7 +505,10 @@ def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: "id": ("s", ssid), "uuid": ("s", str(uuid4())), "type": ("s", "802-11-wireless"), - "interface-name": ("s", self.primary_wifi_interface.interface), + "interface-name": ( + "s", + self.primary_wifi_interface.interface, + ), "autoconnect": ("b", bool(True)), }, "802-11-wireless": { @@ -526,18 +554,20 @@ def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: "wep-key0": ("s", psk), "auth-alg": ("s", "shared"), } - elif (WpaSecurityFlags.P2P_TKIP or WpaSecurityFlags.BROADCAST_TKIP) in ( - _security_types[1] or _security_types[2] - ): + elif ( + WpaSecurityFlags.P2P_TKIP + or WpaSecurityFlags.BROADCAST_TKIP + ) in (_security_types[1] or _security_types[2]): # * TKip # raise NotImplementedError return { "status": "error", "msg": "Security type P2P_TKIP OR BRADCAST_TKIP not supported", } - elif (WpaSecurityFlags.P2P_CCMP or WpaSecurityFlags.BROADCAST_CCMP) in ( - _security_types[1] or _security_types[2] - ): + elif ( + WpaSecurityFlags.P2P_CCMP + or WpaSecurityFlags.BROADCAST_CCMP + ) in (_security_types[1] or _security_types[2]): # * AES/CCMP WPA2 properties["802-11-wireless-security"] = { "key-mgmt": ("s", "wpa-psk"), @@ -608,7 +638,10 @@ def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: try: NetworkManagerSettings().add_connection(properties) - return {"status": "success", "msg": "Network added successfully"} + return { + "status": "success", + "msg": "Network added successfully", + } except NmConnectionFailedError as e: return { "status": "exception", @@ -638,7 +671,10 @@ def disconnect_network(self) -> bool: - True -> wifi interface is not and can perform the disconnection - False -> Wifi interface is none and the disconnect command is not run. """ - if self.primary_wifi_interface == "/" or self.primary_wifi_interface is None: + if ( + self.primary_wifi_interface == "/" + or self.primary_wifi_interface is None + ): return False self.primary_wifi_interface.disconnect() return True @@ -659,9 +695,7 @@ def get_connection_path_by_ssid(self, ssid: str) -> str | None: _connection_path = None _saved_networks = self.get_saved_networks_with_for() if len(_saved_networks) == 0 or _saved_networks is None: - return ( - "There are no saved networks, must add a new network connection first." - ) + return "There are no saved networks, must add a new network connection first." # *Get the connection path by ssid for saved_network in _saved_networks: @@ -712,12 +746,18 @@ def get_connection_signal_by_ssid(self, ssid: str) -> typing.Dict | int: return {"error": "ssid argument must be of type string"} if self.nm is None: return {"error": "No Network Manager instance available"} - if self.primary_wifi_interface == "/" or self.primary_wifi_interface is None: + if ( + self.primary_wifi_interface == "/" + or self.primary_wifi_interface is None + ): return {"error": "No wifi interface"} _signal: int = 0 if self.rescan_networks(): - if self.primary_wifi_interface.device_type == enums.DeviceType.WIFI: + if ( + self.primary_wifi_interface.device_type + == enums.DeviceType.WIFI + ): # Get information on scanned networks: _aps: typing.List[AccessPoint] = list( map( @@ -836,7 +876,9 @@ def create_hotspot( NetworkManagerSettings().add_connection(properties) return {"status": "success"} except Exception as e: - logging.debug(f"Error occurred while adding a hotspot connection: {e.args}") + logging.debug( + f"Error occurred while adding a hotspot connection: {e.args}" + ) return {"status": "error, exception"} def delete_old_hotspot_connection(self) -> None: @@ -881,11 +923,17 @@ def update_connection_settings( if ssid == self.hotspot_ssid: self.hotspot_ssid = new_ssid properties["connection"]["id"] = ("s", str(new_ssid)) - properties["802-11-wireless"]["ssid"] = ("ay", new_ssid.encode("utf-8")) + properties["802-11-wireless"]["ssid"] = ( + "ay", + new_ssid.encode("utf-8"), + ) if password is not None: if ssid == self.hotspot_ssid: self.hotspot_password = password - properties["802-11-wireless-security"]["psk"] = ("s", str(password)) + properties["802-11-wireless-security"]["psk"] = ( + "s", + str(password), + ) con_settings.update(properties) @@ -918,6 +966,9 @@ def __init__(self): self.primary_wired_interface = "path/wireddDummy" self.wireless_active: bool = True + def get_current_ssid(self) -> str: + return "Blocks" + def get_available_interfaces(self) -> typing.List[str]: """get_available_interfaces Gets the names of all available interfaces @@ -932,7 +983,6 @@ def wifi_enabled(self) -> bool: Returns: bool: True if device is enabled | False if not """ - print(self.wireless_active) return self.wireless_active def toggle_wifi(self, toggle: bool): @@ -962,7 +1012,7 @@ def toggle_hotspot(self, toggle: bool): ValueError: If the toggle argument is not a Boolean. """ # TODO: toggle Hotspot, function to activate or deactivate the device hotspot - self.hotspot_active = not self.hotspot_active + self.hotspot_active = toggle def hotspot_enabled(self) -> typing.Optional["bool"]: """Returns a boolean indicating whether the device hotspot is on or not . @@ -971,6 +1021,7 @@ def hotspot_enabled(self) -> typing.Optional["bool"]: bool: True if Hotspot is activated, False otherwise. """ # TODO: Hotspot enbaled or not + return self.hotspot_active def get_wired_interfaces(self) -> typing.List: @@ -1031,26 +1082,100 @@ def get_available_networks(self): - Implemented with map built-in python method instead of for loops. Don't know the performance difference, but tried to not use for loops in these methods just to try. """ # This will only work on wifi, because we can scan networks - return [ - { - "ssid": "BLOCKS", - "security": "wpa", - "frequency": 344, - "channel": 2, - "signal_level": "-12", - "max_bitrate": "1222", - "BSSID": "12:312:je:22", - }, - { - "ssid": "MEO", - "security": "wpa", - "frequency": 344, - "channel": 2, - "signal_level": "-12", - "max_bitrate": "1222", - "BSSID": "12:312:je:22", - }, - ] + return ( + [ + { + "ssid": "BLOCKS", + "security": "wpa", + "frequency": 344, + "channel": 2, + "signal_level": "-12", + "max_bitrate": "1222", + "BSSID": "12:312:je:22", + }, + { + "ssid": "MEO", + "security": "wpa", + "frequency": 344, + "channel": 2, + "signal_level": "-12", + "max_bitrate": "1222", + "BSSID": "12:312:je:22", + }, + { + "ssid": "SkyNet", + "security": "wpa2", + "frequency": 5180, + "channel": 36, + "signal_level": "-45", + "max_bitrate": "867", + "BSSID": "a2:3f:5d:8c:01:aa", + }, + { + "ssid": "CoffeeShop_WiFi", + "security": "open", + "frequency": 2412, + "channel": 1, + "signal_level": "-68", + "max_bitrate": "144", + "BSSID": "bc:85:56:de:12:39", + }, + { + "ssid": "HomeNetwork5G", + "security": "wpa3", + "frequency": 5745, + "channel": 149, + "signal_level": "-38", + "max_bitrate": "1300", + "BSSID": "e3:55:76:9a:cd:ef", + }, + { + "ssid": "PublicLibraryNet", + "security": "wpa2", + "frequency": 2437, + "channel": 6, + "signal_level": "-72", + "max_bitrate": "300", + "BSSID": "00:1a:2b:3c:4d:5e", + }, + { + "ssid": "Device_AP_8934", + "security": "open", + "frequency": 2462, + "channel": 11, + "signal_level": "-80", + "max_bitrate": "54", + "BSSID": "de:ad:be:ef:00:99", + }, + { + "ssid": "IoT_Network", + "security": "wpa2", + "frequency": 2422, + "channel": 3, + "signal_level": "-59", + "max_bitrate": "72", + "BSSID": "aa:bb:cc:dd:ee:ff", + }, + { + "ssid": "FastLane", + "security": "wpa3", + "frequency": 5200, + "channel": 40, + "signal_level": "-33", + "max_bitrate": "2400", + "BSSID": "11:22:33:44:55:66", + }, + { + "ssid": "GUEST1234", + "security": "wpa", + "frequency": 2462, + "channel": 11, + "signal_level": "-50", + "max_bitrate": "600", + "BSSID": "77:88:99:aa:bb:cc", + }, + ], + ) def get_security_type(self, ap: AccessPoint) -> typing.Tuple: """get_security_type Get the security type from a network AccessPoint @@ -1080,14 +1205,7 @@ def get_saved_networks(self) -> typing.List[typing.Dict | None]: I admit that this implementation is way to complicated, I don't even think it's great on memory and time, but i didn't use for loops so mission achieved. """ return [ - { - "SSID": "BLOCKS", - "UUID": "OOAISUDFOASODFJ", - }, - { - "SSID": "PrinterHotspot", - "UUID": "OOAISUDFOASODFJ", - }, + {"SSID": "BLOCKS", "UUID": "OOAISUDFOASODFJ"}, ] def get_saved_networks_with_for(self): @@ -1101,14 +1219,7 @@ def get_saved_networks_with_for(self): https://github.com/KlipperScreen/KlipperScreen/blob/master/ks_includes/sdbus_nm.py Alfredo Monclues (alfrix) 2024 """ return [ - { - "SSID": "BLOCKS", - "UUID": "OOAISUDFOASODFJ", - }, - { - "SSID": "PrinterHotspot", - "UUID": "OOAISUDFOASODFJ", - }, + {"SSID": "BLOCKS", "UUID": "OOAISUDFOASODFJ"}, ] def get_saved_ssid_names(self) -> typing.List[str]: @@ -1117,7 +1228,14 @@ def get_saved_ssid_names(self) -> typing.List[str]: Returns: typing.List[str]: List that contains the names of the saved ssid network names """ - return ["BLOCKS"] + return [ + "BLOCKS", + "PrinterHotspot", + "SkyNet", + "PublicLibraryNet", + "FastLane", + "GUEST1234", + ] def is_known(self, ssid: str): """Whether or not a network is known @@ -1145,9 +1263,9 @@ def add_wifi_network(self, ssid: str, psk: str) -> typing.Dict: On the returned dictionary a key value "error" can appear if an error occurred, the value will say what the error was. """ - print(ssid) + print("added network", ssid) print(psk) - return {"status": "error", "msg": "dummy"} + return {"status": "asdas", "msg": "dummy"} def disconnect_network(self): """disconnect_network Disconnect the wireless device and prevent it from reconnecting. @@ -1192,7 +1310,7 @@ def get_connection_signal_by_ssid(self, ssid: str) -> typing.Dict | int: In the case we are able to scan The method returns the signal strength in % """ - return 14 + return random.randint(1, 100) def connect_network(self, ssid: str): """Connect to a saved network given an ssid @@ -1221,14 +1339,17 @@ def delete_network(self, ssid: str): """ print(f"Deleted network {ssid}") - def create_hotspot(self, ssid: str = "PrinterHotspot", password: str = "123456789"): + def create_hotspot( + self, ssid: str = "PrinterHotspot", password: str = "123456789" + ): print(f"Created hotspot {ssid}, {password}") def delete_old_hotspot_connection(self) -> None: print("Deleted old hotspot ") def get_hotspot_ssid(self): - print("Get hostpot ssid") + print(self.hotspot_ssid) + return self.hotspot_ssid def set_hotspot_ssid(self, ssid: str) -> None: print(f"Set hotspot ssid {ssid}") @@ -1247,4 +1368,7 @@ def update_connection_settings( Returns: typing.Dict: status dictionary with possible keys "error" and "status" """ + print(new_ssid) print(f"Updated a network connection {ssid} | {password} | {new_ssid}") + return {"status": "AUGH", "msg": "dummy"} + diff --git a/BlocksScreen/lib/panels/networkWindow.py b/BlocksScreen/lib/panels/networkWindow.py index 6bc7c6b4..79c470ec 100644 --- a/BlocksScreen/lib/panels/networkWindow.py +++ b/BlocksScreen/lib/panels/networkWindow.py @@ -1,14 +1,23 @@ +from ast import Return import typing from functools import partial from PyQt6 import QtCore, QtGui, QtWidgets -from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot +from PyQt6.QtCore import Qt, pyqtSignal, pyqtSlot, QEvent from PyQt6.QtGui import QPaintEvent from PyQt6.QtWidgets import QListWidgetItem, QStackedWidget, QWidget +# from BlocksScreen.lib.network import SdbusNetworkManager from lib.ui.wifiConnectivityWindow_ui import Ui_wifi_stacked_page from lib.network import SdbusNetworkManagerDummy +from lib.utils.list_button import ListCustomButton + +from lib.utils.toggleAnimatedButton import ToggleAnimatedButton + +from lib.panels.widgets.popupDialogWidget import Popup +import subprocess + # TEST: Network saving, Adding new Network connections, Toggle on and off hotspot, etc.... # TODO: Complete this panel # TODO: Add a Virtual Keyboard @@ -28,40 +37,123 @@ class NetworkControlWindow(QStackedWidget): name="new_connection_result", ) - request_signal_strength = pyqtSignal(str, name="network_signal_strength") - def __init__(self, parent: QWidget, /) -> None: super(NetworkControlWindow, self).__init__(parent) + self.background: QtGui.QPixmap | None = None self.panel = Ui_wifi_stacked_page() self.panel.setupUi(self) + self.popup = Popup(self) + self.panel.network_list_widget.setLayoutDirection( Qt.LayoutDirection.LeftToRight ) # * Instantiate the network control class sdbus self.sdbus_network = SdbusNetworkManagerDummy() self.current_ip_address: typing.List | None = [] + + # * i reelly dont know where to put this, so ya + + current_ssuid = self.sdbus_network.get_current_ssid() + + self.panel.netlist_ip.setText( + str(self.sdbus_network.get_current_ip_addr()) + ) + self.panel.netlist_ssuid.setText(current_ssuid) + + self.panel.netlist_security.setText( + str( + self.sdbus_network.get_security_type_by_ssid(current_ssuid) + ).upper() + ) + self.panel.netlist_strength.setText( + str( + self.sdbus_network.get_connection_signal_by_ssid(current_ssuid) + ) + + "%" + ) + + self.panel.wifi_button.setLeftFontSize(20) + self.panel.hotspot_button.setLeftFontSize(20) + + self.panel.wifi_button.clicked.connect( + partial(self.setCurrentIndex, 1) + ) + + self.panel.hotspot_button.clicked.connect( + partial(self.setCurrentIndex, 4) + ) + + text = self.sdbus_network.get_current_ip_addr() + if text is None: + text = "No IP Address" + self.panel.netlist_ip.setProperty("text_color", "white") + self.panel.netlist_ip.setText( + f"IP: {text[0]}" + ) # Set the current ip address on the network list page + + self.panel.hotspot_password_input_field.installEventFilter(self) + + QtWidgets.QScroller.grabGesture( + self.panel.network_list_widget, + QtWidgets.QScroller.ScrollerGestureType.TouchGesture, + ) + QtWidgets.QScroller.grabGesture( + self.panel.network_list_widget, + QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, + ) + + self.networkdead = False + if self.networkdead: + self.panel.line.hide() + self.panel.netlist_ssuid.hide() + self.panel.ip_frame.hide() + self.panel.stregth_frame.hide() + self.panel.signal_frame.hide() + else: + self.panel.line.show() + self.panel.netlist_ssuid.show() + self.panel.ip_frame.show() + self.panel.stregth_frame.show() + self.panel.signal_frame.show() + self.panel.label_2.hide() + + if self.sdbus_network.wifi_enabled(): + self.panel.Togglewifi.state = ToggleAnimatedButton.State.ON + self.panel.Togglehot.state = ToggleAnimatedButton.State.OFF + else: + self.panel.Togglewifi.state = ToggleAnimatedButton.State.OFF + + self.panel.wifi_backButton.clicked.connect( + partial(self.setCurrentIndex, 0) + ) + + self.panel.Togglewifi.clicked.connect( + lambda: self.wifihotspot_handler("wifi") + ) + self.panel.Togglehot.clicked.connect( + lambda: self.wifihotspot_handler("hotspot") + ) + # * Network List - self.panel.network_list_widget.itemClicked.connect(self.ssid_item_clicked) - self.panel.wifi_backButton.clicked.connect(self.hide) - self.panel.rescan_button.clicked.connect(self.sdbus_network.rescan_networks) + self.panel.network_list_widget.itemClicked.connect( + self.ssid_item_clicked + ) + self.panel.network_backButton.clicked.connect(self.hide) + self.panel.rescan_button.clicked.connect( + self.sdbus_network.rescan_networks + ) self.panel.rescan_button.clicked.connect( self.add_ssid_network_entry ) # To Update the network list - self.panel.wifi_toggle_button.clicked.connect( - partial( - self.sdbus_network.toggle_wifi, - toggle=not bool(self.sdbus_network.wifi_enabled()), - ) - ) # Turn off if enabled/Turn on if disabled + self.request_network_scan.connect(self.rescan_networks) - self.panel.call_hotspot_button.clicked.connect( - partial(self.setCurrentIndex, 3) - ) # Go to hotspot settings page # * Add Network page widget - self.panel.add_network_validation_button.clicked.connect(self.add_network) + self.panel.add_network_validation_button.clicked.connect( + self.add_network + ) self.panel.add_network_page_backButton.clicked.connect( - partial(self.setCurrentIndex, 0) + partial(self.setCurrentIndex, 1) ) self.panel.add_network_password_view.pressed.connect( partial( @@ -78,12 +170,11 @@ def __init__(self, parent: QWidget, /) -> None: # * Saved Connection page widget self.panel.saved_connection_back_button.clicked.connect( - partial(self.setCurrentIndex, 0) + partial(self.setCurrentIndex, 1) ) # Back button on this page always leads to the network list page self.delete_network_signal.connect(self.delete_network) self.panel.saved_connection_change_password_field.returnPressed.connect( - partial( - self.sdbus_network.update_connection_settings, + lambda: self.update_network( ssid=self.panel.saved_connection_network_name.text(), password=self.panel.saved_connection_change_password_field.text(), new_ssid=None, @@ -95,7 +186,7 @@ def __init__(self, parent: QWidget, /) -> None: QtWidgets.QLineEdit.EchoMode.Normal, ) ) - self.panel.saved_connection_change_password_view.pressed.connect( + self.panel.saved_connection_change_password_view.released.connect( partial( self.panel.saved_connection_change_password_field.setEchoMode, QtWidgets.QLineEdit.EchoMode.Password, @@ -103,46 +194,82 @@ def __init__(self, parent: QWidget, /) -> None: ) # * Hotspot page - self.panel.hotspot_toggle.clicked.connect(self.sdbus_network.toggle_hotspot) - self.panel.hotspot_back_button.clicked.connect(partial(self.setCurrentIndex, 0)) + + self.panel.hotspot_back_button.clicked.connect( + partial(self.setCurrentIndex, 0) + ) self.panel.hotspot_name_input_field.returnPressed.connect( - partial( - self.sdbus_network.update_connection_settings, + lambda: self.update_network( ssid=self.sdbus_network.hotspot_ssid, password=None, new_ssid=self.panel.hotspot_name_input_field.text(), ) - ) # Automatically create a new hotspot connection when a new hotspot name is inserted and enter is pressed + ) + # Automatically create a new hotspot connection when a new hotspot name is inserted and enter is pressed self.panel.hotspot_password_input_field.returnPressed.connect( - partial( - self.sdbus_network.update_connection_settings, + lambda: self.update_network( ssid=self.sdbus_network.hotspot_ssid, password=self.panel.hotspot_password_input_field.text(), new_ssid=None, ) ) + + self.panel.hotspot_password_input_field.setHidden(True) + self.panel.hotspot_password_view_button.pressed.connect( - partial( - self.panel.hotspot_password_input_field.setEchoMode, - QtWidgets.QLineEdit.EchoMode.Normal, - ) + partial(self.panel.hotspot_password_input_field.setHidden, False) ) self.panel.hotspot_password_view_button.released.connect( - partial( - self.panel.hotspot_password_input_field.setEchoMode, - QtWidgets.QLineEdit.EchoMode.Password, - ) + partial(self.panel.hotspot_password_input_field.setHidden, True) ) + + self.panel.hotspot_name_input_field.setText( + str(self.sdbus_network.get_hotspot_ssid()) + ) + self.panel.hotspot_password_input_field.setText( + str(self.sdbus_network.hotspot_password) + ) + self.new_connection_result.connect(self.process_new_connection_result) - # * Set ip address boxes with the corresponding ip - self.new_ip_signal.connect(partial(self.panel.hotspot_info_ip_field.setText)) # * request a initial network scan self.request_network_scan.emit() self.hide() + def wifihotspot_handler(self, source: str): + """Toggle Wi-Fi and Hotspot so only one is active at a time.""" + + wifi_enabled = self.sdbus_network.wifi_enabled() + hotspot_enabled = self.sdbus_network.hotspot_enabled() + + if source == "wifi": + self.sdbus_network.toggle_wifi(not wifi_enabled) + if not wifi_enabled and hotspot_enabled: + self.sdbus_network.toggle_hotspot(False) + + elif source == "hotspot": + self.sdbus_network.toggle_hotspot(not hotspot_enabled) + if not hotspot_enabled and wifi_enabled: + self.sdbus_network.toggle_wifi(False) + + # Refresh states after changes + wifi_enabled = self.sdbus_network.wifi_enabled() + hotspot_enabled = self.sdbus_network.hotspot_enabled() + + # Update UI states + self.panel.Togglewifi.state = ( + ToggleAnimatedButton.State.ON + if wifi_enabled + else ToggleAnimatedButton.State.OFF + ) + self.panel.Togglehot.state = ( + ToggleAnimatedButton.State.ON + if hotspot_enabled + else ToggleAnimatedButton.State.OFF + ) + @pyqtSlot(str, name="delete_network") def delete_network(self, ssid: str) -> None: self.sdbus_network.delete_network(ssid=ssid) @@ -178,18 +305,36 @@ def add_network(self) -> None: """ # Check if a password was inserted - if self.panel.add_network_password_field.text() is None: + if not self.panel.add_network_password_field.text(): return _network_psk = self.panel.add_network_password_field.text() _add_network_result: typing.Dict = self.sdbus_network.add_wifi_network( ssid=self.panel.add_network_network_label.text(), psk=_network_psk ) # Add the network connection - # Send a signal with the result of adding a new network - if ("error" or "exception" or "failure") in _add_network_result["status"]: - self.new_connection_result[str].emit(str(_add_network_result["msg"])) + # Send a signal with the result of adding a new networkx + + if any( + word in _add_network_result["status"] + for word in ("error", "exception", "failure") + ): + self.new_connection_result[str].emit( + str(_add_network_result["msg"]) + ) + self.popup.new_message( + message_type=Popup.MessageType.ERROR, + message=f"Could not connect to '{self.panel.add_network_network_label.text()}'\n Please check your password or try again later.", + ) + else: - self.new_connection_result.emit() + self.new_connection_result[str].emit( + str(_add_network_result["msg"]) + ) + self.popup.new_message( + message_type=Popup.MessageType.INFO, + message=f"Connected to '{self.panel.add_network_network_label.text()}' successfully", + ) + self.setCurrentIndex(0) @pyqtSlot(QListWidgetItem, name="ssid_item_clicked") def ssid_item_clicked(self, item: QListWidgetItem) -> None: @@ -198,10 +343,14 @@ def ssid_item_clicked(self, item: QListWidgetItem) -> None: Args: item (QListWidgetItem): The list entry that was clicked """ - _current_item: QWidget | None = self.panel.network_list_widget.itemWidget(item) + _current_item: QWidget | None = ( + self.panel.network_list_widget.itemWidget(item) + ) if _current_item is not None: - _current_ssid_name = _current_item.findChild(QtWidgets.QLabel).text() + _current_ssid_name = _current_item.findChild( + QtWidgets.QLabel + ).text() if ( _current_ssid_name in self.sdbus_network.get_saved_ssid_names() ): # Network already saved go to the information page @@ -215,67 +364,182 @@ def ssid_item_clicked(self, item: QListWidgetItem) -> None: str(_current_ssid_name) ) # Add the network name to the title + def update_network( + self, ssid: str, password: str | None, new_ssid: str | None + ) -> None: + _update_network_result: typing.Dict = ( + self.sdbus_network.update_connection_settings( + ssid=ssid, + password=password, + new_ssid=new_ssid, + ) + ) + + if any( + word in _update_network_result["status"] + for word in ("error", "exception", "failure") + ): + self.new_connection_result[str].emit( + str(_update_network_result["msg"]) + ) + self.popup.new_message( + message_type=Popup.MessageType.ERROR, + message=f"Could not update the settings for '{ssid}'.", + ) + + else: + self.new_connection_result[str].emit( + str(_update_network_result["msg"]) + ) + self.popup.new_message( + message_type=Popup.MessageType.INFO, + message=f"Network settings for '{ssid}' updated successfully.", + ) + + def eventFilter(self, obj, event): + if ( + obj == self.panel.hotspot_password_input_field + and event.type() == QEvent.Type.MouseButtonPress + ): + self.panel.hotspot_password_input_field.setFocus() + # subprocess.Popen(["onboard"]) # Open the virtual keyboard + return super().eventFilter(obj, event) + def add_ssid_network_entry(self) -> None: - """Add scanned networks entries to listWidget""" - index = 0 + """Add scanned networks: saved go to network_list_widget, unsaved to network_list_widget_.""" self.panel.network_list_widget.clear() - for item in self.sdbus_network.get_available_networks(): - if not isinstance(item, dict): + self.panel.network_list_widget.setSpacing(35) + + saved_ssids = set(self.sdbus_network.get_saved_ssid_names()) + + networks = [] + + available_networks = self.sdbus_network.get_available_networks()[ + 0 + ] # unpack tuple + for item in available_networks: + if not isinstance(item, dict) or "ssid" not in item: continue - if ( - "ssid" in item.keys() and item is not None - ): # REFACTOR: Can be better implemented - results = self.configure_network_entry(str(item["ssid"])) - # _item, _item_widget = self.configure_network_entry(str(item["ssid"])) - if results is not None and isinstance(results, tuple): - _item, _item_widget = results - if (_item and _item_widget) is not None: - self.panel.network_list_widget.addItem(_item) - self.panel.network_list_widget.setItemWidget( - _item, _item_widget - ) - index += 1 - - @staticmethod - def configure_network_entry( + + ssid = str(item["ssid"]) + signal = self.sdbus_network.get_connection_signal_by_ssid(ssid) + try: + signal_value = int(signal) + except (ValueError, TypeError): + signal_value = 0 + + is_saved = ssid in saved_ssids + + networks.append( + {"ssid": ssid, "signal": signal_value, "is_saved": is_saved} + ) + + saved_networks = sorted( + [n for n in networks if n["is_saved"]], key=lambda x: -x["signal"] + ) + unsaved_networks = sorted( + [n for n in networks if not n["is_saved"]], + key=lambda x: -x["signal"], + ) + + # ---- Add Saved Networks ---- + for net in saved_networks: + self._add_network_button( + ssid=net["ssid"], + signal=net["signal"], + right_text="Saved", + target_widget=self.panel.network_list_widget, + ) + + # ---- Separator Between Saved and Unsaved ---- + if saved_networks and unsaved_networks: + separator_item = QtWidgets.QListWidgetItem() + separator_widget = QtWidgets.QLabel() + separator_widget.setStyleSheet( + "background-color: gray; margin: 1px 1px; min-height: 1px; max-height: 1px;" + ) + separator_item.setSizeHint( + QtCore.QSize(0, 2) + ) # Total vertical space: 2px + self.panel.network_list_widget.addItem(separator_item) + self.panel.network_list_widget.setItemWidget( + separator_item, separator_widget + ) + + # ---- Add Unsaved Networks ---- + for net in unsaved_networks: + self._add_network_button( + ssid=net["ssid"], + signal=net["signal"], + right_text="Protected", + target_widget=self.panel.network_list_widget, + ) + + # Add a dummy blank space at the end if there are any unsaved networks + if unsaved_networks: + spacer_item = QtWidgets.QListWidgetItem() + spacer_widget = QtWidgets.QWidget() + spacer_widget.setFixedHeight(10) # Adjust height as needed + spacer_item.setSizeHint(spacer_widget.sizeHint()) + self.panel.network_list_widget.addItem(spacer_item) + + self.panel.network_list_widget.setItemWidget( + spacer_item, spacer_widget + ) + + def _add_network_button( + self, ssid: str, - ) -> typing.Tuple[QtWidgets.QListWidgetItem, QWidget] | None: - """Creates a QListWidgetItem to be inserted on the QListWidget with a network information. + signal: int, + right_text: str, + target_widget: QtWidgets.QListWidget, + ): + """Helper to create and insert a network button into the given list widget.""" + if signal >= 70: + wifi_pixmap = QtGui.QPixmap( + ":/network/media/btn_icons/4bar_wifi.svg" + ) + elif signal >= 40: + wifi_pixmap = QtGui.QPixmap( + ":/network/media/btn_icons/3bar_wifi.svg" + ) + elif signal >= 20: + wifi_pixmap = QtGui.QPixmap( + ":/network/media/btn_icons/2bar_wifi.svg" + ) + else: + wifi_pixmap = QtGui.QPixmap( + ":/network/media/btn_icons/1bar_wifi.svg" + ) - Args: - ssid (str): String with the ssid of the network + button = ListCustomButton(parent=target_widget) + button.setText(ssid) + button.setRightText(right_text) + button.setPixmap( + QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg") + ) + button.setSecondPixmap(wifi_pixmap) + button.setFixedHeight(80) + button.setLeftFontSize(17) + button.setRightFontSize(12) - Returns: - typing.Tuple[QtWidgets.QListWidgetItem, QWidget] | None: None if the argument is invalid, not a string - """ - if not isinstance(ssid, str): - return None - # REFACTOR: this code is pretty bad - _list_item = QtWidgets.QListWidgetItem() - _list_item_widget = QWidget() - _item_layout = QtWidgets.QHBoxLayout() - _item_text = QtWidgets.QLabel() - _item_button = QtWidgets.QPushButton() - - _item_button.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) - # _item_button.setStyleSheet("QPushButton{background:Transparent;}") - - _item_text.setText(str(ssid)) - _item_layout.addWidget(_item_text) - _item_layout.addWidget(_item_button) - _list_item_widget.setLayout(_item_layout) - _list_item.setSizeHint(_list_item_widget.sizeHint()) - _item_button.setText(">") - _size = _list_item_widget.geometry() - _button_size = QtCore.QSize(50, 30) - _item_button.setFixedSize(_button_size) - _item_button.setBackgroundRole(QtGui.QPalette.ColorRole.Highlight) - - _list_item.setFlags( - ~Qt.ItemFlag.ItemIsEditable - ) # ~ is for making the item not editable - - return _list_item, _list_item_widget + button.clicked.connect( + lambda checked, s=ssid: self.handle_button_click(s) + ) + + item = QtWidgets.QListWidgetItem() + item.setSizeHint(button.sizeHint()) + target_widget.addItem(item) + target_widget.setItemWidget(item, button) + + def handle_button_click(self, ssid: str): + if ssid in self.sdbus_network.get_saved_ssid_names(): + self.setCurrentIndex(3) + self.panel.saved_connection_network_name.setText(str(ssid)) + + else: + self.setCurrentIndex(2) + self.panel.add_network_network_label.setText(str(ssid)) #################################################################################### # * Reimplemented methods from parent class | Page index control methods * # @@ -320,15 +584,15 @@ def setCurrentIndex(self, index: int): return _cur = self.currentIndex() - if index == 0: # Main page + if index == 1: # Main page self.panel.network_list_widget.clear() self.add_ssid_network_entry() # Add network entries to the list - elif index == 1: # Add network page + elif index == 2: # Add network page self.panel.add_network_password_field.clear() self.panel.add_network_password_field.setPlaceholderText( "Insert password here, press enter when finished." ) - elif index == 2: # Network information page + elif index == 3: # Network information page self.panel.saved_connection_change_password_field.clear() self.panel.saved_connection_change_password_field.setPlaceholderText( "Change network password" @@ -344,10 +608,6 @@ def setCurrentIndex(self, index: int): f"{self.sdbus_network.get_connection_signal_by_ssid(self.panel.saved_connection_network_name.text())}%" ) - elif index == 3: # Hotspot settings page - self.panel.hotspot_info_ip_field.clear() - self.panel.hotspot_name_input_field.clear() - self.update() return super().setCurrentIndex(index) @@ -386,7 +646,7 @@ def call_network_panel( self.panel.network_list_widget.clear() self.setCurrentIndex(0) - _parent_size= self.parent().size() + _parent_size = self.parent().size() self.setGeometry(0, 0, _parent_size.width(), _parent_size.height()) self.updateGeometry() self.update() diff --git a/BlocksScreen/lib/ui/wifiConnectivityWindow.ui b/BlocksScreen/lib/ui/wifiConnectivityWindow.ui index f5ce5b87..efbc5ba9 100644 --- a/BlocksScreen/lib/ui/wifiConnectivityWindow.ui +++ b/BlocksScreen/lib/ui/wifiConnectivityWindow.ui @@ -1,2295 +1,3187 @@ - - - wifi_stacked_page - - - - 0 - 0 - 800 - 480 - - - - - 0 - 0 - - - - StackedWidget - - - #wifi_stacked_page{ - - - background-image: url(:/background/media/1st_background.png); -} - - - - 0 - - - - - 0 - 0 - - - - - - 0 - 60 - 800 - 480 - - - - - 0 - 0 - - - - - - 0 - 50 - 800 - 360 - - - - - 0 - 0 - - - - QListWidget{background-color: transparent;} - -QLabel{ -color: #ffffff; -} - - - Qt::ScrollBarAlwaysOff - - - 20 - - - QAbstractItemView::ScrollPerPixel - - - true - - - - - - 0 - 0 - 100 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 100 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - SSID - - - Qt::AlignCenter - - - - - - - 100 - 0 - 3 - 50 - - - - Qt::Vertical - - - - - - 0 - 50 - 800 - 3 - - - - Qt::Horizontal - - - - - - - 0 - 0 - 800 - 60 - - - - - 0 - 0 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 350 - 0 - 100 - 60 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 15 - - - - Networks - - - Qt::AlignCenter - - - - - - 0 - 0 - 75 - 60 - - - - - 10 - - - - Back - - - - - - 725 - 0 - 75 - 60 - - - - Scan Again - - - - - - 170 - 20 - 75 - 23 - - - - Toggle wifi - - - - - - 550 - 20 - 75 - 23 - - - - Hotspot page - - - - - - - - - 0 - 80 - 800 - 400 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 50 - 100 - 700 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 100 - 50 - - - - Password - - - Qt::AlignCenter - - - - - - 100 - 0 - 3 - 50 - - - - Qt::Vertical - - - - - - 180 - 0 - 400 - 50 - - - - QLineEdit::Password - - - - - - 650 - 0 - 50 - 50 - - - - view - - - - - - - 340 - 260 - 161 - 51 - - - - Validation - - - - - - 50 - 190 - 700 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 700 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - TextLabel - - - - - - - - 0 - 0 - 800 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 350 - 0 - 100 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 10 - - - - NetworkName - - - Qt::AlignCenter - - - - - - 0 - 0 - 80 - 80 - - - - - 10 - - - - Back - - - - - - - - - 0 - 80 - 800 - 400 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 30 - 30 - 650 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 100 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Security Type - - - Qt::AlignCenter - - - - - - 150 - 0 - 500 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - QFrame::Plain - - - TextLabel - - - Qt::AlignCenter - - - - - - - 30 - 100 - 650 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 100 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Signal Strength - - - Qt::AlignCenter - - - - - - 150 - 0 - 500 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - TextLabel - - - Qt::AlignCenter - - - - - - - 30 - 170 - 650 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 100 - 50 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Change Password - - - Qt::AlignCenter - - - - - - 112 - 9 - 471 - 31 - - - - - - - 600 - 10 - 41 - 23 - - - - view - - - - - - - 30 - 240 - 650 - 50 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - - - 0 - 0 - 800 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 350 - 0 - 100 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - SSID - - - Qt::AlignCenter - - - - - - 0 - 0 - 80 - 80 - - - - Back - - - - - - 720 - 0 - 80 - 80 - - - - Delete - - - - - - - - - 0 - 80 - 800 - 400 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 90 - 30 - 621 - 331 - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 101 - 81 - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Hotspot Name: - - - - - - 270 - 20 - 231 - 31 - - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 111 - 71 - - - - - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 127 - 127 - - - - - - - 170 - 170 - 170 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 127 - 127 - - - - - - - 170 - 170 - 170 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 127 - 127 - 127 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 127 - 127 - - - - - - - 170 - 170 - 170 - - - - - - - 127 - 127 - 127 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 127 - 127 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - Hotspot Password: - - - - - - 272 - 19 - 231 - 41 - - - - QLineEdit::Password - - - - - - 530 - 22 - 51 - 31 - - - - PushButton - - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 10 - 10 - 121 - 81 - - - - - 0 - 1 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Hotspot Machine Ip address - - - - - - 296 - 22 - 201 - 51 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - TextLabel - - - - - - - - - - - 0 - 0 - 800 - 80 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - - 0 - 0 - 80 - 80 - - - - Back - - - - - - 720 - 0 - 80 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - Toggle Hot - - - - - - 350 - 0 - 100 - 80 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 255 - 255 - - - - - - - - - 120 - 120 - 120 - - - - - - - 120 - 120 - 120 - - - - - - - - - 15 - - - - Hotspot - - - Qt::AlignCenter - - - - - - - - - - - - - - + + + wifi_stacked_page + + + + 0 + 0 + 808 + 578 + + + + + 0 + 0 + + + + StackedWidget + + + #wifi_stacked_page{ + + + background-image: url(:/background/media/1st_background.png); +} + + + + 1 + + + + + 0 + 0 + + + + + + -10 + 90 + 381 + 401 + + + + + 0 + 0 + + + + + + 210 + 200 + 161 + 121 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 20 + 10 + 121 + 50 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Security +Type + + + Qt::AlignCenter + + + + + + 10 + 60 + 141 + 41 + + + + + 11 + + + + color: rgb(255, 255, 255); + + + TextLabel + + + Qt::AlignCenter + + + + + + 10 + 50 + 140 + 21 + + + + Qt::Horizontal + + + + + + + 30 + 200 + 161 + 121 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 20 + 10 + 121 + 50 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Signal +Strength + + + Qt::AlignCenter + + + + + + 10 + 65 + 141 + 41 + + + + + 11 + + + + color: rgb(255, 255, 255); + + + TextLabel + + + Qt::AlignCenter + + + + + + 10 + 60 + 140 + 3 + + + + Qt::Horizontal + + + + + + + 30 + 110 + 341 + 71 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 311 + 51 + + + + + 15 + + + + color: rgb(255, 255, 255); + + + TextLabel + + + Qt::AlignCenter + + + + + + -10 + -50 + 361 + 181 + + + + + 17 + + + + color: white + + + No network connection. + +Try connecting to Wi-Fi +or turn on the hotspot +using the buttons on the side. + + + Qt::PlainText + + + false + + + Qt::AlignCenter + + + + + + + 40 + 60 + 321 + 20 + + + + Qt::Horizontal + + + + + + 50 + 30 + 301 + 41 + + + + + 17 + + + + color: rgb(255, 255, 255); + + + TextLabel + + + false + + + Qt::AlignCenter + + + + + + + 0 + -20 + 800 + 91 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 320 + 20 + 161 + 71 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 20 + + + + Networks + + + Qt::AlignCenter + + + + + + 0 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Back + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + 620 + 140 + 111 + 50 + + + + + 0 + 0 + + + + + 160 + 50 + + + + + MS Shell Dlg 2 + 13 + false + PreferAntialias + + + + false + + + true + + + Qt::NoContextMenu + + + Qt::LeftToRight + + + + + + Toggle wifi + + + menu_btn + + + normal + + + :/network/media/btn_icons/no_wifi.svg + + + + + + 390 + 90 + 391 + 161 + + + + + 0 + 0 + + + + + 20 + + + + Wi-Fi + + + + + + 390 + 269 + 391 + 161 + + + + + 20 + + + + Hotspot + + + + + + 620 + 320 + 111 + 51 + + + + + 13 + + + + Toggle HOT + + + + + + 740 + 140 + 41 + 51 + + + + color:white; + + + + + + :/arrow_icons/media/btn_icons/right_arrow.svg + + + true + + + + + true + + + + 740 + 319 + 41 + 51 + + + + Qt::NoContextMenu + + + color:white; + + + + + + :/arrow_icons/media/btn_icons/right_arrow.svg + + + true + + + network_list_table_frame + window_header + wifi_button + Togglewifi + hotspot_button + Togglehot + label_3 + label + + + + + + 0 + -20 + 800 + 91 + + + + + 0 + 0 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 320 + 20 + 161 + 71 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 20 + + + + Wi-fi List + + + Qt::AlignCenter + + + + + + 740 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Reload + + + true + + + icon + + + :/ui/media/btn_icons/refresh.svg + + + + + + 0 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Back + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + 0 + 90 + 801 + 421 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 0 + 0 + 801 + 421 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 120 + 215 + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 120 + 215 + + + + + + + 0 + 0 + 255 + + + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 0 + 0 + + + + + + + 0 + 120 + 215 + + + + + + + 0 + 0 + 255 + + + + + + + + Qt::NoFocus + + + background-color:transparent + + + QFrame::NoFrame + + + QFrame::Sunken + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContents + + + false + + + false + + + Qt::IgnoreAction + + + false + + + QAbstractItemView::NoSelection + + + QAbstractItemView::SelectItems + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + + + + + + + 0 + 79 + 801 + 481 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 20 + 70 + 761 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 100 + 61 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Password + + + Qt::AlignCenter + + + + + + 120 + 20 + 541 + 41 + + + + + 0 + 40 + + + + + + + 680 + 10 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + View + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + 140 + 160 + 511 + 81 + + + + + 0 + 0 + + + + + 16777215 + 81 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + + + Qt::AlignCenter + + + + + true + + + + 510 + 270 + 60 + 60 + + + + + 1 + 1 + + + + + 60 + 60 + + + + + 60 + 60 + + + + + + + a + + + + 16 + 16 + + + + false + + + false + + + true + + + icon + + + :/dialog/media/btn_icons/yes.svg + + + + + true + + + + 220 + 270 + 60 + 60 + + + + + 1 + 1 + + + + + 60 + 60 + + + + + 60 + 60 + + + + + + + a + + + + 16 + 16 + + + + false + + + false + + + true + + + icon + + + :/dialog/media/btn_icons/no.svg + + + + + + + 0 + -21 + 800 + 91 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 50 + 20 + 681 + 71 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 20 + + + + NetworkName + + + Qt::AlignCenter + + + + + + 0 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Back + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + + + -1 + 79 + 801 + 411 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 470 + 180 + 211 + 181 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 49 + 30 + 111 + 50 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Security +Type + + + Qt::AlignCenter + + + + + + 30 + 100 + 151 + 61 + + + + + 20 + + + + color:white + + + TextLabel + + + Qt::AlignCenter + + + + + + 10 + 80 + 191 + 16 + + + + Qt::Horizontal + + + + + + + 140 + 180 + 211 + 181 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 50 + 30 + 111 + 50 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Signal +Strength + + + Qt::AlignCenter + + + + + + 30 + 100 + 151 + 61 + + + + + 20 + + + + color:white + + + TextLabel + + + Qt::AlignCenter + + + + + + 10 + 80 + 191 + 16 + + + + Qt::Horizontal + + + + + + + 20 + 70 + 761 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 10 + 100 + 61 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 15 + + + + Change +Password + + + Qt::AlignCenter + + + + + + 120 + 20 + 541 + 41 + + + + + 0 + 40 + + + + + + + 680 + 10 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + View + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + + 0 + -21 + 800 + 91 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 70 + 20 + 651 + 71 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 20 + + + + SSID + + + Qt::AlignCenter + + + + + + 0 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Back + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + 730 + 20 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Delete + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/indf_svg.svg + + + + + + + + + 0 + -30 + 800 + 101 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 320 + 30 + 171 + 71 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + 20 + + + + Hotspot + + + Qt::AlignCenter + + + + + + 0 + 30 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + Back + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + 10 + 80 + 781 + 371 + + + + + + + + 16777215 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 30 + 150 + 21 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 127 + 127 + + + + + + + 170 + 170 + 170 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 127 + 127 + + + + + + + 170 + 170 + 170 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + 127 + 127 + 127 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 127 + 127 + + + + + + + 170 + 170 + 170 + + + + + + + 127 + 127 + 127 + + + + + + + 255 + 255 + 255 + + + + + + + 127 + 127 + 127 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + 0 + 0 + 0 + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 220 + + + + + + + 0 + 0 + 0 + + + + + + + + + Momcake + 10 + + + + Hotspot Password: + + + Qt::AlignCenter + + + + + + 160 + 20 + 521 + 40 + + + + + 0 + 0 + + + + + 120 + 40 + + + + + 16777215 + 40 + + + + QLineEdit::Password + + + + + + 700 + 10 + 60 + 60 + + + + + 60 + 60 + + + + + 60 + 60 + + + + View + + + true + + + back_btn + + + icon + + + :/ui/media/btn_icons/back.svg + + + + + + + + + 16777215 + 81 + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + 10 + 30 + 150 + 21 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 255 + 255 + 255 + + + + + + + 255 + 255 + 255 + + + + + + + + + 120 + 120 + 120 + + + + + + + 120 + 120 + 120 + + + + + + + + + Momcake + 10 + + + + Hotspot Name: + + + Qt::AlignCenter + + + + + + 160 + 20 + 521 + 40 + + + + + 0 + 0 + + + + + 120 + 40 + + + + + 16777215 + 40 + + + + QLineEdit::Password + + + + + + + + + + + IconButton + QPushButton +
lib.utils.icon_button
+
+ + BlocksCustomFrame + QFrame +
lib.utils.blocks_frame
+ 1 +
+ + ToggleAnimatedButton + QPushButton +
lib.utils.toggleAnimatedButton
+
+ + ListCustomButton + QPushButton +
lib.utils.list_button
+
+ + BlocksCustomLinEdit + QLineEdit +
lib.utils.blocks_linedit
+
+
+ + + + + + + + +
diff --git a/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py b/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py index 07fb7e88..81bd7688 100644 --- a/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py +++ b/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py @@ -12,7 +12,7 @@ class Ui_wifi_stacked_page(object): def setupUi(self, wifi_stacked_page): wifi_stacked_page.setObjectName("wifi_stacked_page") - wifi_stacked_page.resize(800, 480) + wifi_stacked_page.resize(808, 578) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -31,38 +31,21 @@ def setupUi(self, wifi_stacked_page): sizePolicy.setHeightForWidth(self.network_list_page.sizePolicy().hasHeightForWidth()) self.network_list_page.setSizePolicy(sizePolicy) self.network_list_page.setObjectName("network_list_page") - self.network_list_table_widget = QtWidgets.QWidget(parent=self.network_list_page) - self.network_list_table_widget.setGeometry(QtCore.QRect(0, 60, 800, 480)) + self.network_list_table_frame = BlocksCustomFrame(parent=self.network_list_page) + self.network_list_table_frame.setGeometry(QtCore.QRect(-10, 90, 381, 401)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.network_list_table_widget.sizePolicy().hasHeightForWidth()) - self.network_list_table_widget.setSizePolicy(sizePolicy) - self.network_list_table_widget.setObjectName("network_list_table_widget") - self.network_list_widget = QtWidgets.QListWidget(parent=self.network_list_table_widget) - self.network_list_widget.setGeometry(QtCore.QRect(0, 50, 800, 360)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.network_list_widget.sizePolicy().hasHeightForWidth()) - self.network_list_widget.setSizePolicy(sizePolicy) - self.network_list_widget.setStyleSheet("QListWidget{background-color: transparent;}\n" -"\n" -"QLabel{\n" -"color: #ffffff;\n" -"}") - self.network_list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) - self.network_list_widget.setAutoScrollMargin(20) - self.network_list_widget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) - self.network_list_widget.setUniformItemSizes(True) - self.network_list_widget.setObjectName("network_list_widget") - self.network_list_table_header_frame = QtWidgets.QFrame(parent=self.network_list_table_widget) - self.network_list_table_header_frame.setGeometry(QtCore.QRect(0, 0, 100, 50)) - self.network_list_table_header_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.network_list_table_header_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.network_list_table_header_frame.setObjectName("network_list_table_header_frame") - self.network_list_table_header_label = QtWidgets.QLabel(parent=self.network_list_table_header_frame) - self.network_list_table_header_label.setGeometry(QtCore.QRect(0, 0, 100, 50)) + sizePolicy.setHeightForWidth(self.network_list_table_frame.sizePolicy().hasHeightForWidth()) + self.network_list_table_frame.setSizePolicy(sizePolicy) + self.network_list_table_frame.setObjectName("network_list_table_frame") + self.stregth_frame = BlocksCustomFrame(parent=self.network_list_table_frame) + self.stregth_frame.setGeometry(QtCore.QRect(210, 200, 161, 121)) + self.stregth_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.stregth_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.stregth_frame.setObjectName("stregth_frame") + self.netlist_security_label = QtWidgets.QLabel(parent=self.stregth_frame) + self.netlist_security_label.setGeometry(QtCore.QRect(20, 10, 121, 50)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -82,21 +65,109 @@ def setupUi(self, wifi_stacked_page): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.network_list_table_header_label.setPalette(palette) - self.network_list_table_header_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.network_list_table_header_label.setObjectName("network_list_table_header_label") - self.line = QtWidgets.QFrame(parent=self.network_list_table_widget) - self.line.setGeometry(QtCore.QRect(100, 0, 3, 50)) - self.line.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line.setObjectName("line") - self.line_2 = QtWidgets.QFrame(parent=self.network_list_table_widget) - self.line_2.setGeometry(QtCore.QRect(0, 50, 800, 3)) + self.netlist_security_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.netlist_security_label.setFont(font) + self.netlist_security_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_security_label.setObjectName("netlist_security_label") + self.netlist_security = QtWidgets.QLabel(parent=self.stregth_frame) + self.netlist_security.setGeometry(QtCore.QRect(10, 60, 141, 41)) + font = QtGui.QFont() + font.setPointSize(11) + self.netlist_security.setFont(font) + self.netlist_security.setStyleSheet("color: rgb(255, 255, 255);") + self.netlist_security.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_security.setObjectName("netlist_security") + self.line_3 = QtWidgets.QFrame(parent=self.stregth_frame) + self.line_3.setGeometry(QtCore.QRect(10, 50, 140, 21)) + self.line_3.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_3.setObjectName("line_3") + self.signal_frame = BlocksCustomFrame(parent=self.network_list_table_frame) + self.signal_frame.setGeometry(QtCore.QRect(30, 200, 161, 121)) + self.signal_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.signal_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.signal_frame.setObjectName("signal_frame") + self.netlist_strength_label = QtWidgets.QLabel(parent=self.signal_frame) + self.netlist_strength_label.setGeometry(QtCore.QRect(20, 10, 121, 50)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) + self.netlist_strength_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.netlist_strength_label.setFont(font) + self.netlist_strength_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_strength_label.setObjectName("netlist_strength_label") + self.netlist_strength = QtWidgets.QLabel(parent=self.signal_frame) + self.netlist_strength.setGeometry(QtCore.QRect(10, 65, 141, 41)) + font = QtGui.QFont() + font.setPointSize(11) + self.netlist_strength.setFont(font) + self.netlist_strength.setStyleSheet("color: rgb(255, 255, 255);") + self.netlist_strength.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_strength.setObjectName("netlist_strength") + self.line_2 = QtWidgets.QFrame(parent=self.signal_frame) + self.line_2.setGeometry(QtCore.QRect(10, 60, 140, 3)) self.line_2.setFrameShape(QtWidgets.QFrame.Shape.HLine) self.line_2.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) self.line_2.setObjectName("line_2") - self.window_header = QtWidgets.QFrame(parent=self.network_list_page) - self.window_header.setGeometry(QtCore.QRect(0, 0, 800, 60)) + self.ip_frame = BlocksCustomFrame(parent=self.network_list_table_frame) + self.ip_frame.setGeometry(QtCore.QRect(30, 110, 341, 71)) + self.ip_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.ip_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.ip_frame.setObjectName("ip_frame") + self.netlist_ip = QtWidgets.QLabel(parent=self.ip_frame) + self.netlist_ip.setGeometry(QtCore.QRect(10, 10, 311, 51)) + font = QtGui.QFont() + font.setPointSize(15) + self.netlist_ip.setFont(font) + self.netlist_ip.setStyleSheet("color: rgb(255, 255, 255);") + self.netlist_ip.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_ip.setObjectName("netlist_ip") + self.label_2 = QtWidgets.QLabel(parent=self.ip_frame) + self.label_2.setGeometry(QtCore.QRect(-10, -50, 361, 181)) + font = QtGui.QFont() + font.setPointSize(17) + self.label_2.setFont(font) + self.label_2.setStyleSheet("color: white") + self.label_2.setTextFormat(QtCore.Qt.TextFormat.PlainText) + self.label_2.setScaledContents(False) + self.label_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label_2.setObjectName("label_2") + self.line = QtWidgets.QFrame(parent=self.network_list_table_frame) + self.line.setGeometry(QtCore.QRect(40, 60, 321, 20)) + self.line.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line.setObjectName("line") + self.netlist_ssuid = QtWidgets.QLabel(parent=self.network_list_table_frame) + self.netlist_ssuid.setGeometry(QtCore.QRect(50, 30, 301, 41)) + font = QtGui.QFont() + font.setPointSize(17) + self.netlist_ssuid.setFont(font) + self.netlist_ssuid.setStyleSheet("color: rgb(255, 255, 255);") + self.netlist_ssuid.setScaledContents(False) + self.netlist_ssuid.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.netlist_ssuid.setObjectName("netlist_ssuid") + self.window_header = BlocksCustomFrame(parent=self.network_list_page) + self.window_header.setGeometry(QtCore.QRect(0, -20, 800, 91)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -105,8 +176,8 @@ def setupUi(self, wifi_stacked_page): self.window_header.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.window_header.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.window_header.setObjectName("window_header") - self.wifi_main_title = QtWidgets.QLabel(parent=self.window_header) - self.wifi_main_title.setGeometry(QtCore.QRect(350, 0, 100, 60)) + self.network_main_title = QtWidgets.QLabel(parent=self.window_header) + self.network_main_title.setGeometry(QtCore.QRect(320, 20, 161, 71)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -126,66 +197,266 @@ def setupUi(self, wifi_stacked_page): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.wifi_main_title.setPalette(palette) + self.network_main_title.setPalette(palette) font = QtGui.QFont() - font.setPointSize(15) - self.wifi_main_title.setFont(font) - self.wifi_main_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.wifi_main_title.setObjectName("wifi_main_title") - self.wifi_backButton = QtWidgets.QPushButton(parent=self.window_header) - self.wifi_backButton.setGeometry(QtCore.QRect(0, 0, 75, 60)) + font.setPointSize(20) + self.network_main_title.setFont(font) + self.network_main_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.network_main_title.setObjectName("network_main_title") + self.network_backButton = IconButton(parent=self.window_header) + self.network_backButton.setGeometry(QtCore.QRect(0, 20, 60, 60)) + self.network_backButton.setMinimumSize(QtCore.QSize(60, 60)) + self.network_backButton.setMaximumSize(QtCore.QSize(60, 60)) + self.network_backButton.setFlat(True) + self.network_backButton.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.network_backButton.setObjectName("network_backButton") + self.Togglewifi = ToggleAnimatedButton(parent=self.network_list_page) + self.Togglewifi.setGeometry(QtCore.QRect(620, 140, 111, 50)) + self.Togglewifi.setMinimumSize(QtCore.QSize(0, 0)) + self.Togglewifi.setMaximumSize(QtCore.QSize(160, 50)) font = QtGui.QFont() - font.setPointSize(10) - self.wifi_backButton.setFont(font) - self.wifi_backButton.setObjectName("wifi_backButton") - self.rescan_button = QtWidgets.QPushButton(parent=self.window_header) - self.rescan_button.setGeometry(QtCore.QRect(725, 0, 75, 60)) - self.rescan_button.setObjectName("rescan_button") - self.wifi_toggle_button = QtWidgets.QPushButton(parent=self.window_header) - self.wifi_toggle_button.setGeometry(QtCore.QRect(170, 20, 75, 23)) - self.wifi_toggle_button.setObjectName("wifi_toggle_button") - self.call_hotspot_button = QtWidgets.QPushButton(parent=self.window_header) - self.call_hotspot_button.setGeometry(QtCore.QRect(550, 20, 75, 23)) - self.call_hotspot_button.setObjectName("call_hotspot_button") + font.setFamily("MS Shell Dlg 2") + font.setPointSize(13) + font.setItalic(False) + font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + self.Togglewifi.setFont(font) + self.Togglewifi.setMouseTracking(False) + self.Togglewifi.setTabletTracking(True) + self.Togglewifi.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) + self.Togglewifi.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.Togglewifi.setStyleSheet("") + self.Togglewifi.setProperty("icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/no_wifi.svg")) + self.Togglewifi.setObjectName("Togglewifi") + self.wifi_button = ListCustomButton(parent=self.network_list_page) + self.wifi_button.setGeometry(QtCore.QRect(390, 90, 391, 161)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.wifi_button.sizePolicy().hasHeightForWidth()) + self.wifi_button.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setPointSize(20) + self.wifi_button.setFont(font) + self.wifi_button.setObjectName("wifi_button") + self.hotspot_button = ListCustomButton(parent=self.network_list_page) + self.hotspot_button.setGeometry(QtCore.QRect(390, 269, 391, 161)) + font = QtGui.QFont() + font.setPointSize(20) + self.hotspot_button.setFont(font) + self.hotspot_button.setObjectName("hotspot_button") + self.Togglehot = ToggleAnimatedButton(parent=self.network_list_page) + self.Togglehot.setGeometry(QtCore.QRect(620, 320, 111, 51)) + font = QtGui.QFont() + font.setPointSize(13) + self.Togglehot.setFont(font) + self.Togglehot.setObjectName("Togglehot") + self.label = QtWidgets.QLabel(parent=self.network_list_page) + self.label.setGeometry(QtCore.QRect(740, 140, 41, 51)) + self.label.setStyleSheet("color:white;") + self.label.setText("") + self.label.setPixmap(QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg")) + self.label.setScaledContents(True) + self.label.setObjectName("label") + self.label_3 = QtWidgets.QLabel(parent=self.network_list_page) + self.label_3.setEnabled(True) + self.label_3.setGeometry(QtCore.QRect(740, 319, 41, 51)) + self.label_3.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.NoContextMenu) + self.label_3.setStyleSheet("color:white;") + self.label_3.setText("") + self.label_3.setPixmap(QtGui.QPixmap(":/arrow_icons/media/btn_icons/right_arrow.svg")) + self.label_3.setScaledContents(True) + self.label_3.setObjectName("label_3") + self.network_list_table_frame.raise_() + self.window_header.raise_() + self.wifi_button.raise_() + self.Togglewifi.raise_() + self.hotspot_button.raise_() + self.Togglehot.raise_() + self.label_3.raise_() + self.label.raise_() wifi_stacked_page.addWidget(self.network_list_page) + self.wifi_page = QtWidgets.QWidget() + self.wifi_page.setObjectName("wifi_page") + self.window_header_2 = BlocksCustomFrame(parent=self.wifi_page) + self.window_header_2.setGeometry(QtCore.QRect(0, -20, 800, 91)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.window_header_2.sizePolicy().hasHeightForWidth()) + self.window_header_2.setSizePolicy(sizePolicy) + self.window_header_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.window_header_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.window_header_2.setObjectName("window_header_2") + self.network_main_title_2 = QtWidgets.QLabel(parent=self.window_header_2) + self.network_main_title_2.setGeometry(QtCore.QRect(320, 20, 161, 71)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) + self.network_main_title_2.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(20) + self.network_main_title_2.setFont(font) + self.network_main_title_2.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.network_main_title_2.setObjectName("network_main_title_2") + self.rescan_button = IconButton(parent=self.window_header_2) + self.rescan_button.setGeometry(QtCore.QRect(740, 20, 60, 60)) + self.rescan_button.setMinimumSize(QtCore.QSize(60, 60)) + self.rescan_button.setMaximumSize(QtCore.QSize(60, 60)) + self.rescan_button.setFlat(True) + self.rescan_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/refresh.svg")) + self.rescan_button.setObjectName("rescan_button") + self.wifi_backButton = IconButton(parent=self.window_header_2) + self.wifi_backButton.setGeometry(QtCore.QRect(0, 20, 60, 60)) + self.wifi_backButton.setMinimumSize(QtCore.QSize(60, 60)) + self.wifi_backButton.setMaximumSize(QtCore.QSize(60, 60)) + self.wifi_backButton.setFlat(True) + self.wifi_backButton.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.wifi_backButton.setObjectName("wifi_backButton") + self.frame_3 = BlocksCustomFrame(parent=self.wifi_page) + self.frame_3.setGeometry(QtCore.QRect(0, 90, 801, 421)) + self.frame_3.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.frame_3.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.frame_3.setObjectName("frame_3") + self.network_list_widget = QtWidgets.QListWidget(parent=self.frame_3) + self.network_list_widget.setGeometry(QtCore.QRect(0, 0, 801, 421)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Button, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Window, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Link, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Button, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Window, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Link, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Button, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.NoBrush) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Base, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Window, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 120, 215, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Highlight, brush) + brush = QtGui.QBrush(QtGui.QColor(0, 0, 255, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Link, brush) + self.network_list_widget.setPalette(palette) + self.network_list_widget.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.network_list_widget.setStyleSheet("background-color:transparent") + self.network_list_widget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.network_list_widget.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.network_list_widget.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.network_list_widget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff) + self.network_list_widget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents) + self.network_list_widget.setAutoScroll(False) + self.network_list_widget.setProperty("showDropIndicator", False) + self.network_list_widget.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) + self.network_list_widget.setAlternatingRowColors(False) + self.network_list_widget.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.NoSelection) + self.network_list_widget.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems) + self.network_list_widget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) + self.network_list_widget.setHorizontalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel) + self.network_list_widget.setObjectName("network_list_widget") + wifi_stacked_page.addWidget(self.wifi_page) self.add_network_page = QtWidgets.QWidget() self.add_network_page.setObjectName("add_network_page") - self.add_network_page_options = QtWidgets.QFrame(parent=self.add_network_page) - self.add_network_page_options.setGeometry(QtCore.QRect(0, 80, 800, 400)) + self.add_network_page_options = BlocksCustomFrame(parent=self.add_network_page) + self.add_network_page_options.setGeometry(QtCore.QRect(0, 79, 801, 481)) self.add_network_page_options.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.add_network_page_options.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.add_network_page_options.setObjectName("add_network_page_options") - self.add_network_frame = QtWidgets.QFrame(parent=self.add_network_page_options) - self.add_network_frame.setGeometry(QtCore.QRect(50, 100, 700, 50)) - self.add_network_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.add_network_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.add_network_frame.setObjectName("add_network_frame") - self.add_network_password_label = QtWidgets.QLabel(parent=self.add_network_frame) - self.add_network_password_label.setGeometry(QtCore.QRect(0, 0, 100, 50)) + self.saved_connection_change_password_frame_2 = BlocksCustomFrame(parent=self.add_network_page_options) + self.saved_connection_change_password_frame_2.setGeometry(QtCore.QRect(20, 70, 761, 81)) + self.saved_connection_change_password_frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.saved_connection_change_password_frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.saved_connection_change_password_frame_2.setObjectName("saved_connection_change_password_frame_2") + self.add_network_password_label = QtWidgets.QLabel(parent=self.saved_connection_change_password_frame_2) + self.add_network_password_label.setGeometry(QtCore.QRect(10, 10, 100, 61)) + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) + brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) + self.add_network_password_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.add_network_password_label.setFont(font) self.add_network_password_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.add_network_password_label.setObjectName("add_network_password_label") - self.line_3 = QtWidgets.QFrame(parent=self.add_network_frame) - self.line_3.setGeometry(QtCore.QRect(100, 0, 3, 50)) - self.line_3.setFrameShape(QtWidgets.QFrame.Shape.VLine) - self.line_3.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) - self.line_3.setObjectName("line_3") - self.add_network_password_field = QtWidgets.QLineEdit(parent=self.add_network_frame) - self.add_network_password_field.setGeometry(QtCore.QRect(180, 0, 400, 50)) - self.add_network_password_field.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) + self.add_network_password_field = BlocksCustomLinEdit(parent=self.saved_connection_change_password_frame_2) + self.add_network_password_field.setGeometry(QtCore.QRect(120, 20, 541, 41)) + self.add_network_password_field.setMinimumSize(QtCore.QSize(0, 40)) self.add_network_password_field.setObjectName("add_network_password_field") - self.add_network_password_view = QtWidgets.QPushButton(parent=self.add_network_frame) - self.add_network_password_view.setGeometry(QtCore.QRect(650, 0, 50, 50)) + self.add_network_password_view = IconButton(parent=self.saved_connection_change_password_frame_2) + self.add_network_password_view.setGeometry(QtCore.QRect(680, 10, 60, 60)) + self.add_network_password_view.setMinimumSize(QtCore.QSize(60, 60)) + self.add_network_password_view.setMaximumSize(QtCore.QSize(60, 60)) + self.add_network_password_view.setFlat(True) + self.add_network_password_view.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.add_network_password_view.setObjectName("add_network_password_view") - self.add_network_validation_button = QtWidgets.QPushButton(parent=self.add_network_page_options) - self.add_network_validation_button.setGeometry(QtCore.QRect(340, 260, 161, 51)) - self.add_network_validation_button.setObjectName("add_network_validation_button") - self.add_network_messages_frame = QtWidgets.QFrame(parent=self.add_network_page_options) - self.add_network_messages_frame.setGeometry(QtCore.QRect(50, 190, 700, 50)) - self.add_network_messages_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.add_network_messages_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.add_network_messages_frame.setObjectName("add_network_messages_frame") - self.add_network_message_label = QtWidgets.QLabel(parent=self.add_network_messages_frame) - self.add_network_message_label.setGeometry(QtCore.QRect(0, 0, 700, 50)) + self.add_network_message_label = QtWidgets.QLabel(parent=self.add_network_page_options) + self.add_network_message_label.setGeometry(QtCore.QRect(140, 160, 511, 81)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.add_network_message_label.sizePolicy().hasHeightForWidth()) + self.add_network_message_label.setSizePolicy(sizePolicy) + self.add_network_message_label.setMaximumSize(QtCore.QSize(16777215, 81)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -206,14 +477,50 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.add_network_message_label.setPalette(palette) + self.add_network_message_label.setText("") + self.add_network_message_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.add_network_message_label.setObjectName("add_network_message_label") - self.add_network_page_header = QtWidgets.QFrame(parent=self.add_network_page) - self.add_network_page_header.setGeometry(QtCore.QRect(0, 0, 800, 80)) + self.add_network_validation_button = IconButton(parent=self.add_network_page_options) + self.add_network_validation_button.setEnabled(True) + self.add_network_validation_button.setGeometry(QtCore.QRect(510, 270, 60, 60)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.add_network_validation_button.sizePolicy().hasHeightForWidth()) + self.add_network_validation_button.setSizePolicy(sizePolicy) + self.add_network_validation_button.setMinimumSize(QtCore.QSize(60, 60)) + self.add_network_validation_button.setMaximumSize(QtCore.QSize(60, 60)) + self.add_network_validation_button.setStyleSheet("") + self.add_network_validation_button.setIconSize(QtCore.QSize(16, 16)) + self.add_network_validation_button.setCheckable(False) + self.add_network_validation_button.setChecked(False) + self.add_network_validation_button.setFlat(True) + self.add_network_validation_button.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg")) + self.add_network_validation_button.setObjectName("add_network_validation_button") + self.cancel_network_validation_button = IconButton(parent=self.add_network_page_options) + self.cancel_network_validation_button.setEnabled(True) + self.cancel_network_validation_button.setGeometry(QtCore.QRect(220, 270, 60, 60)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) + sizePolicy.setHeightForWidth(self.cancel_network_validation_button.sizePolicy().hasHeightForWidth()) + self.cancel_network_validation_button.setSizePolicy(sizePolicy) + self.cancel_network_validation_button.setMinimumSize(QtCore.QSize(60, 60)) + self.cancel_network_validation_button.setMaximumSize(QtCore.QSize(60, 60)) + self.cancel_network_validation_button.setStyleSheet("") + self.cancel_network_validation_button.setIconSize(QtCore.QSize(16, 16)) + self.cancel_network_validation_button.setCheckable(False) + self.cancel_network_validation_button.setChecked(False) + self.cancel_network_validation_button.setFlat(True) + self.cancel_network_validation_button.setProperty("icon_pixmap", QtGui.QPixmap(":/dialog/media/btn_icons/no.svg")) + self.cancel_network_validation_button.setObjectName("cancel_network_validation_button") + self.add_network_page_header = BlocksCustomFrame(parent=self.add_network_page) + self.add_network_page_header.setGeometry(QtCore.QRect(0, -21, 800, 91)) self.add_network_page_header.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.add_network_page_header.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.add_network_page_header.setObjectName("add_network_page_header") self.add_network_network_label = QtWidgets.QLabel(parent=self.add_network_page_header) - self.add_network_network_label.setGeometry(QtCore.QRect(350, 0, 100, 80)) + self.add_network_network_label.setGeometry(QtCore.QRect(50, 20, 681, 71)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -235,31 +542,32 @@ def setupUi(self, wifi_stacked_page): palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.add_network_network_label.setPalette(palette) font = QtGui.QFont() - font.setPointSize(10) + font.setPointSize(20) self.add_network_network_label.setFont(font) self.add_network_network_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.add_network_network_label.setObjectName("add_network_network_label") - self.add_network_page_backButton = QtWidgets.QPushButton(parent=self.add_network_page_header) - self.add_network_page_backButton.setGeometry(QtCore.QRect(0, 0, 80, 80)) - font = QtGui.QFont() - font.setPointSize(10) - self.add_network_page_backButton.setFont(font) + self.add_network_page_backButton = IconButton(parent=self.add_network_page_header) + self.add_network_page_backButton.setGeometry(QtCore.QRect(0, 20, 60, 60)) + self.add_network_page_backButton.setMinimumSize(QtCore.QSize(60, 60)) + self.add_network_page_backButton.setMaximumSize(QtCore.QSize(60, 60)) + self.add_network_page_backButton.setFlat(True) + self.add_network_page_backButton.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.add_network_page_backButton.setObjectName("add_network_page_backButton") wifi_stacked_page.addWidget(self.add_network_page) self.saved_connection_page = QtWidgets.QWidget() self.saved_connection_page.setObjectName("saved_connection_page") - self.network_properties = QtWidgets.QFrame(parent=self.saved_connection_page) - self.network_properties.setGeometry(QtCore.QRect(0, 80, 800, 400)) + self.network_properties = BlocksCustomFrame(parent=self.saved_connection_page) + self.network_properties.setGeometry(QtCore.QRect(-1, 79, 801, 411)) self.network_properties.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.network_properties.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.network_properties.setObjectName("network_properties") - self.saved_connection_security_type_frame = QtWidgets.QFrame(parent=self.network_properties) - self.saved_connection_security_type_frame.setGeometry(QtCore.QRect(30, 30, 650, 50)) + self.saved_connection_security_type_frame = BlocksCustomFrame(parent=self.network_properties) + self.saved_connection_security_type_frame.setGeometry(QtCore.QRect(470, 180, 211, 181)) self.saved_connection_security_type_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.saved_connection_security_type_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.saved_connection_security_type_frame.setObjectName("saved_connection_security_type_frame") self.saved_connection_security_type_label = QtWidgets.QLabel(parent=self.saved_connection_security_type_frame) - self.saved_connection_security_type_label.setGeometry(QtCore.QRect(0, 0, 100, 50)) + self.saved_connection_security_type_label.setGeometry(QtCore.QRect(49, 30, 111, 50)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -280,40 +588,31 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.saved_connection_security_type_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.saved_connection_security_type_label.setFont(font) self.saved_connection_security_type_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.saved_connection_security_type_label.setObjectName("saved_connection_security_type_label") self.saved_connection_security_type_info_label = QtWidgets.QLabel(parent=self.saved_connection_security_type_frame) - self.saved_connection_security_type_info_label.setGeometry(QtCore.QRect(150, 0, 500, 50)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.saved_connection_security_type_info_label.setPalette(palette) - self.saved_connection_security_type_info_label.setFrameShadow(QtWidgets.QFrame.Shadow.Plain) + self.saved_connection_security_type_info_label.setGeometry(QtCore.QRect(30, 100, 151, 61)) + font = QtGui.QFont() + font.setPointSize(20) + self.saved_connection_security_type_info_label.setFont(font) + self.saved_connection_security_type_info_label.setStyleSheet("color:white") self.saved_connection_security_type_info_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.saved_connection_security_type_info_label.setObjectName("saved_connection_security_type_info_label") - self.saved_connection_signal_strength_frame = QtWidgets.QFrame(parent=self.network_properties) - self.saved_connection_signal_strength_frame.setGeometry(QtCore.QRect(30, 100, 650, 50)) + self.line_5 = QtWidgets.QFrame(parent=self.saved_connection_security_type_frame) + self.line_5.setGeometry(QtCore.QRect(10, 80, 191, 16)) + self.line_5.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_5.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_5.setObjectName("line_5") + self.saved_connection_signal_strength_frame = BlocksCustomFrame(parent=self.network_properties) + self.saved_connection_signal_strength_frame.setGeometry(QtCore.QRect(140, 180, 211, 181)) self.saved_connection_signal_strength_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.saved_connection_signal_strength_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.saved_connection_signal_strength_frame.setObjectName("saved_connection_signal_strength_frame") self.sabed_connection_signal_strength_label = QtWidgets.QLabel(parent=self.saved_connection_signal_strength_frame) - self.sabed_connection_signal_strength_label.setGeometry(QtCore.QRect(0, 0, 100, 50)) + self.sabed_connection_signal_strength_label.setGeometry(QtCore.QRect(50, 30, 111, 50)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -334,39 +633,31 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.sabed_connection_signal_strength_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.sabed_connection_signal_strength_label.setFont(font) self.sabed_connection_signal_strength_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.sabed_connection_signal_strength_label.setObjectName("sabed_connection_signal_strength_label") self.saved_connection_signal_strength_info_frame = QtWidgets.QLabel(parent=self.saved_connection_signal_strength_frame) - self.saved_connection_signal_strength_info_frame.setGeometry(QtCore.QRect(150, 0, 500, 50)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.saved_connection_signal_strength_info_frame.setPalette(palette) + self.saved_connection_signal_strength_info_frame.setGeometry(QtCore.QRect(30, 100, 151, 61)) + font = QtGui.QFont() + font.setPointSize(20) + self.saved_connection_signal_strength_info_frame.setFont(font) + self.saved_connection_signal_strength_info_frame.setStyleSheet("color:white") self.saved_connection_signal_strength_info_frame.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.saved_connection_signal_strength_info_frame.setObjectName("saved_connection_signal_strength_info_frame") - self.saved_connection_change_password_frame = QtWidgets.QFrame(parent=self.network_properties) - self.saved_connection_change_password_frame.setGeometry(QtCore.QRect(30, 170, 650, 50)) + self.line_4 = QtWidgets.QFrame(parent=self.saved_connection_signal_strength_frame) + self.line_4.setGeometry(QtCore.QRect(10, 80, 191, 16)) + self.line_4.setFrameShape(QtWidgets.QFrame.Shape.HLine) + self.line_4.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.line_4.setObjectName("line_4") + self.saved_connection_change_password_frame = BlocksCustomFrame(parent=self.network_properties) + self.saved_connection_change_password_frame.setGeometry(QtCore.QRect(20, 70, 761, 81)) self.saved_connection_change_password_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.saved_connection_change_password_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.saved_connection_change_password_frame.setObjectName("saved_connection_change_password_frame") self.saved_connection_change_password_label = QtWidgets.QLabel(parent=self.saved_connection_change_password_frame) - self.saved_connection_change_password_label.setGeometry(QtCore.QRect(0, 0, 100, 50)) + self.saved_connection_change_password_label.setGeometry(QtCore.QRect(10, 10, 100, 61)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -387,26 +678,29 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.saved_connection_change_password_label.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(15) + self.saved_connection_change_password_label.setFont(font) self.saved_connection_change_password_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.saved_connection_change_password_label.setObjectName("saved_connection_change_password_label") - self.saved_connection_change_password_field = QtWidgets.QLineEdit(parent=self.saved_connection_change_password_frame) - self.saved_connection_change_password_field.setGeometry(QtCore.QRect(112, 9, 471, 31)) + self.saved_connection_change_password_field = BlocksCustomLinEdit(parent=self.saved_connection_change_password_frame) + self.saved_connection_change_password_field.setGeometry(QtCore.QRect(120, 20, 541, 41)) + self.saved_connection_change_password_field.setMinimumSize(QtCore.QSize(0, 40)) self.saved_connection_change_password_field.setObjectName("saved_connection_change_password_field") - self.saved_connection_change_password_view = QtWidgets.QPushButton(parent=self.saved_connection_change_password_frame) - self.saved_connection_change_password_view.setGeometry(QtCore.QRect(600, 10, 41, 23)) + self.saved_connection_change_password_view = IconButton(parent=self.saved_connection_change_password_frame) + self.saved_connection_change_password_view.setGeometry(QtCore.QRect(680, 10, 60, 60)) + self.saved_connection_change_password_view.setMinimumSize(QtCore.QSize(60, 60)) + self.saved_connection_change_password_view.setMaximumSize(QtCore.QSize(60, 60)) + self.saved_connection_change_password_view.setFlat(True) + self.saved_connection_change_password_view.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.saved_connection_change_password_view.setObjectName("saved_connection_change_password_view") - self.field_option_4 = QtWidgets.QFrame(parent=self.network_properties) - self.field_option_4.setGeometry(QtCore.QRect(30, 240, 650, 50)) - self.field_option_4.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.field_option_4.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.field_option_4.setObjectName("field_option_4") - self.saved_connection_page_header = QtWidgets.QFrame(parent=self.saved_connection_page) - self.saved_connection_page_header.setGeometry(QtCore.QRect(0, 0, 800, 80)) + self.saved_connection_page_header = BlocksCustomFrame(parent=self.saved_connection_page) + self.saved_connection_page_header.setGeometry(QtCore.QRect(0, -21, 800, 91)) self.saved_connection_page_header.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) self.saved_connection_page_header.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) self.saved_connection_page_header.setObjectName("saved_connection_page_header") self.saved_connection_network_name = QtWidgets.QLabel(parent=self.saved_connection_page_header) - self.saved_connection_network_name.setGeometry(QtCore.QRect(350, 0, 100, 80)) + self.saved_connection_network_name.setGeometry(QtCore.QRect(70, 20, 651, 71)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -427,39 +721,35 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) self.saved_connection_network_name.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(20) + self.saved_connection_network_name.setFont(font) self.saved_connection_network_name.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.saved_connection_network_name.setObjectName("saved_connection_network_name") - self.saved_connection_back_button = QtWidgets.QPushButton(parent=self.saved_connection_page_header) - self.saved_connection_back_button.setGeometry(QtCore.QRect(0, 0, 80, 80)) + self.saved_connection_back_button = IconButton(parent=self.saved_connection_page_header) + self.saved_connection_back_button.setGeometry(QtCore.QRect(0, 20, 60, 60)) + self.saved_connection_back_button.setMinimumSize(QtCore.QSize(60, 60)) + self.saved_connection_back_button.setMaximumSize(QtCore.QSize(60, 60)) + self.saved_connection_back_button.setFlat(True) + self.saved_connection_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.saved_connection_back_button.setObjectName("saved_connection_back_button") - self.saved_connection_delete_network_button = QtWidgets.QPushButton(parent=self.saved_connection_page_header) - self.saved_connection_delete_network_button.setGeometry(QtCore.QRect(720, 0, 80, 80)) + self.saved_connection_delete_network_button = IconButton(parent=self.saved_connection_page_header) + self.saved_connection_delete_network_button.setGeometry(QtCore.QRect(730, 20, 60, 60)) + self.saved_connection_delete_network_button.setMinimumSize(QtCore.QSize(60, 60)) + self.saved_connection_delete_network_button.setMaximumSize(QtCore.QSize(60, 60)) + self.saved_connection_delete_network_button.setFlat(True) + self.saved_connection_delete_network_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/indf_svg.svg")) self.saved_connection_delete_network_button.setObjectName("saved_connection_delete_network_button") wifi_stacked_page.addWidget(self.saved_connection_page) self.hotspot_page = QtWidgets.QWidget() self.hotspot_page.setObjectName("hotspot_page") - self.hotspot_main_frame = QtWidgets.QFrame(parent=self.hotspot_page) - self.hotspot_main_frame.setGeometry(QtCore.QRect(0, 80, 800, 400)) - self.hotspot_main_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.hotspot_main_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.hotspot_main_frame.setObjectName("hotspot_main_frame") - self.verticalLayoutWidget = QtWidgets.QWidget(parent=self.hotspot_main_frame) - self.verticalLayoutWidget.setGeometry(QtCore.QRect(90, 30, 621, 331)) - self.verticalLayoutWidget.setObjectName("verticalLayoutWidget") - self.hotspot_main_frame_layout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget) - self.hotspot_main_frame_layout.setContentsMargins(0, 0, 0, 0) - self.hotspot_main_frame_layout.setObjectName("hotspot_main_frame_layout") - self.hotspot_info_name_frame = QtWidgets.QFrame(parent=self.verticalLayoutWidget) - self.hotspot_info_name_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.hotspot_info_name_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.hotspot_info_name_frame.setObjectName("hotspot_info_name_frame") - self.hotspot_info_name_label = QtWidgets.QLabel(parent=self.hotspot_info_name_frame) - self.hotspot_info_name_label.setGeometry(QtCore.QRect(10, 10, 101, 81)) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.hotspot_info_name_label.sizePolicy().hasHeightForWidth()) - self.hotspot_info_name_label.setSizePolicy(sizePolicy) + self.hotspot_header_frame = BlocksCustomFrame(parent=self.hotspot_page) + self.hotspot_header_frame.setGeometry(QtCore.QRect(0, -30, 800, 101)) + self.hotspot_header_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.hotspot_header_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.hotspot_header_frame.setObjectName("hotspot_header_frame") + self.hotspot_header_title = QtWidgets.QLabel(parent=self.hotspot_header_frame) + self.hotspot_header_title.setGeometry(QtCore.QRect(320, 30, 171, 71)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -479,23 +769,39 @@ def setupUi(self, wifi_stacked_page): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.hotspot_info_name_label.setPalette(palette) - self.hotspot_info_name_label.setObjectName("hotspot_info_name_label") - self.hotspot_name_input_field = QtWidgets.QLineEdit(parent=self.hotspot_info_name_frame) - self.hotspot_name_input_field.setGeometry(QtCore.QRect(270, 20, 231, 31)) - self.hotspot_name_input_field.setObjectName("hotspot_name_input_field") - self.hotspot_main_frame_layout.addWidget(self.hotspot_info_name_frame) - self.hotspot_info_password_frame = QtWidgets.QFrame(parent=self.verticalLayoutWidget) - self.hotspot_info_password_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.hotspot_info_password_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.hotspot_info_password_frame.setObjectName("hotspot_info_password_frame") - self.hotspot_info_password_label = QtWidgets.QLabel(parent=self.hotspot_info_password_frame) - self.hotspot_info_password_label.setGeometry(QtCore.QRect(10, 10, 111, 71)) + self.hotspot_header_title.setPalette(palette) + font = QtGui.QFont() + font.setPointSize(20) + self.hotspot_header_title.setFont(font) + self.hotspot_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.hotspot_header_title.setObjectName("hotspot_header_title") + self.hotspot_back_button = IconButton(parent=self.hotspot_header_frame) + self.hotspot_back_button.setGeometry(QtCore.QRect(0, 30, 60, 60)) + self.hotspot_back_button.setMinimumSize(QtCore.QSize(60, 60)) + self.hotspot_back_button.setMaximumSize(QtCore.QSize(60, 60)) + self.hotspot_back_button.setFlat(True) + self.hotspot_back_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) + self.hotspot_back_button.setObjectName("hotspot_back_button") + self.gridLayoutWidget = QtWidgets.QWidget(parent=self.hotspot_page) + self.gridLayoutWidget.setGeometry(QtCore.QRect(10, 80, 781, 371)) + self.gridLayoutWidget.setObjectName("gridLayoutWidget") + self.gridLayout = QtWidgets.QGridLayout(self.gridLayoutWidget) + self.gridLayout.setContentsMargins(0, 0, 0, 0) + self.gridLayout.setObjectName("gridLayout") + self.frame_2 = BlocksCustomFrame(parent=self.gridLayoutWidget) + self.frame_2.setMaximumSize(QtCore.QSize(16777215, 81)) + self.frame_2.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.frame_2.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.frame_2.setObjectName("frame_2") + self.hotspot_info_password_label = QtWidgets.QLabel(parent=self.frame_2) + self.hotspot_info_password_label.setGeometry(QtCore.QRect(10, 30, 150, 21)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.hotspot_info_password_label.sizePolicy().hasHeightForWidth()) self.hotspot_info_password_label.setSizePolicy(sizePolicy) + self.hotspot_info_password_label.setMinimumSize(QtCore.QSize(0, 0)) + self.hotspot_info_password_label.setMaximumSize(QtCore.QSize(150, 16777215)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -633,104 +939,45 @@ def setupUi(self, wifi_stacked_page): brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.ToolTipText, brush) self.hotspot_info_password_label.setPalette(palette) + font = QtGui.QFont() + font.setFamily("Momcake") + font.setPointSize(10) + self.hotspot_info_password_label.setFont(font) + self.hotspot_info_password_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.hotspot_info_password_label.setObjectName("hotspot_info_password_label") - self.hotspot_password_input_field = QtWidgets.QLineEdit(parent=self.hotspot_info_password_frame) - self.hotspot_password_input_field.setGeometry(QtCore.QRect(272, 19, 231, 41)) + self.hotspot_password_input_field = BlocksCustomLinEdit(parent=self.frame_2) + self.hotspot_password_input_field.setGeometry(QtCore.QRect(160, 20, 521, 40)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.hotspot_password_input_field.sizePolicy().hasHeightForWidth()) + self.hotspot_password_input_field.setSizePolicy(sizePolicy) + self.hotspot_password_input_field.setMinimumSize(QtCore.QSize(120, 40)) + self.hotspot_password_input_field.setMaximumSize(QtCore.QSize(16777215, 40)) self.hotspot_password_input_field.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) self.hotspot_password_input_field.setObjectName("hotspot_password_input_field") - self.hotspot_password_view_button = QtWidgets.QPushButton(parent=self.hotspot_info_password_frame) - self.hotspot_password_view_button.setGeometry(QtCore.QRect(530, 22, 51, 31)) + self.hotspot_password_view_button = IconButton(parent=self.frame_2) + self.hotspot_password_view_button.setGeometry(QtCore.QRect(700, 10, 60, 60)) + self.hotspot_password_view_button.setMinimumSize(QtCore.QSize(60, 60)) + self.hotspot_password_view_button.setMaximumSize(QtCore.QSize(60, 60)) + self.hotspot_password_view_button.setFlat(True) + self.hotspot_password_view_button.setProperty("icon_pixmap", QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) self.hotspot_password_view_button.setObjectName("hotspot_password_view_button") - self.hotspot_main_frame_layout.addWidget(self.hotspot_info_password_frame) - self.hotspot_info_ip_frame = QtWidgets.QFrame(parent=self.verticalLayoutWidget) - self.hotspot_info_ip_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.hotspot_info_ip_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.hotspot_info_ip_frame.setObjectName("hotspot_info_ip_frame") - self.hotspot_info_ip_label = QtWidgets.QLabel(parent=self.hotspot_info_ip_frame) - self.hotspot_info_ip_label.setGeometry(QtCore.QRect(10, 10, 121, 81)) + self.gridLayout.addWidget(self.frame_2, 1, 0, 1, 2) + self.frame = BlocksCustomFrame(parent=self.gridLayoutWidget) + self.frame.setMaximumSize(QtCore.QSize(16777215, 81)) + self.frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) + self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) + self.frame.setObjectName("frame") + self.hotspot_info_name_label = QtWidgets.QLabel(parent=self.frame) + self.hotspot_info_name_label.setGeometry(QtCore.QRect(10, 30, 150, 21)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum) sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth(self.hotspot_info_ip_label.sizePolicy().hasHeightForWidth()) - self.hotspot_info_ip_label.setSizePolicy(sizePolicy) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.hotspot_info_ip_label.setPalette(palette) - self.hotspot_info_ip_label.setObjectName("hotspot_info_ip_label") - self.hotspot_info_ip_field = QtWidgets.QLabel(parent=self.hotspot_info_ip_frame) - self.hotspot_info_ip_field.setGeometry(QtCore.QRect(296, 22, 201, 51)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.hotspot_info_ip_field.setPalette(palette) - self.hotspot_info_ip_field.setObjectName("hotspot_info_ip_field") - self.hotspot_main_frame_layout.addWidget(self.hotspot_info_ip_frame) - self.hotspot_header_frame = QtWidgets.QFrame(parent=self.hotspot_page) - self.hotspot_header_frame.setGeometry(QtCore.QRect(0, 0, 800, 80)) - self.hotspot_header_frame.setFrameShape(QtWidgets.QFrame.Shape.StyledPanel) - self.hotspot_header_frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised) - self.hotspot_header_frame.setObjectName("hotspot_header_frame") - self.hotspot_back_button = QtWidgets.QPushButton(parent=self.hotspot_header_frame) - self.hotspot_back_button.setGeometry(QtCore.QRect(0, 0, 80, 80)) - self.hotspot_back_button.setObjectName("hotspot_back_button") - self.hotspot_toggle = QtWidgets.QPushButton(parent=self.hotspot_header_frame) - self.hotspot_toggle.setGeometry(QtCore.QRect(720, 0, 80, 80)) - palette = QtGui.QPalette() - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Active, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Inactive, QtGui.QPalette.ColorRole.Text, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.WindowText, brush) - brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) - brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.hotspot_toggle.setPalette(palette) - self.hotspot_toggle.setObjectName("hotspot_toggle") - self.hotspot_header_title = QtWidgets.QLabel(parent=self.hotspot_header_frame) - self.hotspot_header_title.setGeometry(QtCore.QRect(350, 0, 100, 80)) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.hotspot_info_name_label.sizePolicy().hasHeightForWidth()) + self.hotspot_info_name_label.setSizePolicy(sizePolicy) + self.hotspot_info_name_label.setMinimumSize(QtCore.QSize(0, 0)) + self.hotspot_info_name_label.setMaximumSize(QtCore.QSize(150, 16777215)) palette = QtGui.QPalette() brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) @@ -750,47 +997,104 @@ def setupUi(self, wifi_stacked_page): brush = QtGui.QBrush(QtGui.QColor(120, 120, 120)) brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) palette.setBrush(QtGui.QPalette.ColorGroup.Disabled, QtGui.QPalette.ColorRole.Text, brush) - self.hotspot_header_title.setPalette(palette) + self.hotspot_info_name_label.setPalette(palette) font = QtGui.QFont() - font.setPointSize(15) - self.hotspot_header_title.setFont(font) - self.hotspot_header_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.hotspot_header_title.setObjectName("hotspot_header_title") + font.setFamily("Momcake") + font.setPointSize(10) + self.hotspot_info_name_label.setFont(font) + self.hotspot_info_name_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.hotspot_info_name_label.setObjectName("hotspot_info_name_label") + self.hotspot_name_input_field = BlocksCustomLinEdit(parent=self.frame) + self.hotspot_name_input_field.setGeometry(QtCore.QRect(160, 20, 521, 40)) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.hotspot_name_input_field.sizePolicy().hasHeightForWidth()) + self.hotspot_name_input_field.setSizePolicy(sizePolicy) + self.hotspot_name_input_field.setMinimumSize(QtCore.QSize(120, 40)) + self.hotspot_name_input_field.setMaximumSize(QtCore.QSize(16777215, 40)) + self.hotspot_name_input_field.setEchoMode(QtWidgets.QLineEdit.EchoMode.Password) + self.hotspot_name_input_field.setObjectName("hotspot_name_input_field") + self.gridLayout.addWidget(self.frame, 0, 0, 1, 2) wifi_stacked_page.addWidget(self.hotspot_page) self.retranslateUi(wifi_stacked_page) - wifi_stacked_page.setCurrentIndex(0) + wifi_stacked_page.setCurrentIndex(1) QtCore.QMetaObject.connectSlotsByName(wifi_stacked_page) def retranslateUi(self, wifi_stacked_page): _translate = QtCore.QCoreApplication.translate wifi_stacked_page.setWindowTitle(_translate("wifi_stacked_page", "StackedWidget")) - self.network_list_table_header_label.setText(_translate("wifi_stacked_page", "SSID")) - self.wifi_main_title.setText(_translate("wifi_stacked_page", "Networks")) + self.netlist_security_label.setText(_translate("wifi_stacked_page", "Security\n" +"Type")) + self.netlist_security.setText(_translate("wifi_stacked_page", "TextLabel")) + self.netlist_strength_label.setText(_translate("wifi_stacked_page", "Signal\n" +"Strength")) + self.netlist_strength.setText(_translate("wifi_stacked_page", "TextLabel")) + self.netlist_ip.setText(_translate("wifi_stacked_page", "TextLabel")) + self.label_2.setText(_translate("wifi_stacked_page", "No network connection.\n" +"\n" +"Try connecting to Wi-Fi \n" +"or turn on the hotspot\n" +"using the buttons on the side.")) + self.netlist_ssuid.setText(_translate("wifi_stacked_page", "TextLabel")) + self.network_main_title.setText(_translate("wifi_stacked_page", "Networks")) + self.network_backButton.setText(_translate("wifi_stacked_page", "Back")) + self.network_backButton.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.network_backButton.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.Togglewifi.setText(_translate("wifi_stacked_page", "Toggle wifi")) + self.Togglewifi.setProperty("class", _translate("wifi_stacked_page", "menu_btn")) + self.Togglewifi.setProperty("button_type", _translate("wifi_stacked_page", "normal")) + self.wifi_button.setText(_translate("wifi_stacked_page", "Wi-Fi")) + self.hotspot_button.setText(_translate("wifi_stacked_page", "Hotspot")) + self.Togglehot.setText(_translate("wifi_stacked_page", "Toggle HOT")) + self.network_main_title_2.setText(_translate("wifi_stacked_page", "Wi-fi List")) + self.rescan_button.setText(_translate("wifi_stacked_page", "Reload")) + self.rescan_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.wifi_backButton.setText(_translate("wifi_stacked_page", "Back")) - self.rescan_button.setText(_translate("wifi_stacked_page", "Scan Again")) - self.wifi_toggle_button.setText(_translate("wifi_stacked_page", "Toggle wifi")) - self.call_hotspot_button.setText(_translate("wifi_stacked_page", "Hotspot page")) + self.wifi_backButton.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.wifi_backButton.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.add_network_password_label.setText(_translate("wifi_stacked_page", "Password")) - self.add_network_password_view.setText(_translate("wifi_stacked_page", "view")) - self.add_network_validation_button.setText(_translate("wifi_stacked_page", "Validation")) - self.add_network_message_label.setText(_translate("wifi_stacked_page", "TextLabel")) + self.add_network_password_view.setText(_translate("wifi_stacked_page", "View")) + self.add_network_password_view.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.add_network_password_view.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.add_network_validation_button.setText(_translate("wifi_stacked_page", "a")) + self.add_network_validation_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.cancel_network_validation_button.setText(_translate("wifi_stacked_page", "a")) + self.cancel_network_validation_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.add_network_network_label.setText(_translate("wifi_stacked_page", "NetworkName")) self.add_network_page_backButton.setText(_translate("wifi_stacked_page", "Back")) - self.saved_connection_security_type_label.setText(_translate("wifi_stacked_page", "Security Type")) + self.add_network_page_backButton.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.add_network_page_backButton.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.saved_connection_security_type_label.setText(_translate("wifi_stacked_page", "Security\n" +"Type")) self.saved_connection_security_type_info_label.setText(_translate("wifi_stacked_page", "TextLabel")) - self.sabed_connection_signal_strength_label.setText(_translate("wifi_stacked_page", "Signal Strength")) + self.sabed_connection_signal_strength_label.setText(_translate("wifi_stacked_page", "Signal\n" +"Strength")) self.saved_connection_signal_strength_info_frame.setText(_translate("wifi_stacked_page", "TextLabel")) - self.saved_connection_change_password_label.setText(_translate("wifi_stacked_page", "Change Password")) - self.saved_connection_change_password_view.setText(_translate("wifi_stacked_page", "view")) + self.saved_connection_change_password_label.setText(_translate("wifi_stacked_page", "Change\n" +"Password")) + self.saved_connection_change_password_view.setText(_translate("wifi_stacked_page", "View")) + self.saved_connection_change_password_view.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.saved_connection_change_password_view.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.saved_connection_network_name.setText(_translate("wifi_stacked_page", "SSID")) self.saved_connection_back_button.setText(_translate("wifi_stacked_page", "Back")) + self.saved_connection_back_button.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.saved_connection_back_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.saved_connection_delete_network_button.setText(_translate("wifi_stacked_page", "Delete")) - self.hotspot_info_name_label.setText(_translate("wifi_stacked_page", "Hotspot Name: ")) - self.hotspot_info_password_label.setText(_translate("wifi_stacked_page", "Hotspot Password:")) - self.hotspot_password_view_button.setText(_translate("wifi_stacked_page", "PushButton")) - self.hotspot_info_ip_label.setText(_translate("wifi_stacked_page", "Hotspot Machine Ip address")) - self.hotspot_info_ip_field.setText(_translate("wifi_stacked_page", "TextLabel")) - self.hotspot_back_button.setText(_translate("wifi_stacked_page", "Back")) - self.hotspot_toggle.setText(_translate("wifi_stacked_page", "Toggle Hot")) + self.saved_connection_delete_network_button.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.saved_connection_delete_network_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) self.hotspot_header_title.setText(_translate("wifi_stacked_page", "Hotspot")) + self.hotspot_back_button.setText(_translate("wifi_stacked_page", "Back")) + self.hotspot_back_button.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.hotspot_back_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.hotspot_info_password_label.setText(_translate("wifi_stacked_page", "Hotspot Password:")) + self.hotspot_password_view_button.setText(_translate("wifi_stacked_page", "View")) + self.hotspot_password_view_button.setProperty("class", _translate("wifi_stacked_page", "back_btn")) + self.hotspot_password_view_button.setProperty("button_type", _translate("wifi_stacked_page", "icon")) + self.hotspot_info_name_label.setText(_translate("wifi_stacked_page", "Hotspot Name: ")) +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_button import ListCustomButton +from lib.utils.toggleAnimatedButton import ToggleAnimatedButton diff --git a/BlocksScreen/lib/utils/blocks_ScrollBar.py b/BlocksScreen/lib/utils/blocks_ScrollBar.py new file mode 100644 index 00000000..08dc6b68 --- /dev/null +++ b/BlocksScreen/lib/utils/blocks_ScrollBar.py @@ -0,0 +1,78 @@ +from PyQt6 import QtCore, QtGui, QtWidgets +import numpy as np + + +class CustomScrollBar(QtWidgets.QScrollBar): + def __init__(self, parent=None): + super().__init__(parent) + self.setFixedWidth(40) + + def paintEvent(self, event): + painter = QtGui.QPainter(self) + painter.setRenderHint(painter.RenderHint.Antialiasing, True) + painter.setRenderHint(painter.RenderHint.SmoothPixmapTransform, True) + painter.setRenderHint(painter.RenderHint.LosslessImageRendering, True) + + groove = self.rect().adjusted(0, 0, -35, 0) + min_val, max_val = self.minimum(), self.maximum() + page_step = self.pageStep() + val = self.value() + + handle_width = 5 + + if max_val == min_val: + return + + handle_percentage = int((self.value() / max_val) * 100) + + if handle_percentage < 15: + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + np.interp(handle_percentage, [0, 15], [0, 40]) + ) + handle_pos = 0 + + elif handle_percentage > 85: + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + np.interp(handle_percentage, [85, 100], [40, 0]) + ) + handle_pos = int( + (groove.height() - base_handle_length) + * (max_val - min_val) + / (max_val - min_val) + ) + else: + val = ( + np.interp((handle_percentage), [15, 85], [0, 100]) + / 100 + * max_val + ) + + base_handle_length = int( + (groove.height() * page_step / (max_val - min_val + page_step)) + + 40 + ) + handle_pos = int( + (groove.height() - base_handle_length) + * (val - min_val) + / (max_val - min_val) + ) + + handle_rect = QtCore.QRect( + groove.x(), + int(groove.y() + handle_pos), + handle_width, + base_handle_length, + ) + + gradient = QtGui.QLinearGradient( + QtCore.QPointF(handle_rect.topLeft()), + QtCore.QPointF(handle_rect.bottomLeft()), + ) + + gradient.setColorAt(0.0, QtGui.QColor(164, 164, 164, 100)) # Top + gradient.setColorAt(0.5, QtGui.QColor(164, 164, 164, 164)) # Center + gradient.setColorAt(1.0, QtGui.QColor(164, 164, 164, 100)) # Bottom + painter.setBrush(gradient) + painter.drawRoundedRect(handle_rect, 1, 1) diff --git a/BlocksScreen/lib/utils/blocks_frame.py b/BlocksScreen/lib/utils/blocks_frame.py new file mode 100644 index 00000000..a686e247 --- /dev/null +++ b/BlocksScreen/lib/utils/blocks_frame.py @@ -0,0 +1,28 @@ +from PyQt6.QtWidgets import QFrame +from PyQt6.QtGui import QPainter, QPen, QBrush, QColor +from PyQt6.QtCore import QRectF + + +class BlocksCustomFrame(QFrame): + def __init__(self, parent=None): + super().__init__(parent) + self._radius = 10 + + def setRadius(self, radius: int): + self._radius = radius + self.update() + + def radius(self): + return self._radius + + def paintEvent(self, event): + painter = QPainter(self) + painter.setRenderHint(QPainter.RenderHint.Antialiasing) + rect = QRectF(self.rect()) + pen = QPen(QColor(190, 190, 190, 50)) + pen.setWidth(2) + painter.setPen(pen) + painter.setBrush(QBrush(QColor(84, 84, 84, 0))) + painter.drawRoundedRect( + rect.adjusted(1, 1, -1, -1), self._radius, self._radius + ) diff --git a/BlocksScreen/lib/utils/blocks_linedit.py b/BlocksScreen/lib/utils/blocks_linedit.py new file mode 100644 index 00000000..fde89e0c --- /dev/null +++ b/BlocksScreen/lib/utils/blocks_linedit.py @@ -0,0 +1,71 @@ +import typing +from PyQt6 import QtCore, QtGui, QtWidgets + + +class BlocksCustomLinEdit(QtWidgets.QLineEdit): + def __init__( + self, + parent: QtWidgets.QWidget, + ) -> None: + super(BlocksCustomLinEdit, self).__init__(parent) + + self.button_background = None + self.button_ellipse = None + self._text: str = "" + self.placeholder_str = "Type here" + self._name: str = "" + self.text_color: QtGui.QColor = QtGui.QColor(0, 0, 0) + self.secret: bool = False # NEW: controls masking + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) + + @property + def name(self): + return self._name + + @name.setter + def name(self, new_name) -> None: + self._name = new_name + self.setObjectName(new_name) + + def setText(self, text: str) -> None: + super().setText(text) # let QLineEdit handle storing and editing + + def setHidden(self, hidden: bool) -> None: + self.secret = hidden + self.update() + + def paintEvent(self, e: typing.Optional[QtGui.QPaintEvent]): + painter = QtGui.QPainter(self) + painter.setRenderHint(painter.RenderHint.Antialiasing, True) + + # Draw background + bg_color = QtGui.QColor(223, 223, 223) + painter.setBrush(bg_color) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.drawRoundedRect(self.rect(), 8, 8) + + margin = 5 # adjust as needed + + # Get display text (masked if secret) + display_text = self.text() + if self.secret and display_text: + display_text = "*" * len(display_text) + + # Draw text + if self.text(): + painter.setPen(self.text_color) + painter.drawText( + self.rect().adjusted(margin, 0, 0, 0), + QtCore.Qt.AlignmentFlag.AlignLeft + | QtCore.Qt.AlignmentFlag.AlignVCenter, + display_text, + ) + else: + # Draw placeholder + painter.setPen(QtGui.QColor(150, 150, 150)) + painter.drawText( + self.rect().adjusted(margin, 0, 0, 0), + QtCore.Qt.AlignmentFlag.AlignLeft + | QtCore.Qt.AlignmentFlag.AlignVCenter, + self.placeholder_str, + ) diff --git a/BlocksScreen/lib/utils/blocks_slider.py b/BlocksScreen/lib/utils/blocks_slider.py index c8823c17..4d1078c7 100644 --- a/BlocksScreen/lib/utils/blocks_slider.py +++ b/BlocksScreen/lib/utils/blocks_slider.py @@ -1,36 +1,22 @@ -import typing +import sys from PyQt6 import QtCore, QtGui, QtWidgets class BlocksSlider(QtWidgets.QSlider): - valueChanged: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( - int, name="valueChanged" - ) - def __init__(self, parent) -> None: super().__init__(parent) - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) self.highlight_color = "#2AC9F9" self.gradient_pos = QtCore.QPointF(0.0, 0.0) - self.setMinimumSize(300, 130) - self.setMaximumSize(400, 130) + self.setMinimumSize(300, 100) + self.setMaximumSize(400, 100) self.setMouseTracking(True) self.setTracking(True) - self.setTabletTracking(True) - self.setOrientation(QtCore.Qt.Orientation.Horizontal) + self.setTickInterval(20) self.setMinimum(0) self.setMaximum(100) - def setMinimum(self, a0: int) -> None: - super().setMinimum(a0) - return self.update() - - def setMaximum(self, a0: int) -> None: - super().setMaximum(a0) - return self.update() - def setOrientation(self, a0: QtCore.Qt.Orientation) -> None: return super().setOrientation(a0) @@ -41,21 +27,26 @@ def mousePressEvent(self, ev: QtGui.QMouseEvent) -> None: ): self.setSliderDown(True) ev.accept() + else: + return super().mousePressEvent(ev) def mouseReleaseEvent(self, ev: QtGui.QMouseEvent) -> None: """Handle mouse release events""" if self.isSliderDown(): self.setSliderDown(False) - self.valueChanged.emit(self.value()) - ev.accept() + return super().mouseReleaseEvent(ev) def mouseMoveEvent(self, ev: QtGui.QMouseEvent) -> None: """Handle mouse move events""" + opt = QtWidgets.QStyleOptionSlider() + self.initStyleOption(opt) if self.isSliderDown(): self._set_slider_pos(ev.position().toPoint().toPointF()) self.gradient_pos = ev.position().toPoint().toPointF() self.update() ev.accept() + else: + return super().mouseMoveEvent(ev) def hit_test(self, pos: QtCore.QPointF) -> bool: """Hit test to allow dragging larger handle area @@ -89,14 +80,10 @@ def _set_slider_pos(self, pos: QtCore.QPointF): min_val + (max_val - min_val) * (pos_y - slider_start) / slider_length ) + self.setSliderPosition(int(round(new_val))) self.setValue(int(round(new_val))) self.update() - def setSliderPosition(self, value) -> None: - if self.isVisible(): - self.valueChanged.emit(value) - super().setSliderPosition(value) - def paintEvent(self, ev: QtGui.QPaintEvent) -> None: opt = QtWidgets.QStyleOptionSlider() self.initStyleOption(opt) @@ -105,7 +92,7 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: # Clip the opt rect inside, so the handle and # groove doesn't exceed the limits opt.rect = opt.rect.adjusted( - 30, 10, -35, 20 + 12, 10, -18, 20 ) # This is a bit hardcoded self._groove_rect = _style.subControlRect( @@ -114,19 +101,37 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: QtWidgets.QStyle.SubControl.SC_SliderGroove, self, ) - self._groove_rect.setSize(QtCore.QSize(self.width() - 60, 30)) + + self._groove_rect.setSize(QtCore.QSize(self.width() - 25, 30)) + self._handle_rect = _style.subControlRect( QtWidgets.QStyle.ComplexControl.CC_Slider, opt, QtWidgets.QStyle.SubControl.SC_SliderHandle, self, ) + self._handle_rect.setSize(QtCore.QSize(20, 50)) + # self.style().subControlRect( + # QtWidgets.QStyle.ComplexControl.CC_Slider, opt, QtWidgets.QStyle.SubControl.SC_SliderGroove or QtWidgets.QStyle.SubControl.SC_SliderHandle + # ) + + # if opt.state & QtWidgets.QStyle.StateFlag.State_Sunken: + # # give the track a color + # ... + # elif opt.state & QtWidgets.QStyle.StateFlag.State_MouseOver: + # # Give another color when the mouse is over the track + # ... + # else: + # # give a default color for the track + # ... _groove_x = (self.width() - self._groove_rect.width()) // 2 - _groove_y = ((self.height() - self._groove_rect.height()) // 2) - 10 + _groove_y = (self.height() - self._groove_rect.height()) // 2 + self._groove_rect.moveTo(QtCore.QPoint(_groove_x, _groove_y)) - _handle_y = (self.height() - self._handle_rect.height()) // 2 - 10 + _handle_y = (self.height() - self._handle_rect.height()) // 2 self._handle_rect.moveTop(_handle_y) + _handle_color = ( QtGui.QColor(164, 164, 164) if self.isSliderDown() @@ -136,11 +141,13 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: _handle_path.addRoundedRect(self._handle_rect.toRectF(), 5, 5) _groove_path = QtGui.QPainterPath() _groove_path.addRoundedRect(self._groove_rect.toRectF(), 15, 15) + if self.isSliderDown(): _handle_x = ( self.sliderPosition() - _handle_path.currentPosition().x() ) // 2 _handle_path.moveTo(int(round(_handle_x)), _handle_y) + gradient_path = QtGui.QPainterPath() gradient_path.addRoundedRect( self._groove_rect.toRectF(), @@ -158,6 +165,7 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: painter.fillPath( _groove_path, _color ) # Primary groove background color + _color = QtGui.QColor(self.highlight_color) _color_1 = QtGui.QColor(self.highlight_color) _color_2 = QtGui.QColor(self.highlight_color) @@ -172,23 +180,24 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: _gradient.setColorAt(0, _color) _gradient.setColorAt(0.5, _color_1) _gradient.setColorAt(1, _color_2) + self.text_box_rect = _style.subControlRect( QtWidgets.QStyle.ComplexControl.CC_Slider, opt, QtWidgets.QStyle.SubControl.SC_SliderTickmarks, self, ) + tick_interval = self.tickInterval() or self.singleStep() min_v, max_v = self.minimum(), self.maximum() painter.setPen(QtGui.QColor("#888888")) - font = QtGui.QFont() - font.setPointSize(16) - painter.setFont(font) fm = QtGui.QFontMetrics(painter.font()) label_offset = 4 + _style.drawComplexControl( QtWidgets.QStyle.ComplexControl.CC_Slider, opt, painter, self ) self.setStyle(_style) + for v in [min_v, max_v]: x = ( QtWidgets.QStyle.sliderPositionFromValue( @@ -198,7 +207,7 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: ) y1 = self._groove_rect.bottom() y2 = y1 + 15 # tick length - label = str(v) + "%" + label = str(v) text_w = fm.horizontalAdvance(label) text_h = fm.ascent() text_x = x - text_w // 2 @@ -206,7 +215,8 @@ def paintEvent(self, ev: QtGui.QPaintEvent) -> None: painter.setPen(QtGui.QColor(255, 255, 255)) painter.drawLine(x, y1, x, y2) painter.drawText(text_x, text_y, label) - + + # Paint the elements with colors painter.setBrush(_gradient) painter.fillPath(gradient_path, painter.brush()) painter.fillPath(_handle_path, _handle_color) diff --git a/BlocksScreen/lib/utils/list_button.py b/BlocksScreen/lib/utils/list_button.py index 87a1e3be..22d3ff05 100644 --- a/BlocksScreen/lib/utils/list_button.py +++ b/BlocksScreen/lib/utils/list_button.py @@ -2,8 +2,8 @@ class ListCustomButton(QtWidgets.QPushButton): - def __init__(self) -> None: - super().__init__() + def __init__(self, parent) -> None: + super(ListCustomButton, self).__init__(parent) self.icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() self.second_icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() self.text_color: QtGui.QColor = QtGui.QColor(255, 255, 255) @@ -22,9 +22,13 @@ def __init__(self) -> None: QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed, ) - self.setFixedHeight(48) + self.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + # New attributes for border + self.border_width = 2 # Reduced to 1px for a cleaner look + self.border_color = QtGui.QColor(self.pressed_color).lighter(50) + def setText(self, text: str) -> None: self._text = text self.update() @@ -71,9 +75,38 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: rect = self.rect() radius = rect.height() / 5.0 - # Main rounded rectangle path + # Adjust the drawing rectangle to account for the border width + # This draws the border and fill *inside* the button's bounds + adjusted_rect = QtCore.QRectF( + rect.x() + self.border_width / 2.0, + rect.y() + self.border_width / 2.0, + rect.width() - self.border_width, + rect.height() - self.border_width, + ) + + # Main rounded rectangle path (using the adjusted rect) path = QtGui.QPainterPath() - path.addRoundedRect(QtCore.QRectF(rect), radius, radius) + path.addRoundedRect(adjusted_rect, radius, radius) + + # Draw border + pen = QtGui.QPen(self.border_color) + pen.setWidth(self.border_width) + painter.setPen(pen) + painter.drawPath(path) + + # Gradient background (left to right) + if not self._is_pressed: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(20) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) + else: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(90) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) # Ellipse ("hole") for the icon on the right ellipse_margin = rect.height() * 0.05 @@ -99,20 +132,6 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: ) left_margin = 10 # default left margin - # Gradient background (left to right) - if not self._is_pressed: - pressed_color = QtGui.QColor(self.pressed_color) - pressed_color.setAlpha(20) - painter.setPen(QtCore.Qt.PenStyle.NoPen) - painter.setBrush(pressed_color) - painter.fillPath(path, pressed_color) - else: - pressed_color = QtGui.QColor(self.pressed_color) - pressed_color.setAlpha(100) - painter.setPen(QtCore.Qt.PenStyle.NoPen) - painter.setBrush(pressed_color) - painter.fillPath(path, pressed_color) - # Draw icon inside the ellipse "hole" (on the right) if not self.icon_pixmap.isNull(): icon_margin = ellipse_size * 0.10 @@ -160,7 +179,7 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: adjusted_y = ( left_icon_rect.y() + (left_icon_rect.height() - left_icon_scaled.height()) / 2.0 - ) # <-- FIXED HERE + ) adjusted_left_icon_rect = QtCore.QRectF( adjusted_x, adjusted_y, diff --git a/BlocksScreen/lib/utils/toggleAnimatedButton.py b/BlocksScreen/lib/utils/toggleAnimatedButton.py index 4b946f0e..48bce5d4 100644 --- a/BlocksScreen/lib/utils/toggleAnimatedButton.py +++ b/BlocksScreen/lib/utils/toggleAnimatedButton.py @@ -93,7 +93,6 @@ def state(self, new_state: State) -> None: if self.isVisible(): self.stateChange.emit(self._state) self.setup_animation() - self.update() @QtCore.pyqtProperty(float) @@ -158,7 +157,10 @@ def setPixmap(self, pixmap: QtGui.QPixmap) -> None: @QtCore.pyqtSlot(name="clicked") def setup_animation(self) -> None: - if self.underMouse(): + if ( + not self.slide_animation.state + == self.slide_animation.State.Running + ): self.slide_animation.setEndValue( self._handle_ONPosition if self.state == ToggleAnimatedButton.State.OFF From c8b12672694051865a6c968b36f2aee28770ac1d Mon Sep 17 00:00:00 2001 From: Hugo Costa Date: Sun, 24 Aug 2025 19:58:43 +0100 Subject: [PATCH 11/20] Work cancel popup (#13) * ADD: added dialog page in this case to comfirmate if the user want to cancel the print * Refactor unused imports --------- Co-authored-by: Roberto Martins --- BlocksScreen/lib/panels/widgets/dialogPage.py | 183 ++++++++++++++++++ .../lib/panels/widgets/jobStatusPage.py | 24 ++- 2 files changed, 205 insertions(+), 2 deletions(-) create mode 100644 BlocksScreen/lib/panels/widgets/dialogPage.py diff --git a/BlocksScreen/lib/panels/widgets/dialogPage.py b/BlocksScreen/lib/panels/widgets/dialogPage.py new file mode 100644 index 00000000..567a1ed7 --- /dev/null +++ b/BlocksScreen/lib/panels/widgets/dialogPage.py @@ -0,0 +1,183 @@ +from PyQt6 import QtCore, QtGui, QtWidgets + + +class DialogPage(QtWidgets.QDialog): + button_clicked = QtCore.pyqtSignal( + str + ) # Signal to emit which button was clicked + + def __init__( + self, + parent: QtWidgets.QWidget, + ) -> None: + super().__init__(parent) + + self.setWindowFlags( + QtCore.Qt.WindowType.Popup + | QtCore.Qt.WindowType.FramelessWindowHint + ) + self.setAttribute( + QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True + ) # Make background transparent + + self.setupUI() + self.repaint() + + def set_message(self, message: str) -> None: + self.label.setText(message) + + def geometry_calc(self) -> None: + app_instance = QtWidgets.QApplication.instance() + main_window = app_instance.activeWindow() if app_instance else None + if main_window is None and app_instance: + for widget in app_instance.allWidgets(): + if isinstance(widget, QtWidgets.QMainWindow): + main_window = widget + + x_offset = 0.7 + y_offset = 0.7 + + width = int(main_window.width() * x_offset) + height = int(main_window.height() * y_offset) + self.testwidth = width + self.testheight = height + x = int(main_window.geometry().x() + (main_window.width() - width) / 2) + y = int( + main_window.geometry().y() + (main_window.height() - height) / 2 + ) + + self.setGeometry(x, y, width, height) + + def paintEvent(self, event: QtGui.QPaintEvent) -> None: + self.geometry_calc() + painter = QtGui.QPainter(self) + painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True) + + rect = self.rect() + radius = 20 # Adjust the radius for rounded corners + + # Set background color + painter.setBrush( + QtGui.QBrush(QtGui.QColor(63, 63, 63)) + ) # Semi-transparent dark gray + + # Set border color and width + border_color = QtGui.QColor(128, 128, 128) # Gray color + border_width = 5 # Reduced border thickness + + pen = QtGui.QPen() + pen.setCapStyle(QtCore.Qt.PenCapStyle.RoundCap) + painter.setPen(QtGui.QPen(border_color, border_width)) + + painter.drawRoundedRect(rect, radius, radius) + + painter.end() + + def sizeHint(self) -> QtCore.QSize: + popup_width = int(self.geometry().width()) + popup_height = int(self.geometry().height()) + # Centering logic + + popup_x = self.x() + popup_y = self.y() + (self.height() - popup_height) // 2 + self.move(popup_x, popup_y) + self.setFixedSize(popup_width, popup_height) + self.setMinimumSize(popup_width, popup_height) + return super().sizeHint() + + def mousePressEvent(self, a0: QtGui.QMouseEvent) -> None: + return + + def resizeEvent(self, event: QtGui.QResizeEvent) -> None: + super().resizeEvent(event) + + label_width = self.testwidth + label_height = self.testheight + label_x = (self.width() - label_width) // 2 + label_y = ( + int(label_height / 4) - 20 + ) # Move the label to the top (adjust as needed) + + self.label.setGeometry(label_x, -label_y, label_width, label_height) + + # Adjust button positions on resize + self.confirm_button.setGeometry( + int(0), self.height() - 70, int(self.width() / 2), 70 + ) + self.cancel_button.setGeometry( + int(self.width() / 2), + self.height() - 70, + int(self.width() / 2), + 70, + ) + + def show(self) -> None: + self.geometry_calc() + return super().show() + + def setupUI(self) -> None: + self.label = QtWidgets.QLabel("Test", self) + font = QtGui.QFont() + font.setPointSize(25) + self.label.setFont(font) + self.label.setStyleSheet("color: #ffffff; background: transparent;") + self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.label.setWordWrap(True) + + # Create Confirm and Cancel buttons + self.confirm_button = QtWidgets.QPushButton("Confirm", self) + self.cancel_button = QtWidgets.QPushButton("Cancel", self) + + # Set button styles + button_font = QtGui.QFont() + button_font.setPointSize(14) + self.confirm_button.setFont(button_font) + self.cancel_button.setFont(button_font) + + # Apply styles for rounded corners + self.confirm_button.setStyleSheet( + """ + background-color: #4CAF50; + color: white; + border: none; + border-bottom-left-radius: 20px; + padding: 10px; + """ + ) + self.cancel_button.setStyleSheet( + """ + background-color: #F44336; + color: white; + border: none; + border-bottom-right-radius: 20px; + padding: 10px; + """ + ) + + # Position buttons + self.confirm_button.setGeometry( + int(0), self.height() - 70, int(self.width() / 2), 70 + ) + self.cancel_button.setGeometry( + int(self.width() / 2), + self.height() - 70, + int(self.width() / 2), + 70, + ) + + # Connect button signals + self.confirm_button.clicked.connect( + lambda: self.on_button_clicked("Confirm") + ) + self.cancel_button.clicked.connect( + lambda: self.on_button_clicked("Cancel") + ) + + def on_button_clicked(self, button_name: str) -> None: + self.button_clicked.emit( + button_name + ) # Emit the signal with the button name + if button_name == "Confirm": + self.accept() # Close the dialog with an accepted state + elif button_name == "Cancel": + self.reject() # Close the dialog with a rejected state diff --git a/BlocksScreen/lib/panels/widgets/jobStatusPage.py b/BlocksScreen/lib/panels/widgets/jobStatusPage.py index e4d52f6e..f30f8ef7 100644 --- a/BlocksScreen/lib/panels/widgets/jobStatusPage.py +++ b/BlocksScreen/lib/panels/widgets/jobStatusPage.py @@ -6,6 +6,7 @@ from lib.utils.blocks_button import BlocksCustomButton from lib.utils.blocks_label import BlocksLabel from lib.utils.display_button import DisplayButton +from lib.panels.widgets import dialogPage import events from PyQt6 import QtCore, QtGui, QtWidgets @@ -47,12 +48,31 @@ class JobStatusWidget(QtWidgets.QWidget): def __init__(self, parent) -> None: super().__init__(parent) + + self.canceldialog = dialogPage.DialogPage(self) + self.setupUI() self.tune_menu_btn.clicked.connect(self.tune_clicked.emit) self.pause_printing_btn.clicked.connect(self.pause_resume_print) - self.stop_printing_btn.clicked.connect( - lambda: self.print_cancel.emit() + self.stop_printing_btn.clicked.connect(self.handleCancel) + + def handleCancel(self) -> None: + """Handle the cancel print job dialog""" + self.canceldialog.set_message( + "Are you sure you \n want to cancel \n this print job?" ) + self.canceldialog.button_clicked.connect(self.on_dialog_button_clicked) + self.canceldialog.show() + + def on_dialog_button_clicked(self, button_name: str) -> None: + """Handle dialog button clicks""" + if button_name == "Confirm": + print( + "Confirm button clicked MY GD HELPO ME IDK WHAT AM I DOING I MISS MY WIFI OH GOD HE IS HERE M-MY , NOOOOOOOOOOooOooOO..." + ) + self.print_cancel.emit() # Emit the print_cancel signal + elif button_name == "Cancel": + print("Cancel button clicked") @QtCore.pyqtSlot(str, name="on_print_start") def on_print_start(self, file: str) -> None: From e9445c91207c3d00a844d8715310334b082d225e Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Fri, 1 Aug 2025 16:24:17 +0100 Subject: [PATCH 12/20] Add: list_button and blocks_Scrollbar , re-do of filePage Ui and its code --- BlocksScreen/lib/moonrakerComm.py | 1 - 1 file changed, 1 deletion(-) diff --git a/BlocksScreen/lib/moonrakerComm.py b/BlocksScreen/lib/moonrakerComm.py index 33f45f18..53136e5e 100644 --- a/BlocksScreen/lib/moonrakerComm.py +++ b/BlocksScreen/lib/moonrakerComm.py @@ -167,7 +167,6 @@ def connect(self) -> bool: f"Unexpected error occurred when trying to acquire oneshot token: {e}" ) return False - _url = f"ws://localhost:7125/websocket?token={_oneshot_token}" self.ws = websocket.WebSocketApp( _url, From 3ce4c80ea785732dbfb288e7ae950556302d9a09 Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Fri, 22 Aug 2025 16:56:24 +0100 Subject: [PATCH 13/20] BUG FIX: centered thumbnail position --- .../lib/panels/widgets/confirmPage.py | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/confirmPage.py index 7c1ee859..9d0c0e51 100644 --- a/BlocksScreen/lib/panels/widgets/confirmPage.py +++ b/BlocksScreen/lib/panels/widgets/confirmPage.py @@ -37,6 +37,11 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: _total_filament = filedata.get("filament_total") _estimated_time = filedata.get("estimated_time") +<<<<<<< HEAD +======= +<<<<<<< HEAD +======= +>>>>>>> ae09c93 (BUG FIX: centered thumbnail position) if isinstance(_estimated_time, str): seconds = 0 @@ -45,11 +50,16 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: _estimated_time = self.estimate_print_time(seconds) +<<<<<<< HEAD +======= +>>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) +>>>>>>> ae09c93 (BUG FIX: centered thumbnail position) self.cf_info.setText( "Total Filament:" + str(_total_filament) + "\n" + "Slicer time: " +<<<<<<< HEAD + str(_estimated_time[0]) + " days " + str(_estimated_time[1]) @@ -61,6 +71,25 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: ) self.repaint() +======= +<<<<<<< HEAD + + str(_estimated_time) + ) + self.repaint() + +======= + + str(_estimated_time[0]) + + " days " + + str(_estimated_time[1]) + + " hours " + + str(_estimated_time[2]) + + " minutes " + + str(_estimated_time[3]) + + " seconds" + ) + self.repaint() + +>>>>>>> ae09c93 (BUG FIX: centered thumbnail position) def estimate_print_time(self, seconds: int) -> list: """Convert time in seconds format to days, hours, minutes, seconds. @@ -75,6 +104,10 @@ def estimate_print_time(self, seconds: int) -> list: days, hours = divmod(num_hours, 24) return [days, hours, minutes, seconds] +<<<<<<< HEAD +======= +>>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) +>>>>>>> ae09c93 (BUG FIX: centered thumbnail position) def paintEvent(self, a0: QtGui.QPaintEvent) -> None: _scene = QtWidgets.QGraphicsScene() if not self.thumbnail.isNull(): @@ -317,7 +350,15 @@ def setupUI(self) -> None: self.cf_content_vertical_layout.addWidget( self.cf_thumbnail, 0, +<<<<<<< HEAD + QtCore.Qt.AlignmentFlag.AlignRight +======= +<<<<<<< HEAD + QtCore.Qt.AlignmentFlag.AlignHCenter +======= QtCore.Qt.AlignmentFlag.AlignRight +>>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) +>>>>>>> ae09c93 (BUG FIX: centered thumbnail position) | QtCore.Qt.AlignmentFlag.AlignVCenter, ) self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) From f750d69ed4441fe75bc25ea5e24439c9668b07b8 Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Mon, 25 Aug 2025 10:17:44 +0100 Subject: [PATCH 14/20] fix merging issues --- .../lib/panels/widgets/confirmPage.py | 35 +------------------ 1 file changed, 1 insertion(+), 34 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/confirmPage.py index 9d0c0e51..6fd56de4 100644 --- a/BlocksScreen/lib/panels/widgets/confirmPage.py +++ b/BlocksScreen/lib/panels/widgets/confirmPage.py @@ -37,11 +37,6 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: _total_filament = filedata.get("filament_total") _estimated_time = filedata.get("estimated_time") -<<<<<<< HEAD -======= -<<<<<<< HEAD -======= ->>>>>>> ae09c93 (BUG FIX: centered thumbnail position) if isinstance(_estimated_time, str): seconds = 0 @@ -50,34 +45,12 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: _estimated_time = self.estimate_print_time(seconds) -<<<<<<< HEAD -======= ->>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) ->>>>>>> ae09c93 (BUG FIX: centered thumbnail position) + self.cf_info.setText( "Total Filament:" + str(_total_filament) + "\n" + "Slicer time: " -<<<<<<< HEAD - + str(_estimated_time[0]) - + " days " - + str(_estimated_time[1]) - + " hours " - + str(_estimated_time[2]) - + " minutes " - + str(_estimated_time[3]) - + " seconds" - ) - self.repaint() - -======= -<<<<<<< HEAD - + str(_estimated_time) - ) - self.repaint() - -======= + str(_estimated_time[0]) + " days " + str(_estimated_time[1]) @@ -88,8 +61,6 @@ def on_show_widget(self, text: str, filedata: dict | None = None) -> None: + " seconds" ) self.repaint() - ->>>>>>> ae09c93 (BUG FIX: centered thumbnail position) def estimate_print_time(self, seconds: int) -> list: """Convert time in seconds format to days, hours, minutes, seconds. @@ -104,10 +75,6 @@ def estimate_print_time(self, seconds: int) -> list: days, hours = divmod(num_hours, 24) return [days, hours, minutes, seconds] -<<<<<<< HEAD -======= ->>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) ->>>>>>> ae09c93 (BUG FIX: centered thumbnail position) def paintEvent(self, a0: QtGui.QPaintEvent) -> None: _scene = QtWidgets.QGraphicsScene() if not self.thumbnail.isNull(): From e2632165cf3f8dedf46719e5ce3034a77bb29d4a Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Mon, 25 Aug 2025 10:18:47 +0100 Subject: [PATCH 15/20] last-fix merging issues --- BlocksScreen/lib/panels/widgets/confirmPage.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/confirmPage.py b/BlocksScreen/lib/panels/widgets/confirmPage.py index 6fd56de4..a549ac9e 100644 --- a/BlocksScreen/lib/panels/widgets/confirmPage.py +++ b/BlocksScreen/lib/panels/widgets/confirmPage.py @@ -317,15 +317,7 @@ def setupUI(self) -> None: self.cf_content_vertical_layout.addWidget( self.cf_thumbnail, 0, -<<<<<<< HEAD QtCore.Qt.AlignmentFlag.AlignRight -======= -<<<<<<< HEAD - QtCore.Qt.AlignmentFlag.AlignHCenter -======= - QtCore.Qt.AlignmentFlag.AlignRight ->>>>>>> 1a620a0 (BUG FIX: centered thumbnail position) ->>>>>>> ae09c93 (BUG FIX: centered thumbnail position) | QtCore.Qt.AlignmentFlag.AlignVCenter, ) self.verticalLayout_4.addLayout(self.cf_content_vertical_layout) From d25e014e5c88effae925ddfc9e0fbe0b9e0645b2 Mon Sep 17 00:00:00 2001 From: HugoCLSC Date: Mon, 25 Aug 2025 10:20:40 +0100 Subject: [PATCH 16/20] fix ListCustomButton inheritance parent --- BlocksScreen/lib/panels/widgets/filesPage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index 84849f51..ff4625ed 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -120,7 +120,7 @@ def add_file_entries(self) -> None: ) for item in sorted_list: - self.button = ListCustomButton() + self.button = ListCustomButton(self) self.button.setText(str(item["path"][:-6])) self.request_file_info.emit(item["path"]) From f513a1f63f559734eec3bb91a3042361b749372f Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 25 Aug 2025 10:51:37 +0100 Subject: [PATCH 17/20] Refactor: ListCustomButton instantiation to remove parent argument and newer version of itself --- BlocksScreen/lib/panels/widgets/filesPage.py | 2 +- .../lib/ui/wifiConnectivityWindow_ui.py | 4 +- BlocksScreen/lib/utils/list_button.py | 59 +++++++------------ 3 files changed, 23 insertions(+), 42 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/filesPage.py b/BlocksScreen/lib/panels/widgets/filesPage.py index ff4625ed..84849f51 100644 --- a/BlocksScreen/lib/panels/widgets/filesPage.py +++ b/BlocksScreen/lib/panels/widgets/filesPage.py @@ -120,7 +120,7 @@ def add_file_entries(self) -> None: ) for item in sorted_list: - self.button = ListCustomButton(self) + self.button = ListCustomButton() self.button.setText(str(item["path"][:-6])) self.request_file_info.emit(item["path"]) diff --git a/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py b/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py index 81bd7688..de78329d 100644 --- a/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py +++ b/BlocksScreen/lib/ui/wifiConnectivityWindow_ui.py @@ -227,7 +227,7 @@ def setupUi(self, wifi_stacked_page): self.Togglewifi.setStyleSheet("") self.Togglewifi.setProperty("icon_pixmap", QtGui.QPixmap(":/network/media/btn_icons/no_wifi.svg")) self.Togglewifi.setObjectName("Togglewifi") - self.wifi_button = ListCustomButton(parent=self.network_list_page) + self.wifi_button = ListCustomButton() self.wifi_button.setGeometry(QtCore.QRect(390, 90, 391, 161)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -238,7 +238,7 @@ def setupUi(self, wifi_stacked_page): font.setPointSize(20) self.wifi_button.setFont(font) self.wifi_button.setObjectName("wifi_button") - self.hotspot_button = ListCustomButton(parent=self.network_list_page) + self.hotspot_button = ListCustomButton() self.hotspot_button.setGeometry(QtCore.QRect(390, 269, 391, 161)) font = QtGui.QFont() font.setPointSize(20) diff --git a/BlocksScreen/lib/utils/list_button.py b/BlocksScreen/lib/utils/list_button.py index 22d3ff05..87a1e3be 100644 --- a/BlocksScreen/lib/utils/list_button.py +++ b/BlocksScreen/lib/utils/list_button.py @@ -2,8 +2,8 @@ class ListCustomButton(QtWidgets.QPushButton): - def __init__(self, parent) -> None: - super(ListCustomButton, self).__init__(parent) + def __init__(self) -> None: + super().__init__() self.icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() self.second_icon_pixmap: QtGui.QPixmap = QtGui.QPixmap() self.text_color: QtGui.QColor = QtGui.QColor(255, 255, 255) @@ -22,13 +22,9 @@ def __init__(self, parent) -> None: QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed, ) - + self.setFixedHeight(48) self.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - # New attributes for border - self.border_width = 2 # Reduced to 1px for a cleaner look - self.border_color = QtGui.QColor(self.pressed_color).lighter(50) - def setText(self, text: str) -> None: self._text = text self.update() @@ -75,38 +71,9 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: rect = self.rect() radius = rect.height() / 5.0 - # Adjust the drawing rectangle to account for the border width - # This draws the border and fill *inside* the button's bounds - adjusted_rect = QtCore.QRectF( - rect.x() + self.border_width / 2.0, - rect.y() + self.border_width / 2.0, - rect.width() - self.border_width, - rect.height() - self.border_width, - ) - - # Main rounded rectangle path (using the adjusted rect) + # Main rounded rectangle path path = QtGui.QPainterPath() - path.addRoundedRect(adjusted_rect, radius, radius) - - # Draw border - pen = QtGui.QPen(self.border_color) - pen.setWidth(self.border_width) - painter.setPen(pen) - painter.drawPath(path) - - # Gradient background (left to right) - if not self._is_pressed: - pressed_color = QtGui.QColor(self.pressed_color) - pressed_color.setAlpha(20) - painter.setPen(QtCore.Qt.PenStyle.NoPen) - painter.setBrush(pressed_color) - painter.fillPath(path, pressed_color) - else: - pressed_color = QtGui.QColor(self.pressed_color) - pressed_color.setAlpha(90) - painter.setPen(QtCore.Qt.PenStyle.NoPen) - painter.setBrush(pressed_color) - painter.fillPath(path, pressed_color) + path.addRoundedRect(QtCore.QRectF(rect), radius, radius) # Ellipse ("hole") for the icon on the right ellipse_margin = rect.height() * 0.05 @@ -132,6 +99,20 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: ) left_margin = 10 # default left margin + # Gradient background (left to right) + if not self._is_pressed: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(20) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) + else: + pressed_color = QtGui.QColor(self.pressed_color) + pressed_color.setAlpha(100) + painter.setPen(QtCore.Qt.PenStyle.NoPen) + painter.setBrush(pressed_color) + painter.fillPath(path, pressed_color) + # Draw icon inside the ellipse "hole" (on the right) if not self.icon_pixmap.isNull(): icon_margin = ellipse_size * 0.10 @@ -179,7 +160,7 @@ def paintEvent(self, e: QtGui.QPaintEvent | None) -> None: adjusted_y = ( left_icon_rect.y() + (left_icon_rect.height() - left_icon_scaled.height()) / 2.0 - ) + ) # <-- FIXED HERE adjusted_left_icon_rect = QtCore.QRectF( adjusted_x, adjusted_y, From 41c56d6b9d9f251e046a0bce4bface8b735e4d39 Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 25 Aug 2025 14:35:49 +0100 Subject: [PATCH 18/20] Refactor: optimized the code --- BlocksScreen/lib/panels/widgets/dialogPage.py | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/dialogPage.py b/BlocksScreen/lib/panels/widgets/dialogPage.py index 567a1ed7..98266d7c 100644 --- a/BlocksScreen/lib/panels/widgets/dialogPage.py +++ b/BlocksScreen/lib/panels/widgets/dialogPage.py @@ -20,36 +20,38 @@ def __init__( QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True ) # Make background transparent + app_instance = QtWidgets.QApplication.instance() + self.main_window = ( + app_instance.activeWindow() if app_instance else None + ) + if self.main_window is None and app_instance: + for widget in app_instance.allWidgets(): + if isinstance(widget, QtWidgets.QMainWindow): + self.main_window = widget + + offset = 0.7 + self.testwidth = int(self.main_window.width() * offset) + self.testheight = int(self.main_window.height() * offset) + self.setupUI() - self.repaint() def set_message(self, message: str) -> None: self.label.setText(message) def geometry_calc(self) -> None: - app_instance = QtWidgets.QApplication.instance() - main_window = app_instance.activeWindow() if app_instance else None - if main_window is None and app_instance: - for widget in app_instance.allWidgets(): - if isinstance(widget, QtWidgets.QMainWindow): - main_window = widget - - x_offset = 0.7 - y_offset = 0.7 + x = int( + self.main_window.geometry().x() + + (self.main_window.width() - self.testwidth) / 2 + ) - width = int(main_window.width() * x_offset) - height = int(main_window.height() * y_offset) - self.testwidth = width - self.testheight = height - x = int(main_window.geometry().x() + (main_window.width() - width) / 2) y = int( - main_window.geometry().y() + (main_window.height() - height) / 2 + self.main_window.geometry().y() + + (self.main_window.height() - self.testheight) / 2 ) - self.setGeometry(x, y, width, height) + self.setGeometry(x, y, self.testwidth, self.testheight) def paintEvent(self, event: QtGui.QPaintEvent) -> None: - self.geometry_calc() painter = QtGui.QPainter(self) painter.setRenderHint(QtGui.QPainter.RenderHint.Antialiasing, True) From 1efc1cb36897b09b45dbab36baf0b486fe0b368b Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 25 Aug 2025 14:48:05 +0100 Subject: [PATCH 19/20] Refactor: another Version of the UI --- BlocksScreen/lib/panels/widgets/dialogPage.py | 69 ++++++++----------- 1 file changed, 29 insertions(+), 40 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/dialogPage.py b/BlocksScreen/lib/panels/widgets/dialogPage.py index 98266d7c..c7ab9907 100644 --- a/BlocksScreen/lib/panels/widgets/dialogPage.py +++ b/BlocksScreen/lib/panels/widgets/dialogPage.py @@ -1,4 +1,5 @@ from PyQt6 import QtCore, QtGui, QtWidgets +from lib.utils.blocks_button import BlocksCustomButton class DialogPage(QtWidgets.QDialog): @@ -58,14 +59,23 @@ def paintEvent(self, event: QtGui.QPaintEvent) -> None: rect = self.rect() radius = 20 # Adjust the radius for rounded corners - # Set background color - painter.setBrush( - QtGui.QBrush(QtGui.QColor(63, 63, 63)) - ) # Semi-transparent dark gray + # Convert the QPoint returned by rect.center() to a QPointF + center_f = QtCore.QPointF(rect.center()) + + # Create a radial gradient + gradient = QtGui.QRadialGradient( + center_f, max(rect.width(), rect.height()) + ) + gradient.setColorAt( + 0.0, QtGui.QColor(50, 50, 50) + ) # Light gray in the center + gradient.setColorAt(1.0, QtGui.QColor(0, 0, 0)) # Black on the outside + + painter.setBrush(QtGui.QBrush(gradient)) # Set border color and width border_color = QtGui.QColor(128, 128, 128) # Gray color - border_width = 5 # Reduced border thickness + border_width = 1 # Reduced border thickness pen = QtGui.QPen() pen.setCapStyle(QtCore.Qt.PenCapStyle.RoundCap) @@ -104,12 +114,12 @@ def resizeEvent(self, event: QtGui.QResizeEvent) -> None: # Adjust button positions on resize self.confirm_button.setGeometry( - int(0), self.height() - 70, int(self.width() / 2), 70 + int(15), self.height() - 110, int(self.width() / 2) - 40, 70 ) self.cancel_button.setGeometry( - int(self.width() / 2), - self.height() - 70, - int(self.width() / 2), + int(self.width() / 2) + 15, + self.height() - 110, + int(self.width() / 2) - 40, 70, ) @@ -127,44 +137,23 @@ def setupUI(self) -> None: self.label.setWordWrap(True) # Create Confirm and Cancel buttons - self.confirm_button = QtWidgets.QPushButton("Confirm", self) - self.cancel_button = QtWidgets.QPushButton("Cancel", self) + self.confirm_button = BlocksCustomButton(self) + self.cancel_button = BlocksCustomButton(self) + + self.confirm_button.setText("Confirm") + self.cancel_button.setText("Cancel") # Set button styles button_font = QtGui.QFont() - button_font.setPointSize(14) + button_font.setPointSize(20) self.confirm_button.setFont(button_font) self.cancel_button.setFont(button_font) - # Apply styles for rounded corners - self.confirm_button.setStyleSheet( - """ - background-color: #4CAF50; - color: white; - border: none; - border-bottom-left-radius: 20px; - padding: 10px; - """ - ) - self.cancel_button.setStyleSheet( - """ - background-color: #F44336; - color: white; - border: none; - border-bottom-right-radius: 20px; - padding: 10px; - """ - ) - - # Position buttons - self.confirm_button.setGeometry( - int(0), self.height() - 70, int(self.width() / 2), 70 + self.confirm_button.setPixmap( + QtGui.QPixmap(":/dialog/media/btn_icons/yes.svg") ) - self.cancel_button.setGeometry( - int(self.width() / 2), - self.height() - 70, - int(self.width() / 2), - 70, + self.cancel_button.setPixmap( + QtGui.QPixmap(":/dialog/media/btn_icons/no.svg") ) # Connect button signals From aa2ad274a4c94b3842918f2440f8319d135363ec Mon Sep 17 00:00:00 2001 From: Roberto Martins Date: Mon, 25 Aug 2025 15:20:58 +0100 Subject: [PATCH 20/20] Refactor: Removed the border of the popup --- BlocksScreen/lib/panels/widgets/dialogPage.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/dialogPage.py b/BlocksScreen/lib/panels/widgets/dialogPage.py index c7ab9907..06aeff04 100644 --- a/BlocksScreen/lib/panels/widgets/dialogPage.py +++ b/BlocksScreen/lib/panels/widgets/dialogPage.py @@ -73,14 +73,6 @@ def paintEvent(self, event: QtGui.QPaintEvent) -> None: painter.setBrush(QtGui.QBrush(gradient)) - # Set border color and width - border_color = QtGui.QColor(128, 128, 128) # Gray color - border_width = 1 # Reduced border thickness - - pen = QtGui.QPen() - pen.setCapStyle(QtCore.Qt.PenCapStyle.RoundCap) - painter.setPen(QtGui.QPen(border_color, border_width)) - painter.drawRoundedRect(rect, radius, radius) painter.end()