This commit is contained in:
Ottermandias 2023-06-20 18:54:33 +02:00
parent d1d369a56b
commit 65ce391051
19 changed files with 757 additions and 158 deletions

View file

@ -9,24 +9,25 @@ public enum ColorId
EquipmentDesign,
ActorAvailable,
ActorUnavailable,
FolderExpanded,
FolderCollapsed,
FolderLine,
}
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 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.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." ),
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." ),
ColorId.FolderExpanded => (0xFFFFF0C0, "Expanded Design Folder", "A design folder that is currently expanded." ),
ColorId.FolderCollapsed => (0xFFFFF0C0, "Collapsed Design Folder", "A design folder that is currently collapsed." ),
ColorId.FolderLine => (0xFFFFF0C0, "Expanded Design Folder Line", "The line signifying which descendants belong to an expanded design folder." ),
_ => (0x00000000, string.Empty, string.Empty ),
// @formatter:on
};

View file

@ -6,14 +6,16 @@ namespace Glamourer.Gui;
public class GlamourerWindowSystem : IDisposable
{
private readonly WindowSystem _windowSystem = new("Glamourer");
private readonly UiBuilder _uiBuilder;
private readonly MainWindow _ui;
private readonly WindowSystem _windowSystem = new("Glamourer");
private readonly UiBuilder _uiBuilder;
private readonly MainWindow _ui;
private readonly PenumbraChangedItemTooltip _penumbraTooltip;
public GlamourerWindowSystem(UiBuilder uiBuilder, MainWindow ui)
public GlamourerWindowSystem(UiBuilder uiBuilder, MainWindow ui, PenumbraChangedItemTooltip penumbraTooltip)
{
_uiBuilder = uiBuilder;
_ui = ui;
_uiBuilder = uiBuilder;
_ui = ui;
_penumbraTooltip = penumbraTooltip;
_windowSystem.AddWindow(ui);
_uiBuilder.Draw += _windowSystem.Draw;
_uiBuilder.OpenConfigUi += _ui.Toggle;

View file

@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Services;
using Glamourer.State;
using Glamourer.Structs;
using ImGuiNET;
using Penumbra.Api.Enums;
using Penumbra.GameData.Enums;
using Penumbra.GameData.Structs;
namespace Glamourer.Gui;
public class PenumbraChangedItemTooltip : IDisposable
{
private readonly PenumbraService _penumbra;
private readonly StateManager _stateManager;
private readonly ItemManager _items;
private readonly ObjectManager _objects;
private readonly EquipItem[] _lastItems = new EquipItem[EquipFlagExtensions.NumEquipFlags / 2];
public IEnumerable<KeyValuePair<EquipSlot, EquipItem>> LastItems
=> EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand).Zip(_lastItems)
.Select(p => new KeyValuePair<EquipSlot, EquipItem>(p.First, p.Second));
public DateTime LastTooltip { get; private set; } = DateTime.MinValue;
public DateTime LastClick { get; private set; } = DateTime.MinValue;
public PenumbraChangedItemTooltip(PenumbraService penumbra, StateManager stateManager, ItemManager items, ObjectManager objects)
{
_penumbra = penumbra;
_stateManager = stateManager;
_items = items;
_objects = objects;
_penumbra.Tooltip += OnPenumbraTooltip;
_penumbra.Click += OnPenumbraClick;
}
public void Dispose()
{
_penumbra.Tooltip -= OnPenumbraTooltip;
_penumbra.Click -= OnPenumbraClick;
}
private void OnPenumbraTooltip(ChangedItemType type, uint id)
{
LastTooltip = DateTime.UtcNow;
if (!_objects.Player.Valid)
return;
switch (type)
{
case ChangedItemType.Item:
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
return;
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
ImGui.TextUnformatted("[Glamourer] Right-Click to apply to current actor (Right Finger).");
ImGui.TextUnformatted("[Glamourer] Shift + Right-Click to apply to current actor (Left Finger).");
if (last.Valid)
ImGui.TextUnformatted(
$"[Glamourer] Control + Right-Click to re-apply {last.Name} to current actor (Right Finger).");
var last2 = _lastItems[EquipSlot.LFinger.ToIndex()];
if (last2.Valid)
ImGui.TextUnformatted(
$"[Glamourer] Shift + Control + Right-Click to re-apply {last.Name} to current actor (Left Finger).");
break;
default:
ImGui.TextUnformatted("[Glamourer] Right-Click to apply to current actor.");
if (last.Valid)
ImGui.TextUnformatted($"[Glamourer] Control + Right-Click to re-apply {last.Name} to current actor.");
break;
}
return;
}
}
private bool CanApplyWeapon(EquipSlot slot, EquipItem item)
{
var main = _objects.Player.GetMainhand();
var mainItem = _items.Identify(slot, main.Set, main.Type, (byte)main.Variant);
if (slot == EquipSlot.MainHand)
return item.Type == mainItem.Type;
return item.Type == mainItem.Type.Offhand();
}
private void OnPenumbraClick(MouseButton button, ChangedItemType type, uint id)
{
LastClick = DateTime.UtcNow;
switch (type)
{
case ChangedItemType.Item:
if (button is not MouseButton.Right)
return;
var (identifier, data) = _objects.PlayerData;
if (!data.Valid)
return;
if (!_stateManager.GetOrCreate(identifier, data.Objects[0], out var state))
return;
if (!_items.ItemService.AwaitedService.TryGetValue(id, out var item))
return;
var slot = item.Type.ToSlot();
var last = _lastItems[slot.ToIndex()];
switch (slot)
{
case EquipSlot.MainHand when !CanApplyWeapon(EquipSlot.MainHand, item):
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
break;
case EquipSlot.RFinger:
switch (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift)
{
case (false, false):
Glamourer.Log.Information($"Applying {item.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, item, state);
break;
case (false, true):
Glamourer.Log.Information($"Applying {item.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, item, state);
break;
case (true, false) when last.Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Right Finger.");
SetLastItem(EquipSlot.RFinger, default, state);
break;
case (true, true) when _lastItems[EquipSlot.LFinger.ToIndex()].Valid:
Glamourer.Log.Information($"Re-Applying {last.Name} to Left Finger.");
SetLastItem(EquipSlot.LFinger, default, state);
break;
}
return;
default:
if (ImGui.GetIO().KeyCtrl && last.Valid)
{
Glamourer.Log.Information($"Re-Applying {last.Name} to {slot.ToName()}.");
SetLastItem(slot, default, state);
}
else
{
Glamourer.Log.Information($"Applying {item.Name} to {slot.ToName()}.");
SetLastItem(slot, item, state);
}
return;
}
return;
}
}
private void SetLastItem(EquipSlot slot, EquipItem item, ActorState state)
{
ref var last = ref _lastItems[slot.ToIndex()];
if (!item.Valid)
{
last = default;
}
else
{
var oldItem = state.ModelData.Item(slot);
if (oldItem.Id != item.Id)
_lastItems[slot.ToIndex()] = oldItem;
}
}
}

View file

@ -75,7 +75,7 @@ public class ActorPanel
if (!child || _state == null)
return;
if (_customizationDrawer.Draw(_state.Data.Customize, false))
if (_customizationDrawer.Draw(_state.ModelData.Customize, false))
{
}
// if (_currentData.Valid)

View file

@ -41,6 +41,8 @@ public unsafe class DebugTab : ITab
private readonly DesignManager _designManager;
private readonly DesignFileSystem _designFileSystem;
private readonly PenumbraChangedItemTooltip _penumbraTooltip;
private readonly StateManager _state;
private int _gameObjectIndex;
@ -51,7 +53,8 @@ public unsafe class DebugTab : ITab
public DebugTab(ChangeCustomizeService changeCustomizeService, VisorService visorService, ObjectTable objects,
UpdateSlotService updateSlotService, WeaponService weaponService, PenumbraService penumbra,
ActorService actors, ItemManager items, CustomizationService customization, ObjectManager objectManager,
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config)
DesignFileSystem designFileSystem, DesignManager designManager, StateManager state, Configuration config,
PenumbraChangedItemTooltip penumbraTooltip)
{
_changeCustomizeService = changeCustomizeService;
_visorService = visorService;
@ -67,6 +70,7 @@ public unsafe class DebugTab : ITab
_designManager = designManager;
_state = state;
_config = config;
_penumbraTooltip = penumbraTooltip;
}
public ReadOnlySpan<byte> Label
@ -434,6 +438,23 @@ public unsafe class DebugTab : ITab
if (ImGui.SmallButton("Redraw"))
_penumbra.RedrawObject(_objects.GetObjectAddress(_gameObjectIndex), RedrawType.Redraw);
}
ImGuiUtil.DrawTableColumn("Last Tooltip Date");
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastTooltip > DateTime.MinValue ? _penumbraTooltip.LastTooltip.ToLongTimeString() : "Never");
ImGui.TableNextColumn();
ImGuiUtil.DrawTableColumn("Last Click Date");
ImGuiUtil.DrawTableColumn(_penumbraTooltip.LastClick > DateTime.MinValue ? _penumbraTooltip.LastClick.ToLongTimeString() : "Never");
ImGui.TableNextColumn();
ImGui.Separator();
ImGui.Separator();
foreach (var (slot, item) in _penumbraTooltip.LastItems)
{
ImGuiUtil.DrawTableColumn($"{slot.ToName()} Revert-Item");
ImGuiUtil.DrawTableColumn(item.Valid ? item.Name : "None");
ImGui.TableNextColumn();
}
}
#endregion
@ -990,7 +1011,7 @@ public unsafe class DebugTab : ITab
continue;
if (_state.GetOrCreate(identifier, actors.Objects[0], out var state))
DrawDesignData(state.Data);
DrawDesignData(state.ModelData);
else
ImGui.TextUnformatted("Invalid actor.");
}
@ -1006,7 +1027,7 @@ public unsafe class DebugTab : ITab
{
using var t = ImRaii.TreeNode(identifier.ToString());
if (t)
DrawDesignData(state.Data);
DrawDesignData(state.ModelData);
}
}

View file

@ -35,6 +35,21 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
_event.Unsubscribe(OnDesignChange);
}
public override ISortMode<Design> SortMode
=> _config.SortMode;
protected override uint ExpandedFolderColor
=> ColorId.FolderExpanded.Value();
protected override uint CollapsedFolderColor
=> ColorId.FolderCollapsed.Value();
protected override uint FolderLineColor
=> ColorId.FolderLine.Value();
protected override bool FoldersDefaultOpen
=> _config.OpenFoldersByDefault;
private void OnDesignChange(DesignChanged.Type type, Design design, object? oldData)
{
switch (type)

View file

@ -1,10 +1,10 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using Dalamud.Interface;
using Glamourer.Gui.Tabs.DesignTab;
using Glamourer.State;
using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Widgets;
@ -12,10 +12,16 @@ namespace Glamourer.Gui.Tabs;
public class SettingsTab : ITab
{
private readonly Configuration _config;
private readonly Configuration _config;
private readonly DesignFileSystemSelector _selector;
private readonly StateListener _stateListener;
public SettingsTab(Configuration config)
=> _config = config;
public SettingsTab(Configuration config, DesignFileSystemSelector selector, StateListener stateListener)
{
_config = config;
_selector = selector;
_stateListener = stateListener;
}
public ReadOnlySpan<byte> Label
=> "Settings"u8;
@ -25,7 +31,7 @@ public class SettingsTab : ITab
using var child = ImRaii.Child("MainWindowChild");
if (!child)
return;
Checkbox("Enabled", "Enable main functionality of keeping and applying state.", _stateListener.Enabled, _stateListener.Enable);
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);
@ -33,6 +39,10 @@ public class SettingsTab : ITab
"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();
DrawFolderSortType();
Checkbox("Auto-Open Design Folders",
"Have design folders open or closed as their default state after launching.", _config.OpenFoldersByDefault,
v => _config.OpenFoldersByDefault = v);
Checkbox("Debug Mode", "Show the debug tab. Only useful for debugging or advanced use.", _config.DebugMode, v => _config.DebugMode = v);
DrawColorSettings();
@ -70,4 +80,28 @@ public class SettingsTab : ITab
ImGui.SameLine();
ImGuiUtil.LabeledHelpMarker(label, tooltip);
}
/// <summary> Different supported sort modes as a combo. </summary>
private void DrawFolderSortType()
{
var sortMode = _config.SortMode;
ImGui.SetNextItemWidth(300 * ImGuiHelpers.GlobalScale);
using (var combo = ImRaii.Combo("##sortMode", sortMode.Name))
{
if (combo)
foreach (var val in Configuration.Constants.ValidSortModes)
{
if (ImGui.Selectable(val.Name, val.GetType() == sortMode.GetType()) && val.GetType() != sortMode.GetType())
{
_config.SortMode = val;
_selector.SetFilterDirty();
_config.Save();
}
ImGuiUtil.HoverTooltip(val.Description);
}
}
ImGuiUtil.LabeledHelpMarker("Sort Mode", "Choose the sort mode for the mod selector in the designs tab.");
}
}