eorzea-votes/client/EorzeaVotes/Ui/ImGuiHelper.cs

208 lines
6.1 KiB
C#

using System.Text;
using Dalamud.Interface;
using EorzeaVotes.Utilities;
using ImGuiNET;
using Regexes = EorzeaVotes.Utilities.Regexes;
namespace EorzeaVotes.Ui;
internal static class ImGuiHelper {
internal static void Help(string text) {
ImGui.SameLine();
ImGui.PushFont(UiBuilder.IconFont);
using (new OnDispose(ImGui.PopFont)) {
using var endColour = WithDisabledColour();
ImGui.TextUnformatted(FontAwesomeIcon.QuestionCircle.ToIconString());
}
Tooltip(text);
}
internal static OnDispose WithDisabledColour() {
var disabled = ImGui.GetStyle().Colors[(int) ImGuiCol.TextDisabled];
ImGui.PushStyleColor(ImGuiCol.Text, disabled);
return new OnDispose(ImGui.PopStyleColor);
}
internal static void Tooltip(string text) {
if (!ImGui.IsItemHovered()) {
return;
}
ImGui.BeginTooltip();
using var end = new OnDispose(ImGui.EndTooltip);
ImGui.PushTextWrapPos(ImGui.CalcTextSize("m").X * 30);
using var pop = new OnDispose(ImGui.PopTextWrapPos);
ImGui.TextUnformatted(text);
}
internal static bool EnumDropDownVertical<T>(string label, string? nullLabel, ref T? value, string? helpTooltip = null, Func<T?, string>? nameFunction = null)
where T : struct, Enum {
const string defaultNullLabel = "None";
ImGui.TextUnformatted(label);
if (helpTooltip != null) {
Help(helpTooltip);
}
ImGui.SetNextItemWidth(-1);
if (!ImGui.BeginCombo($"##{label}", GetName(value))) {
return false;
}
using var end = new OnDispose(ImGui.EndCombo);
var changed = false;
if (nullLabel != null && ImGui.Selectable(nullLabel, !value.HasValue)) {
value = null;
changed = true;
}
foreach (var variant in Enum.GetValues<T>()) {
if (ImGui.Selectable(GetName(variant), value.HasValue && value.Value.Equals(variant))) {
value = variant;
changed = true;
}
}
return changed;
string GetName(T? t) {
return nameFunction == null
? t == null
? nullLabel ?? defaultNullLabel
: Enum.GetName(t.Value) ?? "???"
: nameFunction(t);
}
}
internal static bool InputDateVertical(string label, ref string input, ref DateOnly? date) {
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
if (!ImGui.InputText($"##{label}", ref input, 10)) {
return false;
}
var match = Regexes.DateRegex().Match(input);
if (!match.Success) {
date = null;
return true;
}
var success = true;
success &= ushort.TryParse(match.Groups[1].Value, out var year);
success &= byte.TryParse(match.Groups[2].Value, out var month);
success &= byte.TryParse(match.Groups[3].Value, out var day);
if (!success) {
date = null;
return true;
}
var now = DateOnly.FromDateTime(DateTime.UtcNow);
var valid = year >= now.Year - 115 && year <= now.Year;
// day and month will be caught be the ctor
if (!valid) {
date = null;
return true;
}
try {
date = new DateOnly(year, month, day);
} catch {
date = null;
}
return true;
}
internal static bool ComboCheckboxVertical(string label, ref bool value) {
ImGui.TextUnformatted(label);
ImGui.SetNextItemWidth(-1);
if (!ImGui.BeginCombo($"##{label}", value ? "Yes" : "No")) {
return false;
}
using var end = new OnDispose(ImGui.EndCombo);
var changed = false;
if (ImGui.Selectable("Yes", value)) {
changed = true;
value = true;
}
if (ImGui.Selectable("No", !value)) {
changed = true;
value = false;
}
return changed;
}
internal static OnDispose? WithDisabled(bool disabled) {
if (!disabled) {
return null;
}
ImGui.BeginDisabled();
return new OnDispose(ImGui.EndDisabled);
}
/// <summary>
/// Draw an input with the label above it instead of to the side.
/// </summary>
/// <param name="label">Label for the input</param>
/// <param name="drawInput">Function that draws an input and accepts an ID to be passed to the input label</param>
/// <param name="appendId">Optional string to be appended to the string passed to <see cref="drawInput"/></param>
/// <param name="helpTooltip">Optional string to be shown as a help tooltip next to the label</param>
/// <returns></returns>
internal static bool VerticalInput(string label, Func<string, bool> drawInput, string? appendId = null, string? helpTooltip = null) {
ImGui.TextUnformatted(label);
if (helpTooltip != null) {
Help(helpTooltip);
}
label = $"##{label}";
if (appendId != null) {
label += appendId;
}
ImGui.SetNextItemWidth(-1);
return drawInput(label);
}
internal static bool IconButton(FontAwesomeIcon icon, string? id = null) {
ImGui.PushFont(UiBuilder.IconFont);
using var pop = new OnDispose(ImGui.PopFont);
var label = icon.ToIconString();
if (id != null) {
label += id;
}
return ImGui.Button(label);
}
internal static unsafe bool BeginTabItem(string label, bool forceOpen = false) {
var flags = forceOpen
? ImGuiTabItemFlags.SetSelected
: ImGuiTabItemFlags.None;
var bufSize = Encoding.UTF8.GetByteCount(label);
var labelBuf = stackalloc byte[bufSize + 1];
fixed (char* labelPtr = label) {
Encoding.UTF8.GetBytes(labelPtr, label.Length, labelBuf, bufSize);
}
labelBuf[bufSize] = 0;
return ImGuiNative.igBeginTabItem(labelBuf, null, flags) > 0u;
}
}