git subrepo clone --branch=sono6good https://github.com/essej/JUCE.git deps/juce
subrepo: subdir: "deps/juce" merged: "b13f9084e" upstream: origin: "https://github.com/essej/JUCE.git" branch: "sono6good" commit: "b13f9084e" git-subrepo: version: "0.4.3" origin: "https://github.com/ingydotnet/git-subrepo.git" commit: "2f68596"
This commit is contained in:
952
deps/juce/modules/juce_gui_basics/widgets/juce_TreeView.h
vendored
Normal file
952
deps/juce/modules/juce_gui_basics/widgets/juce_TreeView.h
vendored
Normal file
@ -0,0 +1,952 @@
|
||||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2020 - Raw Material Software Limited
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
By using JUCE, you agree to the terms of both the JUCE 6 End-User License
|
||||
Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
|
||||
|
||||
End User License Agreement: www.juce.com/juce-6-licence
|
||||
Privacy Policy: www.juce.com/juce-privacy-policy
|
||||
|
||||
Or: You may also use this code under the terms of the GPL v3 (see
|
||||
www.gnu.org/licenses).
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
class TreeView;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
An item in a TreeView.
|
||||
|
||||
A TreeViewItem can either be a leaf-node in the tree, or it can contain its
|
||||
own sub-items.
|
||||
|
||||
To implement an item that contains sub-items, override the itemOpennessChanged()
|
||||
method so that when it is opened, it adds the new sub-items to itself using the
|
||||
addSubItem method. Depending on the nature of the item it might choose to only
|
||||
do this the first time it's opened, or it might want to refresh itself each time.
|
||||
It also has the option of deleting its sub-items when it is closed, or leaving them
|
||||
in place.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API TreeViewItem
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Constructor. */
|
||||
TreeViewItem();
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~TreeViewItem();
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of sub-items that have been added to this item.
|
||||
Note that this doesn't mean much if the node isn't open.
|
||||
|
||||
@see getSubItem, mightContainSubItems, addSubItem
|
||||
*/
|
||||
int getNumSubItems() const noexcept;
|
||||
|
||||
/** Returns one of the item's sub-items.
|
||||
Remember that the object returned might get deleted at any time when its parent
|
||||
item is closed or refreshed, depending on the nature of the items you're using.
|
||||
|
||||
@see getNumSubItems
|
||||
*/
|
||||
TreeViewItem* getSubItem (int index) const noexcept;
|
||||
|
||||
/** Removes any sub-items. */
|
||||
void clearSubItems();
|
||||
|
||||
/** Adds a sub-item.
|
||||
|
||||
@param newItem the object to add to the item's sub-item list. Once added, these can be
|
||||
found using getSubItem(). When the items are later removed with
|
||||
removeSubItem() (or when this item is deleted), they will be deleted.
|
||||
@param insertPosition the index which the new item should have when it's added. If this
|
||||
value is less than 0, the item will be added to the end of the list.
|
||||
*/
|
||||
void addSubItem (TreeViewItem* newItem, int insertPosition = -1);
|
||||
|
||||
/** Adds a sub-item with a sort-comparator, assuming that the existing items are already sorted.
|
||||
|
||||
@param comparator the comparator object for sorting - see sortSubItems() for details about
|
||||
the methods this class must provide.
|
||||
@param newItem the object to add to the item's sub-item list. Once added, these can be
|
||||
found using getSubItem(). When the items are later removed with
|
||||
removeSubItem() (or when this item is deleted), they will be deleted.
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void addSubItemSorted (ElementComparator& comparator, TreeViewItem* newItem)
|
||||
{
|
||||
addSubItem (newItem, findInsertIndexInSortedArray (comparator, subItems.begin(), newItem, 0, subItems.size()));
|
||||
}
|
||||
|
||||
/** Removes one of the sub-items.
|
||||
|
||||
@param index the item to remove
|
||||
@param deleteItem if true, the item that is removed will also be deleted.
|
||||
*/
|
||||
void removeSubItem (int index, bool deleteItem = true);
|
||||
|
||||
/** Sorts the list of sub-items using a standard array comparator.
|
||||
|
||||
This will use a comparator object to sort the elements into order. The comparator
|
||||
object must have a method of the form:
|
||||
@code
|
||||
int compareElements (TreeViewItem* first, TreeViewItem* second);
|
||||
@endcode
|
||||
|
||||
..and this method must return:
|
||||
- a value of < 0 if the first comes before the second
|
||||
- a value of 0 if the two objects are equivalent
|
||||
- a value of > 0 if the second comes before the first
|
||||
|
||||
To improve performance, the compareElements() method can be declared as static or const.
|
||||
*/
|
||||
template <class ElementComparator>
|
||||
void sortSubItems (ElementComparator& comparator)
|
||||
{
|
||||
subItems.sort (comparator);
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the TreeView to which this item belongs. */
|
||||
TreeView* getOwnerView() const noexcept { return ownerView; }
|
||||
|
||||
/** Returns the item within which this item is contained. */
|
||||
TreeViewItem* getParentItem() const noexcept { return parentItem; }
|
||||
|
||||
//==============================================================================
|
||||
/** True if this item is currently open in the TreeView.
|
||||
|
||||
@see getOpenness
|
||||
*/
|
||||
bool isOpen() const noexcept;
|
||||
|
||||
/** Opens or closes the item.
|
||||
|
||||
When opened or closed, the item's itemOpennessChanged() method will be called,
|
||||
and a subclass should use this callback to create and add any sub-items that
|
||||
it needs to.
|
||||
|
||||
Note that if this is called when the item is in its default openness state, and
|
||||
this call would not change whether it's open or closed, then no change will be
|
||||
stored. If you want to explicitly set the openness state to be non-default then
|
||||
you should use setOpenness instead.
|
||||
|
||||
@see setOpenness, itemOpennessChanged, mightContainSubItems
|
||||
*/
|
||||
void setOpen (bool shouldBeOpen);
|
||||
|
||||
/** An enum of states to describe the explicit or implicit openness of an item. */
|
||||
enum class Openness
|
||||
{
|
||||
opennessDefault,
|
||||
opennessClosed,
|
||||
opennessOpen
|
||||
};
|
||||
|
||||
/** Returns the openness state of this item.
|
||||
|
||||
@see isOpen
|
||||
*/
|
||||
Openness getOpenness() const noexcept;
|
||||
|
||||
/** Opens or closes the item.
|
||||
|
||||
If this causes the value of isOpen() to change, then the item's itemOpennessChanged()
|
||||
method will be called, and a subclass should use this callback to create and add any
|
||||
sub-items that it needs to.
|
||||
|
||||
@see setOpen
|
||||
*/
|
||||
void setOpenness (Openness newOpenness);
|
||||
|
||||
/** True if this item is currently selected.
|
||||
|
||||
Use this when painting the node, to decide whether to draw it as selected or not.
|
||||
*/
|
||||
bool isSelected() const noexcept;
|
||||
|
||||
/** Selects or deselects the item.
|
||||
|
||||
If shouldNotify == sendNotification, then a callback will be made
|
||||
to itemSelectionChanged() if the item's selection has changed.
|
||||
*/
|
||||
void setSelected (bool shouldBeSelected,
|
||||
bool deselectOtherItemsFirst,
|
||||
NotificationType shouldNotify = sendNotification);
|
||||
|
||||
/** Returns the rectangle that this item occupies.
|
||||
|
||||
If relativeToTreeViewTopLeft is true, the coordinates are relative to the
|
||||
top-left of the TreeView comp, so this will depend on the scroll-position of
|
||||
the tree. If false, it is relative to the top-left of the topmost item in the
|
||||
tree (so this would be unaffected by scrolling the view).
|
||||
*/
|
||||
Rectangle<int> getItemPosition (bool relativeToTreeViewTopLeft) const noexcept;
|
||||
|
||||
/** Sends a signal to the TreeView to make it refresh itself.
|
||||
|
||||
Call this if your items have changed and you want the tree to update to reflect this.
|
||||
*/
|
||||
void treeHasChanged() const noexcept;
|
||||
|
||||
/** Sends a repaint message to redraw just this item.
|
||||
|
||||
Note that you should only call this if you want to repaint a superficial change. If
|
||||
you're altering the tree's nodes, you should instead call treeHasChanged().
|
||||
*/
|
||||
void repaintItem() const;
|
||||
|
||||
/** Returns the row number of this item in the tree.
|
||||
|
||||
The row number of an item will change according to which items are open.
|
||||
|
||||
@see TreeView::getNumRowsInTree(), TreeView::getItemOnRow()
|
||||
*/
|
||||
int getRowNumberInTree() const noexcept;
|
||||
|
||||
/** Returns true if all the item's parent nodes are open.
|
||||
|
||||
This is useful to check whether the item might actually be visible or not.
|
||||
*/
|
||||
bool areAllParentsOpen() const noexcept;
|
||||
|
||||
/** Changes whether lines are drawn to connect any sub-items to this item.
|
||||
|
||||
By default, line-drawing is turned on according to LookAndFeel::areLinesDrawnForTreeView().
|
||||
*/
|
||||
void setLinesDrawnForSubItems (bool shouldDrawLines) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Tells the tree whether this item can potentially be opened.
|
||||
|
||||
If your item could contain sub-items, this should return true; if it returns
|
||||
false then the tree will not try to open the item. This determines whether or
|
||||
not the item will be drawn with a 'plus' button next to it.
|
||||
*/
|
||||
virtual bool mightContainSubItems() = 0;
|
||||
|
||||
/** Returns a string to uniquely identify this item.
|
||||
|
||||
If you're planning on using the TreeView::getOpennessState() method, then
|
||||
these strings will be used to identify which nodes are open. The string
|
||||
should be unique amongst the item's sibling items, but it's ok for there
|
||||
to be duplicates at other levels of the tree.
|
||||
|
||||
If you're not going to store the state, then it's ok not to bother implementing
|
||||
this method.
|
||||
*/
|
||||
virtual String getUniqueName() const;
|
||||
|
||||
/** Called when an item is opened or closed.
|
||||
|
||||
When setOpen() is called and the item has specified that it might
|
||||
have sub-items with the mightContainSubItems() method, this method
|
||||
is called to let the item create or manage its sub-items.
|
||||
|
||||
So when this is called with isNowOpen set to true (i.e. when the item is being
|
||||
opened), a subclass might choose to use clearSubItems() and addSubItem() to
|
||||
refresh its sub-item list.
|
||||
|
||||
When this is called with isNowOpen set to false, the subclass might want
|
||||
to use clearSubItems() to save on space, or it might choose to leave them,
|
||||
depending on the nature of the tree.
|
||||
|
||||
You could also use this callback as a trigger to start a background process
|
||||
which asynchronously creates sub-items and adds them, if that's more
|
||||
appropriate for the task in hand.
|
||||
|
||||
@see mightContainSubItems
|
||||
*/
|
||||
virtual void itemOpennessChanged (bool isNowOpen);
|
||||
|
||||
/** Must return the width required by this item.
|
||||
|
||||
If your item needs to have a particular width in pixels, return that value; if
|
||||
you'd rather have it just fill whatever space is available in the TreeView,
|
||||
return -1.
|
||||
|
||||
If all your items return -1, no horizontal scrollbar will be shown, but if any
|
||||
items have fixed widths and extend beyond the width of the TreeView, a
|
||||
scrollbar will appear.
|
||||
|
||||
Each item can be a different width, but if they change width, you should call
|
||||
treeHasChanged() to update the tree.
|
||||
*/
|
||||
virtual int getItemWidth() const { return -1; }
|
||||
|
||||
/** Must return the height required by this item.
|
||||
|
||||
This is the height in pixels that the item will take up. Items in the tree
|
||||
can be different heights, but if they change height, you should call
|
||||
treeHasChanged() to update the tree.
|
||||
*/
|
||||
virtual int getItemHeight() const { return 20; }
|
||||
|
||||
/** You can override this method to return false if you don't want to allow the
|
||||
user to select this item.
|
||||
*/
|
||||
virtual bool canBeSelected() const { return true; }
|
||||
|
||||
/** Creates a component that will be used to represent this item.
|
||||
|
||||
You don't have to implement this method - if it returns nullptr then no component
|
||||
will be used for the item, and you can just draw it using the paintItem()
|
||||
callback. But if you do return a component, it will be positioned in the
|
||||
TreeView so that it can be used to represent this item.
|
||||
|
||||
The component returned will be managed by the TreeView and will be deleted
|
||||
later when it goes off the screen or is no longer needed. Its position and
|
||||
size will be completely managed by the tree, so don't attempt to move it around.
|
||||
|
||||
Something you may want to do with your component is to give it a pointer to
|
||||
the TreeView that created it. This is perfectly safe, and there's no danger
|
||||
of it becoming a dangling pointer because the TreeView will always delete
|
||||
the component before it is itself deleted.
|
||||
|
||||
As long as you stick to these rules you can return whatever kind of
|
||||
component you like. It's most useful if you're doing things like drag-and-drop
|
||||
of items, or want to use a Label component to edit item names, etc.
|
||||
*/
|
||||
virtual std::unique_ptr<Component> createItemComponent() { return nullptr; }
|
||||
|
||||
//==============================================================================
|
||||
/** Draws the item's contents.
|
||||
|
||||
You can choose to either implement this method and draw each item, or you
|
||||
can use createItemComponent() to create a component that will represent the
|
||||
item.
|
||||
|
||||
If all you need in your tree is to be able to draw the items and detect when
|
||||
the user selects or double-clicks one of them, it's probably enough to
|
||||
use paintItem(), itemClicked() and itemDoubleClicked(). If you need more
|
||||
complicated interactions, you may need to use createItemComponent() instead.
|
||||
|
||||
@param g the graphics context to draw into
|
||||
@param width the width of the area available for drawing
|
||||
@param height the height of the area available for drawing
|
||||
*/
|
||||
virtual void paintItem (Graphics& g, int width, int height);
|
||||
|
||||
/** Draws the item's open/close button.
|
||||
|
||||
If you don't implement this method, the default behaviour is to call
|
||||
LookAndFeel::drawTreeviewPlusMinusBox(), but you can override it for custom
|
||||
effects. You may want to override it and call the base-class implementation
|
||||
with a different backgroundColour parameter, if your implementation has a
|
||||
background colour other than the default (white).
|
||||
*/
|
||||
virtual void paintOpenCloseButton (Graphics&, const Rectangle<float>& area,
|
||||
Colour backgroundColour, bool isMouseOver);
|
||||
|
||||
/** Draws the line that connects this item to the vertical line extending below its parent. */
|
||||
virtual void paintHorizontalConnectingLine (Graphics&, const Line<float>& line);
|
||||
|
||||
/** Draws the line that extends vertically up towards one of its parents, or down to one of its children. */
|
||||
virtual void paintVerticalConnectingLine (Graphics&, const Line<float>& line);
|
||||
|
||||
/** Called when the user clicks on this item.
|
||||
|
||||
If you're using createItemComponent() to create a custom component for the
|
||||
item, the mouse-clicks might not make it through to the TreeView, but this
|
||||
is how you find out about clicks when just drawing each item individually.
|
||||
|
||||
The associated mouse-event details are passed in, so you can find out about
|
||||
which button, where it was, etc.
|
||||
|
||||
@see itemDoubleClicked
|
||||
*/
|
||||
virtual void itemClicked (const MouseEvent&);
|
||||
|
||||
/** Called when the user double-clicks on this item.
|
||||
|
||||
If you're using createItemComponent() to create a custom component for the
|
||||
item, the mouse-clicks might not make it through to the TreeView, but this
|
||||
is how you find out about clicks when just drawing each item individually.
|
||||
|
||||
The associated mouse-event details are passed in, so you can find out about
|
||||
which button, where it was, etc.
|
||||
|
||||
If not overridden, the base class method here will open or close the item as
|
||||
if the 'plus' button had been clicked.
|
||||
|
||||
@see itemClicked
|
||||
*/
|
||||
virtual void itemDoubleClicked (const MouseEvent&);
|
||||
|
||||
/** Called when the item is selected or deselected.
|
||||
|
||||
Use this if you want to do something special when the item's selectedness
|
||||
changes. By default it'll get repainted when this happens.
|
||||
*/
|
||||
virtual void itemSelectionChanged (bool isNowSelected);
|
||||
|
||||
/** Called when the owner view changes */
|
||||
virtual void ownerViewChanged (TreeView* newOwner);
|
||||
|
||||
/** The item can return a tool tip string here if it wants to.
|
||||
|
||||
@see TooltipClient
|
||||
*/
|
||||
virtual String getTooltip();
|
||||
|
||||
/** Use this to set the name for this item that will be read out by accessibility
|
||||
clients.
|
||||
|
||||
The default implementation will return the tooltip string from getTooltip()
|
||||
if it is not empty, otherwise it will return a description of the nested level
|
||||
and row number of the item.
|
||||
|
||||
@see AccessibilityHandler
|
||||
*/
|
||||
virtual String getAccessibilityName();
|
||||
|
||||
//==============================================================================
|
||||
/** To allow items from your TreeView to be dragged-and-dropped, implement this method.
|
||||
|
||||
If this returns a non-null variant then when the user drags an item, the TreeView will
|
||||
try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
|
||||
a drag-and-drop operation, using this string as the source description, with the TreeView
|
||||
itself as the source component.
|
||||
|
||||
If you need more complex drag-and-drop behaviour, you can use custom components for
|
||||
the items, and use those to trigger the drag.
|
||||
|
||||
To accept drag-and-drop in your tree, see isInterestedInDragSource(),
|
||||
isInterestedInFileDrag(), etc.
|
||||
|
||||
@see DragAndDropContainer::startDragging
|
||||
*/
|
||||
virtual var getDragSourceDescription();
|
||||
|
||||
/** If you want your item to be able to have files drag-and-dropped onto it, implement this
|
||||
method and return true.
|
||||
|
||||
If you return true and allow some files to be dropped, you'll also need to implement the
|
||||
filesDropped() method to do something with them.
|
||||
|
||||
Note that this will be called often, so make your implementation very quick! There's
|
||||
certainly no time to try opening the files and having a think about what's inside them!
|
||||
|
||||
For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource().
|
||||
|
||||
@see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource
|
||||
*/
|
||||
virtual bool isInterestedInFileDrag (const StringArray& files);
|
||||
|
||||
/** When files are dropped into this item, this callback is invoked.
|
||||
|
||||
For this to work, you'll need to have also implemented isInterestedInFileDrag().
|
||||
The insertIndex value indicates where in the list of sub-items the files were dropped.
|
||||
If files are dropped onto an area of the tree where there are no visible items, this
|
||||
method is called on the root item of the tree, with an insert index of 0.
|
||||
|
||||
@see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag
|
||||
*/
|
||||
virtual void filesDropped (const StringArray& files, int insertIndex);
|
||||
|
||||
/** If you want your item to act as a DragAndDropTarget, implement this method and return true.
|
||||
|
||||
If you implement this method, you'll also need to implement itemDropped() in order to handle
|
||||
the items when they are dropped.
|
||||
To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag().
|
||||
|
||||
@see DragAndDropTarget::isInterestedInDragSource, itemDropped
|
||||
*/
|
||||
virtual bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails);
|
||||
|
||||
/** When a things are dropped into this item, this callback is invoked.
|
||||
|
||||
For this to work, you need to have also implemented isInterestedInDragSource().
|
||||
The insertIndex value indicates where in the list of sub-items the new items should be placed.
|
||||
If files are dropped onto an area of the tree where there are no visible items, this
|
||||
method is called on the root item of the tree, with an insert index of 0.
|
||||
|
||||
@see isInterestedInDragSource, DragAndDropTarget::itemDropped
|
||||
*/
|
||||
virtual void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex);
|
||||
|
||||
//==============================================================================
|
||||
/** Sets a flag to indicate that the item wants to be allowed
|
||||
to draw all the way across to the left edge of the TreeView.
|
||||
|
||||
By default this is false, which means that when the paintItem()
|
||||
method is called, its graphics context is clipped to only allow
|
||||
drawing within the item's rectangle. If this flag is set to true,
|
||||
then the graphics context isn't clipped on its left side, so it
|
||||
can draw all the way across to the left margin. Note that the
|
||||
context will still have its origin in the same place though, so
|
||||
the coordinates of anything to its left will be negative. It's
|
||||
mostly useful if you want to draw a wider bar behind the
|
||||
highlighted item.
|
||||
*/
|
||||
void setDrawsInLeftMargin (bool canDrawInLeftMargin) noexcept;
|
||||
|
||||
/** Sets a flag to indicate that the item wants to be allowed
|
||||
to draw all the way across to the right edge of the TreeView.
|
||||
|
||||
Similar to setDrawsInLeftMargin: when this flag is set to true,
|
||||
then the graphics context isn't clipped on the right side. Unlike
|
||||
setDrawsInLeftMargin, you will very rarely need to use this function,
|
||||
as this method won't clip the right margin unless your TreeViewItem
|
||||
overrides getItemWidth to return a positive value.
|
||||
|
||||
@see setDrawsInLeftMargin, getItemWidth
|
||||
*/
|
||||
void setDrawsInRightMargin (bool canDrawInRightMargin) noexcept;
|
||||
|
||||
//==============================================================================
|
||||
/** Saves the current state of open/closed nodes so it can be restored later.
|
||||
|
||||
This takes a snapshot of which sub-nodes have been explicitly opened or closed,
|
||||
and records it as XML. To identify node objects it uses the
|
||||
TreeViewItem::getUniqueName() method to create named paths. This
|
||||
means that the same state of open/closed nodes can be restored to a
|
||||
completely different instance of the tree, as long as it contains nodes
|
||||
whose unique names are the same.
|
||||
|
||||
You'd normally want to use TreeView::getOpennessState() rather than call it
|
||||
for a specific item, but this can be handy if you need to briefly save the state
|
||||
for a section of the tree.
|
||||
|
||||
Note that if all nodes of the tree are in their default state, then this may
|
||||
return a nullptr.
|
||||
|
||||
@see TreeView::getOpennessState, restoreOpennessState
|
||||
*/
|
||||
std::unique_ptr<XmlElement> getOpennessState() const;
|
||||
|
||||
/** Restores the openness of this item and all its sub-items from a saved state.
|
||||
|
||||
See TreeView::restoreOpennessState for more details.
|
||||
|
||||
You'd normally want to use TreeView::restoreOpennessState() rather than call it
|
||||
for a specific item, but this can be handy if you need to briefly save the state
|
||||
for a section of the tree.
|
||||
|
||||
@see TreeView::restoreOpennessState, getOpennessState
|
||||
*/
|
||||
void restoreOpennessState (const XmlElement& xml);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the index of this item in its parent's sub-items. */
|
||||
int getIndexInParent() const noexcept;
|
||||
|
||||
/** Returns true if this item is the last of its parent's sub-items. */
|
||||
bool isLastOfSiblings() const noexcept;
|
||||
|
||||
/** Creates a string that can be used to uniquely retrieve this item in the tree.
|
||||
|
||||
The string that is returned can be passed to TreeView::findItemFromIdentifierString().
|
||||
The string takes the form of a path, constructed from the getUniqueName() of this
|
||||
item and all its parents, so these must all be correctly implemented for it to work.
|
||||
|
||||
@see TreeView::findItemFromIdentifierString, getUniqueName
|
||||
*/
|
||||
String getItemIdentifierString() const;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
This handy class takes a copy of a TreeViewItem's openness when you create it,
|
||||
and restores that openness state when its destructor is called.
|
||||
|
||||
This can very handy when you're refreshing sub-items - e.g.
|
||||
@code
|
||||
void MyTreeViewItem::updateChildItems()
|
||||
{
|
||||
OpennessRestorer openness (*this); // saves the openness state here..
|
||||
|
||||
clearSubItems();
|
||||
|
||||
// add a bunch of sub-items here which may or may not be the same as the ones that
|
||||
// were previously there
|
||||
addSubItem (...
|
||||
|
||||
// ..and at this point, the old openness is restored, so any items that haven't
|
||||
// changed will have their old openness retained.
|
||||
}
|
||||
@endcode
|
||||
*/
|
||||
class JUCE_API OpennessRestorer
|
||||
{
|
||||
public:
|
||||
OpennessRestorer (TreeViewItem&);
|
||||
~OpennessRestorer();
|
||||
|
||||
private:
|
||||
TreeViewItem& treeViewItem;
|
||||
std::unique_ptr<XmlElement> oldOpenness;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpennessRestorer)
|
||||
};
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
friend class TreeView;
|
||||
|
||||
void updatePositions (int);
|
||||
int getIndentX() const noexcept;
|
||||
void setOwnerView (TreeView*) noexcept;
|
||||
TreeViewItem* getTopLevelItem() noexcept;
|
||||
TreeViewItem* getDeepestOpenParentItem() noexcept;
|
||||
int getNumRows() const noexcept;
|
||||
TreeViewItem* getItemOnRow (int) noexcept;
|
||||
void deselectAllRecursively (TreeViewItem*);
|
||||
int countSelectedItemsRecursively (int) const noexcept;
|
||||
TreeViewItem* getSelectedItemWithIndex (int) noexcept;
|
||||
TreeViewItem* findItemFromIdentifierString (const String&);
|
||||
void restoreToDefaultOpenness();
|
||||
bool isFullyOpen() const noexcept;
|
||||
std::unique_ptr<XmlElement> getOpennessState (bool) const;
|
||||
bool removeSubItemFromList (int, bool);
|
||||
void removeAllSubItemsFromList();
|
||||
bool areLinesDrawn() const;
|
||||
void draw (Graphics&, int, bool);
|
||||
|
||||
//==============================================================================
|
||||
TreeView* ownerView = nullptr;
|
||||
TreeViewItem* parentItem = nullptr;
|
||||
OwnedArray<TreeViewItem> subItems;
|
||||
|
||||
Openness openness = Openness::opennessDefault;
|
||||
int y = 0, itemHeight = 0, totalHeight = 0, itemWidth = 0, totalWidth = 0, uid = 0;
|
||||
bool selected = false, redrawNeeded = true, drawLinesInside = false, drawLinesSet = false,
|
||||
drawsInLeftMargin = false, drawsInRightMargin = false;
|
||||
|
||||
//==============================================================================
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewItem)
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
A tree-view component.
|
||||
|
||||
Use one of these to hold and display a structure of TreeViewItem objects.
|
||||
|
||||
@tags{GUI}
|
||||
*/
|
||||
class JUCE_API TreeView : public Component,
|
||||
public SettableTooltipClient,
|
||||
public FileDragAndDropTarget,
|
||||
public DragAndDropTarget
|
||||
{
|
||||
public:
|
||||
//==============================================================================
|
||||
/** Creates an empty TreeView.
|
||||
|
||||
Once you've got a TreeView component, you'll need to give it something to
|
||||
display, using the setRootItem() method.
|
||||
*/
|
||||
TreeView (const String& componentName = {});
|
||||
|
||||
/** Destructor. */
|
||||
~TreeView() override;
|
||||
|
||||
//==============================================================================
|
||||
/** Sets the item that is displayed in the TreeView.
|
||||
|
||||
A tree has a single root item which contains as many sub-items as it needs. If
|
||||
you want the tree to contain a number of root items, you should still use a single
|
||||
root item above these, but hide it using setRootItemVisible().
|
||||
|
||||
You can pass nullptr to this method to clear the tree and remove its current root item.
|
||||
|
||||
The object passed in will not be deleted by the TreeView, it's up to the caller
|
||||
to delete it when no longer needed. BUT make absolutely sure that you don't delete
|
||||
this item until you've removed it from the tree, either by calling setRootItem (nullptr),
|
||||
or by deleting the tree first. You can also use deleteRootItem() as a quick way
|
||||
to delete it.
|
||||
*/
|
||||
void setRootItem (TreeViewItem* newRootItem);
|
||||
|
||||
/** Returns the tree's root item.
|
||||
|
||||
This will be the last object passed to setRootItem(), or nullptr if none has been set.
|
||||
*/
|
||||
TreeViewItem* getRootItem() const noexcept { return rootItem; }
|
||||
|
||||
/** This will remove and delete the current root item.
|
||||
|
||||
It's a convenient way of deleting the item and calling setRootItem (nullptr).
|
||||
*/
|
||||
void deleteRootItem();
|
||||
|
||||
/** Changes whether the tree's root item is shown or not.
|
||||
|
||||
If the root item is hidden, only its sub-items will be shown in the TreeView - this
|
||||
lets you make the tree look as if it's got many root items. If it's hidden, this call
|
||||
will also make sure the root item is open (otherwise the TreeView would look empty).
|
||||
*/
|
||||
void setRootItemVisible (bool shouldBeVisible);
|
||||
|
||||
/** Returns true if the root item is visible.
|
||||
|
||||
@see setRootItemVisible
|
||||
*/
|
||||
bool isRootItemVisible() const noexcept { return rootItemVisible; }
|
||||
|
||||
/** Sets whether items are open or closed by default.
|
||||
|
||||
Normally, items are closed until the user opens them, but you can use this
|
||||
to make them default to being open until explicitly closed.
|
||||
|
||||
@see areItemsOpenByDefault
|
||||
*/
|
||||
void setDefaultOpenness (bool isOpenByDefault);
|
||||
|
||||
/** Returns true if the tree's items default to being open.
|
||||
|
||||
@see setDefaultOpenness
|
||||
*/
|
||||
bool areItemsOpenByDefault() const noexcept { return defaultOpenness; }
|
||||
|
||||
/** This sets a flag to indicate that the tree can be used for multi-selection.
|
||||
|
||||
You can always select multiple items internally by calling the
|
||||
TreeViewItem::setSelected() method, but this flag indicates whether the user
|
||||
is allowed to multi-select by clicking on the tree.
|
||||
|
||||
By default it is disabled.
|
||||
|
||||
@see isMultiSelectEnabled
|
||||
*/
|
||||
void setMultiSelectEnabled (bool canMultiSelect);
|
||||
|
||||
/** Returns whether multi-select has been enabled for the tree.
|
||||
|
||||
@see setMultiSelectEnabled
|
||||
*/
|
||||
bool isMultiSelectEnabled() const noexcept { return multiSelectEnabled; }
|
||||
|
||||
/** Sets a flag to indicate whether to hide the open/close buttons.
|
||||
|
||||
@see areOpenCloseButtonsVisible
|
||||
*/
|
||||
void setOpenCloseButtonsVisible (bool shouldBeVisible);
|
||||
|
||||
/** Returns whether open/close buttons are shown.
|
||||
|
||||
@see setOpenCloseButtonsVisible
|
||||
*/
|
||||
bool areOpenCloseButtonsVisible() const noexcept { return openCloseButtonsVisible; }
|
||||
|
||||
//==============================================================================
|
||||
/** Deselects any items that are currently selected. */
|
||||
void clearSelectedItems();
|
||||
|
||||
/** Returns the number of items that are currently selected.
|
||||
|
||||
If maximumDepthToSearchTo is >= 0, it lets you specify a maximum depth to which the
|
||||
tree will be recursed.
|
||||
|
||||
@see getSelectedItem, clearSelectedItems
|
||||
*/
|
||||
int getNumSelectedItems (int maximumDepthToSearchTo = -1) const noexcept;
|
||||
|
||||
/** Returns one of the selected items in the tree.
|
||||
|
||||
@param index the index, 0 to (getNumSelectedItems() - 1)
|
||||
*/
|
||||
TreeViewItem* getSelectedItem (int index) const noexcept;
|
||||
|
||||
/** Moves the selected row up or down by the specified number of rows. */
|
||||
void moveSelectedRow (int deltaRows);
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of rows the tree is using, depending on which items are open.
|
||||
|
||||
@see TreeViewItem::getRowNumberInTree()
|
||||
*/
|
||||
int getNumRowsInTree() const;
|
||||
|
||||
/** Returns the item on a particular row of the tree.
|
||||
|
||||
If the index is out of range, this will return nullptr.
|
||||
|
||||
@see getNumRowsInTree, TreeViewItem::getRowNumberInTree()
|
||||
*/
|
||||
TreeViewItem* getItemOnRow (int index) const;
|
||||
|
||||
/** Returns the item that contains a given y-position relative to the top
|
||||
of the TreeView component.
|
||||
*/
|
||||
TreeViewItem* getItemAt (int yPosition) const noexcept;
|
||||
|
||||
/** Tries to scroll the tree so that this item is on-screen somewhere. */
|
||||
void scrollToKeepItemVisible (TreeViewItem* item);
|
||||
|
||||
/** Returns the TreeView's Viewport object. */
|
||||
Viewport* getViewport() const noexcept;
|
||||
|
||||
/** Returns the number of pixels by which each nested level of the tree is indented.
|
||||
|
||||
@see setIndentSize
|
||||
*/
|
||||
int getIndentSize() noexcept;
|
||||
|
||||
/** Changes the distance by which each nested level of the tree is indented.
|
||||
|
||||
@see getIndentSize
|
||||
*/
|
||||
void setIndentSize (int newIndentSize);
|
||||
|
||||
/** Searches the tree for an item with the specified identifier.
|
||||
|
||||
The identifier string must have been created by calling TreeViewItem::getItemIdentifierString().
|
||||
If no such item exists, this will return false. If the item is found, all of its items
|
||||
will be automatically opened.
|
||||
*/
|
||||
TreeViewItem* findItemFromIdentifierString (const String& identifierString) const;
|
||||
|
||||
/** Returns the component that currently represents a given TreeViewItem. */
|
||||
Component* getItemComponent (const TreeViewItem* item) const;
|
||||
|
||||
//==============================================================================
|
||||
/** Saves the current state of open/closed nodes so it can be restored later.
|
||||
|
||||
This takes a snapshot of which nodes have been explicitly opened or closed,
|
||||
and records it as XML. To identify node objects it uses the
|
||||
TreeViewItem::getUniqueName() method to create named paths. This
|
||||
means that the same state of open/closed nodes can be restored to a
|
||||
completely different instance of the tree, as long as it contains nodes
|
||||
whose unique names are the same.
|
||||
|
||||
@param alsoIncludeScrollPosition if this is true, the state will also
|
||||
include information about where the
|
||||
tree has been scrolled to vertically,
|
||||
so this can also be restored
|
||||
@see restoreOpennessState
|
||||
*/
|
||||
std::unique_ptr<XmlElement> getOpennessState (bool alsoIncludeScrollPosition) const;
|
||||
|
||||
/** Restores a previously saved arrangement of open/closed nodes.
|
||||
|
||||
This will try to restore a snapshot of the tree's state that was created by
|
||||
the getOpennessState() method. If any of the nodes named in the original
|
||||
XML aren't present in this tree, they will be ignored.
|
||||
|
||||
If restoreStoredSelection is true, it will also try to re-select any items that
|
||||
were selected in the stored state.
|
||||
|
||||
@see getOpennessState
|
||||
*/
|
||||
void restoreOpennessState (const XmlElement& newState, bool restoreStoredSelection);
|
||||
|
||||
//==============================================================================
|
||||
/** A set of colour IDs to use to change the colour of various aspects of the TreeView.
|
||||
|
||||
These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
|
||||
methods.
|
||||
|
||||
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
||||
*/
|
||||
enum ColourIds
|
||||
{
|
||||
backgroundColourId = 0x1000500, /**< A background colour to fill the component with. */
|
||||
linesColourId = 0x1000501, /**< The colour to draw the lines with.*/
|
||||
dragAndDropIndicatorColourId = 0x1000502, /**< The colour to use for the drag-and-drop target position indicator. */
|
||||
selectedItemBackgroundColourId = 0x1000503, /**< The colour to use to fill the background of any selected items. */
|
||||
oddItemsColourId = 0x1000504, /**< The colour to use to fill the background of the odd numbered items. */
|
||||
evenItemsColourId = 0x1000505 /**< The colour to use to fill the background of the even numbered items. */
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** This abstract base class is implemented by LookAndFeel classes to provide
|
||||
TreeView drawing functionality.
|
||||
*/
|
||||
struct JUCE_API LookAndFeelMethods
|
||||
{
|
||||
virtual ~LookAndFeelMethods() = default;
|
||||
|
||||
virtual void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area,
|
||||
Colour backgroundColour, bool isItemOpen, bool isMouseOver) = 0;
|
||||
|
||||
virtual bool areLinesDrawnForTreeView (TreeView&) = 0;
|
||||
virtual int getTreeViewIndentSize (TreeView&) = 0;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** @internal */
|
||||
void paint (Graphics&) override;
|
||||
/** @internal */
|
||||
void resized() override;
|
||||
/** @internal */
|
||||
bool keyPressed (const KeyPress&) override;
|
||||
/** @internal */
|
||||
void colourChanged() override;
|
||||
/** @internal */
|
||||
void enablementChanged() override;
|
||||
/** @internal */
|
||||
bool isInterestedInFileDrag (const StringArray&) override;
|
||||
/** @internal */
|
||||
void fileDragEnter (const StringArray&, int, int) override;
|
||||
/** @internal */
|
||||
void fileDragMove (const StringArray&, int, int) override;
|
||||
/** @internal */
|
||||
void fileDragExit (const StringArray&) override;
|
||||
/** @internal */
|
||||
void filesDropped (const StringArray&, int, int) override;
|
||||
/** @internal */
|
||||
bool isInterestedInDragSource (const SourceDetails&) override;
|
||||
/** @internal */
|
||||
void itemDragEnter (const SourceDetails&) override;
|
||||
/** @internal */
|
||||
void itemDragMove (const SourceDetails&) override;
|
||||
/** @internal */
|
||||
void itemDragExit (const SourceDetails&) override;
|
||||
/** @internal */
|
||||
void itemDropped (const SourceDetails&) override;
|
||||
|
||||
private:
|
||||
friend class TreeViewItem;
|
||||
|
||||
class ItemComponent;
|
||||
class ContentComponent;
|
||||
class TreeViewport;
|
||||
class InsertPointHighlight;
|
||||
class TargetGroupHighlight;
|
||||
class TreeAccessibilityHandler;
|
||||
struct InsertPoint;
|
||||
|
||||
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
|
||||
void itemsChanged() noexcept;
|
||||
void updateVisibleItems();
|
||||
void updateButtonUnderMouse (const MouseEvent&);
|
||||
void showDragHighlight (const InsertPoint&) noexcept;
|
||||
void hideDragHighlight() noexcept;
|
||||
void handleDrag (const StringArray&, const SourceDetails&);
|
||||
void handleDrop (const StringArray&, const SourceDetails&);
|
||||
bool toggleOpenSelectedItem();
|
||||
void moveOutOfSelectedItem();
|
||||
void moveIntoSelectedItem();
|
||||
void moveByPages (int);
|
||||
|
||||
std::unique_ptr<TreeViewport> viewport;
|
||||
TreeViewItem* rootItem = nullptr;
|
||||
std::unique_ptr<InsertPointHighlight> dragInsertPointHighlight;
|
||||
std::unique_ptr<TargetGroupHighlight> dragTargetGroupHighlight;
|
||||
int indentSize = -1;
|
||||
bool defaultOpenness = false, rootItemVisible = true, multiSelectEnabled = false, openCloseButtonsVisible = true;
|
||||
|
||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView)
|
||||
};
|
||||
|
||||
} // namespace juce
|
Reference in New Issue
Block a user