diff --git a/HellionChat/Configuration.cs b/HellionChat/Configuration.cs index 51a1941..5381ed4 100755 --- a/HellionChat/Configuration.cs +++ b/HellionChat/Configuration.cs @@ -113,6 +113,11 @@ public class Configuration : IPluginConfiguration public int AutoTellTabsLimit = 15; public bool AutoTellTabsCompactDisplay; public int AutoTellTabsHistoryPreload = 20; + + // Sidebar width in pixels. Default 44 mirrors the icon-only layout from + // v1.2.0; users can widen up to 160 to fit a section-header line like + // "Active Tells (3)" without truncation. + public int SidebarWidth = 44; public bool AutoTellTabsShowGreetedToggle; public bool SeenPopOutInputHint; public bool PopOutInputEnabled = true; @@ -339,6 +344,7 @@ public class Configuration : IPluginConfiguration AutoTellTabsLimit = other.AutoTellTabsLimit; AutoTellTabsCompactDisplay = other.AutoTellTabsCompactDisplay; AutoTellTabsHistoryPreload = other.AutoTellTabsHistoryPreload; + SidebarWidth = other.SidebarWidth; AutoTellTabsShowGreetedToggle = other.AutoTellTabsShowGreetedToggle; SeenPopOutInputHint = other.SeenPopOutInputHint; diff --git a/HellionChat/Resources/HellionStrings.Designer.cs b/HellionChat/Resources/HellionStrings.Designer.cs index 3282998..2aaddc8 100644 --- a/HellionChat/Resources/HellionStrings.Designer.cs +++ b/HellionChat/Resources/HellionStrings.Designer.cs @@ -177,6 +177,9 @@ internal class HellionStrings internal static string PinTab_LimitReached => Get(nameof(PinTab_LimitReached)); internal static string PinTab_PinnedTooltip => Get(nameof(PinTab_PinnedTooltip)); internal static string PinTab_PinTooltip => Get(nameof(PinTab_PinTooltip)); + internal static string PinTab_SectionHeader => Get(nameof(PinTab_SectionHeader)); + internal static string Settings_ThemeAndLayout_SidebarWidth_Name => Get(nameof(Settings_ThemeAndLayout_SidebarWidth_Name)); + internal static string Settings_ThemeAndLayout_SidebarWidth_Description => Get(nameof(Settings_ThemeAndLayout_SidebarWidth_Description)); // Hellion Chat — Auto-Tell-Tabs Chat settings tab internal static string ChatLog_AutoTellTabs_Section_Title => Get(nameof(ChatLog_AutoTellTabs_Section_Title)); diff --git a/HellionChat/Resources/HellionStrings.de.resx b/HellionChat/Resources/HellionStrings.de.resx index 766e2bf..e9fc2ff 100644 --- a/HellionChat/Resources/HellionStrings.de.resx +++ b/HellionChat/Resources/HellionStrings.de.resx @@ -404,6 +404,15 @@ Angepinnte Tabs überleben Relog und behalten die Bindung an die Tell-Person. + + Angepinnt + + + Sidebar-Breite + + + Breite der Tab-Sidebar in Pixeln. Default (44 px) ist Icon-only; breiter machen damit Sektion-Header wie „Aktive Tells (3)" nicht abgeschnitten werden. + diff --git a/HellionChat/Resources/HellionStrings.resx b/HellionChat/Resources/HellionStrings.resx index 101a6eb..8940f46 100644 --- a/HellionChat/Resources/HellionStrings.resx +++ b/HellionChat/Resources/HellionStrings.resx @@ -398,6 +398,15 @@ Pinned tabs survive relog and stay bound to this conversation partner. + + Pinned + + + Sidebar width + + + Width of the tab sidebar in pixels. The default (44 px) is icon-only; widen it to fit the section headers like "Active Tells (3)" without truncation. + Maximum of {0} pinned tell tabs reached. Unpin one first, or use Promote to permanent. diff --git a/HellionChat/Ui/ChatLogWindow.cs b/HellionChat/Ui/ChatLogWindow.cs index bab4bfc..e67f85c 100644 --- a/HellionChat/Ui/ChatLogWindow.cs +++ b/HellionChat/Ui/ChatLogWindow.cs @@ -1673,6 +1673,30 @@ public sealed class ChatLogWindow : Window Plugin.WantedTab = null; } + // Sidebar render order: persistent tabs in their original Plugin.Config.Tabs + // position, then pinned TempTabs, then unpinned TempTabs. Returns indices + // into Plugin.Config.Tabs so tabI in the loop body still mirrors the real + // list position (LastTab / WantedTab stay consistent). + private static List BuildSidebarRenderOrder() + { + var tabs = Plugin.Config.Tabs; + var persistent = new List(tabs.Count); + var pinned = new List(); + var unpinned = new List(); + for (var i = 0; i < tabs.Count; i++) + { + if (TabLifecycleHelpers.IsInPinnedPool(tabs[i])) + pinned.Add(i); + else if (TabLifecycleHelpers.IsInUnpinnedPool(tabs[i])) + unpinned.Add(i); + else + persistent.Add(i); + } + persistent.AddRange(pinned); + persistent.AddRange(unpinned); + return persistent; + } + private void DrawTabSidebar() { var currentTab = -1; @@ -1685,7 +1709,8 @@ public sealed class ChatLogWindow : Window if (!tabTable.Success) return; - ImGui.TableSetupColumn("tabs", ImGuiTableColumnFlags.WidthFixed, 44f); + var sidebarWidth = Math.Clamp(Plugin.Config.SidebarWidth, 44, 160); + ImGui.TableSetupColumn("tabs", ImGuiTableColumnFlags.WidthFixed, sidebarWidth); ImGui.TableSetupColumn("chat", ImGuiTableColumnFlags.WidthStretch, 1); ImGui.TableNextColumn(); @@ -1704,23 +1729,42 @@ public sealed class ChatLogWindow : Window ImGui.Dummy(new Vector2(0, ImGui.GetFrameHeightWithSpacing())); var previousTab = Plugin.CurrentTab; - // Divider rendered once before the first temp tab with a live unit counter. + // Render order: persistent → pinned TempTabs → unpinned TempTabs. + // Underlying Plugin.Config.Tabs order is untouched (tabI mirrors + // the real list index), only the display sequence groups by + // section so each section can carry its own divider header. + var renderOrder = BuildSidebarRenderOrder(); + var pinnedHeaderRendered = false; var tempTabHeaderRendered = false; - var tempTabCount = Plugin.Config.Tabs.Count(t => t.IsTempTab); + var pinnedCount = Plugin.Config.Tabs.Count(TabLifecycleHelpers.IsInPinnedPool); + var unpinnedTempCount = Plugin.Config.Tabs.Count( + TabLifecycleHelpers.IsInUnpinnedPool + ); - for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++) + foreach (var tabI in renderOrder) { var tab = Plugin.Config.Tabs[tabI]; if (tab.PopOut) continue; - if (tab.IsTempTab && !tempTabHeaderRendered) + if (TabLifecycleHelpers.IsInPinnedPool(tab) && !pinnedHeaderRendered) { ImGui.Separator(); if (!Plugin.Config.AutoTellTabsCompactDisplay) { ImGui.TextDisabled( - $"{HellionStrings.AutoTellTabs_SectionHeader} ({tempTabCount})" + $"{HellionStrings.PinTab_SectionHeader} ({pinnedCount})" + ); + } + pinnedHeaderRendered = true; + } + else if (TabLifecycleHelpers.IsInUnpinnedPool(tab) && !tempTabHeaderRendered) + { + ImGui.Separator(); + if (!Plugin.Config.AutoTellTabsCompactDisplay) + { + ImGui.TextDisabled( + $"{HellionStrings.AutoTellTabs_SectionHeader} ({unpinnedTempCount})" ); } tempTabHeaderRendered = true; @@ -1809,9 +1853,12 @@ public sealed class ChatLogWindow : Window using (ImRaii.PushColor(ImGuiCol.Text, ColourUtil.RgbaToAbgr(iconColor))) using (Plugin.FontManager.FontAwesome.Push()) { + // Button stretches with the configured sidebar width so a + // user-widened sidebar feels intentional, not a 36px icon + // floating in empty space. clicked = ImGui.Button( $"{icon.ToIconString()}##sidebar-tab-{tabI}", - new Vector2(36f, ImGui.GetFrameHeight()) + new Vector2(sidebarWidth - 8f, ImGui.GetFrameHeight()) ); } @@ -1871,22 +1918,23 @@ public sealed class ChatLogWindow : Window ); } - // Pin indicator: small thumbtack glyph top-left of the icon. - // Sits opposite the unread dot so they never collide. + // Pin indicator: subtle thumbtack glyph top-left of the icon. + // Muted colour because the "Pinned" section header already + // groups these tabs visually — this is just a per-tab + // confirmation glyph, not the primary discoverability cue. if (tab.IsPinned) { var min = ImGui.GetItemRectMin(); - const float pinPadding = 2f; + const float pinPadding = 1f; var pinPos = new Vector2(min.X + pinPadding, min.Y + pinPadding); + var pinColor = theme.Colors.TextMuted; + // Dim further so the glyph reads as a hint, not a badge. + var pinAbgr = ColourUtil.RgbaToAbgr(pinColor) & 0x77FFFFFFu; using (Plugin.FontManager.FontAwesome.Push()) { ImGui .GetWindowDrawList() - .AddText( - pinPos, - ColourUtil.RgbaToAbgr(theme.Colors.Accent), - FontAwesomeIcon.Thumbtack.ToIconString() - ); + .AddText(pinPos, pinAbgr, FontAwesomeIcon.Thumbtack.ToIconString()); } } diff --git a/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs b/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs index 890b76f..34baf54 100644 --- a/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs +++ b/HellionChat/Ui/SettingsTabs/ThemeAndLayout.cs @@ -250,6 +250,26 @@ internal sealed class ThemeAndLayout : ISettingsTab string.Format(Language.Options_SidebarTabView_Description, Plugin.PluginName) ); + if (Mutable.SidebarTabView) + { + var sidebarWidth = Mutable.SidebarWidth; + if ( + ImGui.SliderInt( + HellionStrings.Settings_ThemeAndLayout_SidebarWidth_Name, + ref sidebarWidth, + 44, + 160, + $"{sidebarWidth} px" + ) + ) + { + Mutable.SidebarWidth = sidebarWidth; + } + ImGuiUtil.HelpMarker( + HellionStrings.Settings_ThemeAndLayout_SidebarWidth_Description + ); + } + ImGui.Spacing(); ImGui.Separator(); ImGui.Spacing();