Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea8e659179 | ||
|
|
43bec22244 | ||
|
|
67cb8156fa | ||
|
|
0437172f67 | ||
|
|
85200fb23d | ||
|
|
03b05ecc08 | ||
|
|
34db86fdac | ||
|
|
ed74e97693 | ||
|
|
9eb1d2cc88 | ||
|
|
9a64fecd3d | ||
|
|
904e8ba82b | ||
|
|
a80d28c616 |
10
README.md
10
README.md
@@ -1,10 +1,8 @@
|
|||||||
## overlaynote
|
## overlaynote
|
||||||
minimal note overlay
|
minimal note overlay
|
||||||
v1.0
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
*v1* <br>
|
|
||||||
<a href="https://git.backend-3.com/admin/overlaynote/releases">download</a>
|
|
||||||
|
|
||||||
|
|
||||||
|
v1.1
|
||||||
|
<a href="https://git.backend-3.com/admin/overlaynote/releases/download/v1.1/overlaynote.exe" download style="text-decoration:underline;">download</a>
|
||||||
|
|
||||||
|
<img width="790vw" src="https://git.backend-3.com/admin/i/raw/branch/main/1etagdzc.png" >
|
||||||
|
|||||||
@@ -1,34 +1,62 @@
|
|||||||
# v3.1.1 settings.py
|
# v4.0.0 settings.py
|
||||||
import json
|
import json
|
||||||
|
import sys
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Final
|
from typing import Final
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_app_dir() -> Path:
|
||||||
|
if getattr(sys, "frozen", False):
|
||||||
|
return Path(
|
||||||
|
sys.executable
|
||||||
|
).resolve().parent
|
||||||
|
|
||||||
|
return (
|
||||||
|
Path(__file__)
|
||||||
|
.resolve()
|
||||||
|
.parent
|
||||||
|
.parent
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
APP_DIR: Final[Path] = (
|
APP_DIR: Final[Path] = (
|
||||||
Path(__file__).resolve().parent.parent
|
resolve_app_dir()
|
||||||
|
)
|
||||||
|
|
||||||
|
APP_DIR.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
SETTINGS_FILE: Final[Path] = (
|
SETTINGS_FILE: Final[Path] = (
|
||||||
APP_DIR / "settings.json"
|
APP_DIR / "settings.json"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
STATE_FILE: Final[Path] = (
|
||||||
|
APP_DIR / "active.json"
|
||||||
|
)
|
||||||
|
|
||||||
|
MARKDOWN_FILE: Final[Path] = (
|
||||||
|
APP_DIR / "note.md"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
DEFAULT_SETTINGS: Final[dict] = {
|
DEFAULT_SETTINGS: Final[dict] = {
|
||||||
"active_profile": "default",
|
"active_profile": "default",
|
||||||
"profiles": {
|
"profiles": {
|
||||||
"default": {
|
"default": {
|
||||||
"theme": "macos_blue",
|
"theme": "dark",
|
||||||
"window": {
|
"window": {
|
||||||
"width": 260,
|
"width": 250,
|
||||||
"height": 300,
|
"height": 260,
|
||||||
"min_width": 220,
|
"min_width": 200,
|
||||||
"min_height": 140,
|
"min_height": 100,
|
||||||
"layout_margin": 4,
|
"layout_margin": 0,
|
||||||
"layout_spacing": 4,
|
"layout_spacing": 0,
|
||||||
"drag_handle_height": 28,
|
"drag_handle_height": 0,
|
||||||
"resize_grip_size": 16,
|
"resize_grip_size": 16,
|
||||||
"corner_radius": 16,
|
"corner_radius": 8,
|
||||||
"startup_stabilize_ms": 80,
|
"startup_stabilize_ms": 80,
|
||||||
},
|
},
|
||||||
"appearance": {
|
"appearance": {
|
||||||
@@ -36,10 +64,10 @@ DEFAULT_SETTINGS: Final[dict] = {
|
|||||||
"enable_acrylic": True,
|
"enable_acrylic": True,
|
||||||
"enable_glass_blur": True,
|
"enable_glass_blur": True,
|
||||||
"enable_animations": True,
|
"enable_animations": True,
|
||||||
"enable_shadow": True,
|
"enable_shadow": False,
|
||||||
"opacity_active": 0.99,
|
"opacity_active": 0.97,
|
||||||
"opacity_inactive": 0.95,
|
"opacity_inactive": 0.95,
|
||||||
"opacity_dragging": 0.98,
|
"opacity_dragging": 0.89,
|
||||||
"focus_animation_ms": 180,
|
"focus_animation_ms": 180,
|
||||||
},
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
@@ -50,7 +78,7 @@ DEFAULT_SETTINGS: Final[dict] = {
|
|||||||
"Arial",
|
"Arial",
|
||||||
"system-ui",
|
"system-ui",
|
||||||
],
|
],
|
||||||
"font_size": 15,
|
"font_size": 13,
|
||||||
"preview_delay_ms": 700,
|
"preview_delay_ms": 700,
|
||||||
"save_debounce_ms": 500,
|
"save_debounce_ms": 500,
|
||||||
"max_note_size": 2_000_000,
|
"max_note_size": 2_000_000,
|
||||||
@@ -58,7 +86,7 @@ DEFAULT_SETTINGS: Final[dict] = {
|
|||||||
"enable_clickable_links": True,
|
"enable_clickable_links": True,
|
||||||
"enable_antialiasing": True,
|
"enable_antialiasing": True,
|
||||||
"enable_spellcheck": False,
|
"enable_spellcheck": False,
|
||||||
"padding": 8,
|
"padding": 0,
|
||||||
},
|
},
|
||||||
"behavior": {
|
"behavior": {
|
||||||
"enable_tray": True,
|
"enable_tray": True,
|
||||||
@@ -68,127 +96,49 @@ DEFAULT_SETTINGS: Final[dict] = {
|
|||||||
"high_contrast_inactive": False,
|
"high_contrast_inactive": False,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"light": {
|
|
||||||
"theme": "light",
|
|
||||||
"window": {
|
|
||||||
"width": 260,
|
|
||||||
"height": 300,
|
|
||||||
"min_width": 220,
|
|
||||||
"min_height": 140,
|
|
||||||
"layout_margin": 4,
|
|
||||||
"layout_spacing": 4,
|
|
||||||
"drag_handle_height": 28,
|
|
||||||
"resize_grip_size": 16,
|
|
||||||
"corner_radius": 16,
|
|
||||||
"startup_stabilize_ms": 80,
|
|
||||||
},
|
|
||||||
"appearance": {
|
|
||||||
"enable_mica": True,
|
|
||||||
"enable_acrylic": True,
|
|
||||||
"enable_glass_blur": True,
|
|
||||||
"enable_animations": True,
|
|
||||||
"enable_shadow": False,
|
|
||||||
"opacity_active": 0.99,
|
|
||||||
"opacity_inactive": 0.95,
|
|
||||||
"opacity_dragging": 0.98,
|
|
||||||
"focus_animation_ms": 120,
|
|
||||||
},
|
|
||||||
"editor": {
|
|
||||||
"font_family": [
|
|
||||||
"Inter",
|
|
||||||
"Segoe UI",
|
|
||||||
"Arial",
|
|
||||||
"system-ui",
|
|
||||||
],
|
|
||||||
"font_size": 13,
|
|
||||||
"preview_delay_ms": 500,
|
|
||||||
"save_debounce_ms": 400,
|
|
||||||
"max_note_size": 2_000_000,
|
|
||||||
"enable_markdown_preview": True,
|
|
||||||
"enable_clickable_links": True,
|
|
||||||
"enable_antialiasing": True,
|
|
||||||
"enable_spellcheck": False,
|
|
||||||
"padding": 8,
|
|
||||||
},
|
|
||||||
"behavior": {
|
|
||||||
"enable_tray": True,
|
|
||||||
"enable_persistence": True,
|
|
||||||
"enable_window_memory": True,
|
|
||||||
"enable_auto_restore": True,
|
|
||||||
"high_contrast_inactive": False,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"accessibility": {
|
|
||||||
"theme": "dark",
|
|
||||||
"window": {
|
|
||||||
"width": 320,
|
|
||||||
"height": 380,
|
|
||||||
"min_width": 260,
|
|
||||||
"min_height": 180,
|
|
||||||
"layout_margin": 6,
|
|
||||||
"layout_spacing": 6,
|
|
||||||
"drag_handle_height": 32,
|
|
||||||
"resize_grip_size": 18,
|
|
||||||
"corner_radius": 18,
|
|
||||||
"startup_stabilize_ms": 80,
|
|
||||||
},
|
|
||||||
"appearance": {
|
|
||||||
"enable_mica": True,
|
|
||||||
"enable_acrylic": True,
|
|
||||||
"enable_glass_blur": True,
|
|
||||||
"enable_animations": False,
|
|
||||||
"enable_shadow": True,
|
|
||||||
"opacity_active": 0.92,
|
|
||||||
"opacity_inactive": 0.98,
|
|
||||||
"opacity_dragging": 1.0,
|
|
||||||
"focus_animation_ms": 0,
|
|
||||||
},
|
|
||||||
"editor": {
|
|
||||||
"font_family": [
|
|
||||||
"Inter",
|
|
||||||
"Segoe UI",
|
|
||||||
"Arial",
|
|
||||||
"system-ui",
|
|
||||||
],
|
|
||||||
"font_size": 15,
|
|
||||||
"preview_delay_ms": 300,
|
|
||||||
"save_debounce_ms": 300,
|
|
||||||
"max_note_size": 2_000_000,
|
|
||||||
"enable_markdown_preview": True,
|
|
||||||
"enable_clickable_links": True,
|
|
||||||
"enable_antialiasing": True,
|
|
||||||
"enable_spellcheck": False,
|
|
||||||
"padding": 6,
|
|
||||||
},
|
|
||||||
"behavior": {
|
|
||||||
"enable_tray": True,
|
|
||||||
"enable_persistence": True,
|
|
||||||
"enable_window_memory": True,
|
|
||||||
"enable_auto_restore": True,
|
|
||||||
"high_contrast_inactive": True,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def atomic_write(
|
||||||
|
path: Path,
|
||||||
|
content: str,
|
||||||
|
) -> None:
|
||||||
|
path.parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
temp = path.with_suffix(
|
||||||
|
f"{path.suffix}.tmp"
|
||||||
|
)
|
||||||
|
|
||||||
|
temp.write_text(
|
||||||
|
content,
|
||||||
|
encoding="utf-8",
|
||||||
|
)
|
||||||
|
|
||||||
|
temp.replace(path)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(slots=True)
|
@dataclass(slots=True)
|
||||||
class SettingsManager:
|
class SettingsManager:
|
||||||
settings: dict
|
settings: dict
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load(cls) -> "SettingsManager":
|
def load(cls) -> "SettingsManager":
|
||||||
|
SETTINGS_FILE.parent.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
if not SETTINGS_FILE.exists():
|
if not SETTINGS_FILE.exists():
|
||||||
SETTINGS_FILE.write_text(
|
atomic_write(
|
||||||
|
SETTINGS_FILE,
|
||||||
json.dumps(
|
json.dumps(
|
||||||
DEFAULT_SETTINGS,
|
DEFAULT_SETTINGS,
|
||||||
indent=2,
|
indent=2,
|
||||||
),
|
),
|
||||||
encoding="utf-8",
|
|
||||||
)
|
|
||||||
|
|
||||||
return cls(
|
|
||||||
DEFAULT_SETTINGS
|
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -203,9 +153,21 @@ class SettingsManager:
|
|||||||
data,
|
data,
|
||||||
)
|
)
|
||||||
|
|
||||||
return cls(merged)
|
manager = cls(merged)
|
||||||
|
|
||||||
|
manager.save()
|
||||||
|
|
||||||
|
return manager
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
|
atomic_write(
|
||||||
|
SETTINGS_FILE,
|
||||||
|
json.dumps(
|
||||||
|
DEFAULT_SETTINGS,
|
||||||
|
indent=2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
return cls(
|
return cls(
|
||||||
DEFAULT_SETTINGS
|
DEFAULT_SETTINGS
|
||||||
)
|
)
|
||||||
@@ -245,12 +207,12 @@ class SettingsManager:
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def save(self) -> None:
|
def save(self) -> None:
|
||||||
SETTINGS_FILE.write_text(
|
atomic_write(
|
||||||
|
SETTINGS_FILE,
|
||||||
json.dumps(
|
json.dumps(
|
||||||
self.settings,
|
self.settings,
|
||||||
indent=2,
|
indent=2,
|
||||||
),
|
),
|
||||||
encoding="utf-8",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -284,22 +246,6 @@ class SettingsManager:
|
|||||||
|
|
||||||
return profiles[active]
|
return profiles[active]
|
||||||
|
|
||||||
def set_active_profile(
|
|
||||||
self,
|
|
||||||
profile_name: str,
|
|
||||||
) -> None:
|
|
||||||
if (
|
|
||||||
profile_name
|
|
||||||
not in self.profiles
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
self.settings[
|
|
||||||
"active_profile"
|
|
||||||
] = profile_name
|
|
||||||
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def reload(self) -> None:
|
def reload(self) -> None:
|
||||||
loaded = (
|
loaded = (
|
||||||
SettingsManager.load()
|
SettingsManager.load()
|
||||||
@@ -315,43 +261,3 @@ class SettingsManager:
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def create_profile(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
data: dict,
|
|
||||||
) -> None:
|
|
||||||
self.settings[
|
|
||||||
"profiles"
|
|
||||||
][name] = data
|
|
||||||
|
|
||||||
self.save()
|
|
||||||
|
|
||||||
def delete_profile(
|
|
||||||
self,
|
|
||||||
name: str,
|
|
||||||
) -> None:
|
|
||||||
if name == "default":
|
|
||||||
return
|
|
||||||
|
|
||||||
if (
|
|
||||||
name
|
|
||||||
not in self.settings[
|
|
||||||
"profiles"
|
|
||||||
]
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
del self.settings[
|
|
||||||
"profiles"
|
|
||||||
][name]
|
|
||||||
|
|
||||||
if (
|
|
||||||
self.active_profile_name
|
|
||||||
== name
|
|
||||||
):
|
|
||||||
self.settings[
|
|
||||||
"active_profile"
|
|
||||||
] = "default"
|
|
||||||
|
|
||||||
self.save()
|
|
||||||
529
core/app.py
529
core/app.py
@@ -1,18 +1,15 @@
|
|||||||
# v3.1.0 app.py
|
# v4.2.1 app.py
|
||||||
import atexit
|
import atexit
|
||||||
import signal
|
|
||||||
import traceback
|
|
||||||
import contextlib
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import signal
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
import traceback
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from pathlib import Path
|
|
||||||
from typing import Final
|
|
||||||
|
|
||||||
from PyQt6.QtCore import (
|
from PyQt6.QtCore import (
|
||||||
QEasingCurve,
|
QEasingCurve,
|
||||||
@@ -49,10 +46,16 @@ from PyQt6.QtWidgets import (
|
|||||||
from qframelesswindow import AcrylicWindow
|
from qframelesswindow import AcrylicWindow
|
||||||
|
|
||||||
from config.profiles import THEMES
|
from config.profiles import THEMES
|
||||||
|
|
||||||
from config.settings import (
|
from config.settings import (
|
||||||
APP_DIR,
|
APP_DIR,
|
||||||
|
MARKDOWN_FILE,
|
||||||
|
SETTINGS_FILE,
|
||||||
|
STATE_FILE,
|
||||||
SettingsManager,
|
SettingsManager,
|
||||||
|
atomic_write,
|
||||||
)
|
)
|
||||||
|
|
||||||
from ui.editor import LinkTextEdit
|
from ui.editor import LinkTextEdit
|
||||||
from ui.styles import build_stylesheet
|
from ui.styles import build_stylesheet
|
||||||
|
|
||||||
@@ -63,15 +66,6 @@ logging.basicConfig(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
STATE_FILE: Final[Path] = (
|
|
||||||
APP_DIR / "sticky_state.json"
|
|
||||||
)
|
|
||||||
|
|
||||||
MARKDOWN_FILE: Final[Path] = (
|
|
||||||
APP_DIR / "sticky.md"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class WindowState(Enum):
|
class WindowState(Enum):
|
||||||
IDLE = auto()
|
IDLE = auto()
|
||||||
DRAGGING = auto()
|
DRAGGING = auto()
|
||||||
@@ -87,9 +81,8 @@ class ActiveState(Enum):
|
|||||||
class PersistedState:
|
class PersistedState:
|
||||||
x: int = 100
|
x: int = 100
|
||||||
y: int = 100
|
y: int = 100
|
||||||
width: int = 260
|
width: int = 250
|
||||||
height: int = 300
|
height: int = 260
|
||||||
theme_index: int = 0
|
|
||||||
|
|
||||||
|
|
||||||
class DragHandle(QFrame):
|
class DragHandle(QFrame):
|
||||||
@@ -141,15 +134,16 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self._is_quitting = False
|
self._is_quitting = False
|
||||||
self._force_close = False
|
self._force_close = False
|
||||||
|
|
||||||
self._closing = False
|
|
||||||
|
|
||||||
self.settings_manager = (
|
self.settings_manager = (
|
||||||
SettingsManager.load()
|
SettingsManager.load()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.ensure_runtime_files()
|
||||||
|
|
||||||
self.profile = (
|
self.profile = (
|
||||||
self.settings_manager.profile
|
self.settings_manager.profile
|
||||||
)
|
)
|
||||||
@@ -164,6 +158,10 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
|
|
||||||
self.drag_offset = QPoint()
|
self.drag_offset = QPoint()
|
||||||
|
|
||||||
|
self.drag_origin = QPoint()
|
||||||
|
|
||||||
|
self.pending_drag = False
|
||||||
|
|
||||||
self.last_saved_hash = ""
|
self.last_saved_hash = ""
|
||||||
|
|
||||||
self.last_preview_hash = ""
|
self.last_preview_hash = ""
|
||||||
@@ -172,12 +170,17 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
|
|
||||||
self.configure_font()
|
self.configure_font()
|
||||||
|
|
||||||
self.build_ui()
|
|
||||||
|
|
||||||
self.setup_timers()
|
self.setup_timers()
|
||||||
|
|
||||||
|
self.build_ui()
|
||||||
|
|
||||||
self.configure_window()
|
self.configure_window()
|
||||||
|
|
||||||
|
QTimer.singleShot(
|
||||||
|
80,
|
||||||
|
self.restore_state,
|
||||||
|
)
|
||||||
|
|
||||||
QTimer.singleShot(
|
QTimer.singleShot(
|
||||||
120,
|
120,
|
||||||
self.initialize_effects,
|
self.initialize_effects,
|
||||||
@@ -188,11 +191,6 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
self.build_tray,
|
self.build_tray,
|
||||||
)
|
)
|
||||||
|
|
||||||
QTimer.singleShot(
|
|
||||||
80,
|
|
||||||
self.restore_state,
|
|
||||||
)
|
|
||||||
|
|
||||||
QTimer.singleShot(
|
QTimer.singleShot(
|
||||||
260,
|
260,
|
||||||
self.apply_style,
|
self.apply_style,
|
||||||
@@ -205,6 +203,34 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
|
|
||||||
self.register_shutdown_hooks()
|
self.register_shutdown_hooks()
|
||||||
|
|
||||||
|
def ensure_runtime_files(self) -> None:
|
||||||
|
APP_DIR.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
if not SETTINGS_FILE.exists():
|
||||||
|
self.settings_manager.save()
|
||||||
|
|
||||||
|
if not MARKDOWN_FILE.exists():
|
||||||
|
atomic_write(
|
||||||
|
MARKDOWN_FILE,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
|
if not STATE_FILE.exists():
|
||||||
|
atomic_write(
|
||||||
|
STATE_FILE,
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"x": 100,
|
||||||
|
"y": 100,
|
||||||
|
"width": 250,
|
||||||
|
"height": 260,
|
||||||
|
},
|
||||||
|
indent=2,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
def configure_font(self) -> None:
|
def configure_font(self) -> None:
|
||||||
self.font_object = QFont()
|
self.font_object = QFont()
|
||||||
@@ -253,6 +279,16 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
self.show_preview
|
self.show_preview
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.drag_timer = QTimer(self)
|
||||||
|
|
||||||
|
self.drag_timer.setSingleShot(
|
||||||
|
True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.drag_timer.timeout.connect(
|
||||||
|
self.activate_delayed_drag
|
||||||
|
)
|
||||||
|
|
||||||
self.opacity_anim = (
|
self.opacity_anim = (
|
||||||
QPropertyAnimation(
|
QPropertyAnimation(
|
||||||
self,
|
self,
|
||||||
@@ -270,7 +306,6 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
QEasingCurve.Type.OutCubic
|
QEasingCurve.Type.OutCubic
|
||||||
)
|
)
|
||||||
|
|
||||||
# v1.0.1 configure_window.py
|
|
||||||
def configure_window(self) -> None:
|
def configure_window(self) -> None:
|
||||||
window = self.profile["window"]
|
window = self.profile["window"]
|
||||||
|
|
||||||
@@ -289,6 +324,11 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.setWindowFlag(
|
||||||
|
Qt.WindowType.FramelessWindowHint,
|
||||||
|
True,
|
||||||
|
)
|
||||||
|
|
||||||
self.setAttribute(
|
self.setAttribute(
|
||||||
Qt.WidgetAttribute.WA_TranslucentBackground,
|
Qt.WidgetAttribute.WA_TranslucentBackground,
|
||||||
True,
|
True,
|
||||||
@@ -298,19 +338,11 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
Qt.WidgetAttribute.WA_NoSystemBackground,
|
Qt.WidgetAttribute.WA_NoSystemBackground,
|
||||||
True,
|
True,
|
||||||
)
|
)
|
||||||
self.setWindowFlag(
|
|
||||||
Qt.WindowType.WindowCloseButtonHint,
|
|
||||||
False,
|
|
||||||
)
|
|
||||||
self.setAutoFillBackground(
|
self.setAutoFillBackground(
|
||||||
False
|
False
|
||||||
)
|
)
|
||||||
|
|
||||||
QTimer.singleShot(
|
|
||||||
120,
|
|
||||||
self.initialize_effects,
|
|
||||||
)
|
|
||||||
|
|
||||||
def build_ui(self) -> None:
|
def build_ui(self) -> None:
|
||||||
self.root = QWidget(self)
|
self.root = QWidget(self)
|
||||||
|
|
||||||
@@ -318,48 +350,34 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
"container"
|
"container"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.root.setGeometry(
|
||||||
|
self.rect()
|
||||||
|
)
|
||||||
|
|
||||||
self.layout = QVBoxLayout(
|
self.layout = QVBoxLayout(
|
||||||
self.root
|
self.root
|
||||||
)
|
)
|
||||||
|
|
||||||
window = self.profile["window"]
|
|
||||||
|
|
||||||
margin = window[
|
|
||||||
"layout_margin"
|
|
||||||
]
|
|
||||||
|
|
||||||
self.layout.setContentsMargins(
|
self.layout.setContentsMargins(
|
||||||
margin,
|
4,
|
||||||
margin,
|
4,
|
||||||
margin,
|
4,
|
||||||
margin,
|
4,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.layout.setSpacing(
|
self.layout.setSpacing(0)
|
||||||
window["layout_spacing"]
|
|
||||||
)
|
self.titleBar.hide()
|
||||||
|
|
||||||
|
self.titleBar.setFixedHeight(0)
|
||||||
|
|
||||||
self.drag_handle = DragHandle(
|
self.drag_handle = DragHandle(
|
||||||
self.root
|
self.root
|
||||||
)
|
)
|
||||||
|
|
||||||
self.drag_handle.setFixedHeight(
|
self.drag_handle.hide()
|
||||||
window[
|
|
||||||
"drag_handle_height"
|
|
||||||
]
|
|
||||||
)
|
|
||||||
|
|
||||||
self.drag_handle.drag_started.connect(
|
self.drag_handle.setFixedHeight(0)
|
||||||
self.start_drag
|
|
||||||
)
|
|
||||||
|
|
||||||
self.drag_handle.drag_moved.connect(
|
|
||||||
self.perform_drag
|
|
||||||
)
|
|
||||||
|
|
||||||
self.drag_handle.drag_finished.connect(
|
|
||||||
self.finish_drag
|
|
||||||
)
|
|
||||||
|
|
||||||
self.editor = LinkTextEdit(
|
self.editor = LinkTextEdit(
|
||||||
self.root
|
self.root
|
||||||
@@ -377,6 +395,37 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
0
|
0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.editor.setViewportMargins(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setAcceptRichText(
|
||||||
|
False
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setMouseTracking(
|
||||||
|
True
|
||||||
|
)
|
||||||
|
|
||||||
|
self.editor.setStyleSheet("""
|
||||||
|
QTextEdit {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
QTextEdit > QWidget {
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px;
|
||||||
|
border: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
self.editor.textChanged.connect(
|
self.editor.textChanged.connect(
|
||||||
self.queue_save
|
self.queue_save
|
||||||
)
|
)
|
||||||
@@ -406,13 +455,13 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
content_layout.setContentsMargins(
|
content_layout.setContentsMargins(
|
||||||
0,
|
4,
|
||||||
0,
|
4,
|
||||||
0,
|
4,
|
||||||
0,
|
4,
|
||||||
)
|
)
|
||||||
|
|
||||||
content_layout.setSpacing(0)
|
content_layout.setSpacing(1)
|
||||||
|
|
||||||
content_layout.addWidget(
|
content_layout.addWidget(
|
||||||
self.editor,
|
self.editor,
|
||||||
@@ -428,10 +477,6 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
self.root
|
self.root
|
||||||
)
|
)
|
||||||
|
|
||||||
self.layout.addWidget(
|
|
||||||
self.drag_handle
|
|
||||||
)
|
|
||||||
|
|
||||||
self.layout.addWidget(
|
self.layout.addWidget(
|
||||||
content,
|
content,
|
||||||
1,
|
1,
|
||||||
@@ -444,12 +489,12 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
| Qt.AlignmentFlag.AlignRight,
|
| Qt.AlignmentFlag.AlignRight,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.titleBar.hide()
|
|
||||||
self.editor.setFocus()
|
self.editor.setFocus()
|
||||||
|
|
||||||
def build_tray(self) -> None:
|
def build_tray(self) -> None:
|
||||||
if QSystemTrayIcon.isSystemTrayAvailable() is False:
|
if not QSystemTrayIcon.isSystemTrayAvailable():
|
||||||
return
|
return
|
||||||
|
|
||||||
if not self.profile[
|
if not self.profile[
|
||||||
"behavior"
|
"behavior"
|
||||||
]["enable_tray"]:
|
]["enable_tray"]:
|
||||||
@@ -603,6 +648,7 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def initialize_effects(self) -> None:
|
def initialize_effects(self) -> None:
|
||||||
appearance = (
|
appearance = (
|
||||||
self.profile["appearance"]
|
self.profile["appearance"]
|
||||||
@@ -631,16 +677,18 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
self.repaint()
|
self.repaint()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception(
|
logging.exception(
|
||||||
"window_effect_failure"
|
"window_effect_failure"
|
||||||
)
|
)
|
||||||
def start_drag(
|
|
||||||
self,
|
def activate_delayed_drag(self) -> None:
|
||||||
global_pos: QPoint,
|
if not self.pending_drag:
|
||||||
) -> None:
|
return
|
||||||
|
|
||||||
self.window_state = (
|
self.window_state = (
|
||||||
WindowState.DRAGGING
|
WindowState.DRAGGING
|
||||||
)
|
)
|
||||||
@@ -651,27 +699,84 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
|
|
||||||
self.apply_style()
|
self.apply_style()
|
||||||
|
|
||||||
self.drag_offset = (
|
|
||||||
global_pos
|
|
||||||
- self.frameGeometry().topLeft()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.setWindowOpacity(
|
self.setWindowOpacity(
|
||||||
self.profile["appearance"][
|
self.profile["appearance"][
|
||||||
"opacity_dragging"
|
"opacity_dragging"
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
def perform_drag(
|
def mousePressEvent(self, event) -> None:
|
||||||
self,
|
if (
|
||||||
global_pos: QPoint,
|
event.button()
|
||||||
) -> None:
|
== Qt.MouseButton.LeftButton
|
||||||
target = (
|
):
|
||||||
global_pos
|
self.pending_drag = True
|
||||||
- self.drag_offset
|
|
||||||
|
self.drag_origin = (
|
||||||
|
event.globalPosition()
|
||||||
|
.toPoint()
|
||||||
|
)
|
||||||
|
|
||||||
|
self.drag_offset = (
|
||||||
|
self.drag_origin
|
||||||
|
- self.frameGeometry().topLeft()
|
||||||
|
)
|
||||||
|
|
||||||
|
if hasattr(
|
||||||
|
self,
|
||||||
|
"drag_timer",
|
||||||
|
):
|
||||||
|
self.drag_timer.start(180)
|
||||||
|
|
||||||
|
super().mousePressEvent(event)
|
||||||
|
|
||||||
|
def mouseMoveEvent(self, event) -> None:
|
||||||
|
if not (
|
||||||
|
event.buttons()
|
||||||
|
& Qt.MouseButton.LeftButton
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
|
global_pos = (
|
||||||
|
event.globalPosition()
|
||||||
|
.toPoint()
|
||||||
)
|
)
|
||||||
|
|
||||||
self.move(target)
|
if (
|
||||||
|
self.pending_drag
|
||||||
|
and (
|
||||||
|
global_pos
|
||||||
|
- self.drag_origin
|
||||||
|
).manhattanLength()
|
||||||
|
> 6
|
||||||
|
):
|
||||||
|
if (
|
||||||
|
self.window_state
|
||||||
|
== WindowState.DRAGGING
|
||||||
|
):
|
||||||
|
self.move(
|
||||||
|
global_pos
|
||||||
|
- self.drag_offset
|
||||||
|
)
|
||||||
|
|
||||||
|
super().mouseMoveEvent(event)
|
||||||
|
|
||||||
|
def mouseReleaseEvent(self, event) -> None:
|
||||||
|
if hasattr(
|
||||||
|
self,
|
||||||
|
"drag_timer",
|
||||||
|
):
|
||||||
|
self.drag_timer.stop()
|
||||||
|
|
||||||
|
self.pending_drag = False
|
||||||
|
|
||||||
|
if (
|
||||||
|
self.window_state
|
||||||
|
== WindowState.DRAGGING
|
||||||
|
):
|
||||||
|
self.finish_drag()
|
||||||
|
|
||||||
|
super().mouseReleaseEvent(event)
|
||||||
|
|
||||||
def finish_drag(self) -> None:
|
def finish_drag(self) -> None:
|
||||||
self.window_state = (
|
self.window_state = (
|
||||||
@@ -690,7 +795,15 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.queue_save()
|
||||||
|
|
||||||
def queue_save(self) -> None:
|
def queue_save(self) -> None:
|
||||||
|
if not hasattr(
|
||||||
|
self,
|
||||||
|
"save_timer",
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
self.save_timer.start(
|
self.save_timer.start(
|
||||||
self.profile["editor"][
|
self.profile["editor"][
|
||||||
"save_debounce_ms"
|
"save_debounce_ms"
|
||||||
@@ -698,6 +811,12 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def queue_preview(self) -> None:
|
def queue_preview(self) -> None:
|
||||||
|
if not hasattr(
|
||||||
|
self,
|
||||||
|
"preview_timer",
|
||||||
|
):
|
||||||
|
return
|
||||||
|
|
||||||
if not self.profile[
|
if not self.profile[
|
||||||
"editor"
|
"editor"
|
||||||
][
|
][
|
||||||
@@ -721,9 +840,11 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
or not self.isActiveWindow()
|
or not self.isActiveWindow()
|
||||||
):
|
):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.preview.setFocusPolicy(
|
self.preview.setFocusPolicy(
|
||||||
Qt.FocusPolicy.NoFocus
|
Qt.FocusPolicy.NoFocus
|
||||||
)
|
)
|
||||||
|
|
||||||
markdown = (
|
markdown = (
|
||||||
self.editor.toPlainText()
|
self.editor.toPlainText()
|
||||||
)
|
)
|
||||||
@@ -751,49 +872,65 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
self.preview.show()
|
self.preview.show()
|
||||||
|
|
||||||
def save_state(self) -> None:
|
def save_state(self) -> None:
|
||||||
markdown = (
|
try:
|
||||||
self.editor.toPlainText()
|
APP_DIR.mkdir(
|
||||||
)
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
current_hash = sha256(
|
|
||||||
markdown.encode("utf-8")
|
|
||||||
).hexdigest()
|
|
||||||
|
|
||||||
if current_hash != self.last_saved_hash:
|
|
||||||
MARKDOWN_FILE.write_text(
|
|
||||||
markdown,
|
|
||||||
encoding="utf-8",
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.last_saved_hash = (
|
markdown = (
|
||||||
|
self.editor.toPlainText()
|
||||||
|
)
|
||||||
|
|
||||||
|
current_hash = sha256(
|
||||||
|
markdown.encode("utf-8")
|
||||||
|
).hexdigest()
|
||||||
|
|
||||||
|
if (
|
||||||
current_hash
|
current_hash
|
||||||
|
!= self.last_saved_hash
|
||||||
|
):
|
||||||
|
atomic_write(
|
||||||
|
MARKDOWN_FILE,
|
||||||
|
markdown,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.last_saved_hash = (
|
||||||
|
current_hash
|
||||||
|
)
|
||||||
|
|
||||||
|
atomic_write(
|
||||||
|
STATE_FILE,
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"x": self.x(),
|
||||||
|
"y": self.y(),
|
||||||
|
"width": self.width(),
|
||||||
|
"height": self.height(),
|
||||||
|
},
|
||||||
|
indent=2,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
STATE_FILE.write_text(
|
except Exception:
|
||||||
json.dumps(
|
logging.exception(
|
||||||
{
|
"save_state_failure"
|
||||||
"x": self.x(),
|
)
|
||||||
"y": self.y(),
|
|
||||||
"width": self.width(),
|
|
||||||
"height": self.height(),
|
|
||||||
},
|
|
||||||
indent=2,
|
|
||||||
),
|
|
||||||
encoding="utf-8",
|
|
||||||
)
|
|
||||||
|
|
||||||
def restore_state(self) -> None:
|
def restore_state(self) -> None:
|
||||||
if MARKDOWN_FILE.exists():
|
try:
|
||||||
self.editor.setPlainText(
|
self.ensure_runtime_files()
|
||||||
|
|
||||||
|
markdown = (
|
||||||
MARKDOWN_FILE.read_text(
|
MARKDOWN_FILE.read_text(
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
if not STATE_FILE.exists():
|
self.editor.setPlainText(
|
||||||
return
|
markdown
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
|
||||||
state = json.loads(
|
state = json.loads(
|
||||||
STATE_FILE.read_text(
|
STATE_FILE.read_text(
|
||||||
encoding="utf-8",
|
encoding="utf-8",
|
||||||
@@ -801,13 +938,25 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
self.resize(
|
self.resize(
|
||||||
state["width"],
|
max(
|
||||||
state["height"],
|
state.get(
|
||||||
|
"width",
|
||||||
|
250,
|
||||||
|
),
|
||||||
|
200,
|
||||||
|
),
|
||||||
|
max(
|
||||||
|
state.get(
|
||||||
|
"height",
|
||||||
|
260,
|
||||||
|
),
|
||||||
|
100,
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.move(
|
self.move(
|
||||||
state["x"],
|
state.get("x", 100),
|
||||||
state["y"],
|
state.get("y", 100),
|
||||||
)
|
)
|
||||||
|
|
||||||
self.clamp_to_screen()
|
self.clamp_to_screen()
|
||||||
@@ -867,29 +1016,38 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
self.apply_style()
|
self.apply_style()
|
||||||
|
|
||||||
def open_settings(self) -> None:
|
def open_settings(self) -> None:
|
||||||
path = (
|
SETTINGS_FILE.touch(
|
||||||
APP_DIR / "settings.json"
|
exist_ok=True
|
||||||
)
|
)
|
||||||
|
|
||||||
path.touch(exist_ok=True)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if os.name == "nt":
|
if os.name == "nt":
|
||||||
os.startfile(str(path))
|
os.startfile(
|
||||||
|
str(SETTINGS_FILE)
|
||||||
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if sys.platform.startswith(
|
if sys.platform.startswith(
|
||||||
"linux"
|
"linux"
|
||||||
):
|
):
|
||||||
subprocess.Popen(
|
subprocess.Popen(
|
||||||
["xdg-open", str(path)]
|
[
|
||||||
|
"xdg-open",
|
||||||
|
str(SETTINGS_FILE),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if sys.platform == "darwin":
|
if sys.platform == "darwin":
|
||||||
subprocess.Popen(
|
subprocess.Popen(
|
||||||
["open", str(path)]
|
[
|
||||||
|
"open",
|
||||||
|
str(SETTINGS_FILE),
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
@@ -897,18 +1055,21 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
"open_settings_failure"
|
"open_settings_failure"
|
||||||
)
|
)
|
||||||
|
|
||||||
def nativeEvent(self, eventType, message):
|
def moveEvent(self, event) -> None:
|
||||||
try:
|
super().moveEvent(event)
|
||||||
return super().nativeEvent(eventType, message)
|
|
||||||
except KeyboardInterrupt:
|
if (
|
||||||
self.safe_exit()
|
getattr(
|
||||||
return False, 0
|
self,
|
||||||
except SystemExit:
|
"startup_ready",
|
||||||
self.safe_exit()
|
False,
|
||||||
return False, 0
|
)
|
||||||
except Exception:
|
and hasattr(
|
||||||
traceback.print_exc()
|
self,
|
||||||
return False, 0
|
"save_timer",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
self.queue_save()
|
||||||
|
|
||||||
def resizeEvent(self, event) -> None:
|
def resizeEvent(self, event) -> None:
|
||||||
super().resizeEvent(event)
|
super().resizeEvent(event)
|
||||||
@@ -919,15 +1080,29 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
if root is None:
|
if root is not None:
|
||||||
return
|
geometry = self.rect()
|
||||||
|
|
||||||
geometry = self.rect()
|
if (
|
||||||
|
root.geometry()
|
||||||
|
!= geometry
|
||||||
|
):
|
||||||
|
root.setGeometry(
|
||||||
|
geometry
|
||||||
|
)
|
||||||
|
|
||||||
if root.geometry() != geometry:
|
if (
|
||||||
root.setGeometry(
|
getattr(
|
||||||
geometry
|
self,
|
||||||
|
"startup_ready",
|
||||||
|
False,
|
||||||
)
|
)
|
||||||
|
and hasattr(
|
||||||
|
self,
|
||||||
|
"save_timer",
|
||||||
|
)
|
||||||
|
):
|
||||||
|
self.queue_save()
|
||||||
|
|
||||||
def focusInEvent(self, event) -> None:
|
def focusInEvent(self, event) -> None:
|
||||||
super().focusInEvent(event)
|
super().focusInEvent(event)
|
||||||
@@ -966,16 +1141,21 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def closeEvent(self, event) -> None:
|
def closeEvent(self, event) -> None:
|
||||||
if self._is_quitting or self._force_close:
|
if (
|
||||||
|
self._is_quitting
|
||||||
|
or self._force_close
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
self.save_state()
|
self.save_state()
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
event.accept()
|
event.accept()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
event.ignore()
|
event.ignore()
|
||||||
|
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
def register_shutdown_hooks(self) -> None:
|
def register_shutdown_hooks(self) -> None:
|
||||||
@@ -984,11 +1164,20 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
def handle_shutdown(*_) -> None:
|
def handle_shutdown(*_) -> None:
|
||||||
self.safe_exit()
|
self.safe_exit()
|
||||||
|
|
||||||
atexit.register(handle_shutdown)
|
atexit.register(
|
||||||
|
handle_shutdown
|
||||||
|
)
|
||||||
|
|
||||||
for sig in (signal.SIGINT, signal.SIGTERM):
|
for sig in (
|
||||||
|
signal.SIGINT,
|
||||||
|
signal.SIGTERM,
|
||||||
|
):
|
||||||
try:
|
try:
|
||||||
signal.signal(sig, handle_shutdown)
|
signal.signal(
|
||||||
|
sig,
|
||||||
|
handle_shutdown,
|
||||||
|
)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -1013,24 +1202,38 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if hasattr(self, "save_timer"):
|
if hasattr(
|
||||||
|
self,
|
||||||
|
"save_timer",
|
||||||
|
):
|
||||||
self.save_timer.stop()
|
self.save_timer.stop()
|
||||||
|
|
||||||
if hasattr(self, "preview_timer"):
|
if hasattr(
|
||||||
|
self,
|
||||||
|
"preview_timer",
|
||||||
|
):
|
||||||
self.preview_timer.stop()
|
self.preview_timer.stop()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if hasattr(self, "tray"):
|
if hasattr(
|
||||||
|
self,
|
||||||
|
"tray",
|
||||||
|
):
|
||||||
self.tray.hide()
|
self.tray.hide()
|
||||||
|
|
||||||
self.tray.deleteLater()
|
self.tray.deleteLater()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.hide()
|
self.hide()
|
||||||
|
|
||||||
self.deleteLater()
|
self.deleteLater()
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
@@ -1040,6 +1243,6 @@ class StickyNoteApp(AcrylicWindow):
|
|||||||
app.quit()
|
app.quit()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
app.quit()
|
app.quit()
|
||||||
except:
|
except Exception:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
26
start.py
26
start.py
@@ -1,31 +1,45 @@
|
|||||||
# v1.0.3 start.py
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
|
|
||||||
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
|
|
||||||
|
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1"
|
||||||
|
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt
|
from PyQt6.QtCore import Qt
|
||||||
from PyQt6.QtGui import QGuiApplication
|
from PyQt6.QtGui import QGuiApplication
|
||||||
from PyQt6.QtWidgets import QApplication
|
from PyQt6.QtWidgets import QApplication
|
||||||
|
|
||||||
|
from config.settings import (
|
||||||
|
APP_DIR,
|
||||||
|
)
|
||||||
from core.app import StickyNoteApp
|
from core.app import StickyNoteApp
|
||||||
|
|
||||||
|
|
||||||
|
APP_DIR.mkdir(
|
||||||
|
parents=True,
|
||||||
|
exist_ok=True,
|
||||||
|
)
|
||||||
|
|
||||||
QGuiApplication.setHighDpiScaleFactorRoundingPolicy(
|
QGuiApplication.setHighDpiScaleFactorRoundingPolicy(
|
||||||
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
Qt.HighDpiScaleFactorRoundingPolicy.PassThrough
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
signal.signal(signal.SIGINT, signal.SIG_DFL)
|
signal.signal(
|
||||||
|
signal.SIGINT,
|
||||||
|
signal.SIG_DFL,
|
||||||
|
)
|
||||||
|
|
||||||
app = QApplication(sys.argv)
|
app = QApplication(sys.argv)
|
||||||
|
|
||||||
|
app.setQuitOnLastWindowClosed(
|
||||||
|
False
|
||||||
|
)
|
||||||
|
|
||||||
window = StickyNoteApp()
|
window = StickyNoteApp()
|
||||||
|
|
||||||
window.show()
|
window.show()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
BIN
ui/app.ico
Normal file
BIN
ui/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.7 KiB |
37
ui/editor.py
37
ui/editor.py
@@ -1,10 +1,19 @@
|
|||||||
# v3.0.0 editor.py
|
# v4.1.0 editor-link-click-fix-v1
|
||||||
import re
|
import re
|
||||||
import webbrowser
|
import webbrowser
|
||||||
|
|
||||||
from PyQt6.QtCore import Qt, QUrl
|
from PyQt6.QtCore import (
|
||||||
from PyQt6.QtGui import QDesktopServices
|
Qt,
|
||||||
from PyQt6.QtWidgets import QTextEdit
|
QUrl,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt6.QtGui import (
|
||||||
|
QDesktopServices,
|
||||||
|
)
|
||||||
|
|
||||||
|
from PyQt6.QtWidgets import (
|
||||||
|
QTextEdit,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
URL_PATTERN = re.compile(
|
URL_PATTERN = re.compile(
|
||||||
@@ -15,9 +24,14 @@ URL_PATTERN = re.compile(
|
|||||||
|
|
||||||
class LinkTextEdit(QTextEdit):
|
class LinkTextEdit(QTextEdit):
|
||||||
|
|
||||||
def mouseReleaseEvent(self, event) -> None:
|
def mouseReleaseEvent(
|
||||||
|
self,
|
||||||
|
event,
|
||||||
|
) -> None:
|
||||||
if (
|
if (
|
||||||
event.modifiers()
|
event.button()
|
||||||
|
== Qt.MouseButton.LeftButton
|
||||||
|
and event.modifiers()
|
||||||
& Qt.KeyboardModifier.ControlModifier
|
& Qt.KeyboardModifier.ControlModifier
|
||||||
):
|
):
|
||||||
cursor = self.cursorForPosition(
|
cursor = self.cursorForPosition(
|
||||||
@@ -47,14 +61,19 @@ class LinkTextEdit(QTextEdit):
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
webbrowser.open(target)
|
webbrowser.open(
|
||||||
|
target
|
||||||
|
)
|
||||||
|
|
||||||
except Exception:
|
except Exception:
|
||||||
QDesktopServices.openUrl(
|
QDesktopServices.openUrl(
|
||||||
QUrl(target)
|
QUrl(target)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
event.accept()
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
super().mouseReleaseEvent(event)
|
super().mouseReleaseEvent(
|
||||||
|
event
|
||||||
|
)
|
||||||
@@ -28,7 +28,7 @@ def build_stylesheet(
|
|||||||
QWidget#container {{
|
QWidget#container {{
|
||||||
background: {background};
|
background: {background};
|
||||||
border: 1px solid {border};
|
border: 1px solid {border};
|
||||||
border-radius: 16px;
|
border-radius: 7px;
|
||||||
}}
|
}}
|
||||||
|
|
||||||
QWidget#container:hover {{
|
QWidget#container:hover {{
|
||||||
|
|||||||
Reference in New Issue
Block a user