Some more interface work.

This commit is contained in:
Ottermandias 2023-07-12 18:29:21 +02:00
parent 6f34d74752
commit 129f9e070f
17 changed files with 485 additions and 243 deletions

View file

@ -81,7 +81,7 @@ public static class DesignBase64Migration
data.SetItem(EquipSlot.MainHand, main); data.SetItem(EquipSlot.MainHand, main);
data.SetStain(EquipSlot.MainHand, cur[0].Stain); data.SetStain(EquipSlot.MainHand, cur[0].Stain);
var off = items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, (byte)cur[1].Variant, main.Type); var off = items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, (byte)cur[1].Variant, main.Type);
if (main.Type.Offhand() != FullEquipType.Unknown && !off.Valid) if (main.Type.ValidOffhand() != FullEquipType.Unknown && !off.Valid)
throw new Exception($"Base64 string invalid, weapon could not be identified."); throw new Exception($"Base64 string invalid, weapon could not be identified.");
data.SetItem(EquipSlot.OffHand, off); data.SetItem(EquipSlot.OffHand, off);

View file

@ -337,10 +337,8 @@ public class DesignManager
if (item.Type != currentMain.Type) if (item.Type != currentMain.Type)
{ {
var newOffId = item.Type.Offhand().IsOffhandType() var defaultOffhand = _items.GetDefaultOffhand(item);
? item.ItemId if (!_items.IsOffhandValid(item, defaultOffhand.ItemId, out newOff))
: ItemManager.NothingId(item.Type.Offhand());
if (!_items.IsOffhandValid(item, newOffId, out newOff))
return; return;
} }

View file

@ -7,6 +7,7 @@ using Dalamud.Data;
using Dalamud.Interface; using Dalamud.Interface;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.Services; using Glamourer.Services;
using Glamourer.Structs;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii; using OtterGui.Raii;
@ -33,7 +34,7 @@ public class EquipmentDrawer
_codes = codes; _codes = codes;
_textures = textures; _textures = textures;
_stainData = items.Stains; _stainData = items.Stains;
_stainCombo = new FilterComboColors(140, _stainCombo = new FilterComboColors(280,
_stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false)))); _stainData.Data.Prepend(new KeyValuePair<byte, (string Name, uint Dye, bool Gloss)>(0, ("None", 0, false))));
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray(); _itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2); _weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
@ -54,39 +55,262 @@ public class EquipmentDrawer
public void Prepare() public void Prepare()
{ {
_iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y); _iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y);
_comboLength = 320 * ImGuiHelpers.GlobalScale; _comboLength = 300 * ImGuiHelpers.GlobalScale;
} }
private string VerifyRestrictedGear(EquipItem gear, EquipSlot slot, Gender gender, Race race) private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race)
{ {
if (slot.IsAccessory()) if (slot.IsAccessory())
return gear.Name; return false;
var (changed, _) = _items.ResolveRestrictedGear(gear.Armor(), slot, race, gender); var (changed, _) = _items.ResolveRestrictedGear(gear.Armor(), slot, race, gender);
if (changed) return changed;
return gear.Name + " (Restricted)";
return gear.Name;
} }
public bool DrawArmor(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, Race race = Race.Unknown) [Flags]
public enum EquipChange : byte
{ {
Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}."); None = 0x00,
Item = 0x01,
Stain = 0x02,
ApplyItem = 0x04,
ApplyStain = 0x08,
Item2 = 0x10,
Stain2 = 0x20,
ApplyItem2 = 0x40,
ApplyStain2 = 0x80,
}
if (_codes.EnabledArtisan) public EquipChange DrawEquip(EquipSlot slot, in DesignData designData, out EquipItem rArmor, out StainId rStain, EquipFlag? cApply,
return DrawArmorArtisan(current, slot, out armor, gender, race); 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);
current.DrawIcon(_textures, _iconSize); public EquipChange 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)
{
if (!locked && _codes.EnabledArtisan)
return DrawEquipArtisan(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain);
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing);
var changes = EquipChange.None;
cArmor.DrawIcon(_textures, _iconSize);
ImGui.SameLine(); ImGui.SameLine();
using var group = ImRaii.Group(); using var group = ImRaii.Group();
if (DrawItem(slot, cArmor, out rArmor, out var label, locked))
changes |= EquipChange.Item;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(slot, cApply.Value, out rApply, locked))
changes |= EquipChange.ApplyItem;
}
else
{
rApply = true;
}
ImGui.SameLine();
ImGui.TextUnformatted(label);
if (DrawStain(slot, cStain, out rStain, locked))
changes |= EquipChange.Stain;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(slot, cApply.Value, out rApplyStain, locked))
changes |= EquipChange.ApplyStain;
}
else
{
rApplyStain = true;
}
if (VerifyRestrictedGear(slot, rArmor, gender, race))
{
ImGui.SameLine();
ImGui.TextUnformatted("(Restricted)");
}
return changes;
}
public EquipChange DrawWeapons(in DesignData designData, out EquipItem rMainhand, out EquipItem rOffhand, out StainId rMainhandStain,
out StainId rOffhandStain, EquipFlag? cApply, 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,
out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked);
public EquipChange DrawWeapons(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)
{
var changes = EquipChange.None;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing,
ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y });
cMainhand.DrawIcon(_textures, _iconSize);
ImGui.SameLine();
using (var group = ImRaii.Group())
{
rOffhand = cOffhand;
if (DrawMainhand(cMainhand, cApply.HasValue, out rMainhand, out var mainhandLabel, locked))
{
changes |= EquipChange.Item;
if (rMainhand.Type.ValidOffhand() != cMainhand.Type.ValidOffhand())
{
rOffhand = _items.GetDefaultOffhand(rMainhand);
changes |= EquipChange.Item2;
}
}
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(EquipSlot.MainHand, cApply.Value, out rApplyMainhand, locked))
changes |= EquipChange.ApplyItem;
}
else
{
rApplyMainhand = true;
}
ImGui.SameLine();
ImGui.TextUnformatted(mainhandLabel);
if (DrawStain(EquipSlot.MainHand, cMainhandStain, out rMainhandStain, locked))
changes |= EquipChange.Stain;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(EquipSlot.MainHand, cApply.Value, out rApplyMainhandStain, locked))
changes |= EquipChange.ApplyStain;
}
else
{
rApplyMainhandStain = true;
}
}
if (rOffhand.Type is FullEquipType.Unknown)
{
rOffhandStain = cOffhandStain;
rApplyOffhand = false;
rApplyOffhandStain = false;
return changes;
}
rOffhand.DrawIcon(_textures, _iconSize);
ImGui.SameLine();
using (var group = ImRaii.Group())
{
if (DrawOffhand(rMainhand, rOffhand, out rOffhand, out var offhandLabel, locked))
changes |= EquipChange.Item2;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(EquipSlot.OffHand, cApply.Value, out rApplyOffhand, locked))
changes |= EquipChange.ApplyItem2;
}
else
{
rApplyOffhand = true;
}
ImGui.SameLine();
ImGui.TextUnformatted(offhandLabel);
if (DrawStain(EquipSlot.OffHand, cOffhandStain, out rOffhandStain, locked))
changes |= EquipChange.Stain2;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApplyStain(EquipSlot.OffHand, cApply.Value, out rApplyOffhandStain, locked))
changes |= EquipChange.ApplyStain2;
}
else
{
rApplyOffhandStain = true;
}
}
return changes;
}
public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon, out string label, bool locked)
{
weapon = current;
if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo))
{
label = string.Empty;
return false;
}
label = combo.Label;
using var disabled = ImRaii.Disabled(locked);
if (!combo.Draw(weapon.Name, weapon.ItemId, _comboLength))
return false;
weapon = combo.CurrentSelection;
return true;
}
public bool DrawOffhand(EquipItem mainhand, EquipItem current, out EquipItem weapon, out string label, bool locked)
{
weapon = current;
if (!_weaponCombo.TryGetValue(current.Type, out var combo))
{
label = string.Empty;
return false;
}
label = combo.Label;
using var disabled = ImRaii.Disabled(locked);
var change = combo.Draw(weapon.Name, weapon.ItemId, _comboLength);
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 (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
change = true;
weapon = defaultOffhand;
}
}
}
return change;
}
public 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);
public 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)
{
Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawItem)} on {slot}.");
var combo = _itemCombo[slot.ToIndex()]; var combo = _itemCombo[slot.ToIndex()];
label = combo.Label;
armor = current; armor = current;
var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.ItemId, _comboLength); using var disabled = ImRaii.Disabled(locked);
var change = combo.Draw(armor.Name, armor.ItemId, _comboLength);
if (change) if (change)
armor = combo.CurrentSelection; armor = combo.CurrentSelection;
if (armor.ModelId.Value != 0) if (!locked && armor.ModelId.Value != 0)
{ {
ImGuiUtil.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
@ -99,101 +323,34 @@ public class EquipmentDrawer
return change; return change;
} }
public bool DrawStain(StainId current, EquipSlot slot, out StainId ret) private bool DrawStain(EquipSlot slot, StainId current, out StainId ret, bool locked)
{ {
if (_codes.EnabledArtisan) var found = _stainData.TryGetValue(current, out var stain);
return DrawStainArtisan(current, slot, out ret); using var disabled = ImRaii.Disabled(locked);
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength);
var found = _stainData.TryGetValue(current, out var stain);
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength);
ret = current; ret = current;
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain)) if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain))
ret = stain.RowIndex; ret = stain.RowIndex;
ImGuiUtil.HoverTooltip("Right-click to clear."); if (!locked && ret != Stain.None.RowIndex)
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
ret = Stain.None.RowIndex;
change = true;
}
return change;
}
public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon)
{
weapon = current;
if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo))
return false;
if (!combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale))
return false;
weapon = combo.CurrentSelection;
return true;
}
public bool DrawOffhand(EquipItem current, FullEquipType mainType, out EquipItem weapon)
{
weapon = current;
var offType = mainType.Offhand();
if (offType == FullEquipType.Unknown)
return false;
if (!_weaponCombo.TryGetValue(offType, out var combo))
return false;
var change = combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale);
if (change)
{
weapon = combo.CurrentSelection;
}
else if (!offType.IsOffhandType() && weapon.ModelId.Value != 0)
{ {
ImGuiUtil.HoverTooltip("Right-click to clear."); ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{ {
ret = Stain.None.RowIndex;
change = true; change = true;
weapon = ItemManager.NothingItem(offType);
} }
} }
return change; return change;
} }
public bool DrawApply(Design design, EquipSlot slot, out bool enabled)
=> DrawCheckbox($"##apply{slot}", design.DoApplyEquip(slot), out enabled);
public bool DrawApplyStain(Design design, EquipSlot slot, out bool enabled)
=> DrawCheckbox($"##applyStain{slot}", design.DoApplyStain(slot), out enabled);
private static bool DrawCheckbox(string label, bool value, out bool on)
{
var ret = ImGuiUtil.Checkbox(label, string.Empty, value, v => value = v);
on = value;
return ret;
}
public bool DrawVisor(bool current, out bool on)
=> DrawCheckbox("##visorToggled", current, out on);
public bool DrawHat(bool current, out bool on)
=> DrawCheckbox("##hatVisible", current, out on);
public bool DrawWeapon(bool current, out bool on)
=> DrawCheckbox("##weaponVisible", current, out on);
public bool DrawWetness(bool current, out bool on)
=> DrawCheckbox("##wetness", current, out on);
/// <summary> Draw an input for armor that can set arbitrary values instead of choosing items. </summary> /// <summary> Draw an input for armor that can set arbitrary values instead of choosing items. </summary>
private bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, private bool DrawArmorArtisan(EquipSlot slot, EquipItem current, out EquipItem armor)
Race race = Race.Unknown)
{ {
using var id = ImRaii.PushId((int)slot); int setId = current.ModelId.Value;
int setId = current.ModelId.Value; int variant = current.Variant;
int variant = current.Variant; var ret = false;
var ret = false;
armor = current; armor = current;
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##setId", ref setId, 0, 0)) if (ImGui.InputInt("##setId", ref setId, 0, 0))
@ -222,10 +379,9 @@ public class EquipmentDrawer
} }
/// <summary> Draw an input for stain that can set arbitrary values instead of choosing valid stains. </summary> /// <summary> Draw an input for stain that can set arbitrary values instead of choosing valid stains. </summary>
private bool DrawStainArtisan(StainId current, EquipSlot slot, out StainId stain) private bool DrawStainArtisan(EquipSlot slot, StainId current, out StainId stain)
{ {
using var id = ImRaii.PushId((int)slot); int stainId = current.Value;
int stainId = current.Value;
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
if (ImGui.InputInt("##stain", ref stainId, 0, 0)) if (ImGui.InputInt("##stain", ref stainId, 0, 0))
{ {
@ -240,4 +396,31 @@ public class EquipmentDrawer
stain = current; stain = current;
return false; return false;
} }
private EquipChange DrawEquipArtisan(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain,
EquipFlag? cApply, out bool rApply, out bool rApplyStain)
{
var changes = EquipChange.None;
if (DrawStainArtisan(slot, cStain, out rStain))
changes |= EquipChange.Stain;
ImGui.SameLine();
if (DrawArmorArtisan(slot, cArmor, out rArmor))
changes |= EquipChange.Item;
if (cApply.HasValue)
{
ImGui.SameLine();
if (DrawApply(slot, cApply.Value, out rApply, false))
changes |= EquipChange.ApplyItem;
ImGui.SameLine();
if (DrawApplyStain(slot, cApply.Value, out rApplyStain, false))
changes |= EquipChange.ApplyStain;
}
else
{
rApply = false;
rApplyStain = false;
}
return changes;
}
} }

View file

@ -48,7 +48,7 @@ public sealed class ItemCombo : FilterComboCache<EquipItem>
public bool Draw(string previewName, uint previewIdx, float width) public bool Draw(string previewName, uint previewIdx, float width)
{ {
_currentItem = previewIdx; _currentItem = previewIdx;
return Draw(Label, previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
} }
protected override bool DrawSelectable(int globalIdx, bool selected) protected override bool DrawSelectable(int globalIdx, bool selected)

View file

@ -41,7 +41,7 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
public bool Draw(string previewName, uint previewId, float width) public bool Draw(string previewName, uint previewId, float width)
{ {
_currentItemId = previewId; _currentItemId = previewId;
return Draw(Label, previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing());
} }
protected override bool DrawSelectable(int globalIdx, bool selected) protected override bool DrawSelectable(int globalIdx, bool selected)

View file

@ -45,7 +45,7 @@ public class MainWindow : Window
pi.UiBuilder.DisableGposeUiHide = true; pi.UiBuilder.DisableGposeUiHide = true;
SizeConstraints = new WindowSizeConstraints() SizeConstraints = new WindowSizeConstraints()
{ {
MinimumSize = new Vector2(675, 675), MinimumSize = new Vector2(700, 675),
MaximumSize = ImGui.GetIO().DisplaySize, MaximumSize = ImGui.GetIO().DisplaySize,
}; };
Settings = settings; Settings = settings;

View file

@ -177,7 +177,7 @@ public class PenumbraChangedItemTooltip : IDisposable
if (slot == EquipSlot.MainHand) if (slot == EquipSlot.MainHand)
return item.Type == mainItem.Type; return item.Type == mainItem.Type;
return item.Type == mainItem.Type.Offhand(); return item.Type == mainItem.Type.ValidOffhand();
} }
private void OnPenumbraClick(MouseButton button, ChangedItemType type, uint id) private void OnPenumbraClick(MouseButton button, ChangedItemType type, uint id)

View file

@ -69,8 +69,11 @@ public class ActorPanel
{ {
var textColor = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) : var textColor = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) :
_data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value(); _data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
HeaderDrawer.Draw(_actorName, textColor, ImGui.GetColorU32(ImGuiCol.FrameBg), 0, HeaderDrawer.Draw(_actorName, textColor, ImGui.GetColorU32(ImGuiCol.FrameBg),
3, SetFromClipboardButton(), ExportToClipboardButton(), SaveAsDesignButton(), LockedButton(),
HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v));
SaveDesignDrawPopup();
} }
private (string, Actor) GetHeaderName() private (string, Actor) GetHeaderName()
@ -90,12 +93,6 @@ public class ActorPanel
if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state)) if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
return; return;
SetFromClipboard();
ImGui.SameLine();
ExportToClipboardButton();
ImGui.SameLine();
SaveDesignButton();
ImGui.SameLine();
DrawApplyToSelf(); DrawApplyToSelf();
ImGui.SameLine(); ImGui.SameLine();
DrawApplyToTarget(); DrawApplyToTarget();
@ -116,36 +113,40 @@ public class ActorPanel
_equipmentDrawer.Prepare(); _equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots) foreach (var slot in EquipSlotExtensions.EqdpSlots)
{ {
var stain = _state.ModelData.Stain(slot); var changes = _equipmentDrawer.DrawEquip(slot, _state.ModelData, out var newArmor, out var newStain, null, out _, out _,
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain)) _state.IsLocked);
_stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual); switch (changes)
{
ImGui.SameLine(); case EquipmentDrawer.EquipChange.Item:
var armor = _state.ModelData.Item(slot); _stateManager.ChangeItem(_state, slot, newArmor, StateChanged.Source.Manual);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _state.ModelData.Customize.Gender, _state.ModelData.Customize.Race)) break;
_stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual); case EquipmentDrawer.EquipChange.Stain:
_stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual);
break;
case EquipmentDrawer.EquipChange.Item | EquipmentDrawer.EquipChange.Stain:
_stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual);
break;
}
} }
var mhStain = _state.ModelData.Stain(EquipSlot.MainHand); var weaponChanges = _equipmentDrawer.DrawWeapons(_state.ModelData, out var newMainhand, out var newOffhand, out var newMainhandStain,
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain)) out var newOffhandStain, null, out _, out _, out _, out _, _state.IsLocked);
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMhStain, StateChanged.Source.Manual);
ImGui.SameLine(); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item))
var mh = _state.ModelData.Item(EquipSlot.MainHand); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
if (_equipmentDrawer.DrawMainhand(mh, false, out var newMh)) _stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMainhand, newMainhandStain, StateChanged.Source.Manual);
_stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMh, newMhStain, StateChanged.Source.Manual); else
_stateManager.ChangeItem(_state, EquipSlot.MainHand, newMainhand, StateChanged.Source.Manual);
else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMainhandStain, StateChanged.Source.Manual);
if (newMh.Type.Offhand() is not FullEquipType.Unknown) if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
{ if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
var ohStain = _state.ModelData.Stain(EquipSlot.OffHand); _stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOffhand, newOffhandStain, StateChanged.Source.Manual);
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain)) else
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOhStain, StateChanged.Source.Manual); _stateManager.ChangeItem(_state, EquipSlot.OffHand, newOffhand, StateChanged.Source.Manual);
else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
ImGui.SameLine(); _stateManager.ChangeStain(_state, EquipSlot.OffHand, newOffhandStain, StateChanged.Source.Manual);
var oh = _state.ModelData.Item(EquipSlot.OffHand);
if (_equipmentDrawer.DrawOffhand(oh, newMh.Type, out var newOh))
_stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOh, newOhStain, StateChanged.Source.Manual);
}
} }
private void DrawMonsterPanel() private void DrawMonsterPanel()
@ -209,12 +210,68 @@ public class ActorPanel
_stateManager.TurnHuman(_state, StateChanged.Source.Manual); _stateManager.TurnHuman(_state, StateChanged.Source.Manual);
} }
private void SetFromClipboard() private HeaderDrawer.Button SetFromClipboardButton()
=> new()
{
Description = "Try to apply a design from your clipboard.",
Icon = FontAwesomeIcon.Clipboard,
OnClick = SetFromClipboard,
Visible = _state != null,
};
private HeaderDrawer.Button ExportToClipboardButton()
=> new()
{
Description = "Copy the current design to your clipboard.",
Icon = FontAwesomeIcon.Copy,
OnClick = ExportToClipboard,
Visible = _state?.ModelData.IsHuman ?? false,
};
private HeaderDrawer.Button SaveAsDesignButton()
=> new()
{
Description = "Save the current state as a design.",
Icon = FontAwesomeIcon.Save,
OnClick = SaveDesignOpen,
Visible = _state?.ModelData.IsHuman ?? false,
};
private HeaderDrawer.Button LockedButton()
=> new()
{
Description = "The current state of this actor is locked by external tools.",
Icon = FontAwesomeIcon.Lock,
OnClick = () => { },
Disabled = true,
Visible = _state?.IsLocked ?? false,
TextColor = ColorId.ActorUnavailable.Value(),
BorderColor = ColorId.ActorUnavailable.Value(),
};
private string _newName = string.Empty;
private DesignBase? _newDesign = null;
private void SaveDesignOpen()
{ {
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), new Vector2(ImGui.GetFrameHeight()), ImGui.OpenPopup("Save as Design");
"Try to apply a design from your clipboard.", false, true)) _newName = _state!.Identifier.ToName();
_newDesign = _converter.Convert(_state, EquipFlagExtensions.All, CustomizeFlagExtensions.All);
}
private void SaveDesignDrawPopup()
{
if (!ImGuiUtil.OpenNameField("Save as Design", ref _newName))
return; return;
if (_newDesign != null && _newName.Length > 0)
_designManager.CreateClone(_newDesign, _newName);
_newDesign = null;
_newName = string.Empty;
}
private void SetFromClipboard()
{
try try
{ {
var text = ImGui.GetClipboardText(); var text = ImGui.GetClipboardText();
@ -228,12 +285,8 @@ public class ActorPanel
} }
} }
private void ExportToClipboardButton() private void ExportToClipboard()
{ {
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Copy.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Copy the current design to your clipboard.", false, true))
return;
try try
{ {
var text = _converter.ShareBase64(_state!); var text = _converter.ShareBase64(_state!);
@ -267,7 +320,7 @@ public class ActorPanel
{ {
var (id, data) = _objects.PlayerData; var (id, data) = _objects.PlayerData;
if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero, "Apply the current state to your own character.", if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero, "Apply the current state to your own character.",
!data.Valid || id == _identifier)) !data.Valid || id == _identifier || !_state!.ModelData.IsHuman))
return; return;
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
@ -283,33 +336,11 @@ public class ActorPanel
? "Apply the current state to your current target." ? "Apply the current state to your current target."
: "The current target can not be manipulated." : "The current target can not be manipulated."
: "No valid target selected."; : "No valid target selected.";
if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid || id == _identifier)) if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid || id == _identifier || !_state!.ModelData.IsHuman))
return; return;
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
_stateManager.ApplyDesign(_converter.Convert(_state!, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant), state, _stateManager.ApplyDesign(_converter.Convert(_state!, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant), state,
StateChanged.Source.Manual); StateChanged.Source.Manual);
} }
private string _newName = string.Empty;
private DesignBase? _newDesign = null;
private void SaveDesignButton()
{
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Save the current state as a design.", !_state!.ModelData.IsHuman, true))
{
ImGui.OpenPopup("Save as Design");
_newName = _state.Identifier.ToName();
_newDesign = _converter.Convert(_state, EquipFlagExtensions.All, CustomizeFlagExtensions.All);
}
if (ImGuiUtil.OpenNameField("Save as Design", ref _newName))
{
if (_newDesign != null && _newName.Length > 0)
_designManager.CreateClone(_newDesign, _newName);
_newDesign = null;
_newName = string.Empty;
}
}
} }

View file

@ -57,23 +57,39 @@ public class DesignPanel
: _selector.Selected.WriteProtected() : _selector.Selected.WriteProtected()
? new HeaderDrawer.Button ? new HeaderDrawer.Button
{ {
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Make this design editable.", Description = "Make this design editable.",
Icon = FontAwesomeIcon.Lock, Icon = FontAwesomeIcon.Lock,
OnClick = () => _manager.SetWriteProtection(_selector.Selected!, false), OnClick = () => _manager.SetWriteProtection(_selector.Selected!, false),
} }
: new HeaderDrawer.Button : new HeaderDrawer.Button
{ {
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Write-protect this design.", Description = "Write-protect this design.",
Icon = FontAwesomeIcon.LockOpen, Icon = FontAwesomeIcon.LockOpen,
OnClick = () => _manager.SetWriteProtection(_selector.Selected!, true), 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() private void DrawHeader()
=> HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), 0, LockButton(), => HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg),
2, SetFromClipboardButton(), ExportToClipboardButton(), LockButton(),
HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v));
private string SelectionName private string SelectionName
@ -117,37 +133,37 @@ public class DesignPanel
_equipmentDrawer.Prepare(); _equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots) foreach (var slot in EquipSlotExtensions.EqdpSlots)
{ {
var stain = _selector.Selected!.DesignData.Stain(slot); var changes = _equipmentDrawer.DrawEquip(slot, _selector.Selected!.DesignData, out var newArmor, out var newStain,
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain)) _selector.Selected.ApplyEquip, out var newApply, out var newApplyStain, _selector.Selected!.WriteProtected());
_manager.ChangeStain(_selector.Selected!, slot, newStain); if (changes.HasFlag(EquipmentDrawer.EquipChange.Item))
_manager.ChangeEquip(_selector.Selected, slot, newArmor);
ImGui.SameLine(); if (changes.HasFlag(EquipmentDrawer.EquipChange.Stain))
var armor = _selector.Selected!.DesignData.Item(slot); _manager.ChangeStain(_selector.Selected, slot, newStain);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _selector.Selected!.DesignData.Customize.Gender, if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
_selector.Selected!.DesignData.Customize.Race)) _manager.ChangeApplyEquip(_selector.Selected, slot, newApply);
_manager.ChangeEquip(_selector.Selected!, slot, newArmor); if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
_manager.ChangeApplyStain(_selector.Selected, slot, newApplyStain);
} }
var mhStain = _selector.Selected!.DesignData.Stain(EquipSlot.MainHand); var weaponChanges = _equipmentDrawer.DrawWeapons(_selector.Selected!.DesignData, out var newMainhand, out var newOffhand,
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain)) out var newMainhandStain, out var newOffhandStain, _selector.Selected.ApplyEquip, out var applyMain, out var applyMainStain,
_manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain); out var applyOff, out var applyOffStain, _selector.Selected!.WriteProtected());
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item))
ImGui.SameLine(); _manager.ChangeWeapon(_selector.Selected, EquipSlot.MainHand, newMainhand);
var mh = _selector.Selected!.DesignData.Item(EquipSlot.MainHand); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
if (_equipmentDrawer.DrawMainhand(mh, true, out var newMh)) _manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newMainhandStain);
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.MainHand, newMh); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.MainHand, applyMain);
if (newMh.Type.Offhand() is not FullEquipType.Unknown) if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
{ _manager.ChangeApplyStain(_selector.Selected, EquipSlot.MainHand, applyMainStain);
var ohStain = _selector.Selected!.DesignData.Stain(EquipSlot.OffHand); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain)) _manager.ChangeWeapon(_selector.Selected, EquipSlot.OffHand, newOffhand);
_manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
_manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newOffhandStain);
ImGui.SameLine(); if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem2))
var oh = _selector.Selected!.DesignData.Item(EquipSlot.OffHand); _manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff);
if (_equipmentDrawer.DrawOffhand(oh, newMh.Type, out var newOh)) if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain2))
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.OffHand, newOh); _manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain);
}
} }
private void DrawCustomize() private void DrawCustomize()
@ -279,21 +295,13 @@ public class DesignPanel
private void DrawButtonRow() private void DrawButtonRow()
{ {
SetFromClipboardButton();
ImGui.SameLine();
ExportToClipboardButton();
ImGui.SameLine();
DrawApplyToSelf(); DrawApplyToSelf();
ImGui.SameLine(); ImGui.SameLine();
DrawApplyToTarget(); DrawApplyToTarget();
} }
private void SetFromClipboardButton() private void SetFromClipboard()
{ {
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Try to apply a design from your clipboard.", _selector.Selected!.WriteProtected(), true))
return;
try try
{ {
var text = ImGui.GetClipboardText(); var text = ImGui.GetClipboardText();
@ -307,12 +315,8 @@ public class DesignPanel
} }
} }
private void ExportToClipboardButton() private void ExportToClipboard()
{ {
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Copy.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
"Copy the current design to your clipboard.", false, true))
return;
try try
{ {
var text = _converter.ShareBase64(_selector.Selected!); var text = _converter.ShareBase64(_selector.Selected!);

View file

@ -29,9 +29,11 @@ public static class HeaderDrawer
public Button() public Button()
{ {
Visible = true; Visible = true;
Width = ImGui.GetFrameHeightWithSpacing(); Width = ImGui.GetFrameHeightWithSpacing();
Disabled = false; BorderColor = ColorId.HeaderButtons.Value();
TextColor = ColorId.HeaderButtons.Value();
Disabled = false;
} }
public readonly void Draw() public readonly void Draw()
@ -41,24 +43,22 @@ public static class HeaderDrawer
using var color = ImRaii.PushColor(ImGuiCol.Border, BorderColor) using var color = ImRaii.PushColor(ImGuiCol.Border, BorderColor)
.Push(ImGuiCol.Text, TextColor, TextColor != 0); .Push(ImGuiCol.Text, TextColor, TextColor != 0);
if (ImGuiUtil.DrawDisabledButton(Icon.ToIconString(), new Vector2(Width, ImGui.GetFrameHeight()), Description, Disabled, true)) if (ImGuiUtil.DrawDisabledButton(Icon.ToIconString(), new Vector2(Width, ImGui.GetFrameHeight()), string.Empty, Disabled, true))
OnClick?.Invoke(); OnClick?.Invoke();
color.Pop();
ImGuiUtil.HoverTooltip(Description);
} }
public static Button IncognitoButton(bool current, Action<bool> setter) public static Button IncognitoButton(bool current, Action<bool> setter)
=> current => current
? new Button ? new Button
{ {
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Toggle incognito mode off.", Description = "Toggle incognito mode off.",
Icon = FontAwesomeIcon.EyeSlash, Icon = FontAwesomeIcon.EyeSlash,
OnClick = () => setter(false), OnClick = () => setter(false),
} }
: new Button : new Button
{ {
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Toggle incognito mode on.", Description = "Toggle incognito mode on.",
Icon = FontAwesomeIcon.Eye, Icon = FontAwesomeIcon.Eye,
OnClick = () => setter(true), OnClick = () => setter(true),
@ -83,7 +83,7 @@ public static class HeaderDrawer
var midSize = ImGui.GetContentRegionAvail().X - rightButtonSize - ImGuiHelpers.GlobalScale; var midSize = ImGui.GetContentRegionAvail().X - rightButtonSize - ImGuiHelpers.GlobalScale;
style.Pop(); style.Pop();
style.Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.5f + (rightButtonSize - leftButtonSize) / 2 / midSize, 0.5f)); style.Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.5f + (rightButtonSize - leftButtonSize) / midSize, 0.5f));
if (textColor != 0) if (textColor != 0)
ImGuiUtil.DrawTextButton(text, new Vector2(midSize, ImGui.GetFrameHeight()), frameColor, textColor); ImGuiUtil.DrawTextButton(text, new Vector2(midSize, ImGui.GetFrameHeight()), frameColor, textColor);
else else

View file

@ -177,7 +177,7 @@ public class UnlockOverview
ImGui.TextUnformatted(item.Name); ImGui.TextUnformatted(item.Name);
var slot = item.Type.ToSlot(); var slot = item.Type.ToSlot();
ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})"); ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})");
if (item.Type.Offhand().IsOffhandType()) if (item.Type.ValidOffhand().IsOffhandType())
ImGui.TextUnformatted( ImGui.TextUnformatted(
$"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}"); $"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}");
else else

View file

@ -241,7 +241,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
ImGui.AlignTextToFramePadding(); ImGui.AlignTextToFramePadding();
ImGuiUtil.RightAlign(item.ModelString); ImGuiUtil.RightAlign(item.ModelString);
if (ImGui.IsItemHovered() if (ImGui.IsItemHovered()
&& item.Type.Offhand().IsOffhandType() && item.Type.ValidOffhand().IsOffhandType()
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand)) && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
{ {
using var tt = ImRaii.Tooltip(); using var tt = ImRaii.Tooltip();
@ -260,7 +260,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase)) if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase))
return true; return true;
if (item.Type.Offhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand)) if (item.Type.ValidOffhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
return FilterRegex?.IsMatch(offhand.ModelString) return FilterRegex?.IsMatch(offhand.ModelString)
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase); ?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);

View file

@ -1,16 +1,15 @@
using System.Numerics; using System.Numerics;
using Dalamud.Interface; using Dalamud.Interface;
using Glamourer.Services; using Glamourer.Services;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
namespace Glamourer.Gui; namespace Glamourer.Gui;
public static class UiHelpers public static class UiHelpers
{ {
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size) public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size)
{ {
var isEmpty = item.ModelId.Value == 0; var isEmpty = item.ModelId.Value == 0;
@ -31,4 +30,25 @@ public static class UiHelpers
ImGuiUtil.HoverIcon(ptr, textureSize, size); ImGuiUtil.HoverIcon(ptr, textureSize, size);
} }
} }
}
public static bool DrawCheckbox(string label, string tooltip, bool value, out bool on, bool locked)
{
using var disabled = ImRaii.Disabled(locked);
var ret = ImGuiUtil.Checkbox(label, string.Empty, value, v => value = v);
ImGuiUtil.HoverTooltip(tooltip);
on = value;
return ret;
}
public static bool DrawVisor(bool current, out bool on, bool locked)
=> DrawCheckbox("##visorToggled", string.Empty, current, out on, locked);
public static bool DrawHat(bool current, out bool on, bool locked)
=> DrawCheckbox("##hatVisible", string.Empty, current, out on, locked);
public static bool DrawWeapon(bool current, out bool on, bool locked)
=> DrawCheckbox("##weaponVisible", string.Empty, current, out on, locked);
public static bool DrawWetness(bool current, out bool on, bool locked)
=> DrawCheckbox("##wetness", string.Empty, current, out on, locked);
}

View file

@ -40,9 +40,7 @@ public unsafe class WeaponService : IDisposable
private readonly Hook<LoadWeaponDelegate> _loadWeaponHook; private readonly Hook<LoadWeaponDelegate> _loadWeaponHook;
private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, byte skipGameObject, byte unk4)
byte skipGameObject,
byte unk4)
{ {
var actor = (Actor)((nint*)drawData)[1]; var actor = (Actor)((nint*)drawData)[1];
var weapon = new CharacterWeapon(weaponValue); var weapon = new CharacterWeapon(weaponValue);
@ -61,7 +59,7 @@ public unsafe class WeaponService : IDisposable
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4); _loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
if (tmpWeapon.Value != weapon.Value) if (tmpWeapon.Value != weapon.Value)
_loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4); _loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4);
Glamourer.Log.Excessive( Glamourer.Log.Information(
$"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}"); $"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}");
} }

View file

@ -7,7 +7,6 @@ using Lumina.Excel;
using Penumbra.GameData.Data; using Penumbra.GameData.Data;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs; using Penumbra.GameData.Structs;
using static OtterGui.Raii.ImRaii;
using Race = Penumbra.GameData.Enums.Race; using Race = Penumbra.GameData.Enums.Race;
namespace Glamourer.Services; namespace Glamourer.Services;
@ -116,12 +115,21 @@ public class ItemManager : IDisposable
} }
} }
/// <summary> Return the default offhand for a given mainhand, that is for both handed weapons, return the correct offhand part, and for everything else Nothing. </summary>
public EquipItem GetDefaultOffhand(EquipItem mainhand)
{
var offhandType = mainhand.Type.ValidOffhand();
if (offhandType.IsOffhandType())
return Resolve(offhandType, mainhand.ItemId);
return NothingItem(offhandType);
}
public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, byte variant, FullEquipType mainhandType = FullEquipType.Unknown) public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, byte variant, FullEquipType mainhandType = FullEquipType.Unknown)
{ {
if (slot is EquipSlot.OffHand) if (slot is EquipSlot.OffHand)
{ {
var weaponType = mainhandType.Offhand(); var weaponType = mainhandType.ValidOffhand();
if (id.Value == 0) if (id.Value == 0)
return NothingItem(weaponType); return NothingItem(weaponType);
} }
@ -161,7 +169,7 @@ public class ItemManager : IDisposable
return allowUnknown ? string.Empty : $"The item {itemId} yields an unknown item."; return allowUnknown ? string.Empty : $"The item {itemId} yields an unknown item.";
} }
if (IsItemValid(slot, (uint) itemId, out item)) if (IsItemValid(slot, (uint)itemId, out item))
return string.Empty; return string.Empty;
item = NothingItem(slot); item = NothingItem(slot);
@ -201,7 +209,7 @@ public class ItemManager : IDisposable
/// <summary> Returns whether an offhand is valid given mainhand. </summary> /// <summary> Returns whether an offhand is valid given mainhand. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
public bool IsOffhandValid(in EquipItem main, uint offId, out EquipItem off) public bool IsOffhandValid(in EquipItem main, uint offId, out EquipItem off)
=> IsOffhandValid(main.Type.Offhand(), offId, out off); => IsOffhandValid(main.Type.ValidOffhand(), offId, out off);
/// <summary> /// <summary>
/// Check whether a combination of an item id for a mainhand and for an offhand is valid. /// Check whether a combination of an item id for a mainhand and for an offhand is valid.
@ -219,7 +227,7 @@ public class ItemManager : IDisposable
ret = $"The mainhand weapon {mainId} does not exist, reset to default sword."; ret = $"The mainhand weapon {mainId} does not exist, reset to default sword.";
} }
var offType = main.Type.Offhand(); var offType = main.Type.ValidOffhand();
if (IsOffhandValid(offType, offId, out off)) if (IsOffhandValid(offType, offId, out off))
return ret; return ret;

View file

@ -172,7 +172,7 @@ public class StateApplier
/// </summary> /// </summary>
public void ChangeMainhand(ActorData data, EquipItem weapon, StainId stain) public void ChangeMainhand(ActorData data, EquipItem weapon, StainId stain)
{ {
var slot = weapon.Type.Offhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand; var slot = weapon.Type.ValidOffhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand;
foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) foreach (var actor in data.Objects.Where(a => a.Model.IsHuman))
_weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain)); _weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain));
} }

View file

@ -138,7 +138,7 @@ public class StateEditor
// Can not change weapon type from expected type in state. // Can not change weapon type from expected type in state.
if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType
|| slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.Offhand()) || slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.ValidOffhand())
return false; return false;
state.ModelData.SetItem(slot, item); state.ModelData.SetItem(slot, item);