diff --git a/Dalamud/Interface/Windowing/Window.cs b/Dalamud/Interface/Windowing/Window.cs new file mode 100644 index 000000000..98e73f6f9 --- /dev/null +++ b/Dalamud/Interface/Windowing/Window.cs @@ -0,0 +1,144 @@ +using System.Numerics; + +using ImGuiNET; + +namespace Dalamud.Interface.Windowing +{ + /// + /// Base class you can use to implement an ImGui window for use with the built-in . + /// + public abstract class Window + { + private bool internalIsOpen; + + /// + /// Initializes a new instance of the class. + /// + /// The name/ID of this window. + /// If you have multiple windows with the same name, you will need to + /// append an unique ID to it by specifying it after "###" behind the window title. + /// + /// The of this window. + /// Whether or not this window should be limited to the main game window. + protected Window(string name, ImGuiWindowFlags flags, bool forceMainWindow = false) + { + this.WindowName = name; + this.Flags = flags; + this.ForceMainWindow = forceMainWindow; + } + + /// + /// Gets or sets the name of the window. + /// If you have multiple windows with the same name, you will need to + /// append an unique ID to it by specifying it after "###" behind the window title. + /// + public string WindowName { get; set; } + + /// + /// Gets or sets the position of this window. + /// + public Vector2? Position { get; set; } + + /// + /// Gets or sets the condition that defines when the position of this window is set. + /// + public ImGuiCond PositionCondition { get; set; } + + /// + /// Gets or sets the size of the window. + /// + public Vector2? Size { get; set; } + + /// + /// Gets or sets the condition that defines when the size of this window is set. + /// + public ImGuiCond SizeCondition { get; set; } + + /// + /// Gets or sets the minimum size of this window. + /// + public Vector2? SizeConstraintsMin { get; set; } + + /// + /// Gets or sets the maximum size of this window. + /// + public Vector2? SizeConstraintsMax { get; set; } + + /// + /// Gets or sets a value indicating whether or not this window is collapsed. + /// + public bool? Collapsed { get; set; } + + /// + /// Gets or sets the condition that defines when the collapsed state of this window is set. + /// + public ImGuiCond CollapsedCondition { get; set; } + + /// + /// Gets or sets the window flags. + /// + public ImGuiWindowFlags Flags { get; set; } + + /// + /// Gets or sets a value indicating whether or not this ImGui window will be forced to stay inside the main game window. + /// + public bool ForceMainWindow { get; set; } + + /// + /// Gets or sets a value indicating whether or not this window will stay open. + /// + public bool IsOpen + { + get => this.internalIsOpen; + set => this.internalIsOpen = value; + } + + /// + /// In this method, implement your drawing code. + /// You do NOT need to ImGui.Begin your window. + /// + public abstract void Draw(); + + /// + /// Draw the window via ImGui. + /// + internal void DrawInternal() + { + this.ApplyConditionals(); + + if (this.ForceMainWindow) + ImGuiHelpers.ForceMainWindow(); + + if (ImGui.Begin(this.WindowName, ref this.internalIsOpen, this.Flags)) + { + // Draw the actual window contents + this.Draw(); + + ImGui.End(); + } + } + + private void ApplyConditionals() + { + if (this.Position.HasValue) + { + ImGui.SetNextWindowPos(this.Position.Value, this.PositionCondition); + } + + if (this.Size.HasValue) + { + ImGui.SetNextWindowPos(this.Size.Value, this.SizeCondition); + } + + if (this.Collapsed.HasValue) + { + ImGui.SetNextWindowCollapsed(this.Collapsed.Value, this.CollapsedCondition); + } + + if (this.SizeConstraintsMin.HasValue && this.SizeConstraintsMax.HasValue) + { + ImGui.SetNextWindowSizeConstraints(this.SizeConstraintsMin.Value, this.SizeConstraintsMax.Value); + } + } + } +} diff --git a/Dalamud/Interface/Windowing/WindowSystem.cs b/Dalamud/Interface/Windowing/WindowSystem.cs new file mode 100644 index 000000000..b683bb8c3 --- /dev/null +++ b/Dalamud/Interface/Windowing/WindowSystem.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +using ImGuiNET; + +namespace Dalamud.Interface.Windowing +{ + /// + /// Class running a WindowSystem using implementations to simplify ImGui windowing. + /// + public class WindowSystem + { + private readonly List windows = new List(); + + /// + /// Initializes a new instance of the class. + /// + /// The name/ID-space of this . + public WindowSystem(string imNamespace = null) + { + this.Namespace = imNamespace; + } + + /// + /// 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); + } + + /// + /// 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) + { + window.DrawInternal(); + } + + if (hasNamespace) + ImGui.PopID(); + } + } +}