feat: add new ImGui windowing system

This commit is contained in:
goat 2021-04-05 17:48:03 +02:00
parent efdf9ca1ee
commit 266865a14c
2 changed files with 217 additions and 0 deletions

View file

@ -0,0 +1,144 @@
using System.Numerics;
using ImGuiNET;
namespace Dalamud.Interface.Windowing
{
/// <summary>
/// Base class you can use to implement an ImGui window for use with the built-in <see cref="WindowSystem"/>.
/// </summary>
public abstract class Window
{
private bool internalIsOpen;
/// <summary>
/// Initializes a new instance of the <see cref="Window"/> class.
/// </summary>
/// <param name="name">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.
/// </param>
/// <param name="flags">The <see cref="ImGuiWindowFlags"/> of this window.</param>
/// <param name="forceMainWindow">Whether or not this window should be limited to the main game window.</param>
protected Window(string name, ImGuiWindowFlags flags, bool forceMainWindow = false)
{
this.WindowName = name;
this.Flags = flags;
this.ForceMainWindow = forceMainWindow;
}
/// <summary>
/// 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.
/// </summary>
public string WindowName { get; set; }
/// <summary>
/// Gets or sets the position of this window.
/// </summary>
public Vector2? Position { get; set; }
/// <summary>
/// Gets or sets the condition that defines when the position of this window is set.
/// </summary>
public ImGuiCond PositionCondition { get; set; }
/// <summary>
/// Gets or sets the size of the window.
/// </summary>
public Vector2? Size { get; set; }
/// <summary>
/// Gets or sets the condition that defines when the size of this window is set.
/// </summary>
public ImGuiCond SizeCondition { get; set; }
/// <summary>
/// Gets or sets the minimum size of this window.
/// </summary>
public Vector2? SizeConstraintsMin { get; set; }
/// <summary>
/// Gets or sets the maximum size of this window.
/// </summary>
public Vector2? SizeConstraintsMax { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not this window is collapsed.
/// </summary>
public bool? Collapsed { get; set; }
/// <summary>
/// Gets or sets the condition that defines when the collapsed state of this window is set.
/// </summary>
public ImGuiCond CollapsedCondition { get; set; }
/// <summary>
/// Gets or sets the window flags.
/// </summary>
public ImGuiWindowFlags Flags { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not this ImGui window will be forced to stay inside the main game window.
/// </summary>
public bool ForceMainWindow { get; set; }
/// <summary>
/// Gets or sets a value indicating whether or not this window will stay open.
/// </summary>
public bool IsOpen
{
get => this.internalIsOpen;
set => this.internalIsOpen = value;
}
/// <summary>
/// In this method, implement your drawing code.
/// You do NOT need to ImGui.Begin your window.
/// </summary>
public abstract void Draw();
/// <summary>
/// Draw the window via ImGui.
/// </summary>
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);
}
}
}
}

View file

@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
using System.Linq;
using ImGuiNET;
namespace Dalamud.Interface.Windowing
{
/// <summary>
/// Class running a WindowSystem using <see cref="Window"/> implementations to simplify ImGui windowing.
/// </summary>
public class WindowSystem
{
private readonly List<Window> windows = new List<Window>();
/// <summary>
/// Initializes a new instance of the <see cref="WindowSystem"/> class.
/// </summary>
/// <param name="imNamespace">The name/ID-space of this <see cref="WindowSystem"/>.</param>
public WindowSystem(string imNamespace = null)
{
this.Namespace = imNamespace;
}
/// <summary>
/// Gets or sets the name/ID-space of this <see cref="WindowSystem"/>.
/// </summary>
public string Namespace { get; set; }
/// <summary>
/// Add a window to this <see cref="WindowSystem"/>.
/// </summary>
/// <param name="window">The window to add.</param>
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);
}
/// <summary>
/// Remove a window from this <see cref="WindowSystem"/>.
/// </summary>
/// <param name="window">The window to remove.</param>
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);
}
/// <summary>
/// Draw all registered windows using ImGui.
/// </summary>
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();
}
}
}