diff --git a/HellionChat/Ui/Components/InputBar.cs b/HellionChat/Ui/Components/InputBar.cs index 0601264..54cef39 100644 --- a/HellionChat/Ui/Components/InputBar.cs +++ b/HellionChat/Ui/Components/InputBar.cs @@ -110,8 +110,43 @@ internal sealed class InputBar dl.AddRectFilled(origin, max, pillAbgr, 6f); dl.AddText(origin + new Vector2(PillPaddingX, 3f), textAbgr, label); - // Reserve the layout slot so SameLine after the pill knows the width. - ImGui.Dummy(new Vector2(width, PillHeight)); + // Hit area over the rendered pill so a click opens the channel + // picker. InvisibleButton both reserves the layout slot and gives + // the popup a stable anchor item. + ImGui.InvisibleButton("##hellion-pill", new Vector2(width, PillHeight)); + if (ImGui.IsItemClicked() && tab is not null) + ImGui.OpenPopup("##hellion-channel-picker"); + + DrawChannelPickerPopup(tab); + } + + private static void DrawChannelPickerPopup(Tab? tab) + { + if (!ImGui.BeginPopup("##hellion-channel-picker")) + return; + + try + { + if (tab is null || tab.SelectedChannels.Count == 0) + { + ImGui.TextDisabled("No channels"); + return; + } + + foreach (var chatType in tab.SelectedChannels.Keys) + { + if (chatType.ToInputChannel() is not { } input) + continue; + + var isCurrent = tab.CurrentChannel.Channel == input; + if (ImGui.Selectable(input.ToChatType().Name(), isCurrent)) + tab.CurrentChannel.SetChannel(input); + } + } + finally + { + ImGui.EndPopup(); + } } private void DrawInputField(Tab? activeTab) diff --git a/HellionChat/Ui/Components/Sidebar.cs b/HellionChat/Ui/Components/Sidebar.cs index 3b3bda0..1efed53 100644 --- a/HellionChat/Ui/Components/Sidebar.cs +++ b/HellionChat/Ui/Components/Sidebar.cs @@ -117,7 +117,10 @@ internal sealed class Sidebar ImGui.InvisibleButton("row", new Vector2(tabHitWidth, RowHeight)); var rowHovered = ImGui.IsItemHovered(); if (ImGui.IsItemClicked()) + { activeTab = tab; + EnsureCurrentChannel(tab); + } dl.DrawHoverSheen( origin, @@ -209,11 +212,36 @@ internal sealed class Sidebar ChatType.NoviceNetwork or ChatType.NoviceNetworkSystem => FontAwesomeIcon.Users, ChatType.PvpTeam or ChatType.PvpTeamAnnouncement or ChatType.PvpTeamLoginLogout => FontAwesomeIcon.Users, - ChatType.System or ChatType.Echo => FontAwesomeIcon.Cog, + ChatType.System + or ChatType.BattleSystem + or ChatType.GatheringSystem + or ChatType.Error + or ChatType.Notice + or ChatType.LootNotice + or ChatType.Echo => FontAwesomeIcon.Cog, ChatType.CustomEmote or ChatType.StandardEmote => FontAwesomeIcon.Comments, _ => FontAwesomeIcon.Comment, }; + // Pick a sensible input channel for the tab if it has none yet — + // walking SelectedChannels for the first key with a ToInputChannel + // mapping lets the channel pill render the tab's actual channel + // instead of falling back to "—" on first activation. + private static void EnsureCurrentChannel(Tab tab) + { + if (tab.CurrentChannel.Channel != InputChannel.Invalid) + return; + + foreach (var chatType in tab.SelectedChannels.Keys) + { + if (chatType.ToInputChannel() is { } input) + { + tab.CurrentChannel.SetChannel(input); + return; + } + } + } + private void LogPopOutStub(Tab tab) { // The channel-popout pool is built in a later cycle; logging here diff --git a/HellionChat/Ui/Windows/MainWindow.cs b/HellionChat/Ui/Windows/MainWindow.cs index 0d16e9a..e38c87f 100644 --- a/HellionChat/Ui/Windows/MainWindow.cs +++ b/HellionChat/Ui/Windows/MainWindow.cs @@ -51,6 +51,9 @@ internal sealed class MainWindow : Window MinimumSize = new Vector2(MinWidth, MinHeight), MaximumSize = new Vector2(float.MaxValue, float.MaxValue), }; + // The message list owns its own scroll inside the body child; + // the outer window must not show a second scrollbar. + Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; IsOpen = Plugin.Config.MainWindowOpen; RespectCloseHotkey = false; }