using System; using System.Collections.Generic; using System.Linq; using Dalamud.Interface.Internal.ManagedAsserts; using ImGuiNET; using Serilog; namespace Dalamud.Interface.Windowing { /// /// Class running a WindowSystem using implementations to simplify ImGui windowing. /// public class WindowSystem { private static DateTimeOffset lastAnyFocus; private readonly List windows = new(); private string lastFocusedWindowName = string.Empty; /// /// Initializes a new instance of the class. /// /// The name/ID-space of this . public WindowSystem(string? imNamespace = null) { this.Namespace = imNamespace; } /// /// Gets a value indicating whether any contains any /// that has focus and is not marked to be excluded from consideration. /// public static bool HasAnyWindowSystemFocus { get; internal set; } = false; /// /// Gets the name of the currently focused window system that is redirecting normal escape functionality. /// public static string FocusedWindowSystemNamespace { get; internal set; } = string.Empty; /// /// Gets the timespan since the last time any window was focused. /// public static TimeSpan TimeSinceLastAnyFocus => DateTimeOffset.Now - lastAnyFocus; /// /// Gets a value indicating whether any window in this has focus and is /// not marked to be excluded from consideration. /// public bool HasAnyFocus { get; private set; } /// /// Gets or sets the name/ID-space of this . /// public string? Namespace { get; set; } /// /// Add a window to this . /// /// The window to add. public void AddWindow(Window window) { if (this.windows.Any(x => x.WindowName == window.WindowName)) throw new ArgumentException("A window with this name/ID already exists."); this.windows.Add(window); } /// /// Remove a window from this . /// /// The window to remove. public void RemoveWindow(Window window) { if (!this.windows.Contains(window)) throw new ArgumentException("This window is not registered on this WindowSystem."); this.windows.Remove(window); } /// /// Remove all windows from this . /// public void RemoveAllWindows() => this.windows.Clear(); /// /// Draw all registered windows using ImGui. /// public void Draw() { var hasNamespace = !string.IsNullOrEmpty(this.Namespace); if (hasNamespace) ImGui.PushID(this.Namespace); foreach (var window in this.windows) { #if DEBUG // Log.Verbose($"[WS{(hasNamespace ? "/" + this.Namespace : string.Empty)}] Drawing {window.WindowName}"); #endif var snapshot = ImGuiManagedAsserts.GetSnapshot(); window.DrawInternal(); var source = ($"{this.Namespace}::" ?? string.Empty) + window.WindowName; ImGuiManagedAsserts.ReportProblems(source, snapshot); } var focusedWindow = this.windows.FirstOrDefault(window => window.IsFocused && window.RespectCloseHotkey); this.HasAnyFocus = focusedWindow != default; if (this.HasAnyFocus) { if (this.lastFocusedWindowName != focusedWindow.WindowName) { Log.Verbose($"WindowSystem \"{this.Namespace}\" Window \"{focusedWindow.WindowName}\" has focus now"); this.lastFocusedWindowName = focusedWindow.WindowName; } HasAnyWindowSystemFocus = true; FocusedWindowSystemNamespace = this.Namespace; lastAnyFocus = DateTimeOffset.Now; } else { if (this.lastFocusedWindowName != string.Empty) { Log.Verbose($"WindowSystem \"{this.Namespace}\" Window \"{this.lastFocusedWindowName}\" lost focus"); this.lastFocusedWindowName = string.Empty; } } if (hasNamespace) ImGui.PopID(); } } }