This commit is contained in:
Ottermandias 2023-06-28 22:47:48 +02:00
parent 90e451049e
commit d621369094
12 changed files with 387 additions and 58 deletions

View file

@ -10,16 +10,15 @@ namespace Glamourer.Automation;
public class AutoDesign
{
[Flags]
public enum Type : uint
public enum Type : byte
{
Armor = 0x01,
Customizations = 0x02,
Meta = 0x04,
Weapons = 0x08,
Stains = 0x10,
Accessories = 0x20,
Weapons = 0x04,
Stains = 0x08,
Accessories = 0x10,
All = Armor | Accessories | Customizations | Meta | Weapons | Stains,
All = Armor | Accessories | Customizations | Weapons | Stains,
}
public Design Design;

View file

@ -148,6 +148,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>
if (set.Enabled == value)
return;
set.Enabled = value;
AutoDesignSet? oldEnabled = null;
if (value)
{

View file

@ -55,7 +55,10 @@ public sealed class AutomationChanged : EventWrapper<Action<AutomationChanged.Ty
}
public enum Priority
{ }
{
/// <seealso cref="Gui.Tabs.AutomationTab.SetSelector.OnAutomationChanged"/>
SetSelector = 0,
}
public AutomationChanged()
: base(nameof(AutomationChanged))

View file

@ -12,6 +12,8 @@ public enum ColorId
FolderExpanded,
FolderCollapsed,
FolderLine,
EnabledAutoSet,
DisabledAutoSet,
}
public static class Colors
@ -28,7 +30,9 @@ public static class Colors
ColorId.FolderExpanded => (0xFFFFF0C0, "Expanded Design Folder", "A design folder that is currently expanded." ),
ColorId.FolderCollapsed => (0xFFFFF0C0, "Collapsed Design Folder", "A design folder that is currently collapsed." ),
ColorId.FolderLine => (0xFFFFF0C0, "Expanded Design Folder Line", "The line signifying which descendants belong to an expanded design folder." ),
_ => (0x00000000, string.Empty, string.Empty ),
ColorId.EnabledAutoSet => (0xFFA0F0A0, "Enabled Automation Set", "An automation set that is currently enabled. Only one set can be enabled for each identifier at once." ),
ColorId.DisabledAutoSet => (0xFF808080, "Disabled Automation Set", "An automation set that is currently disabled." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -4,6 +4,7 @@ using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Glamourer.Gui.Tabs;
using Glamourer.Gui.Tabs.ActorTab;
using Glamourer.Gui.Tabs.AutomationTab;
using Glamourer.Gui.Tabs.DesignTab;
using ImGuiNET;
using OtterGui.Custom;
@ -15,25 +16,27 @@ public class MainWindow : Window
{
public enum TabType
{
None = -1,
Settings = 0,
Debug = 1,
Actors = 2,
Designs = 3,
None = -1,
Settings = 0,
Debug = 1,
Actors = 2,
Designs = 3,
Automation = 4,
}
private readonly Configuration _config;
private readonly ITab[] _tabs;
public readonly SettingsTab Settings;
public readonly ActorTab Actors;
public readonly DebugTab Debug;
public readonly DesignTab Designs;
public readonly SettingsTab Settings;
public readonly ActorTab Actors;
public readonly DebugTab Debug;
public readonly DesignTab Designs;
public readonly AutomationTab Automation;
public TabType SelectTab = TabType.None;
public MainWindow(DalamudPluginInterface pi, Configuration config, SettingsTab settings, ActorTab actors, DesignTab designs,
DebugTab debugTab)
DebugTab debugTab, AutomationTab automation)
: base(GetLabel())
{
pi.UiBuilder.DisableGposeUiHide = true;
@ -42,16 +45,18 @@ public class MainWindow : Window
MinimumSize = new Vector2(675, 675),
MaximumSize = ImGui.GetIO().DisplaySize,
};
Settings = settings;
Debug = debugTab;
Designs = designs;
Actors = actors;
_config = config;
Settings = settings;
Actors = actors;
Designs = designs;
Automation = automation;
Debug = debugTab;
_config = config;
_tabs = new ITab[]
{
settings,
actors,
designs,
automation,
debugTab,
};
@ -71,20 +76,22 @@ public class MainWindow : Window
private ReadOnlySpan<byte> ToLabel(TabType type)
=> type switch
{
TabType.Settings => Settings.Label,
TabType.Debug => Debug.Label,
TabType.Actors => Actors.Label,
TabType.Designs => Designs.Label,
_ => ReadOnlySpan<byte>.Empty,
TabType.Settings => Settings.Label,
TabType.Debug => Debug.Label,
TabType.Actors => Actors.Label,
TabType.Designs => Designs.Label,
TabType.Automation => Automation.Label,
_ => ReadOnlySpan<byte>.Empty,
};
private TabType FromLabel(ReadOnlySpan<byte> label)
{
// @formatter:off
if (label == Actors.Label) return TabType.Actors;
if (label == Designs.Label) return TabType.Designs;
if (label == Settings.Label) return TabType.Settings;
if (label == Debug.Label) return TabType.Debug;
if (label == Actors.Label) return TabType.Actors;
if (label == Designs.Label) return TabType.Designs;
if (label == Settings.Label) return TabType.Settings;
if (label == Automation.Label) return TabType.Automation;
if (label == Debug.Label) return TabType.Debug;
// @formatter:on
return TabType.None;
}

View file

@ -1,11 +1,11 @@
using System.Numerics;
using Glamourer.Customization;
using Glamourer.Events;
using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.Interop.Structs;
using Glamourer.State;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
@ -54,9 +54,6 @@ public class ActorPanel
if (!_stateManager.GetOrCreate(_identifier, _actor, out _state))
return;
//if (_state != null)
// _stateManager.Update(ref _state.Data, _actor);
using var group = ImRaii.Group();
DrawHeader();
DrawPanel();
@ -66,13 +63,9 @@ public class ActorPanel
{
var color = _data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var c = ImRaii.PushColor(ImGuiCol.Text, color)
.Push(ImGuiCol.Button, buttonColor)
.Push(ImGuiCol.ButtonHovered, buttonColor)
.Push(ImGuiCol.ButtonActive, buttonColor);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.Button($"{(_data.Valid ? _data.Label : _identifier.ToString())}##playerHeader", -Vector2.UnitX);
ImGuiUtil.DrawTextButton($"{(_data.Valid ? _data.Label : _identifier.ToString())}##playerHeader", -Vector2.UnitX, buttonColor, color);
}
private unsafe void DrawPanel()

View file

@ -0,0 +1,31 @@
using System;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class AutomationTab : ITab
{
private readonly SetSelector _selector;
private readonly SetPanel _panel;
public AutomationTab(SetSelector selector, SetPanel panel)
{
_selector = selector;
_panel = panel;
}
public ReadOnlySpan<byte> Label
=> "Automation"u8;
public void DrawContent()
{
_selector.Draw(GetSetSelectorSize());
ImGui.SameLine();
_panel.Draw();
}
public float GetSetSelectorSize()
=> 200f * ImGuiHelpers.GlobalScale;
}

View file

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Automation;
using Glamourer.Designs;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class SetPanel
{
private readonly AutoDesignManager _manager;
private readonly SetSelector _selector;
public SetPanel(SetSelector selector, AutoDesignManager manager)
{
_selector = selector;
_manager = manager;
}
private AutoDesignSet Selection
=> _selector.Selection!;
public void Draw()
{
if (!_selector.HasSelection)
return;
using var group = ImRaii.Group();
DrawHeader();
DrawPanel();
}
private void DrawHeader()
{
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGuiUtil.DrawTextButton(Selection.Name, -Vector2.UnitX, buttonColor);
}
private string? _tempName;
private void DrawPanel()
{
using var child = ImRaii.Child("##SetPanel", -Vector2.One, true);
if (!child)
return;
var name = _tempName ?? Selection.Name;
if (ImGui.InputText("##Name", ref name, 64))
_tempName = name;
if (ImGui.IsItemDeactivated())
{
_manager.Rename(_selector.SelectionIndex, name);
_tempName = null;
}
ImGui.SameLine();
var enabled = Selection.Enabled;
if (ImGui.Checkbox("Enabled", ref enabled))
_manager.SetState(_selector.SelectionIndex, enabled);
using var table = ImRaii.Table("SetTable", 4, ImGuiTableFlags.RowBg);
if (!table)
return;
ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 40 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 200 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, 5 * ImGui.GetFrameHeight() + 4 * 2 * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch);
foreach (var (design, idx) in Selection.Designs.WithIndex())
{
ImGuiUtil.DrawTableColumn($"#{idx:D2}");
ImGui.TableNextColumn();
DrawDesignCombo(Selection, design, idx);
ImGui.TableNextColumn();
ImGui.TableNextColumn();
DrawJobGroupCombo(Selection, design, idx);
}
}
private void DrawDesignCombo(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
using var combo = ImRaii.Combo("##design", design.Design.Name);
if (!combo)
return;
}
private void DrawJobGroupCombo(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
using var combo = ImRaii.Combo("##JobGroups", design.Jobs.Name);
if (!combo)
return;
}
private void DrawApplicationTypeBoxes(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, 2 * ImGuiHelpers.GlobalScale);
var newType = design.ApplicationType;
foreach (var (type, description) in Types)
{
var value = design.ApplicationType.HasFlag(type);
if (ImGui.Checkbox($"##{(byte)type}", ref value))
newType = value ? newType | type : newType & ~type;
ImGuiUtil.HoverTooltip(description);
}
}
private static readonly IReadOnlyList<(AutoDesign.Type, string)> Types = new[]
{
(AutoDesign.Type.Customizations,
"Apply all customization changes that are enabled in this design and that are valid in a fixed design and for the given race and gender."),
(AutoDesign.Type.Armor, "Apply all armor piece changes that are enabled in this design and that are valid in a fixed design."),
(AutoDesign.Type.Accessories, "Apply all accessory changes that are enabled in this design and that are valid in a fixed design."),
(AutoDesign.Type.Stains, "Apply all dye changes that are enabled in this design."),
(AutoDesign.Type.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
};
}

View file

@ -0,0 +1,171 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Automation;
using Glamourer.Events;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Vector2 = FFXIVClientStructs.FFXIV.Common.Math.Vector2;
namespace Glamourer.Gui.Tabs.AutomationTab;
public class SetSelector : IDisposable
{
private readonly AutoDesignManager _manager;
private readonly AutomationChanged _event;
public AutoDesignSet? Selection { get; private set; }
public int SelectionIndex = -1;
private bool IncognitoMode;
private readonly List<AutoDesignSet> _list = new();
public SetSelector(AutoDesignManager manager, AutomationChanged @event)
{
_manager = manager;
_event = @event;
_event.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector);
}
public void Dispose()
{
_event.Unsubscribe(OnAutomationChanged);
}
private void OnAutomationChanged(AutomationChanged.Type type, AutoDesignSet? set, object? data)
{
switch (type)
{
case AutomationChanged.Type.DeletedSet:
if (set == Selection)
{
Selection = null;
SelectionIndex = -1;
}
_dirty = true;
break;
case AutomationChanged.Type.AddedSet:
case AutomationChanged.Type.RenamedSet:
case AutomationChanged.Type.MovedSet:
case AutomationChanged.Type.ChangeIdentifier:
case AutomationChanged.Type.ToggleSet:
_dirty = true;
break;
}
}
private LowerString _filter = LowerString.Empty;
private uint _enabledFilter = 0;
private float _width;
private Vector2 _defaultItemSpacing;
private Vector2 _selectableSize;
private bool _dirty = true;
private bool CheckFilters(AutoDesignSet set, string identifierString)
{
if (_enabledFilter switch
{
1 => set.Enabled,
3 => !set.Enabled,
_ => false,
})
return false;
if (!_filter.IsEmpty && !_filter.IsContained(set.Name) && !_filter.IsContained(identifierString))
return false;
return true;
}
private void UpdateList()
{
if (!_dirty)
return;
_list.Clear();
foreach (var set in _manager)
{
var id = set.Identifier.ToString();
if (CheckFilters(set, id))
_list.Add(set);
}
}
public bool HasSelection
=> Selection != null;
public void Draw(float width)
{
_width = width;
using var group = ImRaii.Group();
_defaultItemSpacing = ImGui.GetStyle().ItemSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.SetNextItemWidth(_width - ImGui.GetFrameHeight());
if (LowerString.InputWithHint("##filter", "Filter...", ref _filter, 64))
_dirty = true;
ImGui.SameLine();
var f = _enabledFilter;
if (ImGui.CheckboxFlags("##enabledFilter", ref f, 3))
{
_enabledFilter = _enabledFilter switch
{
0 => 3,
3 => 1,
_ => 0,
};
_dirty = true;
}
ImGuiUtil.HoverTooltip("Filter to show only enabled or disabled sets.");
DrawSelector();
DrawSelectionButtons();
}
private void DrawSelector()
{
using var child = ImRaii.Child("##actorSelector", new Vector2(_width, -ImGui.GetFrameHeight()), true);
if (!child)
return;
UpdateList();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
_selectableSize = new Vector2(0, 2 * ImGui.GetTextLineHeight() + ImGui.GetStyle().ItemSpacing.Y);
ImGuiClip.ClippedDraw(_list, DrawSetSelectable, _selectableSize.Y + 2 * ImGui.GetStyle().ItemSpacing.Y);
}
private void DrawSetSelectable(AutoDesignSet set, int index)
{
using var id = ImRaii.PushId(index);
using (var color = ImRaii.PushColor(ImGuiCol.Text, set.Enabled ? ColorId.EnabledAutoSet.Value() : ColorId.DisabledAutoSet.Value()))
{
if (ImGui.Selectable(set.Name, set == Selection, ImGuiSelectableFlags.None, _selectableSize))
{
Selection = set;
SelectionIndex = index;
}
}
var text = set.Identifier.ToString();
if (IncognitoMode)
text = set.Identifier.Incognito(text);
var textSize = ImGui.CalcTextSize(text);
ImGui.SetCursorPos(new Vector2(ImGui.GetContentRegionAvail().X - textSize.X,
ImGui.GetCursorPosY() - ImGui.GetTextLineHeightWithSpacing()));
ImGui.TextUnformatted(text);
}
private void DrawSelectionButtons()
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
var buttonWidth = new Vector2(_width / 1, 0);
// TODO
ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
, "Select the local player character.", true, true);
}
}

View file

@ -1,16 +1,11 @@
using System.Numerics;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.State;
using Glamourer.Structs;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.Api.Enums;
using Penumbra.Api.Helpers;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui.Tabs.DesignTab;

View file

@ -1,7 +1,5 @@
using System;
using Dalamud.Interface;
using Glamourer.Designs;
using Glamourer.Interop;
using ImGuiNET;
using OtterGui.Widgets;
@ -10,18 +8,12 @@ namespace Glamourer.Gui.Tabs.DesignTab;
public class DesignTab : ITab
{
public readonly DesignFileSystemSelector Selector;
private readonly DesignFileSystem _fileSystem;
private readonly DesignManager _designManager;
private readonly DesignPanel _panel;
private readonly ObjectManager _objects;
public DesignTab(DesignFileSystemSelector selector, DesignFileSystem fileSystem, DesignManager designManager, ObjectManager objects, DesignPanel panel)
public DesignTab(DesignFileSystemSelector selector, DesignPanel panel)
{
Selector = selector;
_fileSystem = fileSystem;
_designManager = designManager;
_objects = objects;
_panel = panel;
Selector = selector;
_panel = panel;
}
public ReadOnlySpan<byte> Label

View file

@ -8,6 +8,7 @@ using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.Gui.Tabs;
using Glamourer.Gui.Tabs.ActorTab;
using Glamourer.Gui.Tabs.AutomationTab;
using Glamourer.Gui.Tabs.DesignTab;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
@ -106,7 +107,10 @@ public static class ServiceManager
.AddSingleton<DesignFileSystemSelector>()
.AddSingleton<DesignPanel>()
.AddSingleton<DesignTab>()
.AddSingleton<PenumbraChangedItemTooltip>();
.AddSingleton<PenumbraChangedItemTooltip>()
.AddSingleton<AutomationTab>()
.AddSingleton<SetSelector>()
.AddSingleton<SetPanel>();
private static IServiceCollection AddApi(this IServiceCollection services)
=> services.AddSingleton<CommandService>()