initial fluent-widgets ui
This commit is contained in:
636
qfluentwidgets/components/widgets/command_bar.py
Normal file
636
qfluentwidgets/components/widgets/command_bar.py
Normal file
@ -0,0 +1,636 @@
|
||||
# coding:utf-8
|
||||
from typing import Iterable, List, Tuple, Union
|
||||
|
||||
from PySide6.QtCore import Qt, QSize, QRectF, QRect, QPoint, QEvent
|
||||
from PySide6.QtGui import QAction, QPainter, QColor, QFont, QHoverEvent, QPainterPath
|
||||
from PySide6.QtWidgets import QLayoutItem, QWidget, QFrame, QHBoxLayout, QApplication
|
||||
|
||||
from ...common.font import setFont
|
||||
from ...common.icon import FluentIcon, Icon, Action
|
||||
from ...common.style_sheet import isDarkTheme
|
||||
from .menu import RoundMenu, MenuAnimationType
|
||||
from .button import TransparentToggleToolButton
|
||||
from .tool_tip import ToolTipFilter
|
||||
from .flyout import FlyoutViewBase, Flyout
|
||||
|
||||
|
||||
class CommandButton(TransparentToggleToolButton):
|
||||
""" Command button
|
||||
|
||||
Constructors
|
||||
------------
|
||||
* CommandButton(`parent`: QWidget = None)
|
||||
* CommandButton(`icon`: QIcon | str | FluentIconBase = None, `parent`: QWidget = None)
|
||||
"""
|
||||
|
||||
def _postInit(self):
|
||||
super()._postInit()
|
||||
self.setCheckable(False)
|
||||
self.setToolButtonStyle(Qt.ToolButtonIconOnly)
|
||||
setFont(self, 12)
|
||||
|
||||
self._text = ''
|
||||
self._action = None
|
||||
self._isTight = False
|
||||
|
||||
def setTight(self, isTight: bool):
|
||||
self._isTight = isTight
|
||||
self.update()
|
||||
|
||||
def isTight(self):
|
||||
return self._isTight
|
||||
|
||||
def sizeHint(self) -> QSize:
|
||||
if self.isIconOnly():
|
||||
return QSize(36, 34) if self.isTight() else QSize(48, 34)
|
||||
|
||||
# get the width of text
|
||||
tw = self.fontMetrics().boundingRect(self.text()).width()
|
||||
|
||||
style = self.toolButtonStyle()
|
||||
if style == Qt.ToolButtonTextBesideIcon:
|
||||
return QSize(tw + 47, 34)
|
||||
if style == Qt.ToolButtonTextOnly:
|
||||
return QSize(tw + 32, 34)
|
||||
|
||||
return QSize(tw + 32, 50)
|
||||
|
||||
def isIconOnly(self):
|
||||
if not self.text():
|
||||
return True
|
||||
|
||||
return self.toolButtonStyle() in [Qt.ToolButtonIconOnly, Qt.ToolButtonFollowStyle]
|
||||
|
||||
def _drawIcon(self, icon, painter, rect):
|
||||
pass
|
||||
|
||||
def text(self):
|
||||
return self._text
|
||||
|
||||
def setText(self, text: str):
|
||||
self._text = text
|
||||
self.update()
|
||||
|
||||
def setAction(self, action: QAction):
|
||||
self._action = action
|
||||
self._onActionChanged()
|
||||
|
||||
self.clicked.connect(action.trigger)
|
||||
action.toggled.connect(self.setChecked)
|
||||
action.changed.connect(self._onActionChanged)
|
||||
|
||||
self.installEventFilter(CommandToolTipFilter(self, 700))
|
||||
|
||||
def _onActionChanged(self):
|
||||
action = self.action()
|
||||
self.setIcon(action.icon())
|
||||
self.setText(action.text())
|
||||
self.setToolTip(action.toolTip())
|
||||
self.setEnabled(action.isEnabled())
|
||||
self.setCheckable(action.isCheckable())
|
||||
self.setChecked(action.isChecked())
|
||||
|
||||
def action(self):
|
||||
return self._action
|
||||
|
||||
def paintEvent(self, e):
|
||||
super().paintEvent(e)
|
||||
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing |
|
||||
QPainter.SmoothPixmapTransform)
|
||||
|
||||
if not self.isChecked():
|
||||
painter.setPen(Qt.white if isDarkTheme() else Qt.black)
|
||||
else:
|
||||
painter.setPen(Qt.black if isDarkTheme() else Qt.white)
|
||||
|
||||
if not self.isEnabled():
|
||||
painter.setOpacity(0.43)
|
||||
elif self.isPressed:
|
||||
painter.setOpacity(0.63)
|
||||
|
||||
# draw icon and text
|
||||
style = self.toolButtonStyle()
|
||||
iw, ih = self.iconSize().width(), self.iconSize().height()
|
||||
|
||||
if self.isIconOnly():
|
||||
y = (self.height() - ih) / 2
|
||||
x = (self.width() - iw) / 2
|
||||
super()._drawIcon(self._icon, painter, QRectF(x, y, iw, ih))
|
||||
elif style == Qt.ToolButtonTextOnly:
|
||||
painter.drawText(self.rect(), Qt.AlignCenter, self.text())
|
||||
elif style == Qt.ToolButtonTextBesideIcon:
|
||||
y = (self.height() - ih) / 2
|
||||
super()._drawIcon(self._icon, painter, QRectF(11, y, iw, ih))
|
||||
|
||||
rect = QRectF(26, 0, self.width() - 26, self.height())
|
||||
painter.drawText(rect, Qt.AlignCenter, self.text())
|
||||
elif style == Qt.ToolButtonTextUnderIcon:
|
||||
x = (self.width() - iw) / 2
|
||||
super()._drawIcon(self._icon, painter, QRectF(x, 9, iw, ih))
|
||||
|
||||
rect = QRectF(0, ih + 13, self.width(), self.height() - ih - 13)
|
||||
painter.drawText(rect, Qt.AlignHCenter | Qt.AlignTop, self.text())
|
||||
|
||||
|
||||
class CommandToolTipFilter(ToolTipFilter):
|
||||
""" Command tool tip filter """
|
||||
|
||||
def _canShowToolTip(self) -> bool:
|
||||
return super()._canShowToolTip() and self.parent().isIconOnly()
|
||||
|
||||
|
||||
class MoreActionsButton(CommandButton):
|
||||
""" More action button """
|
||||
|
||||
def _postInit(self):
|
||||
super()._postInit()
|
||||
self.setIcon(FluentIcon.MORE)
|
||||
|
||||
def sizeHint(self):
|
||||
return QSize(40, 34)
|
||||
|
||||
def clearState(self):
|
||||
self.setAttribute(Qt.WA_UnderMouse, False)
|
||||
e = QHoverEvent(QEvent.HoverLeave, QPoint(-1, -1), QPoint())
|
||||
QApplication.sendEvent(self, e)
|
||||
|
||||
|
||||
class CommandSeparator(QWidget):
|
||||
""" Command separator """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setFixedSize(9, 34)
|
||||
|
||||
def paintEvent(self, e):
|
||||
painter = QPainter(self)
|
||||
painter.setPen(QColor(255, 255, 255, 21)
|
||||
if isDarkTheme() else QColor(0, 0, 0, 15))
|
||||
painter.drawLine(5, 2, 5, self.height() - 2)
|
||||
|
||||
|
||||
class CommandMenu(RoundMenu):
|
||||
""" Command menu """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__("", parent)
|
||||
self.setItemHeight(32)
|
||||
self.view.setIconSize(QSize(16, 16))
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class CommandBar(QFrame):
|
||||
""" Command bar """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self._widgets = [] # type: List[QWidget]
|
||||
self._hiddenWidgets = [] # type: List[QWidget]
|
||||
self._hiddenActions = [] # type: List[QAction]
|
||||
|
||||
self._menuAnimation = MenuAnimationType.DROP_DOWN
|
||||
self._toolButtonStyle = Qt.ToolButtonIconOnly
|
||||
self._iconSize = QSize(16, 16)
|
||||
self._isButtonTight = False
|
||||
self._spacing = 4
|
||||
|
||||
self.moreButton = MoreActionsButton(self)
|
||||
self.moreButton.clicked.connect(self._showMoreActionsMenu)
|
||||
self.moreButton.hide()
|
||||
|
||||
setFont(self, 12)
|
||||
self.setAttribute(Qt.WA_TranslucentBackground)
|
||||
|
||||
def setSpaing(self, spacing: int):
|
||||
if spacing == self._spacing:
|
||||
return
|
||||
|
||||
self._spacing = spacing
|
||||
self.updateGeometry()
|
||||
|
||||
def spacing(self):
|
||||
return self._spacing
|
||||
|
||||
def addAction(self, action: QAction):
|
||||
""" add action
|
||||
|
||||
Parameters
|
||||
----------
|
||||
action: QAction
|
||||
the action to add
|
||||
"""
|
||||
if action in self.actions():
|
||||
return
|
||||
|
||||
button = self._createButton(action)
|
||||
self._insertWidgetToLayout(-1, button)
|
||||
super().addAction(action)
|
||||
return button
|
||||
|
||||
def addActions(self, actions: Iterable[QAction]):
|
||||
for action in actions:
|
||||
self.addAction(action)
|
||||
|
||||
def addHiddenAction(self, action: QAction):
|
||||
""" add hidden action """
|
||||
if action in self.actions():
|
||||
return
|
||||
|
||||
self._hiddenActions.append(action)
|
||||
self.updateGeometry()
|
||||
super().addAction(action)
|
||||
|
||||
def addHiddenActions(self, actions: List[QAction]):
|
||||
""" add hidden action """
|
||||
for action in actions:
|
||||
self.addHiddenAction(action)
|
||||
|
||||
def insertAction(self, before: QAction, action: QAction):
|
||||
if before not in self.actions():
|
||||
return
|
||||
|
||||
index = self.actions().index(before)
|
||||
button = self._createButton(action)
|
||||
self._insertWidgetToLayout(index, button)
|
||||
super().insertAction(before, action)
|
||||
return button
|
||||
|
||||
def addSeparator(self):
|
||||
self.insertSeparator(-1)
|
||||
|
||||
def insertSeparator(self, index: int):
|
||||
self._insertWidgetToLayout(index, CommandSeparator(self))
|
||||
|
||||
def addWidget(self, widget: QWidget):
|
||||
""" add widget to command bar """
|
||||
self._insertWidgetToLayout(-1, widget)
|
||||
|
||||
def removeAction(self, action: QAction):
|
||||
if action not in self.actions():
|
||||
return
|
||||
|
||||
for w in self.commandButtons:
|
||||
if w.action() is action:
|
||||
self._widgets.remove(w)
|
||||
w.hide()
|
||||
w.deleteLater()
|
||||
break
|
||||
|
||||
self.updateGeometry()
|
||||
|
||||
def removeWidget(self, widget: QWidget):
|
||||
if widget not in self._widgets:
|
||||
return
|
||||
|
||||
self._widgets.remove(widget)
|
||||
self.updateGeometry()
|
||||
|
||||
def removeHiddenAction(self, action: QAction):
|
||||
if action in self._hiddenActions:
|
||||
self._hiddenActions.remove(action)
|
||||
|
||||
def setToolButtonStyle(self, style: Qt.ToolButtonStyle):
|
||||
""" set the style of tool button """
|
||||
if self.toolButtonStyle() == style:
|
||||
return
|
||||
|
||||
self._toolButtonStyle = style
|
||||
for w in self.commandButtons:
|
||||
w.setToolButtonStyle(style)
|
||||
|
||||
def toolButtonStyle(self):
|
||||
return self._toolButtonStyle
|
||||
|
||||
def setButtonTight(self, isTight: bool):
|
||||
if self.isButtonTight() == isTight:
|
||||
return
|
||||
|
||||
self._isButtonTight = isTight
|
||||
|
||||
for w in self.commandButtons:
|
||||
w.setTight(isTight)
|
||||
|
||||
self.updateGeometry()
|
||||
|
||||
def isButtonTight(self):
|
||||
return self._isButtonTight
|
||||
|
||||
def setIconSize(self, size: QSize):
|
||||
if size == self._iconSize:
|
||||
return
|
||||
|
||||
self._iconSize = size
|
||||
for w in self.commandButtons:
|
||||
w.setIconSize(size)
|
||||
|
||||
def iconSize(self):
|
||||
return self._iconSize
|
||||
|
||||
def resizeEvent(self, e):
|
||||
self.updateGeometry()
|
||||
|
||||
def _createButton(self, action: QAction):
|
||||
""" create command button """
|
||||
button = CommandButton(self)
|
||||
button.setAction(action)
|
||||
button.setToolButtonStyle(self.toolButtonStyle())
|
||||
button.setTight(self.isButtonTight())
|
||||
button.setIconSize(self.iconSize())
|
||||
button.setFont(self.font())
|
||||
return button
|
||||
|
||||
def _insertWidgetToLayout(self, index: int, widget: QWidget):
|
||||
""" add widget to layout """
|
||||
widget.setParent(self)
|
||||
widget.show()
|
||||
|
||||
if index < 0:
|
||||
self._widgets.append(widget)
|
||||
else:
|
||||
self._widgets.insert(index, widget)
|
||||
|
||||
self.setFixedHeight(max(w.height() for w in self._widgets))
|
||||
self.updateGeometry()
|
||||
|
||||
def minimumSizeHint(self) -> QSize:
|
||||
return self.moreButton.size()
|
||||
|
||||
def updateGeometry(self):
|
||||
self._hiddenWidgets.clear()
|
||||
self.moreButton.hide()
|
||||
|
||||
visibles = self._visibleWidgets()
|
||||
x = self.contentsMargins().left()
|
||||
h = self.height()
|
||||
|
||||
for widget in visibles:
|
||||
widget.show()
|
||||
widget.move(x, (h - widget.height()) // 2)
|
||||
x += (widget.width() + self.spacing())
|
||||
|
||||
# show more actions button
|
||||
if self._hiddenActions or len(visibles) < len(self._widgets):
|
||||
self.moreButton.show()
|
||||
self.moreButton.move(x, (h - self.moreButton.height()) // 2)
|
||||
|
||||
for widget in self._widgets[len(visibles):]:
|
||||
widget.hide()
|
||||
self._hiddenWidgets.append(widget)
|
||||
|
||||
def _visibleWidgets(self) -> List[QWidget]:
|
||||
""" return the visible widgets in layout """
|
||||
# have enough spacing to show all widgets
|
||||
if self.suitableWidth() <= self.width():
|
||||
return self._widgets
|
||||
|
||||
w = self.moreButton.width()
|
||||
for index, widget in enumerate(self._widgets):
|
||||
w += widget.width()
|
||||
if index > 0:
|
||||
w += self.spacing()
|
||||
|
||||
if w > self.width():
|
||||
break
|
||||
|
||||
return self._widgets[:index]
|
||||
|
||||
def suitableWidth(self):
|
||||
widths = [w.width() for w in self._widgets]
|
||||
if self._hiddenActions:
|
||||
widths.append(self.moreButton.width())
|
||||
|
||||
return sum(widths) + self.spacing() * max(len(widths) - 1, 0)
|
||||
|
||||
def resizeToSuitableWidth(self):
|
||||
self.setFixedWidth(self.suitableWidth())
|
||||
|
||||
def setFont(self, font: QFont):
|
||||
super().setFont(font)
|
||||
for button in self.commandButtons:
|
||||
button.setFont(font)
|
||||
|
||||
@property
|
||||
def commandButtons(self):
|
||||
return [w for w in self._widgets if isinstance(w, CommandButton)]
|
||||
|
||||
def setMenuDropDown(self, down: bool):
|
||||
""" set the animation direction of more actions menu """
|
||||
if down:
|
||||
self._menuAnimation = MenuAnimationType.DROP_DOWN
|
||||
else:
|
||||
self._menuAnimation = MenuAnimationType.PULL_UP
|
||||
|
||||
def isMenuDropDown(self):
|
||||
return self._menuAnimation == MenuAnimationType.DROP_DOWN
|
||||
|
||||
def _showMoreActionsMenu(self):
|
||||
""" show more actions menu """
|
||||
self.moreButton.clearState()
|
||||
|
||||
actions = self._hiddenActions.copy()
|
||||
|
||||
for w in reversed(self._hiddenWidgets):
|
||||
if isinstance(w, CommandButton):
|
||||
actions.insert(0, w.action())
|
||||
|
||||
menu = CommandMenu(self)
|
||||
menu.addActions(actions)
|
||||
|
||||
x = -menu.width() + menu.layout().contentsMargins().right() + \
|
||||
self.moreButton.width() + 18
|
||||
if self._menuAnimation == MenuAnimationType.DROP_DOWN:
|
||||
y = self.moreButton.height()
|
||||
else:
|
||||
y = -5
|
||||
|
||||
pos = self.moreButton.mapToGlobal(QPoint(x, y))
|
||||
menu.exec(pos, aniType=self._menuAnimation)
|
||||
|
||||
|
||||
class CommandViewMenu(CommandMenu):
|
||||
""" Command view menu """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.view.setObjectName('commandListWidget')
|
||||
|
||||
def setDropDown(self, down: bool, long=False):
|
||||
self.view.setProperty('dropDown', down)
|
||||
self.view.setProperty('long', long)
|
||||
self.view.setStyle(QApplication.style())
|
||||
|
||||
def exec(self, pos, ani=True, aniType=MenuAnimationType.DROP_DOWN):
|
||||
return super().exec(pos, ani, aniType)
|
||||
|
||||
|
||||
class CommandViewBar(CommandBar):
|
||||
""" Command view bar """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setMenuDropDown(True)
|
||||
|
||||
def setMenuDropDown(self, down: bool):
|
||||
""" set the animation direction of more actions menu """
|
||||
if down:
|
||||
self._menuAnimation = MenuAnimationType.FADE_IN_DROP_DOWN
|
||||
else:
|
||||
self._menuAnimation = MenuAnimationType.FADE_IN_PULL_UP
|
||||
|
||||
def isMenuDropDown(self):
|
||||
return self._menuAnimation == MenuAnimationType.FADE_IN_DROP_DOWN
|
||||
|
||||
def _showMoreActionsMenu(self):
|
||||
self.moreButton.clearState()
|
||||
|
||||
actions = self._hiddenActions.copy()
|
||||
|
||||
for w in reversed(self._hiddenWidgets):
|
||||
if isinstance(w, CommandButton):
|
||||
actions.insert(0, w.action())
|
||||
|
||||
menu = CommandViewMenu(self)
|
||||
menu.addActions(actions)
|
||||
|
||||
# adjust the shape of view
|
||||
view = self.parent() # type: CommandBarView
|
||||
view.setMenuVisible(True)
|
||||
|
||||
# adjust the shape of menu
|
||||
menu.closedSignal.connect(lambda: view.setMenuVisible(False))
|
||||
menu.setDropDown(self.isMenuDropDown(), menu.view.width() > view.width()+5)
|
||||
|
||||
# adjust menu size
|
||||
if menu.view.width() < view.width():
|
||||
menu.view.setFixedWidth(view.width())
|
||||
menu.adjustSize()
|
||||
|
||||
x = -menu.width() + menu.layout().contentsMargins().right() + \
|
||||
self.moreButton.width() + 18
|
||||
if self.isMenuDropDown():
|
||||
y = self.moreButton.height()
|
||||
else:
|
||||
y = -13
|
||||
menu.setShadowEffect(0, (0, 0), QColor(0, 0, 0, 0))
|
||||
menu.layout().setContentsMargins(12, 20, 12, 8)
|
||||
|
||||
pos = self.moreButton.mapToGlobal(QPoint(x, y))
|
||||
menu.exec(pos, aniType=self._menuAnimation)
|
||||
|
||||
|
||||
class CommandBarView(FlyoutViewBase):
|
||||
""" Command bar view """
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
self.bar = CommandViewBar(self)
|
||||
self.hBoxLayout = QHBoxLayout(self)
|
||||
|
||||
self.hBoxLayout.setContentsMargins(6, 6, 6, 6)
|
||||
self.hBoxLayout.addWidget(self.bar)
|
||||
self.hBoxLayout.setSizeConstraint(QHBoxLayout.SetMinAndMaxSize)
|
||||
|
||||
self.setButtonTight(True)
|
||||
self.setIconSize(QSize(14, 14))
|
||||
|
||||
self._isMenuVisible = False
|
||||
|
||||
def setMenuVisible(self, isVisible):
|
||||
self._isMenuVisible = isVisible
|
||||
self.update()
|
||||
|
||||
def addWidget(self, widget: QWidget):
|
||||
self.bar.addWidget(widget)
|
||||
|
||||
def setSpaing(self, spacing: int):
|
||||
self.bar.setSpaing(spacing)
|
||||
|
||||
def spacing(self):
|
||||
return self.bar.spacing()
|
||||
|
||||
def addAction(self, action: QAction):
|
||||
return self.bar.addAction(action)
|
||||
|
||||
def addActions(self, actions: Iterable[QAction]):
|
||||
self.bar.addActions(actions)
|
||||
|
||||
def addHiddenAction(self, action: QAction):
|
||||
self.bar.addHiddenAction(action)
|
||||
|
||||
def addHiddenActions(self, actions: List[QAction]):
|
||||
self.bar.addHiddenActions(actions)
|
||||
|
||||
def insertAction(self, before: QAction, action: QAction):
|
||||
return self.bar.insertAction(before, action)
|
||||
|
||||
def addSeparator(self):
|
||||
self.bar.addSeparator()
|
||||
|
||||
def insertSeparator(self, index: int):
|
||||
self.bar.insertSeparator(index)
|
||||
|
||||
def removeAction(self, action: QAction):
|
||||
self.bar.removeAction(action)
|
||||
|
||||
def removeWidget(self, widget: QWidget):
|
||||
self.bar.removeWidget(widget)
|
||||
|
||||
def removeHiddenAction(self, action: QAction):
|
||||
self.bar.removeAction(action)
|
||||
|
||||
def setToolButtonStyle(self, style: Qt.ToolButtonStyle):
|
||||
self.bar.setToolButtonStyle(style)
|
||||
|
||||
def toolButtonStyle(self):
|
||||
return self.bar.toolButtonStyle()
|
||||
|
||||
def setButtonTight(self, isTight: bool):
|
||||
self.bar.setButtonTight(isTight)
|
||||
|
||||
def isButtonTight(self):
|
||||
return self.bar.isButtonTight()
|
||||
|
||||
def setIconSize(self, size: QSize):
|
||||
self.bar.setIconSize(size)
|
||||
|
||||
def iconSize(self):
|
||||
return self.bar.iconSize()
|
||||
|
||||
def setFont(self, font: QFont):
|
||||
self.bar.setFont(font)
|
||||
|
||||
def setMenuDropDown(self, down: bool):
|
||||
self.bar.setMenuDropDown(down)
|
||||
|
||||
def suitableWidth(self):
|
||||
m = self.contentsMargins()
|
||||
return m.left() + m.right() + self.bar.suitableWidth()
|
||||
|
||||
def resizeToSuitableWidth(self):
|
||||
self.bar.resizeToSuitableWidth()
|
||||
self.setFixedWidth(self.suitableWidth())
|
||||
|
||||
def actions(self):
|
||||
return self.bar.actions()
|
||||
|
||||
def paintEvent(self, e):
|
||||
painter = QPainter(self)
|
||||
painter.setRenderHints(QPainter.Antialiasing)
|
||||
|
||||
path = QPainterPath()
|
||||
path.setFillRule(Qt.WindingFill)
|
||||
path.addRoundedRect(QRectF(self.rect().adjusted(1, 1, -1, -1)), 8, 8)
|
||||
|
||||
if self._isMenuVisible:
|
||||
y = self.height() - 10 if self.bar.isMenuDropDown() else 1
|
||||
path.addRect(1, y, self.width() - 2, 9)
|
||||
|
||||
painter.setBrush(
|
||||
QColor(40, 40, 40) if isDarkTheme() else QColor(248, 248, 248))
|
||||
painter.setPen(
|
||||
QColor(56, 56, 56) if isDarkTheme() else QColor(233, 233, 233))
|
||||
painter.drawPath(path.simplified())
|
||||
Reference in New Issue
Block a user