refactor(ui): extract shared ProgressBar / CopyableTextOverlay / DrawPill helpers
UI-standardization audit: three draw patterns were copy-pasted across tabs and dialogs. Promote each to a material:: helper and adopt at every verbatim site. Output is pixel-identical (same colors/geometry threaded through as params). - material::DrawProgressBar / ProgressBar — replaces 3 byte-identical rounded fill bars in the daemon/xmrig/bootstrap download dialogs. - material::CopyableTextOverlay — the click-to-copy affordance (hit button + hand cursor + tooltip + hover underline + clipboard) shared by the peers best-block hash and the 3 mining stats (difficulty/block/address). Returns "copied this frame" so callers keep their own toast (no ui-layer dependency). - material::DrawPill / PillSize — rounded bg + optional border + inset text badge, shared by the explorer status pill, the market Z/T chip, and the network official/custom tag. Divergent one-offs left in place (transactions status pills use schema rounding around pre-positioned multi-line text; the mining filter-pill is a button bg). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -279,6 +279,81 @@ inline ImFont* resolveButtonFont(int perButton, int sectionDefault)
|
||||
return resolveButtonFont(perButton >= 0 ? perButton : sectionDefault);
|
||||
}
|
||||
|
||||
// ── Progress / fill bar ─────────────────────────────────────────────────
|
||||
// A rounded track with a fraction (0..1) fill, drawn at the current cursor and advancing the layout
|
||||
// cursor past it (matches the download-dialog usage). For a placement you control, use the pMin/pMax
|
||||
// overload. Defaults: theme Primary fill, a subtle white track, 4dp corners.
|
||||
inline void DrawProgressBar(ImDrawList* dl, const ImVec2& pMin, const ImVec2& pMax, float frac01,
|
||||
ImU32 fill = 0, ImU32 track = IM_COL32(255, 255, 255, 30), float rounding = -1.0f)
|
||||
{
|
||||
if (fill == 0) fill = Primary();
|
||||
if (rounding < 0.0f) rounding = 4.0f * Layout::dpiScale();
|
||||
frac01 = frac01 < 0.0f ? 0.0f : (frac01 > 1.0f ? 1.0f : frac01);
|
||||
dl->AddRectFilled(pMin, pMax, track, rounding);
|
||||
if (frac01 > 0.0f)
|
||||
dl->AddRectFilled(pMin, ImVec2(pMin.x + (pMax.x - pMin.x) * frac01, pMax.y), fill, rounding);
|
||||
}
|
||||
|
||||
inline void ProgressBar(float width, float height, float frac01,
|
||||
ImU32 fill = 0, ImU32 track = IM_COL32(255, 255, 255, 30))
|
||||
{
|
||||
ImVec2 pMin = ImGui::GetCursorScreenPos();
|
||||
DrawProgressBar(ImGui::GetWindowDrawList(), pMin, ImVec2(pMin.x + width, pMin.y + height), frac01, fill, track);
|
||||
ImGui::Dummy(ImVec2(0, height));
|
||||
}
|
||||
|
||||
// ── Click-to-copy affordance ────────────────────────────────────────────
|
||||
// Turns an already-drawn text run into a click-to-copy control. The caller draws the visible text
|
||||
// (font/color/position of its choosing); this places an invisible hit button (textSize + hitPad) at
|
||||
// `pos`, shows a hand cursor + tooltip + a hover underline, and copies `copyValue` on click. Returns
|
||||
// true the frame it was clicked (already on the clipboard) so the caller can show its own toast.
|
||||
// Caller manages any cursor save/restore around the call.
|
||||
inline bool CopyableTextOverlay(const char* id, const ImVec2& pos, const ImVec2& textSize, float fontSize,
|
||||
const char* copyValue, const char* tooltip, const ImVec2& hitPad)
|
||||
{
|
||||
const float dp = Layout::dpiScale();
|
||||
ImGui::SetCursorScreenPos(pos);
|
||||
ImGui::InvisibleButton(id, ImVec2(textSize.x + hitPad.x, fontSize + hitPad.y));
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
if (tooltip && tooltip[0]) Tooltip("%s", tooltip);
|
||||
const float uy = pos.y + fontSize + 1.0f * dp;
|
||||
ImGui::GetWindowDrawList()->AddLine(ImVec2(pos.x, uy), ImVec2(pos.x + textSize.x, uy),
|
||||
WithAlpha(OnSurface(), 60), 1.0f * dp);
|
||||
}
|
||||
bool copied = false;
|
||||
if (ImGui::IsItemClicked()) {
|
||||
ImGui::SetClipboardText(copyValue);
|
||||
copied = true;
|
||||
}
|
||||
return copied;
|
||||
}
|
||||
|
||||
// ── Pill / badge ─────────────────────────────────────────────────────────
|
||||
// A rounded chip: a filled background sized to `text` + `pad`, an optional 1px border, and the text
|
||||
// inset by `pad`. Use PillSize first when you need to right/center-anchor (compute the width, place
|
||||
// the pill, then draw).
|
||||
inline ImVec2 PillSize(const char* text, ImFont* font, const ImVec2& pad)
|
||||
{
|
||||
ImVec2 t = font->CalcTextSizeA(font->LegacySize, FLT_MAX, 0.0f, text);
|
||||
return ImVec2(t.x + pad.x * 2.0f, font->LegacySize + pad.y * 2.0f);
|
||||
}
|
||||
|
||||
// Draw a pill/badge anchored at top-left `pos`. `border` == 0 draws no outline. rounding < 0 => fully
|
||||
// rounded (height/2). Returns the pill's total size.
|
||||
inline ImVec2 DrawPill(ImDrawList* dl, const ImVec2& pos, const char* text, ImFont* font,
|
||||
ImU32 fg, ImU32 bg, ImU32 border = 0,
|
||||
const ImVec2& pad = ImVec2(4.0f, 2.0f), float rounding = -1.0f)
|
||||
{
|
||||
ImVec2 sz = PillSize(text, font, pad);
|
||||
if (rounding < 0.0f) rounding = sz.y * 0.5f;
|
||||
ImVec2 pMax(pos.x + sz.x, pos.y + sz.y);
|
||||
dl->AddRectFilled(pos, pMax, bg, rounding);
|
||||
if (border != 0) dl->AddRect(pos, pMax, border, rounding, 0, 1.0f * Layout::dpiScale());
|
||||
dl->AddText(font, font->LegacySize, ImVec2(pos.x + pad.x, pos.y + pad.y), fg, text);
|
||||
return sz;
|
||||
}
|
||||
|
||||
// ── Tactile wrappers ────────────────────────────────────────────────────
|
||||
// Drop-in replacements for ImGui::Button / SmallButton that automatically
|
||||
// add the tactile highlight overlay after rendering.
|
||||
|
||||
Reference in New Issue
Block a user