mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2026-02-25 06:01:48 +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.Api.Enums;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using ImSharp;
|
|
||||||
using Luna;
|
using Luna;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
|
@ -12,7 +11,6 @@ public class DesignsApi(
|
||||||
ApiHelpers helpers,
|
ApiHelpers helpers,
|
||||||
DesignManager designs,
|
DesignManager designs,
|
||||||
StateManager stateManager,
|
StateManager stateManager,
|
||||||
DesignFileSystem fileSystem,
|
|
||||||
DesignColors color,
|
DesignColors color,
|
||||||
DesignConverter converter)
|
DesignConverter converter)
|
||||||
: IGlamourerApiDesigns, IApiService
|
: IGlamourerApiDesigns, IApiService
|
||||||
|
|
@ -21,12 +19,11 @@ public class DesignsApi(
|
||||||
=> designs.Designs.ToDictionary(d => d.Identifier, d => d.Name.Text);
|
=> designs.Designs.ToDictionary(d => d.Identifier, d => d.Name.Text);
|
||||||
|
|
||||||
public Dictionary<Guid, (string DisplayName, string FullPath, uint DisplayColor, bool ShownInQdb)> GetDesignListExtended()
|
public Dictionary<Guid, (string DisplayName, string FullPath, uint DisplayColor, bool ShownInQdb)> GetDesignListExtended()
|
||||||
=> fileSystem.ToDictionary(kvp => kvp.Key.Identifier,
|
=> designs.Designs.ToDictionary(d => d.Identifier, d => (d.DisplayName, d.Path.CurrentPath, color.GetColor(d).Color, d.QuickDesign));
|
||||||
kvp => (kvp.Key.Name.Text, kvp.Value.FullName(), color.GetColor(kvp.Key).Color, kvp.Key.QuickDesign));
|
|
||||||
|
|
||||||
public (string DisplayName, string FullPath, uint DisplayColor, bool ShowInQdb) GetExtendedDesignData(Guid designId)
|
public (string DisplayName, string FullPath, uint DisplayColor, bool ShowInQdb) GetExtendedDesignData(Guid designId)
|
||||||
=> designs.Designs.ByIdentifier(designId) is { } d
|
=> 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);
|
: (string.Empty, string.Empty, 0, false);
|
||||||
|
|
||||||
public GlamourerApiEc ApplyDesign(Guid designId, int objectIndex, uint key, ApplyFlag flags)
|
public GlamourerApiEc ApplyDesign(Guid designId, int objectIndex, uint key, ApplyFlag flags)
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
using Glamourer.Api.Api;
|
using Glamourer.Api.Api;
|
||||||
|
using Glamourer.Config;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Api;
|
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 CurrentApiVersionMajor = 1;
|
||||||
public const int CurrentApiVersionMinor = 7;
|
public const int CurrentApiVersionMinor = 7;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Designs.Links;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
|
@ -16,7 +17,7 @@ namespace Glamourer.Automation;
|
||||||
|
|
||||||
public sealed class AutoDesignApplier : IDisposable
|
public sealed class AutoDesignApplier : IDisposable
|
||||||
{
|
{
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly AutoDesignManager _manager;
|
private readonly AutoDesignManager _manager;
|
||||||
private readonly StateManager _state;
|
private readonly StateManager _state;
|
||||||
private readonly JobService _jobs;
|
private readonly JobService _jobs;
|
||||||
|
|
@ -31,7 +32,7 @@ public sealed class AutoDesignApplier : IDisposable
|
||||||
|
|
||||||
private readonly JobChangeState _jobChangeState;
|
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,
|
AutomationChanged @event, ActorObjectManager objects, WeaponLoading weapons, HumanModelList humans, IClientState clientState,
|
||||||
EquippedGearset equippedGearset, DesignMerger designMerger, JobChangeState jobChangeState)
|
EquippedGearset equippedGearset, DesignMerger designMerger, JobChangeState jobChangeState)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,7 @@ public class FixedDesignMigrator(JobService jobs)
|
||||||
var set = autoManager[^1];
|
var set = autoManager[^1];
|
||||||
foreach (var design in data.AsEnumerable().Reverse())
|
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.",
|
Glamourer.Messager.NotificationMessage($"Could not find design with path {design.Item1}, skipped fixed design.",
|
||||||
NotificationType.Warning);
|
NotificationType.Warning);
|
||||||
|
|
|
||||||
|
|
@ -7,14 +7,16 @@ using Glamourer.Gui.Tabs.DesignTab;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
using Luna.Generators;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using OtterGui.Filesystem;
|
|
||||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
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]
|
[JsonIgnore]
|
||||||
public readonly EphemeralConfig Ephemeral;
|
public readonly EphemeralConfig Ephemeral;
|
||||||
|
|
||||||
|
|
@ -59,7 +61,10 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
public DefaultDesignSettings DefaultDesignSettings { get; set; } = new();
|
public DefaultDesignSettings DefaultDesignSettings { get; set; } = new();
|
||||||
|
|
||||||
public HeightDisplayType HeightDisplayType { get; set; } = HeightDisplayType.Centimetre;
|
public HeightDisplayType HeightDisplayType { get; set; } = HeightDisplayType.Centimetre;
|
||||||
public RenameField ShowRename { get; set; } = RenameField.BothDataPrio;
|
|
||||||
|
[ConfigProperty(EventName = "OnRenameChanged")]
|
||||||
|
private RenameField _showRename = RenameField.BothDataPrio;
|
||||||
|
|
||||||
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
public ModifiableHotkey ToggleQuickDesignBar { get; set; } = new(VirtualKey.NO_KEY);
|
||||||
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
public DoubleModifier DeleteDesignModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift);
|
||||||
public DoubleModifier IncognitoModifier { get; set; } = new(ModifierHotkey.Control);
|
public DoubleModifier IncognitoModifier { get; set; } = new(ModifierHotkey.Control);
|
||||||
|
|
@ -70,7 +75,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
|
|
||||||
[JsonConverter(typeof(SortModeConverter))]
|
[JsonConverter(typeof(SortModeConverter))]
|
||||||
[JsonProperty(Order = int.MaxValue)]
|
[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; } = [];
|
public List<(string Code, bool Enabled)> Codes { get; set; } = [];
|
||||||
|
|
||||||
|
|
@ -80,7 +85,7 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
public bool DebugMode { get; set; } = false;
|
public bool DebugMode { get; set; } = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
public int Version { get; set; } = Constants.CurrentVersion;
|
public int Version { get; set; } = CurrentVersion;
|
||||||
|
|
||||||
public Dictionary<ColorId, uint> Colors { get; private set; }
|
public Dictionary<ColorId, uint> Colors { get; private set; }
|
||||||
= ColorId.Values.ToDictionary(c => c, c => c.Data().DefaultColor);
|
= ColorId.Values.ToDictionary(c => c, c => c.Data().DefaultColor);
|
||||||
|
|
@ -142,45 +147,22 @@ public class Configuration : IPluginConfiguration, ISavable
|
||||||
serializer.Serialize(jWriter, this);
|
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>
|
/// <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);
|
serializer.Serialize(writer, value.GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override ISortMode<Design> ReadJson(JsonReader reader, Type objectType, ISortMode<Design>? existingValue,
|
public override ISortMode ReadJson(JsonReader reader, Type objectType, ISortMode? existingValue, bool hasExistingValue,
|
||||||
bool hasExistingValue,
|
|
||||||
JsonSerializer serializer)
|
JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
var name = serializer.Deserialize<string>(reader);
|
if (serializer.Deserialize<string>(reader) is { } name)
|
||||||
if (name == null || !Constants.ValidSortModes.FindFirst(s => s.GetType().Name == name, out var mode))
|
return ISortMode.Valid.GetValueOrDefault(name, existingValue ?? ISortMode.FoldersFirst);
|
||||||
return existingValue ?? ISortMode<Design>.FoldersFirst;
|
|
||||||
|
|
||||||
return mode;
|
return existingValue ?? ISortMode.FoldersFirst;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
namespace Glamourer.Configuration;
|
namespace Glamourer.Config;
|
||||||
|
|
||||||
public class DefaultDesignSettings
|
public class DefaultDesignSettings
|
||||||
{
|
{
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna.Generators;
|
using Luna.Generators;
|
||||||
|
|
||||||
namespace Glamourer.Configuration;
|
namespace Glamourer.Config;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
[NamedEnum(Utf16: false)]
|
[NamedEnum(Utf16: false)]
|
||||||
|
|
@ -42,7 +42,7 @@ 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))
|
if (config.HideDesignPanel.HasFlag(flag))
|
||||||
return default;
|
return default;
|
||||||
|
|
@ -6,11 +6,11 @@ using Luna.Generators;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||||
|
|
||||||
namespace Glamourer.Configuration;
|
namespace Glamourer.Config;
|
||||||
|
|
||||||
public partial class EphemeralConfig : ISavable
|
public partial class EphemeralConfig : ISavable
|
||||||
{
|
{
|
||||||
public int Version { get; set; } = Configuration.Constants.CurrentVersion;
|
public int Version { get; set; } = Configuration.CurrentVersion;
|
||||||
|
|
||||||
[ConfigProperty]
|
[ConfigProperty]
|
||||||
private bool _incognitoMode;
|
private bool _incognitoMode;
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
using Luna.Generators;
|
using Luna.Generators;
|
||||||
|
|
||||||
namespace Glamourer.Configuration;
|
namespace Glamourer.Config;
|
||||||
|
|
||||||
[TooltipEnum]
|
[TooltipEnum]
|
||||||
public enum HeightDisplayType
|
public enum HeightDisplayType
|
||||||
|
|
@ -4,7 +4,7 @@ using Luna.Generators;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Glamourer.Configuration;
|
namespace Glamourer.Config;
|
||||||
|
|
||||||
public sealed partial class UiConfig : ConfigurationFile<FilenameService>
|
public sealed partial class UiConfig : ConfigurationFile<FilenameService>
|
||||||
{
|
{
|
||||||
|
|
@ -14,7 +14,7 @@ using Notification = Luna.Notification;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
public sealed class Design : DesignBase, ISavable, IDesignStandIn, IFileSystemValue<Design>
|
||||||
{
|
{
|
||||||
#region Data
|
#region Data
|
||||||
|
|
||||||
|
|
@ -44,6 +44,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
public new const int FileVersion = 2;
|
public new const int FileVersion = 2;
|
||||||
|
|
||||||
public Guid Identifier { get; internal init; }
|
public Guid Identifier { get; internal init; }
|
||||||
|
public IFileSystemData<Design>? Node { get; set; }
|
||||||
public DateTimeOffset CreationDate { get; internal init; }
|
public DateTimeOffset CreationDate { get; internal init; }
|
||||||
public DateTimeOffset LastEdit { get; internal set; }
|
public DateTimeOffset LastEdit { get; internal set; }
|
||||||
public LowerString Name { get; internal set; } = LowerString.Empty;
|
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 string Color { get; internal set; } = string.Empty;
|
||||||
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
|
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
|
||||||
public LinkContainer Links { get; private set; } = [];
|
public LinkContainer Links { get; private set; } = [];
|
||||||
|
public DataPath Path { get; } = new();
|
||||||
|
|
||||||
public string Incognito
|
public string Incognito
|
||||||
=> Identifier.ToString()[..8];
|
=> Identifier.ToString()[..8];
|
||||||
|
|
@ -124,6 +126,12 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
["Mods"] = SerializeMods(),
|
["Mods"] = SerializeMods(),
|
||||||
["Links"] = Links.Serialize(),
|
["Links"] = Links.Serialize(),
|
||||||
};
|
};
|
||||||
|
if (Path.Folder.Length > 0)
|
||||||
|
ret["FileSystemFolder"] = Path.Folder;
|
||||||
|
if (Path.SortName is not null)
|
||||||
|
ret["SortOrderName"] = Path.SortName;
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,6 +259,9 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
};
|
};
|
||||||
if (design.LastEdit < creationDate)
|
if (design.LastEdit < creationDate)
|
||||||
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);
|
design.SetWriteProtected(json["WriteProtected"]?.ToObject<bool>() ?? false);
|
||||||
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
LoadCustomize(customizations, json["Customize"], design, design.Name, true, false);
|
||||||
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
LoadEquip(items, json["Equipment"], design, design.Name, true);
|
||||||
|
|
@ -340,7 +351,13 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
}
|
}
|
||||||
|
|
||||||
public string LogName(string fileName)
|
public string LogName(string fileName)
|
||||||
=> Path.GetFileNameWithoutExtension(fileName);
|
=> System.IO.Path.GetFileNameWithoutExtension(fileName);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
string IFileSystemValue.Identifier
|
||||||
|
=> Identifier.ToString();
|
||||||
|
|
||||||
|
public string DisplayName
|
||||||
|
=> Name.Text;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
@ -8,7 +9,7 @@ using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public class DesignColorUi(DesignColors colors, Configuration.Configuration config)
|
public class DesignColorUi(DesignColors colors, Configuration config)
|
||||||
{
|
{
|
||||||
private string _newName = string.Empty;
|
private string _newName = string.Empty;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using OtterGui.Classes;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
using Penumbra.String.Functions;
|
using Penumbra.String.Functions;
|
||||||
|
|
@ -47,8 +46,8 @@ public unsafe struct DesignData
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveOptimization | MethodImplOptions.AggressiveInlining)]
|
||||||
public readonly bool ContainsName(LowerString name)
|
public readonly bool ContainsName(string name)
|
||||||
=> ItemNames.Any(name.IsContained);
|
=> ItemNames.Any(i => i.Contains(name, StringComparison.OrdinalIgnoreCase));
|
||||||
|
|
||||||
public readonly StainIds Stain(EquipSlot slot)
|
public readonly StainIds Stain(EquipSlot slot)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Designs.Links;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
|
@ -5,7 +6,6 @@ using Glamourer.GameData;
|
||||||
using Glamourer.Interop.Material;
|
using Glamourer.Interop.Material;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
|
@ -16,14 +16,14 @@ public class DesignEditor(
|
||||||
DesignChanged designChanged,
|
DesignChanged designChanged,
|
||||||
CustomizeService customizations,
|
CustomizeService customizations,
|
||||||
ItemManager items,
|
ItemManager items,
|
||||||
Configuration.Configuration config)
|
Configuration config)
|
||||||
: IDesignEditor
|
: IDesignEditor
|
||||||
{
|
{
|
||||||
protected readonly DesignChanged DesignChanged = designChanged;
|
protected readonly DesignChanged DesignChanged = designChanged;
|
||||||
protected readonly SaveService SaveService = saveService;
|
protected readonly SaveService SaveService = saveService;
|
||||||
protected readonly ItemManager Items = items;
|
protected readonly ItemManager Items = items;
|
||||||
protected readonly CustomizeService Customizations = customizations;
|
protected readonly CustomizeService Customizations = customizations;
|
||||||
protected readonly Configuration.Configuration Config = config;
|
protected readonly Configuration Config = config;
|
||||||
protected readonly Dictionary<Guid, DesignData> UndoStore = [];
|
protected readonly Dictionary<Guid, DesignData> UndoStore = [];
|
||||||
|
|
||||||
private bool _forceFullItemOff;
|
private bool _forceFullItemOff;
|
||||||
|
|
|
||||||
|
|
@ -3,195 +3,64 @@ using Glamourer.Designs.History;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Luna;
|
using Luna;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public sealed class DesignFileSystem : OtterGui.Filesystem.FileSystem<Design>, IDisposable, ISavable
|
public sealed class DesignFileSystem : BaseFileSystem, IDisposable, IRequiredService
|
||||||
{
|
{
|
||||||
|
private readonly DesignFileSystemSaver _saver;
|
||||||
private readonly DesignChanged _designChanged;
|
private readonly DesignChanged _designChanged;
|
||||||
|
|
||||||
private readonly SaveService _saveService;
|
public DesignFileSystem(Logger log, SaveService saveService, DesignStorage designs, DesignChanged designChanged)
|
||||||
private readonly DesignManager _designManager;
|
: base("DesignFileSystem", log, true)
|
||||||
|
|
||||||
public DesignFileSystem(DesignManager designManager, SaveService saveService, DesignChanged designChanged)
|
|
||||||
{
|
{
|
||||||
_designManager = designManager;
|
|
||||||
_saveService = saveService;
|
|
||||||
_designChanged = designChanged;
|
_designChanged = designChanged;
|
||||||
_designChanged.Subscribe(OnDesignChange, DesignChanged.Priority.DesignFileSystem);
|
_saver = new DesignFileSystemSaver(log, this, saveService, designs);
|
||||||
Changed += OnChange;
|
|
||||||
Reload();
|
_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))
|
switch (type)
|
||||||
_saveService.ImmediateSave(this);
|
{
|
||||||
|
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()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_designChanged.Unsubscribe(OnDesignChange);
|
_designChanged.Unsubscribe(OnDesignChanged);
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 Dalamud.Utility;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Designs.Links;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
|
@ -21,7 +22,7 @@ public sealed class DesignManager : DesignEditor
|
||||||
private readonly HumanModelList _humans;
|
private readonly HumanModelList _humans;
|
||||||
|
|
||||||
public DesignManager(SaveService saveService, ItemManager items, CustomizeService customizations,
|
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)
|
: base(saveService, @event, customizations, items, config)
|
||||||
{
|
{
|
||||||
Designs = storage;
|
Designs = storage;
|
||||||
|
|
@ -545,7 +546,6 @@ public sealed class DesignManager : DesignEditor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DesignFileSystem.MigrateOldPaths(SaveService, migratedFileSystemPaths);
|
|
||||||
Glamourer.Log.Information(
|
Glamourer.Log.Information(
|
||||||
$"Successfully migrated {successes} old designs. Skipped {skips} already migrated designs. Failed to migrate {errors} designs.");
|
$"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.Api.Enums;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop.Material;
|
using Glamourer.Interop.Material;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -15,7 +16,7 @@ namespace Glamourer.Designs.Links;
|
||||||
public class DesignMerger(
|
public class DesignMerger(
|
||||||
DesignManager designManager,
|
DesignManager designManager,
|
||||||
CustomizeService customizeService,
|
CustomizeService customizeService,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
ItemUnlockManager itemUnlocks,
|
ItemUnlockManager itemUnlocks,
|
||||||
CustomizeUnlockManager customizeUnlocks) : IService
|
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;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Designs.Special;
|
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 Random _rng = new();
|
||||||
private readonly WeakReference<Design> _lastDesign = new(null!, false);
|
private readonly WeakReference<Design> _lastDesign = new(null!, false);
|
||||||
|
|
|
||||||
|
|
@ -10,19 +10,19 @@ public interface IDesignPredicate
|
||||||
=> Invoke(args.Design, args.LowerName, args.Identifier, args.LowerPath);
|
=> Invoke(args.Design, args.LowerName, args.Identifier, args.LowerPath);
|
||||||
|
|
||||||
public IEnumerable<Design> Get(IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
public IEnumerable<Design> Get(IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
||||||
=> designs.Select(d => Transform(d, fileSystem))
|
=> designs.Select(Transform)
|
||||||
.Where(Invoke)
|
.Where(Invoke)
|
||||||
.Select(t => t.Design);
|
.Select(t => t.Design);
|
||||||
|
|
||||||
public static IEnumerable<Design> Get(IReadOnlyList<IDesignPredicate> predicates, IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
public static IEnumerable<Design> Get(IReadOnlyList<IDesignPredicate> predicates, IEnumerable<Design> designs, DesignFileSystem fileSystem)
|
||||||
=> predicates.Count > 0
|
=> predicates.Count > 0
|
||||||
? designs.Select(d => Transform(d, fileSystem))
|
? designs.Select(Transform)
|
||||||
.Where(t => predicates.Any(p => p.Invoke(t)))
|
.Where(t => predicates.Any(p => p.Invoke(t)))
|
||||||
.Select(t => t.Design)
|
.Select(t => t.Design)
|
||||||
: designs;
|
: designs;
|
||||||
|
|
||||||
private static (Design Design, string LowerName, string Identifier, string LowerPath) Transform(Design d, DesignFileSystem fs)
|
private static (Design Design, string LowerName, string Identifier, string LowerPath) Transform(Design d)
|
||||||
=> (d, d.Name.Lower, d.Identifier.ToString(), fs.TryGetValue(d, out var l) ? l.FullName().ToLowerInvariant() : string.Empty);
|
=> (d, d.Name.Lower, d.Identifier.ToString(), d.Path.CurrentPath.ToLowerInvariant());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class RandomPredicate
|
public static class RandomPredicate
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
|
using Glamourer.Gui.Tabs.DesignTab;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
|
|
||||||
namespace Glamourer.Events;
|
namespace Glamourer.Events;
|
||||||
|
|
@ -135,10 +136,13 @@ public sealed class DesignChanged()
|
||||||
/// <seealso cref="Automation.AutoDesignManager.OnDesignChange"/>
|
/// <seealso cref="Automation.AutoDesignManager.OnDesignChange"/>
|
||||||
AutoDesignManager = 1,
|
AutoDesignManager = 1,
|
||||||
|
|
||||||
/// <seealso cref="DesignFileSystem.OnDesignChange"/>
|
/// <seealso cref="DesignFileSystem.OnDesignChanged"/>
|
||||||
DesignFileSystem = 0,
|
DesignFileSystem = 0,
|
||||||
|
|
||||||
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnDesignChange"/>
|
/// <seealso cref="DesignHeader.OnDesignChanged"/>
|
||||||
|
DesignHeader = 0,
|
||||||
|
|
||||||
|
/// <seealso cref="DesignFileSystemDrawer.OnDesignChanged"/>
|
||||||
DesignFileSystemSelector = -1,
|
DesignFileSystemSelector = -1,
|
||||||
|
|
||||||
/// <seealso cref="DesignComboBase.OnDesignChanged"/>
|
/// <seealso cref="DesignComboBase.OnDesignChanged"/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
|
using Glamourer.Gui.Tabs.DesignTab;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
|
|
||||||
namespace Glamourer.Events;
|
namespace Glamourer.Events;
|
||||||
|
|
@ -16,7 +17,7 @@ public sealed class TabSelected()
|
||||||
{
|
{
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnTabSelected"/>
|
/// <seealso cref="DesignFileSystemDrawer.OnTabSelected"/>
|
||||||
DesignSelector = 0,
|
DesignSelector = 0,
|
||||||
|
|
||||||
/// <seealso cref="Gui.MainWindow.OnTabSelected"/>
|
/// <seealso cref="Gui.MainWindow.OnTabSelected"/>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Glamourer.Api;
|
using Glamourer.Api;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Gui;
|
using Glamourer.Gui;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
|
|
@ -61,7 +62,7 @@ public class Glamourer : IDalamudPlugin
|
||||||
public string GatherSupportInformation()
|
public string GatherSupportInformation()
|
||||||
{
|
{
|
||||||
var sb = new StringBuilder(10240);
|
var sb = new StringBuilder(10240);
|
||||||
var config = _services.GetService<Configuration.Configuration>();
|
var config = _services.GetService<Configuration>();
|
||||||
sb.AppendLine("**Settings**");
|
sb.AppendLine("**Settings**");
|
||||||
sb.Append($"> **`Plugin Version: `** {Version}\n");
|
sb.Append($"> **`Plugin Version: `** {Version}\n");
|
||||||
sb.Append($"> **`Commit Hash: `** {CommitHash}\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>
|
<PropertyGroup>
|
||||||
<RootNamespace>Glamourer</RootNamespace>
|
<RootNamespace>Glamourer</RootNamespace>
|
||||||
<AssemblyName>Glamourer</AssemblyName>
|
<AssemblyName>Glamourer</AssemblyName>
|
||||||
|
|
@ -22,6 +22,11 @@
|
||||||
<EmbeddedResource Include="LegacyTattoo.raw" />
|
<EmbeddedResource Include="LegacyTattoo.raw" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<Use_DalamudPackager>false</Use_DalamudPackager>
|
||||||
|
<Use_Dalamud_ImGui>false</Use_Dalamud_ImGui>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Glamourer.Api\Glamourer.Api.csproj" />
|
<ProjectReference Include="..\Glamourer.Api\Glamourer.Api.csproj" />
|
||||||
<ProjectReference Include="..\Luna\Luna\Luna.csproj" />
|
<ProjectReference Include="..\Luna\Luna\Luna.csproj" />
|
||||||
|
|
@ -31,7 +36,8 @@
|
||||||
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||||
<PackageReference Include="Vortice.Direct3D11" Version="3.4.2-beta" />
|
<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>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
@ -50,7 +56,8 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="GetGitHash" BeforeTargets="GetAssemblyVersion" Returns="InformationalVersion">
|
<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="ExitCode" PropertyName="GitCommitHashSuccess" />
|
||||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" Condition="$(GitCommitHashSuccess) == 0" />
|
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" Condition="$(GitCommitHashSuccess) == 0" />
|
||||||
</Exec>
|
</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;
|
using ImSharp;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
@ -83,6 +84,6 @@ public static class Colors
|
||||||
=> _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor;
|
=> _colors.TryGetValue(color, out var value) ? value : color.Data().DefaultColor;
|
||||||
|
|
||||||
/// <summary> Set the configurable colors dictionary to a value. </summary>
|
/// <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;
|
=> _colors = config.Colors;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using System.Text.Unicode;
|
using System.Text.Unicode;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Interface.Textures;
|
using Dalamud.Interface.Textures;
|
||||||
using Dalamud.Interface.Textures.TextureWraps;
|
using Dalamud.Interface.Textures.TextureWraps;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
|
|
@ -14,7 +15,7 @@ namespace Glamourer.Gui.Customization;
|
||||||
public partial class CustomizationDrawer(
|
public partial class CustomizationDrawer(
|
||||||
ITextureProvider textures,
|
ITextureProvider textures,
|
||||||
CustomizeService service,
|
CustomizeService service,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
FavoriteManager favorites,
|
FavoriteManager favorites,
|
||||||
HeightService heightService)
|
HeightService heightService)
|
||||||
: IDisposable
|
: IDisposable
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Glamourer.Designs;
|
using Glamourer.Config;
|
||||||
|
using Glamourer.Designs;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop.PalettePlus;
|
using Glamourer.Interop.PalettePlus;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -7,7 +8,7 @@ using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Customization;
|
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 readonly Dictionary<Design, CustomizeParameterData> _lastData = [];
|
||||||
private StringU8 _paletteName = StringU8.Empty;
|
private StringU8 _paletteName = StringU8.Empty;
|
||||||
|
|
@ -125,7 +126,7 @@ public class CustomizeParameterDrawer(Configuration.Configuration config, Palett
|
||||||
DrawColorFormatOptions(withApply);
|
DrawColorFormatOptions(withApply);
|
||||||
var value = config.ShowColorConfig;
|
var value = config.ShowColorConfig;
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (Im.Checkbox("Show Config"u8, ref value))
|
if (Im.Checkbox("Show Configuration"u8, ref value))
|
||||||
{
|
{
|
||||||
config.ShowColorConfig = value;
|
config.ShowColorConfig = value;
|
||||||
config.Save();
|
config.Save();
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ using Luna;
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
public abstract class DesignComboBase(
|
public abstract class DesignComboBase(
|
||||||
Configuration.EphemeralConfig config,
|
Config.EphemeralConfig config,
|
||||||
DesignManager designs,
|
DesignManager designs,
|
||||||
DesignChanged designChanged,
|
DesignChanged designChanged,
|
||||||
DesignColors designColors,
|
DesignColors designColors,
|
||||||
|
|
@ -17,7 +17,7 @@ public abstract class DesignComboBase(
|
||||||
DesignFileSystem designFileSystem)
|
DesignFileSystem designFileSystem)
|
||||||
: FilterComboBase<DesignComboBase.CacheItem>(new DesignFilter(), ConfigData.Default with { ComputeWidth = true })
|
: FilterComboBase<DesignComboBase.CacheItem>(new DesignFilter(), ConfigData.Default with { ComputeWidth = true })
|
||||||
{
|
{
|
||||||
protected readonly Configuration.EphemeralConfig Config = config;
|
protected readonly Config.EphemeralConfig Config = config;
|
||||||
protected readonly DesignChanged DesignChanged = designChanged;
|
protected readonly DesignChanged DesignChanged = designChanged;
|
||||||
protected readonly DesignColors DesignColors = designColors;
|
protected readonly DesignColors DesignColors = designColors;
|
||||||
protected readonly DesignFileSystem DesignFileSystem = designFileSystem;
|
protected readonly DesignFileSystem DesignFileSystem = designFileSystem;
|
||||||
|
|
@ -28,7 +28,7 @@ public abstract class DesignComboBase(
|
||||||
protected CacheItem CreateItem(IDesignStandIn design)
|
protected CacheItem CreateItem(IDesignStandIn design)
|
||||||
{
|
{
|
||||||
var color = design is Design d1 ? DesignColors.GetColor(d1).ToVector() : ColorId.NormalDesign.Value().ToVector();
|
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);
|
var name = design.ResolveName(false);
|
||||||
if (path == name)
|
if (path == name)
|
||||||
path = string.Empty;
|
path = string.Empty;
|
||||||
|
|
@ -118,7 +118,10 @@ public abstract class DesignComboBase(
|
||||||
|
|
||||||
protected override void ComputeWidth()
|
protected override void ComputeWidth()
|
||||||
=> ComboWidth = UnfilteredItems.Max(d
|
=> 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)
|
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)
|
DesignFileSystem designFileSystem, DesignManager designs)
|
||||||
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
: 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 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)
|
DesignFileSystem designFileSystem, DesignManager designs)
|
||||||
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
: base(config, designs, designChanged, designColors, tabSelected, designFileSystem)
|
||||||
{
|
{
|
||||||
|
|
@ -295,7 +298,7 @@ public sealed class LinkDesignCombo : DesignComboBase, IUiService, IDisposable
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class RandomDesignCombo(
|
public sealed class RandomDesignCombo(
|
||||||
Configuration.EphemeralConfig config,
|
Config.EphemeralConfig config,
|
||||||
DesignManager designs,
|
DesignManager designs,
|
||||||
DesignChanged designChanged,
|
DesignChanged designChanged,
|
||||||
DesignColors designColors,
|
DesignColors designColors,
|
||||||
|
|
@ -308,12 +311,8 @@ public sealed class RandomDesignCombo(
|
||||||
return exact.Which switch
|
return exact.Which switch
|
||||||
{
|
{
|
||||||
RandomPredicate.Exact.Type.Name => Designs.Designs.FirstOrDefault(d => d.Name == exact.Value),
|
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
|
RandomPredicate.Exact.Type.Path => Designs.Designs.FirstOrDefault(d => d.Node!.FullPath == exact.Value.Text),
|
||||||
? l.Value
|
RandomPredicate.Exact.Type.Identifier => Designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g) ? g : Guid.Empty),
|
||||||
: null,
|
|
||||||
RandomPredicate.Exact.Type.Identifier => Designs.Designs.ByIdentifier(Guid.TryParse(exact.Value.Text, out var g)
|
|
||||||
? g
|
|
||||||
: Guid.Empty),
|
|
||||||
_ => null,
|
_ => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
@ -346,7 +345,7 @@ public sealed class SpecialDesignCombo : DesignComboBase, IUiService
|
||||||
private readonly CacheItem _revert;
|
private readonly CacheItem _revert;
|
||||||
private readonly CacheItem _quick;
|
private readonly CacheItem _quick;
|
||||||
|
|
||||||
public SpecialDesignCombo(Configuration.EphemeralConfig config,
|
public SpecialDesignCombo(Config.EphemeralConfig config,
|
||||||
DesignManager designs,
|
DesignManager designs,
|
||||||
DesignChanged designChanged,
|
DesignChanged designChanged,
|
||||||
DesignColors designColors,
|
DesignColors designColors,
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -33,7 +34,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
? WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing | WindowFlags.NoMove
|
? WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing | WindowFlags.NoMove
|
||||||
: WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing;
|
: WindowFlags.NoDecoration | WindowFlags.NoDocking | WindowFlags.NoFocusOnAppearing;
|
||||||
|
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly QuickDesignCombo _designCombo;
|
private readonly QuickDesignCombo _designCombo;
|
||||||
private readonly StateManager _stateManager;
|
private readonly StateManager _stateManager;
|
||||||
private readonly AutoDesignApplier _autoDesignApplier;
|
private readonly AutoDesignApplier _autoDesignApplier;
|
||||||
|
|
@ -45,7 +46,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
private int _numButtons;
|
private int _numButtons;
|
||||||
private readonly StringBuilder _tooltipBuilder = new(512);
|
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)
|
ActorObjectManager objects, AutoDesignApplier autoDesignApplier, PenumbraService penumbra)
|
||||||
: base("Glamourer Quick Bar", WindowFlags.NoDecoration | WindowFlags.NoDocking)
|
: base("Glamourer Quick Bar", WindowFlags.NoDecoration | WindowFlags.NoDocking)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Gui.Materials;
|
using Glamourer.Gui.Materials;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
|
@ -22,7 +23,7 @@ public class EquipmentDrawer
|
||||||
private readonly BonusItemCombo[] _bonusItemCombo;
|
private readonly BonusItemCombo[] _bonusItemCombo;
|
||||||
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
private readonly Dictionary<FullEquipType, WeaponCombo> _weaponCombo;
|
||||||
private readonly TextureService _textures;
|
private readonly TextureService _textures;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly GPoseService _gPose;
|
private readonly GPoseService _gPose;
|
||||||
private readonly AdvancedDyePopup _advancedDyes;
|
private readonly AdvancedDyePopup _advancedDyes;
|
||||||
private readonly ItemCopyService _itemCopy;
|
private readonly ItemCopyService _itemCopy;
|
||||||
|
|
@ -32,7 +33,7 @@ public class EquipmentDrawer
|
||||||
private EquipSlot _dragTarget;
|
private EquipSlot _dragTarget;
|
||||||
|
|
||||||
public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, TextureService textures,
|
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;
|
_items = items;
|
||||||
_textures = textures;
|
_textures = textures;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,18 @@
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
public class GenericPopupWindow : Luna.Window
|
public class GenericPopupWindow : Luna.Window
|
||||||
{
|
{
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ICondition _condition;
|
private readonly ICondition _condition;
|
||||||
private readonly IClientState _state;
|
private readonly IClientState _state;
|
||||||
public bool OpenFestivalPopup { get; internal set; }
|
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",
|
: base("Glamourer Popups",
|
||||||
WindowFlags.NoBringToFrontOnFocus
|
WindowFlags.NoBringToFrontOnFocus
|
||||||
| WindowFlags.NoDecoration
|
| WindowFlags.NoDecoration
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
|
|
@ -6,10 +7,10 @@ namespace Glamourer.Gui;
|
||||||
public class GlamourerChangelog
|
public class GlamourerChangelog
|
||||||
{
|
{
|
||||||
public const int LastChangelogVersion = 0;
|
public const int LastChangelogVersion = 0;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
public readonly Changelog Changelog;
|
public readonly Changelog Changelog;
|
||||||
|
|
||||||
public GlamourerChangelog(Configuration.Configuration config)
|
public GlamourerChangelog(Configuration config)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Changelog = new Changelog("Glamourer Changelog", ConfigData, Save);
|
Changelog = new Changelog("Glamourer Changelog", ConfigData, Save);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Windowing;
|
using Dalamud.Interface.Windowing;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Gui.Tabs.UnlocksTab;
|
using Glamourer.Gui.Tabs.UnlocksTab;
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
@ -11,7 +12,7 @@ public class GlamourerWindowSystem : IDisposable
|
||||||
private readonly MainWindow _ui;
|
private readonly MainWindow _ui;
|
||||||
|
|
||||||
public GlamourerWindowSystem(IUiBuilder uiBuilder, MainWindow ui, GenericPopupWindow popups,
|
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;
|
_uiBuilder = uiBuilder;
|
||||||
_ui = ui;
|
_ui = ui;
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,11 @@ namespace Glamourer.Gui;
|
||||||
|
|
||||||
public sealed class MainTabBar : TabBar<MainTabType>
|
public sealed class MainTabBar : TabBar<MainTabType>
|
||||||
{
|
{
|
||||||
private readonly Configuration.EphemeralConfig _config;
|
private readonly Config.EphemeralConfig _config;
|
||||||
public readonly TabSelected Event;
|
public readonly TabSelected Event;
|
||||||
public readonly SettingsTab Settings;
|
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)
|
AutomationTab automation, UnlocksTab unlocks, NpcTab npcs, MessagesTab messages, DebugTab debug, TabSelected @event)
|
||||||
: base("MainTabBar", log, settings, actors, designs, automation, unlocks, npcs, messages, debug)
|
: base("MainTabBar", log, settings, actors, designs, automation, unlocks, npcs, messages, debug)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -8,13 +9,13 @@ namespace Glamourer.Gui;
|
||||||
|
|
||||||
public sealed class MainWindow : Window, IDisposable
|
public sealed class MainWindow : Window, IDisposable
|
||||||
{
|
{
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly DesignQuickBar _quickBar;
|
private readonly DesignQuickBar _quickBar;
|
||||||
private readonly MainTabBar _mainTabBar;
|
private readonly MainTabBar _mainTabBar;
|
||||||
private bool _ignorePenumbra;
|
private bool _ignorePenumbra;
|
||||||
|
|
||||||
public MainWindow(IDalamudPluginInterface pi, Configuration.Configuration config, PenumbraService penumbra,
|
public MainWindow(IDalamudPluginInterface pi, Configuration config, PenumbraService penumbra,
|
||||||
MainTabBar mainTabBar, DesignQuickBar quickBar)
|
MainTabBar mainTabBar, DesignQuickBar quickBar)
|
||||||
: base("GlamourerMainWindow")
|
: base("GlamourerMainWindow")
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop.Material;
|
using Glamourer.Interop.Material;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -17,7 +17,7 @@ using Notification = Luna.Notification;
|
||||||
namespace Glamourer.Gui.Materials;
|
namespace Glamourer.Gui.Materials;
|
||||||
|
|
||||||
public sealed unsafe class AdvancedDyePopup(
|
public sealed unsafe class AdvancedDyePopup(
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
StateManager stateManager,
|
StateManager stateManager,
|
||||||
LiveColorTablePreviewer preview,
|
LiveColorTablePreviewer preview,
|
||||||
DirectXService directX) : IService
|
DirectXService directX) : IService
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Glamourer.Designs;
|
using Glamourer.Config;
|
||||||
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop.Material;
|
using Glamourer.Interop.Material;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -7,7 +8,7 @@ using Penumbra.GameData.Files.MaterialStructs;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Materials;
|
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 GlossWidth = 100;
|
||||||
public const float SpecularStrengthWidth = 125;
|
public const float SpecularStrengthWidth = 125;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Gui.Customization;
|
using Glamourer.Gui.Customization;
|
||||||
|
|
@ -25,7 +25,7 @@ public sealed class ActorPanel : IPanel
|
||||||
private readonly CustomizationDrawer _customizationDrawer;
|
private readonly CustomizationDrawer _customizationDrawer;
|
||||||
private readonly EquipmentDrawer _equipmentDrawer;
|
private readonly EquipmentDrawer _equipmentDrawer;
|
||||||
private readonly AutoDesignApplier _autoDesignApplier;
|
private readonly AutoDesignApplier _autoDesignApplier;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly DesignConverter _converter;
|
private readonly DesignConverter _converter;
|
||||||
private readonly ActorObjectManager _objects;
|
private readonly ActorObjectManager _objects;
|
||||||
private readonly ImportService _importService;
|
private readonly ImportService _importService;
|
||||||
|
|
@ -37,7 +37,7 @@ public sealed class ActorPanel : IPanel
|
||||||
CustomizationDrawer customizationDrawer,
|
CustomizationDrawer customizationDrawer,
|
||||||
EquipmentDrawer equipmentDrawer,
|
EquipmentDrawer equipmentDrawer,
|
||||||
AutoDesignApplier autoDesignApplier,
|
AutoDesignApplier autoDesignApplier,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
DesignConverter converter,
|
DesignConverter converter,
|
||||||
ActorObjectManager objects,
|
ActorObjectManager objects,
|
||||||
DesignManager designManager,
|
DesignManager designManager,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ public readonly struct ActorCacheItem(ActorIdentifier identifier, ActorData data
|
||||||
public readonly StringU8 IncognitoText = new(identifier.Incognito(data.Label));
|
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
|
public ReadOnlySpan<byte> Id
|
||||||
=> "ActorSelector"u8;
|
=> "ActorSelector"u8;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ namespace Glamourer.Gui.Tabs.ActorTab;
|
||||||
public sealed class ActorsHeader : SplitButtonHeader
|
public sealed class ActorsHeader : SplitButtonHeader
|
||||||
{
|
{
|
||||||
private readonly ActorSelection _selection;
|
private readonly ActorSelection _selection;
|
||||||
private readonly Configuration.EphemeralConfig _config;
|
private readonly Config.EphemeralConfig _config;
|
||||||
|
|
||||||
public ActorsHeader(SetFromClipboardButton setFromClipboard, ExportToClipboardButton exportToClipboard, SaveAsDesignButton save,
|
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;
|
_selection = selection;
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
|
@ -10,7 +11,7 @@ namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||||
|
|
||||||
public sealed class AutomationButtons : ButtonFooter
|
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 AddButton(objects, manager), 100);
|
||||||
Buttons.AddButton(new DuplicateButton(selection, manager), 90);
|
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>
|
: BaseIconButton<AwesomeIcon>
|
||||||
{
|
{
|
||||||
private bool _enabled;
|
private bool _enabled;
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,28 @@
|
||||||
using ImSharp;
|
using Glamourer.Config;
|
||||||
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||||
|
|
||||||
public sealed class AutomationHeader(Configuration.Configuration config, AutomationSelection selection) : IHeader
|
public sealed class AutomationHeader : SplitButtonHeader
|
||||||
{
|
{
|
||||||
public bool Collapsed
|
private readonly Configuration _config;
|
||||||
=> false;
|
private readonly AutomationSelection _selection;
|
||||||
|
|
||||||
public void Draw(Vector2 size)
|
public AutomationHeader(Configuration config, AutomationSelection selection, IncognitoButton incognito)
|
||||||
=> ImEx.TextFramed(config.Ephemeral.IncognitoMode ? selection.Incognito : selection.Name, size with { Y = Im.Style.FrameHeight });
|
{
|
||||||
|
_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;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||||
|
|
||||||
public class AutomationTab : TwoPanelLayout, ITab<MainTabType>
|
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,
|
public AutomationTab(AutomationFilter filter, SetSelector selector, SetPanel panel, AutomationButtons buttons, AutomationHeader header,
|
||||||
Configuration.Configuration config)
|
Configuration config)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
LeftHeader = new FilterHeader<AutomationCacheItem>(filter, new StringU8("Filter..."u8));
|
LeftHeader = new FilterHeader<AutomationCacheItem>(filter, new StringU8("Filter..."u8));
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.Special;
|
using Glamourer.Designs.Special;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
|
|
@ -14,7 +15,7 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
||||||
private int _designIndex = -1;
|
private int _designIndex = -1;
|
||||||
|
|
||||||
private readonly AutomationChanged _automationChanged;
|
private readonly AutomationChanged _automationChanged;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly AutoDesignManager _autoDesignManager;
|
private readonly AutoDesignManager _autoDesignManager;
|
||||||
private readonly RandomDesignCombo _randomDesignCombo;
|
private readonly RandomDesignCombo _randomDesignCombo;
|
||||||
private readonly AutomationSelection _selection;
|
private readonly AutomationSelection _selection;
|
||||||
|
|
@ -25,7 +26,7 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
||||||
private string? _newDefinition;
|
private string? _newDefinition;
|
||||||
private Design? _newDesign;
|
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)
|
RandomDesignCombo randomDesignCombo, AutomationSelection selection, DesignFileSystem designFileSystem, DesignStorage designs)
|
||||||
{
|
{
|
||||||
_automationChanged = automationChanged;
|
_automationChanged = automationChanged;
|
||||||
|
|
@ -268,19 +269,19 @@ public sealed class RandomRestrictionDrawer : IService, IDisposable
|
||||||
LookupTooltip(designs);
|
LookupTooltip(designs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LookupTooltip(IEnumerable<Design> designs)
|
private static void LookupTooltip(IEnumerable<Design> designs)
|
||||||
{
|
{
|
||||||
using var _ = Im.Tooltip.Begin();
|
using var _ = Im.Tooltip.Begin();
|
||||||
using var enumerator = designs.GetEnumerator();
|
using var enumerator = designs.GetEnumerator();
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
Im.Text("Matches the following designs:"u8);
|
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.Separator();
|
||||||
Im.BulletText(name);
|
Im.BulletText(name);
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
name = _designFileSystem.TryGetValue(enumerator.Current, out l) ? l.FullName() : enumerator.Current.Name.Text;
|
name = enumerator.Current.Path.CurrentPath;
|
||||||
Im.BulletText(name);
|
Im.BulletText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Glamourer.Designs.Special;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -19,7 +20,7 @@ public class SetPanel(
|
||||||
CustomizeUnlockManager customizeUnlocks,
|
CustomizeUnlockManager customizeUnlocks,
|
||||||
CustomizeService customizations,
|
CustomizeService customizations,
|
||||||
IdentifierDrawer identifierDrawer,
|
IdentifierDrawer identifierDrawer,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
RandomRestrictionDrawer randomDrawer,
|
RandomRestrictionDrawer randomDrawer,
|
||||||
AutomationSelection selection) : IPanel
|
AutomationSelection selection) : IPanel
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -8,7 +9,7 @@ namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||||
|
|
||||||
public sealed class SetSelector(
|
public sealed class SetSelector(
|
||||||
AutomationSelection selection,
|
AutomationSelection selection,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
AutoDesignManager manager,
|
AutoDesignManager manager,
|
||||||
AutomationFilter filter,
|
AutomationFilter filter,
|
||||||
ActorObjectManager objects,
|
ActorObjectManager objects,
|
||||||
|
|
@ -54,7 +55,8 @@ public sealed class SetSelector(
|
||||||
var identifier = config.Ephemeral.IncognitoMode ? item.IdentifierIncognito : item.IdentifierString;
|
var identifier = config.Ephemeral.IncognitoMode ? item.IdentifierIncognito : item.IdentifierString;
|
||||||
var textSize = identifier.CalculateSize();
|
var textSize = identifier.CalculateSize();
|
||||||
var textColor = item.Set.Identifiers.Any(objects.ContainsKey) ? cache.AutomationAvailable : cache.AutomationUnavailable;
|
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);
|
Im.Text(identifier, textColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
using ImSharp;
|
using Glamourer.Config;
|
||||||
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||||
|
|
||||||
public sealed class DebugTab(ServiceManager manager) : ITab<MainTabType>
|
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
|
public bool IsVisible
|
||||||
=> _config.DebugMode;
|
=> _config.DebugMode;
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,7 @@ public sealed class DesignConverterPanel(DesignConverter designConverter) : IGam
|
||||||
Im.Text("JSON Parsing Successful!"u8);
|
Im.Text("JSON Parsing Successful!"u8);
|
||||||
|
|
||||||
if (_tmpDesign is not null)
|
if (_tmpDesign is not null)
|
||||||
DesignManagerPanel.DrawDesign(_tmpDesign, null);
|
DesignManagerPanel.DrawDesign(_tmpDesign);
|
||||||
|
|
||||||
if (_clipboardProblem.Length > 0)
|
if (_clipboardProblem.Length > 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
||||||
if (!t)
|
if (!t)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
DrawDesign(design, designFileSystem);
|
DrawDesign(design);
|
||||||
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize,
|
var base64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.Application.Equip, design.Application.Customize,
|
||||||
design.Application.Meta,
|
design.Application.Meta,
|
||||||
design.WriteProtected());
|
design.WriteProtected());
|
||||||
|
|
@ -50,12 +50,12 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
||||||
var designs = designManager.Designs.Where(d => d.Tags.Contains("_DebugTest")).ToArray();
|
var designs = designManager.Designs.Where(d => d.Tags.Contains("_DebugTest")).ToArray();
|
||||||
foreach (var design in designs)
|
foreach (var design in designs)
|
||||||
designManager.Delete(design);
|
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);
|
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);
|
using var table = Im.Table.Begin("##equip"u8, 8, TableFlags.RowBackground | TableFlags.SizingFixedFit);
|
||||||
if (design is Design d)
|
if (design is Design d)
|
||||||
|
|
@ -70,8 +70,7 @@ public sealed class DesignManagerPanel(DesignManager designManager, DesignFileSy
|
||||||
table.DrawDataPair("Identifier"u8, d.Identifier);
|
table.DrawDataPair("Identifier"u8, d.Identifier);
|
||||||
table.NextRow();
|
table.NextRow();
|
||||||
table.DrawColumn("Design File System Path"u8);
|
table.DrawColumn("Design File System Path"u8);
|
||||||
if (fileSystem is not null)
|
table.DrawColumn(d.Path.CurrentPath);
|
||||||
table.DrawColumn(fileSystem.TryGetValue(d, out var leaf) ? leaf.FullName() : "No Path Known"u8);
|
|
||||||
table.NextRow();
|
table.NextRow();
|
||||||
|
|
||||||
table.DrawDataPair("Creation"u8, d.CreationDate);
|
table.DrawDataPair("Creation"u8, d.CreationDate);
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
using Glamourer.State;
|
using Glamourer.Config;
|
||||||
|
using Glamourer.State;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Penumbra.GameData.Gui.Debug;
|
using Penumbra.GameData.Gui.Debug;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
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
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Fun Module"u8;
|
=> "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 Dalamud.Interface.ImGuiNotification;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
@ -10,8 +10,7 @@ namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
public class DesignDetailTab
|
public class DesignDetailTab
|
||||||
{
|
{
|
||||||
private readonly SaveService _saveService;
|
private readonly SaveService _saveService;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly DesignFileSystemSelector _selector;
|
|
||||||
private readonly DesignFileSystem _fileSystem;
|
private readonly DesignFileSystem _fileSystem;
|
||||||
private readonly DesignManager _manager;
|
private readonly DesignManager _manager;
|
||||||
private readonly DesignColors _colors;
|
private readonly DesignColors _colors;
|
||||||
|
|
@ -19,11 +18,10 @@ public class DesignDetailTab
|
||||||
|
|
||||||
private bool _editDescriptionMode;
|
private bool _editDescriptionMode;
|
||||||
|
|
||||||
public DesignDetailTab(SaveService saveService, DesignFileSystemSelector selector, DesignManager manager, DesignFileSystem fileSystem,
|
public DesignDetailTab(SaveService saveService, DesignManager manager, DesignFileSystem fileSystem,
|
||||||
DesignColors colors, Configuration.Configuration config)
|
DesignColors colors, Configuration config)
|
||||||
{
|
{
|
||||||
_saveService = saveService;
|
_saveService = saveService;
|
||||||
_selector = selector;
|
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_fileSystem = fileSystem;
|
_fileSystem = fileSystem;
|
||||||
_colors = colors;
|
_colors = colors;
|
||||||
|
|
@ -42,6 +40,8 @@ public class DesignDetailTab
|
||||||
Im.Line.New();
|
Im.Line.New();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Design Selected
|
||||||
|
=> (Design) _fileSystem.Selection.Selection!.Value;
|
||||||
|
|
||||||
private void DrawDesignInfoTable()
|
private void DrawDesignInfoTable()
|
||||||
{
|
{
|
||||||
|
|
@ -57,13 +57,13 @@ public class DesignDetailTab
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
var width = Im.ContentRegion.Available with { Y = 0 };
|
var width = Im.ContentRegion.Available with { Y = 0 };
|
||||||
Im.Item.SetNextWidth(width.X);
|
Im.Item.SetNextWidth(width.X);
|
||||||
if (ImEx.InputOnDeactivation.Text("##Name"u8, _selector.Selected!.Name.Text, out string newName))
|
if (ImEx.InputOnDeactivation.Text("##Name"u8, Selected.Name.Text, out string newName))
|
||||||
_manager.Rename(_selector.Selected!, newName);
|
_manager.Rename(Selected, newName);
|
||||||
|
|
||||||
var identifier = _selector.Selected!.Identifier.ToString();
|
var identifier = Selected.Identifier.ToString();
|
||||||
table.DrawFrameColumn("Unique Identifier"u8);
|
table.DrawFrameColumn("Unique Identifier"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
|
var fileName = _saveService.FileNames.DesignFile(Selected);
|
||||||
using (Im.Font.PushMono())
|
using (Im.Font.PushMono())
|
||||||
{
|
{
|
||||||
if (Im.Button(identifier, width))
|
if (Im.Button(identifier, width))
|
||||||
|
|
@ -87,10 +87,10 @@ public class DesignDetailTab
|
||||||
table.DrawFrameColumn("Full Selector Path"u8);
|
table.DrawFrameColumn("Full Selector Path"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
Im.Item.SetNextWidth(width.X);
|
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
|
try
|
||||||
{
|
{
|
||||||
_fileSystem.RenameAndMove(_selector.SelectedLeaf, newPath);
|
_fileSystem.RenameAndMove(Selected.Node!, newPath);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
@ -99,56 +99,56 @@ public class DesignDetailTab
|
||||||
|
|
||||||
table.DrawFrameColumn("Quick Design Bar"u8);
|
table.DrawFrameColumn("Quick Design Bar"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (Im.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
|
if (Im.RadioButton("Display##qdb"u8, Selected.QuickDesign))
|
||||||
_manager.SetQuickDesign(_selector.Selected!, true);
|
_manager.SetQuickDesign(Selected, true);
|
||||||
var hovered = Im.Item.Hovered();
|
var hovered = Im.Item.Hovered();
|
||||||
Im.Line.SameInner();
|
Im.Line.SameInner();
|
||||||
if (Im.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
|
if (Im.RadioButton("Hide##qdb"u8, !Selected.QuickDesign))
|
||||||
_manager.SetQuickDesign(_selector.Selected!, false);
|
_manager.SetQuickDesign(Selected, false);
|
||||||
if (hovered || Im.Item.Hovered())
|
if (hovered || Im.Item.Hovered())
|
||||||
Im.Tooltip.Set("Display or hide this design in your quick design bar."u8);
|
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.DrawFrameColumn("Force Redrawing"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (Im.Checkbox("##ForceRedraw"u8, ref forceRedraw))
|
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);
|
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.DrawFrameColumn("Reset Advanced Dyes"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (Im.Checkbox("##ResetAdvancedDyes"u8, ref resetAdvancedDyes))
|
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);
|
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.DrawFrameColumn("Reset Temporary Settings"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (Im.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
|
if (Im.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
|
||||||
_manager.ChangeResetTemporarySettings(_selector.Selected!, resetTemporarySettings);
|
_manager.ChangeResetTemporarySettings(Selected, resetTemporarySettings);
|
||||||
Im.Tooltip.OnHover(
|
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);
|
"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.DrawFrameColumn("Color"u8);
|
||||||
table.NextColumn();
|
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
|
"Associate a color with this design.\n"u8
|
||||||
+ "Right-Click to revert to automatic coloring.\n"u8
|
+ "Right-Click to revert to automatic coloring.\n"u8
|
||||||
+ "Hold Control and scroll the mousewheel to scroll."u8,
|
+ "Hold Control and scroll the mousewheel to scroll."u8,
|
||||||
width.X - Im.Style.ItemSpacing.X - Im.Style.FrameHeight, out var newColorName))
|
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())
|
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();
|
Im.Line.Same();
|
||||||
if (DesignColorUi.DrawColorButton($"Color associated with {_selector.Selected!.Color}", currentColor, out var newColor))
|
if (DesignColorUi.DrawColorButton($"Color associated with {Selected.Color}", currentColor, out var newColor))
|
||||||
_colors.SetColor(_selector.Selected!.Color, newColor);
|
_colors.SetColor(Selected.Color, newColor);
|
||||||
}
|
}
|
||||||
else if (_selector.Selected!.Color.Length != 0)
|
else if (Selected.Color.Length is not 0)
|
||||||
{
|
{
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
ImEx.Icon.Draw(LunaStyle.WarningIcon, _colors.MissingColor);
|
ImEx.Icon.Draw(LunaStyle.WarningIcon, _colors.MissingColor);
|
||||||
|
|
@ -157,11 +157,11 @@ public class DesignDetailTab
|
||||||
|
|
||||||
table.DrawFrameColumn("Creation Date"u8);
|
table.DrawFrameColumn("Creation Date"u8);
|
||||||
table.NextColumn();
|
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.DrawFrameColumn("Last Update Date"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
ImEx.TextFramed($"{_selector.Selected!.LastEdit.LocalDateTime:F}", width, 0);
|
ImEx.TextFramed($"{Selected.LastEdit.LocalDateTime:F}", width, 0);
|
||||||
|
|
||||||
table.DrawFrameColumn("Tags"u8);
|
table.DrawFrameColumn("Tags"u8);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
|
|
@ -170,26 +170,26 @@ public class DesignDetailTab
|
||||||
|
|
||||||
private void DrawTags()
|
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)
|
if (idx < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (idx < _selector.Selected!.Tags.Length)
|
if (idx < Selected.Tags.Length)
|
||||||
{
|
{
|
||||||
if (editedTag.Length is 0)
|
if (editedTag.Length is 0)
|
||||||
_manager.RemoveTag(_selector.Selected!, idx);
|
_manager.RemoveTag(Selected, idx);
|
||||||
else
|
else
|
||||||
_manager.RenameTag(_selector.Selected!, idx, editedTag);
|
_manager.RenameTag(Selected, idx, editedTag);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_manager.AddTag(_selector.Selected!, editedTag);
|
_manager.AddTag(Selected, editedTag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawDescription()
|
private void DrawDescription()
|
||||||
{
|
{
|
||||||
var desc = _selector.Selected!.Description;
|
var desc = Selected.Description;
|
||||||
var size = Im.ContentRegion.Available with { Y = 12 * Im.Style.TextHeightWithSpacing };
|
var size = Im.ContentRegion.Available with { Y = 12 * Im.Style.TextHeightWithSpacing };
|
||||||
if (!_editDescriptionMode)
|
if (!_editDescriptionMode)
|
||||||
{
|
{
|
||||||
|
|
@ -205,7 +205,7 @@ public class DesignDetailTab
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (ImEx.InputOnDeactivation.MultiLine("##desc"u8, desc, out string newDescription, size))
|
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))
|
if (Im.Button("Stop Editing"u8))
|
||||||
_editDescriptionMode = false;
|
_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;
|
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)
|
||||||
{
|
{
|
||||||
|
_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(incognito, 50);
|
||||||
RightButtons.AddButton(new LockedButton(selection), 100);
|
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
|
public override bool IsVisible
|
||||||
=> selection.Design is not null;
|
=> fileSystem.Selection.Selection is not null;
|
||||||
|
|
||||||
public override AwesomeIcon Icon
|
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 Dalamud.Interface;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Designs.Links;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
@ -10,16 +10,19 @@ namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
||||||
public class DesignLinkDrawer(
|
public class DesignLinkDrawer(
|
||||||
DesignLinkManager linkManager,
|
DesignLinkManager linkManager,
|
||||||
DesignFileSystemSelector selector,
|
DesignFileSystem fileSystem,
|
||||||
LinkDesignCombo combo,
|
LinkDesignCombo combo,
|
||||||
DesignColors colorManager,
|
DesignColors colorManager,
|
||||||
Configuration.Configuration config) : IUiService
|
Configuration config) : IUiService
|
||||||
{
|
{
|
||||||
private int _dragDropIndex = -1;
|
private int _dragDropIndex = -1;
|
||||||
private LinkOrder _dragDropOrder = LinkOrder.None;
|
private LinkOrder _dragDropOrder = LinkOrder.None;
|
||||||
private int _dragDropTargetIndex = -1;
|
private int _dragDropTargetIndex = -1;
|
||||||
private LinkOrder _dragDropTargetOrder = LinkOrder.None;
|
private LinkOrder _dragDropTargetOrder = LinkOrder.None;
|
||||||
|
|
||||||
|
private Design Selected
|
||||||
|
=> (Design)fileSystem.Selection.Selection!.Value;
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
using var h = DesignPanelFlag.DesignLinks.Header(config);
|
using var h = DesignPanelFlag.DesignLinks.Header(config);
|
||||||
|
|
@ -45,23 +48,23 @@ public class DesignLinkDrawer(
|
||||||
switch (_dragDropTargetOrder)
|
switch (_dragDropTargetOrder)
|
||||||
{
|
{
|
||||||
case LinkOrder.Before:
|
case LinkOrder.Before:
|
||||||
for (var i = selector.Selected!.Links.Before.Count - 1; i >= _dragDropTargetIndex; --i)
|
for (var i = Selected.Links.Before.Count - 1; i >= _dragDropTargetIndex; --i)
|
||||||
linkManager.MoveDesignLink(selector.Selected!, i, LinkOrder.Before, 0, LinkOrder.After);
|
linkManager.MoveDesignLink(Selected, i, LinkOrder.Before, 0, LinkOrder.After);
|
||||||
break;
|
break;
|
||||||
case LinkOrder.After:
|
case LinkOrder.After:
|
||||||
for (var i = 0; i <= _dragDropTargetIndex; ++i)
|
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);
|
LinkOrder.Before);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else if (_dragDropTargetOrder is LinkOrder.Self)
|
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);
|
LinkOrder.Before);
|
||||||
else
|
else
|
||||||
linkManager.MoveDesignLink(selector.Selected!, _dragDropIndex, _dragDropOrder, _dragDropTargetIndex, _dragDropTargetOrder);
|
linkManager.MoveDesignLink(Selected, _dragDropIndex, _dragDropOrder, _dragDropTargetIndex, _dragDropTargetOrder);
|
||||||
|
|
||||||
_dragDropIndex = -1;
|
_dragDropIndex = -1;
|
||||||
_dragDropTargetIndex = -1;
|
_dragDropTargetIndex = -1;
|
||||||
|
|
@ -81,9 +84,9 @@ public class DesignLinkDrawer(
|
||||||
6 * Im.Style.FrameHeight + 5 * Im.Style.ItemInnerSpacing.X);
|
6 * Im.Style.FrameHeight + 5 * Im.Style.ItemInnerSpacing.X);
|
||||||
|
|
||||||
using var style = ImStyleDouble.ItemSpacing.Push(Im.Style.ItemInnerSpacing);
|
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);
|
DrawSelf(table);
|
||||||
DrawSubList(table, selector.Selected!.Links.After, LinkOrder.After);
|
DrawSubList(table, Selected.Links.After, LinkOrder.After);
|
||||||
DrawNew(table);
|
DrawNew(table);
|
||||||
MoveLink();
|
MoveLink();
|
||||||
}
|
}
|
||||||
|
|
@ -92,7 +95,7 @@ public class DesignLinkDrawer(
|
||||||
{
|
{
|
||||||
using var id = Im.Id.Push((int)LinkOrder.Self);
|
using var id = Im.Id.Push((int)LinkOrder.Self);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
var color = colorManager.GetColor(selector.Selected!);
|
var color = colorManager.GetColor(Selected);
|
||||||
using (AwesomeIcon.Font.Push())
|
using (AwesomeIcon.Font.Push())
|
||||||
{
|
{
|
||||||
using var c = ImGuiColor.Text.Push(color);
|
using var c = ImGuiColor.Text.Push(color);
|
||||||
|
|
@ -104,11 +107,11 @@ public class DesignLinkDrawer(
|
||||||
using (ImGuiColor.Text.Push(color))
|
using (ImGuiColor.Text.Push(color))
|
||||||
{
|
{
|
||||||
Im.Cursor.FrameAlign();
|
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);
|
Im.Tooltip.OnHover("Current Design"u8);
|
||||||
DrawDragDrop(selector.Selected!, LinkOrder.Self, 0);
|
DrawDragDrop(Selected, LinkOrder.Self, 0);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
using (AwesomeIcon.Font.Push())
|
using (AwesomeIcon.Font.Push())
|
||||||
{
|
{
|
||||||
|
|
@ -144,7 +147,7 @@ public class DesignLinkDrawer(
|
||||||
DrawApplicationBoxes(i, order, flags);
|
DrawApplicationBoxes(i, order, flags);
|
||||||
|
|
||||||
if (delete)
|
if (delete)
|
||||||
linkManager.RemoveDesignLink(selector.Selected!, i--, order);
|
linkManager.RemoveDesignLink(Selected, i--, order);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,11 +167,11 @@ public class DesignLinkDrawer(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
canAddBefore = LinkContainer.CanAddLink(selector.Selected!, design, LinkOrder.Before, out var error);
|
canAddBefore = LinkContainer.CanAddLink(Selected, design, LinkOrder.Before, out var error);
|
||||||
ttBefore = canAddBefore
|
ttBefore = canAddBefore
|
||||||
? $"Add a link at the top of the list to {design.Name}."
|
? $"Add a link at the top of the list to {design.Name}."
|
||||||
: $"Can not add a link to {design.Name}:\n{error}";
|
: $"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
|
ttAfter = canAddAfter
|
||||||
? $"Add a link at the bottom of the list to {design.Name}."
|
? $"Add a link at the bottom of the list to {design.Name}."
|
||||||
: $"Can not add a link to {design.Name}:\n{error}";
|
: $"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))
|
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleUp.Icon(), ttBefore, !canAddBefore))
|
||||||
{
|
{
|
||||||
linkManager.AddDesignLink(selector.Selected!, design!, LinkOrder.Before);
|
linkManager.AddDesignLink(Selected, design!, LinkOrder.Before);
|
||||||
linkManager.MoveDesignLink(selector.Selected!, selector.Selected!.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
linkManager.MoveDesignLink(Selected, Selected.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Icon.Button(FontAwesomeIcon.ArrowCircleDown.Icon(), ttAfter, !canAddAfter))
|
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)
|
private void DrawDragDrop(Design design, LinkOrder order, int index)
|
||||||
|
|
@ -228,7 +231,7 @@ public class DesignLinkDrawer(
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
Box(4);
|
Box(4);
|
||||||
if (newType != current)
|
if (newType != current)
|
||||||
linkManager.ChangeApplicationType(selector.Selected!, idx, order, newType);
|
linkManager.ChangeApplicationType(Selected, idx, order, newType);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
void Box(int i)
|
void Box(int i)
|
||||||
|
|
|
||||||
|
|
@ -1,51 +1,40 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface.ImGuiFileDialog;
|
||||||
using Dalamud.Interface.ImGuiFileDialog;
|
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||||
using Glamourer.Api.Enums;
|
using Glamourer.Api.Enums;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.History;
|
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Gui.Customization;
|
using Glamourer.Gui.Customization;
|
||||||
using Glamourer.Gui.Equipment;
|
using Glamourer.Gui.Equipment;
|
||||||
using Glamourer.Gui.Materials;
|
using Glamourer.Gui.Materials;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using Glamourer.Configuration;
|
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Raii;
|
|
||||||
using OtterGui.Text;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Interop;
|
using Penumbra.GameData.Interop;
|
||||||
using static Glamourer.Gui.Tabs.HeaderDrawer;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
||||||
public class DesignPanel : IPanel
|
public class DesignPanel : IPanel
|
||||||
{
|
{
|
||||||
private readonly FileDialogManager _fileDialog = new();
|
private readonly FileDialogManager _fileDialog = new();
|
||||||
private readonly DesignSelection _selection;
|
|
||||||
private readonly CustomizationDrawer _customizationDrawer;
|
private readonly CustomizationDrawer _customizationDrawer;
|
||||||
|
private readonly DesignFileSystem _fileSystem;
|
||||||
private readonly DesignManager _manager;
|
private readonly DesignManager _manager;
|
||||||
private readonly ActorObjectManager _objects;
|
private readonly ActorObjectManager _objects;
|
||||||
private readonly StateManager _state;
|
private readonly StateManager _state;
|
||||||
private readonly EquipmentDrawer _equipmentDrawer;
|
private readonly EquipmentDrawer _equipmentDrawer;
|
||||||
private readonly ModAssociationsTab _modAssociations;
|
private readonly ModAssociationsTab _modAssociations;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly DesignDetailTab _designDetails;
|
private readonly DesignDetailTab _designDetails;
|
||||||
private readonly ImportService _importService;
|
private readonly ImportService _importService;
|
||||||
private readonly DesignConverter _converter;
|
|
||||||
private readonly MultiDesignPanel _multiDesignPanel;
|
private readonly MultiDesignPanel _multiDesignPanel;
|
||||||
private readonly CustomizeParameterDrawer _parameterDrawer;
|
private readonly CustomizeParameterDrawer _parameterDrawer;
|
||||||
private readonly DesignLinkDrawer _designLinkDrawer;
|
private readonly DesignLinkDrawer _designLinkDrawer;
|
||||||
private readonly MaterialDrawer _materials;
|
private readonly MaterialDrawer _materials;
|
||||||
private readonly EditorHistory _history;
|
|
||||||
private readonly Button[] _leftButtons;
|
|
||||||
private readonly Button[] _rightButtons;
|
|
||||||
|
|
||||||
|
|
||||||
public DesignPanel(CustomizationDrawer customizationDrawer,
|
public DesignPanel(CustomizationDrawer customizationDrawer,
|
||||||
|
|
@ -54,7 +43,7 @@ public class DesignPanel : IPanel
|
||||||
StateManager state,
|
StateManager state,
|
||||||
EquipmentDrawer equipmentDrawer,
|
EquipmentDrawer equipmentDrawer,
|
||||||
ModAssociationsTab modAssociations,
|
ModAssociationsTab modAssociations,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
DesignDetailTab designDetails,
|
DesignDetailTab designDetails,
|
||||||
DesignConverter converter,
|
DesignConverter converter,
|
||||||
ImportService importService,
|
ImportService importService,
|
||||||
|
|
@ -62,7 +51,7 @@ public class DesignPanel : IPanel
|
||||||
CustomizeParameterDrawer parameterDrawer,
|
CustomizeParameterDrawer parameterDrawer,
|
||||||
DesignLinkDrawer designLinkDrawer,
|
DesignLinkDrawer designLinkDrawer,
|
||||||
MaterialDrawer materials,
|
MaterialDrawer materials,
|
||||||
EditorHistory history, DesignSelection selection)
|
DesignFileSystem fileSystem)
|
||||||
{
|
{
|
||||||
_customizationDrawer = customizationDrawer;
|
_customizationDrawer = customizationDrawer;
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
|
|
@ -73,33 +62,16 @@ public class DesignPanel : IPanel
|
||||||
_config = config;
|
_config = config;
|
||||||
_designDetails = designDetails;
|
_designDetails = designDetails;
|
||||||
_importService = importService;
|
_importService = importService;
|
||||||
_converter = converter;
|
|
||||||
_multiDesignPanel = multiDesignPanel;
|
_multiDesignPanel = multiDesignPanel;
|
||||||
_parameterDrawer = parameterDrawer;
|
_parameterDrawer = parameterDrawer;
|
||||||
_designLinkDrawer = designLinkDrawer;
|
_designLinkDrawer = designLinkDrawer;
|
||||||
_materials = materials;
|
_materials = materials;
|
||||||
_history = history;
|
_fileSystem = fileSystem;
|
||||||
_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),
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawHeader()
|
|
||||||
=> HeaderDrawer.Draw(SelectionName, 0, ImGuiColor.FrameBackground.Get().Color, _leftButtons, _rightButtons);
|
|
||||||
|
|
||||||
private string SelectionName
|
private Design Selection
|
||||||
=> _selection.Design == null ? "No Selection" : _config.Ephemeral.IncognitoMode ? _selection.Design.Incognito : _selection.Design.Name.Text;
|
=> (Design)_fileSystem.Selection.Selection!.Value;
|
||||||
|
|
||||||
private void DrawEquipment()
|
private void DrawEquipment()
|
||||||
{
|
{
|
||||||
|
|
@ -109,22 +81,22 @@ public class DesignPanel : IPanel
|
||||||
|
|
||||||
_equipmentDrawer.Prepare();
|
_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)
|
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||||
{
|
{
|
||||||
var data = EquipDrawData.FromDesign(_manager, _selection.Design!, slot);
|
var data = EquipDrawData.FromDesign(_manager, Selection, slot);
|
||||||
_equipmentDrawer.DrawEquip(data);
|
_equipmentDrawer.DrawEquip(data);
|
||||||
if (usedAllStain)
|
if (usedAllStain)
|
||||||
_manager.ChangeStains(_selection.Design, slot, newAllStain);
|
_manager.ChangeStains(Selection, slot, newAllStain);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mainhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.MainHand);
|
var mainhand = EquipDrawData.FromDesign(_manager, Selection, EquipSlot.MainHand);
|
||||||
var offhand = EquipDrawData.FromDesign(_manager, _selection.Design!, EquipSlot.OffHand);
|
var offhand = EquipDrawData.FromDesign(_manager, Selection, EquipSlot.OffHand);
|
||||||
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
|
_equipmentDrawer.DrawWeapons(mainhand, offhand, true);
|
||||||
|
|
||||||
foreach (var slot in BonusExtensions.AllFlags)
|
foreach (var slot in BonusExtensions.AllFlags)
|
||||||
{
|
{
|
||||||
var data = BonusDrawData.FromDesign(_manager, _selection.Design!, slot);
|
var data = BonusDrawData.FromDesign(_manager, Selection, slot);
|
||||||
_equipmentDrawer.DrawBonusItem(data);
|
_equipmentDrawer.DrawBonusItem(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -136,30 +108,30 @@ public class DesignPanel : IPanel
|
||||||
|
|
||||||
private void DrawEquipmentMetaToggles()
|
private void DrawEquipmentMetaToggles()
|
||||||
{
|
{
|
||||||
using (var _ = ImRaii.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.HatState, _manager, Selection));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, Selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
using (var _ = ImRaii.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.VisorState, _manager, Selection));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, Selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
using (var _ = ImRaii.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(MetaIndex.WeaponState, _manager, Selection));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, _selection.Design!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, Selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
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;
|
return;
|
||||||
|
|
||||||
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
var expand = _config.AutoExpandDesignPanel.HasFlag(DesignPanelFlag.Customization);
|
||||||
using var h = Im.Tree.HeaderId(_selection.Design!.DesignData.ModelId is 0
|
using var h = Im.Tree.HeaderId(Selection.DesignData.ModelId is 0
|
||||||
? "Customization"
|
? "Customization"u8
|
||||||
: $"Customization (Model Id #{_selection.Design!.DesignData.ModelId})###Customization",
|
: $"Customization (Model Id #{Selection.DesignData.ModelId})###Customization",
|
||||||
expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
|
expand ? TreeNodeFlags.DefaultOpen : TreeNodeFlags.None);
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_customizationDrawer.Draw(_selection.Design!.DesignData.Customize, _selection.Design.Application.Customize,
|
if (_customizationDrawer.Draw(Selection.DesignData.Customize, Selection.Application.Customize,
|
||||||
_selection.Design!.WriteProtected(), false))
|
Selection.WriteProtected(), false))
|
||||||
foreach (var idx in CustomizeIndex.Values)
|
foreach (var idx in CustomizeIndex.Values)
|
||||||
{
|
{
|
||||||
var flag = idx.ToFlag();
|
var flag = idx.ToFlag();
|
||||||
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
|
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
|
||||||
_manager.ChangeApplyCustomize(_selection.Design, idx, newValue);
|
_manager.ChangeApplyCustomize(Selection, idx, newValue);
|
||||||
if (_customizationDrawer.Changed.HasFlag(flag))
|
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));
|
Im.Dummy(new Vector2(Im.Style.TextHeight / 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -197,7 +169,7 @@ public class DesignPanel : IPanel
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_parameterDrawer.Draw(_manager, _selection.Design!);
|
_parameterDrawer.Draw(_manager, Selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawMaterialValues()
|
private void DrawMaterialValues()
|
||||||
|
|
@ -206,52 +178,52 @@ public class DesignPanel : IPanel
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_materials.Draw(_selection.Design!);
|
_materials.Draw(Selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCustomizeApplication()
|
private void DrawCustomizeApplication()
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.PushId("Customizations"u8);
|
using var id = Im.Id.Push("Customizations"u8);
|
||||||
var set = _selection.Design!.CustomizeSet;
|
var set = Selection.CustomizeSet;
|
||||||
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
|
var available = set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.BodyType;
|
||||||
var flags = _selection.Design!.ApplyCustomizeExcludingBodyType == 0 ? 0 :
|
var flags = Selection.ApplyCustomizeExcludingBodyType is 0 ? 0ul :
|
||||||
(_selection.Design!.ApplyCustomize & available) == available ? 3 : 1;
|
(Selection.ApplyCustomize & available) == available ? 3ul : 1ul;
|
||||||
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
|
if (Im.Checkbox("Apply All Customizations"u8, ref flags, 3ul))
|
||||||
{
|
{
|
||||||
var newFlags = flags == 3;
|
var newFlags = flags is 3;
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, newFlags);
|
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Clan, newFlags);
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, newFlags);
|
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Gender, newFlags);
|
||||||
foreach (var index in CustomizationExtensions.AllBasic)
|
foreach (var index in CustomizationExtensions.AllBasic)
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, index, newFlags);
|
_manager.ChangeApplyCustomize(Selection, index, newFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
var applyClan = _selection.Design!.DoApplyCustomize(CustomizeIndex.Clan);
|
var applyClan = Selection.DoApplyCustomize(CustomizeIndex.Clan);
|
||||||
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Clan.ToNameU8()}", ref applyClan))
|
if (Im.Checkbox($"Apply {CustomizeIndex.Clan.ToNameU8()}", ref applyClan))
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Clan, applyClan);
|
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Clan, applyClan);
|
||||||
|
|
||||||
var applyGender = _selection.Design!.DoApplyCustomize(CustomizeIndex.Gender);
|
var applyGender = Selection.DoApplyCustomize(CustomizeIndex.Gender);
|
||||||
if (ImUtf8.Checkbox($"Apply {CustomizeIndex.Gender.ToNameU8()}", ref applyGender))
|
if (Im.Checkbox($"Apply {CustomizeIndex.Gender.ToNameU8()}", ref applyGender))
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, CustomizeIndex.Gender, applyGender);
|
_manager.ChangeApplyCustomize(Selection, CustomizeIndex.Gender, applyGender);
|
||||||
|
|
||||||
|
|
||||||
foreach (var index in CustomizationExtensions.All.Where(set.IsAvailable))
|
foreach (var index in CustomizationExtensions.All.Where(set.IsAvailable))
|
||||||
{
|
{
|
||||||
var apply = _selection.Design!.DoApplyCustomize(index);
|
var apply = Selection.DoApplyCustomize(index);
|
||||||
if (ImUtf8.Checkbox($"Apply {set.Option(index)}", ref apply))
|
if (Im.Checkbox($"Apply {set.Option(index)}", ref apply))
|
||||||
_manager.ChangeApplyCustomize(_selection.Design!, index, apply);
|
_manager.ChangeApplyCustomize(Selection, index, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCrestApplication()
|
private void DrawCrestApplication()
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.PushId("Crests"u8);
|
using var id = Im.Id.Push("Crests"u8);
|
||||||
var flags = (uint)_selection.Design!.Application.Crest;
|
var flags = (ulong)Selection.Application.Crest;
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
var bigChange = Im.Checkbox("Apply All Crests"u8, ref flags, (ulong)CrestExtensions.AllRelevant);
|
||||||
foreach (var flag in CrestExtensions.AllRelevantSet)
|
foreach (var flag in CrestExtensions.AllRelevantSet)
|
||||||
{
|
{
|
||||||
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selection.Design!.DoApplyCrest(flag);
|
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : Selection.DoApplyCrest(flag);
|
||||||
if (ImUtf8.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
if (Im.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyCrest(_selection.Design!, flag, apply);
|
_manager.ChangeApplyCrest(Selection, flag, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -261,63 +233,59 @@ public class DesignPanel : IPanel
|
||||||
if (!h)
|
if (!h)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var disabled = Im.Disabled(_selection.Design!.WriteProtected());
|
using var disabled = Im.Disabled(Selection.WriteProtected());
|
||||||
|
|
||||||
DrawAllButtons();
|
DrawAllButtons();
|
||||||
|
|
||||||
using (var _ = ImUtf8.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
DrawCustomizeApplication();
|
DrawCustomizeApplication();
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
DrawCrestApplication();
|
DrawCrestApplication();
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
DrawMetaApplication();
|
DrawMetaApplication();
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine(210 * Im.Style.GlobalScale + Im.Style.ItemSpacing.X);
|
Im.Line.Same(210 * Im.Style.GlobalScale + Im.Style.ItemSpacing.X);
|
||||||
using (var _ = ImRaii.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
|
void ApplyEquip(string label, EquipFlag allFlags, bool stain, IEnumerable<EquipSlot> slots)
|
||||||
{
|
{
|
||||||
var flags = (uint)(allFlags & _selection.Design!.Application.Equip);
|
var flags = (ulong)(allFlags & Selection.Application.Equip);
|
||||||
using var id = ImUtf8.PushId(label);
|
using var id = Im.Id.Push(label);
|
||||||
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)allFlags);
|
var bigChange = Im.Checkbox($"Apply All {label}", ref flags, (ulong)allFlags);
|
||||||
if (stain)
|
if (stain)
|
||||||
foreach (var slot in slots)
|
foreach (var slot in slots)
|
||||||
{
|
{
|
||||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : _selection.Design!.DoApplyStain(slot);
|
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : Selection.DoApplyStain(slot);
|
||||||
if (ImUtf8.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
|
if (Im.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyStains(_selection.Design!, slot, apply);
|
_manager.ChangeApplyStains(Selection, slot, apply);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
foreach (var slot in slots)
|
foreach (var slot in slots)
|
||||||
{
|
{
|
||||||
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : _selection.Design!.DoApplyEquip(slot);
|
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : Selection.DoApplyEquip(slot);
|
||||||
if (ImUtf8.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
|
if (Im.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyItem(_selection.Design!, slot, apply);
|
_manager.ChangeApplyItem(Selection, slot, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyEquip("Weapons", ApplicationTypeExtensions.WeaponFlags, false, new[]
|
ApplyEquip("Weapons", ApplicationTypeExtensions.WeaponFlags, false, [EquipSlot.MainHand, EquipSlot.OffHand]);
|
||||||
{
|
|
||||||
EquipSlot.MainHand,
|
|
||||||
EquipSlot.OffHand,
|
|
||||||
});
|
|
||||||
|
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
ApplyEquip("Armor", ApplicationTypeExtensions.ArmorFlags, false, EquipSlotExtensions.EquipmentSlots);
|
ApplyEquip("Armor", ApplicationTypeExtensions.ArmorFlags, false, EquipSlotExtensions.EquipmentSlots);
|
||||||
|
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
ApplyEquip("Accessories", ApplicationTypeExtensions.AccessoryFlags, false, EquipSlotExtensions.AccessorySlots);
|
ApplyEquip("Accessories", ApplicationTypeExtensions.AccessoryFlags, false, EquipSlotExtensions.AccessorySlots);
|
||||||
|
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
ApplyEquip("Dyes", ApplicationTypeExtensions.StainFlags, true,
|
ApplyEquip("Dyes", ApplicationTypeExtensions.StainFlags, true,
|
||||||
EquipSlotExtensions.FullSlots);
|
EquipSlotExtensions.FullSlots);
|
||||||
|
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
DrawParameterApplication();
|
DrawParameterApplication();
|
||||||
|
|
||||||
ImUtf8.IconDummy();
|
Im.FrameDummy();
|
||||||
DrawBonusSlotApplication();
|
DrawBonusSlotApplication();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -327,9 +295,9 @@ public class DesignPanel : IPanel
|
||||||
var enabled = _config.DeleteDesignModifier.IsActive();
|
var enabled = _config.DeleteDesignModifier.IsActive();
|
||||||
bool? equip = null;
|
bool? equip = null;
|
||||||
bool? customize = null;
|
bool? customize = null;
|
||||||
var size = new Vector2(210 * Im.Style.GlobalScale, 0);
|
var size = ImEx.ScaledVectorX(210);
|
||||||
if (ImUtf8.ButtonEx("Disable Everything"u8,
|
if (ImEx.Button("Disable Everything"u8, size,
|
||||||
"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8, size,
|
"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8,
|
||||||
!enabled))
|
!enabled))
|
||||||
{
|
{
|
||||||
equip = false;
|
equip = false;
|
||||||
|
|
@ -337,11 +305,11 @@ public class DesignPanel : IPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImUtf8.ButtonEx("Enable Everything"u8,
|
if (ImEx.Button("Enable Everything"u8, size,
|
||||||
"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8, size,
|
"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness."u8,
|
||||||
!enabled))
|
!enabled))
|
||||||
{
|
{
|
||||||
equip = true;
|
equip = true;
|
||||||
|
|
@ -349,10 +317,10 @@ public class DesignPanel : IPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled)
|
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,
|
if (ImEx.Button("Equipment Only"u8, size,
|
||||||
"Enable application of anything related to gear, disable anything that is not related to gear."u8, size,
|
"Enable application of anything related to gear, disable anything that is not related to gear."u8,
|
||||||
!enabled))
|
!enabled))
|
||||||
{
|
{
|
||||||
equip = true;
|
equip = true;
|
||||||
|
|
@ -360,11 +328,11 @@ public class DesignPanel : IPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImUtf8.ButtonEx("Customization Only"u8,
|
if (ImEx.Button("Customization Only"u8, size,
|
||||||
"Enable application of anything related to customization, disable anything that is not related to customization."u8, size,
|
"Enable application of anything related to customization, disable anything that is not related to customization."u8,
|
||||||
!enabled))
|
!enabled))
|
||||||
{
|
{
|
||||||
equip = false;
|
equip = false;
|
||||||
|
|
@ -372,85 +340,82 @@ public class DesignPanel : IPanel
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled)
|
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,
|
"Set the application rules to the default values as if the design was newly created, without any advanced features or wetness."u8,
|
||||||
size,
|
|
||||||
!enabled))
|
!enabled))
|
||||||
{
|
{
|
||||||
_manager.ChangeApplyMulti(_selection.Design!, true, true, true, false, true, true, false, true);
|
_manager.ChangeApplyMulti(Selection, true, true, true, false, true, true, false, true);
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.Wetness, false);
|
_manager.ChangeApplyMeta(Selection, MetaIndex.Wetness, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
ImUtf8.HoverTooltip(ImGuiHoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {_config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImUtf8.ButtonEx("Disable Advanced"u8, "Disable all advanced dyes and customizations but keep everything else as is."u8,
|
if (ImEx.Button("Disable Advanced"u8, size, "Disable all advanced dyes and customizations but keep everything else as is."u8, !enabled))
|
||||||
size,
|
_manager.ChangeApplyMulti(Selection, null, null, null, false, null, null, false, null);
|
||||||
!enabled))
|
|
||||||
_manager.ChangeApplyMulti(_selection.Design!, null, null, null, false, null, null, false, null);
|
|
||||||
|
|
||||||
if (!enabled)
|
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)
|
if (equip is null && customize is null)
|
||||||
return;
|
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);
|
equip, equip, equip);
|
||||||
if (equip.HasValue)
|
if (equip.HasValue)
|
||||||
{
|
{
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.HatState, equip.Value);
|
_manager.ChangeApplyMeta(Selection, MetaIndex.HatState, equip.Value);
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.VisorState, equip.Value);
|
_manager.ChangeApplyMeta(Selection, MetaIndex.VisorState, equip.Value);
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.WeaponState, equip.Value);
|
_manager.ChangeApplyMeta(Selection, MetaIndex.WeaponState, equip.Value);
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, MetaIndex.EarState, equip.Value);
|
_manager.ChangeApplyMeta(Selection, MetaIndex.EarState, equip.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (customize.HasValue)
|
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",
|
new("Apply Wetness"u8),
|
||||||
"Apply Hat Visibility",
|
new("Apply Hat Visibility"u8),
|
||||||
"Apply Visor State",
|
new("Apply Visor State"u8),
|
||||||
"Apply Weapon Visibility",
|
new("Apply Weapon Visibility"u8),
|
||||||
"Apply Viera Ear Visibility",
|
new("Apply Viera Ear Visibility"u8),
|
||||||
];
|
];
|
||||||
|
|
||||||
private void DrawMetaApplication()
|
private void DrawMetaApplication()
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.PushId("Meta");
|
using var id = Im.Id.Push("Meta"u8);
|
||||||
const uint all = (uint)MetaExtensions.All;
|
const ulong all = (ulong)MetaExtensions.All;
|
||||||
var flags = (uint)_selection.Design!.Application.Meta;
|
var flags = (ulong)Selection.Application.Meta;
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
|
var bigChange = Im.Checkbox("Apply All Meta Changes"u8, ref flags, all);
|
||||||
|
|
||||||
foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(MetaLabels))
|
foreach (var (index, label) in MetaExtensions.AllRelevant.Zip(MetaLabels))
|
||||||
{
|
{
|
||||||
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : _selection.Design!.DoApplyMeta(index);
|
var apply = bigChange ? ((MetaFlag)flags).HasFlag(index.ToFlag()) : Selection.DoApplyMeta(index);
|
||||||
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
|
if (Im.Checkbox(label, ref apply) || bigChange)
|
||||||
_manager.ChangeApplyMeta(_selection.Design!, index, apply);
|
_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()
|
private void DrawBonusSlotApplication()
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.PushId("Bonus"u8);
|
using var id = Im.Id.Push("Bonus"u8);
|
||||||
var flags = _selection.Design!.Application.BonusItem;
|
var flags = Selection.Application.BonusItem;
|
||||||
var bigChange = BonusExtensions.AllFlags.Count > 1 && ImUtf8.Checkbox("Apply All Bonus Slots"u8, ref flags, BonusExtensions.All);
|
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))
|
foreach (var (index, label) in BonusExtensions.AllFlags.Zip(BonusSlotLabels))
|
||||||
{
|
{
|
||||||
var apply = bigChange ? flags.HasFlag(index) : _selection.Design!.DoApplyBonusItem(index);
|
var apply = bigChange ? flags.HasFlag(index) : Selection.DoApplyBonusItem(index);
|
||||||
if (ImUtf8.Checkbox(label, ref apply) || bigChange)
|
if (Im.Checkbox(label, ref apply) || bigChange)
|
||||||
_manager.ChangeApplyBonusItem(_selection.Design!, index, apply);
|
_manager.ChangeApplyBonusItem(Selection, index, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -458,69 +423,62 @@ public class DesignPanel : IPanel
|
||||||
private void DrawParameterApplication()
|
private void DrawParameterApplication()
|
||||||
{
|
{
|
||||||
using var id = Im.Id.Push("Parameter"u8);
|
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);
|
var bigChange = Im.Checkbox("Apply All Customize Parameters"u8, ref flags, (ulong)CustomizeParameterExtensions.All);
|
||||||
foreach (var flag in CustomizeParameterExtensions.AllFlags)
|
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)
|
if (Im.Checkbox($"Apply {flag.ToNameU8()}", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyParameter(_selection.Design!, flag, apply);
|
_manager.ChangeApplyParameter(Selection, flag, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Id
|
public ReadOnlySpan<byte> Id
|
||||||
=> "Designs"u8;
|
=> "DesignPanel"u8;
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
using var group = ImUtf8.Group();
|
_importService.CreateDatSource();
|
||||||
//if (_selection.DesignPaths.Count > 1)
|
if (_fileSystem.Selection.OrderedNodes.Count > 1)
|
||||||
if (false)
|
|
||||||
{
|
{
|
||||||
_multiDesignPanel.Draw();
|
_multiDesignPanel.Draw();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
DrawHeader();
|
|
||||||
DrawPanel();
|
DrawPanel();
|
||||||
|
|
||||||
if (_selection.Design == null || _selection.Design.WriteProtected())
|
if (_fileSystem.Selection.Selection is null || Selection.WriteProtected())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_importService.CreateDatTarget(out var dat))
|
if (_importService.CreateDatTarget(out var dat))
|
||||||
{
|
{
|
||||||
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
|
_manager.ChangeCustomize(Selection, CustomizeIndex.Clan, dat.Customize[CustomizeIndex.Clan]);
|
||||||
_manager.ChangeCustomize(_selection.Design!, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
|
_manager.ChangeCustomize(Selection, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]);
|
||||||
foreach (var idx in CustomizationExtensions.AllBasic)
|
foreach (var idx in CustomizationExtensions.AllBasic)
|
||||||
_manager.ChangeCustomize(_selection.Design!, idx, dat.Customize[idx]);
|
_manager.ChangeCustomize(Selection, idx, dat.Customize[idx]);
|
||||||
Glamourer.Messager.NotificationMessage(
|
Glamourer.Messager.NotificationMessage(
|
||||||
$"Applied games .dat file {dat.Description} customizations to {_selection.Design.Name}.", NotificationType.Success, false);
|
$"Applied games .dat file {dat.Description} customizations to {Selection.Name}.", NotificationType.Success, false);
|
||||||
}
|
}
|
||||||
else if (_importService.CreateCharaTarget(out var designBase, out var name))
|
else if (_importService.CreateCharaTarget(out var designBase, out var name))
|
||||||
{
|
{
|
||||||
_manager.ApplyDesign(_selection.Design!, designBase);
|
_manager.ApplyDesign(Selection, designBase);
|
||||||
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selection.Design.Name}.",
|
Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {Selection.Name}.",
|
||||||
NotificationType.Success, false);
|
NotificationType.Success, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_importService.CreateDatSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawPanel()
|
private void DrawPanel()
|
||||||
{
|
{
|
||||||
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.BordersOuter | TableFlags.ScrollY, Im.ContentRegion.Available);
|
using var table = Im.Table.Begin("##Panel"u8, 1, TableFlags.ScrollY, Im.ContentRegion.Available);
|
||||||
if (!table || _selection.Design is null)
|
if (!table || _fileSystem.Selection.Selection is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui.TableSetupScrollFreeze(0, 1);
|
table.SetupScrollFreeze(0, 1);
|
||||||
ImGui.TableNextColumn();
|
table.NextColumn();
|
||||||
if (_selection.Design is null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Im.Dummy(Vector2.Zero);
|
Im.Dummy(Vector2.Zero);
|
||||||
DrawButtonRow();
|
DrawButtonRow();
|
||||||
ImGui.TableNextColumn();
|
table.NextColumn();
|
||||||
|
|
||||||
DrawCustomize();
|
DrawCustomize();
|
||||||
DrawEquipment();
|
DrawEquipment();
|
||||||
|
|
@ -547,15 +505,15 @@ public class DesignPanel : IPanel
|
||||||
private void DrawApplyToSelf()
|
private void DrawApplyToSelf()
|
||||||
{
|
{
|
||||||
var (id, data) = _objects.PlayerData;
|
var (id, data) = _objects.PlayerData;
|
||||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero,
|
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.",
|
"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))
|
!data.Valid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
using var _ = Selection.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||||
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
|
_state.ApplyDesign(state, Selection, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -564,33 +522,33 @@ public class DesignPanel : IPanel
|
||||||
var (id, data) = _objects.TargetData;
|
var (id, data) = _objects.TargetData;
|
||||||
var tt = id.IsValid
|
var tt = id.IsValid
|
||||||
? data.Valid
|
? 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."
|
? "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."
|
: "The current target can not be manipulated."u8
|
||||||
: "No valid target selected.";
|
: "No valid target selected."u8;
|
||||||
if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid))
|
if (!ImEx.Button("Apply to Target"u8, Vector2.Zero, tt, !data.Valid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
using var _ = _selection.Design!.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
using var _ = Selection.TemporarilyRestrictApplication(ApplicationCollection.FromKeys());
|
||||||
_state.ApplyDesign(state, _selection.Design!, ApplySettings.ManualWithLinks with { IsFinal = true });
|
_state.ApplyDesign(state, Selection, ApplySettings.ManualWithLinks with { IsFinal = true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawSaveToDat()
|
private void DrawSaveToDat()
|
||||||
{
|
{
|
||||||
var verified = _importService.Verify(_selection.Design!.DesignData.Customize, out _);
|
var verified = _importService.Verify(Selection.DesignData.Customize, out _);
|
||||||
var tt = verified
|
var tt = verified
|
||||||
? "Export the currently configured customizations of this design to a character creation data file."
|
? "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.";
|
: "The current design contains customizations that can not be applied during character creation."u8;
|
||||||
var startPath = GetUserPath();
|
var startPath = GetUserPath();
|
||||||
if (startPath.Length == 0)
|
if (startPath.Length is 0)
|
||||||
startPath = null;
|
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) =>
|
_fileDialog.SaveFileDialog("Save File...", ".dat", "FFXIV_CHARA_01.dat", ".dat", (v, path) =>
|
||||||
{
|
{
|
||||||
if (v && _selection.Design != null)
|
if (v && _fileSystem.Selection.Selection?.GetValue<Design>() is not null)
|
||||||
_importService.SaveDesignAsDat(path, _selection.Design!.DesignData.Customize, _selection.Design!.Name);
|
_importService.SaveDesignAsDat(path, Selection.DesignData.Customize, Selection.Name);
|
||||||
}, startPath);
|
}, startPath);
|
||||||
|
|
||||||
_fileDialog.Draw();
|
_fileDialog.Draw();
|
||||||
|
|
@ -598,165 +556,4 @@ public class DesignPanel : IPanel
|
||||||
|
|
||||||
private static unsafe string GetUserPath()
|
private static unsafe string GetUserPath()
|
||||||
=> Framework.Instance()->UserPathString;
|
=> 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 Dalamud.Interface.ImGuiNotification;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
@ -7,36 +7,55 @@ using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
||||||
public sealed class DesignTab(DesignFileSystemSelector selector, DesignPanel panel, ImportService importService, DesignManager manager)
|
public sealed class DesignTab : TwoPanelLayout, ITab<MainTabType>
|
||||||
: 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;
|
=> "Designs"u8;
|
||||||
|
|
||||||
public MainTabType Identifier
|
public MainTabType Identifier
|
||||||
=> MainTabType.Designs;
|
=> MainTabType.Designs;
|
||||||
|
|
||||||
public void DrawContent()
|
protected override void DrawLeftGroup(in TwoPanelWidth width)
|
||||||
{
|
{
|
||||||
selector.Draw();
|
base.DrawLeftGroup(in width);
|
||||||
if (importService.CreateCharaTarget(out var designBase, out var name))
|
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}",
|
Glamourer.Messager.NotificationMessage($"Imported Anamnesis .chara file {name} as new design {newDesign.Name}",
|
||||||
NotificationType.Success, false);
|
NotificationType.Success, false);
|
||||||
}
|
}
|
||||||
|
_importService.CreateCharaSource();
|
||||||
Im.Line.Same();
|
|
||||||
panel.Draw();
|
|
||||||
importService.CreateCharaSource();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//protected override void SetWidth(float width, ScalingMode mode)
|
protected override float MinimumWidth
|
||||||
// => _uiConfig.ActorsTabScale = new TwoPanelWidth(width, mode);
|
=> LeftFooter.MinimumWidth;
|
||||||
//
|
|
||||||
//protected override float MinimumWidth
|
protected override float MaximumWidth
|
||||||
// => LeftFooter.MinimumWidth;
|
=> Im.Window.Width - 500 * Im.Style.GlobalScale;
|
||||||
//
|
|
||||||
//protected override float MaximumWidth
|
protected override void SetWidth(float width, ScalingMode mode)
|
||||||
// => Im.Window.Width - 500 * Im.Style.GlobalScale;
|
=> _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 Dalamud.Interface.ImGuiNotification;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -8,11 +8,14 @@ using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
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 (Mod, ModSettings)[]? _copy;
|
||||||
|
|
||||||
|
private Design Selection
|
||||||
|
=> (Design)fileSystem.Selection.Selection!.Value;
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
using var h = DesignPanelFlag.ModAssociations.Header(config);
|
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);
|
var size = new Vector2((Im.ContentRegion.Available.X - 2 * Im.Style.ItemSpacing.X) / 3, 0);
|
||||||
if (Im.Button("Copy All to Clipboard"u8, size))
|
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();
|
Im.Line.Same();
|
||||||
|
|
||||||
|
|
@ -45,7 +48,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
||||||
? $"Add {_copy.Length} mod association(s) from clipboard."
|
? $"Add {_copy.Length} mod association(s) from clipboard."
|
||||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||||
foreach (var (mod, setting) in _copy!)
|
foreach (var (mod, setting) in _copy!)
|
||||||
manager.UpdateMod(selection.Design!, mod, setting);
|
manager.UpdateMod(Selection, mod, setting);
|
||||||
|
|
||||||
Im.Line.Same();
|
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."
|
? $"Set {_copy.Length} mod association(s) from clipboard and discard existing."
|
||||||
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
: "Copy some mod associations to the clipboard, first."u8, _copy is null))
|
||||||
{
|
{
|
||||||
while (selection.Design!.AssociatedMods.Count > 0)
|
while (Selection.AssociatedMods.Count > 0)
|
||||||
manager.RemoveMod(selection.Design!, selection.Design!.AssociatedMods.Keys[0]);
|
manager.RemoveMod(Selection, Selection.AssociatedMods.Keys[0]);
|
||||||
foreach (var (mod, setting) in _copy!)
|
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;
|
var (id, name) = penumbra.CurrentCollection;
|
||||||
if (ImEx.Button("Apply Mod Associations"u8, Vector2.Zero,
|
if (ImEx.Button("Apply Mod Associations"u8, Vector2.Zero,
|
||||||
$"Try to apply all associated mod settings to Penumbras current collection {name}",
|
$"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();
|
ApplyAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void 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);
|
penumbra.SetMod(mod, settings, StateSource.Manual, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -104,7 +107,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
||||||
|
|
||||||
Mod? removedMod = null;
|
Mod? removedMod = null;
|
||||||
(Mod mod, ModSettings settings)? updatedMod = 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);
|
using var id = Im.Id.Push(idx);
|
||||||
DrawAssociatedModRow(table, mod, settings, out var removedModTmp, out var updatedModTmp);
|
DrawAssociatedModRow(table, mod, settings, out var removedModTmp, out var updatedModTmp);
|
||||||
|
|
@ -117,10 +120,10 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignSelection select
|
||||||
DrawNewModRow(table);
|
DrawNewModRow(table);
|
||||||
|
|
||||||
if (removedMod.HasValue)
|
if (removedMod.HasValue)
|
||||||
manager.RemoveMod(selection.Design!, removedMod.Value);
|
manager.RemoveMod(Selection, removedMod.Value);
|
||||||
|
|
||||||
if (updatedMod.HasValue)
|
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,
|
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();
|
table.NextColumn();
|
||||||
var tt = currentDir.Length is 0
|
var tt = currentDir.Length is 0
|
||||||
? "Please select a mod first."u8
|
? "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
|
? "The design already contains an association with the selected mod."u8
|
||||||
: StringU8.Empty;
|
: StringU8.Empty;
|
||||||
|
|
||||||
if (ImEx.Icon.Button(LunaStyle.AddObjectIcon, tt, tt.Length > 0))
|
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();
|
table.NextColumn();
|
||||||
_modCombo.Draw("##new"u8, Im.ContentRegion.Available.X);
|
_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;
|
using ImSharp;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
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)
|
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;
|
=> Im.Style.TextHeightWithSpacing;
|
||||||
|
|
||||||
protected override IEnumerable<CacheItem> GetItems()
|
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)
|
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 Glamourer.Interop.Material;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -6,21 +7,21 @@ using Luna;
|
||||||
namespace Glamourer.Gui.Tabs.DesignTab;
|
namespace Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
||||||
public class MultiDesignPanel(
|
public class MultiDesignPanel(
|
||||||
DesignFileSystemSelector selector,
|
DesignFileSystem fileSystem,
|
||||||
DesignManager editor,
|
DesignManager editor,
|
||||||
DesignColors colors,
|
DesignColors colors,
|
||||||
Configuration.Configuration config)
|
Configuration config)
|
||||||
{
|
{
|
||||||
private readonly DesignColorCombo _colorCombo = new(colors, true);
|
private readonly DesignColorCombo _colorCombo = new(colors, true);
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
{
|
{
|
||||||
if (selector.SelectedPaths.Count == 0)
|
if (fileSystem.Selection.OrderedNodes.Count is 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var width = ImEx.ScaledVectorX(145);
|
var width = ImEx.ScaledVectorX(145);
|
||||||
var treeNodePos = Im.Cursor.Position;
|
var treeNodePos = Im.Cursor.Position;
|
||||||
_numDesigns = DrawDesignList();
|
DrawDesignList();
|
||||||
DrawCounts(treeNodePos);
|
DrawCounts(treeNodePos);
|
||||||
var offset = DrawMultiTagger(width);
|
var offset = DrawMultiTagger(width);
|
||||||
DrawMultiColor(width, offset);
|
DrawMultiColor(width, offset);
|
||||||
|
|
@ -36,14 +37,15 @@ public class MultiDesignPanel(
|
||||||
private void DrawCounts(Vector2 treeNodePos)
|
private void DrawCounts(Vector2 treeNodePos)
|
||||||
{
|
{
|
||||||
var startPos = Im.Cursor.Position;
|
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;
|
Im.Cursor.Position = treeNodePos;
|
||||||
ImEx.TextRightAligned((_numDesigns, numFolders) switch
|
ImEx.TextRightAligned((numDesigns, numFolders) switch
|
||||||
{
|
{
|
||||||
(0, 0) => StringU8.Empty, // should not happen
|
(0, 0) => StringU8.Empty, // should not happen
|
||||||
( > 0, 0) => $"{_numDesigns} Designs",
|
(> 0, 0) => $"{numDesigns} Designs",
|
||||||
(0, > 0) => $"{numFolders} Folders",
|
(0, > 0) => $"{numFolders} Folders",
|
||||||
_ => $"{_numDesigns} Designs, {numFolders} Folders",
|
_ => $"{numDesigns} Designs, {numFolders} Folders",
|
||||||
});
|
});
|
||||||
Im.Cursor.Position = startPos;
|
Im.Cursor.Position = startPos;
|
||||||
}
|
}
|
||||||
|
|
@ -59,10 +61,10 @@ public class MultiDesignPanel(
|
||||||
_numAdvancedDyes = 0;
|
_numAdvancedDyes = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool CountLeaves(DesignFileSystem.IPath path)
|
private void CountLeaves(IFileSystemNode path)
|
||||||
{
|
{
|
||||||
if (path is not DesignFileSystem.Leaf l)
|
if (path is not IFileSystemData<Design> l)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
if (l.Value.QuickDesign)
|
if (l.Value.QuickDesign)
|
||||||
++_numQuickDesignEnabled;
|
++_numQuickDesignEnabled;
|
||||||
|
|
@ -79,55 +81,48 @@ public class MultiDesignPanel(
|
||||||
++_numDesignsWithAdvancedDyes;
|
++_numDesignsWithAdvancedDyes;
|
||||||
_numAdvancedDyes += l.Value.Materials.Count;
|
_numAdvancedDyes += l.Value.Materials.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int DrawDesignList()
|
private void DrawDesignList()
|
||||||
{
|
{
|
||||||
ResetCounts();
|
ResetCounts();
|
||||||
using var tree = Im.Tree.Node("Currently Selected Objects"u8, TreeNodeFlags.DefaultOpen | TreeNodeFlags.NoTreePushOnOpen);
|
using var tree = Im.Tree.Node("Currently Selected Objects"u8, TreeNodeFlags.DefaultOpen | TreeNodeFlags.NoTreePushOnOpen);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
if (!tree)
|
if (!tree)
|
||||||
return selector.SelectedPaths.Count(CountLeaves);
|
return;
|
||||||
|
|
||||||
var sizeType = new Vector2(Im.Style.FrameHeight);
|
var sizeType = new Vector2(Im.Style.FrameHeight);
|
||||||
var availableSizePercent = (Im.ContentRegion.Available.X - sizeType.X - 4 * Im.Style.CellPadding.X) / 100;
|
var availableSizePercent = (Im.ContentRegion.Available.X - sizeType.X - 4 * Im.Style.CellPadding.X) / 100;
|
||||||
var sizeMods = availableSizePercent * 35;
|
var sizeMods = availableSizePercent * 35;
|
||||||
var sizeFolders = availableSizePercent * 65;
|
var sizeFolders = availableSizePercent * 65;
|
||||||
|
|
||||||
var numDesigns = 0;
|
|
||||||
using (var table = Im.Table.Begin("mods"u8, 3, TableFlags.RowBackground))
|
using (var table = Im.Table.Begin("mods"u8, 3, TableFlags.RowBackground))
|
||||||
{
|
{
|
||||||
if (!table)
|
if (!table)
|
||||||
return selector.SelectedPaths.Count(l => l is DesignFileSystem.Leaf);
|
return;
|
||||||
|
|
||||||
table.SetupColumn("type"u8, TableColumnFlags.WidthFixed, sizeType.X);
|
table.SetupColumn("type"u8, TableColumnFlags.WidthFixed, sizeType.X);
|
||||||
table.SetupColumn("mod"u8, TableColumnFlags.WidthFixed, sizeMods);
|
table.SetupColumn("mod"u8, TableColumnFlags.WidthFixed, sizeMods);
|
||||||
table.SetupColumn("path"u8, TableColumnFlags.WidthFixed, sizeFolders);
|
table.SetupColumn("path"u8, TableColumnFlags.WidthFixed, sizeFolders);
|
||||||
|
|
||||||
var i = 0;
|
foreach (var (index, node) in fileSystem.Selection.OrderedNodes.Index())
|
||||||
foreach (var (fullName, path) in selector.SelectedPaths.Select(p => (p.FullName(), p))
|
|
||||||
.OrderBy(p => p.Item1, StringComparer.OrdinalIgnoreCase))
|
|
||||||
{
|
{
|
||||||
using var id = Im.Id.Push(i++);
|
using var id = Im.Id.Push(index);
|
||||||
var (icon, text) = path is DesignFileSystem.Leaf l
|
var (icon, text) = node is IFileSystemData<Design> l
|
||||||
? (LunaStyle.RemoveFileIcon, l.Value.Name.Text)
|
? (LunaStyle.RemoveFileIcon, l.Value.Name.Text)
|
||||||
: (LunaStyle.RemoveFolderIcon, string.Empty);
|
: (LunaStyle.RemoveFolderIcon, string.Empty);
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (ImEx.Icon.Button(icon, "Remove from selection."u8, sizeType))
|
if (ImEx.Icon.Button(icon, "Remove from selection."u8, sizeType))
|
||||||
selector.RemovePathFromMultiSelection(path);
|
fileSystem.Selection.RemoveFromSelection(node);
|
||||||
|
|
||||||
table.DrawFrameColumn(text);
|
table.DrawFrameColumn(text);
|
||||||
table.DrawFrameColumn(fullName);
|
table.DrawFrameColumn(node.FullPath);
|
||||||
|
|
||||||
if (CountLeaves(path))
|
CountLeaves(node);
|
||||||
++numDesigns;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
return numDesigns;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string _tag = string.Empty;
|
private string _tag = string.Empty;
|
||||||
|
|
@ -138,7 +133,6 @@ public class MultiDesignPanel(
|
||||||
private int _numDesignsResetDyes;
|
private int _numDesignsResetDyes;
|
||||||
private int _numAdvancedDyes;
|
private int _numAdvancedDyes;
|
||||||
private int _numDesignsWithAdvancedDyes;
|
private int _numDesignsWithAdvancedDyes;
|
||||||
private int _numDesigns;
|
|
||||||
private readonly List<Design> _addDesigns = [];
|
private readonly List<Design> _addDesigns = [];
|
||||||
private readonly List<(Design, int)> _removeDesigns = [];
|
private readonly List<(Design, int)> _removeDesigns = [];
|
||||||
|
|
||||||
|
|
@ -158,7 +152,8 @@ public class MultiDesignPanel(
|
||||||
? _tag.Length is 0
|
? _tag.Length is 0
|
||||||
? "No tag specified."u8
|
? "No tag specified."u8
|
||||||
: $"All designs selected already contain the tag \"{_tag}\"."
|
: $"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 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)
|
foreach (var design in _addDesigns)
|
||||||
editor.AddTag(design, _tag);
|
editor.AddTag(design, _tag);
|
||||||
|
|
||||||
|
|
@ -169,7 +164,8 @@ public class MultiDesignPanel(
|
||||||
? _tag.Length is 0
|
? _tag.Length is 0
|
||||||
? "No tag specified."u8
|
? "No tag specified."u8
|
||||||
: $"No selected design contains the tag \"{_tag}\" locally."
|
: $"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 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)
|
foreach (var (design, index) in _removeDesigns)
|
||||||
editor.RemoveTag(design, index);
|
editor.RemoveTag(design, index);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
|
|
@ -181,23 +177,21 @@ public class MultiDesignPanel(
|
||||||
ImEx.TextFrameAligned("Multi QDB:"u8);
|
ImEx.TextFrameAligned("Multi QDB:"u8);
|
||||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
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
|
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."
|
? $"All {fileSystem.Selection.DataNodes.Count} 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))
|
: $"Display all {fileSystem.Selection.DataNodes.Count} selected designs in the quick design bar. Changes {diff} designs.",
|
||||||
{
|
diff is 0))
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
editor.SetQuickDesign(design.Value, true);
|
editor.SetQuickDesign(design.GetValue<Design>()!, true);
|
||||||
}
|
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Hide Selected Designs in QDB"u8, buttonWidth, _numQuickDesignEnabled is 0
|
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."
|
? $"All {fileSystem.Selection.DataNodes.Count} 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))
|
: $"Hide all {fileSystem.Selection.DataNodes.Count} selected designs in the quick design bar. Changes {_numQuickDesignEnabled} designs.",
|
||||||
{
|
_numQuickDesignEnabled is 0))
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
editor.SetQuickDesign(design.Value, false);
|
editor.SetQuickDesign(design.GetValue<Design>()!, false);
|
||||||
}
|
|
||||||
|
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
@ -207,19 +201,20 @@ public class MultiDesignPanel(
|
||||||
ImEx.TextFrameAligned("Multi Lock:"u8);
|
ImEx.TextFrameAligned("Multi Lock:"u8);
|
||||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
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
|
if (ImEx.Button("Turn Write-Protected"u8, buttonWidth, diff is 0
|
||||||
? $"All {_numDesigns} selected designs are already write protected."
|
? $"All {fileSystem.Selection.DataNodes.Count} selected designs are already write protected."
|
||||||
: $"Write-protect all {_numDesigns} designs. Changes {diff} designs.", diff is 0))
|
: $"Write-protect all {fileSystem.Selection.DataNodes.Count} designs. Changes {diff} designs.", diff is 0))
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
editor.SetWriteProtection(design.Value, true);
|
editor.SetWriteProtection(design.GetValue<Design>()!, true);
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Remove Write-Protection"u8, buttonWidth, _numDesignsLocked is 0
|
if (ImEx.Button("Remove Write-Protection"u8, buttonWidth, _numDesignsLocked is 0
|
||||||
? $"None of the {_numDesigns} selected designs are write-protected."
|
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs are write-protected."
|
||||||
: $"Remove the write protection of the {_numDesigns} selected designs. Changes {_numDesignsLocked} designs.", _numDesignsLocked is 0))
|
: $"Remove the write protection of the {fileSystem.Selection.DataNodes.Count} selected designs. Changes {_numDesignsLocked} designs.",
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
_numDesignsLocked is 0))
|
||||||
editor.SetWriteProtection(design.Value, false);
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
|
editor.SetWriteProtection(design.GetValue<Design>()!, false);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,19 +223,21 @@ public class MultiDesignPanel(
|
||||||
ImEx.TextFrameAligned("Settings:"u8);
|
ImEx.TextFrameAligned("Settings:"u8);
|
||||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
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
|
if (ImEx.Button("Set Reset Temp. Settings"u8, buttonWidth, diff is 0
|
||||||
? $"All {_numDesigns} selected designs already reset temporary settings."
|
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already reset temporary settings."
|
||||||
: $"Make all {_numDesigns} selected designs reset temporary settings. Changes {diff} designs.", diff is 0))
|
: $"Make all {fileSystem.Selection.DataNodes.Count} selected designs reset temporary settings. Changes {diff} designs.",
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
diff is 0))
|
||||||
editor.ChangeResetTemporarySettings(design.Value, true);
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
|
editor.ChangeResetTemporarySettings(design.GetValue<Design>()!, true);
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Remove Reset Temp. Settings"u8, buttonWidth, _numDesignsResetSettings is 0
|
if (ImEx.Button("Remove Reset Temp. Settings"u8, buttonWidth, _numDesignsResetSettings is 0
|
||||||
? $"None of the {_numDesigns} selected designs reset temporary settings."
|
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs reset temporary settings."
|
||||||
: $"Stop all {_numDesigns} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.", _numDesignsResetSettings is 0))
|
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from resetting temporary settings. Changes {_numDesignsResetSettings} designs.",
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
_numDesignsResetSettings is 0))
|
||||||
editor.ChangeResetTemporarySettings(design.Value, false);
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
|
editor.ChangeResetTemporarySettings(design.GetValue<Design>()!, false);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,19 +246,20 @@ public class MultiDesignPanel(
|
||||||
ImEx.TextFrameAligned("Adv. Dyes:"u8);
|
ImEx.TextFrameAligned("Adv. Dyes:"u8);
|
||||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
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
|
if (ImEx.Button("Set Reset Dyes"u8, buttonWidth, diff is 0
|
||||||
? $"All {_numDesigns} selected designs already reset advanced dyes."
|
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already reset advanced dyes."
|
||||||
: $"Make all {_numDesigns} selected designs reset advanced dyes. Changes {diff} designs.", diff is 0))
|
: $"Make all {fileSystem.Selection.DataNodes.Count} selected designs reset advanced dyes. Changes {diff} designs.", diff is 0))
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
editor.ChangeResetAdvancedDyes(design.Value, true);
|
editor.ChangeResetAdvancedDyes(design.GetValue<Design>()!, true);
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Remove Reset Dyes"u8, buttonWidth, _numDesignsLocked is 0
|
if (ImEx.Button("Remove Reset Dyes"u8, buttonWidth, _numDesignsLocked is 0
|
||||||
? $"None of the {_numDesigns} selected designs reset advanced dyes."
|
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs reset advanced dyes."
|
||||||
: $"Stop all {_numDesigns} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.", _numDesignsResetDyes is 0))
|
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from resetting advanced dyes. Changes {_numDesignsResetDyes} designs.",
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
_numDesignsResetDyes is 0))
|
||||||
editor.ChangeResetAdvancedDyes(design.Value, false);
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
|
editor.ChangeResetAdvancedDyes(design.GetValue<Design>()!, false);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -270,19 +268,20 @@ public class MultiDesignPanel(
|
||||||
ImEx.TextFrameAligned("Redrawing:"u8);
|
ImEx.TextFrameAligned("Redrawing:"u8);
|
||||||
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
Im.Line.Same(offset, Im.Style.ItemSpacing.X);
|
||||||
var buttonWidth = new Vector2((Im.ContentRegion.Available.X - Im.Style.ItemSpacing.X) / 2, 0);
|
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
|
if (ImEx.Button("Force Redraws"u8, buttonWidth, diff is 0
|
||||||
? $"All {_numDesigns} selected designs already force redraws."
|
? $"All {fileSystem.Selection.DataNodes.Count} selected designs already force redraws."
|
||||||
: $"Make all {_numDesigns} designs force redraws. Changes {diff} designs.", diff is 0))
|
: $"Make all {fileSystem.Selection.DataNodes.Count} designs force redraws. Changes {diff} designs.", diff is 0))
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
editor.ChangeForcedRedraw(design.Value, true);
|
editor.ChangeForcedRedraw(design.GetValue<Design>()!, true);
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Remove Forced Redraws"u8, buttonWidth, _numDesignsLocked is 0
|
if (ImEx.Button("Remove Forced Redraws"u8, buttonWidth, _numDesignsLocked is 0
|
||||||
? $"None of the {_numDesigns} selected designs force redraws."
|
? $"None of the {fileSystem.Selection.DataNodes.Count} selected designs force redraws."
|
||||||
: $"Stop all {_numDesigns} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.", _numDesignsForcedRedraw is 0))
|
: $"Stop all {fileSystem.Selection.DataNodes.Count} selected designs from forcing redraws. Changes {_numDesignsForcedRedraw} designs.",
|
||||||
foreach (var design in selector.SelectedPaths.OfType<DesignFileSystem.Leaf>())
|
_numDesignsForcedRedraw is 0))
|
||||||
editor.ChangeForcedRedraw(design.Value, false);
|
foreach (var design in fileSystem.Selection.DataNodes)
|
||||||
|
editor.ChangeForcedRedraw(design.GetValue<Design>()!, false);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -307,22 +306,20 @@ public class MultiDesignPanel(
|
||||||
DesignColors.AutomaticName => "Use the other button to set to automatic."u8,
|
DesignColors.AutomaticName => "Use the other button to set to automatic."u8,
|
||||||
_ => $"All designs selected are already set to the color \"{_colorComboSelection}\".",
|
_ => $"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 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)
|
foreach (var design in _addDesigns)
|
||||||
editor.ChangeColor(design, _colorComboSelection!);
|
editor.ChangeColor(design, _colorComboSelection!);
|
||||||
}
|
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button(_removeDesigns.Count > 0
|
if (ImEx.Button(_removeDesigns.Count > 0
|
||||||
? $"Unset {_removeDesigns.Count} Designs"
|
? $"Unset {_removeDesigns.Count} Designs"
|
||||||
: "Unset"u8, width, _removeDesigns.Count is 0
|
: "Unset"u8, width, _removeDesigns.Count is 0
|
||||||
? "No selected design is set to a non-automatic color."u8
|
? "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))
|
: $"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)
|
foreach (var (design, _) in _removeDesigns)
|
||||||
editor.ChangeColor(design, string.Empty);
|
editor.ChangeColor(design, string.Empty);
|
||||||
}
|
|
||||||
|
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
}
|
}
|
||||||
|
|
@ -337,10 +334,11 @@ public class MultiDesignPanel(
|
||||||
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.",
|
: $"Delete {_numAdvancedDyes} advanced dyes from {_numDesignsWithAdvancedDyes} of the selected designs.",
|
||||||
!enabled || _numDesignsWithAdvancedDyes is 0))
|
!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)
|
while (design.GetValue<Design>()!.Materials.Count > 0)
|
||||||
editor.ChangeMaterialValue(design.Value, MaterialValueIndex.FromKey(design.Value.Materials[0].Item1), null);
|
editor.ChangeMaterialValue(design.GetValue<Design>()!,
|
||||||
|
MaterialValueIndex.FromKey(design.GetValue<Design>()!.Materials[0].Item1), null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enabled && _numDesignsWithAdvancedDyes is not 0)
|
if (!enabled && _numDesignsWithAdvancedDyes is not 0)
|
||||||
|
|
@ -359,8 +357,8 @@ public class MultiDesignPanel(
|
||||||
using (Im.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
if (ImEx.Button("Disable Everything"u8, width,
|
if (ImEx.Button("Disable Everything"u8, width,
|
||||||
_numDesigns > 0
|
fileSystem.Selection.DataNodes.Count > 0
|
||||||
? $"Disable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
|
? $"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))
|
: "No designs selected."u8, !enabled))
|
||||||
{
|
{
|
||||||
equip = false;
|
equip = false;
|
||||||
|
|
@ -372,8 +370,8 @@ public class MultiDesignPanel(
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Enable Everything"u8, width,
|
if (ImEx.Button("Enable Everything"u8, width,
|
||||||
_numDesigns > 0
|
fileSystem.Selection.DataNodes.Count > 0
|
||||||
? $"Enable application of everything, including any existing advanced dyes, advanced customizations, crests and wetness for all {_numDesigns} designs."
|
? $"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))
|
: "No designs selected."u8, !enabled))
|
||||||
{
|
{
|
||||||
equip = true;
|
equip = true;
|
||||||
|
|
@ -384,8 +382,8 @@ public class MultiDesignPanel(
|
||||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
if (ImEx.Button("Equipment Only"u8, width,
|
if (ImEx.Button("Equipment Only"u8, width,
|
||||||
_numDesigns > 0
|
fileSystem.Selection.DataNodes.Count > 0
|
||||||
? $"Enable application of anything related to gear, disable anything that is not related to gear for all {_numDesigns} designs."
|
? $"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))
|
: "No designs selected."u8, !enabled))
|
||||||
{
|
{
|
||||||
equip = true;
|
equip = true;
|
||||||
|
|
@ -397,8 +395,8 @@ public class MultiDesignPanel(
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Customization Only"u8, width,
|
if (ImEx.Button("Customization Only"u8, width,
|
||||||
_numDesigns > 0
|
fileSystem.Selection.DataNodes.Count > 0
|
||||||
? $"Enable application of anything related to customization, disable anything that is not related to customization for all {_numDesigns} designs."
|
? $"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))
|
: "No designs selected."u8, !enabled))
|
||||||
{
|
{
|
||||||
equip = false;
|
equip = false;
|
||||||
|
|
@ -409,10 +407,10 @@ public class MultiDesignPanel(
|
||||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
if (ImEx.Button("Default Application"u8, width,
|
if (ImEx.Button("Default Application"u8, width,
|
||||||
_numDesigns > 0
|
fileSystem.Selection.DataNodes.Count > 0
|
||||||
? $"Set the application rules to the default values as if the {_numDesigns} were newly created,without any advanced features or wetness."
|
? $"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))
|
: "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.ChangeApplyMulti(design, true, true, true, false, true, true, false, true);
|
||||||
editor.ChangeApplyMeta(design, MetaIndex.Wetness, false);
|
editor.ChangeApplyMeta(design, MetaIndex.Wetness, false);
|
||||||
|
|
@ -422,10 +420,10 @@ public class MultiDesignPanel(
|
||||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"Hold {config.DeleteDesignModifier} while clicking.");
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
if (ImEx.Button("Disable Advanced"u8, width, _numDesigns > 0
|
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 {_numDesigns} designs."
|
? $"Disable all advanced dyes and customizations but keep everything else as is for all {fileSystem.Selection.DataNodes.Count} designs."
|
||||||
: "No designs selected."u8, !enabled))
|
: "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);
|
editor.ChangeApplyMulti(design, null, null, null, false, null, null, false, null);
|
||||||
|
|
||||||
if (!enabled)
|
if (!enabled)
|
||||||
|
|
@ -436,7 +434,7 @@ public class MultiDesignPanel(
|
||||||
if (equip is null && customize is null)
|
if (equip is null && customize is null)
|
||||||
return;
|
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,
|
editor.ChangeApplyMulti(design, equip, customize, equip, customize.HasValue && !customize.Value ? false : null, null, equip, equip,
|
||||||
equip);
|
equip);
|
||||||
|
|
@ -459,13 +457,14 @@ public class MultiDesignPanel(
|
||||||
if (_tag.Length is 0)
|
if (_tag.Length is 0)
|
||||||
return;
|
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)
|
if (index >= 0)
|
||||||
_removeDesigns.Add((leaf.Value, index));
|
_removeDesigns.Add((design, index));
|
||||||
else
|
else
|
||||||
_addDesigns.Add(leaf.Value);
|
_addDesigns.Add(design);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -474,12 +473,13 @@ public class MultiDesignPanel(
|
||||||
_addDesigns.Clear();
|
_addDesigns.Clear();
|
||||||
_removeDesigns.Clear();
|
_removeDesigns.Clear();
|
||||||
var selection = string.IsNullOrEmpty(_colorComboSelection) ? DesignColors.AutomaticName : _colorComboSelection;
|
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)
|
var design = leaf.GetValue<Design>()!;
|
||||||
_removeDesigns.Add((leaf.Value, 0));
|
if (design.Color.Length > 0)
|
||||||
if (selection != DesignColors.AutomaticName && leaf.Value.Color != selection)
|
_removeDesigns.Add((design, 0));
|
||||||
_addDesigns.Add(leaf.Value);
|
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;
|
using Luna;
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs;
|
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
|
public override AwesomeIcon Icon
|
||||||
=> config.Ephemeral.IncognitoMode
|
=> config.Ephemeral.IncognitoMode
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Gui.Customization;
|
using Glamourer.Gui.Customization;
|
||||||
using Glamourer.Gui.Equipment;
|
using Glamourer.Gui.Equipment;
|
||||||
|
|
@ -13,7 +13,7 @@ using Penumbra.GameData.Interop;
|
||||||
namespace Glamourer.Gui.Tabs.NpcTab;
|
namespace Glamourer.Gui.Tabs.NpcTab;
|
||||||
|
|
||||||
public sealed class NpcPanel(
|
public sealed class NpcPanel(
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
NpcSelection selection,
|
NpcSelection selection,
|
||||||
CustomizationDrawer customizeDrawer,
|
CustomizationDrawer customizeDrawer,
|
||||||
EquipmentDrawer equipmentDrawer,
|
EquipmentDrawer equipmentDrawer,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,12 @@
|
||||||
using Dalamud.Interface;
|
using Glamourer.Config;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui.Filesystem;
|
|
||||||
using OtterGui.Raii;
|
|
||||||
using OtterGui.Text;
|
|
||||||
using OtterGui.Text.EndObjects;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
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
|
private static ReadOnlySpan<byte> Tooltip
|
||||||
=> "Cheat Codes are not actually for cheating in the game, but for 'cheating' in Glamourer. "u8
|
=> "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()
|
private void DrawCodeInput()
|
||||||
{
|
{
|
||||||
var color = codeService.CheckCode(_currentCode).Item2 is not 0 ? ColorId.ActorAvailable : ColorId.ActorUnavailable;
|
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);
|
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))
|
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();
|
Im.Line.Same();
|
||||||
ImUtf8.Icon(FontAwesomeIcon.ExclamationCircle, ImGuiColor.TextDisabled.Get().Color);
|
ImEx.Icon.Draw(LunaStyle.WarningIcon, ImGuiColor.TextDisabled.Get());
|
||||||
DrawTooltip();
|
DrawTooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawCopyButtons()
|
private void DrawCopyButtons()
|
||||||
{
|
{
|
||||||
var buttonSize = new Vector2(250 * Im.Style.GlobalScale, 0);
|
var buttonSize = ImEx.ScaledVectorX(250);
|
||||||
if (ImUtf8.Button("Who am I?!?"u8, buttonSize))
|
if (Im.Button("Who am I?!?"u8, buttonSize))
|
||||||
funModule.WhoAmI();
|
funModule.WhoAmI();
|
||||||
ImUtf8.HoverTooltip(
|
Im.Tooltip.OnHover("Copy your characters actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||||
"Copy your characters actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
|
||||||
|
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
|
|
||||||
if (ImUtf8.Button("Who is that!?!"u8, buttonSize))
|
if (Im.Button("Who is that!?!"u8, buttonSize))
|
||||||
funModule.WhoIsThat();
|
funModule.WhoIsThat();
|
||||||
ImUtf8.HoverTooltip(
|
Im.Tooltip.OnHover("Copy your targets actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
||||||
"Copy your targets actual current appearance including cheat codes or holiday events to the clipboard as a design."u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeService.CodeFlag DrawCodes()
|
private CodeService.CodeFlag DrawCodes()
|
||||||
|
|
@ -76,7 +70,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
CodeService.CodeFlag knownFlags = 0;
|
CodeService.CodeFlag knownFlags = 0;
|
||||||
for (var i = 0; i < config.Codes.Count; ++i)
|
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 (code, state) = config.Codes[i];
|
||||||
var (action, flag) = codeService.CheckCode(code);
|
var (action, flag) = codeService.CheckCode(code);
|
||||||
if (flag is 0)
|
if (flag is 0)
|
||||||
|
|
@ -84,8 +78,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
|
|
||||||
var data = CodeService.GetData(flag);
|
var data = CodeService.GetData(flag);
|
||||||
|
|
||||||
if (ImUtf8.IconButton(FontAwesomeIcon.Trash,
|
if (ImEx.Icon.Button(LunaStyle.DeleteIcon, $"Delete this cheat code.{(canDelete ? StringU8.Empty : $"\nHold {config.DeleteDesignModifier} while clicking to delete.")}",
|
||||||
$"Delete this cheat code.{(canDelete ? string.Empty : $"\nHold {config.DeleteDesignModifier} while clicking to delete.")}",
|
|
||||||
disabled: !canDelete))
|
disabled: !canDelete))
|
||||||
{
|
{
|
||||||
action!(false);
|
action!(false);
|
||||||
|
|
@ -95,7 +88,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
|
|
||||||
knownFlags |= flag;
|
knownFlags |= flag;
|
||||||
Im.Line.SameInner();
|
Im.Line.SameInner();
|
||||||
if (ImUtf8.Checkbox("\0"u8, ref state))
|
if (Im.Checkbox(StringU8.Empty, ref state))
|
||||||
{
|
{
|
||||||
action!(state);
|
action!(state);
|
||||||
codeService.SaveState();
|
codeService.SaveState();
|
||||||
|
|
@ -103,14 +96,14 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
|
|
||||||
var hovered = Im.Item.Hovered();
|
var hovered = Im.Item.Hovered();
|
||||||
Im.Line.Same();
|
Im.Line.Same();
|
||||||
ImUtf8.Selectable(code);
|
Im.Selectable(code);
|
||||||
hovered |= Im.Item.Hovered();
|
hovered |= Im.Item.Hovered();
|
||||||
DrawSource(i, code);
|
DrawSource(i, code);
|
||||||
DrawTarget(i);
|
DrawTarget(i);
|
||||||
if (hovered)
|
if (hovered)
|
||||||
{
|
{
|
||||||
using var tt = ImUtf8.Tooltip();
|
using var tt = Im.Tooltip.Begin();
|
||||||
ImUtf8.Text(data.Effect);
|
Im.Text(data.Effect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,22 +112,22 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
|
|
||||||
private void DrawSource(int idx, string code)
|
private void DrawSource(int idx, string code)
|
||||||
{
|
{
|
||||||
using var source = ImUtf8.DragDropSource();
|
using var source = Im.DragDrop.Source();
|
||||||
if (!source)
|
if (!source)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!DragDropSource.SetPayload(DragDropLabel))
|
if (!source.SetPayload(DragDropLabel))
|
||||||
_dragCodeIdx = idx;
|
_dragCodeIdx = idx;
|
||||||
ImUtf8.Text($"Dragging {code}...");
|
Im.Text($"Dragging {code}...");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawTarget(int idx)
|
private void DrawTarget(int idx)
|
||||||
{
|
{
|
||||||
using var target = ImUtf8.DragDropTarget();
|
using var target = Im.DragDrop.Target();
|
||||||
if (!target.IsDropping(DragDropLabel) || _dragCodeIdx == -1)
|
if (!target.IsDropping(DragDropLabel) || _dragCodeIdx is -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (Extensions.Move(config.Codes, _dragCodeIdx, idx))
|
if (config.Codes.Move(_dragCodeIdx, idx))
|
||||||
codeService.SaveState();
|
codeService.SaveState();
|
||||||
_dragCodeIdx = -1;
|
_dragCodeIdx = -1;
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +137,7 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
if (knownFlags.HasFlag(CodeService.AllHintCodes))
|
if (knownFlags.HasFlag(CodeService.AllHintCodes))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (ImUtf8.Button(_showCodeHints ? "Hide Hints"u8 : "Show Hints"u8))
|
if (Im.Button(_showCodeHints ? "Hide Hints"u8 : "Show Hints"u8))
|
||||||
_showCodeHints = !_showCodeHints;
|
_showCodeHints = !_showCodeHints;
|
||||||
|
|
||||||
if (!_showCodeHints)
|
if (!_showCodeHints)
|
||||||
|
|
@ -162,23 +155,23 @@ public class CodeDrawer(Configuration.Configuration config, CodeService codeServ
|
||||||
Im.Dummy(Vector2.Zero);
|
Im.Dummy(Vector2.Zero);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
Im.Dummy(Vector2.Zero);
|
Im.Dummy(Vector2.Zero);
|
||||||
ImUtf8.Text(data.Effect);
|
Im.Text(data.Effect);
|
||||||
using var indent = ImRaii.PushIndent(2);
|
using var indent = Im.Indent(2);
|
||||||
using (ImUtf8.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
ImUtf8.Text("Capitalized letters: "u8);
|
Im.Text("Capitalized letters: "u8);
|
||||||
ImUtf8.Text("Punctuation: "u8);
|
Im.Text("Punctuation: "u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Line.SameInner();
|
Im.Line.SameInner();
|
||||||
using (ImUtf8.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
using var mono = Im.Font.PushMono();
|
using var mono = Im.Font.PushMono();
|
||||||
ImUtf8.Text($"{data.CapitalCount}");
|
Im.Text($"{data.CapitalCount}");
|
||||||
ImUtf8.Text($"{data.Punctuation}");
|
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;
|
return;
|
||||||
|
|
||||||
Im.Window.SetNextSize(new Vector2(400, 0));
|
Im.Window.SetNextSize(new Vector2(400, 0));
|
||||||
using var tt = ImUtf8.Tooltip();
|
using var tt = Im.Tooltip.Begin();
|
||||||
ImUtf8.TextWrapped(Tooltip);
|
Im.TextWrapped(Tooltip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,82 @@
|
||||||
using Dalamud.Interface;
|
using Glamourer.Config;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Logger = OtterGui.Log.Logger;
|
|
||||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||||
|
|
||||||
public sealed class CollectionCombo(Configuration.Configuration config, PenumbraService penumbra, Logger log)
|
public sealed class CollectionCombo(Configuration config, PenumbraService penumbra)
|
||||||
: FilterComboCache<(Guid Id, string IdShort, string Name)>(
|
: FilterComboBase<CollectionCombo.CacheItem>(new CollectionFilter()), IUiService
|
||||||
() => penumbra.GetCollections().Select(kvp => (kvp.Key, kvp.Key.ToString()[..8], kvp.Value)).ToArray(),
|
|
||||||
MouseWheelType.Control, log), 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)
|
if (config.Ephemeral.IncognitoMode)
|
||||||
using (Im.Font.PushMono())
|
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();
|
Im.Line.Same();
|
||||||
|
|
||||||
using (Im.Font.PushMono())
|
using (Im.Font.PushMono())
|
||||||
{
|
{
|
||||||
using var color = ImGuiColor.Text.Push(ImGuiColor.TextDisabled.Get());
|
using var color = ImGuiColor.Text.Push(ImGuiColor.TextDisabled.Get());
|
||||||
ImEx.TextRightAligned($"({idShort})");
|
ImEx.TextRightAligned(item.ShortId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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 Dalamud.Interface;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
|
@ -10,7 +11,7 @@ namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||||
|
|
||||||
public class CollectionOverrideDrawer(
|
public class CollectionOverrideDrawer(
|
||||||
CollectionOverrideService collectionOverrides,
|
CollectionOverrideService collectionOverrides,
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
ActorObjectManager objects,
|
ActorObjectManager objects,
|
||||||
ActorManager actors,
|
ActorManager actors,
|
||||||
PenumbraService penumbra,
|
PenumbraService penumbra,
|
||||||
|
|
@ -58,18 +59,15 @@ public class CollectionOverrideDrawer(
|
||||||
DrawActorIdentifier(idx, actor);
|
DrawActorIdentifier(idx, actor);
|
||||||
|
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
if (combo.Draw("##collection", name, "Select the overriding collection. Current GUID:", Im.ContentRegion.Available.X,
|
if (combo.Draw("##collection"u8, name, out var newName, ref collection, Im.ContentRegion.Available.X))
|
||||||
Im.Style.TextHeight))
|
collectionOverrides.ChangeOverride(idx, collection, newName);
|
||||||
{
|
|
||||||
var (guid, _, newName) = combo.CurrentSelection;
|
|
||||||
collectionOverrides.ChangeOverride(idx, guid, newName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Im.Item.Hovered())
|
if (Im.Item.Hovered())
|
||||||
{
|
{
|
||||||
using var tt = Im.Tooltip.Begin();
|
using var tt = Im.Tooltip.Begin();
|
||||||
using var font = Im.Font.PushMono();
|
Im.Text("Select the overriding collection. Current GUID:"u8);
|
||||||
Im.Text($" {collection}");
|
using var indent = Im.Indent();
|
||||||
|
ImEx.MonoText($"{collection}");
|
||||||
}
|
}
|
||||||
|
|
||||||
table.NextColumn();
|
table.NextColumn();
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Configuration;
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Gui.Tabs.DesignTab;
|
using Glamourer.Gui.Tabs.DesignTab;
|
||||||
|
|
@ -15,8 +15,8 @@ using Luna;
|
||||||
namespace Glamourer.Gui.Tabs.SettingsTab;
|
namespace Glamourer.Gui.Tabs.SettingsTab;
|
||||||
|
|
||||||
public sealed class SettingsTab(
|
public sealed class SettingsTab(
|
||||||
Configuration.Configuration config,
|
Configuration config,
|
||||||
DesignFileSystemSelector selector,
|
DesignFileSystemDrawer drawer,
|
||||||
ContextMenuService contextMenuService,
|
ContextMenuService contextMenuService,
|
||||||
IUiBuilder uiBuilder,
|
IUiBuilder uiBuilder,
|
||||||
GlamourerChangelog changelog,
|
GlamourerChangelog changelog,
|
||||||
|
|
@ -28,7 +28,8 @@ public sealed class SettingsTab(
|
||||||
Glamourer glamourer,
|
Glamourer glamourer,
|
||||||
AutoDesignApplier autoDesignApplier,
|
AutoDesignApplier autoDesignApplier,
|
||||||
AutoRedrawChanged autoRedraw,
|
AutoRedrawChanged autoRedraw,
|
||||||
PcpService pcpService)
|
PcpService pcpService,
|
||||||
|
IgnoredMods ignoredMods)
|
||||||
: ITab<MainTabType>
|
: ITab<MainTabType>
|
||||||
{
|
{
|
||||||
private readonly VirtualKey[] _validKeys = keys.GetValidVirtualKeys().Prepend(VirtualKey.NO_KEY).ToArray();
|
private readonly VirtualKey[] _validKeys = keys.GetValidVirtualKeys().Prepend(VirtualKey.NO_KEY).ToArray();
|
||||||
|
|
@ -61,6 +62,7 @@ public sealed class SettingsTab(
|
||||||
DrawInterfaceSettings();
|
DrawInterfaceSettings();
|
||||||
DrawColorSettings();
|
DrawColorSettings();
|
||||||
overrides.Draw();
|
overrides.Draw();
|
||||||
|
DrawIgnoredMods();
|
||||||
codeDrawer.Draw();
|
codeDrawer.Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -256,7 +258,7 @@ public sealed class SettingsTab(
|
||||||
Im.Line.New();
|
Im.Line.New();
|
||||||
Im.Text("Show the following panels in their respective tabs:"u8);
|
Im.Text("Show the following panels in their respective tabs:"u8);
|
||||||
Im.Dummy(Vector2.Zero);
|
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.HideDesignPanel = v;
|
||||||
config.Save();
|
config.Save();
|
||||||
|
|
@ -280,7 +282,7 @@ public sealed class SettingsTab(
|
||||||
Checkbox("Show Unobtained Item Warnings"u8,
|
Checkbox("Show Unobtained Item Warnings"u8,
|
||||||
"Show information whether you have unlocked all items and customizations in your automated design or not."u8,
|
"Show information whether you have unlocked all items and customizations in your automated design or not."u8,
|
||||||
config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v);
|
config.ShowUnlockedItemWarnings, v => config.ShowUnlockedItemWarnings = v);
|
||||||
Checkbox("Show Color Display Config"u8, "Show the Color Display configuration options in the Advanced Customization panels."u8,
|
Checkbox("Show Color Display Configuration"u8, "Show the Color Display configuration options in the Advanced Customization panels."u8,
|
||||||
config.ShowColorConfig, v => config.ShowColorConfig = v);
|
config.ShowColorConfig, v => config.ShowColorConfig = v);
|
||||||
Checkbox("Show Palette+ Import Button"u8,
|
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,
|
"Show the import button that allows you to import Palette+ palettes onto a design in the Advanced Customization options section for designs."u8,
|
||||||
|
|
@ -376,7 +378,7 @@ public sealed class SettingsTab(
|
||||||
if (Im.Button("Import Palette+ to Designs"u8))
|
if (Im.Button("Import Palette+ to Designs"u8))
|
||||||
paletteImport.ImportDesigns();
|
paletteImport.ImportDesigns();
|
||||||
Im.Tooltip.OnHover(
|
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>
|
/// <summary> Draw the entire Color subsection. </summary>
|
||||||
|
|
@ -402,6 +404,7 @@ public sealed class SettingsTab(
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
config.Colors[color] = newColor.Color;
|
config.Colors[color] = newColor.Color;
|
||||||
|
CacheManager.Instance.SetColorsDirty();
|
||||||
config.Save();
|
config.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -445,20 +448,20 @@ public sealed class SettingsTab(
|
||||||
using (var combo = Im.Combo.Begin("##sortMode"u8, sortMode.Name))
|
using (var combo = Im.Combo.Begin("##sortMode"u8, sortMode.Name))
|
||||||
{
|
{
|
||||||
if (combo)
|
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;
|
config.SortMode = value;
|
||||||
selector.SetFilterDirty();
|
drawer.SortMode = value;
|
||||||
config.Save();
|
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()
|
private void DrawRenameSettings()
|
||||||
|
|
@ -472,7 +475,6 @@ public sealed class SettingsTab(
|
||||||
if (Im.Selectable(value.ToNameU8(), config.ShowRename == value))
|
if (Im.Selectable(value.ToNameU8(), config.ShowRename == value))
|
||||||
{
|
{
|
||||||
config.ShowRename = value;
|
config.ShowRename = value;
|
||||||
selector.SetRenameSearchPath(value);
|
|
||||||
config.Save();
|
config.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -503,4 +505,46 @@ public sealed class SettingsTab(
|
||||||
LunaStyle.DrawAlignedHelpMarkerLabel("Character Height Display Type"u8,
|
LunaStyle.DrawAlignedHelpMarkerLabel("Character Height Display Type"u8,
|
||||||
"Select how to display the height of characters in real-world units, if at all."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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ public readonly struct UnlockCacheItem(in EquipItem item, in EquipItem offhand,
|
||||||
public readonly StringPair GauntletModelString = gauntlets.Valid ? new StringPair(gauntlets.ModelString) : StringPair.Empty;
|
public readonly StringPair GauntletModelString = gauntlets.Valid ? new StringPair(gauntlets.ModelString) : StringPair.Empty;
|
||||||
public readonly StringPair RequiredLevel = new($"{item.Level.Value}");
|
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 JobFlag Jobs = jobs.Flags;
|
||||||
public readonly StringU8 JobText = jobs.Name.IsEmpty ? new StringU8($"Unknown {jobs.Id.Id}") : jobs.Name;
|
public readonly StringU8 JobText = jobs.Name.IsEmpty ? new StringU8($"Unknown {jobs.Id.Id}") : jobs.Name;
|
||||||
public required bool Favorite { get; init; }
|
public required bool Favorite { get; init; }
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility.Table;
|
using Dalamud.Interface.Utility.Table;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
|
|
@ -23,9 +24,10 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
||||||
private readonly FavoriteManager _favorites;
|
private readonly FavoriteManager _favorites;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly ObjectUnlocked _unlockEvent;
|
private readonly ObjectUnlocked _unlockEvent;
|
||||||
|
private readonly IgnoredMods _ignoredMods;
|
||||||
|
|
||||||
public UnlockTable(JobService jobs, ItemManager items, ItemUnlockManager unlocks, PenumbraChangedItemTooltip tooltip,
|
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),
|
: 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 SlotColumn(), new TypeColumn(), new UnlockDateColumn(), new ItemIdColumn(), new ModelDataColumn(), new JobColumn(jobs),
|
||||||
new RequiredLevelColumn(), new DyableColumn(), new CrestColumn(), new TradableColumn())
|
new RequiredLevelColumn(), new DyableColumn(), new CrestColumn(), new TradableColumn())
|
||||||
|
|
@ -36,6 +38,7 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
||||||
_unlockEvent = unlockEvent;
|
_unlockEvent = unlockEvent;
|
||||||
_favorites = favorites;
|
_favorites = favorites;
|
||||||
_penumbra = penumbra;
|
_penumbra = penumbra;
|
||||||
|
_ignoredMods = ignoredMods;
|
||||||
|
|
||||||
Flags |= TableFlags.Hideable | TableFlags.Reorderable | TableFlags.Resizable;
|
Flags |= TableFlags.Hideable | TableFlags.Reorderable | TableFlags.Resizable;
|
||||||
}
|
}
|
||||||
|
|
@ -72,6 +75,7 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
||||||
UnlockTimestamp = unlocked,
|
UnlockTimestamp = unlocked,
|
||||||
Mods = mods,
|
Mods = mods,
|
||||||
Favorite = favorite,
|
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;
|
=> Im.Style.FrameHeightWithSpacing;
|
||||||
|
|
||||||
public override void DrawColumn(in UnlockCacheItem item, int globalIndex)
|
public override void DrawColumn(in UnlockCacheItem item, int globalIndex)
|
||||||
{
|
=> UiHelpers.DrawFavoriteStar(_favorites, item.Item);
|
||||||
Im.Cursor.FrameAlign();
|
|
||||||
UiHelpers.DrawFavoriteStar(_favorites, item.Item);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex)
|
protected override bool GetValue(in UnlockCacheItem item, int globalIndex, int triEnumIndex)
|
||||||
=> item.Favorite;
|
=> item.Favorite;
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class ModdedColumn : YesNoColumn<UnlockCacheItem>
|
private sealed class ModdedColumn : FlagColumn<ModdedColumn.Modded, UnlockCacheItem>
|
||||||
{
|
{
|
||||||
|
[Flags]
|
||||||
|
public enum Modded
|
||||||
|
{
|
||||||
|
Relevant = 1,
|
||||||
|
Ignored = 2,
|
||||||
|
None = 4,
|
||||||
|
}
|
||||||
|
|
||||||
private static readonly AwesomeIcon Dot = FontAwesomeIcon.Circle;
|
private static readonly AwesomeIcon Dot = FontAwesomeIcon.Circle;
|
||||||
|
private static readonly AwesomeIcon Hollow = FontAwesomeIcon.DotCircle;
|
||||||
|
|
||||||
public ModdedColumn()
|
public ModdedColumn()
|
||||||
{
|
{
|
||||||
Flags |= TableColumnFlags.NoResize;
|
Flags |= TableColumnFlags.NoResize;
|
||||||
Label = new StringU8("M");
|
Label = new StringU8("M");
|
||||||
FilterLabel = new StringU8("Modded"u8);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override float ComputeWidth(IEnumerable<UnlockCacheItem> allItems)
|
public override float ComputeWidth(IEnumerable<UnlockCacheItem> allItems)
|
||||||
|
|
@ -124,8 +133,11 @@ public sealed class UnlockTable : TableBase<UnlockCacheItem, UnlockTable.Cache>
|
||||||
|
|
||||||
using (AwesomeIcon.Font.Push())
|
using (AwesomeIcon.Font.Push())
|
||||||
{
|
{
|
||||||
using var color = ImGuiColor.Text.Push(ColorId.ModdedItemMarker.Value());
|
var (color, text) = item.RelevantMods > 0
|
||||||
ImEx.TextCentered(Dot.Span);
|
? (ColorId.ModdedItemMarker.Value(), Dot)
|
||||||
|
: (ColorId.ModdedItemMarker.Value().HalfTransparent(), Hollow);
|
||||||
|
using var c = ImGuiColor.Text.Push(color);
|
||||||
|
Im.Text(text.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Im.Item.Hovered())
|
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)
|
protected override Modded GetValue(in UnlockCacheItem item, int globalIndex)
|
||||||
=> item.Mods.Length > 0;
|
=> 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)
|
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>
|
private sealed class NameColumn : TextColumn<UnlockCacheItem>
|
||||||
|
|
|
||||||
|
|
@ -5,11 +5,11 @@ namespace Glamourer.Gui.Tabs.UnlocksTab;
|
||||||
|
|
||||||
public sealed class UnlocksTab : Window, ITab<MainTabType>
|
public sealed class UnlocksTab : Window, ITab<MainTabType>
|
||||||
{
|
{
|
||||||
private readonly Configuration.EphemeralConfig _config;
|
private readonly Config.EphemeralConfig _config;
|
||||||
private readonly UnlockOverview _overview;
|
private readonly UnlockOverview _overview;
|
||||||
private readonly UnlockTable _table;
|
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")
|
: base("Unlocked Equipment")
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Game.Gui.ContextMenu;
|
using Dalamud.Game.Gui.ContextMenu;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
using FFXIVClientStructs.FFXIV.Client.UI.Agent;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -23,7 +24,7 @@ public class ContextMenuService : IDisposable
|
||||||
|
|
||||||
private readonly MenuItem _inventoryItem;
|
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)
|
IContextMenu context)
|
||||||
{
|
{
|
||||||
_contextMenu = context;
|
_contextMenu = context;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -24,7 +25,7 @@ public sealed unsafe class MaterialManager : IRequiredService, IDisposable
|
||||||
private readonly ThreadLocal<List<MaterialValueIndex>> _deleteList = new(() => []);
|
private readonly ThreadLocal<List<MaterialValueIndex>> _deleteList = new(() => []);
|
||||||
|
|
||||||
public MaterialManager(PrepareColorSet prepareColorSet, StateManager stateManager, ActorManager actors, PenumbraService penumbra,
|
public MaterialManager(PrepareColorSet prepareColorSet, StateManager stateManager, ActorManager actors, PenumbraService penumbra,
|
||||||
Configuration.Configuration config)
|
Configuration config)
|
||||||
{
|
{
|
||||||
_stateManager = stateManager;
|
_stateManager = stateManager;
|
||||||
_actors = actors;
|
_actors = actors;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Config;
|
||||||
|
using Glamourer.Designs.Links;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -7,14 +8,19 @@ using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.Interop.Penumbra;
|
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
|
: IService
|
||||||
{
|
{
|
||||||
private readonly HashSet<Guid> _collectionTracker = [];
|
private readonly HashSet<Guid> _collectionTracker = [];
|
||||||
|
|
||||||
public void HandleStateApplication(ActorState state, MergedDesign design, StateSource source, bool skipAutoRedraw, bool respectManual)
|
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;
|
return;
|
||||||
|
|
||||||
if (!objects.TryGetValue(state.Identifier, out var data))
|
if (!objects.TryGetValue(state.Identifier, out var data))
|
||||||
|
|
@ -90,6 +96,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
|
||||||
if (!respectManual && source.IsFixed())
|
if (!respectManual && source.IsFixed())
|
||||||
penumbra.RemoveAllTemporarySettings(index.Value, StateSource.Manual);
|
penumbra.RemoveAllTemporarySettings(index.Value, StateSource.Manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Api.Enums;
|
using Glamourer.Api.Enums;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs.History;
|
using Glamourer.Designs.History;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
|
@ -12,7 +13,7 @@ namespace Glamourer.Interop.Penumbra;
|
||||||
public class PenumbraAutoRedraw : IDisposable, IRequiredService
|
public class PenumbraAutoRedraw : IDisposable, IRequiredService
|
||||||
{
|
{
|
||||||
private const int WaitFrames = 5;
|
private const int WaitFrames = 5;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly PenumbraService _penumbra;
|
private readonly PenumbraService _penumbra;
|
||||||
private readonly StateManager _state;
|
private readonly StateManager _state;
|
||||||
private readonly ActorObjectManager _objects;
|
private readonly ActorObjectManager _objects;
|
||||||
|
|
@ -21,7 +22,7 @@ public class PenumbraAutoRedraw : IDisposable, IRequiredService
|
||||||
private readonly PenumbraAutoRedrawSkip _skip;
|
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,
|
IFramework framework,
|
||||||
StateChanged stateChanged, PenumbraAutoRedrawSkip skip)
|
StateChanged stateChanged, PenumbraAutoRedrawSkip skip)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Ipc.Exceptions;
|
using Dalamud.Plugin.Ipc.Exceptions;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
using Luna;
|
using Luna;
|
||||||
|
|
@ -45,7 +46,7 @@ public class PenumbraService : IDisposable
|
||||||
private const string NameManual = "Glamourer (Manually)";
|
private const string NameManual = "Glamourer (Manually)";
|
||||||
|
|
||||||
private readonly IDalamudPluginInterface _pluginInterface;
|
private readonly IDalamudPluginInterface _pluginInterface;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
|
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
|
||||||
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
|
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
|
||||||
private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase;
|
private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase;
|
||||||
|
|
@ -96,7 +97,7 @@ public class PenumbraService : IDisposable
|
||||||
public int CurrentMinor { get; private set; }
|
public int CurrentMinor { get; private set; }
|
||||||
public DateTime AttachTime { 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;
|
_pluginInterface = pi;
|
||||||
_penumbraReloaded = penumbraReloaded;
|
_penumbraReloaded = penumbraReloaded;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,9 @@
|
||||||
using Luna;
|
using Luna;
|
||||||
using Backup = OtterGui.Classes.Backup;
|
|
||||||
using Logger = OtterGui.Log.Logger;
|
|
||||||
|
|
||||||
namespace Glamourer.Services;
|
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>
|
/// <summary> Collect all relevant files for glamourer configuration. </summary>
|
||||||
private static IReadOnlyList<FileInfo> GlamourerFiles(FilenameService fileNames)
|
private static IReadOnlyList<FileInfo> GlamourerFiles(FilenameService fileNames)
|
||||||
{
|
{
|
||||||
|
|
@ -29,7 +11,7 @@ public class BackupService : IAsyncService
|
||||||
{
|
{
|
||||||
new(fileNames.ConfigurationFile),
|
new(fileNames.ConfigurationFile),
|
||||||
new(fileNames.UiConfiguration),
|
new(fileNames.UiConfiguration),
|
||||||
new(fileNames.DesignFileSystem),
|
new(fileNames.MigrationDesignFileSystem),
|
||||||
new(fileNames.MigrationDesignFile),
|
new(fileNames.MigrationDesignFile),
|
||||||
new(fileNames.AutomationFile),
|
new(fileNames.AutomationFile),
|
||||||
new(fileNames.UnlockFileCustomize),
|
new(fileNames.UnlockFileCustomize),
|
||||||
|
|
@ -42,9 +24,4 @@ public class BackupService : IAsyncService
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task Awaiter { get; }
|
|
||||||
|
|
||||||
public bool Finished
|
|
||||||
=> Awaiter.IsCompletedSuccessfully;
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,12 @@
|
||||||
|
using Glamourer.Config;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Services;
|
namespace Glamourer.Services;
|
||||||
|
|
||||||
public class CodeService
|
public class CodeService
|
||||||
{
|
{
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly SHA256 _hasher = SHA256.Create();
|
private readonly SHA256 _hasher = SHA256.Create();
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
|
|
@ -25,6 +25,7 @@ public class CodeService
|
||||||
OopsAuRa = 0x000400,
|
OopsAuRa = 0x000400,
|
||||||
OopsHrothgar = 0x000800,
|
OopsHrothgar = 0x000800,
|
||||||
OopsViera = 0x001000,
|
OopsViera = 0x001000,
|
||||||
|
|
||||||
//Artisan = 0x002000,
|
//Artisan = 0x002000,
|
||||||
SixtyThree = 0x004000,
|
SixtyThree = 0x004000,
|
||||||
Shirts = 0x008000,
|
Shirts = 0x008000,
|
||||||
|
|
@ -87,7 +88,7 @@ public class CodeService
|
||||||
_ => Race.Unknown,
|
_ => Race.Unknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
public CodeService(Configuration.Configuration config)
|
public CodeService(Configuration config)
|
||||||
{
|
{
|
||||||
_config = config;
|
_config = config;
|
||||||
Load();
|
Load();
|
||||||
|
|
@ -253,4 +254,3 @@ public class CodeService
|
||||||
_ => (false, 0, string.Empty, string.Empty, string.Empty),
|
_ => (false, 0, string.Empty, string.Empty, string.Empty),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
using Dalamud.Game.Text.SeStringHandling;
|
using Dalamud.Game.Text.SeStringHandling;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Config;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Designs.Special;
|
using Glamourer.Designs.Special;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
|
|
@ -32,7 +33,7 @@ public class CommandService : IDisposable, IApiService
|
||||||
private readonly StateManager _stateManager;
|
private readonly StateManager _stateManager;
|
||||||
private readonly AutoDesignApplier _autoDesignApplier;
|
private readonly AutoDesignApplier _autoDesignApplier;
|
||||||
private readonly AutoDesignManager _autoDesignManager;
|
private readonly AutoDesignManager _autoDesignManager;
|
||||||
private readonly Configuration.Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ModSettingApplier _modApplier;
|
private readonly ModSettingApplier _modApplier;
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
private readonly CustomizeService _customizeService;
|
private readonly CustomizeService _customizeService;
|
||||||
|
|
@ -43,8 +44,8 @@ public class CommandService : IDisposable, IApiService
|
||||||
|
|
||||||
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ActorObjectManager objects,
|
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ActorObjectManager objects,
|
||||||
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
|
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
|
||||||
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration.Configuration config, ModSettingApplier modApplier,
|
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config, ModSettingApplier modApplier,
|
||||||
ItemManager items, RandomDesignGenerator randomDesign, CustomizeService customizeService, DesignFileSystemSelector designSelector,
|
ItemManager items, RandomDesignGenerator randomDesign, CustomizeService customizeService, DesignFileSystemDrawer designDrawer,
|
||||||
QuickDesignCombo quickDesignCombo, DesignResolver resolver, PenumbraService penumbra)
|
QuickDesignCombo quickDesignCombo, DesignResolver resolver, PenumbraService penumbra)
|
||||||
{
|
{
|
||||||
_commands = commands;
|
_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