import os from PySide6.QtCore import Qt, QSortFilterProxyModel, QSize, Signal from PySide6.QtWidgets import QTableView, QStyledItemDelegate, QHeaderView from PySide6.QtGui import QStandardItemModel, QStandardItem, QIcon from Kikka.KikkaConst import * from Kikka.Utils.IconHelper import IconHelper class IconPanelItem(QStandardItem): pass class IconPanelModel(QStandardItemModel): def __init__(self): super().__init__() def flags(self, index): return Qt.ItemFlag.ItemIsSelectable | Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsDragEnabled class IconPanelProxyModel(QSortFilterProxyModel): pass class IconPanelStyledItemDelegate(QStyledItemDelegate): def __init__(self, parent=None): super().__init__(parent) def paint(self, painter, option, index): icon = index.data(Qt.ItemDataRole.DecorationRole) if icon: rect = option.rect icon.paint(painter, rect, Qt.AlignmentFlag.AlignCenter) def sizeHint(self, option, index): return QSize(64, 64) class IconPanel(QTableView): SIGNAL_DROP = Signal(str) SIGNAL_DOUBLE_CLICK = Signal(object) def __init__(self, parent=None): super().__init__(parent) self.setAcceptDrops(True) self.initGUI() self.emptyIcon = QIcon(os.path.join(RESOURCES_PATH, "icon1.svg")) self.doubleClicked.connect(self.onDoubleClick) def initGUI(self): self.setDragDropMode(QTableView.DragDropMode.InternalMove) self.setSelectionMode(QTableView.SelectionMode.SingleSelection) # self.setSelectionBehavior(QAbstractItemView.SelectItems) # self.setGridStyle(Qt.DotLine) self.setShowGrid(False) self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) # self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff) self.verticalHeader().setVisible(False) self.verticalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Fixed) self.horizontalHeader().setVisible(False) self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeMode.Fixed) def setData(self, actions): self._model = IconPanelModel() self._items = [] self._model.setColumnCount(4) for i, action in enumerate(actions): item = IconPanelItem() item.setText(action.name) icon_file = action.path icon = IconHelper().getIconByFile(icon_file) if icon is None: icon = self.emptyIcon item.setIcon(icon) item.setData(action) self._items.append(item) self._proxyModel = IconPanelProxyModel() self._proxyModel.setSourceModel(self._model) self.setModel(self._proxyModel) self.setItemDelegate(IconPanelStyledItemDelegate(self)) self.updateView() IconHelper().saveCache() def updateView(self): columnCount = max(self.width() // 64, 3) rowCount = max(len(self._items) // 64, 3) self.setIconSize(QSize(64, 64)) self.horizontalHeader().setDefaultSectionSize(72) self.verticalHeader().setDefaultSectionSize(72) self._model.clear() self._model.setColumnCount(columnCount) for i in range(columnCount): self.setColumnWidth(i, 64) for i in range(rowCount): self.setRowHeight(i, 64) for i, item in enumerate(self._items): self._model.setItem(i // columnCount, i % columnCount, item) def resizeEvent(self, event): super().resizeEvent(event) self.updateView() def dragEnterEvent(self, event): mimeData = event.mimeData() if mimeData.hasUrls(): event.acceptProposedAction() else: event.ignore() def dragMoveEvent(self, event): mimeData = event.mimeData() if mimeData.hasUrls(): event.acceptProposedAction() else: event.ignore() def dropEvent(self, event): mimeData = event.mimeData() if mimeData.hasUrls(): for url in mimeData.urls(): file_path = url.toLocalFile() self.SIGNAL_DROP.emit(file_path) event.acceptProposedAction() def onDoubleClick(self, index): if index.isValid(): item = self._model.item(index.row(), index.column()) action = item.data() self.SIGNAL_DOUBLE_CLICK.emit(action) def mousePressEvent(self, event): return super().mousePressEvent(event)