Recreate legacy controls in PySide6 window
This commit is contained in:
parent
9ded332269
commit
825bdcebe0
|
|
@ -1,14 +1,183 @@
|
|||
"""Main PySide6 window with custom title bar."""
|
||||
"""Main PySide6 window emulating the legacy Tk interface."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import Callable, Dict, List, Tuple
|
||||
|
||||
from PySide6 import QtCore, QtGui, QtWidgets
|
||||
|
||||
DEFAULT_COLOUR = "#763e92"
|
||||
PRESET_COLOURS: List[Tuple[str, str]] = [
|
||||
("Red", "#ff3b30"),
|
||||
("Orange", "#ff9500"),
|
||||
("Yellow", "#ffd60a"),
|
||||
("Green", "#34c759"),
|
||||
("Teal", "#5ac8fa"),
|
||||
("Blue", "#0a84ff"),
|
||||
("Violet", "#af52de"),
|
||||
("Magenta", "#ff2d55"),
|
||||
("White", "#ffffff"),
|
||||
("Grey", "#8e8e93"),
|
||||
("Black", "#000000"),
|
||||
]
|
||||
|
||||
SLIDER_SPECS: List[Tuple[str, str, int, int, int]] = [
|
||||
("Hue min", "hue_min", 0, 360, 0),
|
||||
("Hue max", "hue_max", 0, 360, 360),
|
||||
("Sat min", "sat_min", 0, 100, 25),
|
||||
("Value min", "val_min", 0, 100, 15),
|
||||
("Value max", "val_max", 0, 100, 100),
|
||||
("Overlay alpha", "alpha", 0, 255, 120),
|
||||
]
|
||||
|
||||
|
||||
class ToolbarButton(QtWidgets.QPushButton):
|
||||
"""Rounded toolbar button inspired by the legacy design."""
|
||||
|
||||
def __init__(self, icon_text: str, label: str, callback: Callable[[], None], parent: QtWidgets.QWidget | None = None):
|
||||
super().__init__(f"{icon_text} {label}", parent)
|
||||
self.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.setFixedHeight(34)
|
||||
self.setStyleSheet(
|
||||
"""
|
||||
QPushButton {
|
||||
padding: 8px 16px;
|
||||
border-radius: 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
background-color: rgba(255, 255, 255, 0.04);
|
||||
color: #f7f7fb;
|
||||
font-weight: 600;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: rgba(255, 255, 255, 0.18);
|
||||
}
|
||||
"""
|
||||
)
|
||||
self.clicked.connect(callback)
|
||||
|
||||
|
||||
class ColourSwatch(QtWidgets.QPushButton):
|
||||
"""Clickable palette swatch."""
|
||||
|
||||
def __init__(self, name: str, hex_code: str, callback: Callable[[str, str], None], parent: QtWidgets.QWidget | None = None):
|
||||
super().__init__(parent)
|
||||
self.hex_code = hex_code
|
||||
self.name = name
|
||||
self.setToolTip(f"{name} ({hex_code})")
|
||||
self.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.setFixedSize(28, 28)
|
||||
self.setStyleSheet(
|
||||
f"""
|
||||
QPushButton {{
|
||||
background-color: {hex_code};
|
||||
border: 2px solid rgba(255, 255, 255, 0.18);
|
||||
border-radius: 6px;
|
||||
}}
|
||||
QPushButton:hover {{
|
||||
border-color: rgba(255, 255, 255, 0.45);
|
||||
}}
|
||||
"""
|
||||
)
|
||||
self.clicked.connect(lambda: callback(hex_code, name))
|
||||
|
||||
|
||||
class SliderControl(QtWidgets.QWidget):
|
||||
"""Slider with header and live value label."""
|
||||
|
||||
value_changed = QtCore.Signal(str, int)
|
||||
|
||||
def __init__(self, title: str, key: str, minimum: int, maximum: int, initial: int):
|
||||
super().__init__()
|
||||
self.key = key
|
||||
|
||||
layout = QtWidgets.QVBoxLayout(self)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(4)
|
||||
|
||||
header = QtWidgets.QHBoxLayout()
|
||||
header.setContentsMargins(0, 0, 0, 0)
|
||||
title_label = QtWidgets.QLabel(title)
|
||||
title_label.setStyleSheet("color: rgba(255,255,255,0.85); font-weight: 500;")
|
||||
header.addWidget(title_label)
|
||||
header.addStretch(1)
|
||||
self.value_label = QtWidgets.QLabel(str(initial))
|
||||
self.value_label.setStyleSheet("color: rgba(255,255,255,0.6);")
|
||||
header.addWidget(self.value_label)
|
||||
layout.addLayout(header)
|
||||
|
||||
self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
|
||||
self.slider.setRange(minimum, maximum)
|
||||
self.slider.setValue(initial)
|
||||
self.slider.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.slider.setStyleSheet(
|
||||
"""
|
||||
QSlider::groove:horizontal {
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
height: 6px;
|
||||
background: rgba(255,255,255,0.1);
|
||||
border-radius: 4px;
|
||||
}
|
||||
QSlider::handle:horizontal {
|
||||
background: #9a4dff;
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
width: 14px;
|
||||
margin: -5px 0;
|
||||
border-radius: 7px;
|
||||
}
|
||||
"""
|
||||
)
|
||||
self.slider.valueChanged.connect(self._sync_value)
|
||||
layout.addWidget(self.slider)
|
||||
|
||||
def _sync_value(self, value: int) -> None:
|
||||
self.value_label.setText(str(value))
|
||||
self.value_changed.emit(self.key, value)
|
||||
|
||||
def set_value(self, value: int) -> None:
|
||||
self.slider.blockSignals(True)
|
||||
self.slider.setValue(value)
|
||||
self.slider.blockSignals(False)
|
||||
self.value_label.setText(str(value))
|
||||
|
||||
|
||||
class ImageView(QtWidgets.QLabel):
|
||||
"""Aspect-ratio aware image view."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self._pixmap: QtGui.QPixmap | None = None
|
||||
|
||||
def set_image(self, pixmap: QtGui.QPixmap | None) -> None:
|
||||
self._pixmap = pixmap
|
||||
self._rescale()
|
||||
|
||||
def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
|
||||
super().resizeEvent(event)
|
||||
self._rescale()
|
||||
|
||||
def _rescale(self) -> None:
|
||||
if self._pixmap is None:
|
||||
self.setPixmap(QtGui.QPixmap())
|
||||
self.setText("<No image loaded>")
|
||||
self.setStyleSheet("color: rgba(255,255,255,0.45); font-size: 14px;")
|
||||
return
|
||||
target = self._pixmap.scaled(
|
||||
self.size(),
|
||||
QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation,
|
||||
)
|
||||
self.setPixmap(target)
|
||||
self.setStyleSheet("")
|
||||
|
||||
|
||||
class TitleBar(QtWidgets.QWidget):
|
||||
"""Custom title bar mimicking modern Windows applications."""
|
||||
"""Custom title bar with native window controls."""
|
||||
|
||||
HEIGHT = 40
|
||||
|
||||
|
|
@ -17,8 +186,8 @@ class TitleBar(QtWidgets.QWidget):
|
|||
self.window = window
|
||||
self.setFixedHeight(self.HEIGHT)
|
||||
self.setCursor(QtCore.Qt.ArrowCursor)
|
||||
|
||||
self.setAutoFillBackground(True)
|
||||
|
||||
palette = self.palette()
|
||||
palette.setColor(QtGui.QPalette.Window, QtGui.QColor("#16171d"))
|
||||
self.setPalette(palette)
|
||||
|
|
@ -31,13 +200,12 @@ class TitleBar(QtWidgets.QWidget):
|
|||
if logo_path.exists():
|
||||
pixmap = QtGui.QPixmap(str(logo_path))
|
||||
logo_label = QtWidgets.QLabel()
|
||||
logo_label.setPixmap(pixmap.scaled(24, 24, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
|
||||
logo_label.setPixmap(pixmap.scaled(26, 26, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation))
|
||||
layout.addWidget(logo_label)
|
||||
|
||||
title_label = QtWidgets.QLabel("Interactive Color Range Analyzer")
|
||||
title_label.setStyleSheet("color: #f7f7fb; font-weight: 600;")
|
||||
layout.addWidget(title_label)
|
||||
|
||||
layout.addStretch(1)
|
||||
|
||||
self.min_btn = self._create_button("–", "Minimise window")
|
||||
|
|
@ -52,7 +220,7 @@ class TitleBar(QtWidgets.QWidget):
|
|||
close_btn.clicked.connect(window.close)
|
||||
close_btn.setStyleSheet(
|
||||
"""
|
||||
QPushButton { background-color: transparent; color: #f7f7fb; border: none; padding: 4px 10px; }
|
||||
QPushButton { background: transparent; color: #f7f7fb; border: none; padding: 4px 10px; }
|
||||
QPushButton:hover { background-color: #d0342c; }
|
||||
"""
|
||||
)
|
||||
|
|
@ -72,7 +240,7 @@ class TitleBar(QtWidgets.QWidget):
|
|||
padding: 4px 10px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.12);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
}
|
||||
"""
|
||||
)
|
||||
|
|
@ -90,46 +258,15 @@ class TitleBar(QtWidgets.QWidget):
|
|||
super().mousePressEvent(event)
|
||||
|
||||
|
||||
class ImageView(QtWidgets.QLabel):
|
||||
"""Simple image display widget that keeps aspect ratio."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self._pixmap: QtGui.QPixmap | None = None
|
||||
|
||||
def set_image(self, pixmap: QtGui.QPixmap | None) -> None:
|
||||
self._pixmap = pixmap
|
||||
self._rescale()
|
||||
|
||||
def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
|
||||
super().resizeEvent(event)
|
||||
self._rescale()
|
||||
|
||||
def _rescale(self) -> None:
|
||||
if self._pixmap is None:
|
||||
self.clear()
|
||||
self.setText("<No image loaded>")
|
||||
self.setStyleSheet("color: rgba(255,255,255,0.5); font-size: 14px;")
|
||||
return
|
||||
target = self._pixmap.scaled(
|
||||
self.size(),
|
||||
QtCore.Qt.KeepAspectRatio,
|
||||
QtCore.Qt.SmoothTransformation,
|
||||
)
|
||||
self.setPixmap(target)
|
||||
self.setStyleSheet("")
|
||||
|
||||
|
||||
class MainWindow(QtWidgets.QMainWindow):
|
||||
"""Main application window containing custom chrome and content area."""
|
||||
"""Main application window containing all controls."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
|
||||
self.setWindowFlag(QtCore.Qt.Window)
|
||||
self.setAttribute(QtCore.Qt.WA_TranslucentBackground, False)
|
||||
self.setMinimumSize(900, 600)
|
||||
self.setMinimumSize(1100, 680)
|
||||
|
||||
container = QtWidgets.QWidget()
|
||||
container_layout = QtWidgets.QVBoxLayout(container)
|
||||
|
|
@ -145,46 +282,22 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
content_layout.setContentsMargins(24, 24, 24, 24)
|
||||
content_layout.setSpacing(18)
|
||||
|
||||
toolbar = QtWidgets.QHBoxLayout()
|
||||
toolbar.setSpacing(12)
|
||||
|
||||
self.open_button = QtWidgets.QPushButton("Open Image…")
|
||||
self.open_button.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.open_button.setStyleSheet(
|
||||
"""
|
||||
QPushButton {
|
||||
background: linear-gradient(135deg, #5168ff, #9a4dff);
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
padding: 10px 16px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
"""
|
||||
)
|
||||
self.open_button.clicked.connect(self.open_image)
|
||||
toolbar.addWidget(self.open_button)
|
||||
|
||||
toolbar.addStretch(1)
|
||||
|
||||
self.status_label = QtWidgets.QLabel("No image loaded")
|
||||
self.status_label.setStyleSheet("color: rgba(255,255,255,0.7); font-weight: 500;")
|
||||
toolbar.addWidget(self.status_label)
|
||||
|
||||
content_layout.addLayout(toolbar)
|
||||
|
||||
self.image_view = ImageView()
|
||||
self.image_view.setStyleSheet("border: 1px solid rgba(255,255,255,0.08); border-radius: 12px;")
|
||||
content_layout.addWidget(self.image_view, 1)
|
||||
content_layout.addLayout(self._build_toolbar())
|
||||
content_layout.addLayout(self._build_palette())
|
||||
content_layout.addLayout(self._build_sliders())
|
||||
content_layout.addWidget(self._build_previews(), 1)
|
||||
content_layout.addLayout(self._build_status_section())
|
||||
|
||||
container_layout.addWidget(self.content, 1)
|
||||
self.setCentralWidget(container)
|
||||
|
||||
self._is_maximised = False
|
||||
self._current_image_path: Path | None = None
|
||||
self._current_colour = DEFAULT_COLOUR
|
||||
self._toolbar_actions: Dict[str, Callable[[], None]] = {}
|
||||
self._slider_controls: Dict[str, SliderControl] = {}
|
||||
self._register_default_actions()
|
||||
self._update_colour_display(DEFAULT_COLOUR, "Default colour")
|
||||
|
||||
# Window control helpers -------------------------------------------------
|
||||
|
||||
|
|
@ -206,6 +319,166 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
if handle:
|
||||
handle.startSystemMove()
|
||||
|
||||
# UI builders ------------------------------------------------------------
|
||||
|
||||
def _build_toolbar(self) -> QtWidgets.QHBoxLayout:
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.setSpacing(12)
|
||||
|
||||
buttons = [
|
||||
("open_image", "🖼", "Open image…"),
|
||||
("open_folder", "📂", "Open folder…"),
|
||||
("choose_color", "🎨", "Choose colour"),
|
||||
("pick_from_image", "🖱", "Pick from image"),
|
||||
("save_overlay", "💾", "Save overlay"),
|
||||
("toggle_free_draw", "△", "Toggle free-draw"),
|
||||
("clear_excludes", "🧹", "Clear exclusions"),
|
||||
("undo_exclude", "↩", "Undo last exclusion"),
|
||||
("reset_sliders", "🔄", "Reset sliders"),
|
||||
("toggle_theme", "🌓", "Toggle theme"),
|
||||
]
|
||||
self._toolbar_buttons: Dict[str, ToolbarButton] = {}
|
||||
for key, icon_txt, label in buttons:
|
||||
button = ToolbarButton(icon_txt, label, lambda k=key: self._invoke_action(k))
|
||||
layout.addWidget(button)
|
||||
self._toolbar_buttons[key] = button
|
||||
|
||||
layout.addStretch(1)
|
||||
self.status_label = QtWidgets.QLabel("No image loaded")
|
||||
self.status_label.setStyleSheet("color: rgba(255,255,255,0.7); font-weight: 500;")
|
||||
layout.addWidget(self.status_label, 0, QtCore.Qt.AlignRight)
|
||||
return layout
|
||||
|
||||
def _build_palette(self) -> QtWidgets.QHBoxLayout:
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setSpacing(16)
|
||||
|
||||
current_group = QtWidgets.QHBoxLayout()
|
||||
current_group.setSpacing(8)
|
||||
current_label = QtWidgets.QLabel("Current colour")
|
||||
current_label.setStyleSheet("color: rgba(255,255,255,0.75); font-weight: 500;")
|
||||
current_group.addWidget(current_label)
|
||||
|
||||
self.current_colour_swatch = QtWidgets.QLabel()
|
||||
self.current_colour_swatch.setFixedSize(28, 28)
|
||||
self.current_colour_swatch.setStyleSheet(f"background-color: {DEFAULT_COLOUR}; border-radius: 6px;")
|
||||
current_group.addWidget(self.current_colour_swatch)
|
||||
|
||||
self.current_colour_label = QtWidgets.QLabel(f"({DEFAULT_COLOUR})")
|
||||
self.current_colour_label.setStyleSheet("color: rgba(255,255,255,0.65);")
|
||||
current_group.addWidget(self.current_colour_label)
|
||||
layout.addLayout(current_group)
|
||||
|
||||
more_label = QtWidgets.QLabel("More colours")
|
||||
more_label.setStyleSheet("color: rgba(255,255,255,0.65); font-weight: 500;")
|
||||
layout.addWidget(more_label)
|
||||
|
||||
swatch_container = QtWidgets.QHBoxLayout()
|
||||
swatch_container.setSpacing(8)
|
||||
for name, hex_code in PRESET_COLOURS:
|
||||
swatch = ColourSwatch(name, hex_code, self._update_colour_display)
|
||||
swatch_container.addWidget(swatch)
|
||||
layout.addLayout(swatch_container)
|
||||
layout.addStretch(1)
|
||||
return layout
|
||||
|
||||
def _build_sliders(self) -> QtWidgets.QHBoxLayout:
|
||||
layout = QtWidgets.QHBoxLayout()
|
||||
layout.setSpacing(16)
|
||||
self._slider_controls.clear()
|
||||
for title, key, minimum, maximum, initial in SLIDER_SPECS:
|
||||
control = SliderControl(title, key, minimum, maximum, initial)
|
||||
control.value_changed.connect(self._on_slider_change)
|
||||
layout.addWidget(control)
|
||||
self._slider_controls[key] = control
|
||||
return layout
|
||||
|
||||
def _build_previews(self) -> QtWidgets.QWidget:
|
||||
container = QtWidgets.QWidget()
|
||||
layout = QtWidgets.QGridLayout(container)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
layout.setHorizontalSpacing(16)
|
||||
layout.setVerticalSpacing(0)
|
||||
|
||||
self.prev_button = QtWidgets.QToolButton()
|
||||
self.prev_button.setText("◀")
|
||||
self.prev_button.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.prev_button.setFixedSize(44, 44)
|
||||
self.prev_button.setStyleSheet(
|
||||
"""
|
||||
QToolButton {
|
||||
border-radius: 22px;
|
||||
background-color: rgba(255, 255, 255, 0.08);
|
||||
color: #f7f7fb;
|
||||
font-size: 18px;
|
||||
}
|
||||
QToolButton:hover {
|
||||
background-color: rgba(255, 255, 255, 0.16);
|
||||
}
|
||||
"""
|
||||
)
|
||||
self.prev_button.clicked.connect(lambda: self._invoke_action("show_previous_image"))
|
||||
layout.addWidget(self.prev_button, 0, 0, QtCore.Qt.AlignVCenter)
|
||||
|
||||
self.image_view = ImageView()
|
||||
self.image_view.setStyleSheet("border: 1px solid rgba(255,255,255,0.08); border-radius: 12px;")
|
||||
layout.addWidget(self.image_view, 0, 1)
|
||||
|
||||
self.overlay_view = ImageView()
|
||||
self.overlay_view.setStyleSheet("border: 1px solid rgba(255,255,255,0.08); border-radius: 12px;")
|
||||
layout.addWidget(self.overlay_view, 0, 2)
|
||||
|
||||
self.next_button = QtWidgets.QToolButton()
|
||||
self.next_button.setText("▶")
|
||||
self.next_button.setCursor(QtCore.Qt.PointingHandCursor)
|
||||
self.next_button.setFixedSize(44, 44)
|
||||
self.next_button.setStyleSheet(self.prev_button.styleSheet())
|
||||
self.next_button.clicked.connect(lambda: self._invoke_action("show_next_image"))
|
||||
layout.addWidget(self.next_button, 0, 3, QtCore.Qt.AlignVCenter)
|
||||
layout.setColumnStretch(1, 1)
|
||||
layout.setColumnStretch(2, 1)
|
||||
return container
|
||||
|
||||
def _build_status_section(self) -> QtWidgets.QVBoxLayout:
|
||||
layout = QtWidgets.QVBoxLayout()
|
||||
layout.setSpacing(8)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
self.filename_label = QtWidgets.QLabel("—")
|
||||
self.filename_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.filename_label.setStyleSheet("color: rgba(255,255,255,0.85); font-weight: 600;")
|
||||
layout.addWidget(self.filename_label)
|
||||
|
||||
self.ratio_label = QtWidgets.QLabel("Matches with exclusions: —")
|
||||
self.ratio_label.setAlignment(QtCore.Qt.AlignCenter)
|
||||
self.ratio_label.setStyleSheet("color: #e6b84b; font-weight: 600;")
|
||||
layout.addWidget(self.ratio_label)
|
||||
return layout
|
||||
|
||||
# Action wiring ----------------------------------------------------------
|
||||
|
||||
def _register_default_actions(self) -> None:
|
||||
self._toolbar_actions = {
|
||||
"open_image": self.open_image,
|
||||
"open_folder": self._coming_soon,
|
||||
"choose_color": self._coming_soon,
|
||||
"pick_from_image": self._coming_soon,
|
||||
"save_overlay": self._coming_soon,
|
||||
"toggle_free_draw": self._coming_soon,
|
||||
"clear_excludes": self._coming_soon,
|
||||
"undo_exclude": self._coming_soon,
|
||||
"reset_sliders": self._reset_sliders,
|
||||
"toggle_theme": self._coming_soon,
|
||||
"show_previous_image": self._coming_soon,
|
||||
"show_next_image": self._coming_soon,
|
||||
}
|
||||
|
||||
def _invoke_action(self, key: str) -> None:
|
||||
action = self._toolbar_actions.get(key)
|
||||
if action:
|
||||
action()
|
||||
|
||||
# Image handling ---------------------------------------------------------
|
||||
|
||||
def open_image(self) -> None:
|
||||
|
|
@ -219,5 +492,34 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||
QtWidgets.QMessageBox.warning(self, "ICRA", "Unable to open the selected image.")
|
||||
return
|
||||
self.image_view.set_image(pixmap)
|
||||
self.overlay_view.set_image(None)
|
||||
self._current_image_path = path
|
||||
self.status_label.setText(f"{path.name} · {pixmap.width()}×{pixmap.height()}")
|
||||
self.filename_label.setText(f"{path.name} ({pixmap.width()}×{pixmap.height()})")
|
||||
self.ratio_label.setText("Matches with exclusions: pending")
|
||||
|
||||
# Helpers ----------------------------------------------------------------
|
||||
|
||||
def _update_colour_display(self, hex_code: str, label: str) -> None:
|
||||
self._current_colour = hex_code
|
||||
self.current_colour_swatch.setStyleSheet(f"background-color: {hex_code}; border-radius: 6px;")
|
||||
self.current_colour_label.setText(f"({hex_code})")
|
||||
self.status_label.setText(f"{label}: {hex_code}")
|
||||
|
||||
def _on_slider_change(self, key: str, value: int) -> None:
|
||||
formatted = key.replace("_", " ").title()
|
||||
self.status_label.setText(f"{formatted} → {value}")
|
||||
|
||||
def _reset_sliders(self) -> None:
|
||||
for _, key, _, _, initial in SLIDER_SPECS:
|
||||
control = self._slider_controls.get(key)
|
||||
if control:
|
||||
control.set_value(initial)
|
||||
self.status_label.setText("Sliders reset to defaults")
|
||||
|
||||
def _coming_soon(self) -> None:
|
||||
QtWidgets.QMessageBox.information(
|
||||
self,
|
||||
"Coming soon",
|
||||
"This action is not yet wired up in the PySide6 migration prototype.",
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in New Issue