xsideui 0.9.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.
Files changed (99) hide show
  1. xsideui/__init__.py +89 -0
  2. xsideui/i18n/__init__.py +1 -0
  3. xsideui/i18n/i18n.py +214 -0
  4. xsideui/icon/__init__.py +125 -0
  5. xsideui/icon/icon_name.py +369 -0
  6. xsideui/icon/xicon.py +435 -0
  7. xsideui/icon/xicon_cache.py +257 -0
  8. xsideui/icon/xicon_engine.py +382 -0
  9. xsideui/icon/xicon_theme.py +137 -0
  10. xsideui/icon/xicons_rc.py +16683 -0
  11. xsideui/theme/__init__.py +13 -0
  12. xsideui/theme/color_json/dark.json +165 -0
  13. xsideui/theme/color_json/light.json +165 -0
  14. xsideui/theme/qss/avatar.qss +14 -0
  15. xsideui/theme/qss/card.qss +47 -0
  16. xsideui/theme/qss/carousel.qss +32 -0
  17. xsideui/theme/qss/checkbox.qss +13 -0
  18. xsideui/theme/qss/codeblock.qss +82 -0
  19. xsideui/theme/qss/collapse.qss +37 -0
  20. xsideui/theme/qss/combobox.qss +112 -0
  21. xsideui/theme/qss/dialog.qss +13 -0
  22. xsideui/theme/qss/divider.qss +34 -0
  23. xsideui/theme/qss/groupbox.qss +23 -0
  24. xsideui/theme/qss/label.qss +51 -0
  25. xsideui/theme/qss/lineedit.qss +103 -0
  26. xsideui/theme/qss/listwidget.qss +61 -0
  27. xsideui/theme/qss/loading_mask.qss +12 -0
  28. xsideui/theme/qss/menu.qss +38 -0
  29. xsideui/theme/qss/navbar.qss +30 -0
  30. xsideui/theme/qss/navtree.qss +73 -0
  31. xsideui/theme/qss/notification.qss +33 -0
  32. xsideui/theme/qss/pagination.qss +38 -0
  33. xsideui/theme/qss/popover.qss +28 -0
  34. xsideui/theme/qss/progressbar.qss +28 -0
  35. xsideui/theme/qss/pushbutton.qss +730 -0
  36. xsideui/theme/qss/qdateedit.qss +82 -0
  37. xsideui/theme/qss/qdatetimeedit.qss +82 -0
  38. xsideui/theme/qss/qtimeedit.qss +82 -0
  39. xsideui/theme/qss/radio.qss +12 -0
  40. xsideui/theme/qss/scrollarea.qss +69 -0
  41. xsideui/theme/qss/spinbox.qss +92 -0
  42. xsideui/theme/qss/tablewidget.qss +130 -0
  43. xsideui/theme/qss/tabwidget.qss +53 -0
  44. xsideui/theme/qss/text_edit.qss +79 -0
  45. xsideui/theme/qss/title_bar.qss +23 -0
  46. xsideui/theme/qss/upload.qss +26 -0
  47. xsideui/theme/qss/widget.qss +8 -0
  48. xsideui/theme/qss_loader.py +247 -0
  49. xsideui/theme/theme.py +723 -0
  50. xsideui/theme/theme_types.py +54 -0
  51. xsideui/theme/thmem_config.py +70 -0
  52. xsideui/utils/__init__.py +0 -0
  53. xsideui/utils/qt_compat.py +96 -0
  54. xsideui/widgets/__init__.py +94 -0
  55. xsideui/widgets/badge.py +445 -0
  56. xsideui/widgets/card.py +432 -0
  57. xsideui/widgets/carousel.py +197 -0
  58. xsideui/widgets/checkbox.py +370 -0
  59. xsideui/widgets/codeblock.py +137 -0
  60. xsideui/widgets/collapse.py +160 -0
  61. xsideui/widgets/combobox.py +186 -0
  62. xsideui/widgets/dateedit.py +98 -0
  63. xsideui/widgets/datetimeedit.py +111 -0
  64. xsideui/widgets/dialog.py +248 -0
  65. xsideui/widgets/divider.py +101 -0
  66. xsideui/widgets/flow_layout.py +160 -0
  67. xsideui/widgets/groupbox.py +53 -0
  68. xsideui/widgets/image.py +501 -0
  69. xsideui/widgets/label.py +360 -0
  70. xsideui/widgets/lineedit.py +321 -0
  71. xsideui/widgets/listwidget.py +61 -0
  72. xsideui/widgets/loading_mask.py +279 -0
  73. xsideui/widgets/menu.py +155 -0
  74. xsideui/widgets/messagebox.py +170 -0
  75. xsideui/widgets/navbar.py +395 -0
  76. xsideui/widgets/navbartree.py +216 -0
  77. xsideui/widgets/notification.py +496 -0
  78. xsideui/widgets/pagination.py +283 -0
  79. xsideui/widgets/popover.py +269 -0
  80. xsideui/widgets/progressbar.py +636 -0
  81. xsideui/widgets/pushbutton.py +520 -0
  82. xsideui/widgets/radio.py +334 -0
  83. xsideui/widgets/scrollarea.py +21 -0
  84. xsideui/widgets/slider.py +322 -0
  85. xsideui/widgets/spinbox.py +254 -0
  86. xsideui/widgets/switch.py +373 -0
  87. xsideui/widgets/tablewidget.py +258 -0
  88. xsideui/widgets/tabwidget.py +177 -0
  89. xsideui/widgets/text_edit.py +56 -0
  90. xsideui/widgets/timeedit.py +98 -0
  91. xsideui/widgets/title_bar.py +190 -0
  92. xsideui/widgets/upload.py +378 -0
  93. xsideui/widgets/widget.py +445 -0
  94. xsideui/widgets/xarrowbutton.py +44 -0
  95. xsideui/xenum.py +37 -0
  96. xsideui-0.9.1.dist-info/METADATA +343 -0
  97. xsideui-0.9.1.dist-info/RECORD +99 -0
  98. xsideui-0.9.1.dist-info/WHEEL +5 -0
  99. xsideui-0.9.1.dist-info/top_level.txt +1 -0
xsideui/__init__.py ADDED
@@ -0,0 +1,89 @@
1
+
2
+ from .icon import *
3
+ from .theme import *
4
+ from .widgets import *
5
+ from .xenum import *
6
+ from .i18n import *
7
+
8
+
9
+
10
+
11
+ __all__ = [
12
+ 'XColor',
13
+ 'XSize',
14
+ 'XButtonVariant',
15
+ 'XInputStatus',
16
+ 'XLabel',
17
+ 'XDivider',
18
+ 'XWidget',
19
+ 'XCard',
20
+ 'XHeaderCard',
21
+ 'XGroupCard',
22
+ 'XGroupBox',
23
+ 'XListWidget',
24
+ 'XImage',
25
+ 'XTextEdit',
26
+ 'XCodeBlock',
27
+ 'XRadioButton',
28
+ 'XCheckBox',
29
+ 'XSlider',
30
+ 'XSpinBox',
31
+ 'XDoubleSpinBox',
32
+ 'XSwitch',
33
+ 'XProgressBar',
34
+ 'XCircleProgress',
35
+ 'XFlowLayout',
36
+ 'XLineEdit',
37
+ 'XPushButton',
38
+ 'XPushButtonGroup',
39
+ 'XPushButtonDropdown',
40
+ 'XMenu',
41
+ 'XTabWidget',
42
+ 'XComboBox',
43
+ 'XLoadingMask',
44
+ 'XPopover',
45
+ 'XNotif',
46
+ 'XTableWidget',
47
+ 'XPagination',
48
+ 'XTimeEdit',
49
+ 'XDateEdit',
50
+ 'XDateTimeEdit',
51
+ 'XTitleBar',
52
+ 'XDialog',
53
+ 'XMessageBox',
54
+ 'XNavSimple',
55
+ 'NavItem',
56
+ 'XNavTree',
57
+ 'XCarousel',
58
+ 'XTextBadge',
59
+ 'XDotBadge',
60
+ 'XUpload',
61
+ 'XCollapse',
62
+ 'XCollapseGroup',
63
+ 'XScrollArea',
64
+
65
+ 'theme_manager',
66
+ 'ThemeType',
67
+ 'ThemeConfig',
68
+ 'ThemeColors',
69
+ 'ThemeRegistry',
70
+
71
+
72
+ "XIcon",
73
+ "XIconEngine",
74
+ "XIconCache",
75
+ "XIconThemeAdapter",
76
+ "xicon_cache",
77
+ "xicon_engine",
78
+ "xicon_theme_adapter",
79
+ "IconName",
80
+ "preload_icons",
81
+ "clear_icon_cache",
82
+ "get_icon_names",
83
+ "search_icons",
84
+ "has_icon",
85
+
86
+ "XI18N",
87
+ 'tr'
88
+
89
+ ]
@@ -0,0 +1 @@
1
+ from .i18n import XI18N, tr
xsideui/i18n/i18n.py ADDED
@@ -0,0 +1,214 @@
1
+
2
+ from pathlib import Path
3
+ from typing import List, Optional, Dict
4
+
5
+ from ..utils.qt_compat import (
6
+ QObject, QTranslator, QCoreApplication,
7
+ QEvent, QLibraryInfo, Signal
8
+ )
9
+
10
+
11
+
12
+
13
+ def tr(text: str) -> str:
14
+ """
15
+ 仅用于静态标记,不执行实际翻译。
16
+ 作用:让 lupdate 能够提取到这个字符串,但在运行时它原样返回。
17
+ """
18
+ return text
19
+
20
+ class I18nManager(QObject):
21
+ """
22
+ 国际化管理器(单例模式)
23
+
24
+ 职责:
25
+ 1. 管理和加载 .qm 翻译文件(包括组件库、Qt 标准库、用户自定义库)。
26
+ 2. 提供全局语言切换接口。
27
+ 3. 维护自定义翻译路径和上下文(Context)映射。
28
+ 4. 触发全局 UI 刷新事件。
29
+ """
30
+
31
+ _instance = None
32
+ _initialized = False
33
+
34
+ # 当语言改变时发送此信号 (可选,供非 Widget 类逻辑使用)
35
+ language_changed = Signal(str)
36
+
37
+ def __new__(cls):
38
+ if cls._instance is None:
39
+ cls._instance = super(I18nManager, cls).__new__(cls)
40
+ return cls._instance
41
+
42
+ def __init__(self):
43
+ if I18nManager._initialized:
44
+ return
45
+ super().__init__()
46
+
47
+ # 核心翻译器
48
+ self.app_translator = QTranslator() # 组件库翻译器
49
+ self.qt_translator = QTranslator() # Qt 官方翻译器
50
+ self.custom_translators: List[QTranslator] = [] # 自定义翻译器池
51
+
52
+ self.current_lang = "zh_CN"
53
+
54
+ # 默认语言文件存放路径 (假设在当前文件的 custom_langs 目录下)
55
+ self.base_lang_path = Path(__file__).parent / "custom_langs"
56
+
57
+ # 存储自定义路径: [{"path": str, "context": str}, ...]
58
+ self._custom_paths = []
59
+
60
+ I18nManager._initialized = True
61
+
62
+ def x_tr(self, text: str, context: str = None, args: list = None) -> str:
63
+ """
64
+ 智能翻译函数 (支持占位符填充)
65
+
66
+ :param text: 翻译键 (Key),如 "Export %1 Download"
67
+ :param context: 翻译上下文
68
+ :param args: 占位符填充值列表,按顺序对应 %1, %2...
69
+ """
70
+
71
+ # 1. 构造搜索链
72
+ search_chain = []
73
+ if context:
74
+ search_chain.append(str(context))
75
+
76
+ for info in self.custom_lang_paths:
77
+ ctx = info.get("context")
78
+ if ctx and ctx not in search_chain:
79
+ search_chain.append(ctx)
80
+
81
+ if "XSideUI" not in search_chain:
82
+ search_chain.append("XSideUI")
83
+
84
+ # 2. 依次执行翻译尝试
85
+ translated_text = text
86
+ for ctx in search_chain:
87
+ try:
88
+ res = QCoreApplication.translate(ctx, text)
89
+ except TypeError:
90
+ res = QCoreApplication.translate(ctx.encode('utf-8'), text.encode('utf-8'))
91
+
92
+ if isinstance(res, (bytes, bytearray)):
93
+ res = res.decode('utf-8')
94
+
95
+ # 只要翻译结果和原文不等,说明找到了!
96
+ if res != text:
97
+ translated_text = res
98
+ break
99
+
100
+ # 3. 核心改进:处理 args 填充
101
+ # 即使翻译失败返回了原文,也要尝试填充占位符
102
+ if args:
103
+ print(f"[Args Processing]: Replacing with {args}")
104
+ for i, val in enumerate(args):
105
+ # 将 %1, %2 ... 替换为 args 列表中的内容
106
+ placeholder = f"%{i + 1}"
107
+ translated_text = translated_text.replace(placeholder, str(val))
108
+ return translated_text
109
+
110
+
111
+
112
+ def _get_storage(self) -> List[Dict]:
113
+ """获取存储自定义路径的列表,确保跨模块单例数据同步"""
114
+ app = QCoreApplication.instance()
115
+ if not app:
116
+ return self._custom_paths
117
+ if not hasattr(app, "_global_i18n_paths"):
118
+ app._global_i18n_paths = self._custom_paths
119
+ return app._global_i18n_paths
120
+
121
+ def add_custom_lang_path(self, dir_path: str, context: str = "Global") -> bool:
122
+ """
123
+ 注册外部翻译目录
124
+ :param dir_path: 存放 .qm 文件的文件夹
125
+ :param context: 翻译所属的上下文
126
+ """
127
+ path_obj = Path(dir_path)
128
+ if not path_obj.is_dir():
129
+ return False
130
+
131
+ storage = self._get_storage()
132
+ path_info = {"path": str(dir_path), "context": context}
133
+
134
+ if path_info not in storage:
135
+ storage.append(path_info)
136
+ # 立即尝试加载当前语言对应的自定义翻译
137
+ self._load_custom_translators(self.current_lang)
138
+ self.refresh_ui()
139
+ return True
140
+ return False
141
+
142
+ def _load_custom_translators(self, lang_code: str):
143
+ """加载所有已注册路径下的指定语言文件"""
144
+ app = QCoreApplication.instance()
145
+ if not app:
146
+ return
147
+
148
+ # 卸载旧的自定义翻译器
149
+ for t in self.custom_translators:
150
+ app.removeTranslator(t)
151
+ self.custom_translators.clear()
152
+
153
+ # 遍历注册路径加载新的
154
+ for info in self._get_storage():
155
+ qm_file = Path(info["path"]) / f"{lang_code}.qm"
156
+ if qm_file.exists():
157
+ t = QTranslator()
158
+ if t.load(str(qm_file)):
159
+ app.installTranslator(t)
160
+ self.custom_translators.append(t)
161
+
162
+ def set_language(self, lang_code: str) -> bool:
163
+ """
164
+ 切换全局语言
165
+ :param lang_code: 如 'zh_CN', 'en_US'
166
+ """
167
+ app = QCoreApplication.instance()
168
+ if not app:
169
+ return False
170
+
171
+ self.current_lang = lang_code
172
+
173
+ # 1. 加载组件库自身翻译
174
+ lib_qm = self.base_lang_path / f"{lang_code}.qm"
175
+ app.removeTranslator(self.app_translator)
176
+ if lib_qm.exists():
177
+ if self.app_translator.load(str(lib_qm)):
178
+ app.installTranslator(self.app_translator)
179
+
180
+ # 2. 加载 Qt 标准对话框等翻译
181
+ app.removeTranslator(self.qt_translator)
182
+ # 兼容 Qt5/Qt6 获取路径的方法
183
+ func = getattr(QLibraryInfo, 'path', getattr(QLibraryInfo, 'location', None))
184
+ qt_trans_path = func(QLibraryInfo.TranslationsPath)
185
+
186
+ for name in [f"qt_{lang_code}", f"qtbase_{lang_code}"]:
187
+ if self.qt_translator.load(name, qt_trans_path):
188
+ app.installTranslator(self.qt_translator)
189
+ break
190
+
191
+ # 3. 加载第三方自定义翻译
192
+ self._load_custom_translators(lang_code)
193
+
194
+ # 4. 触发全局刷新
195
+ self.refresh_ui()
196
+ self.language_changed.emit(lang_code)
197
+ return True
198
+
199
+ def refresh_ui(self):
200
+ """
201
+ 核心通知机制:发送 LanguageChange 事件
202
+ Qt 所有的 Widget 收到此事件后,如果重写了 changeEvent,就会触发刷新
203
+ """
204
+ app = QCoreApplication.instance()
205
+ if app:
206
+ QCoreApplication.sendEvent(app, QEvent(QEvent.LanguageChange))
207
+
208
+ @property
209
+ def custom_lang_paths(self):
210
+ return self._get_storage()
211
+
212
+
213
+ # 全局单例对象
214
+ XI18N = I18nManager()
@@ -0,0 +1,125 @@
1
+ """XIcon Component 图标组件系统
2
+
3
+ 高性能SVG图标库,支持:
4
+ - 高效渲染 (基于缓存)
5
+ - 主题感知
6
+ - 链式API
7
+ - 自定义颜色
8
+ - 尺寸变换
9
+ - 旋转/翻转
10
+ - 图标名称枚举(支持 IDE 自动补全)
11
+
12
+ Example:
13
+ >>> # 基础使用(使用枚举)
14
+ >>> from xsideui import XIcon
15
+ >>> qicon = XIcon.get(IconName.SETTING, size=24).icon()
16
+
17
+ """
18
+
19
+ from .xicon import XIcon
20
+ from .xicon_engine import XIconEngine, xicon_engine
21
+ from .xicon_cache import XIconCache, xicon_cache
22
+ from .xicon_theme import (
23
+ XIconThemeAdapter,
24
+ xicon_theme_adapter
25
+ )
26
+ from .icon_name import IconName
27
+
28
+
29
+
30
+
31
+
32
+ def preload_icons(
33
+ names: list,
34
+ sizes: list = None,
35
+ colors: list = None,
36
+ theme_aware: bool = True
37
+ ):
38
+ """预加载图标到缓存
39
+
40
+ 在使用前预加载图标,提高首次显示速度
41
+
42
+ Args:
43
+ names: 图标名称列表
44
+ sizes: 尺寸列表 (默认 [16, 24, 32, 48])
45
+ colors: 颜色列表
46
+ theme_aware: 是否启用主题感知
47
+
48
+ Example:
49
+ >>> from src.icon import preload_icons
50
+ >>> preload_icons(["add", "edit", "delete", "search"])
51
+ """
52
+ return XIconEngine.preload_icons(
53
+ names,
54
+ sizes=sizes,
55
+ colors=colors,
56
+ )
57
+
58
+
59
+ def clear_icon_cache():
60
+ """清理图标缓存"""
61
+ XIconEngine.clear_cache()
62
+
63
+
64
+ def get_icon_names() -> list:
65
+ """获取所有已加载的图标名称"""
66
+ return XIconEngine.get_icon_names()
67
+
68
+
69
+ def search_icons(keyword: str) -> list:
70
+ """搜索图标
71
+
72
+ 通过关键词搜索图标名称
73
+
74
+ Args:
75
+ keyword: 搜索关键词
76
+
77
+ Returns:
78
+ list: 匹配的图标名称列表
79
+
80
+ Example:
81
+ >>> from src.icon import search_icons
82
+ >>> results = search_icons("add")
83
+ >>> # ["add", "add-c", "add-c-f", "add-o", ...]
84
+ """
85
+ from .xicon_engine import XIconEngine
86
+
87
+ all_names = XIconEngine.get_icon_names()
88
+ keyword = keyword.lower()
89
+
90
+ return [
91
+ name for name in all_names
92
+ if keyword in name.lower()
93
+ ]
94
+
95
+
96
+ def has_icon(name: str) -> bool:
97
+ """检查图标是否存在
98
+
99
+ Args:
100
+ name: 图标名称
101
+
102
+ Returns:
103
+ bool: 图标是否存在
104
+ """
105
+ from .xicon_engine import XIconEngine
106
+
107
+ svg_content = XIconEngine.load_svg(name)
108
+ return svg_content is not None
109
+
110
+
111
+ __all__ = [
112
+ "XIcon",
113
+ "XIconEngine",
114
+ "XIconCache",
115
+ "XIconThemeAdapter",
116
+ "xicon_cache",
117
+ "xicon_engine",
118
+ "xicon_theme_adapter",
119
+ "IconName",
120
+ "preload_icons",
121
+ "clear_icon_cache",
122
+ "get_icon_names",
123
+ "search_icons",
124
+ "has_icon",
125
+ ]