Context menu fixes

- Allow opening of titled context menus we didn't create
- Allow customization of the red button context menus
This commit is contained in:
r00telement
2022-01-11 22:38:54 +00:00
parent 6db44881b1
commit a93c9ef8b9
5 changed files with 45 additions and 26 deletions

View File

@@ -314,7 +314,14 @@ namespace PlayerTags.GameInterface.ContextMenus
// Read the context menu items from the game, then allow subscribers to modify them
ContextMenuReaderWriter contextMenuReaderWriter = new ContextMenuReaderWriter(m_CurrentContextMenuAgent, atkValueCount, atkValues);
m_CurrentContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, contextMenuOpenedDelegate, contextMenuReaderWriter.Read());
string? title = null;
if (contextMenuReaderWriter.Title != null)
{
title = contextMenuReaderWriter.Title.TextValue;
}
m_CurrentContextMenuOpenedArgs = NotifyContextMenuOpened(addon, m_CurrentContextMenuAgent, title, contextMenuOpenedDelegate, contextMenuReaderWriter.Read());
if (m_CurrentContextMenuOpenedArgs == null)
{
return;
@@ -413,17 +420,10 @@ namespace PlayerTags.GameInterface.ContextMenus
private unsafe void SubContextMenuOpenedImplementation(IntPtr addon, ref int atkValueCount, ref AtkValue* atkValues)
{
// For now, don't allow to modifying sub context menus unless we created them.
// TODO: May want to allow this.
if (m_CurrentSelectedItem == null)
{
return;
}
ContextMenuOpenedImplementation(addon, ref atkValueCount, ref atkValues);
}
private unsafe ContextMenuOpenedArgs? NotifyContextMenuOpened(IntPtr addon, IntPtr agent, ContextMenuOpenedDelegate contextMenuOpenedDelegate, IEnumerable<ContextMenuItem> initialContextMenuItems)
private unsafe ContextMenuOpenedArgs? NotifyContextMenuOpened(IntPtr addon, IntPtr agent, string? title, ContextMenuOpenedDelegate contextMenuOpenedDelegate, IEnumerable<ContextMenuItem> initialContextMenuItems)
{
var parentAddonName = GetParentAddonName(addon);
@@ -451,6 +451,7 @@ namespace PlayerTags.GameInterface.ContextMenus
var contextMenuOpenedArgs = new ContextMenuOpenedArgs(addon, agent, parentAddonName, initialContextMenuItems)
{
Title = title,
ItemContext = itemContext,
GameObjectContext = gameObjectContext
};

View File

@@ -24,6 +24,11 @@ namespace PlayerTags.GameInterface.ContextMenus
/// </summary>
public string? ParentAddonName { get; }
/// <summary>
/// The title of the context menu.
/// </summary>
public string? Title { get; init; }
/// <summary>
/// The items in the context menu.
/// </summary>

View File

@@ -239,16 +239,22 @@ namespace PlayerTags.GameInterface.ContextMenus
}
// Get the action
byte* actions = null;
byte action = 0;
if (IsInventoryContext)
{
actions = &((AgentInventoryContext*)m_Agent)->Actions;
var actions = &((AgentInventoryContext*)m_Agent)->Actions;
action = *(actions + contextMenuItemAtkValueBaseIndex);
}
else if (StructLayout != null && StructLayout.Value == SubContextMenuStructLayout.Alternate)
{
var actions = &((AgentContext*)m_Agent)->ItemData->RedButtonActions;
action = (byte)*(actions + contextMenuItemIndex);
}
else
{
actions = &((AgentContext*)m_Agent)->ItemData->Actions;
}
byte action = *(actions + contextMenuItemAtkValueBaseIndex);
var actions = &((AgentContext*)m_Agent)->ItemData->Actions;
action = *(actions + contextMenuItemAtkValueBaseIndex);
}
// Get the has previous indicator flag
var hasPreviousIndicatorFlagsAtkValue = &m_AtkValues[HasPreviousIndicatorFlagsIndex];
@@ -281,7 +287,7 @@ namespace PlayerTags.GameInterface.ContextMenus
return gameContextMenuItems.ToArray();
}
public unsafe void Write(ContextMenuOpenedArgs contextMenuOpenedArgs, ContextMenuItem selectedContextMenuItem, AtkValueChangeTypeDelegate_Unmanaged atkValueChangeType, AtkValueSetStringDelegate_Unmanaged atkValueSetString)
public unsafe void Write(ContextMenuOpenedArgs contextMenuOpenedArgs, ContextMenuItem? selectedContextMenuItem, AtkValueChangeTypeDelegate_Unmanaged atkValueChangeType, AtkValueSetStringDelegate_Unmanaged atkValueSetString)
{
var newAtkValuesCount = FirstContextMenuItemIndex + (contextMenuOpenedArgs.ContextMenuItems.Count() * TotalDesiredAtkValuesPerContextMenuItem);
@@ -358,7 +364,7 @@ namespace PlayerTags.GameInterface.ContextMenus
byte action = 0;
if (contextMenuItem is GameContextMenuItem gameContextMenuItem)
{
action = gameContextMenuItem.ItemSelectedAction;
action = gameContextMenuItem.SelectedAction;
}
else if (contextMenuItem is CustomContextMenuItem customContextMenuItem)
{
@@ -375,7 +381,8 @@ namespace PlayerTags.GameInterface.ContextMenus
{
if (IsInventoryContext)
{
action = 0x30;
// TODO: Fix inventory sub context menus
action = /*0x30*/ 0xff;
}
else
{
@@ -383,16 +390,21 @@ namespace PlayerTags.GameInterface.ContextMenus
}
}
byte* actions = null;
if (IsInventoryContext)
{
actions = &((AgentInventoryContext*)m_Agent)->Actions;
var actions = &((AgentInventoryContext*)m_Agent)->Actions;
*(actions + FirstContextMenuItemIndex + contextMenuItemIndex) = action;
}
else if (StructLayout != null && StructLayout.Value == SubContextMenuStructLayout.Alternate)
{
var actions = &((AgentContext*)m_Agent)->ItemData->RedButtonActions;
*(actions + contextMenuItemIndex) = action;
}
else
{
actions = &((AgentContext*)m_Agent)->ItemData->Actions;
var actions = &((AgentContext*)m_Agent)->ItemData->Actions;
*(actions + FirstContextMenuItemIndex + contextMenuItemIndex) = action;
}
*(actions + FirstContextMenuItemIndex + contextMenuItemIndex) = action;
if (contextMenuItem.Indicator == ContextMenuItemIndicator.Previous)
{
@@ -436,7 +448,7 @@ namespace PlayerTags.GameInterface.ContextMenus
object? value = null;
if (atkValue->Type == FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Int)
{
value = atkValue->Int;
value = $"{atkValue->Int:X}";
}
else if (atkValue->Type == FFXIVClientStructs.FFXIV.Component.GUI.ValueType.Bool)
{

View File

@@ -9,5 +9,6 @@ namespace FFXIVClientStructs.FFXIV.Client.UI.Agent
[FieldOffset(0x0)] public ushort AtkValuesCount;
[FieldOffset(0x8)] public AtkValue AtkValues;
[FieldOffset(0x428)] public byte Actions;
[FieldOffset(0x598)] public ulong RedButtonActions;
}
}

View File

@@ -10,17 +10,17 @@ namespace PlayerTags.GameInterface.ContextMenus
/// <summary>
/// The game action that will be handled when the item is selected.
/// </summary>
public byte ItemSelectedAction { get; }
public byte SelectedAction { get; }
/// <summary>
/// Initializes a new instance of the <see cref="GameContextMenuItem"/> class.
/// </summary>
/// <param name="name">The name of the item.</param>
/// <param name="itemSelectedAction">The game action that will be handled when the item is selected.</param>
public GameContextMenuItem(SeString name, byte itemSelectedAction)
/// <param name="selectedAction">The game action that will be handled when the item is selected.</param>
public GameContextMenuItem(SeString name, byte selectedAction)
: base(name)
{
ItemSelectedAction = itemSelectedAction;
SelectedAction = selectedAction;
}
}
}