Dalamud/Dalamud.Interface/Raii/EndObjects.cs
2023-07-27 14:02:34 +02:00

254 lines
9.1 KiB
C#

using System.Numerics;
using ImGuiNET;
namespace Dalamud.Interface.Raii;
// Most ImGui widgets with IDisposable interface that automatically destroys them
// when created with using variables.
public static partial class ImRaii
{
private static int _disabledCount = 0;
public static IEndObject Child(string strId)
=> new EndUnconditionally(ImGui.EndChild, ImGui.BeginChild(strId));
public static IEndObject Child(string strId, Vector2 size)
=> new EndUnconditionally(ImGui.EndChild, ImGui.BeginChild(strId, size));
public static IEndObject Child(string strId, Vector2 size, bool border)
=> new EndUnconditionally(ImGui.EndChild, ImGui.BeginChild(strId, size, border));
public static IEndObject Child(string strId, Vector2 size, bool border, ImGuiWindowFlags flags)
=> new EndUnconditionally(ImGui.EndChild, ImGui.BeginChild(strId, size, border, flags));
public static IEndObject DragDropTarget()
=> new EndConditionally(ImGui.EndDragDropTarget, ImGui.BeginDragDropTarget());
public static IEndObject DragDropSource()
=> new EndConditionally(ImGui.EndDragDropSource, ImGui.BeginDragDropSource());
public static IEndObject DragDropSource(ImGuiDragDropFlags flags)
=> new EndConditionally(ImGui.EndDragDropSource, ImGui.BeginDragDropSource(flags));
public static IEndObject Popup(string id)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopup(id));
public static IEndObject Popup(string id, ImGuiWindowFlags flags)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopup(id, flags));
public static IEndObject PopupModal(string id)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupModal(id));
public static IEndObject PopupModal(string id, ref bool open)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupModal(id, ref open));
public static IEndObject PopupModal(string id, ref bool open, ImGuiWindowFlags flags)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupModal(id, ref open, flags));
public static IEndObject ContextPopup(string id)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupContextWindow(id));
public static IEndObject ContextPopup(string id, ImGuiPopupFlags flags)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupContextWindow(id, flags));
public static IEndObject ContextPopupItem(string id)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupContextItem(id));
public static IEndObject ContextPopupItem(string id, ImGuiPopupFlags flags)
=> new EndConditionally(ImGui.EndPopup, ImGui.BeginPopupContextItem(id, flags));
public static IEndObject Combo(string label, string previewValue)
=> new EndConditionally(ImGui.EndCombo, ImGui.BeginCombo(label, previewValue));
public static IEndObject Combo(string label, string previewValue, ImGuiComboFlags flags)
=> new EndConditionally(ImGui.EndCombo, ImGui.BeginCombo(label, previewValue, flags));
public static IEndObject Group()
{
ImGui.BeginGroup();
return new EndUnconditionally(ImGui.EndGroup, true);
}
public static IEndObject Tooltip()
{
ImGui.BeginTooltip();
return new EndUnconditionally(ImGui.EndTooltip, true);
}
public static IEndObject ListBox(string label)
=> new EndConditionally(ImGui.EndListBox, ImGui.BeginListBox(label));
public static IEndObject ListBox(string label, Vector2 size)
=> new EndConditionally(ImGui.EndListBox, ImGui.BeginListBox(label, size));
public static IEndObject Table(string table, int numColumns)
=> new EndConditionally(ImGui.EndTable, ImGui.BeginTable(table, numColumns));
public static IEndObject Table(string table, int numColumns, ImGuiTableFlags flags)
=> new EndConditionally(ImGui.EndTable, ImGui.BeginTable(table, numColumns, flags));
public static IEndObject Table(string table, int numColumns, ImGuiTableFlags flags, Vector2 outerSize)
=> new EndConditionally(ImGui.EndTable, ImGui.BeginTable(table, numColumns, flags, outerSize));
public static IEndObject Table(string table, int numColumns, ImGuiTableFlags flags, Vector2 outerSize, float innerWidth)
=> new EndConditionally(ImGui.EndTable, ImGui.BeginTable(table, numColumns, flags, outerSize, innerWidth));
public static IEndObject TabBar(string label)
=> new EndConditionally(ImGui.EndTabBar, ImGui.BeginTabBar(label));
public static IEndObject TabBar(string label, ImGuiTabBarFlags flags)
=> new EndConditionally(ImGui.EndTabBar, ImGui.BeginTabBar(label, flags));
public static IEndObject TabItem(string label)
=> new EndConditionally(ImGui.EndTabItem, ImGui.BeginTabItem(label));
public static unsafe IEndObject TabItem(byte* label, ImGuiTabItemFlags flags)
=> new EndConditionally(ImGuiNative.igEndTabItem, ImGuiNative.igBeginTabItem(label, null, flags) != 0);
public static IEndObject TabItem(string label, ref bool open)
=> new EndConditionally(ImGui.EndTabItem, ImGui.BeginTabItem(label, ref open));
public static IEndObject TabItem(string label, ref bool open, ImGuiTabItemFlags flags)
=> new EndConditionally(ImGui.EndTabItem, ImGui.BeginTabItem(label, ref open, flags));
public static IEndObject TreeNode(string label)
=> new EndConditionally(ImGui.TreePop, ImGui.TreeNodeEx(label));
public static IEndObject TreeNode(string label, ImGuiTreeNodeFlags flags)
=> new EndConditionally(flags.HasFlag(ImGuiTreeNodeFlags.NoTreePushOnOpen) ? Nop : ImGui.TreePop, ImGui.TreeNodeEx(label, flags));
public static IEndObject Disabled()
{
ImGui.BeginDisabled();
++_disabledCount;
return DisabledEnd();
}
public static IEndObject Disabled(bool disabled)
{
if (!disabled)
return new EndConditionally(Nop, false);
ImGui.BeginDisabled();
++_disabledCount;
return DisabledEnd();
}
public static IEndObject Enabled()
{
var oldCount = _disabledCount;
if (oldCount == 0)
return new EndConditionally(Nop, false);
void Restore()
{
_disabledCount += oldCount;
while (--oldCount >= 0)
ImGui.BeginDisabled();
}
for (; _disabledCount > 0; --_disabledCount)
ImGui.EndDisabled();
return new EndUnconditionally(Restore, true);
}
private static IEndObject DisabledEnd()
=> new EndUnconditionally(() =>
{
--_disabledCount;
ImGui.EndDisabled();
}, true);
/* Only in OtterGui for now
public static IEndObject FramedGroup(string label)
{
Widget.BeginFramedGroup(label, Vector2.Zero);
return new EndUnconditionally(Widget.EndFramedGroup, true);
}
public static IEndObject FramedGroup(string label, Vector2 minSize, string description = "")
{
Widget.BeginFramedGroup(label, minSize, description);
return new EndUnconditionally(Widget.EndFramedGroup, true);
}
*/
// Exported interface for RAII.
public interface IEndObject : IDisposable
{
public bool Success { get; }
public static bool operator true(IEndObject i)
=> i.Success;
public static bool operator false(IEndObject i)
=> !i.Success;
public static bool operator !(IEndObject i)
=> !i.Success;
public static bool operator &(IEndObject i, bool value)
=> i.Success && value;
public static bool operator |(IEndObject i, bool value)
=> i.Success || value;
// Empty end object.
public static readonly IEndObject Empty = new EndConditionally(Nop, false);
}
// Use end-function regardless of success.
// Used by Child, Group and Tooltip.
private struct EndUnconditionally : IEndObject
{
private Action EndAction { get; }
public bool Success { get; }
public bool Disposed { get; private set; }
public EndUnconditionally(Action endAction, bool success)
{
this.EndAction = endAction;
this.Success = success;
this.Disposed = false;
}
public void Dispose()
{
if (this.Disposed)
return;
this.EndAction();
this.Disposed = true;
}
}
// Use end-function only on success.
private struct EndConditionally : IEndObject
{
private Action EndAction { get; }
public bool Success { get; }
public bool Disposed { get; private set; }
public EndConditionally(Action endAction, bool success)
{
this.EndAction = endAction;
this.Success = success;
this.Disposed = false;
}
public void Dispose()
{
if (this.Disposed)
return;
if (this.Success)
this.EndAction();
this.Disposed = true;
}
}
// Used to avoid tree pops when flag for no push is set.
private static void Nop()
{ }
}