From 60a53d4bff0a7e60041fe6f85824785e47b86bd7 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 25 Nov 2023 21:05:06 +0100 Subject: [PATCH] Refactor drawing of equipment to be more sane. --- .../CustomizationDrawer.Simple.cs | 6 +- .../Gui/Customization/CustomizationDrawer.cs | 47 +- Glamourer/Gui/Equipment/EquipDrawData.cs | 49 + Glamourer/Gui/Equipment/EquipmentDrawer.cs | 916 +++++++----------- Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs | 100 +- Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs | 87 +- Glamourer/Gui/ToggleDrawData.cs | 79 ++ Glamourer/Gui/UiHelpers.cs | 13 +- OtterGui | 2 +- 9 files changed, 536 insertions(+), 763 deletions(-) create mode 100644 Glamourer/Gui/Equipment/EquipDrawData.cs create mode 100644 Glamourer/Gui/ToggleDrawData.cs diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs b/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs index 3e15cad..e9ce9e9 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.Simple.cs @@ -194,14 +194,14 @@ public partial class CustomizationDrawer { switch (UiHelpers.DrawMetaToggle(_currentIndex.ToDefaultName(), tmp, _currentApply, out var newValue, out var newApply, _locked)) { - case DataChange.Item: + case (true, false): _customize.Set(idx, newValue ? CustomizeValue.Max : CustomizeValue.Zero); Changed |= _currentFlag; break; - case DataChange.ApplyItem: + case (false, true): ChangeApply = newApply ? ChangeApply | _currentFlag : ChangeApply & ~_currentFlag; break; - case DataChange.Item | DataChange.ApplyItem: + case (true, true): ChangeApply = newApply ? ChangeApply | _currentFlag : ChangeApply & ~_currentFlag; _customize.Set(idx, newValue ? CustomizeValue.Max : CustomizeValue.Zero); Changed |= _currentFlag; diff --git a/Glamourer/Gui/Customization/CustomizationDrawer.cs b/Glamourer/Gui/Customization/CustomizationDrawer.cs index 0f76b62..fa725f5 100644 --- a/Glamourer/Gui/Customization/CustomizationDrawer.cs +++ b/Glamourer/Gui/Customization/CustomizationDrawer.cs @@ -14,18 +14,16 @@ using CustomizeData = Penumbra.GameData.Structs.CustomizeData; namespace Glamourer.Gui.Customization; -public partial class CustomizationDrawer : IDisposable +public partial class CustomizationDrawer(DalamudPluginInterface pi, CustomizationService _service, CodeService _codes, Configuration _config) + : IDisposable { - private readonly CodeService _codes; - private readonly Configuration _config; - - private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f); - private readonly IDalamudTextureWrap? _legacyTattoo; + private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f); + private readonly IDalamudTextureWrap? _legacyTattoo = GetLegacyTattooIcon(pi); private Exception? _terminate; - private Customize _customize; - private CustomizationSet _set = null!; + private Customize _customize = Customize.Default; + private CustomizationSet _set = null!; public Customize Customize => _customize; @@ -46,21 +44,8 @@ public partial class CustomizationDrawer : IDisposable private float _raceSelectorWidth; private bool _withApply; - private readonly CustomizationService _service; - - public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service, CodeService codes, Configuration config) - { - _service = service; - _codes = codes; - _config = config; - _legacyTattoo = GetLegacyTattooIcon(pi); - _customize = Customize.Default; - } - public void Dispose() - { - _legacyTattoo?.Dispose(); - } + => _legacyTattoo?.Dispose(); public bool Draw(Customize current, bool locked, bool lockedRedraw) { @@ -125,12 +110,6 @@ public partial class CustomizationDrawer : IDisposable Changed |= _currentFlag; } - public bool DrawWetnessState(bool currentValue, out bool newValue, bool locked) - => UiHelpers.DrawCheckbox("Force Wetness", "Force the character to be wet or not.", currentValue, out newValue, locked); - - public DataChange DrawWetnessState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked) - => UiHelpers.DrawMetaToggle("Force Wetness", currentValue, currentApply, out newValue, out newApply, locked); - private bool DrawInternal() { using var spacing = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _spacing); @@ -199,13 +178,13 @@ public partial class CustomizationDrawer : IDisposable private void UpdateSizes() { - _spacing = ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemInnerSpacing.X }; - _iconSize = new Vector2(ImGui.GetTextLineHeight() * 2 + _spacing.Y + 2 * ImGui.GetStyle().FramePadding.Y); - _framedIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding; - _inputIntSize = 2 * _framedIconSize.X + 1 * _spacing.X; + _spacing = ImGui.GetStyle().ItemSpacing with { X = ImGui.GetStyle().ItemInnerSpacing.X }; + _iconSize = new Vector2(ImGui.GetTextLineHeight() * 2 + _spacing.Y + 2 * ImGui.GetStyle().FramePadding.Y); + _framedIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding; + _inputIntSize = 2 * _framedIconSize.X + 1 * _spacing.X; _inputIntSizeNoButtons = _inputIntSize - 2 * _spacing.X - 2 * ImGui.GetFrameHeight(); - _comboSelectorSize = 4 * _framedIconSize.X + 3 * _spacing.X; - _raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X; + _comboSelectorSize = 4 * _framedIconSize.X + 3 * _spacing.X; + _raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X; } private static IDalamudTextureWrap? GetLegacyTattooIcon(DalamudPluginInterface pi) diff --git a/Glamourer/Gui/Equipment/EquipDrawData.cs b/Glamourer/Gui/Equipment/EquipDrawData.cs new file mode 100644 index 0000000..ce2ba04 --- /dev/null +++ b/Glamourer/Gui/Equipment/EquipDrawData.cs @@ -0,0 +1,49 @@ +using System; +using Glamourer.Designs; +using Glamourer.Events; +using Glamourer.State; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; + +namespace Glamourer.Gui.Equipment; + +public ref struct EquipDrawData(EquipSlot slot, in DesignData designData) +{ + public readonly EquipSlot Slot = slot; + public bool Locked; + public bool DisplayApplication; + + public Action ItemSetter = null!; + public Action StainSetter = null!; + public Action ApplySetter = null!; + public Action ApplyStainSetter = null!; + public EquipItem CurrentItem = designData.Item(slot); + public StainId CurrentStain = designData.Stain(slot); + public bool CurrentApply; + public bool CurrentApplyStain; + + public readonly Gender CurrentGender = designData.Customize.Gender; + public readonly Race CurrentRace = designData.Customize.Race; + + public static EquipDrawData FromDesign(DesignManager manager, Design design, EquipSlot slot) + => new(slot, design.DesignData) + { + ItemSetter = i => manager.ChangeEquip(design, slot, i), + StainSetter = i => manager.ChangeStain(design, slot, i), + ApplySetter = b => manager.ChangeApplyEquip(design, slot, b), + ApplyStainSetter = b => manager.ChangeApplyStain(design, slot, b), + CurrentApply = design.DoApplyEquip(slot), + CurrentApplyStain = design.DoApplyStain(slot), + Locked = design.WriteProtected(), + DisplayApplication = true, + }; + + public static EquipDrawData FromState(StateManager manager, ActorState state, EquipSlot slot) + => new(slot, state.ModelData) + { + ItemSetter = i => manager.ChangeItem(state, slot, i, StateChanged.Source.Manual), + StainSetter = i => manager.ChangeStain(state, slot, i, StateChanged.Source.Manual), + Locked = state.IsLocked, + DisplayApplication = false, + }; +} diff --git a/Glamourer/Gui/Equipment/EquipmentDrawer.cs b/Glamourer/Gui/Equipment/EquipmentDrawer.cs index ca78bea..e2b44de 100644 --- a/Glamourer/Gui/Equipment/EquipmentDrawer.cs +++ b/Glamourer/Gui/Equipment/EquipmentDrawer.cs @@ -6,10 +6,8 @@ using System.Numerics; using Dalamud.Interface.Components; using Dalamud.Interface.Utility; using Dalamud.Plugin.Services; -using Glamourer.Designs; using Glamourer.Events; using Glamourer.Services; -using Glamourer.Structs; using Glamourer.Unlocks; using ImGuiNET; using OtterGui; @@ -76,211 +74,71 @@ public class EquipmentDrawer _requiredComboWidth = _requiredComboWidthUnscaled * ImGuiHelpers.GlobalScale; } - private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race) + private bool VerifyRestrictedGear(EquipDrawData data) { - if (slot.IsAccessory()) + if (data.Slot.IsAccessory()) return false; - var (changed, _) = _items.ResolveRestrictedGear(gear.Armor(), slot, race, gender); + var (changed, _) = _items.ResolveRestrictedGear(data.CurrentItem.Armor(), data.Slot, data.CurrentRace, data.CurrentGender); return changed; } - - public DataChange DrawEquip(EquipSlot slot, in DesignData designData, out EquipItem rArmor, out StainId rStain, EquipFlag? cApply, - out bool rApply, out bool rApplyStain, bool locked) - => DrawEquip(slot, designData.Item(slot), out rArmor, designData.Stain(slot), out rStain, cApply, out rApply, out rApplyStain, locked, - designData.Customize.Gender, designData.Customize.Race); - - public DataChange DrawEquip(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, EquipFlag? cApply, - out bool rApply, out bool rApplyStain, bool locked, Gender gender = Gender.Unknown, Race race = Race.Unknown) + public void DrawEquip(EquipDrawData equipDrawData) { if (_config.HideApplyCheckmarks) - cApply = null; + equipDrawData.DisplayApplication = false; - using var id = ImRaii.PushId((int)slot); + using var id = ImRaii.PushId((int)equipDrawData.Slot); var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }; using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); if (_config.SmallEquip) - return DrawEquipSmall(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain, locked, gender, race); - - if (!locked && _codes.EnabledArtisan) - return DrawEquipArtisan(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain); - - return DrawEquipNormal(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain, locked, gender, race); + DrawEquipSmall(equipDrawData); + else if (!equipDrawData.Locked && _codes.EnabledArtisan) + DrawEquipArtisan(equipDrawData); + else + DrawEquipNormal(equipDrawData); } - public DataChange DrawWeapons(in DesignData designData, out EquipItem rMainhand, out EquipItem rOffhand, out StainId rMainhandStain, - out StainId rOffhandStain, EquipFlag? cApply, bool allWeapons, out bool rApplyMainhand, out bool rApplyMainhandStain, - out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked) - => DrawWeapons(designData.Item(EquipSlot.MainHand), out rMainhand, designData.Item(EquipSlot.OffHand), out rOffhand, - designData.Stain(EquipSlot.MainHand), out rMainhandStain, designData.Stain(EquipSlot.OffHand), out rOffhandStain, cApply, - allWeapons, out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked); - - private DataChange DrawWeapons(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand, - StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply, - bool allWeapons, out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, - bool locked) + public void DrawWeapons(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons) { - if (cMainhand.ModelId.Id == 0) - { - rOffhand = cOffhand; - rMainhand = cMainhand; - rMainhandStain = cMainhandStain; - rOffhandStain = cOffhandStain; - rApplyMainhand = false; - rApplyMainhandStain = false; - rApplyOffhand = false; - rApplyOffhandStain = false; - return DataChange.None; - } + if (mainhand.CurrentItem.ModelId.Id == 0) + return; if (_config.HideApplyCheckmarks) - cApply = null; + { + mainhand.DisplayApplication = false; + offhand.DisplayApplication = false; + } using var id = ImRaii.PushId("Weapons"); var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }; using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); if (_config.SmallEquip) - return DrawWeaponsSmall(cMainhand, out rMainhand, cOffhand, out rOffhand, cMainhandStain, out rMainhandStain, cOffhandStain, - out rOffhandStain, cApply, out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked, - allWeapons); - - if (!locked && _codes.EnabledArtisan) - return DrawWeaponsArtisan(cMainhand, out rMainhand, cOffhand, out rOffhand, cMainhandStain, out rMainhandStain, cOffhandStain, - out rOffhandStain, cApply, out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain); - - return DrawWeaponsNormal(cMainhand, out rMainhand, cOffhand, out rOffhand, cMainhandStain, out rMainhandStain, cOffhandStain, - out rOffhandStain, cApply, out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked, - allWeapons); + DrawWeaponsSmall(mainhand, offhand, allWeapons); + else if (!mainhand.Locked && _codes.EnabledArtisan) + DrawWeaponsArtisan(mainhand, offhand); + else + DrawWeaponsNormal(mainhand, offhand, allWeapons); } - public static bool DrawHatState(bool currentValue, out bool newValue, bool locked) - => UiHelpers.DrawCheckbox("Hat Visible", "Hide or show the characters head gear.", currentValue, out newValue, locked); - - public static DataChange DrawHatState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked) - => UiHelpers.DrawMetaToggle("Hat Visible", currentValue, currentApply, out newValue, out newApply, locked); - - public static bool DrawVisorState(bool currentValue, out bool newValue, bool locked) - => UiHelpers.DrawCheckbox("Visor Toggled", "Toggle the visor state of the characters head gear.", currentValue, out newValue, locked); - - public static DataChange DrawVisorState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked) - => UiHelpers.DrawMetaToggle("Visor Toggled", currentValue, currentApply, out newValue, out newApply, locked); - - public static bool DrawWeaponState(bool currentValue, out bool newValue, bool locked) - => UiHelpers.DrawCheckbox("Weapon Visible", "Hide or show the characters weapons when not drawn.", currentValue, out newValue, locked); - - public static DataChange DrawWeaponState(bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked) - => UiHelpers.DrawMetaToggle("Weapon Visible", currentValue, currentApply, out newValue, out newApply, locked); - - private bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon, out string label, bool locked, bool small, bool open) + public static void DrawMetaToggle(in ToggleDrawData data) { - weapon = current; - if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo)) + if (data.DisplayApplication) { - label = string.Empty; - return false; + var (valueChanged, applyChanged) = UiHelpers.DrawMetaToggle(data.Label, data.CurrentValue, data.CurrentApply, out var newValue, + out var newApply, data.Locked); + if (valueChanged) + data.SetValue(newValue); + if (applyChanged) + data.SetApply(newApply); } - - label = combo.Label; - - var unknown = !_gPose.InGPose && current.Type is FullEquipType.Unknown; - var ret = false; - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemInnerSpacing); - using (var disabled = ImRaii.Disabled(locked | unknown)) + else { - if (!locked && open) - UiHelpers.OpenCombo($"##{label}"); - if (combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth)) - { - ret = true; - weapon = combo.CurrentSelection; - } + if (UiHelpers.DrawCheckbox(data.Label, data.Tooltip, data.CurrentValue, out var newValue, data.Locked)) + data.SetValue(newValue); } - - if (unknown && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) - ImGui.SetTooltip("The weapon type could not be identified, thus changing it to other weapons of that type is not possible."); - - return ret; - } - - private bool DrawOffhand(EquipItem mainhand, EquipItem current, out EquipItem weapon, out string label, bool locked, bool small, bool clear, - bool open) - { - weapon = current; - if (!_weaponCombo.TryGetValue(current.Type, out var combo)) - { - label = string.Empty; - return false; - } - - label = combo.Label; - locked |= !_gPose.InGPose && (current.Type is FullEquipType.Unknown || mainhand.Type is FullEquipType.Unknown); - using var disabled = ImRaii.Disabled(locked); - if (!locked && open) - UiHelpers.OpenCombo($"##{combo.Label}"); - var change = combo.Draw(weapon.Name, weapon.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth); - if (change) - weapon = combo.CurrentSelection; - - if (!locked) - { - var defaultOffhand = _items.GetDefaultOffhand(mainhand); - if (defaultOffhand.Id != weapon.Id) - { - ImGuiUtil.HoverTooltip("Right-click to set to Default."); - if (clear || ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - change = true; - weapon = defaultOffhand; - } - } - } - - return change; - } - - private bool DrawApply(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked) - => UiHelpers.DrawCheckbox($"##apply{slot}", "Apply this item when applying the Design.", flags.HasFlag(slot.ToFlag()), out enabled, - locked); - - private bool DrawApplyStain(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked) - => UiHelpers.DrawCheckbox($"##applyStain{slot}", "Apply this dye when applying the Design.", flags.HasFlag(slot.ToStainFlag()), - out enabled, locked); - - private bool DrawItem(EquipSlot slot, EquipItem current, out EquipItem armor, out string label, bool locked, bool small, bool clear, - bool open) - { - Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawItem)} on {slot}."); - var combo = _itemCombo[slot.ToIndex()]; - label = combo.Label; - armor = current; - if (!locked && open) - UiHelpers.OpenCombo($"##{combo.Label}"); - - using var disabled = ImRaii.Disabled(locked); - var change = combo.Draw(armor.Name, armor.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, _requiredComboWidth); - if (change) - armor = combo.CurrentSelection; - else if (combo.CustomVariant.Id > 0) - { - armor = _items.Identify(slot, combo.CustomSetId, combo.CustomVariant); - change = true; - } - - if (!locked && armor.ModelId.Id != 0) - { - if (clear || ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - change = true; - armor = ItemManager.NothingItem(slot); - } - - ImGuiUtil.HoverTooltip("Right-click to clear."); - } - - return change; } public bool DrawAllStain(out StainId ret, bool locked) @@ -308,50 +166,97 @@ public class EquipmentDrawer return change; } - private bool DrawStain(EquipSlot slot, StainId current, out StainId ret, bool locked, bool small) + #region Artisan + + private void DrawEquipArtisan(EquipDrawData data) { - var found = _stainData.TryGetValue(current, out var stain); - using var disabled = ImRaii.Disabled(locked); - var change = small - ? _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss) - : _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength); - ret = current; - if (change) - if (_stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain)) - ret = stain.RowIndex; - else if (_stainCombo.CurrentSelection.Key == Stain.None.RowIndex) - ret = Stain.None.RowIndex; + DrawStainArtisan(data); + ImGui.SameLine(); + DrawArmorArtisan(data); + if (!data.DisplayApplication) + return; - if (!locked && ret != Stain.None.RowIndex) + ImGui.SameLine(); + DrawApply(data); + ImGui.SameLine(); + DrawApplyStain(data); + } + + private void DrawWeaponsArtisan(in EquipDrawData mainhand, in EquipDrawData offhand) + { + using (var _ = ImRaii.PushId(0)) { - if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - ret = Stain.None.RowIndex; - change = true; - } - - ImGuiUtil.HoverTooltip("Right-click to clear."); + DrawStainArtisan(mainhand); + ImGui.SameLine(); + DrawWeapon(mainhand); } - return change; + using (var _ = ImRaii.PushId(1)) + { + DrawStainArtisan(offhand); + ImGui.SameLine(); + DrawWeapon(offhand); + } + + return; + + void DrawWeapon(in EquipDrawData current) + { + int setId = current.CurrentItem.ModelId.Id; + int type = current.CurrentItem.WeaponType.Id; + int variant = current.CurrentItem.Variant.Id; + ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("##setId", ref setId, 0, 0)) + { + var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue); + if (newSetId.Id != current.CurrentItem.ModelId.Id) + current.ItemSetter(_items.Identify(current.Slot, newSetId, current.CurrentItem.WeaponType, current.CurrentItem.Variant)); + } + + ImGui.SameLine(); + ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("##type", ref type, 0, 0)) + { + var newType = (WeaponType)Math.Clamp(type, 0, ushort.MaxValue); + if (newType.Id != current.CurrentItem.WeaponType.Id) + current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.ModelId, newType, current.CurrentItem.Variant)); + } + + ImGui.SameLine(); + ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); + if (ImGui.InputInt("##variant", ref variant, 0, 0)) + { + var newVariant = (Variant)Math.Clamp(variant, 0, byte.MaxValue); + if (newVariant.Id != current.CurrentItem.Variant.Id) + current.ItemSetter(_items.Identify(current.Slot, current.CurrentItem.ModelId, current.CurrentItem.WeaponType, newVariant)); + } + } + } + + /// Draw an input for stain that can set arbitrary values instead of choosing valid stains. + private static void DrawStainArtisan(EquipDrawData data) + { + int stainId = data.CurrentStain.Id; + ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); + if (!ImGui.InputInt("##stain", ref stainId, 0, 0)) + return; + + var newStainId = (StainId)Math.Clamp(stainId, 0, byte.MaxValue); + if (newStainId != data.CurrentStain.Id) + data.StainSetter(newStainId); } /// Draw an input for armor that can set arbitrary values instead of choosing items. - private bool DrawArmorArtisan(EquipSlot slot, EquipItem current, out EquipItem armor) + private void DrawArmorArtisan(EquipDrawData data) { - int setId = current.ModelId.Id; - int variant = current.Variant.Id; - var ret = false; - armor = current; + int setId = data.CurrentItem.ModelId.Id; + int variant = data.CurrentItem.Variant.Id; ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); if (ImGui.InputInt("##setId", ref setId, 0, 0)) { var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue); - if (newSetId.Id != current.ModelId.Id) - { - armor = _items.Identify(slot, newSetId, current.Variant); - ret = true; - } + if (newSetId.Id != data.CurrentItem.ModelId.Id) + data.ItemSetter(_items.Identify(data.Slot, newSetId, data.CurrentItem.Variant)); } ImGui.SameLine(); @@ -359,141 +264,286 @@ public class EquipmentDrawer if (ImGui.InputInt("##variant", ref variant, 0, 0)) { var newVariant = (byte)Math.Clamp(variant, 0, byte.MaxValue); - if (newVariant != current.Variant) - { - armor = _items.Identify(slot, current.ModelId, newVariant); - ret = true; - } + if (newVariant != data.CurrentItem.Variant) + data.ItemSetter(_items.Identify(data.Slot, data.CurrentItem.ModelId, newVariant)); } - - return ret; } - /// Draw an input for stain that can set arbitrary values instead of choosing valid stains. - private bool DrawStainArtisan(EquipSlot slot, StainId current, out StainId stain) - { - int stainId = current.Id; - ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("##stain", ref stainId, 0, 0)) - { - var newStainId = (StainId)Math.Clamp(stainId, 0, byte.MaxValue); - if (newStainId != current) - { - stain = newStainId; - return true; - } - } + #endregion - stain = current; - return false; - } + #region Small - private DataChange DrawEquipArtisan(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, - EquipFlag? cApply, out bool rApply, out bool rApplyStain) + private void DrawEquipSmall(in EquipDrawData equipDrawData) { - var changes = DataChange.None; - if (DrawStainArtisan(slot, cStain, out rStain)) - changes |= DataChange.Stain; + DrawStain(equipDrawData, true); ImGui.SameLine(); - if (DrawArmorArtisan(slot, cArmor, out rArmor)) - changes |= DataChange.Item; - if (cApply.HasValue) + DrawItem(equipDrawData, out var label, true, false, false); + if (equipDrawData.DisplayApplication) { ImGui.SameLine(); - if (DrawApply(slot, cApply.Value, out rApply, false)) - changes |= DataChange.ApplyItem; + DrawApply(equipDrawData); ImGui.SameLine(); - if (DrawApplyStain(slot, cApply.Value, out rApplyStain, false)) - changes |= DataChange.ApplyStain; - } - else - { - rApply = false; - rApplyStain = false; + DrawApplyStain(equipDrawData); } - return changes; - } - - private DataChange DrawEquipSmall(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, - EquipFlag? cApply, out bool rApply, out bool rApplyStain, bool locked, Gender gender, Race race) - { - var changes = DataChange.None; - if (DrawStain(slot, cStain, out rStain, locked, true)) - changes |= DataChange.Stain; - ImGui.SameLine(); - if (DrawItem(slot, cArmor, out rArmor, out var label, locked, true, false, false)) - changes |= DataChange.Item; - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApply(slot, cApply.Value, out rApply, false)) - changes |= DataChange.ApplyItem; - ImGui.SameLine(); - if (DrawApplyStain(slot, cApply.Value, out rApplyStain, false)) - changes |= DataChange.ApplyStain; - } - else - { - rApply = false; - rApplyStain = false; - } - - if (VerifyRestrictedGear(slot, rArmor, gender, race)) + if (VerifyRestrictedGear(equipDrawData)) label += " (Restricted)"; ImGui.SameLine(); ImGui.TextUnformatted(label); - - return changes; } - private DataChange DrawEquipNormal(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, - EquipFlag? cApply, out bool rApply, out bool rApplyStain, bool locked, Gender gender, Race race) + private void DrawWeaponsSmall(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons) { - var changes = DataChange.None; - cArmor.DrawIcon(_textures, _iconSize, slot); + DrawStain(mainhand, true); + ImGui.SameLine(); + DrawMainhand(ref mainhand, ref offhand, out var mainhandLabel, allWeapons, true, false); + if (mainhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApply(mainhand); + ImGui.SameLine(); + DrawApplyStain(mainhand); + } + + if (allWeapons) + mainhandLabel += $" ({mainhand.CurrentItem.Type.ToName()})"; + WeaponHelpMarker(mainhandLabel); + + if (offhand.CurrentItem.Type is FullEquipType.Unknown) + return; + + DrawStain(offhand, true); + ImGui.SameLine(); + DrawOffhand(mainhand, offhand, out var offhandLabel, true, false, false); + if (offhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApply(offhand); + ImGui.SameLine(); + DrawApplyStain(offhand); + } + + WeaponHelpMarker(offhandLabel); + } + + #endregion + + #region Normal + + private void DrawEquipNormal(in EquipDrawData equipDrawData) + { + equipDrawData.CurrentItem.DrawIcon(_textures, _iconSize, equipDrawData.Slot); var right = ImGui.IsItemClicked(ImGuiMouseButton.Right); var left = ImGui.IsItemClicked(ImGuiMouseButton.Left); ImGui.SameLine(); using var group = ImRaii.Group(); - if (DrawItem(slot, cArmor, out rArmor, out var label, locked, false, right, left)) - changes |= DataChange.Item; - if (cApply.HasValue) + DrawItem(equipDrawData, out var label, false, right, left); + if (equipDrawData.DisplayApplication) { ImGui.SameLine(); - if (DrawApply(slot, cApply.Value, out rApply, locked)) - changes |= DataChange.ApplyItem; - } - else - { - rApply = true; + DrawApply(equipDrawData); } ImGui.SameLine(); ImGui.TextUnformatted(label); - if (DrawStain(slot, cStain, out rStain, locked, false)) - changes |= DataChange.Stain; - if (cApply.HasValue) + DrawStain(equipDrawData, false); + if (equipDrawData.DisplayApplication) { ImGui.SameLine(); - if (DrawApplyStain(slot, cApply.Value, out rApplyStain, locked)) - changes |= DataChange.ApplyStain; - } - else - { - rApplyStain = true; + DrawApplyStain(equipDrawData); } - if (VerifyRestrictedGear(slot, rArmor, gender, race)) + if (VerifyRestrictedGear(equipDrawData)) { ImGui.SameLine(); ImGui.TextUnformatted("(Restricted)"); } - - return changes; } + private void DrawWeaponsNormal(EquipDrawData mainhand, EquipDrawData offhand, bool allWeapons) + { + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, + ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }); + + mainhand.CurrentItem.DrawIcon(_textures, _iconSize, EquipSlot.MainHand); + var left = ImGui.IsItemClicked(ImGuiMouseButton.Left); + ImGui.SameLine(); + using (var group = ImRaii.Group()) + { + DrawMainhand(ref mainhand, ref offhand, out var mainhandLabel, allWeapons, false, left); + if (mainhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApply(mainhand); + } + + WeaponHelpMarker(mainhandLabel, allWeapons ? mainhand.CurrentItem.Type.ToName() : null); + + DrawStain(mainhand, false); + if (mainhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApplyStain(mainhand); + } + } + + if (offhand.CurrentItem.Type is FullEquipType.Unknown) + return; + + offhand.CurrentItem.DrawIcon(_textures, _iconSize, EquipSlot.OffHand); + var right = ImGui.IsItemClicked(ImGuiMouseButton.Right); + left = ImGui.IsItemClicked(ImGuiMouseButton.Left); + ImGui.SameLine(); + using (var group = ImRaii.Group()) + { + DrawOffhand(mainhand, offhand, out var offhandLabel, false, right, left); + if (offhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApply(offhand); + } + + WeaponHelpMarker(offhandLabel); + + DrawStain(offhand, false); + if (offhand.DisplayApplication) + { + ImGui.SameLine(); + DrawApplyStain(offhand); + } + } + } + + private void DrawStain(in EquipDrawData data, bool small) + { + var found = _stainData.TryGetValue(data.CurrentStain, out var stain); + using var disabled = ImRaii.Disabled(data.Locked); + var change = small + ? _stainCombo.Draw($"##stain{data.Slot}", stain.RgbaColor, stain.Name, found, stain.Gloss) + : _stainCombo.Draw($"##stain{data.Slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength); + if (change) + if (_stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain)) + data.StainSetter(stain.RowIndex); + else if (_stainCombo.CurrentSelection.Key == Stain.None.RowIndex) + data.StainSetter(Stain.None.RowIndex); + + if (!data.Locked && data.CurrentStain != Stain.None.RowIndex) + { + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + data.StainSetter(Stain.None.RowIndex); + + ImGuiUtil.HoverTooltip("Right-click to clear."); + } + } + + private void DrawItem(in EquipDrawData data, out string label, bool small, bool clear, bool open) + { + Debug.Assert(data.Slot.IsEquipment() || data.Slot.IsAccessory(), $"Called {nameof(DrawItem)} on {data.Slot}."); + + var combo = _itemCombo[data.Slot.ToIndex()]; + label = combo.Label; + if (!data.Locked && open) + UiHelpers.OpenCombo($"##{combo.Label}"); + + using var disabled = ImRaii.Disabled(data.Locked); + var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, + _requiredComboWidth); + if (change) + data.ItemSetter(combo.CurrentSelection); + else if (combo.CustomVariant.Id > 0) + data.ItemSetter(_items.Identify(data.Slot, combo.CustomSetId, combo.CustomVariant)); + + if (!data.Locked && data.CurrentItem.ModelId.Id != 0) + { + if (clear || ImGui.IsItemClicked(ImGuiMouseButton.Right)) + data.ItemSetter(ItemManager.NothingItem(data.Slot)); + + ImGuiUtil.HoverTooltip("Right-click to clear."); + } + } + + private void DrawMainhand(ref EquipDrawData mainhand, ref EquipDrawData offhand, out string label, bool drawAll, bool small, + bool open) + { + if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : mainhand.CurrentItem.Type, out var combo)) + { + label = string.Empty; + return; + } + + label = combo.Label; + var unknown = !_gPose.InGPose && mainhand.CurrentItem.Type is FullEquipType.Unknown; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemInnerSpacing); + using (var _ = ImRaii.Disabled(mainhand.Locked | unknown)) + { + if (!mainhand.Locked && open) + UiHelpers.OpenCombo($"##{label}"); + if (combo.Draw(mainhand.CurrentItem.Name, mainhand.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, + _requiredComboWidth)) + { + mainhand.ItemSetter(combo.CurrentSelection); + if (combo.CurrentSelection.Type.ValidOffhand() != mainhand.CurrentItem.Type.ValidOffhand()) + { + offhand.CurrentItem = _items.GetDefaultOffhand(combo.CurrentSelection); + offhand.ItemSetter(offhand.CurrentItem); + } + + mainhand.CurrentItem = combo.CurrentSelection; + } + } + + if (unknown && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled)) + ImGui.SetTooltip("The weapon type could not be identified, thus changing it to other weapons of that type is not possible."); + } + + private void DrawOffhand(in EquipDrawData mainhand, in EquipDrawData offhand, out string label, bool small, bool clear, bool open) + { + if (!_weaponCombo.TryGetValue(offhand.CurrentItem.Type, out var combo)) + { + label = string.Empty; + return; + } + + label = combo.Label; + var locked = offhand.Locked + || !_gPose.InGPose && (offhand.CurrentItem.Type is FullEquipType.Unknown || mainhand.CurrentItem.Type is FullEquipType.Unknown); + using var disabled = ImRaii.Disabled(locked); + if (!locked && open) + UiHelpers.OpenCombo($"##{combo.Label}"); + if (combo.Draw(offhand.CurrentItem.Name, offhand.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength, + _requiredComboWidth)) + offhand.ItemSetter(combo.CurrentSelection); + + if (locked) + return; + + var defaultOffhand = _items.GetDefaultOffhand(mainhand.CurrentItem); + if (defaultOffhand.Id == offhand.CurrentItem.Id) + return; + + ImGuiUtil.HoverTooltip("Right-click to set to Default."); + if (clear || ImGui.IsItemClicked(ImGuiMouseButton.Right)) + offhand.ItemSetter(defaultOffhand); + } + + private static void DrawApply(in EquipDrawData data) + { + if (UiHelpers.DrawCheckbox($"##apply{data.Slot}", "Apply this item when applying the Design.", data.CurrentApply, out var enabled, + data.Locked)) + data.ApplySetter(enabled); + } + + private static void DrawApplyStain(in EquipDrawData data) + { + if (UiHelpers.DrawCheckbox($"##applyStain{data.Slot}", "Apply this item when applying the Design.", data.CurrentApplyStain, + out var enabled, + data.Locked)) + data.ApplyStainSetter(enabled); + } + + #endregion + private static void WeaponHelpMarker(string label, string? type = null) { ImGui.SameLine(); @@ -502,261 +552,11 @@ public class EquipmentDrawer + "thus it is only allowed to change weapons to other weapons of the same type."); ImGui.SameLine(); ImGui.TextUnformatted(label); - if (type != null) - { - var pos = ImGui.GetItemRectMin(); - pos.Y += ImGui.GetFrameHeightWithSpacing(); - ImGui.GetWindowDrawList().AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), $"({type})"); - } - } + if (type == null) + return; - private DataChange DrawWeaponsSmall(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand, - StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply, - out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked, - bool allWeapons) - { - var changes = DataChange.None; - if (DrawStain(EquipSlot.MainHand, cMainhandStain, out rMainhandStain, locked, true)) - changes |= DataChange.Stain; - ImGui.SameLine(); - - rOffhand = cOffhand; - if (DrawMainhand(cMainhand, allWeapons, out rMainhand, out var mainhandLabel, locked, true, false)) - { - changes |= DataChange.Item; - if (rMainhand.Type.ValidOffhand() != cMainhand.Type.ValidOffhand()) - { - rOffhand = _items.GetDefaultOffhand(rMainhand); - changes |= DataChange.Item2; - } - } - - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApply(EquipSlot.MainHand, cApply.Value, out rApplyMainhand, locked)) - changes |= DataChange.ApplyItem; - ImGui.SameLine(); - if (DrawApplyStain(EquipSlot.MainHand, cApply.Value, out rApplyMainhandStain, locked)) - changes |= DataChange.ApplyStain; - } - else - { - rApplyMainhand = true; - rApplyMainhandStain = true; - } - - if (allWeapons) - mainhandLabel += $" ({cMainhand.Type.ToName()})"; - WeaponHelpMarker(mainhandLabel); - - if (rOffhand.Type is FullEquipType.Unknown) - { - rOffhandStain = cOffhandStain; - rApplyOffhand = false; - rApplyOffhandStain = false; - return changes; - } - - if (DrawStain(EquipSlot.OffHand, cOffhandStain, out rOffhandStain, locked, true)) - changes |= DataChange.Stain2; - - ImGui.SameLine(); - if (DrawOffhand(rMainhand, rOffhand, out rOffhand, out var offhandLabel, locked, true, false, false)) - changes |= DataChange.Item2; - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApply(EquipSlot.OffHand, cApply.Value, out rApplyOffhand, locked)) - changes |= DataChange.ApplyItem2; - ImGui.SameLine(); - if (DrawApplyStain(EquipSlot.OffHand, cApply.Value, out rApplyOffhandStain, locked)) - changes |= DataChange.ApplyStain2; - } - else - { - rApplyOffhand = true; - rApplyOffhandStain = true; - } - - WeaponHelpMarker(offhandLabel); - - return changes; - } - - private DataChange DrawWeaponsNormal(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand, - StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply, - out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked, - bool allWeapons) - { - var changes = DataChange.None; - - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, - ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }); - - cMainhand.DrawIcon(_textures, _iconSize, EquipSlot.MainHand); - var left = ImGui.IsItemClicked(ImGuiMouseButton.Left); - ImGui.SameLine(); - using (var group = ImRaii.Group()) - { - rOffhand = cOffhand; - if (DrawMainhand(cMainhand, allWeapons, out rMainhand, out var mainhandLabel, locked, false, left)) - { - changes |= DataChange.Item; - if (rMainhand.Type.ValidOffhand() != cMainhand.Type.ValidOffhand()) - { - rOffhand = _items.GetDefaultOffhand(rMainhand); - changes |= DataChange.Item2; - } - } - - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApply(EquipSlot.MainHand, cApply.Value, out rApplyMainhand, locked)) - changes |= DataChange.ApplyItem; - } - else - { - rApplyMainhand = true; - } - - WeaponHelpMarker(mainhandLabel, allWeapons ? cMainhand.Type.ToName() : null); - - if (DrawStain(EquipSlot.MainHand, cMainhandStain, out rMainhandStain, locked, false)) - changes |= DataChange.Stain; - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApplyStain(EquipSlot.MainHand, cApply.Value, out rApplyMainhandStain, locked)) - changes |= DataChange.ApplyStain; - } - else - { - rApplyMainhandStain = true; - } - } - - if (rOffhand.Type is FullEquipType.Unknown) - { - rOffhandStain = cOffhandStain; - rApplyOffhand = false; - rApplyOffhandStain = false; - return changes; - } - - rOffhand.DrawIcon(_textures, _iconSize, EquipSlot.OffHand); - var right = ImGui.IsItemClicked(ImGuiMouseButton.Right); - left = ImGui.IsItemClicked(ImGuiMouseButton.Left); - ImGui.SameLine(); - using (var group = ImRaii.Group()) - { - if (DrawOffhand(rMainhand, rOffhand, out rOffhand, out var offhandLabel, locked, false, right, left)) - changes |= DataChange.Item2; - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApply(EquipSlot.OffHand, cApply.Value, out rApplyOffhand, locked)) - changes |= DataChange.ApplyItem2; - } - else - { - rApplyOffhand = true; - } - - WeaponHelpMarker(offhandLabel); - - if (DrawStain(EquipSlot.OffHand, cOffhandStain, out rOffhandStain, locked, false)) - changes |= DataChange.Stain2; - if (cApply.HasValue) - { - ImGui.SameLine(); - if (DrawApplyStain(EquipSlot.OffHand, cApply.Value, out rApplyOffhandStain, locked)) - changes |= DataChange.ApplyStain2; - } - else - { - rApplyOffhandStain = true; - } - } - - return changes; - } - - private DataChange DrawWeaponsArtisan(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand, - StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply, - out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain) - { - rApplyMainhand = (cApply ?? 0).HasFlag(EquipFlag.Mainhand); - rApplyMainhandStain = (cApply ?? 0).HasFlag(EquipFlag.MainhandStain); - rApplyOffhand = (cApply ?? 0).HasFlag(EquipFlag.Offhand); - rApplyOffhandStain = (cApply ?? 0).HasFlag(EquipFlag.MainhandStain); - - bool DrawWeapon(EquipItem current, out EquipItem ret) - { - int setId = current.ModelId.Id; - int type = current.WeaponType.Id; - int variant = current.Variant.Id; - ret = current; - var changed = false; - - ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("##setId", ref setId, 0, 0)) - { - var newSetId = (SetId)Math.Clamp(setId, 0, ushort.MaxValue); - if (newSetId.Id != current.ModelId.Id) - { - ret = _items.Identify(EquipSlot.MainHand, newSetId, current.WeaponType, current.Variant); - changed = true; - } - } - - ImGui.SameLine(); - ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("##type", ref type, 0, 0)) - { - var newType = (WeaponType)Math.Clamp(type, 0, ushort.MaxValue); - if (newType.Id != current.WeaponType.Id) - { - ret = _items.Identify(EquipSlot.MainHand, current.ModelId, newType, current.Variant); - changed = true; - } - } - - ImGui.SameLine(); - ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); - if (ImGui.InputInt("##variant", ref variant, 0, 0)) - { - var newVariant = (Variant)Math.Clamp(variant, 0, byte.MaxValue); - if (newVariant.Id != current.Variant.Id) - { - ret = _items.Identify(EquipSlot.MainHand, current.ModelId, current.WeaponType, newVariant); - changed = true; - } - } - - return changed; - } - - var ret = DataChange.None; - using (var id = ImRaii.PushId(0)) - { - if (DrawStainArtisan(EquipSlot.MainHand, cMainhandStain, out rMainhandStain)) - ret |= DataChange.Stain; - ImGui.SameLine(); - if (DrawWeapon(cMainhand, out rMainhand)) - ret |= DataChange.Item; - } - - using (var id = ImRaii.PushId(1)) - { - if (DrawStainArtisan(EquipSlot.OffHand, cOffhandStain, out rOffhandStain)) - ret |= DataChange.Stain; - ImGui.SameLine(); - if (DrawWeapon(cOffhand, out rOffhand)) - ret |= DataChange.Item; - } - - return ret; + var pos = ImGui.GetItemRectMin(); + pos.Y += ImGui.GetFrameHeightWithSpacing(); + ImGui.GetWindowDrawList().AddText(pos, ImGui.GetColorU32(ImGuiCol.Text), $"({type})"); } } diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs index d049eec..5f54965 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs @@ -24,21 +24,11 @@ using Penumbra.GameData.Enums; namespace Glamourer.Gui.Tabs.ActorTab; -public class ActorPanel +public class ActorPanel(ActorSelector _selector, StateManager _stateManager, CustomizationDrawer _customizationDrawer, + EquipmentDrawer _equipmentDrawer, IdentifierService _identification, AutoDesignApplier _autoDesignApplier, + Configuration _config, DesignConverter _converter, ObjectManager _objects, DesignManager _designManager, ImportService _importService, + ICondition _conditions) { - private readonly ActorSelector _selector; - private readonly StateManager _stateManager; - private readonly CustomizationDrawer _customizationDrawer; - private readonly EquipmentDrawer _equipmentDrawer; - private readonly IdentifierService _identification; - private readonly AutoDesignApplier _autoDesignApplier; - private readonly Configuration _config; - private readonly DesignConverter _converter; - private readonly ObjectManager _objects; - private readonly DesignManager _designManager; - private readonly ImportService _importService; - private readonly ICondition _conditions; - private ActorIdentifier _identifier; private string _actorName = string.Empty; private Actor _actor = Actor.Null; @@ -46,29 +36,10 @@ public class ActorPanel private ActorState? _state; private bool _lockedRedraw; - public ActorPanel(ActorSelector selector, StateManager stateManager, CustomizationDrawer customizationDrawer, - EquipmentDrawer equipmentDrawer, IdentifierService identification, AutoDesignApplier autoDesignApplier, - Configuration config, DesignConverter converter, ObjectManager objects, DesignManager designManager, ImportService importService, - ICondition conditions) - { - _selector = selector; - _stateManager = stateManager; - _customizationDrawer = customizationDrawer; - _equipmentDrawer = equipmentDrawer; - _identification = identification; - _autoDesignApplier = autoDesignApplier; - _config = config; - _converter = converter; - _objects = objects; - _designManager = designManager; - _importService = importService; - _conditions = conditions; - } - private CustomizeFlag CustomizeApplicationFlags => _lockedRedraw ? CustomizeFlagExtensions.AllRelevant & ~CustomizeFlagExtensions.RedrawRequired : CustomizeFlagExtensions.AllRelevant; - public unsafe void Draw() + public void Draw() { using var group = ImRaii.Group(); (_identifier, _data) = _selector.Selection; @@ -161,8 +132,7 @@ public class ActorPanel if (_customizationDrawer.Draw(_state!.ModelData.Customize, _state.IsLocked, _lockedRedraw)) _stateManager.ChangeCustomize(_state, _customizationDrawer.Customize, _customizationDrawer.Changed, StateChanged.Source.Manual); - if (_customizationDrawer.DrawWetnessState(_state!.ModelData.IsWet(), out var newWetness, _state.IsLocked)) - _stateManager.ChangeWetness(_state, newWetness, StateChanged.Source.Manual); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.Wetness, _stateManager, _state)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); } @@ -176,62 +146,22 @@ public class ActorPanel var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _state!.IsLocked); foreach (var slot in EquipSlotExtensions.EqdpSlots) { - var changes = _equipmentDrawer.DrawEquip(slot, _state!.ModelData, out var newArmor, out var newStain, null, out _, out _, - _state.IsLocked); + var data = EquipDrawData.FromState(_stateManager, _state!, slot); + _equipmentDrawer.DrawEquip(data); if (usedAllStain) - { - changes |= DataChange.Stain; - newStain = newAllStain; - } - - switch (changes) - { - case DataChange.Item: - _stateManager.ChangeItem(_state, slot, newArmor, StateChanged.Source.Manual); - break; - case DataChange.Stain: - _stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual); - break; - case DataChange.Item | DataChange.Stain: - _stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual); - break; - } + _stateManager.ChangeStain(_state, slot, newAllStain, StateChanged.Source.Manual); } - var weaponChanges = _equipmentDrawer.DrawWeapons(_state!.ModelData, out var newMainhand, out var newOffhand, out var newMainhandStain, - out var newOffhandStain, null, GameMain.IsInGPose(), out _, out _, out _, out _, _state.IsLocked); - if (usedAllStain) - { - weaponChanges |= DataChange.Stain | DataChange.Stain2; - newMainhandStain = newAllStain; - newOffhandStain = newAllStain; - } - - if (weaponChanges.HasFlag(DataChange.Item)) - if (weaponChanges.HasFlag(DataChange.Stain)) - _stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMainhand, newMainhandStain, StateChanged.Source.Manual); - else - _stateManager.ChangeItem(_state, EquipSlot.MainHand, newMainhand, StateChanged.Source.Manual); - else if (weaponChanges.HasFlag(DataChange.Stain)) - _stateManager.ChangeStain(_state, EquipSlot.MainHand, newMainhandStain, StateChanged.Source.Manual); - - if (weaponChanges.HasFlag(DataChange.Item2)) - if (weaponChanges.HasFlag(DataChange.Stain2)) - _stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOffhand, newOffhandStain, StateChanged.Source.Manual); - else - _stateManager.ChangeItem(_state, EquipSlot.OffHand, newOffhand, StateChanged.Source.Manual); - else if (weaponChanges.HasFlag(DataChange.Stain2)) - _stateManager.ChangeStain(_state, EquipSlot.OffHand, newOffhandStain, StateChanged.Source.Manual); + var mainhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.MainHand); + var offhand = EquipDrawData.FromState(_stateManager, _state, EquipSlot.OffHand); + _equipmentDrawer.DrawWeapons(mainhand, offhand, GameMain.IsInGPose()); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); - if (EquipmentDrawer.DrawHatState(_state!.ModelData.IsHatVisible(), out var newHatState, _state!.IsLocked)) - _stateManager.ChangeHatState(_state, newHatState, StateChanged.Source.Manual); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.HatState, _stateManager, _state)); ImGui.SameLine(); - if (EquipmentDrawer.DrawVisorState(_state!.ModelData.IsVisorToggled(), out var newVisorState, _state!.IsLocked)) - _stateManager.ChangeVisorState(_state, newVisorState, StateChanged.Source.Manual); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.VisorState, _stateManager, _state)); ImGui.SameLine(); - if (EquipmentDrawer.DrawWeaponState(_state!.ModelData.IsWeaponVisible(), out var newWeaponState, _state!.IsLocked)) - _stateManager.ChangeWeaponState(_state, newWeaponState, StateChanged.Source.Manual); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.WeaponState, _stateManager, _state)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); } diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs index bd6e197..c4cf023 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs @@ -2,7 +2,6 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Xml.Linq; using Dalamud.Interface; using Dalamud.Interface.ImGuiFileDialog; using Dalamud.Interface.Internal.Notifications; @@ -95,45 +94,15 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer var usedAllStain = _equipmentDrawer.DrawAllStain(out var newAllStain, _selector.Selected!.WriteProtected()); foreach (var slot in EquipSlotExtensions.EqdpSlots) { - var changes = _equipmentDrawer.DrawEquip(slot, _selector.Selected!.DesignData, out var newArmor, out var newStain, - _selector.Selected.ApplyEquip, out var newApply, out var newApplyStain, _selector.Selected!.WriteProtected()); - if (changes.HasFlag(DataChange.Item)) - _manager.ChangeEquip(_selector.Selected, slot, newArmor); - if (changes.HasFlag(DataChange.Stain)) - _manager.ChangeStain(_selector.Selected, slot, newStain); - else if (usedAllStain) + var data = EquipDrawData.FromDesign(_manager, _selector.Selected!, slot); + _equipmentDrawer.DrawEquip(data); + if (usedAllStain) _manager.ChangeStain(_selector.Selected, slot, newAllStain); - if (changes.HasFlag(DataChange.ApplyItem)) - _manager.ChangeApplyEquip(_selector.Selected, slot, newApply); - if (changes.HasFlag(DataChange.ApplyStain)) - _manager.ChangeApplyStain(_selector.Selected, slot, newApplyStain); } - var weaponChanges = _equipmentDrawer.DrawWeapons(_selector.Selected!.DesignData, out var newMainhand, out var newOffhand, - out var newMainhandStain, out var newOffhandStain, _selector.Selected.ApplyEquip, true, out var applyMain, out var applyMainStain, - out var applyOff, out var applyOffStain, _selector.Selected!.WriteProtected()); - - if (weaponChanges.HasFlag(DataChange.Item)) - _manager.ChangeWeapon(_selector.Selected, EquipSlot.MainHand, newMainhand); - if (weaponChanges.HasFlag(DataChange.Stain)) - _manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newMainhandStain); - else if (usedAllStain) - _manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newAllStain); - if (weaponChanges.HasFlag(DataChange.ApplyItem)) - _manager.ChangeApplyEquip(_selector.Selected, EquipSlot.MainHand, applyMain); - if (weaponChanges.HasFlag(DataChange.ApplyStain)) - _manager.ChangeApplyStain(_selector.Selected, EquipSlot.MainHand, applyMainStain); - if (weaponChanges.HasFlag(DataChange.Item2)) - _manager.ChangeWeapon(_selector.Selected, EquipSlot.OffHand, newOffhand); - if (weaponChanges.HasFlag(DataChange.Stain2)) - _manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newOffhandStain); - else if (usedAllStain) - _manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newAllStain); - if (weaponChanges.HasFlag(DataChange.ApplyItem2)) - _manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff); - if (weaponChanges.HasFlag(DataChange.ApplyStain2)) - _manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain); - + var mainhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.MainHand); + var offhand = EquipDrawData.FromDesign(_manager, _selector.Selected!, EquipSlot.OffHand); + _equipmentDrawer.DrawWeapons(mainhand, offhand, true); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); DrawEquipmentMetaToggles(); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); @@ -141,22 +110,11 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer private void DrawEquipmentMetaToggles() { - var hatChanges = EquipmentDrawer.DrawHatState(_selector.Selected!.DesignData.IsHatVisible(), - _selector.Selected.DoApplyHatVisible(), - out var newHatState, out var newHatApply, _selector.Selected.WriteProtected()); - ApplyChanges(ActorState.MetaIndex.HatState, hatChanges, newHatState, newHatApply); - + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.HatState, _manager, _selector.Selected!)); ImGui.SameLine(); - var visorChanges = EquipmentDrawer.DrawVisorState(_selector.Selected!.DesignData.IsVisorToggled(), - _selector.Selected.DoApplyVisorToggle(), - out var newVisorState, out var newVisorApply, _selector.Selected.WriteProtected()); - ApplyChanges(ActorState.MetaIndex.VisorState, visorChanges, newVisorState, newVisorApply); - + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.VisorState, _manager, _selector.Selected!)); ImGui.SameLine(); - var weaponChanges = EquipmentDrawer.DrawWeaponState(_selector.Selected!.DesignData.IsWeaponVisible(), - _selector.Selected.DoApplyWeaponVisible(), - out var newWeaponState, out var newWeaponApply, _selector.Selected.WriteProtected()); - ApplyChanges(ActorState.MetaIndex.WeaponState, weaponChanges, newWeaponState, newWeaponApply); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.WeaponState, _manager, _selector.Selected!)); } private void DrawCustomize() @@ -178,9 +136,7 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer _manager.ChangeCustomize(_selector.Selected, idx, _customizationDrawer.Customize[idx]); } - var wetnessChanges = _customizationDrawer.DrawWetnessState(_selector.Selected!.DesignData.IsWet(), - _selector.Selected!.DoApplyWetness(), out var newWetnessState, out var newWetnessApply, _selector.Selected!.WriteProtected()); - ApplyChanges(ActorState.MetaIndex.Wetness, wetnessChanges, newWetnessState, newWetnessApply); + EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.Wetness, _manager, _selector.Selected!)); ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2)); } @@ -306,12 +262,14 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer _manager.ChangeCustomize(_selector.Selected!, CustomizeIndex.Gender, dat.Customize[CustomizeIndex.Gender]); foreach (var idx in CustomizationExtensions.AllBasic) _manager.ChangeCustomize(_selector.Selected!, idx, dat.Customize[idx]); - Glamourer.Messager.NotificationMessage($"Applied games .dat file {dat.Description} customizations to {_selector.Selected.Name}.", NotificationType.Success, false); + Glamourer.Messager.NotificationMessage( + $"Applied games .dat file {dat.Description} customizations to {_selector.Selected.Name}.", NotificationType.Success, false); } else if (_importService.CreateCharaTarget(out var designBase, out var name)) { _manager.ApplyDesign(_selector.Selected!, designBase); - Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selector.Selected.Name}.", NotificationType.Success, false); + Glamourer.Messager.NotificationMessage($"Applied Anamnesis .chara file {name} to {_selector.Selected.Name}.", + NotificationType.Success, false); } } @@ -441,23 +399,6 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer _fileDialog.Draw(); } - private void ApplyChanges(ActorState.MetaIndex index, DataChange change, bool value, bool apply) - { - switch (change) - { - case DataChange.Item: - _manager.ChangeMeta(_selector.Selected!, index, value); - break; - case DataChange.ApplyItem: - _manager.ChangeApplyMeta(_selector.Selected!, index, apply); - break; - case DataChange.Item | DataChange.ApplyItem: - _manager.ChangeApplyMeta(_selector.Selected!, index, apply); - _manager.ChangeMeta(_selector.Selected!, index, value); - break; - } - } - private static unsafe string GetUserPath() => Framework.Instance()->UserPath; } diff --git a/Glamourer/Gui/ToggleDrawData.cs b/Glamourer/Gui/ToggleDrawData.cs new file mode 100644 index 0000000..f78cf6f --- /dev/null +++ b/Glamourer/Gui/ToggleDrawData.cs @@ -0,0 +1,79 @@ +using System; +using Glamourer.Designs; +using Glamourer.Events; +using Glamourer.State; + +namespace Glamourer.Gui; + +public ref struct ToggleDrawData +{ + public bool Locked; + public bool DisplayApplication; + + public bool CurrentValue; + public bool CurrentApply; + + public Action SetValue = null!; + public Action SetApply = null!; + + public string Label = string.Empty; + public string Tooltip = string.Empty; + + public ToggleDrawData() + { } + + public static ToggleDrawData FromDesign(ActorState.MetaIndex index, DesignManager manager, Design design) + { + var (label, value, apply, setValue, setApply) = index switch + { + ActorState.MetaIndex.HatState => ("Hat Visible", design.DesignData.IsHatVisible(), design.DoApplyHatVisible(), + (Action)(b => manager.ChangeMeta(design, index, b)), (Action)(b => manager.ChangeApplyMeta(design, index, b))), + ActorState.MetaIndex.VisorState => ("Visor Toggled", design.DesignData.IsVisorToggled(), design.DoApplyVisorToggle(), + b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), + ActorState.MetaIndex.WeaponState => ("Weapon Visible", design.DesignData.IsWeaponVisible(), design.DoApplyWeaponVisible(), + b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), + ActorState.MetaIndex.Wetness => ("Force Wetness", design.DesignData.IsWet(), design.DoApplyWetness(), + b => manager.ChangeMeta(design, index, b), b => manager.ChangeApplyMeta(design, index, b)), + _ => throw new Exception("Unsupported meta index."), + }; + + return new ToggleDrawData + { + Label = label, + Tooltip = string.Empty, + Locked = design.WriteProtected(), + DisplayApplication = true, + CurrentValue = value, + CurrentApply = apply, + SetValue = setValue, + SetApply = setApply, + }; + } + + public static ToggleDrawData FromState(ActorState.MetaIndex index, StateManager manager, ActorState state) + { + var (label, tooltip, value, setValue) = index switch + { + ActorState.MetaIndex.HatState => ("Hat Visible", "Hide or show the characters head gear.", state.ModelData.IsHatVisible(), + (Action)(b => manager.ChangeHatState(state, b, StateChanged.Source.Manual))), + ActorState.MetaIndex.VisorState => ("Visor Toggled", "Toggle the visor state of the characters head gear.", + state.ModelData.IsVisorToggled(), + b => manager.ChangeVisorState(state, b, StateChanged.Source.Manual)), + ActorState.MetaIndex.WeaponState => ("Weapon Visible", "Hide or show the characters weapons when not drawn.", + state.ModelData.IsWeaponVisible(), + b => manager.ChangeWeaponState(state, b, StateChanged.Source.Manual)), + ActorState.MetaIndex.Wetness => ("Force Wetness", "Force the character to be wet or not.", state.ModelData.IsWet(), + b => manager.ChangeWetness(state, b, StateChanged.Source.Manual)), + _ => throw new Exception("Unsupported meta index."), + }; + + return new ToggleDrawData + { + Label = label, + Tooltip = tooltip, + Locked = state.IsLocked, + CurrentValue = value, + SetValue = setValue, + }; + } +} diff --git a/Glamourer/Gui/UiHelpers.cs b/Glamourer/Gui/UiHelpers.cs index 7dcfc7d..22ec758 100644 --- a/Glamourer/Gui/UiHelpers.cs +++ b/Glamourer/Gui/UiHelpers.cs @@ -71,14 +71,15 @@ public static class UiHelpers return ret; } - public static DataChange DrawMetaToggle(string label, bool currentValue, bool currentApply, out bool newValue, + public static (bool, bool) DrawMetaToggle(string label, bool currentValue, bool currentApply, out bool newValue, out bool newApply, bool locked) { var flags = (sbyte)(currentApply ? currentValue ? 1 : -1 : 0); using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemInnerSpacing); using (var disabled = ImRaii.Disabled(locked)) { - if (new TristateCheckbox(ColorId.TriStateCross.Value(), ColorId.TriStateCheck.Value(), ColorId.TriStateNeutral.Value()).Draw("##" + label, flags, out flags)) + if (new TristateCheckbox(ColorId.TriStateCross.Value(), ColorId.TriStateCheck.Value(), ColorId.TriStateNeutral.Value()).Draw( + "##" + label, flags, out flags)) { (newValue, newApply) = flags switch { @@ -99,13 +100,7 @@ public static class UiHelpers ImGui.SameLine(); ImGui.TextUnformatted(label); - return (currentApply != newApply, currentValue != newValue) switch - { - (true, true) => DataChange.ApplyItem | DataChange.Item, - (true, false) => DataChange.ApplyItem, - (false, true) => DataChange.Item, - _ => DataChange.None, - }; + return (currentValue != newValue, currentApply != newApply); } public static (EquipFlag, CustomizeFlag) ConvertKeysToFlags() diff --git a/OtterGui b/OtterGui index 858b610..2a79084 160000 --- a/OtterGui +++ b/OtterGui @@ -1 +1 @@ -Subproject commit 858b610a194ee52b4e8e89c0c64d9f2653025524 +Subproject commit 2a7908493ab0fd0e576d5fa37a3acbd920be6233