9f41c18c0b
Co-authored-by: Cursor <cursoragent@cursor.com>
347 lines
14 KiB
C#
347 lines
14 KiB
C#
using Dalamud.Bindings.ImGui;
|
|
using Dalamud.Interface;
|
|
using Dalamud.Interface.Textures.TextureWraps;
|
|
using Dalamud.Interface.Utility;
|
|
using HSUI.Config.Attributes;
|
|
using HSUI.Helpers;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
|
|
namespace HSUI.Config.Tree
|
|
{
|
|
public delegate void ConfigObjectResetEventHandler(BaseNode sender);
|
|
|
|
public class BaseNode : Node
|
|
{
|
|
public event ConfigObjectResetEventHandler? ConfigObjectResetEvent;
|
|
|
|
private Dictionary<Type, ConfigPageNode> _configPageNodesMap;
|
|
|
|
public bool NeedsSave = false;
|
|
public string? SelectedOptionName = null;
|
|
|
|
private List<Node> _extraNodes = new List<Node>();
|
|
private List<Node> _nodes = new List<Node>();
|
|
|
|
public IReadOnlyCollection<Node> Sections => _nodes.AsReadOnly();
|
|
|
|
private float _scale => ImGuiHelpers.GlobalScale;
|
|
|
|
public BaseNode()
|
|
{
|
|
_configPageNodesMap = new Dictionary<Type, ConfigPageNode>();
|
|
}
|
|
|
|
public void AddExtraSectionNode(SectionNode node)
|
|
{
|
|
_extraNodes.Add(node);
|
|
|
|
_nodes.Clear();
|
|
CreateNodesIfNeeded();
|
|
}
|
|
|
|
public T? GetConfigObject<T>() where T : PluginConfigObject
|
|
{
|
|
var pageNode = GetConfigPageNode<T>();
|
|
|
|
return pageNode != null ? (T)pageNode.ConfigObject : null;
|
|
}
|
|
|
|
public void RemoveConfigObject<T>() where T : PluginConfigObject
|
|
{
|
|
if (_configPageNodesMap.ContainsKey(typeof(T)))
|
|
{
|
|
_configPageNodesMap.Remove(typeof(T));
|
|
}
|
|
}
|
|
|
|
public ConfigPageNode? GetConfigPageNode<T>() where T : PluginConfigObject
|
|
{
|
|
if (_configPageNodesMap.TryGetValue(typeof(T), out var node))
|
|
{
|
|
return node;
|
|
}
|
|
|
|
var configPageNode = GetOrAddConfig<T>();
|
|
|
|
if (configPageNode != null && configPageNode.ConfigObject != null)
|
|
{
|
|
_configPageNodesMap.Add(typeof(T), configPageNode);
|
|
|
|
return configPageNode;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public void SetConfigPageNode(ConfigPageNode configPageNode)
|
|
{
|
|
if (configPageNode.ConfigObject == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_configPageNodesMap[configPageNode.ConfigObject.GetType()] = configPageNode;
|
|
}
|
|
|
|
public bool SetConfigObject(PluginConfigObject configObject)
|
|
{
|
|
if (_configPageNodesMap.TryGetValue(configObject.GetType(), out ConfigPageNode? configPageNode))
|
|
{
|
|
configPageNode.ConfigObject = configObject;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private bool PushStyles()
|
|
{
|
|
ImGui.PushStyleVar(ImGuiStyleVar.ScrollbarRounding, 1); //Scrollbar Radius
|
|
ImGui.PushStyleVar(ImGuiStyleVar.TabRounding, 1); //Tabs Radius Radius
|
|
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 1); //Intractable Elements Radius
|
|
ImGui.PushStyleVar(ImGuiStyleVar.GrabRounding, 1); //Gradable Elements Radius
|
|
ImGui.PushStyleVar(ImGuiStyleVar.PopupRounding, 1); //Popup Radius
|
|
ImGui.PushStyleVar(ImGuiStyleVar.ScrollbarSize, 10); //Popup Radius
|
|
|
|
if (ConfigurationManager.Instance.OverrideDalamudStyle)
|
|
{
|
|
ImGui.PushStyleColor(ImGuiCol.Button, new Vector4(46f / 255f, 45f / 255f, 46f / 255f, 1f));
|
|
ImGui.PushStyleColor(ImGuiCol.ButtonActive, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .2f));
|
|
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .2f));
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.Separator, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .4f));
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.ScrollbarBg, new Vector4(20f / 255f, 21f / 255f, 20f / 255f, .7f));
|
|
ImGui.PushStyleColor(ImGuiCol.ScrollbarGrab, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .7f));
|
|
ImGui.PushStyleColor(ImGuiCol.ScrollbarGrabActive, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .7f));
|
|
ImGui.PushStyleColor(ImGuiCol.ScrollbarGrabHovered, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .7f));
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.Tab, new Vector4(46f / 255f, 45f / 255f, 46f / 255f, 1f));
|
|
ImGui.PushStyleColor(ImGuiCol.TabActive, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .7f));
|
|
ImGui.PushStyleColor(ImGuiCol.TabHovered, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .2f));
|
|
ImGui.PushStyleColor(ImGuiCol.TabUnfocused, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .2f));
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.Border, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, 1f));
|
|
ImGui.PushStyleColor(ImGuiCol.CheckMark, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, 1f));
|
|
|
|
ImGui.PushStyleColor(ImGuiCol.TableBorderStrong, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, 1f));
|
|
ImGui.PushStyleColor(ImGuiCol.TableBorderLight, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .4f));
|
|
ImGui.PushStyleColor(ImGuiCol.TableHeaderBg, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, .2f));
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void PopStyles(bool popColors)
|
|
{
|
|
if (popColors)
|
|
{
|
|
ImGui.PopStyleColor(17);
|
|
}
|
|
|
|
ImGui.PopStyleVar(6);
|
|
}
|
|
|
|
public void CreateNodesIfNeeded()
|
|
{
|
|
if (_nodes.Count > 0) { return; }
|
|
|
|
_nodes.AddRange(_children);
|
|
_nodes.AddRange(_extraNodes);
|
|
}
|
|
|
|
public void RefreshSelectedNode()
|
|
{
|
|
if (_nodes.Count == 0) { return; }
|
|
|
|
foreach (SectionNode node in _nodes.FindAll(x => x is SectionNode))
|
|
{
|
|
node.Selected = node.Name == SelectedOptionName;
|
|
}
|
|
}
|
|
|
|
public void Draw(float alpha)
|
|
{
|
|
CreateNodesIfNeeded();
|
|
if (_nodes.Count == 0) { return; }
|
|
|
|
bool changed = false;
|
|
bool didReset = false;
|
|
|
|
bool popColors = PushStyles();
|
|
|
|
ImGui.BeginGroup(); // Middle section
|
|
{
|
|
ImGui.BeginGroup(); // Left
|
|
{
|
|
// banner
|
|
IDalamudTextureWrap? delvUiBanner = Plugin.BannerTexture?.GetWrapOrDefault();
|
|
if (delvUiBanner != null)
|
|
{
|
|
ImGui.SetCursorPos(new Vector2(15 + 150 * _scale / 2f - delvUiBanner.Width / 2f, 5));
|
|
ImGui.Image(delvUiBanner.Handle, new Vector2(delvUiBanner.Width, delvUiBanner.Height));
|
|
}
|
|
|
|
// version
|
|
ImGui.SetCursorPos(new Vector2(60 * _scale, 35));
|
|
ImGui.Text($"v{Plugin.Version}");
|
|
|
|
|
|
// section list
|
|
if (ImGui.BeginChild("left pane", new Vector2(150 * _scale, -10), true, ImGuiWindowFlags.NoScrollbar))
|
|
{
|
|
|
|
// if no section is selected, select the first
|
|
if (_nodes.Any() && _nodes.Find(o => o is SectionNode sectionNode && sectionNode.Selected) == null)
|
|
{
|
|
SectionNode? selectedSection = (SectionNode?)_nodes.Find(o => o is SectionNode sectionNode && sectionNode.Name == SelectedOptionName);
|
|
if (selectedSection != null)
|
|
{
|
|
selectedSection.Selected = true;
|
|
SelectedOptionName = selectedSection.Name;
|
|
}
|
|
else if (_nodes.Count > 0)
|
|
{
|
|
SectionNode node = (SectionNode)_nodes[0];
|
|
node.Selected = true;
|
|
SelectedOptionName = node.Name;
|
|
}
|
|
}
|
|
|
|
foreach (SectionNode selectionNode in _nodes)
|
|
{
|
|
if (ImGui.Selectable(selectionNode.Name, selectionNode.Selected))
|
|
{
|
|
selectionNode.Selected = true;
|
|
SelectedOptionName = selectionNode.Name;
|
|
|
|
foreach (SectionNode otherNode in _nodes.FindAll(x => x != selectionNode))
|
|
{
|
|
otherNode.Selected = false;
|
|
}
|
|
}
|
|
|
|
DrawExportResetContextMenu(selectionNode, selectionNode.Name + "_section");
|
|
}
|
|
|
|
// changelog button
|
|
float y = ImGui.GetWindowHeight() - (30 * _scale);
|
|
ImGui.PushFont(UiBuilder.IconFont);
|
|
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(255f / 255f, 255f / 255f, 255f / 255f, alpha));
|
|
ImGui.SetCursorPos(new Vector2(19 * _scale, y));
|
|
if (ImGui.Button(FontAwesomeIcon.List.ToIconString(), new Vector2(24 * _scale, 24 * _scale)))
|
|
{
|
|
ConfigurationManager.Instance.OpenChangelogWindow();
|
|
}
|
|
ImGui.PopStyleColor();
|
|
ImGui.PopFont();
|
|
ImGuiHelper.SetTooltip("Changelog");
|
|
}
|
|
|
|
ImGui.EndChild();
|
|
}
|
|
|
|
ImGui.EndGroup(); // Left
|
|
|
|
|
|
didReset |= DrawResetModal();
|
|
|
|
ImGui.SameLine();
|
|
|
|
ImGui.BeginGroup(); // Right
|
|
{
|
|
foreach (SectionNode selectionNode in _nodes)
|
|
{
|
|
didReset |= selectionNode.Draw(ref changed, alpha);
|
|
}
|
|
}
|
|
|
|
ImGui.EndGroup(); // Right
|
|
}
|
|
|
|
ImGui.EndGroup(); // Middle section
|
|
|
|
// close button
|
|
ImGui.PushFont(UiBuilder.IconFont);
|
|
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, alpha));
|
|
ImGui.SetCursorPos(new Vector2(ImGui.GetWindowWidth() - 28 * _scale, 5 * _scale));
|
|
if (ImGui.Button(FontAwesomeIcon.Times.ToIconString(), new Vector2(22 * _scale, 22 * _scale)))
|
|
{
|
|
ConfigurationManager.Instance.CloseConfigWindow();
|
|
}
|
|
ImGui.PopStyleColor();
|
|
ImGui.PopFont();
|
|
ImGuiHelper.SetTooltip("Close");
|
|
|
|
// unlock button
|
|
ImGui.PushFont(UiBuilder.IconFont);
|
|
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, alpha));
|
|
ImGui.SetCursorPos(new Vector2(ImGui.GetWindowWidth() - 60 * _scale, 5 * _scale));
|
|
string lockString = ConfigurationManager.Instance.LockHUD ? FontAwesomeIcon.Lock.ToIconString() : FontAwesomeIcon.LockOpen.ToIconString();
|
|
if (ImGui.Button(lockString, new Vector2(22 * _scale, 22 * _scale)))
|
|
{
|
|
ConfigurationManager.Instance.LockHUD = !ConfigurationManager.Instance.LockHUD;
|
|
}
|
|
ImGui.PopStyleColor();
|
|
ImGui.PopFont();
|
|
ImGuiHelper.SetTooltip("Unlock HUD");
|
|
|
|
// hide button
|
|
ImGui.PushFont(UiBuilder.IconFont);
|
|
ImGui.PushStyleColor(ImGuiCol.Text, new Vector4(229f / 255f, 57f / 255f, 57f / 255f, alpha));
|
|
ImGui.SetCursorPos(new Vector2(ImGui.GetWindowWidth() - 88 * _scale, 5 * _scale));
|
|
string hideString = ConfigurationManager.Instance.ShowHUD ? FontAwesomeIcon.Eye.ToIconString() : FontAwesomeIcon.EyeSlash.ToIconString();
|
|
if (ImGui.Button(hideString, new Vector2(26 * _scale, 22 * _scale)))
|
|
{
|
|
ConfigurationManager.Instance.ShowHUD = !ConfigurationManager.Instance.ShowHUD;
|
|
}
|
|
ImGui.PopStyleColor();
|
|
ImGui.PopFont();
|
|
ImGuiHelper.SetTooltip(ConfigurationManager.Instance.ShowHUD ? "Hide HUD" : "Show HUD");
|
|
|
|
PopStyles(popColors);
|
|
|
|
if (didReset)
|
|
{
|
|
ConfigObjectResetEvent?.Invoke(this);
|
|
}
|
|
|
|
NeedsSave |= changed | didReset;
|
|
}
|
|
|
|
public ConfigPageNode? GetOrAddConfig<T>() where T : PluginConfigObject
|
|
{
|
|
object[] attributes = typeof(T).GetCustomAttributes(true);
|
|
|
|
foreach (object attribute in attributes)
|
|
{
|
|
if (attribute is SectionAttribute sectionAttribute)
|
|
{
|
|
foreach (SectionNode sectionNode in _children)
|
|
{
|
|
if (sectionNode.Name == sectionAttribute.SectionName)
|
|
{
|
|
return sectionNode.GetOrAddConfig<T>();
|
|
}
|
|
}
|
|
|
|
SectionNode newNode = new();
|
|
newNode.Name = sectionAttribute.SectionName;
|
|
newNode.ForceAllowExport = sectionAttribute.ForceAllowExport;
|
|
_children.Add(newNode);
|
|
|
|
return newNode.GetOrAddConfig<T>();
|
|
}
|
|
}
|
|
|
|
Type type = typeof(T);
|
|
throw new ArgumentException("The provided configuration object does not specify a section: " + type.Name);
|
|
}
|
|
}
|
|
}
|