109 lines
4.3 KiB
Python
109 lines
4.3 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
from dataclasses import asdict, dataclass
|
|
from pathlib import Path
|
|
|
|
from PySide6.QtCore import QStandardPaths
|
|
from PySide6.QtGui import QKeySequence
|
|
|
|
|
|
SHORTCUT_DEFINITIONS: list[tuple[str, str, str]] = [
|
|
("open", "Открыть", "Ctrl+O"),
|
|
("save", "Сохранить", "Ctrl+S"),
|
|
("save_as", "Сохранить как", "Ctrl+Shift+S"),
|
|
("generate_script", "Сгенерировать скрипт", "Ctrl+G"),
|
|
("settings", "Параметры", "Ctrl+,"),
|
|
("undo", "Отменить", "Ctrl+Z"),
|
|
("redo", "Повторить", "Ctrl+Y"),
|
|
("delete", "Удалить фиксацию", "Del"),
|
|
("clear_all", "Удалить все", "Ctrl+Shift+Del"),
|
|
("clear_selection", "Очистить выбор", "Esc"),
|
|
("fit_view", "Показать всё", "Ctrl+0"),
|
|
("grid", "Сетка 34 мм", "G"),
|
|
("direction_arrows", "Стрелки направления", "Ctrl+Shift+A"),
|
|
("toggle_sidebar", "Скрыть боковую панель", "F9"),
|
|
("add_line", "Новая линия", "Ctrl+L"),
|
|
("auto_blocks", "Автоблоки", "Ctrl+Shift+B"),
|
|
("brush", "Кисть", "B"),
|
|
]
|
|
DEFAULT_SHORTCUTS = {key: shortcut for key, _title, shortcut in SHORTCUT_DEFINITIONS}
|
|
|
|
|
|
@dataclass
|
|
class AppSettings:
|
|
theme: str = "system"
|
|
show_grid_by_default: bool = False
|
|
show_direction_arrows_by_default: bool = True
|
|
zoom_focus_pull: int = 35
|
|
pan_mode: str = "middle_space"
|
|
instant_space_pan: bool = False
|
|
brush_radius: int = 18
|
|
default_output_dir: str = ""
|
|
confirm_partial_generation: bool = True
|
|
shortcuts: dict[str, str] | None = None
|
|
|
|
@classmethod
|
|
def load(cls) -> "AppSettings":
|
|
path = settings_path()
|
|
if not path.exists():
|
|
return cls()
|
|
try:
|
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
except (OSError, json.JSONDecodeError):
|
|
return cls()
|
|
settings = cls()
|
|
for key, value in data.items():
|
|
if hasattr(settings, key):
|
|
setattr(settings, key, value)
|
|
settings.zoom_focus_pull = clamp_int(settings.zoom_focus_pull, 0, 100, cls.zoom_focus_pull)
|
|
settings.brush_radius = clamp_int(settings.brush_radius, 4, 80, cls.brush_radius)
|
|
if settings.theme not in {"system", "light", "dark"}:
|
|
settings.theme = cls.theme
|
|
if settings.pan_mode not in {"middle", "space", "middle_space"}:
|
|
settings.pan_mode = cls.pan_mode
|
|
settings.instant_space_pan = bool(settings.instant_space_pan)
|
|
settings.show_grid_by_default = bool(settings.show_grid_by_default)
|
|
settings.show_direction_arrows_by_default = bool(settings.show_direction_arrows_by_default)
|
|
settings.confirm_partial_generation = bool(settings.confirm_partial_generation)
|
|
settings.default_output_dir = str(settings.default_output_dir or "")
|
|
settings.shortcuts = normalize_shortcuts(settings.shortcuts)
|
|
return settings
|
|
|
|
def save(self) -> None:
|
|
path = settings_path()
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
path.write_text(json.dumps(asdict(self), ensure_ascii=False, indent=2), encoding="utf-8")
|
|
|
|
def shortcut_for(self, key: str) -> str:
|
|
if self.shortcuts is None:
|
|
return DEFAULT_SHORTCUTS.get(key, "")
|
|
return self.shortcuts.get(key, DEFAULT_SHORTCUTS.get(key, ""))
|
|
|
|
|
|
def settings_path() -> Path:
|
|
config_dir = QStandardPaths.writableLocation(QStandardPaths.AppConfigLocation)
|
|
if not config_dir:
|
|
config_dir = str(Path.home() / ".led_mapper")
|
|
return Path(config_dir) / "settings.json"
|
|
|
|
|
|
def clamp_int(value, minimum: int, maximum: int, fallback: int) -> int: # noqa: ANN001
|
|
try:
|
|
number = int(value)
|
|
except (TypeError, ValueError):
|
|
return fallback
|
|
return max(minimum, min(maximum, number))
|
|
|
|
|
|
def normalize_shortcuts(value) -> dict[str, str]: # noqa: ANN001
|
|
source = value if isinstance(value, dict) else {}
|
|
shortcuts: dict[str, str] = {}
|
|
for key, default in DEFAULT_SHORTCUTS.items():
|
|
raw = source.get(key, default)
|
|
if raw is None:
|
|
raw = ""
|
|
sequence = QKeySequence(str(raw))
|
|
shortcuts[key] = sequence.toString(QKeySequence.SequenceFormat.PortableText)
|
|
return shortcuts
|