RinUI 0.1.4.1__tar.gz → 0.1.5.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 (120) hide show
  1. {rinui-0.1.4.1/RinUI.egg-info → rinui-0.1.5.2}/PKG-INFO +1 -1
  2. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/__init__.py +1 -1
  3. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Text/SpinBox.qml +1 -1
  4. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/core/launcher.py +9 -5
  5. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/core/theme.py +0 -2
  6. rinui-0.1.5.2/RinUI/core/window.py +235 -0
  7. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/CtrlBtn.qml +5 -1
  8. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/FluentWindowBase.qml +1 -1
  9. {rinui-0.1.4.1 → rinui-0.1.5.2/RinUI.egg-info}/PKG-INFO +1 -1
  10. {rinui-0.1.4.1 → rinui-0.1.5.2}/pyproject.toml +1 -1
  11. rinui-0.1.4.1/RinUI/core/window.py +0 -214
  12. {rinui-0.1.4.1 → rinui-0.1.5.2}/LICENSE +0 -0
  13. {rinui-0.1.4.1 → rinui-0.1.5.2}/MANIFEST.in +0 -0
  14. {rinui-0.1.4.1 → rinui-0.1.5.2}/README.md +0 -0
  15. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/assets/fonts/FluentSystemIcons-Index.js +0 -0
  16. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/assets/fonts/FluentSystemIcons-Resizable.ttf +0 -0
  17. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/assets/img/default_app_icon.png +0 -0
  18. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Base.qml +0 -0
  19. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Button.qml +0 -0
  20. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/CheckBox.qml +0 -0
  21. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ComboBox.qml +0 -0
  22. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/DropDownButton.qml +0 -0
  23. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Hyperlink.qml +0 -0
  24. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/PillButton.qml +0 -0
  25. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/RadioButton.qml +0 -0
  26. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/RoundButton.qml +0 -0
  27. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Slider.qml +0 -0
  28. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Switch.qml +0 -0
  29. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ToggleButton.qml +0 -0
  30. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ToolButton.qml +0 -0
  31. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ContextMenu.qml +0 -0
  32. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/DatePicker.qml +0 -0
  33. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/PickerView.qml +0 -0
  34. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/TimePicker.qml +0 -0
  35. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Dialog.qml +0 -0
  36. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/DialogButtonBox.qml +0 -0
  37. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Flyout.qml +0 -0
  38. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Popup.qml +0 -0
  39. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/FocusIndicator.qml +0 -0
  40. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/IconWidget.qml +0 -0
  41. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Indicator.qml +0 -0
  42. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Layout/Expander.qml +0 -0
  43. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Layout/SettingExpander.qml +0 -0
  44. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Layout/SettingItem.qml +0 -0
  45. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/Clip.qml +0 -0
  46. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/Frame.qml +0 -0
  47. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/ListView.qml +0 -0
  48. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/ListViewDelegate.qml +0 -0
  49. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/SettingCard.qml +0 -0
  50. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/TableView.qml +0 -0
  51. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/TableViewDelegate.qml +0 -0
  52. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Media/Avatar.qml +0 -0
  53. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/Menu.qml +0 -0
  54. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuBar.qml +0 -0
  55. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuItem.qml +0 -0
  56. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuItemGroup.qml +0 -0
  57. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuSeparator.qml +0 -0
  58. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/TextInputMenu.qml +0 -0
  59. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/ToolSeparator.qml +0 -0
  60. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/ErrorPage.qml +0 -0
  61. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationBar.qml +0 -0
  62. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationItem.qml +0 -0
  63. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationSubItem.qml +0 -0
  64. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationView.qml +0 -0
  65. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/Segmented.qml +0 -0
  66. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SegmentedItem.qml +0 -0
  67. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SelectorBar.qml +0 -0
  68. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SelectorBarItem.qml +0 -0
  69. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ScrollBar.qml +0 -0
  70. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/ScrollView.qml +0 -0
  71. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Shadow.qml +0 -0
  72. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/BusyIndicator.qml +0 -0
  73. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/InfoBadge.qml +0 -0
  74. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/InfoBar.qml +0 -0
  75. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ProgressBar.qml +0 -0
  76. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ProgressRing.qml +0 -0
  77. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/Toast.qml +0 -0
  78. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ToolTip.qml +0 -0
  79. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Text/Text.qml +0 -0
  80. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Text/TextArea.qml +0 -0
  81. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Text/TextField.qml +0 -0
  82. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/Text/TextInput.qml +0 -0
  83. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/components/qmldir +0 -0
  84. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/core/__init__.py +0 -0
  85. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/core/config.py +0 -0
  86. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/core/translator.py +0 -0
  87. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/hooks/__init__.py +0 -0
  88. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/hooks/hook-RinUI.py +0 -0
  89. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/languages/en_US.qm +0 -0
  90. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/languages/en_US.ts +0 -0
  91. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/languages/zh_CN.qm +0 -0
  92. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/languages/zh_CN.ts +0 -0
  93. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/qmldir +0 -0
  94. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/Appearance.qml +0 -0
  95. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/Colors.qml +0 -0
  96. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/dark.qml +0 -0
  97. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/light.qml +0 -0
  98. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/qmldir +0 -0
  99. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/theme.qml +0 -0
  100. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/themes/utils.qml +0 -0
  101. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/Animation.qml +0 -0
  102. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/FloatLayer.qml +0 -0
  103. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/FontIconLoader.qml +0 -0
  104. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/Position.qml +0 -0
  105. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/Severity.qml +0 -0
  106. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/Typography.qml +0 -0
  107. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/utils/qmldir +0 -0
  108. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/FluentPage.qml +0 -0
  109. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/FluentWindow.qml +0 -0
  110. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/TitleBar.qml +0 -0
  111. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/WindowManager.qml +0 -0
  112. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/qmldir +0 -0
  113. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/window/ApplicationWindow.qml +0 -0
  114. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI/windows/window/Window.qml +0 -0
  115. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI.egg-info/SOURCES.txt +0 -0
  116. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI.egg-info/dependency_links.txt +0 -0
  117. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI.egg-info/entry_points.txt +0 -0
  118. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI.egg-info/requires.txt +0 -0
  119. {rinui-0.1.4.1 → rinui-0.1.5.2}/RinUI.egg-info/top_level.txt +0 -0
  120. {rinui-0.1.4.1 → rinui-0.1.5.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RinUI
3
- Version: 0.1.4.1
3
+ Version: 0.1.5.2
4
4
  Summary: A Fluent Design-like UI library for Qt Quick (QML) based on PySide6
5
5
  Author-email: RinLit <lintu233_qwq@icloud.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,4 +1,4 @@
1
1
  from .core import *
2
2
 
3
- __version__ = "0.1.4.1"
3
+ __version__ = "0.1.5.2"
4
4
  __author__ = "RinLit"
@@ -107,7 +107,7 @@ SpinBox {
107
107
  // 恢复滚轮调整数值
108
108
  WheelHandler {
109
109
  id: wheelHandler
110
- target: spin
110
+ target: root
111
111
  onWheel: (event) => {
112
112
  if (!root.focus) {
113
113
  return; // 如果没有焦点,则不处理滚轮事件
@@ -1,9 +1,9 @@
1
- import os
2
1
  import sys
3
2
  from typing import Union
4
3
 
5
4
  from PySide6.QtCore import QCoreApplication, QUrl, QObject
6
5
  from PySide6.QtGui import QIcon
6
+ from PySide6.QtQuick import QQuickWindow
7
7
  from PySide6.QtWidgets import QApplication
8
8
  from PySide6.QtQml import QQmlApplicationEngine
9
9
  from pathlib import Path
@@ -20,6 +20,7 @@ class RinUIWindow:
20
20
  :param qml_path: str or Path, QML file path (eg = "path/to/main.qml")
21
21
  """
22
22
  super().__init__()
23
+ self.windows = None
23
24
  if hasattr(self, "_initialized") and self._initialized:
24
25
  return
25
26
 
@@ -54,9 +55,9 @@ class RinUIWindow:
54
55
 
55
56
  if qml_path is None:
56
57
  raise ValueError("QML path must be provided to load the window.")
57
- self.qml_path = qml_path
58
+ self.qml_path = Path(qml_path)
58
59
 
59
- if os.path.exists(RINUI_PATH):
60
+ if self.qml_path.exists():
60
61
  self.engine.addImportPath(RINUI_PATH)
61
62
  else:
62
63
  raise FileNotFoundError(f"Cannot find RinUI module: {RINUI_PATH}")
@@ -73,8 +74,10 @@ class RinUIWindow:
73
74
 
74
75
  # 窗口设置
75
76
  self.root_window = self.engine.rootObjects()[0]
77
+ self.windows = [self.root_window] + self.root_window.findChildren(QQuickWindow)
76
78
 
77
- self.theme_manager.set_window(self.root_window)
79
+ for window in self.windows:
80
+ self.theme_manager.set_window(window)
78
81
 
79
82
  # 窗口句柄管理
80
83
  self._window_handle_setup()
@@ -91,7 +94,7 @@ class RinUIWindow:
91
94
 
92
95
  from .window import WinEventFilter, WinEventManager
93
96
 
94
- self.win_event_filter = WinEventFilter(self.root_window)
97
+ self.win_event_filter = WinEventFilter(self.windows)
95
98
  self.win_event_manager = WinEventManager()
96
99
 
97
100
  app_instance = QApplication.instance()
@@ -106,6 +109,7 @@ class RinUIWindow:
106
109
  :return:
107
110
  """
108
111
  app_instance = QApplication.instance()
112
+ path = Path(path).as_posix()
109
113
  if app_instance:
110
114
  app_instance.setWindowIcon(QIcon(path)) # 设置应用程序图标
111
115
  self.root_window.setProperty('icon', QUrl.fromLocalFile(path))
@@ -135,8 +135,6 @@ class ThemeManager(QObject):
135
135
  except Exception as e:
136
136
  print(f"Failed to load config because of {e}, using default config")
137
137
 
138
- # self.hwnd = None # 窗口句柄
139
-
140
138
  self.start_listener()
141
139
 
142
140
  def start_listener(self):
@@ -0,0 +1,235 @@
1
+ import platform
2
+ from typing import Optional
3
+
4
+ from PySide6.QtCore import QAbstractNativeEventFilter, QByteArray, QObject, Slot
5
+ import ctypes
6
+ from ctypes import wintypes
7
+
8
+ import win32con
9
+ from PySide6.QtQuick import QQuickWindow
10
+ from win32gui import ReleaseCapture, GetWindowPlacement, ShowWindow
11
+ from win32con import SW_MAXIMIZE, SW_RESTORE
12
+ from win32api import SendMessage
13
+
14
+ from RinUI.core.config import is_windows
15
+
16
+ # 定义 Windows 类型
17
+ ULONG_PTR = ctypes.c_ulong if ctypes.sizeof(ctypes.c_void_p) == 4 else ctypes.c_ulonglong
18
+ LONG = ctypes.c_long
19
+
20
+
21
+ # 自定义结构体 MONITORINFO
22
+ class MONITORINFO(ctypes.Structure):
23
+ _fields_ = [
24
+ ('cbSize', wintypes.DWORD),
25
+ ('rcMonitor', wintypes.RECT),
26
+ ('rcWork', wintypes.RECT),
27
+ ('dwFlags', wintypes.DWORD)
28
+ ]
29
+
30
+
31
+ class MSG(ctypes.Structure):
32
+ _fields_ = [
33
+ ("hwnd", ctypes.c_void_p),
34
+ ("message", wintypes.UINT),
35
+ ("wParam", wintypes.WPARAM),
36
+ ("lParam", wintypes.LPARAM),
37
+ ("time", wintypes.DWORD),
38
+ ("pt", wintypes.POINT),
39
+ ]
40
+
41
+
42
+ user32 = ctypes.windll.user32
43
+
44
+ # 定义必要的 Windows 常量
45
+ WM_NCCALCSIZE = 0x0083
46
+ WM_NCHITTEST = 0x0084
47
+ WM_SYSCOMMAND = 0x0112
48
+ WM_GETMINMAXINFO = 0x0024
49
+
50
+ WS_CAPTION = 0x00C00000
51
+ WS_THICKFRAME = 0x00040000
52
+
53
+ SC_MINIMIZE = 0xF020
54
+ SC_MAXIMIZE = 0xF030
55
+ SC_RESTORE = 0xF120
56
+
57
+
58
+ class MINMAXINFO(ctypes.Structure):
59
+ _fields_ = [
60
+ ("ptReserved", wintypes.POINT),
61
+ ("ptMaxSize", wintypes.POINT),
62
+ ("ptMaxPosition", wintypes.POINT),
63
+ ("ptMinTrackSize", wintypes.POINT),
64
+ ("ptMaxTrackSize", wintypes.POINT),
65
+ ]
66
+
67
+
68
+ class WinEventManager(QObject):
69
+ @Slot(QObject, result=int)
70
+ def getWindowId(self, window):
71
+ """获取窗口的句柄"""
72
+ print(f"GetWindowId: {window.winId()}")
73
+ return int(window.winId())
74
+
75
+ @Slot(int)
76
+ def dragWindowEvent(self, hwnd: int):
77
+ """ 在Windows 用原生方法拖动"""
78
+ if not is_windows() or type(hwnd) is not int or hwnd == 0:
79
+ print(
80
+ f"Use Qt method to drag window on: {platform.system()}"
81
+ if not is_windows() else f"Invalid window handle: {hwnd}"
82
+ )
83
+ return
84
+
85
+ ReleaseCapture()
86
+ SendMessage(
87
+ hwnd,
88
+ win32con.WM_SYSCOMMAND,
89
+ win32con.SC_MOVE | win32con.HTCAPTION, 0
90
+ )
91
+
92
+ @Slot(int)
93
+ def maximizeWindow(self, hwnd):
94
+ """在Windows上最大化或还原窗口"""
95
+ if not is_windows() or type(hwnd) is not int or hwnd == 0:
96
+ print(
97
+ f"Use Qt method to drag window on: {platform.system()}"
98
+ if not is_windows() else f"Invalid window handle: {hwnd}"
99
+ )
100
+ return
101
+
102
+ try:
103
+ placement = GetWindowPlacement(hwnd)
104
+ current_state = placement[1]
105
+
106
+ if current_state == SW_MAXIMIZE:
107
+ ShowWindow(hwnd, SW_RESTORE)
108
+ else:
109
+ ShowWindow(hwnd, SW_MAXIMIZE)
110
+
111
+ except Exception as e:
112
+ print(f"Error toggling window state: {e}")
113
+
114
+
115
+ class WinEventFilter(QAbstractNativeEventFilter):
116
+ def __init__(self, windows: list):
117
+ super().__init__()
118
+ self.windows = windows # 接受多个窗口
119
+ self.hwnds = {} # 用于存储每个窗口的 hwnd
120
+ self.resize_border = 8
121
+
122
+ for window in self.windows:
123
+ window.visibleChanged.connect(self._on_visible_changed)
124
+ if window.isVisible():
125
+ self._init_window_handle(window)
126
+
127
+ def _on_visible_changed(self, visible: bool):
128
+ for window in self.windows:
129
+ if visible and self.hwnds.get(window) is None:
130
+ self._init_window_handle(window)
131
+
132
+ def _init_window_handle(self, window: QQuickWindow):
133
+ hwnd = int(window.winId())
134
+ self.hwnds[window] = hwnd
135
+ self.set_window_styles(window)
136
+
137
+ def set_window_styles(self, window: QQuickWindow):
138
+ hwnd = self.hwnds.get(window)
139
+ if hwnd is None:
140
+ return
141
+
142
+ style = user32.GetWindowLongPtrW(hwnd, -16) # GWL_STYLE
143
+ style |= WS_CAPTION | WS_THICKFRAME
144
+ user32.SetWindowLongPtrW(hwnd, -16, style) # GWL_STYLE
145
+
146
+ # 重绘
147
+ user32.SetWindowPos(hwnd, 0, 0, 0, 0, 0,
148
+ 0x0002 | 0x0001 | 0x0040) # SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED
149
+
150
+ def nativeEventFilter(self, eventType: QByteArray, message):
151
+ if eventType != b"windows_generic_MSG":
152
+ return False, 0
153
+
154
+ try:
155
+ message_addr = int(message)
156
+ except:
157
+ buf = memoryview(message)
158
+ message_addr = ctypes.addressof(ctypes.c_char.from_buffer(buf))
159
+
160
+ # 直接使用内存地址访问 MSG 字段
161
+ hwnd = ctypes.c_void_p.from_address(message_addr).value
162
+ message_id = wintypes.UINT.from_address(message_addr + ctypes.sizeof(ctypes.c_void_p)).value
163
+ wParam = wintypes.WPARAM.from_address(message_addr + 2 * ctypes.sizeof(ctypes.c_void_p)).value
164
+ lParam = wintypes.LPARAM.from_address(message_addr + 3 * ctypes.sizeof(ctypes.c_void_p)).value
165
+
166
+ # 遍历每个窗口,检查哪个窗口收到了消息
167
+ for window in self.windows:
168
+ hwnd_window = self.hwnds.get(window)
169
+ if hwnd_window == hwnd:
170
+ if message_id == WM_NCHITTEST:
171
+ x = ctypes.c_short(lParam & 0xFFFF).value
172
+ y = ctypes.c_short((lParam >> 16) & 0xFFFF).value
173
+
174
+ rect = wintypes.RECT()
175
+ user32.GetWindowRect(hwnd_window, ctypes.byref(rect))
176
+ left, top, right, bottom = rect.left, rect.top, rect.right, rect.bottom
177
+ border = self.resize_border
178
+
179
+ if left <= x < left + border:
180
+ if top <= y < top + border:
181
+ return True, 13 # HTTOPLEFT
182
+ elif bottom - border <= y < bottom:
183
+ return True, 16 # HTBOTTOMLEFT
184
+ else:
185
+ return True, 10 # HTLEFT
186
+ elif right - border <= x < right:
187
+ if top <= y < top + border:
188
+ return True, 14 # HTTOPRIGHT
189
+ elif bottom - border <= y < bottom:
190
+ return True, 17 # HTBOTTOMRIGHT
191
+ else:
192
+ return True, 11 # HTRIGHT
193
+ elif top <= y < top + border:
194
+ return True, 12 # HTTOP
195
+ elif bottom - border <= y < bottom:
196
+ return True, 15 # HTBOTTOM
197
+
198
+ # 其他区域不处理
199
+ return False, 0
200
+
201
+ # 移除标题栏
202
+ elif message_id == WM_NCCALCSIZE and wParam:
203
+ return True, 0
204
+
205
+ # 支持动画
206
+ elif message_id == WM_SYSCOMMAND:
207
+ return False, 0
208
+
209
+ # 处理 WM_GETMINMAXINFO 消息以支持 Snap 功能
210
+ elif message_id == WM_GETMINMAXINFO:
211
+ # 获取屏幕工作区大小
212
+ monitor = user32.MonitorFromWindow(hwnd_window, 2) # MONITOR_DEFAULTTONEAREST
213
+
214
+ # 使用自定义的 MONITORINFO 结构
215
+ monitor_info = MONITORINFO()
216
+ monitor_info.cbSize = ctypes.sizeof(MONITORINFO)
217
+ monitor_info.dwFlags = 0
218
+ user32.GetMonitorInfoW(monitor, ctypes.byref(monitor_info))
219
+
220
+ # 获取 MINMAXINFO 结构
221
+ minmax_info = MINMAXINFO.from_address(lParam)
222
+
223
+ # 设置最大化位置和大小
224
+ minmax_info.ptMaxPosition.x = monitor_info.rcWork.left - monitor_info.rcMonitor.left
225
+ minmax_info.ptMaxPosition.y = monitor_info.rcWork.top - monitor_info.rcMonitor.top
226
+ minmax_info.ptMaxSize.x = monitor_info.rcWork.right - monitor_info.rcWork.left
227
+ minmax_info.ptMaxSize.y = monitor_info.rcWork.bottom - monitor_info.rcWork.top
228
+
229
+ # 设置最小跟踪大小
230
+ minmax_info.ptMinTrackSize.x = 200 # 最小宽度
231
+ minmax_info.ptMinTrackSize.y = 150 # 最小高度
232
+
233
+ return True, 0
234
+
235
+ return False, 0
@@ -26,7 +26,11 @@ Base {
26
26
  } else if (mode===1) {
27
27
  window.showMinimized();
28
28
  } else if (mode===2) {
29
- window.close();
29
+ if (window.transientParent) {
30
+ window.visible = false;
31
+ } else {
32
+ window.close();
33
+ }
30
34
  }
31
35
  }
32
36
 
@@ -18,7 +18,7 @@ ApplicationWindow {
18
18
  color: "transparent"
19
19
 
20
20
  // 自定义属性
21
- property var icon: "../assets/img/default_app_icon.png" // 图标
21
+ property var icon: undefined // 图标
22
22
  property alias titleEnabled: titleBar.titleEnabled
23
23
  property int titleBarHeight: Theme.currentTheme.appearance.dialogTitleBarHeight
24
24
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RinUI
3
- Version: 0.1.4.1
3
+ Version: 0.1.5.2
4
4
  Summary: A Fluent Design-like UI library for Qt Quick (QML) based on PySide6
5
5
  Author-email: RinLit <lintu233_qwq@icloud.com>
6
6
  Classifier: Programming Language :: Python :: 3
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "RinUI"
7
- version = "0.1.4.1"
7
+ version = "0.1.5.2"
8
8
  authors = [
9
9
  { name = "RinLit", email = "lintu233_qwq@icloud.com" }
10
10
  ]
@@ -1,214 +0,0 @@
1
- import platform
2
-
3
- from PySide6.QtCore import QAbstractNativeEventFilter, QByteArray, QObject, Slot
4
- import ctypes
5
- from ctypes import wintypes
6
-
7
- import win32con
8
- from win32gui import ReleaseCapture, GetWindowPlacement, ShowWindow
9
- from win32con import SW_MAXIMIZE, SW_RESTORE
10
- from win32api import SendMessage
11
-
12
- from RinUI.core.config import is_windows
13
-
14
- # 定义 Windows 类型
15
- ULONG_PTR = ctypes.c_ulong if ctypes.sizeof(ctypes.c_void_p) == 4 else ctypes.c_ulonglong
16
- LONG = ctypes.c_long
17
-
18
-
19
- # 自定义结构体 MONITORINFO
20
- class MONITORINFO(ctypes.Structure):
21
- _fields_ = [
22
- ('cbSize', wintypes.DWORD),
23
- ('rcMonitor', wintypes.RECT),
24
- ('rcWork', wintypes.RECT),
25
- ('dwFlags', wintypes.DWORD)
26
- ]
27
-
28
-
29
- class MSG(ctypes.Structure):
30
- _fields_ = [
31
- ("hwnd", ctypes.c_void_p),
32
- ("message", wintypes.UINT),
33
- ("wParam", wintypes.WPARAM),
34
- ("lParam", wintypes.LPARAM),
35
- ("time", wintypes.DWORD),
36
- ("pt", wintypes.POINT),
37
- ]
38
-
39
-
40
- user32 = ctypes.windll.user32
41
-
42
- # 定义必要的 Windows 常量
43
- WM_NCCALCSIZE = 0x0083
44
- WM_NCHITTEST = 0x0084
45
- WM_SYSCOMMAND = 0x0112
46
- WM_GETMINMAXINFO = 0x0024
47
-
48
- WS_CAPTION = 0x00C00000
49
- WS_THICKFRAME = 0x00040000
50
-
51
- SC_MINIMIZE = 0xF020
52
- SC_MAXIMIZE = 0xF030
53
- SC_RESTORE = 0xF120
54
-
55
-
56
- class MINMAXINFO(ctypes.Structure):
57
- _fields_ = [
58
- ("ptReserved", wintypes.POINT),
59
- ("ptMaxSize", wintypes.POINT),
60
- ("ptMaxPosition", wintypes.POINT),
61
- ("ptMinTrackSize", wintypes.POINT),
62
- ("ptMaxTrackSize", wintypes.POINT),
63
- ]
64
-
65
-
66
- class WinEventManager(QObject):
67
- @Slot(QObject, result=int)
68
- def getWindowId(self, window):
69
- """获取窗口的句柄"""
70
- print(f"GetWindowId: {window.winId()}")
71
- return int(window.winId())
72
-
73
- @Slot(int)
74
- def dragWindowEvent(self, hwnd: int):
75
- """ 在Windows 用原生方法拖动"""
76
- if not is_windows() or type(hwnd) is not int or hwnd == 0:
77
- print(
78
- f"Use Qt method to drag window on: {platform.system()}"
79
- if not is_windows() else f"Invalid window handle: {hwnd}"
80
- )
81
- return
82
-
83
- ReleaseCapture()
84
- SendMessage(
85
- hwnd,
86
- win32con.WM_SYSCOMMAND,
87
- win32con.SC_MOVE | win32con.HTCAPTION, 0
88
- )
89
-
90
- @Slot(int)
91
- def maximizeWindow(self, hwnd):
92
- """在Windows上最大化或还原窗口"""
93
- if not is_windows() or type(hwnd) is not int or hwnd == 0:
94
- print(
95
- f"Use Qt method to drag window on: {platform.system()}"
96
- if not is_windows() else f"Invalid window handle: {hwnd}"
97
- )
98
- return
99
-
100
- try:
101
- placement = GetWindowPlacement(hwnd)
102
- current_state = placement[1]
103
-
104
- if current_state == SW_MAXIMIZE:
105
- ShowWindow(hwnd, SW_RESTORE)
106
- else:
107
- ShowWindow(hwnd, SW_MAXIMIZE)
108
-
109
- except Exception as e:
110
- print(f"Error toggling window state: {e}")
111
-
112
-
113
- class WinEventFilter(QAbstractNativeEventFilter):
114
- def __init__(self, window):
115
- super().__init__()
116
- self.window = window
117
- self.hwnd = int(window.winId())
118
- self.resize_border = 8 # resize 边框宽度
119
-
120
- self.set_window_styles()
121
-
122
- def set_window_styles(self):
123
- """设置必要的窗口样式以启用原生窗口行为"""
124
- style = user32.GetWindowLongPtrW(self.hwnd, -16) # GWL_STYLE
125
-
126
- style |= WS_CAPTION | WS_THICKFRAME
127
- user32.SetWindowLongPtrW(self.hwnd, -16, style) # GWL_STYLE
128
-
129
- # 重绘
130
- user32.SetWindowPos(self.hwnd, 0, 0, 0, 0, 0,
131
- 0x0002 | 0x0001 | 0x0040) # SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED
132
-
133
- def nativeEventFilter(self, eventType: QByteArray, message):
134
- if eventType != b"windows_generic_MSG":
135
- return False, 0
136
-
137
- try:
138
- message_addr = int(message)
139
- except:
140
- buf = memoryview(message)
141
- message_addr = ctypes.addressof(ctypes.c_char.from_buffer(buf))
142
-
143
- # 直接使用内存地址访问 MSG 字段
144
- hwnd = ctypes.c_void_p.from_address(message_addr).value
145
- message_id = wintypes.UINT.from_address(message_addr + ctypes.sizeof(ctypes.c_void_p)).value
146
- wParam = wintypes.WPARAM.from_address(message_addr + 2 * ctypes.sizeof(ctypes.c_void_p)).value
147
- lParam = wintypes.LPARAM.from_address(message_addr + 3 * ctypes.sizeof(ctypes.c_void_p)).value
148
-
149
- if message_id == WM_NCHITTEST:
150
- x = ctypes.c_short(lParam & 0xFFFF).value
151
- y = ctypes.c_short((lParam >> 16) & 0xFFFF).value
152
-
153
- rect = wintypes.RECT()
154
- user32.GetWindowRect(self.hwnd, ctypes.byref(rect))
155
- left, top, right, bottom = rect.left, rect.top, rect.right, rect.bottom
156
- border = self.resize_border
157
-
158
- if left <= x < left + border:
159
- if top <= y < top + border:
160
- return True, 13 # HTTOPLEFT
161
- elif bottom - border <= y < bottom:
162
- return True, 16 # HTBOTTOMLEFT
163
- else:
164
- return True, 10 # HTLEFT
165
- elif right - border <= x < right:
166
- if top <= y < top + border:
167
- return True, 14 # HTTOPRIGHT
168
- elif bottom - border <= y < bottom:
169
- return True, 17 # HTBOTTOMRIGHT
170
- else:
171
- return True, 11 # HTRIGHT
172
- elif top <= y < top + border:
173
- return True, 12 # HTTOP
174
- elif bottom - border <= y < bottom:
175
- return True, 15 # HTBOTTOM
176
-
177
- # 其他区域不处理
178
- return False, 0
179
-
180
- # 移除标题栏
181
- elif message_id == WM_NCCALCSIZE and wParam:
182
- return True, 0
183
-
184
- # 支持动画
185
- elif message_id == WM_SYSCOMMAND:
186
- return False, 0
187
-
188
- # 处理 WM_GETMINMAXINFO 消息以支持 Snap 功能
189
- elif message_id == WM_GETMINMAXINFO:
190
- # 获取屏幕工作区大小
191
- monitor = user32.MonitorFromWindow(self.hwnd, 2) # MONITOR_DEFAULTTONEAREST
192
-
193
- # 使用自定义的 MONITORINFO 结构
194
- monitor_info = MONITORINFO()
195
- monitor_info.cbSize = ctypes.sizeof(MONITORINFO)
196
- monitor_info.dwFlags = 0
197
- user32.GetMonitorInfoW(monitor, ctypes.byref(monitor_info))
198
-
199
- # 获取 MINMAXINFO 结构
200
- minmax_info = MINMAXINFO.from_address(lParam)
201
-
202
- # 设置最大化位置和大小
203
- minmax_info.ptMaxPosition.x = monitor_info.rcWork.left - monitor_info.rcMonitor.left
204
- minmax_info.ptMaxPosition.y = monitor_info.rcWork.top - monitor_info.rcMonitor.top
205
- minmax_info.ptMaxSize.x = monitor_info.rcWork.right - monitor_info.rcWork.left
206
- minmax_info.ptMaxSize.y = monitor_info.rcWork.bottom - monitor_info.rcWork.top
207
-
208
- # 设置最小跟踪大小
209
- minmax_info.ptMinTrackSize.x = 200 # 最小宽度
210
- minmax_info.ptMinTrackSize.y = 150 # 最小高度
211
-
212
- return True, 0
213
-
214
- return False, 0
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes