perf(overview): clip the address list to the visible rows
The Overview address list built all N rows on every frame (icons, labels, balances, buttons, an InvisibleButton and a context-menu check per address) and allocated a vector of N row positions, however few rows fit on screen; the edge mask then walked all their vertices. An ImGuiListClipper now submits only the rows that intersect the list's clip rect, plus: - one guard row on each side, so dividers and anti-aliased edges at the clip boundary are drawn as before; - the row being dragged and the row whose context menu is open, so drag-to-reorder and the menu keep working when they scroll away; - the rows keyboard navigation targets (kept by the clipper itself). Before each row the cursor is put back exactly where the unclipped loop left it, so the density-scaled spacing, which depends on the cursor position, and every row's geometry are unchanged. Row tops are computed from the index, so the per-frame vector is gone, and the scroll extent is the same. The row model (sort, filter) is still rebuilt over all addresses each frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6452,6 +6452,33 @@ void testScrollEdgeFade()
|
||||
}
|
||||
}
|
||||
|
||||
void testAddressRowWindow()
|
||||
{
|
||||
using namespace dragonx::ui;
|
||||
auto w = ComputeAddressRowWindow(100.0f, 300.0f, 100.0f, 50.0f, 10);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 5); // rows 0-3 visible + guard 4 (its top is the clip edge)
|
||||
w = ComputeAddressRowWindow(175.0f, 260.0f, 100.0f, 50.0f, 10);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 5); // rows 1-3 visible + guards 0 and 4
|
||||
w = ComputeAddressRowWindow(420.0f, 520.0f, 100.0f, 50.0f, 20);
|
||||
EXPECT_EQ(w.begin, 5); EXPECT_EQ(w.end, 10); // rows 6-8 visible + guards 5 and 9
|
||||
w = ComputeAddressRowWindow(90.0f, 200.0f, 100.0f, 50.0f, 10);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 3); // list starts below the clip top
|
||||
w = ComputeAddressRowWindow(100.0f, 300.0f, 100.0f, 50.0f, 3);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 3); // clamped to the row count
|
||||
w = ComputeAddressRowWindow(900.0f, 1000.0f, 100.0f, 50.0f, 5);
|
||||
EXPECT_EQ(w.begin, 5); EXPECT_EQ(w.end, 5); // nothing visible: empty (IncludeItemsByIndex no-op)
|
||||
w = ComputeAddressRowWindow(100.0f, 300.0f, 100.0f, 50.0f, 0);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 0);
|
||||
w = ComputeAddressRowWindow(std::numeric_limits<float>::quiet_NaN(), 300.0f, 100.0f, 50.0f, 7);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 7); // non-finite: fail open (every row)
|
||||
w = ComputeAddressRowWindow(100.0f, 300.0f, 100.0f, 0.0f, 4);
|
||||
EXPECT_EQ(w.begin, 0); EXPECT_EQ(w.end, 4); // degenerate pitch: every row
|
||||
// Row entry cursor = where ImGui::ItemSize left it after the previous row's InvisibleButton.
|
||||
EXPECT_NEAR(AddressRowEntryCursorY(0, 100.25f, 60.5f, 4.0f), 100.25, 0.0);
|
||||
EXPECT_NEAR(AddressRowEntryCursorY(1, 100.25f, 60.5f, 4.0f), 164.0, 0.0); // trunc(100.25+60.5+4)
|
||||
EXPECT_NEAR(AddressRowEntryCursorY(3, 100.25f, 60.5f, 4.0f), 285.0, 0.0); // trunc(221.25+60.5+4)
|
||||
}
|
||||
|
||||
void testMiningBenchmarkModel()
|
||||
{
|
||||
dragonx::ui::ThreadBenchmark benchmark;
|
||||
@@ -14783,6 +14810,7 @@ int main()
|
||||
testMiningEarningsCache();
|
||||
testMiningEarningsMidnightRollover();
|
||||
testScrollEdgeFade();
|
||||
testAddressRowWindow();
|
||||
testBalanceAddressListModel();
|
||||
testExplorerBlockCache();
|
||||
testTransactionHistoryCache();
|
||||
|
||||
Reference in New Issue
Block a user