feat(console): jump-to-bottom "N new" pill when scrolled up
Surface new_lines_since_scroll_ (already tracked) as a floating pill at the output panel's bottom-right whenever the user is scrolled up with unseen output; clicking it re-enables auto-scroll and snaps to the bottom. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -304,9 +304,47 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Jump-to-bottom pill — shown at the panel's bottom-right when scrolled up with
|
||||
// unseen output. Restores the layout cursor after its hit area so the input row
|
||||
// still flows below the panel.
|
||||
if (!auto_scroll_ && new_lines_since_scroll_ > 0) {
|
||||
ImVec2 savedCursor = ImGui::GetCursorScreenPos();
|
||||
std::string pill = std::to_string(new_lines_since_scroll_) + " " + TR("console_new_lines");
|
||||
ImFont* pillFont = Type().caption();
|
||||
ImFont* icoF = Type().iconSmall();
|
||||
const char* ico = ICON_MD_ARROW_DOWNWARD;
|
||||
float padX = 10.0f * Layout::hScale();
|
||||
float padY = 5.0f * Layout::hScale();
|
||||
ImVec2 tsz = pillFont->CalcTextSizeA(pillFont->LegacySize, FLT_MAX, 0, pill.c_str());
|
||||
ImVec2 isz = icoF->CalcTextSizeA(icoF->LegacySize, FLT_MAX, 0, ico);
|
||||
float gap = 4.0f * Layout::hScale();
|
||||
float pillW = isz.x + gap + tsz.x + padX * 2.0f;
|
||||
float pillH = std::max(tsz.y, isz.y) + padY * 2.0f;
|
||||
ImVec2 pMax(outPanelMax.x - 12.0f, outPanelMax.y - 12.0f);
|
||||
ImVec2 pMin(pMax.x - pillW, pMax.y - pillH);
|
||||
|
||||
ImGui::SetCursorScreenPos(pMin);
|
||||
ImGui::InvisibleButton("##ConsoleJumpBottom", ImVec2(pillW, pillH));
|
||||
bool hov = ImGui::IsItemHovered();
|
||||
bool clk = ImGui::IsItemClicked();
|
||||
dlOut->AddRectFilled(pMin, pMax, WithAlpha(Primary(), hov ? 240 : 205), pillH * 0.5f);
|
||||
ImU32 fg = IM_COL32(255, 255, 255, 235);
|
||||
dlOut->AddText(icoF, icoF->LegacySize,
|
||||
ImVec2(pMin.x + padX, pMin.y + (pillH - isz.y) * 0.5f), fg, ico);
|
||||
dlOut->AddText(pillFont, pillFont->LegacySize,
|
||||
ImVec2(pMin.x + padX + isz.x + gap, pMin.y + (pillH - tsz.y) * 0.5f), fg, pill.c_str());
|
||||
if (hov) ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (clk) {
|
||||
auto_scroll_ = true;
|
||||
scroll_to_bottom_ = true;
|
||||
new_lines_since_scroll_ = 0;
|
||||
}
|
||||
ImGui::SetCursorScreenPos(savedCursor);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(0, Layout::spacingSm()));
|
||||
|
||||
|
||||
// Input area
|
||||
renderInput(exec);
|
||||
|
||||
|
||||
@@ -982,6 +982,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["console_help_setgenerate"] = " setgenerate - Control mining";
|
||||
strings_["console_help_stop"] = " stop - Stop the daemon";
|
||||
strings_["console_line_count"] = "%zu lines";
|
||||
strings_["console_new_lines"] = "new";
|
||||
strings_["console_new_lines"] = "%d new lines";
|
||||
strings_["console_no_daemon"] = "No daemon";
|
||||
strings_["console_not_connected"] = "Error: Not connected to daemon";
|
||||
|
||||
Reference in New Issue
Block a user