pyloid 0.16.2__py3-none-any.whl → 0.16.5__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.
- pyloid/browser_window.py +247 -3
- pyloid/js_api/window_api.py +36 -0
- pyloid/pyloid.py +78 -4
- {pyloid-0.16.2.dist-info → pyloid-0.16.5.dist-info}/METADATA +1 -1
- {pyloid-0.16.2.dist-info → pyloid-0.16.5.dist-info}/RECORD +7 -7
- {pyloid-0.16.2.dist-info → pyloid-0.16.5.dist-info}/LICENSE +0 -0
- {pyloid-0.16.2.dist-info → pyloid-0.16.5.dist-info}/WHEEL +0 -0
pyloid/browser_window.py
CHANGED
@@ -25,13 +25,47 @@ from .js_api.window_api import WindowAPI
|
|
25
25
|
from PySide6.QtGui import QPixmap, QMovie
|
26
26
|
from PySide6.QtWidgets import QSplashScreen, QLabel
|
27
27
|
from PySide6.QtCore import QSize
|
28
|
+
from typing import TYPE_CHECKING
|
29
|
+
from PySide6.QtWebEngineCore import QWebEngineSettings
|
30
|
+
|
31
|
+
if TYPE_CHECKING:
|
32
|
+
from ..pyloid import Pyloid
|
28
33
|
|
29
34
|
|
30
35
|
# 어차피 load 부분에만 쓰이니까 나중에 분리해서 load 위에서 선언하자.
|
36
|
+
class CustomWebPage(QWebEnginePage):
|
37
|
+
def __init__(self, profile=None):
|
38
|
+
super().__init__(profile)
|
39
|
+
# 권한 요청 시그널 연결
|
40
|
+
self.featurePermissionRequested.connect(self._handlePermissionRequest)
|
41
|
+
self._permission_handlers = {}
|
42
|
+
|
43
|
+
def _handlePermissionRequest(self, origin: QUrl, feature: QWebEnginePage.Feature):
|
44
|
+
"""기본 권한 요청 핸들러"""
|
45
|
+
if feature in self._permission_handlers:
|
46
|
+
# 등록된 핸들러가 있으면 실행
|
47
|
+
handler = self._permission_handlers[feature]
|
48
|
+
handler(origin, feature)
|
49
|
+
else:
|
50
|
+
# 기본적으로 모든 권한 허용
|
51
|
+
self.setFeaturePermission(
|
52
|
+
origin, feature, QWebEnginePage.PermissionPolicy.PermissionGrantedByUser
|
53
|
+
)
|
54
|
+
|
55
|
+
def setPermissionHandler(self, feature: QWebEnginePage.Feature, handler):
|
56
|
+
"""특정 권한에 대한 핸들러 등록"""
|
57
|
+
self._permission_handlers[feature] = handler
|
58
|
+
|
59
|
+
|
31
60
|
class CustomWebEngineView(QWebEngineView):
|
32
61
|
def __init__(self, parent=None):
|
33
62
|
super().__init__(parent._window)
|
34
63
|
self.parent = parent
|
64
|
+
|
65
|
+
# 커스텀 웹 페이지 설정
|
66
|
+
self.custom_page = CustomWebPage()
|
67
|
+
self.setPage(self.custom_page)
|
68
|
+
|
35
69
|
self.drag_relative_position = None
|
36
70
|
self.is_dragging = False
|
37
71
|
self.is_resizing = False
|
@@ -164,7 +198,7 @@ class CustomWebEngineView(QWebEngineView):
|
|
164
198
|
class BrowserWindow:
|
165
199
|
def __init__(
|
166
200
|
self,
|
167
|
-
app,
|
201
|
+
app: "Pyloid",
|
168
202
|
title: str = "pyloid app",
|
169
203
|
width: int = 800,
|
170
204
|
height: int = 600,
|
@@ -195,6 +229,8 @@ class BrowserWindow:
|
|
195
229
|
for js_api in js_apis:
|
196
230
|
self.js_apis.append(js_api)
|
197
231
|
self.shortcuts = {}
|
232
|
+
self.close_on_load = True
|
233
|
+
self.splash_screen = None
|
198
234
|
###########################################################################################
|
199
235
|
|
200
236
|
def _set_custom_frame(
|
@@ -289,13 +325,13 @@ class BrowserWindow:
|
|
289
325
|
def _on_load_finished(self, ok):
|
290
326
|
"""Handles the event when the web page finishes loading."""
|
291
327
|
if ok and self.js_apis:
|
292
|
-
|
293
328
|
# Load qwebchannel.js
|
294
329
|
qwebchannel_js = QFile("://qtwebchannel/qwebchannel.js")
|
295
330
|
if qwebchannel_js.open(QFile.ReadOnly):
|
296
331
|
source = bytes(qwebchannel_js.readAll()).decode("utf-8")
|
297
332
|
self.web_view.page().runJavaScript(source)
|
298
333
|
qwebchannel_js.close()
|
334
|
+
|
299
335
|
|
300
336
|
js_code = """
|
301
337
|
if (typeof QWebChannel !== 'undefined') {
|
@@ -327,6 +363,22 @@ class BrowserWindow:
|
|
327
363
|
window.pyloid.WindowAPI.startSystemDrag();
|
328
364
|
}
|
329
365
|
});
|
366
|
+
|
367
|
+
function updateTheme(theme) {
|
368
|
+
document.documentElement.setAttribute(
|
369
|
+
'data-pyloid-theme',
|
370
|
+
theme
|
371
|
+
);
|
372
|
+
}
|
373
|
+
|
374
|
+
// 테마 변경 이벤트 리스너
|
375
|
+
document.addEventListener('themeChange', (e) => {
|
376
|
+
console.log('themeChange event received:', e);
|
377
|
+
updateTheme(e.detail.theme);
|
378
|
+
});
|
379
|
+
|
380
|
+
updateTheme('%s');
|
381
|
+
|
330
382
|
|
331
383
|
// Dispatch a custom event to signal that the initialization is ready
|
332
384
|
const event = new CustomEvent('pyloidReady');
|
@@ -343,7 +395,7 @@ class BrowserWindow:
|
|
343
395
|
for js_api in self.js_apis
|
344
396
|
]
|
345
397
|
)
|
346
|
-
self.web_view.page().runJavaScript(js_code % js_api_init)
|
398
|
+
self.web_view.page().runJavaScript(js_code % (js_api_init, self.app.theme))
|
347
399
|
|
348
400
|
# if splash screen is set, close it when the page is loaded
|
349
401
|
if self.close_on_load and self.splash_screen:
|
@@ -481,6 +533,57 @@ class BrowserWindow:
|
|
481
533
|
self.y = y
|
482
534
|
self._window.setGeometry(self.x, self.y, self.width, self.height)
|
483
535
|
|
536
|
+
def set_position_by_anchor(self, anchor: str):
|
537
|
+
"""
|
538
|
+
Positions the window at a specific location on the screen.
|
539
|
+
|
540
|
+
Parameters
|
541
|
+
----------
|
542
|
+
anchor : str
|
543
|
+
The anchor point indicating where to position the window.
|
544
|
+
Possible values: 'center', 'top', 'bottom', 'left', 'right',
|
545
|
+
'top-left', 'top-right', 'bottom-left', 'bottom-right'
|
546
|
+
|
547
|
+
Examples
|
548
|
+
--------
|
549
|
+
>>> window.set_position_by_anchor('center')
|
550
|
+
>>> window.set_position_by_anchor('top-right')
|
551
|
+
"""
|
552
|
+
screen = self.app.primaryScreen().availableGeometry()
|
553
|
+
window_size = self.get_size()
|
554
|
+
|
555
|
+
if anchor == "center":
|
556
|
+
x = (screen.width() - window_size["width"]) // 2
|
557
|
+
y = (screen.height() - window_size["height"]) // 2
|
558
|
+
elif anchor == "top":
|
559
|
+
x = (screen.width() - window_size["width"]) // 2
|
560
|
+
y = screen.top()
|
561
|
+
elif anchor == "bottom":
|
562
|
+
x = (screen.width() - window_size["width"]) // 2
|
563
|
+
y = screen.bottom() - window_size["height"]
|
564
|
+
elif anchor == "left":
|
565
|
+
x = screen.left()
|
566
|
+
y = (screen.height() - window_size["height"]) // 2
|
567
|
+
elif anchor == "right":
|
568
|
+
x = screen.right() - window_size["width"]
|
569
|
+
y = (screen.height() - window_size["height"]) // 2
|
570
|
+
elif anchor == "top-left":
|
571
|
+
x = screen.left()
|
572
|
+
y = screen.top()
|
573
|
+
elif anchor == "top-right":
|
574
|
+
x = screen.right() - window_size["width"]
|
575
|
+
y = screen.top()
|
576
|
+
elif anchor == "bottom-left":
|
577
|
+
x = screen.left()
|
578
|
+
y = screen.bottom() - window_size["height"]
|
579
|
+
elif anchor == "bottom-right":
|
580
|
+
x = screen.right() - window_size["width"]
|
581
|
+
y = screen.bottom() - window_size["height"]
|
582
|
+
else:
|
583
|
+
raise ValueError("Invalid anchor point.")
|
584
|
+
|
585
|
+
self.set_position(x, y)
|
586
|
+
|
484
587
|
def set_frame(self, frame: bool):
|
485
588
|
"""
|
486
589
|
Sets the frame of the window.
|
@@ -1322,6 +1425,26 @@ class BrowserWindow:
|
|
1322
1425
|
"""
|
1323
1426
|
return self._window
|
1324
1427
|
|
1428
|
+
def get_QWebEngineView(self) -> CustomWebEngineView:
|
1429
|
+
"""
|
1430
|
+
Returns the CustomWebEngineView object which inherits from QWebEngineView.
|
1431
|
+
|
1432
|
+
Returns
|
1433
|
+
-------
|
1434
|
+
CustomWebEngineView
|
1435
|
+
CustomWebEngineView object of the window
|
1436
|
+
|
1437
|
+
Examples
|
1438
|
+
--------
|
1439
|
+
```python
|
1440
|
+
window = app.create_window("pyloid-window")
|
1441
|
+
web_view = window.get_QWebEngineView()
|
1442
|
+
|
1443
|
+
web_view.page().runJavaScript("console.log('Hello, Pyloid!')")
|
1444
|
+
```
|
1445
|
+
"""
|
1446
|
+
return self.web_view
|
1447
|
+
|
1325
1448
|
###########################################################################################
|
1326
1449
|
# QMainWindow flags
|
1327
1450
|
###########################################################################################
|
@@ -1552,3 +1675,124 @@ class BrowserWindow:
|
|
1552
1675
|
self.splash_screen.close()
|
1553
1676
|
self.close_on_load = None
|
1554
1677
|
self.splash_screen = None
|
1678
|
+
|
1679
|
+
###########################################################################################
|
1680
|
+
# WebEngineView Attribute setting
|
1681
|
+
###########################################################################################
|
1682
|
+
def set_web_engine_view_attribute(self, attribute: QWebEngineSettings, on: bool):
|
1683
|
+
"""
|
1684
|
+
Sets the attribute of the WebEngineView.
|
1685
|
+
|
1686
|
+
Parameters
|
1687
|
+
----------
|
1688
|
+
attribute : QWebEngineSettings
|
1689
|
+
Attribute to set
|
1690
|
+
on : bool
|
1691
|
+
True to enable the attribute, False to disable it
|
1692
|
+
|
1693
|
+
Examples
|
1694
|
+
--------
|
1695
|
+
```python
|
1696
|
+
window.set_web_engine_view_attribute(QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard, False)
|
1697
|
+
```
|
1698
|
+
"""
|
1699
|
+
settings = self.web_view.settings()
|
1700
|
+
settings.setAttribute(attribute, on)
|
1701
|
+
|
1702
|
+
def is_web_engine_view_attribute(self, attribute: QWebEngineSettings) -> bool:
|
1703
|
+
"""
|
1704
|
+
Returns the attribute of the WebEngineView.
|
1705
|
+
|
1706
|
+
Parameters
|
1707
|
+
----------
|
1708
|
+
attribute : QWebEngineSettings
|
1709
|
+
Attribute to get
|
1710
|
+
|
1711
|
+
Returns
|
1712
|
+
-------
|
1713
|
+
bool
|
1714
|
+
True if the attribute is enabled, False otherwise
|
1715
|
+
|
1716
|
+
Examples
|
1717
|
+
--------
|
1718
|
+
```python
|
1719
|
+
window.is_web_engine_view_attribute(QWebEngineSettings.WebAttribute.JavascriptCanAccessClipboard)
|
1720
|
+
```
|
1721
|
+
"""
|
1722
|
+
settings = self.web_view.settings()
|
1723
|
+
return settings.testAttribute(attribute)
|
1724
|
+
|
1725
|
+
def set_permission_handler(self, feature: QWebEnginePage.Feature, handler):
|
1726
|
+
"""
|
1727
|
+
특정 권한에 대한 핸들러를 설정합니다.
|
1728
|
+
|
1729
|
+
Parameters
|
1730
|
+
----------
|
1731
|
+
feature : QWebEnginePage.Feature
|
1732
|
+
설정할 권한 타입
|
1733
|
+
handler : callable
|
1734
|
+
권한 요청을 처리할 핸들러 함수
|
1735
|
+
|
1736
|
+
Examples
|
1737
|
+
--------
|
1738
|
+
```python
|
1739
|
+
def handle_camera(origin, feature):
|
1740
|
+
window.web_view.page().setFeaturePermission(
|
1741
|
+
origin,
|
1742
|
+
feature,
|
1743
|
+
QWebEnginePage.PermissionPolicy.PermissionGrantedByUser
|
1744
|
+
)
|
1745
|
+
|
1746
|
+
window.set_permission_handler(
|
1747
|
+
QWebEnginePage.Feature.MediaVideoCapture,
|
1748
|
+
handle_camera
|
1749
|
+
)
|
1750
|
+
```
|
1751
|
+
"""
|
1752
|
+
self.web_view.custom_page.setPermissionHandler(feature, handler)
|
1753
|
+
|
1754
|
+
def grant_permission(self, feature: QWebEnginePage.Feature):
|
1755
|
+
"""
|
1756
|
+
권한 요청이 왔을 때, 특정 권한을 자동으로 허용하도록 설정합니다.
|
1757
|
+
|
1758
|
+
Parameters
|
1759
|
+
----------
|
1760
|
+
feature : QWebEnginePage.Feature
|
1761
|
+
자동 허용할 권한 타입
|
1762
|
+
|
1763
|
+
Examples
|
1764
|
+
--------
|
1765
|
+
```python
|
1766
|
+
window.grant_permission(QWebEnginePage.Feature.MediaVideoCapture)
|
1767
|
+
```
|
1768
|
+
"""
|
1769
|
+
|
1770
|
+
def auto_grant(origin, feat):
|
1771
|
+
self.web_view.page().setFeaturePermission(
|
1772
|
+
origin, feat, QWebEnginePage.PermissionPolicy.PermissionGrantedByUser
|
1773
|
+
)
|
1774
|
+
|
1775
|
+
self.set_permission_handler(feature, auto_grant)
|
1776
|
+
|
1777
|
+
def deny_permission(self, feature: QWebEnginePage.Feature):
|
1778
|
+
"""
|
1779
|
+
권한 요청이 왔을 때, 특정 권한을 자동으로 거부하도록 설정합니다.
|
1780
|
+
|
1781
|
+
Parameters
|
1782
|
+
----------
|
1783
|
+
feature : QWebEnginePage.Feature
|
1784
|
+
자동 거부할 권한 타입
|
1785
|
+
|
1786
|
+
Examples
|
1787
|
+
--------
|
1788
|
+
```python
|
1789
|
+
window.deny_permission(QWebEnginePage.Feature.Notifications)
|
1790
|
+
```
|
1791
|
+
"""
|
1792
|
+
|
1793
|
+
def auto_deny(origin, feat):
|
1794
|
+
self.web_view.page().setFeaturePermission(
|
1795
|
+
origin, feat, QWebEnginePage.PermissionPolicy.PermissionDeniedByUser
|
1796
|
+
)
|
1797
|
+
|
1798
|
+
self.set_permission_handler(feature, auto_deny)
|
pyloid/js_api/window_api.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from typing import TYPE_CHECKING, Optional
|
2
2
|
|
3
3
|
from ..api import PyloidAPI, Bridge
|
4
|
+
from PySide6.QtCore import QByteArray, QBuffer, QIODeviceBase
|
4
5
|
|
5
6
|
if TYPE_CHECKING:
|
6
7
|
from ..pyloid import Pyloid
|
@@ -208,3 +209,38 @@ class WindowAPI(PyloidAPI):
|
|
208
209
|
window = self.app.get_window_by_id(self.window_id)
|
209
210
|
if window:
|
210
211
|
window.web_view.start_system_drag()
|
212
|
+
|
213
|
+
###############################################################
|
214
|
+
# Clipboard
|
215
|
+
###############################################################
|
216
|
+
|
217
|
+
@Bridge(str)
|
218
|
+
def setClipboardText(self, text: str):
|
219
|
+
"""Sets the text to the clipboard."""
|
220
|
+
self.app.set_clipboard_text(text)
|
221
|
+
|
222
|
+
@Bridge(result=str)
|
223
|
+
def getClipboardText(self):
|
224
|
+
"""Gets the text from the clipboard."""
|
225
|
+
return self.app.get_clipboard_text()
|
226
|
+
|
227
|
+
@Bridge(str, str)
|
228
|
+
def setClipboardImage(self, image_path: str, format: str):
|
229
|
+
"""Sets the image to the clipboard."""
|
230
|
+
self.app.set_clipboard_image(image_path, format)
|
231
|
+
|
232
|
+
@Bridge(result=str)
|
233
|
+
def getClipboardImage(self):
|
234
|
+
"""클립보드의 이미지를 Base64 인코딩된 데이터 URL로 반환합니다."""
|
235
|
+
image = self.app.get_clipboard_image() # QImage 반환 가정
|
236
|
+
if image and not image.isNull():
|
237
|
+
# QImage를 바이트 배열로 변환
|
238
|
+
byte_array = QByteArray()
|
239
|
+
buffer = QBuffer(byte_array)
|
240
|
+
buffer.open(QIODeviceBase.WriteOnly)
|
241
|
+
image.save(buffer, "PNG") # PNG 형식으로 저장
|
242
|
+
|
243
|
+
# Base64로 인코딩
|
244
|
+
base64_data = byte_array.toBase64().data().decode()
|
245
|
+
return f"data:image/png;base64,{base64_data}"
|
246
|
+
return ""
|
pyloid/pyloid.py
CHANGED
@@ -15,7 +15,7 @@ from PySide6.QtGui import (
|
|
15
15
|
from PySide6.QtCore import Qt, Signal, QObject, QTimer
|
16
16
|
from PySide6.QtNetwork import QLocalServer, QLocalSocket
|
17
17
|
from .api import PyloidAPI
|
18
|
-
from typing import List, Optional, Dict, Callable, Union
|
18
|
+
from typing import List, Optional, Dict, Callable, Union, Literal
|
19
19
|
from PySide6.QtCore import qInstallMessageHandler
|
20
20
|
import signal
|
21
21
|
from .utils import is_production
|
@@ -25,6 +25,7 @@ from .filewatcher import FileWatcher
|
|
25
25
|
import logging
|
26
26
|
from .browser_window import BrowserWindow
|
27
27
|
from .tray import TrayEvent
|
28
|
+
from PySide6.QtCore import QCoreApplication
|
28
29
|
|
29
30
|
# for linux debug
|
30
31
|
os.environ["QTWEBENGINE_DICTIONARIES_PATH"] = "/"
|
@@ -32,6 +33,11 @@ os.environ["QTWEBENGINE_DICTIONARIES_PATH"] = "/"
|
|
32
33
|
# for macos debug
|
33
34
|
logging.getLogger("Qt").setLevel(logging.ERROR)
|
34
35
|
|
36
|
+
QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling)
|
37
|
+
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = (
|
38
|
+
"--enable-features=WebRTCPipeWireCapturer --ignore-certificate-errors --allow-insecure-localhost"
|
39
|
+
)
|
40
|
+
|
35
41
|
|
36
42
|
def custom_message_handler(mode, context, message):
|
37
43
|
if not hasattr(custom_message_handler, "vulkan_warning_shown") and (
|
@@ -56,6 +62,7 @@ def custom_message_handler(mode, context, message):
|
|
56
62
|
|
57
63
|
qInstallMessageHandler(custom_message_handler)
|
58
64
|
|
65
|
+
|
59
66
|
class _WindowController(QObject):
|
60
67
|
create_window_signal = Signal(
|
61
68
|
QApplication, str, int, int, int, int, bool, bool, bool, list
|
@@ -123,6 +130,51 @@ class Pyloid(QApplication):
|
|
123
130
|
self.icon_frames = []
|
124
131
|
self.current_frame = 0
|
125
132
|
|
133
|
+
self.theme = (
|
134
|
+
"dark"
|
135
|
+
if self.styleHints().colorScheme() == Qt.ColorScheme.Dark
|
136
|
+
else "light"
|
137
|
+
)
|
138
|
+
|
139
|
+
# Add color scheme tracking
|
140
|
+
self.styleHints().colorSchemeChanged.connect(self._handle_color_scheme_change)
|
141
|
+
|
142
|
+
# def set_theme(self, theme: Literal["system", "dark", "light"]):
|
143
|
+
# """
|
144
|
+
# 시스템의 테마를 설정합니다.
|
145
|
+
|
146
|
+
# Parameters
|
147
|
+
# ----------
|
148
|
+
# theme : Literal["system", "dark", "light"]
|
149
|
+
# 설정할 테마 ("system", "dark", "light" 중 하나)
|
150
|
+
|
151
|
+
# Examples
|
152
|
+
# --------
|
153
|
+
# >>> app = Pyloid(app_name="Pyloid-App")
|
154
|
+
# >>> app.set_theme("dark") # 다크 테마로 설정
|
155
|
+
# >>> app.set_theme("light") # 라이트 테마로 설정
|
156
|
+
# >>> app.set_theme("system") # 시스템 테마를 따름
|
157
|
+
# """
|
158
|
+
# self.theme = theme
|
159
|
+
|
160
|
+
# if theme == "system":
|
161
|
+
# # 시스템 테마를 light/dark 문자열로 변환
|
162
|
+
# system_theme = (
|
163
|
+
# "dark"
|
164
|
+
# if self.styleHints().colorScheme() == Qt.ColorScheme.Dark
|
165
|
+
# else "light"
|
166
|
+
# )
|
167
|
+
# self._handle_color_scheme_change(system_theme)
|
168
|
+
# self.styleHints().colorSchemeChanged.connect(
|
169
|
+
# lambda: self._handle_color_scheme_change(system_theme)
|
170
|
+
# )
|
171
|
+
# else:
|
172
|
+
# # 기존 이벤트 연결 해제
|
173
|
+
# self.styleHints().colorSchemeChanged.disconnect(
|
174
|
+
# lambda: self._handle_color_scheme_change(self.theme)
|
175
|
+
# )
|
176
|
+
# self._handle_color_scheme_change(self.theme)
|
177
|
+
|
126
178
|
def set_icon(self, icon_path: str):
|
127
179
|
"""
|
128
180
|
Dynamically sets the application's icon.
|
@@ -407,7 +459,7 @@ class Pyloid(QApplication):
|
|
407
459
|
app = Pyloid(app_name="Pyloid-App")
|
408
460
|
|
409
461
|
window = app.get_window_by_id("123e4567-e89b-12d3-a456-426614174000")
|
410
|
-
|
462
|
+
|
411
463
|
if window:
|
412
464
|
print("Window found:", window)
|
413
465
|
```
|
@@ -1244,7 +1296,9 @@ class Pyloid(QApplication):
|
|
1244
1296
|
###########################################################################################
|
1245
1297
|
# File dialog
|
1246
1298
|
###########################################################################################
|
1247
|
-
def open_file_dialog(
|
1299
|
+
def open_file_dialog(
|
1300
|
+
self, dir: Optional[str] = None, filter: Optional[str] = None
|
1301
|
+
) -> Optional[str]:
|
1248
1302
|
"""
|
1249
1303
|
Opens a file dialog to select a file to open.
|
1250
1304
|
|
@@ -1270,7 +1324,9 @@ class Pyloid(QApplication):
|
|
1270
1324
|
file_path, _ = QFileDialog.getOpenFileName(None, dir=dir, filter=filter)
|
1271
1325
|
return file_path if file_path else None
|
1272
1326
|
|
1273
|
-
def save_file_dialog(
|
1327
|
+
def save_file_dialog(
|
1328
|
+
self, dir: Optional[str] = None, filter: Optional[str] = None
|
1329
|
+
) -> Optional[str]:
|
1274
1330
|
"""
|
1275
1331
|
Opens a file dialog to select a file to save.
|
1276
1332
|
|
@@ -1320,4 +1376,22 @@ class Pyloid(QApplication):
|
|
1320
1376
|
directory_path = QFileDialog.getExistingDirectory(None, dir=dir)
|
1321
1377
|
return directory_path if directory_path else None
|
1322
1378
|
|
1379
|
+
def _handle_color_scheme_change(self):
|
1380
|
+
self.theme = (
|
1381
|
+
"dark"
|
1382
|
+
if self.styleHints().colorScheme() == Qt.ColorScheme.Dark
|
1383
|
+
else "light"
|
1384
|
+
)
|
1385
|
+
|
1386
|
+
js_code = f"""
|
1387
|
+
document.dispatchEvent(new CustomEvent('themeChange', {{
|
1388
|
+
detail: {{ theme: "{self.theme}" }}
|
1389
|
+
}}));
|
1390
|
+
"""
|
1323
1391
|
|
1392
|
+
# 모든 윈도우에 변경사항 적용
|
1393
|
+
for window in self.windows:
|
1394
|
+
window.web_view.page().runJavaScript(js_code)
|
1395
|
+
window.web_view.page().setBackgroundColor(
|
1396
|
+
Qt.GlobalColor.black if self.theme == "dark" else Qt.GlobalColor.white
|
1397
|
+
)
|
@@ -1,17 +1,17 @@
|
|
1
1
|
pyloid/__init__.py,sha256=OOPhOKNQVmAM8hnfTeE7lHzxb8LsFNcgegBAvDrA-vY,293
|
2
2
|
pyloid/api.py,sha256=np0pFVUlen_GpN0svY0A3awY_ZjVFk-RpHQZZKFUMuo,2157
|
3
3
|
pyloid/autostart.py,sha256=K7DQYl4LHItvPp0bt1V9WwaaZmVSTeGvadkcwG-KKrI,3899
|
4
|
-
pyloid/browser_window.py,sha256=
|
4
|
+
pyloid/browser_window.py,sha256=aISmYtmf-suKPiN42wGskeNRVlkmkSV4CIKKfB-W8Cw,58251
|
5
5
|
pyloid/custom/titlebar.py,sha256=itzK9pJbZMQ7BKca9kdbuHMffurrw15UijR6OU03Xsk,3894
|
6
6
|
pyloid/filewatcher.py,sha256=3M5zWVUf1OhlkWJcDFC8ZA9agO4Q-U8WdgGpy6kaVz0,4601
|
7
7
|
pyloid/js_api/event_api.py,sha256=_52yyBonqecmMvJpFW7OMNi_jX8Nrteqw_kI6r-DGG0,951
|
8
|
-
pyloid/js_api/window_api.py,sha256=
|
8
|
+
pyloid/js_api/window_api.py,sha256=_EAZ0GG0oa0EeIIyWnys03InLQuQfv4ZPezMouOJEGc,8155
|
9
9
|
pyloid/monitor.py,sha256=nmcoOmlHeTysrZVT5mmL92ASbqMg8aH-hQg35qKWi0M,27540
|
10
|
-
pyloid/pyloid.py,sha256=
|
10
|
+
pyloid/pyloid.py,sha256=2YcI0vn5VvCf4oXwsS3Y_7itlzjGlHQEQIbpwR_rkZ4,43874
|
11
11
|
pyloid/timer.py,sha256=RqMsChFUd93cxMVgkHWiIKrci0QDTBgJSTULnAtYT8M,8712
|
12
12
|
pyloid/tray.py,sha256=D12opVEc2wc2T4tK9epaN1oOdeziScsIVNM2uCN7C-A,1710
|
13
13
|
pyloid/utils.py,sha256=VGZE2liY8_AElEqxVe1YLbk3fWlcAevpRc6oOTTgi-U,1927
|
14
|
-
pyloid-0.16.
|
15
|
-
pyloid-0.16.
|
16
|
-
pyloid-0.16.
|
17
|
-
pyloid-0.16.
|
14
|
+
pyloid-0.16.5.dist-info/LICENSE,sha256=MTYF-6xpRekyTUglRweWtbfbwBL1I_3Bgfbm_SNOuI8,11525
|
15
|
+
pyloid-0.16.5.dist-info/METADATA,sha256=P8jz2kA5mL5UU9U-LqjGhwfpKLCHg8x6o2nzFOyn7Fs,3050
|
16
|
+
pyloid-0.16.5.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
17
|
+
pyloid-0.16.5.dist-info/RECORD,,
|
File without changes
|
File without changes
|