This commit is contained in:
Ottermandias 2023-07-07 20:24:44 +02:00
parent 5c003d8cd4
commit f8e9cc8988
43 changed files with 2215 additions and 668 deletions

View file

@ -16,6 +16,7 @@ public enum ColorId
DisabledAutoSet,
AutomationActorAvailable,
AutomationActorUnavailable,
HeaderButtons,
}
public static class Colors
@ -36,6 +37,7 @@ public static class Colors
ColorId.DisabledAutoSet => (0xFF808080, "Disabled Automation Set", "An automation set that is currently disabled." ),
ColorId.AutomationActorAvailable => (0xFFFFFFFF, "Automation Actor Available", "A character associated with the given automated design set is currently visible." ),
ColorId.AutomationActorUnavailable => (0xFF808080, "Automation Actor Unavailable", "No character associated with the given automated design set is currently visible." ),
ColorId.HeaderButtons => (0xFFFFF0C0, "Header Buttons", "The text and border color of buttons in the header, like the Incognito toggle." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -121,17 +121,20 @@ public partial class CustomizationDrawer
PercentageInputInt();
ImGui.TextUnformatted(_set.Option(CustomizeIndex.LegacyTattoo));
if (_set.DataByValue(CustomizeIndex.Face, _customize.Face, out _, _customize.Face) < 0)
ImGui.TextUnformatted("(Using Face 1)");
}
private void DrawMultiIcons()
{
var options = _set.Order[CharaMakeParams.MenuType.IconCheckmark];
using var _ = ImRaii.Group();
var options = _set.Order[CharaMakeParams.MenuType.IconCheckmark];
using var group = ImRaii.Group();
var face = _set.DataByValue(CustomizeIndex.Face, _customize.Face, out _, _customize.Face) < 0 ? _set.Faces[0].Value : _customize.Face;
foreach (var (featureIdx, idx) in options.WithIndex())
{
using var id = SetId(featureIdx);
var enabled = _customize.Get(featureIdx) != CustomizeValue.Zero;
var feature = _set.Data(featureIdx, 0, _customize.Face);
var feature = _set.Data(featureIdx, 0, face);
var icon = featureIdx == CustomizeIndex.LegacyTattoo
? _legacyTattoo ?? _service.AwaitedService.GetIcon(feature.IconId)
: _service.AwaitedService.GetIcon(feature.IconId);

View file

@ -1,15 +1,22 @@
using System.Numerics;
using System;
using System.Numerics;
using System.Xml.Linq;
using Dalamud.Interface;
using Glamourer.Events;
using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.Interop.Structs;
using Glamourer.Services;
using Glamourer.State;
using ImGuiNET;
using Lumina.Excel.GeneratedSheets;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui.Tabs.ActorTab;
@ -19,6 +26,8 @@ public class ActorPanel
private readonly StateManager _stateManager;
private readonly CustomizationDrawer _customizationDrawer;
private readonly EquipmentDrawer _equipmentDrawer;
private readonly HumanModelList _humans;
private readonly IdentifierService _identification;
private ActorIdentifier _identifier;
private string _actorName = string.Empty;
@ -27,12 +36,14 @@ public class ActorPanel
private ActorState? _state;
public ActorPanel(ActorSelector selector, StateManager stateManager, CustomizationDrawer customizationDrawer,
EquipmentDrawer equipmentDrawer)
EquipmentDrawer equipmentDrawer, HumanModelList humans, IdentifierService identification)
{
_selector = selector;
_stateManager = stateManager;
_customizationDrawer = customizationDrawer;
_equipmentDrawer = equipmentDrawer;
_humans = humans;
_identification = identification;
}
public void Draw()
@ -47,15 +58,16 @@ public class ActorPanel
private void DrawHeader()
{
var frameHeight = ImGui.GetFrameHeightWithSpacing();
var color = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) : _data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
var color = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) :
_data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGuiUtil.DrawTextButton($"{_actorName}##playerHeader", new Vector2(-frameHeight, ImGui.GetFrameHeight()), buttonColor, color);
ImGui.SameLine();
style.Push(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
using (var c = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value())
.Push(ImGuiCol.Border, ColorId.FolderExpanded.Value()))
using (var c = ImRaii.PushColor(ImGuiCol.Text, ColorId.HeaderButtons.Value())
.Push(ImGuiCol.Border, ColorId.HeaderButtons.Value()))
{
if (ImGuiUtil.DrawDisabledButton(
$"{(_selector.IncognitoMode ? FontAwesomeIcon.Eye : FontAwesomeIcon.EyeSlash).ToIconString()}###IncognitoMode",
@ -79,13 +91,9 @@ public class ActorPanel
return (_selector.IncognitoMode ? _identifier.Incognito(null) : _identifier.ToString(), Actor.Null);
}
private unsafe void DrawPanel()
private void DrawHumanPanel()
{
using var child = ImRaii.Child("##Panel", -Vector2.One, true);
if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
return;
if (_customizationDrawer.Draw(_state.ModelData.Customize, false))
if (_customizationDrawer.Draw(_state!.ModelData.Customize, false))
_stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual);
foreach (var slot in EquipSlotExtensions.EqdpSlots)
@ -122,6 +130,79 @@ public class ActorPanel
}
}
private void DrawMonsterPanel()
{
var names = _identification.AwaitedService.ModelCharaNames(_state!.ModelData.ModelId);
var turnHuman = ImGui.Button("Turn Human");
ImGui.Separator();
using (var box = ImRaii.ListBox("##MonsterList",
new Vector2(ImGui.GetContentRegionAvail().X, 10 * ImGui.GetTextLineHeightWithSpacing())))
{
if (names.Count == 0)
ImGui.TextUnformatted("Unknown Monster");
else
ImGuiClip.ClippedDraw(names, p => ImGui.TextUnformatted($"{p.Name} ({p.Kind.ToName()} #{p.Id})"),
ImGui.GetTextLineHeightWithSpacing());
}
ImGui.Separator();
ImGui.TextUnformatted("Customization Data");
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
{
foreach (var b in _state.ModelData.Customize.Data)
{
using (var g = ImRaii.Group())
{
ImGui.TextUnformatted($" {b:X2}");
ImGui.TextUnformatted($"{b,3}");
}
ImGui.SameLine();
if (ImGui.GetContentRegionAvail().X < ImGui.GetStyle().ItemSpacing.X + ImGui.CalcTextSize("XXX").X)
ImGui.NewLine();
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
}
ImGui.Separator();
ImGui.TextUnformatted("Equipment Data");
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
{
foreach (var b in _state.ModelData.GetEquipmentBytes())
{
using (var g = ImRaii.Group())
{
ImGui.TextUnformatted($" {b:X2}");
ImGui.TextUnformatted($"{b,3}");
}
ImGui.SameLine();
if (ImGui.GetContentRegionAvail().X < ImGui.GetStyle().ItemSpacing.X + ImGui.CalcTextSize("XXX").X)
ImGui.NewLine();
}
if (ImGui.GetCursorPosX() != 0)
ImGui.NewLine();
}
if (turnHuman)
_stateManager.TurnHuman(_state, StateChanged.Source.Manual);
}
private unsafe void DrawPanel()
{
using var child = ImRaii.Child("##Panel", -Vector2.One, true);
if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
return;
if (_humans.IsHuman(_state.ModelData.ModelId))
DrawHumanPanel();
else
DrawMonsterPanel();
}
private unsafe void RevertButton()
{

View file

@ -99,9 +99,10 @@ public class ActorSelector
_identifier = _objects.Player.GetIdentifier(_actors.AwaitedService);
ImGui.SameLine();
Actor targetActor = _targets.Target?.Address;
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth,
"Select the current target, if it is in the list.", _objects.IsInGPose || !targetActor, true))
_identifier = targetActor.GetIdentifier(_actors.AwaitedService);
var (id, data) = _objects.TargetData;
var tt = data.Valid ? $"Select the current target {id} in the list." :
id.IsValid ? $"The target {id} is not in the list." : "No target selected.";
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth, tt, _objects.IsInGPose || !data.Valid, true))
_identifier = id;
}
}

View file

@ -68,8 +68,8 @@ public class SetPanel
ImGuiUtil.DrawTextButton(_selector.SelectionName, new Vector2(-frameHeight, ImGui.GetFrameHeight()), buttonColor);
ImGui.SameLine();
style.Push(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value())
.Push(ImGuiCol.Border, ColorId.FolderExpanded.Value());
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.HeaderButtons.Value())
.Push(ImGuiCol.Border, ColorId.HeaderButtons.Value());
if (ImGuiUtil.DrawDisabledButton(
$"{(_selector.IncognitoMode ? FontAwesomeIcon.Eye : FontAwesomeIcon.EyeSlash).ToIconString()}###IncognitoMode",
new Vector2(frameHeight, ImGui.GetFrameHeight()), string.Empty, false, true))

View file

@ -46,12 +46,12 @@ public class SetSelector : IDisposable
_config = config;
_actors = actors;
_objects = objects;
_event.Subscribe(OnAutomationChanged, AutomationChanged.Priority.SetSelector);
_event.Subscribe(OnAutomationChange, AutomationChanged.Priority.SetSelector);
}
public void Dispose()
{
_event.Unsubscribe(OnAutomationChanged);
_event.Unsubscribe(OnAutomationChange);
}
public string SelectionName
@ -60,7 +60,7 @@ public class SetSelector : IDisposable
public string GetSetName(AutoDesignSet? set, int index)
=> set == null ? "No Selection" : IncognitoMode ? $"Auto Design Set #{index + 1}" : set.Name;
private void OnAutomationChanged(AutomationChanged.Type type, AutoDesignSet? set, object? data)
private void OnAutomationChange(AutomationChanged.Type type, AutoDesignSet? set, object? data)
{
switch (type)
{

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Text;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Game.ClientState.Objects.Types;
using Dalamud.Interface;
@ -19,7 +20,9 @@ using Glamourer.Interop.Structs;
using Glamourer.Services;
using Glamourer.State;
using Glamourer.Unlocks;
using Glamourer.Utility;
using ImGuiNET;
using Newtonsoft.Json.Linq;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
@ -42,7 +45,7 @@ public unsafe class DebugTab : ITab
private readonly ObjectTable _objects;
private readonly ObjectManager _objectManager;
private readonly GlamourerIpc _ipc;
private readonly CodeService _code;
private readonly CodeService _code;
private readonly ItemManager _items;
private readonly ActorService _actors;
@ -54,6 +57,7 @@ public unsafe class DebugTab : ITab
private readonly DesignManager _designManager;
private readonly DesignFileSystem _designFileSystem;
private readonly AutoDesignManager _autoDesignManager;
private readonly DesignConverter _designConverter;
private readonly PenumbraChangedItemTooltip _penumbraTooltip;
@ -70,7 +74,7 @@ public unsafe class DebugTab : ITab
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config,
PenumbraChangedItemTooltip penumbraTooltip, MetaService metaService, GlamourerIpc ipc, DalamudPluginInterface pluginInterface,
AutoDesignManager autoDesignManager, JobService jobs, CodeService code, CustomizeUnlockManager customizeUnlocks,
ItemUnlockManager itemUnlocks)
ItemUnlockManager itemUnlocks, DesignConverter designConverter)
{
_changeCustomizeService = changeCustomizeService;
_visorService = visorService;
@ -92,9 +96,10 @@ public unsafe class DebugTab : ITab
_pluginInterface = pluginInterface;
_autoDesignManager = autoDesignManager;
_jobs = jobs;
_code = code;
_code = code;
_customizeUnlocks = customizeUnlocks;
_itemUnlocks = itemUnlocks;
_designConverter = designConverter;
}
public ReadOnlySpan<byte> Label
@ -817,6 +822,7 @@ public unsafe class DebugTab : ITab
DrawDesignManager();
DrawDesignTester();
DrawDesignConverter();
}
private void DrawDesignManager()
@ -927,6 +933,83 @@ public unsafe class DebugTab : ITab
}
}
private string _clipboardText = string.Empty;
private byte[] _clipboardData = Array.Empty<byte>();
private byte[] _dataUncompressed = Array.Empty<byte>();
private byte _version = 0;
private string _textUncompressed = string.Empty;
private JObject? _json = null;
private DesignBase? _tmpDesign = null;
private Exception? _clipboardProblem = null;
private void DrawDesignConverter()
{
using var tree = ImRaii.TreeNode("Design Converter");
if (!tree)
return;
if (ImGui.Button("Import Clipboard"))
{
_clipboardText = string.Empty;
_clipboardData = Array.Empty<byte>();
_dataUncompressed = Array.Empty<byte>();
_textUncompressed = string.Empty;
_json = null;
_tmpDesign = null;
_clipboardProblem = null;
try
{
_clipboardText = ImGui.GetClipboardText();
_clipboardData = Convert.FromBase64String(_clipboardText);
_version = _clipboardData.Decompress(out _dataUncompressed);
_textUncompressed = Encoding.UTF8.GetString(_dataUncompressed);
_json = JObject.Parse(_textUncompressed);
_tmpDesign = _designConverter.FromBase64(_clipboardText, true, true);
}
catch (Exception ex)
{
_clipboardProblem = ex;
}
}
if (_clipboardText.Length > 0)
{
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(_clipboardText);
}
if (_clipboardData.Length > 0)
{
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(string.Join(" ", _clipboardData.Select(b => b.ToString("X2"))));
}
if (_dataUncompressed.Length > 0)
{
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(string.Join(" ", _dataUncompressed.Select(b => b.ToString("X2"))));
}
if (_textUncompressed.Length > 0)
{
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(_textUncompressed);
}
if (_json != null)
ImGui.TextUnformatted("JSON Parsing Successful!");
if (_tmpDesign != null)
DrawDesign(_tmpDesign);
if (_clipboardProblem != null)
{
using var f = ImRaii.PushFont(UiBuilder.MonoFont);
ImGuiUtil.TextWrapped(_clipboardProblem.ToString());
}
}
public void DrawState(ActorData data, ActorState state)
{
using var table = ImRaii.Table("##state", 7, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
@ -955,20 +1038,20 @@ public unsafe class DebugTab : ITab
return $"{item.Name} ({item.ModelId.Value}{(item.WeaponType != 0 ? $"-{item.WeaponType.Value}" : string.Empty)}-{item.Variant})";
}
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state[ActorState.MetaFlag.ModelId]);
PrintRow("Model ID", state.BaseData.ModelId, state.ModelData.ModelId, state[ActorState.MetaIndex.ModelId]);
ImGui.TableNextRow();
PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state[ActorState.MetaFlag.Wetness]);
PrintRow("Wetness", state.BaseData.IsWet(), state.ModelData.IsWet(), state[ActorState.MetaIndex.Wetness]);
ImGui.TableNextRow();
if (state.BaseData.ModelId == 0 && state.ModelData.ModelId == 0)
{
PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state[ActorState.MetaFlag.HatState]);
PrintRow("Hat Visible", state.BaseData.IsHatVisible(), state.ModelData.IsHatVisible(), state[ActorState.MetaIndex.HatState]);
ImGui.TableNextRow();
PrintRow("Visor Toggled", state.BaseData.IsVisorToggled(), state.ModelData.IsVisorToggled(),
state[ActorState.MetaFlag.VisorState]);
state[ActorState.MetaIndex.VisorState]);
ImGui.TableNextRow();
PrintRow("Weapon Visible", state.BaseData.IsWeaponVisible(), state.ModelData.IsWeaponVisible(),
state[ActorState.MetaFlag.WeaponState]);
state[ActorState.MetaIndex.WeaponState]);
ImGui.TableNextRow();
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{
@ -1053,33 +1136,36 @@ public unsafe class DebugTab : ITab
}
}
private void DrawDesign(Design design)
private void DrawDesign(DesignBase design)
{
using var table = ImRaii.Table("##equip", 6, ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit);
ImGuiUtil.DrawTableColumn("Name");
ImGuiUtil.DrawTableColumn(design.Name);
ImGuiUtil.DrawTableColumn($"({design.Index})");
ImGui.TableNextColumn();
ImGui.TextUnformatted("Description (Hover)");
ImGuiUtil.HoverTooltip(design.Description);
ImGui.TableNextRow();
if (design is Design d)
{
ImGuiUtil.DrawTableColumn("Name");
ImGuiUtil.DrawTableColumn(d.Name);
ImGuiUtil.DrawTableColumn($"({d.Index})");
ImGui.TableNextColumn();
ImGui.TextUnformatted("Description (Hover)");
ImGuiUtil.HoverTooltip(d.Description);
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Identifier");
ImGuiUtil.DrawTableColumn(design.Identifier.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Design File System Path");
ImGuiUtil.DrawTableColumn(_designFileSystem.FindLeaf(design, out var leaf) ? leaf.FullName() : "No Path Known");
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Identifier");
ImGuiUtil.DrawTableColumn(d.Identifier.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Design File System Path");
ImGuiUtil.DrawTableColumn(_designFileSystem.FindLeaf(d, out var leaf) ? leaf.FullName() : "No Path Known");
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Creation");
ImGuiUtil.DrawTableColumn(design.CreationDate.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Update");
ImGuiUtil.DrawTableColumn(design.LastEdit.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Tags");
ImGuiUtil.DrawTableColumn(string.Join(", ", design.Tags));
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Creation");
ImGuiUtil.DrawTableColumn(d.CreationDate.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Update");
ImGuiUtil.DrawTableColumn(d.LastEdit.ToString());
ImGui.TableNextRow();
ImGuiUtil.DrawTableColumn("Tags");
ImGuiUtil.DrawTableColumn(string.Join(", ", d.Tags));
ImGui.TableNextRow();
}
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
{
@ -1174,10 +1260,8 @@ public unsafe class DebugTab : ITab
foreach (var (identifier, state) in _state.Where(kvp => !_objectManager.ContainsKey(kvp.Key)))
{
using var t = ImRaii.TreeNode(identifier.ToString());
if (!t)
return;
DrawState(ActorData.Invalid, state);
if (t)
DrawState(ActorData.Invalid, state);
}
}

View file

@ -0,0 +1,173 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Designs;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab;
public class DesignDetailTab
{
private readonly SaveService _saveService;
private readonly DesignFileSystemSelector _selector;
private readonly DesignFileSystem _fileSystem;
private readonly DesignManager _manager;
private readonly TagButtons _tagButtons = new();
private string? _newPath;
private string? _newDescription;
private string? _newName;
private bool _editDescriptionMode;
public DesignDetailTab(SaveService saveService, DesignFileSystemSelector selector, DesignManager manager, DesignFileSystem fileSystem)
{
_saveService = saveService;
_selector = selector;
_manager = manager;
_fileSystem = fileSystem;
}
public void Draw()
{
if (!ImGui.CollapsingHeader("Design Details"))
return;
DrawDesignInfoTable();
DrawDescription();
ImGui.NewLine();
}
private void DrawDesignInfoTable()
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
using var table = ImRaii.Table("Details", 2);
if (!table)
return;
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Last Update Datem").X);
ImGui.TableSetupColumn("Data", ImGuiTableColumnFlags.WidthStretch);
ImGuiUtil.DrawFrameColumn("Design Name");
ImGui.TableNextColumn();
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
var name = _newName ?? _selector.Selected!.Name;
ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Name", ref name, 128))
_newName = name;
if (ImGui.IsItemDeactivatedAfterEdit())
{
_manager.Rename(_selector.Selected!, name);
_newName = null;
}
var identifier = _selector.Selected!.Identifier.ToString();
ImGuiUtil.DrawFrameColumn("Unique Identifier");
ImGui.TableNextColumn();
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
using (var mono = ImRaii.PushFont(UiBuilder.MonoFont))
{
if (ImGui.Button(identifier, width))
try
{
Process.Start(new ProcessStartInfo(fileName) { UseShellExecute = true });
}
catch (Exception ex)
{
Glamourer.Chat.NotificationMessage(ex, $"Could not open file {fileName}.", $"Could not open file {fileName}", "Failure",
NotificationType.Warning);
}
}
ImGuiUtil.HoverTooltip($"Open the file\n\t{fileName}\ncontaining this design in the .json-editor of your choice.");
ImGuiUtil.DrawFrameColumn("Full Selector Path");
ImGui.TableNextColumn();
var path = _newPath ?? _selector.SelectedLeaf!.FullName();
ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Path", ref path, 1024))
_newPath = path;
if (ImGui.IsItemDeactivatedAfterEdit())
try
{
_fileSystem.RenameAndMove(_selector.SelectedLeaf!, path);
_newPath = null;
}
catch (Exception ex)
{
Glamourer.Chat.NotificationMessage(ex, ex.Message, "Could not rename or move design", "Error", NotificationType.Error);
}
ImGuiUtil.DrawFrameColumn("Creation Date");
ImGui.TableNextColumn();
ImGuiUtil.DrawTextButton(_selector.Selected!.CreationDate.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Last Update Date");
ImGui.TableNextColumn();
ImGuiUtil.DrawTextButton(_selector.Selected!.LastEdit.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Tags");
ImGui.TableNextColumn();
DrawTags();
}
private void DrawTags()
{
var idx = _tagButtons.Draw(string.Empty, string.Empty, _selector.Selected!.Tags, out var editedTag);
if (idx < 0)
return;
if (idx < _selector.Selected!.Tags.Length)
{
if (editedTag.Length == 0)
_manager.RemoveTag(_selector.Selected!, idx);
else
_manager.RenameTag(_selector.Selected!, idx, editedTag);
}
else
{
_manager.AddTag(_selector.Selected!, editedTag);
}
}
private void DrawDescription()
{
var desc = _selector.Selected!.Description;
var size = new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeightWithSpacing());
if (!_editDescriptionMode)
{
using (var textBox = ImRaii.ListBox("##desc", size))
{
ImGuiUtil.TextWrapped(desc);
}
if (ImGui.Button("Edit Description"))
_editDescriptionMode = true;
}
else
{
var edit = _newDescription ?? desc;
if (ImGui.InputTextMultiline("##desc", ref edit, (uint)Math.Max(2000, 4 * edit.Length), size))
_newDescription = edit;
if (ImGui.IsItemDeactivatedAfterEdit())
{
_manager.ChangeDescription(_selector.Selected!, edit);
_newDescription = null;
}
if (ImGui.Button("Stop Editing"))
_editDescriptionMode = false;
}
}
}

View file

@ -1,6 +1,9 @@
using System.Numerics;
using System;
using System.Collections.Generic;
using System.Numerics;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Designs;
using Glamourer.Events;
using ImGuiNET;
@ -13,9 +16,14 @@ namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class DesignFileSystemSelector : FileSystemSelector<Design, DesignFileSystemSelector.DesignState>
{
private readonly DesignManager _designManager;
private readonly DesignChanged _event;
private readonly Configuration _config;
private readonly DesignManager _designManager;
private readonly DesignChanged _event;
private readonly Configuration _config;
private readonly DesignConverter _converter;
private string? _clipboardText;
private Design? _cloneDesign = null;
private string _newName = string.Empty;
public bool IncognitoMode
{
@ -27,24 +35,37 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
}
}
public new DesignFileSystem.Leaf? SelectedLeaf
=> base.SelectedLeaf;
public struct DesignState
{ }
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, KeyState keyState, DesignChanged @event,
Configuration config)
Configuration config, DesignConverter converter)
: base(fileSystem, keyState)
{
_designManager = designManager;
_event = @event;
_config = config;
_converter = converter;
_event.Subscribe(OnDesignChange, DesignChanged.Priority.DesignFileSystemSelector);
AddButton(DeleteButton, 1000);
AddButton(NewDesignButton, 0);
AddButton(ImportDesignButton, 10);
AddButton(CloneDesignButton, 20);
AddButton(DeleteButton, 1000);
}
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 = IncognitoMode ? leaf.Value.Incognito : leaf.Name;
var name = IncognitoMode ? leaf.Value.Incognito : leaf.Value.Name.Text;
using var _ = ImRaii.TreeNode(name, flag);
}
@ -78,11 +99,51 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
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:
SetFilterDirty();
break;
}
}
private void NewDesignButton(Vector2 size)
{
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), size, "Create a new design with default configuration.", false,
true))
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
{
_clipboardText = ImGui.GetClipboardText();
ImGui.OpenPopup("##NewDesign");
}
catch
{
Glamourer.Chat.NotificationMessage("Could not import data from clipboard.", "Failure", NotificationType.Error);
}
}
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;
_cloneDesign = Selected!;
ImGui.OpenPopup("##NewDesign");
}
private void DeleteButton(Vector2 size)
{
var keys = _config.DeleteDesignModifier.IsActive();
@ -91,10 +152,40 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
: "Delete the currently selected design entirely from your drive.\n"
+ "This can not be undone.";
if (!keys)
tt += $"\nHold {_config.DeleteDesignModifier} while clicking to delete the mod.";
tt += $"\nHold {_config.DeleteDesignModifier} while clicking to delete the design.";
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, SelectedLeaf == null || !keys, true)
&& Selected != null)
_designManager.Delete(Selected);
}
private void DrawNewDesignPopup()
{
if (!ImGuiUtil.OpenNameField("##NewDesign", ref _newName))
return;
if (_clipboardText != null)
{
var design = _converter.FromBase64(_clipboardText, true, true);
if (design is Design d)
_designManager.CreateClone(d, _newName);
else if (design != null)
_designManager.CreateClone(design, _newName);
else
Glamourer.Chat.NotificationMessage("Could not create a design, clipboard did not contain valid design data.", "Failure",
NotificationType.Error);
_clipboardText = null;
}
else if (_cloneDesign != null)
{
_designManager.CreateClone(_cloneDesign, _newName);
_cloneDesign = null;
}
else
{
_designManager.CreateEmpty(_newName);
}
_newName = string.Empty;
}
}

View file

@ -1,10 +1,19 @@
using System.Numerics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Glamourer.Automation;
using Glamourer.Customization;
using Glamourer.Designs;
using Glamourer.Gui.Customization;
using Glamourer.Gui.Equipment;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Services;
using Glamourer.State;
using Glamourer.Structs;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
@ -20,93 +29,334 @@ public class DesignPanel
private readonly CustomizationDrawer _customizationDrawer;
private readonly StateManager _state;
private readonly EquipmentDrawer _equipmentDrawer;
private readonly CustomizationService _customizationService;
private readonly ModAssociationsTab _modAssociations;
private readonly DesignDetailTab _designDetails;
private readonly DesignConverter _converter;
public DesignPanel(DesignFileSystemSelector selector, CustomizationDrawer customizationDrawer, DesignManager manager, ObjectManager objects,
StateManager state, EquipmentDrawer equipmentDrawer)
StateManager state, EquipmentDrawer equipmentDrawer, CustomizationService customizationService, PenumbraService penumbra,
ModAssociationsTab modAssociations, DesignDetailTab designDetails, DesignConverter converter)
{
_selector = selector;
_customizationDrawer = customizationDrawer;
_manager = manager;
_objects = objects;
_state = state;
_equipmentDrawer = equipmentDrawer;
_selector = selector;
_customizationDrawer = customizationDrawer;
_manager = manager;
_objects = objects;
_state = state;
_equipmentDrawer = equipmentDrawer;
_customizationService = customizationService;
_modAssociations = modAssociations;
_designDetails = designDetails;
_converter = converter;
}
private void DrawHeader()
{
var selection = _selector.Selected;
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
var frameHeight = ImGui.GetFrameHeightWithSpacing();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGuiUtil.DrawTextButton(SelectionName, new Vector2(-frameHeight, ImGui.GetFrameHeight()), buttonColor);
ImGuiUtil.DrawTextButton(SelectionName, new Vector2(selection != null ? -2 * frameHeight : -frameHeight, ImGui.GetFrameHeight()),
buttonColor);
ImGui.SameLine();
style.Push(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
using var color = ImRaii.PushColor(ImGuiCol.Text, ColorId.FolderExpanded.Value())
.Push(ImGuiCol.Border, ColorId.FolderExpanded.Value());
using var color = ImRaii.PushColor(ImGuiCol.Border, ColorId.HeaderButtons.Value())
.Push(ImGuiCol.Text, ColorId.HeaderButtons.Value());
var hoverText = string.Empty;
if (selection != null)
{
if (ImGuiUtil.DrawDisabledButton(
$"{(selection.WriteProtected() ? FontAwesomeIcon.LockOpen : FontAwesomeIcon.Lock).ToIconString()}###Locked",
new Vector2(frameHeight, ImGui.GetFrameHeight()), string.Empty, false, true))
_manager.SetWriteProtection(selection, !selection.WriteProtected());
if (ImGui.IsItemHovered())
hoverText = selection.WriteProtected() ? "Make this design editable." : "Write-protect this design.";
}
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton(
$"{(_selector.IncognitoMode ? FontAwesomeIcon.Eye : FontAwesomeIcon.EyeSlash).ToIconString()}###IncognitoMode",
new Vector2(frameHeight, ImGui.GetFrameHeight()), string.Empty, false, true))
_selector.IncognitoMode = !_selector.IncognitoMode;
var hovered = ImGui.IsItemHovered();
color.Pop(2);
if (hovered)
ImGui.SetTooltip(_selector.IncognitoMode ? "Toggle incognito mode off." : "Toggle incognito mode on.");
if (ImGui.IsItemHovered())
hoverText = _selector.IncognitoMode ? "Toggle incognito mode off." : "Toggle incognito mode on.";
if (hoverText.Length > 0)
ImGui.SetTooltip(hoverText);
}
private string SelectionName
=> _selector.Selected == null ? "No Selection" : _selector.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
private void DrawMetaData()
{
if (!ImGui.CollapsingHeader("MetaData"))
return;
using (var group1 = ImRaii.Group())
{
var apply = _selector.Selected!.DesignData.IsHatVisible();
if (ImGui.Checkbox("Hat Visible", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.HatState, apply);
apply = _selector.Selected.DesignData.IsWeaponVisible();
if (ImGui.Checkbox("Weapon Visible", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.WeaponState, apply);
}
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
using (var group2 = ImRaii.Group())
{
var apply = _selector.Selected.DesignData.IsVisorToggled();
if (ImGui.Checkbox("Visor Toggled", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.VisorState, apply);
apply = _selector.Selected.DesignData.IsWet();
if (ImGui.Checkbox("Force Wetness", ref apply))
_manager.ChangeMeta(_selector.Selected, ActorState.MetaIndex.Wetness, apply);
}
}
private void DrawEquipment()
{
if (!ImGui.CollapsingHeader("Equipment"))
return;
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var stain = _selector.Selected!.DesignData.Stain(slot);
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
_manager.ChangeStain(_selector.Selected!, slot, newStain.RowIndex);
ImGui.SameLine();
var armor = _selector.Selected!.DesignData.Item(slot);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _selector.Selected!.DesignData.Customize.Gender,
_selector.Selected!.DesignData.Customize.Race))
_manager.ChangeEquip(_selector.Selected!, slot, newArmor);
}
var mhStain = _selector.Selected!.DesignData.Stain(EquipSlot.MainHand);
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
_manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain.RowIndex);
ImGui.SameLine();
var mh = _selector.Selected!.DesignData.Item(EquipSlot.MainHand);
if (_equipmentDrawer.DrawMainhand(mh, true, out var newMh))
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.MainHand, newMh);
if (newMh.Type.Offhand() is not FullEquipType.Unknown)
{
var ohStain = _selector.Selected!.DesignData.Stain(EquipSlot.OffHand);
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
_manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain.RowIndex);
ImGui.SameLine();
var oh = _selector.Selected!.DesignData.Item(EquipSlot.OffHand);
if (_equipmentDrawer.DrawMainhand(oh, false, out var newOh))
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.OffHand, newOh);
}
}
private void DrawCustomize()
{
if (ImGui.CollapsingHeader("Customization"))
_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected!.WriteProtected());
}
private void DrawApplicationRules()
{
if (!ImGui.CollapsingHeader("Application Rules"))
return;
using (var group1 = ImRaii.Group())
{
var set = _customizationService.AwaitedService.GetList(_selector.Selected!.DesignData.Customize.Clan,
_selector.Selected!.DesignData.Customize.Gender);
var all = CustomizationExtensions.All.Where(set.IsAvailable).Select(c => c.ToFlag()).Aggregate((a, b) => a | b);
var flags = (_selector.Selected!.ApplyCustomize & all) == 0 ? 0 : (_selector.Selected!.ApplyCustomize & all) == all ? 3 : 1;
if (ImGui.CheckboxFlags("Apply All Customizations", ref flags, 3))
{
var newFlags = flags == 3;
foreach (var index in CustomizationExtensions.All)
_manager.ChangeApplyCustomize(_selector.Selected!, index, newFlags);
}
var applyClan = _selector.Selected!.DoApplyCustomize(CustomizeIndex.Clan);
if (ImGui.Checkbox($"Apply {CustomizeIndex.Clan.ToDefaultName()}", ref applyClan))
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, applyClan);
var applyGender = _selector.Selected!.DoApplyCustomize(CustomizeIndex.Gender);
if (ImGui.Checkbox($"Apply {CustomizeIndex.Gender.ToDefaultName()}", ref applyGender))
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, applyGender);
foreach (var index in CustomizationExtensions.All.Where(set.IsAvailable))
{
var apply = _selector.Selected!.DoApplyCustomize(index);
if (ImGui.Checkbox($"Apply {index.ToDefaultName()}", ref apply))
_manager.ChangeApplyCustomize(_selector.Selected!, index, apply);
}
}
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
using (var group2 = ImRaii.Group())
{
void ApplyEquip(string label, EquipFlag all, bool stain, IEnumerable<EquipSlot> slots)
{
var flags = (uint)(all & _selector.Selected!.ApplyEquip);
var bigChange = ImGui.CheckboxFlags($"Apply All {label}", ref flags, (uint)all);
if (stain)
foreach (var slot in slots)
{
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToStainFlag()) : _selector.Selected!.DoApplyStain(slot);
if (ImGui.Checkbox($"Apply {slot.ToName()} Dye", ref apply) || bigChange)
_manager.ChangeApplyStain(_selector.Selected!, slot, apply);
}
else
foreach (var slot in slots)
{
var apply = bigChange ? ((EquipFlag)flags).HasFlag(slot.ToFlag()) : _selector.Selected!.DoApplyEquip(slot);
if (ImGui.Checkbox($"Apply {slot.ToName()}", ref apply) || bigChange)
_manager.ChangeApplyEquip(_selector.Selected!, slot, apply);
}
}
ApplyEquip("Weapons", AutoDesign.WeaponFlags, false, new[]
{
EquipSlot.MainHand,
EquipSlot.OffHand,
});
ImGui.NewLine();
ApplyEquip("Armor", AutoDesign.ArmorFlags, false, EquipSlotExtensions.EquipmentSlots);
ImGui.NewLine();
ApplyEquip("Accessories", AutoDesign.AccessoryFlags, false, EquipSlotExtensions.AccessorySlots);
ImGui.NewLine();
ApplyEquip("Dyes", AutoDesign.StainFlags, true,
EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.MainHand).Prepend(EquipSlot.OffHand));
ImGui.NewLine();
const uint all = 0x0Fu;
var flags = (_selector.Selected!.DoApplyHatVisible() ? 0x01u : 0x00)
| (_selector.Selected!.DoApplyVisorToggle() ? 0x02u : 0x00)
| (_selector.Selected!.DoApplyWeaponVisible() ? 0x04u : 0x00)
| (_selector.Selected!.DoApplyWetness() ? 0x08u : 0x00);
var bigChange = ImGui.CheckboxFlags("Apply All Meta Changes", ref flags, all);
var apply = bigChange ? (flags & 0x01) == 0x01 : _selector.Selected!.DoApplyHatVisible();
if (ImGui.Checkbox("Apply Hat Visibility", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.HatState, apply);
apply = bigChange ? (flags & 0x02) == 0x02 : _selector.Selected!.DoApplyVisorToggle();
if (ImGui.Checkbox("Apply Visor State", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.VisorState, apply);
apply = bigChange ? (flags & 0x04) == 0x04 : _selector.Selected!.DoApplyWeaponVisible();
if (ImGui.Checkbox("Apply Weapon Visibility", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.WeaponState, apply);
apply = bigChange ? (flags & 0x08) == 0x08 : _selector.Selected!.DoApplyWetness();
if (ImGui.Checkbox("Apply Wetness", ref apply) || bigChange)
_manager.ChangeApplyMeta(_selector.Selected!, ActorState.MetaIndex.Wetness, apply);
}
}
public void Draw()
{
using var group = ImRaii.Group();
using var group = ImRaii.Group();
DrawHeader();
var design = _selector.Selected;
using var child = ImRaii.Child("##Panel", -Vector2.One, true);
if (!child || design == null)
return;
if (ImGui.Button("TEST"))
{
var (id, data) = _objects.PlayerData;
if (data.Valid && _state.GetOrCreate(id, data.Objects[0], out var state))
_state.ApplyDesign(design, state);
}
_customizationDrawer.Draw(design.DesignData.Customize, design.WriteProtected());
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var stain = design.DesignData.Stain(slot);
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
_manager.ChangeStain(design, slot, newStain.RowIndex);
ImGui.SameLine();
var armor = design.DesignData.Item(slot);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, design.DesignData.Customize.Gender, design.DesignData.Customize.Race))
_manager.ChangeEquip(design, slot, newArmor);
}
var mhStain = design.DesignData.Stain(EquipSlot.MainHand);
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
_manager.ChangeStain(design, EquipSlot.MainHand, newMhStain.RowIndex);
DrawButtonRow();
DrawMetaData();
DrawCustomize();
DrawEquipment();
_designDetails.Draw();
DrawApplicationRules();
_modAssociations.Draw();
}
private void DrawButtonRow()
{
DrawSetFromClipboard();
ImGui.SameLine();
var mh = design.DesignData.Item(EquipSlot.MainHand);
if (_equipmentDrawer.DrawMainhand(mh, true, out var newMh))
_manager.ChangeWeapon(design, EquipSlot.MainHand, newMh);
DrawExportToClipboard();
ImGui.SameLine();
DrawApplyToSelf();
ImGui.SameLine();
DrawApplyToTarget();
}
if (newMh.Type.Offhand() is not FullEquipType.Unknown)
private void DrawSetFromClipboard()
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Try to apply a design from your clipboard.", _selector.Selected!.WriteProtected(), true))
return;
try
{
var ohStain = design.DesignData.Stain(EquipSlot.OffHand);
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
_manager.ChangeStain(design, EquipSlot.OffHand, newOhStain.RowIndex);
ImGui.SameLine();
var oh = design.DesignData.Item(EquipSlot.OffHand);
if (_equipmentDrawer.DrawMainhand(oh, false, out var newOh))
_manager.ChangeWeapon(design, EquipSlot.OffHand, newOh);
var text = ImGui.GetClipboardText();
var design = _converter.FromBase64(text, true, true) ?? throw new Exception("The clipboard did not contain valid data.");
_manager.ApplyDesign(_selector.Selected!, design);
}
catch (Exception ex)
{
Glamourer.Chat.NotificationMessage(ex, $"Could not apply clipboard to {_selector.Selected!.Name}.",
$"Could not apply clipboard to design {_selector.Selected!.Identifier}", "Failure", NotificationType.Error);
}
}
private void DrawExportToClipboard()
{
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Copy.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Copy the current design to your clipboard.", false, true))
return;
try
{
var text = _converter.ShareBase64(_selector.Selected!);
ImGui.SetClipboardText(text);
}
catch (Exception ex)
{
Glamourer.Chat.NotificationMessage(ex, $"Could not copy {_selector.Selected!.Name} data to clipboard.",
$"Could not copy data from design {_selector.Selected!.Identifier} to clipboard", "Failure", NotificationType.Error);
}
}
private void DrawApplyToSelf()
{
var (id, data) = _objects.PlayerData;
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero, "Apply the current design with its settings to your character.",
!data.Valid))
return;
if (_state.GetOrCreate(id, data.Objects[0], out var state))
_state.ApplyDesign(_selector.Selected!, state);
}
private void DrawApplyToTarget()
{
var (id, data) = _objects.TargetData;
var tt = id.IsValid
? data.Valid
? "Apply the current design with its settings to your current target."
: "The current target can not be manipulated."
: "No valid target selected.";
if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid))
return;
if (_state.GetOrCreate(id, data.Objects[0], out var state))
_state.ApplyDesign(_selector.Selected!, state);
}
}

View file

@ -0,0 +1,144 @@
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Utility;
using Glamourer.Designs;
using Glamourer.Interop.Penumbra;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui.Tabs.DesignTab;
public class ModAssociationsTab
{
private readonly PenumbraService _penumbra;
private readonly DesignFileSystemSelector _selector;
private readonly DesignManager _manager;
private readonly ModCombo _modCombo;
public ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelector selector, DesignManager manager)
{
_penumbra = penumbra;
_selector = selector;
_manager = manager;
_modCombo = new ModCombo(penumbra);
}
public void Draw()
{
if (!ImGui.CollapsingHeader("Mod Associations"))
return;
DrawApplyAllButton();
DrawTable();
}
private void DrawApplyAllButton()
{
var current = _penumbra.CurrentCollection;
if (!ImGuiUtil.DrawDisabledButton($"Try Applying All Associated Mods to {current}##applyAll",
new Vector2(ImGui.GetContentRegionAvail().X, 0), string.Empty, current is "<Unavailable>"))
return;
foreach (var (mod, settings) in _selector.Selected!.AssociatedMods)
_penumbra.SetMod(mod, settings);
}
private void DrawTable()
{
using var table = ImRaii.Table("Mods", 6, ImGuiTableFlags.RowBg);
if (!table)
return;
ImGui.TableSetupColumn("##Delete", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight());
ImGui.TableSetupColumn("Mod Name", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Directory Name", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("State", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("State").X);
ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Priority").X);
ImGui.TableSetupColumn("##Options", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Try Applyingm").X);
ImGui.TableHeadersRow();
Mod? removedMod = null;
foreach (var ((mod, settings), idx) in _selector.Selected!.AssociatedMods.WithIndex())
{
using var id = ImRaii.PushId(idx);
DrawAssociatedModRow(mod, settings, out removedMod);
}
DrawNewModRow();
if (removedMod.HasValue)
_manager.RemoveMod(_selector.Selected!, removedMod.Value);
}
private void DrawAssociatedModRow(Mod mod, ModSettings settings, out Mod? removedMod)
{
removedMod = null;
ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Delete this mod from associations", false, true))
removedMod = mod;
ImGuiUtil.DrawTableColumn(mod.Name);
ImGuiUtil.DrawTableColumn(mod.DirectoryName);
ImGui.TableNextColumn();
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
{
ImGuiUtil.DrawTextButton((settings.Enabled ? FontAwesomeIcon.Check : FontAwesomeIcon.Cross).ToIconString(),
new Vector2(ImGui.GetContentRegionAvail().X, 0), 0);
}
ImGui.TableNextColumn();
ImGuiUtil.RightAlign(settings.Priority.ToString());
ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton("Try Applying", new Vector2(ImGui.GetContentRegionAvail().X, 0), string.Empty,
!_penumbra.Available))
{
var text = _penumbra.SetMod(mod, settings);
if (text.Length > 0)
Glamourer.Chat.NotificationMessage(text, "Failure", NotificationType.Warning);
}
DrawAssociatedModTooltip(settings);
}
private static void DrawAssociatedModTooltip(ModSettings settings)
{
if (settings is not { Enabled: true, Settings.Count: > 0 } || !ImGui.IsItemHovered())
return;
using var t = ImRaii.Tooltip();
ImGui.TextUnformatted("This will also try to apply the following settings to the current collection:");
ImGui.NewLine();
using (var _ = ImRaii.Group())
{
ModCombo.DrawSettingsLeft(settings);
}
ImGui.SameLine(ImGui.GetContentRegionAvail().X / 2);
using (var _ = ImRaii.Group())
{
ModCombo.DrawSettingsRight(settings);
}
}
private void DrawNewModRow()
{
var currentName = _modCombo.CurrentSelection.Mod.Name;
ImGui.TableNextColumn();
var tt = currentName.IsNullOrEmpty()
? "Please select a mod first."
: _selector.Selected!.AssociatedMods.ContainsKey(_modCombo.CurrentSelection.Mod)
? "The design already contains an association with the selected mod."
: string.Empty;
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), new Vector2(ImGui.GetFrameHeight()), tt, tt.Length > 0,
true))
_manager.AddMod(_selector.Selected!, _modCombo.CurrentSelection.Mod, _modCombo.CurrentSelection.Settings);
ImGui.TableNextColumn();
_modCombo.Draw("##new", currentName.IsNullOrEmpty() ? "Select new Mod..." : currentName, string.Empty,
200 * ImGuiHelpers.GlobalScale, ImGui.GetTextLineHeight());
}
}

View file

@ -0,0 +1,85 @@
using System;
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Interop.Penumbra;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class ModCombo : FilterComboCache<(Mod Mod, ModSettings Settings)>
{
public ModCombo(PenumbraService penumbra)
: base(penumbra.GetMods)
{ }
protected override string ToString((Mod Mod, ModSettings Settings) obj)
=> obj.Mod.Name;
protected override bool IsVisible(int globalIndex, LowerString filter)
=> filter.IsContained(Items[globalIndex].Mod.Name) || filter.IsContained(Items[globalIndex].Mod.DirectoryName);
protected override bool DrawSelectable(int globalIdx, bool selected)
{
using var id = ImRaii.PushId(globalIdx);
var (mod, settings) = Items[globalIdx];
bool ret;
using (var color = ImRaii.PushColor(ImGuiCol.Text, ImGui.GetColorU32(ImGuiCol.TextDisabled), !settings.Enabled))
{
ret = ImGui.Selectable(mod.Name, selected);
}
if (ImGui.IsItemHovered())
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.PopupBorderSize, 2 * ImGuiHelpers.GlobalScale);
using var tt = ImRaii.Tooltip();
var namesDifferent = mod.Name != mod.DirectoryName;
ImGui.Dummy(new Vector2(300 * ImGuiHelpers.GlobalScale, 0));
using (var group = ImRaii.Group())
{
if (namesDifferent)
ImGui.TextUnformatted("Directory Name");
ImGui.TextUnformatted("Enabled");
ImGui.TextUnformatted("Priority");
DrawSettingsLeft(settings);
}
ImGui.SameLine(Math.Max(ImGui.GetItemRectSize().X + 3 * ImGui.GetStyle().ItemSpacing.X, 150 * ImGuiHelpers.GlobalScale));
using (var group = ImRaii.Group())
{
if (namesDifferent)
ImGui.TextUnformatted(mod.DirectoryName);
ImGui.TextUnformatted(settings.Enabled.ToString());
ImGui.TextUnformatted(settings.Priority.ToString());
DrawSettingsRight(settings);
}
}
return ret;
}
public static void DrawSettingsLeft(ModSettings settings)
{
foreach (var setting in settings.Settings)
{
ImGui.TextUnformatted(setting.Key);
for (var i = 1; i < setting.Value.Count; ++i)
ImGui.NewLine();
}
}
public static void DrawSettingsRight(ModSettings settings)
{
foreach (var setting in settings.Settings)
{
if (setting.Value.Count == 0)
ImGui.TextUnformatted("<None Enabled>");
else
foreach (var option in setting.Value)
ImGui.TextUnformatted(option);
}
}
}

View file

@ -42,7 +42,6 @@ public class UnlockOverview
if (ImGui.Selectable(type.ToName(), _selected1 == type))
{
ClearIcons(_selected1);
_selected1 = type;
_selected2 = SubRace.Unknown;
_selected3 = Gender.Unknown;
@ -59,7 +58,6 @@ public class UnlockOverview
if (ImGui.Selectable($"{(gender is Gender.Male ? '♂' : '♀')} {clan.ToShortName()} Hair & Paint",
_selected2 == clan && _selected3 == gender))
{
ClearIcons(_selected1);
_selected1 = FullEquipType.Unknown;
_selected2 = clan;
_selected3 = gender;
@ -68,15 +66,6 @@ public class UnlockOverview
}
}
private void ClearIcons(FullEquipType type)
{
if (!_items.ItemService.AwaitedService.TryGetValue(type, out var items))
return;
foreach (var item in items)
_customizations.AwaitedService.RemoveIcon(item.IconId);
}
public UnlockOverview(ItemManager items, CustomizationService customizations, ItemUnlockManager itemUnlocks,
CustomizeUnlockManager customizeUnlocks, PenumbraChangedItemTooltip tooltip, TextureCache textureCache)
{