Initial release: HSUI v1.0.0.0 - HUD replacement with configurable hotbars
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user