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:
parent
c2398791be
commit
5957cef205
1 changed files with 36 additions and 33 deletions
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue