mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Allow drag & drop of equipment pieces.
This commit is contained in:
parent
d7b189b714
commit
282935c6d6
6 changed files with 169 additions and 4 deletions
83
Glamourer/Gui/Equipment/EquipItemSlotCache.cs
Normal file
83
Glamourer/Gui/Equipment/EquipItemSlotCache.cs
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
using Glamourer.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Equipment;
|
||||
|
||||
[InlineArray(13)]
|
||||
public struct EquipItemSlotCache
|
||||
{
|
||||
private EquipItem _element;
|
||||
|
||||
public EquipItem Dragged
|
||||
{
|
||||
get => this[^1];
|
||||
set => this[^1] = value;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
=> ((Span<EquipItem>)this).Clear();
|
||||
|
||||
public EquipItem this[EquipSlot slot]
|
||||
{
|
||||
get => this[(int)slot.ToIndex()];
|
||||
set => this[(int)slot.ToIndex()] = value;
|
||||
}
|
||||
|
||||
public void Update(ItemManager items, in EquipItem item, EquipSlot startSlot)
|
||||
{
|
||||
if (item.Id == Dragged.Id && item.Type == Dragged.Type)
|
||||
return;
|
||||
|
||||
switch (startSlot)
|
||||
{
|
||||
case EquipSlot.MainHand:
|
||||
{
|
||||
Clear();
|
||||
this[EquipSlot.MainHand] = item;
|
||||
if (item.Type is FullEquipType.Sword)
|
||||
this[EquipSlot.OffHand] = items.FindClosestShield(item.ItemId, out var shield) ? shield : default;
|
||||
else
|
||||
this[EquipSlot.OffHand] = items.ItemData.Secondary.GetValueOrDefault(item.ItemId);
|
||||
break;
|
||||
}
|
||||
case EquipSlot.OffHand:
|
||||
{
|
||||
Clear();
|
||||
if (item.Type is FullEquipType.Shield)
|
||||
this[EquipSlot.MainHand] = items.FindClosestSword(item.ItemId, out var sword) ? sword : default;
|
||||
else
|
||||
this[EquipSlot.MainHand] = items.ItemData.Primary.GetValueOrDefault(item.ItemId);
|
||||
this[EquipSlot.OffHand] = item;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
this[EquipSlot.MainHand] = default;
|
||||
this[EquipSlot.OffHand] = default;
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
{
|
||||
if (startSlot == slot)
|
||||
{
|
||||
this[slot] = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
var slotItem = items.Identify(slot, item.PrimaryId, item.Variant);
|
||||
if (!slotItem.Valid || slotItem.ItemId.Id is not 0 != item.ItemId.Id is not 0)
|
||||
{
|
||||
slotItem = items.Identify(EquipSlot.OffHand, item.PrimaryId, item.SecondaryId, 1, item.Type);
|
||||
if (slotItem.ItemId.Id is not 0 != item.ItemId.Id is not 0)
|
||||
slotItem = default;
|
||||
}
|
||||
|
||||
this[slot] = slotItem;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Dragged = item;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,6 +38,8 @@ public class EquipmentDrawer
|
|||
private float _requiredComboWidth;
|
||||
|
||||
private Stain? _draggedStain;
|
||||
private EquipItemSlotCache _draggedItem;
|
||||
private EquipSlot _dragTarget;
|
||||
|
||||
public EquipmentDrawer(FavoriteManager favorites, IDataManager gameData, ItemManager items, TextureService textures,
|
||||
Configuration config, GPoseService gPose, AdvancedDyePopup advancedDyes, ItemCopyService itemCopy)
|
||||
|
|
@ -80,6 +82,7 @@ public class EquipmentDrawer
|
|||
|
||||
_requiredComboWidth = _requiredComboWidthUnscaled * ImGuiHelpers.GlobalScale;
|
||||
_advancedMaterialColor = ColorId.AdvancedDyeActive.Value();
|
||||
_dragTarget = EquipSlot.Unknown;
|
||||
}
|
||||
|
||||
private bool VerifyRestrictedGear(EquipDrawData data)
|
||||
|
|
@ -429,7 +432,7 @@ public class EquipmentDrawer
|
|||
using var dragSource = ImUtf8.DragDropSource();
|
||||
if (dragSource.Success)
|
||||
{
|
||||
if (DragDropSource.SetPayload("stainDragDrop"u8))
|
||||
DragDropSource.SetPayload("stainDragDrop"u8);
|
||||
_draggedStain = stain;
|
||||
ImUtf8.Text($"Dragging {stain.Name}...");
|
||||
}
|
||||
|
|
@ -455,6 +458,7 @@ public class EquipmentDrawer
|
|||
using var disabled = ImRaii.Disabled(data.Locked);
|
||||
var change = combo.Draw(data.CurrentItem.Name, data.CurrentItem.ItemId, small ? _comboLength - ImGui.GetFrameHeight() : _comboLength,
|
||||
_requiredComboWidth);
|
||||
DrawGearDragDrop(data);
|
||||
if (change)
|
||||
data.SetItem(combo.CurrentSelection);
|
||||
else if (combo.CustomVariant.Id > 0)
|
||||
|
|
@ -495,6 +499,50 @@ public class EquipmentDrawer
|
|||
data.SetItem(item);
|
||||
}
|
||||
|
||||
private void DrawGearDragDrop(in EquipDrawData data)
|
||||
{
|
||||
if (data.CurrentItem.Valid)
|
||||
{
|
||||
using var dragSource = ImUtf8.DragDropSource();
|
||||
if (dragSource.Success)
|
||||
{
|
||||
DragDropSource.SetPayload("equipDragDrop"u8);
|
||||
_draggedItem.Update(_items, data.CurrentItem, data.Slot);
|
||||
}
|
||||
}
|
||||
|
||||
using var dragTarget = ImUtf8.DragDropTarget();
|
||||
if (!dragTarget)
|
||||
return;
|
||||
|
||||
var item = _draggedItem[data.Slot];
|
||||
if (!item.Valid)
|
||||
return;
|
||||
|
||||
_dragTarget = data.Slot;
|
||||
if (!dragTarget.IsDropping("equipDragDrop"u8))
|
||||
return;
|
||||
|
||||
data.SetItem(item);
|
||||
_draggedItem.Clear();
|
||||
}
|
||||
|
||||
public unsafe void DrawDragDropTooltip()
|
||||
{
|
||||
var payload = ImGui.GetDragDropPayload().NativePtr;
|
||||
if (payload is null)
|
||||
return;
|
||||
|
||||
if (!MemoryMarshal.CreateReadOnlySpanFromNullTerminated(payload->DataType).SequenceEqual("equipDragDrop"u8))
|
||||
return;
|
||||
|
||||
using var tt = ImUtf8.Tooltip();
|
||||
if (_dragTarget is EquipSlot.Unknown)
|
||||
ImUtf8.Text($"Dragging {_draggedItem.Dragged.Name}...");
|
||||
else
|
||||
ImUtf8.Text($"Converting to {_draggedItem[_dragTarget].Name}...");
|
||||
}
|
||||
|
||||
private static bool ResetOrClear<T>(bool locked, bool clicked, bool allowRevert, bool allowClear,
|
||||
in T currentItem, in T revertItem, in T clearItem, out T? item) where T : IEquatable<T>
|
||||
{
|
||||
|
|
@ -546,6 +594,7 @@ public class EquipmentDrawer
|
|||
else if (combo.CustomVariant.Id > 0 && (drawAll || ItemData.ConvertWeaponId(combo.CustomSetId) == mainhand.CurrentItem.Type))
|
||||
changedItem = _items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant);
|
||||
_itemCopy.HandleCopyPaste(mainhand);
|
||||
DrawGearDragDrop(mainhand);
|
||||
|
||||
if (ResetOrClear(mainhand.Locked || unknown, open, mainhand.AllowRevert, false, mainhand.CurrentItem, mainhand.GameItem,
|
||||
default, out var c))
|
||||
|
|
@ -589,6 +638,7 @@ public class EquipmentDrawer
|
|||
else if (combo.CustomVariant.Id > 0 && ItemData.ConvertWeaponId(combo.CustomSetId) == offhand.CurrentItem.Type)
|
||||
offhand.SetItem(_items.Identify(mainhand.Slot, combo.CustomSetId, combo.CustomWeaponId, combo.CustomVariant));
|
||||
_itemCopy.HandleCopyPaste(offhand);
|
||||
DrawGearDragDrop(offhand);
|
||||
|
||||
var defaultOffhand = _items.GetDefaultOffhand(mainhand.CurrentItem);
|
||||
if (ResetOrClear(locked, clear, offhand.AllowRevert, true, offhand.CurrentItem, offhand.GameItem, defaultOffhand, out var item))
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ public class ActorPanel
|
|||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
DrawEquipmentMetaToggles();
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
_equipmentDrawer.DrawDragDropTooltip();
|
||||
}
|
||||
|
||||
private void DrawParameterHeader()
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ public class DesignPanel
|
|||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
DrawEquipmentMetaToggles();
|
||||
ImGui.Dummy(new Vector2(ImGui.GetTextLineHeight() / 2));
|
||||
_equipmentDrawer.DrawDragDropTooltip();
|
||||
}
|
||||
|
||||
private void DrawEquipmentMetaToggles()
|
||||
|
|
|
|||
|
|
@ -174,6 +174,36 @@ public class ItemManager
|
|||
return NothingItem(offhandType);
|
||||
}
|
||||
|
||||
public bool FindClosestShield(ItemId id, out EquipItem item)
|
||||
{
|
||||
var list = ItemData.ByType[FullEquipType.Shield];
|
||||
try
|
||||
{
|
||||
item = list.Where(i => i.ItemId.Id > id.Id && i.ItemId.Id - id.Id < 50).MinBy(i => i.ItemId.Id);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public bool FindClosestSword(ItemId id, out EquipItem item)
|
||||
{
|
||||
var list = ItemData.ByType[FullEquipType.Sword];
|
||||
try
|
||||
{
|
||||
item = list.Where(i => i.ItemId.Id < id.Id && id.Id - i.ItemId.Id < 50).MaxBy(i => i.ItemId.Id);
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
item = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public EquipItem Identify(EquipSlot slot, PrimaryId id, SecondaryId type, Variant variant,
|
||||
FullEquipType mainhandType = FullEquipType.Unknown)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 574ef3a8afd42b949e713e247a0b812886f088bb
|
||||
Subproject commit ff7b3b4014a97455f823380c78b8a7c5107f8e2f
|
||||
Loading…
Add table
Add a link
Reference in a new issue