1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

TreeView: Improve performance when rendering very large trees

Previously, trees with thousands of items could take a long time to
render when scrolling due to poor complexity of getAllVisibleItems()
This commit is contained in:
reuk 2024-03-18 14:21:12 +00:00
parent c2398791be
commit 5957cef205
No known key found for this signature in database
GPG key ID: FCB43929F012EE5C

View file

@ -632,6 +632,29 @@ private:
: nextItem; : nextItem;
} }
template <typename Fn>
static void forEachDepthFirst (TreeViewItem* item, bool includeItem, Fn&& callback)
{
if (includeItem)
callback (item);
if (item->isOpen())
for (auto i = 0; i < item->getNumSubItems(); ++i)
forEachDepthFirst (item->getSubItem (i), true, callback);
}
std::vector<TreeViewItem*> collectAllItems() const
{
size_t count{};
forEachDepthFirst (owner.rootItem, owner.rootItemVisible, [&] (auto*) { ++count; });
std::vector<TreeViewItem*> allItems;
allItems.reserve (count);
forEachDepthFirst (owner.rootItem, owner.rootItemVisible, [&] (auto* item) { allItems.push_back (item); });
return allItems;
}
std::vector<TreeViewItem*> getAllVisibleItems() const std::vector<TreeViewItem*> getAllVisibleItems() const
{ {
if (owner.rootItem == nullptr) if (owner.rootItem == nullptr)
@ -639,47 +662,27 @@ private:
const auto visibleTop = -getY(); const auto visibleTop = -getY();
const auto visibleBottom = visibleTop + getParentHeight(); const auto visibleBottom = visibleTop + getParentHeight();
auto allItems = collectAllItems();
std::vector<TreeViewItem*> visibleItems; const auto lower = std::lower_bound (allItems.begin(), allItems.end(), visibleTop, [] (TreeViewItem* item, const auto y)
auto* item = [&]
{ {
auto* i = owner.rootItemVisible ? owner.rootItem return item->y + item->getItemHeight() < y;
: owner.rootItem->subItems.getFirst(); });
while (i != nullptr && i->y + i->getItemHeight() < visibleTop) const auto upper = std::upper_bound (allItems.begin(), allItems.end(), visibleBottom, [] (const auto y, TreeViewItem* item)
i = getNextVisibleItem (i, true);
return i;
}();
auto addOffscreenItemBuffer = [&visibleItems] (TreeViewItem* i, int num, bool forwards)
{ {
while (--num >= 0) return y < item->y;
{ });
i = getNextVisibleItem (i, forwards);
if (i == nullptr) const std::ptrdiff_t padding = 2;
return;
visibleItems.push_back (i); const auto frontToErase = std::max (padding, std::distance (allItems.begin(), lower)) - padding;
} const auto backToErase = std::max (padding, std::distance (upper, allItems.end())) - padding;
};
addOffscreenItemBuffer (item, 2, false); allItems.erase (allItems.begin(), std::next (allItems.begin(), frontToErase));
allItems.erase (std::prev (allItems.end(), backToErase), allItems.end());
while (item != nullptr && item->y < visibleBottom) return allItems;
{
visibleItems.push_back (item);
item = getNextVisibleItem (item, true);
}
if (item != nullptr)
visibleItems.push_back (item);
addOffscreenItemBuffer (item, 2, true);
return visibleItems;
} }
//============================================================================== //==============================================================================