提交 315fdcb6 编写于 作者: 之一Yo's avatar 之一Yo

添加 InfoBar 组件

上级 88f7ca83
......@@ -257,5 +257,13 @@ class HomeInterface(ScrollArea):
routeKey="statusInfoInterface",
index=1
)
stateInfoView.addSampleCard(
icon="app/resource/images/controls/InfoBar.png",
title="InfoBar",
content=self.tr(
"An inline message to display app-wide status change information."),
routeKey="statusInfoInterface",
index=3
)
self.vBoxLayout.addWidget(stateInfoView)
......@@ -211,7 +211,7 @@ class MainWindow(FramelessWindow):
def initWindow(self):
self.resize(960, 780)
self.setMinimumWidth(580)
self.setMinimumWidth(760)
self.setWindowIcon(QIcon('app/resource/images/logo.png'))
self.setWindowTitle('PyQt-Fluent-Widgets')
self.titleBar.setAttribute(Qt.WA_StyledBackground)
......
# coding:utf-8
from PyQt5.QtCore import Qt
from PyQt5.QtGui import QPixmap
from PyQt5.QtWidgets import QWidget, QLabel
from qfluentwidgets import StateToolTip, ToolTipFilter, PushButton, PixmapLabel
from PyQt5.QtGui import QPixmap, QColor
from PyQt5.QtWidgets import QWidget, QHBoxLayout
from qfluentwidgets import (StateToolTip, ToolTipFilter, PushButton, PixmapLabel,
InfoBar, InfoBarIcon, FluentIcon, InfoBarPosition)
from .gallery_interface import GalleryInterface
from ..common.translator import Translator
......@@ -19,6 +20,7 @@ class StatusInfoInterface(GalleryInterface):
parent=parent
)
# state tool tip
self.stateTooltip = None
button = PushButton(self.tr('Show StateToolTip'))
button.clicked.connect(self.onStateButtonClicked)
......@@ -28,6 +30,7 @@ class StatusInfoInterface(GalleryInterface):
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/status_tool_tip/demo.py'
)
# tool tip
button = PushButton(self.tr('Button with a simple ToolTip'))
button.installEventFilter(ToolTipFilter(button))
button.setToolTip(self.tr('Simple ToolTip'))
......@@ -50,9 +53,89 @@ class StatusInfoInterface(GalleryInterface):
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/tool_tip/demo.py'
)
# short info bar
infoBar = InfoBar(
icon=InfoBarIcon.SUCCESS,
title=self.tr('Success'),
content=self.tr("Essential app message for your users."),
orient=Qt.Horizontal,
isClosable=True,
duration=-1,
position=InfoBarPosition.NONE,
parent=self
)
self.addExampleCard(
self.tr('A closable InfoBar'),
infoBar,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/info_bar/demo.py'
)
# long info bar
content = self.tr("A long essential app message for your users to be informed of, acknowledge, or take action on. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dapibus dolor vitae justo rutrum, ut lobortis nibh mattis. Aenean id elit commodo, semper felis nec.")
infoBar = InfoBar(
icon=InfoBarIcon.WARNING,
title=self.tr('Warning'),
content=content,
orient=Qt.Vertical,
isClosable=True,
duration=-1,
position=InfoBarPosition.NONE,
parent=self
)
self.addExampleCard(
self.tr('A closable InfoBar with long message'),
infoBar,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/info_bar/demo.py',
)
# add custom widget to info bar
infoBar = InfoBar(
icon=FluentIcon.GITHUB,
title=self.tr('GitHub'),
content=self.tr("When you look long into an abyss, the abyss looks into you."),
orient=Qt.Horizontal,
isClosable=True,
duration=-1,
position=InfoBarPosition.NONE,
parent=self
)
infoBar.addWidget(PushButton('Action'))
infoBar.setCustomBackgroundColor("white", "#202020")
self.addExampleCard(
self.tr('An InfoBar with custom icon, background color and widget.'),
infoBar,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/info_bar/demo.py',
)
# different type info bar
w = QWidget(self)
hBoxLayout = QHBoxLayout(w)
button1 = PushButton(self.tr('Information'), w)
button2 = PushButton(self.tr('Success'), w)
button3 = PushButton(self.tr('Warning'), w)
button4 = PushButton(self.tr('Error'), w)
button1.clicked.connect(self.createInfoInfoBar)
button2.clicked.connect(self.createSuccessInfoBar)
button3.clicked.connect(self.createWarningInfoBar)
button4.clicked.connect(self.createErrorInfoBar)
hBoxLayout.addWidget(button1)
hBoxLayout.addWidget(button2)
hBoxLayout.addWidget(button3)
hBoxLayout.addWidget(button4)
hBoxLayout.setContentsMargins(0, 0, 0, 0)
hBoxLayout.setSpacing(15)
self.addExampleCard(
self.tr('InfoBar with different pop-up locations'),
w,
'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/info_bar/demo.py',
)
def onStateButtonClicked(self):
if self.stateTooltip:
self.stateTooltip.setContent(self.tr('The model training is complete!') +' 😆')
self.stateTooltip.setContent(
self.tr('The model training is complete!') + ' 😆')
self.sender().setText(self.tr('Show StateToolTip'))
self.stateTooltip.setState(True)
self.stateTooltip = None
......@@ -62,3 +145,52 @@ class StatusInfoInterface(GalleryInterface):
self.sender().setText(self.tr('Hide StateToolTip'))
self.stateTooltip.move(self.stateTooltip.getSuitablePos())
self.stateTooltip.show()
def createInfoInfoBar(self):
content = "A long essential app message for your users to be informed of, acknowledge, or take action on. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dapibus dolor vitae justo rutrum, ut lobortis nibh mattis. Aenean id elit commodo, semper felis nec."
w = InfoBar(
icon=InfoBarIcon.INFORMATION,
title='Information',
content=content,
orient=Qt.Vertical, # vertical layout
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=2000,
parent=self
)
w.show()
def createSuccessInfoBar(self):
content = "A short essential success app message."
# convenient static mothod
InfoBar.success(
title='Title',
content=content,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=2000,
parent=self
)
def createWarningInfoBar(self):
InfoBar.warning(
title='Title',
content="A short essential app warning message.",
orient=Qt.Horizontal,
isClosable=False, # disable close button
position=InfoBarPosition.TOP_LEFT,
duration=2000,
parent=self
)
def createErrorInfoBar(self):
InfoBar.error(
title=self.tr('No Internet'),
content="A error message which won't disappear automatically.",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=-1, # won't disappear automatically
parent=self
)
# coding:utf-8
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout
from qfluentwidgets import InfoBarIcon, InfoBar, PushButton, setTheme, Theme, FluentIcon, InfoBarPosition
class Demo(QWidget):
def __init__(self):
super().__init__()
# setTheme(Theme.DARK)
self.hBoxLayout = QHBoxLayout(self)
self.button1 = PushButton('Information', self)
self.button2 = PushButton('Success', self)
self.button3 = PushButton('Warning', self)
self.button4 = PushButton('Error', self)
self.button1.clicked.connect(self.createInfoInfoBar)
self.button2.clicked.connect(self.createSuccessInfoBar)
self.button3.clicked.connect(self.createWarningInfoBar)
self.button4.clicked.connect(self.createErrorInfoBar)
self.hBoxLayout.addWidget(self.button1)
self.hBoxLayout.addWidget(self.button2)
self.hBoxLayout.addWidget(self.button3)
self.hBoxLayout.addWidget(self.button4)
self.hBoxLayout.setContentsMargins(30, 0, 30, 0)
self.resize(700, 700)
def createInfoInfoBar(self):
content = "A long essential app message for your users to be informed of, acknowledge, or take action on. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin dapibus dolor vitae justo rutrum, ut lobortis nibh mattis. Aenean id elit commodo, semper felis nec."
w = InfoBar(
icon=InfoBarIcon.INFORMATION,
title='Title',
content=content,
orient=Qt.Vertical, # vertical layout
isClosable=True,
position=InfoBarPosition.TOP_RIGHT,
duration=2000,
parent=self
)
w.addWidget(PushButton('Action'))
w.show()
def createSuccessInfoBar(self):
content = "A short essential success app message."
# convenient static mothod
InfoBar.success(
title='Title',
content=content,
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.TOP,
duration=2000,
parent=self
)
def createWarningInfoBar(self):
InfoBar.warning(
title='Title',
content="A short essential app warning message.",
orient=Qt.Horizontal,
isClosable=False, # disable close button
position=InfoBarPosition.TOP_LEFT,
duration=2000,
parent=self
)
def createErrorInfoBar(self):
InfoBar.error(
title='Title',
content="A short essential app error message.",
orient=Qt.Horizontal,
isClosable=True,
position=InfoBarPosition.BOTTOM_RIGHT,
duration=-1, # won't disappear automatically
parent=self
)
if __name__ == '__main__':
# enable dpi scale
QApplication.setHighDpiScaleFactorRoundingPolicy(
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
app = QApplication(sys.argv)
w = Demo()
w.show()
app.exec_()
......@@ -12,7 +12,7 @@ Examples are available at https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/ma
:license: GPLv3, see LICENSE for more details.
"""
__version__ = "0.4.8"
__version__ = "0.4.9"
from .components import *
from .common import *
......
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#FF99A4" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#000" d="M648.53 1484.8 q16 0 32.54 -6.4 q16.53 -6.4 28.26 -18.13 l314.67 -315.74 l314.67 315.74 q11.73 11.73 28.26 18.13 q16.54 6.4 32.54 6.4 q36.26 0 60.79 -24.54 q24.54 -24.53 24.54 -60.79 q0 -36.27 -24.53 -60.8 l-315.74 -314.67 l315.74 -314.67 q24.53 -24.53 24.53 -60.8 q0 -36.26 -24.54 -60.79 q-24.53 -24.53 -60.79 -24.53 q-36.27 0 -60.8 24.53 l-314.67 315.74 l-314.67 -315.74 q-24.53 -24.53 -60.8 -24.53 q-36.26 0 -60.79 24.53 q-24.53 24.53 -24.53 60.79 q0 16 6.4 32.54 q6.4 16.53 18.13 28.26 l315.74 314.67 l-315.74 314.67 q-11.73 11.73 -18.13 28.26 q-6.4 16.54 -6.4 32.54 q0 35.2 25.07 60.27 q25.06 25.06 60.26 25.06 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#C42B1C" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#ffffff" d="M648.53 1484.8 q16 0 32.54 -6.4 q16.53 -6.4 28.26 -18.13 l314.67 -315.74 l314.67 315.74 q11.73 11.73 28.26 18.13 q16.54 6.4 32.54 6.4 q36.26 0 60.79 -24.54 q24.54 -24.53 24.54 -60.79 q0 -36.27 -24.53 -60.8 l-315.74 -314.67 l315.74 -314.67 q24.53 -24.53 24.53 -60.8 q0 -36.26 -24.54 -60.79 q-24.53 -24.53 -60.79 -24.53 q-36.27 0 -60.8 24.53 l-314.67 315.74 l-314.67 -315.74 q-24.53 -24.53 -60.8 -24.53 q-36.26 0 -60.79 24.53 q-24.53 24.53 -24.53 60.79 q0 16 6.4 32.54 q6.4 16.53 18.13 28.26 l315.74 314.67 l-315.74 314.67 q-11.73 11.73 -18.13 28.26 q-6.4 16.54 -6.4 32.54 q0 35.2 25.07 60.27 q25.06 25.06 60.26 25.06 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#29f7ff" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#000" d="M1126.4 614.4 q0 -42.67 -29.87 -72.53 q-29.87 -29.87 -72.54 -29.87 q-42.67 0 -72.53 29.87 q-29.87 29.87 -29.87 72.53 q0 42.67 29.87 72.53 q29.87 29.87 72.53 29.87 q42.67 0 72.54 -29.87 q29.87 -29.86 29.87 -72.53 ZM1092.27 1433.6 l0 -546.13 q0 -27.74 -20.27 -48 q-20.27 -20.26 -48 -20.26 q-27.73 0 -48 20.26 q-20.27 20.26 -20.27 48 l0 546.13 q0 27.73 20.27 48 q20.27 20.27 48 20.27 q27.73 0 48 -20.27 q20.27 -20.27 20.27 -48 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#00b7c3" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#ffffff" d="M1126.4 614.4 q0 -42.67 -29.87 -72.53 q-29.87 -29.87 -72.54 -29.87 q-42.67 0 -72.53 29.87 q-29.87 29.87 -29.87 72.53 q0 42.67 29.87 72.53 q29.87 29.87 72.53 29.87 q42.67 0 72.54 -29.87 q29.87 -29.86 29.87 -72.53 ZM1092.27 1433.6 l0 -546.13 q0 -27.74 -20.27 -48 q-20.27 -20.26 -48 -20.26 q-27.73 0 -48 20.26 q-20.27 20.26 -20.27 48 l0 546.13 q0 27.73 20.27 48 q20.27 20.27 48 20.27 q27.73 0 48 -20.27 q20.27 -20.27 20.27 -48 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#6CCB5F" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#000" d="M1518.93 750.93 q0 -36.26 -24.53 -60.79 q-24.53 -24.53 -60.8 -24.53 q-36.27 0 -60.8 24.53 l-485.33 486.4 l-212.27 -213.33 q-24.53 -24.53 -60.8 -24.53 q-36.27 0 -60.8 24.53 q-24.53 24.53 -24.53 60.8 q0 16 6.4 32.53 q6.4 16.54 18.13 28.27 l273.07 273.07 q11.73 11.73 28.26 18.13 q16.54 6.4 32.54 6.4 q16 0 32.53 -6.4 q16.53 -6.4 28.27 -18.13 l546.13 -546.14 q24.53 -24.53 24.53 -60.8 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#0F7B0F" d="M0 1024 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 q-141.87 0 -272.54 -36.8 q-130.66 -36.8 -244.26 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.8 q-36.8 -131.2 -36.8 -272 Z"/>
<path fill="#ffffff" d="M1518.93 750.93 q0 -36.26 -24.53 -60.79 q-24.53 -24.53 -60.8 -24.53 q-36.27 0 -60.8 24.53 l-485.33 486.4 l-212.27 -213.33 q-24.53 -24.53 -60.8 -24.53 q-36.27 0 -60.8 24.53 q-24.53 24.53 -24.53 60.8 q0 16 6.4 32.53 q6.4 16.54 18.13 28.27 l273.07 273.07 q11.73 11.73 28.26 18.13 q16.54 6.4 32.54 6.4 q16 0 32.53 -6.4 q16.53 -6.4 28.27 -18.13 l546.13 -546.14 q24.53 -24.53 24.53 -60.8 Z"/>
</svg>
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#FCE100" d="M1024 2048 q-140.8 0 -272 -36.8 q-131.2 -36.8 -244.8 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.27 q-36.8 -130.66 -36.8 -272.53 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 Z"/>
<path fill="#000" d="M1126.4 1399.47 q0 -42.67 -29.87 -72.54 q-29.87 -29.87 -72.54 -29.87 q-42.67 0 -72.53 29.87 q-29.87 29.87 -29.87 72.54 q0 42.66 29.87 72.53 q29.87 29.87 72.53 29.87 q42.67 0 72.54 -29.87 q29.87 -29.87 29.87 -72.53 ZM1092.27 580.27 q0 -27.74 -20.27 -48 q-20.27 -20.26 -48 -20.26 q-27.73 0 -48 20.26 q-20.27 20.26 -20.27 48 l0 546.13 q0 27.73 20.27 48 q20.27 20.27 48 20.27 q27.73 0 48 -20.27 q20.27 -20.27 20.27 -48 l0 -546.13 Z"/>
</svg>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<svg id="" width="16" height="16" style="width:16px;height:16px;" version="1.1"
xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2048 2048" enable-background="new 0 0 2048 2048"
xml:space="preserve">
<path fill="#9D5D00" d="M1024 2048 q-140.8 0 -272 -36.8 q-131.2 -36.8 -244.8 -103.46 q-113.6 -66.67 -206.94 -160 q-93.33 -93.34 -160 -206.93 q-66.66 -113.6 -103.46 -244.27 q-36.8 -130.66 -36.8 -272.53 q0 -140.8 36.8 -271.46 q36.8 -130.67 103.46 -244.8 q66.67 -114.13 160 -207.47 q93.34 -93.33 207.47 -160 q114.13 -66.66 244.8 -103.46 q130.66 -36.8 271.46 -36.8 q140.8 0 271.47 36.8 q130.66 36.8 244.26 103.46 q113.6 66.67 207.47 160.54 q93.87 93.87 160.54 207.47 q66.66 113.6 103.46 244.27 q36.8 130.66 36.8 271.46 q0 140.8 -36.8 271.47 q-36.8 130.66 -103.46 244.8 q-66.67 114.13 -160 207.47 q-93.34 93.33 -207.47 160 q-114.13 66.66 -244.8 103.46 q-130.67 36.8 -271.47 36.8 Z"/>
<path fill="#ffffff" d="M1126.4 1399.47 q0 -42.67 -29.87 -72.54 q-29.87 -29.87 -72.54 -29.87 q-42.67 0 -72.53 29.87 q-29.87 29.87 -29.87 72.54 q0 42.66 29.87 72.53 q29.87 29.87 72.53 29.87 q42.67 0 72.54 -29.87 q29.87 -29.87 29.87 -72.53 ZM1092.27 580.27 q0 -27.74 -20.27 -48 q-20.27 -20.26 -48 -20.26 q-27.73 0 -48 20.26 q-20.27 20.26 -20.27 48 l0 546.13 q0 27.73 20.27 48 q20.27 20.27 48 20.27 q27.73 0 48 -20.27 q20.27 -20.27 20.27 -48 l0 -546.13 Z"/>
</svg>
\ No newline at end of file
InfoBar {
border: 1px solid rgb(29, 29, 29);
border-radius: 6px;
background-color: rgb(39, 39, 39);
}
#titleLabel {
font: 14px 'Segoe UI', 'Microsoft YaHei';
font-weight: bold;
color: white;
}
#contentLabel {
font: 14px 'Segoe UI', 'Microsoft YaHei';
color: white;
}
InfoBar[type="Info"] {
background-color: rgb(39, 39, 39);
}
InfoBar[type="Success"] {
background-color: rgb(57, 61, 27);
}
InfoBar[type="Warning"] {
background-color: rgb(67, 53, 25);
}
InfoBar[type="Error"] {
background-color: rgb(68, 39, 38);
}
InfoBarCloseButton {
background-color: transparent;
border-radius: 5px;
}
InfoBarCloseButton:hover {
background-color: rgba(255, 255, 255, 9);
}
InfoBarCloseButton:pressed {
background-color: rgba(255, 255, 255, 6);
}
\ No newline at end of file
InfoBar {
border: 1px solid rgb(229, 229, 229);
border-radius: 6px;
background-color: rgb(244, 244, 244);
}
#titleLabel {
font: 14px 'Segoe UI', 'Microsoft YaHei';
font-weight: bold;
color: black;
}
#contentLabel {
font: 14px 'Segoe UI', 'Microsoft YaHei';
color: black;
}
InfoBar[type="Info"] {
background-color: rgb(244, 244, 244);
}
InfoBar[type="Success"] {
background-color: rgb(223, 246, 221);
}
InfoBar[type="Warning"] {
background-color: rgb(255, 244, 206);
}
InfoBar[type="Error"] {
background-color: rgb(253, 231, 233);
}
InfoBarCloseButton {
background-color: transparent;
border-radius: 5px;
}
InfoBarCloseButton:hover {
background-color: rgba(0, 0, 0, 9);
}
InfoBarCloseButton:pressed {
background-color: rgba(0, 0, 0, 6);
}
\ No newline at end of file
此差异已折叠。
......@@ -118,6 +118,14 @@
<file>images/check_box/Accept_white.svg</file>
<file>images/check_box/PartialAccept_black.svg</file>
<file>images/check_box/PartialAccept_white.svg</file>
<file>images/info_bar/Error_light.svg</file>
<file>images/info_bar/Error_dark.svg</file>
<file>images/info_bar/Success_light.svg</file>
<file>images/info_bar/Success_dark.svg</file>
<file>images/info_bar/Warning_light.svg</file>
<file>images/info_bar/Warning_dark.svg</file>
<file>images/info_bar/Info_light.svg</file>
<file>images/info_bar/Info_dark.svg</file>
<file>qss/dark/color_dialog.qss</file>
<file>qss/dark/dialog.qss</file>
......@@ -136,6 +144,7 @@
<file>qss/dark/slider.qss</file>
<file>qss/dark/line_edit.qss</file>
<file>qss/dark/check_box.qss</file>
<file>qss/dark/info_bar.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/dialog.qss</file>
......@@ -154,5 +163,6 @@
<file>qss/light/slider.qss</file>
<file>qss/light/line_edit.qss</file>
<file>qss/light/check_box.qss</file>
<file>qss/light/info_bar.qss</file>
</qresource>
</RCC>
\ No newline at end of file
# coding:utf-8
from enum import Enum
from PyQt5.QtCore import QPoint, QRect, QRectF, Qt
from PyQt5.QtGui import QIcon, QIconEngine, QImage, QPainter, QPixmap
from PyQt5.QtXml import QDomDocument
from PyQt5.QtCore import QPoint, QRect, QRectF, Qt, QFile
from PyQt5.QtGui import QIcon, QIconEngine, QImage, QPainter, QPixmap, QColor
from PyQt5.QtSvg import QSvgRenderer
from .config import isDarkTheme, Theme
......@@ -52,13 +53,13 @@ def getIconColor():
return "white" if isDarkTheme() else 'black'
def drawSvgIcon(iconPath, painter, rect):
def drawSvgIcon(icon, painter, rect):
""" draw svg icon
Parameters
----------
iconPath: str
the path of svg icon
icon: str | bytes | QByteArray
the path or code of svg icon
painter: QPainter
painter
......@@ -66,10 +67,52 @@ def drawSvgIcon(iconPath, painter, rect):
rect: QRect | QRectF
the rect to render icon
"""
renderer = QSvgRenderer(iconPath)
renderer = QSvgRenderer(icon)
renderer.render(painter, QRectF(rect))
def writeSvg(iconPath: str, indexes=None, **attributes):
""" write svg with specified attributes
Parameters
----------
iconPath: str
svg icon path
indexes: List[int]
the path to be filled
**attributes:
the attributes of path
Returns
-------
svg: str
svg code
"""
if not iconPath.lower().endswith('.svg'):
return ""
f = QFile(iconPath)
f.open(QFile.ReadOnly)
dom = QDomDocument()
dom.setContent(f.readAll())
f.close()
# change the color of each path
pathNodes = dom.elementsByTagName('path')
indexes = range(pathNodes.length()) if not indexes else indexes
for i in indexes:
element = pathNodes.at(i).toElement()
for k, v in attributes.items():
element.setAttribute(k, v)
return dom.toString()
def drawIcon(icon, painter, rect):
""" draw icon
......@@ -142,7 +185,6 @@ class FluentIconBase:
drawSvgIcon(self.path(theme), painter, rect)
class FluentIcon(FluentIconBase, Enum):
""" Fluent icon """
......@@ -204,4 +246,3 @@ class FluentIcon(FluentIconBase, Enum):
c = "white" if theme == Theme.DARK else "black"
return f':/qfluentwidgets/images/icons/{self.value}_{c}.svg'
......@@ -3,7 +3,6 @@ from enum import Enum
from string import Template
import weakref
import darkdetect
from PyQt5.QtCore import QFile, QObject
from PyQt5.QtGui import QColor
from PyQt5.QtWidgets import QWidget
......
......@@ -10,4 +10,5 @@ from .button import PrimaryPushButton, PushButton, RadioButton, HyperlinkButton,
from .line_edit import LineEdit
from .check_box import CheckBox
from .icon_widget import IconWidget
from .label import PixmapLabel
\ No newline at end of file
from .label import PixmapLabel
from .info_bar import InfoBar, InfoBarIcon, InfoBarPosition
\ No newline at end of file
# coding:utf-8
from enum import Enum
from typing import Union
import weakref
from PyQt5.QtCore import (Qt, QEvent, QSize, QRectF, QObject, QPropertyAnimation,
QEasingCurve, QTimer, pyqtSignal, QParallelAnimationGroup, QPoint)
from PyQt5.QtGui import QPainter, QIcon, QColor
from PyQt5.QtWidgets import (QWidget, QFrame, QLabel, QHBoxLayout, QVBoxLayout,
QToolButton, QGraphicsOpacityEffect)
from ...common.auto_wrap import TextWrap
from ...common.style_sheet import setStyleSheet, themeColor
from ...common.icon import FluentIconBase, Theme, isDarkTheme, writeSvg, drawSvgIcon, drawIcon
from ...common.icon import FluentIcon as FIF
class InfoBarCloseButton(QToolButton):
""" Close button """
def __init__(self, parent=None):
super().__init__(parent=parent)
self.setFixedSize(36, 36)
self.setIconSize(QSize(12, 12))
self.setCursor(Qt.PointingHandCursor)
self.setObjectName('infoBarCloseButton')
setStyleSheet(self, 'info_bar')
def paintEvent(self, e):
super().paintEvent(e)
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing |
QPainter.SmoothPixmapTransform)
FIF.CLOSE.render(painter, QRectF(11, 12, 12, 12))
class InfoBarIcon(FluentIconBase, Enum):
""" Info bar icon """
INFORMATION = "Info"
SUCCESS = "Success"
WARNING = "Warning"
ERROR = "Error"
def path(self, theme=Theme.AUTO):
if theme == Theme.AUTO:
color = "dark" if isDarkTheme() else "light"
else:
color = theme.value.lower()
return f':/qfluentwidgets/images/info_bar/{self.value}_{color}.svg'
class InfoBarPosition(Enum):
""" Info bar position """
TOP = 0
BOTTOM = 1
TOP_LEFT = 2
TOP_RIGHT = 3
BOTTOM_LEFT = 4
BOTTOM_RIGHT = 5
NONE = 6
class InfoIconWidget(QWidget):
""" Icon widget """
def __init__(self, icon: InfoBarIcon, parent=None):
super().__init__(parent=parent)
self.setFixedSize(15, 15)
self.icon = icon
def paintEvent(self, e):
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing |
QPainter.SmoothPixmapTransform)
if self.icon != InfoBarIcon.INFORMATION:
drawIcon(self.icon, painter, self.rect())
else:
svg = writeSvg(self.icon.path(), [0], fill=themeColor().name())
drawSvgIcon(svg.encode(), painter, self.rect())
class InfoBar(QFrame):
""" Information bar """
closedSignal = pyqtSignal()
def __init__(self, icon: Union[InfoBarIcon, FluentIconBase, QIcon, str], title: str, content: str,
orient=Qt.Horizontal, isClosable=True, duration=1000, position=InfoBarPosition.TOP_RIGHT,
parent=None):
"""
Parameters
----------
icon: InfoBarIcon | FluentIconBase | QIcon | str
the icon of info bar
title: str
the title of info bar
content: str
the content of info bar
orient: Qt.Orientation
the layout direction of info bar, use `Qt.Horizontal` for short content
isClosable: bool
whether to show the close button
duraction: int
the time for info bar to display in milliseconds. If duration is less than zero,
info bar will never disappear.
parent: QWidget
parent widget
"""
super().__init__(parent=parent)
self.title = title
self.content = content
self.orient = orient
self.icon = icon
self.duration = duration
self.isClosable = isClosable
self.position = position
self.titleLabel = QLabel(title, self)
self.contentLabel = QLabel(self)
self.closeButton = InfoBarCloseButton(self)
self.iconWidget = InfoIconWidget(icon)
self.vBoxLayout = QVBoxLayout(self)
self.hBoxLayout = QHBoxLayout()
self.contentLayout = QHBoxLayout() if self.orient == Qt.Horizontal else QVBoxLayout()
self.opacityEffect = QGraphicsOpacityEffect(self)
self.opacityAni = QPropertyAnimation(
self.opacityEffect, b'opacity', self)
self.lightBackgroundColor = None
self.darkBackgroundColor = None
self.__initWidget()
def __initWidget(self):
self.titleLabel.setMinimumHeight(36)
self.opacityEffect.setOpacity(1)
self.setGraphicsEffect(self.opacityEffect)
self.closeButton.setVisible(self.isClosable)
self.__initLayout()
self.__setQss()
self.closeButton.clicked.connect(self.close)
def __initLayout(self):
self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
self.vBoxLayout.setSizeConstraint(QVBoxLayout.SetMinimumSize)
self.contentLayout.setSizeConstraint(QHBoxLayout.SetMinimumSize)
self.vBoxLayout.setSpacing(0)
self.hBoxLayout.setSpacing(0)
self.vBoxLayout.addLayout(self.hBoxLayout)
self.hBoxLayout.addWidget(self.iconWidget)
self.hBoxLayout.addSpacing(15)
self.hBoxLayout.addWidget(self.titleLabel)
# add content label to layout
if self.orient == Qt.Horizontal:
self.vBoxLayout.setAlignment(Qt.AlignVCenter)
self.hBoxLayout.addSpacing(12)
self.contentLayout.setContentsMargins(0, 0, 20*self.isClosable, 0)
self.contentLayout.setSpacing(12)
self.hBoxLayout.addLayout(self.contentLayout)
self.contentLabel.setText(self.content)
else:
self.vBoxLayout.setAlignment(Qt.AlignTop)
self.contentLayout.setContentsMargins(47, 0, 40, 18)
self.contentLayout.setSpacing(14)
self.vBoxLayout.addLayout(self.contentLayout)
self.contentLayout.setAlignment(Qt.AlignTop)
self._adjustText()
self.contentLayout.addWidget(self.contentLabel)
# add close button to layout
if self.isClosable:
self.hBoxLayout.addWidget(self.closeButton)
mb = 6 if self.orient == Qt.Horizontal else 0
self.hBoxLayout.setContentsMargins(16, 6, 7, mb)
else:
self.hBoxLayout.setContentsMargins(16, 6, 16, 6)
def __setQss(self):
self.titleLabel.setObjectName('titleLabel')
self.contentLabel.setObjectName('contentLabel')
if isinstance(self.icon, Enum):
self.setProperty('type', self.icon.value)
setStyleSheet(self, 'info_bar')
def __fadeOut(self):
""" fade out """
self.opacityAni.setDuration(200)
self.opacityAni.setStartValue(1)
self.opacityAni.setEndValue(0)
self.opacityAni.finished.connect(self.close)
self.opacityAni.start()
def _adjustText(self):
w = 900 if not self.parent() else (self.parent().width() - 50)
chars = max(min(w / 9, 120), 30)
self.contentLabel.setText(TextWrap.wrap(self.content, chars, False)[0])
self.adjustSize()
def addWidget(self, widget: QWidget, stretch=0):
""" add widget to info bar """
self.contentLayout.addWidget(widget, stretch, Qt.AlignLeft)
def setCustomBackgroundColor(self, light, dark):
""" set the custom background color
Parameters
----------
light, dark: str | Qt.GlobalColor | QColor
background color in light/dark theme mode
"""
self.lightBackgroundColor = QColor(light)
self.darkBackgroundColor = QColor(dark)
self.update()
def eventFilter(self, obj, e: QEvent):
if obj is self.parent():
if e.type() in [QEvent.Resize, QEvent.WindowStateChange]:
self._adjustText()
return super().eventFilter(obj, e)
def closeEvent(self, e):
self.closedSignal.emit()
self.deleteLater()
def showEvent(self, e):
self._adjustText()
super().showEvent(e)
if self.duration >= 0:
QTimer.singleShot(self.duration, self.__fadeOut)
if self.position != InfoBarPosition.NONE:
manager = InfoBarManager.make(self.position)
manager.add(self)
if self.parent():
self.parent().installEventFilter(self)
def paintEvent(self, e):
super().paintEvent(e)
if self.lightBackgroundColor is None:
return
painter = QPainter(self)
painter.setRenderHints(QPainter.Antialiasing)
painter.setPen(Qt.NoPen)
if isDarkTheme():
painter.setBrush(self.darkBackgroundColor)
else:
painter.setBrush(self.lightBackgroundColor)
rect = self.rect().adjusted(1, 1, -1, -1)
painter.drawRoundedRect(rect, 6, 6)
@classmethod
def new(cls, icon, title, content, orient=Qt.Horizontal, isClosable=True, duration=1000,
position=InfoBarPosition.TOP_RIGHT, parent=None):
w = InfoBar(icon, title, content, orient,
isClosable, duration, position, parent)
w.show()
return w
@classmethod
def info(cls, title, content, orient=Qt.Horizontal, isClosable=True, duration=1000,
position=InfoBarPosition.TOP_RIGHT, parent=None):
return cls.new(InfoBarIcon.INFORMATION, title, content, orient, isClosable, duration, position, parent)
@classmethod
def success(cls, title, content, orient=Qt.Horizontal, isClosable=True, duration=1000,
position=InfoBarPosition.TOP_RIGHT, parent=None):
return cls.new(InfoBarIcon.SUCCESS, title, content, orient, isClosable, duration, position, parent)
@classmethod
def warning(cls, title, content, orient=Qt.Horizontal, isClosable=True, duration=1000,
position=InfoBarPosition.TOP_RIGHT, parent=None):
return cls.new(InfoBarIcon.WARNING, title, content, orient, isClosable, duration, position, parent)
@classmethod
def error(cls, title, content, orient=Qt.Horizontal, isClosable=True, duration=1000,
position=InfoBarPosition.TOP_RIGHT, parent=None):
return cls.new(InfoBarIcon.ERROR, title, content, orient, isClosable, duration, position, parent)
class InfoBarManager(QObject):
""" Info bar manager """
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super(InfoBarManager, cls).__new__(
cls, *args, **kwargs)
cls._instance.__initialized = False
return cls._instance
def __init__(self):
super().__init__()
if self.__initialized:
return
self.spacing = 16
self.margin = 24
self.infoBars = weakref.WeakKeyDictionary()
self.aniGroups = weakref.WeakKeyDictionary()
self.slideAnis = []
self.dropAnis = []
self.__initialized = True
def add(self, infoBar: InfoBar):
""" add info bar """
p = infoBar.parent() # type:QWidget
if not p:
return
if p not in self.infoBars:
p.installEventFilter(self)
self.infoBars[p] = []
self.aniGroups[p] = QParallelAnimationGroup(self)
if infoBar in self.infoBars[p]:
return
# add drop animation
if self.infoBars[p]:
dropAni = QPropertyAnimation(infoBar, b'pos')
dropAni.setDuration(200)
self.aniGroups[p].addAnimation(dropAni)
self.dropAnis.append(dropAni)
infoBar.setProperty('dropAni', dropAni)
# add slide animation
self.infoBars[p].append(infoBar)
slideAni = self._createSlideAni(infoBar)
self.slideAnis.append(slideAni)
infoBar.setProperty('slideAni', slideAni)
infoBar.closedSignal.connect(lambda: self.remove(infoBar))
slideAni.start()
def remove(self, infoBar: InfoBar):
""" remove info bar """
p = infoBar.parent()
if p not in self.infoBars:
return
if infoBar not in self.infoBars[p]:
return
self.infoBars[p].remove(infoBar)
# remove drop animation
dropAni = infoBar.property('dropAni') # type: QPropertyAnimation
if dropAni:
self.aniGroups[p].removeAnimation(dropAni)
self.dropAnis.remove(dropAni)
# remove slider animation
slideAni = infoBar.property('slideAni')
if slideAni:
self.slideAnis.remove(slideAni)
# adjust the position of the remaining info bars
self._updateDropAni(p)
self.aniGroups[p].start()
def _createSlideAni(self, infoBar: InfoBar):
slideAni = QPropertyAnimation(infoBar, b'pos')
slideAni.setEasingCurve(QEasingCurve.OutQuad)
slideAni.setDuration(200)
slideAni.setStartValue(self._slideStartPos(infoBar))
slideAni.setEndValue(self._pos(infoBar))
return slideAni
def _updateDropAni(self, parent):
for bar in self.infoBars[parent]:
ani = bar.property('dropAni')
if not ani:
continue
ani.setStartValue(bar.pos())
ani.setEndValue(self._pos(bar))
def _pos(self, infoBar: InfoBar, parentSize=None) -> QPoint:
raise NotImplementedError
def _slideStartPos(self, infoBar: InfoBar) -> QPoint:
raise NotImplementedError
def eventFilter(self, obj, e: QEvent):
if obj not in self.infoBars:
return False
if e.type() in [QEvent.Resize, QEvent.WindowStateChange]:
size = e.size() if e.type() == QEvent.Resize else None
for bar in self.infoBars[obj]:
bar.move(self._pos(bar, size))
return super().eventFilter(obj, e)
@staticmethod
def make(position: InfoBarPosition):
""" mask info bar manager according to the display position """
managers = {
InfoBarPosition.TOP: TopInfoBarManager,
InfoBarPosition.BOTTOM: BottomInfoBarManager,
InfoBarPosition.TOP_RIGHT: TopRightInfoBarManager,
InfoBarPosition.BOTTOM_RIGHT: BottomRightInfoBarManager,
InfoBarPosition.TOP_LEFT: TopLeftInfoBarManager,
InfoBarPosition.BOTTOM_LEFT: BottomLeftInfoBarManager,
}
if position not in managers:
raise ValueError(f'`{position}` is an invalid info bar position.')
return managers[position]()
class TopInfoBarManager(InfoBarManager):
""" Top position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize=None):
p = infoBar.parent()
parentSize = parentSize or p.size()
x = (infoBar.parent().width() - infoBar.width()) // 2
y = self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y += (bar.height() + self.spacing)
return QPoint(x, y)
def _slideStartPos(self, infoBar: InfoBar):
pos = self._pos(infoBar)
return QPoint(pos.x(), pos.y() - 16)
class TopRightInfoBarManager(InfoBarManager):
""" Top right position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize=None):
p = infoBar.parent()
parentSize = parentSize or p.size()
x = parentSize.width() - infoBar.width() - self.margin
y = self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y += (bar.height() + self.spacing)
return QPoint(x, y)
def _slideStartPos(self, infoBar: InfoBar):
return QPoint(infoBar.parent().width(), self._pos(infoBar).y())
class BottomRightInfoBarManager(InfoBarManager):
""" Bottom right position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize=None) -> QPoint:
p = infoBar.parent()
parentSize = parentSize or p.size()
x = parentSize.width() - infoBar.width() - self.margin
y = parentSize.height() - infoBar.height() - self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y -= (bar.height() + self.spacing)
return QPoint(x, y)
def _slideStartPos(self, infoBar: InfoBar):
return QPoint(infoBar.parent().width(), self._pos(infoBar).y())
class TopLeftInfoBarManager(InfoBarManager):
""" Top left position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize=None) -> QPoint:
p = infoBar.parent()
parentSize = parentSize or p.size()
y = self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y += (bar.height() + self.spacing)
return QPoint(self.margin, y)
def _slideStartPos(self, infoBar: InfoBar):
return QPoint(-infoBar.width(), self._pos(infoBar).y())
class BottomLeftInfoBarManager(InfoBarManager):
""" Bottom left position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize: QSize = None) -> QPoint:
p = infoBar.parent()
parentSize = parentSize or p.size()
y = parentSize.height() - infoBar.height() - self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y -= (bar.height() + self.spacing)
return QPoint(self.margin, y)
def _slideStartPos(self, infoBar: InfoBar):
return QPoint(-infoBar.width(), self._pos(infoBar).y())
class BottomInfoBarManager(InfoBarManager):
""" Bottom position info bar manager """
def _pos(self, infoBar: InfoBar, parentSize: QSize = None) -> QPoint:
p = infoBar.parent()
parentSize = parentSize or p.size()
x = (parentSize.width() - infoBar.width()) // 2
y = parentSize.height() - infoBar.height() - self.margin
index = self.infoBars[p].index(infoBar)
for bar in self.infoBars[p][0:index]:
y -= (bar.height() + self.spacing)
return QPoint(x, y)
def _slideStartPos(self, infoBar: InfoBar):
pos = self._pos(infoBar)
return QPoint(pos.x(), pos.y() + 16)
......@@ -6,7 +6,7 @@ with open('README.md', encoding='utf-8') as f:
setuptools.setup(
name="PyQt-Fluent-Widgets",
version="0.4.8",
version="0.4.9",
keywords="pyqt fluent widgets",
author="zhiyiYo",
author_email="shokokawaii@outlook.com",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册