This commit is contained in:
Ottermandias 2023-06-19 23:59:22 +02:00
parent 80ab57e96d
commit d1d369a56b
31 changed files with 1637 additions and 80 deletions

View file

@ -7,22 +7,26 @@ public enum ColorId
CustomizationDesign,
StateDesign,
EquipmentDesign,
ActorAvailable,
ActorUnavailable,
}
public static class Colors
{
public const uint DiscordColor = 0xFFDA8972;
public const uint ReniColorButton = 0xFFCC648D;
public const uint ReniColorHovered = 0xFFB070B0;
public const uint ReniColorActive = 0xFF9070E0;
public const uint DiscordColor = 0xFFDA8972;
public const uint ReniColorButton = 0xFFCC648D;
public const uint ReniColorHovered = 0xFFB070B0;
public const uint ReniColorActive = 0xFF9070E0;
public static (uint DefaultColor, string Name, string Description) Data(this ColorId color)
=> color switch
{
// @formatter:off
ColorId.CustomizationDesign => (0xFFC000C0, "Customization Design", "A design that only changes customizations on a character." ),
ColorId.StateDesign => (0xFF00C0C0, "State Design", "A design that only changes meta state on a character." ),
ColorId.EquipmentDesign => (0xFF00C000, "Equipment Design", "A design that only changes equipment on a character." ),
ColorId.CustomizationDesign => (0xFFC000C0, "Customization Design", "A design that only changes customizations on a character." ),
ColorId.StateDesign => (0xFF00C0C0, "State Design", "A design that only changes meta state on a character." ),
ColorId.EquipmentDesign => (0xFF00C000, "Equipment Design", "A design that only changes equipment on a character." ),
ColorId.ActorAvailable => (0xFF18C018, "Actor Available", "The header in the Actor tab panel if the currently selected actor exists in the game world at least once." ),
ColorId.ActorUnavailable => (0xFF1818C0, "Actor Unavailable", "The Header in the Actor tab panel if the currently selected actor does not exist in the game world." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -0,0 +1,64 @@
using System;
using System.Numerics;
using Glamourer.Customization;
using ImGuiNET;
using OtterGui.Raii;
namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer
{
private const string ColorPickerPopupName = "ColorPicker";
private void DrawColorPicker(CustomizeIndex index)
{
using var _ = SetId(index);
var (current, custom) = GetCurrentCustomization(index);
var color = ImGui.ColorConvertU32ToFloat4(custom.Color);
// Print 1-based index instead of 0.
if (ImGui.ColorButton($"{current + 1}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
ImGui.OpenPopup(ColorPickerPopupName);
ImGui.SameLine();
using (var group = ImRaii.Group())
{
DataInputInt(current);
ImGui.TextUnformatted(_currentOption);
}
DrawColorPickerPopup();
}
private void DrawColorPickerPopup()
{
using var popup = ImRaii.Popup(ColorPickerPopupName, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < _currentCount; ++i)
{
var custom = _set.Data(_currentIndex, i, _customize[CustomizeIndex.Face]);
if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color)))
{
UpdateValue(custom.Value);
ImGui.CloseCurrentPopup();
}
if (i % 8 != 7)
ImGui.SameLine();
}
}
// Obtain the current customization and print a warning if it is not known.
private (int, CustomizeData) GetCurrentCustomization(CustomizeIndex index)
{
var current = _set.DataByValue(index, _customize[index], out var custom, _customize.Face);
if (_set.IsAvailable(index) && current < 0)
throw new Exception($"Read invalid customization value {_customize[index]} for {index}.");
return (current, custom!.Value);
}
}

View file

@ -0,0 +1,56 @@
using System;
using System.Linq;
using Dalamud.Interface;
using Glamourer.Customization;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer
{
private void DrawRaceGenderSelector()
{
DrawGenderSelector();
ImGui.SameLine();
using var group = ImRaii.Group();
DrawRaceCombo();
var gender = _service.AwaitedService.GetName(CustomName.Gender);
var clan = _service.AwaitedService.GetName(CustomName.Clan);
ImGui.TextUnformatted($"{gender} & {clan}");
}
private void DrawGenderSelector()
{
using var font = ImRaii.PushFont(UiBuilder.IconFont);
var icon = _customize.Gender switch
{
Gender.Male when _customize.Race is Race.Hrothgar => FontAwesomeIcon.MarsDouble,
Gender.Male => FontAwesomeIcon.Mars,
Gender.Female => FontAwesomeIcon.Venus,
_ => throw new Exception($"Gender value {_customize.Gender} is not a valid gender for a design."),
};
if (!ImGuiUtil.DrawDisabledButton(icon.ToIconString(), _framedIconSize, string.Empty, icon == FontAwesomeIcon.MarsDouble, true))
return;
_service.ChangeGender(ref _customize, _customize.Gender is Gender.Male ? Gender.Female : Gender.Male);
}
private void DrawRaceCombo()
{
ImGui.SetNextItemWidth(_raceSelectorWidth);
using var combo = ImRaii.Combo("##subRaceCombo", _service.ClanName(_customize.Clan, _customize.Gender));
if (!combo)
return;
foreach (var subRace in Enum.GetValues<SubRace>().Skip(1)) // Skip Unknown
{
if (ImGui.Selectable(_service.ClanName(subRace, _customize.Gender), subRace == _customize.Clan))
_service.ChangeClan(ref _customize, subRace);
}
}
}

View file

@ -0,0 +1,150 @@
using System;
using System.Numerics;
using Glamourer.Customization;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer
{
private const string IconSelectorPopup = "Style Picker";
private void DrawIconSelector(CustomizeIndex index)
{
using var _ = SetId(index);
using var bigGroup = ImRaii.Group();
var label = _currentOption;
var current = _set.DataByValue(index, _currentByte, out var custom, _customize.Face);
if (current < 0)
{
label = $"{_currentOption} (Custom #{_customize[index]})";
current = 0;
custom = _set.Data(index, 0);
}
var icon = _service.AwaitedService.GetIcon(custom!.Value.IconId);
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
ImGui.OpenPopup(IconSelectorPopup);
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
ImGui.SameLine();
using (var group = ImRaii.Group())
{
if (_currentIndex == CustomizeIndex.Face)
FaceInputInt(current);
else
DataInputInt(current);
ImGui.TextUnformatted($"{label} ({custom.Value.Value})");
}
DrawIconPickerPopup();
}
private bool UpdateFace(CustomizeData data)
{
// Hrothgar Hack
var value = _set.Race == Race.Hrothgar ? data.Value + 4 : data.Value;
if (_customize.Face == value)
return false;
_customize.Face = value;
Changed |= CustomizeFlag.Face;
return true;
}
private void FaceInputInt(int currentIndex)
{
++currentIndex;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt("##text", ref currentIndex, 1, 1))
{
currentIndex = Math.Clamp(currentIndex - 1, 0, _currentCount - 1);
var data = _set.Data(_currentIndex, currentIndex, _customize.Face);
UpdateFace(data);
}
ImGuiUtil.HoverTooltip($"Input Range: [1, {_currentCount}]");
}
private void DrawIconPickerPopup()
{
using var popup = ImRaii.Popup(IconSelectorPopup, ImGuiWindowFlags.AlwaysAutoResize);
if (!popup)
return;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
for (var i = 0; i < _currentCount; ++i)
{
var custom = _set.Data(_currentIndex, i, _customize.Face);
var icon = _service.AwaitedService.GetIcon(custom.IconId);
using (var _ = ImRaii.Group())
{
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
{
if (_currentIndex == CustomizeIndex.Face)
UpdateFace(custom);
else
UpdateValue(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);
}
if (i % 8 != 7)
ImGui.SameLine();
}
}
// Only used for facial features, so fixed ID.
private void DrawMultiIconSelector()
{
using var bigGroup = ImRaii.Group();
DrawMultiIcons();
ImGui.SameLine();
using var group = ImRaii.Group();
ImGui.Dummy(new Vector2(0, ImGui.GetTextLineHeightWithSpacing() + ImGui.GetStyle().ItemSpacing.Y / 2));
_currentCount = 256;
PercentageInputInt();
ImGui.TextUnformatted(_set.Option(CustomizeIndex.LegacyTattoo));
}
private void DrawMultiIcons()
{
var options = _set.Order[CharaMakeParams.MenuType.IconCheckmark];
using var _ = ImRaii.Group();
foreach (var (featureIdx, idx) in options.WithIndex())
{
using var id = SetId(featureIdx);
var enabled = _customize.Get(featureIdx) != CustomizeValue.Zero;
var feature = _set.Data(featureIdx, 0, _customize.Face);
var icon = featureIdx == CustomizeIndex.LegacyTattoo
? _legacyTattoo ?? _service.AwaitedService.GetIcon(feature.IconId)
: _service.AwaitedService.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.Set(featureIdx, enabled ? CustomizeValue.Zero : CustomizeValue.Max);
Changed |= _currentFlag;
}
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
if (idx % 4 != 3)
ImGui.SameLine();
}
}
}

View file

@ -0,0 +1,102 @@
using System;
using Glamourer.Customization;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer
{
private void PercentageSelector(CustomizeIndex index)
{
using var _ = SetId(index);
using var bigGroup = ImRaii.Group();
DrawPercentageSlider();
ImGui.SameLine();
PercentageInputInt();
ImGui.SameLine();
ImGui.TextUnformatted(_currentOption);
}
private void DrawPercentageSlider()
{
var tmp = (int)_currentByte.Value;
ImGui.SetNextItemWidth(_comboSelectorSize);
if (ImGui.SliderInt("##slider", ref tmp, 0, _currentCount - 1, "%i", ImGuiSliderFlags.AlwaysClamp))
UpdateValue((CustomizeValue)tmp);
}
private void PercentageInputInt()
{
var tmp = (int)_currentByte.Value;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt("##text", ref tmp, 1, 1))
UpdateValue((CustomizeValue)Math.Clamp(tmp, 0, _currentCount - 1));
ImGuiUtil.HoverTooltip($"Input Range: [0, {_currentCount - 1}]");
}
// Integral input for an icon- or color based item.
private void DataInputInt(int currentIndex)
{
++currentIndex;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt("##text", ref currentIndex, 1, 1))
{
currentIndex = Math.Clamp(currentIndex - 1, 0, _currentCount - 1);
var data = _set.Data(_currentIndex, currentIndex, _customize.Face);
UpdateValue(data.Value);
}
ImGuiUtil.HoverTooltip($"Input Range: [1, {_currentCount}]");
}
private void DrawListSelector(CustomizeIndex index)
{
using var _ = SetId(index);
using var bigGroup = ImRaii.Group();
ListCombo();
ImGui.SameLine();
ListInputInt();
ImGui.SameLine();
ImGui.TextUnformatted(_currentOption);
}
private void ListCombo()
{
ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale);
using var combo = ImRaii.Combo("##combo", $"{_currentOption} #{_currentByte.Value + 1}");
if (!combo)
return;
for (var i = 0; i < _currentCount; ++i)
{
if (ImGui.Selectable($"{_currentOption} #{i + 1}##combo", i == _currentByte.Value))
UpdateValue((CustomizeValue)i);
}
}
private void ListInputInt()
{
var tmp = _currentByte.Value + 1;
ImGui.SetNextItemWidth(_inputIntSize);
if (ImGui.InputInt("##text", ref tmp, 1, 1) && tmp > 0 && tmp <= _currentCount)
UpdateValue((CustomizeValue)Math.Clamp(tmp - 1, 0, _currentCount - 1));
ImGuiUtil.HoverTooltip($"Input Range: [1, {_currentCount}]");
}
// Draw a customize checkbox.
private void DrawCheckbox(CustomizeIndex idx)
{
using var id = SetId(idx);
var tmp = _currentByte != CustomizeValue.Zero;
if (ImGui.Checkbox(_currentOption, ref tmp))
{
_customize.Set(idx, tmp ? CustomizeValue.Max : CustomizeValue.Zero);
Changed |= _currentFlag;
}
}
}

View file

@ -0,0 +1,152 @@
using System;
using System.Numerics;
using System.Reflection;
using Dalamud.Plugin;
using Glamourer.Customization;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Raii;
namespace Glamourer.Gui.Customization;
public partial class CustomizationDrawer : IDisposable
{
private readonly Vector4 _redTint = new(0.6f, 0.3f, 0.3f, 1f);
private readonly ImGuiScene.TextureWrap? _legacyTattoo;
private Exception? _terminate = null;
private Customize _customize;
private CustomizationSet _set = null!;
public Customize Customize;
public CustomizeFlag CurrentFlag { get; private set; }
public CustomizeFlag Changed { get; private set; }
public bool RequiresRedraw
=> Changed.RequiresRedraw();
private bool _locked = false;
private Vector2 _iconSize;
private Vector2 _framedIconSize;
private float _inputIntSize;
private float _comboSelectorSize;
private float _raceSelectorWidth;
private readonly CustomizationService _service;
public CustomizationDrawer(DalamudPluginInterface pi, CustomizationService service)
{
_service = service;
_legacyTattoo = GetLegacyTattooIcon(pi);
Customize = Customize.Default;
}
public void Dispose()
{
_legacyTattoo?.Dispose();
}
public bool Draw(Customize current, bool locked)
{
CurrentFlag = CustomizeFlagExtensions.All;
Init(current, locked);
return DrawInternal();
}
private void Init(Customize current, bool locked)
{
UpdateSizes();
_terminate = null;
Changed = 0;
_customize.Load(current);
_locked = locked;
}
// Set state for drawing of current customization.
private CustomizeIndex _currentIndex;
private CustomizeFlag _currentFlag;
private CustomizeValue _currentByte = CustomizeValue.Zero;
private int _currentCount;
private string _currentOption = string.Empty;
// Prepare a new customization option.
private ImRaii.Id SetId(CustomizeIndex index)
{
_currentIndex = index;
_currentFlag = index.ToFlag();
_currentByte = _customize[index];
_currentCount = _set.Count(index, _customize.Face);
_currentOption = _set.Option(index);
return ImRaii.PushId((int)index);
}
// Update the current id with a new value.
private void UpdateValue(CustomizeValue value)
{
if (_currentByte == value)
return;
_customize[_currentIndex] = value;
Changed |= _currentFlag;
}
private bool DrawInternal()
{
using var disabled = ImRaii.Disabled(_locked);
try
{
DrawRaceGenderSelector();
_set = _service.AwaitedService.GetList(_customize.Clan, _customize.Gender);
foreach (var id in _set.Order[CharaMakeParams.MenuType.Percentage])
PercentageSelector(id);
Functions.IteratePairwise(_set.Order[CharaMakeParams.MenuType.IconSelector], DrawIconSelector, ImGui.SameLine);
DrawMultiIconSelector();
foreach (var id in _set.Order[CharaMakeParams.MenuType.ListSelector])
DrawListSelector(id);
Functions.IteratePairwise(_set.Order[CharaMakeParams.MenuType.ColorPicker], DrawColorPicker, ImGui.SameLine);
Functions.IteratePairwise(_set.Order[CharaMakeParams.MenuType.Checkmark], DrawCheckbox,
() => ImGui.SameLine(_inputIntSize + _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X));
return Changed != 0;
}
catch (Exception ex)
{
_terminate = ex;
using var color = ImRaii.PushColor(ImGuiCol.Text, 0xFF4040FF);
ImGui.NewLine();
ImGuiUtil.TextWrapped(_terminate.ToString());
return false;
}
}
private void UpdateSizes()
{
_iconSize = new Vector2(ImGui.GetTextLineHeightWithSpacing() * 2);
_framedIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding;
_inputIntSize = 2 * _framedIconSize.X + ImGui.GetStyle().ItemSpacing.X;
_comboSelectorSize = 4 * _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X;
_raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X;
}
private static ImGuiScene.TextureWrap? GetLegacyTattooIcon(DalamudPluginInterface pi)
{
using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw");
if (resource == null)
return null;
var rawImage = new byte[resource.Length];
var length = resource.Read(rawImage, 0, (int)resource.Length);
return length == resource.Length
? pi.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4)
: null;
}
}

View file

@ -3,6 +3,8 @@ using System.Numerics;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin;
using Glamourer.Gui.Tabs;
using Glamourer.Gui.Tabs.ActorTab;
using Glamourer.Gui.Tabs.DesignTab;
using ImGuiNET;
using OtterGui.Custom;
using OtterGui.Widgets;
@ -16,17 +18,22 @@ public class MainWindow : Window
None = -1,
Settings = 0,
Debug = 1,
Actors = 2,
Designs = 3,
}
private readonly Configuration _config;
private readonly ITab[] _tabs;
public readonly SettingsTab Settings;
public readonly ActorTab Actors;
public readonly DebugTab Debug;
public readonly DesignTab Designs;
public TabType SelectTab = TabType.None;
public MainWindow(DalamudPluginInterface pi, Configuration config, SettingsTab settings, DebugTab debugTab)
public MainWindow(DalamudPluginInterface pi, Configuration config, SettingsTab settings, ActorTab actors, DesignTab designs,
DebugTab debugTab)
: base(GetLabel())
{
pi.UiBuilder.DisableGposeUiHide = true;
@ -37,10 +44,14 @@ public class MainWindow : Window
};
Settings = settings;
Debug = debugTab;
Designs = designs;
Actors = actors;
_config = config;
_tabs = new ITab[]
{
settings,
actors,
designs,
debugTab,
};
@ -62,12 +73,16 @@ public class MainWindow : Window
{
TabType.Settings => Settings.Label,
TabType.Debug => Debug.Label,
TabType.Actors => Actors.Label,
TabType.Designs => Designs.Label,
_ => ReadOnlySpan<byte>.Empty,
};
private TabType FromLabel(ReadOnlySpan<byte> label)
{
// @formatter:off
if (label == Actors.Label) return TabType.Actors;
if (label == Designs.Label) return TabType.Designs;
if (label == Settings.Label) return TabType.Settings;
if (label == Debug.Label) return TabType.Debug;
// @formatter:on

View file

@ -0,0 +1,218 @@
using System.Numerics;
using Glamourer.Gui.Customization;
using Glamourer.Interop.Structs;
using Glamourer.State;
using ImGuiNET;
using OtterGui.Raii;
using Penumbra.GameData.Actors;
using Penumbra.GameData.Enums;
namespace Glamourer.Gui.Tabs.ActorTab;
public class ActorPanel
{
private readonly ActorSelector _selector;
private readonly StateManager _stateManager;
private readonly CustomizationDrawer _customizationDrawer;
private ActorIdentifier _identifier;
private string _actorName = string.Empty;
private Actor _actor = Actor.Null;
private ActorData _data;
private ActorState? _state;
public ActorPanel(ActorSelector selector, StateManager stateManager, CustomizationDrawer customizationDrawer)
{
_selector = selector;
_stateManager = stateManager;
_customizationDrawer = customizationDrawer;
}
public void Draw()
{
if (!_selector.HasSelection)
return;
(_identifier, _data) = _selector.Selection;
if (_data.Valid)
{
_actorName = _data.Label;
_actor = _data.Objects[0];
}
else
{
_actorName = _identifier.ToString();
_actor = Actor.Null;
}
if (!_stateManager.GetOrCreate(_identifier, _actor, out _state))
return;
//if (_state != null)
// _stateManager.Update(ref _state.Data, _actor);
using var group = ImRaii.Group();
DrawHeader();
DrawPanel();
}
private void DrawHeader()
{
var color = _data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value();
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($"{(_data.Valid ? _data.Label : _identifier.ToString())}##playerHeader", -Vector2.UnitX);
}
private unsafe void DrawPanel()
{
using var child = ImRaii.Child("##ActorPanel", -Vector2.One, true);
if (!child || _state == null)
return;
if (_customizationDrawer.Draw(_state.Data.Customize, false))
{
}
// if (_currentData.Valid)
// _currentSave.Initialize(_items, _currentData.Objects[0]);
//
// RevertButton();
// ActorDebug.Draw(_currentSave.ModelData);
// return;
//
// if (_main._customizationDrawer.Draw(_currentSave.ModelData.Customize, _identifier.Type == IdentifierType.Special))
// _activeDesigns.ChangeCustomize(_currentSave, _main._customizationDrawer.Changed, _main._customizationDrawer.Customize.Data,
// false);
//
// foreach (var slot in EquipSlotExtensions.EqdpSlots)
// {
// var current = _currentSave.Armor(slot);
// if (_main._equipmentDrawer.DrawStain(current.Stain, slot, out var stain))
// _activeDesigns.ChangeStain(_currentSave, slot, stain.RowIndex, false);
// ImGui.SameLine();
// if (_main._equipmentDrawer.DrawArmor(current, slot, out var armor, _currentSave.ModelData.Customize.Gender,
// _currentSave.ModelData.Customize.Race))
// _activeDesigns.ChangeEquipment(_currentSave, slot, armor, false);
// }
//
// var currentMain = _currentSave.WeaponMain;
// if (_main._equipmentDrawer.DrawStain(currentMain.Stain, EquipSlot.MainHand, out var stainMain))
// _activeDesigns.ChangeStain(_currentSave, EquipSlot.MainHand, stainMain.RowIndex, false);
// ImGui.SameLine();
// _main._equipmentDrawer.DrawMainhand(currentMain, true, out var main);
// if (currentMain.Type.Offhand() != FullEquipType.Unknown)
// {
// var currentOff = _currentSave.WeaponOff;
// if (_main._equipmentDrawer.DrawStain(currentOff.Stain, EquipSlot.OffHand, out var stainOff))
// _activeDesigns.ChangeStain(_currentSave, EquipSlot.OffHand, stainOff.RowIndex, false);
// ImGui.SameLine();
// _main._equipmentDrawer.DrawOffhand(currentOff, main.Type, out var off);
// }
//
// if (_main._equipmentDrawer.DrawVisor(_currentSave, out var value))
// _activeDesigns.ChangeVisor(_currentSave, value, false);
}
private unsafe void RevertButton()
{
//if (ImGui.Button("Revert"))
// _activeDesigns.RevertDesign(_currentSave!);
//foreach (var actor in _currentData.Objects)
// _currentSave!.ApplyToActor(actor);
//
//if (_currentData.Objects.Count > 0)
// _currentSave = _manipulations.GetOrCreateSave(_currentData.Objects[0]);
//
//_currentSave!.Reset();
//if (_currentData.Objects.Count > 0)
// ImGui.TextUnformatted(_currentData.Objects[0].Pointer->GameObject.DataID.ToString());
//VisorBox();
}
//private unsafe void VisorBox()
//{
// var (flags, mask) = (_currentSave!.Data.Flags & (ApplicationFlags.SetVisor | ApplicationFlags.Visor)) switch
// {
// ApplicationFlags.SetVisor => (0u, 3u),
// ApplicationFlags.Visor => (1u, 3u),
// ApplicationFlags.SetVisor | ApplicationFlags.Visor => (3u, 3u),
// _ => (2u, 3u),
// };
// var tmp = flags;
// if (ImGui.CheckboxFlags("Visor Toggled", ref tmp, mask))
// {
// _currentSave.Data.Flags = flags switch
// {
// 0 => (_currentSave.Data.Flags | ApplicationFlags.Visor) & ~ApplicationFlags.SetVisor,
// 1 => _currentSave.Data.Flags | ApplicationFlags.SetVisor,
// 2 => _currentSave.Data.Flags | ApplicationFlags.SetVisor,
// _ => _currentSave.Data.Flags & ~(ApplicationFlags.SetVisor | ApplicationFlags.Visor),
// };
// if (_currentSave.Data.Flags.HasFlag(ApplicationFlags.SetVisor))
// {
// var on = _currentSave.Data.Flags.HasFlag(ApplicationFlags.Visor);
// foreach (var actor in _currentData.Objects.Where(a => a.IsHuman && a.DrawObject))
// RedrawManager.SetVisor(actor.DrawObject.Pointer, on);
// }
// }
//}
//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);
// }
//}
}

View file

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Numerics;
using Dalamud.Game.ClientState.Objects;
using Dalamud.Interface;
using Glamourer.Interop;
using Glamourer.Interop.Structs;
using Glamourer.Services;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using Penumbra.GameData.Actors;
namespace Glamourer.Gui.Tabs.ActorTab;
public class ActorSelector
{
private readonly ObjectManager _objects;
private readonly ActorService _actors;
private readonly TargetManager _targets;
private ActorIdentifier _identifier = ActorIdentifier.Invalid;
public ActorSelector(ObjectManager objects, TargetManager targets, ActorService actors)
{
_objects = objects;
_targets = targets;
_actors = actors;
}
private LowerString _actorFilter = LowerString.Empty;
private Vector2 _defaultItemSpacing;
private float _width;
public (ActorIdentifier Identifier, ActorData Data) Selection
=> _objects.TryGetValue(_identifier, out var data) ? (_identifier, data) : (_identifier, ActorData.Invalid);
public bool HasSelection
=> _identifier.IsValid;
public void Draw(float width)
{
_width = width;
using var group = ImRaii.Group();
_defaultItemSpacing = ImGui.GetStyle().ItemSpacing;
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
ImGui.SetNextItemWidth(_width);
LowerString.InputWithHint("##actorFilter", "Filter...", ref _actorFilter, 64);
DrawSelector();
DrawSelectionButtons();
}
private void DrawSelector()
{
using var child = ImRaii.Child("##actorSelector", new Vector2(_width, -ImGui.GetFrameHeight()), true);
if (!child)
return;
_objects.Update();
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, _defaultItemSpacing);
var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight());
var remainder = ImGuiClip.FilteredClippedDraw(_objects, skips, CheckFilter, DrawSelectable);
ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight());
}
private bool CheckFilter(KeyValuePair<ActorIdentifier, ActorData> pair)
=> _actorFilter.IsEmpty || pair.Value.Label.Contains(_actorFilter.Lower, StringComparison.OrdinalIgnoreCase);
private void DrawSelectable(KeyValuePair<ActorIdentifier, ActorData> pair)
{
var equals = pair.Key.Equals(_identifier);
if (ImGui.Selectable(pair.Value.Label, equals) && !equals)
_identifier = pair.Key.CreatePermanent();
}
private void DrawSelectionButtons()
{
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)
.Push(ImGuiStyleVar.FrameRounding, 0);
var buttonWidth = new Vector2(_width / 2, 0);
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth
, "Select the local player character.", !_objects.Player, true))
_identifier = _objects.Player.GetIdentifier(_actors.AwaitedService);
ImGui.SameLine();
Actor targetActor = _targets.Target?.Address;
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth,
"Select the current target, if it is in the list.", _objects.IsInGPose || !targetActor, true))
_identifier = targetActor.GetIdentifier(_actors.AwaitedService);
}
}

View file

@ -0,0 +1,28 @@
using System;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.ActorTab;
public class ActorTab : ITab
{
private readonly ActorSelector _selector;
private readonly ActorPanel _panel;
public ReadOnlySpan<byte> Label
=> "Actors"u8;
public void DrawContent()
{
_selector.Draw(200 * ImGuiHelpers.GlobalScale);
ImGui.SameLine();
_panel.Draw();
}
public ActorTab(ActorSelector selector, ActorPanel panel)
{
_selector = selector;
_panel = panel;
}
}

View file

@ -66,7 +66,7 @@ public unsafe class DebugTab : ITab
_designFileSystem = designFileSystem;
_designManager = designManager;
_state = state;
_config = config;
_config = config;
}
public ReadOnlySpan<byte> Label
@ -74,6 +74,10 @@ public unsafe class DebugTab : ITab
public void DrawContent()
{
using var child = ImRaii.Child("MainWindowChild");
if (!child)
return;
DrawInteropHeader();
DrawGameDataHeader();
DrawPenumbraHeader();
@ -829,7 +833,7 @@ public unsafe class DebugTab : ITab
}
}
private static void DrawDesignData(in DesignData data)
public static void DrawDesignData(in DesignData data)
{
if (data.ModelId == 0)
{

View file

@ -0,0 +1,66 @@
using System.Numerics;
using Dalamud.Game.ClientState.Keys;
using Dalamud.Interface;
using Glamourer.Designs;
using Glamourer.Events;
using OtterGui;
using OtterGui.Filesystem;
using OtterGui.FileSystem.Selector;
namespace Glamourer.Gui.Tabs.DesignTab;
public sealed class DesignFileSystemSelector : FileSystemSelector<Design, DesignFileSystemSelector.DesignState>
{
private readonly DesignManager _designManager;
private readonly DesignChanged _event;
private readonly Configuration _config;
public struct DesignState
{ }
public DesignFileSystemSelector(DesignManager designManager, DesignFileSystem fileSystem, KeyState keyState, DesignChanged @event,
Configuration config)
: base(fileSystem, keyState)
{
_designManager = designManager;
_event = @event;
_config = config;
_event.Subscribe(OnDesignChange, DesignChanged.Priority.DesignFileSystemSelector);
AddButton(DeleteButton, 1000);
}
public override void Dispose()
{
base.Dispose();
_event.Unsubscribe(OnDesignChange);
}
private void OnDesignChange(DesignChanged.Type type, Design design, object? oldData)
{
switch (type)
{
case DesignChanged.Type.ReloadedAll:
case DesignChanged.Type.Renamed:
case DesignChanged.Type.AddedTag:
case DesignChanged.Type.ChangedTag:
case DesignChanged.Type.RemovedTag:
SetFilterDirty();
break;
}
}
private void DeleteButton(Vector2 size)
{
var keys = _config.DeleteDesignModifier.IsActive();
var tt = SelectedLeaf == null
? "No design selected."
: "Delete the currently selected design entirely from your drive.\n"
+ "This can not be undone.";
if (!keys)
tt += $"\nHold {_config.DeleteDesignModifier} while clicking to delete the mod.";
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), size, tt, SelectedLeaf == null || !keys, true)
&& Selected != null)
_designManager.Delete(Selected);
}
}

View file

@ -0,0 +1,33 @@
using System.Numerics;
using Glamourer.Designs;
using Glamourer.Gui.Customization;
using OtterGui.Raii;
namespace Glamourer.Gui.Tabs.DesignTab;
public class DesignPanel
{
private readonly DesignFileSystemSelector _selector;
private readonly DesignManager _manager;
private readonly CustomizationDrawer _customizationDrawer;
public DesignPanel(DesignFileSystemSelector selector, CustomizationDrawer customizationDrawer, DesignManager manager)
{
_selector = selector;
_customizationDrawer = customizationDrawer;
_manager = manager;
}
public void Draw()
{
var design = _selector.Selected;
if (design == null)
return;
using var child = ImRaii.Child("##panel", -Vector2.One, true);
if (!child)
return;
_customizationDrawer.Draw(design.DesignData.Customize, design.WriteProtected());
}
}

View file

@ -0,0 +1,39 @@
using System;
using Dalamud.Interface;
using Glamourer.Designs;
using Glamourer.Interop;
using ImGuiNET;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab;
public class DesignTab : ITab
{
public readonly DesignFileSystemSelector Selector;
private readonly DesignFileSystem _fileSystem;
private readonly DesignManager _designManager;
private readonly DesignPanel _panel;
private readonly ObjectManager _objects;
public DesignTab(DesignFileSystemSelector selector, DesignFileSystem fileSystem, DesignManager designManager, ObjectManager objects, DesignPanel panel)
{
Selector = selector;
_fileSystem = fileSystem;
_designManager = designManager;
_objects = objects;
_panel = panel;
}
public ReadOnlySpan<byte> Label
=> "Designs"u8;
public void DrawContent()
{
Selector.Draw(GetDesignSelectorSize());
ImGui.SameLine();
_panel.Draw();
}
public float GetDesignSelectorSize()
=> 200f * ImGuiHelpers.GlobalScale;
}

View file

@ -1,8 +1,10 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Interface;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
@ -20,20 +22,23 @@ public class SettingsTab : ITab
public void DrawContent()
{
using var child = ImRaii.Child("##SettingsTab", -Vector2.One, false);
using var child = ImRaii.Child("MainWindowChild");
if (!child)
return;
Checkbox("Restricted Gear Protection",
"Use gender- and race-appropriate models when detecting certain items not available for a characters current gender and race.",
_config.UseRestrictedGearProtection, v => _config.UseRestrictedGearProtection = v);
if (Widget.DoubleModifierSelector("Design Deletion Modifier",
"A modifier you need to hold while clicking the Delete Design button for it to take effect.", 100 * ImGuiHelpers.GlobalScale,
_config.DeleteDesignModifier, v => _config.DeleteDesignModifier = v))
_config.Save();
Checkbox("Debug Mode", "Show the debug tab. Only useful for debugging or advanced use.", _config.DebugMode, v => _config.DebugMode = v);
DrawColorSettings();
MainWindow.DrawSupportButtons();
}
/// <summary> Draw the entire Color subsection. </summary>
private void DrawColorSettings()
{