|
|
@@ -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;
|
|
|
|
|
|
|
|