fix(ui): isolate scroll-button state from pop-outs and tidy toolbar

Guard _childScrolledUp writes behind updateScrollState param so pop-out
windows no longer contaminate the main window's scroll state. Widen the
honorific title slot budget when the scroll button is visible, fix stale
comment, and apply csharpier formatting.
This commit is contained in:
2026-05-21 14:43:26 +02:00
parent b5aebaad35
commit 636a62814f
2 changed files with 33 additions and 11 deletions
+30 -8
View File
@@ -781,7 +781,7 @@ public sealed class ChatLogWindow : Window
private bool _scrollToBottomRequested;
// UI-5: cached each frame inside the ##chat2-messages child. True when the
// user has scrolled up enough that the overlay button should be shown.
// user has scrolled up enough that the toolbar button should be shown.
private bool _childScrolledUp;
public override void Draw()
@@ -1544,7 +1544,13 @@ public sealed class ChatLogWindow : Window
CurrentHideState = HideState.User;
}
internal void DrawMessageLog(Tab tab, PayloadHandler handler, float childHeight, bool switchedTab)
internal void DrawMessageLog(
Tab tab,
PayloadHandler handler,
float childHeight,
bool switchedTab,
bool updateScrollState = true
)
{
using (var child = ImRaii.Child("##chat2-messages", new Vector2(-1, childHeight)))
{
@@ -1557,11 +1563,14 @@ public sealed class ChatLogWindow : Window
// Cached for the header toolbar's scroll-to-bottom button, which is
// drawn one frame later. GetScrollMaxY / GetScrollY here refer to
// the child's scroll context.
// the child's scroll context. Pop-out windows pass updateScrollState:
// false so they do not overwrite the main window's cached state.
if (updateScrollState)
_childScrolledUp = ImGui.GetScrollMaxY() - ImGui.GetScrollY() > 1f;
}
else
{
if (updateScrollState)
_childScrolledUp = false;
}
}
@@ -1603,15 +1612,17 @@ public sealed class ChatLogWindow : Window
// Custom styles can have cellPadding that go above 4, which GetScrollY isn't respecting
var cellPaddingOffset =
!compact && oldCellPadding.Y > 4f ? oldCellPadding.Y - 4f : 0f;
if (switchedTab || _scrollToBottomRequested
|| ImGui.GetScrollY() + cellPaddingOffset >= ImGui.GetScrollMaxY())
if (
switchedTab
|| _scrollToBottomRequested
|| ImGui.GetScrollY() + cellPaddingOffset >= ImGui.GetScrollMaxY()
)
ImGui.SetScrollHereY(1f);
_scrollToBottomRequested = false;
handler.Draw();
}
}
}
private void DrawMessages(
@@ -2349,7 +2360,12 @@ public sealed class ChatLogWindow : Window
var spacing = ImGui.GetStyle().ItemSpacing.X;
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + avail - 2 * iconWidth - spacing);
if (ImGuiUtil.IconButton(FontAwesomeIcon.ArrowDown, tooltip: HellionStrings.ChatLog_ScrollToBottom_Tooltip))
if (
ImGuiUtil.IconButton(
FontAwesomeIcon.ArrowDown,
tooltip: HellionStrings.ChatLog_ScrollToBottom_Tooltip
)
)
_scrollToBottomRequested = true;
// Keep the pop-out button on the same toolbar row. Without this the
@@ -2408,7 +2424,13 @@ public sealed class ChatLogWindow : Window
crownWidth = ImGui.CalcTextSize(FontAwesomeIcon.Crown.ToIconString()).X;
}
var maxTitleWidth = avail - iconWidth - gapBeforeButton - crownWidth - gapAfterCrown;
// When the scroll button is also present it occupies iconWidth + ItemSpacing.X
// to the left of the pop-out button, so shrink the title budget accordingly.
var scrollButtonReserve = _childScrolledUp
? iconWidth + ImGui.GetStyle().ItemSpacing.X
: 0f;
var maxTitleWidth =
avail - iconWidth - scrollButtonReserve - gapBeforeButton - crownWidth - gapAfterCrown;
if (maxTitleWidth <= 0)
{
return;
+1 -1
View File
@@ -118,7 +118,7 @@ internal class Popout : Window
var handler = ChatLogWindow.HandlerLender.Borrow();
var logHeight = ImGui.GetContentRegionAvail().Y - inputBarHeight - hintBannerHeight;
ChatLogWindow.DrawMessageLog(Tab, handler, logHeight, false);
ChatLogWindow.DrawMessageLog(Tab, handler, logHeight, false, updateScrollState: false);
if (inputEnabled && InputBar != null)
{