# coding:utf-8 from typing import List from PyQt6.QtCore import Qt, pyqtSignal from PyQt6.QtWidgets import QApplication, QFrame, QVBoxLayout, QLabel, QWidget, QHBoxLayout from qfluentwidgets import (FluentIcon, IconWidget, FlowLayout, isDarkTheme, Theme, applyThemeColor, SmoothScrollArea, SearchLineEdit, StrongBodyLabel, BodyLabel) from .gallery_interface import GalleryInterface from ..common.translator import Translator from ..common.config import cfg from ..common.style_sheet import StyleSheet from ..common.trie import Trie class LineEdit(SearchLineEdit): """ Search line edit """ def __init__(self, parent=None): super().__init__(parent) self.setPlaceholderText(self.tr('Search icons')) self.setFixedWidth(304) self.textChanged.connect(self.search) class IconCard(QFrame): """ Icon card """ clicked = pyqtSignal(FluentIcon) def __init__(self, icon: FluentIcon, parent=None): super().__init__(parent=parent) self.icon = icon self.isSelected = False self.iconWidget = IconWidget(icon, self) self.nameLabel = QLabel(self) self.vBoxLayout = QVBoxLayout(self) self.setFixedSize(96, 96) self.vBoxLayout.setSpacing(0) self.vBoxLayout.setContentsMargins(8, 28, 8, 0) self.vBoxLayout.setAlignment(Qt.AlignTop) self.iconWidget.setFixedSize(28, 28) self.vBoxLayout.addWidget(self.iconWidget, 0, Qt.AlignHCenter) self.vBoxLayout.addSpacing(14) self.vBoxLayout.addWidget(self.nameLabel, 0, Qt.AlignHCenter) text = self.nameLabel.fontMetrics().elidedText(icon.value, Qt.ElideRight, 90) self.nameLabel.setText(text) def mouseReleaseEvent(self, e): if self.isSelected: return self.clicked.emit(self.icon) def setSelected(self, isSelected: bool, force=False): if isSelected == self.isSelected and not force: return self.isSelected = isSelected if not isSelected: self.iconWidget.setIcon(self.icon) else: icon = self.icon.icon(Theme.LIGHT if isDarkTheme() else Theme.DARK) self.iconWidget.setIcon(icon) self.setProperty('isSelected', isSelected) self.setStyle(QApplication.style()) class IconInfoPanel(QFrame): """ Icon info panel """ def __init__(self, icon: FluentIcon, parent=None): super().__init__(parent=parent) self.nameLabel = QLabel(icon.value, self) self.iconWidget = IconWidget(icon, self) self.iconNameTitleLabel = QLabel(self.tr('Icon name'), self) self.iconNameLabel = QLabel(icon.value, self) self.enumNameTitleLabel = QLabel(self.tr('Enum member'), self) self.enumNameLabel = QLabel("FluentIcon." + icon.name, self) self.vBoxLayout = QVBoxLayout(self) self.vBoxLayout.setContentsMargins(16, 20, 16, 20) self.vBoxLayout.setSpacing(0) self.vBoxLayout.setAlignment(Qt.AlignTop) self.vBoxLayout.addWidget(self.nameLabel) self.vBoxLayout.addSpacing(16) self.vBoxLayout.addWidget(self.iconWidget) self.vBoxLayout.addSpacing(45) self.vBoxLayout.addWidget(self.iconNameTitleLabel) self.vBoxLayout.addSpacing(5) self.vBoxLayout.addWidget(self.iconNameLabel) self.vBoxLayout.addSpacing(34) self.vBoxLayout.addWidget(self.enumNameTitleLabel) self.vBoxLayout.addSpacing(5) self.vBoxLayout.addWidget(self.enumNameLabel) self.iconWidget.setFixedSize(48, 48) self.setFixedWidth(216) self.nameLabel.setObjectName('nameLabel') self.iconNameTitleLabel.setObjectName('subTitleLabel') self.enumNameTitleLabel.setObjectName('subTitleLabel') def setIcon(self, icon: FluentIcon): self.iconWidget.setIcon(icon) self.nameLabel.setText(icon.value) self.iconNameLabel.setText(icon.value) self.enumNameLabel.setText("FluentIcon."+icon.name) class IconCardView(QWidget): """ Icon card view """ def __init__(self, parent=None): super().__init__(parent=parent) self.trie = Trie() self.iconLibraryLabel = StrongBodyLabel(self.tr('Fluent Icons Library'), self) self.searchLineEdit = LineEdit(self) self.view = QFrame(self) self.scrollArea = SmoothScrollArea(self.view) self.scrollWidget = QWidget(self.scrollArea) self.infoPanel = IconInfoPanel(FluentIcon.MENU, self) self.vBoxLayout = QVBoxLayout(self) self.hBoxLayout = QHBoxLayout(self.view) self.flowLayout = FlowLayout(self.scrollWidget, isTight=True) self.cards = [] # type:List[IconCard] self.icons = [] self.currentIndex = -1 self.__initWidget() def __initWidget(self): self.scrollArea.setWidget(self.scrollWidget) self.scrollArea.setViewportMargins(0, 5, 0, 5) self.scrollArea.setWidgetResizable(True) self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.vBoxLayout.setContentsMargins(0, 0, 0, 0) self.vBoxLayout.setSpacing(12) self.vBoxLayout.addWidget(self.iconLibraryLabel) self.vBoxLayout.addWidget(self.searchLineEdit) self.vBoxLayout.addWidget(self.view) self.hBoxLayout.setSpacing(0) self.hBoxLayout.setContentsMargins(0, 0, 0, 0) self.hBoxLayout.addWidget(self.scrollArea) self.hBoxLayout.addWidget(self.infoPanel, 0, Qt.AlignRight) self.flowLayout.setVerticalSpacing(8) self.flowLayout.setHorizontalSpacing(8) self.flowLayout.setContentsMargins(8, 3, 8, 8) self.__setQss() cfg.themeChanged.connect(self.__setQss) self.searchLineEdit.clearSignal.connect(self.showAllIcons) self.searchLineEdit.searchSignal.connect(self.search) for icon in FluentIcon._member_map_.values(): self.addIcon(icon) self.setSelectedIcon(self.icons[0]) def addIcon(self, icon: FluentIcon): """ add icon to view """ card = IconCard(icon, self) card.clicked.connect(self.setSelectedIcon) self.trie.insert(icon.value, len(self.cards)) self.cards.append(card) self.icons.append(icon) self.flowLayout.addWidget(card) def setSelectedIcon(self, icon: FluentIcon): """ set selected icon """ index = self.icons.index(icon) if self.currentIndex >= 0: self.cards[self.currentIndex].setSelected(False) self.currentIndex = index self.cards[index].setSelected(True) self.infoPanel.setIcon(icon) def __setQss(self): self.view.setObjectName('iconView') self.scrollWidget.setObjectName('scrollWidget') StyleSheet.ICON_INTERFACE.apply(self) StyleSheet.ICON_INTERFACE.apply(self.scrollWidget) if self.currentIndex >= 0: self.cards[self.currentIndex].setSelected(True, True) def search(self, keyWord: str): """ search icons """ items = self.trie.items(keyWord.lower()) indexes = {i[1] for i in items} self.flowLayout.removeAllWidgets() for i, card in enumerate(self.cards): isVisible = i in indexes card.setVisible(isVisible) if isVisible: self.flowLayout.addWidget(card) def showAllIcons(self): self.flowLayout.removeAllWidgets() for card in self.cards: card.show() self.flowLayout.addWidget(card) class IconInterface(GalleryInterface): """ Icon interface """ def __init__(self, parent=None): t = Translator() super().__init__( title=t.icons, subtitle="qfluentwidgets.common.icon", parent=parent ) self.setObjectName('iconInterface') self.iconView = IconCardView(self) self.vBoxLayout.addWidget(self.iconView)