diff --git a/src/ui/windows/console_tab.cpp b/src/ui/windows/console_tab.cpp index 5ba09c2..919be6e 100644 --- a/src/ui/windows/console_tab.cpp +++ b/src/ui/windows/console_tab.cpp @@ -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); diff --git a/src/util/i18n.cpp b/src/util/i18n.cpp index 629311d..834d39c 100644 --- a/src/util/i18n.cpp +++ b/src/util/i18n.cpp @@ -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";