This commit is contained in:
Ottermandias 2022-08-23 18:06:28 +02:00
parent cb2e2f0128
commit 941bba1518
39 changed files with 2569 additions and 1579 deletions

View file

@ -1,12 +1,14 @@
using System;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
using Glamourer.Interop;
using Glamourer.State;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
@ -14,8 +16,15 @@ internal partial class Interface
{
private class ActorTab
{
private ObjectManager.ActorData _data = new(string.Empty, new Actor.InvalidIdentifier(), Actor.Null, false, Actor.Null);
private Actor _nextSelect = Actor.Null;
private readonly CurrentManipulations _manipulations;
public ActorTab(CurrentManipulations manipulations)
=> _manipulations = manipulations;
private Actor.IIdentifier _identifier = Actor.IIdentifier.Invalid;
private ObjectManager.ActorData _currentData = ObjectManager.ActorData.Invalid;
private string _currentLabel = string.Empty;
private CurrentDesign? _currentSave;
public void Draw()
{
@ -24,62 +33,107 @@ internal partial class Interface
return;
DrawActorSelector();
if (_data.Label.Length == 0)
return;
if (!ObjectManager.Actors.TryGetValue(_identifier, out _currentData))
_currentData = ObjectManager.ActorData.Invalid;
else
_currentLabel = _currentData.Label;
ImGui.SameLine();
if (_data.Actor.IsHuman)
DrawActorPanel();
else
DrawMonsterPanel();
DrawPanel();
}
private void DrawActorPanel()
private unsafe void DrawPanel()
{
if (_identifier == Actor.IIdentifier.Invalid)
return;
using var group = ImRaii.Group();
if (!Glamourer.RedrawManager.CurrentManipulations.GetSave(_data.Actor, out var save))
DrawPanelHeader();
using var child = ImRaii.Child("##ActorPanel", -Vector2.One, true);
if (!child || _currentSave == null)
return;
if (DrawCustomization(save.Customize, save.Equipment, !_data.Modifiable))
{
//Glamourer.RedrawManager.Set(_data.Actor.Address, _character);
Glamourer.Penumbra.RedrawObject(_data.Actor.Character, RedrawType.Redraw, true);
}
if (_currentData.Valid)
_currentSave.Update(_currentData.Objects[0]);
if (ImGui.Button("Set Machinist Goggles"))
{
Glamourer.RedrawManager.ChangeEquip(_data.Actor.Address, EquipSlot.Head, new CharacterArmor(265, 1, 0));
}
if (ImGui.Button("Set Weapon"))
{
Glamourer.RedrawManager.LoadWeapon(_data.Actor.Address, new CharacterWeapon(0x00C9, 0x004E, 0x0001, 0x00), new CharacterWeapon(0x0065, 0x003D, 0x0001, 0x00));
}
var d = _currentData.Objects[0].DrawObject.Pointer;
var x = (*(delegate* unmanaged<Human*, byte>**)d)[50](d);
ImGui.Text($"{x} {_currentData.Objects[0].ModelId}");
if (x == 1)
CustomizationDrawer.Draw(_currentSave.Data.Customize, _currentSave.Data.Equipment, _currentData.Objects,
_identifier is Actor.SpecialIdentifier);
}
private void DrawMonsterPanel()
private const uint RedHeaderColor = 0xFF1818C0;
private const uint GreenHeaderColor = 0xFF18C018;
private void DrawPanelHeader()
{
using var group = ImRaii.Group();
var currentModel = (uint)_data.Actor.ModelId;
var models = GameData.Models(Dalamud.GameData);
var currentData = models.Models.TryGetValue(currentModel, out var c) ? c.FirstName : $"#{currentModel}";
using var combo = ImRaii.Combo("Model Id", currentData);
if (!combo)
return;
foreach (var (id, data) in models.Models)
{
if (ImGui.Selectable(data.FirstName, id == currentModel) && id != currentModel)
{
_data.Actor.SetModelId((int)id);
_data.Actor.ObjectKind =
Glamourer.Penumbra.RedrawObject(_data.Actor.Character, RedrawType.Redraw, true);
}
ImGuiUtil.HoverTooltip(data.AllNames);
}
var color = _currentData.Valid ? GreenHeaderColor : RedHeaderColor;
var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
using var c = ImRaii.PushColor(ImGuiCol.Text, color)
.Push(ImGuiCol.Button, buttonColor)
.Push(ImGuiCol.ButtonHovered, buttonColor)
.Push(ImGuiCol.ButtonActive, buttonColor);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.Button($"{_currentLabel}##playerHeader", -Vector2.UnitX);
}
//private void DrawActorPanel()
//{
// using var group = ImRaii.Group();
// if (!_data.Identifier.IsValid)
// return;
//
// if (DrawCustomization(_currentSave.Customize, _currentSave.Equipment, !_data.Modifiable))
// //Glamourer.RedrawManager.Set(_data.Actor.Address, _character);
// Glamourer.Penumbra.RedrawObject(_data.Actor.Character, RedrawType.Redraw, true);
//
// if (ImGui.Button("Set Machinist Goggles"))
// Glamourer.RedrawManager.ChangeEquip(_data.Actor, EquipSlot.Head, new CharacterArmor(265, 1, 0));
//
// if (ImGui.Button("Set Weapon"))
// Glamourer.RedrawManager.LoadWeapon(_data.Actor.Address, new CharacterWeapon(0x00C9, 0x004E, 0x0001, 0x00),
// new CharacterWeapon(0x0065, 0x003D, 0x0001, 0x00));
//
// if (ImGui.Button("Set Customize"))
// {
// unsafe
// {
// var data = _data.Actor.Customize.Data->Clone();
// Glamourer.RedrawManager.UpdateCustomize(_data.Actor.DrawObject, new Customize(&data)
// {
// SkinColor = 154,
// });
// }
// }
//}
//
//private void DrawMonsterPanel()
//{
// using var group = ImRaii.Group();
// var currentModel = (uint)_data.Actor.ModelId;
// var models = GameData.Models(Dalamud.GameData);
// var currentData = models.Models.TryGetValue(currentModel, out var c) ? c.FirstName : $"#{currentModel}";
// using var combo = ImRaii.Combo("Model Id", currentData);
// if (!combo)
// return;
//
// foreach (var (id, data) in models.Models)
// {
// if (ImGui.Selectable(data.FirstName, id == currentModel) && id != currentModel)
// {
// _data.Actor.SetModelId((int)id);
// Glamourer.Penumbra.RedrawObject(_data.Actor.Character, RedrawType.Redraw, true);
// }
//
// ImGuiUtil.HoverTooltip(data.AllNames);
// }
//}
private LowerString _actorFilter = LowerString.Empty;
@ -91,63 +145,55 @@ internal partial class Interface
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.SetNextItemWidth(_actorSelectorWidth);
LowerString.InputWithHint("##actorFilter", "Filter...", ref _actorFilter, 64);
using (var child = ImRaii.Child("##actorSelector", new Vector2(_actorSelectorWidth, -ImGui.GetFrameHeight()), true))
{
if (!child)
return;
_data.Actor = Actor.Null;
_data.GPose = Actor.Null;
_data.Modifiable = false;
style.Push(ImGuiStyleVar.ItemSpacing, oldSpacing);
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
var remainder = ImGuiClip.FilteredClippedDraw(ObjectManager.GetEnumerator(), skips, CheckFilter, DrawSelectable);
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
style.Pop();
}
DrawSelector(oldSpacing);
DrawSelectionButtons();
}
private void UpdateSelection(ObjectManager.ActorData data)
private void DrawSelector(Vector2 oldSpacing)
{
_data = data;
//_character.Load(_data.Actor);
using var child = ImRaii.Child("##actorSelector", new Vector2(_actorSelectorWidth, -ImGui.GetFrameHeight()), true);
if (!child)
return;
ObjectManager.Update();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, oldSpacing);
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
var remainder = ImGuiClip.FilteredClippedDraw(ObjectManager.List, skips, CheckFilter, DrawSelectable);
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
}
private bool CheckFilter(ObjectManager.ActorData data)
{
if (_nextSelect && _nextSelect == data.Actor || data.Label == _data.Label)
UpdateSelection(data);
return data.Label.Contains(_actorFilter.Lower, StringComparison.OrdinalIgnoreCase);
}
private bool CheckFilter((Actor.IIdentifier, ObjectManager.ActorData) pair)
=> _actorFilter.IsEmpty || pair.Item2.Label.Contains(_actorFilter.Lower, StringComparison.OrdinalIgnoreCase);
private void DrawSelectable(ObjectManager.ActorData data)
private void DrawSelectable((Actor.IIdentifier, ObjectManager.ActorData) pair)
{
var equal = data.Label == _data.Label;
if (ImGui.Selectable(data.Label, equal) && !equal)
UpdateSelection(data);
var equal = pair.Item1.Equals(_identifier);
if (ImGui.Selectable(pair.Item2.Label, equal) && !equal)
{
_identifier = pair.Item1.CreatePermanent();
_currentData = pair.Item2;
_currentSave = _currentData.Valid ? _manipulations.GetOrCreateSave(_currentData.Objects[0]) : null;
}
}
private void DrawSelectionButtons()
{
_nextSelect = Actor.Null;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
var buttonWidth = new Vector2(_actorSelectorWidth / 2, 0);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
, "Select the local player character.", !ObjectManager.Player, true))
_nextSelect = _inGPose ? ObjectManager.GPosePlayer : ObjectManager.Player;
_identifier = ObjectManager.Player.GetIdentifier();
ImGui.SameLine();
Actor targetActor = Dalamud.Targets.Target?.Address;
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth,
"Select the current target, if it is in the list.", _inGPose || !targetActor, true))
_nextSelect = targetActor;
"Select the current target, if it is in the list.", ObjectManager.IsInGPose || !targetActor, true))
_identifier = targetActor.GetIdentifier();
}
}
private readonly ActorTab _actorTab = new();
}
//internal partial class Interface

View file

@ -1,9 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using Dalamud.Logging;
using Glamourer.Customization;
using Glamourer.Interop;
using Glamourer.Util;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
@ -15,405 +18,385 @@ namespace Glamourer.Gui;
internal partial class Interface
{
private static byte _tempStorage;
private static CustomizationId _tempType;
private static bool DrawCustomization(Customize customize, CharacterEquip equip, bool locked)
private class CustomizationDrawer
{
if (!ImGui.CollapsingHeader("Character Customization"))
return false;
private Customize _customize;
private CharacterEquip _equip;
private IReadOnlyCollection<Actor> _actors = Array.Empty<Actor>();
private CustomizationSet _set = null!;
var ret = DrawRaceGenderSelector(customize, equip, locked);
var set = Glamourer.Customization.GetList(customize.Clan, customize.Gender);
foreach (var id in set.Order[CharaMakeParams.MenuType.Percentage])
ret |= PercentageSelector(set, id, customize, locked);
Functions.IteratePairwise(set.Order[CharaMakeParams.MenuType.IconSelector], c => DrawIconSelector(set, c, customize, locked),
ImGui.SameLine);
ret |= DrawMultiIconSelector(set, customize, locked);
foreach (var id in set.Order[CharaMakeParams.MenuType.ListSelector])
ret |= DrawListSelector(set, id, customize, locked);
Functions.IteratePairwise(set.Order[CharaMakeParams.MenuType.ColorPicker], c => DrawColorPicker(set, c, customize, locked),
ImGui.SameLine);
ret |= Checkbox(set.Option(CustomizationId.HighlightsOnFlag), customize.HighlightsOn, b => customize.HighlightsOn = b, locked);
var xPos = _inputIntSize + _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X;
ImGui.SameLine(xPos);
ret |= Checkbox($"{Glamourer.Customization.GetName(CustomName.Reverse)} {set.Option(CustomizationId.FacePaint)}",
customize.FacePaintReversed, b => customize.FacePaintReversed = b, locked);
ret |= Checkbox($"{Glamourer.Customization.GetName(CustomName.IrisSmall)} {Glamourer.Customization.GetName(CustomName.IrisSize)}",
customize.SmallIris, b => customize.SmallIris = b, locked);
if (customize.Race != Race.Hrothgar)
public static void Draw(Customize customize, CharacterEquip equip, IReadOnlyCollection<Actor> actors, bool locked)
{
var d = new CustomizationDrawer()
{
_customize = customize,
_equip = equip,
_actors = actors,
};
if (!ImGui.CollapsingHeader("Character Customization"))
return;
using var disabled = ImRaii.Disabled(locked);
d.DrawRaceGenderSelector();
d._set = Glamourer.Customization.GetList(customize.Clan, customize.Gender);
foreach (var id in d._set.Order[CharaMakeParams.MenuType.Percentage])
d.PercentageSelector(id);
Functions.IteratePairwise(d._set.Order[CharaMakeParams.MenuType.IconSelector], d.DrawIconSelector, ImGui.SameLine);
d.DrawMultiIconSelector();
foreach (var id in d._set.Order[CharaMakeParams.MenuType.ListSelector])
d.DrawListSelector(id);
Functions.IteratePairwise(d._set.Order[CharaMakeParams.MenuType.ColorPicker], d.DrawColorPicker, ImGui.SameLine);
d.Checkbox(d._set.Option(CustomizationId.HighlightsOnFlag), customize.HighlightsOn, b => customize.HighlightsOn = b);
var xPos = _inputIntSize + _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X;
ImGui.SameLine(xPos);
ret |= Checkbox(set.Option(CustomizationId.LipColor), customize.Lipstick, b => customize.Lipstick = b, locked);
}
d.Checkbox($"{Glamourer.Customization.GetName(CustomName.Reverse)} {d._set.Option(CustomizationId.FacePaint)}",
customize.FacePaintReversed, b => customize.FacePaintReversed = b);
d.Checkbox($"{Glamourer.Customization.GetName(CustomName.IrisSmall)} {Glamourer.Customization.GetName(CustomName.IrisSize)}",
customize.SmallIris, b => customize.SmallIris = b);
return ret;
}
private static bool DrawRaceGenderSelector(Customize customize, CharacterEquip equip, bool locked)
{
var ret = DrawGenderSelector(customize, equip, locked);
ImGui.SameLine();
using var group = ImRaii.Group();
ret |= DrawRaceCombo(customize, equip, locked);
var gender = Glamourer.Customization.GetName(CustomName.Gender);
var clan = Glamourer.Customization.GetName(CustomName.Clan);
ImGui.TextUnformatted($"{gender} & {clan}");
return ret;
}
private static bool DrawGenderSelector(Customize customize, CharacterEquip equip, bool locked)
{
using var font = ImRaii.PushFont(UiBuilder.IconFont);
var icon = customize.Gender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus;
var restricted = customize.Race == Race.Hrothgar;
if (restricted)
icon = FontAwesomeIcon.MarsDouble;
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, restricted || locked, true))
return false;
var gender = customize.Gender == Gender.Male ? Gender.Female : Gender.Male;
return false; //customize.ChangeGender(gender, locked ? CharacterEquip.Null : equip);
}
private static bool DrawRaceCombo(Customize customize, CharacterEquip equip, bool locked)
{
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
ImGui.SetNextItemWidth(_raceSelectorWidth);
using var combo = ImRaii.Combo("##subRaceCombo", customize.ClanName());
if (!combo)
return false;
if (locked)
ImGui.CloseCurrentPopup();
var ret = false;
foreach (var subRace in Enum.GetValues<SubRace>().Skip(1)) // Skip Unknown
{
if (ImGui.Selectable(CustomizeExtensions.ClanName(subRace, customize.Gender), subRace == customize.Clan))
ret |= false; //customize.ChangeRace(subRace, equip);
}
return ret;
}
private static bool Checkbox(string label, bool current, Action<bool> setter, bool locked)
{
var tmp = current;
var ret = false;
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
if (ImGui.Checkbox($"##{label}", ref tmp) && tmp == current && !locked)
{
setter(tmp);
ret = true;
}
alpha.Pop();
ImGui.SameLine();
ImGui.TextUnformatted(label);
return ret;
}
private static bool PercentageSelector(CustomizationSet set, CustomizationId id, Customize customization, bool locked)
{
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)id);
int value = id == _tempType ? _tempStorage : customization[id];
var count = set.Count(id);
ImGui.SetNextItemWidth(_comboSelectorSize);
var (min, max) = locked ? (value, value) : (0, count - 1);
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
if (ImGui.SliderInt("##slider", ref value, min, max, string.Empty, ImGuiSliderFlags.AlwaysClamp) && !locked)
{
_tempStorage = (byte)value;
_tempType = id;
}
var ret = ImGui.IsItemDeactivatedAfterEdit();
ImGui.SameLine();
ret |= InputInt("##input", id, --value, min, max, locked);
alpha.Pop();
ImGui.SameLine();
ImGui.TextUnformatted(set.OptionName[(int)id]);
if (ret)
customization[id] = _tempStorage;
return ret;
}
private static bool InputInt(string label, CustomizationId id, int startValue, int minValue, int maxValue, bool locked)
{
var tmp = startValue + 1;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt(label, ref tmp, 1, 1, ImGuiInputTextFlags.EnterReturnsTrue)
&& !locked
&& tmp != startValue + 1
&& tmp >= minValue
&& tmp <= maxValue)
{
_tempType = id;
_tempStorage = (byte)(tmp - 1);
}
var ret = ImGui.IsItemDeactivatedAfterEdit() && !locked;
if (!locked)
ImGuiUtil.HoverTooltip($"Input Range: [{minValue}, {maxValue}]");
return ret;
}
private static bool DrawIconSelector(CustomizationSet set, CustomizationId id, Customize customize, bool locked)
{
const string popupName = "Style Picker";
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)id);
var count = set.Count(id);
var label = set.Option(id);
var current = set.DataByValue(id, _tempType == id ? _tempStorage : customize[id], out var custom);
if (current < 0)
{
label = $"{label} (Custom #{customize[id]})";
current = 0;
custom = set.Data(id, 0);
}
var icon = Glamourer.Customization.GetIcon(custom!.Value.IconId);
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize) && !locked)
ImGui.OpenPopup(popupName);
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
ImGui.SameLine();
using var group = ImRaii.Group();
var (min, max) = locked ? (current, current) : (1, count);
var ret = InputInt("##text", id, current, min, max, locked);
if (ret)
customize[id] = set.Data(id, _tempStorage).Value;
ImGui.TextUnformatted($"{label} ({custom.Value.Value})");
ret |= DrawIconPickerPopup(popupName, set, id, customize);
return ret;
}
private static bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, Customize customize)
{
using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return false;
var ret = false;
var count = set.Count(id);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i)
{
var custom = set.Data(id, i);
var icon = Glamourer.Customization.GetIcon(custom.IconId);
using var group = ImRaii.Group();
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
if (customize.Race != Race.Hrothgar)
{
customize[id] = custom.Value;
ret = true;
ImGui.CloseCurrentPopup();
}
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
var text = custom.Value.ToString();
var textWidth = ImGui.CalcTextSize(text).X;
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (_iconSize.X - textWidth + 2 * ImGui.GetStyle().FramePadding.X) / 2);
ImGui.TextUnformatted(text);
group.Dispose();
if (i % 8 != 7)
ImGui.SameLine();
}
return ret;
}
private static bool DrawColorPicker(CustomizationSet set, CustomizationId id, Customize customize, bool locked)
{
const string popupName = "Color Picker";
using var _ = ImRaii.PushId((int)id);
var ret = false;
var count = set.Count(id);
var label = set.Option(id);
var (current, custom) = GetCurrentCustomization(set, id, customize);
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
if (ImGui.ColorButton($"{current + 1}##color", ImGui.ColorConvertU32ToFloat4(custom.Color), ImGuiColorEditFlags.None, _framedIconSize)
&& !locked)
ImGui.OpenPopup(popupName);
ImGui.SameLine();
using (var group = ImRaii.Group())
{
var (min, max) = locked ? (current, current) : (1, count);
if (InputInt("##text", id, current, min, max, locked))
{
customize[id] = set.Data(id, current).Value;
ret = true;
ImGui.SameLine(xPos);
d.Checkbox(d._set.Option(CustomizationId.LipColor), customize.Lipstick, b => customize.Lipstick = b);
}
}
private void DrawRaceGenderSelector()
{
DrawGenderSelector();
ImGui.SameLine();
using var group = ImRaii.Group();
DrawRaceCombo();
var gender = Glamourer.Customization.GetName(CustomName.Gender);
var clan = Glamourer.Customization.GetName(CustomName.Clan);
ImGui.TextUnformatted($"{gender} & {clan}");
}
private void DrawGenderSelector()
{
using var font = ImRaii.PushFont(UiBuilder.IconFont);
var icon = _customize.Gender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus;
var restricted = _customize.Race == Race.Hrothgar;
if (restricted)
icon = FontAwesomeIcon.MarsDouble;
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, restricted, true))
return;
var gender = _customize.Gender == Gender.Male ? Gender.Female : Gender.Male;
if (!_customize.ChangeGender(_equip, gender))
return;
foreach (var actor in _actors.Where(a => a))
Glamourer.Penumbra.RedrawObject(actor.Character, RedrawType.Redraw, false);
}
private void DrawRaceCombo()
{
ImGui.SetNextItemWidth(_raceSelectorWidth);
using var combo = ImRaii.Combo("##subRaceCombo", _customize.ClanName());
if (!combo)
return;
foreach (var subRace in Enum.GetValues<SubRace>().Skip(1)) // Skip Unknown
{
if (ImGui.Selectable(CustomizeExtensions.ClanName(subRace, _customize.Gender), subRace == _customize.Clan)
&& _customize.ChangeRace(_equip, subRace))
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.Penumbra.RedrawObject(actor.Character, RedrawType.Redraw, false);
}
}
private void Checkbox(string label, bool current, Action<bool> setter)
{
var tmp = current;
if (ImGui.Checkbox($"##{label}", ref tmp) && tmp != current)
{
setter(tmp);
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
ImGui.SameLine();
ImGui.TextUnformatted(label);
}
return ret | DrawColorPickerPopup(popupName, set, id, customize);
}
private static (int, Customization.Customization) GetCurrentCustomization(CustomizationSet set, CustomizationId id,
Customize customize)
{
var current = set.DataByValue(id, customize[id], out var custom);
if (set.IsAvailable(id) && current < 0)
private void PercentageSelector(CustomizationId id)
{
PluginLog.Warning($"Read invalid customization value {customize[id]} for {id}.");
current = 0;
custom = set.Data(id, 0);
}
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)id);
int value = _customize[id];
var count = _set.Count(id);
ImGui.SetNextItemWidth(_comboSelectorSize);
return (current, custom!.Value);
}
private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, Customize customize)
{
using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return false;
var ret = false;
var count = set.Count(id);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i)
{
var custom = set.Data(id, i);
if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color)))
void OnChange(int v)
{
customize[id] = custom.Value;
ret = true;
ImGui.CloseCurrentPopup();
_customize[id] = (byte)v;
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
if (i % 8 != 7)
ImGui.SameLine();
if (ImGui.SliderInt("##slider", ref value, 0, count - 1, "%i", ImGuiSliderFlags.AlwaysClamp))
OnChange(value);
ImGui.SameLine();
InputInt("##input", --value, 0, count - 1, OnChange);
ImGui.SameLine();
ImGui.TextUnformatted(_set.OptionName[(int)id]);
}
return ret;
}
private static bool DrawMultiIconSelector(CustomizationSet set, Customize customize, bool locked)
{
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)CustomizationId.FacialFeaturesTattoos);
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
var ret = DrawMultiIcons(set, customize, locked);
ImGui.SameLine();
using var group = ImRaii.Group();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() + 3 * ImGui.GetStyle().ItemSpacing.Y / 2);
int value = customize[CustomizationId.FacialFeaturesTattoos];
var (min, max) = locked ? (value, value) : (1, 256);
if (InputInt(string.Empty, CustomizationId.FacialFeaturesTattoos, value, min, max, locked))
private static void InputInt(string label, int startValue, int minValue, int maxValue, Action<int> setter)
{
customize[CustomizationId.FacialFeaturesTattoos] = (byte)value;
ret = true;
var tmp = startValue + 1;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt(label, ref tmp, 1, 1, ImGuiInputTextFlags.EnterReturnsTrue)
&& tmp != startValue + 1
&& tmp >= minValue
&& tmp <= maxValue)
setter(tmp);
ImGuiUtil.HoverTooltip($"Input Range: [{minValue}, {maxValue}]");
}
ImGui.TextUnformatted(set.Option(CustomizationId.FacialFeaturesTattoos));
return ret;
}
private static bool DrawMultiIcons(CustomizationSet set, Customize customize, bool locked)
{
using var _ = ImRaii.Group();
var face = customize.Face;
if (set.Faces.Count < face)
face = 1;
var ret = false;
var count = set.Count(CustomizationId.FacialFeaturesTattoos);
for (var i = 0; i < count; ++i)
private void DrawIconSelector(CustomizationId id)
{
var enabled = customize.FacialFeatures[i];
var feature = set.FacialFeature(face, i);
var icon = i == count - 1
? LegacyTattoo ?? Glamourer.Customization.GetIcon(feature.IconId)
: Glamourer.Customization.GetIcon(feature.IconId);
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int)ImGui.GetStyle().FramePadding.X,
Vector4.Zero, enabled ? Vector4.One : RedTint)
&& !locked)
const string popupName = "Style Picker";
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)id);
var count = _set.Count(id, _customize.Face);
var label = _set.Option(id);
var current = _set.DataByValue(id, _customize[id], out var custom);
if (current < 0)
{
customize.FacialFeatures.Set(i, !enabled);
ret = true;
label = $"{label} (Custom #{_customize[id]})";
current = 0;
custom = _set.Data(id, 0);
}
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 1f, !locked);
var icon = Glamourer.Customization.GetIcon(custom!.Value.IconId);
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
ImGui.OpenPopup(popupName);
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
if (i % 4 != 3)
ImGui.SameLine();
void OnChange(int v)
{
var value = _set.Data(id, v - 1).Value;
// Hrothgar hack
if (_set.Race == Race.Hrothgar && id == CustomizationId.Face)
value += 4;
if (_customize[id] == value)
return;
_customize[id] = value;
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
ImGui.SameLine();
using var group = ImRaii.Group();
InputInt("##text", current, 1, count, OnChange);
ImGui.TextUnformatted($"{label} ({custom.Value.Value})");
DrawIconPickerPopup(popupName, id, OnChange);
}
return ret;
}
private static bool DrawListSelector(CustomizationSet set, CustomizationId id, Customize customize, bool locked)
{
using var _ = ImRaii.PushId((int)id);
using var bigGroup = ImRaii.Group();
var ret = false;
int current = customize[id];
var count = set.Count(id);
ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale);
using var alpha = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, locked);
using (var combo = ImRaii.Combo("##combo", $"{set.Option(id)} #{current + 1}"))
private void DrawIconPickerPopup(string label, CustomizationId id, Action<int> setter)
{
if (combo)
for (var i = 0; i < count; ++i)
using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return;
var count = _set.Count(id, _customize.Face);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i)
{
var custom = _set.Data(id, i, _customize.Face);
var icon = Glamourer.Customization.GetIcon(custom.IconId);
using var group = ImRaii.Group();
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
{
if (!ImGui.Selectable($"{set.Option(id)} #{i + 1}##combo", i == current) || i == current || locked)
continue;
customize[id] = (byte)i;
ret = true;
setter(custom.Value);
ImGui.CloseCurrentPopup();
}
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
var text = custom.Value.ToString();
var textWidth = ImGui.CalcTextSize(text).X;
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (_iconSize.X - textWidth + 2 * ImGui.GetStyle().FramePadding.X) / 2);
ImGui.TextUnformatted(text);
group.Dispose();
if (i % 8 != 7)
ImGui.SameLine();
}
}
ImGui.SameLine();
var (min, max) = locked ? (current, current) : (1, count);
if (InputInt("##text", id, current, min, max, locked))
private void DrawColorPicker(CustomizationId id)
{
customize[id] = (byte)current;
ret = true;
const string popupName = "Color Picker";
using var _ = ImRaii.PushId((int)id);
var count = _set.Count(id);
var label = _set.Option(id);
var (current, custom) = GetCurrentCustomization(id);
if (ImGui.ColorButton($"{current + 1}##color", ImGui.ColorConvertU32ToFloat4(custom.Color), ImGuiColorEditFlags.None,
_framedIconSize))
ImGui.OpenPopup(popupName);
ImGui.SameLine();
void OnChange(int v)
{
_customize[id] = _set.Data(id, v).Value;
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
using (var group = ImRaii.Group())
{
InputInt("##text", current, 1, count, OnChange);
ImGui.TextUnformatted(label);
}
DrawColorPickerPopup(popupName, id, OnChange);
}
ImGui.SameLine();
alpha.Pop();
ImGui.TextUnformatted(set.Option(id));
private (int, Customization.Customization) GetCurrentCustomization(CustomizationId id)
{
var current = _set.DataByValue(id, _customize[id], out var custom);
if (_set.IsAvailable(id) && current < 0)
{
PluginLog.Warning($"Read invalid customization value {_customize[id]} for {id}.");
current = 0;
custom = _set.Data(id, 0);
}
return ret;
return (current, custom!.Value);
}
private void DrawColorPickerPopup(string label, CustomizationId id, Action<int> setter)
{
using var popup = ImRaii.Popup(label, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return;
var count = _set.Count(id);
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < count; ++i)
{
var custom = _set.Data(id, i);
if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color)))
{
setter(custom.Value);
ImGui.CloseCurrentPopup();
}
if (i % 8 != 7)
ImGui.SameLine();
}
}
private void DrawMultiIconSelector()
{
using var bigGroup = ImRaii.Group();
using var _ = ImRaii.PushId((int)CustomizationId.FacialFeaturesTattoos);
void OnChange(int v)
{
_customize[CustomizationId.FacialFeaturesTattoos] = (byte)v;
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
DrawMultiIcons();
ImGui.SameLine();
int value = _customize[CustomizationId.FacialFeaturesTattoos];
using var group = ImRaii.Group();
ImGui.Dummy(new Vector2(0, ImGui.GetTextLineHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y / 2));
InputInt(string.Empty, --value, 0, 255, OnChange);
ImGui.TextUnformatted(_set.Option(CustomizationId.FacialFeaturesTattoos));
}
private void DrawMultiIcons()
{
using var _ = ImRaii.Group();
var face = _customize.Face;
var ret = false;
var count = _set.Count(CustomizationId.FacialFeaturesTattoos);
for (var i = 0; i < count; ++i)
{
var enabled = _customize.FacialFeatures[i];
var feature = _set.FacialFeature(face, i);
var icon = i == count - 1
? LegacyTattoo ?? Glamourer.Customization.GetIcon(feature.IconId)
: Glamourer.Customization.GetIcon(feature.IconId);
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int)ImGui.GetStyle().FramePadding.X,
Vector4.Zero, enabled ? Vector4.One : RedTint))
{
_customize.FacialFeatures.Set(i, !enabled);
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
if (i % 4 != 3)
ImGui.SameLine();
}
}
private void DrawListSelector(CustomizationId id)
{
using var _ = ImRaii.PushId((int)id);
using var bigGroup = ImRaii.Group();
int current = _customize[id];
var count = _set.Count(id);
void OnChange(int v)
{
_customize[id] = (byte)v;
foreach (var actor in _actors.Where(a => a && a.DrawObject))
Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _customize);
}
ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale);
using (var combo = ImRaii.Combo("##combo", $"{_set.Option(id)} #{current + 1}"))
{
if (combo)
for (var i = 0; i < count; ++i)
{
if (!ImGui.Selectable($"{_set.Option(id)} #{i + 1}##combo", i == current) || i == current)
continue;
OnChange(i);
}
}
ImGui.SameLine();
InputInt("##text", current, 1, count, OnChange);
ImGui.SameLine();
ImGui.TextUnformatted(_set.Option(id));
}
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Numerics;
using Glamourer.State;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;

View file

@ -3,6 +3,7 @@ using System.Numerics;
using System.Reflection;
using Dalamud.Interface;
using Glamourer.Customization;
using Glamourer.Interop;
using ImGuiNET;
namespace Glamourer.Gui;
@ -20,13 +21,11 @@ internal partial class Interface
private static float _inputIntSize;
private static float _comboSelectorSize;
private static float _raceSelectorWidth;
private static bool _inGPose;
private static void UpdateState()
{
// General
_inGPose = ObjectManager.IsInGPose();
_spacing = _spacing with { Y = ImGui.GetTextLineHeightWithSpacing() / 2 };
_actorSelectorWidth = 200 * ImGuiHelpers.GlobalScale;

View file

@ -1,17 +1,108 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Glamourer.Interop;
using Glamourer.State;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
namespace Glamourer.Gui;
internal partial class Interface : Window, IDisposable
{
private class DebugStateTab
{
private readonly CurrentManipulations _currentManipulations;
private LowerString _manipulationFilter = LowerString.Empty;
private Actor.IIdentifier _selection = Actor.IIdentifier.Invalid;
private CurrentDesign? _save = null;
private bool _delete = false;
public DebugStateTab(CurrentManipulations currentManipulations)
=> _currentManipulations = currentManipulations;
public void Draw()
{
using var tab = ImRaii.TabItem("Current Manipulations");
if (!tab)
return;
DrawManipulationSelector();
if (_save == null)
return;
ImGui.SameLine();
DrawActorPanel();
if (_delete)
{
_delete = false;
_currentManipulations.DeleteSave(_selection);
_selection = Actor.IIdentifier.Invalid;
}
}
private void DrawSelector(Vector2 oldSpacing)
{
using var child = ImRaii.Child("##actorSelector", new Vector2(_actorSelectorWidth, -1), true);
if (!child)
return;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, oldSpacing);
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
var remainder = ImGuiClip.FilteredClippedDraw(_currentManipulations, skips, CheckFilter, DrawSelectable);
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
}
private void DrawManipulationSelector()
{
using var group = ImRaii.Group();
var oldSpacing = ImGui.GetStyle().ItemSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.SetNextItemWidth(_actorSelectorWidth);
LowerString.InputWithHint("##actorFilter", "Filter...", ref _manipulationFilter, 64);
_save = null;
DrawSelector(oldSpacing);
}
private bool CheckFilter(KeyValuePair<Actor.IIdentifier, CurrentDesign> data)
{
if (data.Key.Equals(_selection))
_save = data.Value;
return _manipulationFilter.Length == 0 || _manipulationFilter.IsContained(data.Key.ToString()!);
}
private void DrawSelectable(KeyValuePair<Actor.IIdentifier, CurrentDesign> data)
{
var equal = data.Key.Equals(_selection);
if (ImGui.Selectable(data.Key.ToString(), equal))
{
_selection = data.Key;
_save = data.Value;
}
}
private void DrawActorPanel()
{
using var group = ImRaii.Group();
if (ImGui.Button("Delete"))
_delete = true;
CustomizationDrawer.Draw(_save!.Data.Customize, _save.Data.Equipment, Array.Empty<Actor>(), false);
}
}
private readonly Glamourer _plugin;
private readonly ActorTab _actorTab;
private readonly DebugStateTab _debugStateTab;
public Interface(Glamourer plugin)
: base(GetLabel())
{
@ -23,6 +114,8 @@ internal partial class Interface : Window, IDisposable
MinimumSize = new Vector2(675, 675),
MaximumSize = ImGui.GetIO().DisplaySize,
};
_actorTab = new ActorTab(_plugin.CurrentManipulations);
_debugStateTab = new DebugStateTab(_plugin.CurrentManipulations);
}
public override void Draw()
@ -31,13 +124,21 @@ internal partial class Interface : Window, IDisposable
if (!tabBar)
return;
UpdateState();
try
{
UpdateState();
_actorTab.Draw();
DrawSettingsTab();
// DrawSaves();
// DrawFixedDesignsTab();
// DrawRevertablesTab();
_actorTab.Draw();
DrawSettingsTab();
_debugStateTab.Draw();
// DrawSaves();
// DrawFixedDesignsTab();
// DrawRevertablesTab();
}
catch (Exception e)
{
PluginLog.Error($"Unexpected Error during Draw:\n{e}");
}
}
public void Dispose()

View file

@ -9,8 +9,7 @@ internal partial class Interface
//private bool _holdShift;
//private bool _holdCtrl;
//private const string DesignNamePopupLabel = "Save Design As...";
//private const uint RedHeaderColor = 0xFF1818C0;
//private const uint GreenHeaderColor = 0xFF18C018;
//
//private void DrawPlayerHeader()
//{