monkeyqt 0.2.0__tar.gz → 0.2.2__tar.gz

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 (84) hide show
  1. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/PKG-INFO +1 -1
  2. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/__init__.py +47 -5
  3. monkeyqt-0.2.2/monkeyqt/components/basic/__init__.py +14 -0
  4. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/basic/button.py +177 -162
  5. monkeyqt-0.2.2/monkeyqt/components/basic/checkbox.py +208 -0
  6. monkeyqt-0.2.2/monkeyqt/components/basic/select_card.py +1094 -0
  7. monkeyqt-0.2.2/monkeyqt/components/data/console.py +846 -0
  8. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/data_table.py +126 -32
  9. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/image_compare.py +3 -1
  10. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/image_split.py +6 -4
  11. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/preview_dialogs.py +41 -25
  12. monkeyqt-0.2.2/monkeyqt/components/data/pro_table.py +2724 -0
  13. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/table.py +93 -5
  14. monkeyqt-0.2.2/monkeyqt/components/feedback/__init__.py +28 -0
  15. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/feedback/alert.py +57 -22
  16. monkeyqt-0.2.2/monkeyqt/components/feedback/card.py +414 -0
  17. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/feedback/progress_bar.py +19 -13
  18. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/feedback/progress_ring.py +21 -9
  19. monkeyqt-0.2.2/monkeyqt/components/feedback/tooltip.py +703 -0
  20. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/auth.py +13 -115
  21. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/captcha.py +210 -208
  22. monkeyqt-0.2.2/monkeyqt/components/form/combobox.py +538 -0
  23. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/date_picker.py +55 -22
  24. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/form.py +10 -6
  25. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/input.py +162 -129
  26. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/multicombobox.py +288 -104
  27. monkeyqt-0.2.2/monkeyqt/components/form/slider.py +484 -0
  28. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/switch.py +7 -4
  29. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/form/upload.py +52 -33
  30. monkeyqt-0.2.2/monkeyqt/components/layout/__init__.py +23 -0
  31. monkeyqt-0.2.2/monkeyqt/components/layout/page.py +49 -0
  32. monkeyqt-0.2.2/monkeyqt/components/layout/scroll_area.py +134 -0
  33. monkeyqt-0.2.2/monkeyqt/components/layout/widget.py +667 -0
  34. monkeyqt-0.2.2/monkeyqt/components/layout/window.py +1859 -0
  35. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/layout/window_shell.py +3 -2
  36. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/__init__.py +19 -0
  37. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/avatar_menu.py +9 -7
  38. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/breadcrumb.py +41 -29
  39. monkeyqt-0.2.2/monkeyqt/components/navigation/dropdown.py +87 -0
  40. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/history.py +73 -26
  41. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/pagination.py +98 -43
  42. monkeyqt-0.2.2/monkeyqt/components/navigation/segmented.py +889 -0
  43. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/sidebar.py +267 -102
  44. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/tabs.py +60 -29
  45. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/navigation/topbar.py +64 -35
  46. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/core/icons.py +49 -0
  47. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/__init__.py +2 -0
  48. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/adapter.py +4521 -4279
  49. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/components/theme_selector.py +50 -22
  50. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/engine.py +329 -39
  51. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/manager.py +26 -9
  52. monkeyqt-0.2.2/monkeyqt/themes/palette_theme.py +109 -0
  53. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/style_utils.py +73 -3
  54. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/tokens.py +3 -4
  55. monkeyqt-0.2.2/monkeyqt/themes/unified_qss.py +698 -0
  56. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt.egg-info/PKG-INFO +1 -1
  57. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt.egg-info/SOURCES.txt +11 -0
  58. monkeyqt-0.2.0/monkeyqt/components/basic/checkbox.py +0 -122
  59. monkeyqt-0.2.0/monkeyqt/components/data/console.py +0 -281
  60. monkeyqt-0.2.0/monkeyqt/components/feedback/__init__.py +0 -0
  61. monkeyqt-0.2.0/monkeyqt/components/feedback/card.py +0 -272
  62. monkeyqt-0.2.0/monkeyqt/components/form/combobox.py +0 -248
  63. monkeyqt-0.2.0/monkeyqt/components/form/slider.py +0 -220
  64. monkeyqt-0.2.0/monkeyqt/components/layout/window.py +0 -1093
  65. monkeyqt-0.2.0/monkeyqt/components/navigation/dropdown.py +0 -71
  66. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/LICENSE +0 -0
  67. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/README.md +0 -0
  68. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/common/enums.py +0 -0
  69. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/__init__.py +0 -0
  70. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/data/avatar.py +0 -0
  71. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/components/layout/box.py +0 -0
  72. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/core/theme.py +0 -0
  73. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/core/theme_data.py +0 -0
  74. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/designer/plugins.py +0 -0
  75. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/icons.py +0 -0
  76. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/__main__.py +0 -0
  77. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/components/__init__.py +0 -0
  78. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/gallery.py +0 -0
  79. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt/themes/names.py +0 -0
  80. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt.egg-info/dependency_links.txt +0 -0
  81. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt.egg-info/requires.txt +0 -0
  82. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/monkeyqt.egg-info/top_level.txt +0 -0
  83. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/pyproject.toml +0 -0
  84. {monkeyqt-0.2.0 → monkeyqt-0.2.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: monkeyqt
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: An Enterprise-grade PySide6 UI Component Library
5
5
  Project-URL: Homepage, https://github.com/luohuabuxiema/MonkeyQt
6
6
  Requires-Python: >=3.8
@@ -1,11 +1,19 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  from .components.basic.button import MkButton
3
3
  from .components.basic.checkbox import MkCheckBox
4
+ from .components.basic.select_card import MkSelectItem, MkSelectCard, MkItemActionButton, MkSelectGroupHeader
4
5
  # Navigation
5
6
  from .components.navigation.sidebar import MkMenu
6
7
  from .components.navigation.topbar import MkTopbar
7
8
  from .components.navigation.breadcrumb import MkBreadcrumb
8
9
  from .components.navigation.tabs import MkTabs
10
+ from .components.navigation.segmented import (
11
+ MkSegmented,
12
+ MkSegmentedTabs,
13
+ MkSegmentedControl,
14
+ MkCapsuleTabs,
15
+ SegmentedTabBar,
16
+ )
9
17
  from .components.navigation.pagination import MkPagination
10
18
  from .components.navigation.dropdown import MkDropdown
11
19
  from .components.navigation.history import MkAnimatedStackedWidget, MkHistoryNavigation
@@ -25,8 +33,7 @@ from .components.form.multicombobox import MkMultiComboBox
25
33
 
26
34
  # Data
27
35
  from .components.data.avatar import MkAvatar
28
- from .components.data.table import MkTable
29
- from .components.data.data_table import MkDataTable
36
+ from .components.data.pro_table import MkProTable
30
37
  from .components.data.image_compare import MkImageCompare
31
38
  from .components.data.image_split import MkImageSplit
32
39
  from .components.data.console import MkConsole
@@ -36,11 +43,25 @@ from .components.feedback.alert import MkAlert
36
43
  from .components.feedback.progress_bar import MkProgressBar
37
44
  from .components.feedback.progress_ring import MkProgressRing
38
45
  from .components.feedback.card import MkCard
46
+ from .components.feedback.tooltip import (
47
+ MkTooltipPopover,
48
+ MkInfoIcon,
49
+ MkInfoIconButton,
50
+ MkTooltip,
51
+ create_field_header,
52
+ create_input_field,
53
+ create_switch_field,
54
+ )
39
55
 
40
56
  # Layout
41
57
  from .components.layout.window import MkTitleBar, MkWindow
42
58
  from .components.layout.window_shell import MkWindowShell
43
59
  from .components.layout.box import MkQVBoxLayout, MkQHBoxLayout, MkVBox, MkHBox
60
+ from .components.layout.widget import MkQWidget, MkWidget
61
+ from .components.layout.scroll_area import MkScrollArea, MkStackedWidget
62
+ from .components.layout.page import MkPage
63
+
64
+
44
65
 
45
66
 
46
67
  # Themes (68 UI Styles)
@@ -55,17 +76,26 @@ from .themes import (
55
76
  exclude_from_theme,
56
77
  include_in_theme,
57
78
  MkThemeSelector,
79
+ modern_scrollbar_qss,
58
80
  )
59
81
 
60
- __version__ = "0.2.0"
82
+ __version__ = "0.2.2"
61
83
 
62
84
  __all__ = [
63
85
  "MkButton",
64
86
  "MkCheckBox",
87
+ "MkSelectItem",
88
+ "MkSelectCard",
89
+ "MkItemActionButton",
65
90
  "MkMenu",
66
91
  "MkTopbar",
67
92
  "MkBreadcrumb",
68
93
  "MkTabs",
94
+ "MkSegmented",
95
+ "MkSegmentedTabs",
96
+ "MkSegmentedControl",
97
+ "MkCapsuleTabs",
98
+ "SegmentedTabBar",
69
99
  "MkPagination",
70
100
  "MkDropdown",
71
101
  "MkAnimatedStackedWidget",
@@ -83,8 +113,7 @@ __all__ = [
83
113
  "MkMessage",
84
114
  "MkUpload",
85
115
  "MkAvatar",
86
- "MkTable",
87
- "MkDataTable",
116
+ "MkProTable",
88
117
  "MkImageCompare",
89
118
  "MkImageSplit",
90
119
  "MkConsole",
@@ -92,6 +121,13 @@ __all__ = [
92
121
  "MkProgressBar",
93
122
  "MkProgressRing",
94
123
  "MkCard",
124
+ "MkTooltipPopover",
125
+ "MkInfoIcon",
126
+ "MkInfoIconButton",
127
+ "MkTooltip",
128
+ "create_field_header",
129
+ "create_input_field",
130
+ "create_switch_field",
95
131
  "MkTitleBar",
96
132
  "MkWindow",
97
133
  "MkWindowShell",
@@ -99,6 +135,11 @@ __all__ = [
99
135
  "MkQHBoxLayout",
100
136
  "MkVBox",
101
137
  "MkHBox",
138
+ "MkQWidget",
139
+ "MkWidget",
140
+ "MkScrollArea",
141
+ "MkStackedWidget",
142
+ "MkPage",
102
143
  # Theme engine and helpers
103
144
  "ThemeEngine",
104
145
  "apply_monkeyqt_theme",
@@ -110,4 +151,5 @@ __all__ = [
110
151
  "exclude_from_theme",
111
152
  "include_in_theme",
112
153
  "MkThemeSelector",
154
+ "modern_scrollbar_qss",
113
155
  ]
@@ -0,0 +1,14 @@
1
+ # -*- coding: utf-8 -*-
2
+ from .button import MkButton
3
+ from .checkbox import MkCheckBox
4
+ from .select_card import MkSelectItem, MkSelectCard, MkItemActionButton, MkSelectGroupHeader, MkItemIndicator
5
+
6
+ __all__ = [
7
+ "MkButton",
8
+ "MkCheckBox",
9
+ "MkSelectItem",
10
+ "MkSelectCard",
11
+ "MkItemActionButton",
12
+ "MkSelectGroupHeader",
13
+ "MkItemIndicator",
14
+ ]
@@ -1,7 +1,8 @@
1
1
  # -*- coding: utf-8 -*-
2
+ from monkeyqt.themes.engine import ThemeEngine as _MkThemeEngine
2
3
  from PySide6.QtWidgets import QPushButton, QWidget, QGraphicsDropShadowEffect
3
4
  from PySide6.QtCore import Qt, QPropertyAnimation, QEasingCurve, Property, QRect
4
- from PySide6.QtGui import QPainter, QColor, QPen, QBrush, QPainterPath, QFont, QLinearGradient
5
+ from PySide6.QtGui import QPainter, QColor, QPen, QBrush, QPainterPath, QFont, QLinearGradient, QIcon
5
6
  from monkeyqt.themes.engine import ThemeEngine
6
7
  from monkeyqt.themes.style_utils import (
7
8
  darken,
@@ -91,119 +92,9 @@ class MkButton(QPushButton):
91
92
  if hasattr(self, "_liquid_timer") and self._liquid_timer.isActive():
92
93
  self._liquid_timer.stop()
93
94
 
94
- primary = t.get("--primary", "#409EFF")
95
- bg = t.get("--bg", "#FFFFFF")
96
- fg = t.get("--fg", "#1E293B")
97
- border = t.get("--border", "#E2E8F0")
98
- radius = t.get("--radius", "6px")
99
- border_w = t.get("--border-width", "1px")
100
-
101
- if t.is_neumorphic() or t.is_glass() or t.is_brutal() or t.is_glow() or t.is_pixel():
102
- text = t.get("--glass-text", fg) if t.is_glass() else fg
103
- self.setStyleSheet(f"""
104
- QPushButton {{
105
- background: transparent;
106
- border: none;
107
- color: {text};
108
- padding: 8px 20px;
109
- font-weight: 700;
110
- }}
111
- QPushButton:disabled {{
112
- color: #94A3B8;
113
- }}
114
- """)
115
- self.setGraphicsEffect(None)
116
- self._apply_size_qss()
117
- self.update()
118
- return
119
-
120
- hover_primary = t._lighten_hex(primary, 0.15) if primary.startswith("#") else primary
121
- press_primary = t._darken_hex(primary, 0.1) if primary.startswith("#") else primary
122
-
123
- if self._btn_type == "primary":
124
- btn_bg = primary
125
- btn_fg = "#FFFFFF"
126
- btn_border = primary
127
- btn_hover_bg = hover_primary
128
- btn_press_bg = press_primary
129
- elif self._btn_type == "danger":
130
- btn_bg = "#EF4444"
131
- btn_fg = "#FFFFFF"
132
- btn_border = "#EF4444"
133
- btn_hover_bg = "#F87171"
134
- btn_press_bg = "#DC2626"
135
- elif self._btn_type == "success":
136
- btn_bg = "#22C55E"
137
- btn_fg = "#FFFFFF"
138
- btn_border = "#22C55E"
139
- btn_hover_bg = "#4ADE80"
140
- btn_press_bg = "#16A34A"
141
- elif self._btn_type == "warning":
142
- btn_bg = "#F59E0B"
143
- btn_fg = "#FFFFFF"
144
- btn_border = "#F59E0B"
145
- btn_hover_bg = "#FBBF24"
146
- btn_press_bg = "#D97706"
147
- elif self._btn_type == "secondary":
148
- btn_bg = "transparent"
149
- btn_fg = primary
150
- btn_border = primary
151
- btn_hover_bg = t._lighten_hex(primary, 0.9) if primary.startswith("#") else "#F0F4FF"
152
- btn_press_bg = t._lighten_hex(primary, 0.8) if primary.startswith("#") else "#E0E7FF"
153
- else:
154
- neutral = self._neutral_palette()
155
- btn_bg = neutral["background"]
156
- btn_fg = neutral["foreground"]
157
- btn_border = neutral["border"]
158
- btn_hover_bg = neutral["hover_background"]
159
- btn_press_bg = neutral["pressed_background"]
160
-
161
- if self._btn_type in ("default", "info"):
162
- neutral = self._neutral_palette()
163
- btn_hover_fg = neutral["hover_foreground"]
164
- btn_press_fg = neutral["pressed_foreground"]
165
- btn_hover_border = neutral["hover_border"]
166
- btn_press_border = neutral["pressed_border"]
167
- disabled_bg = neutral["disabled_background"]
168
- disabled_fg = neutral["disabled_foreground"]
169
- disabled_border = neutral["disabled_border"]
170
- else:
171
- btn_hover_fg = btn_fg
172
- btn_press_fg = btn_fg
173
- btn_hover_border = btn_border
174
- btn_press_border = btn_border
175
- disabled_bg = "#E2E8F0"
176
- disabled_fg = "#94A3B8"
177
- disabled_border = "#E2E8F0"
178
-
179
- self.setStyleSheet(f"""
180
- QPushButton {{
181
- background-color: {btn_bg};
182
- color: {btn_fg};
183
- border: {border_w} solid {btn_border};
184
- border-radius: {radius};
185
- padding: 8px 20px;
186
- font-weight: 600;
187
- }}
188
- QPushButton:hover {{
189
- background-color: {btn_hover_bg};
190
- color: {btn_hover_fg};
191
- border-color: {btn_hover_border};
192
- }}
193
- QPushButton:pressed {{
194
- background-color: {btn_press_bg};
195
- color: {btn_press_fg};
196
- border-color: {btn_press_border};
197
- }}
198
- QPushButton:disabled {{
199
- opacity: 0.5;
200
- background-color: {disabled_bg};
201
- color: {disabled_fg};
202
- border-color: {disabled_border};
203
- }}
204
- """)
205
95
  self.setGraphicsEffect(None)
206
96
  self._apply_size_qss()
97
+ self.update()
207
98
 
208
99
  def _neutral_palette(self):
209
100
  """Build theme-aware states for the neutral default and info variants."""
@@ -218,40 +109,98 @@ class MkButton(QPushButton):
218
109
  dark_theme = t.is_dark()
219
110
  is_info = self._btn_type == "info"
220
111
 
221
- background = surface_muted if is_info else surface
112
+ if dark_theme:
113
+ # 严格参考暗黑现代化按钮规范:
114
+ # (正常态): 深炭灰底色 #212121,纯白文字 #FAFAFA,暗细边框 #303030
115
+ # (悬停态): 现代反转高亮浅白灰底色 #E5E5E5,深黑清晰文字 #171717
116
+ # (禁用态): 纯中灰底色 #7E7E7E,暗灰弱化文字 #212121
117
+ if is_info:
118
+ background = surface_muted if surface_muted != bg else "#262626"
119
+ foreground = "#F5F5F5"
120
+ btn_border = border if border != "#E2E8F0" else "#383838"
121
+ hover_background = "#3A3A3A"
122
+ hover_foreground = "#FFFFFF"
123
+ hover_border = "#505050"
124
+ pressed_background = "#1C1C1C"
125
+ pressed_foreground = "#E5E5E5"
126
+ pressed_border = "#2A2A2A"
127
+ disabled_background = "#7E7E7E"
128
+ disabled_foreground = "#212121"
129
+ disabled_border = "#7E7E7E"
130
+ else:
131
+ background = "#212121"
132
+ foreground = "#FAFAFA"
133
+ btn_border = "#303030"
134
+ hover_background = "#282828"
135
+ hover_foreground = "#FAFAFA"
136
+ hover_border = "#383838"
137
+ pressed_background = "#1C1C1C"
138
+ pressed_foreground = "#FAFAFA"
139
+ pressed_border = "#2A2A2A"
140
+ disabled_background = "#7E7E7E"
141
+ disabled_foreground = "#212121"
142
+ disabled_border = "#7E7E7E"
143
+
144
+ return {
145
+ "background": background,
146
+ "foreground": foreground,
147
+ "border": btn_border,
148
+ "hover_background": hover_background,
149
+ "hover_foreground": hover_foreground,
150
+ "hover_border": hover_border,
151
+ "pressed_background": pressed_background,
152
+ "pressed_foreground": pressed_foreground,
153
+ "pressed_border": pressed_border,
154
+ "disabled_background": disabled_background,
155
+ "disabled_foreground": disabled_foreground,
156
+ "disabled_border": disabled_border,
157
+ }
158
+
159
+ # 雅致亮色 (Light Mode) 现代化中性与行动按钮规范 (严格参考用户图一至图五):
160
+ # 图一 (默认态 Default - Connect GitHub): 纯白底色 #FFFFFF,深黑文字 #0F172A,浅灰细边框 #E2E8F0
161
+ # 图二 (中灰填色 Info/Add): 中灰底色 #8B8B8B,纯白文字 #FFFFFF,边框 #8B8B8B
162
+ # 图三 (悬停态 Hover - Connect GitHub): 浅白灰底色 #F5F5F5,深黑文字 #0F172A,浅灰边框 #CBD5E1
163
+ # 按压态 (Pressed): 浅白灰底色 #E5E5E5,深黑文字 #0F172A,浅灰边框 #94A3B8
222
164
  if is_info:
223
- hover_background = (
224
- lighten(background, 0.10)
225
- if dark_theme
226
- else darken(background, 0.055)
227
- )
228
- pressed_background = darken(background, 0.10)
165
+ background = "#8B8B8B"
166
+ foreground = "#FFFFFF"
167
+ btn_border = "#8B8B8B"
168
+ hover_background = "#71717A"
169
+ hover_foreground = "#FFFFFF"
170
+ hover_border = "#71717A"
171
+ pressed_background = "#52525B"
172
+ pressed_foreground = "#FFFFFF"
173
+ pressed_border = "#52525B"
174
+ disabled_background = "#E2E8F0"
175
+ disabled_foreground = "#94A3B8"
176
+ disabled_border = "#E2E8F0"
229
177
  else:
230
- hover_background = surface_muted
231
- if qcolor(hover_background).rgba() == qcolor(background).rgba():
232
- hover_background = (
233
- lighten(background, 0.08)
234
- if dark_theme
235
- else darken(background, 0.045)
236
- )
237
- pressed_background = darken(background, 0.08)
238
-
239
- disabled_background = darken(surface_muted, 0.14 if dark_theme else 0.03)
240
- hover_border = border if is_info else primary
178
+ background = "#FFFFFF"
179
+ foreground = _button_text_color(fg, "#FFFFFF")
180
+ btn_border = qss_color(border, "#E2E8F0")
181
+ hover_background = "#F5F5F5"
182
+ hover_foreground = _button_text_color(fg, hover_background)
183
+ hover_border = "#CBD5E1"
184
+ pressed_background = "#E5E5E5"
185
+ pressed_foreground = _button_text_color(fg, pressed_background)
186
+ pressed_border = "#94A3B8"
187
+ disabled_background = "#F8FAFC"
188
+ disabled_foreground = qss_color(text_muted, "#94A3B8")
189
+ disabled_border = qss_color(border, "#E2E8F0")
241
190
 
242
191
  return {
243
- "background": qss_color(background, bg),
244
- "foreground": _button_text_color(fg, background),
245
- "border": qss_color(border, "#E2E8F0"),
246
- "hover_background": qss_color(hover_background, surface_muted),
247
- "hover_foreground": _button_text_color(fg, hover_background),
248
- "hover_border": qss_color(hover_border, border),
249
- "pressed_background": qss_color(pressed_background, surface),
250
- "pressed_foreground": _button_text_color(fg, pressed_background),
251
- "pressed_border": qss_color(border, "#E2E8F0"),
252
- "disabled_background": qss_color(disabled_background, surface_muted),
253
- "disabled_foreground": qss_color(text_muted, fg),
254
- "disabled_border": qss_color(border, "#E2E8F0"),
192
+ "background": background,
193
+ "foreground": foreground,
194
+ "border": btn_border,
195
+ "hover_background": hover_background,
196
+ "hover_foreground": hover_foreground,
197
+ "hover_border": hover_border,
198
+ "pressed_background": pressed_background,
199
+ "pressed_foreground": pressed_foreground,
200
+ "pressed_border": pressed_border,
201
+ "disabled_background": disabled_background,
202
+ "disabled_foreground": disabled_foreground,
203
+ "disabled_border": disabled_border,
255
204
  }
256
205
 
257
206
  def _apply_size_qss(self):
@@ -260,16 +209,13 @@ class MkButton(QPushButton):
260
209
  size_qss = "padding: 12px 19px; font-size: 14px;"
261
210
  elif getattr(self, "_mk_size", "default") == "small":
262
211
  size_qss = "padding: 5px 11px; font-size: 12px; border-radius: 3px;"
212
+ qss = "QPushButton { background: transparent; border: none; outline: none; }"
263
213
  if size_qss:
264
- self.setStyleSheet(self.styleSheet() + f"\nQPushButton {{ {size_qss} }}")
214
+ qss += f"\nQPushButton {{ {size_qss} }}"
215
+ _MkThemeEngine.apply_style_sheet(self, qss)
265
216
 
266
217
  def paintEvent(self, event):
267
218
  t = ThemeEngine
268
-
269
- if not (t.is_neumorphic() or t.is_glass() or t.is_glow() or t.is_brutal() or t.is_pixel()):
270
- super().paintEvent(event)
271
- return
272
-
273
219
  painter = QPainter(self)
274
220
  painter.setRenderHint(QPainter.RenderHint.Antialiasing)
275
221
  rect = self.rect()
@@ -307,12 +253,23 @@ class MkButton(QPushButton):
307
253
  text_color = qcolor(neutral["foreground"])
308
254
  else:
309
255
  if not self.isEnabled():
310
- btn_color = qcolor("#CBD5E1")
311
- text_color = qcolor("#64748B")
312
- if self._hovered:
313
- btn_color = btn_color.lighter(115)
314
- if self._pressed:
315
- btn_color = btn_color.darker(110)
256
+ if t.is_dark():
257
+ btn_color = qcolor("#7E7E7E")
258
+ text_color = qcolor("#212121")
259
+ else:
260
+ btn_color = qcolor("#CBD5E1")
261
+ text_color = qcolor("#64748B")
262
+ elif self._hovered:
263
+ # 若主色为深黑/炭黑(如雅致亮色 #171717,参考图四与图五),悬停转换为炭灰 #454545,避免 lighter 无效
264
+ if self._btn_type == "primary" and btn_color.lightness() < 60:
265
+ btn_color = qcolor("#454545")
266
+ else:
267
+ btn_color = btn_color.lighter(115)
268
+ elif self._pressed:
269
+ if self._btn_type == "primary" and btn_color.lightness() < 60:
270
+ btn_color = qcolor("#0A0A0A")
271
+ else:
272
+ btn_color = btn_color.darker(110)
316
273
 
317
274
  if t.is_neumorphic():
318
275
  inset = rect.adjusted(4, 4, -4, -4)
@@ -392,6 +349,47 @@ class MkButton(QPushButton):
392
349
  painter.drawRect(inset)
393
350
  painter.setPen(QPen(QColor("#000000"), 2))
394
351
  painter.drawRect(inset)
352
+ else:
353
+ inset = rect.adjusted(1, 1, -1, -1)
354
+ border_w = t.get("--border-width", "1px")
355
+ bw = parse_px(border_w, 1, 0, 8)
356
+
357
+ if self._btn_type == "secondary":
358
+ if t.is_dark():
359
+ border_color = qcolor(primary)
360
+ if self._hovered: btn_color = qcolor("rgba(255, 255, 255, 0.12)")
361
+ elif self._pressed: btn_color = qcolor("rgba(255, 255, 255, 0.20)")
362
+ else: btn_color = QColor(0, 0, 0, 0)
363
+ else:
364
+ if self._hovered:
365
+ btn_color = qcolor("#F5F5F5")
366
+ border_color = qcolor("#CBD5E1")
367
+ elif self._pressed:
368
+ btn_color = qcolor("#E5E5E5")
369
+ border_color = qcolor("#94A3B8")
370
+ else:
371
+ btn_color = QColor(0, 0, 0, 0)
372
+ border_color = qcolor("#E2E8F0")
373
+ elif self._btn_type in ("default", "info"):
374
+ neutral = self._neutral_palette()
375
+ border_color = qcolor(neutral["border"])
376
+ if not self.isEnabled():
377
+ border_color = qcolor(neutral["disabled_border"])
378
+ elif self._hovered:
379
+ border_color = qcolor(neutral["hover_border"])
380
+ elif self._pressed:
381
+ border_color = qcolor(neutral["pressed_border"])
382
+ else:
383
+ border_color = btn_color
384
+ if not self.isEnabled():
385
+ border_color = qcolor("#7E7E7E" if t.is_dark() else "#CBD5E1")
386
+
387
+ painter.setBrush(QBrush(btn_color))
388
+ if border_color and bw > 0:
389
+ painter.setPen(QPen(border_color, bw))
390
+ else:
391
+ painter.setPen(Qt.PenStyle.NoPen)
392
+ painter.drawRoundedRect(inset, radius, radius)
395
393
 
396
394
  if self._btn_type in ("default", "info") and not self.isEnabled():
397
395
  text_color = qcolor(self._neutral_palette()["disabled_foreground"])
@@ -470,8 +468,8 @@ class MkButton(QPushButton):
470
468
  return readable_text(qcolor(primary))
471
469
  elif self._btn_type in ("danger", "success", "warning"):
472
470
  return "#FFFFFF"
473
- elif self._btn_type in ("text", "outline"):
474
- return primary
471
+ elif self._btn_type in ("text", "outline", "secondary"):
472
+ return fg if not t.is_dark() else "#FAFAFA"
475
473
 
476
474
  if t.is_glow():
477
475
  return primary
@@ -482,7 +480,15 @@ class MkButton(QPushButton):
482
480
  return fg
483
481
 
484
482
  def setIcon(self, icon):
485
- if hasattr(icon, "_ph_spec"):
483
+ if isinstance(icon, str):
484
+ try:
485
+ from monkeyqt.icons import Ph
486
+ pm = Ph.pixmap(icon, size=16, color=self._get_button_text_color())
487
+ if pm and not pm.isNull():
488
+ icon = QIcon(pm)
489
+ except Exception:
490
+ pass
491
+ elif hasattr(icon, "_ph_spec"):
486
492
  self._ph_icon_spec = getattr(icon, "_ph_spec", None)
487
493
  try:
488
494
  spec = dict(self._ph_icon_spec)
@@ -495,18 +501,28 @@ class MkButton(QPushButton):
495
501
  super().setIcon(icon)
496
502
 
497
503
  def set_theme_style(self, style_name: str = None):
504
+ self._update_style()
498
505
  if getattr(self, "_ph_icon_spec", None):
499
506
  try:
500
-
501
507
  spec = dict(self._ph_icon_spec)
502
508
  orig_color = spec.get("color")
503
509
  if orig_color in (None, "auto", "default", "fg", "foreground", "currentcolor"):
504
510
  spec["color"] = self._get_button_text_color()
505
511
  new_icon = Ph.icon(**spec)
506
512
  super().setIcon(new_icon)
507
- except Exception as e:
513
+ except Exception:
508
514
  pass
509
- self._update_style()
515
+ t = ThemeEngine
516
+ if t.is_liquid_glass():
517
+ if not hasattr(self, "_liquid_timer"):
518
+ from PySide6.QtCore import QTimer
519
+ self._liquid_timer = QTimer(self)
520
+ self._liquid_timer.timeout.connect(self._on_liquid_timeout)
521
+ if not self._liquid_timer.isActive():
522
+ self._liquid_timer.start(33)
523
+ else:
524
+ if hasattr(self, "_liquid_timer") and self._liquid_timer.isActive():
525
+ self._liquid_timer.stop()
510
526
  self.update()
511
527
 
512
528
  @Property(str)
@@ -543,5 +559,4 @@ class MkButton(QPushButton):
543
559
  self._mk_size = value
544
560
  self.setProperty("mk_size", value)
545
561
  self._update_style()
546
- self.style().unpolish(self)
547
- self.style().polish(self)
562
+ self.update()