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.

274 lines
8.3KB

  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. setDrawsInLeftMargin (true);
  55. }
  56. JucerTreeViewBase::~JucerTreeViewBase()
  57. {
  58. masterReference.clear();
  59. }
  60. void JucerTreeViewBase::refreshSubItems()
  61. {
  62. WholeTreeOpennessRestorer wtor (*this);
  63. clearSubItems();
  64. addSubItems();
  65. }
  66. Font JucerTreeViewBase::getFont() const
  67. {
  68. return Font (getItemHeight() * 0.6f);
  69. }
  70. void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour /*backgroundColour*/, bool isMouseOver)
  71. {
  72. g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId : treeIconColourId));
  73. TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
  74. }
  75. void JucerTreeViewBase::paintIcon (Graphics &g, Rectangle<float> area)
  76. {
  77. g.setColour (getContentColour (true));
  78. getIcon().draw (g, area, isIconCrossedOut());
  79. }
  80. void JucerTreeViewBase::paintItem (Graphics& g, int width, int height)
  81. {
  82. ignoreUnused (width, height);
  83. auto bounds = g.getClipBounds().withY (0).withHeight (height).toFloat();
  84. g.setColour (getOwnerView()->findColour (treeIconColourId).withMultipliedAlpha (0.4f));
  85. g.fillRect (bounds.removeFromBottom (0.5f).reduced (5, 0));
  86. }
  87. Colour JucerTreeViewBase::getContentColour (bool isIcon) const
  88. {
  89. if (isMissing())
  90. return Colours::red;
  91. if (isSelected())
  92. return getOwnerView()->findColour (defaultHighlightedTextColourId);
  93. return getOwnerView()->findColour (isIcon ? treeIconColourId : defaultTextColourId);
  94. }
  95. void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle<int>& area)
  96. {
  97. g.setFont (getFont());
  98. g.setColour (getContentColour (false));
  99. g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 1.0f);
  100. }
  101. Component* JucerTreeViewBase::createItemComponent()
  102. {
  103. return new TreeItemComponent (*this);
  104. }
  105. //==============================================================================
  106. class RenameTreeItemCallback : public ModalComponentManager::Callback,
  107. public TextEditorListener
  108. {
  109. public:
  110. RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
  111. : item (ti)
  112. {
  113. ed.setMultiLine (false, false);
  114. ed.setPopupMenuEnabled (false);
  115. ed.setSelectAllWhenFocused (true);
  116. ed.setFont (item.getFont());
  117. ed.addListener (this);
  118. ed.setText (item.getRenamingName());
  119. ed.setBounds (bounds);
  120. parent.addAndMakeVisible (ed);
  121. ed.enterModalState (true, this);
  122. }
  123. void modalStateFinished (int resultCode) override
  124. {
  125. if (resultCode != 0)
  126. item.setName (ed.getText());
  127. }
  128. void textEditorTextChanged (TextEditor&) override {}
  129. void textEditorReturnKeyPressed (TextEditor& editor) override { editor.exitModalState (1); }
  130. void textEditorEscapeKeyPressed (TextEditor& editor) override { editor.exitModalState (0); }
  131. void textEditorFocusLost (TextEditor& editor) override { editor.exitModalState (0); }
  132. private:
  133. struct RenameEditor : public TextEditor
  134. {
  135. void inputAttemptWhenModal() override { exitModalState (0); }
  136. };
  137. RenameEditor ed;
  138. JucerTreeViewBase& item;
  139. JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
  140. };
  141. void JucerTreeViewBase::showRenameBox()
  142. {
  143. Rectangle<int> r (getItemPosition (true));
  144. r.setLeft (r.getX() + textX);
  145. r.setHeight (getItemHeight());
  146. new RenameTreeItemCallback (*this, *getOwnerView(), r);
  147. }
  148. void JucerTreeViewBase::itemClicked (const MouseEvent& e)
  149. {
  150. if (e.mods.isPopupMenu())
  151. {
  152. if (getOwnerView()->getNumSelectedItems() > 1)
  153. showMultiSelectionPopupMenu();
  154. else
  155. showPopupMenu();
  156. }
  157. else if (isSelected())
  158. {
  159. itemSelectionChanged (true);
  160. }
  161. }
  162. void JucerTreeViewBase::deleteItem() {}
  163. void JucerTreeViewBase::deleteAllSelectedItems() {}
  164. void JucerTreeViewBase::showDocument() {}
  165. void JucerTreeViewBase::showPopupMenu() {}
  166. void JucerTreeViewBase::showPlusMenu() {}
  167. void JucerTreeViewBase::showMultiSelectionPopupMenu() {}
  168. static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
  169. {
  170. if (item != nullptr)
  171. item->handlePopupMenuResult (resultCode);
  172. }
  173. void JucerTreeViewBase::launchPopupMenu (PopupMenu& m)
  174. {
  175. m.showMenuAsync (PopupMenu::Options(),
  176. ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
  177. }
  178. void JucerTreeViewBase::handlePopupMenuResult (int)
  179. {
  180. }
  181. ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
  182. {
  183. for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
  184. if (ProjectContentComponent* pcc = dynamic_cast<ProjectContentComponent*> (c))
  185. return pcc;
  186. return nullptr;
  187. }
  188. //==============================================================================
  189. class JucerTreeViewBase::ItemSelectionTimer : public Timer
  190. {
  191. public:
  192. ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
  193. void timerCallback() override { owner.invokeShowDocument(); }
  194. private:
  195. JucerTreeViewBase& owner;
  196. JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
  197. };
  198. void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
  199. {
  200. if (isNowSelected)
  201. {
  202. delayedSelectionTimer = new ItemSelectionTimer (*this);
  203. delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
  204. }
  205. else
  206. {
  207. cancelDelayedSelectionTimer();
  208. }
  209. }
  210. void JucerTreeViewBase::invokeShowDocument()
  211. {
  212. cancelDelayedSelectionTimer();
  213. showDocument();
  214. }
  215. void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
  216. {
  217. invokeShowDocument();
  218. }
  219. void JucerTreeViewBase::cancelDelayedSelectionTimer()
  220. {
  221. delayedSelectionTimer = nullptr;
  222. }