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.

183 lines
6.2KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library.
  4. Copyright (c) 2022 - 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 7 End-User License
  8. Agreement and JUCE Privacy Policy.
  9. End User License Agreement: www.juce.com/juce-7-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. #pragma once
  19. //==============================================================================
  20. class StartPageTreeHolder : public Component
  21. {
  22. public:
  23. enum class Open { no, yes };
  24. StartPageTreeHolder (const String& title,
  25. const StringArray& headerNames,
  26. const std::vector<StringArray>& itemNames,
  27. std::function<void (int, int)>&& selectedCallback,
  28. Open shouldBeOpen)
  29. : headers (headerNames),
  30. items (itemNames),
  31. itemSelectedCallback (std::move (selectedCallback))
  32. {
  33. jassert (headers.size() == (int) items.size());
  34. tree.setTitle (title);
  35. tree.setRootItem (new TreeRootItem (*this));
  36. tree.setRootItemVisible (false);
  37. tree.setIndentSize (15);
  38. tree.setDefaultOpenness (shouldBeOpen == Open::yes);
  39. addAndMakeVisible (tree);
  40. }
  41. ~StartPageTreeHolder() override
  42. {
  43. tree.deleteRootItem();
  44. }
  45. void paint (Graphics& g) override
  46. {
  47. g.fillAll (findColour (secondaryBackgroundColourId));
  48. }
  49. void resized() override
  50. {
  51. tree.setBounds (getLocalBounds());
  52. }
  53. void setSelectedItem (const String& category, int index)
  54. {
  55. auto* root = tree.getRootItem();
  56. for (int i = root->getNumSubItems(); --i >=0;)
  57. {
  58. if (auto* item = root->getSubItem (i))
  59. {
  60. if (item->getUniqueName() == category)
  61. item->getSubItem (index)->setSelected (true, true);
  62. }
  63. }
  64. }
  65. private:
  66. //==============================================================================
  67. class TreeSubItem : public TreeViewItem
  68. {
  69. public:
  70. TreeSubItem (StartPageTreeHolder& o, const String& n, const StringArray& subItemsIn)
  71. : owner (o), name (n), isHeader (subItemsIn.size() > 0)
  72. {
  73. for (auto& s : subItemsIn)
  74. addSubItem (new TreeSubItem (owner, s, {}));
  75. }
  76. bool mightContainSubItems() override { return isHeader; }
  77. bool canBeSelected() const override { return ! isHeader; }
  78. int getItemWidth() const override { return -1; }
  79. int getItemHeight() const override { return 25; }
  80. String getUniqueName() const override { return name; }
  81. String getAccessibilityName() override { return getUniqueName(); }
  82. void paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour, bool isMouseOver) override
  83. {
  84. g.setColour (getOwnerView()->findColour (isSelected() ? defaultHighlightedTextColourId
  85. : treeIconColourId));
  86. TreeViewItem::paintOpenCloseButton (g, area, getOwnerView()->findColour (defaultIconColourId), isMouseOver);
  87. }
  88. void paintItem (Graphics& g, int w, int h) override
  89. {
  90. Rectangle<int> bounds (w, h);
  91. auto shouldBeHighlighted = isSelected();
  92. if (shouldBeHighlighted)
  93. {
  94. g.setColour (getOwnerView()->findColour (defaultHighlightColourId));
  95. g.fillRect (bounds);
  96. }
  97. g.setColour (shouldBeHighlighted ? getOwnerView()->findColour (defaultHighlightedTextColourId)
  98. : getOwnerView()->findColour (defaultTextColourId));
  99. g.drawFittedText (name, bounds.reduced (5).withTrimmedLeft (10), Justification::centredLeft, 1);
  100. }
  101. void itemClicked (const MouseEvent& e) override
  102. {
  103. if (isSelected())
  104. itemSelectionChanged (true);
  105. if (e.mods.isPopupMenu() && mightContainSubItems())
  106. setOpen (! isOpen());
  107. }
  108. void itemSelectionChanged (bool isNowSelected) override
  109. {
  110. jassert (! isHeader);
  111. if (isNowSelected)
  112. owner.itemSelectedCallback (getParentItem()->getIndexInParent(), getIndexInParent());
  113. }
  114. private:
  115. StartPageTreeHolder& owner;
  116. String name;
  117. bool isHeader = false;
  118. //==============================================================================
  119. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeSubItem)
  120. };
  121. struct TreeRootItem : public TreeViewItem
  122. {
  123. explicit TreeRootItem (StartPageTreeHolder& o)
  124. : owner (o)
  125. {
  126. for (int i = 0; i < owner.headers.size(); ++i)
  127. addSubItem (new TreeSubItem (owner, owner.headers[i], owner.items[(size_t) i]));
  128. }
  129. bool mightContainSubItems() override { return ! owner.headers.isEmpty();}
  130. StartPageTreeHolder& owner;
  131. //==============================================================================
  132. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeRootItem)
  133. };
  134. //==============================================================================
  135. TreeView tree;
  136. StringArray headers;
  137. std::vector<StringArray> items;
  138. std::function<void (int, int)> itemSelectedCallback;
  139. //==============================================================================
  140. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StartPageTreeHolder)
  141. };