feat(sidebar): restore tab rename via shared context menu
This commit is contained in:
@@ -400,6 +400,7 @@ public sealed class Plugin : IAsyncDalamudPlugin
|
|||||||
new SelfTests.DisclosureArmStep(this),
|
new SelfTests.DisclosureArmStep(this),
|
||||||
new SelfTests.TellRoutingBuildStep(this),
|
new SelfTests.TellRoutingBuildStep(this),
|
||||||
new SelfTests.TellPillTransparencyStep(this),
|
new SelfTests.TellPillTransparencyStep(this),
|
||||||
|
new SelfTests.TabRenamePersistStep(this),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Re-surface the wizard for existing users when a major UX
|
// Re-surface the wizard for existing users when a major UX
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Plugin.SelfTest;
|
||||||
|
using HellionChat.Ui.Components;
|
||||||
|
|
||||||
|
namespace HellionChat.SelfTests;
|
||||||
|
|
||||||
|
// B3-1: rename must persist. Drives the real ApplyTabRename (the InputText
|
||||||
|
// callback path), then SaveConfig + reload from disk and asserts the new name
|
||||||
|
// survived — a fresh-from-config tab, not the same reference (a reference check
|
||||||
|
// would pass on a dead roundtrip). Uses a persistent (non-temp) tab: unpinned
|
||||||
|
// temp tabs are stripped on save (ShouldStripOnSave) and would not survive.
|
||||||
|
internal sealed class TabRenamePersistStep : ISelfTestStep
|
||||||
|
{
|
||||||
|
private readonly Plugin plugin;
|
||||||
|
|
||||||
|
public TabRenamePersistStep(Plugin plugin) => this.plugin = plugin;
|
||||||
|
|
||||||
|
public string Name => "Hellion Chat - Tab rename persists";
|
||||||
|
|
||||||
|
public SelfTestStepResult RunStep()
|
||||||
|
{
|
||||||
|
var tab = Plugin.Config.Tabs.FirstOrDefault(t => !t.IsTempTab);
|
||||||
|
if (tab is null)
|
||||||
|
{
|
||||||
|
ImGui.Text("No persistent tab to rename");
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
var original = tab.Name;
|
||||||
|
var probe = original + "##selftest";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!TabContextMenu.ApplyTabRename(tab, probe))
|
||||||
|
{
|
||||||
|
ImGui.Text("ApplyTabRename reported no change");
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
plugin.SaveConfig();
|
||||||
|
|
||||||
|
// Reload from disk into a throwaway config; assert the new name landed.
|
||||||
|
var reloaded = Plugin.Interface.GetPluginConfig() as Configuration;
|
||||||
|
var match = reloaded?.Tabs.Any(t => t.Name == probe) ?? false;
|
||||||
|
if (!match)
|
||||||
|
{
|
||||||
|
ImGui.Text("Renamed tab not found after reload");
|
||||||
|
return SelfTestStepResult.Fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
tab.Name = original;
|
||||||
|
plugin.SaveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
return SelfTestStepResult.Pass;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CleanUp() { }
|
||||||
|
}
|
||||||
@@ -159,12 +159,7 @@ internal sealed class Sidebar
|
|||||||
if (expanded)
|
if (expanded)
|
||||||
dl.AddText(origin + new Vector2(32f, 8f), textAbgr, tab.Name);
|
dl.AddText(origin + new Vector2(32f, 8f), textAbgr, tab.Name);
|
||||||
|
|
||||||
if (ImGui.BeginPopupContextItem("ctx"))
|
TabContextMenu.Draw(tab, "ctx", _pool);
|
||||||
{
|
|
||||||
if (ImGui.MenuItem("Pop Out"))
|
|
||||||
_pool.TryOpen(tab);
|
|
||||||
ImGui.EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
var popHovered = false;
|
var popHovered = false;
|
||||||
if (hasPopOut)
|
if (hasPopOut)
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Dalamud.Bindings.ImGui;
|
||||||
|
using Dalamud.Interface.Utility;
|
||||||
|
|
||||||
|
namespace HellionChat.Ui.Components;
|
||||||
|
|
||||||
|
// Shared right-click menu for both tab layouts (Sidebar rows + TopTabBar). One
|
||||||
|
// source of truth instead of two divergent inline blocks. Static: it has no own
|
||||||
|
// state and reaches the live Config/Plugin through Plugin.Instance/Plugin.Config.
|
||||||
|
internal static class TabContextMenu
|
||||||
|
{
|
||||||
|
// MUST be called immediately after the row-carrying ImGui item (Sidebar
|
||||||
|
// "row" InvisibleButton / TopTabBar Selectable). popupId only names the
|
||||||
|
// popup; the open trigger is a right-click on the LAST submitted item
|
||||||
|
// (g.LastItemData via IsItemHovered) — any interactive item in between
|
||||||
|
// would steal the trigger. Only DrawList ops may sit between.
|
||||||
|
public static void Draw(Tab tab, string popupId, Windows.ChannelPopoutPool pool)
|
||||||
|
{
|
||||||
|
if (!ImGui.BeginPopupContextItem(popupId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Rename: focus the field the first frame the popup appears.
|
||||||
|
if (ImGui.IsWindowAppearing())
|
||||||
|
ImGui.SetKeyboardFocusHere();
|
||||||
|
ImGui.SetNextItemWidth(250f * ImGuiHelpers.GlobalScale);
|
||||||
|
var name = tab.Name;
|
||||||
|
if (ImGui.InputText("##tab-name", ref name, 512) && ApplyTabRename(tab, name))
|
||||||
|
Plugin.Instance.SaveConfig();
|
||||||
|
|
||||||
|
if (ImGui.MenuItem("Pop Out"))
|
||||||
|
pool.TryOpen(tab);
|
||||||
|
|
||||||
|
ImGui.EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Factored out so the SelfTest drives the real rename path, not a field poke.
|
||||||
|
// Returns true when the name actually changed (gates the SaveConfig write).
|
||||||
|
internal static bool ApplyTabRename(Tab tab, string newName)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(newName) || newName == tab.Name)
|
||||||
|
return false;
|
||||||
|
tab.Name = newName;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -38,12 +38,7 @@ internal sealed class TopTabBar
|
|||||||
TabLifecycleHelpers.EnsureCurrentChannel(tab);
|
TabLifecycleHelpers.EnsureCurrentChannel(tab);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui.BeginPopupContextItem($"toptab_ctx_{i}"))
|
TabContextMenu.Draw(tab, $"toptab_ctx_{i}", _pool);
|
||||||
{
|
|
||||||
if (ImGui.MenuItem("Pop Out"))
|
|
||||||
_pool.TryOpen(tab);
|
|
||||||
ImGui.EndPopup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.Separator();
|
ImGui.Separator();
|
||||||
|
|||||||
Reference in New Issue
Block a user