fix(ui): wrap the DAEMON BINARY status line so it can't clip

The Settings -> NODE & SECURITY daemon-binary status was one long inline
row of SameLine() Text calls that overran the content width and clipped
its colored tail at narrow windows / higher font scale. Rebuild it as
color-tagged atoms laid out with manual wrapping (dropping a separator
that would dangle at a line break), so the full status always shows.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-07 22:16:30 -05:00
parent 6c19fac6f5
commit 48c79567d7

View File

@@ -2128,49 +2128,68 @@ void RenderSettingsPage(App* app) {
return std::string(buf);
};
const ImVec4 dbDim = ImGui::ColorConvertU32ToFloat4(OnSurfaceMedium());
ImGui::Dummy(ImVec2(0, Layout::spacingLg()));
Type().textColored(TypeStyle::Overline, OnSurfaceMedium(), TR("daemon_binary"));
ImGui::Dummy(ImVec2(0, Layout::spacingXs()));
// Inline single line: Installed <v> (<size> · <date>) · Bundled <v> (<size>) · <status>
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted(TR("daemon_installed"));
ImGui::SameLine(0, Layout::spacingXs());
// Status line: Installed <v> (<size> · <date>) · Bundled <v> (<size>) · <status>.
// Built as color-tagged atoms and laid out with manual wrapping — as one long inline
// row of SameLine() Text calls it overran the content width and clipped its colored
// tail at narrow windows / higher font scale (the status was effectively hidden).
struct DbAtom { std::string text; ImU32 col; bool sep; };
std::vector<DbAtom> dbAtoms;
const ImU32 dbNorm = ImGui::GetColorU32(ImGuiCol_Text);
const ImU32 dbDimU = OnSurfaceMedium();
dbAtoms.push_back({ TR("daemon_installed"), dbNorm, false });
if (inst.exists) {
ImGui::TextUnformatted(inst.version.empty() ? TR("unknown") : inst.version.c_str());
ImGui::SameLine(0, Layout::spacingXs());
ImGui::TextColored(dbDim, "(%s · %s)",
util::Platform::formatFileSize(inst.size).c_str(),
fmtDate(inst.modifiedEpoch).c_str());
dbAtoms.push_back({ inst.version.empty() ? std::string(TR("unknown")) : inst.version, dbNorm, false });
char dbParen[96];
std::snprintf(dbParen, sizeof(dbParen), "(%s · %s)",
util::Platform::formatFileSize(inst.size).c_str(),
fmtDate(inst.modifiedEpoch).c_str());
dbAtoms.push_back({ dbParen, dbDimU, false });
} else {
ImGui::TextColored(dbDim, "%s", TR("daemon_not_installed"));
dbAtoms.push_back({ TR("daemon_not_installed"), dbDimU, false });
}
ImGui::SameLine(0, Layout::spacingXs());
ImGui::TextColored(dbDim, "·");
ImGui::SameLine(0, Layout::spacingXs());
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted(TR("daemon_bundled"));
ImGui::SameLine(0, Layout::spacingXs());
dbAtoms.push_back({ "·", dbDimU, true });
dbAtoms.push_back({ TR("daemon_bundled"), dbNorm, false });
if (bun.available) {
ImGui::TextUnformatted(bun.version.empty() ? TR("unknown") : bun.version.c_str());
ImGui::SameLine(0, Layout::spacingXs());
ImGui::TextColored(dbDim, "(%s)", util::Platform::formatFileSize(bun.size).c_str());
dbAtoms.push_back({ bun.version.empty() ? std::string(TR("unknown")) : bun.version, dbNorm, false });
dbAtoms.push_back({ "(" + util::Platform::formatFileSize(bun.size) + ")", dbDimU, false });
} else {
ImGui::TextColored(dbDim, "%s", TR("daemon_none_bundled"));
dbAtoms.push_back({ TR("daemon_none_bundled"), dbDimU, false });
}
if (bun.available) {
const bool sameSize = inst.exists && inst.size == bun.size;
ImGui::SameLine(0, Layout::spacingXs());
ImGui::TextColored(dbDim, "·");
ImGui::SameLine(0, Layout::spacingXs());
dbAtoms.push_back({ "·", dbDimU, true });
if (!inst.exists)
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "%s", TR("daemon_status_missing"));
dbAtoms.push_back({ TR("daemon_status_missing"), ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 0.8f, 0.2f, 1.0f)), false });
else if (sameSize)
ImGui::TextColored(ImVec4(0.3f, 0.8f, 0.3f, 1.0f), "%s", TR("daemon_status_match"));
dbAtoms.push_back({ TR("daemon_status_match"), ImGui::ColorConvertFloat4ToU32(ImVec4(0.3f, 0.8f, 0.3f, 1.0f)), false });
else
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.2f, 1.0f), "%s", TR("daemon_status_differ"));
dbAtoms.push_back({ TR("daemon_status_differ"), ImGui::ColorConvertFloat4ToU32(ImVec4(1.0f, 0.8f, 0.2f, 1.0f)), false });
}
// Lay the atoms out left-to-right, wrapping to a new line when the next one would
// exceed the content width. A "·" separator is dropped when it (plus the atom after
// it) doesn't fit, so a wrapped line never starts or ends with a dangling separator.
const float dbAvail = ImGui::GetContentRegionAvail().x;
const float dbGap = Layout::spacingXs();
float dbX = 0.0f;
ImGui::AlignTextToFramePadding();
for (std::size_t i = 0; i < dbAtoms.size(); ++i) {
const float w = ImGui::CalcTextSize(dbAtoms[i].text.c_str()).x;
if (dbAtoms[i].sep) {
const float nextW = (i + 1 < dbAtoms.size())
? ImGui::CalcTextSize(dbAtoms[i + 1].text.c_str()).x : 0.0f;
if (dbX > 0.0f && dbX + dbGap + w + dbGap + nextW > dbAvail) continue;
}
const bool wrap = (dbX > 0.0f) && (dbX + dbGap + w > dbAvail);
if (dbX > 0.0f && !wrap) { ImGui::SameLine(0, dbGap); dbX += dbGap; }
else if (wrap) { dbX = 0.0f; }
ImGui::TextColored(ImGui::ColorConvertU32ToFloat4(dbAtoms[i].col), "%s", dbAtoms[i].text.c_str());
dbX += w;
}
// In-app node update: download + verify the latest dragonxd from the project Gitea.