The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

266 lines
8.0KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2015 - ROLI Ltd.
  5. Permission is granted to use this software under the terms of either:
  6. a) the GPL v2 (or any later version)
  7. b) the Affero GPL v3
  8. Details of these licenses can be found at: www.gnu.org/licenses
  9. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  10. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  11. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  12. ------------------------------------------------------------------------------
  13. To release a closed-source product which uses JUCE, commercial licenses are
  14. available: visit www.juce.com for more information.
  15. ==============================================================================
  16. */
  17. #include "../jucer_Headers.h"
  18. #include "jucer_JucerTreeViewBase.h"
  19. #include "../Project/jucer_ProjectContentComponent.h"
  20. //==============================================================================
  21. void TreePanelBase::setRoot (JucerTreeViewBase* root)
  22. {
  23. rootItem = root;
  24. tree.setRootItem (root);
  25. tree.getRootItem()->setOpen (true);
  26. if (project != nullptr)
  27. {
  28. const ScopedPointer<XmlElement> treeOpenness (project->getStoredProperties()
  29. .getXmlValue (opennessStateKey));
  30. if (treeOpenness != nullptr)
  31. {
  32. tree.restoreOpennessState (*treeOpenness, true);
  33. for (int i = tree.getNumSelectedItems(); --i >= 0;)
  34. if (JucerTreeViewBase* item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)))
  35. item->cancelDelayedSelectionTimer();
  36. }
  37. }
  38. }
  39. void TreePanelBase::saveOpenness()
  40. {
  41. if (project != nullptr)
  42. {
  43. const ScopedPointer<XmlElement> opennessState (tree.getOpennessState (true));
  44. if (opennessState != nullptr)
  45. project->getStoredProperties().setValue (opennessStateKey, opennessState);
  46. else
  47. project->getStoredProperties().removeValue (opennessStateKey);
  48. }
  49. }
  50. //==============================================================================
  51. JucerTreeViewBase::JucerTreeViewBase() : textX (0)
  52. {
  53. setLinesDrawnForSubItems (false);
  54. }
  55. JucerTreeViewBase::~JucerTreeViewBase()
  56. {
  57. masterReference.clear();
  58. }
  59. void JucerTreeViewBase::refreshSubItems()
  60. {
  61. WholeTreeOpennessRestorer wtor (*this);
  62. clearSubItems();
  63. addSubItems();
  64. }
  65. Font JucerTreeViewBase::getFont() const
  66. {
  67. return Font (getItemHeight() * 0.6f);
  68. }
  69. void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour /*backgroundColour*/, bool isMouseOver)
  70. {
  71. TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (mainBackgroundColourId), isMouseOver);
  72. }
  73. Colour JucerTreeViewBase::getBackgroundColour() const
  74. {
  75. Colour background (getOwnerView()->findColour (mainBackgroundColourId));
  76. if (isSelected())
  77. background = background.overlaidWith (getOwnerView()->findColour (TreeView::selectedItemBackgroundColourId));
  78. return background;
  79. }
  80. Colour JucerTreeViewBase::getContrastingColour (float contrast) const
  81. {
  82. return getBackgroundColour().contrasting (contrast);
  83. }
  84. Colour JucerTreeViewBase::getContrastingColour (Colour target, float minContrast) const
  85. {
  86. return getBackgroundColour().contrasting (target, minContrast);
  87. }
  88. void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle<int>& area)
  89. {
  90. g.setFont (getFont());
  91. g.setColour (isMissing() ? getContrastingColour (Colours::red, 0.8f)
  92. : getContrastingColour (0.8f));
  93. g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 0.8f);
  94. }
  95. Component* JucerTreeViewBase::createItemComponent()
  96. {
  97. return new TreeItemComponent (*this);
  98. }
  99. //==============================================================================
  100. class RenameTreeItemCallback : public ModalComponentManager::Callback,
  101. public TextEditorListener
  102. {
  103. public:
  104. RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
  105. : item (ti)
  106. {
  107. ed.setMultiLine (false, false);
  108. ed.setPopupMenuEnabled (false);
  109. ed.setSelectAllWhenFocused (true);
  110. ed.setFont (item.getFont());
  111. ed.addListener (this);
  112. ed.setText (item.getRenamingName());
  113. ed.setBounds (bounds);
  114. parent.addAndMakeVisible (ed);
  115. ed.enterModalState (true, this);
  116. }
  117. void modalStateFinished (int resultCode) override
  118. {
  119. if (resultCode != 0)
  120. item.setName (ed.getText());
  121. }
  122. void textEditorTextChanged (TextEditor&) override {}
  123. void textEditorReturnKeyPressed (TextEditor& editor) override { editor.exitModalState (1); }
  124. void textEditorEscapeKeyPressed (TextEditor& editor) override { editor.exitModalState (0); }
  125. void textEditorFocusLost (TextEditor& editor) override { editor.exitModalState (0); }
  126. private:
  127. struct RenameEditor : public TextEditor
  128. {
  129. void inputAttemptWhenModal() override { exitModalState (0); }
  130. };
  131. RenameEditor ed;
  132. JucerTreeViewBase& item;
  133. JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
  134. };
  135. void JucerTreeViewBase::showRenameBox()
  136. {
  137. Rectangle<int> r (getItemPosition (true));
  138. r.setLeft (r.getX() + textX);
  139. r.setHeight (getItemHeight());
  140. new RenameTreeItemCallback (*this, *getOwnerView(), r);
  141. }
  142. void JucerTreeViewBase::itemClicked (const MouseEvent& e)
  143. {
  144. if (e.mods.isPopupMenu())
  145. {
  146. if (getOwnerView()->getNumSelectedItems() > 1)
  147. showMultiSelectionPopupMenu();
  148. else
  149. showPopupMenu();
  150. }
  151. else if (isSelected())
  152. {
  153. itemSelectionChanged (true);
  154. }
  155. }
  156. void JucerTreeViewBase::deleteItem() {}
  157. void JucerTreeViewBase::deleteAllSelectedItems() {}
  158. void JucerTreeViewBase::showDocument() {}
  159. void JucerTreeViewBase::showPopupMenu() {}
  160. void JucerTreeViewBase::showMultiSelectionPopupMenu() {}
  161. static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
  162. {
  163. if (item != nullptr)
  164. item->handlePopupMenuResult (resultCode);
  165. }
  166. void JucerTreeViewBase::launchPopupMenu (PopupMenu& m)
  167. {
  168. m.showMenuAsync (PopupMenu::Options(),
  169. ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
  170. }
  171. void JucerTreeViewBase::handlePopupMenuResult (int)
  172. {
  173. }
  174. ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
  175. {
  176. for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
  177. if (ProjectContentComponent* pcc = dynamic_cast<ProjectContentComponent*> (c))
  178. return pcc;
  179. return nullptr;
  180. }
  181. //==============================================================================
  182. class JucerTreeViewBase::ItemSelectionTimer : public Timer
  183. {
  184. public:
  185. ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
  186. void timerCallback() override { owner.invokeShowDocument(); }
  187. private:
  188. JucerTreeViewBase& owner;
  189. JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
  190. };
  191. void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
  192. {
  193. if (isNowSelected)
  194. {
  195. delayedSelectionTimer = new ItemSelectionTimer (*this);
  196. delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
  197. }
  198. else
  199. {
  200. cancelDelayedSelectionTimer();
  201. }
  202. }
  203. void JucerTreeViewBase::invokeShowDocument()
  204. {
  205. cancelDelayedSelectionTimer();
  206. showDocument();
  207. }
  208. void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
  209. {
  210. invokeShowDocument();
  211. }
  212. void JucerTreeViewBase::cancelDelayedSelectionTimer()
  213. {
  214. delayedSelectionTimer = nullptr;
  215. }