mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-25 14:11:47 +01:00
Current state.
This commit is contained in:
parent
04a8449967
commit
b88bba1a87
115 changed files with 2225 additions and 1776 deletions
|
|
@ -1 +1 @@
|
|||
Subproject commit 51b3c72e91816af0002dd543d64944e777b246ba
|
||||
Subproject commit 941dc7e1da694127a4405f4888ae162133131268
|
||||
|
|
@ -2,7 +2,6 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
|
|
@ -12,7 +11,6 @@ public class DesignsApi(
|
|||
ApiHelpers helpers,
|
||||
DesignManager designs,
|
||||
StateManager stateManager,
|
||||
DesignFileSystem fileSystem,
|
||||
DesignColors color,
|
||||
DesignConverter converter)
|
||||
: IGlamourerApiDesigns, IApiService
|
||||
|
|
@ -21,12 +19,11 @@ public class DesignsApi(
|
|||
=> designs.Designs.ToDictionary(d => d.Identifier, d => d.Name.Text);
|
||||
|
||||
public Dictionary<Guid, (string DisplayName, string FullPath, uint DisplayColor, bool ShownInQdb)> GetDesignListExtended()
|
||||
=> fileSystem.ToDictionary(kvp => kvp.Key.Identifier,
|
||||
kvp => (kvp.Key.Name.Text, kvp.Value.FullName(), color.GetColor(kvp.Key).Color, kvp.Key.QuickDesign));
|
||||
=> designs.Designs.ToDictionary(d => d.Identifier, d => (d.DisplayName, d.Path.CurrentPath, color.GetColor(d).Color, d.QuickDesign));
|
||||
|
||||
public (string DisplayName, string FullPath, uint DisplayColor, bool ShowInQdb) GetExtendedDesignData(Guid designId)
|
||||
=> designs.Designs.ByIdentifier(designId) is { } d
|
||||
? (d.Name.Text, fileSystem.TryGetValue(d, out var leaf) ? leaf.FullName() : d.Name.Text, color.GetColor(d).Color, d.QuickDesign)
|
||||
? (d.Name.Text, d.Path.CurrentPath, color.GetColor(d).Color, d.QuickDesign)
|
||||
: (string.Empty, string.Empty, 0, false);
|
||||
|
||||
public GlamourerApiEc ApplyDesign(Guid designId, int objectIndex, uint key, ApplyFlag flags)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using Glamourer.Api.Api;
|
||||
using Glamourer.Config;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Api;
|
||||
|
||||
public class GlamourerApi(Configuration.Configuration config, DesignsApi designs, StateApi state, ItemsApi items) : IGlamourerApi, IApiService
|
||||
public class GlamourerApi(Configuration config, DesignsApi designs, StateApi state, ItemsApi items) : IGlamourerApi, IApiService
|
||||
{
|
||||
public const int CurrentApiVersionMajor = 1;
|
||||
public const int CurrentApiVersionMinor = 7;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Events;
|
||||
|
|
@ -16,22 +17,22 @@ namespace Glamourer.Automation;
|
|||
|
||||
public sealed class AutoDesignApplier : IDisposable
|
||||
{
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly WeaponLoading _weapons;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly DesignMerger _designMerger;
|
||||
private readonly IClientState _clientState;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly StateManager _state;
|
||||
private readonly JobService _jobs;
|
||||
private readonly EquippedGearset _equippedGearset;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly AutomationChanged _event;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly WeaponLoading _weapons;
|
||||
private readonly HumanModelList _humans;
|
||||
private readonly DesignMerger _designMerger;
|
||||
private readonly IClientState _clientState;
|
||||
|
||||
private readonly JobChangeState _jobChangeState;
|
||||
|
||||
public AutoDesignApplier(Configuration.Configuration config, AutoDesignManager manager, StateManager state, JobService jobs, ActorManager actors,
|
||||
public AutoDesignApplier(Configuration config, AutoDesignManager manager, StateManager state, JobService jobs, ActorManager actors,
|
||||
AutomationChanged @event, ActorObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||
EquippedGearset equippedGearset, DesignMerger designMerger, JobChangeState jobChangeState)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ public class FixedDesignMigrator(JobService jobs)
|
|||
var set = autoManager[^1];
|
||||
foreach (var design in data.AsEnumerable().Reverse())
|
||||
{
|
||||
if (!designFileSystem.Find(design.Item1, out var child) || child is not DesignFileSystem.Leaf leaf)
|
||||
if (!designFileSystem.Find(design.Item1, out var child) || child is not IFileSystemData<Design> leaf)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Could not find design with path {design.Item1}, skipped fixed design.",
|
||||
NotificationType.Warning);
|
||||
|
|
|
|||
|
|
@ -7,14 +7,16 @@ using Glamourer.Gui.Tabs.DesignTab;
|
|||
using Glamourer.Services;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Luna.Generators;
|
||||
using Newtonsoft.Json;
|
||||
using OtterGui.Filesystem;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
||||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
public class Configuration : IPluginConfiguration, ISavable
|
||||
public sealed partial class Configuration : IPluginConfiguration, ISavable
|
||||
{
|
||||
public const int CurrentVersion = 9;
|
||||
|
||||
[JsonIgnore]
|
||||
public readonly EphemeralConfig Ephemeral;
|
||||
|
||||
|
|
@ -58,8 +60,11 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
|
||||
public DefaultDesignSettings DefaultDesignSettings { get; set; } = new();
|
||||
|
||||
public HeightDisplayType HeightDisplayType { get; set; } = HeightDisplayType.Centimetre;
|
||||
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
||||
public HeightDisplayType HeightDisplayType { get; set; } = HeightDisplayType.Centimetre;
|
||||
|
||||
[ConfigProperty(EventName = "OnRenameChanged")]
|
||||
private RenameField _showRename = RenameField.BothDataPrio;
|
||||
|
||||
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
||||
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
||||
public DoubleModifier IncognitoModifier { get; set; } = new(ModifierHotkey.Control);
|
||||
|
|
@ -70,7 +75,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
|
||||
[JsonConverter(typeof(SortModeConverter))]
|
||||
[JsonProperty(Order = int.MaxValue)]
|
||||
public ISortMode<Design> SortMode { get; set; } = ISortMode<Design>.FoldersFirst;
|
||||
public ISortMode SortMode { get; set; } = ISortMode.FoldersFirst;
|
||||
|
||||
public List<(string Code, bool Enabled)> Codes { get; set; } = [];
|
||||
|
||||
|
|
@ -80,7 +85,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
public bool DebugMode { get; set; } = false;
|
||||
#endif
|
||||
|
||||
public int Version { get; set; } = Constants.CurrentVersion;
|
||||
public int Version { get; set; } = CurrentVersion;
|
||||
|
||||
public Dictionary<ColorId, uint> Colors { get; private set; }
|
||||
= ColorId.Values.ToDictionary(c => c, c => c.Data().DefaultColor);
|
||||
|
|
@ -142,45 +147,22 @@ public class Configuration : IPluginConfiguration, ISavable
|
|||
serializer.Serialize(jWriter, this);
|
||||
}
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const int CurrentVersion = 8;
|
||||
|
||||
public static readonly ISortMode<Design>[] ValidSortModes =
|
||||
[
|
||||
ISortMode<Design>.FoldersFirst,
|
||||
ISortMode<Design>.Lexicographical,
|
||||
new DesignFileSystem.CreationDate(),
|
||||
new DesignFileSystem.InverseCreationDate(),
|
||||
new DesignFileSystem.UpdateDate(),
|
||||
new DesignFileSystem.InverseUpdateDate(),
|
||||
ISortMode<Design>.InverseFoldersFirst,
|
||||
ISortMode<Design>.InverseLexicographical,
|
||||
ISortMode<Design>.FoldersLast,
|
||||
ISortMode<Design>.InverseFoldersLast,
|
||||
ISortMode<Design>.InternalOrder,
|
||||
ISortMode<Design>.InverseInternalOrder,
|
||||
];
|
||||
}
|
||||
|
||||
/// <summary> Convert SortMode Types to their name. </summary>
|
||||
private class SortModeConverter : JsonConverter<ISortMode<Design>>
|
||||
private class SortModeConverter : JsonConverter<ISortMode>
|
||||
{
|
||||
public override void WriteJson(JsonWriter writer, ISortMode<Design>? value, JsonSerializer serializer)
|
||||
public override void WriteJson(JsonWriter writer, ISortMode? value, JsonSerializer serializer)
|
||||
{
|
||||
value ??= ISortMode<Design>.FoldersFirst;
|
||||
value ??= ISortMode.FoldersFirst;
|
||||
serializer.Serialize(writer, value.GetType().Name);
|
||||
}
|
||||
|
||||
public override ISortMode<Design> ReadJson(JsonReader reader, Type objectType, ISortMode<Design>? existingValue,
|
||||
bool hasExistingValue,
|
||||
public override ISortMode ReadJson(JsonReader reader, Type objectType, ISortMode? existingValue, bool hasExistingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
var name = serializer.Deserialize<string>(reader);
|
||||
if (name == null || !Constants.ValidSortModes.FindFirst(s => s.GetType().Name == name, out var mode))
|
||||
return existingValue ?? ISortMode<Design>.FoldersFirst;
|
||||
if (serializer.Deserialize<string>(reader) is { } name)
|
||||
return ISortMode.Valid.GetValueOrDefault(name, existingValue ?? ISortMode.FoldersFirst);
|
||||
|
||||
return mode;
|
||||
return existingValue ?? ISortMode.FoldersFirst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
public class DefaultDesignSettings
|
||||
{
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
using ImSharp;
|
||||
using Luna.Generators;
|
||||
|
||||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
[Flags]
|
||||
[NamedEnum(Utf16: false)]
|
||||
|
|
@ -40,9 +40,9 @@ public enum DesignPanelFlag : uint
|
|||
|
||||
public static partial class DesignPanelFlagExtensions
|
||||
{
|
||||
private static readonly StringU8 Expand = new("Expand"u8);
|
||||
private static readonly StringU8 Expand = new("Expand"u8);
|
||||
|
||||
public static Im.HeaderDisposable Header(this DesignPanelFlag flag, global::Glamourer.Configuration.Configuration config)
|
||||
public static Im.HeaderDisposable Header(this DesignPanelFlag flag, Configuration config)
|
||||
{
|
||||
if (config.HideDesignPanel.HasFlag(flag))
|
||||
return default;
|
||||
|
|
@ -6,11 +6,11 @@ using Luna.Generators;
|
|||
using Newtonsoft.Json;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
||||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
public partial class EphemeralConfig : ISavable
|
||||
{
|
||||
public int Version { get; set; } = Configuration.Constants.CurrentVersion;
|
||||
public int Version { get; set; } = Configuration.CurrentVersion;
|
||||
|
||||
[ConfigProperty]
|
||||
private bool _incognitoMode;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
using Luna.Generators;
|
||||
|
||||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
[TooltipEnum]
|
||||
public enum HeightDisplayType
|
||||
|
|
@ -4,7 +4,7 @@ using Luna.Generators;
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Glamourer.Configuration;
|
||||
namespace Glamourer.Config;
|
||||
|
||||
public sealed partial class UiConfig : ConfigurationFile<FilenameService>
|
||||
{
|
||||
|
|
@ -14,7 +14,7 @@ using Notification = Luna.Notification;
|
|||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||
public sealed class Design : DesignBase, ISavable, IDesignStandIn, IFileSystemValue<Design>
|
||||
{
|
||||
#region Data
|
||||
|
||||
|
|
@ -44,6 +44,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
public new const int FileVersion = 2;
|
||||
|
||||
public Guid Identifier { get; internal init; }
|
||||
public IFileSystemData<Design>? Node { get; set; }
|
||||
public DateTimeOffset CreationDate { get; internal init; }
|
||||
public DateTimeOffset LastEdit { get; internal set; }
|
||||
public LowerString Name { get; internal set; } = LowerString.Empty;
|
||||
|
|
@ -57,6 +58,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
public string Color { get; internal set; } = string.Empty;
|
||||
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
|
||||
public LinkContainer Links { get; private set; } = [];
|
||||
public DataPath Path { get; } = new();
|
||||
|
||||
public string Incognito
|
||||
=> Identifier.ToString()[..8];
|
||||
|
|
@ -124,6 +126,12 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
["Mods"] = SerializeMods(),
|
||||
["Links"] = Links.Serialize(),
|
||||
};
|
||||
if (Path.Folder.Length > 0)
|
||||
ret["FileSystemFolder"] = Path.Folder;
|
||||
if (Path.SortName is not null)
|
||||
ret["SortOrderName"] = Path.SortName;
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -251,6 +259,9 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
};
|
||||
if (design.LastEdit < creationDate)
|
||||
design.LastEdit = creationDate;
|
||||
design.Path.Folder = json["FileSystemFolder"]?.Value<string>() ?? string.Empty;
|
||||
design.Path.SortName = json["SortOrderName"]?.Value<string>()?.FixName();
|
||||
|
||||
design.SetWriteProtected(json["WriteProtected"]?.ToObject<bool>() ?? false);
|
||||
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
||||
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
||||
|
|
@ -340,7 +351,13 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
|||
}
|
||||
|
||||
public string LogName(string fileName)
|
||||
=> Path.GetFileNameWithoutExtension(fileName);
|
||||
=> System.IO.Path.GetFileNameWithoutExtension(fileName);
|
||||
|
||||
#endregion
|
||||
|
||||
string IFileSystemValue.Identifier
|
||||
=> Identifier.ToString();
|
||||
|
||||
public string DisplayName
|
||||
=> Name.Text;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Services;
|
||||
using ImSharp;
|
||||
|
|
@ -8,7 +9,7 @@ using Newtonsoft.Json.Linq;
|
|||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public class DesignColorUi(DesignColors colors, Configuration.Configuration config)
|
||||
public class DesignColorUi(DesignColors colors, Configuration config)
|
||||
{
|
||||
private string _newName = string.Empty;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String.Functions;
|
||||
|
|
@ -47,8 +46,8 @@ public unsafe struct DesignData
|
|||
{ }
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
|
||||
public readonly bool ContainsName(LowerString name)
|
||||
=> ItemNames.Any(name.IsContained);
|
||||
public readonly bool ContainsName(string name)
|
||||
=> ItemNames.Any(i => i.Contains(name, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
public readonly StainIds Stain(EquipSlot slot)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Glamourer.Config;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Events;
|
||||
|
|
@ -5,7 +6,6 @@ using Glamourer.GameData;
|
|||
using Glamourer.Interop.Material;
|
||||
using Glamourer.Services;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -16,14 +16,14 @@ public class DesignEditor(
|
|||
DesignChanged designChanged,
|
||||
CustomizeService customizations,
|
||||
ItemManager items,
|
||||
Configuration.Configuration config)
|
||||
Configuration config)
|
||||
: IDesignEditor
|
||||
{
|
||||
protected readonly DesignChanged DesignChanged = designChanged;
|
||||
protected readonly SaveService SaveService = saveService;
|
||||
protected readonly ItemManager Items = items;
|
||||
protected readonly CustomizeService Customizations = customizations;
|
||||
protected readonly Configuration.Configuration Config = config;
|
||||
protected readonly Configuration Config = config;
|
||||
protected readonly Dictionary<Guid, DesignData> UndoStore = [];
|
||||
|
||||
private bool _forceFullItemOff;
|
||||
|
|
|
|||
|
|
@ -3,195 +3,64 @@ using Glamourer.Designs.History;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Luna;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public sealed class DesignFileSystem : OtterGui.Filesystem.FileSystem<Design>, IDisposable, ISavable
|
||||
public sealed class DesignFileSystem : BaseFileSystem, IDisposable, IRequiredService
|
||||
{
|
||||
private readonly DesignChanged _designChanged;
|
||||
private readonly DesignFileSystemSaver _saver;
|
||||
private readonly DesignChanged _designChanged;
|
||||
|
||||
private readonly SaveService _saveService;
|
||||
private readonly DesignManager _designManager;
|
||||
|
||||
public DesignFileSystem(DesignManager designManager, SaveService saveService, DesignChanged designChanged)
|
||||
public DesignFileSystem(Logger log, SaveService saveService, DesignStorage designs, DesignChanged designChanged)
|
||||
: base("DesignFileSystem", log, true)
|
||||
{
|
||||
_designManager = designManager;
|
||||
_saveService = saveService;
|
||||
_designChanged = designChanged;
|
||||
_designChanged.Subscribe(OnDesignChange, DesignChanged.Priority.DesignFileSystem);
|
||||
Changed += OnChange;
|
||||
Reload();
|
||||
_saver = new DesignFileSystemSaver(log, this, saveService, designs);
|
||||
|
||||
_saver.Load();
|
||||
_designChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignFileSystem);
|
||||
}
|
||||
|
||||
private void Reload()
|
||||
private void OnDesignChanged(DesignChanged.Type type, Design design, ITransaction? _)
|
||||
{
|
||||
if (Load(new FileInfo(_saveService.FileNames.DesignFileSystem), _designManager.Designs, DesignToIdentifier, DesignToName))
|
||||
_saveService.ImmediateSave(this);
|
||||
switch (type)
|
||||
{
|
||||
case DesignChanged.Type.ReloadedAll: _saver.Load(); break;
|
||||
case DesignChanged.Type.Created:
|
||||
var parent = Root;
|
||||
if (design.Path.Folder.Length > 0)
|
||||
try
|
||||
{
|
||||
parent = FindOrCreateAllFolders(design.Path.Folder);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex,
|
||||
$"Could not move design to {design.Path} because the folder could not be created.",
|
||||
NotificationType.Error);
|
||||
}
|
||||
|
||||
Glamourer.Log.Debug("Reloaded design filesystem.");
|
||||
var (data, _) = CreateDuplicateDataNode(parent, design.Path.SortName ?? design.Name, design);
|
||||
Selection.Select(data);
|
||||
break;
|
||||
case DesignChanged.Type.Deleted:
|
||||
if (design.Node is { } node)
|
||||
{
|
||||
if (node.Selected)
|
||||
Selection.UnselectAll();
|
||||
Delete(node);
|
||||
}
|
||||
|
||||
break;
|
||||
case DesignChanged.Type.Renamed when design.Path.SortName is null:
|
||||
RenameWithDuplicates(design.Node!, design.Path.GetIntendedName(design.Name.Text));
|
||||
break;
|
||||
// TODO: Maybe add path changes?
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_designChanged.Unsubscribe(OnDesignChange);
|
||||
}
|
||||
|
||||
public struct CreationDate : OtterGui.Filesystem.ISortMode<Design>
|
||||
{
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Older First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their creation date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderBy(l => l.Value.CreationDate));
|
||||
}
|
||||
|
||||
public struct UpdateDate : OtterGui.Filesystem.ISortMode<Design>
|
||||
{
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Older First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their last update date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderBy(l => l.Value.LastEdit));
|
||||
}
|
||||
|
||||
public struct InverseCreationDate : OtterGui.Filesystem.ISortMode<Design>
|
||||
{
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Newer First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse creation date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderByDescending(l => l.Value.CreationDate));
|
||||
}
|
||||
|
||||
public struct InverseUpdateDate : OtterGui.Filesystem.ISortMode<Design>
|
||||
{
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Newer First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse last update date."u8;
|
||||
|
||||
public IEnumerable<IPath> GetChildren(Folder f)
|
||||
=> f.GetSubFolders().Cast<IPath>().Concat(f.GetLeaves().OrderByDescending(l => l.Value.LastEdit));
|
||||
}
|
||||
|
||||
private void OnChange(OtterGui.Filesystem.FileSystemChangeType type, IPath _1, IPath? _2, IPath? _3)
|
||||
{
|
||||
if (type != OtterGui.Filesystem.FileSystemChangeType.Reload)
|
||||
_saveService.QueueSave(this);
|
||||
}
|
||||
|
||||
private void OnDesignChange(DesignChanged.Type type, Design design, ITransaction? data)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DesignChanged.Type.Created:
|
||||
var parent = Root;
|
||||
if ((data as CreationTransaction?)?.Path is { } path)
|
||||
try
|
||||
{
|
||||
parent = FindOrCreateAllFolders(path);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not move design to {path} because the folder could not be created.",
|
||||
NotificationType.Error);
|
||||
}
|
||||
|
||||
CreateDuplicateLeaf(parent, design.Name.Text, design);
|
||||
|
||||
return;
|
||||
case DesignChanged.Type.Deleted:
|
||||
if (TryGetValue(design, out var leaf1))
|
||||
Delete(leaf1);
|
||||
return;
|
||||
case DesignChanged.Type.ReloadedAll:
|
||||
Reload();
|
||||
return;
|
||||
case DesignChanged.Type.Renamed when (data as RenameTransaction?)?.Old is { } oldName:
|
||||
if (!TryGetValue(design, out var leaf2))
|
||||
return;
|
||||
|
||||
var old = oldName.FixName();
|
||||
if (old == leaf2.Name || leaf2.Name.IsDuplicateName(out var baseName, out _) && baseName == old)
|
||||
RenameWithDuplicates(leaf2, design.Name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Used for saving and loading.
|
||||
private static string DesignToIdentifier(Design design)
|
||||
=> design.Identifier.ToString();
|
||||
|
||||
private static string DesignToName(Design design)
|
||||
=> design.Name.Text.FixName();
|
||||
|
||||
private static bool DesignHasDefaultPath(Design design, string fullPath)
|
||||
{
|
||||
var regex = new Regex($@"^{Regex.Escape(DesignToName(design))}( \(\d+\))?$");
|
||||
return regex.IsMatch(fullPath);
|
||||
}
|
||||
|
||||
private static (string, bool) SaveDesign(Design design, string fullPath)
|
||||
// Only save pairs with non-default paths.
|
||||
=> DesignHasDefaultPath(design, fullPath)
|
||||
? (string.Empty, false)
|
||||
: (DesignToIdentifier(design), true);
|
||||
|
||||
internal static void MigrateOldPaths(SaveService saveService, Dictionary<string, string> oldPaths)
|
||||
{
|
||||
if (oldPaths.Count == 0)
|
||||
return;
|
||||
|
||||
var file = saveService.FileNames.DesignFileSystem;
|
||||
try
|
||||
{
|
||||
JObject jObject;
|
||||
if (File.Exists(file))
|
||||
{
|
||||
var text = File.ReadAllText(file);
|
||||
jObject = JObject.Parse(text);
|
||||
var dict = jObject["Data"]?.ToObject<Dictionary<string, string>>();
|
||||
if (dict != null)
|
||||
foreach (var (key, value) in dict)
|
||||
oldPaths.TryAdd(key, value);
|
||||
|
||||
jObject["Data"] = JToken.FromObject(oldPaths);
|
||||
}
|
||||
else
|
||||
{
|
||||
jObject = new JObject
|
||||
{
|
||||
["Data"] = JToken.FromObject(oldPaths),
|
||||
["EmptyFolders"] = JToken.FromObject(Array.Empty<string>()),
|
||||
};
|
||||
}
|
||||
|
||||
var data = jObject.ToString(Formatting.Indented);
|
||||
File.WriteAllText(file, data);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Log.Error($"Could not migrate old folder paths to new version:\n{ex}");
|
||||
}
|
||||
}
|
||||
|
||||
public string ToFilePath(FilenameService fileNames)
|
||||
=> fileNames.DesignFileSystem;
|
||||
|
||||
public void Save(StreamWriter writer)
|
||||
{
|
||||
SaveToFile(writer, SaveDesign, true);
|
||||
_designChanged.Unsubscribe(OnDesignChanged);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
57
Glamourer/Designs/DesignFileSystemSaver.cs
Normal file
57
Glamourer/Designs/DesignFileSystemSaver.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
using Glamourer.Services;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public sealed class DesignFileSystemSaver(Logger log, BaseFileSystem fileSystem, SaveService saveService, DesignStorage designs)
|
||||
: FileSystemSaver<SaveService, FilenameService>(log, fileSystem, saveService)
|
||||
{
|
||||
protected override void SaveDataValue(IFileSystemValue value)
|
||||
{
|
||||
if (value is Design design)
|
||||
SaveService.QueueSave(design);
|
||||
}
|
||||
|
||||
protected override string LockedFile(FilenameService provider)
|
||||
=> provider.FileSystemLockedNodes;
|
||||
|
||||
protected override string ExpandedFile(FilenameService provider)
|
||||
=> provider.FileSystemExpandedFolders;
|
||||
|
||||
protected override string EmptyFoldersFile(FilenameService provider)
|
||||
=> provider.FileSystemEmptyFolders;
|
||||
|
||||
protected override string SelectionFile(FilenameService provider)
|
||||
=> provider.FileSystemSelectedNodes;
|
||||
|
||||
protected override string MigrationFile(FilenameService provider)
|
||||
=> provider.MigrationDesignFileSystem;
|
||||
|
||||
protected override bool GetValueFromIdentifier(ReadOnlySpan<char> identifier, [NotNullWhen(true)] out IFileSystemValue? value)
|
||||
{
|
||||
if (!Guid.TryParse(identifier, out var guid))
|
||||
{
|
||||
value = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
value = designs.FirstOrDefault(d => d.Identifier == guid);
|
||||
return value is not null;
|
||||
}
|
||||
|
||||
protected override void CreateDataNodes()
|
||||
{
|
||||
foreach (var design in designs)
|
||||
{
|
||||
try
|
||||
{
|
||||
var folder = design.Path.Folder.Length is 0 ? FileSystem.Root : FileSystem.FindOrCreateAllFolders(design.Path.Folder);
|
||||
FileSystem.CreateDuplicateDataNode(folder, design.Path.SortName ?? design.Name, design);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"Could not create folder structure for design {design.Name} at path {design.Path.Folder}: {ex}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Utility;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Events;
|
||||
|
|
@ -21,7 +22,7 @@ public sealed class DesignManager : DesignEditor
|
|||
private readonly HumanModelList _humans;
|
||||
|
||||
public DesignManager(SaveService saveService, ItemManager items, CustomizeService customizations,
|
||||
DesignChanged @event, HumanModelList humans, DesignStorage storage, DesignLinkLoader designLinkLoader, Configuration.Configuration config)
|
||||
DesignChanged @event, HumanModelList humans, DesignStorage storage, DesignLinkLoader designLinkLoader, Configuration config)
|
||||
: base(saveService, @event, customizations, items, config)
|
||||
{
|
||||
Designs = storage;
|
||||
|
|
@ -545,7 +546,6 @@ public sealed class DesignManager : DesignEditor
|
|||
}
|
||||
}
|
||||
|
||||
DesignFileSystem.MigrateOldPaths(SaveService, migratedFileSystemPaths);
|
||||
Glamourer.Log.Information(
|
||||
$"Successfully migrated {successes} old designs. Skipped {skips} already migrated designs. Failed to migrate {errors} designs.");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.Services;
|
||||
|
|
@ -15,7 +16,7 @@ namespace Glamourer.Designs.Links;
|
|||
public class DesignMerger(
|
||||
DesignManager designManager,
|
||||
CustomizeService customizeService,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
ItemUnlockManager itemUnlocks,
|
||||
CustomizeUnlockManager customizeUnlocks) : IService
|
||||
{
|
||||
|
|
|
|||
99
Glamourer/Designs/SortMode.cs
Normal file
99
Glamourer/Designs/SortMode.cs
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
using System.Collections.Frozen;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Designs;
|
||||
|
||||
public readonly struct CreationDate : ISortMode
|
||||
{
|
||||
public static readonly CreationDate Instance = new();
|
||||
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Older First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their creation date."u8;
|
||||
|
||||
public IEnumerable<IFileSystemNode> GetChildren(IFileSystemFolder f)
|
||||
=> f.GetSubFolders().Cast<IFileSystemNode>().Concat(f.GetLeaves().OfType<IFileSystemData<Design>>().OrderBy(l => l.Value.CreationDate));
|
||||
}
|
||||
|
||||
public readonly struct UpdateDate : ISortMode
|
||||
{
|
||||
public static readonly UpdateDate Instance = new();
|
||||
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Older First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their last update date."u8;
|
||||
|
||||
public IEnumerable<IFileSystemNode> GetChildren(IFileSystemFolder f)
|
||||
=> f.GetSubFolders().Cast<IFileSystemNode>().Concat(f.GetLeaves().OfType<IFileSystemData<Design>>().OrderBy(l => l.Value.LastEdit));
|
||||
}
|
||||
|
||||
public readonly struct InverseCreationDate : ISortMode
|
||||
{
|
||||
public static readonly InverseCreationDate Instance = new();
|
||||
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Creation Date (Newer First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse creation date."u8;
|
||||
|
||||
public IEnumerable<IFileSystemNode> GetChildren(IFileSystemFolder f)
|
||||
=> f.GetSubFolders().Cast<IFileSystemNode>()
|
||||
.Concat(f.GetLeaves().OfType<IFileSystemData<Design>>().OrderByDescending(l => l.Value.CreationDate));
|
||||
}
|
||||
|
||||
public readonly struct InverseUpdateDate : ISortMode
|
||||
{
|
||||
public static readonly InverseUpdateDate Instance = new();
|
||||
|
||||
public ReadOnlySpan<byte> Name
|
||||
=> "Update Date (Newer First)"u8;
|
||||
|
||||
public ReadOnlySpan<byte> Description
|
||||
=> "In each folder, sort all subfolders lexicographically, then sort all leaves using their inverse last update date."u8;
|
||||
|
||||
public IEnumerable<IFileSystemNode> GetChildren(IFileSystemFolder f)
|
||||
=> f.GetSubFolders().Cast<IFileSystemNode>()
|
||||
.Concat(f.GetLeaves().OfType<IFileSystemData<Design>>().OrderByDescending(l => l.Value.LastEdit));
|
||||
}
|
||||
|
||||
public static class SortModeExtensions
|
||||
{
|
||||
private static readonly FrozenDictionary<string, ISortMode> ValidSortModes = new Dictionary<string, ISortMode>
|
||||
{
|
||||
[nameof(ISortMode.FoldersFirst)] = ISortMode.FoldersFirst,
|
||||
[nameof(ISortMode.Lexicographical)] = ISortMode.Lexicographical,
|
||||
[nameof(CreationDate)] = ISortMode.CreationDate,
|
||||
[nameof(InverseCreationDate)] = ISortMode.InverseCreationDate,
|
||||
[nameof(UpdateDate)] = ISortMode.UpdateDate,
|
||||
[nameof(InverseUpdateDate)] = ISortMode.InverseUpdateDate,
|
||||
[nameof(ISortMode.InverseFoldersFirst)] = ISortMode.InverseFoldersFirst,
|
||||
[nameof(ISortMode.InverseLexicographical)] = ISortMode.InverseLexicographical,
|
||||
[nameof(ISortMode.FoldersLast)] = ISortMode.FoldersLast,
|
||||
[nameof(ISortMode.InverseFoldersLast)] = ISortMode.InverseFoldersLast,
|
||||
[nameof(ISortMode.InternalOrder)] = ISortMode.InternalOrder,
|
||||
[nameof(ISortMode.InverseInternalOrder)] = ISortMode.InverseInternalOrder,
|
||||
}.ToFrozenDictionary();
|
||||
|
||||
extension(ISortMode)
|
||||
{
|
||||
public static ISortMode CreationDate
|
||||
=> CreationDate.Instance;
|
||||
|
||||
public static ISortMode InverseCreationDate
|
||||
=> InverseCreationDate.Instance;
|
||||
|
||||
public static ISortMode UpdateDate
|
||||
=> UpdateDate.Instance;
|
||||
|
||||
public static ISortMode InverseUpdateDate
|
||||
=> InverseUpdateDate.Instance;
|
||||
|
||||
public static IReadOnlyDictionary<string, ISortMode> Valid
|
||||
=> ValidSortModes;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
|
||||
using Glamourer.Config;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Designs.Special;
|
||||
|
||||
public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileSystem, Configuration.Configuration config) : IService
|
||||
public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileSystem, Configuration config) : IService
|
||||
{
|
||||
private readonly Random _rng = new();
|
||||
private readonly WeakReference<Design> _lastDesign = new(null!, false);
|
||||
|
|
|
|||
|
|
@ -10,19 +10,19 @@ public interface IDesignPredicate
|
|||
=> Invoke(args.Design, args.LowerName, args.Identifier, args.LowerPath);
|
||||
|
||||
public IEnumerable<Design> Get(IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
||||
=> designs.Select(d => Transform(d, fileSystem))
|
||||
=> designs.Select(Transform)
|
||||
.Where(Invoke)
|
||||
.Select(t => t.Design);
|
||||
|
||||
public static IEnumerable<Design> Get(IReadOnlyList<IDesignPredicate> predicates, IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
||||
=> predicates.Count > 0
|
||||
? designs.Select(d => Transform(d, fileSystem))
|
||||
? designs.Select(Transform)
|
||||
.Where(t => predicates.Any(p => p.Invoke(t)))
|
||||
.Select(t => t.Design)
|
||||
: designs;
|
||||
|
||||
private static (Design Design, string LowerName, string Identifier, string LowerPath) Transform(Design d, DesignFileSystem fs)
|
||||
=> (d, d.Name.Lower, d.Identifier.ToString(), fs.TryGetValue(d, out var l) ? l.FullName().ToLowerInvariant() : string.Empty);
|
||||
private static (Design Design, string LowerName, string Identifier, string LowerPath) Transform(Design d)
|
||||
=> (d, d.Name.Lower, d.Identifier.ToString(), d.Path.CurrentPath.ToLowerInvariant());
|
||||
}
|
||||
|
||||
public static class RandomPredicate
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Gui.Tabs.DesignTab;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
@ -135,10 +136,13 @@ public sealed class DesignChanged()
|
|||
/// <seealso cref="Automation.AutoDesignManager.OnDesignChange"/>
|
||||
AutoDesignManager = 1,
|
||||
|
||||
/// <seealso cref="DesignFileSystem.OnDesignChange"/>
|
||||
/// <seealso cref="DesignFileSystem.OnDesignChanged"/>
|
||||
DesignFileSystem = 0,
|
||||
|
||||
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnDesignChange"/>
|
||||
/// <seealso cref="DesignHeader.OnDesignChanged"/>
|
||||
DesignHeader = 0,
|
||||
|
||||
/// <seealso cref="DesignFileSystemDrawer.OnDesignChanged"/>
|
||||
DesignFileSystemSelector = -1,
|
||||
|
||||
/// <seealso cref="DesignComboBase.OnDesignChanged"/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Gui.Tabs.DesignTab;
|
||||
using OtterGui.Classes;
|
||||
|
||||
namespace Glamourer.Events;
|
||||
|
|
@ -16,7 +17,7 @@ public sealed class TabSelected()
|
|||
{
|
||||
public enum Priority
|
||||
{
|
||||
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnTabSelected"/>
|
||||
/// <seealso cref="DesignFileSystemDrawer.OnTabSelected"/>
|
||||
DesignSelector = 0,
|
||||
|
||||
/// <seealso cref="Gui.MainWindow.OnTabSelected"/>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Plugin;
|
||||
using Glamourer.Api;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
|
|
@ -61,7 +62,7 @@ public class Glamourer : IDalamudPlugin
|
|||
public string GatherSupportInformation()
|
||||
{
|
||||
var sb = new StringBuilder(10240);
|
||||
var config = _services.GetService<Configuration.Configuration>();
|
||||
var config = _services.GetService<Configuration>();
|
||||
sb.AppendLine("**Settings**");
|
||||
sb.Append($"> **`Plugin Version: `** {Version}\n");
|
||||
sb.Append($"> **`Commit Hash: `** {CommitHash}\n");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
<Project Sdk="Dalamud.NET.Sdk/14.0.1">
|
||||
<Project Sdk="Dalamud.NET.Sdk/14.0.2">
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Glamourer</RootNamespace>
|
||||
<AssemblyName>Glamourer</AssemblyName>
|
||||
|
|
@ -22,6 +22,11 @@
|
|||
<EmbeddedResource Include="LegacyTattoo.raw" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<Use_DalamudPackager>false</Use_DalamudPackager>
|
||||
<Use_Dalamud_ImGui>false</Use_Dalamud_ImGui>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Glamourer.Api\Glamourer.Api.csproj" />
|
||||
<ProjectReference Include="..\Luna\Luna\Luna.csproj" />
|
||||
|
|
@ -31,7 +36,8 @@
|
|||
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
<PackageReference Include="Vortice.Direct3D11" Version="3.4.2-beta" />
|
||||
|
||||
<ProjectReference Include="..\Luna\Luna.Generators\Luna.Generators.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
|
||||
<ProjectReference Include="..\Luna\Luna.Generators\Luna.Generators.csproj" OutputItemType="Analyzer"
|
||||
ReferenceOutputAssembly="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
@ -50,7 +56,8 @@
|
|||
</ItemGroup>
|
||||
|
||||
<Target Name="GetGitHash" BeforeTargets="GetAssemblyVersion" Returns="InformationalVersion">
|
||||
<Exec Command="git rev-parse --short HEAD" ConsoleToMSBuild="true" StandardOutputImportance="low" ContinueOnError="true">
|
||||
<Exec Command="git rev-parse --short HEAD" ConsoleToMSBuild="true" StandardOutputImportance="low"
|
||||
ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="GitCommitHashSuccess" />
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" Condition="$(GitCommitHashSuccess) == 0" />
|
||||
</Exec>
|
||||
|
|
|
|||
2
Glamourer/Glamourer.csproj.DotSettings
Normal file
2
Glamourer/Glamourer.csproj.DotSettings
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=gui_005Ctabs_005Cdesigntab_005Cselector/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
|
@ -83,6 +84,6 @@ public static class Colors
|
|||
=> _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor;
|
||||
|
||||
/// <summary> Set the configurable colors dictionary to a value. </summary>
|
||||
public static void SetColors(Configuration.Configuration config)
|
||||
public static void SetColors(Configuration config)
|
||||
=> _colors = config.Colors;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using System.Text.Unicode;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Interface.Textures;
|
||||
using Dalamud.Interface.Textures.TextureWraps;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
|
|
@ -14,7 +15,7 @@ namespace Glamourer.Gui.Customization;
|
|||
public partial class CustomizationDrawer(
|
||||
ITextureProvider textures,
|
||||
CustomizeService service,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
FavoriteManager favorites,
|
||||
HeightService heightService)
|
||||
: IDisposable
|
||||
|
|
@ -81,7 +82,7 @@ public partial class CustomizationDrawer(
|
|||
private CustomizeValue _currentByte = CustomizeValue.Zero;
|
||||
private bool _currentApply;
|
||||
private int _currentCount;
|
||||
private StringU8 _currentOption = StringU8.Empty;
|
||||
private StringU8 _currentOption = StringU8.Empty;
|
||||
|
||||
// Prepare a new customization option.
|
||||
private Im.IdDisposable SetId(CustomizeIndex index)
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop.PalettePlus;
|
||||
using Glamourer.State;
|
||||
|
|
@ -7,7 +8,7 @@ using Luna;
|
|||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
public class CustomizeParameterDrawer(Configuration.Configuration config, PaletteImport import) : IService
|
||||
public class CustomizeParameterDrawer(Configuration config, PaletteImport import) : IService
|
||||
{
|
||||
private readonly Dictionary<Design, CustomizeParameterData> _lastData = [];
|
||||
private StringU8 _paletteName = StringU8.Empty;
|
||||
|
|
@ -125,7 +126,7 @@ public class CustomizeParameterDrawer(Configuration.Configuration config, Palett
|
|||
DrawColorFormatOptions(withApply);
|
||||
var value = config.ShowColorConfig;
|
||||
Im.Line.Same();
|
||||
if (Im.Checkbox("Show Config"u8, ref value))
|
||||
if (Im.Checkbox("Show Configuration"u8, ref value))
|
||||
{
|
||||
config.ShowColorConfig = value;
|
||||
config.Save();
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ using Luna;
|
|||
namespace Glamourer.Gui;
|
||||
|
||||
public abstract class DesignComboBase(
|
||||
Configuration.EphemeralConfig config,
|
||||
Config.EphemeralConfig config,
|
||||
DesignManager designs,
|
||||
DesignChanged designChanged,
|
||||
DesignColors designColors,
|
||||
|
|
@ -17,18 +17,18 @@ public abstract class DesignComboBase(
|
|||
DesignFileSystem designFileSystem)
|
||||
: FilterComboBase<DesignComboBase.CacheItem>(new DesignFilter(), ConfigData.Default with { ComputeWidth = true })
|
||||
{
|
||||
protected readonly Configuration.EphemeralConfig Config = config;
|
||||
protected readonly DesignChanged DesignChanged = designChanged;
|
||||
protected readonly DesignColors DesignColors = designColors;
|
||||
protected readonly DesignFileSystem DesignFileSystem = designFileSystem;
|
||||
protected readonly TabSelected TabSelected = tabSelected;
|
||||
protected readonly DesignManager Designs = designs;
|
||||
protected IDesignStandIn? CurrentDesign;
|
||||
protected readonly Config.EphemeralConfig Config = config;
|
||||
protected readonly DesignChanged DesignChanged = designChanged;
|
||||
protected readonly DesignColors DesignColors = designColors;
|
||||
protected readonly DesignFileSystem DesignFileSystem = designFileSystem;
|
||||
protected readonly TabSelected TabSelected = tabSelected;
|
||||
protected readonly DesignManager Designs = designs;
|
||||
protected IDesignStandIn? CurrentDesign;
|
||||
|
||||
protected CacheItem CreateItem(IDesignStandIn design)
|
||||
{
|
||||
var color = design is Design d1 ? DesignColors.GetColor(d1).ToVector() : ColorId.NormalDesign.Value().ToVector();
|
||||
var path = design is Design d2 && DesignFileSystem.TryGetValue(d2, out var leaf) ? leaf.FullName() : string.Empty;
|
||||
var path = design is Design d2 ? d2.Node!.FullPath : string.Empty;
|
||||
var name = design.ResolveName(false);
|
||||
if (path == name)
|
||||
path = string.Empty;
|
||||
|
|
@ -118,7 +118,10 @@ public abstract class DesignComboBase(
|
|||
|
||||
protected override void ComputeWidth()
|
||||
=> ComboWidth = UnfilteredItems.Max(d
|
||||
=> d.Name.Utf8.CalculateSize(false).X + d.FullPath.Utf8.CalculateSize(false).X + 2 * Im.Style.ItemSpacing.X + Im.Style.ScrollbarSize);
|
||||
=> d.Name.Utf8.CalculateSize(false).X
|
||||
+ d.FullPath.Utf8.CalculateSize(false).X
|
||||
+ 2 * Im.Style.ItemSpacing.X
|
||||
+ Im.Style.ScrollbarSize);
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
|
|
@ -203,7 +206,7 @@ public sealed class QuickDesignCombo : DesignComboBase, IDisposable, IUiService
|
|||
}
|
||||
|
||||
|
||||
public QuickDesignCombo(Configuration.EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||
public QuickDesignCombo(Config.EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||
DesignFileSystem designFileSystem, DesignManager designs)
|
||||
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||
{
|
||||
|
|
@ -264,7 +267,7 @@ public sealed class LinkDesignCombo : DesignComboBase, IUiService, IDisposable
|
|||
{
|
||||
public Design? NewSelection { get; private set; }
|
||||
|
||||
public LinkDesignCombo(Configuration.EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||
public LinkDesignCombo(Config.EphemeralConfig config, DesignChanged designChanged, DesignColors designColors, TabSelected tabSelected,
|
||||
DesignFileSystem designFileSystem, DesignManager designs)
|
||||
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||
{
|
||||
|
|
@ -295,7 +298,7 @@ public sealed class LinkDesignCombo : DesignComboBase, IUiService, IDisposable
|
|||
}
|
||||
|
||||
public sealed class RandomDesignCombo(
|
||||
Configuration.EphemeralConfig config,
|
||||
Config.EphemeralConfig config,
|
||||
DesignManager designs,
|
||||
DesignChanged designChanged,
|
||||
DesignColors designColors,
|
||||
|
|
@ -307,14 +310,10 @@ public sealed class RandomDesignCombo(
|
|||
{
|
||||
return exact.Which switch
|
||||
{
|
||||
RandomPredicate.Exact.Type.Name => Designs.Designs.FirstOrDefault(d => d.Name == exact.Value),
|
||||
RandomPredicate.Exact.Type.Path => DesignFileSystem.Find(exact.Value.Text, out var c) && c is DesignFileSystem.Leaf l
|
||||
? l.Value
|
||||
: null,
|
||||
RandomPredicate.Exact.Type.Identifier => Designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g)
|
||||
? g
|
||||
: Guid.Empty),
|
||||
_ => null,
|
||||
RandomPredicate.Exact.Type.Name => Designs.Designs.FirstOrDefault(d => d.Name == exact.Value),
|
||||
RandomPredicate.Exact.Type.Path => Designs.Designs.FirstOrDefault(d => d.Node!.FullPath == exact.Value.Text),
|
||||
RandomPredicate.Exact.Type.Identifier => Designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g) ? g : Guid.Empty),
|
||||
_ => null,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -346,7 +345,7 @@ public sealed class SpecialDesignCombo : DesignComboBase, IUiService
|
|||
private readonly CacheItem _revert;
|
||||
private readonly CacheItem _quick;
|
||||
|
||||
public SpecialDesignCombo(Configuration.EphemeralConfig config,
|
||||
public SpecialDesignCombo(Config.EphemeralConfig config,
|
||||
DesignManager designs,
|
||||
DesignChanged designChanged,
|
||||
DesignColors designColors,
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
|
|
@ -33,19 +34,19 @@ public sealed class DesignQuickBar : Window, IDisposable
|
|||
? WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing | WindowFlags.NoMove
|
||||
: WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing;
|
||||
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly QuickDesignCombo _designCombo;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly IKeyState _keyState;
|
||||
private readonly Im.ColorStyleDisposable _style = new();
|
||||
private DateTime _keyboardToggle = DateTime.UnixEpoch;
|
||||
private int _numButtons;
|
||||
private readonly StringBuilder _tooltipBuilder = new(512);
|
||||
private readonly Configuration _config;
|
||||
private readonly QuickDesignCombo _designCombo;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly IKeyState _keyState;
|
||||
private readonly Im.ColorStyleDisposable _style = new();
|
||||
private DateTime _keyboardToggle = DateTime.UnixEpoch;
|
||||
private int _numButtons;
|
||||
private readonly StringBuilder _tooltipBuilder = new(512);
|
||||
|
||||
public DesignQuickBar(Configuration.Configuration config, QuickDesignCombo designCombo, StateManager stateManager, IKeyState keyState,
|
||||
public DesignQuickBar(Configuration config, QuickDesignCombo designCombo, StateManager stateManager, IKeyState keyState,
|
||||
ActorObjectManager objects, AutoDesignApplier autoDesignApplier, PenumbraService penumbra)
|
||||
: base("Glamourer Quick Bar", WindowFlags.NoDecoration | WindowFlags.NoDocking)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Gui.Materials;
|
||||
using Glamourer.Services;
|
||||
|
|
@ -22,7 +23,7 @@ public class EquipmentDrawer
|
|||
private readonly BonusItemCombo[] _bonusItemCombo;
|
||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||
private readonly TextureService _textures;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly Configuration _config;
|
||||
private readonly GPoseService _gPose;
|
||||
private readonly AdvancedDyePopup _advancedDyes;
|
||||
private readonly ItemCopyService _itemCopy;
|
||||
|
|
@ -32,7 +33,7 @@ public class EquipmentDrawer
|
|||
private EquipSlot _dragTarget;
|
||||
|
||||
public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, TextureService textures,
|
||||
Configuration.Configuration config, GPoseService gPose, AdvancedDyePopup advancedDyes, ItemCopyService itemCopy)
|
||||
Configuration config, GPoseService gPose, AdvancedDyePopup advancedDyes, ItemCopyService itemCopy)
|
||||
{
|
||||
_items = items;
|
||||
_textures = textures;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,18 @@
|
|||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
public class GenericPopupWindow : Luna.Window
|
||||
{
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IClientState _state;
|
||||
public bool OpenFestivalPopup { get; internal set; }
|
||||
private readonly Configuration _config;
|
||||
private readonly ICondition _condition;
|
||||
private readonly IClientState _state;
|
||||
public bool OpenFestivalPopup { get; internal set; }
|
||||
|
||||
public GenericPopupWindow(Configuration.Configuration config, IClientState state, ICondition condition)
|
||||
public GenericPopupWindow(Configuration config, IClientState state, ICondition condition)
|
||||
: base("Glamourer Popups",
|
||||
WindowFlags.NoBringToFrontOnFocus
|
||||
| WindowFlags.NoDecoration
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
|
|
@ -5,11 +6,11 @@ namespace Glamourer.Gui;
|
|||
|
||||
public class GlamourerChangelog
|
||||
{
|
||||
public const int LastChangelogVersion = 0;
|
||||
private readonly Configuration.Configuration _config;
|
||||
public readonly Changelog Changelog;
|
||||
public const int LastChangelogVersion = 0;
|
||||
private readonly Configuration _config;
|
||||
public readonly Changelog Changelog;
|
||||
|
||||
public GlamourerChangelog(Configuration.Configuration config)
|
||||
public GlamourerChangelog(Configuration config)
|
||||
{
|
||||
_config = config;
|
||||
Changelog = new Changelog("Glamourer Changelog", ConfigData, Save);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Windowing;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Gui.Tabs.UnlocksTab;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
|
@ -11,7 +12,7 @@ public class GlamourerWindowSystem : IDisposable
|
|||
private readonly MainWindow _ui;
|
||||
|
||||
public GlamourerWindowSystem(IUiBuilder uiBuilder, MainWindow ui, GenericPopupWindow popups,
|
||||
Configuration.Configuration config, UnlocksTab unlocksTab, GlamourerChangelog changelog, DesignQuickBar quick)
|
||||
Configuration config, UnlocksTab unlocksTab, GlamourerChangelog changelog, DesignQuickBar quick)
|
||||
{
|
||||
_uiBuilder = uiBuilder;
|
||||
_ui = ui;
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@ namespace Glamourer.Gui;
|
|||
|
||||
public sealed class MainTabBar : TabBar<MainTabType>
|
||||
{
|
||||
private readonly Configuration.EphemeralConfig _config;
|
||||
private readonly Config.EphemeralConfig _config;
|
||||
public readonly TabSelected Event;
|
||||
public readonly SettingsTab Settings;
|
||||
|
||||
public MainTabBar(Logger log, Configuration.EphemeralConfig config, SettingsTab settings, ActorTab actors, DesignTab designs,
|
||||
public MainTabBar(Logger log, Config.EphemeralConfig config, SettingsTab settings, ActorTab actors, DesignTab designs,
|
||||
AutomationTab automation, UnlocksTab unlocks, NpcTab npcs, MessagesTab messages, DebugTab debug, TabSelected @event)
|
||||
: base("MainTabBar", log, settings, actors, designs, automation, unlocks, npcs, messages, debug)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
|
@ -8,20 +9,20 @@ namespace Glamourer.Gui;
|
|||
|
||||
public sealed class MainWindow : Window, IDisposable
|
||||
{
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly DesignQuickBar _quickBar;
|
||||
private readonly MainTabBar _mainTabBar;
|
||||
private bool _ignorePenumbra;
|
||||
private readonly Configuration _config;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly DesignQuickBar _quickBar;
|
||||
private readonly MainTabBar _mainTabBar;
|
||||
private bool _ignorePenumbra;
|
||||
|
||||
public MainWindow(IDalamudPluginInterface pi, Configuration.Configuration config, PenumbraService penumbra,
|
||||
public MainWindow(IDalamudPluginInterface pi, Configuration config, PenumbraService penumbra,
|
||||
MainTabBar mainTabBar, DesignQuickBar quickBar)
|
||||
: base("GlamourerMainWindow")
|
||||
{
|
||||
pi.UiBuilder.DisableGposeUiHide = true;
|
||||
SizeConstraints = new WindowSizeConstraints
|
||||
{
|
||||
MinimumSize = new Vector2(700, 675),
|
||||
MinimumSize = new Vector2(700, 675),
|
||||
MaximumSize = new Vector2(3840, 2160),
|
||||
};
|
||||
_mainTabBar = mainTabBar;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using Glamourer.State;
|
||||
|
|
@ -17,7 +17,7 @@ using Notification = Luna.Notification;
|
|||
namespace Glamourer.Gui.Materials;
|
||||
|
||||
public sealed unsafe class AdvancedDyePopup(
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
StateManager stateManager,
|
||||
LiveColorTablePreviewer preview,
|
||||
DirectXService directX) : IService
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
|
@ -7,7 +8,7 @@ using Penumbra.GameData.Files.MaterialStructs;
|
|||
|
||||
namespace Glamourer.Gui.Materials;
|
||||
|
||||
public class MaterialDrawer(DesignManager designManager, Configuration.Configuration config) : IService
|
||||
public class MaterialDrawer(DesignManager designManager, Configuration config) : IService
|
||||
{
|
||||
public const float GlossWidth = 100;
|
||||
public const float SpecularStrengthWidth = 125;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Gui.Customization;
|
||||
|
|
@ -25,7 +25,7 @@ public sealed class ActorPanel : IPanel
|
|||
private readonly CustomizationDrawer _customizationDrawer;
|
||||
private readonly EquipmentDrawer _equipmentDrawer;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly Configuration _config;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly ImportService _importService;
|
||||
|
|
@ -37,7 +37,7 @@ public sealed class ActorPanel : IPanel
|
|||
CustomizationDrawer customizationDrawer,
|
||||
EquipmentDrawer equipmentDrawer,
|
||||
AutoDesignApplier autoDesignApplier,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
DesignConverter converter,
|
||||
ActorObjectManager objects,
|
||||
DesignManager designManager,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public readonly struct ActorCacheItem(ActorIdentifier identifier, ActorData data
|
|||
public readonly StringU8 IncognitoText = new(identifier.Incognito(data.Label));
|
||||
}
|
||||
|
||||
public sealed class ActorSelector(ActorSelection selection, ActorObjectManager objects, ActorFilter filter, PenumbraService penumbra, Configuration.EphemeralConfig config) : IPanel
|
||||
public sealed class ActorSelector(ActorSelection selection, ActorObjectManager objects, ActorFilter filter, PenumbraService penumbra, Config.EphemeralConfig config) : IPanel
|
||||
{
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "ActorSelector"u8;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,10 +6,10 @@ namespace Glamourer.Gui.Tabs.ActorTab;
|
|||
public sealed class ActorsHeader : SplitButtonHeader
|
||||
{
|
||||
private readonly ActorSelection _selection;
|
||||
private readonly Configuration.EphemeralConfig _config;
|
||||
private readonly Config.EphemeralConfig _config;
|
||||
|
||||
public ActorsHeader(SetFromClipboardButton setFromClipboard, ExportToClipboardButton exportToClipboard, SaveAsDesignButton save,
|
||||
UndoButton undo, LockedButton locked, IncognitoButton incognito, ActorSelection selection, Configuration.EphemeralConfig config)
|
||||
UndoButton undo, LockedButton locked, IncognitoButton incognito, ActorSelection selection, Config.EphemeralConfig config)
|
||||
{
|
||||
_selection = selection;
|
||||
_config = config;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
|
@ -10,7 +11,7 @@ namespace Glamourer.Gui.Tabs.AutomationTab;
|
|||
|
||||
public sealed class AutomationButtons : ButtonFooter
|
||||
{
|
||||
public AutomationButtons(Configuration.Configuration config, AutoDesignManager manager, AutomationSelection selection, ActorObjectManager objects)
|
||||
public AutomationButtons(Configuration config, AutoDesignManager manager, AutomationSelection selection, ActorObjectManager objects)
|
||||
{
|
||||
Buttons.AddButton(new AddButton(objects, manager), 100);
|
||||
Buttons.AddButton(new DuplicateButton(selection, manager), 90);
|
||||
|
|
@ -134,7 +135,7 @@ public sealed class AutomationButtons : ButtonFooter
|
|||
}
|
||||
}
|
||||
|
||||
private sealed class DeleteButton(AutomationSelection selection, Configuration.Configuration config, AutoDesignManager manager)
|
||||
private sealed class DeleteButton(AutomationSelection selection, Configuration config, AutoDesignManager manager)
|
||||
: BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private bool _enabled;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,28 @@
|
|||
using ImSharp;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public sealed class AutomationHeader(Configuration.Configuration config, AutomationSelection selection) : IHeader
|
||||
public sealed class AutomationHeader : SplitButtonHeader
|
||||
{
|
||||
public bool Collapsed
|
||||
=> false;
|
||||
private readonly Configuration _config;
|
||||
private readonly AutomationSelection _selection;
|
||||
|
||||
public void Draw(Vector2 size)
|
||||
=> ImEx.TextFramed(config.Ephemeral.IncognitoMode ? selection.Incognito : selection.Name, size with { Y = Im.Style.FrameHeight });
|
||||
public AutomationHeader(Configuration config, AutomationSelection selection, IncognitoButton incognito)
|
||||
{
|
||||
_config = config;
|
||||
_selection = selection;
|
||||
RightButtons.AddButton(incognito, 100);
|
||||
}
|
||||
|
||||
public override void Draw(Vector2 size)
|
||||
{
|
||||
var color = ColorId.HeaderButtons.Value();
|
||||
using var _ = ImGuiColor.Text.Push(color).Push(ImGuiColor.Border, color);
|
||||
base.Draw(size with { Y = Im.Style.FrameHeight });
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Text
|
||||
=> _config.Ephemeral.IncognitoMode ? _selection.Incognito : _selection.Name;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
using ImSharp;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public class AutomationTab : TwoPanelLayout, ITab<MainTabType>
|
||||
{
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly Configuration _config;
|
||||
|
||||
public AutomationTab(AutomationFilter filter, SetSelector selector, SetPanel panel, AutomationButtons buttons, AutomationHeader header,
|
||||
Configuration.Configuration config)
|
||||
Configuration config)
|
||||
{
|
||||
_config = config;
|
||||
LeftHeader = new FilterHeader<AutomationCacheItem>(filter, new StringU8("Filter..."u8));
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.Events;
|
||||
|
|
@ -13,19 +14,19 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
private AutoDesignSet? _set;
|
||||
private int _designIndex = -1;
|
||||
|
||||
private readonly AutomationChanged _automationChanged;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly AutoDesignManager _autoDesignManager;
|
||||
private readonly RandomDesignCombo _randomDesignCombo;
|
||||
private readonly AutomationSelection _selection;
|
||||
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.Configuration config, AutoDesignManager autoDesignManager,
|
||||
public RandomRestrictionDrawer(AutomationChanged automationChanged, Configuration config, AutoDesignManager autoDesignManager,
|
||||
RandomDesignCombo randomDesignCombo, AutomationSelection selection, DesignFileSystem designFileSystem, DesignStorage designs)
|
||||
{
|
||||
_automationChanged = automationChanged;
|
||||
|
|
@ -268,19 +269,19 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
|||
LookupTooltip(designs);
|
||||
}
|
||||
|
||||
private void LookupTooltip(IEnumerable<Design> designs)
|
||||
private static void LookupTooltip(IEnumerable<Design> designs)
|
||||
{
|
||||
using var _ = Im.Tooltip.Begin();
|
||||
using var enumerator = designs.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
Im.Text("Matches the following designs:"u8);
|
||||
var name = _designFileSystem.TryGetValue(enumerator.Current, out var l) ? l.FullName() : enumerator.Current.Name.Text;
|
||||
var name = enumerator.Current.Path.CurrentPath;
|
||||
Im.Separator();
|
||||
Im.BulletText(name);
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
name = _designFileSystem.TryGetValue(enumerator.Current, out l) ? l.FullName() : enumerator.Current.Name.Text;
|
||||
name = enumerator.Current.Path.CurrentPath;
|
||||
Im.BulletText(name);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Glamourer.Designs.Special;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -19,7 +20,7 @@ public class SetPanel(
|
|||
CustomizeUnlockManager customizeUnlocks,
|
||||
CustomizeService customizations,
|
||||
IdentifierDrawer identifierDrawer,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
RandomRestrictionDrawer randomDrawer,
|
||||
AutomationSelection selection) : IPanel
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Events;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
|
@ -8,7 +9,7 @@ namespace Glamourer.Gui.Tabs.AutomationTab;
|
|||
|
||||
public sealed class SetSelector(
|
||||
AutomationSelection selection,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
AutoDesignManager manager,
|
||||
AutomationFilter filter,
|
||||
ActorObjectManager objects,
|
||||
|
|
@ -54,7 +55,8 @@ public sealed class SetSelector(
|
|||
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.Cursor.Position = new Vector2(Im.ContentRegion.Available.X - textSize.X - Im.Style.FramePadding.X,
|
||||
Im.Cursor.Y - Im.Style.TextHeightWithSpacing);
|
||||
Im.Text(identifier, textColor);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
using ImSharp;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public sealed class DebugTab(ServiceManager manager) : ITab<MainTabType>
|
||||
{
|
||||
private readonly Configuration.Configuration _config = manager.GetService<Configuration.Configuration>();
|
||||
private readonly Configuration _config = manager.GetService<Configuration>();
|
||||
|
||||
public bool IsVisible
|
||||
=> _config.DebugMode;
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ public sealed class DesignConverterPanel(DesignConverter designConverter) : IGam
|
|||
Im.Text("JSON Parsing Successful!"u8);
|
||||
|
||||
if (_tmpDesign is not null)
|
||||
DesignManagerPanel.DrawDesign(_tmpDesign, null);
|
||||
DesignManagerPanel.DrawDesign(_tmpDesign);
|
||||
|
||||
if (_clipboardProblem.Length > 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
|||
if (!t)
|
||||
continue;
|
||||
|
||||
DrawDesign(design, designFileSystem);
|
||||
DrawDesign(design);
|
||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize,
|
||||
design.Application.Meta,
|
||||
design.WriteProtected());
|
||||
|
|
@ -50,12 +50,12 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
|||
var designs = designManager.Designs.Where(d => d.Tags.Contains("_DebugTest")).ToArray();
|
||||
foreach (var design in designs)
|
||||
designManager.Delete(design);
|
||||
if (designFileSystem.Find("Test Designs", out var path) && path is DesignFileSystem.Folder { TotalChildren: 0 })
|
||||
if (designFileSystem.Find("Test Designs", out var path) && path is IFileSystemFolder { TotalDescendants: 0 })
|
||||
designFileSystem.Delete(path);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawDesign(DesignBase design, DesignFileSystem? fileSystem)
|
||||
public static void DrawDesign(DesignBase design)
|
||||
{
|
||||
using var table = Im.Table.Begin("##equip"u8, 8, TableFlags.RowBackground | TableFlags.SizingFixedFit);
|
||||
if (design is Design d)
|
||||
|
|
@ -70,8 +70,7 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
|||
table.DrawDataPair("Identifier"u8, d.Identifier);
|
||||
table.NextRow();
|
||||
table.DrawColumn("Design File System Path"u8);
|
||||
if (fileSystem is not null)
|
||||
table.DrawColumn(fileSystem.TryGetValue(d, out var leaf) ? leaf.FullName() : "No Path Known"u8);
|
||||
table.DrawColumn(d.Path.CurrentPath);
|
||||
table.NextRow();
|
||||
|
||||
table.DrawDataPair("Creation"u8, d.CreationDate);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
using Glamourer.State;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Penumbra.GameData.Gui.Debug;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
public sealed class FunPanel(FunModule funModule, Configuration.Configuration config) : IGameDataDrawer
|
||||
public sealed class FunPanel(FunModule funModule, Configuration config) : IGameDataDrawer
|
||||
{
|
||||
public ReadOnlySpan<byte> Label
|
||||
=> "Fun Module"u8;
|
||||
|
|
|
|||
55
Glamourer/Gui/Tabs/DesignTab/ApplyCharacterButton.cs
Normal file
55
Glamourer/Gui/Tabs/DesignTab/ApplyCharacterButton.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class ApplyCharacterButton(
|
||||
DesignFileSystem fileSystem,
|
||||
DesignManager manager,
|
||||
ActorObjectManager objects,
|
||||
StateManager stateManager,
|
||||
DesignConverter converter) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private static readonly AwesomeIcon UserIcon = FontAwesomeIcon.UserEdit;
|
||||
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null && objects.Player.Valid;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> UserIcon;
|
||||
|
||||
public override bool Enabled
|
||||
=> !((Design)fileSystem.Selection.Selection!.Value).WriteProtected();
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Overwrite this design with your character's current state."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
var selection = (Design)fileSystem.Selection.Selection!.Value;
|
||||
try
|
||||
{
|
||||
var (player, actor) = objects.PlayerData;
|
||||
if (!player.IsValid || !actor.Valid || !stateManager.GetOrCreate(player, actor.Objects[0], out var state))
|
||||
throw new Exception("No player state available.");
|
||||
|
||||
var design = converter.Convert(state, ApplicationRules.FromModifiers(state))
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
selection.GetMaterialDataRef().Clear();
|
||||
manager.ApplyDesign(selection, design);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply player state to {selection.Name}.",
|
||||
$"Could not apply player state to design {selection.Identifier}", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using ImSharp;
|
||||
|
|
@ -9,21 +9,19 @@ namespace Glamourer.Gui.Tabs.DesignTab;
|
|||
|
||||
public class DesignDetailTab
|
||||
{
|
||||
private readonly SaveService _saveService;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly DesignFileSystemSelector _selector;
|
||||
private readonly DesignFileSystem _fileSystem;
|
||||
private readonly DesignManager _manager;
|
||||
private readonly DesignColors _colors;
|
||||
private readonly DesignColorCombo _colorCombo;
|
||||
private readonly SaveService _saveService;
|
||||
private readonly Configuration _config;
|
||||
private readonly DesignFileSystem _fileSystem;
|
||||
private readonly DesignManager _manager;
|
||||
private readonly DesignColors _colors;
|
||||
private readonly DesignColorCombo _colorCombo;
|
||||
|
||||
private bool _editDescriptionMode;
|
||||
|
||||
public DesignDetailTab(SaveService saveService, DesignFileSystemSelector selector, DesignManager manager, DesignFileSystem fileSystem,
|
||||
DesignColors colors, Configuration.Configuration config)
|
||||
public DesignDetailTab(SaveService saveService, DesignManager manager, DesignFileSystem fileSystem,
|
||||
DesignColors colors, Configuration config)
|
||||
{
|
||||
_saveService = saveService;
|
||||
_selector = selector;
|
||||
_manager = manager;
|
||||
_fileSystem = fileSystem;
|
||||
_colors = colors;
|
||||
|
|
@ -42,6 +40,8 @@ public class DesignDetailTab
|
|||
Im.Line.New();
|
||||
}
|
||||
|
||||
private Design Selected
|
||||
=> (Design) _fileSystem.Selection.Selection!.Value;
|
||||
|
||||
private void DrawDesignInfoTable()
|
||||
{
|
||||
|
|
@ -57,13 +57,13 @@ public class DesignDetailTab
|
|||
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);
|
||||
if (ImEx.InputOnDeactivation.Text("##Name"u8, Selected.Name.Text, out string newName))
|
||||
_manager.Rename(Selected, newName);
|
||||
|
||||
var identifier = _selector.Selected!.Identifier.ToString();
|
||||
var identifier = Selected.Identifier.ToString();
|
||||
table.DrawFrameColumn("Unique Identifier"u8);
|
||||
table.NextColumn();
|
||||
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
|
||||
var fileName = _saveService.FileNames.DesignFile(Selected);
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
if (Im.Button(identifier, width))
|
||||
|
|
@ -87,10 +87,10 @@ public class DesignDetailTab
|
|||
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))
|
||||
if (ImEx.InputOnDeactivation.Text("##Path"u8, Selected.Path.CurrentPath, out string newPath))
|
||||
try
|
||||
{
|
||||
_fileSystem.RenameAndMove(_selector.SelectedLeaf, newPath);
|
||||
_fileSystem.RenameAndMove(Selected.Node!, newPath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
|
@ -99,56 +99,56 @@ public class DesignDetailTab
|
|||
|
||||
table.DrawFrameColumn("Quick Design Bar"u8);
|
||||
table.NextColumn();
|
||||
if (Im.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(_selector.Selected!, true);
|
||||
if (Im.RadioButton("Display##qdb"u8, Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(Selected, true);
|
||||
var hovered = Im.Item.Hovered();
|
||||
Im.Line.SameInner();
|
||||
if (Im.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(_selector.Selected!, false);
|
||||
if (Im.RadioButton("Hide##qdb"u8, !Selected.QuickDesign))
|
||||
_manager.SetQuickDesign(Selected, false);
|
||||
if (hovered || Im.Item.Hovered())
|
||||
Im.Tooltip.Set("Display or hide this design in your quick design bar."u8);
|
||||
|
||||
var forceRedraw = _selector.Selected!.ForcedRedraw;
|
||||
var forceRedraw = Selected.ForcedRedraw;
|
||||
table.DrawFrameColumn("Force Redrawing"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ForceRedraw"u8, ref forceRedraw))
|
||||
_manager.ChangeForcedRedraw(_selector.Selected!, forceRedraw);
|
||||
_manager.ChangeForcedRedraw(Selected, forceRedraw);
|
||||
Im.Tooltip.OnHover("Set this design to always force a redraw when it is applied through any means."u8);
|
||||
|
||||
var resetAdvancedDyes = _selector.Selected!.ResetAdvancedDyes;
|
||||
var resetAdvancedDyes = Selected.ResetAdvancedDyes;
|
||||
table.DrawFrameColumn("Reset Advanced Dyes"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ResetAdvancedDyes"u8, ref resetAdvancedDyes))
|
||||
_manager.ChangeResetAdvancedDyes(_selector.Selected!, resetAdvancedDyes);
|
||||
_manager.ChangeResetAdvancedDyes(Selected, resetAdvancedDyes);
|
||||
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;
|
||||
var resetTemporarySettings = Selected.ResetTemporarySettings;
|
||||
table.DrawFrameColumn("Reset Temporary Settings"u8);
|
||||
table.NextColumn();
|
||||
if (Im.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
|
||||
_manager.ChangeResetTemporarySettings(_selector.Selected!, resetTemporarySettings);
|
||||
_manager.ChangeResetTemporarySettings(Selected, resetTemporarySettings);
|
||||
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);
|
||||
|
||||
table.DrawFrameColumn("Color"u8);
|
||||
table.NextColumn();
|
||||
if (_colorCombo.Draw("##colorCombo"u8, _selector.Selected!.Color.Length is 0 ? DesignColors.AutomaticName : _selector.Selected!.Color,
|
||||
if (_colorCombo.Draw("##colorCombo"u8, Selected.Color.Length is 0 ? DesignColors.AutomaticName : Selected.Color,
|
||||
"Associate a color with this design.\n"u8
|
||||
+ "Right-Click to revert to automatic coloring.\n"u8
|
||||
+ "Hold Control and scroll the mousewheel to scroll."u8,
|
||||
width.X - Im.Style.ItemSpacing.X - Im.Style.FrameHeight, out var newColorName))
|
||||
_manager.ChangeColor(_selector.Selected!, newColorName == DesignColors.AutomaticName ? string.Empty : newColorName);
|
||||
_manager.ChangeColor(Selected, newColorName == DesignColors.AutomaticName ? string.Empty : newColorName);
|
||||
|
||||
if (Im.Item.RightClicked())
|
||||
_manager.ChangeColor(_selector.Selected!, string.Empty);
|
||||
_manager.ChangeColor(Selected, string.Empty);
|
||||
|
||||
if (_colors.TryGetValue(_selector.Selected!.Color, out var currentColor))
|
||||
if (_colors.TryGetValue(Selected.Color, out var currentColor))
|
||||
{
|
||||
Im.Line.Same();
|
||||
if (DesignColorUi.DrawColorButton($"Color associated with {_selector.Selected!.Color}", currentColor, out var newColor))
|
||||
_colors.SetColor(_selector.Selected!.Color, newColor);
|
||||
if (DesignColorUi.DrawColorButton($"Color associated with {Selected.Color}", currentColor, out var newColor))
|
||||
_colors.SetColor(Selected.Color, newColor);
|
||||
}
|
||||
else if (_selector.Selected!.Color.Length != 0)
|
||||
else if (Selected.Color.Length is not 0)
|
||||
{
|
||||
Im.Line.Same();
|
||||
ImEx.Icon.Draw(LunaStyle.WarningIcon, _colors.MissingColor);
|
||||
|
|
@ -157,11 +157,11 @@ public class DesignDetailTab
|
|||
|
||||
table.DrawFrameColumn("Creation Date"u8);
|
||||
table.NextColumn();
|
||||
ImEx.TextFramed($"{_selector.Selected!.CreationDate.LocalDateTime:F}", width, 0);
|
||||
ImEx.TextFramed($"{Selected.CreationDate.LocalDateTime:F}", width, 0);
|
||||
|
||||
table.DrawFrameColumn("Last Update Date"u8);
|
||||
table.NextColumn();
|
||||
ImEx.TextFramed($"{_selector.Selected!.LastEdit.LocalDateTime:F}", width, 0);
|
||||
ImEx.TextFramed($"{Selected.LastEdit.LocalDateTime:F}", width, 0);
|
||||
|
||||
table.DrawFrameColumn("Tags"u8);
|
||||
table.NextColumn();
|
||||
|
|
@ -170,26 +170,26 @@ public class DesignDetailTab
|
|||
|
||||
private void DrawTags()
|
||||
{
|
||||
var idx = TagButtons.Draw(StringU8.Empty, StringU8.Empty, _selector.Selected!.Tags, out var editedTag);
|
||||
var idx = TagButtons.Draw(StringU8.Empty, StringU8.Empty, Selected.Tags, out var editedTag);
|
||||
if (idx < 0)
|
||||
return;
|
||||
|
||||
if (idx < _selector.Selected!.Tags.Length)
|
||||
if (idx < Selected.Tags.Length)
|
||||
{
|
||||
if (editedTag.Length is 0)
|
||||
_manager.RemoveTag(_selector.Selected!, idx);
|
||||
_manager.RemoveTag(Selected, idx);
|
||||
else
|
||||
_manager.RenameTag(_selector.Selected!, idx, editedTag);
|
||||
_manager.RenameTag(Selected, idx, editedTag);
|
||||
}
|
||||
else
|
||||
{
|
||||
_manager.AddTag(_selector.Selected!, editedTag);
|
||||
_manager.AddTag(Selected, editedTag);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDescription()
|
||||
{
|
||||
var desc = _selector.Selected!.Description;
|
||||
var desc = Selected.Description;
|
||||
var size = Im.ContentRegion.Available with { Y = 12 * Im.Style.TextHeightWithSpacing };
|
||||
if (!_editDescriptionMode)
|
||||
{
|
||||
|
|
@ -205,7 +205,7 @@ public class DesignDetailTab
|
|||
else
|
||||
{
|
||||
if (ImEx.InputOnDeactivation.MultiLine("##desc"u8, desc, out string newDescription, size))
|
||||
_manager.ChangeDescription(_selector.Selected!, newDescription);
|
||||
_manager.ChangeDescription(Selected, newDescription);
|
||||
|
||||
if (Im.Button("Stop Editing"u8))
|
||||
_editDescriptionMode = false;
|
||||
|
|
|
|||
|
|
@ -1,405 +0,0 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.FileSystem.Selector;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignFileSystemSelector : FileSystemSelector<Design, DesignFileSystemSelector.DesignState>, IPanel
|
||||
{
|
||||
private readonly DesignManager _designManager;
|
||||
private readonly DesignChanged _event;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly TabSelected _selectionEvent;
|
||||
private readonly DesignColors _designColors;
|
||||
private readonly DesignApplier _designApplier;
|
||||
|
||||
private string? _clipboardText;
|
||||
private Design? _cloneDesign;
|
||||
private string _newName = string.Empty;
|
||||
|
||||
public new DesignFileSystem.Leaf? SelectedLeaf
|
||||
=> base.SelectedLeaf;
|
||||
|
||||
public record struct DesignState(Rgba32 Color)
|
||||
{ }
|
||||
|
||||
protected override float CurrentWidth
|
||||
=> _config.Ephemeral.CurrentDesignSelectorWidth * Im.Style.GlobalScale;
|
||||
|
||||
protected override float MinimumAbsoluteRemainder
|
||||
=> 470 * Im.Style.GlobalScale;
|
||||
|
||||
protected override float MinimumScaling
|
||||
=> _config.Ephemeral.DesignSelectorMinimumScale;
|
||||
|
||||
protected override float MaximumScaling
|
||||
=> _config.Ephemeral.DesignSelectorMaximumScale;
|
||||
|
||||
protected override void SetSize(Vector2 size)
|
||||
{
|
||||
base.SetSize(size);
|
||||
var adaptedSize = MathF.Round(size.X / Im.Style.GlobalScale);
|
||||
if (adaptedSize == _config.Ephemeral.CurrentDesignSelectorWidth)
|
||||
return;
|
||||
|
||||
_config.Ephemeral.CurrentDesignSelectorWidth = adaptedSize;
|
||||
_config.Ephemeral.Save();
|
||||
}
|
||||
|
||||
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, IKeyState keyState, DesignChanged @event,
|
||||
Configuration.Configuration config, DesignConverter converter, TabSelected selectionEvent, OtterGui.Log.Logger log, DesignColors designColors,
|
||||
DesignApplier designApplier)
|
||||
: base(fileSystem, keyState, log, allowMultipleSelection: true)
|
||||
{
|
||||
_designManager = designManager;
|
||||
_event = @event;
|
||||
_config = config;
|
||||
_converter = converter;
|
||||
_selectionEvent = selectionEvent;
|
||||
_designColors = designColors;
|
||||
_designApplier = designApplier;
|
||||
_event.Subscribe(OnDesignChange, DesignChanged.Priority.DesignFileSystemSelector);
|
||||
_selectionEvent.Subscribe(OnTabSelected, TabSelected.Priority.DesignSelector);
|
||||
_designColors.ColorChanged += SetFilterDirty;
|
||||
|
||||
AddButton(NewDesignButton, 0);
|
||||
AddButton(ImportDesignButton, 10);
|
||||
AddButton(CloneDesignButton, 20);
|
||||
AddButton(DeleteButton, 1000);
|
||||
UnsubscribeRightClickLeaf(RenameLeaf);
|
||||
SetRenameSearchPath(_config.ShowRename);
|
||||
SetFilterTooltip();
|
||||
|
||||
if (_config.Ephemeral.SelectedDesign == Guid.Empty)
|
||||
return;
|
||||
|
||||
var design = designManager.Designs.ByIdentifier(_config.Ephemeral.SelectedDesign);
|
||||
if (design != null)
|
||||
SelectByValue(design);
|
||||
}
|
||||
|
||||
public void SetRenameSearchPath(RenameField value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case RenameField.RenameSearchPath:
|
||||
SubscribeRightClickLeaf(RenameLeafDesign, 1000);
|
||||
UnsubscribeRightClickLeaf(RenameDesign);
|
||||
break;
|
||||
case RenameField.RenameData:
|
||||
UnsubscribeRightClickLeaf(RenameLeafDesign);
|
||||
SubscribeRightClickLeaf(RenameDesign, 1000);
|
||||
break;
|
||||
case RenameField.BothSearchPathPrio:
|
||||
UnsubscribeRightClickLeaf(RenameLeafDesign);
|
||||
UnsubscribeRightClickLeaf(RenameDesign);
|
||||
SubscribeRightClickLeaf(RenameLeafDesign, 1001);
|
||||
SubscribeRightClickLeaf(RenameDesign, 1000);
|
||||
break;
|
||||
case RenameField.BothDataPrio:
|
||||
UnsubscribeRightClickLeaf(RenameLeafDesign);
|
||||
UnsubscribeRightClickLeaf(RenameDesign);
|
||||
SubscribeRightClickLeaf(RenameLeafDesign, 1000);
|
||||
SubscribeRightClickLeaf(RenameDesign, 1001);
|
||||
break;
|
||||
default:
|
||||
UnsubscribeRightClickLeaf(RenameLeafDesign);
|
||||
UnsubscribeRightClickLeaf(RenameDesign);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenameLeafDesign(DesignFileSystem.Leaf leaf)
|
||||
{
|
||||
Im.Separator();
|
||||
RenameLeaf(leaf);
|
||||
}
|
||||
|
||||
private void RenameDesign(DesignFileSystem.Leaf leaf)
|
||||
{
|
||||
Im.Separator();
|
||||
var currentName = leaf.Value.Name.Text;
|
||||
if (ImGui.IsWindowAppearing())
|
||||
ImGui.SetKeyboardFocusHere(0);
|
||||
ImGui.TextUnformatted("Rename Design:");
|
||||
if (Im.Input.Text("##RenameDesign"u8, ref currentName, StringU8.Empty, InputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
_designManager.Rename(leaf.Value, currentName);
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip("Enter a new name here to rename the changed design.");
|
||||
}
|
||||
|
||||
protected override void Select(FileSystem<Design>.Leaf? leaf, bool clear, in DesignState storage = default)
|
||||
{
|
||||
base.Select(leaf, clear, storage);
|
||||
var id = SelectedLeaf?.Value.Identifier ?? Guid.Empty;
|
||||
if (id != _config.Ephemeral.SelectedDesign)
|
||||
{
|
||||
_config.Ephemeral.SelectedDesign = id;
|
||||
_config.Ephemeral.Save();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawPopups()
|
||||
{
|
||||
DrawNewDesignPopup();
|
||||
}
|
||||
|
||||
protected override void DrawLeafName(FileSystem<Design>.Leaf leaf, in DesignState state, bool selected)
|
||||
{
|
||||
var flag = selected ? ImGuiTreeNodeFlags.Selected | LeafFlags : LeafFlags;
|
||||
var name = _config.Ephemeral.IncognitoMode ? leaf.Value.Incognito : leaf.Value.Name.Text;
|
||||
using var color = ImGuiColor.Text.Push(state.Color);
|
||||
using var _ = ImUtf8.TreeNode(name, flag);
|
||||
if (_config.AllowDoubleClickToApply && ImGui.IsItemHovered() && ImGui.IsMouseDoubleClicked(ImGuiMouseButton.Left))
|
||||
_designApplier.ApplyToPlayer(leaf.Value);
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
base.Dispose();
|
||||
_event.Unsubscribe(OnDesignChange);
|
||||
_selectionEvent.Unsubscribe(OnTabSelected);
|
||||
_designColors.ColorChanged -= SetFilterDirty;
|
||||
}
|
||||
|
||||
public override ISortMode<Design> SortMode
|
||||
=> _config.SortMode;
|
||||
|
||||
protected override uint ExpandedFolderColor
|
||||
=> ColorId.FolderExpanded.Value().Color;
|
||||
|
||||
protected override uint CollapsedFolderColor
|
||||
=> ColorId.FolderCollapsed.Value().Color;
|
||||
|
||||
protected override uint FolderLineColor
|
||||
=> ColorId.FolderLine.Value().Color;
|
||||
|
||||
protected override bool FoldersDefaultOpen
|
||||
=> _config.OpenFoldersByDefault;
|
||||
|
||||
private void OnDesignChange(DesignChanged.Type type, Design design, ITransaction? _)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DesignChanged.Type.ReloadedAll:
|
||||
case DesignChanged.Type.Renamed:
|
||||
case DesignChanged.Type.AddedTag:
|
||||
case DesignChanged.Type.ChangedTag:
|
||||
case DesignChanged.Type.RemovedTag:
|
||||
case DesignChanged.Type.AddedMod:
|
||||
case DesignChanged.Type.RemovedMod:
|
||||
case DesignChanged.Type.Created:
|
||||
case DesignChanged.Type.Deleted:
|
||||
case DesignChanged.Type.ApplyCustomize:
|
||||
case DesignChanged.Type.ApplyEquip:
|
||||
case DesignChanged.Type.ApplyStain:
|
||||
case DesignChanged.Type.ApplyCrest:
|
||||
case DesignChanged.Type.Customize:
|
||||
case DesignChanged.Type.Equip:
|
||||
case DesignChanged.Type.ChangedColor:
|
||||
SetFilterDirty();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void NewDesignButton(Vector2 size)
|
||||
{
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size, "Create a new design with default configuration.", false,
|
||||
true))
|
||||
{
|
||||
_cloneDesign = null;
|
||||
_clipboardText = null;
|
||||
ImGui.OpenPopup("##NewDesign");
|
||||
}
|
||||
}
|
||||
|
||||
private void ImportDesignButton(Vector2 size)
|
||||
{
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.FileImport.ToIconString(), size, "Try to import a design from your clipboard.", false,
|
||||
true))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
_cloneDesign = null;
|
||||
_clipboardText = ImGui.GetClipboardText();
|
||||
ImGui.OpenPopup("##NewDesign");
|
||||
}
|
||||
catch
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void CloneDesignButton(Vector2 size)
|
||||
{
|
||||
var tt = SelectedLeaf == null
|
||||
? "No design selected."
|
||||
: "Clone the currently selected design to a duplicate";
|
||||
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clone.ToIconString(), size, tt, SelectedLeaf == null, true))
|
||||
return;
|
||||
|
||||
_clipboardText = null;
|
||||
_cloneDesign = Selected!;
|
||||
ImGui.OpenPopup("##NewDesign");
|
||||
}
|
||||
|
||||
private void DeleteButton(Vector2 size)
|
||||
=> DeleteSelectionButton(size,
|
||||
new OtterGui.Classes.DoubleModifier(new OtterGui.Classes.ModifierHotkey(_config.DeleteDesignModifier.Modifier1),
|
||||
new OtterGui.Classes.ModifierHotkey(_config.DeleteDesignModifier.Modifier2)), "design", "designs", _designManager.Delete);
|
||||
|
||||
private void DrawNewDesignPopup()
|
||||
{
|
||||
if (!ImGuiUtil.OpenNameField("##NewDesign", ref _newName))
|
||||
return;
|
||||
|
||||
if (_clipboardText != null)
|
||||
{
|
||||
var design = _converter.FromBase64(_clipboardText, true, true, out _);
|
||||
if (design is Design d)
|
||||
_designManager.CreateClone(d, _newName, true);
|
||||
else if (design != null)
|
||||
_designManager.CreateClone(design, _newName, true);
|
||||
else
|
||||
Glamourer.Messager.NotificationMessage("Could not create a design, clipboard did not contain valid design data.",
|
||||
NotificationType.Error, false);
|
||||
_clipboardText = null;
|
||||
}
|
||||
else if (_cloneDesign != null)
|
||||
{
|
||||
_designManager.CreateClone(_cloneDesign, _newName, true);
|
||||
_cloneDesign = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
_designManager.CreateEmpty(_newName, true);
|
||||
}
|
||||
|
||||
_newName = string.Empty;
|
||||
}
|
||||
|
||||
private void OnTabSelected(MainTabType type, Design? design)
|
||||
{
|
||||
if (type == MainTabType.Designs && design != null)
|
||||
SelectByValue(design);
|
||||
}
|
||||
|
||||
#region Filters
|
||||
|
||||
private const StringComparison IgnoreCase = StringComparison.OrdinalIgnoreCase;
|
||||
private LowerString _designFilter = LowerString.Empty;
|
||||
private int _filterType = -1;
|
||||
|
||||
private void SetFilterTooltip()
|
||||
{
|
||||
FilterTooltip = "Filter designs for those where their full paths or names contain the given substring.\n"
|
||||
+ "Enter m:[string] to filter for designs with with a mod association containing the string.\n"
|
||||
+ "Enter t:[string] to filter for designs set to specific tags.\n"
|
||||
+ "Enter c:[string] to filter for designs set to specific colors.\n"
|
||||
+ "Enter i:[string] to filter for designs containing specific items.\n"
|
||||
+ "Enter n:[string] to filter only for design names and no paths.\n\n"
|
||||
+ "Use None as a placeholder value that only matches empty lists or names.";
|
||||
}
|
||||
|
||||
/// <summary> Appropriately identify and set the string filter and its type. </summary>
|
||||
protected override bool ChangeFilter(string filterValue)
|
||||
{
|
||||
(_designFilter, _filterType) = filterValue.Length switch
|
||||
{
|
||||
0 => (LowerString.Empty, -1),
|
||||
> 1 when filterValue[1] == ':' =>
|
||||
filterValue[0] switch
|
||||
{
|
||||
'n' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 1),
|
||||
'N' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 1),
|
||||
'm' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 2),
|
||||
'M' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 2),
|
||||
't' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 3),
|
||||
'T' => filterValue.Length == 2 ? (LowerString.Empty, -1) : ParseFilter(filterValue, 3),
|
||||
'i' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 4),
|
||||
'I' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 4),
|
||||
'c' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 5),
|
||||
'C' => filterValue.Length == 2 ? (LowerString.Empty, -1) : (new LowerString(filterValue[2..]), 5),
|
||||
_ => (new LowerString(filterValue), 0),
|
||||
},
|
||||
_ => (new LowerString(filterValue), 0),
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private const int EmptyOffset = 128;
|
||||
|
||||
private static (LowerString, int) ParseFilter(string value, int id)
|
||||
{
|
||||
value = value[2..];
|
||||
var lower = new LowerString(value);
|
||||
return (lower, lower.Lower is "none" ? id + EmptyOffset : id);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The overwritten filter method also computes the state.
|
||||
/// Folders have default state and are filtered out on the direct string instead of the other options.
|
||||
/// If any filter is set, they should be hidden by default unless their children are visible,
|
||||
/// or they contain the path search string.
|
||||
/// </summary>
|
||||
protected override bool ApplyFiltersAndState(FileSystem<Design>.IPath path, out DesignState state)
|
||||
{
|
||||
if (path is DesignFileSystem.Folder f)
|
||||
{
|
||||
state = default;
|
||||
return FilterValue.Length > 0 && !f.FullName().Contains(FilterValue, IgnoreCase);
|
||||
}
|
||||
|
||||
return ApplyFiltersAndState((DesignFileSystem.Leaf)path, out state);
|
||||
}
|
||||
|
||||
/// <summary> Apply the string filters. </summary>
|
||||
private bool ApplyStringFilters(DesignFileSystem.Leaf leaf, Design design)
|
||||
{
|
||||
return _filterType switch
|
||||
{
|
||||
-1 => false,
|
||||
0 => !(_designFilter.IsContained(leaf.FullName()) || design.Name.Contains(_designFilter)),
|
||||
1 => !design.Name.Contains(_designFilter),
|
||||
2 => !design.AssociatedMods.Any(kvp => _designFilter.IsContained(kvp.Key.Name)),
|
||||
3 => !design.Tags.Any(_designFilter.IsContained),
|
||||
4 => !design.DesignData.ContainsName(_designFilter),
|
||||
5 => !_designFilter.IsContained(design.Color.Length == 0 ? DesignColors.AutomaticName : design.Color),
|
||||
2 + EmptyOffset => design.AssociatedMods.Count > 0,
|
||||
3 + EmptyOffset => design.Tags.Length > 0,
|
||||
_ => false, // Should never happen
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary> Combined wrapper for handling all filters and setting state. </summary>
|
||||
private bool ApplyFiltersAndState(DesignFileSystem.Leaf leaf, out DesignState state)
|
||||
{
|
||||
state = new DesignState(_designColors.GetColor(leaf.Value));
|
||||
return ApplyStringFilters(leaf, leaf.Value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "DesignSelector"u8;
|
||||
}
|
||||
|
|
@ -1,21 +1,107 @@
|
|||
using Luna;
|
||||
using System.Security.AccessControl;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Interop;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignHeader : SplitButtonHeader
|
||||
public sealed class DesignHeader : SplitButtonHeader, IDisposable
|
||||
{
|
||||
public DesignHeader(DesignSelection selection, IncognitoButton incognito)
|
||||
private readonly DesignFileSystem _fileSystem;
|
||||
private readonly DesignChanged _designChanged;
|
||||
private readonly Configuration _config;
|
||||
|
||||
private StringU8 _header = new("No Selection"u8);
|
||||
private StringU8 _incognito = new("No Selection"u8);
|
||||
|
||||
public DesignHeader(DesignFileSystem fileSystem, IncognitoButton incognito, DesignChanged designChanged, Configuration config,
|
||||
DesignConverter converter, StateManager stateManager, EditorHistory history, DesignManager manager, ActorObjectManager objects)
|
||||
{
|
||||
RightButtons.AddButton(incognito, 50);
|
||||
RightButtons.AddButton(new LockedButton(selection), 100);
|
||||
_fileSystem = fileSystem;
|
||||
_designChanged = designChanged;
|
||||
_config = config;
|
||||
LeftButtons.AddButton(new SetFromClipboardButton(fileSystem, converter, manager), 100);
|
||||
LeftButtons.AddButton(new DesignUndoButton(fileSystem, manager), 90);
|
||||
LeftButtons.AddButton(new ExportToClipboardButton(fileSystem, converter), 80);
|
||||
LeftButtons.AddButton(new ApplyCharacterButton(fileSystem, manager, objects, stateManager, converter), 70);
|
||||
LeftButtons.AddButton(new UndoButton(fileSystem, history), 60);
|
||||
|
||||
RightButtons.AddButton(incognito, 50);
|
||||
RightButtons.AddButton(new LockedButton(fileSystem, manager), 100);
|
||||
_fileSystem.Selection.Changed += OnSelectionChanged;
|
||||
OnSelectionChanged();
|
||||
designChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignHeader);
|
||||
}
|
||||
|
||||
private sealed class LockedButton(DesignSelection selection) : BaseIconButton<AwesomeIcon>
|
||||
private void OnDesignChanged(DesignChanged.Type arg1, Design arg2, ITransaction? arg3)
|
||||
{
|
||||
if (arg1 is not DesignChanged.Type.Renamed)
|
||||
return;
|
||||
|
||||
if (arg2 != _fileSystem.Selection.Selection?.Value)
|
||||
return;
|
||||
|
||||
_header = new StringU8(arg2.Name.Text);
|
||||
}
|
||||
|
||||
private void OnSelectionChanged()
|
||||
{
|
||||
if (_fileSystem.Selection.Selection?.GetValue<Design>() is { } selection)
|
||||
{
|
||||
_header = new StringU8(selection.Name.Text);
|
||||
_incognito = new StringU8(selection.Incognito);
|
||||
}
|
||||
else if (_fileSystem.Selection.OrderedNodes.Count > 0)
|
||||
{
|
||||
_header = new StringU8($"{_fileSystem.Selection.OrderedNodes.Count} Objects Selected");
|
||||
_incognito = _header;
|
||||
}
|
||||
else
|
||||
{
|
||||
_header = new StringU8("No Selection"u8);
|
||||
_incognito = _header;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Draw(Vector2 size)
|
||||
{
|
||||
var color = ColorId.HeaderButtons.Value();
|
||||
using var _ = ImGuiColor.Text.Push(color).Push(ImGuiColor.Border, color);
|
||||
base.Draw(size with { Y = Im.Style.FrameHeight });
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Text
|
||||
=> _config.Ephemeral.IncognitoMode ? _incognito : _header;
|
||||
|
||||
private sealed class LockedButton(DesignFileSystem fileSystem, DesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> selection.Design is not null;
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> selection.Design!.WriteProtected() ? LunaStyle.LockedIcon : LunaStyle.UnlockedIcon;
|
||||
=> ((Design)fileSystem.Selection.Selection!.Value).WriteProtected() ? LunaStyle.LockedIcon : LunaStyle.UnlockedIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(((Design)fileSystem.Selection.Selection!.Value).WriteProtected()
|
||||
? "Make this design editable."u8
|
||||
: "Write-protect this design."u8);
|
||||
|
||||
public override void OnClick()
|
||||
=> manager.SetWriteProtection((Design)fileSystem.Selection.Selection!.Value,
|
||||
!((Design)fileSystem.Selection.Selection!.Value).WriteProtected());
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_fileSystem.Selection.Changed -= OnSelectionChanged;
|
||||
_designChanged.Unsubscribe(OnDesignChanged);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Links;
|
||||
using ImSharp;
|
||||
|
|
@ -10,16 +10,19 @@ namespace Glamourer.Gui.Tabs.DesignTab;
|
|||
|
||||
public class DesignLinkDrawer(
|
||||
DesignLinkManager linkManager,
|
||||
DesignFileSystemSelector selector,
|
||||
DesignFileSystem fileSystem,
|
||||
LinkDesignCombo combo,
|
||||
DesignColors colorManager,
|
||||
Configuration.Configuration config) : IUiService
|
||||
Configuration config) : IUiService
|
||||
{
|
||||
private int _dragDropIndex = -1;
|
||||
private LinkOrder _dragDropOrder = LinkOrder.None;
|
||||
private int _dragDropTargetIndex = -1;
|
||||
private LinkOrder _dragDropTargetOrder = LinkOrder.None;
|
||||
|
||||
private Design Selected
|
||||
=> (Design)fileSystem.Selection.Selection!.Value;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var h = DesignPanelFlag.DesignLinks.Header(config);
|
||||
|
|
@ -45,23 +48,23 @@ public class DesignLinkDrawer(
|
|||
switch (_dragDropTargetOrder)
|
||||
{
|
||||
case LinkOrder.Before:
|
||||
for (var i = selector.Selected!.Links.Before.Count - 1; i >= _dragDropTargetIndex; --i)
|
||||
linkManager.MoveDesignLink(selector.Selected!, i, LinkOrder.Before, 0, LinkOrder.After);
|
||||
for (var i = Selected.Links.Before.Count - 1; i >= _dragDropTargetIndex; --i)
|
||||
linkManager.MoveDesignLink(Selected, i, LinkOrder.Before, 0, LinkOrder.After);
|
||||
break;
|
||||
case LinkOrder.After:
|
||||
for (var i = 0; i <= _dragDropTargetIndex; ++i)
|
||||
{
|
||||
linkManager.MoveDesignLink(selector.Selected!, 0, LinkOrder.After, selector.Selected!.Links.Before.Count,
|
||||
linkManager.MoveDesignLink(Selected, 0, LinkOrder.After, Selected.Links.Before.Count,
|
||||
LinkOrder.Before);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
else if (_dragDropTargetOrder is LinkOrder.Self)
|
||||
linkManager.MoveDesignLink(selector.Selected!, _dragDropIndex, _dragDropOrder, selector.Selected!.Links.Before.Count,
|
||||
linkManager.MoveDesignLink(Selected, _dragDropIndex, _dragDropOrder, Selected.Links.Before.Count,
|
||||
LinkOrder.Before);
|
||||
else
|
||||
linkManager.MoveDesignLink(selector.Selected!, _dragDropIndex, _dragDropOrder, _dragDropTargetIndex, _dragDropTargetOrder);
|
||||
linkManager.MoveDesignLink(Selected, _dragDropIndex, _dragDropOrder, _dragDropTargetIndex, _dragDropTargetOrder);
|
||||
|
||||
_dragDropIndex = -1;
|
||||
_dragDropTargetIndex = -1;
|
||||
|
|
@ -81,9 +84,9 @@ public class DesignLinkDrawer(
|
|||
6 * Im.Style.FrameHeight + 5 * Im.Style.ItemInnerSpacing.X);
|
||||
|
||||
using var style = ImStyleDouble.ItemSpacing.Push(Im.Style.ItemInnerSpacing);
|
||||
DrawSubList(table, selector.Selected!.Links.Before, LinkOrder.Before);
|
||||
DrawSubList(table, Selected.Links.Before, LinkOrder.Before);
|
||||
DrawSelf(table);
|
||||
DrawSubList(table, selector.Selected!.Links.After, LinkOrder.After);
|
||||
DrawSubList(table, Selected.Links.After, LinkOrder.After);
|
||||
DrawNew(table);
|
||||
MoveLink();
|
||||
}
|
||||
|
|
@ -92,7 +95,7 @@ public class DesignLinkDrawer(
|
|||
{
|
||||
using var id = Im.Id.Push((int)LinkOrder.Self);
|
||||
table.NextColumn();
|
||||
var color = colorManager.GetColor(selector.Selected!);
|
||||
var color = colorManager.GetColor(Selected);
|
||||
using (AwesomeIcon.Font.Push())
|
||||
{
|
||||
using var c = ImGuiColor.Text.Push(color);
|
||||
|
|
@ -104,11 +107,11 @@ public class DesignLinkDrawer(
|
|||
using (ImGuiColor.Text.Push(color))
|
||||
{
|
||||
Im.Cursor.FrameAlign();
|
||||
Im.Selectable(config.Ephemeral.IncognitoMode ? selector.Selected!.Incognito : selector.Selected!.Name.Text);
|
||||
Im.Selectable(config.Ephemeral.IncognitoMode ? Selected.Incognito : Selected.Name.Text);
|
||||
}
|
||||
|
||||
Im.Tooltip.OnHover("Current Design"u8);
|
||||
DrawDragDrop(selector.Selected!, LinkOrder.Self, 0);
|
||||
DrawDragDrop(Selected, LinkOrder.Self, 0);
|
||||
table.NextColumn();
|
||||
using (AwesomeIcon.Font.Push())
|
||||
{
|
||||
|
|
@ -144,7 +147,7 @@ public class DesignLinkDrawer(
|
|||
DrawApplicationBoxes(i, order, flags);
|
||||
|
||||
if (delete)
|
||||
linkManager.RemoveDesignLink(selector.Selected!, i--, order);
|
||||
linkManager.RemoveDesignLink(Selected, i--, order);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -164,11 +167,11 @@ public class DesignLinkDrawer(
|
|||
}
|
||||
else
|
||||
{
|
||||
canAddBefore = LinkContainer.CanAddLink(selector.Selected!, design, LinkOrder.Before, out var error);
|
||||
canAddBefore = LinkContainer.CanAddLink(Selected, design, LinkOrder.Before, out var error);
|
||||
ttBefore = canAddBefore
|
||||
? $"Add a link at the top of the list to {design.Name}."
|
||||
: $"Can not add a link to {design.Name}:\n{error}";
|
||||
canAddAfter = LinkContainer.CanAddLink(selector.Selected!, design, LinkOrder.After, out error);
|
||||
canAddAfter = LinkContainer.CanAddLink(Selected, design, LinkOrder.After, out error);
|
||||
ttAfter = canAddAfter
|
||||
? $"Add a link at the bottom of the list to {design.Name}."
|
||||
: $"Can not add a link to {design.Name}:\n{error}";
|
||||
|
|
@ -176,13 +179,13 @@ public class DesignLinkDrawer(
|
|||
|
||||
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleUp.Icon(), ttBefore, !canAddBefore))
|
||||
{
|
||||
linkManager.AddDesignLink(selector.Selected!, design!, LinkOrder.Before);
|
||||
linkManager.MoveDesignLink(selector.Selected!, selector.Selected!.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
||||
linkManager.AddDesignLink(Selected, design!, LinkOrder.Before);
|
||||
linkManager.MoveDesignLink(Selected, Selected.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleDown.Icon(), ttAfter, !canAddAfter))
|
||||
linkManager.AddDesignLink(selector.Selected!, design!, LinkOrder.After);
|
||||
linkManager.AddDesignLink(Selected, design!, LinkOrder.After);
|
||||
}
|
||||
|
||||
private void DrawDragDrop(Design design, LinkOrder order, int index)
|
||||
|
|
@ -228,7 +231,7 @@ public class DesignLinkDrawer(
|
|||
Im.Line.Same();
|
||||
Box(4);
|
||||
if (newType != current)
|
||||
linkManager.ChangeApplicationType(selector.Selected!, idx, order, newType);
|
||||
linkManager.ChangeApplicationType(Selected, idx, order, newType);
|
||||
return;
|
||||
|
||||
void Box(int i)
|
||||
|
|
|
|||
|
|
@ -1,51 +1,40 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Interface.ImGuiFileDialog;
|
||||
using Dalamud.Interface.ImGuiNotification;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Gui.Customization;
|
||||
using Glamourer.Gui.Equipment;
|
||||
using Glamourer.Gui.Materials;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using Glamourer.Configuration;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Interop;
|
||||
using static Glamourer.Gui.Tabs.HeaderDrawer;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public class DesignPanel : IPanel
|
||||
{
|
||||
private readonly FileDialogManager _fileDialog = new();
|
||||
private readonly DesignSelection _selection;
|
||||
private readonly CustomizationDrawer _customizationDrawer;
|
||||
private readonly DesignManager _manager;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly StateManager _state;
|
||||
private readonly EquipmentDrawer _equipmentDrawer;
|
||||
private readonly ModAssociationsTab _modAssociations;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly DesignDetailTab _designDetails;
|
||||
private readonly ImportService _importService;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly MultiDesignPanel _multiDesignPanel;
|
||||
private readonly CustomizeParameterDrawer _parameterDrawer;
|
||||
private readonly DesignLinkDrawer _designLinkDrawer;
|
||||
private readonly MaterialDrawer _materials;
|
||||
private readonly EditorHistory _history;
|
||||
private readonly Button[] _leftButtons;
|
||||
private readonly Button[] _rightButtons;
|
||||
private readonly FileDialogManager _fileDialog = new();
|
||||
private readonly CustomizationDrawer _customizationDrawer;
|
||||
private readonly DesignFileSystem _fileSystem;
|
||||
private readonly DesignManager _manager;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly StateManager _state;
|
||||
private readonly EquipmentDrawer _equipmentDrawer;
|
||||
private readonly ModAssociationsTab _modAssociations;
|
||||
private readonly Configuration _config;
|
||||
private readonly DesignDetailTab _designDetails;
|
||||
private readonly ImportService _importService;
|
||||
private readonly MultiDesignPanel _multiDesignPanel;
|
||||
private readonly CustomizeParameterDrawer _parameterDrawer;
|
||||
private readonly DesignLinkDrawer _designLinkDrawer;
|
||||
private readonly MaterialDrawer _materials;
|
||||
|
||||
|
||||
public DesignPanel(CustomizationDrawer customizationDrawer,
|
||||
|
|
@ -54,7 +43,7 @@ public class DesignPanel : IPanel
|
|||
StateManager state,
|
||||
EquipmentDrawer equipmentDrawer,
|
||||
ModAssociationsTab modAssociations,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
DesignDetailTab designDetails,
|
||||
DesignConverter converter,
|
||||
ImportService importService,
|
||||
|
|
@ -62,7 +51,7 @@ public class DesignPanel : IPanel
|
|||
CustomizeParameterDrawer parameterDrawer,
|
||||
DesignLinkDrawer designLinkDrawer,
|
||||
MaterialDrawer materials,
|
||||
EditorHistory history, DesignSelection selection)
|
||||
DesignFileSystem fileSystem)
|
||||
{
|
||||
_customizationDrawer = customizationDrawer;
|
||||
_manager = manager;
|
||||
|
|
@ -73,33 +62,16 @@ public class DesignPanel : IPanel
|
|||
_config = config;
|
||||
_designDetails = designDetails;
|
||||
_importService = importService;
|
||||
_converter = converter;
|
||||
_multiDesignPanel = multiDesignPanel;
|
||||
_parameterDrawer = parameterDrawer;
|
||||
_designLinkDrawer = designLinkDrawer;
|
||||
_materials = materials;
|
||||
_history = history;
|
||||
_selection = selection;
|
||||
_leftButtons =
|
||||
[
|
||||
new SetFromClipboardButton(this),
|
||||
new DesignUndoButton(this),
|
||||
new ExportToClipboardButton(this),
|
||||
new ApplyCharacterButton(this),
|
||||
new UndoButton(this),
|
||||
];
|
||||
_rightButtons =
|
||||
[
|
||||
new LockButton(this),
|
||||
//new IncognitoButton(_config),
|
||||
];
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
private void DrawHeader()
|
||||
=> HeaderDrawer.Draw(SelectionName, 0, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
|
||||
|
||||
private string SelectionName
|
||||
=> _selection.Design == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? _selection.Design.Incognito : _selection.Design.Name.Text;
|
||||
private Design Selection
|
||||
=> (Design)_fileSystem.Selection.Selection!.Value;
|
||||
|
||||
private void DrawEquipment()
|
||||
{
|
||||
|
|
@ -109,22 +81,22 @@ public class DesignPanel : IPanel
|
|||
|
||||
_equipmentDrawer.Prepare();
|
||||
|
||||
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _selection.Design!.WriteProtected());
|
||||
var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, Selection.WriteProtected());
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
var data = EquipDrawData.FromDesign(_manager, _selection.Design!, slot);
|
||||
var data = EquipDrawData.FromDesign(_manager, Selection, slot);
|
||||
_equipmentDrawer.DrawEquip(data);
|
||||
if (usedAllStain)
|
||||
_manager.ChangeStains(_selection.Design, slot, newAllStain);
|
||||
_manager.ChangeStains(Selection, slot, newAllStain);
|
||||
}
|
||||
|
||||
var mainhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.MainHand);
|
||||
var offhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.OffHand);
|
||||
var mainhand = EquipDrawData.FromDesign(_manager, Selection, EquipSlot.MainHand);
|
||||
var offhand = EquipDrawData.FromDesign(_manager, Selection, EquipSlot.OffHand);
|
||||
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
|
||||
|
||||
foreach (var slot in BonusExtensions.AllFlags)
|
||||
{
|
||||
var data = BonusDrawData.FromDesign(_manager, _selection.Design!, slot);
|
||||
var data = BonusDrawData.FromDesign(_manager, Selection, slot);
|
||||
_equipmentDrawer.DrawBonusItem(data);
|
||||
}
|
||||
|
||||
|
|
@ -136,30 +108,30 @@ public class DesignPanel : IPanel
|
|||
|
||||
private void DrawEquipmentMetaToggles()
|
||||
{
|
||||
using (var _ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, Selection));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, Selection));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, Selection));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, Selection));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, Selection));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, Selection));
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.EarState, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.EarState, _manager, Selection));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -169,25 +141,25 @@ public class DesignPanel : IPanel
|
|||
return;
|
||||
|
||||
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
||||
using var h = Im.Tree.HeaderId(_selection.Design!.DesignData.ModelId is 0
|
||||
? "Customization"
|
||||
: $"Customization (Model Id #{_selection.Design!.DesignData.ModelId})###Customization",
|
||||
using var h = Im.Tree.HeaderId(Selection.DesignData.ModelId is 0
|
||||
? "Customization"u8
|
||||
: $"Customization (Model Id #{Selection.DesignData.ModelId})###Customization",
|
||||
expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
|
||||
if (!h)
|
||||
return;
|
||||
|
||||
if (_customizationDrawer.Draw(_selection.Design!.DesignData.Customize, _selection.Design.Application.Customize,
|
||||
_selection.Design!.WriteProtected(), false))
|
||||
if (_customizationDrawer.Draw(Selection.DesignData.Customize, Selection.Application.Customize,
|
||||
Selection.WriteProtected(), false))
|
||||
foreach (var idx in CustomizeIndex.Values)
|
||||
{
|
||||
var flag = idx.ToFlag();
|
||||
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
|
||||
_manager.ChangeApplyCustomize(_selection.Design, idx, newValue);
|
||||
_manager.ChangeApplyCustomize(Selection, idx, newValue);
|
||||
if (_customizationDrawer.Changed.HasFlag(flag))
|
||||
_manager.ChangeCustomize(_selection.Design, idx, _customizationDrawer.Customize[idx]);
|
||||
_manager.ChangeCustomize(Selection, idx, _customizationDrawer.Customize[idx]);
|
||||
}
|
||||
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.Wetness, _manager, _selection.Design!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.Wetness, _manager, Selection));
|
||||
Im.Dummy(new Vector2(Im.Style.TextHeight / 2));
|
||||
}
|
||||
|
||||
|
|
@ -197,7 +169,7 @@ public class DesignPanel : IPanel
|
|||
if (!h)
|
||||
return;
|
||||
|
||||
_parameterDrawer.Draw(_manager, _selection.Design!);
|
||||
_parameterDrawer.Draw(_manager, Selection);
|
||||
}
|
||||
|
||||
private void DrawMaterialValues()
|
||||
|
|
@ -206,52 +178,52 @@ public class DesignPanel : IPanel
|
|||
if (!h)
|
||||
return;
|
||||
|
||||
_materials.Draw(_selection.Design!);
|
||||
_materials.Draw(Selection);
|
||||
}
|
||||
|
||||
private void DrawCustomizeApplication()
|
||||
{
|
||||
using var id = ImUtf8.PushId("Customizations"u8);
|
||||
var set = _selection.Design!.CustomizeSet;
|
||||
using var id = Im.Id.Push("Customizations"u8);
|
||||
var set = Selection.CustomizeSet;
|
||||
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
|
||||
var flags = _selection.Design!.ApplyCustomizeExcludingBodyType == 0 ? 0 :
|
||||
(_selection.Design!.ApplyCustomize & available) == available ? 3 : 1;
|
||||
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
|
||||
var flags = Selection.ApplyCustomizeExcludingBodyType is 0 ? 0ul :
|
||||
(Selection.ApplyCustomize & available) == available ? 3ul : 1ul;
|
||||
if (Im.Checkbox("Apply All Customizations"u8, ref flags, 3ul))
|
||||
{
|
||||
var newFlags = flags == 3;
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, newFlags);
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, newFlags);
|
||||
var newFlags = flags is 3;
|
||||
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Clan, newFlags);
|
||||
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Gender, newFlags);
|
||||
foreach (var index in CustomizationExtensions.AllBasic)
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, index, newFlags);
|
||||
_manager.ChangeApplyCustomize(Selection, index, newFlags);
|
||||
}
|
||||
|
||||
var applyClan = _selection.Design!.DoApplyCustomize(CustomizeIndex.Clan);
|
||||
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Clan.ToNameU8()}", ref applyClan))
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, applyClan);
|
||||
var applyClan = Selection.DoApplyCustomize(CustomizeIndex.Clan);
|
||||
if (Im.Checkbox($"Apply {CustomizeIndex.Clan.ToNameU8()}", ref applyClan))
|
||||
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Clan, applyClan);
|
||||
|
||||
var applyGender = _selection.Design!.DoApplyCustomize(CustomizeIndex.Gender);
|
||||
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Gender.ToNameU8()}", ref applyGender))
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, applyGender);
|
||||
var applyGender = Selection.DoApplyCustomize(CustomizeIndex.Gender);
|
||||
if (Im.Checkbox($"Apply {CustomizeIndex.Gender.ToNameU8()}", ref applyGender))
|
||||
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Gender, applyGender);
|
||||
|
||||
|
||||
foreach (var index in CustomizationExtensions.All.Where(set.IsAvailable))
|
||||
{
|
||||
var apply = _selection.Design!.DoApplyCustomize(index);
|
||||
if (ImUtf8.Checkbox($"Apply {set.Option(index)}", ref apply))
|
||||
_manager.ChangeApplyCustomize(_selection.Design!, index, apply);
|
||||
var apply = Selection.DoApplyCustomize(index);
|
||||
if (Im.Checkbox($"Apply {set.Option(index)}", ref apply))
|
||||
_manager.ChangeApplyCustomize(Selection, index, apply);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawCrestApplication()
|
||||
{
|
||||
using var id = ImUtf8.PushId("Crests"u8);
|
||||
var flags = (uint)_selection.Design!.Application.Crest;
|
||||
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
||||
using var id = Im.Id.Push("Crests"u8);
|
||||
var flags = (ulong)Selection.Application.Crest;
|
||||
var bigChange = Im.Checkbox("Apply All Crests"u8, ref flags, (ulong)CrestExtensions.AllRelevant);
|
||||
foreach (var flag in CrestExtensions.AllRelevantSet)
|
||||
{
|
||||
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selection.Design!.DoApplyCrest(flag);
|
||||
if (ImUtf8.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
||||
_manager.ChangeApplyCrest(_selection.Design!, flag, apply);
|
||||
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : Selection.DoApplyCrest(flag);
|
||||
if (Im.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
||||
_manager.ChangeApplyCrest(Selection, flag, apply);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -261,63 +233,59 @@ public class DesignPanel : IPanel
|
|||
if (!h)
|
||||
return;
|
||||
|
||||
using var disabled = Im.Disabled(_selection.Design!.WriteProtected());
|
||||
using var disabled = Im.Disabled(Selection.WriteProtected());
|
||||
|
||||
DrawAllButtons();
|
||||
|
||||
using (var _ = ImUtf8.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
DrawCustomizeApplication();
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
DrawCrestApplication();
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
DrawMetaApplication();
|
||||
}
|
||||
|
||||
ImGui.SameLine(210 * Im.Style.GlobalScale + Im.Style.ItemSpacing.X);
|
||||
using (var _ = ImRaii.Group())
|
||||
Im.Line.Same(210 * Im.Style.GlobalScale + Im.Style.ItemSpacing.X);
|
||||
using (Im.Group())
|
||||
{
|
||||
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
|
||||
{
|
||||
var flags = (uint)(allFlags & _selection.Design!.Application.Equip);
|
||||
using var id = ImUtf8.PushId(label);
|
||||
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)allFlags);
|
||||
var flags = (ulong)(allFlags & Selection.Application.Equip);
|
||||
using var id = Im.Id.Push(label);
|
||||
var bigChange = Im.Checkbox($"Apply All {label}", ref flags, (ulong)allFlags);
|
||||
if (stain)
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : _selection.Design!.DoApplyStain(slot);
|
||||
if (ImUtf8.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
|
||||
_manager.ChangeApplyStains(_selection.Design!, slot, apply);
|
||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : Selection.DoApplyStain(slot);
|
||||
if (Im.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
|
||||
_manager.ChangeApplyStains(Selection, slot, apply);
|
||||
}
|
||||
else
|
||||
foreach (var slot in slots)
|
||||
{
|
||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : _selection.Design!.DoApplyEquip(slot);
|
||||
if (ImUtf8.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
|
||||
_manager.ChangeApplyItem(_selection.Design!, slot, apply);
|
||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : Selection.DoApplyEquip(slot);
|
||||
if (Im.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
|
||||
_manager.ChangeApplyItem(Selection, slot, apply);
|
||||
}
|
||||
}
|
||||
|
||||
ApplyEquip("Weapons", ApplicationTypeExtensions.WeaponFlags, false, new[]
|
||||
{
|
||||
EquipSlot.MainHand,
|
||||
EquipSlot.OffHand,
|
||||
});
|
||||
ApplyEquip("Weapons", ApplicationTypeExtensions.WeaponFlags, false, [EquipSlot.MainHand, EquipSlot.OffHand]);
|
||||
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
ApplyEquip("Armor", ApplicationTypeExtensions.ArmorFlags, false, EquipSlotExtensions.EquipmentSlots);
|
||||
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
ApplyEquip("Accessories", ApplicationTypeExtensions.AccessoryFlags, false, EquipSlotExtensions.AccessorySlots);
|
||||
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
ApplyEquip("Dyes", ApplicationTypeExtensions.StainFlags, true,
|
||||
EquipSlotExtensions.FullSlots);
|
||||
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
DrawParameterApplication();
|
||||
|
||||
ImUtf8.IconDummy();
|
||||
Im.FrameDummy();
|
||||
DrawBonusSlotApplication();
|
||||
}
|
||||
}
|
||||
|
|
@ -327,9 +295,9 @@ public class DesignPanel : IPanel
|
|||
var enabled = _config.DeleteDesignModifier.IsActive();
|
||||
bool? equip = null;
|
||||
bool? customize = null;
|
||||
var size = new Vector2(210 * Im.Style.GlobalScale, 0);
|
||||
if (ImUtf8.ButtonEx("Disable Everything"u8,
|
||||
"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8, size,
|
||||
var size = ImEx.ScaledVectorX(210);
|
||||
if (ImEx.Button("Disable Everything"u8, size,
|
||||
"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8,
|
||||
!enabled))
|
||||
{
|
||||
equip = false;
|
||||
|
|
@ -337,11 +305,11 @@ public class DesignPanel : IPanel
|
|||
}
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImUtf8.ButtonEx("Enable Everything"u8,
|
||||
"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8, size,
|
||||
if (ImEx.Button("Enable Everything"u8, size,
|
||||
"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8,
|
||||
!enabled))
|
||||
{
|
||||
equip = true;
|
||||
|
|
@ -349,10 +317,10 @@ public class DesignPanel : IPanel
|
|||
}
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
if (ImUtf8.ButtonEx("Equipment Only"u8,
|
||||
"Enable application of anything related to gear, disable anything that is not related to gear."u8, size,
|
||||
if (ImEx.Button("Equipment Only"u8, size,
|
||||
"Enable application of anything related to gear, disable anything that is not related to gear."u8,
|
||||
!enabled))
|
||||
{
|
||||
equip = true;
|
||||
|
|
@ -360,11 +328,11 @@ public class DesignPanel : IPanel
|
|||
}
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImUtf8.ButtonEx("Customization Only"u8,
|
||||
"Enable application of anything related to customization, disable anything that is not related to customization."u8, size,
|
||||
if (ImEx.Button("Customization Only"u8, size,
|
||||
"Enable application of anything related to customization, disable anything that is not related to customization."u8,
|
||||
!enabled))
|
||||
{
|
||||
equip = false;
|
||||
|
|
@ -372,85 +340,82 @@ public class DesignPanel : IPanel
|
|||
}
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
if (ImUtf8.ButtonEx("Default Application"u8,
|
||||
if (ImEx.Button("Default Application"u8, size,
|
||||
"Set the application rules to the default values as if the design was newly created, without any advanced features or wetness."u8,
|
||||
size,
|
||||
!enabled))
|
||||
{
|
||||
_manager.ChangeApplyMulti(_selection.Design!, true, true, true, false, true, true, false, true);
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.Wetness, false);
|
||||
_manager.ChangeApplyMulti(Selection, true, true, true, false, true, true, false, true);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.Wetness, false);
|
||||
}
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImUtf8.ButtonEx("Disable Advanced"u8, "Disable all advanced dyes and customizations but keep everything else as is."u8,
|
||||
size,
|
||||
!enabled))
|
||||
_manager.ChangeApplyMulti(_selection.Design!, null, null, null, false, null, null, false, null);
|
||||
if (ImEx.Button("Disable Advanced"u8, size, "Disable all advanced dyes and customizations but keep everything else as is."u8, !enabled))
|
||||
_manager.ChangeApplyMulti(Selection, null, null, null, false, null, null, false, null);
|
||||
|
||||
if (!enabled)
|
||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
if (equip is null && customize is null)
|
||||
return;
|
||||
|
||||
_manager.ChangeApplyMulti(_selection.Design!, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null,
|
||||
_manager.ChangeApplyMulti(Selection, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null,
|
||||
equip, equip, equip);
|
||||
if (equip.HasValue)
|
||||
{
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.HatState, equip.Value);
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.VisorState, equip.Value);
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.WeaponState, equip.Value);
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.EarState, equip.Value);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.HatState, equip.Value);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.VisorState, equip.Value);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.WeaponState, equip.Value);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.EarState, equip.Value);
|
||||
}
|
||||
|
||||
if (customize.HasValue)
|
||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.Wetness, customize.Value);
|
||||
_manager.ChangeApplyMeta(Selection, MetaIndex.Wetness, customize.Value);
|
||||
}
|
||||
|
||||
private static readonly IReadOnlyList<string> MetaLabels =
|
||||
private static readonly IReadOnlyList<StringU8> MetaLabels =
|
||||
[
|
||||
"Apply Wetness",
|
||||
"Apply Hat Visibility",
|
||||
"Apply Visor State",
|
||||
"Apply Weapon Visibility",
|
||||
"Apply Viera Ear Visibility",
|
||||
new("Apply Wetness"u8),
|
||||
new("Apply Hat Visibility"u8),
|
||||
new("Apply Visor State"u8),
|
||||
new("Apply Weapon Visibility"u8),
|
||||
new("Apply Viera Ear Visibility"u8),
|
||||
];
|
||||
|
||||
private void DrawMetaApplication()
|
||||
{
|
||||
using var id = ImUtf8.PushId("Meta");
|
||||
const uint all = (uint)MetaExtensions.All;
|
||||
var flags = (uint)_selection.Design!.Application.Meta;
|
||||
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
|
||||
using var id = Im.Id.Push("Meta"u8);
|
||||
const ulong all = (ulong)MetaExtensions.All;
|
||||
var flags = (ulong)Selection.Application.Meta;
|
||||
var bigChange = Im.Checkbox("Apply All Meta Changes"u8, ref flags, all);
|
||||
|
||||
foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(MetaLabels))
|
||||
{
|
||||
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selection.Design!.DoApplyMeta(index);
|
||||
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
|
||||
_manager.ChangeApplyMeta(_selection.Design!, index, apply);
|
||||
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : Selection.DoApplyMeta(index);
|
||||
if (Im.Checkbox(label, ref apply) || bigChange)
|
||||
_manager.ChangeApplyMeta(Selection, index, apply);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly IReadOnlyList<string> BonusSlotLabels =
|
||||
private static readonly IReadOnlyList<StringU8> BonusSlotLabels =
|
||||
[
|
||||
"Apply Facewear",
|
||||
new("Apply Facewear"u8),
|
||||
];
|
||||
|
||||
private void DrawBonusSlotApplication()
|
||||
{
|
||||
using var id = ImUtf8.PushId("Bonus"u8);
|
||||
var flags = _selection.Design!.Application.BonusItem;
|
||||
var bigChange = BonusExtensions.AllFlags.Count > 1 && ImUtf8.Checkbox("Apply All Bonus Slots"u8, ref flags, BonusExtensions.All);
|
||||
using var id = Im.Id.Push("Bonus"u8);
|
||||
var flags = Selection.Application.BonusItem;
|
||||
var bigChange = BonusExtensions.AllFlags.Count > 1 && Im.Checkbox("Apply All Bonus Slots"u8, ref flags, BonusExtensions.All);
|
||||
foreach (var (index, label) in BonusExtensions.AllFlags.Zip(BonusSlotLabels))
|
||||
{
|
||||
var apply = bigChange ? flags.HasFlag(index) : _selection.Design!.DoApplyBonusItem(index);
|
||||
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
|
||||
_manager.ChangeApplyBonusItem(_selection.Design!, index, apply);
|
||||
var apply = bigChange ? flags.HasFlag(index) : Selection.DoApplyBonusItem(index);
|
||||
if (Im.Checkbox(label, ref apply) || bigChange)
|
||||
_manager.ChangeApplyBonusItem(Selection, index, apply);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -458,69 +423,62 @@ public class DesignPanel : IPanel
|
|||
private void DrawParameterApplication()
|
||||
{
|
||||
using var id = Im.Id.Push("Parameter"u8);
|
||||
var flags = (ulong)_selection.Design!.Application.Parameters;
|
||||
var flags = (ulong)Selection.Application.Parameters;
|
||||
var bigChange = Im.Checkbox("Apply All Customize Parameters"u8, ref flags, (ulong)CustomizeParameterExtensions.All);
|
||||
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
||||
{
|
||||
var apply = bigChange ? ((CustomizeParameterFlag)flags).HasFlag(flag) : _selection.Design!.DoApplyParameter(flag);
|
||||
var apply = bigChange ? ((CustomizeParameterFlag)flags).HasFlag(flag) : Selection.DoApplyParameter(flag);
|
||||
if (Im.Checkbox($"Apply {flag.ToNameU8()}", ref apply) || bigChange)
|
||||
_manager.ChangeApplyParameter(_selection.Design!, flag, apply);
|
||||
_manager.ChangeApplyParameter(Selection, flag, apply);
|
||||
}
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Id
|
||||
=> "Designs"u8;
|
||||
=> "DesignPanel"u8;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var group = ImUtf8.Group();
|
||||
//if (_selection.DesignPaths.Count > 1)
|
||||
if (false)
|
||||
_importService.CreateDatSource();
|
||||
if (_fileSystem.Selection.OrderedNodes.Count > 1)
|
||||
{
|
||||
_multiDesignPanel.Draw();
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
DrawPanel();
|
||||
|
||||
if (_fileSystem.Selection.Selection is null || Selection.WriteProtected())
|
||||
return;
|
||||
|
||||
if (_importService.CreateDatTarget(out var dat))
|
||||
{
|
||||
DrawHeader();
|
||||
DrawPanel();
|
||||
|
||||
if (_selection.Design == null || _selection.Design.WriteProtected())
|
||||
return;
|
||||
|
||||
if (_importService.CreateDatTarget(out var dat))
|
||||
{
|
||||
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
|
||||
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
|
||||
foreach (var idx in CustomizationExtensions.AllBasic)
|
||||
_manager.ChangeCustomize(_selection.Design!, idx, dat.Customize[idx]);
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Applied games .dat file {dat.Description} customizations to {_selection.Design.Name}.", NotificationType.Success, false);
|
||||
}
|
||||
else if (_importService.CreateCharaTarget(out var designBase, out var name))
|
||||
{
|
||||
_manager.ApplyDesign(_selection.Design!, designBase);
|
||||
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selection.Design.Name}.",
|
||||
NotificationType.Success, false);
|
||||
}
|
||||
_manager.ChangeCustomize(Selection, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
|
||||
_manager.ChangeCustomize(Selection, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
|
||||
foreach (var idx in CustomizationExtensions.AllBasic)
|
||||
_manager.ChangeCustomize(Selection, idx, dat.Customize[idx]);
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Applied games .dat file {dat.Description} customizations to {Selection.Name}.", NotificationType.Success, false);
|
||||
}
|
||||
else if (_importService.CreateCharaTarget(out var designBase, out var name))
|
||||
{
|
||||
_manager.ApplyDesign(Selection, designBase);
|
||||
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {Selection.Name}.",
|
||||
NotificationType.Success, false);
|
||||
}
|
||||
|
||||
_importService.CreateDatSource();
|
||||
}
|
||||
|
||||
private void DrawPanel()
|
||||
{
|
||||
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.BordersOuter | TableFlags.ScrollY, Im.ContentRegion.Available);
|
||||
if (!table || _selection.Design is null)
|
||||
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.ScrollY, Im.ContentRegion.Available);
|
||||
if (!table || _fileSystem.Selection.Selection is null)
|
||||
return;
|
||||
|
||||
ImGui.TableSetupScrollFreeze(0, 1);
|
||||
ImGui.TableNextColumn();
|
||||
if (_selection.Design is null)
|
||||
return;
|
||||
table.SetupScrollFreeze(0, 1);
|
||||
table.NextColumn();
|
||||
|
||||
Im.Dummy(Vector2.Zero);
|
||||
DrawButtonRow();
|
||||
ImGui.TableNextColumn();
|
||||
table.NextColumn();
|
||||
|
||||
DrawCustomize();
|
||||
DrawEquipment();
|
||||
|
|
@ -547,15 +505,15 @@ public class DesignPanel : IPanel
|
|||
private void DrawApplyToSelf()
|
||||
{
|
||||
var (id, data) = _objects.PlayerData;
|
||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero,
|
||||
"Apply the current design with its settings to your character.\nHold Control to only apply gear.\nHold Shift to only apply customizations.",
|
||||
if (!ImEx.Button("Apply to Yourself"u8, Vector2.Zero,
|
||||
"Apply the current design with its settings to your character.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8,
|
||||
!data.Valid))
|
||||
return;
|
||||
|
||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||
{
|
||||
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
using var _ = Selection.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||
_state.ApplyDesign(state, Selection, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -564,33 +522,33 @@ public class DesignPanel : IPanel
|
|||
var (id, data) = _objects.TargetData;
|
||||
var tt = id.IsValid
|
||||
? data.Valid
|
||||
? "Apply the current design with its settings to your current target.\nHold Control to only apply gear.\nHold Shift to only apply customizations."
|
||||
: "The current target can not be manipulated."
|
||||
: "No valid target selected.";
|
||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid))
|
||||
? "Apply the current design with its settings to your current target.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8
|
||||
: "The current target can not be manipulated."u8
|
||||
: "No valid target selected."u8;
|
||||
if (!ImEx.Button("Apply to Target"u8, Vector2.Zero, tt, !data.Valid))
|
||||
return;
|
||||
|
||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||
{
|
||||
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
using var _ = Selection.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||
_state.ApplyDesign(state, Selection, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawSaveToDat()
|
||||
{
|
||||
var verified = _importService.Verify(_selection.Design!.DesignData.Customize, out _);
|
||||
var verified = _importService.Verify(Selection.DesignData.Customize, out _);
|
||||
var tt = verified
|
||||
? "Export the currently configured customizations of this design to a character creation data file."
|
||||
: "The current design contains customizations that can not be applied during character creation.";
|
||||
? "Export the currently configured customizations of this design to a character creation data file."u8
|
||||
: "The current design contains customizations that can not be applied during character creation."u8;
|
||||
var startPath = GetUserPath();
|
||||
if (startPath.Length == 0)
|
||||
if (startPath.Length is 0)
|
||||
startPath = null;
|
||||
if (ImGuiUtil.DrawDisabledButton("Export to Dat", Vector2.Zero, tt, !verified))
|
||||
if (ImEx.Button("Export to Dat"u8, Vector2.Zero, tt, !verified))
|
||||
_fileDialog.SaveFileDialog("Save File...", ".dat", "FFXIV_CHARA_01.dat", ".dat", (v, path) =>
|
||||
{
|
||||
if (v && _selection.Design != null)
|
||||
_importService.SaveDesignAsDat(path, _selection.Design!.DesignData.Customize, _selection.Design!.Name);
|
||||
if (v && _fileSystem.Selection.Selection?.GetValue<Design>() is not null)
|
||||
_importService.SaveDesignAsDat(path, Selection.DesignData.Customize, Selection.Name);
|
||||
}, startPath);
|
||||
|
||||
_fileDialog.Draw();
|
||||
|
|
@ -598,165 +556,4 @@ public class DesignPanel : IPanel
|
|||
|
||||
private static unsafe string GetUserPath()
|
||||
=> Framework.Instance()->UserPathString;
|
||||
|
||||
|
||||
|
||||
private sealed class LockButton(DesignPanel panel) : Button
|
||||
{
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null;
|
||||
|
||||
protected override string Description
|
||||
=> panel._selection.Design!.WriteProtected()
|
||||
? "Make this design editable."
|
||||
: "Write-protect this design.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> panel._selection.Design!.WriteProtected()
|
||||
? FontAwesomeIcon.Lock
|
||||
: FontAwesomeIcon.LockOpen;
|
||||
|
||||
protected override void OnClick()
|
||||
=> panel._manager.SetWriteProtection(panel._selection.Design!, !panel._selection.Design!.WriteProtected());
|
||||
}
|
||||
|
||||
private sealed class SetFromClipboardButton(DesignPanel panel) : Button
|
||||
{
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null;
|
||||
|
||||
protected override bool Disabled
|
||||
=> panel._selection.Design?.WriteProtected() ?? true;
|
||||
|
||||
protected override string Description
|
||||
=> "Try to apply a design from your clipboard over this design.\nHold Control to only apply gear.\nHold Shift to only apply customizations.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Clipboard;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = ImGui.GetClipboardText();
|
||||
var (applyEquip, applyCustomize) = UiHelpers.ConvertKeysToBool();
|
||||
var design = panel._converter.FromBase64(text, applyCustomize, applyEquip, out _)
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
panel._manager.ApplyDesign(panel._selection.Design!, design);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {panel._selection.Design!.Name}.",
|
||||
$"Could not apply clipboard to design {panel._selection.Design!.Identifier}", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class DesignUndoButton(DesignPanel panel) : Button
|
||||
{
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null;
|
||||
|
||||
protected override bool Disabled
|
||||
=> !panel._manager.CanUndo(panel._selection.Design) || (panel._selection.Design?.WriteProtected() ?? true);
|
||||
|
||||
protected override string Description
|
||||
=> "Undo the last time you applied an entire design onto this design, if you accidentally overwrote your design with a different one.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.SyncAlt;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
panel._manager.UndoDesignChange(panel._selection.Design!);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not undo last changes to {panel._selection.Design!.Name}.",
|
||||
NotificationType.Error,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ExportToClipboardButton(DesignPanel panel) : Button
|
||||
{
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null;
|
||||
|
||||
protected override string Description
|
||||
=> "Copy the current design to your clipboard.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Copy;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = panel._converter.ShareBase64(panel._selection.Design!);
|
||||
ImGui.SetClipboardText(text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {panel._selection.Design!.Name} data to clipboard.",
|
||||
$"Could not copy data from design {panel._selection.Design!.Identifier} to clipboard", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class ApplyCharacterButton(DesignPanel panel) : Button
|
||||
{
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null && panel._objects.Player.Valid;
|
||||
|
||||
protected override string Description
|
||||
=> "Overwrite this design with your character's current state.";
|
||||
|
||||
protected override bool Disabled
|
||||
=> panel._selection.Design?.WriteProtected() ?? true;
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.UserEdit;
|
||||
|
||||
protected override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var (player, actor) = panel._objects.PlayerData;
|
||||
if (!player.IsValid || !actor.Valid || !panel._state.GetOrCreate(player, actor.Objects[0], out var state))
|
||||
throw new Exception("No player state available.");
|
||||
|
||||
var design = panel._converter.Convert(state, ApplicationRules.FromModifiers(state))
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
panel._selection.Design!.GetMaterialDataRef().Clear();
|
||||
panel._manager.ApplyDesign(panel._selection.Design!, design);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply player state to {panel._selection.Design!.Name}.",
|
||||
$"Could not apply player state to design {panel._selection.Design!.Identifier}", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class UndoButton(DesignPanel panel) : Button
|
||||
{
|
||||
protected override string Description
|
||||
=> "Undo the last change.";
|
||||
|
||||
protected override FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.Undo;
|
||||
|
||||
public override bool Visible
|
||||
=> panel._selection.Design != null;
|
||||
|
||||
protected override bool Disabled
|
||||
=> (panel._selection.Design?.WriteProtected() ?? true) || !panel._history.CanUndo(panel._selection.Design);
|
||||
|
||||
protected override void OnClick()
|
||||
=> panel._history.Undo(panel._selection.Design!);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +0,0 @@
|
|||
using Glamourer.Designs;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignSelection : IUiService, IDisposable
|
||||
{
|
||||
public Design? Design { get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{ }
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop;
|
||||
using ImSharp;
|
||||
|
|
@ -7,36 +7,55 @@ using Luna;
|
|||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignTab(DesignFileSystemSelector selector, DesignPanel panel, ImportService importService, DesignManager manager)
|
||||
: ITab<MainTabType>
|
||||
public sealed class DesignTab : TwoPanelLayout, ITab<MainTabType>
|
||||
{
|
||||
public ReadOnlySpan<byte> Label
|
||||
private readonly ImportService _importService;
|
||||
private readonly DesignManager _manager;
|
||||
private readonly UiConfig _uiConfig;
|
||||
|
||||
public DesignTab(DesignFileSystemDrawer drawer, DesignPanel panel, ImportService importService, DesignManager manager, DesignFilter filter,
|
||||
DesignHeader header, UiConfig uiConfig)
|
||||
{
|
||||
LeftHeader = drawer.Header;
|
||||
LeftPanel = drawer;
|
||||
LeftFooter = drawer.Footer;
|
||||
|
||||
RightHeader = header;
|
||||
RightPanel = panel;
|
||||
RightFooter = NopHeaderFooter.Instance;
|
||||
_importService = importService;
|
||||
_manager = manager;
|
||||
_uiConfig = uiConfig;
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Label
|
||||
=> "Designs"u8;
|
||||
|
||||
public MainTabType Identifier
|
||||
=> MainTabType.Designs;
|
||||
|
||||
public void DrawContent()
|
||||
protected override void DrawLeftGroup(in TwoPanelWidth width)
|
||||
{
|
||||
selector.Draw();
|
||||
if (importService.CreateCharaTarget(out var designBase, out var name))
|
||||
base.DrawLeftGroup(in width);
|
||||
if (_importService.CreateCharaTarget(out var designBase, out var name))
|
||||
{
|
||||
var newDesign = manager.CreateClone(designBase, name, true);
|
||||
var newDesign = _manager.CreateClone(designBase, name, true);
|
||||
Glamourer.Messager.NotificationMessage($"Imported Anamnesis .chara file {name} as new design {newDesign.Name}",
|
||||
NotificationType.Success, false);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
panel.Draw();
|
||||
importService.CreateCharaSource();
|
||||
_importService.CreateCharaSource();
|
||||
}
|
||||
|
||||
//protected override void SetWidth(float width, ScalingMode mode)
|
||||
// => _uiConfig.ActorsTabScale = new TwoPanelWidth(width, mode);
|
||||
//
|
||||
//protected override float MinimumWidth
|
||||
// => LeftFooter.MinimumWidth;
|
||||
//
|
||||
//protected override float MaximumWidth
|
||||
// => Im.Window.Width - 500 * Im.Style.GlobalScale;
|
||||
protected override float MinimumWidth
|
||||
=> LeftFooter.MinimumWidth;
|
||||
|
||||
protected override float MaximumWidth
|
||||
=> Im.Window.Width - 500 * Im.Style.GlobalScale;
|
||||
|
||||
protected override void SetWidth(float width, ScalingMode mode)
|
||||
=> _uiConfig.DesignsTabScale = new TwoPanelWidth(width, mode);
|
||||
|
||||
|
||||
public void DrawContent()
|
||||
=> Draw(_uiConfig.DesignsTabScale);
|
||||
}
|
||||
|
|
|
|||
39
Glamourer/Gui/Tabs/DesignTab/DesignUndoButton.cs
Normal file
39
Glamourer/Gui/Tabs/DesignTab/DesignUndoButton.cs
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignUndoButton(DesignFileSystem fileSystem, DesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.ResetIcon;
|
||||
|
||||
public override bool Enabled
|
||||
=> !((Design)fileSystem.Selection.Selection!.Value).WriteProtected() && manager.CanUndo((Design)fileSystem.Selection.Selection!.Value);
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(
|
||||
"Undo the last time you applied an entire design onto this design, if you accidentally overwrote your design with a different one."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
manager.UndoDesignChange((Design)fileSystem.Selection.Selection!.Value);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex,
|
||||
$"Could not undo last changes to {((Design)fileSystem.Selection.Selection!.Value).Name}.",
|
||||
NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
36
Glamourer/Gui/Tabs/DesignTab/ExportToClipboardButton.cs
Normal file
36
Glamourer/Gui/Tabs/DesignTab/ExportToClipboardButton.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class ExportToClipboardButton(DesignFileSystem fileSystem, DesignConverter converter) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.ToClipboardIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Copy the current design to your clipboard."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
var design = (Design)fileSystem.Selection.Selection!.Value;
|
||||
try
|
||||
{
|
||||
var text = converter.ShareBase64(design);
|
||||
Im.Clipboard.Set(text);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not copy {design.Name} data to clipboard.",
|
||||
$"Could not copy data from design {design.Identifier} to clipboard", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
Glamourer/Gui/Tabs/DesignTab/LockButton.cs
Normal file
28
Glamourer/Gui/Tabs/DesignTab/LockButton.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class LockButton(DesignFileSystem fileSystem, DesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> ((Design)fileSystem.Selection.Selection!.Value).WriteProtected()
|
||||
? LunaStyle.LockedIcon
|
||||
: LunaStyle.UnlockedIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(((Design)fileSystem.Selection.Selection!.Value).WriteProtected()
|
||||
? "Make this design editable."u8
|
||||
: "Write-protect this design."u8);
|
||||
|
||||
public override void OnClick()
|
||||
=> manager.SetWriteProtection((Design)fileSystem.Selection.Selection!.Value,
|
||||
!((Design)fileSystem.Selection.Selection!.Value).WriteProtected());
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
|
|
@ -8,11 +8,14 @@ using Luna;
|
|||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public class ModAssociationsTab(PenumbraService penumbra, DesignSelection selection, DesignManager manager, Configuration.Configuration config)
|
||||
public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystem fileSystem, DesignManager manager, Configuration config)
|
||||
{
|
||||
private readonly ModCombo _modCombo = new(penumbra, selection);
|
||||
private readonly ModCombo _modCombo = new(penumbra, fileSystem);
|
||||
private (Mod, ModSettings)[]? _copy;
|
||||
|
||||
private Design Selection
|
||||
=> (Design)fileSystem.Selection.Selection!.Value;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
using var h = DesignPanelFlag.ModAssociations.Header(config);
|
||||
|
|
@ -36,7 +39,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
{
|
||||
var size = new Vector2((Im.ContentRegion.Available.X - 2 * Im.Style.ItemSpacing.X) / 3, 0);
|
||||
if (Im.Button("Copy All to Clipboard"u8, size))
|
||||
_copy = selection.Design!.AssociatedMods.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
||||
_copy = Selection.AssociatedMods.Select(kvp => (kvp.Key, kvp.Value)).ToArray();
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
|
|
@ -45,7 +48,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
? $"Add {_copy.Length} mod association(s) from clipboard."
|
||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||
foreach (var (mod, setting) in _copy!)
|
||||
manager.UpdateMod(selection.Design!, mod, setting);
|
||||
manager.UpdateMod(Selection, mod, setting);
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
|
|
@ -54,10 +57,10 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
? $"Set {_copy.Length} mod association(s) from clipboard and discard existing."
|
||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||
{
|
||||
while (selection.Design!.AssociatedMods.Count > 0)
|
||||
manager.RemoveMod(selection.Design!, selection.Design!.AssociatedMods.Keys[0]);
|
||||
while (Selection.AssociatedMods.Count > 0)
|
||||
manager.RemoveMod(Selection, Selection.AssociatedMods.Keys[0]);
|
||||
foreach (var (mod, setting) in _copy!)
|
||||
manager.AddMod(selection.Design!, mod, setting);
|
||||
manager.AddMod(Selection, mod, setting);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,13 +79,13 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
var (id, name) = penumbra.CurrentCollection;
|
||||
if (ImEx.Button("Apply Mod Associations"u8, Vector2.Zero,
|
||||
$"Try to apply all associated mod settings to Penumbras current collection {name}",
|
||||
selection.Design!.AssociatedMods.Count is 0 || id == Guid.Empty))
|
||||
Selection.AssociatedMods.Count is 0 || id == Guid.Empty))
|
||||
ApplyAll();
|
||||
}
|
||||
|
||||
public void ApplyAll()
|
||||
{
|
||||
foreach (var (mod, settings) in selection.Design!.AssociatedMods)
|
||||
foreach (var (mod, settings) in Selection.AssociatedMods)
|
||||
penumbra.SetMod(mod, settings, StateSource.Manual, false);
|
||||
}
|
||||
|
||||
|
|
@ -104,7 +107,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
|
||||
Mod? removedMod = null;
|
||||
(Mod mod, ModSettings settings)? updatedMod = null;
|
||||
foreach (var (idx, (mod, settings)) in selection.Design!.AssociatedMods.Index())
|
||||
foreach (var (idx, (mod, settings)) in Selection.AssociatedMods.Index())
|
||||
{
|
||||
using var id = Im.Id.Push(idx);
|
||||
DrawAssociatedModRow(table, mod, settings, out var removedModTmp, out var updatedModTmp);
|
||||
|
|
@ -117,10 +120,10 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
DrawNewModRow(table);
|
||||
|
||||
if (removedMod.HasValue)
|
||||
manager.RemoveMod(selection.Design!, removedMod.Value);
|
||||
manager.RemoveMod(Selection, removedMod.Value);
|
||||
|
||||
if (updatedMod.HasValue)
|
||||
manager.UpdateMod(selection.Design!, updatedMod.Value.mod, updatedMod.Value.settings);
|
||||
manager.UpdateMod(Selection, updatedMod.Value.mod, updatedMod.Value.settings);
|
||||
}
|
||||
|
||||
private void DrawAssociatedModRow(in Im.TableDisposable table, Mod mod, ModSettings settings, out Mod? removedMod,
|
||||
|
|
@ -245,12 +248,12 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
|||
table.NextColumn();
|
||||
var tt = currentDir.Length is 0
|
||||
? "Please select a mod first."u8
|
||||
: selection.Design!.AssociatedMods.ContainsKey(new Mod(_modCombo.SelectionName, currentDir))
|
||||
: Selection.AssociatedMods.ContainsKey(new Mod(_modCombo.SelectionName, currentDir))
|
||||
? "The design already contains an association with the selected mod."u8
|
||||
: StringU8.Empty;
|
||||
|
||||
if (ImEx.Icon.Button(LunaStyle.AddObjectIcon, tt, tt.Length > 0))
|
||||
manager.AddMod(selection.Design!, new Mod(_modCombo.SelectionName, _modCombo.Selection), _modCombo.Settings);
|
||||
manager.AddMod(Selection, new Mod(_modCombo.SelectionName, _modCombo.Selection), _modCombo.Settings);
|
||||
table.NextColumn();
|
||||
_modCombo.Draw("##new"u8, Im.ContentRegion.Available.X);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImSharp;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class ModCombo(PenumbraService penumbra, DesignSelection selection) : FilterComboBase<ModCombo.CacheItem>(new ModFilter())
|
||||
public sealed class ModCombo(PenumbraService penumbra, DesignFileSystem fileSystem) : FilterComboBase<ModCombo.CacheItem>(new ModFilter())
|
||||
{
|
||||
public readonly struct CacheItem(in Mod mod, in ModSettings settings, int count)
|
||||
{
|
||||
|
|
@ -42,7 +43,7 @@ public sealed class ModCombo(PenumbraService penumbra, DesignSelection selection
|
|||
=> Im.Style.TextHeightWithSpacing;
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
=> penumbra.GetMods(selection.Design?.FilteredItemNames.ToArray() ?? []).Select(t => new CacheItem(t.Mod, t.Settings, t.Count));
|
||||
=> penumbra.GetMods(fileSystem.Selection.Selection?.GetValue<Design>()?.FilteredItemNames.ToArray() ?? []).Select(t => new CacheItem(t.Mod, t.Settings, t.Count));
|
||||
|
||||
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Material;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
|
@ -6,21 +7,21 @@ using Luna;
|
|||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public class MultiDesignPanel(
|
||||
DesignFileSystemSelector selector,
|
||||
DesignFileSystem fileSystem,
|
||||
DesignManager editor,
|
||||
DesignColors colors,
|
||||
Configuration.Configuration config)
|
||||
Configuration config)
|
||||
{
|
||||
private readonly DesignColorCombo _colorCombo = new(colors, true);
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (selector.SelectedPaths.Count == 0)
|
||||
if (fileSystem.Selection.OrderedNodes.Count is 0)
|
||||
return;
|
||||
|
||||
var width = ImEx.ScaledVectorX(145);
|
||||
var treeNodePos = Im.Cursor.Position;
|
||||
_numDesigns = DrawDesignList();
|
||||
DrawDesignList();
|
||||
DrawCounts(treeNodePos);
|
||||
var offset = DrawMultiTagger(width);
|
||||
DrawMultiColor(width, offset);
|
||||
|
|
@ -36,14 +37,15 @@ public class MultiDesignPanel(
|
|||
private void DrawCounts(Vector2 treeNodePos)
|
||||
{
|
||||
var startPos = Im.Cursor.Position;
|
||||
var numFolders = selector.SelectedPaths.Count - _numDesigns;
|
||||
var numDesigns = fileSystem.Selection.DataNodes.Count;
|
||||
var numFolders = fileSystem.Selection.Folders.Count;
|
||||
Im.Cursor.Position = treeNodePos;
|
||||
ImEx.TextRightAligned((_numDesigns, numFolders) switch
|
||||
ImEx.TextRightAligned((numDesigns, numFolders) switch
|
||||
{
|
||||
(0, 0) => StringU8.Empty, // should not happen
|
||||
( > 0, 0) => $"{_numDesigns} Designs",
|
||||
(0, > 0) => $"{numFolders} Folders",
|
||||
_ => $"{_numDesigns} Designs, {numFolders} Folders",
|
||||
(0, 0) => StringU8.Empty, // should not happen
|
||||
(> 0, 0) => $"{numDesigns} Designs",
|
||||
(0, > 0) => $"{numFolders} Folders",
|
||||
_ => $"{numDesigns} Designs, {numFolders} Folders",
|
||||
});
|
||||
Im.Cursor.Position = startPos;
|
||||
}
|
||||
|
|
@ -59,10 +61,10 @@ public class MultiDesignPanel(
|
|||
_numAdvancedDyes = 0;
|
||||
}
|
||||
|
||||
private bool CountLeaves(DesignFileSystem.IPath path)
|
||||
private void CountLeaves(IFileSystemNode path)
|
||||
{
|
||||
if (path is not DesignFileSystem.Leaf l)
|
||||
return false;
|
||||
if (path is not IFileSystemData<Design> l)
|
||||
return;
|
||||
|
||||
if (l.Value.QuickDesign)
|
||||
++_numQuickDesignEnabled;
|
||||
|
|
@ -79,55 +81,48 @@ public class MultiDesignPanel(
|
|||
++_numDesignsWithAdvancedDyes;
|
||||
_numAdvancedDyes += l.Value.Materials.Count;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private int DrawDesignList()
|
||||
private void DrawDesignList()
|
||||
{
|
||||
ResetCounts();
|
||||
using var tree = Im.Tree.Node("Currently Selected Objects"u8, TreeNodeFlags.DefaultOpen | TreeNodeFlags.NoTreePushOnOpen);
|
||||
Im.Separator();
|
||||
if (!tree)
|
||||
return selector.SelectedPaths.Count(CountLeaves);
|
||||
return;
|
||||
|
||||
var sizeType = new Vector2(Im.Style.FrameHeight);
|
||||
var availableSizePercent = (Im.ContentRegion.Available.X - sizeType.X - 4 * Im.Style.CellPadding.X) / 100;
|
||||
var sizeMods = availableSizePercent * 35;
|
||||
var sizeFolders = availableSizePercent * 65;
|
||||
|
||||
var numDesigns = 0;
|
||||
using (var table = Im.Table.Begin("mods"u8, 3, TableFlags.RowBackground))
|
||||
{
|
||||
if (!table)
|
||||
return selector.SelectedPaths.Count(l => l is DesignFileSystem.Leaf);
|
||||
return;
|
||||
|
||||
table.SetupColumn("type"u8, TableColumnFlags.WidthFixed, sizeType.X);
|
||||
table.SetupColumn("mod"u8, TableColumnFlags.WidthFixed, sizeMods);
|
||||
table.SetupColumn("path"u8, TableColumnFlags.WidthFixed, sizeFolders);
|
||||
|
||||
var i = 0;
|
||||
foreach (var (fullName, path) in selector.SelectedPaths.Select(p => (p.FullName(), p))
|
||||
.OrderBy(p => p.Item1, StringComparer.OrdinalIgnoreCase))
|
||||
foreach (var (index, node) in fileSystem.Selection.OrderedNodes.Index())
|
||||
{
|
||||
using var id = Im.Id.Push(i++);
|
||||
var (icon, text) = path is DesignFileSystem.Leaf l
|
||||
using var id = Im.Id.Push(index);
|
||||
var (icon, text) = node is IFileSystemData<Design> l
|
||||
? (LunaStyle.RemoveFileIcon, l.Value.Name.Text)
|
||||
: (LunaStyle.RemoveFolderIcon, string.Empty);
|
||||
table.NextColumn();
|
||||
if (ImEx.Icon.Button(icon, "Remove from selection."u8, sizeType))
|
||||
selector.RemovePathFromMultiSelection(path);
|
||||
fileSystem.Selection.RemoveFromSelection(node);
|
||||
|
||||
table.DrawFrameColumn(text);
|
||||
table.DrawFrameColumn(fullName);
|
||||
table.DrawFrameColumn(node.FullPath);
|
||||
|
||||
if (CountLeaves(path))
|
||||
++numDesigns;
|
||||
CountLeaves(node);
|
||||
}
|
||||
}
|
||||
|
||||
Im.Separator();
|
||||
return numDesigns;
|
||||
}
|
||||
|
||||
private string _tag = string.Empty;
|
||||
|
|
@ -138,7 +133,6 @@ public class MultiDesignPanel(
|
|||
private int _numDesignsResetDyes;
|
||||
private int _numAdvancedDyes;
|
||||
private int _numDesignsWithAdvancedDyes;
|
||||
private int _numDesigns;
|
||||
private readonly List<Design> _addDesigns = [];
|
||||
private readonly List<(Design, int)> _removeDesigns = [];
|
||||
|
||||
|
|
@ -153,23 +147,25 @@ public class MultiDesignPanel(
|
|||
UpdateTagCache();
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button(_addDesigns.Count > 0
|
||||
? $"Add to {_addDesigns.Count} Designs"
|
||||
: "Add"u8, width, _addDesigns.Count is 0
|
||||
? _tag.Length is 0
|
||||
? "No tag specified."u8
|
||||
: $"All designs selected already contain the tag \"{_tag}\"."
|
||||
: $"Add the tag \"{_tag}\" to {_addDesigns.Count} designs as a local tag:\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}", _addDesigns.Count is 0))
|
||||
? $"Add to {_addDesigns.Count} Designs"
|
||||
: "Add"u8, width, _addDesigns.Count is 0
|
||||
? _tag.Length is 0
|
||||
? "No tag specified."u8
|
||||
: $"All designs selected already contain the tag \"{_tag}\"."
|
||||
: $"Add the tag \"{_tag}\" to {_addDesigns.Count} designs as a local tag:\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}",
|
||||
_addDesigns.Count is 0))
|
||||
foreach (var design in _addDesigns)
|
||||
editor.AddTag(design, _tag);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button(_removeDesigns.Count > 0
|
||||
? $"Remove from {_removeDesigns.Count} Designs"
|
||||
: "Remove", width, _removeDesigns.Count is 0
|
||||
? _tag.Length is 0
|
||||
? "No tag specified."u8
|
||||
: $"No selected design contains the tag \"{_tag}\" locally."
|
||||
: $"Remove the local tag \"{_tag}\" from {_removeDesigns.Count} designs:\n\n\t{string.Join("\n\t", _removeDesigns.Select(m => m.Item1.Name.Text))}", _removeDesigns.Count is 0))
|
||||
? $"Remove from {_removeDesigns.Count} Designs"
|
||||
: "Remove", width, _removeDesigns.Count is 0
|
||||
? _tag.Length is 0
|
||||
? "No tag specified."u8
|
||||
: $"No selected design contains the tag \"{_tag}\" locally."
|
||||
: $"Remove the local tag \"{_tag}\" from {_removeDesigns.Count} designs:\n\n\t{string.Join("\n\t", _removeDesigns.Select(m => m.Item1.Name.Text))}",
|
||||
_removeDesigns.Count is 0))
|
||||
foreach (var (design, index) in _removeDesigns)
|
||||
editor.RemoveTag(design, index);
|
||||
Im.Separator();
|
||||
|
|
@ -181,23 +177,21 @@ public class MultiDesignPanel(
|
|||
ImEx.TextFrameAligned("Multi QDB:"u8);
|
||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
||||
var diff = _numDesigns - _numQuickDesignEnabled;
|
||||
var diff = fileSystem.Selection.DataNodes.Count - _numQuickDesignEnabled;
|
||||
if (ImEx.Button("Display Selected Designs in QDB"u8, buttonWidth, diff is 0
|
||||
? $"All {_numDesigns} selected designs are already displayed in the quick design bar."
|
||||
: $"Display all {_numDesigns} selected designs in the quick design bar. Changes {diff} designs.", diff is 0))
|
||||
{
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.SetQuickDesign(design.Value, true);
|
||||
}
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs are already displayed in the quick design bar."
|
||||
: $"Display all {fileSystem.Selection.DataNodes.Count} selected designs in the quick design bar. Changes {diff} designs.",
|
||||
diff is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.SetQuickDesign(design.GetValue<Design>()!, true);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Hide Selected Designs in QDB"u8, buttonWidth, _numQuickDesignEnabled is 0
|
||||
? $"All {_numDesigns} selected designs are already hidden in the quick design bar."
|
||||
: $"Hide all {_numDesigns} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs.", _numQuickDesignEnabled is 0))
|
||||
{
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.SetQuickDesign(design.Value, false);
|
||||
}
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs are already hidden in the quick design bar."
|
||||
: $"Hide all {fileSystem.Selection.DataNodes.Count} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs.",
|
||||
_numQuickDesignEnabled is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.SetQuickDesign(design.GetValue<Design>()!, false);
|
||||
|
||||
Im.Separator();
|
||||
}
|
||||
|
|
@ -207,19 +201,20 @@ public class MultiDesignPanel(
|
|||
ImEx.TextFrameAligned("Multi Lock:"u8);
|
||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
||||
var diff = _numDesigns - _numDesignsLocked;
|
||||
var diff = fileSystem.Selection.DataNodes.Count - _numDesignsLocked;
|
||||
if (ImEx.Button("Turn Write-Protected"u8, buttonWidth, diff is 0
|
||||
? $"All {_numDesigns} selected designs are already write protected."
|
||||
: $"Write-protect all {_numDesigns} designs. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.SetWriteProtection(design.Value, true);
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs are already write protected."
|
||||
: $"Write-protect all {fileSystem.Selection.DataNodes.Count} designs. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.SetWriteProtection(design.GetValue<Design>()!, true);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Remove Write-Protection"u8, buttonWidth, _numDesignsLocked is 0
|
||||
? $"None of the {_numDesigns} selected designs are write-protected."
|
||||
: $"Remove the write protection of the {_numDesigns} selected designs. Changes {_numDesignsLocked} designs.", _numDesignsLocked is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.SetWriteProtection(design.Value, false);
|
||||
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs are write-protected."
|
||||
: $"Remove the write protection of the {fileSystem.Selection.DataNodes.Count} selected designs. Changes {_numDesignsLocked} designs.",
|
||||
_numDesignsLocked is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.SetWriteProtection(design.GetValue<Design>()!, false);
|
||||
Im.Separator();
|
||||
}
|
||||
|
||||
|
|
@ -228,19 +223,21 @@ public class MultiDesignPanel(
|
|||
ImEx.TextFrameAligned("Settings:"u8);
|
||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
||||
var diff = _numDesigns - _numDesignsResetSettings;
|
||||
var diff = fileSystem.Selection.DataNodes.Count - _numDesignsResetSettings;
|
||||
if (ImEx.Button("Set Reset Temp. Settings"u8, buttonWidth, diff is 0
|
||||
? $"All {_numDesigns} selected designs already reset temporary settings."
|
||||
: $"Make all {_numDesigns} selected designs reset temporary settings. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeResetTemporarySettings(design.Value, true);
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already reset temporary settings."
|
||||
: $"Make all {fileSystem.Selection.DataNodes.Count} selected designs reset temporary settings. Changes {diff} designs.",
|
||||
diff is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeResetTemporarySettings(design.GetValue<Design>()!, true);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Remove Reset Temp. Settings"u8, buttonWidth, _numDesignsResetSettings is 0
|
||||
? $"None of the {_numDesigns} selected designs reset temporary settings."
|
||||
: $"Stop all {_numDesigns} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.", _numDesignsResetSettings is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeResetTemporarySettings(design.Value, false);
|
||||
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs reset temporary settings."
|
||||
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.",
|
||||
_numDesignsResetSettings is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeResetTemporarySettings(design.GetValue<Design>()!, false);
|
||||
Im.Separator();
|
||||
}
|
||||
|
||||
|
|
@ -249,19 +246,20 @@ public class MultiDesignPanel(
|
|||
ImEx.TextFrameAligned("Adv. Dyes:"u8);
|
||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
||||
var diff = _numDesigns - _numDesignsResetDyes;
|
||||
var diff = fileSystem.Selection.DataNodes.Count - _numDesignsResetDyes;
|
||||
if (ImEx.Button("Set Reset Dyes"u8, buttonWidth, diff is 0
|
||||
? $"All {_numDesigns} selected designs already reset advanced dyes."
|
||||
: $"Make all {_numDesigns} selected designs reset advanced dyes. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeResetAdvancedDyes(design.Value, true);
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already reset advanced dyes."
|
||||
: $"Make all {fileSystem.Selection.DataNodes.Count} selected designs reset advanced dyes. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeResetAdvancedDyes(design.GetValue<Design>()!, true);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Remove Reset Dyes"u8, buttonWidth, _numDesignsLocked is 0
|
||||
? $"None of the {_numDesigns} selected designs reset advanced dyes."
|
||||
: $"Stop all {_numDesigns} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.", _numDesignsResetDyes is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeResetAdvancedDyes(design.Value, false);
|
||||
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs reset advanced dyes."
|
||||
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.",
|
||||
_numDesignsResetDyes is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeResetAdvancedDyes(design.GetValue<Design>()!, false);
|
||||
Im.Separator();
|
||||
}
|
||||
|
||||
|
|
@ -270,19 +268,20 @@ public class MultiDesignPanel(
|
|||
ImEx.TextFrameAligned("Redrawing:"u8);
|
||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
||||
var diff = _numDesigns - _numDesignsForcedRedraw;
|
||||
var diff = fileSystem.Selection.DataNodes.Count - _numDesignsForcedRedraw;
|
||||
if (ImEx.Button("Force Redraws"u8, buttonWidth, diff is 0
|
||||
? $"All {_numDesigns} selected designs already force redraws."
|
||||
: $"Make all {_numDesigns} designs force redraws. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeForcedRedraw(design.Value, true);
|
||||
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already force redraws."
|
||||
: $"Make all {fileSystem.Selection.DataNodes.Count} designs force redraws. Changes {diff} designs.", diff is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeForcedRedraw(design.GetValue<Design>()!, true);
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Remove Forced Redraws"u8, buttonWidth, _numDesignsLocked is 0
|
||||
? $"None of the {_numDesigns} selected designs force redraws."
|
||||
: $"Stop all {_numDesigns} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.", _numDesignsForcedRedraw is 0))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
editor.ChangeForcedRedraw(design.Value, false);
|
||||
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs force redraws."
|
||||
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.",
|
||||
_numDesignsForcedRedraw is 0))
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
editor.ChangeForcedRedraw(design.GetValue<Design>()!, false);
|
||||
Im.Separator();
|
||||
}
|
||||
|
||||
|
|
@ -299,30 +298,28 @@ public class MultiDesignPanel(
|
|||
UpdateColorCache();
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button(_addDesigns.Count > 0
|
||||
? $"Set for {_addDesigns.Count} Designs"
|
||||
: "Set"u8, width, _addDesigns.Count is 0
|
||||
? _colorComboSelection switch
|
||||
{
|
||||
null => "No color specified."u8,
|
||||
DesignColors.AutomaticName => "Use the other button to set to automatic."u8,
|
||||
_ => $"All designs selected are already set to the color \"{_colorComboSelection}\".",
|
||||
}
|
||||
: $"Set the color of {_addDesigns.Count} designs to \"{_colorComboSelection}\"\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}", _addDesigns.Count is 0))
|
||||
{
|
||||
? $"Set for {_addDesigns.Count} Designs"
|
||||
: "Set"u8, width, _addDesigns.Count is 0
|
||||
? _colorComboSelection switch
|
||||
{
|
||||
null => "No color specified."u8,
|
||||
DesignColors.AutomaticName => "Use the other button to set to automatic."u8,
|
||||
_ => $"All designs selected are already set to the color \"{_colorComboSelection}\".",
|
||||
}
|
||||
: $"Set the color of {_addDesigns.Count} designs to \"{_colorComboSelection}\"\n\n\t{StringU8.Join("\n\t"u8, _addDesigns.Select(m => m.Name.Text))}",
|
||||
_addDesigns.Count is 0))
|
||||
foreach (var design in _addDesigns)
|
||||
editor.ChangeColor(design, _colorComboSelection!);
|
||||
}
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button(_removeDesigns.Count > 0
|
||||
? $"Unset {_removeDesigns.Count} Designs"
|
||||
: "Unset"u8, width, _removeDesigns.Count is 0
|
||||
? "No selected design is set to a non-automatic color."u8
|
||||
: $"Set {_removeDesigns.Count} designs to use automatic color again:\n\n\t{StringU8.Join("\n\t"u8, _removeDesigns.Select(m => m.Item1.Name.Text))}", _removeDesigns.Count is 0))
|
||||
{
|
||||
? $"Unset {_removeDesigns.Count} Designs"
|
||||
: "Unset"u8, width, _removeDesigns.Count is 0
|
||||
? "No selected design is set to a non-automatic color."u8
|
||||
: $"Set {_removeDesigns.Count} designs to use automatic color again:\n\n\t{StringU8.Join("\n\t"u8, _removeDesigns.Select(m => m.Item1.Name.Text))}",
|
||||
_removeDesigns.Count is 0))
|
||||
foreach (var (design, _) in _removeDesigns)
|
||||
editor.ChangeColor(design, string.Empty);
|
||||
}
|
||||
|
||||
Im.Separator();
|
||||
}
|
||||
|
|
@ -333,14 +330,15 @@ public class MultiDesignPanel(
|
|||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||
var enabled = config.DeleteDesignModifier.IsActive();
|
||||
if (ImEx.Button("Delete All Advanced Dyes"u8, Im.ContentRegion.Available with { Y = 0 }, _numDesignsWithAdvancedDyes is 0
|
||||
? "No selected designs contain any advanced dyes."u8
|
||||
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.",
|
||||
? "No selected designs contain any advanced dyes."u8
|
||||
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.",
|
||||
!enabled || _numDesignsWithAdvancedDyes is 0))
|
||||
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
foreach (var design in fileSystem.Selection.DataNodes)
|
||||
{
|
||||
while (design.Value.Materials.Count > 0)
|
||||
editor.ChangeMaterialValue(design.Value, MaterialValueIndex.FromKey(design.Value.Materials[0].Item1), null);
|
||||
while (design.GetValue<Design>()!.Materials.Count > 0)
|
||||
editor.ChangeMaterialValue(design.GetValue<Design>()!,
|
||||
MaterialValueIndex.FromKey(design.GetValue<Design>()!.Materials[0].Item1), null);
|
||||
}
|
||||
|
||||
if (!enabled && _numDesignsWithAdvancedDyes is not 0)
|
||||
|
|
@ -359,8 +357,8 @@ public class MultiDesignPanel(
|
|||
using (Im.Group())
|
||||
{
|
||||
if (ImEx.Button("Disable Everything"u8, width,
|
||||
_numDesigns > 0
|
||||
? $"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
|
||||
fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||
: "No designs selected."u8, !enabled))
|
||||
{
|
||||
equip = false;
|
||||
|
|
@ -372,8 +370,8 @@ public class MultiDesignPanel(
|
|||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Enable Everything"u8, width,
|
||||
_numDesigns > 0
|
||||
? $"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
|
||||
fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||
: "No designs selected."u8, !enabled))
|
||||
{
|
||||
equip = true;
|
||||
|
|
@ -384,8 +382,8 @@ public class MultiDesignPanel(
|
|||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
if (ImEx.Button("Equipment Only"u8, width,
|
||||
_numDesigns > 0
|
||||
? $"Enable application of anything related to gear, disable anything that is not related to gear for all {_numDesigns} designs."
|
||||
fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Enable application of anything related to gear, disable anything that is not related to gear for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||
: "No designs selected."u8, !enabled))
|
||||
{
|
||||
equip = true;
|
||||
|
|
@ -397,8 +395,8 @@ public class MultiDesignPanel(
|
|||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Customization Only"u8, width,
|
||||
_numDesigns > 0
|
||||
? $"Enable application of anything related to customization, disable anything that is not related to customization for all {_numDesigns} designs."
|
||||
fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Enable application of anything related to customization, disable anything that is not related to customization for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||
: "No designs selected."u8, !enabled))
|
||||
{
|
||||
equip = false;
|
||||
|
|
@ -409,10 +407,10 @@ public class MultiDesignPanel(
|
|||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
if (ImEx.Button("Default Application"u8, width,
|
||||
_numDesigns > 0
|
||||
? $"Set the application rules to the default values as if the {_numDesigns} were newly created,without any advanced features or wetness."
|
||||
fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Set the application rules to the default values as if the {fileSystem.Selection.DataNodes.Count} were newly created,without any advanced features or wetness."
|
||||
: "No designs selected."u8, !enabled))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
|
||||
foreach (var design in fileSystem.Selection.DataNodes.Select(l => l.GetValue<Design>()!))
|
||||
{
|
||||
editor.ChangeApplyMulti(design, true, true, true, false, true, true, false, true);
|
||||
editor.ChangeApplyMeta(design, MetaIndex.Wetness, false);
|
||||
|
|
@ -422,10 +420,10 @@ public class MultiDesignPanel(
|
|||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||
|
||||
Im.Line.Same();
|
||||
if (ImEx.Button("Disable Advanced"u8, width, _numDesigns > 0
|
||||
? $"Disable all advanced dyes and customizations but keep everything else as is for all {_numDesigns} designs."
|
||||
if (ImEx.Button("Disable Advanced"u8, width, fileSystem.Selection.DataNodes.Count > 0
|
||||
? $"Disable all advanced dyes and customizations but keep everything else as is for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||
: "No designs selected."u8, !enabled))
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
|
||||
foreach (var design in fileSystem.Selection.DataNodes.Select(l => l.GetValue<Design>()!))
|
||||
editor.ChangeApplyMulti(design, null, null, null, false, null, null, false, null);
|
||||
|
||||
if (!enabled)
|
||||
|
|
@ -436,7 +434,7 @@ public class MultiDesignPanel(
|
|||
if (equip is null && customize is null)
|
||||
return;
|
||||
|
||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>().Select(l => l.Value))
|
||||
foreach (var design in fileSystem.Selection.DataNodes.Select(l => l.GetValue<Design>()!))
|
||||
{
|
||||
editor.ChangeApplyMulti(design, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null, equip, equip,
|
||||
equip);
|
||||
|
|
@ -459,13 +457,14 @@ public class MultiDesignPanel(
|
|||
if (_tag.Length is 0)
|
||||
return;
|
||||
|
||||
foreach (var leaf in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
foreach (var leaf in fileSystem.Selection.DataNodes)
|
||||
{
|
||||
var index = leaf.Value.Tags.AsEnumerable().IndexOf(_tag);
|
||||
var design = leaf.GetValue<Design>()!;
|
||||
var index = design.Tags.AsEnumerable().IndexOf(_tag);
|
||||
if (index >= 0)
|
||||
_removeDesigns.Add((leaf.Value, index));
|
||||
_removeDesigns.Add((design, index));
|
||||
else
|
||||
_addDesigns.Add(leaf.Value);
|
||||
_addDesigns.Add(design);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -474,12 +473,13 @@ public class MultiDesignPanel(
|
|||
_addDesigns.Clear();
|
||||
_removeDesigns.Clear();
|
||||
var selection = string.IsNullOrEmpty(_colorComboSelection) ? DesignColors.AutomaticName : _colorComboSelection;
|
||||
foreach (var leaf in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
||||
foreach (var leaf in fileSystem.Selection.DataNodes)
|
||||
{
|
||||
if (leaf.Value.Color.Length > 0)
|
||||
_removeDesigns.Add((leaf.Value, 0));
|
||||
if (selection != DesignColors.AutomaticName && leaf.Value.Color != selection)
|
||||
_addDesigns.Add(leaf.Value);
|
||||
var design = leaf.GetValue<Design>()!;
|
||||
if (design.Color.Length > 0)
|
||||
_removeDesigns.Add((design, 0));
|
||||
if (selection != DesignColors.AutomaticName && design.Color != selection)
|
||||
_addDesigns.Add(design);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DeleteSelectionButton(DesignFileSystem fileSystem, DesignManager manager, Configuration config)
|
||||
: BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.DeleteIcon;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void DrawTooltip()
|
||||
{
|
||||
var anySelected = fileSystem.Selection.DataNodes.Count > 0;
|
||||
var modifier = Enabled;
|
||||
|
||||
Im.Text(anySelected
|
||||
? "Delete the currently selected designs entirely from your drive\nThis can not be undone."u8
|
||||
: "No designs selected."u8);
|
||||
if (!modifier)
|
||||
Im.Text($"\nHold {config.DeleteDesignModifier} while clicking to delete the designs.");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Enabled
|
||||
=> config.DeleteDesignModifier.IsActive() && fileSystem.Selection.DataNodes.Count > 0;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void OnClick()
|
||||
{
|
||||
foreach (var node in fileSystem.Selection.DataNodes.ToArray())
|
||||
{
|
||||
if (node.GetValue<Design>() is { } design)
|
||||
manager.Delete(design);
|
||||
}
|
||||
}
|
||||
}
|
||||
112
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemCache.cs
Normal file
112
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFileSystemCache.cs
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Events;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignFileSystemCache : FileSystemCache<DesignFileSystemCache.DesignData>
|
||||
{
|
||||
public DesignFileSystemCache(DesignFileSystemDrawer parent)
|
||||
: base(parent)
|
||||
{
|
||||
parent.DesignChanged.Subscribe(OnDesignChanged, DesignChanged.Priority.DesignFileSystemSelector);
|
||||
parent.DesignColors.ColorChanged += OnColorChanged;
|
||||
}
|
||||
|
||||
private void OnColorChanged()
|
||||
{
|
||||
foreach (var node in AllNodes.Values)
|
||||
node.Dirty = true;
|
||||
}
|
||||
|
||||
private void OnDesignChanged(DesignChanged.Type type, Design design, ITransaction? _2)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case DesignChanged.Type.Created:
|
||||
case DesignChanged.Type.Deleted:
|
||||
case DesignChanged.Type.ReloadedAll:
|
||||
case DesignChanged.Type.Renamed:
|
||||
case DesignChanged.Type.ChangedDescription:
|
||||
case DesignChanged.Type.ChangedColor:
|
||||
case DesignChanged.Type.AddedTag:
|
||||
case DesignChanged.Type.RemovedTag:
|
||||
case DesignChanged.Type.ChangedTag:
|
||||
case DesignChanged.Type.AddedMod:
|
||||
case DesignChanged.Type.RemovedMod:
|
||||
case DesignChanged.Type.UpdatedMod:
|
||||
case DesignChanged.Type.ChangedLink:
|
||||
case DesignChanged.Type.Equip:
|
||||
case DesignChanged.Type.BonusItem:
|
||||
case DesignChanged.Type.Weapon:
|
||||
VisibleDirty = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (design.Node is { } node && AllNodes.TryGetValue(node, out var cache))
|
||||
cache.Dirty = true;
|
||||
}
|
||||
|
||||
private new DesignFileSystemDrawer Parent
|
||||
=> (DesignFileSystemDrawer)base.Parent;
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (ColorsDirty)
|
||||
{
|
||||
CollapsedFolderColor = ColorId.FolderCollapsed.Value().ToVector();
|
||||
ExpandedFolderColor = ColorId.FolderExpanded.Value().ToVector();
|
||||
LineColor = ColorId.FolderLine.Value().ToVector();
|
||||
Dirty &= ~IManagedCache.DirtyFlags.Colors;
|
||||
OnColorChanged();
|
||||
}
|
||||
}
|
||||
|
||||
protected override DesignData ConvertNode(in IFileSystemNode node)
|
||||
=> new((IFileSystemData<Design>)node);
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
base.Dispose(disposing);
|
||||
Parent.DesignChanged.Unsubscribe(OnDesignChanged);
|
||||
Parent.DesignColors.ColorChanged -= OnColorChanged;
|
||||
}
|
||||
|
||||
public sealed class DesignData(IFileSystemData<Design> node) : BaseFileSystemNodeCache<DesignData>
|
||||
{
|
||||
public readonly IFileSystemData<Design> Node = node;
|
||||
public Vector4 Color;
|
||||
public StringU8 Name = new(node.Value.Name.Text);
|
||||
public StringU8 Incognito = new(node.Value.Incognito);
|
||||
|
||||
public override void Update(FileSystemCache cache, IFileSystemNode node)
|
||||
{
|
||||
var drawer = (DesignFileSystemDrawer)cache.Parent;
|
||||
Color = drawer.DesignColors.GetColor(Node.Value).ToVector();
|
||||
Name = new StringU8(Node.Value.Name.Text);
|
||||
}
|
||||
|
||||
protected override void DrawInternal(FileSystemCache<DesignData> cache, IFileSystemNode node)
|
||||
{
|
||||
var c = (DesignFileSystemCache)cache;
|
||||
using var color = ImGuiColor.Text.Push(Color);
|
||||
using var id = Im.Id.Push(Node.Value.Index);
|
||||
var flags = node.Selected ? TreeNodeFlags.NoTreePushOnOpen | TreeNodeFlags.Selected : TreeNodeFlags.NoTreePushOnOpen;
|
||||
Im.Tree.Leaf(c.Parent.Config.Ephemeral.IncognitoMode ? Incognito : Name, flags);
|
||||
CheckDoubleClick(c);
|
||||
}
|
||||
|
||||
private void CheckDoubleClick(DesignFileSystemCache cache)
|
||||
{
|
||||
if (!cache.Parent.Config.AllowDoubleClickToApply)
|
||||
return;
|
||||
if (!Im.Item.Hovered())
|
||||
return;
|
||||
|
||||
if (Im.Mouse.IsDoubleClicked(MouseButton.Left))
|
||||
cache.Parent.DesignApplier.ApplyToPlayer(Node.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignFileSystemDrawer : FileSystemDrawer<DesignFileSystemCache.DesignData>, IDisposable
|
||||
{
|
||||
internal readonly Configuration Config;
|
||||
internal readonly DesignApplier DesignApplier;
|
||||
internal readonly DesignChanged DesignChanged;
|
||||
internal readonly DesignColors DesignColors;
|
||||
internal readonly DesignManager Manager;
|
||||
|
||||
public DesignFileSystemDrawer(DesignFileSystem fileSystem, DesignManager manager, DesignConverter converter, Configuration config,
|
||||
DesignApplier designApplier, DesignChanged designChanged, DesignColors designColors)
|
||||
: base(fileSystem, new DesignFilter())
|
||||
{
|
||||
Manager = manager;
|
||||
Config = config;
|
||||
DesignApplier = designApplier;
|
||||
DesignChanged = designChanged;
|
||||
DesignColors = designColors;
|
||||
Footer.Buttons.AddButton(new NewDesignButton(manager), 1000);
|
||||
Footer.Buttons.AddButton(new ImportDesignButton(converter, manager), 900);
|
||||
Footer.Buttons.AddButton(new DuplicateDesignButton(fileSystem, manager), 800);
|
||||
Footer.Buttons.AddButton(new DeleteSelectionButton(fileSystem, manager, config), -100);
|
||||
|
||||
SortMode = Config.SortMode;
|
||||
OnRenameChanged(Config.ShowRename, default);
|
||||
Config.OnRenameChanged += OnRenameChanged;
|
||||
}
|
||||
|
||||
private void OnRenameChanged(RenameField newValue, RenameField _)
|
||||
{
|
||||
DataContext.RemoveButtons<MoveDesignInput>();
|
||||
DataContext.RemoveButtons<RenameDesignInput>();
|
||||
switch (newValue)
|
||||
{
|
||||
case RenameField.RenameSearchPath: DataContext.AddButton(new RenameDesignInput(this), -1000); break;
|
||||
case RenameField.RenameData: DataContext.AddButton(new MoveDesignInput(this), -1000); break;
|
||||
case RenameField.BothSearchPathPrio:
|
||||
DataContext.AddButton(new RenameDesignInput(this), -1000);
|
||||
DataContext.AddButton(new MoveDesignInput(this), -1001);
|
||||
break;
|
||||
case RenameField.BothDataPrio:
|
||||
DataContext.AddButton(new RenameDesignInput(this), -1001);
|
||||
DataContext.AddButton(new MoveDesignInput(this), -1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Config.OnRenameChanged -= OnRenameChanged;
|
||||
}
|
||||
|
||||
public override ReadOnlySpan<byte> Id
|
||||
=> "Designs"u8;
|
||||
|
||||
protected override FileSystemCache<DesignFileSystemCache.DesignData> CreateCache()
|
||||
=> new DesignFileSystemCache(this);
|
||||
}
|
||||
150
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFilter.cs
Normal file
150
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFilter.cs
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DesignFilter : TokenizedFilter<DesignFilterTokenType, DesignFileSystemCache.DesignData, DesignFilterToken>,
|
||||
IFileSystemFilter<DesignFileSystemCache.DesignData>, IUiService
|
||||
{
|
||||
protected override void DrawTooltip()
|
||||
{
|
||||
if (!Im.Item.Hovered())
|
||||
return;
|
||||
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
var highlightColor = ColorId.EnabledAutoSet.Value().ToVector();
|
||||
Im.Text("Filter designs for those where their full paths or names contain the given strings, split by spaces."u8);
|
||||
ImEx.TextMultiColored("Enter "u8).Then("m:[string]"u8, highlightColor)
|
||||
.Then(" to filter for designs with a mod association containing the string."u8).End();
|
||||
ImEx.TextMultiColored("Enter "u8).Then("t:[string]"u8, highlightColor).Then(" to filter for designs set to specific tags."u8).End();
|
||||
ImEx.TextMultiColored("Enter "u8).Then("c:[string]"u8, highlightColor)
|
||||
.Then(" to filter for designs set to specific colors."u8).End();
|
||||
ImEx.TextMultiColored("Enter "u8).Then("i:[string]"u8, highlightColor).Then(" to filter for designs containing specific items."u8)
|
||||
.End();
|
||||
ImEx.TextMultiColored("Enter "u8).Then("n:[string]"u8, highlightColor).Then(" to filter only for design names, ignoring the paths."u8)
|
||||
.End();
|
||||
ImEx.TextMultiColored("Enter "u8).Then("f:[string]"u8, highlightColor).Then(
|
||||
" to filter for designs containing the text in name, path, description, tags, mod associations, colors or contained items."u8)
|
||||
.End();
|
||||
Im.Line.New();
|
||||
ImEx.TextMultiColored("Use "u8).Then("None"u8, highlightColor).Then(" as a placeholder value that only matches empty lists or names."u8)
|
||||
.End();
|
||||
Im.Text("Regularly, a design has to match all supplied criteria separately."u8);
|
||||
ImEx.TextMultiColored("Put a "u8).Then("'-'"u8, highlightColor)
|
||||
.Then(" in front of a search token to search only for designs not matching the criterion."u8).End();
|
||||
ImEx.TextMultiColored("Put a "u8).Then("'?'"u8, highlightColor)
|
||||
.Then(" in front of a search token to search for designs matching at least one of the '?'-criteria."u8).End();
|
||||
ImEx.TextMultiColored("Wrap spaces in "u8).Then("\"[string with space]\""u8, highlightColor)
|
||||
.Then(" to match this exact combination of words."u8).End();
|
||||
}
|
||||
|
||||
protected override bool Matches(in DesignFilterToken token, in DesignFileSystemCache.DesignData cacheItem)
|
||||
=> token.Type switch
|
||||
{
|
||||
DesignFilterTokenType.Default => cacheItem.Node.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase)
|
||||
|| cacheItem.Node.Value.Name.Text.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.Mod => CheckMods(token.Needle, cacheItem),
|
||||
DesignFilterTokenType.Tag => CheckTags(token.Needle, cacheItem),
|
||||
DesignFilterTokenType.Color => cacheItem.Node.Value.Color.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.Item => cacheItem.Node.Value.DesignData.ContainsName(token.Needle),
|
||||
DesignFilterTokenType.Name => cacheItem.Node.Value.Name.Text.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.FullContext => CheckFullContext(token.Needle, cacheItem),
|
||||
_ => true,
|
||||
};
|
||||
|
||||
protected override bool MatchesNone(DesignFilterTokenType type, bool negated, in DesignFileSystemCache.DesignData cacheItem)
|
||||
=> type switch
|
||||
{
|
||||
DesignFilterTokenType.Mod when negated => cacheItem.Node.Value.AssociatedMods.Count > 0,
|
||||
DesignFilterTokenType.Mod => cacheItem.Node.Value.AssociatedMods.Count is 0,
|
||||
DesignFilterTokenType.Tag when negated => cacheItem.Node.Value.Tags.Length > 0,
|
||||
DesignFilterTokenType.Tag => cacheItem.Node.Value.Tags.Length is 0,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
private static bool CheckMods(string needle, in DesignFileSystemCache.DesignData cacheItem)
|
||||
=> cacheItem.Node.Value.AssociatedMods.Any(kvp => kvp.Key.Name.Contains(needle, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
private static bool CheckTags(string needle, in DesignFileSystemCache.DesignData cacheItem)
|
||||
=> cacheItem.Node.Value.Tags.Any(t => t.Contains(needle, StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
private static bool CheckFullContext(string needle, in DesignFileSystemCache.DesignData cacheItem)
|
||||
{
|
||||
if (needle.Length is 0)
|
||||
return true;
|
||||
|
||||
if (cacheItem.Node.FullPath.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
var design = cacheItem.Node.Value;
|
||||
if (design.Name.Text.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (design.Description.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (CheckTags(needle, cacheItem))
|
||||
return true;
|
||||
|
||||
if (design.Color.Contains(needle, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
if (CheckMods(needle, cacheItem))
|
||||
return true;
|
||||
|
||||
if (design.DesignData.ContainsName(needle))
|
||||
return true;
|
||||
|
||||
if (design.Identifier.ToString().Contains(needle, StringComparison.OrdinalIgnoreCase))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool WouldBeVisible(in FileSystemFolderCache folder)
|
||||
{
|
||||
switch (State)
|
||||
{
|
||||
case FilterState.NoFilters: return true;
|
||||
case FilterState.NoMatches: return false;
|
||||
}
|
||||
|
||||
foreach (var token in Forced)
|
||||
{
|
||||
if (token.Type switch
|
||||
{
|
||||
DesignFilterTokenType.Name => !folder.Name.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.Default => !folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.FullContext => !folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
_ => true,
|
||||
})
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var token in Negated)
|
||||
{
|
||||
if (token.Type switch
|
||||
{
|
||||
DesignFilterTokenType.Name => folder.Name.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.Default => folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.FullContext => folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
_ => false,
|
||||
})
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var token in General)
|
||||
{
|
||||
if (token.Type switch
|
||||
{
|
||||
DesignFilterTokenType.Name => folder.Name.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.Default => folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
DesignFilterTokenType.FullContext => !folder.FullPath.Contains(token.Needle, StringComparison.OrdinalIgnoreCase),
|
||||
_ => false,
|
||||
})
|
||||
return true;
|
||||
}
|
||||
|
||||
return General.Count is 0;
|
||||
}
|
||||
}
|
||||
49
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFilterToken.cs
Normal file
49
Glamourer/Gui/Tabs/DesignTab/Selector/DesignFilterToken.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
using ImSharp;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public enum DesignFilterTokenType
|
||||
{
|
||||
Default,
|
||||
Mod,
|
||||
Tag,
|
||||
Color,
|
||||
Item,
|
||||
Name,
|
||||
FullContext,
|
||||
}
|
||||
|
||||
public readonly struct DesignFilterToken() : IFilterToken<DesignFilterTokenType, DesignFilterToken>
|
||||
{
|
||||
public string Needle { get; init; } = string.Empty;
|
||||
public DesignFilterTokenType Type { get; init; }
|
||||
|
||||
public bool Contains(DesignFilterToken other)
|
||||
{
|
||||
if (Type != other.Type)
|
||||
return false;
|
||||
|
||||
return Needle.Contains(other.Needle);
|
||||
}
|
||||
|
||||
public static bool ConvertToken(char tokenCharacter, out DesignFilterTokenType type)
|
||||
{
|
||||
type = tokenCharacter switch
|
||||
{
|
||||
'm' or 'M' => DesignFilterTokenType.Mod,
|
||||
'n' or 'N' => DesignFilterTokenType.Name,
|
||||
't' or 'T' => DesignFilterTokenType.Tag,
|
||||
'i' or 'I' => DesignFilterTokenType.Item,
|
||||
'c' or 'C' => DesignFilterTokenType.Color,
|
||||
'f' or 'F' => DesignFilterTokenType.FullContext,
|
||||
_ => DesignFilterTokenType.Default,
|
||||
};
|
||||
return type is not DesignFilterTokenType.Default;
|
||||
}
|
||||
|
||||
public static bool AllowsNone(DesignFilterTokenType type)
|
||||
=> type is DesignFilterTokenType.Tag or DesignFilterTokenType.Mod;
|
||||
|
||||
public static void ProcessList(List<DesignFilterToken> list)
|
||||
{ }
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class DuplicateDesignButton(DesignFileSystem fileSystem, DesignManager designManager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private readonly WeakReference<Design> _design = new(null!);
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.DuplicateIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override bool Enabled
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(fileSystem.Selection.Selection is null ? "No design selected."u8 : "Clone the currently selected design to a duplicate."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
_design.SetTarget(fileSystem.Selection.Selection?.GetValue<Design>()!);
|
||||
Im.Popup.Open("##CloneDesign"u8);
|
||||
}
|
||||
|
||||
protected override void PostDraw()
|
||||
{
|
||||
if (!InputPopup.OpenName("##CloneDesign"u8, out var newName))
|
||||
return;
|
||||
|
||||
if (_design.TryGetTarget(out var design))
|
||||
designManager.CreateClone(design, newName, true);
|
||||
_design.SetTarget(null!);
|
||||
}
|
||||
}
|
||||
52
Glamourer/Gui/Tabs/DesignTab/Selector/ImportDesignButton.cs
Normal file
52
Glamourer/Gui/Tabs/DesignTab/Selector/ImportDesignButton.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class ImportDesignButton(DesignConverter converter, DesignManager manager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
private string _clipboardText = string.Empty;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.ImportIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Try to import a design from your clipboard."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
_clipboardText = Im.Clipboard.GetUtf16();
|
||||
Im.Popup.Open("##ImportDesign"u8);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage("Could not import data from clipboard.", NotificationType.Error, false);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void PostDraw()
|
||||
{
|
||||
if (!InputPopup.OpenName("##ImportDesign"u8, out var newName))
|
||||
return;
|
||||
|
||||
if (_clipboardText.Length is 0)
|
||||
return;
|
||||
|
||||
var design = converter.FromBase64(_clipboardText, true, true, out _);
|
||||
if (design is Design d)
|
||||
manager.CreateClone(d, newName, true);
|
||||
else if (design is not null)
|
||||
manager.CreateClone(design, newName, true);
|
||||
else
|
||||
Glamourer.Messager.NotificationMessage("Could not create a design, clipboard did not contain valid design data.",
|
||||
NotificationType.Error, false);
|
||||
_clipboardText = string.Empty;
|
||||
}
|
||||
}
|
||||
34
Glamourer/Gui/Tabs/DesignTab/Selector/MoveDesignInput.cs
Normal file
34
Glamourer/Gui/Tabs/DesignTab/Selector/MoveDesignInput.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class MoveDesignInput(DesignFileSystemDrawer fileSystem) : BaseButton<IFileSystemData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override ReadOnlySpan<byte> Label(in IFileSystemData _)
|
||||
=> "##Move"u8;
|
||||
|
||||
/// <summary> Replaces the normal menu item handling for a text input, so the other fields are not used. </summary>
|
||||
/// <inheritdoc/>
|
||||
public override bool DrawMenuItem(in IFileSystemData data)
|
||||
{
|
||||
var currentPath = data.FullPath;
|
||||
using var style = Im.Style.PushDefault(ImStyleDouble.FramePadding);
|
||||
MenuSeparator.DrawSeparator();
|
||||
Im.Text("Move Design:"u8);
|
||||
if (Im.Window.Appearing)
|
||||
Im.Keyboard.SetFocusHere();
|
||||
var ret = Im.Input.Text(Label(data), ref currentPath, flags: InputTextFlags.EnterReturnsTrue);
|
||||
Im.Tooltip.OnHover(
|
||||
"Enter a full path here to move the design or change its search path. Creates all required parent directories, if possible."u8);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
fileSystem.FileSystem.RenameAndMove(data, currentPath);
|
||||
fileSystem.FileSystem.ExpandAllAncestors(data);
|
||||
Im.Popup.CloseCurrent();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
28
Glamourer/Gui/Tabs/DesignTab/Selector/NewDesignButton.cs
Normal file
28
Glamourer/Gui/Tabs/DesignTab/Selector/NewDesignButton.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class NewDesignButton(DesignManager designManager) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.AddObjectIcon;
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Create a new design with default configuration."u8);
|
||||
|
||||
public override void OnClick()
|
||||
=> Im.Popup.Open("##NewDesign"u8);
|
||||
|
||||
protected override void PostDraw()
|
||||
{
|
||||
if (!InputPopup.OpenName("##NewDesign"u8, out var newName))
|
||||
return;
|
||||
|
||||
designManager.CreateEmpty(newName, true);
|
||||
}
|
||||
}
|
||||
34
Glamourer/Gui/Tabs/DesignTab/Selector/RenameDesignInput.cs
Normal file
34
Glamourer/Gui/Tabs/DesignTab/Selector/RenameDesignInput.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class RenameDesignInput(DesignFileSystemDrawer fileSystem) : BaseButton<IFileSystemData>
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override ReadOnlySpan<byte> Label(in IFileSystemData _)
|
||||
=> "##Rename"u8;
|
||||
|
||||
/// <summary> Replaces the normal menu item handling for a text input, so the other fields are not used. </summary>
|
||||
/// <inheritdoc/>
|
||||
public override bool DrawMenuItem(in IFileSystemData data)
|
||||
{
|
||||
var design = (Design)data.Value;
|
||||
var currentName = design.Name.Text;
|
||||
using var style = Im.Style.PushDefault(ImStyleDouble.FramePadding);
|
||||
MenuSeparator.DrawSeparator();
|
||||
Im.Text("Rename Design:"u8);
|
||||
if (Im.Window.Appearing)
|
||||
Im.Keyboard.SetFocusHere();
|
||||
var ret = Im.Input.Text(Label(data), ref currentName, flags: InputTextFlags.EnterReturnsTrue);
|
||||
Im.Tooltip.OnHover("Enter a new name here to rename the changed design."u8);
|
||||
if (!ret)
|
||||
return false;
|
||||
|
||||
fileSystem.Manager.Rename(design, currentName);
|
||||
Im.Popup.CloseCurrent();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
44
Glamourer/Gui/Tabs/DesignTab/SetFromClipboardButton.cs
Normal file
44
Glamourer/Gui/Tabs/DesignTab/SetFromClipboardButton.cs
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Glamourer.Designs;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class SetFromClipboardButton(DesignFileSystem fileSystem, DesignConverter converter, DesignManager manager)
|
||||
: BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.FromClipboardIcon;
|
||||
|
||||
public override bool Enabled
|
||||
=> !((Design)fileSystem.Selection.Selection!.Value).WriteProtected();
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text(
|
||||
"Try to apply a design from your clipboard over this design.\nHold Control to only apply gear.\nHold Shift to only apply customizations."u8);
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
try
|
||||
{
|
||||
var text = Im.Clipboard.GetUtf16();
|
||||
var (applyEquip, applyCustomize) = UiHelpers.ConvertKeysToBool();
|
||||
var design = converter.FromBase64(text, applyCustomize, applyEquip, out _)
|
||||
?? throw new Exception("The clipboard did not contain valid data.");
|
||||
manager.ApplyDesign((Design)fileSystem.Selection.Selection!.Value, design);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(ex, $"Could not apply clipboard to {((Design)fileSystem.Selection.Selection!.Value).Name}.",
|
||||
$"Could not apply clipboard to design {((Design)fileSystem.Selection.Selection!.Value).Identifier}", NotificationType.Error,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Glamourer/Gui/Tabs/DesignTab/UndoButton.cs
Normal file
27
Glamourer/Gui/Tabs/DesignTab/UndoButton.cs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.History;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||
|
||||
public sealed class UndoButton(DesignFileSystem fileSystem, EditorHistory history) : BaseIconButton<AwesomeIcon>
|
||||
{
|
||||
public override bool IsVisible
|
||||
=> fileSystem.Selection.Selection is not null;
|
||||
|
||||
public override AwesomeIcon Icon
|
||||
=> LunaStyle.UndoIcon;
|
||||
|
||||
public override bool Enabled
|
||||
=> !((Design)fileSystem.Selection.Selection!.Value).WriteProtected() && history.CanUndo((Design)fileSystem.Selection.Selection!.Value);
|
||||
|
||||
public override bool HasTooltip
|
||||
=> true;
|
||||
|
||||
public override void DrawTooltip()
|
||||
=> Im.Text("Undo the last change."u8);
|
||||
|
||||
public override void OnClick()
|
||||
=> history.Undo((Design)fileSystem.Selection.Selection!.Value);
|
||||
}
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Bindings.ImGui;
|
||||
using ImSharp;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
||||
public static class HeaderDrawer
|
||||
{
|
||||
public abstract class Button
|
||||
{
|
||||
protected abstract void OnClick();
|
||||
|
||||
protected virtual string Description
|
||||
=> string.Empty;
|
||||
|
||||
protected virtual Rgba32 BorderColor
|
||||
=> ColorId.HeaderButtons.Value();
|
||||
|
||||
protected virtual Rgba32 TextColor
|
||||
=> ColorId.HeaderButtons.Value();
|
||||
|
||||
protected virtual FontAwesomeIcon Icon
|
||||
=> FontAwesomeIcon.None;
|
||||
|
||||
protected virtual bool Disabled
|
||||
=> false;
|
||||
|
||||
public virtual bool Visible
|
||||
=> true;
|
||||
|
||||
public void Draw(float width)
|
||||
{
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
using var color = ImGuiColor.Border.Push(BorderColor)
|
||||
.Push(ImGuiColor.Text, TextColor, TextColor.IsVisible);
|
||||
if (ImGuiUtil.DrawDisabledButton(Icon.ToIconString(), new Vector2(width, Im.Style.FrameHeight), string.Empty, Disabled, true))
|
||||
OnClick();
|
||||
color.Pop();
|
||||
ImGuiUtil.HoverTooltip(Description);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Draw(string text, uint textColor, uint frameColor, Button[] leftButtons, Button[] rightButtons)
|
||||
{
|
||||
var width = Im.Style.FrameHeightWithSpacing;
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
|
||||
.Push(ImGuiStyleVar.FrameRounding, 0)
|
||||
.Push(ImGuiStyleVar.FrameBorderSize, Im.Style.GlobalScale);
|
||||
|
||||
var leftButtonSize = 0f;
|
||||
foreach (var button in leftButtons.Where(b => b.Visible))
|
||||
{
|
||||
button.Draw(width);
|
||||
Im.Line.Same();
|
||||
leftButtonSize += width;
|
||||
}
|
||||
|
||||
var rightButtonSize = rightButtons.Count(b => b.Visible) * width;
|
||||
var midSize = Im.ContentRegion.Available.X - rightButtonSize - Im.Style.GlobalScale;
|
||||
|
||||
style.Pop();
|
||||
style.Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.5f + (rightButtonSize - leftButtonSize) / midSize, 0.5f));
|
||||
if (textColor != 0)
|
||||
ImGuiUtil.DrawTextButton(text, new Vector2(midSize, Im.Style.FrameHeight), frameColor, textColor);
|
||||
else
|
||||
ImGuiUtil.DrawTextButton(text, new Vector2(midSize, Im.Style.FrameHeight), frameColor);
|
||||
style.Pop();
|
||||
style.Push(ImGuiStyleVar.FrameBorderSize, Im.Style.GlobalScale);
|
||||
|
||||
foreach (var button in rightButtons.Where(b => b.Visible))
|
||||
{
|
||||
Im.Line.Same();
|
||||
button.Draw(width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,10 @@
|
|||
using ImSharp;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
||||
public sealed class IncognitoButton(Configuration.Configuration config) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
public sealed class IncognitoButton(Configuration config) : BaseIconButton<AwesomeIcon>, IUiService
|
||||
{
|
||||
public override AwesomeIcon Icon
|
||||
=> config.Ephemeral.IncognitoMode
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui.Customization;
|
||||
using Glamourer.Gui.Equipment;
|
||||
|
|
@ -13,7 +13,7 @@ using Penumbra.GameData.Interop;
|
|||
namespace Glamourer.Gui.Tabs.NpcTab;
|
||||
|
||||
public sealed class NpcPanel(
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
NpcSelection selection,
|
||||
CustomizationDrawer customizeDrawer,
|
||||
EquipmentDrawer equipmentDrawer,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,12 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui.Filesystem;
|
||||
using OtterGui.Raii;
|
||||
using OtterGui.Text;
|
||||
using OtterGui.Text.EndObjects;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||
|
||||
public class CodeDrawer(Configuration.Configuration config, CodeService codeService, FunModule funModule) : IUiService
|
||||
public class CodeDrawer(Configuration config, CodeService codeService, FunModule funModule) : IUiService
|
||||
{
|
||||
private static ReadOnlySpan<byte> Tooltip
|
||||
=> "Cheat Codes are not actually for cheating in the game, but for 'cheating' in Glamourer. "u8
|
||||
|
|
@ -41,7 +37,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
private void DrawCodeInput()
|
||||
{
|
||||
var color = codeService.CheckCode(_currentCode).Item2 is not 0 ? ColorId.ActorAvailable : ColorId.ActorUnavailable;
|
||||
using var border = ImRaii.PushFrameBorder(Im.Style.GlobalScale, color.Value().Color, _currentCode.Length > 0);
|
||||
using var border = ImStyleBorder.Frame.Push(color.Value(), Im.Style.GlobalScale, _currentCode.Length > 0);
|
||||
Im.Item.SetNextWidth(500 * Im.Style.GlobalScale + Im.Style.ItemSpacing.X);
|
||||
if (Im.Input.Text("##Code"u8, ref _currentCode, "Enter Cheat Code..."u8, InputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
|
|
@ -50,24 +46,22 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
}
|
||||
|
||||
Im.Line.Same();
|
||||
ImUtf8.Icon(FontAwesomeIcon.ExclamationCircle, ImGuiColor.TextDisabled.Get().Color);
|
||||
ImEx.Icon.Draw(LunaStyle.WarningIcon, ImGuiColor.TextDisabled.Get());
|
||||
DrawTooltip();
|
||||
}
|
||||
|
||||
private void DrawCopyButtons()
|
||||
{
|
||||
var buttonSize = new Vector2(250 * Im.Style.GlobalScale, 0);
|
||||
if (ImUtf8.Button("Who am I?!?"u8, buttonSize))
|
||||
var buttonSize = ImEx.ScaledVectorX(250);
|
||||
if (Im.Button("Who am I?!?"u8, buttonSize))
|
||||
funModule.WhoAmI();
|
||||
ImUtf8.HoverTooltip(
|
||||
"Copy your characters actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||
Im.Tooltip.OnHover("Copy your characters actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||
|
||||
Im.Line.Same();
|
||||
|
||||
if (ImUtf8.Button("Who is that!?!"u8, buttonSize))
|
||||
if (Im.Button("Who is that!?!"u8, buttonSize))
|
||||
funModule.WhoIsThat();
|
||||
ImUtf8.HoverTooltip(
|
||||
"Copy your targets actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||
Im.Tooltip.OnHover("Copy your targets actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||
}
|
||||
|
||||
private CodeService.CodeFlag DrawCodes()
|
||||
|
|
@ -76,7 +70,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
CodeService.CodeFlag knownFlags = 0;
|
||||
for (var i = 0; i < config.Codes.Count; ++i)
|
||||
{
|
||||
using var id = ImUtf8.PushId(i);
|
||||
using var id = Im.Id.Push(i);
|
||||
var (code, state) = config.Codes[i];
|
||||
var (action, flag) = codeService.CheckCode(code);
|
||||
if (flag is 0)
|
||||
|
|
@ -84,8 +78,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
|
||||
var data = CodeService.GetData(flag);
|
||||
|
||||
if (ImUtf8.IconButton(FontAwesomeIcon.Trash,
|
||||
$"Delete this cheat code.{(canDelete ? string.Empty : $"\nHold {config.DeleteDesignModifier} while clicking to delete.")}",
|
||||
if (ImEx.Icon.Button(LunaStyle.DeleteIcon, $"Delete this cheat code.{(canDelete ? StringU8.Empty : $"\nHold {config.DeleteDesignModifier} while clicking to delete.")}",
|
||||
disabled: !canDelete))
|
||||
{
|
||||
action!(false);
|
||||
|
|
@ -95,7 +88,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
|
||||
knownFlags |= flag;
|
||||
Im.Line.SameInner();
|
||||
if (ImUtf8.Checkbox("\0"u8, ref state))
|
||||
if (Im.Checkbox(StringU8.Empty, ref state))
|
||||
{
|
||||
action!(state);
|
||||
codeService.SaveState();
|
||||
|
|
@ -103,14 +96,14 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
|
||||
var hovered = Im.Item.Hovered();
|
||||
Im.Line.Same();
|
||||
ImUtf8.Selectable(code);
|
||||
Im.Selectable(code);
|
||||
hovered |= Im.Item.Hovered();
|
||||
DrawSource(i, code);
|
||||
DrawTarget(i);
|
||||
if (hovered)
|
||||
{
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
ImUtf8.Text(data.Effect);
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
Im.Text(data.Effect);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -119,22 +112,22 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
|
||||
private void DrawSource(int idx, string code)
|
||||
{
|
||||
using var source = ImUtf8.DragDropSource();
|
||||
using var source = Im.DragDrop.Source();
|
||||
if (!source)
|
||||
return;
|
||||
|
||||
if (!DragDropSource.SetPayload(DragDropLabel))
|
||||
if (!source.SetPayload(DragDropLabel))
|
||||
_dragCodeIdx = idx;
|
||||
ImUtf8.Text($"Dragging {code}...");
|
||||
Im.Text($"Dragging {code}...");
|
||||
}
|
||||
|
||||
private void DrawTarget(int idx)
|
||||
{
|
||||
using var target = ImUtf8.DragDropTarget();
|
||||
if (!target.IsDropping(DragDropLabel) || _dragCodeIdx == -1)
|
||||
using var target = Im.DragDrop.Target();
|
||||
if (!target.IsDropping(DragDropLabel) || _dragCodeIdx is -1)
|
||||
return;
|
||||
|
||||
if (Extensions.Move(config.Codes, _dragCodeIdx, idx))
|
||||
if (config.Codes.Move(_dragCodeIdx, idx))
|
||||
codeService.SaveState();
|
||||
_dragCodeIdx = -1;
|
||||
}
|
||||
|
|
@ -144,7 +137,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
if (knownFlags.HasFlag(CodeService.AllHintCodes))
|
||||
return;
|
||||
|
||||
if (ImUtf8.Button(_showCodeHints ? "Hide Hints"u8 : "Show Hints"u8))
|
||||
if (Im.Button(_showCodeHints ? "Hide Hints"u8 : "Show Hints"u8))
|
||||
_showCodeHints = !_showCodeHints;
|
||||
|
||||
if (!_showCodeHints)
|
||||
|
|
@ -162,23 +155,23 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
Im.Dummy(Vector2.Zero);
|
||||
Im.Separator();
|
||||
Im.Dummy(Vector2.Zero);
|
||||
ImUtf8.Text(data.Effect);
|
||||
using var indent = ImRaii.PushIndent(2);
|
||||
using (ImUtf8.Group())
|
||||
Im.Text(data.Effect);
|
||||
using var indent = Im.Indent(2);
|
||||
using (Im.Group())
|
||||
{
|
||||
ImUtf8.Text("Capitalized letters: "u8);
|
||||
ImUtf8.Text("Punctuation: "u8);
|
||||
Im.Text("Capitalized letters: "u8);
|
||||
Im.Text("Punctuation: "u8);
|
||||
}
|
||||
|
||||
Im.Line.SameInner();
|
||||
using (ImUtf8.Group())
|
||||
using (Im.Group())
|
||||
{
|
||||
using var mono = Im.Font.PushMono();
|
||||
ImUtf8.Text($"{data.CapitalCount}");
|
||||
ImUtf8.Text($"{data.Punctuation}");
|
||||
Im.Text($"{data.CapitalCount}");
|
||||
Im.Text($"{data.Punctuation}");
|
||||
}
|
||||
|
||||
ImUtf8.TextWrapped(data.Hint);
|
||||
Im.TextWrapped(data.Hint);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -189,7 +182,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
|||
return;
|
||||
|
||||
Im.Window.SetNextSize(new Vector2(400, 0));
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
ImUtf8.TextWrapped(Tooltip);
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
Im.TextWrapped(Tooltip);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,82 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using OtterGui.Widgets;
|
||||
using Logger = OtterGui.Log.Logger;
|
||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||
|
||||
public sealed class CollectionCombo(Configuration.Configuration config, PenumbraService penumbra, Logger log)
|
||||
: FilterComboCache<(Guid Id, string IdShort, string Name)>(
|
||||
() => penumbra.GetCollections().Select(kvp => (kvp.Key, kvp.Key.ToString()[..8], kvp.Value)).ToArray(),
|
||||
MouseWheelType.Control, log), IUiService
|
||||
public sealed class CollectionCombo(Configuration config, PenumbraService penumbra)
|
||||
: FilterComboBase<CollectionCombo.CacheItem>(new CollectionFilter()), IUiService
|
||||
{
|
||||
protected override bool DrawSelectable(int globalIdx, bool selected)
|
||||
private Guid _selected = Guid.Empty;
|
||||
|
||||
public readonly struct CacheItem(Guid id, string name)
|
||||
{
|
||||
public readonly StringPair Name = new(name);
|
||||
public readonly Guid Id = id;
|
||||
public readonly StringU8 Incognito = id.ShortGuidU8();
|
||||
public readonly StringU8 ShortId = new($"({id.ShortGuidU8()})");
|
||||
}
|
||||
|
||||
protected override float ItemHeight
|
||||
=> Im.Style.TextHeightWithSpacing;
|
||||
|
||||
protected override IEnumerable<CacheItem> GetItems()
|
||||
=> penumbra.GetCollections().Select(kvp => new CacheItem(kvp.Key, kvp.Value));
|
||||
|
||||
public bool Draw(Utf8StringHandler<LabelStringHandlerBuffer> label, Utf8StringHandler<HintStringHandlerBuffer> preview, out string newName,
|
||||
ref Guid id, float width)
|
||||
{
|
||||
_selected = id;
|
||||
if (!base.Draw(label, preview, StringU8.Empty, width, out var ret))
|
||||
{
|
||||
newName = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
newName = ret.Name.Utf16;
|
||||
id = ret.Id;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool DrawItem(in CacheItem item, int globalIndex, bool selected)
|
||||
{
|
||||
var (_, idShort, name) = Items[globalIdx];
|
||||
if (config.Ephemeral.IncognitoMode)
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
return Im.Selectable(idShort);
|
||||
return Im.Selectable(item.Incognito, selected);
|
||||
}
|
||||
|
||||
var ret = Im.Selectable(name, selected);
|
||||
var ret = Im.Selectable(item.Name.Utf8, selected);
|
||||
Im.Line.Same();
|
||||
|
||||
using (Im.Font.PushMono())
|
||||
{
|
||||
using var color = ImGuiColor.Text.Push(ImGuiColor.TextDisabled.Get());
|
||||
ImEx.TextRightAligned($"({idShort})");
|
||||
ImEx.TextRightAligned(item.ShortId);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
protected override bool IsSelected(CacheItem item, int globalIndex)
|
||||
=> item.Id == _selected;
|
||||
|
||||
private sealed class CollectionFilter : Utf8FilterBase<CacheItem>
|
||||
{
|
||||
public override bool WouldBeVisible(in CacheItem item, int globalIndex)
|
||||
=> base.WouldBeVisible(in item, globalIndex) || WouldBeVisible(item.Incognito);
|
||||
|
||||
protected override ReadOnlySpan<byte> ToFilterString(in CacheItem item, int globalIndex)
|
||||
=> item.Name;
|
||||
}
|
||||
|
||||
protected override FilterComboBaseCache<CacheItem> CreateCache()
|
||||
=> new Cache(this);
|
||||
|
||||
private sealed class Cache(CollectionCombo parent) : FilterComboBaseCache<CacheItem>(parent)
|
||||
{
|
||||
protected override void ComputeWidth()
|
||||
=> ComboWidth = AllItems.Max(i => i.Name.Utf8.CalculateSize().X + Im.Style.ItemSpacing.X * 2 + i.ShortId.CalculateSize().X);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Dalamud.Interface;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Services;
|
||||
using ImSharp;
|
||||
|
|
@ -10,7 +11,7 @@ namespace Glamourer.Gui.Tabs.SettingsTab;
|
|||
|
||||
public class CollectionOverrideDrawer(
|
||||
CollectionOverrideService collectionOverrides,
|
||||
Configuration.Configuration config,
|
||||
Configuration config,
|
||||
ActorObjectManager objects,
|
||||
ActorManager actors,
|
||||
PenumbraService penumbra,
|
||||
|
|
@ -58,18 +59,15 @@ public class CollectionOverrideDrawer(
|
|||
DrawActorIdentifier(idx, actor);
|
||||
|
||||
table.NextColumn();
|
||||
if (combo.Draw("##collection", name, "Select the overriding collection. Current GUID:", Im.ContentRegion.Available.X,
|
||||
Im.Style.TextHeight))
|
||||
{
|
||||
var (guid, _, newName) = combo.CurrentSelection;
|
||||
collectionOverrides.ChangeOverride(idx, guid, newName);
|
||||
}
|
||||
if (combo.Draw("##collection"u8, name, out var newName, ref collection, Im.ContentRegion.Available.X))
|
||||
collectionOverrides.ChangeOverride(idx, collection, newName);
|
||||
|
||||
if (Im.Item.Hovered())
|
||||
{
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
using var font = Im.Font.PushMono();
|
||||
Im.Text($" {collection}");
|
||||
using var tt = Im.Tooltip.Begin();
|
||||
Im.Text("Select the overriding collection. Current GUID:"u8);
|
||||
using var indent = Im.Indent();
|
||||
ImEx.MonoText($"{collection}");
|
||||
}
|
||||
|
||||
table.NextColumn();
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Configuration;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Gui.Tabs.DesignTab;
|
||||
|
|
@ -15,8 +15,8 @@ using Luna;
|
|||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||
|
||||
public sealed class SettingsTab(
|
||||
Configuration.Configuration config,
|
||||
DesignFileSystemSelector selector,
|
||||
Configuration config,
|
||||
DesignFileSystemDrawer drawer,
|
||||
ContextMenuService contextMenuService,
|
||||
IUiBuilder uiBuilder,
|
||||
GlamourerChangelog changelog,
|
||||
|
|
@ -28,7 +28,8 @@ public sealed class SettingsTab(
|
|||
Glamourer glamourer,
|
||||
AutoDesignApplier autoDesignApplier,
|
||||
AutoRedrawChanged autoRedraw,
|
||||
PcpService pcpService)
|
||||
PcpService pcpService,
|
||||
IgnoredMods ignoredMods)
|
||||
: ITab<MainTabType>
|
||||
{
|
||||
private readonly VirtualKey[] _validKeys = keys.GetValidVirtualKeys().Prepend(VirtualKey.NO_KEY).ToArray();
|
||||
|
|
@ -61,6 +62,7 @@ public sealed class SettingsTab(
|
|||
DrawInterfaceSettings();
|
||||
DrawColorSettings();
|
||||
overrides.Draw();
|
||||
DrawIgnoredMods();
|
||||
codeDrawer.Draw();
|
||||
}
|
||||
|
||||
|
|
@ -256,7 +258,7 @@ public sealed class SettingsTab(
|
|||
Im.Line.New();
|
||||
Im.Text("Show the following panels in their respective tabs:"u8);
|
||||
Im.Dummy(Vector2.Zero);
|
||||
Configuration.DesignPanelFlagExtensions.DrawTable("##panelTable"u8, config.HideDesignPanel, config.AutoExpandDesignPanel, v =>
|
||||
DesignPanelFlagExtensions.DrawTable("##panelTable"u8, config.HideDesignPanel, config.AutoExpandDesignPanel, v =>
|
||||
{
|
||||
config.HideDesignPanel = v;
|
||||
config.Save();
|
||||
|
|
@ -280,8 +282,8 @@ public sealed class SettingsTab(
|
|||
Checkbox("Show Unobtained Item Warnings"u8,
|
||||
"Show information whether you have unlocked all items and customizations in your automated design or not."u8,
|
||||
config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v);
|
||||
Checkbox("Show Color Display Config"u8, "Show the Color Display configuration options in the Advanced Customization panels."u8,
|
||||
config.ShowColorConfig, v => config.ShowColorConfig = v);
|
||||
Checkbox("Show Color Display Configuration"u8, "Show the Color Display configuration options in the Advanced Customization panels."u8,
|
||||
config.ShowColorConfig, v => config.ShowColorConfig = v);
|
||||
Checkbox("Show Palette+ Import Button"u8,
|
||||
"Show the import button that allows you to import Palette+ palettes onto a design in the Advanced Customization options section for designs."u8,
|
||||
config.ShowPalettePlusImport, v => config.ShowPalettePlusImport = v);
|
||||
|
|
@ -376,7 +378,7 @@ public sealed class SettingsTab(
|
|||
if (Im.Button("Import Palette+ to Designs"u8))
|
||||
paletteImport.ImportDesigns();
|
||||
Im.Tooltip.OnHover(
|
||||
$"Import all existing Palettes from your Palette+ Config into Designs at PalettePlus/[Name] if these do not exist. Existing Palettes are:\n\n\t - {string.Join("\n\t - ", paletteImport.Data.Keys)}");
|
||||
$"Import all existing Palettes from your Palette+ Configuration into Designs at PalettePlus/[Name] if these do not exist. Existing Palettes are:\n\n\t - {string.Join("\n\t - ", paletteImport.Data.Keys)}");
|
||||
}
|
||||
|
||||
/// <summary> Draw the entire Color subsection. </summary>
|
||||
|
|
@ -402,6 +404,7 @@ public sealed class SettingsTab(
|
|||
continue;
|
||||
|
||||
config.Colors[color] = newColor.Color;
|
||||
CacheManager.Instance.SetColorsDirty();
|
||||
config.Save();
|
||||
}
|
||||
}
|
||||
|
|
@ -445,20 +448,20 @@ public sealed class SettingsTab(
|
|||
using (var combo = Im.Combo.Begin("##sortMode"u8, sortMode.Name))
|
||||
{
|
||||
if (combo)
|
||||
foreach (var val in Configuration.Configuration.Constants.ValidSortModes)
|
||||
foreach (var (_, value) in ISortMode.Valid)
|
||||
{
|
||||
if (Im.Selectable(val.Name, val.GetType() == sortMode.GetType()) && val.GetType() != sortMode.GetType())
|
||||
if (Im.Selectable(value.Name, value.GetType() == sortMode.GetType()) && value.GetType() != sortMode.GetType())
|
||||
{
|
||||
config.SortMode = val;
|
||||
selector.SetFilterDirty();
|
||||
config.SortMode = value;
|
||||
drawer.SortMode = value;
|
||||
config.Save();
|
||||
}
|
||||
|
||||
Im.Tooltip.OnHover(val.Description);
|
||||
Im.Tooltip.OnHover(value.Description);
|
||||
}
|
||||
}
|
||||
|
||||
LunaStyle.DrawAlignedHelpMarkerLabel("Sort Mode"u8, "Choose the sort mode for the mod selector in the designs tab."u8);
|
||||
LunaStyle.DrawAlignedHelpMarkerLabel("Sort Mode"u8, "Choose the sort mode for the design selector in the designs tab."u8);
|
||||
}
|
||||
|
||||
private void DrawRenameSettings()
|
||||
|
|
@ -472,7 +475,6 @@ public sealed class SettingsTab(
|
|||
if (Im.Selectable(value.ToNameU8(), config.ShowRename == value))
|
||||
{
|
||||
config.ShowRename = value;
|
||||
selector.SetRenameSearchPath(value);
|
||||
config.Save();
|
||||
}
|
||||
|
||||
|
|
@ -503,4 +505,46 @@ public sealed class SettingsTab(
|
|||
LunaStyle.DrawAlignedHelpMarkerLabel("Character Height Display Type"u8,
|
||||
"Select how to display the height of characters in real-world units, if at all."u8);
|
||||
}
|
||||
|
||||
private string _newIgnoredMod = string.Empty;
|
||||
|
||||
private void DrawIgnoredMods()
|
||||
{
|
||||
using var header = Im.Tree.HeaderId("Ignored Mods"u8);
|
||||
Im.Tooltip.OnHover("Add mods that are ignored for the 'modded' column in the Unlocks tab."u8);
|
||||
if (!header)
|
||||
return;
|
||||
|
||||
using var listBox = Im.ListBox.Begin("##box"u8, new Vector2(0.4f * Im.ContentRegion.Available.X, Im.Style.FrameHeightWithSpacing * 10));
|
||||
if (!listBox)
|
||||
return;
|
||||
|
||||
var delete = string.Empty;
|
||||
using var alignment = ImStyleDouble.ButtonTextAlign.PushX(0);
|
||||
foreach (var (idx, mod) in ignoredMods.Index())
|
||||
{
|
||||
using var id = Im.Id.Push(idx);
|
||||
if (ImEx.Icon.Button(LunaStyle.DeleteIcon, "Delete this ignored mod."u8))
|
||||
delete = mod;
|
||||
|
||||
Im.Line.SameInner();
|
||||
ImEx.TextFramed(mod, Im.ContentRegion.Available with { Y = Im.Style.FrameHeight});
|
||||
}
|
||||
|
||||
if (delete.Length > 0)
|
||||
ignoredMods.Remove(delete);
|
||||
|
||||
var tt = _newIgnoredMod.Length is 0 ? "Please enter a new mod name or mod directory to ignore."u8 :
|
||||
ignoredMods.Contains(_newIgnoredMod) ? "This mod is already ignored."u8 :
|
||||
"Ignore all mods with this name or directory in the Unlocks tab."u8;
|
||||
if (ImEx.Icon.Button(LunaStyle.AddObjectIcon, tt, tt[0] is not (byte)'I'))
|
||||
{
|
||||
ignoredMods.Add(_newIgnoredMod);
|
||||
_newIgnoredMod = string.Empty;
|
||||
}
|
||||
|
||||
Im.Line.SameInner();
|
||||
Im.Item.SetNextWidthFull();
|
||||
Im.Input.Text("##newMod"u8, ref _newIgnoredMod, "Ignore this Mod..."u8);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,7 +38,8 @@ public readonly struct UnlockCacheItem(in EquipItem item, in EquipItem offhand,
|
|||
public readonly StringPair OffhandModelString = offhand.Valid ? new StringPair(offhand.ModelString) : StringPair.Empty;
|
||||
public readonly StringPair GauntletModelString = gauntlets.Valid ? new StringPair(gauntlets.ModelString) : StringPair.Empty;
|
||||
public readonly StringPair RequiredLevel = new($"{item.Level.Value}");
|
||||
public required (string, string)[] Mods { get; init; }
|
||||
public required (string, string)[] Mods { get; init; }
|
||||
public int RelevantMods { get; init; }
|
||||
public readonly JobFlag Jobs = jobs.Flags;
|
||||
public readonly StringU8 JobText = jobs.Name.IsEmpty ? new StringU8($"Unknown {jobs.Id.Id}") : jobs.Name;
|
||||
public required bool Favorite { get; init; }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility.Table;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
|
|
@ -23,9 +24,10 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
private readonly FavoriteManager _favorites;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly ObjectUnlocked _unlockEvent;
|
||||
private readonly IgnoredMods _ignoredMods;
|
||||
|
||||
public UnlockTable(JobService jobs, ItemManager items, ItemUnlockManager unlocks, PenumbraChangedItemTooltip tooltip,
|
||||
ObjectUnlocked unlockEvent, FavoriteManager favorites, PenumbraService penumbra, TextureService textures)
|
||||
ObjectUnlocked unlockEvent, FavoriteManager favorites, PenumbraService penumbra, TextureService textures, IgnoredMods ignoredMods)
|
||||
: base(new StringU8("Unlock Table"u8), new FavoriteColumn(favorites), new ModdedColumn(), new NameColumn(textures, tooltip),
|
||||
new SlotColumn(), new TypeColumn(), new UnlockDateColumn(), new ItemIdColumn(), new ModelDataColumn(), new JobColumn(jobs),
|
||||
new RequiredLevelColumn(), new DyableColumn(), new CrestColumn(), new TradableColumn())
|
||||
|
|
@ -36,6 +38,7 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
_unlockEvent = unlockEvent;
|
||||
_favorites = favorites;
|
||||
_penumbra = penumbra;
|
||||
_ignoredMods = ignoredMods;
|
||||
|
||||
Flags |= TableFlags.Hideable | TableFlags.Reorderable | TableFlags.Resizable;
|
||||
}
|
||||
|
|
@ -72,6 +75,7 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
UnlockTimestamp = unlocked,
|
||||
Mods = mods,
|
||||
Favorite = favorite,
|
||||
RelevantMods = mods.Count(m => !_ignoredMods.Contains(m.ModName) && !_ignoredMods.Contains(m.ModDirectory)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -94,24 +98,29 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
=> Im.Style.FrameHeightWithSpacing;
|
||||
|
||||
public override void DrawColumn(in UnlockCacheItem item, int globalIndex)
|
||||
{
|
||||
Im.Cursor.FrameAlign();
|
||||
UiHelpers.DrawFavoriteStar(_favorites, item.Item);
|
||||
}
|
||||
=> UiHelpers.DrawFavoriteStar(_favorites, item.Item);
|
||||
|
||||
protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex)
|
||||
=> item.Favorite;
|
||||
}
|
||||
|
||||
private sealed class ModdedColumn : YesNoColumn<UnlockCacheItem>
|
||||
private sealed class ModdedColumn : FlagColumn<ModdedColumn.Modded, UnlockCacheItem>
|
||||
{
|
||||
private static readonly AwesomeIcon Dot = FontAwesomeIcon.Circle;
|
||||
[Flags]
|
||||
public enum Modded
|
||||
{
|
||||
Relevant = 1,
|
||||
Ignored = 2,
|
||||
None = 4,
|
||||
}
|
||||
|
||||
private static readonly AwesomeIcon Dot = FontAwesomeIcon.Circle;
|
||||
private static readonly AwesomeIcon Hollow = FontAwesomeIcon.DotCircle;
|
||||
|
||||
public ModdedColumn()
|
||||
{
|
||||
Flags |= TableColumnFlags.NoResize;
|
||||
Label = new StringU8("M");
|
||||
FilterLabel = new StringU8("Modded"u8);
|
||||
Flags |= TableColumnFlags.NoResize;
|
||||
Label = new StringU8("M");
|
||||
}
|
||||
|
||||
public override float ComputeWidth(IEnumerable<UnlockCacheItem> allItems)
|
||||
|
|
@ -124,8 +133,11 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
|
||||
using (AwesomeIcon.Font.Push())
|
||||
{
|
||||
using var color = ImGuiColor.Text.Push(ColorId.ModdedItemMarker.Value());
|
||||
ImEx.TextCentered(Dot.Span);
|
||||
var (color, text) = item.RelevantMods > 0
|
||||
? (ColorId.ModdedItemMarker.Value(), Dot)
|
||||
: (ColorId.ModdedItemMarker.Value().HalfTransparent(), Hollow);
|
||||
using var c = ImGuiColor.Text.Push(color);
|
||||
Im.Text(text.Span);
|
||||
}
|
||||
|
||||
if (Im.Item.Hovered())
|
||||
|
|
@ -137,11 +149,29 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
}
|
||||
}
|
||||
|
||||
protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex)
|
||||
=> item.Mods.Length > 0;
|
||||
protected override Modded GetValue(in UnlockCacheItem item, int globalIndex)
|
||||
=> item.RelevantMods > 0 ? Modded.Relevant : item.Mods.Length > 0 ? Modded.Ignored : Modded.None;
|
||||
|
||||
protected override StringU8 DisplayString(in UnlockCacheItem item, int globalIndex)
|
||||
=> StringU8.Empty;
|
||||
|
||||
protected override IReadOnlyList<(Modded Value, StringU8 Name)> EnumData
|
||||
=>
|
||||
[
|
||||
(Modded.Relevant, new StringU8("Any Relevant Mods"u8)),
|
||||
(Modded.Ignored, new StringU8("Only Ignored Mods"u8)),
|
||||
(Modded.None, new StringU8("Unmodded"u8)),
|
||||
];
|
||||
|
||||
|
||||
public override int Compare(in UnlockCacheItem lhs, int lhsGlobalIndex, in UnlockCacheItem rhs, int rhsGlobalIndex)
|
||||
=> lhs.Mods.Length.CompareTo(rhs.Mods.Length);
|
||||
{
|
||||
var relevant = lhs.RelevantMods.CompareTo(rhs.RelevantMods);
|
||||
if (relevant is not 0)
|
||||
return relevant;
|
||||
|
||||
return lhs.Mods.Length.CompareTo(rhs.Mods.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class NameColumn : TextColumn<UnlockCacheItem>
|
||||
|
|
@ -241,9 +271,9 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
|||
{
|
||||
public UnlockDateColumn()
|
||||
{
|
||||
Flags &= ~TableColumnFlags.NoResize;
|
||||
Label = new StringU8("Unlocked"u8);
|
||||
FilterLabel = Label;
|
||||
Flags &= ~TableColumnFlags.NoResize;
|
||||
Label = new StringU8("Unlocked"u8);
|
||||
FilterLabel = Label;
|
||||
}
|
||||
|
||||
public override float ComputeWidth(IEnumerable<UnlockCacheItem> allItems)
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ namespace Glamourer.Gui.Tabs.UnlocksTab;
|
|||
|
||||
public sealed class UnlocksTab : Window, ITab<MainTabType>
|
||||
{
|
||||
private readonly Configuration.EphemeralConfig _config;
|
||||
private readonly Config.EphemeralConfig _config;
|
||||
private readonly UnlockOverview _overview;
|
||||
private readonly UnlockTable _table;
|
||||
|
||||
public UnlocksTab(Configuration.EphemeralConfig config, UnlockOverview overview, UnlockTable table)
|
||||
public UnlocksTab(Config.EphemeralConfig config, UnlockOverview overview, UnlockTable table)
|
||||
: base("Unlocked Equipment")
|
||||
{
|
||||
_config = config;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Game.Gui.ContextMenu;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
|
|
@ -23,7 +24,7 @@ public class ContextMenuService : IDisposable
|
|||
|
||||
private readonly MenuItem _inventoryItem;
|
||||
|
||||
public ContextMenuService(ItemManager items, StateManager state, ActorObjectManager objects, Configuration.Configuration config,
|
||||
public ContextMenuService(ItemManager items, StateManager state, ActorObjectManager objects, Configuration config,
|
||||
IContextMenu context)
|
||||
{
|
||||
_contextMenu = context;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
|
|
@ -24,7 +25,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
|||
private readonly ThreadLocal<List<MaterialValueIndex>> _deleteList = new(() => []);
|
||||
|
||||
public MaterialManager(PrepareColorSet prepareColorSet, StateManager stateManager, ActorManager actors, PenumbraService penumbra,
|
||||
Configuration.Configuration config)
|
||||
Configuration config)
|
||||
{
|
||||
_stateManager = stateManager;
|
||||
_actors = actors;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs.Links;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Luna;
|
||||
|
|
@ -7,14 +8,19 @@ using Penumbra.GameData.Structs;
|
|||
|
||||
namespace Glamourer.Interop.Penumbra;
|
||||
|
||||
public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip autoRedrawSkip, Configuration.Configuration config, ActorObjectManager objects, CollectionOverrideService overrides)
|
||||
public class ModSettingApplier(
|
||||
PenumbraService penumbra,
|
||||
PenumbraAutoRedrawSkip autoRedrawSkip,
|
||||
Configuration config,
|
||||
ActorObjectManager objects,
|
||||
CollectionOverrideService overrides)
|
||||
: IService
|
||||
{
|
||||
private readonly HashSet<Guid> _collectionTracker = [];
|
||||
|
||||
public void HandleStateApplication(ActorState state, MergedDesign design, StateSource source, bool skipAutoRedraw, bool respectManual)
|
||||
{
|
||||
if (!config.AlwaysApplyAssociatedMods || (design.AssociatedMods.Count == 0 && !design.ResetTemporarySettings))
|
||||
if (!config.AlwaysApplyAssociatedMods || design.AssociatedMods.Count == 0 && !design.ResetTemporarySettings)
|
||||
return;
|
||||
|
||||
if (!objects.TryGetValue(state.Identifier, out var data))
|
||||
|
|
@ -90,6 +96,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
|
|||
if (!respectManual && source.IsFixed())
|
||||
penumbra.RemoveAllTemporarySettings(index.Value, StateSource.Manual);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Api.Enums;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs.History;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.State;
|
||||
|
|
@ -11,17 +12,17 @@ namespace Glamourer.Interop.Penumbra;
|
|||
|
||||
public class PenumbraAutoRedraw : IDisposable, IRequiredService
|
||||
{
|
||||
private const int WaitFrames = 5;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly StateManager _state;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly IFramework _framework;
|
||||
private readonly StateChanged _stateChanged;
|
||||
private readonly PenumbraAutoRedrawSkip _skip;
|
||||
private const int WaitFrames = 5;
|
||||
private readonly Configuration _config;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly StateManager _state;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly IFramework _framework;
|
||||
private readonly StateChanged _stateChanged;
|
||||
private readonly PenumbraAutoRedrawSkip _skip;
|
||||
|
||||
|
||||
public PenumbraAutoRedraw(PenumbraService penumbra, Configuration.Configuration config, StateManager state, ActorObjectManager objects,
|
||||
public PenumbraAutoRedraw(PenumbraService penumbra, Configuration config, StateManager state, ActorObjectManager objects,
|
||||
IFramework framework,
|
||||
StateChanged stateChanged, PenumbraAutoRedrawSkip skip)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Dalamud.Interface.ImGuiNotification;
|
||||
using Dalamud.Plugin;
|
||||
using Dalamud.Plugin.Ipc.Exceptions;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.State;
|
||||
using Luna;
|
||||
|
|
@ -45,7 +46,7 @@ public class PenumbraService : IDisposable
|
|||
private const string NameManual = "Glamourer (Manually)";
|
||||
|
||||
private readonly IDalamudPluginInterface _pluginInterface;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly Configuration _config;
|
||||
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
|
||||
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
|
||||
private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase;
|
||||
|
|
@ -96,7 +97,7 @@ public class PenumbraService : IDisposable
|
|||
public int CurrentMinor { get; private set; }
|
||||
public DateTime AttachTime { get; private set; }
|
||||
|
||||
public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded, Configuration.Configuration config)
|
||||
public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded, Configuration config)
|
||||
{
|
||||
_pluginInterface = pi;
|
||||
_penumbraReloaded = penumbraReloaded;
|
||||
|
|
|
|||
|
|
@ -1,27 +1,9 @@
|
|||
using Luna;
|
||||
using Backup = OtterGui.Classes.Backup;
|
||||
using Logger = OtterGui.Log.Logger;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public class BackupService : IAsyncService
|
||||
public class BackupService(Logger log, FilenameService provider) : BaseBackupService<FilenameService>(log, provider)
|
||||
{
|
||||
private readonly Logger _logger;
|
||||
private readonly DirectoryInfo _configDirectory;
|
||||
private readonly IReadOnlyList<FileInfo> _fileNames;
|
||||
|
||||
public BackupService(Logger logger, FilenameService fileNames)
|
||||
{
|
||||
_logger = logger;
|
||||
_fileNames = GlamourerFiles(fileNames);
|
||||
_configDirectory = new DirectoryInfo(fileNames.ConfigurationDirectory);
|
||||
Awaiter = Task.Run(() => Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigurationDirectory), _fileNames));
|
||||
}
|
||||
|
||||
/// <summary> Create a permanent backup with a given name for migrations. </summary>
|
||||
public void CreateMigrationBackup(string name)
|
||||
=> Backup.CreatePermanentBackup(_logger, _configDirectory, _fileNames, name);
|
||||
|
||||
/// <summary> Collect all relevant files for glamourer configuration. </summary>
|
||||
private static IReadOnlyList<FileInfo> GlamourerFiles(FilenameService fileNames)
|
||||
{
|
||||
|
|
@ -29,7 +11,7 @@ public class BackupService : IAsyncService
|
|||
{
|
||||
new(fileNames.ConfigurationFile),
|
||||
new(fileNames.UiConfiguration),
|
||||
new(fileNames.DesignFileSystem),
|
||||
new(fileNames.MigrationDesignFileSystem),
|
||||
new(fileNames.MigrationDesignFile),
|
||||
new(fileNames.AutomationFile),
|
||||
new(fileNames.UnlockFileCustomize),
|
||||
|
|
@ -42,9 +24,4 @@ public class BackupService : IAsyncService
|
|||
|
||||
return list;
|
||||
}
|
||||
|
||||
public Task Awaiter { get; }
|
||||
|
||||
public bool Finished
|
||||
=> Awaiter.IsCompletedSuccessfully;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
using Glamourer.Config;
|
||||
using ImSharp;
|
||||
using Luna;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
public class CodeService
|
||||
{
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly SHA256 _hasher = SHA256.Create();
|
||||
private readonly Configuration _config;
|
||||
private readonly SHA256 _hasher = SHA256.Create();
|
||||
|
||||
[Flags]
|
||||
public enum CodeFlag : ulong
|
||||
|
|
@ -25,16 +25,17 @@ public class CodeService
|
|||
OopsAuRa = 0x000400,
|
||||
OopsHrothgar = 0x000800,
|
||||
OopsViera = 0x001000,
|
||||
|
||||
//Artisan = 0x002000,
|
||||
SixtyThree = 0x004000,
|
||||
Shirts = 0x008000,
|
||||
World = 0x010000,
|
||||
Elephants = 0x020000,
|
||||
Crown = 0x040000,
|
||||
Dolphins = 0x080000,
|
||||
Face = 0x100000,
|
||||
Manderville = 0x200000,
|
||||
Smiles = 0x400000,
|
||||
SixtyThree = 0x004000,
|
||||
Shirts = 0x008000,
|
||||
World = 0x010000,
|
||||
Elephants = 0x020000,
|
||||
Crown = 0x040000,
|
||||
Dolphins = 0x080000,
|
||||
Face = 0x100000,
|
||||
Manderville = 0x200000,
|
||||
Smiles = 0x400000,
|
||||
}
|
||||
|
||||
public static readonly CodeFlag AllHintCodes =
|
||||
|
|
@ -87,7 +88,7 @@ public class CodeService
|
|||
_ => Race.Unknown,
|
||||
};
|
||||
|
||||
public CodeService(Configuration.Configuration config)
|
||||
public CodeService(Configuration config)
|
||||
{
|
||||
_config = config;
|
||||
Load();
|
||||
|
|
@ -253,4 +254,3 @@ public class CodeService
|
|||
_ => (false, 0, string.Empty, string.Empty, string.Empty),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Config;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs.Special;
|
||||
using Glamourer.GameData;
|
||||
|
|
@ -24,27 +25,27 @@ public class CommandService : IDisposable, IApiService
|
|||
private const string MainCommandString = "/glamourer";
|
||||
private const string ApplyCommandString = "/glamour";
|
||||
|
||||
private readonly ICommandManager _commands;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly IChatGui _chat;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly AutoDesignManager _autoDesignManager;
|
||||
private readonly Configuration.Configuration _config;
|
||||
private readonly ModSettingApplier _modApplier;
|
||||
private readonly ItemManager _items;
|
||||
private readonly CustomizeService _customizeService;
|
||||
private readonly DesignManager _designManager;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly DesignResolver _resolver;
|
||||
private readonly PenumbraService _penumbra;
|
||||
private readonly ICommandManager _commands;
|
||||
private readonly MainWindow _mainWindow;
|
||||
private readonly IChatGui _chat;
|
||||
private readonly ActorManager _actors;
|
||||
private readonly ActorObjectManager _objects;
|
||||
private readonly StateManager _stateManager;
|
||||
private readonly AutoDesignApplier _autoDesignApplier;
|
||||
private readonly AutoDesignManager _autoDesignManager;
|
||||
private readonly Configuration _config;
|
||||
private readonly ModSettingApplier _modApplier;
|
||||
private readonly ItemManager _items;
|
||||
private readonly CustomizeService _customizeService;
|
||||
private readonly DesignManager _designManager;
|
||||
private readonly DesignConverter _converter;
|
||||
private readonly DesignResolver _resolver;
|
||||
private readonly PenumbraService _penumbra;
|
||||
|
||||
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ActorObjectManager objects,
|
||||
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
|
||||
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration.Configuration config, ModSettingApplier modApplier,
|
||||
ItemManager items, RandomDesignGenerator randomDesign, CustomizeService customizeService, DesignFileSystemSelector designSelector,
|
||||
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config, ModSettingApplier modApplier,
|
||||
ItemManager items, RandomDesignGenerator randomDesign, CustomizeService customizeService, DesignFileSystemDrawer designDrawer,
|
||||
QuickDesignCombo quickDesignCombo, DesignResolver resolver, PenumbraService penumbra)
|
||||
{
|
||||
_commands = commands;
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue