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
10KB

  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. #pragma once
  20. //==============================================================================
  21. class ComponentListComp : public TreePanelBase,
  22. private ActivityList::Listener
  23. {
  24. public:
  25. ComponentListComp (CompileEngineChildProcess& c)
  26. : TreePanelBase (&c.project, "compClassTreeState"),
  27. owner (c)
  28. {
  29. setName ("Components");
  30. tree.setRootItemVisible (false);
  31. tree.setMultiSelectEnabled (false);
  32. tree.setDefaultOpenness (true);
  33. setRoot (new NamespaceItem (&owner.getComponentList().globalNamespace));
  34. classListChanged (owner.getComponentList());
  35. owner.activityList.addListener (this);
  36. }
  37. ~ComponentListComp() override
  38. {
  39. saveOpenness();
  40. owner.activityList.removeListener (this);
  41. }
  42. void classListChanged (const ClassDatabase::ClassList& newClasses) override
  43. {
  44. rootItem->clearSubItems();
  45. static_cast<NamespaceItem*> (rootItem.get())->setNamespace (&newClasses.globalNamespace);
  46. }
  47. void openPreview (const ClassDatabase::Class& comp)
  48. {
  49. owner.openPreview (comp);
  50. }
  51. void showClassDeclaration (const ClassDatabase::Class& comp)
  52. {
  53. owner.handleHighlightCode (comp.getClassDeclarationRange());
  54. }
  55. private:
  56. CompileEngineChildProcess& owner;
  57. struct ClassItem;
  58. struct NamespaceItem : public JucerTreeViewBase
  59. {
  60. NamespaceItem (const ClassDatabase::Namespace* n)
  61. {
  62. setNamespace (n);
  63. }
  64. void setNamespace (const ClassDatabase::Namespace* newNamespace)
  65. {
  66. namespaceToShow = newNamespace;
  67. uniqueID = namespaceToShow != nullptr ? "ns_" + namespaceToShow->fullName : "null";
  68. refreshSubItems();
  69. }
  70. String getRenamingName() const override { return getDisplayName(); }
  71. String getDisplayName() const override { return (namespaceToShow != nullptr ? namespaceToShow->name : String()) + "::"; }
  72. void setName (const String&) override {}
  73. bool isMissing() const override { return false; }
  74. Icon getIcon() const override { return Icon (getIcons().graph, getContentColour (true)); }
  75. bool canBeSelected() const override { return true; }
  76. bool mightContainSubItems() override { return namespaceToShow != nullptr && ! namespaceToShow->isEmpty(); }
  77. String getUniqueName() const override { return uniqueID; }
  78. void addSubItems() override
  79. {
  80. if (namespaceToShow != nullptr)
  81. {
  82. Array<ClassItem*> newComps;
  83. Array<NamespaceItem*> newNamespaces;
  84. for (const auto& c : namespaceToShow->components)
  85. newComps.addSorted (*this, new ClassItem (c, *namespaceToShow));
  86. for(const auto& n : namespaceToShow->namespaces)
  87. {
  88. if (n.getTotalClassesAndNamespaces() < 10)
  89. createFlatItemList (n, newComps);
  90. else
  91. newNamespaces.add (new NamespaceItem (&n));
  92. }
  93. for (auto c : newComps)
  94. addSubItem (c);
  95. for (auto n : newNamespaces)
  96. addSubItem (n);
  97. }
  98. }
  99. void createFlatItemList (const ClassDatabase::Namespace& ns, Array<ClassItem*>& newComps)
  100. {
  101. for (const auto& c : ns.components)
  102. newComps.addSorted (*this, new ClassItem (c, *namespaceToShow));
  103. for (const auto& n : ns.namespaces)
  104. createFlatItemList (n, newComps);
  105. }
  106. static int compareElements (ClassItem* c1, ClassItem* c2)
  107. {
  108. return c1->comp.getName().compareIgnoreCase (c2->comp.getName());
  109. }
  110. private:
  111. const ClassDatabase::Namespace* namespaceToShow = nullptr;
  112. String uniqueID; // must be stored rather than calculated, in case the namespace obj is dangling
  113. };
  114. struct ClassItem : public JucerTreeViewBase
  115. {
  116. ClassItem (const ClassDatabase::Class& c, const ClassDatabase::Namespace& parentNS)
  117. : comp (c),
  118. displayName (comp.getName().substring (parentNS.fullName.length()))
  119. {
  120. }
  121. String getRenamingName() const override { return getDisplayName(); }
  122. String getDisplayName() const override { return displayName; }
  123. void setName (const String&) override {}
  124. bool isMissing() const override { return false; }
  125. Icon getIcon() const override { return Icon (getIcons().box, getContentColour (true)); }
  126. bool canBeSelected() const override { return true; }
  127. bool mightContainSubItems() override { return false; }
  128. String getUniqueName() const override { return comp.getName(); }
  129. int getRightHandButtonSpace() override { return canBeLaunched() ? 60 : 40; }
  130. Component* createItemComponent() override
  131. {
  132. auto* content = new TreeItemComponent (*this);
  133. content->addRightHandButton (new ClassItemButton (*this, true));
  134. if (canBeLaunched())
  135. content->addRightHandButton (new ClassItemButton (*this, false));
  136. return content;
  137. }
  138. Colour getContentColour (bool isIcon) const override
  139. {
  140. auto alpha = comp.getInstantiationFlags().canBeInstantiated() ? 1.0f : 0.4f;
  141. auto& lf = ProjucerApplication::getApp().lookAndFeel;
  142. if (isSelected())
  143. return lf.findColour (defaultHighlightedTextColourId).withMultipliedAlpha (alpha);
  144. return lf.findColour (isIcon ? treeIconColourId : defaultTextColourId).withMultipliedAlpha (alpha);
  145. }
  146. bool canBeLaunched() const
  147. {
  148. return comp.getInstantiationFlags().canBeInstantiated();
  149. }
  150. void showClassDeclaration() const
  151. {
  152. if (ComponentListComp* clc = getOwnerView()->findParentComponentOfClass<ComponentListComp>())
  153. clc->showClassDeclaration (comp);
  154. }
  155. void launchEditor() const
  156. {
  157. if (ComponentListComp* clc = getOwnerView()->findParentComponentOfClass<ComponentListComp>())
  158. clc->openPreview (comp);
  159. }
  160. void itemClicked (const MouseEvent&) override
  161. {
  162. if (! canBeLaunched())
  163. if (ProjectContentComponent* const pcc = getOwnerView()->findParentComponentOfClass<ProjectContentComponent>())
  164. pcc->showBubbleMessage (pcc->getLocalArea (getOwnerView(), getItemPosition (true)),
  165. "Cannot create a live view:\n" + comp.getInstantiationFlags().getReasonForUnavailability());
  166. }
  167. void itemDoubleClicked (const MouseEvent&) override
  168. {
  169. if (canBeLaunched())
  170. launchEditor();
  171. else
  172. showClassDeclaration();
  173. }
  174. struct ClassItemButton : public Button
  175. {
  176. ClassItemButton (const ClassItem& c, bool isShowCodeButton)
  177. : Button (String()), classItem (c), isShowCode (isShowCodeButton)
  178. {
  179. setMouseCursor (MouseCursor::PointingHandCursor);
  180. }
  181. void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) override
  182. {
  183. const Path& path = isShowCode ? getIcons().code
  184. : getIcons().play;
  185. auto colour = classItem.getContentColour (true).withAlpha (isButtonDown ? 1.0f
  186. : (isMouseOverButton ? 0.8f
  187. : 0.5f));
  188. Icon (path, colour).draw (g, getLocalBounds().reduced (getHeight() / 5).toFloat(), false);
  189. }
  190. void clicked() override
  191. {
  192. if (isShowCode)
  193. classItem.showClassDeclaration();
  194. else
  195. classItem.launchEditor();
  196. }
  197. using Button::clicked;
  198. const ClassItem& classItem;
  199. bool isShowCode;
  200. };
  201. struct ClassComponent : public Component
  202. {
  203. ClassComponent (ClassItem& item, bool canBeLaunched)
  204. {
  205. addAndMakeVisible (buttons.add (new ClassItemButton (item, true)));
  206. if (canBeLaunched)
  207. addAndMakeVisible (buttons.add (new ClassItemButton (item, false)));
  208. setInterceptsMouseClicks (false, true);
  209. }
  210. void resized() override
  211. {
  212. auto bounds = getLocalBounds();
  213. for (auto b : buttons)
  214. b->setBounds (bounds.removeFromRight (25).reduced (2));
  215. }
  216. OwnedArray<ClassItemButton> buttons;
  217. };
  218. const ClassDatabase::Class comp;
  219. String displayName;
  220. };
  221. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentListComp)
  222. };