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

TreeView: Coalesce item position recalculation to fix performance issues with large trees

This commit is contained in:
ed 2021-10-13 14:26:04 +01:00
parent e612481771
commit 70968d46c8

View file

@ -632,36 +632,20 @@ private:
//==============================================================================
class TreeView::TreeViewport : public Viewport,
private Timer
private AsyncUpdater
{
public:
TreeViewport() = default;
void updateComponents (bool triggerResize)
{
if (auto* tvc = getContentComp())
{
if (triggerResize)
tvc->resized();
else
tvc->updateComponents();
}
repaint();
}
explicit TreeViewport (TreeView& treeView) : owner (treeView) {}
void visibleAreaChanged (const Rectangle<int>& newVisibleArea) override
{
const auto hasScrolledSideways = (newVisibleArea.getX() != lastX);
lastX = newVisibleArea.getX();
updateComponents (hasScrolledSideways);
startTimer (50);
}
ContentComponent* getContentComp() const noexcept
{
return static_cast<ContentComponent*> (getViewedComponent());
structureChanged = true;
triggerAsyncUpdate();
}
bool keyPressed (const KeyPress& key) override
@ -673,22 +657,76 @@ public:
return Viewport::keyPressed (key);
}
ContentComponent* getContentComp() const noexcept
{
return static_cast<ContentComponent*> (getViewedComponent());
}
enum class Async { yes, no };
void recalculatePositions (Async useAsyncUpdate)
{
needsRecalculating = true;
if (useAsyncUpdate == Async::yes)
triggerAsyncUpdate();
else
handleAsyncUpdate();
}
private:
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
{
return createIgnoredAccessibilityHandler (*this);
}
void timerCallback() override
void handleAsyncUpdate() override
{
stopTimer();
if (auto* tree = getParentComponent())
if (auto* handler = tree->getAccessibilityHandler())
if (structureChanged)
{
if (auto* handler = owner.getAccessibilityHandler())
handler->notifyAccessibilityEvent (AccessibilityEvent::structureChanged);
structureChanged = false;
}
if (needsRecalculating)
{
if (auto* root = owner.rootItem)
{
const auto startY = owner.rootItemVisible ? 0 : -root->itemHeight;
root->updatePositions (startY);
getViewedComponent()->setSize (jmax (getMaximumVisibleWidth(), root->totalWidth + 50),
root->totalHeight + startY);
}
else
{
getViewedComponent()->setSize (0, 0);
}
updateComponents (false);
needsRecalculating = false;
}
}
void updateComponents (bool triggerResize)
{
if (auto* content = getContentComp())
{
if (triggerResize)
content->resized();
else
content->updateComponents();
}
repaint();
}
TreeView& owner;
int lastX = -1;
bool structureChanged = false, needsRecalculating = false;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewport)
};
@ -696,7 +734,7 @@ private:
//==============================================================================
TreeView::TreeView (const String& name) : Component (name)
{
viewport = std::make_unique<TreeViewport>();
viewport = std::make_unique<TreeViewport> (*this);
addAndMakeVisible (viewport.get());
viewport->setViewedComponent (new ContentComponent (*this));
@ -737,7 +775,7 @@ void TreeView::setRootItem (TreeViewItem* const newRootItem)
rootItem->setOpen (true);
}
updateVisibleItems();
viewport->recalculatePositions (TreeViewport::Async::no);
}
}
@ -1097,20 +1135,7 @@ bool TreeView::keyPressed (const KeyPress& key)
void TreeView::updateVisibleItems()
{
if (rootItem != nullptr)
{
rootItem->updatePositions (rootItemVisible ? 0 : -rootItem->itemHeight);
viewport->getViewedComponent()
->setSize (jmax (viewport->getMaximumVisibleWidth(), rootItem->totalWidth + 50),
rootItem->totalHeight - (rootItemVisible ? 0 : rootItem->itemHeight));
}
else
{
viewport->getViewedComponent()->setSize (0, 0);
}
viewport->updateComponents (false);
viewport->recalculatePositions (TreeViewport::Async::yes);
}
//==============================================================================
@ -1774,6 +1799,9 @@ void TreeViewItem::setOwnerView (TreeView* const newOwner) noexcept
int TreeViewItem::getIndentX() const noexcept
{
if (ownerView == nullptr)
return 0;
int x = ownerView->rootItemVisible ? 1 : 0;
if (! ownerView->openCloseButtonsVisible)
@ -2053,6 +2081,9 @@ TreeViewItem::OpennessRestorer::~OpennessRestorer()
void TreeViewItem::draw (Graphics& g, int width, bool isMouseOverButton)
{
if (ownerView == nullptr)
return;
const auto indent = getIndentX();
const auto itemW = (itemWidth < 0 || drawsInRightMargin) ? width - indent : itemWidth;