"""Application configuration (grid, snapping, routing, animation, theming).""" from __future__ import annotations from PyQt6.QtCore import QObject, pyqtSignal class AppConfig(QObject): """Live, observable editor configuration. Emitting :attr:`changed` lets the canvas and items refresh when the user tweaks a setting in the configuration dialog. """ changed = pyqtSignal() def __init__(self, parent: QObject | None = None) -> None: super().__init__(parent) self.grid_size = 20 self.show_grid = True self.snap_to_grid = True # Draw a small arc "hop" where an edge crosses another edge. self.arc_on_crossing = True self.arc_radius = 5.0 # Routing stub length from a port before turning. self.route_stub = 20 # Flow animation. self.animation_speed = 1.0 # multiplier self.color_scheme = "default" # Canvas theme. self.background = "#fafafa" self.grid_color = "#e0e0e0" def snap(self, value: float) -> float: if not self.snap_to_grid or self.grid_size <= 0: return value g = self.grid_size return round(value / g) * g def snap_point(self, x: float, y: float) -> tuple[float, float]: return self.snap(x), self.snap(y) def emit_changed(self) -> None: self.changed.emit() def to_dict(self) -> dict: return { "grid_size": self.grid_size, "show_grid": self.show_grid, "snap_to_grid": self.snap_to_grid, "arc_on_crossing": self.arc_on_crossing, "arc_radius": self.arc_radius, "route_stub": self.route_stub, "animation_speed": self.animation_speed, "color_scheme": self.color_scheme, "background": self.background, "grid_color": self.grid_color, } def update_from(self, data: dict) -> None: for k, v in data.items(): if hasattr(self, k): setattr(self, k, v) self.changed.emit()