Files
Craftimizer/Craftimizer/Utils/DynamicBars.cs
T
2024-02-23 07:16:02 -08:00

131 lines
6.0 KiB
C#

using Craftimizer.Plugin;
using Dalamud.Interface.Utility.Raii;
using ImGuiNET;
using System.Collections.Generic;
using System;
using System.Numerics;
using System.Linq;
using Dalamud.Utility.Numerics;
namespace Craftimizer.Utils;
internal static class DynamicBars
{
public readonly record struct BarData(string Name, Vector4 Color, SimulatedMacro.Reliablity.Param? Reliability, float Value, float Max, IReadOnlyList<int?>? Collectability = null, string? Caption = null, string? DefaultCaptionSizeText = null, Action<DrawerParams>? CustomDrawer = null)
{
public BarData(string name, Action<DrawerParams> customDrawer) : this(name, default, null, 0, 0, null, null, null, customDrawer)
{
}
public BarData(string name, Vector4 color, float value, float max) : this(name, color, null, value, max, null, null, null)
{
}
}
public readonly record struct DrawerParams(float TotalSize, float Spacing);
public static float GetTextSize(IEnumerable<BarData> bars) =>
bars.Max(b =>
{
if (b.CustomDrawer is { })
return 0;
var defaultSize = 0f;
if (b.DefaultCaptionSizeText is { } defaultCaptionSizeText)
defaultSize = ImGui.CalcTextSize(defaultCaptionSizeText).X;
if (b.Caption is { } caption)
return Math.Max(ImGui.CalcTextSize(caption).X, defaultSize);
// max (sp/2) "/" (sp/2) max
return Math.Max(
Math.Max(ImGui.CalcTextSize($"{b.Value:0}").X, ImGui.CalcTextSize($"{b.Max:0}").X) * 2
+ ImGui.GetStyle().ItemSpacing.X
+ ImGui.CalcTextSize("/").X,
defaultSize);
});
public static void Draw(IEnumerable<BarData> bars, float? textSize = null)
{
var spacing = ImGui.GetStyle().ItemSpacing.X;
var totalSize = ImGui.GetContentRegionAvail().X;
totalSize -= 2 * spacing;
textSize ??= GetTextSize(bars);
var maxSize = (textSize.Value - 2 * spacing - ImGui.CalcTextSize("/").X) / 2;
var barSize = totalSize - textSize.Value - spacing;
foreach (var bar in bars)
{
using var panel = ImRaii2.GroupPanel(bar.Name, totalSize, out _);
if (bar.CustomDrawer is { } drawer)
drawer(new(totalSize, spacing));
else
{
var pos = ImGui.GetCursorPos();
var screenPos = ImGui.GetCursorScreenPos();
using (var color = ImRaii.PushColor(ImGuiCol.PlotHistogram, bar.Color))
ImGui.ProgressBar(Math.Clamp(bar.Value / bar.Max, 0, 1), new(barSize, ImGui.GetFrameHeight()), string.Empty);
var passedCollectabilityColor = 0;
if (bar.Collectability is { } collectability)
{
var i = 0;
var rounding = ImGui.GetStyle().FrameRounding;
var height = ImGui.GetFrameHeight();
foreach (var (c, color) in collectability.Zip(Colors.CollectabilityThreshold))
{
++i;
if (c is not { } threshold)
continue;
var offset = barSize * threshold / bar.Max;
var isLast = i == collectability.Count;
var offsetNext = isLast ? barSize : barSize * collectability[i]!.Value / bar.Max;
var passedThreshold = bar.Value >= threshold;
if (passedThreshold)
passedCollectabilityColor = i;
ImGui.GetWindowDrawList().AddRectFilled(
screenPos + new Vector2(offset, 0),
screenPos + new Vector2(offsetNext, height),
ImGui.GetColorU32(color.WithW(passedThreshold ? 0.6f : 0.2f)),
isLast ? rounding : 0
);
ImGui.GetWindowDrawList().AddLine(
screenPos + new Vector2(offset, 0),
screenPos + new Vector2(offset, height),
ImGui.GetColorU32(color),
Math.Max(passedThreshold ? 3 : 1.5f, rounding / 2f)
);
}
}
if (ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenOverlapped))
{
if (bar.Reliability is { } reliability)
{
if (reliability.GetViolinData(bar.Max, (int)(barSize / 5), 0.02) is { } violinData)
{
ImGui.SetCursorPos(pos);
ImGuiUtils.ViolinPlot(violinData, new(barSize, ImGui.GetFrameHeight()));
if (ImGui.IsItemHovered())
ImGuiUtils.Tooltip(
$"Min: {reliability.Min}\n" +
$"Med: {reliability.Median:0.##}\n" +
$"Avg: {reliability.Average:0.##}\n" +
$"Max: {reliability.Max}");
}
}
}
ImGui.SameLine(0, spacing);
ImGui.AlignTextToFramePadding();
using var _color = ImRaii.PushColor(ImGuiCol.Text, passedCollectabilityColor != 0 ? Colors.CollectabilityThreshold[passedCollectabilityColor - 1] : default, passedCollectabilityColor != 0);
if (bar.Caption is { } caption)
ImGuiUtils.TextRight(caption, textSize.Value);
else
{
ImGuiUtils.TextRight($"{bar.Value:0}", maxSize);
ImGui.SameLine(0, spacing / 2);
ImGui.Text("/");
ImGui.SameLine(0, spacing / 2);
ImGuiUtils.TextRight($"{bar.Max:0}", maxSize);
}
}
}
}
}