Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
k54kdk
PyQt Fluent Widgets
提交
2dc6bb7b
P
PyQt Fluent Widgets
项目概览
k54kdk
/
PyQt Fluent Widgets
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PyQt Fluent Widgets
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
2dc6bb7b
编写于
3月 14, 2023
作者:
之一Yo
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
添加导航组件
上级
226e18a1
变更
19
展开全部
隐藏空白更改
内联
并排
Showing
19 changed file
with
40826 addition
and
39715 deletion
+40826
-39715
examples/navigation/demo.py
examples/navigation/demo.py
+192
-0
examples/navigation/resource/demo.qss
examples/navigation/resource/demo.qss
+15
-0
examples/navigation/resource/logo.png
examples/navigation/resource/logo.png
+0
-0
examples/navigation/resource/shoko.png
examples/navigation/resource/shoko.png
+0
-0
qfluentwidgets/_rc/images/icons/Menu_black.svg
qfluentwidgets/_rc/images/icons/Menu_black.svg
+6
-0
qfluentwidgets/_rc/images/icons/Menu_white.svg
qfluentwidgets/_rc/images/icons/Menu_white.svg
+6
-0
qfluentwidgets/_rc/qss/dark/navigation_interface.qss
qfluentwidgets/_rc/qss/dark/navigation_interface.qss
+16
-0
qfluentwidgets/_rc/qss/light/navigation_interface.qss
qfluentwidgets/_rc/qss/light/navigation_interface.qss
+15
-0
qfluentwidgets/_rc/resource.py
qfluentwidgets/_rc/resource.py
+39941
-39708
qfluentwidgets/_rc/resource.qrc
qfluentwidgets/_rc/resource.qrc
+4
-0
qfluentwidgets/common/__init__.py
qfluentwidgets/common/__init__.py
+1
-1
qfluentwidgets/common/icon.py
qfluentwidgets/common/icon.py
+23
-0
qfluentwidgets/components/__init__.py
qfluentwidgets/components/__init__.py
+1
-0
qfluentwidgets/components/dialog_box/dialog.py
qfluentwidgets/components/dialog_box/dialog.py
+25
-4
qfluentwidgets/components/dialog_box/mask_dialog_base.py
qfluentwidgets/components/dialog_box/mask_dialog_base.py
+2
-2
qfluentwidgets/components/navigation/__init__.py
qfluentwidgets/components/navigation/__init__.py
+3
-0
qfluentwidgets/components/navigation/navigation_interface.py
qfluentwidgets/components/navigation/navigation_interface.py
+110
-0
qfluentwidgets/components/navigation/navigation_panel.py
qfluentwidgets/components/navigation/navigation_panel.py
+308
-0
qfluentwidgets/components/navigation/navigation_widget.py
qfluentwidgets/components/navigation/navigation_widget.py
+158
-0
未找到文件。
examples/navigation/demo.py
0 → 100644
浏览文件 @
2dc6bb7b
# coding:utf-8
import
sys
from
PyQt5.QtCore
import
Qt
,
QRect
from
PyQt5.QtGui
import
QIcon
,
QPainter
,
QImage
,
QBrush
,
QColor
,
QFont
from
PyQt5.QtWidgets
import
QApplication
,
QFrame
,
QStackedWidget
,
QHBoxLayout
,
QLabel
from
qfluentwidgets
import
NavigationInterface
,
NavigationItemPostion
,
NavigationWidget
,
MessageBox
from
qfluentwidgets
import
FluentIconFactory
as
FIF
from
qframelesswindow
import
FramelessWindow
,
StandardTitleBar
class
Widget
(
QFrame
):
def
__init__
(
self
,
text
:
str
,
parent
=
None
):
super
().
__init__
(
parent
=
parent
)
self
.
label
=
QLabel
(
text
,
self
)
self
.
label
.
setAlignment
(
Qt
.
AlignCenter
)
self
.
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
hBoxLayout
.
addWidget
(
self
.
label
,
1
,
Qt
.
AlignCenter
)
self
.
setObjectName
(
text
.
replace
(
' '
,
'-'
))
class
AvatarWidget
(
NavigationWidget
):
""" Avatar widget """
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
isSelectable
=
False
,
parent
=
parent
)
self
.
avatar
=
QImage
(
'resource/shoko.png'
).
scaled
(
24
,
24
,
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
def
paintEvent
(
self
,
e
):
painter
=
QPainter
(
self
)
painter
.
setRenderHints
(
QPainter
.
SmoothPixmapTransform
|
QPainter
.
Antialiasing
)
painter
.
setPen
(
Qt
.
NoPen
)
if
self
.
isPressed
:
painter
.
setOpacity
(
0.7
)
# draw background
if
self
.
isSelected
:
painter
.
setBrush
(
QColor
(
0
,
0
,
0
,
6
if
self
.
isEnter
else
10
))
painter
.
drawRoundedRect
(
self
.
rect
(),
5
,
5
)
# draw indicator
painter
.
setBrush
(
QColor
(
0
,
153
,
188
))
painter
.
drawRoundedRect
(
0
,
10
,
3
,
16
,
1.5
,
1.5
)
elif
self
.
isEnter
:
painter
.
setBrush
(
QColor
(
0
,
0
,
0
,
10
))
painter
.
drawRoundedRect
(
self
.
rect
(),
5
,
5
)
# draw avatar
painter
.
setBrush
(
QBrush
(
self
.
avatar
))
painter
.
translate
(
8
,
6
)
painter
.
drawEllipse
(
0
,
0
,
24
,
24
)
painter
.
translate
(
-
8
,
-
6
)
if
not
self
.
isCompacted
:
painter
.
setPen
(
Qt
.
black
)
font
=
QFont
(
'Segoe UI'
)
font
.
setPixelSize
(
14
)
painter
.
setFont
(
font
)
painter
.
drawText
(
QRect
(
44
,
0
,
255
,
36
),
Qt
.
AlignVCenter
,
'zhiyiYo'
)
class
Window
(
FramelessWindow
):
def
__init__
(
self
):
super
().
__init__
()
self
.
setTitleBar
(
StandardTitleBar
(
self
))
self
.
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
navigationInterface
=
NavigationInterface
(
self
,
True
)
self
.
stackWidget
=
QStackedWidget
(
self
)
# create sub interface
self
.
searchInterface
=
Widget
(
'Search Interface'
,
self
)
self
.
musicInterface
=
Widget
(
'Music Interface'
,
self
)
self
.
videoInterface
=
Widget
(
'Video Interface'
,
self
)
self
.
folderInterface
=
Widget
(
'Folder Interface'
,
self
)
self
.
settingInterface
=
Widget
(
'Setting Interface'
,
self
)
self
.
stackWidget
.
addWidget
(
self
.
searchInterface
)
self
.
stackWidget
.
addWidget
(
self
.
musicInterface
)
self
.
stackWidget
.
addWidget
(
self
.
videoInterface
)
self
.
stackWidget
.
addWidget
(
self
.
folderInterface
)
self
.
stackWidget
.
addWidget
(
self
.
settingInterface
)
# initialize layout
self
.
hBoxLayout
.
setSpacing
(
0
)
self
.
hBoxLayout
.
setContentsMargins
(
0
,
self
.
titleBar
.
height
(),
0
,
0
)
self
.
hBoxLayout
.
addWidget
(
self
.
navigationInterface
)
self
.
hBoxLayout
.
addWidget
(
self
.
stackWidget
)
self
.
hBoxLayout
.
setStretchFactor
(
self
.
stackWidget
,
1
)
# add items to navigation interface
self
.
navigationInterface
.
addItem
(
routeKey
=
self
.
searchInterface
.
objectName
(),
iconPath
=
FIF
.
path
(
FIF
.
SEARCH
),
text
=
'Search'
,
onClick
=
lambda
:
self
.
switchTo
(
self
.
searchInterface
)
)
self
.
navigationInterface
.
addItem
(
routeKey
=
self
.
musicInterface
.
objectName
(),
iconPath
=
FIF
.
path
(
FIF
.
MUSIC
),
text
=
'Music library'
,
onClick
=
lambda
:
self
.
switchTo
(
self
.
musicInterface
)
)
self
.
navigationInterface
.
addItem
(
routeKey
=
self
.
navigationInterface
.
objectName
(),
iconPath
=
FIF
.
path
(
FIF
.
VIDEO
),
text
=
'Video library'
,
onClick
=
lambda
:
self
.
switchTo
(
self
.
videoInterface
)
)
self
.
navigationInterface
.
addSeparator
()
# add navigation items to scroll area
self
.
navigationInterface
.
addItem
(
routeKey
=
'folder'
,
iconPath
=
FIF
.
path
(
FIF
.
FOLDER
),
text
=
'Folder library'
,
onClick
=
lambda
:
self
.
switchTo
(
self
.
folderInterface
),
position
=
NavigationItemPostion
.
SCROLL
)
# for i in range(1, 21):
# self.navigationInterface.addItem(
# f'folder{i}',
# FIF.path(FIF.FOLDER),
# f'Folder {i}',
# lambda: print('Folder clicked'),
# position=NavigationItemPostion.SCROLL
# )
# add custom widget to bottom
self
.
navigationInterface
.
addWidget
(
routeKey
=
'avatar'
,
widget
=
AvatarWidget
(),
onClick
=
self
.
showMessageBox
,
position
=
NavigationItemPostion
.
BOTTOM
)
self
.
navigationInterface
.
addItem
(
routeKey
=
'setting'
,
iconPath
=
FIF
.
path
(
FIF
.
SETTING
),
text
=
'Settings'
,
onClick
=
lambda
:
self
.
switchTo
(
self
.
settingInterface
),
position
=
NavigationItemPostion
.
BOTTOM
)
self
.
stackWidget
.
currentChanged
.
connect
(
self
.
onCurrentInterfaceChanged
)
self
.
stackWidget
.
setCurrentIndex
(
1
)
with
open
(
'resource/demo.qss'
,
encoding
=
'utf-8'
)
as
f
:
self
.
setStyleSheet
(
f
.
read
())
self
.
resize
(
900
,
700
)
self
.
setWindowIcon
(
QIcon
(
'resource/logo.png'
))
self
.
setWindowTitle
(
'PyQt-Fluent-Widgets'
)
desktop
=
QApplication
.
desktop
().
availableGeometry
()
w
,
h
=
desktop
.
width
(),
desktop
.
height
()
self
.
move
(
w
//
2
-
self
.
width
()
//
2
,
h
//
2
-
self
.
height
()
//
2
)
def
switchTo
(
self
,
widget
):
self
.
stackWidget
.
setCurrentWidget
(
widget
)
def
onCurrentInterfaceChanged
(
self
,
index
):
widget
=
self
.
stackWidget
.
widget
(
index
)
self
.
navigationInterface
.
setCurrentItem
(
widget
.
objectName
())
def
showMessageBox
(
self
):
w
=
MessageBox
(
'This is a help message'
,
'You clicked a customized navigation widget. You can add more custom widgets by calling `NavigationInterface.addWidget()` 😉'
,
self
)
w
.
exec
()
if
__name__
==
'__main__'
:
QApplication
.
setHighDpiScaleFactorRoundingPolicy
(
Qt
.
HighDpiScaleFactorRoundingPolicy
.
PassThrough
)
QApplication
.
setAttribute
(
Qt
.
AA_EnableHighDpiScaling
)
QApplication
.
setAttribute
(
Qt
.
AA_UseHighDpiPixmaps
)
app
=
QApplication
(
sys
.
argv
)
w
=
Window
()
w
.
show
()
app
.
exec_
()
examples/navigation/resource/demo.qss
0 → 100644
浏览文件 @
2dc6bb7b
Widget > QLabel {
font: 24px 'Segoe UI', 'Microsoft YaHei';
}
Widget {
border: 1px solid rgb(229, 229, 229);
border-right: none;
border-bottom: none;
border-top-left-radius: 10px;
background-color: rgb(249, 249, 249);
}
Window {
background-color: rgb(243, 243, 243);
}
\ No newline at end of file
examples/navigation/resource/logo.png
0 → 100644
浏览文件 @
2dc6bb7b
2.4 KB
examples/navigation/resource/shoko.png
0 → 100644
浏览文件 @
2dc6bb7b
261.8 KB
qfluentwidgets/_rc/images/icons/Menu_black.svg
0 → 100644
浏览文件 @
2dc6bb7b
<?xml version="1.0" encoding="utf-8"?>
<svg
xmlns=
"http://www.w3.org/2000/svg"
height=
"16"
width=
"16"
viewBox=
"0 0 16 16"
>
<g>
<path
id=
"path1"
transform=
"rotate(0,8,8) translate(0,0.5) scale(0.166666666666667,0.166666666666667) "
fill=
"#000000"
d=
"M3,72L93,72 94.13671875,72.22265625 95.109375,72.890625 95.77734375,73.86328125 96,75 95.77734375,76.13671875 95.109375,77.109375 94.13671875,77.77734375 93,78 3,78 1.86328125,77.77734375 0.890625,77.109375 0.22265625,76.13671875 0,75 0.22265625,73.86328125 0.890625,72.890625 1.86328125,72.22265625 3,72z M3,42L93,42 94.13671875,42.2226600646973 95.109375,42.890625 95.77734375,43.8632850646973 96,45 95.77734375,46.1367225646973 95.109375,47.109375 94.13671875,47.77734375 93,48 3,48 1.86328125,47.77734375 0.890625,47.109375 0.22265625,46.1367225646973 0,45 0.22265625,43.8632850646973 0.890625,42.890625 1.86328125,42.2226600646973 3,42z M3,12L93,12 94.13671875,12.22265625 95.109375,12.890625 95.77734375,13.86328125 96,15 95.77734375,16.13671875 95.109375,17.109375 94.13671875,17.77734375 93,18 3,18 1.86328125,17.77734375 0.890625,17.109375 0.22265625,16.13671875 0,15 0.22265625,13.86328125 0.890625,12.890625 1.86328125,12.22265625 3,12z"
/>
</g>
</svg>
qfluentwidgets/_rc/images/icons/Menu_white.svg
0 → 100644
浏览文件 @
2dc6bb7b
<?xml version="1.0" encoding="utf-8"?>
<svg
xmlns=
"http://www.w3.org/2000/svg"
height=
"16"
width=
"16"
viewBox=
"0 0 16 16"
>
<g>
<path
id=
"path1"
transform=
"rotate(0,8,8) translate(0,0.5) scale(0.166666666666667,0.166666666666667) "
fill=
"#ffffff"
d=
"M3,72L93,72 94.13671875,72.22265625 95.109375,72.890625 95.77734375,73.86328125 96,75 95.77734375,76.13671875 95.109375,77.109375 94.13671875,77.77734375 93,78 3,78 1.86328125,77.77734375 0.890625,77.109375 0.22265625,76.13671875 0,75 0.22265625,73.86328125 0.890625,72.890625 1.86328125,72.22265625 3,72z M3,42L93,42 94.13671875,42.2226600646973 95.109375,42.890625 95.77734375,43.8632850646973 96,45 95.77734375,46.1367225646973 95.109375,47.109375 94.13671875,47.77734375 93,48 3,48 1.86328125,47.77734375 0.890625,47.109375 0.22265625,46.1367225646973 0,45 0.22265625,43.8632850646973 0.890625,42.890625 1.86328125,42.2226600646973 3,42z M3,12L93,12 94.13671875,12.22265625 95.109375,12.890625 95.77734375,13.86328125 96,15 95.77734375,16.13671875 95.109375,17.109375 94.13671875,17.77734375 93,18 3,18 1.86328125,17.77734375 0.890625,17.109375 0.22265625,16.13671875 0,15 0.22265625,13.86328125 0.890625,12.890625 1.86328125,12.22265625 3,12z"
/>
</g>
</svg>
qfluentwidgets/_rc/qss/dark/navigation_interface.qss
0 → 100644
浏览文件 @
2dc6bb7b
NavigationPanel {
background-color: rgba(32, 32, 32, --bgOpacity);
border: 1px solid rgba(57, 57, 57, --bgOpacity);
border-top-right-radius: 7px;
border-bottom-right-radius: 7px;
}
QScrollArea,
#scrollWidget {
border: none;
background-color: transparent;
}
NavigationInterface {
background-color: rgb(32, 32, 32);
}
\ No newline at end of file
qfluentwidgets/_rc/qss/light/navigation_interface.qss
0 → 100644
浏览文件 @
2dc6bb7b
NavigationPanel {
background-color: rgba(243, 243, 243, --bgOpacity);
border: 1px solid rgba(229, 229, 229, --bgOpacity);
border-top-right-radius: 7px;
border-bottom-right-radius: 7px;
}
QScrollArea, #scrollWidget {
border: none;
background-color: transparent;
}
NavigationInterface {
background-color: rgb(243, 243, 243);
}
\ No newline at end of file
qfluentwidgets/_rc/resource.py
浏览文件 @
2dc6bb7b
此差异已折叠。
点击以展开。
qfluentwidgets/_rc/resource.qrc
浏览文件 @
2dc6bb7b
...
...
@@ -75,6 +75,8 @@
<file>images/icons/Zoom_white.svg</file>
<file>images/icons/Language_black.svg</file>
<file>images/icons/Language_white.svg</file>
<file>images/icons/Menu_black.svg</file>
<file>images/icons/Menu_white.svg</file>
<file>images/state_tool_tip/close_normal.svg</file>
<file>images/state_tool_tip/close_hover.svg</file>
<file>images/state_tool_tip/close_pressed.svg</file>
...
...
@@ -100,6 +102,7 @@
<file>qss/dark/folder_list_dialog.qss</file>
<file>qss/dark/setting_interface.qss</file>
<file>qss/dark/combo_box.qss</file>
<file>qss/dark/navigation_interface.qss</file>
<file>qss/light/color_dialog.qss</file>
<file>qss/light/dialog.qss</file>
...
...
@@ -114,5 +117,6 @@
<file>qss/light/folder_list_dialog.qss</file>
<file>qss/light/setting_interface.qss</file>
<file>qss/light/combo_box.qss</file>
<file>qss/light/navigation_interface.qss</file>
</qresource>
</RCC>
\ No newline at end of file
qfluentwidgets/common/__init__.py
浏览文件 @
2dc6bb7b
from
.config
import
*
from
.auto_wrap
import
TextWrap
from
.icon
import
Icon
,
getIconColor
,
drawSvgIcon
,
FluentIconFactory
from
.icon
import
Icon
,
getIconColor
,
drawSvgIcon
,
FluentIconFactory
,
drawIcon
from
.style_sheet
import
setStyleSheet
,
getStyleSheet
from
.smooth_scroll
import
SmoothScroll
,
SmoothMode
\ No newline at end of file
qfluentwidgets/common/icon.py
浏览文件 @
2dc6bb7b
...
...
@@ -68,6 +68,28 @@ def drawSvgIcon(iconPath, painter, rect):
renderer
.
render
(
painter
,
QRectF
(
rect
))
def
drawIcon
(
iconPath
,
painter
,
rect
):
""" draw icon
Parameters
----------
iconPath: str
the path of svg icon
painter: QPainter
painter
rect: QRect | QRectF
the rect to render icon
"""
if
not
iconPath
.
lower
().
endswith
(
'svg'
):
image
=
QImage
(
iconPath
).
scaled
(
rect
.
width
(),
rect
.
height
(),
Qt
.
KeepAspectRatio
,
Qt
.
SmoothTransformation
)
painter
.
drawImage
(
rect
,
image
)
else
:
drawSvgIcon
(
iconPath
,
painter
,
rect
)
class
FluentIconFactory
:
""" Fluent icon factory """
...
...
@@ -80,6 +102,7 @@ class FluentIconFactory:
FONT
=
"Font"
INFO
=
"Info"
ZOOM
=
"Zoom"
MENU
=
"Menu"
CLOSE
=
"Close"
MOVIE
=
"Movie"
BRUSH
=
"Brush"
...
...
qfluentwidgets/components/__init__.py
浏览文件 @
2dc6bb7b
...
...
@@ -2,3 +2,4 @@ from .dialog_box import *
from
.layout
import
*
from
.settings
import
*
from
.widgets
import
*
from
.navigation
import
*
\ No newline at end of file
qfluentwidgets/components/dialog_box/dialog.py
浏览文件 @
2dc6bb7b
# coding:utf-8
from
PyQt5.QtCore
import
Qt
,
pyqtSignal
,
QObject
from
PyQt5.QtGui
import
QColor
from
PyQt5.QtCore
import
Qt
,
pyqtSignal
,
QObject
,
QEvent
from
PyQt5.QtGui
import
QColor
,
QResizeEvent
from
PyQt5.QtWidgets
import
QLabel
,
QPushButton
,
QFrame
,
QVBoxLayout
,
QHBoxLayout
from
qframelesswindow
import
FramelessDialog
...
...
@@ -37,11 +37,23 @@ class Ui_MessageBox(QObject):
self
.
yesButton
.
setFocus
()
self
.
buttonGroup
.
setFixedHeight
(
81
)
self
.
contentLabel
.
setText
(
TextWrap
.
wrap
(
self
.
content
,
100
,
False
)[
0
])
self
.
_adjustText
()
self
.
yesButton
.
clicked
.
connect
(
self
.
__onYesButtonClicked
)
self
.
cancelButton
.
clicked
.
connect
(
self
.
__onCancelButtonClicked
)
def
_adjustText
(
self
):
if
self
.
isWindow
():
if
self
.
parent
():
chars
=
max
(
min
(
self
.
parent
().
width
()
/
9
,
100
),
30
)
else
:
chars
=
100
else
:
chars
=
max
(
min
(
self
.
window
().
width
()
/
9
,
100
),
30
)
self
.
contentLabel
.
setText
(
TextWrap
.
wrap
(
self
.
content
,
chars
,
False
)[
0
])
def
__initLayout
(
self
):
self
.
vBoxLayout
.
setSpacing
(
0
)
self
.
vBoxLayout
.
setContentsMargins
(
0
,
0
,
0
,
0
)
...
...
@@ -113,8 +125,17 @@ class MessageBox(MaskDialogBase, Ui_MessageBox):
self
.
setShadowEffect
(
60
,
(
0
,
10
),
QColor
(
0
,
0
,
0
,
50
))
self
.
setMaskColor
(
QColor
(
0
,
0
,
0
,
76
))
self
.
_hBoxLayout
.
removeWidget
(
self
.
widget
)
self
.
_hBoxLayout
.
addWidget
(
self
.
widget
,
1
,
Qt
.
AlignCenter
)
self
.
widget
.
setFixedSize
(
max
(
self
.
contentLabel
.
width
(),
self
.
titleLabel
.
width
())
+
48
,
self
.
contentLabel
.
y
()
+
self
.
contentLabel
.
height
()
+
105
)
\ No newline at end of file
)
def
eventFilter
(
self
,
obj
,
e
:
QEvent
):
if
obj
is
self
.
window
():
if
e
.
type
()
==
QEvent
.
Resize
:
self
.
_adjustText
()
return
super
().
eventFilter
(
obj
,
e
)
qfluentwidgets/components/dialog_box/mask_dialog_base.py
浏览文件 @
2dc6bb7b
...
...
@@ -12,7 +12,7 @@ class MaskDialogBase(QDialog):
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
parent
=
parent
)
self
.
_
_
hBoxLayout
=
QHBoxLayout
(
self
)
self
.
_hBoxLayout
=
QHBoxLayout
(
self
)
self
.
windowMask
=
QWidget
(
self
)
# dialog box in the center of mask, all widgets take it as parent
...
...
@@ -24,7 +24,7 @@ class MaskDialogBase(QDialog):
c
=
0
if
isDarkTheme
()
else
255
self
.
windowMask
.
resize
(
self
.
size
())
self
.
windowMask
.
setStyleSheet
(
f
'background:rgba(
{
c
}
,
{
c
}
,
{
c
}
, 0.6)'
)
self
.
_
_
hBoxLayout
.
addWidget
(
self
.
widget
)
self
.
_hBoxLayout
.
addWidget
(
self
.
widget
)
self
.
setShadowEffect
()
self
.
window
().
installEventFilter
(
self
)
...
...
qfluentwidgets/components/navigation/__init__.py
0 → 100644
浏览文件 @
2dc6bb7b
from
.navigation_widget
import
NavigationWidget
,
NavigationButton
,
NavigationSeparator
from
.navigation_panel
import
NavigationPanel
,
NavigationItemPostion
from
.navigation_interface
import
NavigationInterface
\ No newline at end of file
qfluentwidgets/components/navigation/navigation_interface.py
0 → 100644
浏览文件 @
2dc6bb7b
# coding:utf-8
from
PyQt5.QtCore
import
Qt
,
pyqtSignal
,
QEvent
from
PyQt5.QtGui
import
QResizeEvent
from
PyQt5.QtWidgets
import
QWidget
from
.navigation_panel
import
NavigationPanel
,
NavigationItemPostion
,
NavigationWidget
,
NavigationDisplayMode
from
...common.style_sheet
import
setStyleSheet
class
NavigationInterface
(
QWidget
):
""" Navigation interface """
def
__init__
(
self
,
parent
=
None
,
showMenuButton
=
True
):
"""
Parameters
----------
showMenuButton: bool
whether to show menu button
parent: widget
parent widget
"""
super
().
__init__
(
parent
=
parent
)
self
.
panel
=
NavigationPanel
(
self
)
self
.
panel
.
setMenuButtonVisible
(
showMenuButton
)
self
.
panel
.
installEventFilter
(
self
)
self
.
resize
(
48
,
self
.
height
())
self
.
setMinimumWidth
(
48
)
self
.
setAttribute
(
Qt
.
WA_StyledBackground
)
setStyleSheet
(
self
,
'navigation_interface'
)
def
addItem
(
self
,
routeKey
:
str
,
iconPath
:
str
,
text
:
str
,
onClick
,
selectable
=
True
,
position
=
NavigationItemPostion
.
TOP
):
""" add navigation item
Parameters
----------
routKey: str
the unique name of item
iconPath: str
the svg icon path of navigation item
text: str
the text of navigation item
onClick: callable
the slot connected to item clicked signal
position: NavigationItemPostion
where the button is added
selectable: bool
whether the item is selectable
"""
self
.
panel
.
addItem
(
routeKey
,
iconPath
,
text
,
onClick
,
selectable
,
position
)
def
addWidget
(
self
,
routeKey
:
str
,
widget
:
NavigationWidget
,
onClick
,
position
=
NavigationItemPostion
.
TOP
):
""" add custom widget
Parameters
----------
routKey: str
the unique name of item
widget: NavigationWidget
the custom widget to be added
onClick: callable
the slot connected to item clicked signal
position: NavigationItemPostion
where the button is added
"""
self
.
panel
.
addWidget
(
routeKey
,
widget
,
onClick
,
position
)
def
addSeparator
(
self
,
position
=
NavigationItemPostion
.
TOP
):
""" add separator
Parameters
----------
position: NavigationPostion
where to add the separator
"""
self
.
panel
.
addSeparator
(
position
)
def
setCurrentItem
(
self
,
name
:
str
):
""" set current selected item
Parameters
----------
name: str
the unique name of item
"""
self
.
panel
.
setCurrentItem
(
name
)
def
eventFilter
(
self
,
obj
,
e
:
QEvent
):
if
obj
is
not
self
.
panel
or
e
.
type
()
!=
QEvent
.
Resize
:
return
super
().
eventFilter
(
obj
,
e
)
if
self
.
panel
.
displayMode
!=
NavigationDisplayMode
.
MENU
:
event
=
QResizeEvent
(
e
)
if
event
.
oldSize
().
width
()
!=
event
.
size
().
width
():
self
.
setFixedWidth
(
event
.
size
().
width
())
return
super
().
eventFilter
(
obj
,
e
)
def
resizeEvent
(
self
,
e
:
QResizeEvent
):
if
e
.
oldSize
().
height
()
!=
self
.
height
():
self
.
panel
.
setFixedHeight
(
self
.
height
())
qfluentwidgets/components/navigation/navigation_panel.py
0 → 100644
浏览文件 @
2dc6bb7b
# coding:utf-8
from
enum
import
Enum
from
typing
import
Dict
from
PyQt5.QtCore
import
Qt
,
QPropertyAnimation
,
QRect
,
QSize
,
QEvent
,
QEasingCurve
from
PyQt5.QtGui
import
QResizeEvent
from
PyQt5.QtWidgets
import
QWidget
,
QVBoxLayout
,
QFrame
,
QApplication
from
.navigation_widget
import
NavigationButton
,
MenuButton
,
NavigationWidget
,
NavigationSeparator
from
..widgets.scroll_area
import
ScrollArea
from
...common.style_sheet
import
setStyleSheet
,
getStyleSheet
class
NavigationDisplayMode
(
Enum
):
""" Navigation display mode """
MINIMAL
=
0
COMPACT
=
1
EXPAND
=
2
MENU
=
3
class
NavigationItemPostion
(
Enum
):
""" Navigation item position """
TOP
=
0
SCROLL
=
1
BOTTOM
=
2
class
NavigationPanel
(
QFrame
):
""" Navigation panel """
def
__init__
(
self
,
parent
=
None
,
isMinimalEnabled
=
False
):
super
().
__init__
(
parent
=
parent
)
self
.
_parent
=
parent
# type: QWidget
self
.
scrollArea
=
ScrollArea
(
self
)
self
.
scrollWidget
=
QWidget
()
self
.
menuButton
=
MenuButton
(
self
)
self
.
vBoxLayout
=
NavigationItemLayout
(
self
)
self
.
topLayout
=
NavigationItemLayout
()
self
.
bottomLayout
=
NavigationItemLayout
()
self
.
scrollLayout
=
NavigationItemLayout
(
self
.
scrollWidget
)
self
.
items
=
{}
# type: Dict[str, NavigationWidget]
self
.
_bgOpacity
=
0
self
.
expandAni
=
QPropertyAnimation
(
self
,
b
'geometry'
,
self
)
self
.
isMinimalEnabled
=
isMinimalEnabled
if
isMinimalEnabled
:
self
.
displayMode
=
NavigationDisplayMode
.
MINIMAL
else
:
self
.
displayMode
=
NavigationDisplayMode
.
COMPACT
self
.
__initWidget
()
def
__initWidget
(
self
):
self
.
resize
(
48
,
self
.
height
())
self
.
setAttribute
(
Qt
.
WA_StyledBackground
)
self
.
window
().
installEventFilter
(
self
)
self
.
scrollArea
.
setHorizontalScrollBarPolicy
(
Qt
.
ScrollBarAlwaysOff
)
self
.
scrollArea
.
setVerticalScrollBarPolicy
(
Qt
.
ScrollBarAlwaysOff
)
self
.
scrollArea
.
setWidget
(
self
.
scrollWidget
)
self
.
scrollArea
.
setWidgetResizable
(
True
)
self
.
expandAni
.
setEasingCurve
(
QEasingCurve
.
OutQuad
)
self
.
expandAni
.
setDuration
(
150
)
self
.
menuButton
.
clicked
.
connect
(
self
.
toggle
)
self
.
expandAni
.
finished
.
connect
(
self
.
_onExpandAniFinished
)
self
.
scrollWidget
.
setObjectName
(
'scrollWidget'
)
setStyleSheet
(
self
,
'navigation_interface'
)
self
.
__initLayout
()
def
__initLayout
(
self
):
self
.
vBoxLayout
.
setContentsMargins
(
0
,
5
,
0
,
5
)
self
.
topLayout
.
setContentsMargins
(
4
,
0
,
4
,
0
)
self
.
bottomLayout
.
setContentsMargins
(
4
,
0
,
4
,
0
)
self
.
scrollLayout
.
setContentsMargins
(
4
,
0
,
4
,
0
)
self
.
vBoxLayout
.
setSpacing
(
4
)
self
.
topLayout
.
setSpacing
(
4
)
self
.
bottomLayout
.
setSpacing
(
4
)
self
.
scrollLayout
.
setSpacing
(
4
)
self
.
vBoxLayout
.
addLayout
(
self
.
topLayout
,
0
)
self
.
vBoxLayout
.
addWidget
(
self
.
scrollArea
,
1
,
Qt
.
AlignTop
)
self
.
vBoxLayout
.
addLayout
(
self
.
bottomLayout
,
0
)
self
.
vBoxLayout
.
setAlignment
(
Qt
.
AlignTop
)
self
.
topLayout
.
setAlignment
(
Qt
.
AlignTop
)
self
.
scrollLayout
.
setAlignment
(
Qt
.
AlignTop
)
self
.
bottomLayout
.
setAlignment
(
Qt
.
AlignBottom
)
self
.
topLayout
.
addWidget
(
self
.
menuButton
,
0
,
Qt
.
AlignTop
)
def
addItem
(
self
,
routeKey
:
str
,
iconPath
:
str
,
text
:
str
,
onClick
,
selectable
=
True
,
position
=
NavigationItemPostion
.
TOP
):
""" add navigation item
Parameters
----------
routeKey: str
the unique name of item
iconPath: str
the svg icon path of navigation item
text: str
the text of navigation item
onClick: callable
the slot connected to item clicked signal
position: NavigationItemPostion
where the button is added
selectable: bool
whether the item is selectable
"""
if
text
in
self
.
items
:
return
button
=
NavigationButton
(
iconPath
,
text
,
selectable
,
self
)
self
.
addWidget
(
routeKey
,
button
,
onClick
,
position
)
def
addWidget
(
self
,
routeKey
:
str
,
widget
:
NavigationWidget
,
onClick
,
position
=
NavigationItemPostion
.
TOP
):
""" add custom widget
Parameters
----------
routeKey: str
the unique name of item
widget: NavigationWidget
the custom widget to be added
onClick: callable
the slot connected to item clicked signal
position: NavigationItemPostion
where the button is added
"""
if
routeKey
in
self
.
items
:
return
widget
.
clicked
.
connect
(
self
.
_onWidgetClicked
)
widget
.
clicked
.
connect
(
onClick
)
widget
.
setProperty
(
'routeKey'
,
routeKey
)
self
.
items
[
routeKey
]
=
widget
self
.
_addWidgetToLayout
(
widget
,
position
)
def
addSeparator
(
self
,
position
=
NavigationItemPostion
.
TOP
):
""" add separator
Parameters
----------
position: NavigationPostion
where to add the separator
"""
separator
=
NavigationSeparator
(
self
)
self
.
_addWidgetToLayout
(
separator
,
position
)
def
_addWidgetToLayout
(
self
,
widget
:
NavigationWidget
,
position
:
NavigationItemPostion
):
""" add widget to layout """
if
position
==
NavigationItemPostion
.
TOP
:
widget
.
setParent
(
self
)
self
.
topLayout
.
addWidget
(
widget
,
0
,
Qt
.
AlignTop
)
elif
position
==
NavigationItemPostion
.
SCROLL
:
widget
.
setParent
(
self
.
scrollWidget
)
self
.
scrollLayout
.
addWidget
(
widget
,
0
,
Qt
.
AlignTop
)
else
:
widget
.
setParent
(
self
)
self
.
bottomLayout
.
addWidget
(
widget
,
0
,
Qt
.
AlignBottom
)
widget
.
show
()
def
setMenuButtonVisible
(
self
,
isVisible
:
bool
):
""" set whether the menu button is visible """
self
.
menuButton
.
setVisible
(
isVisible
)
def
expand
(
self
):
""" expand navigation panel """
self
.
_setWidgetCompacted
(
False
)
self
.
expandAni
.
setProperty
(
'expand'
,
True
)
# determine the display mode according to the width of window
# https://learn.microsoft.com/en-us/windows/apps/design/controls/navigationview#default
if
self
.
window
().
width
()
>
1007
and
not
self
.
isMinimalEnabled
:
self
.
displayMode
=
NavigationDisplayMode
.
EXPAND
else
:
self
.
setStyleSheet
(
getStyleSheet
(
'navigation_interface'
).
replace
(
'--bgOpacity'
,
'1'
))
self
.
displayMode
=
NavigationDisplayMode
.
MENU
if
not
self
.
_parent
.
isWindow
():
pos
=
self
.
parent
().
pos
()
self
.
setParent
(
self
.
window
())
self
.
move
(
pos
)
self
.
show
()
self
.
expandAni
.
setStartValue
(
QRect
(
self
.
pos
(),
QSize
(
48
,
self
.
height
())))
self
.
expandAni
.
setEndValue
(
QRect
(
self
.
pos
(),
QSize
(
322
,
self
.
height
())))
self
.
expandAni
.
start
()
def
collapse
(
self
):
""" collapse navigation panel """
if
self
.
expandAni
.
state
()
==
QPropertyAnimation
.
Running
:
return
self
.
expandAni
.
setStartValue
(
QRect
(
self
.
pos
(),
QSize
(
self
.
width
(),
self
.
height
())))
self
.
expandAni
.
setEndValue
(
QRect
(
self
.
pos
(),
QSize
(
48
,
self
.
height
())))
self
.
expandAni
.
setProperty
(
'expand'
,
False
)
self
.
expandAni
.
start
()
def
toggle
(
self
):
""" toggle navigation panel """
if
self
.
displayMode
in
[
NavigationDisplayMode
.
COMPACT
,
NavigationDisplayMode
.
MINIMAL
]:
self
.
expand
()
else
:
self
.
collapse
()
def
setCurrentItem
(
self
,
routeKey
:
str
):
""" set current selected item
Parameters
----------
routeKey: str
the unique name of item
"""
if
routeKey
not
in
self
.
items
:
return
for
k
,
item
in
self
.
items
.
items
():
item
.
setSelected
(
k
==
routeKey
)
def
_onWidgetClicked
(
self
):
widget
=
self
.
sender
()
# type: NavigationWidget
if
not
widget
.
isSelectable
:
return
self
.
setCurrentItem
(
widget
.
property
(
'routeKey'
))
if
widget
is
not
self
.
menuButton
and
self
.
displayMode
==
NavigationDisplayMode
.
MENU
:
self
.
collapse
()
def
resizeEvent
(
self
,
e
:
QResizeEvent
):
if
e
.
oldSize
().
width
()
==
self
.
width
():
return
th
=
self
.
topLayout
.
minimumSize
().
height
()
bh
=
self
.
bottomLayout
.
minimumSize
().
height
()
self
.
scrollArea
.
setFixedHeight
(
self
.
height
()
-
th
-
bh
-
20
)
def
eventFilter
(
self
,
obj
,
e
:
QEvent
):
if
obj
is
not
self
.
window
():
return
super
().
eventFilter
(
obj
,
e
)
if
e
.
type
()
==
QEvent
.
MouseButtonRelease
:
if
not
self
.
geometry
().
contains
(
e
.
pos
())
and
self
.
displayMode
==
NavigationDisplayMode
.
MENU
:
self
.
collapse
()
elif
e
.
type
()
==
QEvent
.
Resize
:
w
=
QResizeEvent
(
e
).
size
().
width
()
if
w
<
1008
and
self
.
displayMode
==
NavigationDisplayMode
.
EXPAND
:
self
.
collapse
()
return
super
().
eventFilter
(
obj
,
e
)
def
_onExpandAniFinished
(
self
):
if
not
self
.
expandAni
.
property
(
'expand'
):
if
self
.
isMinimalEnabled
:
self
.
displayMode
=
NavigationDisplayMode
.
MINIMAL
else
:
self
.
displayMode
=
NavigationDisplayMode
.
COMPACT
s
=
getStyleSheet
(
'navigation_interface'
)
if
self
.
displayMode
==
NavigationDisplayMode
.
MINIMAL
:
self
.
hide
()
self
.
setStyleSheet
(
s
.
replace
(
'--bgOpacity'
,
'0'
))
elif
self
.
displayMode
==
NavigationDisplayMode
.
COMPACT
:
self
.
setStyleSheet
(
s
.
replace
(
'--bgOpacity'
,
'0'
))
for
item
in
self
.
items
.
values
():
item
.
setCompacted
(
True
)
if
not
self
.
_parent
.
isWindow
():
self
.
setParent
(
self
.
_parent
)
self
.
move
(
0
,
0
)
self
.
show
()
def
_setWidgetCompacted
(
self
,
isCompacted
:
bool
):
""" set whether the navigation widget is compacted """
for
item
in
self
.
findChildren
(
NavigationWidget
):
item
.
setCompacted
(
isCompacted
)
class
NavigationItemLayout
(
QVBoxLayout
):
""" Navigation layout """
def
setGeometry
(
self
,
rect
:
QRect
):
super
().
setGeometry
(
rect
)
for
i
in
range
(
self
.
count
()):
item
=
self
.
itemAt
(
i
)
if
isinstance
(
item
.
widget
(),
NavigationSeparator
):
geo
=
item
.
geometry
()
item
.
widget
().
setGeometry
(
0
,
geo
.
y
(),
geo
.
width
(),
geo
.
height
())
qfluentwidgets/components/navigation/navigation_widget.py
0 → 100644
浏览文件 @
2dc6bb7b
# coding:utf-8
from
PyQt5.QtCore
import
Qt
,
pyqtSignal
,
QRect
,
QRectF
from
PyQt5.QtGui
import
QColor
,
QPainter
,
QPen
from
PyQt5.QtWidgets
import
QWidget
from
...common.config
import
isDarkTheme
from
...common.icon
import
drawIcon
from
...common.icon
import
FluentIconFactory
as
FIF
class
NavigationWidget
(
QWidget
):
""" Navigation widget """
clicked
=
pyqtSignal
()
def
__init__
(
self
,
isSelectable
:
bool
,
parent
=
None
):
super
().
__init__
(
parent
)
self
.
isCompacted
=
True
self
.
isSelected
=
False
self
.
isPressed
=
False
self
.
isEnter
=
False
self
.
isSelectable
=
isSelectable
self
.
setFixedSize
(
40
,
36
)
def
enterEvent
(
self
,
e
):
self
.
isEnter
=
True
self
.
update
()
def
leaveEvent
(
self
,
e
):
self
.
isEnter
=
False
self
.
isPressed
=
False
self
.
update
()
def
mousePressEvent
(
self
,
e
):
self
.
isPressed
=
True
self
.
update
()
def
mouseReleaseEvent
(
self
,
e
):
self
.
isPressed
=
False
self
.
update
()
self
.
clicked
.
emit
()
def
setCompacted
(
self
,
isCompacted
:
bool
):
""" set whether the widget is compacted """
if
isCompacted
==
self
.
isCompacted
:
return
self
.
isCompacted
=
isCompacted
if
isCompacted
:
self
.
setFixedSize
(
40
,
36
)
else
:
self
.
setFixedSize
(
312
,
36
)
self
.
update
()
def
setSelected
(
self
,
isSelected
:
bool
):
""" set whether the button is selected
Parameters
----------
isSelected: bool
whether the button is selected
"""
if
not
self
.
isSelectable
or
self
.
isSelected
==
isSelected
:
return
self
.
isSelected
=
isSelected
self
.
update
()
class
NavigationButton
(
NavigationWidget
):
""" Navigation button """
def
__init__
(
self
,
iconPath
:
str
,
text
:
str
,
isSelectable
:
bool
,
parent
=
None
):
"""
Parameters
----------
iconPath: str
the path of button icon
text: str
the text of button
"""
super
().
__init__
(
isSelectable
=
isSelectable
,
parent
=
parent
)
self
.
iconPath
=
iconPath
self
.
_text
=
text
self
.
setStyleSheet
(
"NavigationButton{font: 14px 'Segoe UI', 'Microsoft YaHei'}"
)
def
text
(
self
):
return
self
.
_text
def
paintEvent
(
self
,
e
):
painter
=
QPainter
(
self
)
painter
.
setRenderHints
(
QPainter
.
Antialiasing
|
QPainter
.
TextAntialiasing
|
QPainter
.
SmoothPixmapTransform
)
painter
.
setPen
(
Qt
.
NoPen
)
if
self
.
isPressed
:
painter
.
setOpacity
(
0.7
)
# draw background
c
=
255
if
isDarkTheme
()
else
0
if
self
.
isSelected
:
painter
.
setBrush
(
QColor
(
c
,
c
,
c
,
6
if
self
.
isEnter
else
10
))
painter
.
drawRoundedRect
(
self
.
rect
(),
5
,
5
)
# draw indicator
painter
.
setBrush
(
QColor
(
0
,
153
,
188
))
painter
.
drawRoundedRect
(
0
,
10
,
3
,
16
,
1.5
,
1.5
)
elif
self
.
isEnter
:
painter
.
setBrush
(
QColor
(
c
,
c
,
c
,
10
))
painter
.
drawRoundedRect
(
self
.
rect
(),
5
,
5
)
drawIcon
(
self
.
iconPath
,
painter
,
QRectF
(
11.5
,
10
,
16
,
16
))
# draw text
if
not
self
.
isCompacted
:
painter
.
setFont
(
self
.
font
())
painter
.
setPen
(
QColor
(
c
,
c
,
c
))
painter
.
drawText
(
QRect
(
44
,
0
,
self
.
width
()
-
57
,
self
.
height
()),
Qt
.
AlignVCenter
,
self
.
text
())
class
MenuButton
(
NavigationButton
):
""" Menu button """
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
FIF
.
path
(
FIF
.
MENU
),
''
,
parent
)
def
setCompacted
(
self
,
isCompacted
:
bool
):
self
.
setFixedSize
(
40
,
36
)
class
NavigationSeparator
(
NavigationWidget
):
""" Navigation Separator """
def
__init__
(
self
,
parent
=
None
):
super
().
__init__
(
False
,
parent
=
parent
)
self
.
setCompacted
(
True
)
def
setCompacted
(
self
,
isCompacted
:
bool
):
if
isCompacted
:
self
.
setFixedSize
(
48
,
3
)
else
:
self
.
setFixedSize
(
322
,
3
)
self
.
update
()
def
paintEvent
(
self
,
e
):
painter
=
QPainter
(
self
)
c
=
255
if
isDarkTheme
()
else
0
pen
=
QPen
(
QColor
(
c
,
c
,
c
,
15
))
pen
.
setCosmetic
(
True
)
painter
.
setPen
(
pen
)
painter
.
drawLine
(
0
,
1
,
self
.
width
(),
1
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录