fix(chat): draw the jump-to-latest pill on top of the messages
The pill was drawn on the parent window's draw list after EndChild, but ImGui renders a child window ON TOP of its parent — so the message text covered it. Draw it instead on the thread child's own draw list, after the message loop (later draw commands render on top), with a PushClipRect so the child's content padding / scrollbar doesn't clip it. Clickability is unchanged (hand-drawn + IsMouseHoveringRect / IsMouseClicked test the cursor directly), and it stays pinned to the visible bottom-right corner via absolute screen coordinates. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1398,35 +1398,38 @@ void RenderChatTab(App* app)
|
||||
atBottom = ImGui::GetScrollMaxY() <= 0.0f || ImGui::GetScrollY() >= ImGui::GetScrollMaxY() - 4.0f;
|
||||
// Re-arm auto-scroll once the user returns to the bottom (after the wheel cooldown).
|
||||
if (atBottom && s_chat_scroll_cooldown <= 0.0f) s_chat_auto_scroll = true;
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar(2); // ##ChatMessages WindowPadding + zeroed vertical ItemSpacing
|
||||
// Jump-to-latest pill when scrolled up (Q9). Hand-drawn (rect + IsMouseHoveringRect) rather than
|
||||
// ImGui::Button: the pill overlaps the ##ChatMessages child, which owns mouse-hover in that
|
||||
// region, so a real widget on the parent window never registers the click. IsMouseHoveringRect /
|
||||
// IsMouseClicked test the cursor position directly, independent of window hover ownership.
|
||||
if (!atBottom) {
|
||||
ImDrawList* pdl = ImGui::GetWindowDrawList();
|
||||
const ImVec2 pmin = jumpPillMin, pmax = jumpPillMax;
|
||||
const float pw = pmax.x - pmin.x, ph = pmax.y - pmin.y;
|
||||
const bool hov = ImGui::IsMouseHoveringRect(pmin, pmax);
|
||||
pdl->AddRectFilled(pmin, pmax,
|
||||
hov ? material::Primary() : material::WithAlpha(material::Primary(), 220),
|
||||
ph * 0.5f);
|
||||
ImFont* lf = ImGui::GetFont(); const float lsz = ImGui::GetFontSize();
|
||||
const char* lbl = TR("chat_jump_latest");
|
||||
const ImVec2 tszp = lf->CalcTextSizeA(lsz, FLT_MAX, 0.0f, lbl);
|
||||
pdl->AddText(lf, lsz, ImVec2(pmin.x + (pw - tszp.x) * 0.5f, pmin.y + (ph - tszp.y) * 0.5f),
|
||||
IM_COL32(255, 255, 255, 235), lbl);
|
||||
if (hov) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
s_scroll_to_cid = sel->cid;
|
||||
s_chat_auto_scroll = true; // clicking Latest re-arms follow-the-newest
|
||||
s_chat_scroll_cooldown = 0.0f;
|
||||
|
||||
// Jump-to-latest pill when scrolled up (Q9). Drawn LAST and INSIDE the thread child (on the
|
||||
// child's own draw list) so it sits on top of the messages — a parent-window draw after
|
||||
// EndChild renders UNDER the child and gets covered by the text. PushClipRect keeps the
|
||||
// child's content padding / scrollbar from clipping it. Hand-drawn + IsMouseHoveringRect so
|
||||
// the click lands despite the child owning hover here (a real widget would still miss it).
|
||||
if (!atBottom) {
|
||||
const ImVec2 pmin = jumpPillMin, pmax = jumpPillMax;
|
||||
const float pw = pmax.x - pmin.x, ph = pmax.y - pmin.y;
|
||||
const bool hov = ImGui::IsMouseHoveringRect(pmin, pmax);
|
||||
dl->PushClipRect(pmin, pmax, false);
|
||||
dl->AddRectFilled(pmin, pmax,
|
||||
hov ? material::Primary() : material::WithAlpha(material::Primary(), 220),
|
||||
ph * 0.5f);
|
||||
ImFont* lf = ImGui::GetFont(); const float lsz = ImGui::GetFontSize();
|
||||
const char* lbl = TR("chat_jump_latest");
|
||||
const ImVec2 tszp = lf->CalcTextSizeA(lsz, FLT_MAX, 0.0f, lbl);
|
||||
dl->AddText(lf, lsz, ImVec2(pmin.x + (pw - tszp.x) * 0.5f, pmin.y + (ph - tszp.y) * 0.5f),
|
||||
IM_COL32(255, 255, 255, 235), lbl);
|
||||
dl->PopClipRect();
|
||||
if (hov) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
s_scroll_to_cid = sel->cid;
|
||||
s_chat_auto_scroll = true; // clicking Latest re-arms follow-the-newest
|
||||
s_chat_scroll_cooldown = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleVar(2); // ##ChatMessages WindowPadding + zeroed vertical ItemSpacing
|
||||
// Composer is rendered OUTSIDE this box, directly below it (see after EndChild).
|
||||
} else {
|
||||
if (convs.empty()) centeredEmptyState(ICON_MD_FORUM, TR("chat_empty_title"), TR("chat_empty_start"));
|
||||
|
||||
Reference in New Issue
Block a user