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.

272 lines
9.9KB

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