mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
386 lines
18 KiB
C#
386 lines
18 KiB
C#
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.Events;
|
|
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;
|
|
using Penumbra.GameData.Enums;
|
|
|
|
namespace Glamourer.Gui.Tabs.DesignTab;
|
|
|
|
public class DesignPanel
|
|
{
|
|
private readonly ObjectManager _objects;
|
|
private readonly DesignFileSystemSelector _selector;
|
|
private readonly DesignManager _manager;
|
|
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, CustomizationService customizationService, PenumbraService penumbra,
|
|
ModAssociationsTab modAssociations, DesignDetailTab designDetails, DesignConverter converter)
|
|
{
|
|
_selector = selector;
|
|
_customizationDrawer = customizationDrawer;
|
|
_manager = manager;
|
|
_objects = objects;
|
|
_state = state;
|
|
_equipmentDrawer = equipmentDrawer;
|
|
_customizationService = customizationService;
|
|
_modAssociations = modAssociations;
|
|
_designDetails = designDetails;
|
|
_converter = converter;
|
|
}
|
|
|
|
private HeaderDrawer.Button LockButton()
|
|
=> _selector.Selected == null
|
|
? HeaderDrawer.Button.Invisible
|
|
: _selector.Selected.WriteProtected()
|
|
? new HeaderDrawer.Button
|
|
{
|
|
Description = "Make this design editable.",
|
|
Icon = FontAwesomeIcon.Lock,
|
|
OnClick = () => _manager.SetWriteProtection(_selector.Selected!, false),
|
|
}
|
|
: new HeaderDrawer.Button
|
|
{
|
|
Description = "Write-protect this design.",
|
|
Icon = FontAwesomeIcon.LockOpen,
|
|
OnClick = () => _manager.SetWriteProtection(_selector.Selected!, true),
|
|
};
|
|
|
|
private HeaderDrawer.Button SetFromClipboardButton()
|
|
=> new()
|
|
{
|
|
Description = "Try to apply a design from your clipboard over this design.",
|
|
Icon = FontAwesomeIcon.Clipboard,
|
|
OnClick = SetFromClipboard,
|
|
Visible = _selector.Selected != null,
|
|
Disabled = _selector.Selected?.WriteProtected() ?? true,
|
|
};
|
|
|
|
private HeaderDrawer.Button ExportToClipboardButton()
|
|
=> new()
|
|
{
|
|
Description = "Copy the current design to your clipboard.",
|
|
Icon = FontAwesomeIcon.Copy,
|
|
OnClick = ExportToClipboard,
|
|
Visible = _selector.Selected != null,
|
|
};
|
|
|
|
private void DrawHeader()
|
|
=> HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg),
|
|
2, SetFromClipboardButton(), ExportToClipboardButton(), LockButton(),
|
|
HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v));
|
|
|
|
private string SelectionName
|
|
=> _selector.Selected == null ? "No Selection" : _selector.IncognitoMode ? _selector.Selected.Incognito : _selector.Selected.Name.Text;
|
|
|
|
private void DrawEquipment()
|
|
{
|
|
if (!ImGui.CollapsingHeader("Equipment"))
|
|
return;
|
|
|
|
_equipmentDrawer.Prepare();
|
|
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);
|
|
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, 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);
|
|
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);
|
|
if (weaponChanges.HasFlag(DataChange.ApplyItem2))
|
|
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff);
|
|
if (weaponChanges.HasFlag(DataChange.ApplyStain2))
|
|
_manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain);
|
|
|
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
|
DrawEquipmentMetaToggles();
|
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
|
}
|
|
|
|
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);
|
|
|
|
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);
|
|
|
|
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);
|
|
}
|
|
|
|
private void DrawCustomize()
|
|
{
|
|
if (!ImGui.CollapsingHeader("Customization"))
|
|
return;
|
|
|
|
if (_customizationDrawer.Draw(_selector.Selected!.DesignData.Customize, _selector.Selected.ApplyCustomize,
|
|
_selector.Selected!.WriteProtected(), false))
|
|
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
|
{
|
|
var flag = idx.ToFlag();
|
|
var newValue = _customizationDrawer.ChangeApply.HasFlag(flag);
|
|
_manager.ChangeApplyCustomize(_selector.Selected, idx, newValue);
|
|
if (_customizationDrawer.Changed.HasFlag(flag))
|
|
_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);
|
|
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
|
}
|
|
|
|
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)
|
|
| CustomizeFlag.Clan
|
|
| CustomizeFlag.Gender;
|
|
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;
|
|
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Clan, newFlags);
|
|
_manager.ChangeApplyCustomize(_selector.Selected!, CustomizeIndex.Gender, newFlags);
|
|
foreach (var index in CustomizationExtensions.AllBasic.Where(set.IsAvailable))
|
|
_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();
|
|
DrawHeader();
|
|
|
|
var design = _selector.Selected;
|
|
using var child = ImRaii.Child("##Panel", -Vector2.One, true);
|
|
if (!child || design == null)
|
|
return;
|
|
|
|
DrawButtonRow();
|
|
DrawCustomize();
|
|
DrawEquipment();
|
|
_designDetails.Draw();
|
|
DrawApplicationRules();
|
|
_modAssociations.Draw();
|
|
}
|
|
|
|
private void DrawButtonRow()
|
|
{
|
|
DrawApplyToSelf();
|
|
ImGui.SameLine();
|
|
DrawApplyToTarget();
|
|
}
|
|
|
|
private void SetFromClipboard()
|
|
{
|
|
try
|
|
{
|
|
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 ExportToClipboard()
|
|
{
|
|
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, StateChanged.Source.Manual);
|
|
}
|
|
|
|
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, StateChanged.Source.Manual);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|