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.

280 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2013 - Raw Material Software 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_JucerTreeViewBase.h"
  18. #include "../Project/jucer_ProjectContentComponent.h"
  19. //==============================================================================
  20. void TreePanelBase::setRoot (JucerTreeViewBase* root)
  21. {
  22. rootItem = root;
  23. tree.setRootItem (root);
  24. tree.getRootItem()->setOpen (true);
  25. if (project != nullptr)
  26. {
  27. const ScopedPointer<XmlElement> treeOpenness (project->getStoredProperties()
  28. .getXmlValue (opennessStateKey));
  29. if (treeOpenness != nullptr)
  30. {
  31. tree.restoreOpennessState (*treeOpenness, true);
  32. for (int i = tree.getNumSelectedItems(); --i >= 0;)
  33. if (JucerTreeViewBase* item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i)))
  34. item->cancelDelayedSelectionTimer();
  35. }
  36. }
  37. }
  38. void TreePanelBase::saveOpenness()
  39. {
  40. if (project != nullptr)
  41. {
  42. const ScopedPointer<XmlElement> opennessState (tree.getOpennessState (true));
  43. if (opennessState != nullptr)
  44. project->getStoredProperties().setValue (opennessStateKey, opennessState);
  45. else
  46. project->getStoredProperties().removeValue (opennessStateKey);
  47. }
  48. }
  49. //==============================================================================
  50. JucerTreeViewBase::JucerTreeViewBase() : textX (0)
  51. {
  52. setLinesDrawnForSubItems (false);
  53. }
  54. JucerTreeViewBase::~JucerTreeViewBase()
  55. {
  56. masterReference.clear();
  57. }
  58. void JucerTreeViewBase::refreshSubItems()
  59. {
  60. WholeTreeOpennessRestorer wtor (*this);
  61. clearSubItems();
  62. addSubItems();
  63. }
  64. Font JucerTreeViewBase::getFont() const
  65. {
  66. return Font (getItemHeight() * 0.6f);
  67. }
  68. void JucerTreeViewBase::paintItem (Graphics& g, int /*width*/, int /*height*/)
  69. {
  70. if (isSelected())
  71. g.fillAll (getOwnerView()->findColour (treeviewHighlightColourId));
  72. }
  73. float JucerTreeViewBase::getIconSize() const
  74. {
  75. return jmin (getItemHeight() - 4.0f, 18.0f);
  76. }
  77. void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, int width, int height, bool /*isMouseOver*/)
  78. {
  79. Path p;
  80. if (isOpen())
  81. p.addTriangle (width * 0.2f, height * 0.25f, width * 0.8f, height * 0.25f, width * 0.5f, height * 0.75f);
  82. else
  83. p.addTriangle (width * 0.25f, height * 0.25f, width * 0.8f, height * 0.5f, width * 0.25f, height * 0.75f);
  84. g.setColour (getOwnerView()->findColour (mainBackgroundColourId).contrasting (0.3f));
  85. g.fillPath (p);
  86. }
  87. Colour JucerTreeViewBase::getBackgroundColour() const
  88. {
  89. Colour background (getOwnerView()->findColour (mainBackgroundColourId));
  90. if (isSelected())
  91. background = background.overlaidWith (getOwnerView()->findColour (treeviewHighlightColourId));
  92. return background;
  93. }
  94. Colour JucerTreeViewBase::getContrastingColour (float contrast) const
  95. {
  96. return getBackgroundColour().contrasting (contrast);
  97. }
  98. Colour JucerTreeViewBase::getContrastingColour (const Colour& target, float minContrast) const
  99. {
  100. return getBackgroundColour().contrasting (target, minContrast);
  101. }
  102. void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle<int>& area)
  103. {
  104. g.setFont (getFont());
  105. g.setColour (isMissing() ? getContrastingColour (Colours::red, 0.8f)
  106. : getContrastingColour (0.8f));
  107. g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 0.8f);
  108. }
  109. Component* JucerTreeViewBase::createItemComponent()
  110. {
  111. return new TreeItemComponent (*this);
  112. }
  113. //==============================================================================
  114. class RenameTreeItemCallback : public ModalComponentManager::Callback,
  115. public TextEditorListener
  116. {
  117. public:
  118. RenameTreeItemCallback (JucerTreeViewBase& ti, Component& parent, const Rectangle<int>& bounds)
  119. : item (ti)
  120. {
  121. ed.setMultiLine (false, false);
  122. ed.setPopupMenuEnabled (false);
  123. ed.setSelectAllWhenFocused (true);
  124. ed.setFont (item.getFont());
  125. ed.addListener (this);
  126. ed.setText (item.getRenamingName());
  127. ed.setBounds (bounds);
  128. parent.addAndMakeVisible (&ed);
  129. ed.enterModalState (true, this);
  130. }
  131. void modalStateFinished (int resultCode) override
  132. {
  133. if (resultCode != 0)
  134. item.setName (ed.getText());
  135. }
  136. void textEditorTextChanged (TextEditor&) override {}
  137. void textEditorReturnKeyPressed (TextEditor& editor) override { editor.exitModalState (1); }
  138. void textEditorEscapeKeyPressed (TextEditor& editor) override { editor.exitModalState (0); }
  139. void textEditorFocusLost (TextEditor& editor) override { editor.exitModalState (0); }
  140. private:
  141. struct RenameEditor : public TextEditor
  142. {
  143. void inputAttemptWhenModal() override { exitModalState (0); }
  144. };
  145. RenameEditor ed;
  146. JucerTreeViewBase& item;
  147. JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback)
  148. };
  149. void JucerTreeViewBase::showRenameBox()
  150. {
  151. Rectangle<int> r (getItemPosition (true));
  152. r.setLeft (r.getX() + textX);
  153. r.setHeight (getItemHeight());
  154. new RenameTreeItemCallback (*this, *getOwnerView(), r);
  155. }
  156. void JucerTreeViewBase::itemClicked (const MouseEvent& e)
  157. {
  158. if (e.mods.isPopupMenu())
  159. {
  160. if (getOwnerView()->getNumSelectedItems() > 1)
  161. showMultiSelectionPopupMenu();
  162. else
  163. showPopupMenu();
  164. }
  165. }
  166. void JucerTreeViewBase::deleteItem() {}
  167. void JucerTreeViewBase::deleteAllSelectedItems() {}
  168. void JucerTreeViewBase::showDocument() {}
  169. void JucerTreeViewBase::showPopupMenu() {}
  170. void JucerTreeViewBase::showMultiSelectionPopupMenu() {}
  171. static void treeViewMenuItemChosen (int resultCode, WeakReference<JucerTreeViewBase> item)
  172. {
  173. if (item != nullptr)
  174. item->handlePopupMenuResult (resultCode);
  175. }
  176. void JucerTreeViewBase::launchPopupMenu (PopupMenu& m)
  177. {
  178. m.showMenuAsync (PopupMenu::Options(),
  179. ModalCallbackFunction::create (treeViewMenuItemChosen, WeakReference<JucerTreeViewBase> (this)));
  180. }
  181. void JucerTreeViewBase::handlePopupMenuResult (int)
  182. {
  183. }
  184. ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
  185. {
  186. for (Component* c = getOwnerView(); c != nullptr; c = c->getParentComponent())
  187. if (ProjectContentComponent* pcc = dynamic_cast <ProjectContentComponent*> (c))
  188. return pcc;
  189. return nullptr;
  190. }
  191. //==============================================================================
  192. class JucerTreeViewBase::ItemSelectionTimer : public Timer
  193. {
  194. public:
  195. ItemSelectionTimer (JucerTreeViewBase& tvb) : owner (tvb) {}
  196. void timerCallback() override { owner.invokeShowDocument(); }
  197. private:
  198. JucerTreeViewBase& owner;
  199. JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer)
  200. };
  201. void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
  202. {
  203. if (isNowSelected)
  204. {
  205. delayedSelectionTimer = new ItemSelectionTimer (*this);
  206. delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
  207. }
  208. else
  209. {
  210. cancelDelayedSelectionTimer();
  211. }
  212. }
  213. void JucerTreeViewBase::invokeShowDocument()
  214. {
  215. cancelDelayedSelectionTimer();
  216. showDocument();
  217. }
  218. void JucerTreeViewBase::itemDoubleClicked (const MouseEvent&)
  219. {
  220. invokeShowDocument();
  221. }
  222. void JucerTreeViewBase::cancelDelayedSelectionTimer()
  223. {
  224. delayedSelectionTimer = nullptr;
  225. }