RinUI 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- RinUI/__init__.py +4 -4
- RinUI/assets/fonts/FluentSystemIcons-Index.js +5255 -5255
- RinUI/components/Base.qml +78 -78
- RinUI/components/BasicInput/Button.qml +146 -146
- RinUI/components/BasicInput/CheckBox.qml +98 -98
- RinUI/components/BasicInput/ComboBox.qml +159 -159
- RinUI/components/BasicInput/DropDownButton.qml +20 -20
- RinUI/components/BasicInput/Hyperlink.qml +17 -17
- RinUI/components/BasicInput/PillButton.qml +10 -10
- RinUI/components/BasicInput/RadioButton.qml +94 -94
- RinUI/components/BasicInput/RoundButton.qml +26 -26
- RinUI/components/BasicInput/Slider.qml +212 -212
- RinUI/components/BasicInput/Switch.qml +101 -101
- RinUI/components/BasicInput/ToggleButton.qml +10 -10
- RinUI/components/BasicInput/ToolButton.qml +30 -30
- RinUI/components/ContextMenu.qml +183 -183
- RinUI/components/DateAndTime/DatePicker.qml +142 -140
- RinUI/components/DateAndTime/PickerView.qml +223 -223
- RinUI/components/DateAndTime/TimePicker.qml +114 -114
- RinUI/components/DialogsAndFlyouts/Dialog.qml +106 -106
- RinUI/components/DialogsAndFlyouts/DialogButtonBox.qml +47 -47
- RinUI/components/DialogsAndFlyouts/Flyout.qml +87 -87
- RinUI/components/DialogsAndFlyouts/Popup.qml +110 -106
- RinUI/components/FocusIndicator.qml +33 -33
- RinUI/components/IconWidget.qml +52 -52
- RinUI/components/Indicator.qml +89 -89
- RinUI/components/Layout/Expander.qml +159 -159
- RinUI/components/Layout/SettingExpander.qml +66 -66
- RinUI/components/Layout/SettingItem.qml +70 -70
- RinUI/components/ListAndCollections/Clip.qml +21 -21
- RinUI/components/ListAndCollections/Frame.qml +43 -43
- RinUI/components/ListAndCollections/ListView.qml +104 -104
- RinUI/components/ListAndCollections/ListViewDelegate.qml +82 -82
- RinUI/components/ListAndCollections/SettingCard.qml +72 -72
- RinUI/components/ListAndCollections/TableView.qml +81 -81
- RinUI/components/ListAndCollections/TableViewDelegate.qml +88 -88
- RinUI/components/Media/Avatar.qml +82 -82
- RinUI/components/MenusAndToolbars/Menu.qml +150 -150
- RinUI/components/MenusAndToolbars/MenuBar.qml +42 -42
- RinUI/components/MenusAndToolbars/MenuItem.qml +131 -131
- RinUI/components/MenusAndToolbars/MenuItemGroup.qml +43 -43
- RinUI/components/MenusAndToolbars/MenuSeparator.qml +13 -13
- RinUI/components/MenusAndToolbars/TextInputMenu.qml +37 -37
- RinUI/components/MenusAndToolbars/ToolSeparator.qml +16 -16
- RinUI/components/Navigation/ErrorPage.qml +48 -48
- RinUI/components/Navigation/NavigationBar.qml +179 -179
- RinUI/components/Navigation/NavigationItem.qml +193 -193
- RinUI/components/Navigation/NavigationSubItem.qml +103 -103
- RinUI/components/Navigation/NavigationView.qml +228 -227
- RinUI/components/Navigation/Segmented.qml +16 -16
- RinUI/components/Navigation/SegmentedItem.qml +107 -107
- RinUI/components/Navigation/SelectorBar.qml +12 -12
- RinUI/components/Navigation/SelectorBarItem.qml +88 -88
- RinUI/components/ScrollBar.qml +204 -204
- RinUI/components/ScrollView.qml +12 -12
- RinUI/components/Shadow.qml +47 -47
- RinUI/components/StatusAndInfo/InfoBadge.qml +77 -77
- RinUI/components/StatusAndInfo/InfoBar.qml +256 -251
- RinUI/components/StatusAndInfo/ProgressBar.qml +126 -126
- RinUI/components/StatusAndInfo/ProgressRing.qml +149 -0
- RinUI/components/StatusAndInfo/Toast.qml +236 -236
- RinUI/components/StatusAndInfo/ToolTip.qml +93 -93
- RinUI/components/Text/SpinBox.qml +150 -133
- RinUI/components/Text/Text.qml +44 -44
- RinUI/components/Text/TextArea.qml +117 -117
- RinUI/components/Text/TextField.qml +113 -113
- RinUI/components/Text/TextInput.qml +47 -47
- RinUI/components/qmldir +80 -80
- RinUI/core/__init__.py +4 -4
- RinUI/core/config.py +129 -129
- RinUI/core/launcher.py +129 -129
- RinUI/core/theme.py +339 -339
- RinUI/core/translator.py +25 -25
- RinUI/hooks/__init__.py +3 -3
- RinUI/hooks/hook-RinUI.py +3 -3
- RinUI/qmldir +108 -104
- RinUI/themes/Appearance.qml +36 -0
- RinUI/themes/Colors.qml +36 -0
- RinUI/themes/dark.qml +145 -145
- RinUI/themes/light.qml +145 -145
- RinUI/themes/qmldir +9 -6
- RinUI/themes/theme.qml +151 -149
- RinUI/themes/utils.qml +37 -37
- RinUI/utils/Animation.qml +12 -12
- RinUI/utils/FloatLayer.qml +132 -123
- RinUI/utils/FontIconLoader.qml +13 -13
- RinUI/utils/Position.qml +19 -19
- RinUI/utils/Severity.qml +13 -13
- RinUI/utils/Typography.qml +17 -17
- RinUI/utils/qmldir +4 -4
- RinUI/windows/CtrlBtn.qml +118 -118
- RinUI/windows/FluentPage.qml +92 -92
- RinUI/windows/FluentWindow.qml +31 -30
- RinUI/windows/FluentWindowBase.qml +158 -158
- RinUI/windows/TitleBar.qml +135 -135
- RinUI/windows/qmldir +7 -7
- RinUI/windows/window/ApplicationWindow.qml +8 -8
- RinUI/windows/window/Window.qml +118 -118
- {rinui-0.1.0.data → rinui-0.1.1.data}/data/LICENSE +21 -21
- {rinui-0.1.0.data → rinui-0.1.1.data}/data/README.md +100 -100
- {rinui-0.1.0.dist-info → rinui-0.1.1.dist-info}/METADATA +116 -115
- rinui-0.1.1.dist-info/RECORD +112 -0
- {rinui-0.1.0.dist-info → rinui-0.1.1.dist-info}/WHEEL +1 -1
- {rinui-0.1.0.dist-info → rinui-0.1.1.dist-info/licenses}/LICENSE +21 -21
- RinUI/__pycache__/__init__.cpython-38.pyc +0 -0
- RinUI/config/rin_ui.json +0 -8
- RinUI/core/__pycache__/__init__.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/config.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/launcher.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/theme.cpython-38.pyc +0 -0
- RinUI/core/__pycache__/translator.cpython-38.pyc +0 -0
- rinui-0.1.0.dist-info/RECORD +0 -116
- {rinui-0.1.0.dist-info → rinui-0.1.1.dist-info}/entry_points.txt +0 -0
- {rinui-0.1.0.dist-info → rinui-0.1.1.dist-info}/top_level.txt +0 -0
RinUI/core/config.py
CHANGED
@@ -1,129 +1,129 @@
|
|
1
|
-
import os
|
2
|
-
import json
|
3
|
-
import platform
|
4
|
-
import sys
|
5
|
-
from PySide6.QtCore import QLocale
|
6
|
-
from enum import Enum
|
7
|
-
|
8
|
-
|
9
|
-
def is_win11():
|
10
|
-
if is_windows():
|
11
|
-
if platform.release() >= '10' and int(platform.version().split('.')[2]) >= 22000:
|
12
|
-
return True
|
13
|
-
return False
|
14
|
-
|
15
|
-
|
16
|
-
def is_win10():
|
17
|
-
if is_windows():
|
18
|
-
if platform.release() >= '10' and int(platform.version().split('.')[2]) >= 19000:
|
19
|
-
return True
|
20
|
-
return False
|
21
|
-
|
22
|
-
|
23
|
-
def is_windows():
|
24
|
-
return platform.system() == 'Windows'
|
25
|
-
|
26
|
-
|
27
|
-
def resource_path(relative_path):
|
28
|
-
"""兼容 PyInstaller 打包和开发环境的路径"""
|
29
|
-
if hasattr(sys, '_MEIPASS'):
|
30
|
-
return os.path.join(sys._MEIPASS, relative_path)
|
31
|
-
return os.path.abspath(relative_path)
|
32
|
-
|
33
|
-
|
34
|
-
rinui_core_path = os.path.abspath(os.path.dirname(__file__)) # RinUI/core 目录
|
35
|
-
|
36
|
-
BASE_DIR = os.path.abspath(os.getcwd())
|
37
|
-
PATH = os.path.join(BASE_DIR, "RinUI/config")
|
38
|
-
RINUI_PATH = resource_path(os.path.join(rinui_core_path, "../../")) # 使用 resource_path 处理路径
|
39
|
-
DEFAULT_CONFIG = {
|
40
|
-
"theme": {
|
41
|
-
"current_theme": "Auto",
|
42
|
-
},
|
43
|
-
"win10_feat": {
|
44
|
-
"backdrop_light": 0xA6FFFFFF,
|
45
|
-
"backdrop_dark": 0xA6000000,
|
46
|
-
},
|
47
|
-
"theme_color": "#605ed2",
|
48
|
-
"backdrop_effect": "mica" if is_win11() else "acrylic" if is_win10() else "none",
|
49
|
-
}
|
50
|
-
|
51
|
-
|
52
|
-
class Theme(Enum):
|
53
|
-
Auto = "Auto"
|
54
|
-
Dark = "Dark"
|
55
|
-
Light = "Light"
|
56
|
-
|
57
|
-
|
58
|
-
class BackdropEffect(Enum):
|
59
|
-
None_ = "none"
|
60
|
-
Acrylic = "acrylic"
|
61
|
-
Mica = "mica"
|
62
|
-
Tabbed = "tabbed"
|
63
|
-
|
64
|
-
|
65
|
-
class ConfigManager:
|
66
|
-
def __init__(self, path, filename):
|
67
|
-
"""
|
68
|
-
Json Config Manager
|
69
|
-
:param path: json config file path
|
70
|
-
:param filename: json config file name (eg: rin_ui.json)
|
71
|
-
"""
|
72
|
-
self.path = path
|
73
|
-
self.filename = filename
|
74
|
-
self.config = {}
|
75
|
-
self.full_path = os.path.join(self.path, self.filename)
|
76
|
-
|
77
|
-
def load_config(self, default_config):
|
78
|
-
if default_config is None:
|
79
|
-
print('Warning: "default_config" is None, use empty config instead.')
|
80
|
-
default_config = {}
|
81
|
-
# 如果文件存在,加载配置
|
82
|
-
if os.path.exists(self.full_path):
|
83
|
-
with open(self.full_path, 'r', encoding='utf-8') as f:
|
84
|
-
self.config = json.load(f)
|
85
|
-
else:
|
86
|
-
self.config = default_config # 如果文件不存在,使用默认配置
|
87
|
-
self.save_config()
|
88
|
-
|
89
|
-
def update_config(self): # 更新配置
|
90
|
-
try:
|
91
|
-
with open(self.full_path, 'r', encoding='utf-8') as f:
|
92
|
-
self.config = json.load(f)
|
93
|
-
except Exception as e:
|
94
|
-
print(f'Error: {e}')
|
95
|
-
self.config = {}
|
96
|
-
|
97
|
-
def upload_config(self, key=str or list, value=None):
|
98
|
-
if type(key) is str:
|
99
|
-
self.config[key] = value
|
100
|
-
elif type(key) is list:
|
101
|
-
for k in key:
|
102
|
-
self.config[k] = value
|
103
|
-
else:
|
104
|
-
raise TypeError('key must be str or list')
|
105
|
-
self.save_config()
|
106
|
-
|
107
|
-
def save_config(self):
|
108
|
-
try:
|
109
|
-
# 确保配置文件目录存在
|
110
|
-
if not os.path.exists(self.path):
|
111
|
-
os.makedirs(self.path)
|
112
|
-
with open(self.full_path, 'w', encoding='utf-8') as f:
|
113
|
-
json.dump(self.config, f, ensure_ascii=False, indent=4)
|
114
|
-
except Exception as e:
|
115
|
-
print(f'Error: {e}')
|
116
|
-
|
117
|
-
def __getitem__(self, key):
|
118
|
-
return self.config.get(key)
|
119
|
-
|
120
|
-
def __setitem__(self, key, value):
|
121
|
-
self.config[key] = value
|
122
|
-
self.save_config()
|
123
|
-
|
124
|
-
def __repr__(self):
|
125
|
-
return json.dumps(self.config, ensure_ascii=False, indent=4)
|
126
|
-
|
127
|
-
|
128
|
-
RinConfig = ConfigManager(path=PATH, filename='rin_ui.json')
|
129
|
-
RinConfig.load_config(DEFAULT_CONFIG) # 加载配置
|
1
|
+
import os
|
2
|
+
import json
|
3
|
+
import platform
|
4
|
+
import sys
|
5
|
+
from PySide6.QtCore import QLocale
|
6
|
+
from enum import Enum
|
7
|
+
|
8
|
+
|
9
|
+
def is_win11():
|
10
|
+
if is_windows():
|
11
|
+
if platform.release() >= '10' and int(platform.version().split('.')[2]) >= 22000:
|
12
|
+
return True
|
13
|
+
return False
|
14
|
+
|
15
|
+
|
16
|
+
def is_win10():
|
17
|
+
if is_windows():
|
18
|
+
if platform.release() >= '10' and int(platform.version().split('.')[2]) >= 19000:
|
19
|
+
return True
|
20
|
+
return False
|
21
|
+
|
22
|
+
|
23
|
+
def is_windows():
|
24
|
+
return platform.system() == 'Windows'
|
25
|
+
|
26
|
+
|
27
|
+
def resource_path(relative_path):
|
28
|
+
"""兼容 PyInstaller 打包和开发环境的路径"""
|
29
|
+
if hasattr(sys, '_MEIPASS'):
|
30
|
+
return os.path.join(sys._MEIPASS, relative_path)
|
31
|
+
return os.path.abspath(relative_path)
|
32
|
+
|
33
|
+
|
34
|
+
rinui_core_path = os.path.abspath(os.path.dirname(__file__)) # RinUI/core 目录
|
35
|
+
|
36
|
+
BASE_DIR = os.path.abspath(os.getcwd())
|
37
|
+
PATH = os.path.join(BASE_DIR, "RinUI/config")
|
38
|
+
RINUI_PATH = resource_path(os.path.join(rinui_core_path, "../../")) # 使用 resource_path 处理路径
|
39
|
+
DEFAULT_CONFIG = {
|
40
|
+
"theme": {
|
41
|
+
"current_theme": "Auto",
|
42
|
+
},
|
43
|
+
"win10_feat": {
|
44
|
+
"backdrop_light": 0xA6FFFFFF,
|
45
|
+
"backdrop_dark": 0xA6000000,
|
46
|
+
},
|
47
|
+
"theme_color": "#605ed2",
|
48
|
+
"backdrop_effect": "mica" if is_win11() else "acrylic" if is_win10() else "none",
|
49
|
+
}
|
50
|
+
|
51
|
+
|
52
|
+
class Theme(Enum):
|
53
|
+
Auto = "Auto"
|
54
|
+
Dark = "Dark"
|
55
|
+
Light = "Light"
|
56
|
+
|
57
|
+
|
58
|
+
class BackdropEffect(Enum):
|
59
|
+
None_ = "none"
|
60
|
+
Acrylic = "acrylic"
|
61
|
+
Mica = "mica"
|
62
|
+
Tabbed = "tabbed"
|
63
|
+
|
64
|
+
|
65
|
+
class ConfigManager:
|
66
|
+
def __init__(self, path, filename):
|
67
|
+
"""
|
68
|
+
Json Config Manager
|
69
|
+
:param path: json config file path
|
70
|
+
:param filename: json config file name (eg: rin_ui.json)
|
71
|
+
"""
|
72
|
+
self.path = path
|
73
|
+
self.filename = filename
|
74
|
+
self.config = {}
|
75
|
+
self.full_path = os.path.join(self.path, self.filename)
|
76
|
+
|
77
|
+
def load_config(self, default_config):
|
78
|
+
if default_config is None:
|
79
|
+
print('Warning: "default_config" is None, use empty config instead.')
|
80
|
+
default_config = {}
|
81
|
+
# 如果文件存在,加载配置
|
82
|
+
if os.path.exists(self.full_path):
|
83
|
+
with open(self.full_path, 'r', encoding='utf-8') as f:
|
84
|
+
self.config = json.load(f)
|
85
|
+
else:
|
86
|
+
self.config = default_config # 如果文件不存在,使用默认配置
|
87
|
+
self.save_config()
|
88
|
+
|
89
|
+
def update_config(self): # 更新配置
|
90
|
+
try:
|
91
|
+
with open(self.full_path, 'r', encoding='utf-8') as f:
|
92
|
+
self.config = json.load(f)
|
93
|
+
except Exception as e:
|
94
|
+
print(f'Error: {e}')
|
95
|
+
self.config = {}
|
96
|
+
|
97
|
+
def upload_config(self, key=str or list, value=None):
|
98
|
+
if type(key) is str:
|
99
|
+
self.config[key] = value
|
100
|
+
elif type(key) is list:
|
101
|
+
for k in key:
|
102
|
+
self.config[k] = value
|
103
|
+
else:
|
104
|
+
raise TypeError('key must be str or list')
|
105
|
+
self.save_config()
|
106
|
+
|
107
|
+
def save_config(self):
|
108
|
+
try:
|
109
|
+
# 确保配置文件目录存在
|
110
|
+
if not os.path.exists(self.path):
|
111
|
+
os.makedirs(self.path)
|
112
|
+
with open(self.full_path, 'w', encoding='utf-8') as f:
|
113
|
+
json.dump(self.config, f, ensure_ascii=False, indent=4)
|
114
|
+
except Exception as e:
|
115
|
+
print(f'Error: {e}')
|
116
|
+
|
117
|
+
def __getitem__(self, key):
|
118
|
+
return self.config.get(key)
|
119
|
+
|
120
|
+
def __setitem__(self, key, value):
|
121
|
+
self.config[key] = value
|
122
|
+
self.save_config()
|
123
|
+
|
124
|
+
def __repr__(self):
|
125
|
+
return json.dumps(self.config, ensure_ascii=False, indent=4)
|
126
|
+
|
127
|
+
|
128
|
+
RinConfig = ConfigManager(path=PATH, filename='rin_ui.json')
|
129
|
+
RinConfig.load_config(DEFAULT_CONFIG) # 加载配置
|
RinUI/core/launcher.py
CHANGED
@@ -1,129 +1,129 @@
|
|
1
|
-
import os
|
2
|
-
import sys
|
3
|
-
|
4
|
-
from PySide6.QtCore import QCoreApplication, QUrl, QObject
|
5
|
-
from PySide6.QtGui import QIcon
|
6
|
-
from PySide6.QtWidgets import QApplication
|
7
|
-
from PySide6.QtQml import QQmlApplicationEngine
|
8
|
-
|
9
|
-
from .theme import ThemeManager
|
10
|
-
from .config import BackdropEffect, is_windows, Theme, RINUI_PATH, RinConfig
|
11
|
-
|
12
|
-
|
13
|
-
class RinUIWindow:
|
14
|
-
def __init__(self, qml_path: str):
|
15
|
-
"""
|
16
|
-
Create an application window with RinUI.
|
17
|
-
:param qml_path: str, QML file path (eg = "path/to/main.qml")
|
18
|
-
"""
|
19
|
-
super().__init__()
|
20
|
-
if hasattr(self, "_initialized") and self._initialized:
|
21
|
-
return
|
22
|
-
self._initialized = True
|
23
|
-
print("✨ RinUIWindow Initializing")
|
24
|
-
|
25
|
-
# 退出清理
|
26
|
-
app_instance = QCoreApplication.instance()
|
27
|
-
if not app_instance:
|
28
|
-
raise RuntimeError("QApplication must be created before RinUIWindow.")
|
29
|
-
|
30
|
-
self.engine = QQmlApplicationEngine()
|
31
|
-
self.theme_manager = ThemeManager()
|
32
|
-
self.qml_path = qml_path
|
33
|
-
self.autoSetWindowsEffect = True
|
34
|
-
|
35
|
-
app_instance.aboutToQuit.connect(self.theme_manager.clean_up)
|
36
|
-
self._setup_application()
|
37
|
-
self.print_startup_info()
|
38
|
-
|
39
|
-
def _setup_application(self) -> None:
|
40
|
-
"""Setup"""
|
41
|
-
# RInUI 模块
|
42
|
-
print(f"UI Module Path: {RINUI_PATH}")
|
43
|
-
|
44
|
-
if os.path.exists(RINUI_PATH):
|
45
|
-
self.engine.addImportPath(RINUI_PATH)
|
46
|
-
else:
|
47
|
-
raise FileNotFoundError(f"Cannot find RinUI module: {RINUI_PATH}")
|
48
|
-
|
49
|
-
# 主题管理器
|
50
|
-
self.engine.rootContext().setContextProperty("ThemeManager", self.theme_manager)
|
51
|
-
try:
|
52
|
-
self.engine.load(self.qml_path)
|
53
|
-
except Exception as e:
|
54
|
-
print(f"Cannot Load QML file: {e}")
|
55
|
-
|
56
|
-
if not self.engine.rootObjects():
|
57
|
-
raise RuntimeError(f"Error loading QML file: {self.qml_path}")
|
58
|
-
|
59
|
-
# 窗口设置
|
60
|
-
self.root_window = self.engine.rootObjects()[0]
|
61
|
-
|
62
|
-
self.theme_manager.set_window(self.root_window)
|
63
|
-
self._apply_windows_effects() if self.autoSetWindowsEffect else None
|
64
|
-
|
65
|
-
def setIcon(self, path: str) -> None:
|
66
|
-
"""
|
67
|
-
Sets the icon for the application.
|
68
|
-
:param path: str, icon file path (eg = "path/to/icon.png")
|
69
|
-
:return:
|
70
|
-
"""
|
71
|
-
app_instance = QApplication.instance()
|
72
|
-
if app_instance:
|
73
|
-
app_instance.setWindowIcon(QIcon(path)) # 设置应用程序图标
|
74
|
-
self.root_window.setProperty('icon', QUrl.fromLocalFile(path))
|
75
|
-
else:
|
76
|
-
raise RuntimeError("Cannot set icon before QApplication is created.")
|
77
|
-
|
78
|
-
def _apply_windows_effects(self) -> None:
|
79
|
-
"""
|
80
|
-
Apply Windows effects to the window.
|
81
|
-
:return:
|
82
|
-
"""
|
83
|
-
if sys.platform == "win32":
|
84
|
-
self.theme_manager.apply_backdrop_effect(self.theme_manager.get_backdrop_effect())
|
85
|
-
self.theme_manager.apply_window_effects()
|
86
|
-
|
87
|
-
# func名称遵循 Qt 命名规范
|
88
|
-
def setBackdropEffect(self, effect: BackdropEffect) -> None:
|
89
|
-
"""
|
90
|
-
Sets the backdrop effect for the window. (Only available on Windows)
|
91
|
-
:param effect: BackdropEffect, type of backdrop effect(Acrylic, Mica, Tabbed, None_)
|
92
|
-
:return:
|
93
|
-
"""
|
94
|
-
if not is_windows() and effect != BackdropEffect.None_:
|
95
|
-
raise OSError("Only can set backdrop effect on Windows platform.")
|
96
|
-
self.theme_manager.apply_backdrop_effect(effect.value)
|
97
|
-
|
98
|
-
def setTheme(self, theme: Theme) -> None:
|
99
|
-
"""
|
100
|
-
Sets the theme for the window.
|
101
|
-
:param theme: Theme, type of theme(Auto, Dark, Light)
|
102
|
-
:return:
|
103
|
-
"""
|
104
|
-
self.theme_manager.toggle_theme(theme.value)
|
105
|
-
|
106
|
-
def __getattr__(self, name) -> QObject:
|
107
|
-
"""获取 QML 窗口属性"""
|
108
|
-
try:
|
109
|
-
root = object.__getattribute__(self, "root_window")
|
110
|
-
return getattr(root, name)
|
111
|
-
except AttributeError:
|
112
|
-
raise AttributeError(f"\"RinUIWindow\" object has no attribute '{name}'")
|
113
|
-
|
114
|
-
def print_startup_info(self) -> None:
|
115
|
-
border = "=" * 40
|
116
|
-
print(f"\n{border}")
|
117
|
-
print("✨ RinUIWindow Loaded Successfully!")
|
118
|
-
print(f"QML File Path: {self.qml_path}")
|
119
|
-
print(f"Current Theme: {self.theme_manager.current_theme}")
|
120
|
-
print(f"Backdrop Effect: {self.theme_manager.get_backdrop_effect()}")
|
121
|
-
print(f"OS: {sys.platform}")
|
122
|
-
print(border + "\n")
|
123
|
-
|
124
|
-
|
125
|
-
if __name__ == "__main__":
|
126
|
-
# 新用法,应该更规范了捏
|
127
|
-
app = QApplication(sys.argv)
|
128
|
-
example = RinUIWindow("../../examples/gallery.qml")
|
129
|
-
sys.exit(app.exec())
|
1
|
+
import os
|
2
|
+
import sys
|
3
|
+
|
4
|
+
from PySide6.QtCore import QCoreApplication, QUrl, QObject
|
5
|
+
from PySide6.QtGui import QIcon
|
6
|
+
from PySide6.QtWidgets import QApplication
|
7
|
+
from PySide6.QtQml import QQmlApplicationEngine
|
8
|
+
|
9
|
+
from .theme import ThemeManager
|
10
|
+
from .config import BackdropEffect, is_windows, Theme, RINUI_PATH, RinConfig
|
11
|
+
|
12
|
+
|
13
|
+
class RinUIWindow:
|
14
|
+
def __init__(self, qml_path: str):
|
15
|
+
"""
|
16
|
+
Create an application window with RinUI.
|
17
|
+
:param qml_path: str, QML file path (eg = "path/to/main.qml")
|
18
|
+
"""
|
19
|
+
super().__init__()
|
20
|
+
if hasattr(self, "_initialized") and self._initialized:
|
21
|
+
return
|
22
|
+
self._initialized = True
|
23
|
+
print("✨ RinUIWindow Initializing")
|
24
|
+
|
25
|
+
# 退出清理
|
26
|
+
app_instance = QCoreApplication.instance()
|
27
|
+
if not app_instance:
|
28
|
+
raise RuntimeError("QApplication must be created before RinUIWindow.")
|
29
|
+
|
30
|
+
self.engine = QQmlApplicationEngine()
|
31
|
+
self.theme_manager = ThemeManager()
|
32
|
+
self.qml_path = qml_path
|
33
|
+
self.autoSetWindowsEffect = True
|
34
|
+
|
35
|
+
app_instance.aboutToQuit.connect(self.theme_manager.clean_up)
|
36
|
+
self._setup_application()
|
37
|
+
self.print_startup_info()
|
38
|
+
|
39
|
+
def _setup_application(self) -> None:
|
40
|
+
"""Setup"""
|
41
|
+
# RInUI 模块
|
42
|
+
print(f"UI Module Path: {RINUI_PATH}")
|
43
|
+
|
44
|
+
if os.path.exists(RINUI_PATH):
|
45
|
+
self.engine.addImportPath(RINUI_PATH)
|
46
|
+
else:
|
47
|
+
raise FileNotFoundError(f"Cannot find RinUI module: {RINUI_PATH}")
|
48
|
+
|
49
|
+
# 主题管理器
|
50
|
+
self.engine.rootContext().setContextProperty("ThemeManager", self.theme_manager)
|
51
|
+
try:
|
52
|
+
self.engine.load(self.qml_path)
|
53
|
+
except Exception as e:
|
54
|
+
print(f"Cannot Load QML file: {e}")
|
55
|
+
|
56
|
+
if not self.engine.rootObjects():
|
57
|
+
raise RuntimeError(f"Error loading QML file: {self.qml_path}")
|
58
|
+
|
59
|
+
# 窗口设置
|
60
|
+
self.root_window = self.engine.rootObjects()[0]
|
61
|
+
|
62
|
+
self.theme_manager.set_window(self.root_window)
|
63
|
+
self._apply_windows_effects() if self.autoSetWindowsEffect else None
|
64
|
+
|
65
|
+
def setIcon(self, path: str) -> None:
|
66
|
+
"""
|
67
|
+
Sets the icon for the application.
|
68
|
+
:param path: str, icon file path (eg = "path/to/icon.png")
|
69
|
+
:return:
|
70
|
+
"""
|
71
|
+
app_instance = QApplication.instance()
|
72
|
+
if app_instance:
|
73
|
+
app_instance.setWindowIcon(QIcon(path)) # 设置应用程序图标
|
74
|
+
self.root_window.setProperty('icon', QUrl.fromLocalFile(path))
|
75
|
+
else:
|
76
|
+
raise RuntimeError("Cannot set icon before QApplication is created.")
|
77
|
+
|
78
|
+
def _apply_windows_effects(self) -> None:
|
79
|
+
"""
|
80
|
+
Apply Windows effects to the window.
|
81
|
+
:return:
|
82
|
+
"""
|
83
|
+
if sys.platform == "win32":
|
84
|
+
self.theme_manager.apply_backdrop_effect(self.theme_manager.get_backdrop_effect())
|
85
|
+
self.theme_manager.apply_window_effects()
|
86
|
+
|
87
|
+
# func名称遵循 Qt 命名规范
|
88
|
+
def setBackdropEffect(self, effect: BackdropEffect) -> None:
|
89
|
+
"""
|
90
|
+
Sets the backdrop effect for the window. (Only available on Windows)
|
91
|
+
:param effect: BackdropEffect, type of backdrop effect(Acrylic, Mica, Tabbed, None_)
|
92
|
+
:return:
|
93
|
+
"""
|
94
|
+
if not is_windows() and effect != BackdropEffect.None_:
|
95
|
+
raise OSError("Only can set backdrop effect on Windows platform.")
|
96
|
+
self.theme_manager.apply_backdrop_effect(effect.value)
|
97
|
+
|
98
|
+
def setTheme(self, theme: Theme) -> None:
|
99
|
+
"""
|
100
|
+
Sets the theme for the window.
|
101
|
+
:param theme: Theme, type of theme(Auto, Dark, Light)
|
102
|
+
:return:
|
103
|
+
"""
|
104
|
+
self.theme_manager.toggle_theme(theme.value)
|
105
|
+
|
106
|
+
def __getattr__(self, name) -> QObject:
|
107
|
+
"""获取 QML 窗口属性"""
|
108
|
+
try:
|
109
|
+
root = object.__getattribute__(self, "root_window")
|
110
|
+
return getattr(root, name)
|
111
|
+
except AttributeError:
|
112
|
+
raise AttributeError(f"\"RinUIWindow\" object has no attribute '{name}'")
|
113
|
+
|
114
|
+
def print_startup_info(self) -> None:
|
115
|
+
border = "=" * 40
|
116
|
+
print(f"\n{border}")
|
117
|
+
print("✨ RinUIWindow Loaded Successfully!")
|
118
|
+
print(f"QML File Path: {self.qml_path}")
|
119
|
+
print(f"Current Theme: {self.theme_manager.current_theme}")
|
120
|
+
print(f"Backdrop Effect: {self.theme_manager.get_backdrop_effect()}")
|
121
|
+
print(f"OS: {sys.platform}")
|
122
|
+
print(border + "\n")
|
123
|
+
|
124
|
+
|
125
|
+
if __name__ == "__main__":
|
126
|
+
# 新用法,应该更规范了捏
|
127
|
+
app = QApplication(sys.argv)
|
128
|
+
example = RinUIWindow("../../examples/gallery.qml")
|
129
|
+
sys.exit(app.exec())
|