diff --git a/docs/source/gallery.md b/docs/source/gallery.md
index 6adc26c9ec8d8167481d8feb7d0386a0db0989bc..d686d01baeb4f3f81111812039a867e3419c111a 100644
--- a/docs/source/gallery.md
+++ b/docs/source/gallery.md
@@ -58,5 +58,5 @@
### Material
-### Acrylic Label
+#### Acrylic Label
\ No newline at end of file
diff --git a/examples/gallery/app/common/config.py b/examples/gallery/app/common/config.py
new file mode 100644
index 0000000000000000000000000000000000000000..db56d39e99f15de0b418e2dd667d721d8f76f27e
--- /dev/null
+++ b/examples/gallery/app/common/config.py
@@ -0,0 +1,57 @@
+# coding:utf-8
+from enum import Enum
+
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QGuiApplication, QFont
+from qfluentwidgets import (qconfig, QConfig, ConfigItem, OptionsConfigItem, BoolValidator,
+ ColorConfigItem, OptionsValidator, RangeConfigItem, RangeValidator,
+ FolderListValidator, EnumSerializer, FolderValidator)
+
+
+
+class Language(Enum):
+ """ Language enumeration """
+
+ CHINESE_SIMPLIFIED = "zh"
+ CHINESE_TRADITIONAL = "hk"
+ ENGLISH = "en"
+ AUTO = "Auto"
+
+
+class Config(QConfig):
+ """ Config of application """
+
+ # folders
+ musicFolders = ConfigItem(
+ "Folders", "LocalMusic", [], FolderListValidator())
+ downloadFolder = ConfigItem(
+ "Folders", "Download", "app/download", FolderValidator())
+
+ # main window
+ minimizeToTray = ConfigItem(
+ "MainWindow", "MinimizeToTray", True, BoolValidator())
+ playBarColor = ColorConfigItem("MainWindow", "PlayBarColor", "#225C7F")
+ recentPlaysNumber = RangeConfigItem(
+ "MainWindow", "RecentPlayNumbers", 300, RangeValidator(10, 300))
+ dpiScale = OptionsConfigItem(
+ "MainWindow", "DpiScale", "Auto", OptionsValidator([1, 1.25, 1.5, 1.75, 2, "Auto"]), restart=True)
+ language = OptionsConfigItem(
+ "MainWindow", "Language", Language.AUTO, OptionsValidator(Language), EnumSerializer(Language), restart=True)
+
+ # software update
+ checkUpdateAtStartUp = ConfigItem(
+ "Update", "CheckUpdateAtStartUp", True, BoolValidator())
+
+
+YEAR = 2023
+AUTHOR = "zhiyiYo"
+VERSION = "v0.4.2"
+HELP_URL = "https://pyqt-fluent-widgets.readthedocs.io"
+EXAMPLE_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/tree/master/examples"
+DOCUMENT_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/issues"
+FEEDBACK_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/issues"
+RELEASE_URL = "https://github.com/zhiyiYo/PyQt-Fluent-Widgets/releases/latest"
+
+
+cfg = Config()
+qconfig.load('app/config/config.json', cfg)
\ No newline at end of file
diff --git a/examples/gallery/app/common/icon.py b/examples/gallery/app/common/icon.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2520e519eb22b874fda38fab0ffe59d0ddad4fc
--- /dev/null
+++ b/examples/gallery/app/common/icon.py
@@ -0,0 +1,25 @@
+# coding: utf-8
+from enum import Enum
+
+from qfluentwidgets import FluentIconBase, getIconColor, Theme
+
+
+class Icon(FluentIconBase, Enum):
+
+ HOME = "Home"
+ CHAT = "Chat"
+ MENU = "Menu"
+ LAYOUT = "Layout"
+ GITHUB = "Github"
+ MESSAGE = "Message"
+ CHECKBOX = "CheckBox"
+ DOCUMENT = "Document"
+ CONSTRACT = "Constract"
+
+ def path(self, theme=Theme.AUTO):
+ if theme == Theme.AUTO:
+ c = getIconColor()
+ else:
+ c = "white" if theme == Theme.DARK else "black"
+
+ return f"app/resource/images/icons/{self.value}_{c}.svg"
diff --git a/examples/gallery/app/common/translator.py b/examples/gallery/app/common/translator.py
new file mode 100644
index 0000000000000000000000000000000000000000..63b6e454668c91a4902c1599673a18103159ee48
--- /dev/null
+++ b/examples/gallery/app/common/translator.py
@@ -0,0 +1,14 @@
+# coding: utf-8
+from PyQt5.QtCore import QObject
+
+
+class Translator(QObject):
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.basicInput = self.tr('Basic input')
+ self.menus = self.tr('Menus')
+ self.dialogs = self.tr('Dialogs')
+ self.material = self.tr('Material')
+ self.statusInfo = self.tr('Status & info')
+ self.layout = self.tr('Layout')
\ No newline at end of file
diff --git a/examples/gallery/app/components/avatar_widget.py b/examples/gallery/app/components/avatar_widget.py
new file mode 100644
index 0000000000000000000000000000000000000000..5803a2b9b6435be6b891e6244cbf669b1e25e714
--- /dev/null
+++ b/examples/gallery/app/components/avatar_widget.py
@@ -0,0 +1,42 @@
+# coding: utf-8
+from PyQt5.QtCore import Qt, QRect
+from PyQt5.QtGui import QPainter, QImage, QBrush, QColor, QFont
+from qfluentwidgets import NavigationWidget, isDarkTheme
+
+
+class AvatarWidget(NavigationWidget):
+ """ Avatar widget """
+
+ def __init__(self, image_path, parent=None):
+ super().__init__(isSelectable=False, parent=parent)
+ self.avatar = QImage(image_path).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.isEnter:
+ c = 255 if isDarkTheme() else 0
+ painter.setBrush(QColor(c, c, c, 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.white if isDarkTheme() else Qt.black)
+ font = QFont('Segoe UI')
+ font.setPixelSize(14)
+ painter.setFont(font)
+ painter.drawText(QRect(44, 0, 255, 36), Qt.AlignVCenter, 'zhiyiYo')
\ No newline at end of file
diff --git a/examples/gallery/app/resource/audio/ZhiYinJi.wav b/examples/gallery/app/resource/audio/ZhiYinJi.wav
new file mode 100644
index 0000000000000000000000000000000000000000..83bf05e3565b738f27ff66b7f500aeaea9b659c4
Binary files /dev/null and b/examples/gallery/app/resource/audio/ZhiYinJi.wav differ
diff --git a/examples/gallery/app/resource/i18n/qfluentwidgets_hk.qm b/examples/gallery/app/resource/i18n/qfluentwidgets_hk.qm
new file mode 100644
index 0000000000000000000000000000000000000000..63b1ea253be799e7dab26810befe2ae88ca5128e
Binary files /dev/null and b/examples/gallery/app/resource/i18n/qfluentwidgets_hk.qm differ
diff --git a/examples/gallery/app/resource/i18n/qfluentwidgets_hk.ts b/examples/gallery/app/resource/i18n/qfluentwidgets_hk.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6d9c8503fa23109d2324b4eff82635cf3e2d4e86
--- /dev/null
+++ b/examples/gallery/app/resource/i18n/qfluentwidgets_hk.ts
@@ -0,0 +1,374 @@
+
+
+
+
+
+ ColorDialog
+
+ OK
+ 確認
+
+
+ Cancel
+ 取消
+
+
+ Edit Color
+ 編輯顏色
+
+
+ Red
+ 紅色
+
+
+ Blue
+ 藍色
+
+
+ Green
+ 綠色
+
+
+
+ MessageDialog
+
+ OK
+ 確認
+
+
+ Cancel
+ 取消
+
+
+
+ Dialog
+
+ OK
+ 確認
+
+
+ Cancel
+ 取消
+
+
+
+ FolderListDialog
+
+ Done
+ 完成
+
+
+ Choose folder
+ 選擇文件夾
+
+
+ Are you sure you want to delete the folder?
+ 是否確認刪除此文件夾?
+
+
+ If you delete the
+ 如果將
+
+
+ folder and remove it from the list, the folder will no longer appear in the
+ list, but will not be deleted.
+ 文件夾從列表中移除,則該文件夾不會再出現在列表中,但不會被刪除。
+
+
+
+ SwitchSettingCard
+
+ Off
+ 關
+
+
+ On
+ 開
+
+
+
+ CustomColorSettingCard
+
+ Custom color
+ 自定義顏色
+
+
+ Default color
+ 默認顏色
+
+
+ Choose color
+ 選擇顏色
+
+
+
+ ColorPickerButton
+
+ Choose
+ 選擇
+
+
+
+ FolderListSettingCard
+
+ Add folder
+ 添加文件夾
+
+
+ Choose folder
+ 選擇文件夾
+
+
+ Are you sure you want to delete the folder?
+ 是否確認刪除此文件夾?
+
+
+ If you delete the
+ 如果將
+
+
+ folder and remove it from the list, the folder will no longer appear in the
+ list, but will not be deleted.
+ 文件夾從列表中移除,則該文件夾不會再出現在列表中,但不會被刪除。
+
+
+
+
+
+ SettingInterface
+
+ Settings
+ 設置
+
+
+ Music on this PC
+ 此 PC 上的音樂
+
+
+ Local music library
+ 本地音樂庫
+
+
+ Choose folder
+ 選擇文件夾
+
+
+ Download directory
+ 下載目錄
+
+
+ Personalization
+ 個性化
+
+
+ Use Acrylic effect
+ 啟用亞克力效果
+
+
+ Acrylic effect has better visual experience, but it may cause the window to
+ become stuck
+ 亞克力效果的視覺體驗更好,但可能導致窗口卡頓
+
+
+ Application theme
+ 應用主題
+
+
+ Theme color
+ 主題色
+
+
+ Change the theme color of you application
+ 調整你的應用主題顏色
+
+
+ Change the appearance of your application
+ 調整你的應用外觀
+
+
+ Light
+ 淺色
+
+
+ Dark
+ 深色
+
+
+ Use system setting
+ 跟隨系統設置
+
+
+ Interface zoom
+ 界面縮放
+
+
+ Change the size of widgets and fonts
+ 調整組件和字體的大小
+
+
+ Language
+ 語言
+
+
+ Set your preferred language for UI
+ 選擇界面所使用的語言
+
+
+ Online Music
+ 在線音樂
+
+
+ Number of online music displayed on each page
+ 每頁顯示的在線歌曲數量
+
+
+ Online music quality
+ 在線播放音質
+
+
+ Standard quality
+ 流暢
+
+
+ High quality
+ 高品
+
+
+ Super quality
+ 超品
+
+
+ Lossless quality
+ 無損
+
+
+ Online MV quality
+ 在線 MV 畫質
+
+
+ Full HD
+ 超清
+
+
+ HD
+ 高清
+
+
+ SD
+ 標清
+
+
+ LD
+ 流暢
+
+
+ Desktop Lyric
+ 桌面歌詞
+
+
+ Choose font
+ 選擇字體
+
+
+ Font
+ 字體
+
+
+ Foreground color
+ 前景色
+
+
+ Background color
+ 背景色
+
+
+ Stroke color
+ 描邊色
+
+
+ Stroke size
+ 描邊大小
+
+
+ Alignment
+ 對齊方式
+
+
+ Center aligned
+ 居中對齊
+
+
+ Left aligned
+ 左對齊
+
+
+ Right aligned
+ 右對齊
+
+
+ Main Panel
+ 主面板
+
+
+ Minimize to tray after closing
+ 關閉後最小化到托盤
+
+
+ PyQt-Fluent-Widgets will continue to run in the background
+ PyQt-Fluent-Widgets 將在後臺繼續運行
+
+
+
+ Software update
+ 軟件更新
+
+
+ Check for updates when the application starts
+ 在應用程序啟動時檢查更新
+
+
+ The new version will be more stable and have more features
+ 新版本將更加穩定並擁有更多功能(建議啟用此選項)
+
+
+ About
+ 關於
+
+
+ Open help page
+ 打開幫助頁面
+
+
+ Discover new features and learn useful tips about PyQt-Fluent-Widgets
+ 發現新功能並了解有關 PyQt-Fluent-Widgets 的使用技巧
+
+
+ Provide feedback
+ 提供反饋
+
+
+ Help us improve PyQt-Fluent-Widgets by providing feedback
+ 通過提供反饋幫助我們改進 PyQt-Fluent-Widgets
+
+
+ Check update
+ 檢查更新
+
+
+ Copyright
+ 版權所有
+
+
+ Version
+ 當前版本
+
+
+ Configuration updated successfully
+ 配置更新成功
+
+
+ Configuration takes effect after restart
+ 配置在重啟軟件後生效
+
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/i18n/qfluentwidgets_zh.qm b/examples/gallery/app/resource/i18n/qfluentwidgets_zh.qm
new file mode 100644
index 0000000000000000000000000000000000000000..657157dbe3fb65c76378341f7b113dc3d507bfc4
Binary files /dev/null and b/examples/gallery/app/resource/i18n/qfluentwidgets_zh.qm differ
diff --git a/examples/gallery/app/resource/i18n/qfluentwidgets_zh.ts b/examples/gallery/app/resource/i18n/qfluentwidgets_zh.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0a26e898bccc59de1782ea655d8dd496ee4fb3b6
--- /dev/null
+++ b/examples/gallery/app/resource/i18n/qfluentwidgets_zh.ts
@@ -0,0 +1,371 @@
+
+
+
+
+
+ ColorDialog
+
+ OK
+ 确认
+
+
+ Cancel
+ 取消
+
+
+ Edit Color
+ 编辑颜色
+
+
+ Red
+ 红色
+
+
+ Blue
+ 蓝色
+
+
+ Green
+ 绿色
+
+
+
+ MessageDialog
+
+ OK
+ 确认
+
+
+ Cancel
+ 取消
+
+
+
+ Dialog
+
+ OK
+ 确认
+
+
+ Cancel
+ 取消
+
+
+
+ FolderListDialog
+
+ Done
+ 完成
+
+
+ Choose folder
+ 选择文件夹
+
+
+ Are you sure you want to delete the folder?
+ 是否确认删除此文件夹?
+
+
+ If you delete the
+ 如果将
+
+
+ folder and remove it from the list, the folder will no longer appear in the list, but will not be deleted.
+ 文件夹从列表中移除,则该文件夹不会再出现在列表中,但不会被删除。
+
+
+
+ SwitchSettingCard
+
+ Off
+ 关
+
+
+ On
+ 开
+
+
+
+ CustomColorSettingCard
+
+ Custom color
+ 自定义颜色
+
+
+ Default color
+ 默认颜色
+
+
+ Choose color
+ 选择颜色
+
+
+
+ ColorPickerButton
+
+ Choose
+ 选择
+
+
+
+ FolderListSettingCard
+
+ Add folder
+ 添加文件夹
+
+
+ Choose folder
+ 选择文件夹
+
+
+ Are you sure you want to delete the folder?
+ 是否确认删除此文件夹?
+
+
+ If you delete the
+ 如果将
+
+
+ folder and remove it from the list, the folder will no longer appear in the list, but will not be deleted.
+ 文件夹从列表中移除,则该文件夹不会再出现在列表中,但不会被删除。
+
+
+
+
+
+ SettingInterface
+
+ Settings
+ 设置
+
+
+ Music on this PC
+ 此 PC 上的音乐
+
+
+ Local music library
+ 本地音乐库
+
+
+ Choose folder
+ 选择文件夹
+
+
+ Download directory
+ 下载目录
+
+
+ Personalization
+ 个性化
+
+
+ Use Acrylic effect
+ 启用亚克力效果
+
+
+ Acrylic effect has better visual experience, but it may cause the window to become stuck
+ 亚克力效果的视觉体验更好,但可能导致窗口卡顿
+
+
+ Application theme
+ 应用主题
+
+
+ Theme color
+ 主题色
+
+
+ Change the theme color of you application
+ 调整你的应用主题颜色
+
+
+ Change the appearance of your application
+ 调整你的应用外观
+
+
+ Light
+ 浅色
+
+
+ Dark
+ 深色
+
+
+ Use system setting
+ 跟随系统设置
+
+
+ Interface zoom
+ 界面缩放
+
+
+ Change the size of widgets and fonts
+ 调整组件和字体的大小
+
+
+ Language
+ 语言
+
+
+ Set your preferred language for UI
+ 选择界面所使用的语言
+
+
+ Online Music
+ 在线音乐
+
+
+ Number of online music displayed on each page
+ 每页显示的在线歌曲数量
+
+
+ Online music quality
+ 在线播放音质
+
+
+ Standard quality
+ 流畅
+
+
+ High quality
+ 高品
+
+
+ Super quality
+ 超品
+
+
+ Lossless quality
+ 无损
+
+
+ Online MV quality
+ 在线 MV 画质
+
+
+ Full HD
+ 超清
+
+
+ HD
+ 高清
+
+
+ SD
+ 标清
+
+
+ LD
+ 流畅
+
+
+ Desktop Lyric
+ 桌面歌词
+
+
+ Choose font
+ 选择字体
+
+
+ Font
+ 字体
+
+
+ Foreground color
+ 前景色
+
+
+ Background color
+ 背景色
+
+
+ Stroke color
+ 描边色
+
+
+ Stroke size
+ 描边大小
+
+
+ Alignment
+ 对齐方式
+
+
+ Center aligned
+ 居中对齐
+
+
+ Left aligned
+ 左对齐
+
+
+ Right aligned
+ 右对齐
+
+
+ Main Panel
+ 主面板
+
+
+ Minimize to tray after closing
+ 关闭后最小化到托盘
+
+
+ PyQt-Fluent-Widgets will continue to run in the background
+ PyQt-Fluent-Widgets 将在后台继续运行
+
+
+
+ Software update
+ 软件更新
+
+
+ Check for updates when the application starts
+ 在应用程序启动时检查更新
+
+
+ The new version will be more stable and have more features
+ 新版本将更加稳定并拥有更多功能(建议启用此选项)
+
+
+ About
+ 关于
+
+
+ Open help page
+ 打开帮助页面
+
+
+ Discover new features and learn useful tips about PyQt-Fluent-Widgets
+ 发现新功能并了解有关 PyQt-Fluent-Widgets 的使用技巧
+
+
+ Provide feedback
+ 提供反馈
+
+
+ Help us improve PyQt-Fluent-Widgets by providing feedback
+ 通过提供反馈帮助我们改进 PyQt-Fluent-Widgets
+
+
+ Check update
+ 检查更新
+
+
+ Copyright
+ 版权所有
+
+
+ Version
+ 当前版本
+
+
+ Configuration updated successfully
+ 配置更新成功
+
+
+ Configuration takes effect after restart
+ 配置在重启软件后生效
+
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/header.png b/examples/gallery/app/resource/images/header.png
new file mode 100644
index 0000000000000000000000000000000000000000..d260a7c86ef5d3d552af34124f7f812a115c2443
Binary files /dev/null and b/examples/gallery/app/resource/images/header.png differ
diff --git a/examples/gallery/app/resource/images/icons/Chat_black.svg b/examples/gallery/app/resource/images/icons/Chat_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..976a59f7605b397f00679beca7f1e9512391af7f
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Chat_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Chat_white.svg b/examples/gallery/app/resource/images/icons/Chat_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..87a8afe5ac40e462149686fba9464bb7efe53b43
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Chat_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/CheckBox_black.svg b/examples/gallery/app/resource/images/icons/CheckBox_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..36cd567e09fd9b57de0c1d0e29cfcddd0ef57cac
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/CheckBox_black.svg
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/CheckBox_white.svg b/examples/gallery/app/resource/images/icons/CheckBox_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..93ec5943090355656e4a6d5d839e2d75144c68ae
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/CheckBox_white.svg
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Constract_black.svg b/examples/gallery/app/resource/images/icons/Constract_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..999670948581051e159841cdd99d93234876148d
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Constract_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Constract_white.svg b/examples/gallery/app/resource/images/icons/Constract_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..c0f9f6d1e4163415be318509b12e6baac0f8d521
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Constract_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Document_black.svg b/examples/gallery/app/resource/images/icons/Document_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..650b89a5eebf0644f9cdf7bca092128f251a2406
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Document_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Document_white.svg b/examples/gallery/app/resource/images/icons/Document_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b7dddeb71b6358d602d046d74d5e018134bdeb8e
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Document_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Home_black.svg b/examples/gallery/app/resource/images/icons/Home_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..2e2426e66dc7602d5c72e2f4f09bf74a0d47fbe3
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Home_black.svg
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Home_white.svg b/examples/gallery/app/resource/images/icons/Home_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..29b0d9557f91dcc21fe871b688efdfb196499c6e
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Home_white.svg
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Layout_black.svg b/examples/gallery/app/resource/images/icons/Layout_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..afc2c881c28e2429f7d1a18679d11870f4f7f864
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Layout_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Layout_white.svg b/examples/gallery/app/resource/images/icons/Layout_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..05b0de97c5d0d2325ed8651f30b50ecc938bdd09
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Layout_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Menu_black.svg b/examples/gallery/app/resource/images/icons/Menu_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..e590822a07a604db06cb64e9371bf076e6b631ee
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Menu_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Menu_white.svg b/examples/gallery/app/resource/images/icons/Menu_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..4fd70ed2f82e6f8e5bc74e245703dfda5f1cfaf9
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Menu_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Message_black.svg b/examples/gallery/app/resource/images/icons/Message_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..f5f13eb3c10a3ccf5bafdff683c1d5c303dcfba1
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Message_black.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/Message_white.svg b/examples/gallery/app/resource/images/icons/Message_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..49958fb1bc40e2bdf11bda69c453673070872cac
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/Message_white.svg
@@ -0,0 +1,4 @@
+
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/github_black.svg b/examples/gallery/app/resource/images/icons/github_black.svg
new file mode 100644
index 0000000000000000000000000000000000000000..37fa923df33faeccc4b55228046b5b079a82926d
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/github_black.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/icons/github_white.svg b/examples/gallery/app/resource/images/icons/github_white.svg
new file mode 100644
index 0000000000000000000000000000000000000000..d5e64918546d9dd87c9742239deae2397e634343
--- /dev/null
+++ b/examples/gallery/app/resource/images/icons/github_white.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/examples/gallery/app/resource/images/kunkun.png b/examples/gallery/app/resource/images/kunkun.png
new file mode 100644
index 0000000000000000000000000000000000000000..00a4cfd28a2b8879e249456540fc2a0eb574d23f
Binary files /dev/null and b/examples/gallery/app/resource/images/kunkun.png differ
diff --git a/examples/gallery/app/resource/images/logo.png b/examples/gallery/app/resource/images/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..0bae40eedbdba654e5c5248c923ca700287205a8
Binary files /dev/null and b/examples/gallery/app/resource/images/logo.png differ
diff --git a/examples/gallery/app/resource/images/shoko.png b/examples/gallery/app/resource/images/shoko.png
new file mode 100644
index 0000000000000000000000000000000000000000..7d8894bb8779c83df005c97fb4659dce2eb82484
Binary files /dev/null and b/examples/gallery/app/resource/images/shoko.png differ
diff --git a/examples/gallery/app/resource/qss/dark/gallery_interface.qss b/examples/gallery/app/resource/qss/dark/gallery_interface.qss
new file mode 100644
index 0000000000000000000000000000000000000000..0cf908daec9d13107278a330374794579d12e091
--- /dev/null
+++ b/examples/gallery/app/resource/qss/dark/gallery_interface.qss
@@ -0,0 +1,80 @@
+GalleryInterface,
+ToolBar,
+#view {
+ background-color: transparent;
+}
+
+QScrollArea {
+ border: none;
+}
+
+ToolBar > #titleLabel {
+ font: 28px 'Segoe UI SemiBold', 'Microsoft YaHei';
+ font-weight: bold;
+ background-color: transparent;
+ color: white;
+}
+
+ToolBar > #subtitleLabel {
+ font: 12px 'Segoe UI', 'Microsoft YaHei';
+ background-color: transparent;
+ color: white;
+}
+
+ExampleCard {
+ background-color: transparent;
+}
+
+ExampleCard>#card {
+ border: 1px solid rgb(32, 32, 32);
+ border-radius: 10px;
+ background-color: rgb(36, 36, 36);
+}
+
+ExampleCard>#titleLabel {
+ font: 14px 'Segoe UI SemiBold', 'Microsoft YaHei';
+ background-color: transparent;
+ color: white;
+}
+
+#sourceWidget {
+ background-color: rgb(51, 51, 51);
+ border-top: 1px solid rgb(36, 36, 36);
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
+}
+
+#sourcePathLabel {
+ color: white;
+ font: 14px 'Segoe UI', 'Microsoft YaHei';
+}
+
+QScrollBar {
+ background: transparent;
+ width: 4px;
+ margin-top: 32px;
+ margin-bottom: 0;
+ padding-right: 2px;
+}
+
+/*隐藏上箭头*/
+QScrollBar::sub-line {
+ background: transparent;
+}
+
+/*隐藏下箭头*/
+QScrollBar::add-line {
+ background: transparent;
+}
+
+QScrollBar::handle {
+ background: rgb(122, 122, 122);
+ border: 2px solid rgb(128, 128, 128);
+ border-radius: 1px;
+ min-height: 32px;
+}
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
+ background: none;
+}
\ No newline at end of file
diff --git a/examples/gallery/app/resource/qss/dark/main_window.qss b/examples/gallery/app/resource/qss/dark/main_window.qss
new file mode 100644
index 0000000000000000000000000000000000000000..ed9bac3b7511ed36ee4a3d5406990f6f04f26975
--- /dev/null
+++ b/examples/gallery/app/resource/qss/dark/main_window.qss
@@ -0,0 +1,53 @@
+StackedWidget {
+ border: 1px solid rgb(29, 29, 29);
+ border-right: none;
+ border-bottom: none;
+ border-top-left-radius: 10px;
+ background-color: rgb(39, 39, 39);
+}
+
+
+MainWindow {
+ background-color: rgb(32, 32, 32);
+}
+
+CustomTitleBar {
+ background-color: transparent;
+}
+
+CustomTitleBar > QLabel,
+Widget > QLabel {
+ color: white;
+}
+
+
+CustomTitleBar>QLabel#titleLabel {
+ background: transparent;
+ font: 13px 'Segoe UI';
+ padding: 0 4px
+}
+
+MinimizeButton {
+ qproperty-normalColor: white;
+ qproperty-normalBackgroundColor: transparent;
+ qproperty-hoverColor: white;
+ qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
+ qproperty-pressedColor: white;
+ qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
+}
+
+
+MaximizeButton {
+ qproperty-normalColor: white;
+ qproperty-normalBackgroundColor: transparent;
+ qproperty-hoverColor: white;
+ qproperty-hoverBackgroundColor: rgba(255, 255, 255, 26);
+ qproperty-pressedColor: white;
+ qproperty-pressedBackgroundColor: rgba(255, 255, 255, 51)
+}
+
+CloseButton {
+ qproperty-normalColor: white;
+ qproperty-normalBackgroundColor: transparent;
+}
+
diff --git a/examples/gallery/app/resource/qss/dark/setting_interface.qss b/examples/gallery/app/resource/qss/dark/setting_interface.qss
new file mode 100644
index 0000000000000000000000000000000000000000..df9b41fffd9b5181e0acc5d5e4f0d4e21793d906
--- /dev/null
+++ b/examples/gallery/app/resource/qss/dark/setting_interface.qss
@@ -0,0 +1,48 @@
+SettingInterface, #scrollWidget {
+ background-color: transparent;
+}
+
+QScrollArea {
+ border: none;
+ background-color: transparent;
+}
+
+
+/* 标签 */
+QLabel#settingLabel {
+ font: 33px 'Microsoft YaHei Light';
+ background-color: transparent;
+ color: white;
+}
+
+
+/* 滚动条 */
+QScrollBar {
+ background: transparent;
+ width: 4px;
+ margin-top: 32px;
+ margin-bottom: 0;
+ padding-right: 2px;
+}
+
+/*隐藏上箭头*/
+QScrollBar::sub-line {
+ background: transparent;
+}
+
+/*隐藏下箭头*/
+QScrollBar::add-line {
+ background: transparent;
+}
+
+QScrollBar::handle {
+ background: rgb(122, 122, 122);
+ border: 2px solid rgb(128, 128, 128);
+ border-radius: 1px;
+ min-height: 32px;
+}
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
+ background: none;
+}
\ No newline at end of file
diff --git a/examples/gallery/app/resource/qss/light/gallery_interface.qss b/examples/gallery/app/resource/qss/light/gallery_interface.qss
new file mode 100644
index 0000000000000000000000000000000000000000..55df1ddaae990d61ac92fdfb361671a9773d1054
--- /dev/null
+++ b/examples/gallery/app/resource/qss/light/gallery_interface.qss
@@ -0,0 +1,77 @@
+GalleryInterface, ToolBar, #view {
+ background-color: transparent;
+}
+
+QScrollArea {
+ border: none;
+}
+
+ToolBar > #titleLabel {
+ font: 28px 'Segoe UI SemiBold', 'Microsoft YaHei';
+ background-color: transparent;
+ color: black;
+}
+
+ToolBar > #subtitleLabel {
+ font: 12px 'Segoe UI', 'Microsoft YaHei';
+ background-color: transparent;
+ color: rgb(95, 95, 95);
+}
+
+ExampleCard {
+ background-color: transparent;
+}
+
+ExampleCard > #card {
+ border: 1px solid rgb(234, 234, 234);
+ border-radius: 10px;
+ background-color: rgb(243, 243, 243);
+}
+
+ExampleCard > #titleLabel {
+ font: 14px 'Segoe UI SemiBold', 'Microsoft YaHei';
+ background-color: transparent;
+ color: black;
+}
+
+#sourceWidget {
+ background-color: rgb(253, 253, 253);
+ border-top: 1px solid rgb(234, 234, 234);
+ border-bottom-left-radius: 10px;
+ border-bottom-right-radius: 10px;
+}
+
+#sourcePathLabel {
+ color: black;
+ font: 14px 'Segoe UI', 'Microsoft YaHei';
+}
+
+QScrollBar {
+ background: transparent;
+ width: 4px;
+ margin-top: 32px;
+ margin-bottom: 0;
+ padding-right: 2px;
+}
+
+/*隐藏上箭头*/
+QScrollBar::sub-line {
+ background: transparent;
+}
+
+/*隐藏下箭头*/
+QScrollBar::add-line {
+ background: transparent;
+}
+
+QScrollBar::handle {
+ background: rgb(122, 122, 122);
+ border: 2px solid rgb(128, 128, 128);
+ border-radius: 1px;
+ min-height: 32px;
+}
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
+ background: none;
+}
\ No newline at end of file
diff --git a/examples/gallery/app/resource/qss/light/main_window.qss b/examples/gallery/app/resource/qss/light/main_window.qss
new file mode 100644
index 0000000000000000000000000000000000000000..758578d7b1d580a2949c5902405bbe934b02b1c5
--- /dev/null
+++ b/examples/gallery/app/resource/qss/light/main_window.qss
@@ -0,0 +1,42 @@
+StackedWidget {
+ border: 1px solid rgb(229, 229, 229);
+ border-right: none;
+ border-bottom: none;
+ border-top-left-radius: 10px;
+ background-color: rgb(249, 249, 249);
+}
+
+MainWindow {
+ background-color: rgb(243, 243, 243);
+}
+
+CustomTitleBar > QLabel#titleLabel {
+ color: black;
+ background: transparent;
+ font: 13px 'Segoe UI';
+ padding: 0 4px
+}
+
+MinimizeButton {
+ qproperty-normalColor: black;
+ qproperty-normalBackgroundColor: transparent;
+ qproperty-hoverColor: black;
+ qproperty-hoverBackgroundColor: rgba(0, 0, 0, 26);
+ qproperty-pressedColor: black;
+ qproperty-pressedBackgroundColor: rgba(0, 0, 0, 51)
+}
+
+
+MaximizeButton {
+ qproperty-normalColor: black;
+ qproperty-normalBackgroundColor: transparent;
+ qproperty-hoverColor: black;
+ qproperty-hoverBackgroundColor: rgba(0, 0, 0, 26);
+ qproperty-pressedColor: black;
+ qproperty-pressedBackgroundColor: rgba(0, 0, 0, 51)
+}
+
+CloseButton {
+ qproperty-normalColor: black;
+ qproperty-normalBackgroundColor: transparent;
+}
\ No newline at end of file
diff --git a/examples/gallery/app/resource/qss/light/setting_interface.qss b/examples/gallery/app/resource/qss/light/setting_interface.qss
new file mode 100644
index 0000000000000000000000000000000000000000..ce639874c2a40be58fc6cf1bfbf9b918477f0057
--- /dev/null
+++ b/examples/gallery/app/resource/qss/light/setting_interface.qss
@@ -0,0 +1,47 @@
+SettingInterface, #scrollWidget {
+ background-color: transparent;
+}
+
+QScrollArea {
+ background-color: transparent;
+ border: none;
+}
+
+
+/* 标签 */
+QLabel#settingLabel {
+ font: 33px 'Microsoft YaHei Light';
+ background-color: transparent;
+}
+
+
+/* 滚动条 */
+QScrollBar {
+ background: transparent;
+ width: 4px;
+ margin-top: 32px;
+ margin-bottom: 0;
+ padding-right: 2px;
+}
+
+/*隐藏上箭头*/
+QScrollBar::sub-line {
+ background: transparent;
+}
+
+/*隐藏下箭头*/
+QScrollBar::add-line {
+ background: transparent;
+}
+
+QScrollBar::handle {
+ background: rgb(122, 122, 122);
+ border: 2px solid rgb(128, 128, 128);
+ border-radius: 1px;
+ min-height: 32px;
+}
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
+ background: none;
+}
\ No newline at end of file
diff --git a/examples/gallery/app/view/basic_input_interface.py b/examples/gallery/app/view/basic_input_interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..bcf9d9c94e7fb96817088b40b53fe3c63d0f2199
--- /dev/null
+++ b/examples/gallery/app/view/basic_input_interface.py
@@ -0,0 +1,103 @@
+# coding:utf-8
+from PyQt5.QtCore import Qt, QSize
+from PyQt5.QtWidgets import QWidget, QVBoxLayout, QButtonGroup
+from PyQt5.QtMultimedia import QSound
+from qfluentwidgets import (PushButton, ToolButton, PrimaryPushButton, HyperlinkButton,
+ ComboBox, RadioButton, CheckBox, Slider)
+
+from .gallery_interface import GalleryInterface
+from ..common.translator import Translator
+
+
+class BasicInputInterface(GalleryInterface):
+ """ Basic input interface """
+
+ def __init__(self, parent=None):
+ translator = Translator()
+ super().__init__(
+ title=translator.basicInput,
+ subtitle='qfluentwidgets.components.widgets',
+ parent=parent
+ )
+
+ self.addExampleCard(
+ self.tr('A simple button with text content'),
+ PushButton('Standard push button'),
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
+ )
+
+ button = ToolButton('app/resource/images/kunkun.png')
+ button.setIconSize(QSize(40, 40))
+ button.clicked.connect(lambda: QSound.play(
+ 'app/resource/audio/ZhiYinJi.wav'))
+ button.resize(70, 70)
+ self.addExampleCard(
+ self.tr('A button with graphical content'),
+ button,
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
+ )
+
+ self.addExampleCard(
+ self.tr('Accent style applied to button'),
+ PrimaryPushButton('Accent style button'),
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
+ )
+
+ self.addExampleCard(
+ self.tr('A hyperlink button that navigates to a URI'),
+ HyperlinkButton('http://github.com', 'GitHub home page'),
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/button/demo.py'
+ )
+
+ self.addExampleCard(
+ self.tr('A 2-state CheckBox'),
+ CheckBox('Two-state CheckBox'),
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/check_box/demo.py'
+ )
+
+ checkBox = CheckBox('Three-state CheckBox')
+ checkBox.setTristate(True)
+ self.addExampleCard(
+ self.tr('A 3-state CheckBox'),
+ checkBox,
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/check_box/demo.py'
+ )
+
+ comboBox = ComboBox()
+ comboBox.addItems(['shoko 🥰', '西宫硝子 😊', '一级棒卡哇伊的硝子酱 😘'])
+ comboBox.setCurrentIndex(0)
+ comboBox.setMinimumWidth(210)
+ self.addExampleCard(
+ self.tr('A ComboBox with items'),
+ comboBox,
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/combo_box/demo.py'
+ )
+
+ radioWidget = QWidget()
+ radioLayout = QVBoxLayout(radioWidget)
+ radioLayout.setContentsMargins(2, 0, 0, 0)
+ radioLayout.setSpacing(15)
+ radioButton1 = RadioButton('Star Platinum', radioWidget)
+ radioButton2 = RadioButton('Crazy Diamond', radioWidget)
+ radioButton3 = RadioButton('Soft and Wet', radioWidget)
+ buttonGroup = QButtonGroup(radioWidget)
+ buttonGroup.addButton(radioButton1)
+ buttonGroup.addButton(radioButton2)
+ buttonGroup.addButton(radioButton3)
+ radioLayout.addWidget(radioButton1)
+ radioLayout.addWidget(radioButton2)
+ radioLayout.addWidget(radioButton3)
+ self.addExampleCard(
+ self.tr('A group of RadioButton controls in a button group'),
+ radioWidget,
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/radio_button/demo.py'
+ )
+
+ slider = Slider(Qt.Horizontal)
+ slider.setRange(0, 100)
+ slider.setFixedWidth(200)
+ self.addExampleCard(
+ self.tr('A simple horizontal slider'),
+ slider,
+ 'https://github.com/zhiyiYo/PyQt-Fluent-Widgets/blob/master/examples/slider/demo.py'
+ )
diff --git a/examples/gallery/app/view/gallery_interface.py b/examples/gallery/app/view/gallery_interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..8174f304df7b07953f4d84e5d58bc0fc21f2fedb
--- /dev/null
+++ b/examples/gallery/app/view/gallery_interface.py
@@ -0,0 +1,171 @@
+# coding:utf-8
+from PyQt5.QtCore import Qt, pyqtSignal, QUrl, QEvent
+from PyQt5.QtGui import QDesktopServices
+from PyQt5.QtWidgets import QWidget, QLabel, QVBoxLayout, QHBoxLayout, QFrame
+
+from qfluentwidgets import (ScrollArea, PushButton, ToolButton, FluentIcon,
+ isDarkTheme, IconWidget, Theme)
+from ..common.icon import Icon
+from ..common.config import cfg, FEEDBACK_URL, DOCUMENT_URL, EXAMPLE_URL
+
+
+class ToolBar(QWidget):
+ """ Tool bar """
+
+ def __init__(self, title, subtitle, parent=None):
+ super().__init__(parent=parent)
+ self.titleLabel = QLabel(title, self)
+ self.subtitleLabel = QLabel(subtitle, self)
+
+ self.documentButton = PushButton(
+ self.tr('Documentation'), self, Icon.DOCUMENT)
+ self.sourceButton = PushButton(self.tr('Source'), self, Icon.GITHUB)
+ self.themeButton = ToolButton(Icon.CONSTRACT, self)
+ self.feedbackButton = ToolButton(FluentIcon.FEEDBACK, self)
+
+ self.vBoxLayout = QVBoxLayout(self)
+ self.buttonLayout = QHBoxLayout()
+
+ self.__initWidget()
+
+ def __initWidget(self):
+ self.setFixedHeight(138)
+ self.vBoxLayout.setSpacing(0)
+ self.vBoxLayout.setContentsMargins(36, 22, 36, 12)
+ self.vBoxLayout.addWidget(self.titleLabel)
+ self.vBoxLayout.addSpacing(4)
+ self.vBoxLayout.addWidget(self.subtitleLabel)
+ self.vBoxLayout.addSpacing(4)
+ self.vBoxLayout.addLayout(self.buttonLayout, 1)
+ self.vBoxLayout.setAlignment(Qt.AlignTop)
+
+ self.buttonLayout.setSpacing(4)
+ self.buttonLayout.setContentsMargins(0, 0, 0, 0)
+ self.buttonLayout.addWidget(self.documentButton, 0, Qt.AlignLeft)
+ self.buttonLayout.addWidget(self.sourceButton, 0, Qt.AlignLeft)
+ self.buttonLayout.addStretch(1)
+ self.buttonLayout.addWidget(self.themeButton, 0, Qt.AlignRight)
+ self.buttonLayout.addWidget(self.feedbackButton, 0, Qt.AlignRight)
+ self.buttonLayout.setAlignment(Qt.AlignVCenter | Qt.AlignLeft)
+
+ self.titleLabel.setObjectName('titleLabel')
+ self.subtitleLabel.setObjectName('subtitleLabel')
+
+ self.themeButton.clicked.connect(self.toggleTheme)
+ self.documentButton.clicked.connect(
+ lambda: QDesktopServices.openUrl(QUrl(DOCUMENT_URL)))
+ self.sourceButton.clicked.connect(
+ lambda: QDesktopServices.openUrl(QUrl(EXAMPLE_URL)))
+ self.feedbackButton.clicked.connect(
+ lambda: QDesktopServices.openUrl(QUrl(FEEDBACK_URL)))
+
+ def toggleTheme(self):
+ theme = Theme.LIGHT if isDarkTheme() else Theme.DARK
+ cfg.set(cfg.themeMode, theme)
+
+
+class ExampleCard(QWidget):
+ """ Example card """
+
+ def __init__(self, title, widget: QWidget, sourcePath, parent=None):
+ super().__init__(parent=parent)
+ self.widget = widget
+ self.titleLabel = QLabel(title, self)
+ self.card = QFrame(self)
+
+ self.sourceWidget = QFrame(self.card)
+ self.sourcePath = sourcePath
+ self.sourcePathLabel = QLabel(self.tr('Source code'), self.sourceWidget)
+ self.linkIcon = IconWidget(FluentIcon.LINK, self.sourceWidget)
+
+ self.vBoxLayout = QVBoxLayout(self)
+ self.cardLayout = QVBoxLayout(self.card)
+ self.topLayout = QHBoxLayout()
+ self.bottomLayout = QHBoxLayout(self.sourceWidget)
+
+ self.__initWidget()
+
+ def __initWidget(self):
+ self.linkIcon.setFixedSize(16, 16)
+ self.__initLayout()
+
+ self.sourceWidget.setCursor(Qt.PointingHandCursor)
+ self.sourceWidget.installEventFilter(self)
+
+ self.titleLabel.setObjectName('titleLabel')
+ self.card.setObjectName('card')
+ self.sourcePathLabel.setObjectName('sourcePathLabel')
+ self.sourceWidget.setObjectName('sourceWidget')
+
+ def __initLayout(self):
+ self.vBoxLayout.setSizeConstraint(QVBoxLayout.SetMinimumSize)
+ self.cardLayout.setSizeConstraint(QVBoxLayout.SetMinimumSize)
+ self.topLayout.setSizeConstraint(QHBoxLayout.SetMinimumSize)
+
+ self.vBoxLayout.setSpacing(12)
+ self.vBoxLayout.setContentsMargins(0, 0, 0, 0)
+ self.topLayout.setContentsMargins(12, 12, 12, 12)
+ self.bottomLayout.setContentsMargins(18, 18, 18, 18)
+ self.cardLayout.setContentsMargins(0, 0, 0, 0)
+
+ self.vBoxLayout.addWidget(self.titleLabel, 0, Qt.AlignTop)
+ self.vBoxLayout.addWidget(self.card, 0, Qt.AlignTop)
+ self.vBoxLayout.setAlignment(Qt.AlignTop)
+
+ self.cardLayout.setSpacing(0)
+ self.cardLayout.setAlignment(Qt.AlignTop)
+ self.cardLayout.addLayout(self.topLayout, 0)
+ self.cardLayout.addWidget(self.sourceWidget, 0, Qt.AlignBottom)
+
+ self.widget.setParent(self.card)
+ self.topLayout.addWidget(self.widget)
+ self.topLayout.addStretch(1)
+ self.widget.show()
+
+ self.bottomLayout.addWidget(self.sourcePathLabel, 0, Qt.AlignLeft)
+ self.bottomLayout.addStretch(1)
+ self.bottomLayout.addWidget(self.linkIcon, 0, Qt.AlignRight)
+ self.bottomLayout.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
+
+ def eventFilter(self, obj, e):
+ if obj is self.sourceWidget:
+ if e.type() == QEvent.MouseButtonRelease:
+ QDesktopServices.openUrl(QUrl(self.sourcePath))
+
+ return super().eventFilter(obj, e)
+
+
+class GalleryInterface(ScrollArea):
+ """ Gallery interface """
+
+ def __init__(self, title: str, subtitle: str, parent=None):
+ super().__init__(parent=parent)
+ self.view = QWidget(self)
+ self.toolBar = ToolBar(title, subtitle, self)
+ self.vBoxLayout = QVBoxLayout(self.view)
+
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.setViewportMargins(0, self.toolBar.height(), 0, 0)
+ self.setWidget(self.view)
+ self.setWidgetResizable(True)
+
+ self.vBoxLayout.setSpacing(30)
+ self.vBoxLayout.setAlignment(Qt.AlignTop)
+ self.vBoxLayout.setContentsMargins(36, 20, 36, 36)
+
+ self.__setQss()
+ cfg.themeChanged.connect(self.__setQss)
+
+ def addExampleCard(self, title, widget, sourcePath: str):
+ card = ExampleCard(title, widget, sourcePath, self.view)
+ self.vBoxLayout.addWidget(card, 0, Qt.AlignTop)
+
+ def resizeEvent(self, e):
+ super().resizeEvent(e)
+ self.toolBar.resize(self.width(), self.toolBar.height())
+
+ def __setQss(self):
+ self.view.setObjectName('view')
+ theme = 'dark' if isDarkTheme() else 'light'
+ with open(f'app/resource/qss/{theme}/gallery_interface.qss', encoding='utf-8') as f:
+ self.setStyleSheet(f.read())
diff --git a/examples/gallery/app/view/main_window.py b/examples/gallery/app/view/main_window.py
new file mode 100644
index 0000000000000000000000000000000000000000..d4307ece675b07ea18bd3c37dfd32a9dac828cec
--- /dev/null
+++ b/examples/gallery/app/view/main_window.py
@@ -0,0 +1,196 @@
+# coding: utf-8
+from PyQt5.QtCore import Qt, pyqtSignal
+from PyQt5.QtGui import QIcon
+from PyQt5.QtWidgets import QApplication, QStackedWidget, QHBoxLayout, QFrame, QWidget
+
+from qfluentwidgets import (NavigationInterface, NavigationItemPostion, MessageBox,
+ isDarkTheme)
+from qfluentwidgets import FluentIcon as FIF
+from qframelesswindow import FramelessWindow
+
+from .title_bar import CustomTitleBar
+from .setting_interface import SettingInterface, cfg
+from .basic_input_interface import BasicInputInterface
+from ..components.avatar_widget import AvatarWidget
+from ..common.icon import Icon
+
+
+class StackedWidget(QFrame):
+ """ Stacked widget """
+
+ currentWidgetChanged = pyqtSignal(QWidget)
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.hBoxLayout = QHBoxLayout(self)
+ self.view = QStackedWidget(self)
+
+ self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
+ self.hBoxLayout.addWidget(self.view)
+
+ self.view.currentChanged.connect(
+ lambda i: self.currentWidgetChanged.emit(self.view.widget(i)))
+
+ def addWidget(self, widget):
+ """ add widget to view """
+ self.view.addWidget(widget)
+
+ def setCurrentWidget(self, widget):
+ self.view.setCurrentWidget(widget)
+
+ def setCurrentIndex(self, index):
+ self.view.setCurrentIndex(index)
+
+
+class MainWindow(FramelessWindow):
+
+ def __init__(self):
+ super().__init__()
+ self.setTitleBar(CustomTitleBar(self))
+ self.hBoxLayout = QHBoxLayout(self)
+ self.widgetLayout = QHBoxLayout()
+
+ self.stackWidget = StackedWidget(self)
+ self.navigationInterface = NavigationInterface(self, True, True)
+
+ # create sub interface
+ self.basicInputInterface = BasicInputInterface(self)
+ self.settingInterface = SettingInterface(self)
+
+ self.stackWidget.addWidget(self.basicInputInterface)
+ self.stackWidget.addWidget(self.settingInterface)
+
+ # initialize layout
+ self.initLayout()
+
+ # add items to navigation interface
+ self.initNavigation()
+
+ self.initWindow()
+
+ def initLayout(self):
+ self.hBoxLayout.setSpacing(0)
+ self.hBoxLayout.setContentsMargins(0, 0, 0, 0)
+ self.hBoxLayout.addWidget(self.navigationInterface)
+ self.hBoxLayout.addLayout(self.widgetLayout)
+ self.hBoxLayout.setStretchFactor(self.widgetLayout, 1)
+
+ self.widgetLayout.addWidget(self.stackWidget)
+ self.widgetLayout.setContentsMargins(0, 48, 0, 0)
+
+ self.navigationInterface.displayModeChanged.connect(
+ self.titleBar.raise_)
+ self.titleBar.raise_()
+
+ def initNavigation(self):
+ self.basicInputInterface.setObjectName('basicInterface')
+ self.settingInterface.setObjectName('settingsInterface')
+
+ self.navigationInterface.addItem(
+ routeKey='Home',
+ icon=Icon.HOME,
+ text=self.tr('Home'),
+ onClick=print
+ )
+ self.navigationInterface.addSeparator()
+
+ self.navigationInterface.addItem(
+ routeKey=self.basicInputInterface.objectName(),
+ icon=Icon.CHECKBOX,
+ text=self.tr('Basic input'),
+ onClick=lambda: self.switchTo(self.basicInputInterface),
+ position=NavigationItemPostion.SCROLL
+ )
+ self.navigationInterface.addItem(
+ routeKey='Dialogs',
+ icon=Icon.MESSAGE,
+ text=self.tr('Dialogs'),
+ onClick=print,
+ position=NavigationItemPostion.SCROLL
+ )
+ self.navigationInterface.addItem(
+ routeKey='Status&info',
+ icon=Icon.LAYOUT,
+ text=self.tr('Layout'),
+ onClick=print,
+ position=NavigationItemPostion.SCROLL
+ )
+ self.navigationInterface.addItem(
+ routeKey='Menus',
+ icon=Icon.MENU,
+ text=self.tr('Menus'),
+ onClick=print,
+ position=NavigationItemPostion.SCROLL
+ )
+ self.navigationInterface.addItem(
+ routeKey='Material',
+ icon=FIF.PALETTE,
+ text=self.tr('Material'),
+ onClick=print,
+ position=NavigationItemPostion.SCROLL
+ )
+ self.navigationInterface.addItem(
+ routeKey='Layout',
+ icon=Icon.CHAT,
+ text=self.tr('Status & info'),
+ onClick=print,
+ position=NavigationItemPostion.SCROLL
+ )
+
+ # add custom widget to bottom
+ self.navigationInterface.addWidget(
+ routeKey='avatar',
+ widget=AvatarWidget('app/resource/images/shoko.png'),
+ onClick=self.showMessageBox,
+ position=NavigationItemPostion.BOTTOM
+ )
+
+ self.navigationInterface.addItem(
+ routeKey=self.settingInterface.objectName(),
+ icon=FIF.SETTING,
+ text='Settings',
+ onClick=lambda: self.switchTo(self.settingInterface),
+ position=NavigationItemPostion.BOTTOM
+ )
+
+ #!IMPORTANT: don't forget to set the default route key if you enable the return button
+ self.navigationInterface.setDefaultRouteKey(
+ self.basicInputInterface.objectName())
+
+ self.stackWidget.currentWidgetChanged.connect(
+ lambda w: self.navigationInterface.setCurrentItem(w.objectName()))
+ self.navigationInterface.setCurrentItem(self.basicInputInterface.objectName())
+ self.stackWidget.setCurrentIndex(0)
+
+ def initWindow(self):
+ self.resize(900, 700)
+ self.setWindowIcon(QIcon('app/resource/images/logo.png'))
+ self.setWindowTitle('PyQt-Fluent-Widgets')
+ self.titleBar.setAttribute(Qt.WA_StyledBackground)
+
+ desktop = QApplication.desktop().availableGeometry()
+ w, h = desktop.width(), desktop.height()
+ self.move(w//2 - self.width()//2, h//2 - self.height()//2)
+
+ cfg.themeChanged.connect(self.setQss)
+ self.setQss()
+
+ def setQss(self):
+ color = 'dark' if isDarkTheme() else 'light'
+ with open(f'app/resource/qss/{color}/main_window.qss', encoding='utf-8') as f:
+ self.setStyleSheet(f.read())
+
+ def switchTo(self, widget):
+ self.stackWidget.setCurrentWidget(widget)
+
+ def resizeEvent(self, e):
+ self.titleBar.move(46, 0)
+ self.titleBar.resize(self.width()-46, self.titleBar.height())
+
+ 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()
diff --git a/examples/gallery/app/view/setting_interface.py b/examples/gallery/app/view/setting_interface.py
new file mode 100644
index 0000000000000000000000000000000000000000..b0c64605a109f6e820c29704bfca62fca24a57fa
--- /dev/null
+++ b/examples/gallery/app/view/setting_interface.py
@@ -0,0 +1,219 @@
+# coding:utf-8
+from qfluentwidgets import (SettingCardGroup, SwitchSettingCard, FolderListSettingCard,
+ OptionsSettingCard, PushSettingCard,
+ HyperlinkCard, PrimaryPushSettingCard, ScrollArea,
+ ComboBoxSettingCard, ExpandLayout, Theme, ToastToolTip, CustomColorSettingCard,
+ setTheme, setThemeColor)
+from qfluentwidgets import FluentIcon as FIF
+from PyQt5.QtCore import Qt, pyqtSignal, QUrl, QStandardPaths
+from PyQt5.QtGui import QDesktopServices
+from PyQt5.QtWidgets import QWidget, QLabel, QFileDialog
+
+from ..common.config import cfg, HELP_URL, FEEDBACK_URL, AUTHOR, VERSION, YEAR
+
+
+class SettingInterface(ScrollArea):
+ """ Setting interface """
+
+ checkUpdateSig = pyqtSignal()
+ musicFoldersChanged = pyqtSignal(list)
+ acrylicEnableChanged = pyqtSignal(bool)
+ downloadFolderChanged = pyqtSignal(str)
+ minimizeToTrayChanged = pyqtSignal(bool)
+
+ def __init__(self, parent=None):
+ super().__init__(parent=parent)
+ self.scrollWidget = QWidget()
+ self.expandLayout = ExpandLayout(self.scrollWidget)
+
+ # setting label
+ self.settingLabel = QLabel(self.tr("Settings"), self)
+
+ # music folders
+ self.musicInThisPCGroup = SettingCardGroup(
+ self.tr("Music on this PC"), self.scrollWidget)
+ self.musicFolderCard = FolderListSettingCard(
+ cfg.musicFolders,
+ self.tr("Local music library"),
+ directory=QStandardPaths.writableLocation(QStandardPaths.MusicLocation),
+ parent=self.musicInThisPCGroup
+ )
+ self.downloadFolderCard = PushSettingCard(
+ self.tr('Choose folder'),
+ FIF.DOWNLOAD,
+ self.tr("Download directory"),
+ cfg.get(cfg.downloadFolder),
+ self.musicInThisPCGroup
+ )
+
+ # personalization
+ self.personalGroup = SettingCardGroup(self.tr('Personalization'), self.scrollWidget)
+ self.themeCard = OptionsSettingCard(
+ cfg.themeMode,
+ FIF.BRUSH,
+ self.tr('Application theme'),
+ self.tr("Change the appearance of your application"),
+ texts=[
+ self.tr('Light'), self.tr('Dark'),
+ self.tr('Use system setting')
+ ],
+ parent=self.personalGroup
+ )
+ self.themeColorCard=CustomColorSettingCard(
+ cfg.themeColor,
+ FIF.PALETTE,
+ self.tr('Theme color'),
+ self.tr('Change the theme color of you application'),
+ self.personalGroup
+ )
+ self.zoomCard = OptionsSettingCard(
+ cfg.dpiScale,
+ FIF.ZOOM,
+ self.tr("Interface zoom"),
+ self.tr("Change the size of widgets and fonts"),
+ texts=[
+ "100%", "125%", "150%", "175%", "200%",
+ self.tr("Use system setting")
+ ],
+ parent=self.personalGroup
+ )
+ self.languageCard = ComboBoxSettingCard(
+ cfg.language,
+ FIF.LANGUAGE,
+ self.tr('Language'),
+ self.tr('Set your preferred language for UI'),
+ texts=['简体中文', '繁體中文', 'English', self.tr('Use system setting')],
+ parent=self.personalGroup
+ )
+
+ # update software
+ self.updateSoftwareGroup = SettingCardGroup(self.tr("Software update"), self.scrollWidget)
+ self.updateOnStartUpCard = SwitchSettingCard(
+ FIF.UPDATE,
+ self.tr('Check for updates when the application starts'),
+ self.tr('The new version will be more stable and have more features'),
+ configItem=cfg.checkUpdateAtStartUp,
+ parent=self.updateSoftwareGroup
+ )
+
+ # application
+ self.aboutGroup = SettingCardGroup(self.tr('About'), self.scrollWidget)
+ self.helpCard = HyperlinkCard(
+ HELP_URL,
+ self.tr('Open help page'),
+ FIF.HELP,
+ self.tr('Help'),
+ self.tr('Discover new features and learn useful tips about PyQt-Fluent-Widgets'),
+ self.aboutGroup
+ )
+ self.feedbackCard = PrimaryPushSettingCard(
+ self.tr('Provide feedback'),
+ FIF.FEEDBACK,
+ self.tr('Provide feedback'),
+ self.tr('Help us improve PyQt-Fluent-Widgets by providing feedback'),
+ self.aboutGroup
+ )
+ self.aboutCard = PrimaryPushSettingCard(
+ self.tr('Check update'),
+ FIF.INFO,
+ self.tr('About'),
+ '© ' + self.tr('Copyright') + f" {YEAR}, {AUTHOR}. " +
+ self.tr('Version') + f" {VERSION[1:]}",
+ self.aboutGroup
+ )
+
+ self.__initWidget()
+
+ def __initWidget(self):
+ self.resize(1000, 800)
+ self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.setViewportMargins(0, 80, 0, 20)
+ self.setWidget(self.scrollWidget)
+ self.setWidgetResizable(True)
+
+ # initialize style sheet
+ self.__setQss(cfg.theme)
+
+ # initialize layout
+ self.__initLayout()
+ self.__connectSignalToSlot()
+
+ def __initLayout(self):
+ self.settingLabel.move(36, 30)
+
+ # add cards to group
+ self.musicInThisPCGroup.addSettingCard(self.musicFolderCard)
+ self.musicInThisPCGroup.addSettingCard(self.downloadFolderCard)
+
+ self.personalGroup.addSettingCard(self.themeCard)
+ self.personalGroup.addSettingCard(self.themeColorCard)
+ self.personalGroup.addSettingCard(self.zoomCard)
+ self.personalGroup.addSettingCard(self.languageCard)
+
+ self.updateSoftwareGroup.addSettingCard(self.updateOnStartUpCard)
+
+ self.aboutGroup.addSettingCard(self.helpCard)
+ self.aboutGroup.addSettingCard(self.feedbackCard)
+ self.aboutGroup.addSettingCard(self.aboutCard)
+
+ # add setting card group to layout
+ self.expandLayout.setSpacing(28)
+ self.expandLayout.setContentsMargins(36, 10, 36, 0)
+ self.expandLayout.addWidget(self.musicInThisPCGroup)
+ self.expandLayout.addWidget(self.personalGroup)
+ self.expandLayout.addWidget(self.updateSoftwareGroup)
+ self.expandLayout.addWidget(self.aboutGroup)
+
+ def __setQss(self, theme: Theme):
+ """ set style sheet """
+ self.scrollWidget.setObjectName('scrollWidget')
+ self.settingLabel.setObjectName('settingLabel')
+
+ theme = 'dark' if theme == Theme.DARK else 'light'
+ with open(f'app/resource/qss/{theme}/setting_interface.qss', encoding='utf-8') as f:
+ self.setStyleSheet(f.read())
+
+ def __showRestartTooltip(self):
+ """ show restart tooltip """
+ ToastToolTip.warn(
+ self.tr('Configuration updated successfully'),
+ self.tr('Configuration takes effect after restart'),
+ self.window()
+ )
+
+ def __onDownloadFolderCardClicked(self):
+ """ download folder card clicked slot """
+ folder = QFileDialog.getExistingDirectory(
+ self, self.tr("Choose folder"), "./")
+ if not folder or cfg.get(cfg.downloadFolder) == folder:
+ return
+
+ cfg.set(cfg.downloadFolder, folder)
+ self.downloadFolderCard.setContent(folder)
+
+ def __onThemeChanged(self, theme: Theme):
+ """ theme changed slot """
+ # change the theme of qfluentwidgets
+ setTheme(theme)
+
+ # chang the theme of setting interface
+ self.__setQss(theme)
+
+ def __connectSignalToSlot(self):
+ """ connect signal to slot """
+ cfg.appRestartSig.connect(self.__showRestartTooltip)
+ cfg.themeChanged.connect(self.__onThemeChanged)
+
+ # music in the pc
+ self.musicFolderCard.folderChanged.connect(
+ self.musicFoldersChanged)
+ self.downloadFolderCard.clicked.connect(
+ self.__onDownloadFolderCardClicked)
+
+ # personalization
+ self.themeColorCard.colorChanged.connect(setThemeColor)
+
+ # about
+ self.aboutCard.clicked.connect(self.checkUpdateSig)
+ self.feedbackCard.clicked.connect(
+ lambda: QDesktopServices.openUrl(QUrl(FEEDBACK_URL)))
diff --git a/examples/gallery/app/view/title_bar.py b/examples/gallery/app/view/title_bar.py
new file mode 100644
index 0000000000000000000000000000000000000000..e661a040075feb0c555ca8321d664bb25c201a9e
--- /dev/null
+++ b/examples/gallery/app/view/title_bar.py
@@ -0,0 +1,31 @@
+# coding: utf-8
+from PyQt5.QtCore import Qt
+from PyQt5.QtGui import QIcon
+from PyQt5.QtWidgets import QLabel
+from qframelesswindow import TitleBar
+
+
+class CustomTitleBar(TitleBar):
+ """ Title bar with icon and title """
+
+ def __init__(self, parent):
+ super().__init__(parent)
+ # add window icon
+ self.iconLabel = QLabel(self)
+ self.iconLabel.setFixedSize(18, 18)
+ self.hBoxLayout.insertSpacing(0, 10)
+ self.hBoxLayout.insertWidget(1, self.iconLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
+ self.window().windowIconChanged.connect(self.setIcon)
+
+ # add title label
+ self.titleLabel = QLabel(self)
+ self.hBoxLayout.insertWidget(2, self.titleLabel, 0, Qt.AlignLeft | Qt.AlignBottom)
+ self.titleLabel.setObjectName('titleLabel')
+ self.window().windowTitleChanged.connect(self.setTitle)
+
+ def setTitle(self, title):
+ self.titleLabel.setText(title)
+ self.titleLabel.adjustSize()
+
+ def setIcon(self, icon):
+ self.iconLabel.setPixmap(QIcon(icon).pixmap(18, 18))
diff --git a/examples/gallery/demo.py b/examples/gallery/demo.py
new file mode 100644
index 0000000000000000000000000000000000000000..51f8c3acf5d61178f1af3925a3b769799b2306ec
--- /dev/null
+++ b/examples/gallery/demo.py
@@ -0,0 +1,42 @@
+# coding:utf-8
+import os
+import sys
+
+from PyQt5.QtCore import Qt, QLocale, QTranslator
+from PyQt5.QtWidgets import QApplication
+
+from app.common.config import cfg, Language
+from app.view.main_window import MainWindow
+
+
+# enable dpi scale
+if cfg.get(cfg.dpiScale) == "Auto":
+ QApplication.setHighDpiScaleFactorRoundingPolicy(
+ Qt.HighDpiScaleFactorRoundingPolicy.PassThrough)
+ QApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
+else:
+ os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"
+ os.environ["QT_SCALE_FACTOR"] = str(cfg.get(cfg.dpiScale))
+
+QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)
+
+# create application
+app = QApplication(sys.argv)
+app.setAttribute(Qt.AA_DontCreateNativeWidgetSiblings)
+
+# internationalization
+translator = QTranslator()
+language = cfg.get(cfg.language)
+
+if language == Language.AUTO:
+ translator.load(QLocale.system(), "app/resource/i18n/qfluentwidgets_")
+elif language != Language.ENGLISH:
+ translator.load(f"app/resource/i18n/qfluentwidgets_{language.value}.qm")
+
+app.installTranslator(translator)
+
+# create main window
+w = MainWindow()
+w.show()
+
+app.exec_()
\ No newline at end of file
diff --git a/qfluentwidgets/common/config.py b/qfluentwidgets/common/config.py
index 093255787c120716b9f57e94375297f36543bc2e..5e8d22935791ac23c1826290fae17adb9c313a28 100644
--- a/qfluentwidgets/common/config.py
+++ b/qfluentwidgets/common/config.py
@@ -155,9 +155,11 @@ class ColorSerializer(ConfigSerializer):
return QColor(value)
-class ConfigItem:
+class ConfigItem(QObject):
""" Config item """
+ valueChanged = pyqtSignal(object)
+
def __init__(self, group, name, default, validator=None, serializer=None, restart=False):
"""
Parameters
@@ -180,6 +182,7 @@ class ConfigItem:
restart: bool
whether to restart the application after updating value
"""
+ super().__init__()
self.group = group
self.name = name
self.validator = validator or ConfigValidator()
@@ -196,7 +199,11 @@ class ConfigItem:
@value.setter
def value(self, v):
- self.__value = self.validator.correct(v)
+ v = self.validator.correct(v)
+ ov = self.__value
+ self.__value = v
+ if ov != v:
+ self.valueChanged.emit(v)
@property
def key(self):
diff --git a/qfluentwidgets/components/settings/expand_setting_card.py b/qfluentwidgets/components/settings/expand_setting_card.py
index 1b3182479e8f2abff320d5d0335f690f31954b36..6e99530b1ef5ac824d0b47e319c25dfec8a0302a 100644
--- a/qfluentwidgets/components/settings/expand_setting_card.py
+++ b/qfluentwidgets/components/settings/expand_setting_card.py
@@ -199,6 +199,10 @@ class ExpandSettingCard(QFrame):
if self.view.isVisible():
self.resize(self.width(), h + self.card.height())
+ def setValue(self, value):
+ """ set the value of config item """
+ pass
+
class GroupSeparator(QWidget):
diff --git a/qfluentwidgets/components/settings/options_setting_card.py b/qfluentwidgets/components/settings/options_setting_card.py
index ba0451745865aac8a9cd34c833f5a56eee4c7bfa..5785a3b9a3f30b0f950edbf2f3435dd0ce44072e 100644
--- a/qfluentwidgets/components/settings/options_setting_card.py
+++ b/qfluentwidgets/components/settings/options_setting_card.py
@@ -56,7 +56,8 @@ class OptionsSettingCard(ExpandSettingCard):
button.setProperty(self.configName, option)
self._adjustViewSize()
- self.setSelected(qconfig.get(self.configItem))
+ self.setValue(qconfig.get(self.configItem))
+ configItem.valueChanged.connect(self.setValue)
self.buttonGroup.buttonClicked.connect(self.__onButtonClicked)
def __onButtonClicked(self, button: RadioButton):
@@ -71,11 +72,14 @@ class OptionsSettingCard(ExpandSettingCard):
self.choiceLabel.adjustSize()
self.optionChanged.emit(self.configItem)
- def setSelected(self, value):
+ def setValue(self, value):
""" select button according to the value """
+ qconfig.set(self.configItem, value)
+
for button in self.viewLayout.widgets:
isChecked = button.property(self.configName) == value
button.setChecked(isChecked)
+
if isChecked:
self.choiceLabel.setText(button.text())
self.choiceLabel.adjustSize()
diff --git a/qfluentwidgets/components/settings/setting_card.py b/qfluentwidgets/components/settings/setting_card.py
index 99c9f043415e4500ec97479c103db866ee6e2fb2..eb9e9e9f5fc51fdc7a80b7352a64ad546a9d2ac7 100644
--- a/qfluentwidgets/components/settings/setting_card.py
+++ b/qfluentwidgets/components/settings/setting_card.py
@@ -1,8 +1,8 @@
# coding:utf-8
from typing import Union
-from PyQt5.QtCore import QUrl, Qt, pyqtSignal
-from PyQt5.QtGui import QColor, QDesktopServices, QIcon, QPainter
+from PyQt5.QtCore import Qt, pyqtSignal
+from PyQt5.QtGui import QColor, QIcon, QPainter
from PyQt5.QtWidgets import (QFrame, QHBoxLayout, QLabel, QToolButton,
QVBoxLayout, QPushButton)
@@ -13,7 +13,7 @@ from ..widgets.slider import Slider
from ..widgets.icon_widget import IconWidget
from ..widgets.button import HyperlinkButton
from ...common.style_sheet import setStyleSheet
-from ...common.config import qconfig, isDarkTheme
+from ...common.config import qconfig, isDarkTheme, ConfigItem
from ...common.icon import FluentIconBase
@@ -79,13 +79,18 @@ class SettingCard(QFrame):
self.contentLabel.setText(content)
self.contentLabel.setVisible(bool(content))
+ def setValue(self, value):
+ """ set the value of config item """
+ pass
+
class SwitchSettingCard(SettingCard):
""" Setting card with switch button """
checkedChanged = pyqtSignal(bool)
- def __init__(self, icon: Union[str, QIcon, FluentIconBase], title, content=None, configItem=None, parent=None):
+ def __init__(self, icon: Union[str, QIcon, FluentIconBase], title, content=None,
+ configItem: ConfigItem = None, parent=None):
"""
Parameters
----------
@@ -110,7 +115,8 @@ class SwitchSettingCard(SettingCard):
self.tr('Off'), self, IndicatorPosition.RIGHT)
if configItem:
- self.setChecked(qconfig.get(configItem))
+ self.setValue(qconfig.get(configItem))
+ configItem.valueChanged.connect(self.setValue)
# add switch button to layout
self.hBoxLayout.addWidget(self.switchButton, 0, Qt.AlignRight)
@@ -120,11 +126,10 @@ class SwitchSettingCard(SettingCard):
def __onCheckedChanged(self, isChecked: bool):
""" switch button checked state changed slot """
- self.setChecked(isChecked)
+ self.setValue(isChecked)
self.checkedChanged.emit(isChecked)
- def setChecked(self, isChecked: bool):
- """ set switch button checked state """
+ def setValue(self, isChecked: bool):
if self.configItem:
qconfig.set(self.configItem, isChecked)
@@ -177,14 +182,18 @@ class RangeSettingCard(SettingCard):
self.hBoxLayout.addSpacing(16)
self.valueLabel.setObjectName('valueLabel')
+ configItem.valueChanged.connect(self.setValue)
self.slider.valueChanged.connect(self.__onValueChanged)
def __onValueChanged(self, value: int):
""" slider value changed slot """
+ self.setValue(value)
+ self.valueChanged.emit(value)
+
+ def setValue(self, value):
qconfig.set(self.configItem, value)
self.valueLabel.setNum(value)
self.valueLabel.adjustSize()
- self.valueChanged.emit(value)
class PushSettingCard(SettingCard):
@@ -333,11 +342,16 @@ class ColorSettingCard(SettingCard):
self.hBoxLayout.addWidget(self.colorPicker, 0, Qt.AlignRight)
self.hBoxLayout.addSpacing(16)
self.colorPicker.colorChanged.connect(self.__onColorChanged)
+ configItem.valueChanged.connect(self.setValue)
def __onColorChanged(self, color: QColor):
qconfig.set(self.configItem, color)
self.colorChanged.emit(color)
+ def setValue(self, color: QColor):
+ self.colorPicker.setColor(color)
+ qconfig.set(self.configItem, color)
+
class ComboBoxSettingCard(SettingCard):
""" Setting card with a combo box """
@@ -375,6 +389,11 @@ class ComboBoxSettingCard(SettingCard):
self.comboBox.addItems(texts)
self.comboBox.setCurrentText(self.optionToText[qconfig.get(configItem)])
self.comboBox.currentTextChanged.connect(self._onCurrentTextChanged)
+ configItem.valueChanged.connect(self.setValue)
def _onCurrentTextChanged(self, text):
+ qconfig.set(self.configItem, self.textToOption[text])
+
+ def setValue(self, text):
+ self.comboBox.setCurrentText(text)
qconfig.set(self.configItem, self.textToOption[text])
\ No newline at end of file
diff --git a/qfluentwidgets/components/widgets/__init__.py b/qfluentwidgets/components/widgets/__init__.py
index 47852bcc239bbcfc3249c35a03c17286942659c8..3fc5973ca2aa132faaaa42625b91d7ccfc49841a 100644
--- a/qfluentwidgets/components/widgets/__init__.py
+++ b/qfluentwidgets/components/widgets/__init__.py
@@ -8,4 +8,5 @@ from .scroll_area import ScrollArea, SmoothMode, SmoothScrollArea, SmoothScrollB
from .tool_tip import ToolTip, ToolTipFilter
from .button import PrimaryPushButton, PushButton, RadioButton, HyperlinkButton, ToolButton
from .line_edit import LineEdit
-from .check_box import CheckBox
\ No newline at end of file
+from .check_box import CheckBox
+from .icon_widget import IconWidget
\ No newline at end of file
diff --git a/qfluentwidgets/components/widgets/line_edit.py b/qfluentwidgets/components/widgets/line_edit.py
index 8bc2ec35785956ee7ce2dafc7ca445333595a358..8fed341e6c96d4c49470a53705b2568d844d88eb 100644
--- a/qfluentwidgets/components/widgets/line_edit.py
+++ b/qfluentwidgets/components/widgets/line_edit.py
@@ -16,6 +16,7 @@ class LineEdit(QLineEdit):
setStyleSheet(self, 'line_edit')
self.setFixedHeight(33)
+ self.setAttribute(Qt.WA_MacShowFocusRect, False)
self.clearButton = QToolButton(self)
self.setTextMargins(0, 0, 33, 0)
diff --git a/qfluentwidgets/components/widgets/menu.py b/qfluentwidgets/components/widgets/menu.py
index b1ba3527558fb02c0b841116aaa549bfaf0fd0ea..383c532b0841f12579275e513169c22aa96af9d5 100644
--- a/qfluentwidgets/components/widgets/menu.py
+++ b/qfluentwidgets/components/widgets/menu.py
@@ -563,8 +563,8 @@ class RoundMenu(QWidget):
rect = QApplication.screenAt(QCursor.pos()).availableGeometry()
w, h = self.width() + 5, self.height() + 5
- pos.setX(max(10, min(pos.x() - self.layout().contentsMargins().left(), rect.right() - w)))
- pos.setY(max(10, min(pos.y() - 4, rect.bottom() - h)))
+ pos.setX(min(pos.x() - self.layout().contentsMargins().left(), rect.right() - w))
+ pos.setY(min(pos.y() - 4, rect.bottom() - h))
if ani:
self.ani.setStartValue(pos-QPoint(0, int(h/2)))
diff --git a/qfluentwidgets/components/widgets/switch_button.py b/qfluentwidgets/components/widgets/switch_button.py
index 68251b80144b4f5f473ef8c5c086dfccf042aa4a..9489c2ffb2ac299f8e0646ce25e4f3996bc51685 100644
--- a/qfluentwidgets/components/widgets/switch_button.py
+++ b/qfluentwidgets/components/widgets/switch_button.py
@@ -52,8 +52,9 @@ class Indicator(QToolButton):
return
super().setChecked(isChecked)
+ self.sliderRadius = (self.height()-2*self.padding)//2
self.sliderEndX = self.width()-2*self.sliderRadius - \
- self.padding if self.isChecked() else self.padding
+ self.padding if isChecked else self.padding
self.timer.start(5)
def mouseReleaseEvent(self, e):
diff --git a/qfluentwidgets/components/widgets/tool_tip.py b/qfluentwidgets/components/widgets/tool_tip.py
index 15f1bfe749f6533208dc8fbf996782e821faafc5..3f3f10082a3ff37afa64efc34850151a13423952 100644
--- a/qfluentwidgets/components/widgets/tool_tip.py
+++ b/qfluentwidgets/components/widgets/tool_tip.py
@@ -93,7 +93,7 @@ class ToolTip(QFrame):
# adjust postion to prevent tooltips from appearing outside the screen
rect = QApplication.screenAt(QCursor.pos()).availableGeometry()
- x = min(max(0, x), rect.width() - self.width() - 4)
+ x = min(max(0, x) if QCursor().pos().x() >= 0 else x, rect.width() - self.width() - 4)
y = min(max(0, y), rect.height() - self.height() - 4)
self.move(x, y)