VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / modules / juce_gui_basics / widgets / juce_TreeView.h
blob51b3f64ecede71fcd59325ec481141c351f0ad5f
1 /*
2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
8 licensing.
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21 DISCLAIMED.
23 ==============================================================================
26 namespace juce
29 class TreeView;
31 //==============================================================================
32 /**
33 An item in a TreeView.
35 A TreeViewItem can either be a leaf-node in the tree, or it can contain its
36 own sub-items.
38 To implement an item that contains sub-items, override the itemOpennessChanged()
39 method so that when it is opened, it adds the new sub-items to itself using the
40 addSubItem method. Depending on the nature of the item it might choose to only
41 do this the first time it's opened, or it might want to refresh itself each time.
42 It also has the option of deleting its sub-items when it is closed, or leaving them
43 in place.
45 @tags{GUI}
47 class JUCE_API TreeViewItem
49 public:
50 //==============================================================================
51 /** Constructor. */
52 TreeViewItem();
54 /** Destructor. */
55 virtual ~TreeViewItem();
57 //==============================================================================
58 /** Returns the number of sub-items that have been added to this item.
59 Note that this doesn't mean much if the node isn't open.
61 @see getSubItem, mightContainSubItems, addSubItem
63 int getNumSubItems() const noexcept;
65 /** Returns one of the item's sub-items.
66 Remember that the object returned might get deleted at any time when its parent
67 item is closed or refreshed, depending on the nature of the items you're using.
69 @see getNumSubItems
71 TreeViewItem* getSubItem (int index) const noexcept;
73 /** Removes any sub-items. */
74 void clearSubItems();
76 /** Adds a sub-item.
78 @param newItem the object to add to the item's sub-item list. Once added, these can be
79 found using getSubItem(). When the items are later removed with
80 removeSubItem() (or when this item is deleted), they will be deleted.
81 @param insertPosition the index which the new item should have when it's added. If this
82 value is less than 0, the item will be added to the end of the list.
84 void addSubItem (TreeViewItem* newItem, int insertPosition = -1);
86 /** Adds a sub-item with a sort-comparator, assuming that the existing items are already sorted.
88 @param comparator the comparator object for sorting - see sortSubItems() for details about
89 the methods this class must provide.
90 @param newItem the object to add to the item's sub-item list. Once added, these can be
91 found using getSubItem(). When the items are later removed with
92 removeSubItem() (or when this item is deleted), they will be deleted.
94 template <class ElementComparator>
95 void addSubItemSorted (ElementComparator& comparator, TreeViewItem* newItem)
97 addSubItem (newItem, findInsertIndexInSortedArray (comparator, subItems.begin(), newItem, 0, subItems.size()));
100 /** Removes one of the sub-items.
102 @param index the item to remove
103 @param deleteItem if true, the item that is removed will also be deleted.
105 void removeSubItem (int index, bool deleteItem = true);
107 /** Sorts the list of sub-items using a standard array comparator.
109 This will use a comparator object to sort the elements into order. The comparator
110 object must have a method of the form:
111 @code
112 int compareElements (TreeViewItem* first, TreeViewItem* second);
113 @endcode
115 ..and this method must return:
116 - a value of < 0 if the first comes before the second
117 - a value of 0 if the two objects are equivalent
118 - a value of > 0 if the second comes before the first
120 To improve performance, the compareElements() method can be declared as static or const.
122 template <class ElementComparator>
123 void sortSubItems (ElementComparator& comparator)
125 subItems.sort (comparator);
128 //==============================================================================
129 /** Returns the TreeView to which this item belongs. */
130 TreeView* getOwnerView() const noexcept { return ownerView; }
132 /** Returns the item within which this item is contained. */
133 TreeViewItem* getParentItem() const noexcept { return parentItem; }
135 //==============================================================================
136 /** True if this item is currently open in the TreeView.
138 @see getOpenness
140 bool isOpen() const noexcept;
142 /** Opens or closes the item.
144 When opened or closed, the item's itemOpennessChanged() method will be called,
145 and a subclass should use this callback to create and add any sub-items that
146 it needs to.
148 Note that if this is called when the item is in its default openness state, and
149 this call would not change whether it's open or closed, then no change will be
150 stored. If you want to explicitly set the openness state to be non-default then
151 you should use setOpenness instead.
153 @see setOpenness, itemOpennessChanged, mightContainSubItems
155 void setOpen (bool shouldBeOpen);
157 /** An enum of states to describe the explicit or implicit openness of an item. */
158 enum class Openness
160 opennessDefault,
161 opennessClosed,
162 opennessOpen
165 /** Returns the openness state of this item.
167 @see isOpen
169 Openness getOpenness() const noexcept;
171 /** Opens or closes the item.
173 If this causes the value of isOpen() to change, then the item's itemOpennessChanged()
174 method will be called, and a subclass should use this callback to create and add any
175 sub-items that it needs to.
177 @see setOpen
179 void setOpenness (Openness newOpenness);
181 /** True if this item is currently selected.
183 Use this when painting the node, to decide whether to draw it as selected or not.
185 bool isSelected() const noexcept;
187 /** Selects or deselects the item.
189 If shouldNotify == sendNotification, then a callback will be made
190 to itemSelectionChanged() if the item's selection has changed.
192 void setSelected (bool shouldBeSelected,
193 bool deselectOtherItemsFirst,
194 NotificationType shouldNotify = sendNotification);
196 /** Returns the rectangle that this item occupies.
198 If relativeToTreeViewTopLeft is true, the coordinates are relative to the
199 top-left of the TreeView comp, so this will depend on the scroll-position of
200 the tree. If false, it is relative to the top-left of the topmost item in the
201 tree (so this would be unaffected by scrolling the view).
203 Rectangle<int> getItemPosition (bool relativeToTreeViewTopLeft) const noexcept;
205 /** Sends a signal to the TreeView to make it refresh itself.
207 Call this if your items have changed and you want the tree to update to reflect this.
209 void treeHasChanged() const noexcept;
211 /** Sends a repaint message to redraw just this item.
213 Note that you should only call this if you want to repaint a superficial change. If
214 you're altering the tree's nodes, you should instead call treeHasChanged().
216 void repaintItem() const;
218 /** Returns the row number of this item in the tree.
220 The row number of an item will change according to which items are open.
222 @see TreeView::getNumRowsInTree(), TreeView::getItemOnRow()
224 int getRowNumberInTree() const noexcept;
226 /** Returns true if all the item's parent nodes are open.
228 This is useful to check whether the item might actually be visible or not.
230 bool areAllParentsOpen() const noexcept;
232 /** Changes whether lines are drawn to connect any sub-items to this item.
234 By default, line-drawing is turned on according to LookAndFeel::areLinesDrawnForTreeView().
236 void setLinesDrawnForSubItems (bool shouldDrawLines) noexcept;
238 //==============================================================================
239 /** Tells the tree whether this item can potentially be opened.
241 If your item could contain sub-items, this should return true; if it returns
242 false then the tree will not try to open the item. This determines whether or
243 not the item will be drawn with a 'plus' button next to it.
245 virtual bool mightContainSubItems() = 0;
247 /** Returns a string to uniquely identify this item.
249 If you're planning on using the TreeView::getOpennessState() method, then
250 these strings will be used to identify which nodes are open. The string
251 should be unique amongst the item's sibling items, but it's ok for there
252 to be duplicates at other levels of the tree.
254 If you're not going to store the state, then it's ok not to bother implementing
255 this method.
257 virtual String getUniqueName() const;
259 /** Called when an item is opened or closed.
261 When setOpen() is called and the item has specified that it might
262 have sub-items with the mightContainSubItems() method, this method
263 is called to let the item create or manage its sub-items.
265 So when this is called with isNowOpen set to true (i.e. when the item is being
266 opened), a subclass might choose to use clearSubItems() and addSubItem() to
267 refresh its sub-item list.
269 When this is called with isNowOpen set to false, the subclass might want
270 to use clearSubItems() to save on space, or it might choose to leave them,
271 depending on the nature of the tree.
273 You could also use this callback as a trigger to start a background process
274 which asynchronously creates sub-items and adds them, if that's more
275 appropriate for the task in hand.
277 @see mightContainSubItems
279 virtual void itemOpennessChanged (bool isNowOpen);
281 /** Must return the width required by this item.
283 If your item needs to have a particular width in pixels, return that value; if
284 you'd rather have it just fill whatever space is available in the TreeView,
285 return -1.
287 If all your items return -1, no horizontal scrollbar will be shown, but if any
288 items have fixed widths and extend beyond the width of the TreeView, a
289 scrollbar will appear.
291 Each item can be a different width, but if they change width, you should call
292 treeHasChanged() to update the tree.
294 virtual int getItemWidth() const { return -1; }
296 /** Must return the height required by this item.
298 This is the height in pixels that the item will take up. Items in the tree
299 can be different heights, but if they change height, you should call
300 treeHasChanged() to update the tree.
302 virtual int getItemHeight() const { return 20; }
304 /** You can override this method to return false if you don't want to allow the
305 user to select this item.
307 virtual bool canBeSelected() const { return true; }
309 /** Creates a component that will be used to represent this item.
311 You don't have to implement this method - if it returns nullptr then no component
312 will be used for the item, and you can just draw it using the paintItem()
313 callback. But if you do return a component, it will be positioned in the
314 TreeView so that it can be used to represent this item.
316 The component returned will be managed by the TreeView and will be deleted
317 later when it goes off the screen or is no longer needed. Its position and
318 size will be completely managed by the tree, so don't attempt to move it around.
320 Something you may want to do with your component is to give it a pointer to
321 the TreeView that created it. This is perfectly safe, and there's no danger
322 of it becoming a dangling pointer because the TreeView will always delete
323 the component before it is itself deleted.
325 As long as you stick to these rules you can return whatever kind of
326 component you like. It's most useful if you're doing things like drag-and-drop
327 of items, or want to use a Label component to edit item names, etc.
329 virtual std::unique_ptr<Component> createItemComponent() { return nullptr; }
331 //==============================================================================
332 /** Draws the item's contents.
334 You can choose to either implement this method and draw each item, or you
335 can use createItemComponent() to create a component that will represent the
336 item.
338 If all you need in your tree is to be able to draw the items and detect when
339 the user selects or double-clicks one of them, it's probably enough to
340 use paintItem(), itemClicked() and itemDoubleClicked(). If you need more
341 complicated interactions, you may need to use createItemComponent() instead.
343 @param g the graphics context to draw into
344 @param width the width of the area available for drawing
345 @param height the height of the area available for drawing
347 virtual void paintItem (Graphics& g, int width, int height);
349 /** Draws the item's open/close button.
351 If you don't implement this method, the default behaviour is to call
352 LookAndFeel::drawTreeviewPlusMinusBox(), but you can override it for custom
353 effects. You may want to override it and call the base-class implementation
354 with a different backgroundColour parameter, if your implementation has a
355 background colour other than the default (white).
357 virtual void paintOpenCloseButton (Graphics&, const Rectangle<float>& area,
358 Colour backgroundColour, bool isMouseOver);
360 /** Draws the line that connects this item to the vertical line extending below its parent. */
361 virtual void paintHorizontalConnectingLine (Graphics&, const Line<float>& line);
363 /** Draws the line that extends vertically up towards one of its parents, or down to one of its children. */
364 virtual void paintVerticalConnectingLine (Graphics&, const Line<float>& line);
366 /** This should return true if you want to use a custom component, and also use
367 the TreeView's built-in mouse handling support, enabling drag-and-drop,
368 itemClicked() and itemDoubleClicked(); return false if the component should
369 consume all mouse clicks.
371 virtual bool customComponentUsesTreeViewMouseHandler() const { return false; }
373 /** Called when the user clicks on this item.
375 If you're using createItemComponent() to create a custom component for the
376 item, the mouse-clicks might not make it through to the TreeView, but this
377 is how you find out about clicks when just drawing each item individually.
379 The associated mouse-event details are passed in, so you can find out about
380 which button, where it was, etc.
382 @see itemDoubleClicked
384 virtual void itemClicked (const MouseEvent&);
386 /** Called when the user double-clicks on this item.
388 If you're using createItemComponent() to create a custom component for the
389 item, the mouse-clicks might not make it through to the TreeView, but this
390 is how you find out about clicks when just drawing each item individually.
392 The associated mouse-event details are passed in, so you can find out about
393 which button, where it was, etc.
395 If not overridden, the base class method here will open or close the item as
396 if the 'plus' button had been clicked.
398 @see itemClicked
400 virtual void itemDoubleClicked (const MouseEvent&);
402 /** Called when the item is selected or deselected.
404 Use this if you want to do something special when the item's selectedness
405 changes. By default it'll get repainted when this happens.
407 virtual void itemSelectionChanged (bool isNowSelected);
409 /** Called when the owner view changes */
410 virtual void ownerViewChanged (TreeView* newOwner);
412 /** The item can return a tool tip string here if it wants to.
414 @see TooltipClient
416 virtual String getTooltip();
418 /** Use this to set the name for this item that will be read out by accessibility
419 clients.
421 The default implementation will return the tooltip string from getTooltip()
422 if it is not empty, otherwise it will return a description of the nested level
423 and row number of the item.
425 @see AccessibilityHandler
427 virtual String getAccessibilityName();
429 //==============================================================================
430 /** To allow items from your TreeView to be dragged-and-dropped, implement this method.
432 If this returns a non-null variant then when the user drags an item, the TreeView will
433 try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
434 a drag-and-drop operation, using this string as the source description, with the TreeView
435 itself as the source component.
437 If you need more complex drag-and-drop behaviour, you can use custom components for
438 the items, and use those to trigger the drag.
440 To accept drag-and-drop in your tree, see isInterestedInDragSource(),
441 isInterestedInFileDrag(), etc.
443 @see DragAndDropContainer::startDragging
445 virtual var getDragSourceDescription();
447 /** If you want your item to be able to have files drag-and-dropped onto it, implement this
448 method and return true.
450 If you return true and allow some files to be dropped, you'll also need to implement the
451 filesDropped() method to do something with them.
453 Note that this will be called often, so make your implementation very quick! There's
454 certainly no time to try opening the files and having a think about what's inside them!
456 For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource().
458 @see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource
460 virtual bool isInterestedInFileDrag (const StringArray& files);
462 /** When files are dropped into this item, this callback is invoked.
464 For this to work, you'll need to have also implemented isInterestedInFileDrag().
465 The insertIndex value indicates where in the list of sub-items the files were dropped.
466 If files are dropped onto an area of the tree where there are no visible items, this
467 method is called on the root item of the tree, with an insert index of 0.
469 @see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag
471 virtual void filesDropped (const StringArray& files, int insertIndex);
473 /** If you want your item to act as a DragAndDropTarget, implement this method and return true.
475 If you implement this method, you'll also need to implement itemDropped() in order to handle
476 the items when they are dropped.
477 To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag().
479 @see DragAndDropTarget::isInterestedInDragSource, itemDropped
481 virtual bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails);
483 /** When a things are dropped into this item, this callback is invoked.
485 For this to work, you need to have also implemented isInterestedInDragSource().
486 The insertIndex value indicates where in the list of sub-items the new items should be placed.
487 If files are dropped onto an area of the tree where there are no visible items, this
488 method is called on the root item of the tree, with an insert index of 0.
490 @see isInterestedInDragSource, DragAndDropTarget::itemDropped
492 virtual void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex);
494 //==============================================================================
495 /** Sets a flag to indicate that the item wants to be allowed
496 to draw all the way across to the left edge of the TreeView.
498 By default this is false, which means that when the paintItem()
499 method is called, its graphics context is clipped to only allow
500 drawing within the item's rectangle. If this flag is set to true,
501 then the graphics context isn't clipped on its left side, so it
502 can draw all the way across to the left margin. Note that the
503 context will still have its origin in the same place though, so
504 the coordinates of anything to its left will be negative. It's
505 mostly useful if you want to draw a wider bar behind the
506 highlighted item.
508 void setDrawsInLeftMargin (bool canDrawInLeftMargin) noexcept;
510 /** Sets a flag to indicate that the item wants to be allowed
511 to draw all the way across to the right edge of the TreeView.
513 Similar to setDrawsInLeftMargin: when this flag is set to true,
514 then the graphics context isn't clipped on the right side. Unlike
515 setDrawsInLeftMargin, you will very rarely need to use this function,
516 as this method won't clip the right margin unless your TreeViewItem
517 overrides getItemWidth to return a positive value.
519 @see setDrawsInLeftMargin, getItemWidth
521 void setDrawsInRightMargin (bool canDrawInRightMargin) noexcept;
523 //==============================================================================
524 /** Saves the current state of open/closed nodes so it can be restored later.
526 This takes a snapshot of which sub-nodes have been explicitly opened or closed,
527 and records it as XML. To identify node objects it uses the
528 TreeViewItem::getUniqueName() method to create named paths. This
529 means that the same state of open/closed nodes can be restored to a
530 completely different instance of the tree, as long as it contains nodes
531 whose unique names are the same.
533 You'd normally want to use TreeView::getOpennessState() rather than call it
534 for a specific item, but this can be handy if you need to briefly save the state
535 for a section of the tree.
537 Note that if all nodes of the tree are in their default state, then this may
538 return a nullptr.
540 @see TreeView::getOpennessState, restoreOpennessState
542 std::unique_ptr<XmlElement> getOpennessState() const;
544 /** Restores the openness of this item and all its sub-items from a saved state.
546 See TreeView::restoreOpennessState for more details.
548 You'd normally want to use TreeView::restoreOpennessState() rather than call it
549 for a specific item, but this can be handy if you need to briefly save the state
550 for a section of the tree.
552 @see TreeView::restoreOpennessState, getOpennessState
554 void restoreOpennessState (const XmlElement& xml);
556 //==============================================================================
557 /** Returns the index of this item in its parent's sub-items. */
558 int getIndexInParent() const noexcept;
560 /** Returns true if this item is the last of its parent's sub-items. */
561 bool isLastOfSiblings() const noexcept;
563 /** Creates a string that can be used to uniquely retrieve this item in the tree.
565 The string that is returned can be passed to TreeView::findItemFromIdentifierString().
566 The string takes the form of a path, constructed from the getUniqueName() of this
567 item and all its parents, so these must all be correctly implemented for it to work.
569 @see TreeView::findItemFromIdentifierString, getUniqueName
571 String getItemIdentifierString() const;
573 //==============================================================================
575 This handy class takes a copy of a TreeViewItem's openness when you create it,
576 and restores that openness state when its destructor is called.
578 This can very handy when you're refreshing sub-items - e.g.
579 @code
580 void MyTreeViewItem::updateChildItems()
582 OpennessRestorer openness (*this); // saves the openness state here..
584 clearSubItems();
586 // add a bunch of sub-items here which may or may not be the same as the ones that
587 // were previously there
588 addSubItem (...
590 // ..and at this point, the old openness is restored, so any items that haven't
591 // changed will have their old openness retained.
593 @endcode
595 class JUCE_API OpennessRestorer
597 public:
598 OpennessRestorer (TreeViewItem&);
599 ~OpennessRestorer();
601 private:
602 TreeViewItem& treeViewItem;
603 std::unique_ptr<XmlElement> oldOpenness;
605 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpennessRestorer)
608 private:
609 //==============================================================================
610 friend class TreeView;
612 void updatePositions (int);
613 int getIndentX() const noexcept;
614 void setOwnerView (TreeView*) noexcept;
615 TreeViewItem* getTopLevelItem() noexcept;
616 TreeViewItem* getDeepestOpenParentItem() noexcept;
617 int getNumRows() const noexcept;
618 TreeViewItem* getItemOnRow (int) noexcept;
619 void deselectAllRecursively (TreeViewItem*);
620 int countSelectedItemsRecursively (int) const noexcept;
621 TreeViewItem* getSelectedItemWithIndex (int) noexcept;
622 TreeViewItem* findItemFromIdentifierString (const String&);
623 void restoreToDefaultOpenness();
624 bool isFullyOpen() const noexcept;
625 std::unique_ptr<XmlElement> getOpennessState (bool) const;
626 bool removeSubItemFromList (int, bool);
627 void removeAllSubItemsFromList();
628 bool areLinesDrawn() const;
629 void draw (Graphics&, int, bool);
631 //==============================================================================
632 TreeView* ownerView = nullptr;
633 TreeViewItem* parentItem = nullptr;
634 OwnedArray<TreeViewItem> subItems;
636 Openness openness = Openness::opennessDefault;
637 int y = 0, itemHeight = 0, totalHeight = 0, itemWidth = 0, totalWidth = 0, uid = 0;
638 bool selected = false, redrawNeeded = true, drawLinesInside = false, drawLinesSet = false,
639 drawsInLeftMargin = false, drawsInRightMargin = false;
641 //==============================================================================
642 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewItem)
645 //==============================================================================
647 A tree-view component.
649 Use one of these to hold and display a structure of TreeViewItem objects.
651 @tags{GUI}
653 class JUCE_API TreeView : public Component,
654 public SettableTooltipClient,
655 public FileDragAndDropTarget,
656 public DragAndDropTarget
658 public:
659 //==============================================================================
660 /** Creates an empty TreeView.
662 Once you've got a TreeView component, you'll need to give it something to
663 display, using the setRootItem() method.
665 TreeView (const String& componentName = {});
667 /** Destructor. */
668 ~TreeView() override;
670 //==============================================================================
671 /** Sets the item that is displayed in the TreeView.
673 A tree has a single root item which contains as many sub-items as it needs. If
674 you want the tree to contain a number of root items, you should still use a single
675 root item above these, but hide it using setRootItemVisible().
677 You can pass nullptr to this method to clear the tree and remove its current root item.
679 The object passed in will not be deleted by the TreeView, it's up to the caller
680 to delete it when no longer needed. BUT make absolutely sure that you don't delete
681 this item until you've removed it from the tree, either by calling setRootItem (nullptr),
682 or by deleting the tree first. You can also use deleteRootItem() as a quick way
683 to delete it.
685 void setRootItem (TreeViewItem* newRootItem);
687 /** Returns the tree's root item.
689 This will be the last object passed to setRootItem(), or nullptr if none has been set.
691 TreeViewItem* getRootItem() const noexcept { return rootItem; }
693 /** This will remove and delete the current root item.
695 It's a convenient way of deleting the item and calling setRootItem (nullptr).
697 void deleteRootItem();
699 /** Changes whether the tree's root item is shown or not.
701 If the root item is hidden, only its sub-items will be shown in the TreeView - this
702 lets you make the tree look as if it's got many root items. If it's hidden, this call
703 will also make sure the root item is open (otherwise the TreeView would look empty).
705 void setRootItemVisible (bool shouldBeVisible);
707 /** Returns true if the root item is visible.
709 @see setRootItemVisible
711 bool isRootItemVisible() const noexcept { return rootItemVisible; }
713 /** Sets whether items are open or closed by default.
715 Normally, items are closed until the user opens them, but you can use this
716 to make them default to being open until explicitly closed.
718 @see areItemsOpenByDefault
720 void setDefaultOpenness (bool isOpenByDefault);
722 /** Returns true if the tree's items default to being open.
724 @see setDefaultOpenness
726 bool areItemsOpenByDefault() const noexcept { return defaultOpenness; }
728 /** This sets a flag to indicate that the tree can be used for multi-selection.
730 You can always select multiple items internally by calling the
731 TreeViewItem::setSelected() method, but this flag indicates whether the user
732 is allowed to multi-select by clicking on the tree.
734 By default it is disabled.
736 @see isMultiSelectEnabled
738 void setMultiSelectEnabled (bool canMultiSelect);
740 /** Returns whether multi-select has been enabled for the tree.
742 @see setMultiSelectEnabled
744 bool isMultiSelectEnabled() const noexcept { return multiSelectEnabled; }
746 /** Sets a flag to indicate whether to hide the open/close buttons.
748 @see areOpenCloseButtonsVisible
750 void setOpenCloseButtonsVisible (bool shouldBeVisible);
752 /** Returns whether open/close buttons are shown.
754 @see setOpenCloseButtonsVisible
756 bool areOpenCloseButtonsVisible() const noexcept { return openCloseButtonsVisible; }
758 //==============================================================================
759 /** Deselects any items that are currently selected. */
760 void clearSelectedItems();
762 /** Returns the number of items that are currently selected.
764 If maximumDepthToSearchTo is >= 0, it lets you specify a maximum depth to which the
765 tree will be recursed.
767 @see getSelectedItem, clearSelectedItems
769 int getNumSelectedItems (int maximumDepthToSearchTo = -1) const noexcept;
771 /** Returns one of the selected items in the tree.
773 @param index the index, 0 to (getNumSelectedItems() - 1)
775 TreeViewItem* getSelectedItem (int index) const noexcept;
777 /** Moves the selected row up or down by the specified number of rows. */
778 void moveSelectedRow (int deltaRows);
780 //==============================================================================
781 /** Returns the number of rows the tree is using, depending on which items are open.
783 @see TreeViewItem::getRowNumberInTree()
785 int getNumRowsInTree() const;
787 /** Returns the item on a particular row of the tree.
789 If the index is out of range, this will return nullptr.
791 @see getNumRowsInTree, TreeViewItem::getRowNumberInTree()
793 TreeViewItem* getItemOnRow (int index) const;
795 /** Returns the item that contains a given y-position relative to the top
796 of the TreeView component.
798 TreeViewItem* getItemAt (int yPosition) const noexcept;
800 /** Tries to scroll the tree so that this item is on-screen somewhere. */
801 void scrollToKeepItemVisible (TreeViewItem* item);
803 /** Returns the TreeView's Viewport object. */
804 Viewport* getViewport() const noexcept;
806 /** Returns the number of pixels by which each nested level of the tree is indented.
808 @see setIndentSize
810 int getIndentSize() noexcept;
812 /** Changes the distance by which each nested level of the tree is indented.
814 @see getIndentSize
816 void setIndentSize (int newIndentSize);
818 /** Searches the tree for an item with the specified identifier.
820 The identifier string must have been created by calling TreeViewItem::getItemIdentifierString().
821 If no such item exists, this will return false. If the item is found, all of its items
822 will be automatically opened.
824 TreeViewItem* findItemFromIdentifierString (const String& identifierString) const;
826 /** Returns the component that currently represents a given TreeViewItem. */
827 Component* getItemComponent (const TreeViewItem* item) const;
829 //==============================================================================
830 /** Saves the current state of open/closed nodes so it can be restored later.
832 This takes a snapshot of which nodes have been explicitly opened or closed,
833 and records it as XML. To identify node objects it uses the
834 TreeViewItem::getUniqueName() method to create named paths. This
835 means that the same state of open/closed nodes can be restored to a
836 completely different instance of the tree, as long as it contains nodes
837 whose unique names are the same.
839 @param alsoIncludeScrollPosition if this is true, the state will also
840 include information about where the
841 tree has been scrolled to vertically,
842 so this can also be restored
843 @see restoreOpennessState
845 std::unique_ptr<XmlElement> getOpennessState (bool alsoIncludeScrollPosition) const;
847 /** Restores a previously saved arrangement of open/closed nodes.
849 This will try to restore a snapshot of the tree's state that was created by
850 the getOpennessState() method. If any of the nodes named in the original
851 XML aren't present in this tree, they will be ignored.
853 If restoreStoredSelection is true, it will also try to re-select any items that
854 were selected in the stored state.
856 @see getOpennessState
858 void restoreOpennessState (const XmlElement& newState, bool restoreStoredSelection);
860 //==============================================================================
861 /** A set of colour IDs to use to change the colour of various aspects of the TreeView.
863 These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
864 methods.
866 @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
868 enum ColourIds
870 backgroundColourId = 0x1000500, /**< A background colour to fill the component with. */
871 linesColourId = 0x1000501, /**< The colour to draw the lines with.*/
872 dragAndDropIndicatorColourId = 0x1000502, /**< The colour to use for the drag-and-drop target position indicator. */
873 selectedItemBackgroundColourId = 0x1000503, /**< The colour to use to fill the background of any selected items. */
874 oddItemsColourId = 0x1000504, /**< The colour to use to fill the background of the odd numbered items. */
875 evenItemsColourId = 0x1000505 /**< The colour to use to fill the background of the even numbered items. */
878 //==============================================================================
879 /** This abstract base class is implemented by LookAndFeel classes to provide
880 TreeView drawing functionality.
882 struct JUCE_API LookAndFeelMethods
884 virtual ~LookAndFeelMethods() = default;
886 virtual void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area,
887 Colour backgroundColour, bool isItemOpen, bool isMouseOver) = 0;
889 virtual bool areLinesDrawnForTreeView (TreeView&) = 0;
890 virtual int getTreeViewIndentSize (TreeView&) = 0;
893 //==============================================================================
894 /** @internal */
895 void paint (Graphics&) override;
896 /** @internal */
897 void resized() override;
898 /** @internal */
899 bool keyPressed (const KeyPress&) override;
900 /** @internal */
901 void colourChanged() override;
902 /** @internal */
903 void enablementChanged() override;
904 /** @internal */
905 bool isInterestedInFileDrag (const StringArray&) override;
906 /** @internal */
907 void fileDragEnter (const StringArray&, int, int) override;
908 /** @internal */
909 void fileDragMove (const StringArray&, int, int) override;
910 /** @internal */
911 void fileDragExit (const StringArray&) override;
912 /** @internal */
913 void filesDropped (const StringArray&, int, int) override;
914 /** @internal */
915 bool isInterestedInDragSource (const SourceDetails&) override;
916 /** @internal */
917 void itemDragEnter (const SourceDetails&) override;
918 /** @internal */
919 void itemDragMove (const SourceDetails&) override;
920 /** @internal */
921 void itemDragExit (const SourceDetails&) override;
922 /** @internal */
923 void itemDropped (const SourceDetails&) override;
925 private:
926 friend class TreeViewItem;
928 class ItemComponent;
929 class ContentComponent;
930 class TreeViewport;
931 class InsertPointHighlight;
932 class TargetGroupHighlight;
933 class TreeAccessibilityHandler;
934 struct InsertPoint;
936 std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
937 void itemsChanged() noexcept;
938 void updateVisibleItems();
939 void updateButtonUnderMouse (const MouseEvent&);
940 void showDragHighlight (const InsertPoint&) noexcept;
941 void hideDragHighlight() noexcept;
942 void handleDrag (const StringArray&, const SourceDetails&);
943 void handleDrop (const StringArray&, const SourceDetails&);
944 bool toggleOpenSelectedItem();
945 void moveOutOfSelectedItem();
946 void moveIntoSelectedItem();
947 void moveByPages (int);
949 std::unique_ptr<TreeViewport> viewport;
950 TreeViewItem* rootItem = nullptr;
951 std::unique_ptr<InsertPointHighlight> dragInsertPointHighlight;
952 std::unique_ptr<TargetGroupHighlight> dragTargetGroupHighlight;
953 int indentSize = -1;
954 bool defaultOpenness = false, rootItemVisible = true, multiSelectEnabled = false, openCloseButtonsVisible = true;
956 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView)
959 } // namespace juce