mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-02-24 13:41:49 +01:00
- Convert ImPlot to the new ref style
This commit is contained in:
parent
8d55dccd75
commit
a6d22e34f3
10 changed files with 857 additions and 356 deletions
|
|
@ -0,0 +1,73 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotAlignedDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotAlignedDisposable"/> struct. </summary>
|
||||
/// <param name="groupId"> The ID of the plot as text. </param>
|
||||
/// <param name="vertical"> Whether the plot should be vertical. </param>
|
||||
internal PlotAlignedDisposable(string groupId, bool vertical = true)
|
||||
{
|
||||
this.Success = ImPlot.BeginAlignedPlots(groupId, vertical);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotAlignedDisposable(string,bool)"/>
|
||||
internal PlotAlignedDisposable(ReadOnlySpan<byte> groupId, bool vertical = true)
|
||||
{
|
||||
this.Success = ImPlot.BeginAlignedPlots(groupId, vertical);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotAlignedDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotAlignedDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotAlignedDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotAlignedDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotAlignedDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotAlignedDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndAlignedPlots();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndAlignedPlots();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,124 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
// ReSharper disable once CheckNamespace
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
public sealed class PlotColorDisposable : IDisposable
|
||||
{
|
||||
internal static readonly List<(ImPlotCol Type, uint BackupColor)> Stack = [];
|
||||
|
||||
/// <summary> Gets the number of colors currently pushed using this disposable. </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary> Push a color to the color stack. </summary>
|
||||
/// <param name="type"> The type of color to change. </param>
|
||||
/// <param name="color"> The color to change it to. </param>
|
||||
/// <param name="condition"> If this is false, the color is not pushed. </param>
|
||||
/// <returns> A disposable object that can be used to push further colors and pops those colors after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep colors pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotColorDisposable Push(ImPlotCol type, uint color, bool condition = true)
|
||||
=> condition ? this.InternalPush(type, color) : this;
|
||||
|
||||
/// <summary> Push a color to the color stack. </summary>
|
||||
/// <param name="type"> The type of color to change. </param>
|
||||
/// <param name="color"> The color to change it to. </param>
|
||||
/// /// <param name="condition"> If this is false, the color is not pushed. </param>
|
||||
/// <returns> A disposable object that can be used to push further colors and pops those colors after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep colors pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotColorDisposable Push(ImPlotCol type, Vector4 color, bool condition = true)
|
||||
=> condition ? this.InternalPush(type, color) : this;
|
||||
|
||||
/// <summary> Push a color to the color stack. </summary>
|
||||
/// <param name="type"> The type of color to change. </param>
|
||||
/// <param name="color"> The color to change it to. If this is null, no color will be set. </param>
|
||||
/// /// <param name="condition"> If this is false, the color is not pushed. </param>
|
||||
/// <returns> A disposable object that can be used to push further colors and pops those colors after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep colors pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotColorDisposable Push(ImPlotCol type, Vector4? color, bool condition = true)
|
||||
{
|
||||
if (!color.HasValue)
|
||||
return this;
|
||||
|
||||
return condition ? this.InternalPush(type, color.Value) : this;
|
||||
}
|
||||
|
||||
private PlotColorDisposable InternalPush(ImPlotCol type, uint color)
|
||||
{
|
||||
Stack.Add((type, GetColorU32(type)));
|
||||
ImPlot.PushStyleColor(type, color);
|
||||
++this.Count;
|
||||
return this;
|
||||
}
|
||||
|
||||
private PlotColorDisposable InternalPush(ImPlotCol type, Vector4 color)
|
||||
{
|
||||
Stack.Add((type, GetColorU32(type)));
|
||||
ImPlot.PushStyleColor(type, color);
|
||||
++this.Count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Reverts all pushed colors to their previous values temporarily. </summary>
|
||||
/// <returns> A disposable object that can be used to push further colors and pops those colors after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep colors pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public static PlotColorDisposable PlotDefaultColors()
|
||||
{
|
||||
var ret = new PlotColorDisposable();
|
||||
var reverseStack = Stack.GroupBy(p => p.Type).Select(p => (p.Key, p.First().BackupColor)).ToArray();
|
||||
foreach (var (idx, val) in reverseStack)
|
||||
ret.Push(idx, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary> Push the default value, i.e. the value as if nothing was ever pushed to this, of a color to the color stack. </summary>
|
||||
/// <param name="type"> The type of color to return to its default value. </param>
|
||||
/// <returns> A disposable object that can be used to push further colors and pops those colors after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep colors pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotColorDisposable PlotPushDefault(ImPlotCol type)
|
||||
{
|
||||
foreach (var styleMod in Stack.Where(m => m.Type == type))
|
||||
return this.Push(type, styleMod.BackupColor);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Pop a number of colors. </summary>
|
||||
/// <param name="num"> The number of colors to pop. This is clamped to the number of colors pushed by this object. </param>
|
||||
public PlotColorDisposable Pop(int num = 1)
|
||||
{
|
||||
num = Math.Min(num, this.Count);
|
||||
if (num > 0)
|
||||
{
|
||||
this.Count -= num;
|
||||
ImPlot.PopStyleColor(num);
|
||||
Stack.RemoveRange(Stack.Count - num, num);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Pop all pushed colors. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
this.Pop(this.Count);
|
||||
this.Count = 0;
|
||||
}
|
||||
|
||||
/// <summary> Pop a number of colors. </summary>
|
||||
/// <param name="num"> The number of colors to pop. The number is not checked against the color stack. </param>
|
||||
/// <remarks> Avoid using this function, and colors across scopes, as much as possible. </remarks>
|
||||
public static void PopUnsafe(int num = 1)
|
||||
=> ImPlot.PopStyleColor(num);
|
||||
|
||||
// Reimplementation of https://github.com/ocornut/imgui/blob/868facff9ded2d61425c67deeba354eb24275bd1/imgui.cpp#L3035
|
||||
// for ImPlot
|
||||
private static uint GetColorU32(ImPlotCol idx)
|
||||
=> ImGui.GetColorU32(ImPlot.GetStyle().Colors[(int)idx]);
|
||||
}
|
||||
}
|
||||
75
Dalamud/Interface/Utility/Raii/Disposables/PlotDisposable.cs
Normal file
75
Dalamud/Interface/Utility/Raii/Disposables/PlotDisposable.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using System.Numerics;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotDisposable"/> struct. </summary>
|
||||
/// <param name="titleId"> The ID of the plot as text. </param>
|
||||
/// <param name="size"> The desired size of the plot. </param>
|
||||
/// <param name="flags"> Additional flags for the plot. </param>
|
||||
internal PlotDisposable(string titleId, Vector2 size, ImPlotFlags flags)
|
||||
{
|
||||
this.Success = ImPlot.BeginPlot(titleId, size, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotDisposable(string,Vector2,ImPlotFlags)"/>
|
||||
internal PlotDisposable(ReadOnlySpan<byte> titleId, Vector2 size, ImPlotFlags flags)
|
||||
{
|
||||
this.Success = ImPlot.BeginPlot(titleId, size, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndPlot();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndPlot();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,93 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotDragDropSourceDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotDragDropSourceDisposable"/> struct. </summary>
|
||||
/// <param name="labelId"> The ID of the plot as text. </param>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
internal PlotDragDropSourceDisposable(string labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
{
|
||||
this.Success = ImPlot.BeginDragDropSourceItem(labelId, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotDragDropSourceDisposable(string,ImGuiDragDropFlags)"/>
|
||||
internal PlotDragDropSourceDisposable(ReadOnlySpan<byte> labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
{
|
||||
this.Success = ImPlot.BeginDragDropSourceItem(labelId, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Initialize a new instance of the <see cref="PlotDragDropSourceDisposable"/> struct with SourceAxis. </summary>
|
||||
/// <param name="axis"> The axis to drag. </param>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
/// <returns> A disposable object that indicates whether the source is active. Use with using. </returns>
|
||||
internal static PlotDragDropSourceDisposable AxisPlot(ImAxis axis, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new(ImPlot.BeginDragDropSourceAxis(axis, flags));
|
||||
|
||||
/// <summary> Initialize a new instance of the <see cref="PlotDragDropSourceDisposable"/> struct with SourcePlot. </summary>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
/// <returns> A disposable object that indicates whether the source is active. Use with using. </returns>
|
||||
internal static PlotDragDropSourceDisposable SourcePlot(ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new(ImPlot.BeginDragDropSourcePlot(flags));
|
||||
|
||||
private PlotDragDropSourceDisposable(bool success)
|
||||
{
|
||||
this.Success = success;
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotDragDropSourceDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotDragDropSourceDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotDragDropSourceDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotDragDropSourceDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotDragDropSourceDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotDragDropSourceDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndDragDropSource();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndDragDropSource();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotDragDropTargetDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary> Initialize a new instance of the <see cref="PlotDragDropTargetDisposable"/> struct with SourceAxis. </summary>
|
||||
/// <param name="axis"> The axis to drag. </param>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
/// <returns> A disposable object that indicates whether the source is active. Use with using. </returns>
|
||||
internal static PlotDragDropTargetDisposable AxisPlot(ImAxis axis)
|
||||
=> new(ImPlot.BeginDragDropTargetAxis(axis));
|
||||
|
||||
/// <summary> Initialize a new instance of the <see cref="PlotDragDropTargetDisposable"/> struct with SourcePlot. </summary>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
/// <returns> A disposable object that indicates whether the source is active. Use with using. </returns>
|
||||
internal static PlotDragDropTargetDisposable LegendPlot()
|
||||
=> new(ImPlot.BeginDragDropTargetLegend());
|
||||
|
||||
/// <summary> Initialize a new instance of the <see cref="PlotDragDropTargetDisposable"/> struct with SourcePlot. </summary>
|
||||
/// <param name="flags"> Additional flags to control the drag and drop behaviour. </param>
|
||||
/// <returns> A disposable object that indicates whether the source is active. Use with using. </returns>
|
||||
internal static PlotDragDropTargetDisposable SourcePlot()
|
||||
=> new(ImPlot.BeginDragDropTargetPlot());
|
||||
|
||||
private PlotDragDropTargetDisposable(bool success)
|
||||
{
|
||||
this.Success = success;
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotDragDropTargetDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotDragDropTargetDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotDragDropTargetDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotDragDropTargetDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotDragDropTargetDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotDragDropTargetDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndDragDropTarget();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndDragDropTarget();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotLegendDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotLegendDisposable"/> struct. </summary>
|
||||
/// <param name="labelId"> The ID of the plot as text. </param>
|
||||
/// <param name="mouseButton"> The mouse button to use for opening the legend popup. </param>
|
||||
internal PlotLegendDisposable(string labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
{
|
||||
this.Success = ImPlot.BeginLegendPopup(labelId, mouseButton);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotLegendDisposable(string,ImGuiMouseButton)"/>
|
||||
internal PlotLegendDisposable(ReadOnlySpan<byte> labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
{
|
||||
this.Success = ImPlot.BeginLegendPopup(labelId, mouseButton);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotLegendDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotLegendDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotLegendDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotLegendDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotLegendDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotLegendDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndLegendPopup();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndLegendPopup();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using System.Numerics;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around style pushing. </summary>
|
||||
public sealed class PlotStyleDisposable : IDisposable
|
||||
{
|
||||
internal static readonly List<(ImPlotStyleVar Type, Vector2 Value)> Stack = [];
|
||||
|
||||
/// <summary> The number of styles currently pushed using this disposable. </summary>
|
||||
public int Count { get; private set; }
|
||||
|
||||
/// <summary> Push a style variable to the style stack. </summary>
|
||||
/// <param name="type"> The type of style variable to change. </param>
|
||||
/// <param name="value"> The value to change it to. </param>
|
||||
/// <param name="condition"> If this is false, the style is not pushed. </param>
|
||||
/// <returns> A disposable object that can be used to push further style variables and pops those style variables after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep styles pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotStyleDisposable Push(ImPlotStyleVar type, float value, bool condition)
|
||||
=> condition ? this.Push(type, value) : this;
|
||||
|
||||
/// <inheritdoc cref="Push(ImGuiStyleVar,float,bool)"/>
|
||||
public PlotStyleDisposable Push(ImPlotStyleVar type, Vector2 value, bool condition)
|
||||
=> condition ? this.Push(type, value) : this;
|
||||
|
||||
public PlotStyleDisposable Push(ImPlotStyleVar type, float value)
|
||||
{
|
||||
CheckStyleIdx(type, typeof(float));
|
||||
Stack.Add((type, GetStyle(type)));
|
||||
|
||||
ImPlot.PushStyleVar(type, value);
|
||||
++this.Count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Push(ImGuiStyleVar,float,bool)"/>
|
||||
public PlotStyleDisposable Push(ImPlotStyleVar type, Vector2 value)
|
||||
{
|
||||
CheckStyleIdx(type, typeof(Vector2));
|
||||
Stack.Add((type, GetStyle(type)));
|
||||
|
||||
ImPlot.PushStyleVar(type, value);
|
||||
++this.Count;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Push styles that revert all current style changes made temporarily. </summary>
|
||||
public static PlotStyleDisposable PlotDefaultStyle()
|
||||
{
|
||||
var ret = new PlotStyleDisposable();
|
||||
var reverseStack = Stack.GroupBy(p => p.Type).Select(p => (p.Key, p.First().Value)).ToArray();
|
||||
foreach (var (idx, val) in reverseStack)
|
||||
{
|
||||
if (idx == ImPlotStyleVar.Marker)
|
||||
ret.Push(idx, (int)val.X);
|
||||
else if (float.IsNaN(val.Y))
|
||||
ret.Push(idx, val.X);
|
||||
else
|
||||
ret.Push(idx, val);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// <summary> Push the default value, i.e. the value as if nothing was ever pushed to this, of a style variable to the style stack. </summary>
|
||||
/// <param name="type"> The type of style variable to return to its default value. </param>
|
||||
/// <returns> A disposable object that can be used to push further style variables and pops those style variables after leaving scope. Use with using. </returns>
|
||||
/// <remarks> If you need to keep styles pushed longer than the current scope, use without using and use <seealso cref="PopUnsafe"/>. </remarks>
|
||||
public PlotStyleDisposable PlotPushDefault(ImPlotStyleVar type)
|
||||
{
|
||||
foreach (var styleMod in Stack.Where(m => m.Type == type))
|
||||
return Push(type, styleMod.Value);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Pop a number of style variables. </summary>
|
||||
/// <param name="num"> The number of style variables to pop. This is clamped to the number of style variables pushed by this object. </param>
|
||||
public PlotStyleDisposable Pop(int num = 1)
|
||||
{
|
||||
num = Math.Min(num, this.Count);
|
||||
if (num > 0)
|
||||
{
|
||||
this.Count -= num;
|
||||
ImPlot.PopStyleVar(num);
|
||||
Stack.RemoveRange(Stack.Count - num, num);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary> Pop all pushed styles. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
ImPlot.PopStyleVar(this.Count);
|
||||
this.Count = 0;
|
||||
}
|
||||
|
||||
/// <summary> Pop a number of style variables. </summary>
|
||||
/// <param name="num"> The number of style variables to pop. The number is not checked against the style stack. </param>
|
||||
/// <remarks> Avoid using this function, and styles across scopes, as much as possible. </remarks>
|
||||
public static void PopUnsafe(int num = 1)
|
||||
=> ImPlot.PopStyleVar(num);
|
||||
|
||||
private static void CheckStyleIdx(ImPlotStyleVar idx, Type type)
|
||||
{
|
||||
var shouldThrow = idx switch
|
||||
{
|
||||
ImPlotStyleVar.LineWeight => type != typeof(float),
|
||||
ImPlotStyleVar.Marker => type != typeof(int),
|
||||
ImPlotStyleVar.MarkerSize => type != typeof(float),
|
||||
ImPlotStyleVar.MarkerWeight => type != typeof(float),
|
||||
ImPlotStyleVar.FillAlpha => type != typeof(float),
|
||||
ImPlotStyleVar.ErrorBarSize => type != typeof(float),
|
||||
ImPlotStyleVar.ErrorBarWeight => type != typeof(float),
|
||||
// ImPlotStyleVar.DigitalBitHeight => type != typeof(float),
|
||||
// ImPlotStyleVar.DigitalBitGap => type != typeof(float),
|
||||
// ImPlotStyleVar.PlotBorderSize => type != typeof(float),
|
||||
ImPlotStyleVar.MinorAlpha => type != typeof(float),
|
||||
ImPlotStyleVar.MajorTickLen => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorTickLen => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MajorTickSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorTickSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MajorGridSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorGridSize => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LabelPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendInnerPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendSpacing => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MousePosPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.AnnotationPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.FitPadding => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotDefaultSize => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotMinSize => type != typeof(Vector2),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(idx), idx, null),
|
||||
};
|
||||
|
||||
if (shouldThrow)
|
||||
throw new ArgumentException($"Unable to push {type} to {idx}.");
|
||||
}
|
||||
|
||||
public static Vector2 GetStyle(ImPlotStyleVar idx)
|
||||
{
|
||||
var style = ImPlot.GetStyle();
|
||||
return idx switch
|
||||
{
|
||||
ImPlotStyleVar.LineWeight => new Vector2(style.LineWeight, float.NaN),
|
||||
ImPlotStyleVar.Marker => new Vector2(style.Marker, float.NaN),
|
||||
ImPlotStyleVar.MarkerSize => new Vector2(style.MarkerSize, float.NaN),
|
||||
ImPlotStyleVar.MarkerWeight => new Vector2(style.MarkerWeight, float.NaN),
|
||||
ImPlotStyleVar.FillAlpha => new Vector2(style.FillAlpha, float.NaN),
|
||||
ImPlotStyleVar.ErrorBarSize => new Vector2(style.ErrorBarSize, float.NaN),
|
||||
ImPlotStyleVar.ErrorBarWeight => new Vector2(style.ErrorBarWeight, float.NaN),
|
||||
// ImPlotStyleVar.DigitalBitHeight => new Vector2(style.DigitalBitHeight, float.NaN),
|
||||
// ImPlotStyleVar.DigitalBitGap => new Vector2(style.DigitalBitGap, float.NaN),
|
||||
// ImPlotStyleVar.PlotBorderSize => new Vector2(style.PlotBorderSize, float.NaN),
|
||||
ImPlotStyleVar.MinorAlpha => new Vector2(style.MinorAlpha, float.NaN),
|
||||
ImPlotStyleVar.MajorTickLen => style.MajorTickLen,
|
||||
ImPlotStyleVar.MinorTickLen => style.MinorTickLen,
|
||||
ImPlotStyleVar.MajorTickSize => style.MajorTickSize,
|
||||
ImPlotStyleVar.MinorTickSize => style.MinorTickSize,
|
||||
ImPlotStyleVar.MajorGridSize => style.MajorGridSize,
|
||||
ImPlotStyleVar.MinorGridSize => style.MinorGridSize,
|
||||
// ImPlotStyleVar.PlotPadding => style.PlotPadding,
|
||||
ImPlotStyleVar.LabelPadding => style.LabelPadding,
|
||||
ImPlotStyleVar.LegendPadding => style.LegendPadding,
|
||||
ImPlotStyleVar.LegendInnerPadding => style.LegendInnerPadding,
|
||||
ImPlotStyleVar.LegendSpacing => style.LegendSpacing,
|
||||
ImPlotStyleVar.MousePosPadding => style.MousePosPadding,
|
||||
ImPlotStyleVar.AnnotationPadding => style.AnnotationPadding,
|
||||
ImPlotStyleVar.FitPadding => style.FitPadding,
|
||||
// ImPlotStyleVar.PlotDefaultSize => style.PlotDefaultSize,
|
||||
// ImPlotStyleVar.PlotMinSize => style.PlotMinSize,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(idx), idx, null),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
// ReSharper disable once CheckNamespace
|
||||
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Bindings.ImPlot;
|
||||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
public static partial class ImRaii
|
||||
{
|
||||
/// <summary> A wrapper around ImGui tables. </summary>
|
||||
public ref struct PlotSubDisposable : IDisposable
|
||||
{
|
||||
/// <summary> Whether creating the table succeeded. This needs to be checked before calling any of the member methods. </summary>
|
||||
public readonly bool Success;
|
||||
|
||||
/// <summary> Whether the table is already ended. </summary>
|
||||
public bool Alive { get; private set; }
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotSubDisposable"/> struct. </summary>
|
||||
/// <param name="titleId"> The ID of the plot as text. </param>
|
||||
/// <param name="rows"> The number of rows in the plot. </param>
|
||||
/// <param name="cols"> The number of columns in the plot. </param>
|
||||
/// <param name="size"> The desired size of the plot. </param>
|
||||
/// <param name="flags"> Additional flags for the plot. </param>
|
||||
internal PlotSubDisposable(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
{
|
||||
this.Success = ImPlot.BeginSubplots(titleId, rows, cols, size, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotSubDisposable(string,int,int,Vector2,ImPlotSubplotFlags)"/>
|
||||
internal PlotSubDisposable(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
{
|
||||
this.Success = ImPlot.BeginSubplots(titleId, rows, cols, size, flags);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="PlotSubDisposable"/> struct. </summary>
|
||||
/// <param name="titleId"> The ID of the plot as text. </param>
|
||||
/// <param name="rows"> The number of rows in the plot. </param>
|
||||
/// <param name="cols"> The number of columns in the plot. </param>
|
||||
/// <param name="size"> The desired size of the plot. </param>
|
||||
/// <param name="flags"> Additional flags for the plot. </param>
|
||||
/// <param name="rowRatios"> The row ratios for the plot. </param>
|
||||
/// <param name="colRatios"> The column ratios for the plot. </param>
|
||||
internal PlotSubDisposable(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
{
|
||||
this.Success = ImPlot.BeginSubplots(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="PlotSubDisposable(string,int,int,Vector2,ImPlotSubplotFlags,ref float,ref float)"/>
|
||||
internal PlotSubDisposable(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
{
|
||||
this.Success = ImPlot.BeginSubplots(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios);
|
||||
this.Alive = true;
|
||||
}
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static implicit operator bool(PlotSubDisposable value)
|
||||
=> value.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator true(PlotSubDisposable i)
|
||||
=> i.Success;
|
||||
|
||||
/// <summary> Conversion to bool. </summary>
|
||||
public static bool operator false(PlotSubDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on NOT operators. </summary>
|
||||
public static bool operator !(PlotSubDisposable i)
|
||||
=> !i.Success;
|
||||
|
||||
/// <summary> Conversion to bool on AND operators. </summary>
|
||||
public static bool operator &(PlotSubDisposable i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
/// <summary> Conversion to bool on OR operators. </summary>
|
||||
public static bool operator |(PlotSubDisposable i, bool value)
|
||||
=> i.Success || value;
|
||||
|
||||
/// <summary> End the Table on leaving scope. </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.Alive)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
ImPlot.EndSubplots();
|
||||
this.Alive = false;
|
||||
}
|
||||
|
||||
/// <summary> End a Table without using an IDisposable. </summary>
|
||||
public static void EndUnsafe()
|
||||
=> ImPlot.EndSubplots();
|
||||
}
|
||||
}
|
||||
|
|
@ -207,109 +207,4 @@ public static partial class ImRaii
|
|||
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;
|
||||
}
|
||||
|
||||
// Use end-function regardless of success.
|
||||
// Used by Child, Group and Tooltip.
|
||||
public ref 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;
|
||||
}
|
||||
|
||||
public static bool operator true(EndUnconditionally i)
|
||||
=> i.Success;
|
||||
|
||||
public static bool operator false(EndUnconditionally i)
|
||||
=> !i.Success;
|
||||
|
||||
public static bool operator !(EndUnconditionally i)
|
||||
=> !i.Success;
|
||||
|
||||
public static bool operator &(EndUnconditionally i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
public static bool operator |(EndUnconditionally i, bool value)
|
||||
=> i.Success || value;
|
||||
}
|
||||
|
||||
// Use end-function only on success.
|
||||
public ref struct EndConditionally : IEndObject
|
||||
{
|
||||
public EndConditionally(Action endAction, bool success)
|
||||
{
|
||||
this.EndAction = endAction;
|
||||
this.Success = success;
|
||||
this.Disposed = false;
|
||||
}
|
||||
|
||||
public bool Success { get; }
|
||||
|
||||
public bool Disposed { get; private set; }
|
||||
|
||||
private Action EndAction { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (this.Disposed)
|
||||
return;
|
||||
|
||||
if (this.Success)
|
||||
this.EndAction();
|
||||
this.Disposed = true;
|
||||
}
|
||||
|
||||
public static bool operator true(EndConditionally i)
|
||||
=> i.Success;
|
||||
|
||||
public static bool operator false(EndConditionally i)
|
||||
=> !i.Success;
|
||||
|
||||
public static bool operator !(EndConditionally i)
|
||||
=> !i.Success;
|
||||
|
||||
public static bool operator &(EndConditionally i, bool value)
|
||||
=> i.Success && value;
|
||||
|
||||
public static bool operator |(EndConditionally i, bool value)
|
||||
=> i.Success || value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
using Dalamud.Bindings.ImGui;
|
||||
|
|
@ -7,293 +5,92 @@ using Dalamud.Bindings.ImPlot;
|
|||
|
||||
namespace Dalamud.Interface.Utility.Raii;
|
||||
|
||||
// TODO Convert to new syntax
|
||||
|
||||
// All previous files, but only for ImPlot specific functions.
|
||||
public static partial class ImRaii
|
||||
{
|
||||
#region EndObjects
|
||||
|
||||
public static EndConditionally Plot(string titleId, Vector2 size, ImPlotFlags flags)
|
||||
=> new EndConditionally(ImPlot.EndPlot, ImPlot.BeginPlot(titleId, size, flags));
|
||||
public static PlotDisposable Plot(string titleId, Vector2 size, ImPlotFlags flags)
|
||||
=> new(titleId, size, flags);
|
||||
|
||||
public static EndConditionally Plot(ReadOnlySpan<byte> titleId, Vector2 size, ImPlotFlags flags)
|
||||
=> new EndConditionally(ImPlot.EndPlot, ImPlot.BeginPlot(titleId, size, flags));
|
||||
public static PlotDisposable Plot(ReadOnlySpan<byte> titleId, Vector2 size, ImPlotFlags flags)
|
||||
=> new(titleId, size, flags);
|
||||
|
||||
public static EndConditionally AlignedPlots(string groupId, bool vertical = true)
|
||||
=> new EndConditionally(ImPlot.EndAlignedPlots, ImPlot.BeginAlignedPlots(groupId, vertical));
|
||||
public static PlotAlignedDisposable AlignedPlots(string groupId, bool vertical = true)
|
||||
=> new(groupId, vertical);
|
||||
|
||||
public static EndConditionally AlignedPlots(ReadOnlySpan<byte> groupId, bool vertical = true)
|
||||
=> new EndConditionally(ImPlot.EndAlignedPlots, ImPlot.BeginAlignedPlots(groupId, vertical));
|
||||
public static PlotAlignedDisposable AlignedPlots(ReadOnlySpan<byte> groupId, bool vertical = true)
|
||||
=> new(groupId, vertical);
|
||||
|
||||
public static EndConditionally LegendPopup(string labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
=> new EndConditionally(ImPlot.EndLegendPopup, ImPlot.BeginLegendPopup(labelId, mouseButton));
|
||||
public static PlotLegendDisposable LegendPopup(string labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
=> new(labelId, mouseButton);
|
||||
|
||||
public static EndConditionally LegendPopup(ReadOnlySpan<byte> labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
=> new EndConditionally(ImPlot.EndLegendPopup, ImPlot.BeginLegendPopup(labelId, mouseButton));
|
||||
public static PlotLegendDisposable LegendPopup(ReadOnlySpan<byte> labelId, ImGuiMouseButton mouseButton = ImGuiMouseButton.Right)
|
||||
=> new(labelId, mouseButton);
|
||||
|
||||
public static EndConditionally Subplots(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndSubplots, ImPlot.BeginSubplots(titleId, rows, cols, size, flags));
|
||||
public static PlotSubDisposable Subplots(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
=> new(titleId, rows, cols, size, flags);
|
||||
|
||||
public static EndConditionally Subplots(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndSubplots, ImPlot.BeginSubplots(titleId, rows, cols, size, flags));
|
||||
public static PlotSubDisposable Subplots(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags = ImPlotSubplotFlags.None)
|
||||
=> new(titleId, rows, cols, size, flags);
|
||||
|
||||
public static EndConditionally Subplots(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
=> new EndConditionally(ImPlot.EndSubplots, ImPlot.BeginSubplots(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios));
|
||||
public static PlotSubDisposable Subplots(string titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
=> new(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios);
|
||||
|
||||
public static EndConditionally Subplots(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
=> new EndConditionally(ImPlot.EndSubplots, ImPlot.BeginSubplots(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios));
|
||||
public static PlotSubDisposable Subplots(ReadOnlySpan<byte> titleId, int rows, int cols, Vector2 size, ImPlotSubplotFlags flags, ref float rowRatios, ref float colRatios)
|
||||
=> new(titleId, rows, cols, size, flags, ref rowRatios, ref colRatios);
|
||||
|
||||
public static EndConditionally DragDropSourceAxis(ImAxis axis, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndDragDropSource, ImPlot.BeginDragDropSourceAxis(axis, flags));
|
||||
public static PlotDragDropSourceDisposable DragDropSourceItem(string labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new(labelId, flags);
|
||||
|
||||
public static EndConditionally DragDropSourceItem(string labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndDragDropSource, ImPlot.BeginDragDropSourceItem(labelId, flags));
|
||||
public static PlotDragDropSourceDisposable DragDropSourceItem(ReadOnlySpan<byte> labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new(labelId, flags);
|
||||
|
||||
public static EndConditionally DragDropSourceItem(ReadOnlySpan<byte> labelId, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndDragDropSource, ImPlot.BeginDragDropSourceItem(labelId, flags));
|
||||
public static PlotDragDropSourceDisposable DragDropSourceAxis(ImAxis axis, ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> PlotDragDropSourceDisposable.AxisPlot(axis, flags);
|
||||
|
||||
public static EndConditionally DragDropSourcePlot(ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> new EndConditionally(ImPlot.EndDragDropSource, ImPlot.BeginDragDropSourcePlot(flags));
|
||||
public static PlotDragDropSourceDisposable DragDropSourcePlot(ImGuiDragDropFlags flags = ImGuiDragDropFlags.None)
|
||||
=> PlotDragDropSourceDisposable.SourcePlot(flags);
|
||||
|
||||
public static EndConditionally DragDropTargetAxis(ImAxis axis)
|
||||
=> new EndConditionally(ImPlot.EndDragDropTarget, ImPlot.BeginDragDropTargetAxis(axis));
|
||||
public static PlotDragDropTargetDisposable DragDropTargetAxis(ImAxis axis)
|
||||
=> PlotDragDropTargetDisposable.AxisPlot(axis);
|
||||
|
||||
public static EndConditionally DragDropTargetLegend()
|
||||
=> new EndConditionally(ImPlot.EndDragDropTarget, ImPlot.BeginDragDropTargetLegend());
|
||||
public static PlotDragDropTargetDisposable DragDropTargetLegend()
|
||||
=> PlotDragDropTargetDisposable.LegendPlot();
|
||||
|
||||
public static EndConditionally DragDropTargetPlot()
|
||||
=> new EndConditionally(ImPlot.EndDragDropTarget, ImPlot.BeginDragDropTargetPlot());
|
||||
public static PlotDragDropTargetDisposable DragDropTargetPlot()
|
||||
=> PlotDragDropTargetDisposable.SourcePlot();
|
||||
|
||||
#endregion EndObjects
|
||||
|
||||
#region Style
|
||||
|
||||
public static PlotStyle PushStyle(ImPlotStyleVar idx, int value, bool condition = true)
|
||||
=> new PlotStyle().Push(idx, value, condition);
|
||||
public static PlotStyleDisposable PushStyle(ImPlotStyleVar idx, int value, bool condition = true)
|
||||
=> new PlotStyleDisposable().Push(idx, value, condition);
|
||||
|
||||
public static PlotStyle PushStyle(ImPlotStyleVar idx, float value, bool condition = true)
|
||||
=> new PlotStyle().Push(idx, value, condition);
|
||||
public static PlotStyleDisposable PushStyle(ImPlotStyleVar idx, float value, bool condition = true)
|
||||
=> new PlotStyleDisposable().Push(idx, value, condition);
|
||||
|
||||
public static PlotStyle PushStyle(ImPlotStyleVar idx, Vector2 value, bool condition = true)
|
||||
=> new PlotStyle().Push(idx, value, condition);
|
||||
public static PlotStyleDisposable PushStyle(ImPlotStyleVar idx, Vector2 value, bool condition = true)
|
||||
=> new PlotStyleDisposable().Push(idx, value, condition);
|
||||
|
||||
// Push styles that revert all current plot style changes made temporarily.
|
||||
public static PlotStyle DefaultPlotStyle()
|
||||
{
|
||||
var ret = new PlotStyle();
|
||||
var reverseStack = PlotStyle.Stack.GroupBy(p => p.Item1).Select(p => (p.Key, p.First().Item2)).ToArray();
|
||||
foreach (var (idx, val) in reverseStack)
|
||||
{
|
||||
if (idx == ImPlotStyleVar.Marker)
|
||||
ret.Push(idx, (int)val.X);
|
||||
else if (float.IsNaN(val.Y))
|
||||
ret.Push(idx, val.X);
|
||||
else
|
||||
ret.Push(idx, val);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public sealed class PlotStyle : IDisposable
|
||||
{
|
||||
internal static readonly List<(ImPlotStyleVar, Vector2)> Stack = [];
|
||||
|
||||
private int count;
|
||||
|
||||
private static void CheckStyleIdx(ImPlotStyleVar idx, Type type)
|
||||
{
|
||||
var shouldThrow = idx switch
|
||||
{
|
||||
ImPlotStyleVar.LineWeight => type != typeof(float),
|
||||
ImPlotStyleVar.Marker => type != typeof(int),
|
||||
ImPlotStyleVar.MarkerSize => type != typeof(float),
|
||||
ImPlotStyleVar.MarkerWeight => type != typeof(float),
|
||||
ImPlotStyleVar.FillAlpha => type != typeof(float),
|
||||
ImPlotStyleVar.ErrorBarSize => type != typeof(float),
|
||||
ImPlotStyleVar.ErrorBarWeight => type != typeof(float),
|
||||
// ImPlotStyleVar.DigitalBitHeight => type != typeof(float),
|
||||
// ImPlotStyleVar.DigitalBitGap => type != typeof(float),
|
||||
// ImPlotStyleVar.PlotBorderSize => type != typeof(float),
|
||||
ImPlotStyleVar.MinorAlpha => type != typeof(float),
|
||||
ImPlotStyleVar.MajorTickLen => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorTickLen => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MajorTickSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorTickSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MajorGridSize => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MinorGridSize => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LabelPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendInnerPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.LegendSpacing => type != typeof(Vector2),
|
||||
ImPlotStyleVar.MousePosPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.AnnotationPadding => type != typeof(Vector2),
|
||||
ImPlotStyleVar.FitPadding => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotDefaultSize => type != typeof(Vector2),
|
||||
// ImPlotStyleVar.PlotMinSize => type != typeof(Vector2),
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(idx), idx, null),
|
||||
};
|
||||
|
||||
if (shouldThrow)
|
||||
throw new ArgumentException($"Unable to push {type} to {idx}.");
|
||||
}
|
||||
|
||||
public static Vector2 GetStyle(ImPlotStyleVar idx)
|
||||
{
|
||||
var style = ImPlot.GetStyle();
|
||||
return idx switch
|
||||
{
|
||||
ImPlotStyleVar.LineWeight => new Vector2(style.LineWeight, float.NaN),
|
||||
ImPlotStyleVar.Marker => new Vector2(style.Marker, float.NaN),
|
||||
ImPlotStyleVar.MarkerSize => new Vector2(style.MarkerSize, float.NaN),
|
||||
ImPlotStyleVar.MarkerWeight => new Vector2(style.MarkerWeight, float.NaN),
|
||||
ImPlotStyleVar.FillAlpha => new Vector2(style.FillAlpha, float.NaN),
|
||||
ImPlotStyleVar.ErrorBarSize => new Vector2(style.ErrorBarSize, float.NaN),
|
||||
ImPlotStyleVar.ErrorBarWeight => new Vector2(style.ErrorBarWeight, float.NaN),
|
||||
// ImPlotStyleVar.DigitalBitHeight => new Vector2(style.DigitalBitHeight, float.NaN),
|
||||
// ImPlotStyleVar.DigitalBitGap => new Vector2(style.DigitalBitGap, float.NaN),
|
||||
// ImPlotStyleVar.PlotBorderSize => new Vector2(style.PlotBorderSize, float.NaN),
|
||||
ImPlotStyleVar.MinorAlpha => new Vector2(style.MinorAlpha, float.NaN),
|
||||
ImPlotStyleVar.MajorTickLen => style.MajorTickLen,
|
||||
ImPlotStyleVar.MinorTickLen => style.MinorTickLen,
|
||||
ImPlotStyleVar.MajorTickSize => style.MajorTickSize,
|
||||
ImPlotStyleVar.MinorTickSize => style.MinorTickSize,
|
||||
ImPlotStyleVar.MajorGridSize => style.MajorGridSize,
|
||||
ImPlotStyleVar.MinorGridSize => style.MinorGridSize,
|
||||
// ImPlotStyleVar.PlotPadding => style.PlotPadding,
|
||||
ImPlotStyleVar.LabelPadding => style.LabelPadding,
|
||||
ImPlotStyleVar.LegendPadding => style.LegendPadding,
|
||||
ImPlotStyleVar.LegendInnerPadding => style.LegendInnerPadding,
|
||||
ImPlotStyleVar.LegendSpacing => style.LegendSpacing,
|
||||
ImPlotStyleVar.MousePosPadding => style.MousePosPadding,
|
||||
ImPlotStyleVar.AnnotationPadding => style.AnnotationPadding,
|
||||
ImPlotStyleVar.FitPadding => style.FitPadding,
|
||||
// ImPlotStyleVar.PlotDefaultSize => style.PlotDefaultSize,
|
||||
// ImPlotStyleVar.PlotMinSize => style.PlotMinSize,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(idx), idx, null),
|
||||
};
|
||||
}
|
||||
|
||||
public PlotStyle Push(ImPlotStyleVar idx, int value, bool condition = true)
|
||||
{
|
||||
if (!condition)
|
||||
return this;
|
||||
|
||||
// Should be accurate for +/- 2^24 markers, which is fine, because the only valid range
|
||||
// for markers is [-1, 9].
|
||||
CheckStyleIdx(idx, typeof(int));
|
||||
Stack.Add((idx, GetStyle(idx)));
|
||||
ImPlot.PushStyleVar(idx, value);
|
||||
++this.count;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlotStyle Push(ImPlotStyleVar idx, float value, bool condition = true)
|
||||
{
|
||||
if (!condition)
|
||||
return this;
|
||||
|
||||
CheckStyleIdx(idx, typeof(float));
|
||||
Stack.Add((idx, GetStyle(idx)));
|
||||
ImPlot.PushStyleVar(idx, value);
|
||||
++this.count;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlotStyle Push(ImPlotStyleVar idx, Vector2 value, bool condition = true)
|
||||
{
|
||||
if (!condition)
|
||||
return this;
|
||||
|
||||
CheckStyleIdx(idx, typeof(Vector2));
|
||||
Stack.Add((idx, GetStyle(idx)));
|
||||
ImPlot.PushStyleVar(idx, value);
|
||||
++this.count;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Pop(int num = 1)
|
||||
{
|
||||
num = Math.Min(num, this.count);
|
||||
this.count -= num;
|
||||
ImPlot.PopStyleVar(num);
|
||||
Stack.RemoveRange(Stack.Count - num, num);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> this.Pop(this.count);
|
||||
}
|
||||
public static PlotStyleDisposable DefaultPlotStyle()
|
||||
=> PlotStyleDisposable.PlotDefaultStyle();
|
||||
|
||||
#endregion Style
|
||||
|
||||
#region Color
|
||||
|
||||
public static PlotColor PushColor(ImPlotCol idx, uint color, bool condition = true)
|
||||
=> new PlotColor().Push(idx, color, condition);
|
||||
public static PlotColorDisposable PushColor(ImPlotCol idx, uint color, bool condition = true)
|
||||
=> new PlotColorDisposable().Push(idx, color, condition);
|
||||
|
||||
public static PlotColor PushColor(ImPlotCol idx, Vector4 color, bool condition = true)
|
||||
=> new PlotColor().Push(idx, color, condition);
|
||||
public static PlotColorDisposable PushColor(ImPlotCol idx, Vector4 color, bool condition = true)
|
||||
=> new PlotColorDisposable().Push(idx, color, condition);
|
||||
|
||||
// Push colors that revert all current color changes made temporarily.
|
||||
public static PlotColor DefaultPlotColors()
|
||||
{
|
||||
var ret = new PlotColor();
|
||||
var reverseStack = PlotColor.Stack.GroupBy(p => p.Item1).Select(p => (p.Key, p.First().Item2)).ToArray();
|
||||
foreach (var (idx, val) in reverseStack)
|
||||
ret.Push(idx, val);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public sealed class PlotColor : IDisposable
|
||||
{
|
||||
internal static readonly List<(ImPlotCol, uint)> Stack = [];
|
||||
private int count;
|
||||
|
||||
// Reimplementation of https://github.com/ocornut/imgui/blob/868facff9ded2d61425c67deeba354eb24275bd1/imgui.cpp#L3035
|
||||
// for ImPlot
|
||||
private static uint GetColorU32(ImPlotCol idx)
|
||||
=> ImGui.GetColorU32(ImPlot.GetStyle().Colors[(int)idx]);
|
||||
|
||||
public PlotColor Push(ImPlotCol idx, uint color, bool condition = true)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
Stack.Add((idx, GetColorU32(idx)));
|
||||
ImPlot.PushStyleColor(idx, color);
|
||||
++this.count;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public PlotColor Push(ImPlotCol idx, Vector4 color, bool condition = true)
|
||||
{
|
||||
if (condition)
|
||||
{
|
||||
Stack.Add((idx, GetColorU32(idx)));
|
||||
ImPlot.PushStyleColor(idx, color);
|
||||
++this.count;
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void Pop(int num = 1)
|
||||
{
|
||||
num = Math.Min(num, this.count);
|
||||
this.count -= num;
|
||||
ImPlot.PopStyleColor(num);
|
||||
Stack.RemoveRange(Stack.Count - num, num);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
=> this.Pop(this.count);
|
||||
}
|
||||
public static PlotColorDisposable DefaultPlotColors()
|
||||
=> PlotColorDisposable.PlotDefaultColors();
|
||||
|
||||
#endregion Color
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue