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.SetStain(EquipSlot.MainHand, cur[0].Stain);
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.");
data.SetItem(EquipSlot.OffHand, off);

View file

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

View file

@ -7,6 +7,7 @@ using Dalamud.Data;
using Dalamud.Interface;
using Glamourer.Designs;
using Glamourer.Services;
using Glamourer.Structs;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
@ -33,7 +34,7 @@ public class EquipmentDrawer
_codes = codes;
_textures = textures;
_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))));
_itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray();
_weaponCombo = new Dictionary<FullEquipType, WeaponCombo>(FullEquipTypeExtensions.WeaponTypes.Count * 2);
@ -54,39 +55,262 @@ public class EquipmentDrawer
public void Prepare()
{
_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())
return gear.Name;
return false;
var (changed, _) = _items.ResolveRestrictedGear(gear.Armor(), slot, race, gender);
if (changed)
return gear.Name + " (Restricted)";
return gear.Name;
return changed;
}
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)
return DrawArmorArtisan(current, slot, out armor, gender, race);
public EquipChange 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);
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();
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()];
label = combo.Label;
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)
armor = combo.CurrentSelection;
if (armor.ModelId.Value != 0)
if (!locked && armor.ModelId.Value != 0)
{
ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
@ -99,101 +323,34 @@ public class EquipmentDrawer
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)
return DrawStainArtisan(current, slot, out ret);
var found = _stainData.TryGetValue(current, out var stain);
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength);
var found = _stainData.TryGetValue(current, out var stain);
using var disabled = ImRaii.Disabled(locked);
var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength);
ret = current;
if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain))
ret = stain.RowIndex;
ImGuiUtil.HoverTooltip("Right-click to clear.");
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)
if (!locked && ret != Stain.None.RowIndex)
{
ImGuiUtil.HoverTooltip("Right-click to clear.");
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
ret = Stain.None.RowIndex;
change = true;
weapon = ItemManager.NothingItem(offType);
}
}
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>
private bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown,
Race race = Race.Unknown)
private bool DrawArmorArtisan(EquipSlot slot, EquipItem current, out EquipItem armor)
{
using var id = ImRaii.PushId((int)slot);
int setId = current.ModelId.Value;
int variant = current.Variant;
var ret = false;
int setId = current.ModelId.Value;
int variant = current.Variant;
var ret = false;
armor = current;
ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale);
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>
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);
if (ImGui.InputInt("##stain", ref stainId, 0, 0))
{
@ -240,4 +396,31 @@ public class EquipmentDrawer
stain = current;
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)
{
_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)

View file

@ -41,7 +41,7 @@ public sealed class WeaponCombo : FilterComboCache<EquipItem>
public bool Draw(string previewName, uint previewId, float width)
{
_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)

View file

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

View file

@ -177,7 +177,7 @@ public class PenumbraChangedItemTooltip : IDisposable
if (slot == EquipSlot.MainHand)
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)

View file

@ -69,8 +69,11 @@ public class ActorPanel
{
var textColor = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) :
_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));
SaveDesignDrawPopup();
}
private (string, Actor) GetHeaderName()
@ -90,12 +93,6 @@ public class ActorPanel
if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state))
return;
SetFromClipboard();
ImGui.SameLine();
ExportToClipboardButton();
ImGui.SameLine();
SaveDesignButton();
ImGui.SameLine();
DrawApplyToSelf();
ImGui.SameLine();
DrawApplyToTarget();
@ -116,36 +113,40 @@ public class ActorPanel
_equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var stain = _state.ModelData.Stain(slot);
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
_stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual);
ImGui.SameLine();
var armor = _state.ModelData.Item(slot);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _state.ModelData.Customize.Gender, _state.ModelData.Customize.Race))
_stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual);
var changes = _equipmentDrawer.DrawEquip(slot, _state.ModelData, out var newArmor, out var newStain, null, out _, out _,
_state.IsLocked);
switch (changes)
{
case EquipmentDrawer.EquipChange.Item:
_stateManager.ChangeItem(_state, slot, newArmor, StateChanged.Source.Manual);
break;
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);
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMhStain, StateChanged.Source.Manual);
var weaponChanges = _equipmentDrawer.DrawWeapons(_state.ModelData, out var newMainhand, out var newOffhand, out var newMainhandStain,
out var newOffhandStain, null, out _, out _, out _, out _, _state.IsLocked);
ImGui.SameLine();
var mh = _state.ModelData.Item(EquipSlot.MainHand);
if (_equipmentDrawer.DrawMainhand(mh, false, out var newMh))
_stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMh, newMhStain, StateChanged.Source.Manual);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item))
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.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(EquipmentDrawer.EquipChange.Stain))
_stateManager.ChangeStain(_state, EquipSlot.MainHand, newMainhandStain, StateChanged.Source.Manual);
if (newMh.Type.Offhand() is not FullEquipType.Unknown)
{
var ohStain = _state.ModelData.Stain(EquipSlot.OffHand);
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOhStain, StateChanged.Source.Manual);
ImGui.SameLine();
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);
}
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.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(EquipmentDrawer.EquipChange.Stain2))
_stateManager.ChangeStain(_state, EquipSlot.OffHand, newOffhandStain, StateChanged.Source.Manual);
}
private void DrawMonsterPanel()
@ -209,12 +210,68 @@ public class ActorPanel
_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()),
"Try to apply a design from your clipboard.", false, true))
ImGui.OpenPopup("Save as Design");
_newName = _state!.Identifier.ToName();
_newDesign = _converter.Convert(_state, EquipFlagExtensions.All, CustomizeFlagExtensions.All);
}
private void SaveDesignDrawPopup()
{
if (!ImGuiUtil.OpenNameField("Save as Design", ref _newName))
return;
if (_newDesign != null && _newName.Length > 0)
_designManager.CreateClone(_newDesign, _newName);
_newDesign = null;
_newName = string.Empty;
}
private void SetFromClipboard()
{
try
{
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
{
var text = _converter.ShareBase64(_state!);
@ -267,7 +320,7 @@ public class ActorPanel
{
var (id, data) = _objects.PlayerData;
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;
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."
: "The current target can not be manipulated."
: "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;
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
_stateManager.ApplyDesign(_converter.Convert(_state!, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant), state,
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()
? new HeaderDrawer.Button
{
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Make this design editable.",
Icon = FontAwesomeIcon.Lock,
OnClick = () => _manager.SetWriteProtection(_selector.Selected!, false),
}
: new HeaderDrawer.Button
{
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
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), 0, LockButton(),
=> HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg),
2, SetFromClipboardButton(), ExportToClipboardButton(), LockButton(),
HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v));
private string SelectionName
@ -117,37 +133,37 @@ public class DesignPanel
_equipmentDrawer.Prepare();
foreach (var slot in EquipSlotExtensions.EqdpSlots)
{
var stain = _selector.Selected!.DesignData.Stain(slot);
if (_equipmentDrawer.DrawStain(stain, slot, out var newStain))
_manager.ChangeStain(_selector.Selected!, slot, newStain);
ImGui.SameLine();
var armor = _selector.Selected!.DesignData.Item(slot);
if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _selector.Selected!.DesignData.Customize.Gender,
_selector.Selected!.DesignData.Customize.Race))
_manager.ChangeEquip(_selector.Selected!, slot, newArmor);
var 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(EquipmentDrawer.EquipChange.Item))
_manager.ChangeEquip(_selector.Selected, slot, newArmor);
if (changes.HasFlag(EquipmentDrawer.EquipChange.Stain))
_manager.ChangeStain(_selector.Selected, slot, newStain);
if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
_manager.ChangeApplyEquip(_selector.Selected, slot, newApply);
if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
_manager.ChangeApplyStain(_selector.Selected, slot, newApplyStain);
}
var mhStain = _selector.Selected!.DesignData.Stain(EquipSlot.MainHand);
if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain))
_manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain);
ImGui.SameLine();
var mh = _selector.Selected!.DesignData.Item(EquipSlot.MainHand);
if (_equipmentDrawer.DrawMainhand(mh, true, out var newMh))
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.MainHand, newMh);
if (newMh.Type.Offhand() is not FullEquipType.Unknown)
{
var ohStain = _selector.Selected!.DesignData.Stain(EquipSlot.OffHand);
if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain))
_manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain);
ImGui.SameLine();
var oh = _selector.Selected!.DesignData.Item(EquipSlot.OffHand);
if (_equipmentDrawer.DrawOffhand(oh, newMh.Type, out var newOh))
_manager.ChangeWeapon(_selector.Selected!, EquipSlot.OffHand, newOh);
}
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(EquipmentDrawer.EquipChange.Item))
_manager.ChangeWeapon(_selector.Selected, EquipSlot.MainHand, newMainhand);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain))
_manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newMainhandStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem))
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.MainHand, applyMain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain))
_manager.ChangeApplyStain(_selector.Selected, EquipSlot.MainHand, applyMainStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2))
_manager.ChangeWeapon(_selector.Selected, EquipSlot.OffHand, newOffhand);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2))
_manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newOffhandStain);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem2))
_manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff);
if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain2))
_manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain);
}
private void DrawCustomize()
@ -279,21 +295,13 @@ public class DesignPanel
private void DrawButtonRow()
{
SetFromClipboardButton();
ImGui.SameLine();
ExportToClipboardButton();
ImGui.SameLine();
DrawApplyToSelf();
ImGui.SameLine();
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
{
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
{
var text = _converter.ShareBase64(_selector.Selected!);

View file

@ -29,9 +29,11 @@ public static class HeaderDrawer
public Button()
{
Visible = true;
Width = ImGui.GetFrameHeightWithSpacing();
Disabled = false;
Visible = true;
Width = ImGui.GetFrameHeightWithSpacing();
BorderColor = ColorId.HeaderButtons.Value();
TextColor = ColorId.HeaderButtons.Value();
Disabled = false;
}
public readonly void Draw()
@ -41,24 +43,22 @@ public static class HeaderDrawer
using var color = ImRaii.PushColor(ImGuiCol.Border, BorderColor)
.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();
color.Pop();
ImGuiUtil.HoverTooltip(Description);
}
public static Button IncognitoButton(bool current, Action<bool> setter)
=> current
? new Button
{
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Toggle incognito mode off.",
Icon = FontAwesomeIcon.EyeSlash,
OnClick = () => setter(false),
}
: new Button
{
BorderColor = ColorId.HeaderButtons.Value(),
TextColor = ColorId.HeaderButtons.Value(),
Description = "Toggle incognito mode on.",
Icon = FontAwesomeIcon.Eye,
OnClick = () => setter(true),
@ -83,7 +83,7 @@ public static class HeaderDrawer
var midSize = ImGui.GetContentRegionAvail().X - rightButtonSize - ImGuiHelpers.GlobalScale;
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)
ImGuiUtil.DrawTextButton(text, new Vector2(midSize, ImGui.GetFrameHeight()), frameColor, textColor);
else

View file

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

View file

@ -241,7 +241,7 @@ public class UnlockTable : Table<EquipItem>, IDisposable
ImGui.AlignTextToFramePadding();
ImGuiUtil.RightAlign(item.ModelString);
if (ImGui.IsItemHovered()
&& item.Type.Offhand().IsOffhandType()
&& item.Type.ValidOffhand().IsOffhandType()
&& _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand))
{
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))
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)
?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase);

View file

@ -1,16 +1,15 @@
using System.Numerics;
using Dalamud.Interface;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
public static class UiHelpers
{
public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size)
{
var isEmpty = item.ModelId.Value == 0;
@ -31,4 +30,25 @@ public static class UiHelpers
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 void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2,
byte skipGameObject,
byte unk4)
private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, byte skipGameObject, byte unk4)
{
var actor = (Actor)((nint*)drawData)[1];
var weapon = new CharacterWeapon(weaponValue);
@ -61,7 +59,7 @@ public unsafe class WeaponService : IDisposable
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
if (tmpWeapon.Value != weapon.Value)
_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}");
}

View file

@ -7,7 +7,6 @@ using Lumina.Excel;
using Penumbra.GameData.Data;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
using static OtterGui.Raii.ImRaii;
using Race = Penumbra.GameData.Enums.Race;
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)
{
if (slot is EquipSlot.OffHand)
{
var weaponType = mainhandType.Offhand();
var weaponType = mainhandType.ValidOffhand();
if (id.Value == 0)
return NothingItem(weaponType);
}
@ -161,7 +169,7 @@ public class ItemManager : IDisposable
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;
item = NothingItem(slot);
@ -201,7 +209,7 @@ public class ItemManager : IDisposable
/// <summary> Returns whether an offhand is valid given mainhand. </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
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>
/// 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.";
}
var offType = main.Type.Offhand();
var offType = main.Type.ValidOffhand();
if (IsOffhandValid(offType, offId, out off))
return ret;

View file

@ -172,7 +172,7 @@ public class StateApplier
/// </summary>
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))
_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.
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;
state.ModelData.SetItem(slot, item);