fix(ui): draw scroll-to-bottom button in a standalone overlay window
Button drawn in the parent window over the ##chat2-messages child was never clickable: ImGui resolves g.HoveredWindow to the child for that screen rect, so ItemHoverable rejects any item submitted in the parent. A top-level Begin/End window is a sibling in the window list and wins the hit-test for its own rect. ownerId parameter keeps the window name distinct between the main window and each pop-out, preventing Begin/End collisions when both render in the same frame.
This commit is contained in:
@@ -1548,7 +1548,8 @@ public sealed class ChatLogWindow : Window
|
|||||||
Tab tab,
|
Tab tab,
|
||||||
PayloadHandler handler,
|
PayloadHandler handler,
|
||||||
float childHeight,
|
float childHeight,
|
||||||
bool switchedTab
|
bool switchedTab,
|
||||||
|
string ownerId = "main"
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Capture these before entering the child so we can position the overlay
|
// Capture these before entering the child so we can position the overlay
|
||||||
@@ -1581,7 +1582,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
// (which caused it to drift) and avoids the scrollbar's inner clip rect
|
// (which caused it to drift) and avoids the scrollbar's inner clip rect
|
||||||
// (which caused it to be cut off on the right edge).
|
// (which caused it to be cut off on the right edge).
|
||||||
if (_childScrolledUp)
|
if (_childScrolledUp)
|
||||||
DrawScrollToBottomButtonOverlay(childScreenPos, childWidth, childHeight);
|
DrawScrollToBottomButtonOverlay(childScreenPos, childWidth, childHeight, ownerId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawLogNormalStyle(Tab tab, PayloadHandler handler, bool switchedTab)
|
private void DrawLogNormalStyle(Tab tab, PayloadHandler handler, bool switchedTab)
|
||||||
@@ -1631,35 +1632,61 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI-5: floating jump-to-latest button, drawn in the PARENT window after the
|
// UI-5: floating jump-to-latest button.
|
||||||
// ##chat2-messages child closes. Placing it here prevents two bugs:
|
//
|
||||||
// 1. Inside the child, SetCursorPos adds to CursorMaxPos.y and inflates
|
// Why a standalone overlay window rather than drawing in the parent?
|
||||||
// ContentSize.y / ScrollMaxY every frame, so the button chased its own
|
// When this button was drawn in the parent window after the ##chat2-messages
|
||||||
// shadow and never landed at a stable position.
|
// child closed, ImGui's hit-test still resolved g.HoveredWindow to the child
|
||||||
// 2. GetWindowWidth() inside the child includes the scrollbar column, so the
|
// (the child occupies the same screen rect). ItemHoverable then rejected the
|
||||||
// button overlapped the scrollbar and was clipped by the inner clip rect.
|
// button submitted in the parent, so it was visible but never clickable.
|
||||||
// Screen-space positioning via SetCursorScreenPos is immune to both.
|
//
|
||||||
|
// A top-level Begin/End window is a sibling in the window list, not nested
|
||||||
|
// under the child, so it wins the hit-test for its own rect and the button
|
||||||
|
// inside it is fully clickable.
|
||||||
|
//
|
||||||
|
// The ownerId parameter makes the window name unique per calling context so
|
||||||
|
// the main window and each pop-out don't share a single ImGui window entry.
|
||||||
private void DrawScrollToBottomButtonOverlay(
|
private void DrawScrollToBottomButtonOverlay(
|
||||||
Vector2 childScreenPos,
|
Vector2 childScreenPos,
|
||||||
float childWidth,
|
float childWidth,
|
||||||
float childHeight)
|
float childHeight,
|
||||||
|
string ownerId)
|
||||||
{
|
{
|
||||||
var size = ImGui.GetFrameHeight();
|
var size = ImGui.GetFrameHeight();
|
||||||
var pad = 8f * ImGuiHelpers.GlobalScale;
|
var pad = 8f * ImGuiHelpers.GlobalScale;
|
||||||
var scrollbarWidth = ImGui.GetStyle().ScrollbarSize;
|
var scrollbarWidth = ImGui.GetStyle().ScrollbarSize;
|
||||||
|
|
||||||
|
// Position confirmed correct in-game: bottom-right of the chat child,
|
||||||
|
// inset by pad, and pulled left of the vertical scrollbar.
|
||||||
var btnPos = new Vector2(
|
var btnPos = new Vector2(
|
||||||
childScreenPos.X + childWidth - scrollbarWidth - size - pad,
|
childScreenPos.X + childWidth - scrollbarWidth - size - pad,
|
||||||
childScreenPos.Y + childHeight - size - pad);
|
childScreenPos.Y + childHeight - size - pad);
|
||||||
|
|
||||||
ImGui.SetCursorScreenPos(btnPos);
|
ImGui.SetNextWindowPos(btnPos, ImGuiCond.Always);
|
||||||
|
ImGui.SetNextWindowSize(new Vector2(size, size), ImGuiCond.Always);
|
||||||
|
|
||||||
|
const ImGuiWindowFlags overlayFlags =
|
||||||
|
ImGuiWindowFlags.NoTitleBar
|
||||||
|
| ImGuiWindowFlags.NoResize
|
||||||
|
| ImGuiWindowFlags.NoMove
|
||||||
|
| ImGuiWindowFlags.NoScrollbar
|
||||||
|
| ImGuiWindowFlags.NoScrollWithMouse
|
||||||
|
| ImGuiWindowFlags.NoSavedSettings
|
||||||
|
| ImGuiWindowFlags.NoFocusOnAppearing
|
||||||
|
| ImGuiWindowFlags.NoBackground;
|
||||||
|
|
||||||
|
// End() must be called unconditionally after Begin() — ImGui rule.
|
||||||
|
if (ImGui.Begin($"##scroll-to-bottom-overlay-{ownerId}", overlayFlags))
|
||||||
|
{
|
||||||
if (ImGuiUtil.IconButton(
|
if (ImGuiUtil.IconButton(
|
||||||
FontAwesomeIcon.ArrowDown,
|
FontAwesomeIcon.ArrowDown,
|
||||||
tooltip: HellionStrings.ChatLog_ScrollToBottom_Tooltip))
|
tooltip: HellionStrings.ChatLog_ScrollToBottom_Tooltip))
|
||||||
_scrollToBottomRequested = true;
|
_scrollToBottomRequested = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.End();
|
||||||
|
}
|
||||||
|
|
||||||
private void DrawMessages(
|
private void DrawMessages(
|
||||||
Tab tab,
|
Tab tab,
|
||||||
PayloadHandler handler,
|
PayloadHandler handler,
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ internal class Popout : Window
|
|||||||
|
|
||||||
var handler = ChatLogWindow.HandlerLender.Borrow();
|
var handler = ChatLogWindow.HandlerLender.Borrow();
|
||||||
var logHeight = ImGui.GetContentRegionAvail().Y - inputBarHeight - hintBannerHeight;
|
var logHeight = ImGui.GetContentRegionAvail().Y - inputBarHeight - hintBannerHeight;
|
||||||
ChatLogWindow.DrawMessageLog(Tab, handler, logHeight, false);
|
ChatLogWindow.DrawMessageLog(Tab, handler, logHeight, false, Tab.Identifier.ToString());
|
||||||
|
|
||||||
if (inputEnabled && InputBar != null)
|
if (inputEnabled && InputBar != null)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user