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.

313 lines
9.6KB

  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. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. namespace TabbedComponentHelpers
  21. {
  22. const Identifier deleteComponentId ("deleteByTabComp_");
  23. void deleteIfNecessary (Component* const comp)
  24. {
  25. if (comp != nullptr && (bool) comp->getProperties() [deleteComponentId])
  26. delete comp;
  27. }
  28. const Rectangle<int> getTabArea (Rectangle<int>& content, BorderSize<int>& outline,
  29. const TabbedButtonBar::Orientation orientation, const int tabDepth)
  30. {
  31. switch (orientation)
  32. {
  33. case TabbedButtonBar::TabsAtTop: outline.setTop (0); return content.removeFromTop (tabDepth);
  34. case TabbedButtonBar::TabsAtBottom: outline.setBottom (0); return content.removeFromBottom (tabDepth);
  35. case TabbedButtonBar::TabsAtLeft: outline.setLeft (0); return content.removeFromLeft (tabDepth);
  36. case TabbedButtonBar::TabsAtRight: outline.setRight (0); return content.removeFromRight (tabDepth);
  37. default: jassertfalse; break;
  38. }
  39. return Rectangle<int>();
  40. }
  41. }
  42. //==============================================================================
  43. class TabbedComponent::ButtonBar : public TabbedButtonBar
  44. {
  45. public:
  46. ButtonBar (TabbedComponent& owner_, const TabbedButtonBar::Orientation orientation_)
  47. : TabbedButtonBar (orientation_),
  48. owner (owner_)
  49. {
  50. }
  51. void currentTabChanged (int newCurrentTabIndex, const String& newTabName)
  52. {
  53. owner.changeCallback (newCurrentTabIndex, newTabName);
  54. }
  55. void popupMenuClickOnTab (int tabIndex, const String& tabName)
  56. {
  57. owner.popupMenuClickOnTab (tabIndex, tabName);
  58. }
  59. const Colour getTabBackgroundColour (const int tabIndex)
  60. {
  61. return owner.tabs->getTabBackgroundColour (tabIndex);
  62. }
  63. TabBarButton* createTabButton (const String& tabName, int tabIndex)
  64. {
  65. return owner.createTabButton (tabName, tabIndex);
  66. }
  67. private:
  68. TabbedComponent& owner;
  69. JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar);
  70. };
  71. //==============================================================================
  72. TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation)
  73. : tabDepth (30),
  74. outlineThickness (1),
  75. edgeIndent (0)
  76. {
  77. addAndMakeVisible (tabs = new ButtonBar (*this, orientation));
  78. }
  79. TabbedComponent::~TabbedComponent()
  80. {
  81. clearTabs();
  82. tabs = nullptr;
  83. }
  84. //==============================================================================
  85. void TabbedComponent::setOrientation (const TabbedButtonBar::Orientation orientation)
  86. {
  87. tabs->setOrientation (orientation);
  88. resized();
  89. }
  90. TabbedButtonBar::Orientation TabbedComponent::getOrientation() const noexcept
  91. {
  92. return tabs->getOrientation();
  93. }
  94. void TabbedComponent::setTabBarDepth (const int newDepth)
  95. {
  96. if (tabDepth != newDepth)
  97. {
  98. tabDepth = newDepth;
  99. resized();
  100. }
  101. }
  102. TabBarButton* TabbedComponent::createTabButton (const String& tabName, const int /*tabIndex*/)
  103. {
  104. return new TabBarButton (tabName, *tabs);
  105. }
  106. //==============================================================================
  107. void TabbedComponent::clearTabs()
  108. {
  109. if (panelComponent != nullptr)
  110. {
  111. panelComponent->setVisible (false);
  112. removeChildComponent (panelComponent);
  113. panelComponent = nullptr;
  114. }
  115. tabs->clearTabs();
  116. for (int i = contentComponents.size(); --i >= 0;)
  117. TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (i));
  118. contentComponents.clear();
  119. }
  120. void TabbedComponent::addTab (const String& tabName,
  121. const Colour& tabBackgroundColour,
  122. Component* const contentComponent,
  123. const bool deleteComponentWhenNotNeeded,
  124. const int insertIndex)
  125. {
  126. contentComponents.insert (insertIndex, WeakReference<Component> (contentComponent));
  127. if (deleteComponentWhenNotNeeded && contentComponent != nullptr)
  128. contentComponent->getProperties().set (TabbedComponentHelpers::deleteComponentId, true);
  129. tabs->addTab (tabName, tabBackgroundColour, insertIndex);
  130. }
  131. void TabbedComponent::setTabName (const int tabIndex, const String& newName)
  132. {
  133. tabs->setTabName (tabIndex, newName);
  134. }
  135. void TabbedComponent::removeTab (const int tabIndex)
  136. {
  137. if (isPositiveAndBelow (tabIndex, contentComponents.size()))
  138. {
  139. TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (tabIndex));
  140. contentComponents.remove (tabIndex);
  141. tabs->removeTab (tabIndex);
  142. }
  143. }
  144. int TabbedComponent::getNumTabs() const
  145. {
  146. return tabs->getNumTabs();
  147. }
  148. StringArray TabbedComponent::getTabNames() const
  149. {
  150. return tabs->getTabNames();
  151. }
  152. Component* TabbedComponent::getTabContentComponent (const int tabIndex) const noexcept
  153. {
  154. return contentComponents [tabIndex];
  155. }
  156. const Colour TabbedComponent::getTabBackgroundColour (const int tabIndex) const noexcept
  157. {
  158. return tabs->getTabBackgroundColour (tabIndex);
  159. }
  160. void TabbedComponent::setTabBackgroundColour (const int tabIndex, const Colour& newColour)
  161. {
  162. tabs->setTabBackgroundColour (tabIndex, newColour);
  163. if (getCurrentTabIndex() == tabIndex)
  164. repaint();
  165. }
  166. void TabbedComponent::setCurrentTabIndex (const int newTabIndex, const bool sendChangeMessage)
  167. {
  168. tabs->setCurrentTabIndex (newTabIndex, sendChangeMessage);
  169. }
  170. int TabbedComponent::getCurrentTabIndex() const
  171. {
  172. return tabs->getCurrentTabIndex();
  173. }
  174. String TabbedComponent::getCurrentTabName() const
  175. {
  176. return tabs->getCurrentTabName();
  177. }
  178. void TabbedComponent::setOutline (const int thickness)
  179. {
  180. outlineThickness = thickness;
  181. resized();
  182. repaint();
  183. }
  184. void TabbedComponent::setIndent (const int indentThickness)
  185. {
  186. edgeIndent = indentThickness;
  187. resized();
  188. repaint();
  189. }
  190. void TabbedComponent::paint (Graphics& g)
  191. {
  192. g.fillAll (findColour (backgroundColourId));
  193. Rectangle<int> content (getLocalBounds());
  194. BorderSize<int> outline (outlineThickness);
  195. TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth);
  196. g.reduceClipRegion (content);
  197. g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex()));
  198. if (outlineThickness > 0)
  199. {
  200. RectangleList rl (content);
  201. rl.subtract (outline.subtractedFrom (content));
  202. g.reduceClipRegion (rl);
  203. g.fillAll (findColour (outlineColourId));
  204. }
  205. }
  206. void TabbedComponent::resized()
  207. {
  208. Rectangle<int> content (getLocalBounds());
  209. BorderSize<int> outline (outlineThickness);
  210. tabs->setBounds (TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth));
  211. content = BorderSize<int> (edgeIndent).subtractedFrom (outline.subtractedFrom (content));
  212. for (int i = contentComponents.size(); --i >= 0;)
  213. if (contentComponents.getReference (i) != nullptr)
  214. contentComponents.getReference (i)->setBounds (content);
  215. }
  216. void TabbedComponent::lookAndFeelChanged()
  217. {
  218. for (int i = contentComponents.size(); --i >= 0;)
  219. if (contentComponents.getReference (i) != nullptr)
  220. contentComponents.getReference (i)->lookAndFeelChanged();
  221. }
  222. void TabbedComponent::changeCallback (const int newCurrentTabIndex, const String& newTabName)
  223. {
  224. if (panelComponent != nullptr)
  225. {
  226. panelComponent->setVisible (false);
  227. removeChildComponent (panelComponent);
  228. panelComponent = nullptr;
  229. }
  230. if (getCurrentTabIndex() >= 0)
  231. {
  232. panelComponent = getTabContentComponent (getCurrentTabIndex());
  233. if (panelComponent != nullptr)
  234. {
  235. // do these ops as two stages instead of addAndMakeVisible() so that the
  236. // component has always got a parent when it gets the visibilityChanged() callback
  237. addChildComponent (panelComponent);
  238. panelComponent->setVisible (true);
  239. panelComponent->toFront (true);
  240. }
  241. repaint();
  242. }
  243. resized();
  244. currentTabChanged (newCurrentTabIndex, newTabName);
  245. }
  246. void TabbedComponent::currentTabChanged (const int, const String&) {}
  247. void TabbedComponent::popupMenuClickOnTab (const int, const String&) {}
  248. END_JUCE_NAMESPACE