fix(ui): wire chat send and fix sidebar icons, channel pill, scrollbar
Five smoke bugs from the first in-game test: 1. Sidebar showed fa-comment for every tab because the resolve path only honoured tab.Icon. Channel-type fallback restored — auto-tell tabs render the envelope, the rest map their first SelectedChannels key onto FontAwesome (Linkshells → link, FC → users, Party → user-friends, System/Echo → cog, emotes → comments). 2. InputBar's channel pill read from tab.Channel (the saved default), which is null on most non-FC tabs and rendered as "—". The pill now reads tab.CurrentChannel.Channel first so the runtime input state surfaces on every tab, with the saved default as a second fallback. 3. MessageList was making its own ImRaii.Child inside the main-area child MainWindow already owns. That nested scroll created the second scrollbar on the outer window. The component now lays out directly into the parent's scroll region. 4. The input field reserved 90px for the three FontAwesome buttons, which clipped them on standard frame padding. Reserve raised to 130px so the trailing buttons fully render. 5. Pressing Enter dropped the buffer — there was no send wiring. The field now uses ImGuiInputTextFlags.EnterReturnsTrue and routes the pending message through GameFunctions.ChatBox.SendMessage. Lines that don't start with a slash get the active channel's prefix prepended so typing in /fc lands on the FC channel instead of the current game-side default. InputBar gains an ILogger<InputBar> for the send-failure path; the DI registration in PluginHostFactory is updated to match.
This commit is contained in:
@@ -3,28 +3,33 @@ using Dalamud.Bindings.ImGui;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using HellionChat.Code;
|
||||
using HellionChat.GameFunctions;
|
||||
using HellionChat.Themes;
|
||||
using HellionChat.Ui.StyleEngine;
|
||||
using HellionChat.Util;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace HellionChat.Ui.Components;
|
||||
|
||||
// Bottom input row: channel pill, text field, quick buttons. Channel pill
|
||||
// recolours by tab type — cyan accent for a normal channel, ember accent
|
||||
// for a tell. Send wiring lands when the main window assembles the
|
||||
// components; for now this layer only handles buffer state and the symbol
|
||||
// picker overlay.
|
||||
// for a tell. Enter on the input field sends through ChatBox; messages
|
||||
// that don't already start with a slash get the active channel's prefix
|
||||
// prepended so a typed line in /fc reaches free-company chat instead of
|
||||
// the current game-side channel.
|
||||
internal sealed class InputBar
|
||||
{
|
||||
public const float Height = 32f;
|
||||
private const float PillHeight = 22f;
|
||||
private const float PillPaddingX = 8f;
|
||||
private const int BufferCapacity = 500;
|
||||
private const float QuickButtonsReserve = 130f;
|
||||
|
||||
private readonly SymbolPicker _symbolPicker;
|
||||
private readonly FontManager _fonts;
|
||||
private readonly ThemeRegistry _themes;
|
||||
private readonly TokenResolver _resolver;
|
||||
private readonly ILogger<InputBar> _logger;
|
||||
|
||||
private string _pendingMessage = string.Empty;
|
||||
|
||||
@@ -32,13 +37,15 @@ internal sealed class InputBar
|
||||
SymbolPicker symbolPicker,
|
||||
FontManager fonts,
|
||||
ThemeRegistry themes,
|
||||
TokenResolver resolver
|
||||
TokenResolver resolver,
|
||||
ILogger<InputBar> logger
|
||||
)
|
||||
{
|
||||
_symbolPicker = symbolPicker;
|
||||
_fonts = fonts;
|
||||
_themes = themes;
|
||||
_resolver = resolver;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public string PendingMessage => _pendingMessage;
|
||||
@@ -62,7 +69,7 @@ internal sealed class InputBar
|
||||
|
||||
DrawChannelPill(activeTab, isTell, pillAbgr, pillTextAbgr);
|
||||
ImGui.SameLine();
|
||||
DrawInputField();
|
||||
DrawInputField(activeTab);
|
||||
ImGui.SameLine();
|
||||
DrawQuickButtons();
|
||||
|
||||
@@ -77,8 +84,17 @@ internal sealed class InputBar
|
||||
{
|
||||
if (isTell && tab?.TellTarget is { } t && t.IsSet())
|
||||
return $"→ {t.Name}";
|
||||
if (tab?.Channel is { } ch)
|
||||
return ch.ToChatType().Name();
|
||||
|
||||
// CurrentChannel carries the runtime input state; Tab.Channel is the
|
||||
// saved default and is null for most non-FC tabs, which produced
|
||||
// the "—" placeholder users saw.
|
||||
var current = tab?.CurrentChannel?.Channel ?? InputChannel.Invalid;
|
||||
if (current != InputChannel.Invalid)
|
||||
return current.ToChatType().Name();
|
||||
|
||||
if (tab?.Channel is { } saved)
|
||||
return saved.ToChatType().Name();
|
||||
|
||||
return "—";
|
||||
}
|
||||
|
||||
@@ -98,10 +114,52 @@ internal sealed class InputBar
|
||||
ImGui.Dummy(new Vector2(width, PillHeight));
|
||||
}
|
||||
|
||||
private void DrawInputField()
|
||||
private void DrawInputField(Tab? activeTab)
|
||||
{
|
||||
ImGui.SetNextItemWidth(-90f);
|
||||
ImGui.InputText("##hellion-input", ref _pendingMessage, BufferCapacity);
|
||||
ImGui.SetNextItemWidth(-QuickButtonsReserve);
|
||||
if (
|
||||
ImGui.InputText(
|
||||
"##hellion-input",
|
||||
ref _pendingMessage,
|
||||
BufferCapacity,
|
||||
ImGuiInputTextFlags.EnterReturnsTrue
|
||||
)
|
||||
)
|
||||
{
|
||||
TrySend(activeTab);
|
||||
}
|
||||
}
|
||||
|
||||
private void TrySend(Tab? activeTab)
|
||||
{
|
||||
var text = _pendingMessage.Trim();
|
||||
if (string.IsNullOrEmpty(text))
|
||||
return;
|
||||
|
||||
// Slash commands route through verbatim — the game's chat parser
|
||||
// handles /tell, /fc, /hellion etc. on its own. Other text gets
|
||||
// the active channel's prefix so the line lands on the channel
|
||||
// the user is reading instead of the game-side default.
|
||||
string toSend;
|
||||
if (text.StartsWith('/'))
|
||||
{
|
||||
toSend = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
var current = activeTab?.CurrentChannel?.Channel ?? InputChannel.Invalid;
|
||||
toSend = current == InputChannel.Invalid ? text : $"{current.Prefix()} {text}";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
ChatBox.SendMessage(toSend);
|
||||
_pendingMessage = string.Empty;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "Failed to send chat message ({Length} chars)", toSend.Length);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawQuickButtons()
|
||||
|
||||
Reference in New Issue
Block a user