diff --git a/BlocksScreen/lib/panels/filamentTab.py b/BlocksScreen/lib/panels/filamentTab.py
index 015e7915..f3e22949 100644
--- a/BlocksScreen/lib/panels/filamentTab.py
+++ b/BlocksScreen/lib/panels/filamentTab.py
@@ -382,6 +382,16 @@ def _build_spool_page(self) -> QtWidgets.QWidget:
frame_lay.addWidget(self._spool_load_widget, 1)
self._spool_list_view.hide()
+ self._no_spools_label = QtWidgets.QLabel("", frame)
+ self._no_spools_label.setWordWrap(True)
+ self._no_spools_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
+ self._no_spools_label.setStyleSheet("color: gray;")
+ no_spools_font = QtGui.QFont()
+ no_spools_font.setPointSize(13)
+ self._no_spools_label.setFont(no_spools_font)
+ self._no_spools_label.hide()
+ frame_lay.addWidget(self._no_spools_label)
+
self._add_spool_page = AddSpoolPage(self)
self._add_filament_page = AddFilamentPage(self)
@@ -617,6 +627,7 @@ def on_spools_received(self, result: dict) -> None:
"""Handles the result from the API call to get spools for the spoolman page."""
self._spool_load_widget.hide()
self._spool_list_view.show()
+ self._no_spools_label.hide()
self.reset_spool_info()
@@ -660,6 +671,16 @@ def on_spools_received(self, result: dict) -> None:
self._spool_id_map[name] = spool
self.update()
+ if self._spool_id_map:
+ self._no_spools_label.hide()
+ else:
+ self._no_spools_label.setText(
+ f'No spools found for "{self._material_filter}"'
+ if self._material_filter
+ else "No spools found"
+ )
+ self._no_spools_label.show()
+
def _on_spool_selected(self) -> None:
item = self._spool_model.get_selected_item()
if item is None:
diff --git a/BlocksScreen/lib/panels/widgets/addFilamentPage.py b/BlocksScreen/lib/panels/widgets/addFilamentPage.py
index 08e4b09a..2332f6f3 100644
--- a/BlocksScreen/lib/panels/widgets/addFilamentPage.py
+++ b/BlocksScreen/lib/panels/widgets/addFilamentPage.py
@@ -29,6 +29,7 @@ class AddFilamentPage(QtWidgets.QWidget):
def __init__(self, parent=None) -> None:
super().__init__(parent)
self._keyboard_field: QtWidgets.QLineEdit | None = None
+ self._color_hex = "ffffff"
self._build_ui()
@@ -66,7 +67,7 @@ def setData(self, material: str, extruder_temp: int):
def reset(self):
self._name_field.setText("")
self._material_field.setText("---")
- self._color_field.setText("ffffff")
+ self._set_color("ffffff")
self._ext_temp_field.setText("---")
self._bed_temp_field.setText("---")
self._density_field.setText("---")
@@ -135,30 +136,37 @@ def _on_bed_temp_change(self, _name: str, value: int) -> None:
self._bed_temp_field.setText(str(value))
def _open_color_wheel(self) -> None:
- self.color_whell.set_color_hex(
- self._color_field.text().strip().lstrip("#") or "ffffff"
- )
+ self.color_whell.set_color_hex(self._color_hex or "ffffff")
self._color_whell_popup.show()
@QtCore.pyqtSlot(str, name="on-color-selected")
def _on_color_selected(self, hex_str: str) -> None:
- self._color_field.setText(hex_str)
-
- def _update_swatch(self) -> None:
- hex_text = self._color_field.text().strip("#").strip()
- if len(hex_text) == 6:
- color = QtGui.QColor(f"#{hex_text}")
- self._color_swatch.setStyleSheet(
- f"border-radius: 8px;"
- f"background: rgb({color.red()},{color.green()},{color.blue()});"
- f"border: 2px solid rgba(255,255,255,80);"
- )
+ self._set_color(hex_str)
+
+ def _set_color(self, hex_str: str) -> None:
+ """Stores *hex_str* (what the Spoolman API needs) and updates the
+ RGB text label + swatch preview shown to the user."""
+ hex_text = hex_str.strip().lstrip("#")
+ if len(hex_text) != 6:
+ return
+ self._color_hex = hex_text
+ color = QtGui.QColor(f"#{hex_text}")
+ self._color_field.setText(
+ f"R:{color.red()} "
+ f"G:{color.green()} "
+ f"B:{color.blue()}"
+ )
+ self._color_swatch.setStyleSheet(
+ f"border-radius: 8px;"
+ f"background: rgb({color.red()},{color.green()},{color.blue()});"
+ f"border: 2px solid rgba(255,255,255,80);"
+ )
def _on_submit(self) -> None:
body: dict = {}
name = self._name_field.text().strip()
material = self._material_field.text().strip()
- color_hex = self._color_field.text().strip().strip("#")
+ color_hex = self._color_hex
ext_temp = self._ext_temp_field.text().strip()
bed_temp = self._bed_temp_field.text().strip()
density_text = self._density_field.text().strip()
@@ -184,7 +192,7 @@ def _on_submit(self) -> None:
body["density"] = 1.24
body["diameter"] = 1.75 # Default diameter, can be modified later if needed
- if not vendor_text == "---":
+ if vendor_text != "---":
self.request_add_manufacturer.emit({"name": vendor_text})
self.request_filament_body = body
return
@@ -232,7 +240,7 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
blank.setFixedSize(60, 60)
hdr.addWidget(blank)
- title_lbl = QtWidgets.QLabel("Add Filament", self)
+ title_lbl = QtWidgets.QLabel("New Filament", self)
title_lbl.setFont(_f(22))
title_lbl.setFixedHeight(60)
title_lbl.setStyleSheet("color: white; background: transparent;")
@@ -257,13 +265,19 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
self._name_field = _make_field(left_frame)
self._material_field = _make_field(left_frame)
- self._color_field = _make_field(left_frame)
+
+ self._color_field = QtWidgets.QLabel(left_frame)
+ self._color_field.setFont(_f(14))
+ self._color_field.setFixedHeight(46)
+ self._color_field.setStyleSheet("color: rgb(255, 255, 255);")
self._color_swatch = QtWidgets.QLabel(left_frame)
self._color_swatch.setFixedSize(70, 70)
self._color_swatch.setStyleSheet(
"border-radius: 8px; background: #ffffff; border: 2px solid rgba(255,255,255,80);"
)
+ self._color_swatch.setCursor(QtCore.Qt.CursorShape.PointingHandCursor)
+ self._color_swatch.mousePressEvent = lambda event: self._open_color_wheel()
left_lay.addWidget(_key_lbl("Name:", left_frame))
left_lay.addWidget(self._name_field)
@@ -271,13 +285,13 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
left_lay.addWidget(_key_lbl("Material:", left_frame))
left_lay.addWidget(self._material_field)
- left_lay.addWidget(_key_lbl("Color (hex):", left_frame))
+ left_lay.addWidget(_key_lbl("Color:", left_frame))
color_row = QtWidgets.QHBoxLayout()
color_row.setSpacing(30)
color_row.setContentsMargins(0, 0, 0, 0)
- self._color_field.setMaximumWidth(100)
- color_row.addWidget(self._color_field)
+ self._color_field.setMaximumWidth(220)
color_row.addWidget(self._color_swatch)
+ color_row.addWidget(self._color_field)
color_row.addStretch(1)
left_lay.addLayout(color_row)
@@ -324,7 +338,7 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
self._name_field.setPlaceholderText("e.g. PLA Generic")
self._material_field.setText("PLA")
- self._color_field.setText("ffffff")
+ self._set_color("ffffff")
self._ext_temp_field.setText("220")
self._bed_temp_field.setText("60")
self._density_field.setText("1.24")
@@ -334,7 +348,6 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
self._material_field.clicked.connect(
lambda: self._show_keyboard(self._material_field)
)
- self._color_field.clicked.connect(self._open_color_wheel)
self._ext_temp_field.clicked.connect(
lambda: self.request_numpad[str, int, "PyQt_PyObject", int, int].emit(
"Extruder Temp",
@@ -360,13 +373,18 @@ def _make_field(parent: QtWidgets.QWidget) -> BlocksCustomLinEdit:
lambda: self._show_keyboard(self._vendor_field, max_char=65)
)
- self._color_field.textChanged.connect(self._update_swatch)
-
+ spacer = QtWidgets.QSpacerItem(
+ 5,
+ 5,
+ QtWidgets.QSizePolicy.Policy.Minimum,
+ QtWidgets.QSizePolicy.Policy.Minimum,
+ )
+ root.addItem(spacer)
# Submit
submit_btn = BlocksCustomButton(self)
- submit_btn.setFixedSize(220, 80)
+ submit_btn.setFixedSize(400, 80)
submit_btn.setFont(_f(16))
- submit_btn.setText("Add\nFilament")
+ submit_btn.setText("New Filament")
submit_btn.setPixmap(
QtGui.QPixmap(":/filament_related/media/btn_icons/add filament.svg")
)
diff --git a/BlocksScreen/lib/panels/widgets/addSpoolPage.py b/BlocksScreen/lib/panels/widgets/addSpoolPage.py
index 9c082991..6ee4147d 100644
--- a/BlocksScreen/lib/panels/widgets/addSpoolPage.py
+++ b/BlocksScreen/lib/panels/widgets/addSpoolPage.py
@@ -59,11 +59,15 @@ def reset(self) -> None:
"""Clear state and trigger a fresh filament fetch. Call before showing."""
self._selected_filament_id = None
self._submit_btn.setEnabled(False)
+ self._lot_field.setEnabled(False)
+ self._weight_field.setEnabled(False)
+ self._location_field.setEnabled(False)
self._location_field.clear()
self._lot_field.clear()
self._weight_field.clear()
self._fil_list_view.hide()
self._fil_load_widget.show()
+ self._no_filaments_label.hide()
self._fil_model.clear()
self._fil_delegate.clear()
self.request_filaments.emit()
@@ -87,7 +91,7 @@ def on_filaments_received(self, result: dict) -> None:
self._fil_delegate.clear()
self._fil_model.add_item(
ListItem(
- text="+ Add Filament",
+ text=" New Filament",
left_icon=self._make_add_pixmap(),
_lfontsize=14,
height=60,
@@ -116,6 +120,16 @@ def on_filaments_received(self, result: dict) -> None:
self._filament_id_map[name] = fil
self.update()
+ if self._filament_id_map:
+ self._no_filaments_label.hide()
+ else:
+ self._no_filaments_label.setText(
+ f'No filaments found for "{self._material_filter}"'
+ if self._material_filter
+ else "No filaments found"
+ )
+ self._no_filaments_label.show()
+
@staticmethod
def _make_add_pixmap() -> QtGui.QPixmap:
pixmap = QtGui.QPixmap(32, 32)
@@ -142,12 +156,15 @@ def on_add_spool_result(self, result: dict) -> None:
def _on_filament_selected(self, item: ListItem) -> None:
if not item:
return
- if item.text == "+ Add Filament":
+ if item.text == " New Filament":
self.open_add_filament.emit()
return
filament = self._filament_id_map.get(item.text)
if filament:
self._selected_filament_id = filament.get("id")
+ self._lot_field.setEnabled(True)
+ self._weight_field.setEnabled(True)
+ self._location_field.setEnabled(True)
self._submit_btn.setEnabled(True)
def _show_keyboard(
@@ -341,6 +358,16 @@ def _key_lbl(text: str) -> QtWidgets.QLabel:
left_lay.addWidget(self._fil_load_widget, 1)
self._fil_list_view.hide()
+ self._no_filaments_label = QtWidgets.QLabel("", left_frame)
+ self._no_filaments_label.setWordWrap(True)
+ self._no_filaments_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
+ self._no_filaments_label.setStyleSheet("color: gray;")
+ no_fil_font = QtGui.QFont()
+ no_fil_font.setPointSize(13)
+ self._no_filaments_label.setFont(no_fil_font)
+ self._no_filaments_label.hide()
+ left_lay.addWidget(self._no_filaments_label)
+
body.addWidget(left_frame, 1)
# Right: optional spool fields
diff --git a/BlocksScreen/lib/panels/widgets/spoolmanPage.py b/BlocksScreen/lib/panels/widgets/spoolmanPage.py
index 0bb774bc..4b061c77 100644
--- a/BlocksScreen/lib/panels/widgets/spoolmanPage.py
+++ b/BlocksScreen/lib/panels/widgets/spoolmanPage.py
@@ -192,7 +192,7 @@ def _build_model_list(self) -> None:
self.model.add_item(
ListItem(
- text="+ Add Spool",
+ text=" Add Spool",
left_icon=self._make_add_pixmap(),
_lfontsize=14,
height=60,
@@ -234,12 +234,17 @@ def _build_model_list(self) -> None:
self.spool_list_widget.blockSignals(False)
+ if self._display_name_to_spool:
+ self._no_spools_label.hide()
+ else:
+ self._no_spools_label.show()
+
@QtCore.pyqtSlot(ListItem, name="on-item-clicked")
def on_item_clicked(self, item: ListItem) -> None:
"""Handle when a spool item is clicked in the list."""
if not item:
return
- if item.text == "+ Add Spool":
+ if item.text == " Add Spool":
self._on_add_spool_clicked()
return
self._selected_spool = self._display_name_to_spool.get(item.text)
@@ -398,9 +403,19 @@ def _icon_btn(icon_path: str) -> IconButton:
QtWidgets.QScroller.ScrollerGestureType.LeftMouseButtonGesture,
)
+ self._no_spools_label = QtWidgets.QLabel("No spools found", list_frame)
+ self._no_spools_label.setWordWrap(True)
+ self._no_spools_label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
+ self._no_spools_label.setStyleSheet("color: gray;")
+ no_spools_font = QtGui.QFont()
+ no_spools_font.setPointSize(13)
+ self._no_spools_label.setFont(no_spools_font)
+ self._no_spools_label.hide()
+
list_layout = QtWidgets.QVBoxLayout()
list_layout.setContentsMargins(4, 4, 4, 4)
list_layout.addWidget(self.spool_list_widget, 1)
+ list_layout.addWidget(self._no_spools_label)
list_frame.setLayout(list_layout)
main_layout.addWidget(list_frame, 3)
@@ -421,6 +436,14 @@ def _icon_btn(icon_path: str) -> IconButton:
white_palette.ColorRole.WindowText, QtGui.QColor("#FFFFFF")
)
+ spacer = QtWidgets.QSpacerItem(
+ 30,
+ 30,
+ QtWidgets.QSizePolicy.Policy.Minimum,
+ QtWidgets.QSizePolicy.Policy.Minimum,
+ )
+ info_layout.addItem(spacer)
+
def _add_row(title_text: str) -> QtWidgets.QLabel:
row = QtWidgets.QHBoxLayout()
row.setSpacing(4)