initial fluent-widgets ui
This commit is contained in:
6
qfluentwidgets/components/material/__init__.py
Normal file
6
qfluentwidgets/components/material/__init__.py
Normal file
@ -0,0 +1,6 @@
|
||||
from .acrylic_menu import AcrylicMenu, AcrylicLineEditMenu, AcrylicCheckableMenu, AcrylicCheckableSystemTrayMenu, AcrylicSystemTrayMenu
|
||||
from .acrylic_line_edit import AcrylicLineEditBase, AcrylicLineEdit, AcrylicSearchLineEdit
|
||||
from .acrylic_combo_box import AcrylicComboBox, AcrylicComboBoxSettingCard, AcrylicEditableComboBox
|
||||
from .acrylic_widget import AcrylicWidget, AcrylicBrush
|
||||
from .acrylic_flyout import AcrylicFlyoutView, AcrylicFlyoutViewBase, AcrylicFlyout
|
||||
from .acrylic_tool_tip import AcrylicToolTip, AcrylicToolTipFilter
|
||||
96
qfluentwidgets/components/material/acrylic_combo_box.py
Normal file
96
qfluentwidgets/components/material/acrylic_combo_box.py
Normal file
@ -0,0 +1,96 @@
|
||||
# coding:utf-8
|
||||
from PySide6.QtCore import Qt, QPoint
|
||||
from PySide6.QtGui import QAction
|
||||
|
||||
|
||||
from .acrylic_menu import AcrylicMenuBase, AcrylicMenuActionListWidget
|
||||
from .acrylic_line_edit import AcrylicLineEditBase
|
||||
from ..widgets.combo_box import ComboBoxMenu, ComboBox, EditableComboBox
|
||||
from ..widgets.menu import MenuAnimationType, RoundMenu, IndicatorMenuItemDelegate
|
||||
from ..settings import SettingCard
|
||||
from ...common.config import OptionsConfigItem, qconfig
|
||||
|
||||
|
||||
class AcrylicComboMenuActionListWidget(AcrylicMenuActionListWidget):
|
||||
|
||||
def _topMargin(self):
|
||||
return 2
|
||||
|
||||
|
||||
class AcrylicComboBoxMenu(AcrylicMenuBase, RoundMenu):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setUpMenu(AcrylicComboMenuActionListWidget(self))
|
||||
|
||||
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.view.setItemDelegate(IndicatorMenuItemDelegate())
|
||||
self.view.setObjectName('comboListWidget')
|
||||
self.setItemHeight(33)
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class AcrylicComboBox(ComboBox):
|
||||
""" Acrylic combo box """
|
||||
|
||||
def _createComboMenu(self):
|
||||
return AcrylicComboBoxMenu(self)
|
||||
|
||||
|
||||
class AcrylicEditableComboBox(AcrylicLineEditBase, EditableComboBox):
|
||||
""" Acrylic combo box """
|
||||
|
||||
def _createComboMenu(self):
|
||||
return AcrylicComboBoxMenu(self)
|
||||
|
||||
|
||||
class AcrylicComboBoxSettingCard(SettingCard):
|
||||
""" Setting card with a combo box """
|
||||
|
||||
def __init__(self, configItem: OptionsConfigItem, icon, title, content=None, texts=None, parent=None):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
configItem: OptionsConfigItem
|
||||
configuration item operated by the card
|
||||
|
||||
icon: str | QIcon | FluentIconBase
|
||||
the icon to be drawn
|
||||
|
||||
title: str
|
||||
the title of card
|
||||
|
||||
content: str
|
||||
the content of card
|
||||
|
||||
texts: List[str]
|
||||
the text of items
|
||||
|
||||
parent: QWidget
|
||||
parent widget
|
||||
"""
|
||||
super().__init__(icon, title, content, parent)
|
||||
self.configItem = configItem
|
||||
self.comboBox = AcrylicComboBox(self)
|
||||
self.hBoxLayout.addWidget(self.comboBox, 0, Qt.AlignRight)
|
||||
self.hBoxLayout.addSpacing(16)
|
||||
|
||||
self.optionToText = {o: t for o, t in zip(configItem.options, texts)}
|
||||
for text, option in zip(texts, configItem.options):
|
||||
self.comboBox.addItem(text, userData=option)
|
||||
|
||||
self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)])
|
||||
self.comboBox.currentIndexChanged.connect(self._onCurrentIndexChanged)
|
||||
configItem.valueChanged.connect(self.setValue)
|
||||
|
||||
def _onCurrentIndexChanged(self, index: int):
|
||||
qconfig.set(self.configItem, self.comboBox.itemData(index))
|
||||
|
||||
def setValue(self, value):
|
||||
if value not in self.optionToText:
|
||||
return
|
||||
|
||||
self.comboBox.setCurrentText(self.optionToText[value])
|
||||
qconfig.set(self.configItem, value)
|
||||
105
qfluentwidgets/components/material/acrylic_flyout.py
Normal file
105
qfluentwidgets/components/material/acrylic_flyout.py
Normal file
@ -0,0 +1,105 @@
|
||||
# coding:utf-8
|
||||
from typing import Union
|
||||
from PySide6.QtCore import QPoint, Qt, QRect, QRectF
|
||||
from PySide6.QtGui import QPixmap, QPainter, QColor, QPainterPath, QIcon, QImage
|
||||
from PySide6.QtWidgets import QWidget
|
||||
|
||||
from ...common.style_sheet import isDarkTheme
|
||||
from ...common.icon import FluentIconBase
|
||||
from ..widgets.flyout import FlyoutAnimationType, FlyoutViewBase, FlyoutView, Flyout, FlyoutAnimationManager
|
||||
from .acrylic_widget import AcrylicWidget
|
||||
|
||||
|
||||
class AcrylicFlyoutViewBase(AcrylicWidget, FlyoutViewBase):
|
||||
""" Acrylic flyout view base """
|
||||
|
||||
def acrylicClipPath(self):
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 8, 8)
|
||||
return path
|
||||
|
||||
def paintEvent(self, e):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing)
|
||||
self._drawAcrylic(painter)
|
||||
|
||||
# draw border
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.setPen(self.borderColor())
|
||||
rect = QRectF(self.rect()).adjusted(1, 1, -1, -1)
|
||||
painter.drawRoundedRect(rect, 8, 8)
|
||||
|
||||
|
||||
class AcrylicFlyoutView(AcrylicWidget, FlyoutView):
|
||||
""" Acrylic flyout view """
|
||||
|
||||
def acrylicClipPath(self):
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 8, 8)
|
||||
return path
|
||||
|
||||
def paintEvent(self, e):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing)
|
||||
self._drawAcrylic(painter)
|
||||
|
||||
# draw border
|
||||
painter.setBrush(Qt.NoBrush)
|
||||
painter.setPen(self.borderColor())
|
||||
rect = self.rect().adjusted(1, 1, -1, -1)
|
||||
painter.drawRoundedRect(rect, 8, 8)
|
||||
|
||||
|
||||
class AcrylicFlyout(Flyout):
|
||||
""" Acrylic flyout """
|
||||
|
||||
@classmethod
|
||||
def create(cls, title: str, content: str, icon: Union[FluentIconBase, QIcon, str] = None,
|
||||
image: Union[str, QPixmap, QImage] = None, isClosable=False, target: Union[QWidget, QPoint] = None,
|
||||
parent=None, aniType=FlyoutAnimationType.PULL_UP, isDeleteOnClose=True):
|
||||
""" create and show a flyout using the default view
|
||||
|
||||
Parameters
|
||||
----------
|
||||
title: str
|
||||
the title of teaching tip
|
||||
|
||||
content: str
|
||||
the content of teaching tip
|
||||
|
||||
icon: InfoBarIcon | FluentIconBase | QIcon | str
|
||||
the icon of teaching tip
|
||||
|
||||
image: str | QPixmap | QImage
|
||||
the image of teaching tip
|
||||
|
||||
isClosable: bool
|
||||
whether to show the close button
|
||||
|
||||
target: QWidget | QPoint
|
||||
the target widget or position to show flyout
|
||||
|
||||
parent: QWidget
|
||||
parent window
|
||||
|
||||
aniType: FlyoutAnimationType
|
||||
flyout animation type
|
||||
|
||||
isDeleteOnClose: bool
|
||||
whether delete flyout automatically when flyout is closed
|
||||
"""
|
||||
view = AcrylicFlyoutView(title, content, icon, image, isClosable)
|
||||
w = cls.make(view, target, parent, aniType, isDeleteOnClose)
|
||||
view.closed.connect(w.close)
|
||||
return w
|
||||
|
||||
def exec(self, pos: QPoint, aniType=FlyoutAnimationType.PULL_UP):
|
||||
""" show calendar view """
|
||||
self.aniManager = FlyoutAnimationManager.make(aniType, self)
|
||||
|
||||
if isinstance(self.view, AcrylicWidget):
|
||||
pos = self.aniManager._adjustPosition(pos)
|
||||
self.view.acrylicBrush.grabImage(QRect(pos, self.layout().sizeHint()))
|
||||
|
||||
self.show()
|
||||
self.aniManager.exec(pos)
|
||||
27
qfluentwidgets/components/material/acrylic_line_edit.py
Normal file
27
qfluentwidgets/components/material/acrylic_line_edit.py
Normal file
@ -0,0 +1,27 @@
|
||||
# coding:utf-8
|
||||
from .acrylic_menu import AcrylicCompleterMenu, AcrylicLineEditMenu
|
||||
from ..widgets.line_edit import LineEdit, SearchLineEdit
|
||||
|
||||
|
||||
class AcrylicLineEditBase:
|
||||
""" Acrylic line edit base """
|
||||
|
||||
def __init__(self, *args, **kwargs) -> None:
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def setCompleter(self, completer):
|
||||
super().setCompleter(completer)
|
||||
self.setCompleterMenu(AcrylicCompleterMenu(self))
|
||||
|
||||
def contextMenuEvent(self, e):
|
||||
menu = AcrylicLineEditMenu(self)
|
||||
menu.exec(e.globalPos())
|
||||
|
||||
|
||||
|
||||
class AcrylicLineEdit(AcrylicLineEditBase, LineEdit):
|
||||
""" Acrylic line edit """
|
||||
|
||||
|
||||
class AcrylicSearchLineEdit(AcrylicLineEditBase, SearchLineEdit):
|
||||
""" Acrylic search line edit """
|
||||
204
qfluentwidgets/components/material/acrylic_menu.py
Normal file
204
qfluentwidgets/components/material/acrylic_menu.py
Normal file
@ -0,0 +1,204 @@
|
||||
# coding:utf-8
|
||||
from typing import List
|
||||
from PySide6.QtCore import Qt, QRect, QRectF, QSize
|
||||
from PySide6.QtGui import QPainter, QColor, QPainterPath, QAction
|
||||
from PySide6.QtWidgets import QLineEdit, QListWidgetItem, QListWidget
|
||||
|
||||
from ..widgets.menu import (RoundMenu, MenuAnimationType, MenuAnimationManager, MenuActionListWidget,
|
||||
IndicatorMenuItemDelegate, LineEditMenu, MenuIndicatorType, CheckableMenu)
|
||||
from ..widgets.line_edit import CompleterMenu, LineEdit
|
||||
from ..widgets.acrylic_label import AcrylicBrush
|
||||
from ...common.style_sheet import isDarkTheme
|
||||
|
||||
|
||||
class AcrylicMenuActionListWidget(MenuActionListWidget):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.acrylicBrush = AcrylicBrush(self.viewport(), 35)
|
||||
self.setViewportMargins(0, 0, 0, 0)
|
||||
self.setProperty("transparent", True)
|
||||
|
||||
super().addItem(self.createPlaceholderItem(self._topMargin()))
|
||||
super().addItem(self.createPlaceholderItem(self._bottomMargin()))
|
||||
|
||||
def _updateAcrylicColor(self):
|
||||
if isDarkTheme():
|
||||
tintColor = QColor(32, 32, 32, 200)
|
||||
luminosityColor = QColor(0, 0, 0, 0)
|
||||
else:
|
||||
tintColor = QColor(255, 255, 255, 160)
|
||||
luminosityColor = QColor(255, 255, 255, 50)
|
||||
|
||||
self.acrylicBrush.tintColor = tintColor
|
||||
self.acrylicBrush.luminosityColor = luminosityColor
|
||||
|
||||
def _topMargin(self):
|
||||
return 6
|
||||
|
||||
def _bottomMargin(self):
|
||||
return 6
|
||||
|
||||
def setItemHeight(self, height: int):
|
||||
""" set the height of item """
|
||||
if height == self._itemHeight:
|
||||
return
|
||||
|
||||
for i in range(1, self.count() - 1):
|
||||
item = self.item(i)
|
||||
if not self.itemWidget(item):
|
||||
item.setSizeHint(QSize(item.sizeHint().width(), height))
|
||||
|
||||
self._itemHeight = height
|
||||
self.adjustSize()
|
||||
|
||||
def addItem(self, item):
|
||||
return super().insertItem(self.count() - 1, item)
|
||||
|
||||
def createPlaceholderItem(self, height=2):
|
||||
item = QListWidgetItem()
|
||||
item.setSizeHint(QSize(1, height))
|
||||
item.setFlags(Qt.ItemFlag.NoItemFlags)
|
||||
return item
|
||||
|
||||
def clipPath(self):
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(QRectF(self.rect()).adjusted(0, 0, -2.5, -2.5), 8, 8)
|
||||
return path
|
||||
|
||||
def paintEvent(self, e) -> None:
|
||||
painter = QPainter(self.viewport())
|
||||
painter.setRenderHints(QPainter.Antialiasing |
|
||||
QPainter.SmoothPixmapTransform)
|
||||
|
||||
self.acrylicBrush.clipPath = self.clipPath()
|
||||
self._updateAcrylicColor()
|
||||
self.acrylicBrush.paint()
|
||||
|
||||
super().paintEvent(e)
|
||||
|
||||
|
||||
class AcrylicMenuBase:
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def setUpMenu(self, view):
|
||||
self.hBoxLayout.removeWidget(self.view)
|
||||
self.view.deleteLater()
|
||||
|
||||
self.view = view
|
||||
self.hBoxLayout.addWidget(self.view)
|
||||
|
||||
self.setShadowEffect()
|
||||
|
||||
self.view.itemClicked.connect(self._onItemClicked)
|
||||
self.view.itemEntered.connect(self._onItemEntered)
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
p = MenuAnimationManager.make(self, aniType)._endPosition(pos)
|
||||
self.view.acrylicBrush.grabImage(QRect(p, self.layout().sizeHint()))
|
||||
super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class AcrylicMenu(AcrylicMenuBase, RoundMenu):
|
||||
""" Acrylic menu """
|
||||
|
||||
def __init__(self, title="", parent=None):
|
||||
super().__init__(title, parent)
|
||||
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class AcrylicCompleterMenuActionListWidget(AcrylicMenuActionListWidget):
|
||||
|
||||
def clipPath(self):
|
||||
path = QPainterPath()
|
||||
path.setFillRule(Qt.FillRule.WindingFill)
|
||||
path.addRoundedRect(QRectF(self.rect()).adjusted(1, 1, -2.5, -2.5), 8, 8)
|
||||
|
||||
if self.property("dropDown"):
|
||||
path.addRect(1, 1, 11, 11)
|
||||
path.addRect(self.width() - 12, 1, 11, 11)
|
||||
else:
|
||||
path.addRect(1, self.height() - 11, 11, 11)
|
||||
path.addRect(self.width() - 12, self.height() - 11, 11, 11)
|
||||
|
||||
return path
|
||||
|
||||
|
||||
class AcrylicCompleterMenu(AcrylicMenuBase, CompleterMenu):
|
||||
""" Acrylic completer menu """
|
||||
|
||||
def __init__(self, lineEdit: LineEdit):
|
||||
super().__init__(lineEdit)
|
||||
self.setUpMenu(AcrylicCompleterMenuActionListWidget(self))
|
||||
|
||||
self.view.setObjectName('completerListWidget')
|
||||
self.view.setItemDelegate(IndicatorMenuItemDelegate())
|
||||
self.view.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
|
||||
self.setItemHeight(33)
|
||||
|
||||
def _onItemClicked(self, item):
|
||||
self._hideMenu(False)
|
||||
self._onCompletionItemSelected(item.text(), self.view.row(item)-1)
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
def setItems(self, items):
|
||||
""" set completion items """
|
||||
self.view.clear()
|
||||
|
||||
self.items = items
|
||||
|
||||
QListWidget.addItem(self.view, self.view.createPlaceholderItem(self.view._topMargin()))
|
||||
self.view.addItems(items)
|
||||
|
||||
for i in range(1, self.view.count()):
|
||||
item = self.view.item(i)
|
||||
item.setSizeHint(QSize(1, self.itemHeight))
|
||||
|
||||
QListWidget.addItem(self.view, self.view.createPlaceholderItem(self.view._bottomMargin()))
|
||||
|
||||
|
||||
class AcrylicLineEditMenu(AcrylicMenuBase, LineEditMenu):
|
||||
""" Acrylic line edit menu """
|
||||
|
||||
def __init__(self, parent: QLineEdit):
|
||||
super().__init__(parent)
|
||||
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class AcrylicCheckableMenu(AcrylicMenuBase, CheckableMenu):
|
||||
""" Checkable menu """
|
||||
|
||||
def __init__(self, title="", parent=None, indicatorType=MenuIndicatorType.CHECK):
|
||||
super().__init__(title, parent, indicatorType)
|
||||
self.setUpMenu(AcrylicMenuActionListWidget(self))
|
||||
self.view.setObjectName('checkableListWidget')
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class AcrylicSystemTrayMenu(AcrylicMenu):
|
||||
""" System tray menu """
|
||||
|
||||
def showEvent(self, e):
|
||||
super().showEvent(e)
|
||||
self.adjustPosition()
|
||||
self.view.acrylicBrush.grabImage(QRect(self.pos(), self.layout().sizeHint()))
|
||||
|
||||
|
||||
class AcrylicCheckableSystemTrayMenu(AcrylicCheckableMenu):
|
||||
""" Checkable system tray menu """
|
||||
|
||||
def showEvent(self, e):
|
||||
super().showEvent(e)
|
||||
self.adjustPosition()
|
||||
39
qfluentwidgets/components/material/acrylic_tool_tip.py
Normal file
39
qfluentwidgets/components/material/acrylic_tool_tip.py
Normal file
@ -0,0 +1,39 @@
|
||||
# coding: utf-8
|
||||
from PySide6.QtCore import QRect, QRectF
|
||||
from PySide6.QtGui import QPainterPath
|
||||
from PySide6.QtWidgets import QApplication, QFrame
|
||||
|
||||
from .acrylic_widget import AcrylicWidget
|
||||
from ..widgets.tool_tip import ToolTip, ToolTipFilter
|
||||
|
||||
|
||||
class AcrylicToolTipContainer(AcrylicWidget, QFrame):
|
||||
""" Acrylic tool tip container """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.setProperty("transparent", True)
|
||||
|
||||
def acrylicClipPath(self):
|
||||
path = QPainterPath()
|
||||
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 3, 3)
|
||||
return path
|
||||
|
||||
|
||||
class AcrylicToolTip(ToolTip):
|
||||
""" Acrylic tool tip """
|
||||
|
||||
def _createContainer(self):
|
||||
return AcrylicToolTipContainer(self)
|
||||
|
||||
def showEvent(self, e):
|
||||
pos = self.pos() + self.container.pos()
|
||||
self.container.acrylicBrush.grabImage(QRect(pos, self.container.size()))
|
||||
return super().showEvent(e)
|
||||
|
||||
|
||||
class AcrylicToolTipFilter(ToolTipFilter):
|
||||
""" Acrylic tool tip filter """
|
||||
|
||||
def _createToolTip(self):
|
||||
return AcrylicToolTip(self.parent().toolTip(), self.parent().window())
|
||||
42
qfluentwidgets/components/material/acrylic_widget.py
Normal file
42
qfluentwidgets/components/material/acrylic_widget.py
Normal file
@ -0,0 +1,42 @@
|
||||
# coding:utf-8
|
||||
from PySide6.QtGui import QPainterPath, QPainter, QColor
|
||||
|
||||
from ..widgets.acrylic_label import AcrylicBrush
|
||||
from ...common.style_sheet import isDarkTheme
|
||||
|
||||
|
||||
class AcrylicWidget:
|
||||
""" Acrylic widget """
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.acrylicBrush = AcrylicBrush(self, 30)
|
||||
|
||||
def _updateAcrylicColor(self):
|
||||
if isDarkTheme():
|
||||
tintColor = QColor(32, 32, 32, 200)
|
||||
luminosityColor = QColor(0, 0, 0, 0)
|
||||
else:
|
||||
tintColor = QColor(255, 255, 255, 180)
|
||||
luminosityColor = QColor(255, 255, 255, 0)
|
||||
|
||||
self.acrylicBrush.tintColor = tintColor
|
||||
self.acrylicBrush.luminosityColor = luminosityColor
|
||||
|
||||
def acrylicClipPath(self):
|
||||
return QPainterPath()
|
||||
|
||||
def _drawAcrylic(self, painter: QPainter):
|
||||
path = self.acrylicClipPath()
|
||||
if not path.isEmpty():
|
||||
self.acrylicBrush.clipPath = self.acrylicClipPath()
|
||||
|
||||
self._updateAcrylicColor()
|
||||
self.acrylicBrush.paint()
|
||||
|
||||
def paintEvent(self, e):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform)
|
||||
|
||||
self._drawAcrylic(painter)
|
||||
super().paintEvent(e)
|
||||
Reference in New Issue
Block a user