/* ============================================================================== This file is part of the JUCE library. Copyright (c) 2013 - Raw Material Software Ltd. Permission is granted to use this software under the terms of either: a) the GPL v2 (or any later version) b) the Affero GPL v3 Details of these licenses can be found at: www.gnu.org/licenses JUCE is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. ------------------------------------------------------------------------------ To release a closed-source product which uses JUCE, commercial licenses are available: visit www.juce.com for more information. ============================================================================== */ #include "jucer_JucerTreeViewBase.h" #include "../Project/jucer_ProjectContentComponent.h" //============================================================================== void TreePanelBase::setRoot (JucerTreeViewBase* root) { rootItem = root; tree.setRootItem (root); tree.getRootItem()->setOpen (true); if (project != nullptr) { const ScopedPointer treeOpenness (project->getStoredProperties() .getXmlValue (opennessStateKey)); if (treeOpenness != nullptr) { tree.restoreOpennessState (*treeOpenness, true); for (int i = tree.getNumSelectedItems(); --i >= 0;) if (JucerTreeViewBase* item = dynamic_cast (tree.getSelectedItem (i))) item->cancelDelayedSelectionTimer(); } } } void TreePanelBase::saveOpenness() { if (project != nullptr) { const ScopedPointer opennessState (tree.getOpennessState (true)); if (opennessState != nullptr) project->getStoredProperties().setValue (opennessStateKey, opennessState); else project->getStoredProperties().removeValue (opennessStateKey); } } //============================================================================== JucerTreeViewBase::JucerTreeViewBase() : textX (0) { setLinesDrawnForSubItems (false); } JucerTreeViewBase::~JucerTreeViewBase() { masterReference.clear(); } void JucerTreeViewBase::refreshSubItems() { WholeTreeOpennessRestorer wtor (*this); clearSubItems(); addSubItems(); } Font JucerTreeViewBase::getFont() const { return Font (getItemHeight() * 0.6f); } float JucerTreeViewBase::getIconSize() const { return jmin (getItemHeight() - 4.0f, 18.0f); } void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle& area, Colour /*backgroundColour*/, bool isMouseOver) { TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (mainBackgroundColourId), isMouseOver); } Colour JucerTreeViewBase::getBackgroundColour() const { Colour background (getOwnerView()->findColour (mainBackgroundColourId)); if (isSelected()) background = background.overlaidWith (getOwnerView()->findColour (TreeView::selectedItemBackgroundColourId)); return background; } Colour JucerTreeViewBase::getContrastingColour (float contrast) const { return getBackgroundColour().contrasting (contrast); } Colour JucerTreeViewBase::getContrastingColour (Colour target, float minContrast) const { return getBackgroundColour().contrasting (target, minContrast); } void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle& area) { g.setFont (getFont()); g.setColour (isMissing() ? getContrastingColour (Colours::red, 0.8f) : getContrastingColour (0.8f)); g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 0.8f); } Component* JucerTreeViewBase::createItemComponent() { return new TreeItemComponent (*this); } //============================================================================== class RenameTreeItemCallback : public ModalComponentManager::Callback, public TextEditorListener { public: RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle& bounds) : item (ti) { ed.setMultiLine (false, false); ed.setPopupMenuEnabled (false); ed.setSelectAllWhenFocused (true); ed.setFont (item.getFont()); ed.addListener (this); ed.setText (item.getRenamingName()); ed.setBounds (bounds); parent.addAndMakeVisible (ed); ed.enterModalState (true, this); } void modalStateFinished (int resultCode) override { if (resultCode != 0) item.setName (ed.getText()); } void textEditorTextChanged (TextEditor&) override {} void textEditorReturnKeyPressed (TextEditor& editor) override { editor.exitModalState (1); } void textEditorEscapeKeyPressed (TextEditor& editor) override { editor.exitModalState (0); } void textEditorFocusLost (TextEditor& editor) override { editor.exitModalState (0); } private: struct RenameEditor : public TextEditor { void inputAttemptWhenModal() override { exitModalState (0); } }; RenameEditor ed; JucerTreeViewBase& item; JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback) }; void JucerTreeViewBase::showRenameBox() { Rectangle r (getItemPosition (true)); r.setLeft (r.getX() + textX); r.setHeight (getItemHeight()); new RenameTreeItemCallback (*this, *getOwnerView(), r); } void JucerTreeViewBase::itemClicked (const MouseEvent& e) { if (e.mods.isPopupMenu()) { if (getOwnerView()->getNumSelectedItems() > 1) showMultiSelectionPopupMenu(); else showPopupMenu(); } } void JucerTreeViewBase::deleteItem() {} void JucerTreeViewBase::deleteAllSelectedItems() {} void JucerTreeViewBase::showDocument() {} void JucerTreeViewBase::showPopupMenu() {} void JucerTreeViewBase::showMultiSelectionPopupMenu() {} static void treeViewMenuItemChosen (int resultCode, WeakReference item) { if (item != nullptr) item->handlePopupMenuResult (resultCode); } void JucerTreeViewBase::launchPopupMenu (PopupMenu& m) { m.showMenuAsync (PopupMenu::Options(), ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference (this))); } void JucerTreeViewBase::handlePopupMenuResult (int) { } ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const { for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent()) if (ProjectContentComponent* pcc = dynamic_cast (c)) return pcc; return nullptr; } //============================================================================== class JucerTreeViewBase::ItemSelectionTimer : public Timer { public: ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {} void timerCallback() override { owner.invokeShowDocument(); } private: JucerTreeViewBase& owner; JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer) }; void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected) { if (isNowSelected) { delayedSelectionTimer = new ItemSelectionTimer (*this); delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture()); } else { cancelDelayedSelectionTimer(); } } void JucerTreeViewBase::invokeShowDocument() { cancelDelayedSelectionTimer(); showDocument(); } void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&) { invokeShowDocument(); } void JucerTreeViewBase::cancelDelayedSelectionTimer() { delayedSelectionTimer = nullptr; }