From 9d389e6e5f9d2cb55e29869292425306fb7c4aad Mon Sep 17 00:00:00 2001 From: bartool Date: Sun, 7 Sep 2025 13:22:31 +0200 Subject: [PATCH] refactor color list widget to implement edit functionality and improve UI interactions --- ui/widgets/color_list_widget.py | 121 +++++++++++++++----------------- 1 file changed, 56 insertions(+), 65 deletions(-) diff --git a/ui/widgets/color_list_widget.py b/ui/widgets/color_list_widget.py index 9d13c08..6bf88d9 100644 --- a/ui/widgets/color_list_widget.py +++ b/ui/widgets/color_list_widget.py @@ -2,18 +2,11 @@ from PySide6.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLineEdit, QListView, QAbstractItemView, QComboBox, QLabel, QStyledItemDelegate, QStyleOptionButton, QStyle, ) -from PySide6.QtGui import QPixmap, QIcon, QColor, QStandardItemModel, QStandardItem -from PySide6.QtCore import Qt, QSortFilterProxyModel, QSize, QRect, Signal, QModelIndex, QEvent +from PySide6.QtGui import QPixmap, QIcon, QColor, QStandardItemModel, QStandardItem, QPainter, QCursor +from PySide6.QtCore import Qt, QSortFilterProxyModel, QSize, QRect, Signal, QModelIndex, QEvent, QItemSelectionModel import sys - -def color_icon(color: QColor, size: int = 24) -> QIcon: - pixmap = QPixmap(size, size) - pixmap.fill(color) - return QIcon(pixmap) - - class FilterProxy(QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent) @@ -31,29 +24,42 @@ class FilterProxy(QSortFilterProxyModel): name = model.data(index, Qt.ItemDataRole.DisplayRole) return self.search_text.lower() in name.lower() -class DeleteButtonDelegate(QStyledItemDelegate): - deleteClicked = Signal(QModelIndex) + +class EditButtonDelegate(QStyledItemDelegate): + editClicked = Signal(QModelIndex) + + def __init__(self, parent=None): + super().__init__(parent) + self.button_clicked_row = None + self.margin = 8 def paint(self, painter, option, index): super().paint(painter, option, index) - button = QStyleOptionButton() - button.rect = QRect(option.rect.right() - 60, option.rect.top(), 60, option.rect.height()) # type: ignore - button.text = "Usuń" # type: ignore - QApplication.style().drawControl(QStyle.ControlElement.CE_PushButton, button, painter) + if option.state & QStyle.StateFlag.State_MouseOver: + button = QStyleOptionButton() + button.rect = QRect(option.rect.right() - 60, option.rect.top() + self.margin , 60, option.rect.height() - self.margin * 2) # type: ignore + button.text = "EDYTUJ" # type: ignore + QApplication.style().drawControl(QStyle.ControlElement.CE_PushButton, button, painter) + def editorEvent(self, event, model, option, index): + button_rect = QRect(option.rect.right() - 60, option.rect.top() + self.margin , 60, option.rect.height() - self.margin * 2) + if event.type() == QEvent.Type.MouseButtonRelease: - button_rect = QRect(option.rect.right() - 60, option.rect.top(), 60, option.rect.height()) + # button_rect = QRect(option.rect.right() - 60, option.rect.top(), 60, option.rect.height()) if button_rect.contains(event.pos()): - self.deleteClicked.emit(index) + self.button_clicked_row = index.row() + self.editClicked.emit(index) return True return super().editorEvent(event, model, option, index) + class ColorListWidget(QWidget): - def __init__(self, colors: list[dict], parent=None): + editColor = Signal(str) + def __init__(self, parent=None): super().__init__(parent) - self.colors = colors + self.colors = None layout = QVBoxLayout(self) @@ -62,74 +68,54 @@ class ColorListWidget(QWidget): self.filter_edit.setMinimumHeight(32) self.filter_edit.setStyleSheet("font-size: 12pt;") + edit_clear = self.filter_edit.addAction(QIcon.fromTheme(QIcon.ThemeIcon.EditClear), QLineEdit.ActionPosition.TrailingPosition) + edit_clear.triggered.connect(lambda: self.filter_edit.clear()) + layout.addWidget(self.filter_edit) self.model = QStandardItemModel(self) - if colors: - self.set_colors(colors) - # for color in colors: - # item = QStandardItem( color['name']) - # item.setIcon(color_icon(QColor(color['hex']), 112)) - - # self.model.appendRow(item) self.proxy_model = FilterProxy(self) self.proxy_model.setSourceModel(self.model) self.list_view = QListView() self.list_view.setModel(self.proxy_model) - # self.list_view.setModel(self.model) + self.list_view.setEditTriggers(QAbstractItemView.EditTrigger.NoEditTriggers) self.list_view.setSelectionMode(QAbstractItemView.SelectionMode.SingleSelection) + self.list_view.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems) + self.list_view.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection) self.list_view.setUniformItemSizes(True) self.list_view.setSpacing(2) self.list_view.setIconSize(QSize(36, 36)) - self.list_view.setStyleSheet(""" - QListView::icon { - margin-right: 12px; /* odstęp między ikoną a tekstem */ - } - """) + self.list_view.setMouseTracking(True) + layout.addWidget(self.list_view) - delegate = DeleteButtonDelegate(self.list_view) - delegate.deleteClicked.connect(self.on_delete_item) - self.list_view.setItemDelegate(delegate) + self.delegate = EditButtonDelegate(self.list_view) + self.delegate.editClicked.connect(self.on_edit_clicked) + self.list_view.setItemDelegate(self.delegate) - self.filter_edit.textChanged.connect(self.proxy_model.setSearchText) - # self.list_view.selectionModel().selectionChanged.connect(self.on_selection_changed) - self.list_view.selectionModel().currentChanged.connect(self.on_current_changed) + self.filter_edit.textChanged.connect(self.on_filter_changed) self.list_view.clicked.connect(self.on_item_clicked) - def set_colors(self, colors: list[dict]): - self.colors = colors + def on_filter_changed(self, text: str): + self.proxy_model.setSearchText(text) + self.list_view.clearSelection() + + def set_colors(self, db_colors: list[dict]): self.model.clear() - for color in colors: + for color in db_colors: item = QStandardItem( color['name']) - item.setIcon(color_icon(QColor(color['color']), 112)) + item.setIcon(QIcon(color['icon_path'])) self.model.appendRow(item) - - def on_current_changed(self, current, previous): - if current.isValid(): - source_index = self.proxy_model.mapToSource(current) - item = self.model.itemFromIndex(source_index) - print(f"Wybrano kolor: {item.text()}") - - def on_selection_changed(self, selected, deselected): - indexes = selected.indexes() - if indexes: - index = indexes[0] - source_index = self.proxy_model.mapToSource(index) - item = self.model.itemFromIndex(source_index) - line = item.text() - print(f"Wybrano kolor: {line}") - return line - else: - line = "" - print("Brak zaznaczenia") - return line - def on_item_clicked(self, index): + if self.delegate.button_clicked_row == index.row(): + self.delegate.button_clicked_row = None + return + + self.list_view.selectionModel().select(index, QItemSelectionModel.SelectionFlag.ClearAndSelect) source_index = self.proxy_model.mapToSource(index) item = self.model.itemFromIndex(source_index) if item: @@ -137,6 +123,11 @@ class ColorListWidget(QWidget): print(f"Kliknięto kolor: {line}") return line - def on_delete_item(self, index): + def on_edit_clicked(self, index): source_index = self.proxy_model.mapToSource(index) - self.model.removeRow(source_index.row()) + # print("Edit:", self.model.itemFromIndex(source_index).text()) + item = self.model.itemFromIndex(source_index) + if item: + line = item.text() + print(f"Edycja koloru: {line}") + self.editColor.emit(line)