RinUI 0.1.5.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.5.1/RinUI.egg-info → rinui-0.1.5.2}/PKG-INFO +1 -1
  2. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/__init__.py +1 -1
  3. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/core/launcher.py +6 -2
  4. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/core/theme.py +0 -2
  5. rinui-0.1.5.2/RinUI/core/window.py +235 -0
  6. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/CtrlBtn.qml +5 -1
  7. {rinui-0.1.5.1 → rinui-0.1.5.2/RinUI.egg-info}/PKG-INFO +1 -1
  8. {rinui-0.1.5.1 → rinui-0.1.5.2}/pyproject.toml +1 -1
  9. rinui-0.1.5.1/RinUI/core/window.py +0 -228
  10. {rinui-0.1.5.1 → rinui-0.1.5.2}/LICENSE +0 -0
  11. {rinui-0.1.5.1 → rinui-0.1.5.2}/MANIFEST.in +0 -0
  12. {rinui-0.1.5.1 → rinui-0.1.5.2}/README.md +0 -0
  13. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/assets/fonts/FluentSystemIcons-Index.js +0 -0
  14. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/assets/fonts/FluentSystemIcons-Resizable.ttf +0 -0
  15. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/assets/img/default_app_icon.png +0 -0
  16. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Base.qml +0 -0
  17. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Button.qml +0 -0
  18. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/CheckBox.qml +0 -0
  19. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ComboBox.qml +0 -0
  20. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/DropDownButton.qml +0 -0
  21. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Hyperlink.qml +0 -0
  22. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/PillButton.qml +0 -0
  23. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/RadioButton.qml +0 -0
  24. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/RoundButton.qml +0 -0
  25. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Slider.qml +0 -0
  26. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/Switch.qml +0 -0
  27. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ToggleButton.qml +0 -0
  28. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/BasicInput/ToolButton.qml +0 -0
  29. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ContextMenu.qml +0 -0
  30. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/DatePicker.qml +0 -0
  31. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/PickerView.qml +0 -0
  32. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DateAndTime/TimePicker.qml +0 -0
  33. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Dialog.qml +0 -0
  34. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/DialogButtonBox.qml +0 -0
  35. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Flyout.qml +0 -0
  36. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/DialogsAndFlyouts/Popup.qml +0 -0
  37. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/FocusIndicator.qml +0 -0
  38. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/IconWidget.qml +0 -0
  39. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Indicator.qml +0 -0
  40. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Layout/Expander.qml +0 -0
  41. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Layout/SettingExpander.qml +0 -0
  42. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Layout/SettingItem.qml +0 -0
  43. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/Clip.qml +0 -0
  44. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/Frame.qml +0 -0
  45. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/ListView.qml +0 -0
  46. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/ListViewDelegate.qml +0 -0
  47. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/SettingCard.qml +0 -0
  48. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/TableView.qml +0 -0
  49. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ListAndCollections/TableViewDelegate.qml +0 -0
  50. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Media/Avatar.qml +0 -0
  51. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/Menu.qml +0 -0
  52. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuBar.qml +0 -0
  53. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuItem.qml +0 -0
  54. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuItemGroup.qml +0 -0
  55. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/MenuSeparator.qml +0 -0
  56. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/TextInputMenu.qml +0 -0
  57. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/MenusAndToolbars/ToolSeparator.qml +0 -0
  58. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/ErrorPage.qml +0 -0
  59. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationBar.qml +0 -0
  60. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationItem.qml +0 -0
  61. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationSubItem.qml +0 -0
  62. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/NavigationView.qml +0 -0
  63. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/Segmented.qml +0 -0
  64. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SegmentedItem.qml +0 -0
  65. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SelectorBar.qml +0 -0
  66. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Navigation/SelectorBarItem.qml +0 -0
  67. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ScrollBar.qml +0 -0
  68. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/ScrollView.qml +0 -0
  69. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Shadow.qml +0 -0
  70. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/BusyIndicator.qml +0 -0
  71. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/InfoBadge.qml +0 -0
  72. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/InfoBar.qml +0 -0
  73. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ProgressBar.qml +0 -0
  74. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ProgressRing.qml +0 -0
  75. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/Toast.qml +0 -0
  76. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/StatusAndInfo/ToolTip.qml +0 -0
  77. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Text/SpinBox.qml +0 -0
  78. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Text/Text.qml +0 -0
  79. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Text/TextArea.qml +0 -0
  80. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Text/TextField.qml +0 -0
  81. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/Text/TextInput.qml +0 -0
  82. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/components/qmldir +0 -0
  83. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/core/__init__.py +0 -0
  84. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/core/config.py +0 -0
  85. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/core/translator.py +0 -0
  86. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/hooks/__init__.py +0 -0
  87. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/hooks/hook-RinUI.py +0 -0
  88. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/languages/en_US.qm +0 -0
  89. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/languages/en_US.ts +0 -0
  90. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/languages/zh_CN.qm +0 -0
  91. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/languages/zh_CN.ts +0 -0
  92. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/qmldir +0 -0
  93. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/Appearance.qml +0 -0
  94. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/Colors.qml +0 -0
  95. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/dark.qml +0 -0
  96. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/light.qml +0 -0
  97. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/qmldir +0 -0
  98. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/theme.qml +0 -0
  99. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/themes/utils.qml +0 -0
  100. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/Animation.qml +0 -0
  101. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/FloatLayer.qml +0 -0
  102. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/FontIconLoader.qml +0 -0
  103. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/Position.qml +0 -0
  104. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/Severity.qml +0 -0
  105. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/Typography.qml +0 -0
  106. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/utils/qmldir +0 -0
  107. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/FluentPage.qml +0 -0
  108. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/FluentWindow.qml +0 -0
  109. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/FluentWindowBase.qml +0 -0
  110. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/TitleBar.qml +0 -0
  111. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/WindowManager.qml +0 -0
  112. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/qmldir +0 -0
  113. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/window/ApplicationWindow.qml +0 -0
  114. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI/windows/window/Window.qml +0 -0
  115. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI.egg-info/SOURCES.txt +0 -0
  116. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI.egg-info/dependency_links.txt +0 -0
  117. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI.egg-info/entry_points.txt +0 -0
  118. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI.egg-info/requires.txt +0 -0
  119. {rinui-0.1.5.1 → rinui-0.1.5.2}/RinUI.egg-info/top_level.txt +0 -0
  120. {rinui-0.1.5.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.5.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.5.1"
3
+ __version__ = "0.1.5.2"
4
4
  __author__ = "RinLit"
@@ -3,6 +3,7 @@ from typing import Union
3
3
 
4
4
  from PySide6.QtCore import QCoreApplication, QUrl, QObject
5
5
  from PySide6.QtGui import QIcon
6
+ from PySide6.QtQuick import QQuickWindow
6
7
  from PySide6.QtWidgets import QApplication
7
8
  from PySide6.QtQml import QQmlApplicationEngine
8
9
  from pathlib import Path
@@ -19,6 +20,7 @@ class RinUIWindow:
19
20
  :param qml_path: str or Path, QML file path (eg = "path/to/main.qml")
20
21
  """
21
22
  super().__init__()
23
+ self.windows = None
22
24
  if hasattr(self, "_initialized") and self._initialized:
23
25
  return
24
26
 
@@ -72,8 +74,10 @@ class RinUIWindow:
72
74
 
73
75
  # 窗口设置
74
76
  self.root_window = self.engine.rootObjects()[0]
77
+ self.windows = [self.root_window] + self.root_window.findChildren(QQuickWindow)
75
78
 
76
- self.theme_manager.set_window(self.root_window)
79
+ for window in self.windows:
80
+ self.theme_manager.set_window(window)
77
81
 
78
82
  # 窗口句柄管理
79
83
  self._window_handle_setup()
@@ -90,7 +94,7 @@ class RinUIWindow:
90
94
 
91
95
  from .window import WinEventFilter, WinEventManager
92
96
 
93
- self.win_event_filter = WinEventFilter(self.root_window)
97
+ self.win_event_filter = WinEventFilter(self.windows)
94
98
  self.win_event_manager = WinEventManager()
95
99
 
96
100
  app_instance = QApplication.instance()
@@ -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
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: RinUI
3
- Version: 0.1.5.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.5.1"
7
+ version = "0.1.5.2"
8
8
  authors = [
9
9
  { name = "RinLit", email = "lintu233_qwq@icloud.com" }
10
10
  ]
@@ -1,228 +0,0 @@
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, window: QQuickWindow):
117
- super().__init__()
118
- self.window = window
119
- self.hwnd: Optional[int] = None
120
- self.resize_border = 8
121
-
122
- if not self.window.isVisible():
123
- self.window.visibleChanged.connect(self._on_visible_changed)
124
- else:
125
- self._init_window_handle()
126
-
127
- def _on_visible_changed(self, visible: bool):
128
- if visible and self.hwnd is None:
129
- self._init_window_handle()
130
-
131
- def _init_window_handle(self):
132
- self.hwnd = int(self.window.winId())
133
- self.set_window_styles()
134
- print(f"Window handle set: {self.hwnd}")
135
-
136
- def set_window_styles(self):
137
- """设置必要的窗口样式以启用原生窗口行为"""
138
- style = user32.GetWindowLongPtrW(self.hwnd, -16) # GWL_STYLE
139
-
140
- style |= WS_CAPTION | WS_THICKFRAME
141
- user32.SetWindowLongPtrW(self.hwnd, -16, style) # GWL_STYLE
142
-
143
- # 重绘
144
- user32.SetWindowPos(self.hwnd, 0, 0, 0, 0, 0,
145
- 0x0002 | 0x0001 | 0x0040) # SWP_NOMOVE | SWP_NOSIZE | SWP_FRAMECHANGED
146
-
147
- def nativeEventFilter(self, eventType: QByteArray, message):
148
- if eventType != b"windows_generic_MSG":
149
- return False, 0
150
-
151
- try:
152
- message_addr = int(message)
153
- except:
154
- buf = memoryview(message)
155
- message_addr = ctypes.addressof(ctypes.c_char.from_buffer(buf))
156
-
157
- # 直接使用内存地址访问 MSG 字段
158
- hwnd = ctypes.c_void_p.from_address(message_addr).value
159
- message_id = wintypes.UINT.from_address(message_addr + ctypes.sizeof(ctypes.c_void_p)).value
160
- wParam = wintypes.WPARAM.from_address(message_addr + 2 * ctypes.sizeof(ctypes.c_void_p)).value
161
- lParam = wintypes.LPARAM.from_address(message_addr + 3 * ctypes.sizeof(ctypes.c_void_p)).value
162
-
163
- if message_id == WM_NCHITTEST:
164
- x = ctypes.c_short(lParam & 0xFFFF).value
165
- y = ctypes.c_short((lParam >> 16) & 0xFFFF).value
166
-
167
- rect = wintypes.RECT()
168
- user32.GetWindowRect(self.hwnd, ctypes.byref(rect))
169
- left, top, right, bottom = rect.left, rect.top, rect.right, rect.bottom
170
- border = self.resize_border
171
-
172
- if left <= x < left + border:
173
- if top <= y < top + border:
174
- return True, 13 # HTTOPLEFT
175
- elif bottom - border <= y < bottom:
176
- return True, 16 # HTBOTTOMLEFT
177
- else:
178
- return True, 10 # HTLEFT
179
- elif right - border <= x < right:
180
- if top <= y < top + border:
181
- return True, 14 # HTTOPRIGHT
182
- elif bottom - border <= y < bottom:
183
- return True, 17 # HTBOTTOMRIGHT
184
- else:
185
- return True, 11 # HTRIGHT
186
- elif top <= y < top + border:
187
- return True, 12 # HTTOP
188
- elif bottom - border <= y < bottom:
189
- return True, 15 # HTBOTTOM
190
-
191
- # 其他区域不处理
192
- return False, 0
193
-
194
- # 移除标题栏
195
- elif message_id == WM_NCCALCSIZE and wParam:
196
- return True, 0
197
-
198
- # 支持动画
199
- elif message_id == WM_SYSCOMMAND:
200
- return False, 0
201
-
202
- # 处理 WM_GETMINMAXINFO 消息以支持 Snap 功能
203
- elif message_id == WM_GETMINMAXINFO:
204
- # 获取屏幕工作区大小
205
- monitor = user32.MonitorFromWindow(self.hwnd, 2) # MONITOR_DEFAULTTONEAREST
206
-
207
- # 使用自定义的 MONITORINFO 结构
208
- monitor_info = MONITORINFO()
209
- monitor_info.cbSize = ctypes.sizeof(MONITORINFO)
210
- monitor_info.dwFlags = 0
211
- user32.GetMonitorInfoW(monitor, ctypes.byref(monitor_info))
212
-
213
- # 获取 MINMAXINFO 结构
214
- minmax_info = MINMAXINFO.from_address(lParam)
215
-
216
- # 设置最大化位置和大小
217
- minmax_info.ptMaxPosition.x = monitor_info.rcWork.left - monitor_info.rcMonitor.left
218
- minmax_info.ptMaxPosition.y = monitor_info.rcWork.top - monitor_info.rcMonitor.top
219
- minmax_info.ptMaxSize.x = monitor_info.rcWork.right - monitor_info.rcWork.left
220
- minmax_info.ptMaxSize.y = monitor_info.rcWork.bottom - monitor_info.rcWork.top
221
-
222
- # 设置最小跟踪大小
223
- minmax_info.ptMinTrackSize.x = 200 # 最小宽度
224
- minmax_info.ptMinTrackSize.y = 150 # 最小高度
225
-
226
- return True, 0
227
-
228
- 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