mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-22 23:47:45 +01:00
Update automation tab, mod associations panel.
This commit is contained in:
parent
f2ac7e3353
commit
4646fd57ab
14 changed files with 676 additions and 611 deletions
|
|
@ -64,7 +64,10 @@ public sealed class AutomationChanged()
|
|||
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Gui.Tabs.AutomationTab.SetSelector.OnAutomationChange"/>
|
||||
/// <seealso cref="Gui.Tabs.AutomationTab.AutomationSelection.OnAutomationChanged"/>
|
||||
AutomationSelection = 0,
|
||||
|
||||
/// <seealso cref="Gui.Tabs.AutomationTab.SetSelector.Cache.OnAutomationChanged"/>
|
||||
SetSelector = 0,
|
||||
|
||||
/// <seealso cref="AutoDesignApplier.OnAutomationChange"/>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Glamourer.Gui.Tabs.ActorTab;
|
|||
|
||||
public sealed class ActorSelection(StateManager manager, ActorObjectManager objects, ICondition conditions) : IUiService
|
||||
{
|
||||
private static readonly StringU8 NoSelection = new("No Selection"u8);
|
||||
private static readonly StringU8 NoSelection = new("No Actor Selected"u8);
|
||||
|
||||
public ActorIdentifier Identifier { get; private set; }
|
||||
public ActorState? State { get; private set; }
|
||||
|
|
|
|||
168
Glamourer/Gui/Tabs/AutomationTab/AutomationButtons.cs
Normal file
168
Glamourer/Gui/Tabs/AutomationTab/AutomationButtons.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
using Glamourer.Automation;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class AutomationButtons : ButtonFooter
|
||||
{
|
||||
public AutomationButtons(Configuration config, AutoDesignManager manager, AutomationSelection selection, ActorObjectManager objects)
|
||||
{
|
||||
Buttons.AddButton(new AddButton(objects, manager), 100);
|
||||
Buttons.AddButton(new DuplicateButton(selection, manager), 90);
|
||||
Buttons.AddButton(new HelpButton(), 80);
|
||||
Buttons.AddButton(new DeleteButton(selection, config, manager), 70);
|
||||
}
|
||||
|
||||
private sealed class AddButton(ActorObjectManager objects, AutoDesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private ActorIdentifier _identifier;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.AddObjectIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
protected override void PreDraw()
|
||||
{
|
||||
_identifier = objects.Actors.GetCurrentPlayer();
|
||||
if (!_identifier.IsValid)
|
||||
_identifier = objects.Actors.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), WorldId.AnyWorld);
|
||||
}
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text($"Create a new Automatic Design Set for {_identifier}. The associated player can be changed later.");
|
||||
|
||||
public override bool Enabled
|
||||
=> _identifier.IsValid;
|
||||
|
||||
public override void OnClick()
|
||||
=> manager.AddDesignSet("New Automation Set", _identifier);
|
||||
}
|
||||
|
||||
private sealed class DuplicateButton(AutomationSelection selection, AutoDesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.DuplicateIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Duplicate the current Automatic Design Set."u8);
|
||||
|
||||
public override bool Enabled
|
||||
=> selection.Set is not null;
|
||||
|
||||
public override void OnClick()
|
||||
=> manager.DuplicateDesignSet(selection.Set!);
|
||||
}
|
||||
|
||||
private sealed class HelpButton : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.InfoIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("How does Automation work?"u8);
|
||||
|
||||
|
||||
public override void OnClick()
|
||||
=> Im.Popup.Open("Automation Help"u8);
|
||||
|
||||
protected override void PostDraw()
|
||||
{
|
||||
var longestLine =
|
||||
Im.Font.CalculateSize(
|
||||
"A single set can contain multiple automated designs that apply under different conditions and different parts of their design."u8);
|
||||
ImEx.HelpPopup("Automation Help"u8, new Vector2(longestLine.X + 50 * Im.Style.GlobalScale, 33 * Im.Style.TextHeightWithSpacing),
|
||||
DrawHelp);
|
||||
}
|
||||
|
||||
private static void DrawHelp()
|
||||
{
|
||||
var halfLine = new Vector2(Im.Style.TextHeight / 2);
|
||||
Im.Dummy(halfLine);
|
||||
Im.Text("What is Automation?"u8);
|
||||
Im.BulletText("Automation helps you to automatically apply Designs to specific characters under specific circumstances."u8);
|
||||
Im.Dummy(halfLine);
|
||||
|
||||
Im.Text("Automated Design Sets"u8);
|
||||
Im.BulletText("First, you create automated design sets. An automated design set can be... "u8);
|
||||
using var indent = Im.Indent();
|
||||
Im.BulletText("... enabled, or"u8, ColorId.EnabledAutoSet.Value());
|
||||
Im.BulletText("... disabled."u8, ColorId.DisabledAutoSet.Value());
|
||||
indent.Unindent();
|
||||
Im.BulletText("You can create new, empty automated design sets, or duplicate existing ones."u8);
|
||||
Im.BulletText("You can name automated design sets arbitrarily."u8);
|
||||
Im.BulletText("You can re-order automated design sets via drag & drop in the selector."u8);
|
||||
Im.BulletText("Each automated design set is assigned to exactly one specific character."u8);
|
||||
indent.Indent();
|
||||
Im.BulletText("On creation, it is assigned to your current Player Character."u8);
|
||||
Im.BulletText("You can assign sets to any players, retainers, mannequins and most human NPCs."u8);
|
||||
Im.BulletText("Only one automated design set can be enabled at the same time for each specific character."u8);
|
||||
indent.Indent();
|
||||
Im.BulletText("Enabling another automatically disables the prior one."u8);
|
||||
indent.Unindent();
|
||||
indent.Unindent();
|
||||
|
||||
Im.Dummy(halfLine);
|
||||
Im.Text("Automated Designs"u8);
|
||||
Im.BulletText(
|
||||
"A single set can contain multiple automated designs that apply under different conditions and different parts of their design."u8);
|
||||
Im.BulletText("The order of these automated designs can also be changed via drag & drop, and is relevant for the application."u8);
|
||||
Im.BulletText("Automated designs respect their own, coarse applications rules, and the designs own application rules."u8);
|
||||
Im.BulletText("Automated designs can be configured to be job- or job-group specific and only apply on these jobs, then."u8);
|
||||
Im.BulletText("There is also the special option 'Reset', which can be used to reset remaining slots to the game's values."u8);
|
||||
Im.BulletText("Automated designs apply from top to bottom, either on top of your characters current state, or its game state."u8);
|
||||
Im.BulletText("For a value to apply, it needs to:"u8);
|
||||
indent.Unindent();
|
||||
Im.BulletText("Be configured to apply in the design itself."u8);
|
||||
Im.BulletText("Be configured to apply in the automation rules."u8);
|
||||
Im.BulletText("Fulfill the conditions of the automation rules."u8);
|
||||
Im.BulletText("Be a valid value for the current (on its own application) state of the character."u8);
|
||||
Im.BulletText("Not have had anything applied to the same value before from a different design."u8);
|
||||
indent.Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DeleteButton(AutomationSelection selection, Configuration config, AutoDesignManager manager)
|
||||
: BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private bool _enabled;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.DeleteIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
{
|
||||
if (selection.Set is null)
|
||||
{
|
||||
Im.Text("No Automatic Design Set selected."u8);
|
||||
}
|
||||
else
|
||||
{
|
||||
Im.Text("Delete the currently selected design set."u8);
|
||||
if (!_enabled)
|
||||
Im.Text($"\nHold {config.DeleteDesignModifier} to delete.");
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Enabled
|
||||
=> (_enabled = config.DeleteDesignModifier.IsActive()) && selection.Set is not null;
|
||||
|
||||
public override void OnClick()
|
||||
=> manager.DeleteDesignSet(selection.Index);
|
||||
}
|
||||
}
|
||||
14
Glamourer/Gui/Tabs/AutomationTab/AutomationCacheItem.cs
Normal file
14
Glamourer/Gui/Tabs/AutomationTab/AutomationCacheItem.cs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
using Glamourer.Automation;
|
||||
using ImSharp;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public readonly struct AutomationCacheItem(AutoDesignSet set, int index)
|
||||
{
|
||||
public readonly AutoDesignSet Set = set;
|
||||
public readonly int Index = index;
|
||||
public readonly StringPair Name = new(set.Name);
|
||||
public readonly StringPair IdentifierString = new(set.Identifiers.First().ToString());
|
||||
public readonly StringU8 Incognito = new($"Auto Design Set #{index + 1}");
|
||||
public readonly StringU8 IdentifierIncognito = new(set.Identifiers.First().Incognito(null));
|
||||
}
|
||||
64
Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs
Normal file
64
Glamourer/Gui/Tabs/AutomationTab/AutomationFilter.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class AutomationFilter : TextFilterBase<AutomationCacheItem>, IUiService
|
||||
{
|
||||
private bool? _setStateFilter;
|
||||
|
||||
protected override string ToFilterString(in AutomationCacheItem item, int globalIndex)
|
||||
=> item.Name.Utf16;
|
||||
|
||||
public override bool WouldBeVisible(in AutomationCacheItem item, int globalIndex)
|
||||
=> _setStateFilter switch
|
||||
{
|
||||
true => item.Set.Enabled,
|
||||
false => !item.Set.Enabled,
|
||||
null => true,
|
||||
}
|
||||
&& base.WouldBeVisible(in item, globalIndex);
|
||||
|
||||
public override bool DrawFilter(ReadOnlySpan<byte> label, Vector2 availableRegion)
|
||||
{
|
||||
availableRegion.X -= Im.Style.FrameHeight;
|
||||
var ret = base.DrawFilter(label, availableRegion);
|
||||
Im.Line.NoSpacing();
|
||||
using (ImGuiColor.FrameBackground.Push(0x807070FF, _setStateFilter is not null))
|
||||
{
|
||||
if (ImEx.TriStateCheckbox("##state"u8, ref _setStateFilter, Rgba32.Transparent, ColorParameter.Default, ColorParameter.Default))
|
||||
{
|
||||
ret = true;
|
||||
InvokeEvent();
|
||||
}
|
||||
}
|
||||
|
||||
if (Im.Item.Hovered())
|
||||
{
|
||||
if (Im.Item.RightClicked())
|
||||
{
|
||||
// Ensure that a right-click clears the text filter if it is currently being edited.
|
||||
Im.Id.ClearActive();
|
||||
Clear();
|
||||
}
|
||||
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
Im.Text("Filter to only show enabled or disabled sets."u8);
|
||||
if (Text.Length is not 0 || _setStateFilter is not null)
|
||||
Im.Text("\nRight-click to clear all filters, including the text filter."u8);
|
||||
}
|
||||
|
||||
var pos = Im.Item.UpperLeftCorner;
|
||||
pos.X -= Im.Style.GlobalScale;
|
||||
Im.Window.DrawList.Shape.Line(pos, pos with { Y = Im.Item.LowerRightCorner.Y }, ImGuiColor.Border.Get(), Im.Style.GlobalScale);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
var changes = _setStateFilter is not null;
|
||||
_setStateFilter = null;
|
||||
if (!Set(string.Empty) && changes)
|
||||
InvokeEvent();
|
||||
}
|
||||
}
|
||||
13
Glamourer/Gui/Tabs/AutomationTab/AutomationHeader.cs
Normal file
13
Glamourer/Gui/Tabs/AutomationTab/AutomationHeader.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class AutomationHeader(Configuration config, AutomationSelection selection) : IHeader
|
||||
{
|
||||
public bool Collapsed
|
||||
=> false;
|
||||
|
||||
public void Draw(Vector2 size)
|
||||
=> ImEx.TextFramed(config.Ephemeral.IncognitoMode ? selection.Incognito : selection.Name, size with { Y = Im.Style.FrameHeight });
|
||||
}
|
||||
61
Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs
Normal file
61
Glamourer/Gui/Tabs/AutomationTab/AutomationSelection.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
using Glamourer.Automation;
|
||||
using Glamourer.Events;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class AutomationSelection : IUiService, IDisposable
|
||||
{
|
||||
public static readonly StringU8 NoSelection = new("No Set Selected"u8);
|
||||
|
||||
private readonly AutomationChanged _automationChanged;
|
||||
|
||||
public int DraggedDesignIndex = -1;
|
||||
|
||||
public AutoDesignSet? Set { get; private set; }
|
||||
public int Index { get; private set; } = -1;
|
||||
public StringU8 Name { get; private set; } = NoSelection;
|
||||
public StringU8 Incognito { get; private set; } = NoSelection;
|
||||
|
||||
public AutomationSelection(AutomationChanged automationChanged)
|
||||
{
|
||||
_automationChanged = automationChanged;
|
||||
_automationChanged.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_automationChanged.Unsubscribe(OnAutomationChanged);
|
||||
}
|
||||
|
||||
private void OnAutomationChanged(AutomationChanged.Type type, AutoDesignSet? set, object? data)
|
||||
{
|
||||
if (set != Set)
|
||||
return;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case AutomationChanged.Type.DeletedSet: Update(null); break;
|
||||
case AutomationChanged.Type.RenamedSet: Name = new StringU8(set!.Name); break;
|
||||
case AutomationChanged.Type.MovedSet: Index = (((int, int))data!).Item2; break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Update(in AutomationCacheItem? item)
|
||||
{
|
||||
Set = item?.Set;
|
||||
if (Set is null)
|
||||
{
|
||||
Index = -1;
|
||||
Name = NoSelection;
|
||||
Incognito = NoSelection;
|
||||
}
|
||||
else
|
||||
{
|
||||
Index = item!.Value.Index;
|
||||
Name = item!.Value.Name.Utf8;
|
||||
Incognito = item!.Value.Incognito;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,12 +3,27 @@ using Luna;
|
|||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public class AutomationTab(SetSelector selector, SetPanel panel, Configuration config) : ITab<MainTabType>
|
||||
public class AutomationTab : TwoPanelLayout, ITab<MainTabType>
|
||||
{
|
||||
public bool IsVisible
|
||||
=> config.EnableAutoDesigns;
|
||||
private readonly Configuration _config;
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
public AutomationTab(AutomationFilter filter, SetSelector selector, SetPanel panel, AutomationButtons buttons, AutomationHeader header,
|
||||
Configuration config)
|
||||
{
|
||||
_config = config;
|
||||
LeftHeader = new FilterHeader<AutomationCacheItem>(filter, new StringU8("Filter..."u8));
|
||||
LeftPanel = selector;
|
||||
LeftFooter = buttons;
|
||||
|
||||
RightHeader = header;
|
||||
RightPanel = panel;
|
||||
RightFooter = NopHeaderFooter.Instance;
|
||||
}
|
||||
|
||||
public bool IsVisible
|
||||
=> _config.EnableAutoDesigns;
|
||||
|
||||
public override ReadOnlySpan<byte> Label
|
||||
=> "Automation"u8;
|
||||
|
||||
public MainTabType Identifier
|
||||
|
|
@ -16,11 +31,6 @@ public class AutomationTab(SetSelector selector, SetPanel panel, Configuration c
|
|||
|
||||
public void DrawContent()
|
||||
{
|
||||
selector.Draw(GetSetSelectorSize());
|
||||
Im.Line.Same();
|
||||
panel.Draw();
|
||||
Draw(TwoPanelWidth.IndeterminateRelative);
|
||||
}
|
||||
|
||||
public float GetSetSelectorSize()
|
||||
=> 200f * Im.Style.GlobalScale;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,26 +13,26 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
private AutoDesignSet? _set;
|
||||
private int _designIndex = -1;
|
||||
|
||||
private readonly AutomationChanged _automationChanged;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _autoDesignManager;
|
||||
private readonly RandomDesignCombo _randomDesignCombo;
|
||||
private readonly SetSelector _selector;
|
||||
private readonly DesignStorage _designs;
|
||||
private readonly DesignFileSystem _designFileSystem;
|
||||
private readonly AutomationChanged _automationChanged;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _autoDesignManager;
|
||||
private readonly RandomDesignCombo _randomDesignCombo;
|
||||
private readonly AutomationSelection _selection;
|
||||
private readonly DesignStorage _designs;
|
||||
private readonly DesignFileSystem _designFileSystem;
|
||||
|
||||
private string _newText = string.Empty;
|
||||
private string? _newDefinition;
|
||||
private Design? _newDesign;
|
||||
|
||||
public RandomRestrictionDrawer(AutomationChanged automationChanged, Configuration config, AutoDesignManager autoDesignManager,
|
||||
RandomDesignCombo randomDesignCombo, SetSelector selector, DesignFileSystem designFileSystem, DesignStorage designs)
|
||||
RandomDesignCombo randomDesignCombo, AutomationSelection selection, DesignFileSystem designFileSystem, DesignStorage designs)
|
||||
{
|
||||
_automationChanged = automationChanged;
|
||||
_config = config;
|
||||
_autoDesignManager = autoDesignManager;
|
||||
_randomDesignCombo = randomDesignCombo;
|
||||
_selector = selector;
|
||||
_selection = selection;
|
||||
_designFileSystem = designFileSystem;
|
||||
_designs = designs;
|
||||
_automationChanged.Subscribe(OnAutomationChange, AutomationChanged.Priority.RandomRestrictionDrawer);
|
||||
|
|
@ -87,7 +87,7 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
if (_set is null || _designIndex < 0 || _designIndex >= _set.Designs.Count)
|
||||
return;
|
||||
|
||||
if (_set != _selector.Selection)
|
||||
if (_set != _selection.Set)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
|
|
@ -283,8 +283,10 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
name = _designFileSystem.TryGetValue(enumerator.Current, out l) ? l.FullName() : enumerator.Current.Name.Text;
|
||||
Im.BulletText(name);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Im.Text("Matches no currently existing designs."u8);
|
||||
}
|
||||
|
||||
|
|
@ -314,7 +316,8 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
"Add a new condition that the design must be assigned to the given color."u8, invalid)
|
||||
&& Add(new RandomPredicate.Exact(RandomPredicate.Exact.Type.Color, _newText));
|
||||
|
||||
if (_randomDesignCombo.Draw(StringU8.Empty, _newDesign, out var newDesign, Im.ContentRegion.Available.X - Im.Style.ItemInnerSpacing.X - buttonSize.X))
|
||||
if (_randomDesignCombo.Draw(StringU8.Empty, _newDesign, out var newDesign,
|
||||
Im.ContentRegion.Available.X - Im.Style.ItemInnerSpacing.X - buttonSize.X))
|
||||
_newDesign = newDesign as Design;
|
||||
Im.Line.SameInner();
|
||||
if (ImEx.Button("Exact Design"u8, buttonSize, "Add a single, specific design."u8, _newDesign is null))
|
||||
|
|
@ -346,7 +349,8 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
var definition = _newDefinition ?? currentDefinition;
|
||||
definition = definition.Replace(";", ";\n\t").Replace("{", "{\n\t").Replace("}", "\n}");
|
||||
var lines = definition.Count(c => c is '\n');
|
||||
if (Im.Input.MultiLine("##definition"u8, ref definition, Im.ContentRegion.Available with { Y = (lines + 1) * Im.Style.TextHeight + Im.Style.FrameHeight },
|
||||
if (Im.Input.MultiLine("##definition"u8, ref definition,
|
||||
Im.ContentRegion.Available with { Y = (lines + 1) * Im.Style.TextHeight + Im.Style.FrameHeight },
|
||||
InputTextFlags.CtrlEnterForNewLine))
|
||||
_newDefinition = definition;
|
||||
if (Im.Item.DeactivatedAfterEdit && _newDefinition is not null && _newDefinition != currentDefinition)
|
||||
|
|
@ -373,8 +377,8 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
{
|
||||
var designs = IDesignPredicate.Get(list, _designs, _designFileSystem).ToList();
|
||||
Im.Button(designs.Count > 0
|
||||
? $"All Restrictions Combined Match {designs.Count} Designs"
|
||||
: "None of the Restrictions Matches Any Designs"u8, Im.ContentRegion.Available with { Y = 0 });
|
||||
? $"All Restrictions Combined Match {designs.Count} Designs"
|
||||
: "None of the Restrictions Matches Any Designs"u8, Im.ContentRegion.Available with { Y = 0 });
|
||||
if (Im.Item.Hovered())
|
||||
LookupTooltip(designs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,16 +6,12 @@ using Glamourer.Services;
|
|||
using Glamourer.Unlocks;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Action = System.Action;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public class SetPanel(
|
||||
SetSelector selector,
|
||||
AutoDesignManager manager,
|
||||
JobService jobs,
|
||||
ItemUnlockManager itemUnlocks,
|
||||
|
|
@ -24,45 +20,34 @@ public class SetPanel(
|
|||
CustomizeService customizations,
|
||||
IdentifierDrawer identifierDrawer,
|
||||
Configuration config,
|
||||
RandomRestrictionDrawer randomDrawer)
|
||||
RandomRestrictionDrawer randomDrawer,
|
||||
AutomationSelection selection) : IPanel
|
||||
{
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(manager, jobs, Glamourer.Log);
|
||||
private readonly HeaderDrawer.Button[] _rightButtons = []; // [new IncognitoButton(config)];
|
||||
private string? _tempName;
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(manager, jobs);
|
||||
private int _dragIndex = -1;
|
||||
|
||||
private Action? _endAction;
|
||||
|
||||
private AutoDesignSet Selection
|
||||
=> selector.Selection!;
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "SetPanel"u8;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var group = Im.Group();
|
||||
DrawHeader();
|
||||
DrawPanel();
|
||||
}
|
||||
|
||||
private void DrawHeader()
|
||||
=> HeaderDrawer.Draw(selector.SelectionName, 0, ImGuiColor.FrameBackground.Get().Color, [], _rightButtons);
|
||||
|
||||
private void DrawPanel()
|
||||
{
|
||||
using var child = Im.Child.Begin("##Panel"u8, Im.ContentRegion.Available, true);
|
||||
if (!child || !selector.HasSelection)
|
||||
if (!child || selection.Index < 0)
|
||||
return;
|
||||
|
||||
using (Im.Group())
|
||||
{
|
||||
var enabled = Selection.Enabled;
|
||||
var enabled = selection.Set!.Enabled;
|
||||
if (Im.Checkbox("##Enabled"u8, ref enabled))
|
||||
manager.SetState(selector.SelectionIndex, enabled);
|
||||
manager.SetState(selection.Index, enabled);
|
||||
LunaStyle.DrawAlignedHelpMarkerLabel("Enabled"u8,
|
||||
"Whether the designs in this set should be applied at all. Only one set can be enabled for a character at the same time."u8);
|
||||
|
||||
var useGame = selector.Selection!.BaseState is AutoDesignSet.Base.Game;
|
||||
var useGame = selection.Set!.BaseState is AutoDesignSet.Base.Game;
|
||||
if (Im.Checkbox("##gameState"u8, ref useGame))
|
||||
manager.ChangeBaseState(selector.SelectionIndex, useGame ? AutoDesignSet.Base.Game : AutoDesignSet.Base.Current);
|
||||
manager.ChangeBaseState(selection.Index, useGame ? AutoDesignSet.Base.Game : AutoDesignSet.Base.Current);
|
||||
LunaStyle.DrawAlignedHelpMarkerLabel("Use Game State as Base"u8,
|
||||
"When this is enabled, the designs matching conditions will be applied successively on top of what your character is supposed to look like for the game. "u8
|
||||
+ "Otherwise, they will be applied on top of the characters actual current look using Glamourer."u8);
|
||||
|
|
@ -81,9 +66,9 @@ public class SetPanel(
|
|||
LunaStyle.DrawAlignedHelpMarkerLabel("Show Editing"u8,
|
||||
"Show options to change the name or the associated character or NPC of this design set."u8);
|
||||
|
||||
var resetSettings = selector.Selection!.ResetTemporarySettings;
|
||||
var resetSettings = selection.Set!.ResetTemporarySettings;
|
||||
if (Im.Checkbox("##resetSettings"u8, ref resetSettings))
|
||||
manager.ChangeResetSettings(selector.SelectionIndex, resetSettings);
|
||||
manager.ChangeResetSettings(selection.Index, resetSettings);
|
||||
|
||||
LunaStyle.DrawAlignedHelpMarkerLabel("Reset Temporary Settings"u8,
|
||||
"Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs."u8);
|
||||
|
|
@ -95,19 +80,13 @@ public class SetPanel(
|
|||
Im.Separator();
|
||||
Im.Dummy(Vector2.Zero);
|
||||
|
||||
var name = _tempName ?? Selection.Name;
|
||||
var flags = config.Ephemeral.IncognitoMode ? InputTextFlags.ReadOnly | InputTextFlags.Password : InputTextFlags.None;
|
||||
Im.Item.SetNextWidthScaled(330);
|
||||
if (Im.Input.Text("Rename Set##Name"u8, ref name, StringU8.Empty, flags))
|
||||
_tempName = name;
|
||||
if (ImEx.InputOnDeactivation.Text("Rename Set##Name"u8, selection.Name, out string newName, default, flags))
|
||||
manager.Rename(selection.Index, newName);
|
||||
|
||||
if (Im.Item.Deactivated)
|
||||
{
|
||||
manager.Rename(selector.SelectionIndex, name);
|
||||
_tempName = null;
|
||||
}
|
||||
|
||||
DrawIdentifierSelection(selector.SelectionIndex);
|
||||
DrawIdentifierSelection(selection.Index);
|
||||
}
|
||||
|
||||
Im.Dummy(Vector2.Zero);
|
||||
|
|
@ -176,26 +155,26 @@ public class SetPanel(
|
|||
table.SetupColumn(""u8, TableColumnFlags.WidthFixed, 2 * Im.Style.FrameHeight + 4 * Im.Style.GlobalScale);
|
||||
|
||||
table.HeaderRow();
|
||||
foreach (var (idx, design) in Selection.Designs.Index())
|
||||
foreach (var (idx, design) in selection.Set!.Designs.Index())
|
||||
{
|
||||
using var id = Im.Id.Push(idx);
|
||||
table.NextColumn();
|
||||
var keyValid = config.DeleteDesignModifier.IsActive();
|
||||
if (ImEx.Icon.Button(LunaStyle.DeleteIcon, "Remove this design from the set."u8, !keyValid))
|
||||
_endAction = () => manager.DeleteDesign(Selection, idx);
|
||||
if(!keyValid)
|
||||
_endAction = () => manager.DeleteDesign(selection.Set!, idx);
|
||||
if (!keyValid)
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} to remove.");
|
||||
table.NextColumn();
|
||||
DrawSelectable(idx, design.Design);
|
||||
|
||||
table.NextColumn();
|
||||
DrawRandomEditing(Selection, design, idx);
|
||||
designCombo.Draw(Selection, design, idx);
|
||||
DrawDragDrop(Selection, idx);
|
||||
DrawRandomEditing(selection.Set!, design, idx);
|
||||
designCombo.Draw(selection.Set!, design, idx);
|
||||
DrawDragDrop(selection.Set!, idx);
|
||||
if (singleRow)
|
||||
{
|
||||
table.NextColumn();
|
||||
DrawApplicationTypeBoxes(Selection, design, idx, singleRow);
|
||||
DrawApplicationTypeBoxes(selection.Set!, design, idx, singleRow);
|
||||
table.NextColumn();
|
||||
DrawConditions(design, idx);
|
||||
}
|
||||
|
|
@ -203,7 +182,7 @@ public class SetPanel(
|
|||
{
|
||||
DrawConditions(design, idx);
|
||||
table.NextColumn();
|
||||
DrawApplicationTypeBoxes(Selection, design, idx, singleRow);
|
||||
DrawApplicationTypeBoxes(selection.Set!, design, idx, singleRow);
|
||||
}
|
||||
|
||||
if (config.ShowUnlockedItemWarnings)
|
||||
|
|
@ -216,7 +195,7 @@ public class SetPanel(
|
|||
table.NextColumn();
|
||||
table.DrawFrameColumn("New"u8);
|
||||
table.NextColumn();
|
||||
designCombo.Draw(Selection, null, -1);
|
||||
designCombo.Draw(selection.Set!, null, -1);
|
||||
table.NextRow();
|
||||
|
||||
_endAction?.Invoke();
|
||||
|
|
@ -258,7 +237,7 @@ public class SetPanel(
|
|||
|
||||
Im.Tooltip.OnHover($"{sb}");
|
||||
|
||||
DrawDragDrop(Selection, idx);
|
||||
DrawDragDrop(selection.Set!, idx);
|
||||
}
|
||||
|
||||
private void DrawConditions(AutoDesign design, int idx)
|
||||
|
|
@ -267,7 +246,7 @@ public class SetPanel(
|
|||
if (Im.Button(usingGearset ? "Gearset:##usingGearset"u8 : "Jobs:##usingGearset"u8))
|
||||
{
|
||||
usingGearset = !usingGearset;
|
||||
manager.ChangeGearsetCondition(Selection, idx, (short)(usingGearset ? 0 : -1));
|
||||
manager.ChangeGearsetCondition(selection.Set!, idx, (short)(usingGearset ? 0 : -1));
|
||||
}
|
||||
|
||||
Im.Tooltip.OnHover("Click to switch between Job and Gearset restrictions."u8);
|
||||
|
|
@ -277,11 +256,11 @@ public class SetPanel(
|
|||
{
|
||||
Im.Item.SetNextWidthFull();
|
||||
if (ImEx.InputOnDeactivation.Scalar("##whichGearset"u8, design.GearsetIndex + 1, out var newIndex))
|
||||
manager.ChangeGearsetCondition(Selection, idx, (short)(Math.Clamp(newIndex, 1, 100) - 1));
|
||||
manager.ChangeGearsetCondition(selection.Set!, idx, (short)(Math.Clamp(newIndex, 1, 100) - 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
_jobGroupCombo.Draw(Selection, design, idx);
|
||||
_jobGroupCombo.Draw(selection.Set!, design, idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -397,8 +376,8 @@ public class SetPanel(
|
|||
Im.Text($"Moving design #{index + 1:D2}...");
|
||||
if (source.SetPayload("DesignDragDrop"u8))
|
||||
{
|
||||
_dragIndex = index;
|
||||
selector.DragDesignIndex = index;
|
||||
_dragIndex = index;
|
||||
selection.DraggedDesignIndex = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -406,8 +385,8 @@ public class SetPanel(
|
|||
|
||||
private void DrawApplicationTypeBoxes(AutoDesignSet set, AutoDesign design, int autoDesignIndex, bool singleLine)
|
||||
{
|
||||
using var style = ImStyleDouble.ItemSpacing.Push(new Vector2(2 * Im.Style.GlobalScale));
|
||||
var newType = design.Type;
|
||||
using var style = ImStyleDouble.ItemSpacing.Push(new Vector2(2 * Im.Style.GlobalScale));
|
||||
var newType = design.Type;
|
||||
using (ImStyleBorder.Frame.Push(ColorId.FolderLine.Value()))
|
||||
{
|
||||
Im.Checkbox("##all"u8, ref newType, ApplicationType.All);
|
||||
|
|
@ -468,23 +447,24 @@ public class SetPanel(
|
|||
manager.ChangeIdentifier(setIndex, identifierDrawer.OwnedIdentifier);
|
||||
}
|
||||
|
||||
private sealed class JobGroupCombo(AutoDesignManager manager, JobService jobs, OtterGui.Log.Logger log)
|
||||
: FilterComboCache<JobGroup>(() => jobs.JobGroups.Values.ToList(), MouseWheelType.None, log)
|
||||
private sealed class JobGroupCombo(AutoDesignManager manager, JobService jobs)
|
||||
: SimpleFilterCombo<JobGroup>(SimpleFilterType.Partwise)
|
||||
{
|
||||
public void Draw(AutoDesignSet set, AutoDesign design, int autoDesignIndex)
|
||||
{
|
||||
CurrentSelection = design.Jobs;
|
||||
CurrentSelectionIdx = jobs.JobGroups.Values.IndexOf(j => j.Id == design.Jobs.Id);
|
||||
if (Draw("##JobGroups", design.Jobs.Name.ToString(),
|
||||
"Select for which job groups this design should be applied.\nControl + Right-Click to set to all classes.",
|
||||
Im.ContentRegion.Available.X, Im.Style.TextHeightWithSpacing)
|
||||
&& CurrentSelectionIdx >= 0)
|
||||
manager.ChangeJobCondition(set, autoDesignIndex, CurrentSelection);
|
||||
if (Draw("##jobGroups"u8, design.Jobs, "Select for which job groups this design should be applied.\nControl + Right-Click to set to all classes."u8, Im.ContentRegion.Available.X, out var newGroup))
|
||||
manager.ChangeJobCondition(set, autoDesignIndex, newGroup);
|
||||
else if (Im.Io.KeyControl && Im.Item.RightClicked())
|
||||
manager.ChangeJobCondition(set, autoDesignIndex, jobs.JobGroups[1]);
|
||||
}
|
||||
|
||||
protected override string ToString(JobGroup obj)
|
||||
=> obj.Name.ToString();
|
||||
public override StringU8 DisplayString(in JobGroup value)
|
||||
=> value.Name;
|
||||
|
||||
public override string FilterString(in JobGroup value)
|
||||
=> value.Name.ToString();
|
||||
|
||||
public override IEnumerable<JobGroup> GetBaseItems()
|
||||
=>jobs.JobGroups.Values;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,346 +1,155 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Events;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
using Penumbra.String;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public class SetSelector : IDisposable
|
||||
public sealed class SetSelector(
|
||||
AutomationSelection selection,
|
||||
Configuration config,
|
||||
AutoDesignManager manager,
|
||||
AutomationFilter filter,
|
||||
ActorObjectManager objects,
|
||||
AutomationChanged automationChanged)
|
||||
: IPanel
|
||||
{
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly List<(AutoDesignSet, int)> _list = [];
|
||||
private readonly AutomationFilter _filter = filter;
|
||||
private readonly AutoDesignManager _manager = manager;
|
||||
private readonly AutomationChanged _automationChanged = automationChanged;
|
||||
|
||||
public AutoDesignSet? Selection { get; private set; }
|
||||
public int SelectionIndex { get; private set; } = -1;
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "Automation Selector"u8;
|
||||
|
||||
private int _dragIndex = -1;
|
||||
private Action? _endAction;
|
||||
|
||||
internal int DragDesignIndex = -1;
|
||||
|
||||
public SetSelector(AutoDesignManager manager, AutomationChanged @event, Configuration config, ActorObjectManager objects)
|
||||
public void Draw()
|
||||
{
|
||||
_manager = manager;
|
||||
_event = @event;
|
||||
_config = config;
|
||||
_objects = objects;
|
||||
_event.Subscribe(OnAutomationChange, AutomationChanged.Priority.SetSelector);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_event.Unsubscribe(OnAutomationChange);
|
||||
}
|
||||
|
||||
public string SelectionName
|
||||
=> GetSetName(Selection, SelectionIndex);
|
||||
|
||||
public string GetSetName(AutoDesignSet? set, int index)
|
||||
=> set == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? $"Auto Design Set #{index + 1}" : set.Name;
|
||||
|
||||
private void OnAutomationChange(AutomationChanged.Type type, AutoDesignSet? set, object? data)
|
||||
{
|
||||
switch (type)
|
||||
Im.Cursor.Y += Im.Style.FramePadding.Y;
|
||||
var cache = CacheManager.Instance.GetOrCreateCache(Im.Id.Current, () => new Cache(this));
|
||||
using var clip = new Im.ListClipper(cache.Count, cache.SelectableSize.Y);
|
||||
foreach (var item in clip.Iterate(cache))
|
||||
{
|
||||
case AutomationChanged.Type.DeletedSet:
|
||||
if (set == Selection)
|
||||
Im.Cursor.X += Im.Style.FramePadding.X;
|
||||
using var id = Im.Id.Push(item.Index);
|
||||
using var group = Im.Group();
|
||||
DrawSetSelectable(cache, item);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSetSelectable(Cache cache, in AutomationCacheItem item)
|
||||
{
|
||||
using (ImGuiColor.Text.Push(item.Set.Enabled ? cache.EnabledSet : cache.DisabledSet))
|
||||
{
|
||||
if (Im.Selectable(config.Ephemeral.IncognitoMode ? item.Incognito : item.Name.Utf8, item.Set == selection.Set,
|
||||
SelectableFlags.None, cache.SelectableSize))
|
||||
selection.Update(item);
|
||||
}
|
||||
|
||||
var lineEnd = Im.Item.LowerRightCorner;
|
||||
var lineStart = new Vector2(Im.Item.UpperLeftCorner.X, lineEnd.Y);
|
||||
Im.Window.DrawList.Shape.Line(lineStart, lineEnd, cache.LineColor, Im.Style.GlobalScale);
|
||||
|
||||
DrawDragDrop(cache, item);
|
||||
|
||||
var identifier = config.Ephemeral.IncognitoMode ? item.IdentifierIncognito : item.IdentifierString;
|
||||
var textSize = identifier.CalculateSize();
|
||||
var textColor = item.Set.Identifiers.Any(objects.ContainsKey) ? cache.AutomationAvailable : cache.AutomationUnavailable;
|
||||
Im.Cursor.Position = new Vector2(Im.ContentRegion.Available.X - textSize.X - Im.Style.FramePadding.X, Im.Cursor.Y - Im.Style.TextHeightWithSpacing);
|
||||
Im.Text(identifier, textColor);
|
||||
}
|
||||
|
||||
private void DrawDragDrop(Cache cache, in AutomationCacheItem item)
|
||||
{
|
||||
using (var target = Im.DragDrop.Target())
|
||||
{
|
||||
if (target.IsDropping("DesignSetDragDrop"u8))
|
||||
{
|
||||
if (cache.SetDragIndex >= 0)
|
||||
{
|
||||
SelectionIndex = _manager.Count == 0 ? -1 : SelectionIndex == 0 ? 0 : SelectionIndex - 1;
|
||||
Selection = SelectionIndex >= 0 ? _manager[SelectionIndex] : null;
|
||||
var idx = cache.SetDragIndex;
|
||||
_manager.MoveSet(idx, item.Index);
|
||||
}
|
||||
|
||||
_dirty = true;
|
||||
break;
|
||||
case AutomationChanged.Type.AddedSet:
|
||||
SelectionIndex = (((int, string))data!).Item1;
|
||||
Selection = set!;
|
||||
_dirty = true;
|
||||
break;
|
||||
case AutomationChanged.Type.MovedSet:
|
||||
_dirty = true;
|
||||
var (oldIdx, newIdx) = ((int, int))data!;
|
||||
if (SelectionIndex == oldIdx)
|
||||
SelectionIndex = newIdx;
|
||||
break;
|
||||
case AutomationChanged.Type.RenamedSet:
|
||||
case AutomationChanged.Type.ChangeIdentifier:
|
||||
case AutomationChanged.Type.ToggleSet:
|
||||
_dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private LowerString _filter = LowerString.Empty;
|
||||
private uint _enabledFilter;
|
||||
private float _width;
|
||||
private Vector2 _defaultItemSpacing;
|
||||
private Vector2 _selectableSize;
|
||||
private bool _dirty = true;
|
||||
|
||||
private bool CheckFilters(AutoDesignSet set, string identifierString)
|
||||
{
|
||||
if (_enabledFilter switch
|
||||
cache.SetDragIndex = -1;
|
||||
}
|
||||
else if (target.IsDropping("DesignDragDrop"u8))
|
||||
{
|
||||
1 => set.Enabled,
|
||||
3 => !set.Enabled,
|
||||
_ => false,
|
||||
})
|
||||
return false;
|
||||
if (selection.DraggedDesignIndex >= 0)
|
||||
{
|
||||
var idx = selection.DraggedDesignIndex;
|
||||
var setTo = item.Set;
|
||||
var setFrom = selection.Set!;
|
||||
_manager.MoveDesignToSet(setFrom, idx, setTo);
|
||||
}
|
||||
|
||||
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, idx) in _manager.WithIndex())
|
||||
{
|
||||
var id = set.Identifiers[0].ToString();
|
||||
if (CheckFilters(set, id))
|
||||
_list.Add((set, idx));
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasSelection
|
||||
=> Selection != null;
|
||||
|
||||
public void Draw(float width)
|
||||
{
|
||||
_width = width;
|
||||
using var group = ImRaii.Group();
|
||||
_defaultItemSpacing = Im.Style.ItemSpacing;
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||
ImGui.SetNextItemWidth(_width - Im.Style.FrameHeight);
|
||||
if (LowerString.InputWithHint("##filter", "Filter...", ref _filter, 64))
|
||||
_dirty = true;
|
||||
Im.Line.Same();
|
||||
var f = _enabledFilter;
|
||||
|
||||
if (ImGui.CheckboxFlags("##enabledFilter", ref f, 3u))
|
||||
{
|
||||
_enabledFilter = _enabledFilter switch
|
||||
{
|
||||
0 => 3,
|
||||
3 => 1,
|
||||
_ => 0,
|
||||
};
|
||||
_dirty = true;
|
||||
}
|
||||
|
||||
var pos = ImGui.GetItemRectMin();
|
||||
pos.X -= Im.Style.GlobalScale;
|
||||
ImGui.GetWindowDrawList().AddLine(pos, pos with { Y = ImGui.GetItemRectMax().Y }, ImGuiColor.Border.Get().Color,
|
||||
Im.Style.GlobalScale);
|
||||
|
||||
ImGuiUtil.HoverTooltip("Filter to show only enabled or disabled sets.");
|
||||
|
||||
DrawSelector();
|
||||
DrawSelectionButtons();
|
||||
}
|
||||
|
||||
private void DrawSelector()
|
||||
{
|
||||
using var child = ImRaii.Child("##Selector", new Vector2(_width, -Im.Style.FrameHeight), true);
|
||||
if (!child)
|
||||
return;
|
||||
|
||||
UpdateList();
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
|
||||
_selectableSize = new Vector2(0, 2 * Im.Style.TextHeight + Im.Style.ItemSpacing.Y);
|
||||
ImGuiClip.ClippedDraw(_list, DrawSetSelectable, _selectableSize.Y + 2 * Im.Style.ItemSpacing.Y);
|
||||
_endAction?.Invoke();
|
||||
_endAction = null;
|
||||
}
|
||||
|
||||
private void DrawSetSelectable((AutoDesignSet Set, int Index) pair)
|
||||
{
|
||||
using var id = Im.Id.Push(pair.Index);
|
||||
using (ImGuiColor.Text.Push(pair.Set.Enabled ? ColorId.EnabledAutoSet.Value() : ColorId.DisabledAutoSet.Value()))
|
||||
{
|
||||
if (ImGui.Selectable(GetSetName(pair.Set, pair.Index), pair.Set == Selection, ImGuiSelectableFlags.None, _selectableSize))
|
||||
{
|
||||
Selection = pair.Set;
|
||||
SelectionIndex = pair.Index;
|
||||
selection.DraggedDesignIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
var lineEnd = ImGui.GetItemRectMax();
|
||||
var lineStart = new Vector2(ImGui.GetItemRectMin().X, lineEnd.Y);
|
||||
ImGui.GetWindowDrawList().AddLine(lineStart, lineEnd, ImGuiColor.Border.Get().Color, Im.Style.GlobalScale);
|
||||
|
||||
DrawDragDrop(pair.Set, pair.Index);
|
||||
|
||||
var text = pair.Set.Identifiers[0].ToString();
|
||||
if (_config.Ephemeral.IncognitoMode)
|
||||
text = pair.Set.Identifiers[0].Incognito(text);
|
||||
var textSize = ImGui.CalcTextSize(text);
|
||||
var textColor = pair.Set.Identifiers.Any(_objects.ContainsKey) ? ColorId.AutomationActorAvailable : ColorId.AutomationActorUnavailable;
|
||||
ImGui.SetCursorPos(new Vector2(Im.ContentRegion.Available.X - textSize.X,
|
||||
ImGui.GetCursorPosY() - Im.Style.TextHeightWithSpacing));
|
||||
Im.Text(text, textColor.Value());
|
||||
}
|
||||
|
||||
private void DrawSelectionButtons()
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0);
|
||||
var buttonWidth = new Vector2(_width / 4, 0);
|
||||
NewSetButton(buttonWidth);
|
||||
Im.Line.Same();
|
||||
DuplicateSetButton(buttonWidth);
|
||||
Im.Line.Same();
|
||||
HelpButton(buttonWidth);
|
||||
Im.Line.Same();
|
||||
DeleteSetButton(buttonWidth);
|
||||
}
|
||||
|
||||
private static void HelpButton(Vector2 size)
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.QuestionCircle.ToIconString(), size, "How does Automation work?", false, true))
|
||||
ImGui.OpenPopup("Automation Help");
|
||||
|
||||
static void HalfLine()
|
||||
=> Im.Dummy(new Vector2(Im.Style.TextHeight / 2));
|
||||
|
||||
const string longestLine =
|
||||
"A single set can contain multiple automated designs that apply under different conditions and different parts of their design.";
|
||||
|
||||
ImGuiUtil.HelpPopup("Automation Help",
|
||||
new Vector2(ImGui.CalcTextSize(longestLine).X + 50 * Im.Style.GlobalScale, 33 * Im.Style.TextHeightWithSpacing), () =>
|
||||
{
|
||||
HalfLine();
|
||||
ImGui.TextUnformatted("What is Automation?");
|
||||
ImGui.BulletText("Automation helps you to automatically apply Designs to specific characters under specific circumstances.");
|
||||
HalfLine();
|
||||
|
||||
ImGui.TextUnformatted("Automated Design Sets");
|
||||
ImGui.BulletText("First, you create automated design sets. An automated design set can be... ");
|
||||
using var indent = ImRaii.PushIndent();
|
||||
Im.BulletText("... enabled, or"u8, ColorId.EnabledAutoSet.Value());
|
||||
Im.BulletText("... disabled."u8, ColorId.DisabledAutoSet.Value());
|
||||
indent.Pop(1);
|
||||
ImGui.BulletText("You can create new, empty automated design sets, or duplicate existing ones.");
|
||||
ImGui.BulletText("You can name automated design sets arbitrarily.");
|
||||
ImGui.BulletText("You can re-order automated design sets via drag & drop in the selector.");
|
||||
ImGui.BulletText("Each automated design set is assigned to exactly one specific character.");
|
||||
indent.Push();
|
||||
ImGui.BulletText("On creation, it is assigned to your current Player Character.");
|
||||
ImGui.BulletText("You can assign sets to any players, retainers, mannequins and most human NPCs.");
|
||||
ImGui.BulletText("Only one automated design set can be enabled at the same time for each specific character.");
|
||||
indent.Push();
|
||||
ImGui.BulletText("Enabling another automatically disables the prior one.");
|
||||
indent.Pop(2);
|
||||
|
||||
HalfLine();
|
||||
ImGui.TextUnformatted("Automated Designs");
|
||||
ImGui.BulletText(longestLine);
|
||||
ImGui.BulletText(
|
||||
"The order of these automated designs can also be changed via drag & drop, and is relevant for the application.");
|
||||
ImGui.BulletText("Automated designs respect their own, coarse applications rules, and the designs own application rules.");
|
||||
ImGui.BulletText("Automated designs can be configured to be job- or job-group specific and only apply on these jobs, then.");
|
||||
ImGui.BulletText("There is also the special option 'Reset', which can be used to reset remaining slots to the game's values.");
|
||||
ImGui.BulletText(
|
||||
"Automated designs apply from top to bottom, either on top of your characters current state, or its game state.");
|
||||
ImGui.BulletText("For a value to apply, it needs to:");
|
||||
indent.Push();
|
||||
ImGui.BulletText("Be configured to apply in the design itself.");
|
||||
ImGui.BulletText("Be configured to apply in the automation rules.");
|
||||
ImGui.BulletText("Fulfill the conditions of the automation rules.");
|
||||
ImGui.BulletText("Be a valid value for the current (on its own application) state of the character.");
|
||||
ImGui.BulletText("Not have had anything applied to the same value before from a different design.");
|
||||
indent.Pop(1);
|
||||
});
|
||||
}
|
||||
|
||||
private void NewSetButton(Vector2 size)
|
||||
{
|
||||
var id = _objects.Actors.GetCurrentPlayer();
|
||||
if (!id.IsValid)
|
||||
id = _objects.Actors.CreatePlayer(ByteString.FromSpanUnsafe("New Design"u8, true, false, true), ushort.MaxValue);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size,
|
||||
$"Create a new Automatic Design Set for {id}. The associated player can be changed later.", !id.IsValid, true))
|
||||
_manager.AddDesignSet("New Automation Set", id);
|
||||
}
|
||||
|
||||
private void DuplicateSetButton(Vector2 size)
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clone.ToIconString(), size, "Duplicate the current Automatic Design Set.",
|
||||
Selection == null, true))
|
||||
_manager.DuplicateDesignSet(Selection!);
|
||||
}
|
||||
|
||||
|
||||
private void DeleteSetButton(Vector2 size)
|
||||
{
|
||||
var keyValid = _config.DeleteDesignModifier.IsActive();
|
||||
var (disabled, tt) = HasSelection
|
||||
? keyValid
|
||||
? (false, "Delete the currently selected design set.")
|
||||
: (true, $"Delete the currently selected design set.\nHold {_config.DeleteDesignModifier} to delete.")
|
||||
: (true, "No Automatic Design Set selected.");
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, disabled, true))
|
||||
_manager.DeleteDesignSet(SelectionIndex);
|
||||
}
|
||||
|
||||
private void DrawDragDrop(AutoDesignSet set, int index)
|
||||
{
|
||||
const string dragDropLabel = "DesignSetDragDrop";
|
||||
using (var target = ImRaii.DragDropTarget())
|
||||
using (var source = Im.DragDrop.Source())
|
||||
{
|
||||
if (target.Success)
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
Im.Text($"Moving design set {item.Name.Utf8} from position {item.Index + 1}...");
|
||||
if (source.SetPayload("DesignSetDragDrop"u8))
|
||||
cache.SetDragIndex = item.Index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private sealed class Cache : BasicFilterCache<AutomationCacheItem>
|
||||
{
|
||||
public Vector2 SelectableSize;
|
||||
public Vector4 EnabledSet;
|
||||
public Vector4 DisabledSet;
|
||||
public Vector4 AutomationAvailable;
|
||||
public Vector4 AutomationUnavailable;
|
||||
public Rgba32 LineColor;
|
||||
|
||||
public int SetDragIndex = -1;
|
||||
private readonly SetSelector _parent;
|
||||
|
||||
public Cache(SetSelector parent)
|
||||
: base(parent._filter)
|
||||
{
|
||||
_parent = parent;
|
||||
_parent._automationChanged.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
_parent._automationChanged.Unsubscribe(OnAutomationChanged);
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
private void OnAutomationChanged(AutomationChanged.Type type, AutoDesignSet? set, object? data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
if (ImGuiUtil.IsDropping(dragDropLabel))
|
||||
{
|
||||
if (_dragIndex >= 0)
|
||||
{
|
||||
var idx = _dragIndex;
|
||||
_endAction = () => _manager.MoveSet(idx, index);
|
||||
}
|
||||
|
||||
_dragIndex = -1;
|
||||
}
|
||||
else if (ImGuiUtil.IsDropping("DesignDragDrop"))
|
||||
{
|
||||
if (DragDesignIndex >= 0)
|
||||
{
|
||||
var idx = DragDesignIndex;
|
||||
var setTo = set;
|
||||
var setFrom = Selection!;
|
||||
_endAction = () => _manager.MoveDesignToSet(setFrom, idx, setTo);
|
||||
}
|
||||
|
||||
DragDesignIndex = -1;
|
||||
}
|
||||
case AutomationChanged.Type.DeletedSet:
|
||||
case AutomationChanged.Type.AddedSet:
|
||||
case AutomationChanged.Type.MovedSet:
|
||||
case AutomationChanged.Type.RenamedSet:
|
||||
case AutomationChanged.Type.ChangeIdentifier:
|
||||
case AutomationChanged.Type.ToggleSet:
|
||||
Dirty |= IManagedCache.DirtyFlags.Custom;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
using (var source = ImRaii.DragDropSource())
|
||||
protected override IEnumerable<AutomationCacheItem> GetItems()
|
||||
=> _parent._manager.Index().Select(s => new AutomationCacheItem(s.Item, s.Index));
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (source)
|
||||
{
|
||||
ImGui.TextUnformatted($"Moving design set {GetSetName(set, index)} from position {index + 1}...");
|
||||
if (ImGui.SetDragDropPayload(dragDropLabel, null, 0))
|
||||
_dragIndex = index;
|
||||
}
|
||||
SelectableSize = new Vector2(0, 2 * Im.Style.TextHeight + Im.Style.ItemSpacing.Y);
|
||||
EnabledSet = ColorId.EnabledAutoSet.Value().ToVector();
|
||||
DisabledSet = ColorId.DisabledAutoSet.Value().ToVector();
|
||||
AutomationAvailable = ColorId.AutomationActorAvailable.Value().ToVector();
|
||||
AutomationUnavailable = ColorId.AutomationActorUnavailable.Value().ToVector();
|
||||
LineColor = ImGuiColor.Border.Get();
|
||||
base.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,8 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using TagButtons = OtterGui.Widgets.TagButtons;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
|
|
@ -22,15 +15,8 @@ public class DesignDetailTab
|
|||
private readonly DesignManager _manager;
|
||||
private readonly DesignColors _colors;
|
||||
private readonly DesignColorCombo _colorCombo;
|
||||
private readonly TagButtons _tagButtons = new();
|
||||
|
||||
private string? _newPath;
|
||||
private string? _newDescription;
|
||||
private string? _newName;
|
||||
|
||||
private bool _editDescriptionMode;
|
||||
private Design? _changeDesign;
|
||||
private DesignFileSystem.Leaf? _changeLeaf;
|
||||
private bool _editDescriptionMode;
|
||||
|
||||
public DesignDetailTab(SaveService saveService, DesignFileSystemSelector selector, DesignManager manager, DesignFileSystem fileSystem,
|
||||
DesignColors colors, Configuration config)
|
||||
|
|
@ -58,7 +44,7 @@ public class DesignDetailTab
|
|||
|
||||
private void DrawDesignInfoTable()
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
|
||||
using var style = ImStyleDouble.ButtonTextAlign.Push(new Vector2(0, 0.5f));
|
||||
using var table = Im.Table.Begin("Details"u8, 2);
|
||||
if (!table)
|
||||
return;
|
||||
|
|
@ -66,31 +52,20 @@ public class DesignDetailTab
|
|||
table.SetupColumn("Type"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("Reset Temporary Settings"u8).X);
|
||||
table.SetupColumn("Data"u8, TableColumnFlags.WidthStretch);
|
||||
|
||||
ImUtf8.DrawFrameColumn("Design Name"u8);
|
||||
ImGui.TableNextColumn();
|
||||
var width = new Vector2(Im.ContentRegion.Available.X, 0);
|
||||
var name = _newName ?? _selector.Selected!.Name;
|
||||
ImGui.SetNextItemWidth(width.X);
|
||||
if (ImUtf8.InputText("##Name"u8, ref name))
|
||||
{
|
||||
_newName = name;
|
||||
_changeDesign = _selector.Selected;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemDeactivatedAfterEdit() && _changeDesign != null)
|
||||
{
|
||||
_manager.Rename(_changeDesign, name);
|
||||
_newName = null;
|
||||
_changeDesign = null;
|
||||
}
|
||||
table.DrawFrameColumn("Design Name"u8);
|
||||
table.NextColumn();
|
||||
var width = Im.ContentRegion.Available with { Y = 0 };
|
||||
Im.Item.SetNextWidth(width.X);
|
||||
if (ImEx.InputOnDeactivation.Text("##Name"u8, _selector.Selected!.Name.Text, out string newName))
|
||||
_manager.Rename(_selector.Selected!, newName);
|
||||
|
||||
var identifier = _selector.Selected!.Identifier.ToString();
|
||||
ImUtf8.DrawFrameColumn("Unique Identifier"u8);
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawFrameColumn("Unique Identifier"u8);
|
||||
table.NextColumn();
|
||||
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
if (ImGui.Button(identifier, width))
|
||||
if (Im.Button(identifier, width))
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(fileName) { UseShellExecute = true });
|
||||
|
|
@ -102,72 +77,60 @@ public class DesignDetailTab
|
|||
}
|
||||
|
||||
if (Im.Item.RightClicked())
|
||||
ImGui.SetClipboardText(identifier);
|
||||
Im.Clipboard.Set(identifier);
|
||||
}
|
||||
|
||||
ImUtf8.HoverTooltip(
|
||||
Im.Tooltip.OnHover(
|
||||
$"Open the file\n\t{fileName}\ncontaining this design in the .json-editor of your choice.\n\nRight-Click to copy identifier to clipboard.");
|
||||
|
||||
ImUtf8.DrawFrameColumn("Full Selector Path"u8);
|
||||
ImGui.TableNextColumn();
|
||||
var path = _newPath ?? _selector.SelectedLeaf!.FullName();
|
||||
ImGui.SetNextItemWidth(width.X);
|
||||
if (ImUtf8.InputText("##Path"u8, ref path))
|
||||
{
|
||||
_newPath = path;
|
||||
_changeLeaf = _selector.SelectedLeaf!;
|
||||
}
|
||||
|
||||
if (ImGui.IsItemDeactivatedAfterEdit() && _changeLeaf != null)
|
||||
table.DrawFrameColumn("Full Selector Path"u8);
|
||||
table.NextColumn();
|
||||
Im.Item.SetNextWidth(width.X);
|
||||
if (ImEx.InputOnDeactivation.Text("##Path"u8, _selector.SelectedLeaf!.FullName(), out string newPath))
|
||||
try
|
||||
{
|
||||
_fileSystem.RenameAndMove(_changeLeaf, path);
|
||||
_newPath = null;
|
||||
_changeLeaf = null;
|
||||
_fileSystem.RenameAndMove(_selector.SelectedLeaf, newPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, ex.Message, "Could not rename or move design", NotificationType.Error);
|
||||
}
|
||||
|
||||
ImUtf8.DrawFrameColumn("Quick Design Bar"u8);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
|
||||
table.DrawFrameColumn("Quick Design Bar"u8);
|
||||
table.NextColumn();
|
||||
if (Im.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(_selector.Selected!, true);
|
||||
var hovered = ImGui.IsItemHovered();
|
||||
Im.Line.Same();
|
||||
if (ImUtf8.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
|
||||
var hovered = Im.Item.Hovered();
|
||||
Im.Line.SameInner();
|
||||
if (Im.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(_selector.Selected!, false);
|
||||
if (hovered || ImGui.IsItemHovered())
|
||||
{
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
ImUtf8.Text("Display or hide this design in your quick design bar."u8);
|
||||
}
|
||||
if (hovered || Im.Item.Hovered())
|
||||
Im.Tooltip.Set("Display or hide this design in your quick design bar."u8);
|
||||
|
||||
var forceRedraw = _selector.Selected!.ForcedRedraw;
|
||||
ImUtf8.DrawFrameColumn("Force Redrawing"u8);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.Checkbox("##ForceRedraw"u8, ref forceRedraw))
|
||||
table.DrawFrameColumn("Force Redrawing"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ForceRedraw"u8, ref forceRedraw))
|
||||
_manager.ChangeForcedRedraw(_selector.Selected!, forceRedraw);
|
||||
ImUtf8.HoverTooltip("Set this design to always force a redraw when it is applied through any means."u8);
|
||||
Im.Tooltip.OnHover("Set this design to always force a redraw when it is applied through any means."u8);
|
||||
|
||||
var resetAdvancedDyes = _selector.Selected!.ResetAdvancedDyes;
|
||||
ImUtf8.DrawFrameColumn("Reset Advanced Dyes"u8);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.Checkbox("##ResetAdvancedDyes"u8, ref resetAdvancedDyes))
|
||||
table.DrawFrameColumn("Reset Advanced Dyes"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ResetAdvancedDyes"u8, ref resetAdvancedDyes))
|
||||
_manager.ChangeResetAdvancedDyes(_selector.Selected!, resetAdvancedDyes);
|
||||
ImUtf8.HoverTooltip("Set this design to reset any previously applied advanced dyes when it is applied through any means."u8);
|
||||
Im.Tooltip.OnHover("Set this design to reset any previously applied advanced dyes when it is applied through any means."u8);
|
||||
|
||||
var resetTemporarySettings = _selector.Selected!.ResetTemporarySettings;
|
||||
ImUtf8.DrawFrameColumn("Reset Temporary Settings"u8);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImUtf8.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
|
||||
table.DrawFrameColumn("Reset Temporary Settings"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
|
||||
_manager.ChangeResetTemporarySettings(_selector.Selected!, resetTemporarySettings);
|
||||
ImUtf8.HoverTooltip(
|
||||
Im.Tooltip.OnHover(
|
||||
"Set this design to reset any temporary settings previously applied to the associated collection when it is applied through any means."u8);
|
||||
|
||||
ImUtf8.DrawFrameColumn("Color"u8);
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawFrameColumn("Color"u8);
|
||||
table.NextColumn();
|
||||
if (_colorCombo.Draw("##colorCombo"u8, _selector.Selected!.Color.Length is 0 ? DesignColors.AutomaticName : _selector.Selected!.Color,
|
||||
"Associate a color with this design.\n"u8
|
||||
+ "Right-Click to revert to automatic coloring.\n"u8
|
||||
|
|
@ -191,28 +154,28 @@ public class DesignDetailTab
|
|||
Im.Tooltip.OnHover("The color associated with this design does not exist."u8);
|
||||
}
|
||||
|
||||
ImUtf8.DrawFrameColumn("Creation Date"u8);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.DrawTextButton(_selector.Selected!.CreationDate.LocalDateTime.ToString("F"), width, 0);
|
||||
table.DrawFrameColumn("Creation Date"u8);
|
||||
table.NextColumn();
|
||||
ImEx.TextFramed($"{_selector.Selected!.CreationDate.LocalDateTime:F}", width, 0);
|
||||
|
||||
ImUtf8.DrawFrameColumn("Last Update Date"u8);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiUtil.DrawTextButton(_selector.Selected!.LastEdit.LocalDateTime.ToString("F"), width, 0);
|
||||
table.DrawFrameColumn("Last Update Date"u8);
|
||||
table.NextColumn();
|
||||
ImEx.TextFramed($"{_selector.Selected!.LastEdit.LocalDateTime:F}", width, 0);
|
||||
|
||||
ImUtf8.DrawFrameColumn("Tags"u8);
|
||||
ImGui.TableNextColumn();
|
||||
table.DrawFrameColumn("Tags"u8);
|
||||
table.NextColumn();
|
||||
DrawTags();
|
||||
}
|
||||
|
||||
private void DrawTags()
|
||||
{
|
||||
var idx = _tagButtons.Draw(string.Empty, string.Empty, _selector.Selected!.Tags, out var editedTag);
|
||||
var idx = TagButtons.Draw(StringU8.Empty, StringU8.Empty, _selector.Selected!.Tags, out var editedTag);
|
||||
if (idx < 0)
|
||||
return;
|
||||
|
||||
if (idx < _selector.Selected!.Tags.Length)
|
||||
{
|
||||
if (editedTag.Length == 0)
|
||||
if (editedTag.Length is 0)
|
||||
_manager.RemoveTag(_selector.Selected!, idx);
|
||||
else
|
||||
_manager.RenameTag(_selector.Selected!, idx, editedTag);
|
||||
|
|
@ -226,30 +189,24 @@ public class DesignDetailTab
|
|||
private void DrawDescription()
|
||||
{
|
||||
var desc = _selector.Selected!.Description;
|
||||
var size = new Vector2(Im.ContentRegion.Available.X, 12 * Im.Style.TextHeightWithSpacing);
|
||||
var size = Im.ContentRegion.Available with { Y = 12 * Im.Style.TextHeightWithSpacing };
|
||||
if (!_editDescriptionMode)
|
||||
{
|
||||
using (var textBox = ImUtf8.ListBox("##desc"u8, size))
|
||||
using (var textBox = Im.ListBox.Begin("##desc"u8, size))
|
||||
{
|
||||
ImUtf8.TextWrapped(desc);
|
||||
if (textBox)
|
||||
Im.TextWrapped(desc);
|
||||
}
|
||||
|
||||
if (ImUtf8.Button("Edit Description"u8))
|
||||
if (Im.Button("Edit Description"u8))
|
||||
_editDescriptionMode = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
var edit = _newDescription ?? desc;
|
||||
if (ImUtf8.InputMultiLine("##desc"u8, ref edit, size))
|
||||
_newDescription = edit;
|
||||
if (ImEx.InputOnDeactivation.MultiLine("##desc"u8, desc, out string newDescription, size))
|
||||
_manager.ChangeDescription(_selector.Selected!, newDescription);
|
||||
|
||||
if (ImGui.IsItemDeactivatedAfterEdit())
|
||||
{
|
||||
_manager.ChangeDescription(_selector.Selected!, edit);
|
||||
_newDescription = null;
|
||||
}
|
||||
|
||||
if (ImUtf8.Button("Stop Editing"u8))
|
||||
if (Im.Button("Stop Editing"u8))
|
||||
_editDescriptionMode = false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,9 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Utility;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Extensions;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.Widget;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
|
|
@ -28,11 +18,11 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
if (!h.Alive)
|
||||
return;
|
||||
|
||||
ImGuiUtil.HoverTooltip(
|
||||
"This tab can store information about specific mods associated with this design.\n\n"
|
||||
+ "It does NOT change any mod settings automatically, though there is functionality to apply desired mod settings manually.\n"
|
||||
+ "You can also use it to quickly open the associated mod page in Penumbra.\n\n"
|
||||
+ "It is not feasible to apply those changes automatically in general cases, since there would be no way to revert those changes, handle multiple designs applying at once, etc.");
|
||||
Im.Tooltip.OnHover(
|
||||
"This tab can store information about specific mods associated with this design.\n\n"u8
|
||||
+ "It does NOT change any mod settings automatically, though there is functionality to apply desired mod settings manually.\n"u8
|
||||
+ "You can also use it to quickly open the associated mod page in Penumbra.\n\n"u8
|
||||
+ "It is not feasible to apply those changes automatically in general cases, since there would be no way to revert those changes, handle multiple designs applying at once, etc."u8);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
|
|
@ -44,24 +34,24 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
private void DrawCopyButtons()
|
||||
{
|
||||
var size = new Vector2((Im.ContentRegion.Available.X - 2 * Im.Style.ItemSpacing.X) / 3, 0);
|
||||
if (ImGui.Button("Copy All to Clipboard", size))
|
||||
if (Im.Button("Copy All to Clipboard"u8, size))
|
||||
_copy = selector.Selected!.AssociatedMods.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
if (ImGuiUtil.DrawDisabledButton("Add from Clipboard", size,
|
||||
_copy != null
|
||||
if (ImEx.Button("Add from Clipboard"u8, size,
|
||||
_copy is not null
|
||||
? $"Add {_copy.Length} mod association(s) from clipboard."
|
||||
: "Copy some mod associations to the clipboard, first.", _copy == null))
|
||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||
foreach (var (mod, setting) in _copy!)
|
||||
manager.UpdateMod(selector.Selected!, mod, setting);
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
if (ImGuiUtil.DrawDisabledButton("Set from Clipboard", size,
|
||||
_copy != null
|
||||
if (ImEx.Button("Set from Clipboard"u8, size,
|
||||
_copy is not null
|
||||
? $"Set {_copy.Length} mod association(s) from clipboard and discard existing."
|
||||
: "Copy some mod associations to the clipboard, first.", _copy == null))
|
||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||
{
|
||||
while (selector.Selected!.AssociatedMods.Count > 0)
|
||||
manager.RemoveMod(selector.Selected!, selector.Selected!.AssociatedMods.Keys[0]);
|
||||
|
|
@ -75,17 +65,17 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
var (id, name) = penumbra.CurrentCollection;
|
||||
if (config.Ephemeral.IncognitoMode)
|
||||
name = id.ShortGuid();
|
||||
if (ImGuiUtil.DrawDisabledButton($"Try Applying All Associated Mods to {name}##applyAll",
|
||||
new Vector2(Im.ContentRegion.Available.X, 0), string.Empty, id == Guid.Empty))
|
||||
if (ImEx.Button($"Try Applying All Associated Mods to {name}##applyAll",
|
||||
Im.ContentRegion.Available with { Y = 0 }, string.Empty, id == Guid.Empty))
|
||||
ApplyAll();
|
||||
}
|
||||
|
||||
public void DrawApplyButton()
|
||||
{
|
||||
var (id, name) = penumbra.CurrentCollection;
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply Mod Associations", Vector2.Zero,
|
||||
if (ImEx.Button("Apply Mod Associations"u8, Vector2.Zero,
|
||||
$"Try to apply all associated mod settings to Penumbras current collection {name}",
|
||||
selector.Selected!.AssociatedMods.Count == 0 || id == Guid.Empty))
|
||||
selector.Selected!.AssociatedMods.Count is 0 || id == Guid.Empty))
|
||||
ApplyAll();
|
||||
}
|
||||
|
||||
|
|
@ -104,26 +94,26 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
table.SetupColumn("##Buttons"u8, TableColumnFlags.WidthFixed, Im.Style.FrameHeight * 3 + Im.Style.ItemInnerSpacing.X * 2);
|
||||
table.SetupColumn("Mod Name"u8, TableColumnFlags.WidthStretch);
|
||||
if (config.UseTemporarySettings)
|
||||
table.SetupColumn("Remove"u8, TableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Remove"u8).X);
|
||||
table.SetupColumn("Inherit"u8, TableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Inherit"u8).X);
|
||||
table.SetupColumn("State"u8, TableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("State"u8).X);
|
||||
table.SetupColumn("Priority"u8, TableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Priority"u8).X);
|
||||
table.SetupColumn("##Options"u8, TableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Applym"u8).X);
|
||||
table.SetupColumn("Remove"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("Remove"u8).X);
|
||||
table.SetupColumn("Inherit"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("Inherit"u8).X);
|
||||
table.SetupColumn("State"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("State"u8).X);
|
||||
table.SetupColumn("Priority"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("Priority"u8).X);
|
||||
table.SetupColumn("##Options"u8, TableColumnFlags.WidthFixed, Im.Font.CalculateSize("Applym"u8).X);
|
||||
table.HeaderRow();
|
||||
|
||||
Mod? removedMod = null;
|
||||
(Mod mod, ModSettings settings)? updatedMod = null;
|
||||
foreach (var ((mod, settings), idx) in selector.Selected!.AssociatedMods.WithIndex())
|
||||
foreach (var (idx, (mod, settings)) in selector.Selected!.AssociatedMods.Index())
|
||||
{
|
||||
using var id = Im.Id.Push(idx);
|
||||
DrawAssociatedModRow(mod, settings, out var removedModTmp, out var updatedModTmp);
|
||||
DrawAssociatedModRow(table, mod, settings, out var removedModTmp, out var updatedModTmp);
|
||||
if (removedModTmp.HasValue)
|
||||
removedMod = removedModTmp;
|
||||
if (updatedModTmp.HasValue)
|
||||
updatedMod = updatedModTmp;
|
||||
}
|
||||
|
||||
DrawNewModRow();
|
||||
DrawNewModRow(table);
|
||||
|
||||
if (removedMod.HasValue)
|
||||
manager.RemoveMod(selector.Selected!, removedMod.Value);
|
||||
|
|
@ -132,99 +122,92 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
manager.UpdateMod(selector.Selected!, updatedMod.Value.mod, updatedMod.Value.settings);
|
||||
}
|
||||
|
||||
private void DrawAssociatedModRow(Mod mod, ModSettings settings, out Mod? removedMod, out (Mod, ModSettings)? updatedMod)
|
||||
private void DrawAssociatedModRow(in Im.TableDisposable table, Mod mod, ModSettings settings, out Mod? removedMod,
|
||||
out (Mod, ModSettings)? updatedMod)
|
||||
{
|
||||
removedMod = null;
|
||||
updatedMod = null;
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
var canDelete = config.DeleteDesignModifier.IsActive();
|
||||
if (canDelete)
|
||||
{
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Trash, "Delete this mod from associations."u8))
|
||||
removedMod = mod;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImUtf8.IconButton(FontAwesomeIcon.Trash, $"Delete this mod from associations.\nHold {config.DeleteDesignModifier} to delete.",
|
||||
disabled: true);
|
||||
}
|
||||
if (ImEx.Icon.Button(LunaStyle.DeleteIcon, "Delete this mod from associations."u8))
|
||||
removedMod = mod;
|
||||
if (!canDelete)
|
||||
Im.Tooltip.OnHover($"\nHold {config.DeleteDesignModifier} to delete.");
|
||||
|
||||
Im.Line.SameInner();
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Clipboard, "Copy this mod setting to clipboard."u8))
|
||||
if (ImEx.Icon.Button(LunaStyle.ToClipboardIcon, "Copy this mod setting to clipboard."u8))
|
||||
_copy = [(mod, settings)];
|
||||
|
||||
Im.Line.SameInner();
|
||||
ImUtf8.IconButton(FontAwesomeIcon.RedoAlt, "Update the settings of this mod association."u8);
|
||||
if (ImGui.IsItemHovered())
|
||||
ImEx.Icon.Button(LunaStyle.RefreshIcon, "Update the settings of this mod association."u8);
|
||||
if (Im.Item.Hovered())
|
||||
{
|
||||
var newSettings = penumbra.GetModSettings(mod, out var source);
|
||||
if (ImGui.IsItemClicked())
|
||||
if (Im.Item.Clicked())
|
||||
updatedMod = (mod, newSettings);
|
||||
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.PopupBorderSize, 2 * Im.Style.GlobalScale);
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
using var style = ImStyleSingle.PopupBorderThickness.Push(2 * Im.Style.GlobalScale);
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
if (source.Length > 0)
|
||||
ImUtf8.Text($"Using temporary settings made by {source}.");
|
||||
Im.Text($"Using temporary settings made by {source}.");
|
||||
Im.Separator();
|
||||
var namesDifferent = mod.Name != mod.DirectoryName;
|
||||
Im.Dummy(new Vector2(300 * Im.Style.GlobalScale, 0));
|
||||
using (ImRaii.Group())
|
||||
Im.Dummy(300 * Im.Style.GlobalScale);
|
||||
using (Im.Group())
|
||||
{
|
||||
if (namesDifferent)
|
||||
ImUtf8.Text("Directory Name"u8);
|
||||
ImUtf8.Text("Force Inherit"u8);
|
||||
ImUtf8.Text("Enabled"u8);
|
||||
ImUtf8.Text("Priority"u8);
|
||||
Im.Text("Directory Name"u8);
|
||||
Im.Text("Force Inherit"u8);
|
||||
Im.Text("Enabled"u8);
|
||||
Im.Text("Priority"u8);
|
||||
ModCombo.DrawSettingsLeft(newSettings);
|
||||
}
|
||||
|
||||
ImGui.SameLine(Math.Max(ImGui.GetItemRectSize().X + 3 * Im.Style.ItemSpacing.X, 150 * Im.Style.GlobalScale));
|
||||
using (ImRaii.Group())
|
||||
Im.Line.Same(Math.Max(Im.Item.Size.X + 3 * Im.Style.ItemSpacing.X, 150 * Im.Style.GlobalScale));
|
||||
using (Im.Group())
|
||||
{
|
||||
if (namesDifferent)
|
||||
ImUtf8.Text(mod.DirectoryName);
|
||||
Im.Text(mod.DirectoryName);
|
||||
|
||||
ImUtf8.Text(newSettings.ForceInherit.ToString());
|
||||
ImUtf8.Text(newSettings.Enabled.ToString());
|
||||
ImUtf8.Text(newSettings.Priority.ToString());
|
||||
Im.Text($"{newSettings.ForceInherit}");
|
||||
Im.Text($"{newSettings.Enabled}");
|
||||
Im.Text($"{newSettings.Priority}");
|
||||
ModCombo.DrawSettingsRight(newSettings);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
|
||||
if (ImUtf8.Selectable($"{mod.Name}##name"))
|
||||
if (Im.Selectable($"{mod.Name}##name"))
|
||||
penumbra.OpenModPage(mod);
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip($"Mod Directory: {mod.DirectoryName}\n\nClick to open mod page in Penumbra.");
|
||||
Im.Tooltip.OnHover($"Mod Directory: {mod.DirectoryName}\n\nClick to open mod page in Penumbra.");
|
||||
if (config.UseTemporarySettings)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
var remove = settings.Remove;
|
||||
if (TwoStateCheckbox.Instance.Draw("##Remove"u8, ref remove))
|
||||
if (ImEx.TwoStateCheckbox("##Remove"u8, ref remove))
|
||||
updatedMod = (mod, settings with { Remove = remove });
|
||||
ImUtf8.HoverTooltip(
|
||||
Im.Tooltip.OnHover(
|
||||
"Remove any temporary settings applied by Glamourer instead of applying the configured settings. Only works when using temporary settings, ignored otherwise."u8);
|
||||
}
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
var inherit = settings.ForceInherit;
|
||||
if (TwoStateCheckbox.Instance.Draw("##ForceInherit"u8, ref inherit))
|
||||
if (ImEx.TwoStateCheckbox("##ForceInherit"u8, ref inherit))
|
||||
updatedMod = (mod, settings with { ForceInherit = inherit });
|
||||
ImUtf8.HoverTooltip("Force the mod to inherit its settings from inherited collections."u8);
|
||||
ImGui.TableNextColumn();
|
||||
Im.Tooltip.OnHover("Force the mod to inherit its settings from inherited collections."u8);
|
||||
table.NextColumn();
|
||||
var enabled = settings.Enabled;
|
||||
if (TwoStateCheckbox.Instance.Draw("##Enabled"u8, ref enabled))
|
||||
if (ImEx.TwoStateCheckbox("##Enabled"u8, ref enabled))
|
||||
updatedMod = (mod, settings with { Enabled = enabled });
|
||||
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
var priority = settings.Priority;
|
||||
ImGui.SetNextItemWidth(Im.ContentRegion.Available.X);
|
||||
if (ImUtf8.InputScalarOnDeactivated("##Priority"u8, ref priority))
|
||||
Im.Item.SetNextWidthFull();
|
||||
if (ImEx.InputOnDeactivation.Scalar("##Priority"u8, ref priority))
|
||||
updatedMod = (mod, settings with { Priority = priority });
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply", new Vector2(Im.ContentRegion.Available.X, 0), string.Empty,
|
||||
!penumbra.Available))
|
||||
table.NextColumn();
|
||||
if (ImEx.Button("Apply"u8, Im.ContentRegion.Available with { Y = 0 }, StringU8.Empty, !penumbra.Available))
|
||||
{
|
||||
var text = penumbra.SetMod(mod, settings, StateSource.Manual, false);
|
||||
if (text.Length > 0)
|
||||
|
|
@ -236,40 +219,39 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
|
|||
|
||||
private static void DrawAssociatedModTooltip(ModSettings settings)
|
||||
{
|
||||
if (settings is not { Enabled: true, Settings.Count: > 0 } || !ImGui.IsItemHovered())
|
||||
if (settings is not { Enabled: true, Settings.Count: > 0 } || !Im.Item.Hovered())
|
||||
return;
|
||||
|
||||
using var t = ImRaii.Tooltip();
|
||||
ImGui.TextUnformatted("This will also try to apply the following settings to the current collection:");
|
||||
using var t = Im.Tooltip.Begin();
|
||||
Im.Text("This will also try to apply the following settings to the current collection:"u8);
|
||||
|
||||
Im.Line.New();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
ModCombo.DrawSettingsLeft(settings);
|
||||
}
|
||||
|
||||
ImGui.SameLine(Im.ContentRegion.Available.X / 2);
|
||||
using (var _ = ImRaii.Group())
|
||||
Im.Line.Same(Im.ContentRegion.Available.X / 2);
|
||||
using (Im.Group())
|
||||
{
|
||||
ModCombo.DrawSettingsRight(settings);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawNewModRow()
|
||||
private void DrawNewModRow(in Im.TableDisposable table)
|
||||
{
|
||||
var currentName = _modCombo.CurrentSelection.Mod.Name;
|
||||
ImGui.TableNextColumn();
|
||||
var tt = currentName.IsNullOrEmpty()
|
||||
? "Please select a mod first."
|
||||
table.NextColumn();
|
||||
var tt = string.IsNullOrEmpty(currentName)
|
||||
? "Please select a mod first."u8
|
||||
: selector.Selected!.AssociatedMods.ContainsKey(_modCombo.CurrentSelection.Mod)
|
||||
? "The design already contains an association with the selected mod."
|
||||
: string.Empty;
|
||||
? "The design already contains an association with the selected mod."u8
|
||||
: StringU8.Empty;
|
||||
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), new Vector2(Im.Style.FrameHeight), tt, tt.Length > 0,
|
||||
true))
|
||||
if (ImEx.Icon.Button(LunaStyle.AddObjectIcon, tt, tt.Length > 0))
|
||||
manager.AddMod(selector.Selected!, _modCombo.CurrentSelection.Mod, _modCombo.CurrentSelection.Settings);
|
||||
ImGui.TableNextColumn();
|
||||
_modCombo.Draw("##new", currentName.IsNullOrEmpty() ? "Select new Mod..." : currentName, string.Empty,
|
||||
table.NextColumn();
|
||||
_modCombo.Draw("##new", string.IsNullOrEmpty(currentName) ? "Select new Mod..." : currentName, string.Empty,
|
||||
Im.ContentRegion.Available.X, Im.Style.TextHeight);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
|||
Subproject commit 042b829099c34608782c2a70da3cf189ac5f53be
|
||||
Subproject commit e80bdf5c10c6c30efccdff7d1adcb4a638eba4df
|
||||
Loading…
Add table
Add a link
Reference in a new issue