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.

263 lines
8.0KB

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