import Foundation /// Persisted layout positions using normalized (0..1) coordinates. /// Survives resolution changes and provides stability across activations. struct LayoutPosition: Codable, Equatable { let normalizedX: Double let normalizedY: Double let normalizedWidth: Double let normalizedHeight: Double func absoluteRect(in bounds: CGRect) -> CGRect { CGRect( x: bounds.origin.x + normalizedX * bounds.width, y: bounds.origin.y + normalizedY * bounds.height, width: normalizedWidth * bounds.width, height: normalizedHeight * bounds.height ) } static func from(rect: CGRect, in bounds: CGRect) -> LayoutPosition { LayoutPosition( normalizedX: (rect.origin.x - bounds.origin.x) / bounds.width, normalizedY: (rect.origin.y - bounds.origin.y) / bounds.height, normalizedWidth: rect.width / bounds.width, normalizedHeight: rect.height / bounds.height ) } } /// Stores the full layout state for a screen configuration. final class LayoutState { /// Maps window fingerprint key to its normalized position. private(set) var positions: [String: LayoutPosition] = [:] /// The fingerprint of the last snapshot used for layout. private(set) var lastFingerprint: Set = [] func store(key: String, position: LayoutPosition) { positions[key] = position } func position(for key: String) -> LayoutPosition? { positions[key] } func updateFingerprint(_ fingerprint: Set) { lastFingerprint = fingerprint } func clear() { positions.removeAll() lastFingerprint.removeAll() } /// Remove positions for keys no longer present. func prune(keeping keys: Set) { positions = positions.filter { keys.contains($0.key) } } }