f37369cdda
Co-authored-by: Cursor <cursoragent@cursor.com>
214 lines
6.1 KiB
C#
214 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Reflection;
|
|
using HSUI.Config.Attributes;
|
|
using HSUI.Helpers;
|
|
using Dalamud.Bindings.ImGui;
|
|
|
|
namespace HSUI.Config.Tree
|
|
{
|
|
public abstract class ConfigNode
|
|
{
|
|
public bool CollapseControl { get; set; }
|
|
|
|
public bool IsChild { get; set; }
|
|
|
|
public string Name { get; private set; }
|
|
|
|
public bool Nest { get; set; } = true;
|
|
|
|
public string? ParentName { get; set; }
|
|
|
|
public int Position { get; set; } = Int32.MaxValue;
|
|
|
|
public bool Separator { get; set; }
|
|
|
|
public bool Spacing { get; set; }
|
|
|
|
public bool CollapsingHeader { get; set; }
|
|
|
|
public string? ID { get; private set; }
|
|
|
|
protected PluginConfigObject ConfigObject { get; set; }
|
|
|
|
public ConfigNode(PluginConfigObject configObject, string? id, string name)
|
|
{
|
|
ConfigObject = configObject;
|
|
ID = id;
|
|
Name = name;
|
|
}
|
|
|
|
public abstract bool Draw(ref bool changed, int depth = 0);
|
|
|
|
protected void DrawSeparatorOrSpacing()
|
|
{
|
|
if (Separator)
|
|
{
|
|
ImGuiHelper.DrawSeparator(1, 1);
|
|
}
|
|
|
|
if (Spacing)
|
|
{
|
|
ImGuiHelper.DrawSpacing(1);
|
|
}
|
|
}
|
|
|
|
protected static void DrawNestIndicator(int depth)
|
|
{
|
|
// This draws the L shaped symbols and padding to the left of config items collapsible under a checkbox.
|
|
// Shift cursor to the right to pad for children with depth more than 1.
|
|
// 26 is an arbitrary value I found to be around half the width of a checkbox
|
|
ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(26, 0) * Math.Max((depth - 1), 0));
|
|
|
|
if (ConfigurationManager.Instance.OverrideDalamudStyle)
|
|
{
|
|
ImGui.TextColored(new Vector4(229f / 255f, 57f / 255f, 57f / 255f, 1f), "\u2514");
|
|
}
|
|
else
|
|
{
|
|
ImGui.Text("\u2514");
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
}
|
|
|
|
protected static ConfigAttribute? GetConfigAttribute(FieldInfo field)
|
|
{
|
|
return field.GetCustomAttributes(true).Where(a => a is ConfigAttribute).FirstOrDefault() as ConfigAttribute;
|
|
}
|
|
}
|
|
|
|
public class FieldNode : ConfigNode
|
|
{
|
|
private SortedDictionary<int, ConfigNode> _childNodes;
|
|
private ConfigAttribute? _configAttribute;
|
|
private FieldInfo _mainField;
|
|
|
|
public FieldInfo Field => _mainField;
|
|
|
|
public FieldNode(FieldInfo mainField, PluginConfigObject configObject, string? id) : base(configObject, id, mainField.Name)
|
|
{
|
|
_mainField = mainField;
|
|
_childNodes = new SortedDictionary<int, ConfigNode>();
|
|
|
|
_configAttribute = GetConfigAttribute(mainField);
|
|
if (_configAttribute is not null)
|
|
{
|
|
Separator = _configAttribute.separator;
|
|
Spacing = _configAttribute.spacing;
|
|
}
|
|
}
|
|
|
|
public void AddChild(int position, ConfigNode field)
|
|
{
|
|
field.IsChild = true;
|
|
|
|
while (_childNodes.ContainsKey(position))
|
|
{
|
|
position++;
|
|
}
|
|
|
|
_childNodes.Add(position, field);
|
|
}
|
|
|
|
public override bool Draw(ref bool changed, int depth = 0)
|
|
{
|
|
bool reset = false;
|
|
DrawSeparatorOrSpacing();
|
|
|
|
if (!Nest)
|
|
{
|
|
depth = 0;
|
|
}
|
|
|
|
if (depth > 0)
|
|
{
|
|
DrawNestIndicator(depth);
|
|
}
|
|
|
|
bool collapsing = CollapsingHeader && ConfigObject.Disableable;
|
|
|
|
// Draw the ConfigAttribute
|
|
if (!collapsing)
|
|
{
|
|
DrawConfigAttribute(ref changed, _mainField);
|
|
}
|
|
|
|
bool enabled = _mainField.GetValue(ConfigObject) as bool? ?? false;
|
|
|
|
// Draw children
|
|
if (CollapseControl && Attribute.IsDefined(_mainField, typeof(CheckboxAttribute)))
|
|
{
|
|
if (collapsing)
|
|
{
|
|
if (ImGui.CollapsingHeader(ID + "##CollapsingHeader"))
|
|
{
|
|
DrawNestIndicator(depth);
|
|
DrawConfigAttribute(ref changed, _mainField);
|
|
|
|
if (enabled)
|
|
{
|
|
reset |= DrawChildren(ref changed, depth);
|
|
}
|
|
}
|
|
}
|
|
else if (!collapsing && enabled)
|
|
{
|
|
ImGui.BeginGroup();
|
|
reset |= DrawChildren(ref changed, depth);
|
|
ImGui.EndGroup();
|
|
}
|
|
}
|
|
|
|
return reset;
|
|
}
|
|
|
|
private bool DrawChildren(ref bool changed, int depth)
|
|
{
|
|
bool reset = false;
|
|
|
|
int childDepth = depth + 1;
|
|
foreach (ConfigNode child in _childNodes.Values)
|
|
{
|
|
if (child.Separator)
|
|
{
|
|
childDepth = 0;
|
|
}
|
|
|
|
reset |= child.Draw(ref changed, childDepth);
|
|
}
|
|
|
|
return reset;
|
|
}
|
|
|
|
private void DrawConfigAttribute(ref bool changed, FieldInfo field)
|
|
{
|
|
if (_configAttribute is not null)
|
|
{
|
|
changed |= _configAttribute.Draw(field, ConfigObject, ID, CollapsingHeader);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class ManualDrawNode : ConfigNode
|
|
{
|
|
private MethodInfo _drawMethod;
|
|
|
|
public ManualDrawNode(MethodInfo method, PluginConfigObject configObject, string? id) : base(configObject, id, id ?? "")
|
|
{
|
|
_drawMethod = method;
|
|
}
|
|
|
|
public override bool Draw(ref bool changed, int depth = 0)
|
|
{
|
|
object[] args = new object[] { false };
|
|
bool? result = (bool?)_drawMethod.Invoke(ConfigObject, args);
|
|
|
|
bool arg = (bool)args[0];
|
|
changed |= arg;
|
|
return result ?? false;
|
|
}
|
|
}
|
|
} |