fix: large-wallet sync starvation + shutdown/console-flash UX (Windows full node) #2
@@ -179,6 +179,17 @@ inline float kSidePanelWidthRatio() { return schema::UI().drawElement("panels",
|
||||
// [layout] content-max-width; default is generous so data-dense screens stay comfortable.
|
||||
inline float kContentMaxWidth() { return schema::UI().drawElement("layout", "content-max-width").sizeOr(1600.0f) * dpiScale(); }
|
||||
|
||||
// Shared compose-card envelope for the Send + Receive tabs (and any tab wanting the same box): fill the
|
||||
// available column up to the content-max-width cap, then center the leftover as margin. Both tabs MUST
|
||||
// derive their card width/offset from this so the two envelopes stay byte-for-byte identical — they
|
||||
// previously drifted (Send capped at 760dp, Receive at 860dp), so the Send card rendered narrower than
|
||||
// Receive on any window wider than ~860dp. Returns {width, offsetX} in the same units as availW.
|
||||
struct CardBox { float width; float offsetX; };
|
||||
inline CardBox mainComposeCardBox(float availW) {
|
||||
float w = std::min(availW, kContentMaxWidth());
|
||||
return CardBox{ w, std::max(0.0f, (availW - w) * 0.5f) };
|
||||
}
|
||||
|
||||
inline float kTableMinHeight() { return schema::UI().drawElement("panels", "table").getFloat("min-height", 150.0f) * dpiScale(); }
|
||||
inline float kTableHeightRatio() { return schema::UI().drawElement("panels", "table").getFloat("height-ratio", 0.45f); }
|
||||
|
||||
|
||||
@@ -544,11 +544,16 @@ inline bool TactileButton(const char* label, const ImVec2& size = ImVec2(0, 0),
|
||||
ImVec2 bMin = ImGui::GetItemRectMin();
|
||||
ImVec2 bMax = ImGui::GetItemRectMax();
|
||||
|
||||
// For icon fonts, manually draw centered icon after getting button rect
|
||||
// For icon fonts, manually draw centered icon after getting button rect. Measure/draw only the
|
||||
// VISIBLE label (up to the "##id" separator): CalcTextSizeA/AddText don't strip "##" the way
|
||||
// ImGui's own text render does, so an id suffix like "##pickContact" would inflate textSz and
|
||||
// shove the glyph left off-center (and try to draw the notdef id chars).
|
||||
if (isIconFont && size.x > 0 && size.y > 0) {
|
||||
ImVec2 textSz = useFont->CalcTextSizeA(useFont->LegacySize, FLT_MAX, 0, label);
|
||||
const char* labelEnd = label;
|
||||
while (*labelEnd && !(labelEnd[0] == '#' && labelEnd[1] == '#')) ++labelEnd;
|
||||
ImVec2 textSz = useFont->CalcTextSizeA(useFont->LegacySize, FLT_MAX, 0, label, labelEnd);
|
||||
ImVec2 textPos(bMin.x + (size.x - textSz.x) * 0.5f, bMin.y + (size.y - textSz.y) * 0.5f);
|
||||
dl->AddText(useFont, useFont->LegacySize, textPos, ImGui::GetColorU32(ImGuiCol_Text), label);
|
||||
dl->AddText(useFont, useFont->LegacySize, textPos, ImGui::GetColorU32(ImGuiCol_Text), label, labelEnd);
|
||||
}
|
||||
|
||||
float rounding = ImGui::GetStyle().FrameRounding;
|
||||
|
||||
@@ -175,6 +175,11 @@ static void RenderAddressDropdown(App* app, float width) {
|
||||
}
|
||||
}
|
||||
|
||||
// Combo/button widths first — the preview truncates to the combo's real pixel width below.
|
||||
float copyBtnW = std::max(schema::UI().drawElement("tabs.receive", "copy-btn-min-width").size, schema::UI().drawElement("tabs.receive", "copy-btn-width").size * Layout::hScale(width));
|
||||
float newBtnW = std::max(schema::UI().drawElement("tabs.receive", "new-btn-min-width").size, schema::UI().drawElement("tabs.receive", "new-btn-width").size * Layout::hScale(width));
|
||||
float dropdownW = width - copyBtnW - newBtnW - Layout::spacingSm() * 2;
|
||||
|
||||
// Build preview string
|
||||
if (!app->isConnected()) {
|
||||
s_source_preview = TR(app->isLiteBuild() ? "lite_no_wallet_short" : "not_connected");
|
||||
@@ -183,18 +188,27 @@ static void RenderAddressDropdown(App* app, float width) {
|
||||
const auto& addr = state.addresses[s_selected_address_idx];
|
||||
bool isZ = addr.type == "shielded";
|
||||
const char* tag = isZ ? "[Z]" : "[T]";
|
||||
std::string trunc = util::truncateMiddle(addr.address,
|
||||
static_cast<int>(std::max(schema::UI().drawElement("tabs.receive", "addr-preview-trunc-min").size, width / schema::UI().drawElement("tabs.receive", "addr-preview-trunc-divisor").size)));
|
||||
snprintf(buf, sizeof(buf), "%s %s \xe2\x80\x94 %.8f %s",
|
||||
tag, trunc.c_str(), addr.balance, DRAGONX_TICKER);
|
||||
// Reserve pixel room for the tag prefix and the trailing balance, then middle-truncate the
|
||||
// address to whatever remains — measured with the combo's own Body2 font. Char-count
|
||||
// truncation kept MORE chars as the column widened, so at 150% the scaled font overflowed
|
||||
// and the combo hard-clipped "— 12.00000000 DRGX" to "— 1"; measuring in pixels keeps the
|
||||
// balance visible at any scale.
|
||||
ImFont* comboFont = Type().getFont(TypeStyle::Body2);
|
||||
float comboFontSz = comboFont->LegacySize;
|
||||
char prefix[16]; snprintf(prefix, sizeof(prefix), "%s ", tag);
|
||||
char suffix[64]; snprintf(suffix, sizeof(suffix), " \xe2\x80\x94 %.8f %s", addr.balance, DRAGONX_TICKER);
|
||||
float fixedW = comboFont->CalcTextSizeA(comboFontSz, FLT_MAX, 0.0f, prefix).x
|
||||
+ comboFont->CalcTextSizeA(comboFontSz, FLT_MAX, 0.0f, suffix).x;
|
||||
// Combo interior = dropdownW minus its dropdown-arrow button (~frame height) and both frame paddings.
|
||||
float addrBudget = dropdownW - ImGui::GetFrameHeight() - ImGui::GetStyle().FramePadding.x * 2.0f - fixedW;
|
||||
if (addrBudget < 24.0f) addrBudget = 24.0f; // floor: truncate to a stub rather than overflow
|
||||
std::string trunc = material::TruncateToWidth(addr.address, comboFont, comboFontSz, addrBudget);
|
||||
snprintf(buf, sizeof(buf), "%s%s%s", prefix, trunc.c_str(), suffix);
|
||||
s_source_preview = buf;
|
||||
} else {
|
||||
s_source_preview = TR("select_receiving_address");
|
||||
}
|
||||
|
||||
float copyBtnW = std::max(schema::UI().drawElement("tabs.receive", "copy-btn-min-width").size, schema::UI().drawElement("tabs.receive", "copy-btn-width").size * Layout::hScale(width));
|
||||
float newBtnW = std::max(schema::UI().drawElement("tabs.receive", "new-btn-min-width").size, schema::UI().drawElement("tabs.receive", "new-btn-width").size * Layout::hScale(width));
|
||||
float dropdownW = width - copyBtnW - newBtnW - Layout::spacingSm() * 2;
|
||||
ImGui::SetNextItemWidth(dropdownW);
|
||||
ImGui::PushFont(Type().getFont(TypeStyle::Body2));
|
||||
if (ImGui::BeginCombo("##RecvAddr", s_source_preview.c_str())) {
|
||||
@@ -584,12 +598,14 @@ void RenderReceiveTab(App* app)
|
||||
// ================================================================
|
||||
{
|
||||
// Cap + center the card so the address/amount column stops stretching while the
|
||||
// QR plateaus. cardW never exceeds formW (only shrinks); leftover becomes margin.
|
||||
// QR plateaus. Shared with the Send tab via mainComposeCardBox() so the two card
|
||||
// envelopes are identical (they must never drift in width/position again).
|
||||
// The RECENT RECEIVED list below stays on the uncapped formW (handled separately).
|
||||
float cardDp = Layout::dpiScale();
|
||||
float cardW = std::min(formW, 860.0f * cardDp);
|
||||
Layout::CardBox cardBox = Layout::mainComposeCardBox(formW);
|
||||
float cardW = cardBox.width;
|
||||
float cardLeftX = ImGui::GetCursorScreenPos().x;
|
||||
float cardOffsetX = std::max(0.0f, (formW - cardW) * 0.5f);
|
||||
float cardOffsetX = cardBox.offsetX;
|
||||
if (cardOffsetX > 0.0f)
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + cardOffsetX);
|
||||
|
||||
@@ -911,7 +927,13 @@ void RenderReceiveTab(App* app)
|
||||
{
|
||||
float btnGap = Layout::spacingMd();
|
||||
float btnH = std::max(schema::UI().drawElement("tabs.receive", "action-btn-min-height").size, schema::UI().drawElement("tabs.receive", "action-btn-height").size * vScale);
|
||||
float otherBtnW = std::max(S.drawElement("tabs.receive", "action-btn-min-width").size, innerW * S.drawElement("tabs.receive", "action-btn-width-ratio").size);
|
||||
// Justify the footer edge-to-edge like Send's [Review Send][Cancel] row instead of packing
|
||||
// fixed-width buttons from the left (which left a large dead gap on the right). Split innerW
|
||||
// into equal shares over the live button count: 2 by default (Clear Request + Explorer),
|
||||
// 4 when an amount is requested (+ Copy URI + Share).
|
||||
int nBtns = (s_request_amount > 0 ? 2 : 0) + 2;
|
||||
float otherBtnW = std::max(S.drawElement("tabs.receive", "action-btn-min-width").size,
|
||||
(innerW - (nBtns - 1) * btnGap) / (float)nBtns);
|
||||
|
||||
bool firstBtn = true;
|
||||
|
||||
|
||||
@@ -1272,12 +1272,13 @@ void RenderSendTab(App* app)
|
||||
float contentStartY = ImGui::GetCursorPosY();
|
||||
|
||||
float formAvailW = ImGui::GetContentRegionAvail().x;
|
||||
// The compose form reads best as a centered fixed-width column, not edge-to-edge.
|
||||
// Cap the card to a readable form width and center it; the recent-sends list below
|
||||
// deliberately keeps the full column width (formAvailW).
|
||||
const float sendDp = Layout::dpiScale();
|
||||
float formCardW = std::min(formAvailW, 760.0f * sendDp);
|
||||
float formOffsetX = std::max(0.0f, (formAvailW - formCardW) * 0.5f);
|
||||
// Fill the available column up to the content-max-width cap, then center. Shared with the
|
||||
// Receive tab via mainComposeCardBox() so the two card envelopes are identical in width and
|
||||
// position (Send previously capped at 760dp vs Receive's 860dp, so Send rendered narrower).
|
||||
// The recent-sends list below deliberately keeps the full column width (formAvailW).
|
||||
Layout::CardBox formBox = Layout::mainComposeCardBox(formAvailW);
|
||||
float formCardW = formBox.width;
|
||||
float formOffsetX = formBox.offsetX;
|
||||
float formW = formAvailW;
|
||||
ImGui::BeginGroup();
|
||||
|
||||
@@ -1367,7 +1368,10 @@ void RenderSendTab(App* app)
|
||||
|
||||
float pasteW = std::max(schema::UI().drawElement("tabs.send", "paste-btn-min-width").size, colW * schema::UI().drawElement("tabs.send", "paste-btn-width-ratio").size);
|
||||
float contactsW = ImGui::GetFrameHeight(); // compact square icon button for the contact picker
|
||||
ImGui::PushItemWidth(colW - pasteW - contactsW - Layout::spacingSm() * 2.0f);
|
||||
// Reserve the TWO real SameLine gaps (each = ItemSpacing.x) between input|Paste|icon.
|
||||
// Reserving spacingSm (a smaller token) under-counted the gap, so the row overshot colW by
|
||||
// ~2*(ItemSpacing.x - spacingSm) and the icon's right border clipped past the card edge.
|
||||
ImGui::PushItemWidth(colW - pasteW - contactsW - ImGui::GetStyle().ItemSpacing.x * 2.0f);
|
||||
|
||||
// Show clipboard preview as transparent overlay when paste button is hovered
|
||||
bool paste_hovered = false;
|
||||
@@ -1425,9 +1429,12 @@ void RenderSendTab(App* app)
|
||||
}
|
||||
}
|
||||
|
||||
// Contact picker — pick a saved contact's address as the recipient.
|
||||
// Contact picker — pick a saved contact's address as the recipient. Pin the height to the
|
||||
// frame height (== the input + Paste height) so the larger iconMed font doesn't auto-size
|
||||
// this square button taller than its row-mates. (Passing a non-zero size also routes
|
||||
// TactileButton through its precise InvisibleButton + centered-glyph path.)
|
||||
ImGui::SameLine();
|
||||
if (material::TactileButton(ICON_MD_CONTACTS "##pickContact", ImVec2(contactsW, 0),
|
||||
if (material::TactileButton(ICON_MD_CONTACTS "##pickContact", ImVec2(contactsW, ImGui::GetFrameHeight()),
|
||||
material::Type().iconMed()))
|
||||
ImGui::OpenPopup("##ContactPickerPopup");
|
||||
if (ImGui::IsItemHovered()) material::Tooltip("%s", TR("send_contacts_button"));
|
||||
|
||||
Reference in New Issue
Block a user