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.

283 lines
8.4KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  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. {
  35. JucerTreeViewBase* item = dynamic_cast<JucerTreeViewBase*> (tree.getSelectedItem (i));
  36. if (item != nullptr)
  37. item->cancelDelayedSelectionTimer();
  38. }
  39. }
  40. }
  41. }
  42. void TreePanelBase::saveOpenness()
  43. {
  44. if (project != nullptr)
  45. {
  46. const ScopedPointer<XmlElement> opennessState (tree.getOpennessState (true));
  47. if (opennessState != nullptr)
  48. project->getStoredProperties().setValue (opennessStateKey, opennessState);
  49. else
  50. project->getStoredProperties().removeValue (opennessStateKey);
  51. }
  52. }
  53. //==============================================================================
  54. JucerTreeViewBase::JucerTreeViewBase()
  55. : textX (0)
  56. {
  57. setLinesDrawnForSubItems (false);
  58. }
  59. void JucerTreeViewBase::refreshSubItems()
  60. {
  61. WholeTreeOpennessRestorer openness (*this);
  62. clearSubItems();
  63. addSubItems();
  64. }
  65. Font JucerTreeViewBase::getFont() const
  66. {
  67. return Font (getItemHeight() * 0.6f);
  68. }
  69. void JucerTreeViewBase::paintItem (Graphics& g, int width, int height)
  70. {
  71. if (isSelected())
  72. g.fillAll (getOwnerView()->findColour (treeviewHighlightColourId));
  73. }
  74. float JucerTreeViewBase::getIconSize() const
  75. {
  76. return jmin (getItemHeight() - 4.0f, 18.0f);
  77. }
  78. void JucerTreeViewBase::paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver)
  79. {
  80. Path p;
  81. if (isOpen())
  82. p.addTriangle (width * 0.2f, height * 0.25f, width * 0.8f, height * 0.25f, width * 0.5f, height * 0.75f);
  83. else
  84. p.addTriangle (width * 0.25f, height * 0.25f, width * 0.8f, height * 0.5f, width * 0.25f, height * 0.75f);
  85. g.setColour (getOwnerView()->findColour (mainBackgroundColourId).contrasting (0.3f));
  86. g.fillPath (p);
  87. }
  88. Colour JucerTreeViewBase::getBackgroundColour() const
  89. {
  90. Colour background (getOwnerView()->findColour (mainBackgroundColourId));
  91. if (isSelected())
  92. background = background.overlaidWith (getOwnerView()->findColour (treeviewHighlightColourId));
  93. return background;
  94. }
  95. Colour JucerTreeViewBase::getContrastingColour (float contrast) const
  96. {
  97. return getBackgroundColour().contrasting (contrast);
  98. }
  99. Colour JucerTreeViewBase::getContrastingColour (const Colour& target, float minContrast) const
  100. {
  101. return getBackgroundColour().contrasting (target, minContrast);
  102. }
  103. void JucerTreeViewBase::paintContent (Graphics& g, const Rectangle<int>& area)
  104. {
  105. g.setFont (getFont());
  106. g.setColour (isMissing() ? getContrastingColour (Colours::red, 0.8f)
  107. : getContrastingColour (0.8f));
  108. g.drawFittedText (getDisplayName(), area, Justification::centredLeft, 1, 0.8f);
  109. }
  110. Component* JucerTreeViewBase::createItemComponent()
  111. {
  112. return new TreeItemComponent (*this);
  113. }
  114. //==============================================================================
  115. class RenameTreeItemCallback : public ModalComponentManager::Callback,
  116. public TextEditorListener
  117. {
  118. public:
  119. RenameTreeItemCallback (JucerTreeViewBase& item_, Component& parent, const Rectangle<int>& bounds)
  120. : item (item_)
  121. {
  122. ed.setMultiLine (false, false);
  123. ed.setPopupMenuEnabled (false);
  124. ed.setSelectAllWhenFocused (true);
  125. ed.setFont (item.getFont());
  126. ed.addListener (this);
  127. ed.setText (item.getRenamingName());
  128. ed.setBounds (bounds);
  129. parent.addAndMakeVisible (&ed);
  130. ed.enterModalState (true, this);
  131. }
  132. void modalStateFinished (int resultCode)
  133. {
  134. if (resultCode != 0)
  135. item.setName (ed.getText());
  136. }
  137. void textEditorTextChanged (TextEditor&) {}
  138. void textEditorReturnKeyPressed (TextEditor& editor) { editor.exitModalState (1); }
  139. void textEditorEscapeKeyPressed (TextEditor& editor) { editor.exitModalState (0); }
  140. void textEditorFocusLost (TextEditor& editor) { editor.exitModalState (0); }
  141. private:
  142. TextEditor ed;
  143. JucerTreeViewBase& item;
  144. JUCE_DECLARE_NON_COPYABLE (RenameTreeItemCallback);
  145. };
  146. void JucerTreeViewBase::showRenameBox()
  147. {
  148. Rectangle<int> r (getItemPosition (true));
  149. r.setLeft (r.getX() + textX);
  150. r.setHeight (getItemHeight());
  151. new RenameTreeItemCallback (*this, *getOwnerView(), r);
  152. }
  153. void JucerTreeViewBase::itemClicked (const MouseEvent& e)
  154. {
  155. if (e.mods.isPopupMenu())
  156. {
  157. if (getOwnerView()->getNumSelectedItems() > 1)
  158. showMultiSelectionPopupMenu();
  159. else
  160. showPopupMenu();
  161. }
  162. }
  163. void JucerTreeViewBase::deleteItem() {}
  164. void JucerTreeViewBase::deleteAllSelectedItems() {}
  165. void JucerTreeViewBase::showDocument() {}
  166. void JucerTreeViewBase::showPopupMenu() {}
  167. void JucerTreeViewBase::showMultiSelectionPopupMenu() {}
  168. static void treeViewMenuItemChosen (int resultCode, JucerTreeViewBase* item)
  169. {
  170. item->handlePopupMenuResult (resultCode);
  171. }
  172. void JucerTreeViewBase::launchPopupMenu (PopupMenu& m)
  173. {
  174. m.showMenuAsync (PopupMenu::Options(),
  175. ModalCallbackFunction::create (treeViewMenuItemChosen, this));
  176. }
  177. void JucerTreeViewBase::handlePopupMenuResult (int)
  178. {
  179. }
  180. ProjectContentComponent* JucerTreeViewBase::getProjectContentComponent() const
  181. {
  182. Component* c = getOwnerView();
  183. while (c != nullptr)
  184. {
  185. ProjectContentComponent* pcc = dynamic_cast <ProjectContentComponent*> (c);
  186. if (pcc != nullptr)
  187. return pcc;
  188. c = c->getParentComponent();
  189. }
  190. return 0;
  191. }
  192. //==============================================================================
  193. class JucerTreeViewBase::ItemSelectionTimer : public Timer
  194. {
  195. public:
  196. ItemSelectionTimer (JucerTreeViewBase& owner_) : owner (owner_) {}
  197. void timerCallback() { owner.invokeShowDocument(); }
  198. private:
  199. JucerTreeViewBase& owner;
  200. JUCE_DECLARE_NON_COPYABLE (ItemSelectionTimer);
  201. };
  202. void JucerTreeViewBase::itemSelectionChanged (bool isNowSelected)
  203. {
  204. if (isNowSelected)
  205. {
  206. delayedSelectionTimer = new ItemSelectionTimer (*this);
  207. delayedSelectionTimer->startTimer (getMillisecsAllowedForDragGesture());
  208. }
  209. else
  210. {
  211. cancelDelayedSelectionTimer();
  212. }
  213. }
  214. void JucerTreeViewBase::invokeShowDocument()
  215. {
  216. cancelDelayedSelectionTimer();
  217. showDocument();
  218. }
  219. void JucerTreeViewBase::itemDoubleClicked (const MouseEvent& e)
  220. {
  221. invokeShowDocument();
  222. }
  223. void JucerTreeViewBase::cancelDelayedSelectionTimer()
  224. {
  225. delayedSelectionTimer = nullptr;
  226. }