From 9bb820e18445abcc3ad393313a38cbd879e9bb27 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Tue, 9 Dec 2025 20:09:19 +0000 Subject: [PATCH 1/7] refactor: migrated sensorsPanel.py sensor list from a QtWidgets.QListWidgetItem to a ListModelView Arq with some bugfixes Signed-off-by: Guilherme Costa --- .../lib/panels/widgets/sensorWidget.py | 208 +++++++-- .../lib/panels/widgets/sensorsPanel.py | 433 ++++++++++++------ 2 files changed, 456 insertions(+), 185 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/sensorWidget.py index 5223ac83..745f28ec 100644 --- a/BlocksScreen/lib/panels/widgets/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/sensorWidget.py @@ -1,4 +1,6 @@ +from ctypes import alignment import enum +import typing from lib.utils.blocks_label import BlocksLabel from lib.utils.toggleAnimatedButton import ToggleAnimatedButton @@ -30,6 +32,10 @@ class SensorState(enum.IntEnum): OFF = False ON = True + run_gcode_signal: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( + str, name="run_gcode" + ) + def __init__(self, parent, sensor_name: str): super(SensorWidget, self).__init__(parent) self.name = str(sensor_name).split(" ")[1] @@ -40,18 +46,22 @@ def __init__(self, parent, sensor_name: str): ) self.setObjectName(self.name) - self.setMinimumSize(parent.contentsRect().width(), 60) + self.setMinimumSize(250, 250) self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) self._sensor_type: SensorWidget.SensorType = self.SensorType.SWITCH self._flags: SensorWidget.SensorFlags = self.SensorFlags.CLICKABLE self.filament_state: SensorWidget.FilamentState = ( - SensorWidget.FilamentState.MISSING + SensorWidget.FilamentState.PRESENT + ) + self.sensor_state: SensorWidget.SensorState = ( + SensorWidget.SensorState.ON ) - self.sensor_state: SensorWidget.SensorState = SensorWidget.SensorState.OFF self._icon_label = None self._text_label = None - self._text: str = str(self.sensor_type.name) + " Sensor: " + str(self.name) + self._text: str = ( + f"{self.name}" + ) self._item_rect: QtCore.QRect = QtCore.QRect() self.icon_pixmap_fp: QtGui.QPixmap = QtGui.QPixmap( ":/filament_related/media/btn_icons/filament_sensor_turn_on.svg" @@ -59,7 +69,10 @@ def __init__(self, parent, sensor_name: str): self.icon_pixmap_fnp: QtGui.QPixmap = QtGui.QPixmap( ":/filament_related/media/btn_icons/filament_sensor_off.svg" ) - self._setupUI() + self.setupUI() + #self.toggle_button.stateChange.connect(self.toggle_button_state) + self.toggle_button.stateChange.connect(self.toggle_sensor_state) + @property def type(self) -> SensorType: @@ -89,12 +102,33 @@ def text(self, new_text) -> None: if self._text_label is not None: self._text_label.setText(f"{new_text}") self._text = new_text - - @QtCore.pyqtSlot(bool, name="change_fil_sensor_state") + + @QtCore.pyqtSlot(FilamentState, name="change_fil_sensor_state") def change_fil_sensor_state(self, state: FilamentState): """Change filament sensor state""" if isinstance(state, SensorWidget.FilamentState): - self.filament_state = state + if state == SensorWidget.FilamentState.PRESENT: + self.filament_state = SensorWidget.FilamentState.MISSING + else: + self.filament_state = SensorWidget.FilamentState.PRESENT + self.update() + + + def toggle_button_state(self, state: ToggleAnimatedButton.State) -> None: + if state.value != self.sensor_state.value: + self.sensor_state = self.SensorState(state.value) + self.toggle_button.state = ToggleAnimatedButton.State(self.sensor_state.value) + self.repaint() + + @QtCore.pyqtSlot(ToggleAnimatedButton.State, name="state-change") + def toggle_sensor_state(self, state: ToggleAnimatedButton.State) -> None: + if state.value != self.sensor_state.value: + self.sensor_state = self.SensorState(state.value) + self.run_gcode_signal.emit(f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={int(self.sensor_state.value)}") + self.repaint() + + def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: + return super().resizeEvent(a0) def paintEvent(self, a0: QtGui.QPaintEvent) -> None: """Re-implemented method, paint widget""" @@ -118,9 +152,9 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ) if self.filament_state == SensorWidget.FilamentState.PRESENT: - _color = QtGui.QColor(2, 204, 59, 100) + _color = QtGui.QColor(2, 204, 59, 200) else: - _color = QtGui.QColor(204, 50, 50, 100) + _color = QtGui.QColor(204, 50, 50, 200) _brush = QtGui.QBrush() _brush.setColor(_color) @@ -133,62 +167,140 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: if self.filament_state == self.FilamentState.PRESENT else self.icon_pixmap_fnp ) - background_rect = QtGui.QPainterPath() - background_rect.addRoundedRect( - self.contentsRect().toRectF(), - 15, - 15, - QtCore.Qt.SizeMode.AbsoluteSize, - ) - style_painter.setBrush(_brush) - style_painter.fillPath(background_rect, _brush) - style_painter.end() + _font = QtGui.QFont() + _font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) + _font.setPointSize(20) + style_painter.setFont(_font) + + if self.sensor_state == SensorWidget.SensorState.ON: + _color = QtGui.QColor(2, 204, 59, 200) + else: + _color = QtGui.QColor(204, 50, 50, 200) + + style_painter.setPen(_color) - @property - def toggle_sensor_gcode_command(self) -> str: - """Toggle filament sensor""" - self.sensor_state = ( - SensorWidget.SensorState.ON - if self.sensor_state == SensorWidget.SensorState.OFF - else SensorWidget.SensorState.OFF + label_name = self._text_label_name_ + label_detected = self._text_label_detected + label_state = self._text_label_state + + palette = label_name.palette() + palette.setColor(palette.ColorRole.WindowText,_color) + + style_painter.drawItemText( + label_name.geometry(), + label_name.alignment(), + palette, + True, + label_name.text(), + ) + + palette_as_needed = label_detected.palette() + palette_as_needed.setColor( + palette_as_needed.ColorRole.WindowText, QtGui.QColorConstants.White + ) + style_painter.setPen(QtGui.QColor("white")) + + _font.setPointSize(15) + style_painter.setFont(_font) + style_painter.drawItemText( + label_state.geometry(), + label_state.alignment(), + palette_as_needed, + True, + f"Filament: {self.filament_state.name}", ) - return str( - f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={not self.sensor_state.value}" + + style_painter.setFont(_font) + style_painter.drawItemText( + label_detected.geometry(), + label_detected.alignment(), + palette_as_needed, + True, + f"Enable: {self.sensor_state.name}" ) + style_painter.end() def _setupUI(self): _policy = QtWidgets.QSizePolicy.Policy.MinimumExpanding size_policy = QtWidgets.QSizePolicy(_policy, _policy) size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) - self.sensor_horizontal_layout = QtWidgets.QHBoxLayout() - self.sensor_horizontal_layout.setGeometry(QtCore.QRect(0, 0, 640, 60)) - self.sensor_horizontal_layout.setObjectName("sensorHorizontalLayout") + self.sensor_vertical_layout = QtWidgets.QVBoxLayout() + #self.sensor_vertical_layout.setGeometry(QtCore.QRect(0, 0, 640, 100)) + self.sensor_vertical_layout.setObjectName("sensorVerticalLayout") self._icon_label = BlocksLabel(self) size_policy.setHeightForWidth(self._icon_label.sizePolicy().hasHeightForWidth()) self._icon_label.setSizePolicy(size_policy) - self._icon_label.setMinimumSize(60, 60) - self._icon_label.setMaximumSize(60, 60) + self._icon_label.setMinimumSize(80, 80) + self._icon_label.setMaximumSize(80, 80) self._icon_label.setPixmap( self.icon_pixmap_fp if self.filament_state == self.FilamentState.PRESENT else self.icon_pixmap_fnp ) - self.sensor_horizontal_layout.addWidget(self._icon_label) - self._text_label = QtWidgets.QLabel(parent=self) - size_policy.setHeightForWidth(self._text_label.sizePolicy().hasHeightForWidth()) - self._text_label.setMinimumSize(100, 60) - self._text_label.setMaximumSize(500, 60) + self._text_label_name_ = QtWidgets.QLabel(parent=self) + size_policy.setHeightForWidth( + self._text_label_name_.sizePolicy().hasHeightForWidth() + ) + self._text_label_name_.setMinimumSize(self.rect().width(), 60) + self._text_label_name_.setMaximumSize(self.rect().width(), 60) + self._text_label_name_.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + palette = self._text_label_name_.palette() + palette.setColor( + palette.ColorRole.WindowText, QtGui.QColorConstants.Transparent + ) + self._text_label_name_.setPalette(palette) + self._text_label_name_.setText(str(self._text)) + self._icon_label.setSizePolicy(size_policy) + #LABEL 2 + self._text_label_detected = QtWidgets.QLabel(parent=self) + size_policy.setHeightForWidth( + self._text_label_detected.sizePolicy().hasHeightForWidth() + ) + self._text_label_detected.setMinimumSize(self.rect().width(), 60) + self._text_label_detected.setMaximumSize(self.rect().width(), 60) + _font = QtGui.QFont() _font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - _font.setPointSize(18) - palette = self._text_label.palette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColorConstants.White) - self._text_label.setPalette(palette) - self._text_label.setFont(_font) - self._text_label.setText(str(self._text)) - self.sensor_horizontal_layout.addWidget(self._text_label) + _font.setPointSize(12) + palette_as_needed = self._text_label_detected.palette() + palette_as_needed.setColor( + palette_as_needed.ColorRole.WindowText, QtGui.QColorConstants.Transparent + ) + filament_state = not self.filament_state + self._text_label_detected.setPalette(palette_as_needed) + self._text_label_detected.setFont(_font) + self._text_label_detected.setText(f"Filament: {self.filament_state}") + + #LABEL 3 + self._text_label_state = QtWidgets.QLabel(parent=self) + size_policy.setHeightForWidth( + self._text_label_state.sizePolicy().hasHeightForWidth() + ) + self._text_label_state.setMinimumSize(self.rect().width(), 60) + self._text_label_state.setMaximumSize(self.rect().width(), 60) + + self._text_label_state.setPalette(palette_as_needed) + self._text_label_state.setFont(_font) + self._text_label_state.setText(f"Enable: {self.sensor_state.name}") + + + self._text_label_name_.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self._text_label_state.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self._text_label_detected.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + + + + self._icon_label.setSizePolicy(size_policy) self.toggle_button = ToggleAnimatedButton(self) self.toggle_button.setMaximumWidth(100) - self.sensor_horizontal_layout.addWidget(self.toggle_button) - self.setLayout(self.sensor_horizontal_layout) + self.toggle_button.state = ToggleAnimatedButton.State.ON + + self._text_label_detected.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self._icon_label,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self._text_label_name_, alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self._text_label_state,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self._text_label_detected,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self.toggle_button) + + self.setLayout(self.sensor_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 51a5b2c1..cc404c86 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -1,7 +1,13 @@ +from dataclasses import astuple import typing +import logger +from lib.panels.widgets.loadPage import LoadScreen +from lib.utils.blocks_frame import BlocksCustomFrame +from lib.utils.icon_button import IconButton from lib.panels.widgets.sensorWidget import SensorWidget from lib.utils.icon_button import IconButton +from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem from PyQt6 import QtCore, QtGui, QtWidgets @@ -19,14 +25,25 @@ class SensorsWindow(QtWidgets.QWidget): def __init__(self, parent): super(SensorsWindow, self).__init__(parent) - self._setupUi() - self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True) + self.model = EntryListModel() + self.entry_delegate = EntryDelegate() + self.sensor_tracking_widget = {} + self.current_widget = None + self.setupUi() + 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) + def reset_view_model(self) -> None: + """Clears items from ListView + (Resets `QAbstractListModel` by clearing entries) + """ + self.model.clear() + self.entry_delegate.clear() + @QtCore.pyqtSlot(dict, name="handle_available_fil_sensors") def handle_available_fil_sensors(self, sensors: dict) -> None: """Handle available filament sensors, create `SensorWidget` for each detected @@ -34,6 +51,7 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: """ if not isinstance(sensors, dict): return + self.reset_view_model() filtered_sensors = list( filter( lambda printer_obj: str(printer_obj).startswith( @@ -44,51 +62,46 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: ) ) if filtered_sensors: - self.fs_sensors_list.setRowHidden(self.fs_sensors_list.row(self.item), True) self.sensor_list = [ self.create_sensor_widget(name=sensor) for sensor in filtered_sensors ] else: - self.fs_sensors_list.setRowHidden( - self.fs_sensors_list.row(self.item), False - ) + self.no_update_placeholder.show() + + @QtCore.pyqtSlot(str, str, bool, name="handle_fil_state_change") def handle_fil_state_change( self, sensor_name: str, parameter: str, value: bool ) -> None: - """Handle filament state chage""" - if sensor_name in self.sensor_list: - _split = sensor_name.split(" ") - _item = self.fs_sensors_list.findChild( - SensorWidget, - name=_split[1], - options=QtCore.Qt.FindChildOption.FindChildrenRecursively, - ) + _item = self.sensor_tracking_widget[sensor_name] + if _item: if parameter == "filament_detected": - if isinstance(_item, SensorWidget) and hasattr( - _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) - _item.repaint() + state = SensorWidget.FilamentState(not value) + _item.change_fil_sensor_state( + state + ) elif parameter == "enabled": - if _item and isinstance(_item, SensorWidget): - self.run_gcode_signal.emit(_item.toggle_sensor_gcode_command) - - @QtCore.pyqtSlot(QtWidgets.QListWidgetItem, name="handle_sensor_clicked") - def handle_sensor_clicked(self, sensor: QtWidgets.QListWidgetItem) -> None: - """Handle filament sensor clicked""" - _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) + _item.toggle_button_state(SensorWidget.SensorState(bool(value))) + + def showEvent(self, event: QtGui.QShowEvent | None) -> None: + """Re-add clients to update list""" + return super().showEvent(event) + + + @QtCore.pyqtSlot(ListItem, name="on-item-clicked") + def on_item_clicked(self, item: ListItem) -> None: + """Setup information for the currently clicked list item on the info box. + Keeps track of the list item + """ + if not item: + return + + self.current_widget.hide() + name_id = item.text + self.current_widget = self.sensor_tracking_widget[name_id] + self.current_widget.show() + def create_sensor_widget(self, name: str) -> SensorWidget: """Creates a sensor row to be added to the QListWidget @@ -96,132 +109,278 @@ def create_sensor_widget(self, name: str) -> SensorWidget: Args: name (str): The name of the filament sensor object """ - _item_widget = SensorWidget(self.fs_sensors_list, name) - _list_item = QtWidgets.QListWidgetItem() - _list_item.setFlags(~QtCore.Qt.ItemFlag.ItemIsEditable) - _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) - ) + _item_widget = SensorWidget(self.infobox_frame, name) + self.info_box_layout.addWidget(_item_widget) + + + if self.current_widget: + _item_widget.hide() + else: + _item_widget.show() + self.current_widget = _item_widget + + name_id = str(name).split(" ")[1] - self.fs_sensors_list.setItemWidget(_list_item, _item_widget) + item = ListItem( + text=name_id, + right_text="", + right_icon=None, + left_icon=None, + callback= None, + selected=False, + allow_check=False, + _lfontsize=17, + _rfontsize=12, + height=80, + notificate=False + ) + _item_widget.run_gcode_signal.connect(self.run_gcode_signal) + self.sensor_tracking_widget[name_id] = _item_widget + self.model.add_item(item) + return _item_widget - def _setupUi(self): - self.setObjectName("filament_sensors_page") + def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ... + + def setupUi(self) -> None: + """Setup UI for updatePage""" + font_id = QtGui.QFontDatabase.addApplicationFont( + ":/font/media/fonts for text/Momcake-Bold.ttf" + ) + font_family = QtGui.QFontDatabase.applicationFontFamilies(font_id)[0] sizePolicy = QtWidgets.QSizePolicy( QtWidgets.QSizePolicy.Policy.MinimumExpanding, QtWidgets.QSizePolicy.Policy.MinimumExpanding, ) - self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) + sizePolicy.setHorizontalStretch(1) + sizePolicy.setVerticalStretch(1) self.setSizePolicy(sizePolicy) - self.setMinimumSize(QtCore.QSize(710, 410)) + self.setMinimumSize(QtCore.QSize(710, 400)) self.setMaximumSize(QtCore.QSize(720, 420)) - self.content_vertical_layout = QtWidgets.QVBoxLayout() - self.content_vertical_layout.setObjectName("contentVerticalLayout") - self.fs_header_layout = QtWidgets.QHBoxLayout() - self.fs_header_layout.setContentsMargins(0, 0, 0, 0) - self.fs_header_layout.setObjectName("fs_header_layout") - self.fs_header_layout.setGeometry(QtCore.QRect(10, 10, 691, 71)) - self.fs_page_title = QtWidgets.QLabel(parent=self) - sizePolicy.setHeightForWidth( - self.fs_page_title.sizePolicy().hasHeightForWidth() - ) - self.fs_page_title.setSizePolicy(sizePolicy) - self.fs_page_title.setMinimumSize(QtCore.QSize(300, 71)) - self.fs_page_title.setMaximumSize(QtCore.QSize(16777215, 71)) + self.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.update_page_content_layout = QtWidgets.QVBoxLayout() + self.update_page_content_layout.setContentsMargins(15, 15, 2, 2) + + self.header_content_layout = QtWidgets.QHBoxLayout() + self.header_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop) + self.fs_page_title = QtWidgets.QLabel(self) + self.fs_page_title.setMinimumSize(QtCore.QSize(100, 60)) + self.fs_page_title.setMaximumSize(QtCore.QSize(16777215, 60)) font = QtGui.QFont() - font.setPointSize(22) - palette = QtGui.QPalette() - palette.setColor(palette.ColorRole.WindowText, QtGui.QColorConstants.White) - self.fs_page_title.setPalette(palette) + font.setFamily(font_family) + font.setPointSize(24) + palette = self.fs_page_title.palette() + palette.setColor(palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")) self.fs_page_title.setFont(font) + self.fs_page_title.setPalette(palette) + self.fs_page_title.setLayoutDirection(QtCore.Qt.LayoutDirection.RightToLeft) + self.fs_page_title.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) self.fs_page_title.setObjectName("fs_page_title") - self.fs_header_layout.addWidget(self.fs_page_title, 0) + self.fs_page_title.setText("Filament Sensors") + self.header_content_layout.addWidget(self.fs_page_title, 0) self.fs_back_button = IconButton(self) - sizePolicy.setHeightForWidth( - self.fs_back_button.sizePolicy().hasHeightForWidth() - ) - self.fs_back_button.setSizePolicy(sizePolicy) self.fs_back_button.setMinimumSize(QtCore.QSize(60, 60)) self.fs_back_button.setMaximumSize(QtCore.QSize(60, 60)) self.fs_back_button.setFlat(True) self.fs_back_button.setPixmap(QtGui.QPixmap(":/ui/media/btn_icons/back.svg")) - self.fs_back_button.setObjectName("fs_back_button") - self.fs_header_layout.addWidget( - self.fs_back_button, - 0, + self.header_content_layout.addWidget(self.fs_back_button, 0) + self.update_page_content_layout.addLayout(self.header_content_layout, 0) + + self.main_content_layout = QtWidgets.QHBoxLayout() + self.main_content_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + + self.sensor_buttons_frame = BlocksCustomFrame(self) + + self.sensor_buttons_frame.setMinimumSize(QtCore.QSize(320, 300)) + self.sensor_buttons_frame.setMaximumSize(QtCore.QSize(450, 500)) + + palette = QtGui.QPalette() + brush = QtGui.QBrush(QtGui.QColor(0, 0, 0, 0)) + brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) + palette.setBrush( + QtGui.QPalette.ColorGroup.Active, + QtGui.QPalette.ColorRole.Button, + brush, ) - self.content_vertical_layout.addLayout(self.fs_header_layout) - self.fs_sensors_list = QtWidgets.QListWidget(self) - sizePolicy = QtWidgets.QSizePolicy( - QtWidgets.QSizePolicy.Policy.MinimumExpanding, - QtWidgets.QSizePolicy.Policy.MinimumExpanding, + 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, ) - sizePolicy.setHorizontalStretch(1) - sizePolicy.setVerticalStretch(1) - sizePolicy.setHeightForWidth( - self.fs_sensors_list.sizePolicy().hasHeightForWidth() + 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, ) - self.fs_sensors_list.setSizePolicy(sizePolicy) - self.fs_sensors_list.setMinimumSize(QtCore.QSize(650, 300)) - self.fs_sensors_list.setMaximumSize(QtCore.QSize(700, 300)) - self.fs_sensors_list.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) - self.fs_sensors_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) - self.fs_sensors_list.setObjectName("fs_sensors_list") - self.fs_sensors_list.setViewMode(self.fs_sensors_list.ViewMode.ListMode) - self.fs_sensors_list.setItemAlignment( - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignVCenter - ) - self.fs_sensors_list.setFlow(self.fs_sensors_list.Flow.TopToBottom) - self.fs_sensors_list.setFrameStyle(0) - palette = self.fs_sensors_list.palette() - palette.setColor(palette.ColorRole.Base, QtGui.QColorConstants.Transparent) + 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.fs_sensors_list = QtWidgets.QListView(self.sensor_buttons_frame) + self.fs_sensors_list.setModel(self.model) + self.fs_sensors_list.setItemDelegate(self.entry_delegate) + self.entry_delegate.item_selected.connect(self.on_item_clicked) + self.fs_sensors_list.setMouseTracking(True) + self.fs_sensors_list.setTabletTracking(True) + self.fs_sensors_list.setSpacing(7) self.fs_sensors_list.setPalette(palette) - self.fs_sensors_list.setDropIndicatorShown(False) - self.fs_sensors_list.setAcceptDrops(False) + self.fs_sensors_list.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus) + self.fs_sensors_list.setStyleSheet("background-color:transparent") + self.fs_sensors_list.setFrameShadow(QtWidgets.QFrame.Shadow.Sunken) + self.fs_sensors_list.setMinimumSize(self.sensor_buttons_frame.size()) + self.fs_sensors_list.setFrameShape(QtWidgets.QFrame.Shape.NoFrame) + self.fs_sensors_list.setVerticalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.fs_sensors_list.setHorizontalScrollBarPolicy( + QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff + ) + self.fs_sensors_list.setSizeAdjustPolicy( + QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents + ) + self.fs_sensors_list.setAutoScroll(False) self.fs_sensors_list.setProperty("showDropIndicator", False) - self.content_vertical_layout.setStretch(0, 0) - self.content_vertical_layout.setStretch(1, 1) - self.content_vertical_layout.addWidget( + self.fs_sensors_list.setDefaultDropAction( + QtCore.Qt.DropAction.IgnoreAction + ) + self.fs_sensors_list.setAlternatingRowColors(False) + self.fs_sensors_list.setSelectionMode( + QtWidgets.QAbstractItemView.SelectionMode.NoSelection + ) + self.fs_sensors_list.setSelectionBehavior( + QtWidgets.QAbstractItemView.SelectionBehavior.SelectItems + ) + self.fs_sensors_list.setVerticalScrollMode( + QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + ) + self.fs_sensors_list.setHorizontalScrollMode( + QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel + ) + QtWidgets.QScroller.grabGesture( self.fs_sensors_list, - 1, - QtCore.Qt.AlignmentFlag.AlignHCenter | QtCore.Qt.AlignmentFlag.AlignVCenter, + QtWidgets.QScroller.ScrollerGestureType.TouchGesture, ) - - font = QtGui.QFont() - font.setPointSize(25) - - self.item = QtWidgets.QListWidgetItem() - self.item.setSizeHint( - QtCore.QSize(self.fs_sensors_list.width(), self.fs_sensors_list.height()) + QtWidgets.QScroller.grabGesture( + self.fs_sensors_list, + QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture, ) + self.sensor_buttons_layout = QtWidgets.QVBoxLayout() + self.sensor_buttons_layout.setContentsMargins(15, 20, 20, 5) + self.sensor_buttons_layout.addWidget(self.fs_sensors_list, 0) + self.sensor_buttons_frame.setLayout(self.sensor_buttons_layout) - self.label = QtWidgets.QLabel("No sensors found") - self.label.setFont(font) - self.label.setStyleSheet("color: gray;") - self.label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.label.hide() - - self.fs_sensors_list.addItem(self.item) - self.fs_sensors_list.setItemWidget(self.item, self.label) + self.main_content_layout.addWidget(self.sensor_buttons_frame, 0) + + self.infobox_frame = BlocksCustomFrame() + self.infobox_frame.setMinimumSize(QtCore.QSize(250, 300)) + self.infobox_frame.setMaximumSize(QtCore.QSize(450, 500)) - self.content_vertical_layout.addSpacing(5) - self.setLayout(self.content_vertical_layout) - self._retranslateUi() + self.info_box_layout = QtWidgets.QVBoxLayout() + self.info_box_layout.setContentsMargins(0, 0, 0, 0) - def _retranslateUi(self): - _translate = QtCore.QCoreApplication.translate - self.setWindowTitle(_translate("filament_sensors_page", "Form")) - self.fs_page_title.setText( - _translate("filament_sensors_page", "Filament Sensors") - ) - self.fs_back_button.setProperty( - "button_type", _translate("filament_sensors_page", "icon") + font = QtGui.QFont() + font.setFamily(font_family) + font.setPointSize(20) + self.version_box = QtWidgets.QHBoxLayout() + self.no_update_placeholder = QtWidgets.QLabel(self) + self.no_update_placeholder.setMinimumSize(QtCore.QSize(200, 60)) + self.no_update_placeholder.setMaximumSize(QtCore.QSize(300, 60)) + self.no_update_placeholder.setFont(font) + self.no_update_placeholder.setPalette(palette) + self.no_update_placeholder.setSizePolicy(sizePolicy) + self.no_update_placeholder.setText("No Sensors Available") + self.no_update_placeholder.setWordWrap(True) + self.no_update_placeholder.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) + self.info_box_layout.addWidget( + self.no_update_placeholder, 0, QtCore.Qt.AlignmentFlag.AlignBottom ) + self.no_update_placeholder.hide() + self.infobox_frame.setLayout(self.info_box_layout) + self.main_content_layout.addWidget(self.infobox_frame, 1) + self.update_page_content_layout.addLayout(self.main_content_layout, 1) + self.setLayout(self.update_page_content_layout) \ No newline at end of file From 2a477aae06022760054ea88ec02e9bb31f7fd214 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Wed, 10 Dec 2025 12:50:01 +0000 Subject: [PATCH 2/7] sensors: resolve bugs and some cleanup Signed-off-by: Guilherme Costa --- .../lib/panels/widgets/sensorWidget.py | 128 ++++++------------ .../lib/panels/widgets/sensorsPanel.py | 20 +-- 2 files changed, 54 insertions(+), 94 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/sensorWidget.py index 745f28ec..d3d7192d 100644 --- a/BlocksScreen/lib/panels/widgets/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/sensorWidget.py @@ -1,4 +1,3 @@ -from ctypes import alignment import enum import typing @@ -37,7 +36,7 @@ class SensorState(enum.IntEnum): ) def __init__(self, parent, sensor_name: str): - super(SensorWidget, self).__init__(parent) + super().__init__(parent) self.name = str(sensor_name).split(" ")[1] self.sensor_type: SensorWidget.SensorType = ( self.SensorType.SWITCH @@ -59,9 +58,7 @@ def __init__(self, parent, sensor_name: str): ) self._icon_label = None self._text_label = None - self._text: str = ( - f"{self.name}" - ) + self._text = self.name self._item_rect: QtCore.QRect = QtCore.QRect() self.icon_pixmap_fp: QtGui.QPixmap = QtGui.QPixmap( ":/filament_related/media/btn_icons/filament_sensor_turn_on.svg" @@ -70,7 +67,6 @@ def __init__(self, parent, sensor_name: str): ":/filament_related/media/btn_icons/filament_sensor_off.svg" ) self.setupUI() - #self.toggle_button.stateChange.connect(self.toggle_button_state) self.toggle_button.stateChange.connect(self.toggle_sensor_state) @@ -105,13 +101,10 @@ def text(self, new_text) -> None: @QtCore.pyqtSlot(FilamentState, name="change_fil_sensor_state") def change_fil_sensor_state(self, state: FilamentState): - """Change filament sensor state""" - if isinstance(state, SensorWidget.FilamentState): - if state == SensorWidget.FilamentState.PRESENT: - self.filament_state = SensorWidget.FilamentState.MISSING - else: - self.filament_state = SensorWidget.FilamentState.PRESENT - self.update() + if not isinstance(state, SensorWidget.FilamentState): + return + self.filament_state = SensorWidget.FilamentState(not state.value) + self.update() def toggle_button_state(self, state: ToggleAnimatedButton.State) -> None: @@ -150,17 +143,6 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: style_painter.setRenderHint( style_painter.RenderHint.LosslessImageRendering, True ) - - if self.filament_state == SensorWidget.FilamentState.PRESENT: - _color = QtGui.QColor(2, 204, 59, 200) - else: - _color = QtGui.QColor(204, 50, 50, 200) - _brush = QtGui.QBrush() - _brush.setColor(_color) - - _brush.setStyle(QtCore.Qt.BrushStyle.SolidPattern) - pen = style_painter.pen() - pen.setStyle(QtCore.Qt.PenStyle.NoPen) if self._icon_label: self._icon_label.setPixmap( self.icon_pixmap_fp @@ -168,55 +150,48 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: else self.icon_pixmap_fnp ) _font = QtGui.QFont() - _font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) _font.setPointSize(20) style_painter.setFont(_font) - - if self.sensor_state == SensorWidget.SensorState.ON: - _color = QtGui.QColor(2, 204, 59, 200) - else: - _color = QtGui.QColor(204, 50, 50, 200) - - style_painter.setPen(_color) label_name = self._text_label_name_ label_detected = self._text_label_detected label_state = self._text_label_state palette = label_name.palette() - palette.setColor(palette.ColorRole.WindowText,_color) - + palette.setColor( + palette.ColorRole.WindowText, QtGui.QColorConstants.White + ) style_painter.drawItemText( label_name.geometry(), label_name.alignment(), palette, True, label_name.text(), + QtGui.QPalette.ColorRole.WindowText ) - palette_as_needed = label_detected.palette() - palette_as_needed.setColor( - palette_as_needed.ColorRole.WindowText, QtGui.QColorConstants.White - ) - style_painter.setPen(QtGui.QColor("white")) - - _font.setPointSize(15) + _font.setPointSize(16) style_painter.setFont(_font) + filament_text = self.filament_state.name.capitalize() + tab_spacer = 12 * "\t" style_painter.drawItemText( label_state.geometry(), label_state.alignment(), - palette_as_needed, + palette, True, - f"Filament: {self.filament_state.name}", + f"Filament: {tab_spacer}{filament_text}", + QtGui.QPalette.ColorRole.WindowText ) - style_painter.setFont(_font) + sensor_state_text = self.sensor_state.name.capitalize() + tab_spacer += 3 * "\t" style_painter.drawItemText( label_detected.geometry(), label_detected.alignment(), - palette_as_needed, + palette, True, - f"Enable: {self.sensor_state.name}" + f"Enable: {tab_spacer}{sensor_state_text}", + QtGui.QPalette.ColorRole.WindowText ) style_painter.end() @@ -226,13 +201,16 @@ def _setupUI(self): size_policy.setHeightForWidth(self.sizePolicy().hasHeightForWidth()) self.setSizePolicy(size_policy) self.sensor_vertical_layout = QtWidgets.QVBoxLayout() - #self.sensor_vertical_layout.setGeometry(QtCore.QRect(0, 0, 640, 100)) self.sensor_vertical_layout.setObjectName("sensorVerticalLayout") self._icon_label = BlocksLabel(self) - size_policy.setHeightForWidth(self._icon_label.sizePolicy().hasHeightForWidth()) + size_policy.setHeightForWidth( + self._icon_label.sizePolicy().hasHeightForWidth() + ) + parent_width = self.parentWidget().width() self._icon_label.setSizePolicy(size_policy) - self._icon_label.setMinimumSize(80, 80) - self._icon_label.setMaximumSize(80, 80) + self._icon_label.setMinimumSize(120, 100) + self._icon_label.setMinimumSize(120, 100) + self._icon_label.setPixmap( self.icon_pixmap_fp if self.filament_state == self.FilamentState.PRESENT @@ -242,8 +220,7 @@ def _setupUI(self): size_policy.setHeightForWidth( self._text_label_name_.sizePolicy().hasHeightForWidth() ) - self._text_label_name_.setMinimumSize(self.rect().width(), 60) - self._text_label_name_.setMaximumSize(self.rect().width(), 60) + self._text_label_name_.setMinimumSize(self.rect().width(), 40) self._text_label_name_.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) palette = self._text_label_name_.palette() palette.setColor( @@ -252,55 +229,38 @@ def _setupUI(self): self._text_label_name_.setPalette(palette) self._text_label_name_.setText(str(self._text)) self._icon_label.setSizePolicy(size_policy) - #LABEL 2 + self._text_label_detected = QtWidgets.QLabel(parent=self) size_policy.setHeightForWidth( self._text_label_detected.sizePolicy().hasHeightForWidth() ) - self._text_label_detected.setMinimumSize(self.rect().width(), 60) - self._text_label_detected.setMaximumSize(self.rect().width(), 60) + self._text_label_detected.setMinimumSize(parent_width, 20) - _font = QtGui.QFont() - _font.setStyleStrategy(QtGui.QFont.StyleStrategy.PreferAntialias) - _font.setPointSize(12) - palette_as_needed = self._text_label_detected.palette() - palette_as_needed.setColor( - palette_as_needed.ColorRole.WindowText, QtGui.QColorConstants.Transparent - ) - filament_state = not self.filament_state - self._text_label_detected.setPalette(palette_as_needed) - self._text_label_detected.setFont(_font) + + self._text_label_detected.setPalette(palette) self._text_label_detected.setText(f"Filament: {self.filament_state}") - #LABEL 3 self._text_label_state = QtWidgets.QLabel(parent=self) size_policy.setHeightForWidth( self._text_label_state.sizePolicy().hasHeightForWidth() ) - self._text_label_state.setMinimumSize(self.rect().width(), 60) - self._text_label_state.setMaximumSize(self.rect().width(), 60) + self._text_label_state.setMinimumSize(parent_width, 20) - self._text_label_state.setPalette(palette_as_needed) - self._text_label_state.setFont(_font) + self._text_label_state.setPalette(palette) self._text_label_state.setText(f"Enable: {self.sensor_state.name}") - - self._text_label_name_.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self._text_label_state.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self._text_label_detected.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - - - self._icon_label.setSizePolicy(size_policy) self.toggle_button = ToggleAnimatedButton(self) - self.toggle_button.setMaximumWidth(100) + self.toggle_button.setMinimumSize(100,50) self.toggle_button.state = ToggleAnimatedButton.State.ON - self._text_label_detected.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self._icon_label,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self._text_label_name_, alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self._text_label_state,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self._text_label_detected,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self.toggle_button) + self.sensor_vertical_layout.addWidget(self._icon_label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget(self._text_label_name_,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addStretch() + self.sensor_vertical_layout.addWidget(self._text_label_state,alignment=QtCore.Qt.AlignmentFlag.AlignLeft) + self.sensor_vertical_layout.addStretch() + self.sensor_vertical_layout.addWidget(self._text_label_detected,alignment=QtCore.Qt.AlignmentFlag.AlignLeft) + self.sensor_vertical_layout.addStretch() + self.sensor_vertical_layout.addWidget(self.toggle_button,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) self.setLayout(self.sensor_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index cc404c86..777bc1b9 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -1,12 +1,8 @@ -from dataclasses import astuple import typing -import logger -from lib.panels.widgets.loadPage import LoadScreen from lib.utils.blocks_frame import BlocksCustomFrame from lib.utils.icon_button import IconButton from lib.panels.widgets.sensorWidget import SensorWidget -from lib.utils.icon_button import IconButton from lib.utils.list_model import EntryDelegate, EntryListModel, ListItem from PyQt6 import QtCore, QtGui, QtWidgets @@ -21,14 +17,13 @@ class SensorsWindow(QtWidgets.QWidget): request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( name="request_back" ) - sensor_list: list[SensorWidget] = [] - def __init__(self, parent): super(SensorsWindow, self).__init__(parent) self.model = EntryListModel() self.entry_delegate = EntryDelegate() self.sensor_tracking_widget = {} self.current_widget = None + self.sensor_list: list[SensorWidget] = [] self.setupUi() self.setAttribute( QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True @@ -74,7 +69,7 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: def handle_fil_state_change( self, sensor_name: str, parameter: str, value: bool ) -> None: - _item = self.sensor_tracking_widget[sensor_name] + _item = self.sensor_tracking_widget.get(sensor_name) if _item: if parameter == "filament_detected": state = SensorWidget.FilamentState(not value) @@ -82,7 +77,7 @@ def handle_fil_state_change( state ) elif parameter == "enabled": - _item.toggle_button_state(SensorWidget.SensorState(bool(value))) + _item.toggle_button_state(SensorWidget.SensorState(value)) def showEvent(self, event: QtGui.QShowEvent | None) -> None: """Re-add clients to update list""" @@ -97,9 +92,14 @@ def on_item_clicked(self, item: ListItem) -> None: if not item: return - self.current_widget.hide() + if self.current_widget: + self.current_widget.hide() + name_id = item.text - self.current_widget = self.sensor_tracking_widget[name_id] + current_widget = self.sensor_tracking_widget.get(name_id) + if current_widget is None: + return + self.current_widget = current_widget self.current_widget.show() From 01599241c412dbb17b04e493c9106f3e1a3c6871 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Wed, 10 Dec 2025 17:36:33 +0000 Subject: [PATCH 3/7] sensors: add cutter sensor handling and visual update for list item Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/sensorsPanel.py | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 777bc1b9..5867ae3d 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -48,12 +48,10 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: return self.reset_view_model() filtered_sensors = list( - filter( - lambda printer_obj: str(printer_obj).startswith( - "filament_switch_sensor" - ) - or str(printer_obj).startswith("filament_motion_sensor"), - sensors.keys(), + filter( + lambda printer_obj: str(printer_obj).startswith("filament_switch_sensor") + or str(printer_obj).startswith("filament_motion_sensor") or str(printer_obj).startswith("cutter_sensor"), + sensors.keys(), ) ) if filtered_sensors: @@ -118,14 +116,11 @@ def create_sensor_widget(self, name: str) -> SensorWidget: else: _item_widget.show() self.current_widget = _item_widget - name_id = str(name).split(" ")[1] - - item = ListItem( text=name_id, right_text="", - right_icon=None, + right_icon=self.pixmap, left_icon=None, callback= None, selected=False, @@ -379,6 +374,7 @@ def setupUi(self) -> None: self.info_box_layout.addWidget( self.no_update_placeholder, 0, QtCore.Qt.AlignmentFlag.AlignBottom ) + self.pixmap = QtGui.QPixmap(":/ui/media/btn_icons/info.svg") self.no_update_placeholder.hide() self.infobox_frame.setLayout(self.info_box_layout) self.main_content_layout.addWidget(self.infobox_frame, 1) From 4797287f412cc78d461f7178853f1d1e0176ca67 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Thu, 11 Dec 2025 15:44:00 +0000 Subject: [PATCH 4/7] code cleanup and formatting Signed-off-by: Guilherme Costa --- .../lib/panels/widgets/sensorWidget.py | 93 +++++++++---------- .../lib/panels/widgets/sensorsPanel.py | 60 +++++------- 2 files changed, 71 insertions(+), 82 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/sensorWidget.py index d3d7192d..705a19ce 100644 --- a/BlocksScreen/lib/panels/widgets/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/sensorWidget.py @@ -53,9 +53,7 @@ def __init__(self, parent, sensor_name: str): self.filament_state: SensorWidget.FilamentState = ( SensorWidget.FilamentState.PRESENT ) - self.sensor_state: SensorWidget.SensorState = ( - SensorWidget.SensorState.ON - ) + self.sensor_state: SensorWidget.SensorState = SensorWidget.SensorState.ON self._icon_label = None self._text_label = None self._text = self.name @@ -68,7 +66,6 @@ def __init__(self, parent, sensor_name: str): ) self.setupUI() self.toggle_button.stateChange.connect(self.toggle_sensor_state) - @property def type(self) -> SensorType: @@ -98,43 +95,40 @@ def text(self, new_text) -> None: if self._text_label is not None: self._text_label.setText(f"{new_text}") self._text = new_text - + @QtCore.pyqtSlot(FilamentState, name="change_fil_sensor_state") def change_fil_sensor_state(self, state: FilamentState): + """Invert the filament state in response to a Klipper update""" if not isinstance(state, SensorWidget.FilamentState): return self.filament_state = SensorWidget.FilamentState(not state.value) self.update() - - + def toggle_button_state(self, state: ToggleAnimatedButton.State) -> None: + """Called when the Klipper firmware reports an update to the filament sensor state""" if state.value != self.sensor_state.value: self.sensor_state = self.SensorState(state.value) - self.toggle_button.state = ToggleAnimatedButton.State(self.sensor_state.value) + self.toggle_button.state = ToggleAnimatedButton.State( + self.sensor_state.value + ) self.repaint() - - @QtCore.pyqtSlot(ToggleAnimatedButton.State, name="state-change") + + @QtCore.pyqtSlot(ToggleAnimatedButton.State, name="state-change") def toggle_sensor_state(self, state: ToggleAnimatedButton.State) -> None: + """Emit the appropriate G-Code command to change the filament sensor state.""" if state.value != self.sensor_state.value: self.sensor_state = self.SensorState(state.value) - self.run_gcode_signal.emit(f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={int(self.sensor_state.value)}") + self.run_gcode_signal.emit( + f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={int(self.sensor_state.value)}" + ) self.repaint() - + def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: + """Handle widget resize events.""" return super().resizeEvent(a0) def paintEvent(self, a0: QtGui.QPaintEvent) -> None: """Re-implemented method, paint widget""" - # if ( - # self._scaled_select_on_pixmap is not None - # and self._scaled_select_off_pixmap is not None - # ): # Update the toggle button pixmap which indicates the sensor state - # self._button_icon_label.setPixmap( - # self._scaled_select_on_pixmap - # if self.sensor_state == SensorWidget.SensorState.ON - # else self._scaled_select_off_pixmap - # ) - style_painter = QtWidgets.QStylePainter(self) style_painter.setRenderHint(style_painter.RenderHint.Antialiasing, True) style_painter.setRenderHint( @@ -153,23 +147,21 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: _font.setPointSize(20) style_painter.setFont(_font) - label_name = self._text_label_name_ - label_detected = self._text_label_detected - label_state = self._text_label_state + label_name = self._text_label_name_ + label_detected = self._text_label_detected + label_state = self._text_label_state palette = label_name.palette() - palette.setColor( - palette.ColorRole.WindowText, QtGui.QColorConstants.White - ) + palette.setColor(palette.ColorRole.WindowText, QtGui.QColorConstants.White) style_painter.drawItemText( label_name.geometry(), label_name.alignment(), palette, True, label_name.text(), - QtGui.QPalette.ColorRole.WindowText + QtGui.QPalette.ColorRole.WindowText, ) - + _font.setPointSize(16) style_painter.setFont(_font) filament_text = self.filament_state.name.capitalize() @@ -180,9 +172,9 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: palette, True, f"Filament: {tab_spacer}{filament_text}", - QtGui.QPalette.ColorRole.WindowText + QtGui.QPalette.ColorRole.WindowText, ) - + sensor_state_text = self.sensor_state.name.capitalize() tab_spacer += 3 * "\t" style_painter.drawItemText( @@ -191,7 +183,7 @@ def paintEvent(self, a0: QtGui.QPaintEvent) -> None: palette, True, f"Enable: {tab_spacer}{sensor_state_text}", - QtGui.QPalette.ColorRole.WindowText + QtGui.QPalette.ColorRole.WindowText, ) style_painter.end() @@ -203,14 +195,12 @@ def _setupUI(self): self.sensor_vertical_layout = QtWidgets.QVBoxLayout() self.sensor_vertical_layout.setObjectName("sensorVerticalLayout") self._icon_label = BlocksLabel(self) - size_policy.setHeightForWidth( - self._icon_label.sizePolicy().hasHeightForWidth() - ) + size_policy.setHeightForWidth(self._icon_label.sizePolicy().hasHeightForWidth()) parent_width = self.parentWidget().width() self._icon_label.setSizePolicy(size_policy) self._icon_label.setMinimumSize(120, 100) self._icon_label.setMinimumSize(120, 100) - + self._icon_label.setPixmap( self.icon_pixmap_fp if self.filament_state == self.FilamentState.PRESENT @@ -236,10 +226,9 @@ def _setupUI(self): ) self._text_label_detected.setMinimumSize(parent_width, 20) - self._text_label_detected.setPalette(palette) self._text_label_detected.setText(f"Filament: {self.filament_state}") - + self._text_label_state = QtWidgets.QLabel(parent=self) size_policy.setHeightForWidth( self._text_label_state.sizePolicy().hasHeightForWidth() @@ -248,19 +237,29 @@ def _setupUI(self): self._text_label_state.setPalette(palette) self._text_label_state.setText(f"Enable: {self.sensor_state.name}") - + self._icon_label.setSizePolicy(size_policy) self.toggle_button = ToggleAnimatedButton(self) - self.toggle_button.setMinimumSize(100,50) + self.toggle_button.setMinimumSize(100, 50) self.toggle_button.state = ToggleAnimatedButton.State.ON - self.sensor_vertical_layout.addWidget(self._icon_label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - self.sensor_vertical_layout.addWidget(self._text_label_name_,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) + self.sensor_vertical_layout.addWidget( + self._icon_label, alignment=QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.sensor_vertical_layout.addWidget( + self._text_label_name_, alignment=QtCore.Qt.AlignmentFlag.AlignCenter + ) self.sensor_vertical_layout.addStretch() - self.sensor_vertical_layout.addWidget(self._text_label_state,alignment=QtCore.Qt.AlignmentFlag.AlignLeft) + self.sensor_vertical_layout.addWidget( + self._text_label_state, alignment=QtCore.Qt.AlignmentFlag.AlignLeft + ) self.sensor_vertical_layout.addStretch() - self.sensor_vertical_layout.addWidget(self._text_label_detected,alignment=QtCore.Qt.AlignmentFlag.AlignLeft) + self.sensor_vertical_layout.addWidget( + self._text_label_detected, alignment=QtCore.Qt.AlignmentFlag.AlignLeft + ) self.sensor_vertical_layout.addStretch() - self.sensor_vertical_layout.addWidget(self.toggle_button,alignment=QtCore.Qt.AlignmentFlag.AlignCenter) - + self.sensor_vertical_layout.addWidget( + self.toggle_button, alignment=QtCore.Qt.AlignmentFlag.AlignCenter + ) + self.setLayout(self.sensor_vertical_layout) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 5867ae3d..56c911fb 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -17,6 +17,7 @@ class SensorsWindow(QtWidgets.QWidget): request_back: typing.ClassVar[QtCore.pyqtSignal] = QtCore.pyqtSignal( name="request_back" ) + def __init__(self, parent): super(SensorsWindow, self).__init__(parent) self.model = EntryListModel() @@ -24,10 +25,8 @@ def __init__(self, parent): self.sensor_tracking_widget = {} self.current_widget = None self.sensor_list: list[SensorWidget] = [] - self.setupUi() - self.setAttribute( - QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True - ) + self._setupUi() + self.setAttribute(QtCore.Qt.WidgetAttribute.WA_TranslucentBackground, True) self.setAttribute(QtCore.Qt.WidgetAttribute.WA_AcceptTouchEvents, True) self.setTabletTracking(True) self.fs_back_button.clicked.connect(self.request_back) @@ -38,20 +37,21 @@ def reset_view_model(self) -> None: """ self.model.clear() self.entry_delegate.clear() - + @QtCore.pyqtSlot(dict, name="handle_available_fil_sensors") def handle_available_fil_sensors(self, sensors: dict) -> None: - """Handle available filament sensors, create `SensorWidget` for each detected - sensor - """ + """Handle available filament sensors, create `SensorWidget` for each detected sensor""" if not isinstance(sensors, dict): return self.reset_view_model() filtered_sensors = list( - filter( - lambda printer_obj: str(printer_obj).startswith("filament_switch_sensor") - or str(printer_obj).startswith("filament_motion_sensor") or str(printer_obj).startswith("cutter_sensor"), - sensors.keys(), + filter( + lambda printer_obj: str(printer_obj).startswith( + "filament_switch_sensor" + ) + or str(printer_obj).startswith("filament_motion_sensor") + or str(printer_obj).startswith("cutter_sensor"), + sensors.keys(), ) ) if filtered_sensors: @@ -61,26 +61,22 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: else: self.no_update_placeholder.show() - - @QtCore.pyqtSlot(str, str, bool, name="handle_fil_state_change") def handle_fil_state_change( self, sensor_name: str, parameter: str, value: bool ) -> None: + """Handle Klipper signals for filament sensor changes""" _item = self.sensor_tracking_widget.get(sensor_name) if _item: if parameter == "filament_detected": - state = SensorWidget.FilamentState(not value) - _item.change_fil_sensor_state( - state - ) + state = SensorWidget.FilamentState(not value) + _item.change_fil_sensor_state(state) elif parameter == "enabled": _item.toggle_button_state(SensorWidget.SensorState(value)) - + def showEvent(self, event: QtGui.QShowEvent | None) -> None: """Re-add clients to update list""" return super().showEvent(event) - @QtCore.pyqtSlot(ListItem, name="on-item-clicked") def on_item_clicked(self, item: ListItem) -> None: @@ -89,10 +85,10 @@ def on_item_clicked(self, item: ListItem) -> None: """ if not item: return - + if self.current_widget: self.current_widget.hide() - + name_id = item.text current_widget = self.sensor_tracking_widget.get(name_id) if current_widget is None: @@ -100,7 +96,6 @@ def on_item_clicked(self, item: ListItem) -> None: self.current_widget = current_widget self.current_widget.show() - def create_sensor_widget(self, name: str) -> SensorWidget: """Creates a sensor row to be added to the QListWidget @@ -110,7 +105,6 @@ def create_sensor_widget(self, name: str) -> SensorWidget: _item_widget = SensorWidget(self.infobox_frame, name) self.info_box_layout.addWidget(_item_widget) - if self.current_widget: _item_widget.hide() else: @@ -122,23 +116,21 @@ def create_sensor_widget(self, name: str) -> SensorWidget: right_text="", right_icon=self.pixmap, left_icon=None, - callback= None, + callback=None, selected=False, allow_check=False, _lfontsize=17, _rfontsize=12, height=80, - notificate=False + notificate=False, ) _item_widget.run_gcode_signal.connect(self.run_gcode_signal) self.sensor_tracking_widget[name_id] = _item_widget self.model.add_item(item) - + return _item_widget - def paintEvent(self, a0: QtGui.QPaintEvent) -> None: ... - - def setupUi(self) -> None: + def _setupUi(self) -> None: """Setup UI for updatePage""" font_id = QtGui.QFontDatabase.addApplicationFont( ":/font/media/fonts for text/Momcake-Bold.ttf" @@ -320,9 +312,7 @@ def setupUi(self) -> None: ) self.fs_sensors_list.setAutoScroll(False) self.fs_sensors_list.setProperty("showDropIndicator", False) - self.fs_sensors_list.setDefaultDropAction( - QtCore.Qt.DropAction.IgnoreAction - ) + self.fs_sensors_list.setDefaultDropAction(QtCore.Qt.DropAction.IgnoreAction) self.fs_sensors_list.setAlternatingRowColors(False) self.fs_sensors_list.setSelectionMode( QtWidgets.QAbstractItemView.SelectionMode.NoSelection @@ -350,7 +340,7 @@ def setupUi(self) -> None: self.sensor_buttons_frame.setLayout(self.sensor_buttons_layout) self.main_content_layout.addWidget(self.sensor_buttons_frame, 0) - + self.infobox_frame = BlocksCustomFrame() self.infobox_frame.setMinimumSize(QtCore.QSize(250, 300)) self.infobox_frame.setMaximumSize(QtCore.QSize(450, 500)) @@ -379,4 +369,4 @@ def setupUi(self) -> None: self.infobox_frame.setLayout(self.info_box_layout) self.main_content_layout.addWidget(self.infobox_frame, 1) self.update_page_content_layout.addLayout(self.main_content_layout, 1) - self.setLayout(self.update_page_content_layout) \ No newline at end of file + self.setLayout(self.update_page_content_layout) From 1d942876d47b5647f0b29eeb86b9fb91e1f555e9 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Thu, 11 Dec 2025 18:03:52 +0000 Subject: [PATCH 5/7] sensorwidget bugfix Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/sensorWidget.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/sensorWidget.py index 705a19ce..d32d3d4f 100644 --- a/BlocksScreen/lib/panels/widgets/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/sensorWidget.py @@ -64,7 +64,7 @@ def __init__(self, parent, sensor_name: str): self.icon_pixmap_fnp: QtGui.QPixmap = QtGui.QPixmap( ":/filament_related/media/btn_icons/filament_sensor_off.svg" ) - self.setupUI() + self._setupUI() self.toggle_button.stateChange.connect(self.toggle_sensor_state) @property From 29679ff05f7161369ff79a3d763a1ba7cae37bf5 Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Fri, 12 Dec 2025 12:02:11 +0000 Subject: [PATCH 6/7] sensorsPanel.py: ensure first item is checked on startup sensorWidget.py: lock toggle_button until action succeeds and replace repaint() with update() for proper refresh Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/sensorWidget.py | 10 +++++----- BlocksScreen/lib/panels/widgets/sensorsPanel.py | 3 +++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorWidget.py b/BlocksScreen/lib/panels/widgets/sensorWidget.py index d32d3d4f..e0ed9955 100644 --- a/BlocksScreen/lib/panels/widgets/sensorWidget.py +++ b/BlocksScreen/lib/panels/widgets/sensorWidget.py @@ -106,22 +106,23 @@ def change_fil_sensor_state(self, state: FilamentState): def toggle_button_state(self, state: ToggleAnimatedButton.State) -> None: """Called when the Klipper firmware reports an update to the filament sensor state""" + self.toggle_button.setDisabled(False) if state.value != self.sensor_state.value: self.sensor_state = self.SensorState(state.value) self.toggle_button.state = ToggleAnimatedButton.State( self.sensor_state.value ) - self.repaint() + self.update() @QtCore.pyqtSlot(ToggleAnimatedButton.State, name="state-change") def toggle_sensor_state(self, state: ToggleAnimatedButton.State) -> None: """Emit the appropriate G-Code command to change the filament sensor state.""" if state.value != self.sensor_state.value: - self.sensor_state = self.SensorState(state.value) + self.toggle_button.setDisabled(True) self.run_gcode_signal.emit( - f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={int(self.sensor_state.value)}" + f"SET_FILAMENT_SENSOR SENSOR={self.text} ENABLE={int(state.value)}" ) - self.repaint() + self.update() def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: """Handle widget resize events.""" @@ -199,7 +200,6 @@ def _setupUI(self): parent_width = self.parentWidget().width() self._icon_label.setSizePolicy(size_policy) self._icon_label.setMinimumSize(120, 100) - self._icon_label.setMinimumSize(120, 100) self._icon_label.setPixmap( self.icon_pixmap_fp diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 56c911fb..4a73fc24 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -58,6 +58,9 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: self.sensor_list = [ self.create_sensor_widget(name=sensor) for sensor in filtered_sensors ] + self.model.setData( + self.model.index(0), True, EntryListModel.EnableRole + ) else: self.no_update_placeholder.show() From 2d6ae820b87242b0ae3382bff3fc7d113c38f40d Mon Sep 17 00:00:00 2001 From: Guilherme Costa Date: Fri, 12 Dec 2025 12:06:02 +0000 Subject: [PATCH 7/7] sensorsPanel.py: reformat code to be complient with ruff guidelines Signed-off-by: Guilherme Costa --- BlocksScreen/lib/panels/widgets/sensorsPanel.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/BlocksScreen/lib/panels/widgets/sensorsPanel.py b/BlocksScreen/lib/panels/widgets/sensorsPanel.py index 4a73fc24..29eea5e7 100644 --- a/BlocksScreen/lib/panels/widgets/sensorsPanel.py +++ b/BlocksScreen/lib/panels/widgets/sensorsPanel.py @@ -58,9 +58,7 @@ def handle_available_fil_sensors(self, sensors: dict) -> None: self.sensor_list = [ self.create_sensor_widget(name=sensor) for sensor in filtered_sensors ] - self.model.setData( - self.model.index(0), True, EntryListModel.EnableRole - ) + self.model.setData(self.model.index(0), True, EntryListModel.EnableRole) else: self.no_update_placeholder.show()