mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-30 02:50:05 +00:00
TreeView: Coalesce item position recalculation to fix performance issues with large trees
This commit is contained in:
parent
e612481771
commit
70968d46c8
1 changed files with 73 additions and 42 deletions
|
|
@ -632,36 +632,20 @@ private:
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
class TreeView::TreeViewport : public Viewport,
|
class TreeView::TreeViewport : public Viewport,
|
||||||
private Timer
|
private AsyncUpdater
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TreeViewport() = default;
|
explicit TreeViewport (TreeView& treeView) : owner (treeView) {}
|
||||||
|
|
||||||
void updateComponents (bool triggerResize)
|
|
||||||
{
|
|
||||||
if (auto* tvc = getContentComp())
|
|
||||||
{
|
|
||||||
if (triggerResize)
|
|
||||||
tvc->resized();
|
|
||||||
else
|
|
||||||
tvc->updateComponents();
|
|
||||||
}
|
|
||||||
|
|
||||||
repaint();
|
|
||||||
}
|
|
||||||
|
|
||||||
void visibleAreaChanged (const Rectangle<int>& newVisibleArea) override
|
void visibleAreaChanged (const Rectangle<int>& newVisibleArea) override
|
||||||
{
|
{
|
||||||
const auto hasScrolledSideways = (newVisibleArea.getX() != lastX);
|
const auto hasScrolledSideways = (newVisibleArea.getX() != lastX);
|
||||||
|
|
||||||
lastX = newVisibleArea.getX();
|
lastX = newVisibleArea.getX();
|
||||||
updateComponents (hasScrolledSideways);
|
updateComponents (hasScrolledSideways);
|
||||||
|
|
||||||
startTimer (50);
|
structureChanged = true;
|
||||||
}
|
triggerAsyncUpdate();
|
||||||
|
|
||||||
ContentComponent* getContentComp() const noexcept
|
|
||||||
{
|
|
||||||
return static_cast<ContentComponent*> (getViewedComponent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool keyPressed (const KeyPress& key) override
|
bool keyPressed (const KeyPress& key) override
|
||||||
|
|
@ -673,22 +657,76 @@ public:
|
||||||
return Viewport::keyPressed (key);
|
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:
|
private:
|
||||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
|
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
|
||||||
{
|
{
|
||||||
return createIgnoredAccessibilityHandler (*this);
|
return createIgnoredAccessibilityHandler (*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timerCallback() override
|
void handleAsyncUpdate() override
|
||||||
{
|
{
|
||||||
stopTimer();
|
if (structureChanged)
|
||||||
|
{
|
||||||
if (auto* tree = getParentComponent())
|
if (auto* handler = owner.getAccessibilityHandler())
|
||||||
if (auto* handler = tree->getAccessibilityHandler())
|
|
||||||
handler->notifyAccessibilityEvent (AccessibilityEvent::structureChanged);
|
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;
|
int lastX = -1;
|
||||||
|
bool structureChanged = false, needsRecalculating = false;
|
||||||
|
|
||||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewport)
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewport)
|
||||||
};
|
};
|
||||||
|
|
@ -696,7 +734,7 @@ private:
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
TreeView::TreeView (const String& name) : Component (name)
|
TreeView::TreeView (const String& name) : Component (name)
|
||||||
{
|
{
|
||||||
viewport = std::make_unique<TreeViewport>();
|
viewport = std::make_unique<TreeViewport> (*this);
|
||||||
addAndMakeVisible (viewport.get());
|
addAndMakeVisible (viewport.get());
|
||||||
viewport->setViewedComponent (new ContentComponent (*this));
|
viewport->setViewedComponent (new ContentComponent (*this));
|
||||||
|
|
||||||
|
|
@ -737,7 +775,7 @@ void TreeView::setRootItem (TreeViewItem* const newRootItem)
|
||||||
rootItem->setOpen (true);
|
rootItem->setOpen (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateVisibleItems();
|
viewport->recalculatePositions (TreeViewport::Async::no);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1097,20 +1135,7 @@ bool TreeView::keyPressed (const KeyPress& key)
|
||||||
|
|
||||||
void TreeView::updateVisibleItems()
|
void TreeView::updateVisibleItems()
|
||||||
{
|
{
|
||||||
if (rootItem != nullptr)
|
viewport->recalculatePositions (TreeViewport::Async::yes);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
|
|
@ -1774,6 +1799,9 @@ void TreeViewItem::setOwnerView (TreeView* const newOwner) noexcept
|
||||||
|
|
||||||
int TreeViewItem::getIndentX() const noexcept
|
int TreeViewItem::getIndentX() const noexcept
|
||||||
{
|
{
|
||||||
|
if (ownerView == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
int x = ownerView->rootItemVisible ? 1 : 0;
|
int x = ownerView->rootItemVisible ? 1 : 0;
|
||||||
|
|
||||||
if (! ownerView->openCloseButtonsVisible)
|
if (! ownerView->openCloseButtonsVisible)
|
||||||
|
|
@ -2053,6 +2081,9 @@ TreeViewItem::OpennessRestorer::~OpennessRestorer()
|
||||||
|
|
||||||
void TreeViewItem::draw (Graphics& g, int width, bool isMouseOverButton)
|
void TreeViewItem::draw (Graphics& g, int width, bool isMouseOverButton)
|
||||||
{
|
{
|
||||||
|
if (ownerView == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
const auto indent = getIndentX();
|
const auto indent = getIndentX();
|
||||||
const auto itemW = (itemWidth < 0 || drawsInRightMargin) ? width - indent : itemWidth;
|
const auto itemW = (itemWidth < 0 || drawsInRightMargin) ? width - indent : itemWidth;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue