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.

276 lines
8.3KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2017 - ROLI Ltd.
  5. JUCE is an open source library subject to commercial or open-source
  6. licensing.
  7. By using JUCE, you agree to the terms of both the JUCE 5 End-User License
  8. Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
  9. 27th April 2017).
  10. End User License Agreement: www.juce.com/juce-5-licence
  11. Privacy Policy: www.juce.com/juce-5-privacy-policy
  12. Or: You may also use this code under the terms of the GPL v3 (see
  13. www.gnu.org/licenses).
  14. JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
  15. EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
  16. DISCLAIMED.
  17. ==============================================================================
  18. */
  19. #include "../jucer_Headers.h"
  20. #include "jucer_JucerTreeViewBase.h"
  21. #include "../Project/jucer_ProjectContentComponent.h"
  22. //==============================================================================
  23. void TreePanelBase::setRoot (JucerTreeViewBase* root)
  24. {
  25. rootItem = root;
  26. tree.setRootItem (root);
  27. tree.getRootItem()->setOpen (true);
  28. if (project != nullptr)
  29. {
  30. const ScopedPointer<XmlElement> treeOpenness (project->getStoredProperties()
  31. .getXmlValue (opennessStateKey));
  32. if (treeOpenness != nullptr)
  33. {
  34. tree.restoreOpennessState (*treeOpenness, true);
  35. for (int i = tree.getNumSelectedItems(); --i >= 0;)
  36. if (JucerTreeViewBase* item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)))
  37. item->cancelDelayedSelectionTimer();
  38. }
  39. }
  40. }
  41. void TreePanelBase::saveOpenness()
  42. {
  43. if (project != nullptr)
  44. {
  45. const ScopedPointer<XmlElement> opennessState (tree.getOpennessState (true));
  46. if (opennessState != nullptr)
  47. project->getStoredProperties().setValue (opennessStateKey, opennessState);
  48. else
  49. project->getStoredProperties().removeValue (opennessStateKey);
  50. }
  51. }
  52. //==============================================================================
  53. JucerTreeViewBase::JucerTreeViewBase() : textX (0)
  54. {
  55. setLinesDrawnForSubItems (false);
  56. setDrawsInLeftMargin (true);
  57. }
  58. JucerTreeViewBase::~JucerTreeViewBase()
  59. {
  60. masterReference.clear();
  61. }
  62. void JucerTreeViewBase::refreshSubItems()
  63. {
  64. WholeTreeOpennessRestorer wtor (*this);
  65. clearSubItems();
  66. addSubItems();
  67. }
  68. Font JucerTreeViewBase::getFont() const
  69. {
  70. return Font (getItemHeight() * 0.6f);
  71. }
  72. void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour /*backgroundColour*/, bool isMouseOver)
  73. {
  74. g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId : treeIconColourId));
  75. TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
  76. }
  77. void JucerTreeViewBase::paintIcon (Graphics &g, Rectangle<float> area)
  78. {
  79. g.setColour (getContentColour (true));
  80. getIcon().draw (g, area, isIconCrossedOut());
  81. }
  82. void JucerTreeViewBase::paintItem (Graphics& g, int width, int height)
  83. {
  84. ignoreUnused (width, height);
  85. auto bounds = g.getClipBounds().withY (0).withHeight (height).toFloat();
  86. g.setColour (getOwnerView()->findColour (treeIconColourId).withMultipliedAlpha (0.4f));
  87. g.fillRect (bounds.removeFromBottom (0.5f).reduced (5, 0));
  88. }
  89. Colour JucerTreeViewBase::getContentColour (bool isIcon) const
  90. {
  91. if (isMissing())
  92. return Colours::red;
  93. if (isSelected())
  94. return getOwnerView()->findColour (defaultHighlightedTextColourId);
  95. return getOwnerView()->findColour (isIcon ? treeIconColourId : defaultTextColourId);
  96. }
  97. void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle<int>& area)
  98. {
  99. g.setFont (getFont());
  100. g.setColour (getContentColour (false));
  101. g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 1.0f);
  102. }
  103. Component* JucerTreeViewBase::createItemComponent()
  104. {
  105. return new TreeItemComponent (*this);
  106. }
  107. //==============================================================================
  108. class RenameTreeItemCallback : public ModalComponentManager::Callback,
  109. public TextEditorListener
  110. {
  111. public:
  112. RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
  113. : item (ti)
  114. {
  115. ed.setMultiLine (false, false);
  116. ed.setPopupMenuEnabled (false);
  117. ed.setSelectAllWhenFocused (true);
  118. ed.setFont (item.getFont());
  119. ed.addListener (this);
  120. ed.setText (item.getRenamingName());
  121. ed.setBounds (bounds);
  122. parent.addAndMakeVisible (ed);
  123. ed.enterModalState (true, this);
  124. }
  125. void modalStateFinished (int resultCode) override
  126. {
  127. if (resultCode != 0)
  128. item.setName (ed.getText());
  129. }
  130. void textEditorTextChanged (TextEditor&) override {}
  131. void textEditorReturnKeyPressed (TextEditor& editor) override { editor.exitModalState (1); }
  132. void textEditorEscapeKeyPressed (TextEditor& editor) override { editor.exitModalState (0); }
  133. void textEditorFocusLost (TextEditor& editor) override { editor.exitModalState (0); }
  134. private:
  135. struct RenameEditor : public TextEditor
  136. {
  137. void inputAttemptWhenModal() override { exitModalState (0); }
  138. };
  139. RenameEditor ed;
  140. JucerTreeViewBase& item;
  141. JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
  142. };
  143. void JucerTreeViewBase::showRenameBox()
  144. {
  145. Rectangle<int> r (getItemPosition (true));
  146. r.setLeft (r.getX() + textX);
  147. r.setHeight (getItemHeight());
  148. new RenameTreeItemCallback (*this, *getOwnerView(), r);
  149. }
  150. void JucerTreeViewBase::itemClicked (const MouseEvent& e)
  151. {
  152. if (e.mods.isPopupMenu())
  153. {
  154. if (getOwnerView()->getNumSelectedItems() > 1)
  155. showMultiSelectionPopupMenu();
  156. else
  157. showPopupMenu();
  158. }
  159. else if (isSelected())
  160. {
  161. itemSelectionChanged (true);
  162. }
  163. }
  164. void JucerTreeViewBase::deleteItem() {}
  165. void JucerTreeViewBase::deleteAllSelectedItems() {}
  166. void JucerTreeViewBase::showDocument() {}
  167. void JucerTreeViewBase::showPopupMenu() {}
  168. void JucerTreeViewBase::showPlusMenu() {}
  169. void JucerTreeViewBase::showMultiSelectionPopupMenu() {}
  170. static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
  171. {
  172. if (item != nullptr)
  173. item->handlePopupMenuResult (resultCode);
  174. }
  175. void JucerTreeViewBase::launchPopupMenu (PopupMenu& m)
  176. {
  177. m.showMenuAsync (PopupMenu::Options(),
  178. ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
  179. }
  180. void JucerTreeViewBase::handlePopupMenuResult (int)
  181. {
  182. }
  183. ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
  184. {
  185. for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
  186. if (ProjectContentComponent* pcc = dynamic_cast<ProjectContentComponent*> (c))
  187. return pcc;
  188. return nullptr;
  189. }
  190. //==============================================================================
  191. class JucerTreeViewBase::ItemSelectionTimer : public Timer
  192. {
  193. public:
  194. ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
  195. void timerCallback() override { owner.invokeShowDocument(); }
  196. private:
  197. JucerTreeViewBase& owner;
  198. JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
  199. };
  200. void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
  201. {
  202. if (isNowSelected)
  203. {
  204. delayedSelectionTimer = new ItemSelectionTimer (*this);
  205. delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
  206. }
  207. else
  208. {
  209. cancelDelayedSelectionTimer();
  210. }
  211. }
  212. void JucerTreeViewBase::invokeShowDocument()
  213. {
  214. cancelDelayedSelectionTimer();
  215. showDocument();
  216. }
  217. void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
  218. {
  219. invokeShowDocument();
  220. }
  221. void JucerTreeViewBase::cancelDelayedSelectionTimer()
  222. {
  223. delayedSelectionTimer = nullptr;
  224. }