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.

365 lines
10KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-7 by Raw Material Software ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the
  7. GNU General Public License, as published by the Free Software Foundation;
  8. either version 2 of the License, or (at your option) any later version.
  9. JUCE is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with JUCE; if not, visit www.gnu.org/licenses or write to the
  15. Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  16. Boston, MA 02111-1307 USA
  17. ------------------------------------------------------------------------------
  18. If you'd like to release a closed-source product which uses JUCE, commercial
  19. licenses are also available: visit www.rawmaterialsoftware.com/juce for
  20. more information.
  21. ==============================================================================
  22. */
  23. #include "../../../../juce_core/basics/juce_StandardHeader.h"
  24. BEGIN_JUCE_NAMESPACE
  25. #include "juce_TabbedComponent.h"
  26. #include "../../graphics/geometry/juce_RectangleList.h"
  27. //==============================================================================
  28. class TabCompButtonBar : public TabbedButtonBar
  29. {
  30. public:
  31. TabCompButtonBar (TabbedComponent* const owner_,
  32. const TabbedButtonBar::Orientation orientation)
  33. : TabbedButtonBar (orientation),
  34. owner (owner_)
  35. {
  36. }
  37. ~TabCompButtonBar()
  38. {
  39. }
  40. void currentTabChanged (const int newCurrentTabIndex,
  41. const String& newTabName)
  42. {
  43. owner->changeCallback (newCurrentTabIndex, newTabName);
  44. }
  45. void popupMenuClickOnTab (const int tabIndex,
  46. const String& tabName)
  47. {
  48. owner->popupMenuClickOnTab (tabIndex, tabName);
  49. }
  50. const Colour getTabBackgroundColour (const int tabIndex)
  51. {
  52. return owner->tabs->getTabBackgroundColour (tabIndex);
  53. }
  54. TabBarButton* createTabButton (const String& tabName, const int tabIndex)
  55. {
  56. return owner->createTabButton (tabName, tabIndex);
  57. }
  58. juce_UseDebuggingNewOperator
  59. private:
  60. TabbedComponent* const owner;
  61. TabCompButtonBar (const TabCompButtonBar&);
  62. const TabCompButtonBar& operator= (const TabCompButtonBar&);
  63. };
  64. TabbedComponent::TabbedComponent (const TabbedButtonBar::Orientation orientation)
  65. : panelComponent (0),
  66. tabDepth (30),
  67. outlineColour (Colours::grey),
  68. outlineThickness (1),
  69. edgeIndent (0)
  70. {
  71. addAndMakeVisible (tabs = new TabCompButtonBar (this, orientation));
  72. }
  73. TabbedComponent::~TabbedComponent()
  74. {
  75. clearTabs();
  76. delete tabs;
  77. }
  78. //==============================================================================
  79. void TabbedComponent::setOrientation (const TabbedButtonBar::Orientation orientation)
  80. {
  81. tabs->setOrientation (orientation);
  82. resized();
  83. }
  84. TabbedButtonBar::Orientation TabbedComponent::getOrientation() const throw()
  85. {
  86. return tabs->getOrientation();
  87. }
  88. void TabbedComponent::setTabBarDepth (const int newDepth)
  89. {
  90. if (tabDepth != newDepth)
  91. {
  92. tabDepth = newDepth;
  93. resized();
  94. }
  95. }
  96. TabBarButton* TabbedComponent::createTabButton (const String& tabName, const int tabIndex)
  97. {
  98. return new TabBarButton (tabName, tabs, tabIndex);
  99. }
  100. //==============================================================================
  101. void TabbedComponent::clearTabs()
  102. {
  103. if (panelComponent != 0)
  104. {
  105. panelComponent->setVisible (false);
  106. removeChildComponent (panelComponent);
  107. panelComponent = 0;
  108. }
  109. tabs->clearTabs();
  110. for (int i = contentComponents.size(); --i >= 0;)
  111. {
  112. Component* const c = contentComponents.getUnchecked(i);
  113. // be careful not to delete these components until they've been removed from the tab component
  114. jassert (c == 0 || c->isValidComponent());
  115. if (c != 0 && c->getComponentPropertyBool (T("deleteByTabComp_"), false, false))
  116. delete c;
  117. }
  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, contentComponent);
  127. if (contentComponent != 0)
  128. contentComponent->setComponentProperty (T("deleteByTabComp_"), deleteComponentWhenNotNeeded);
  129. tabs->addTab (tabName, tabBackgroundColour, insertIndex);
  130. }
  131. void TabbedComponent::setTabName (const int tabIndex,
  132. const String& newName)
  133. {
  134. tabs->setTabName (tabIndex, newName);
  135. }
  136. void TabbedComponent::removeTab (const int tabIndex)
  137. {
  138. Component* const c = contentComponents [tabIndex];
  139. if (c != 0 && c->getComponentPropertyBool (T("deleteByTabComp_"), false, false))
  140. {
  141. if (c == panelComponent)
  142. panelComponent = 0;
  143. delete c;
  144. }
  145. contentComponents.remove (tabIndex);
  146. tabs->removeTab (tabIndex);
  147. }
  148. int TabbedComponent::getNumTabs() const
  149. {
  150. return tabs->getNumTabs();
  151. }
  152. const StringArray TabbedComponent::getTabNames() const
  153. {
  154. return tabs->getTabNames();
  155. }
  156. Component* TabbedComponent::getTabContentComponent (const int tabIndex) const throw()
  157. {
  158. return contentComponents [tabIndex];
  159. }
  160. const Colour TabbedComponent::getTabBackgroundColour (const int tabIndex) const throw()
  161. {
  162. return tabs->getTabBackgroundColour (tabIndex);
  163. }
  164. void TabbedComponent::setTabBackgroundColour (const int tabIndex, const Colour& newColour)
  165. {
  166. tabs->setTabBackgroundColour (tabIndex, newColour);
  167. if (getCurrentTabIndex() == tabIndex)
  168. repaint();
  169. }
  170. void TabbedComponent::setCurrentTabIndex (const int newTabIndex)
  171. {
  172. tabs->setCurrentTabIndex (newTabIndex);
  173. }
  174. int TabbedComponent::getCurrentTabIndex() const
  175. {
  176. return tabs->getCurrentTabIndex();
  177. }
  178. const String& TabbedComponent::getCurrentTabName() const
  179. {
  180. return tabs->getCurrentTabName();
  181. }
  182. void TabbedComponent::setOutline (const Colour& colour, int thickness)
  183. {
  184. outlineColour = colour;
  185. outlineThickness = thickness;
  186. repaint();
  187. }
  188. void TabbedComponent::setIndent (const int indentThickness)
  189. {
  190. edgeIndent = indentThickness;
  191. }
  192. void TabbedComponent::paint (Graphics& g)
  193. {
  194. const TabbedButtonBar::Orientation o = getOrientation();
  195. int x = 0;
  196. int y = 0;
  197. int r = getWidth();
  198. int b = getHeight();
  199. if (o == TabbedButtonBar::TabsAtTop)
  200. y += tabDepth;
  201. else if (o == TabbedButtonBar::TabsAtBottom)
  202. b -= tabDepth;
  203. else if (o == TabbedButtonBar::TabsAtLeft)
  204. x += tabDepth;
  205. else if (o == TabbedButtonBar::TabsAtRight)
  206. r -= tabDepth;
  207. g.reduceClipRegion (x, y, r - x, b - y);
  208. g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex()));
  209. if (outlineThickness > 0)
  210. {
  211. if (o == TabbedButtonBar::TabsAtTop)
  212. --y;
  213. else if (o == TabbedButtonBar::TabsAtBottom)
  214. ++b;
  215. else if (o == TabbedButtonBar::TabsAtLeft)
  216. --x;
  217. else if (o == TabbedButtonBar::TabsAtRight)
  218. ++r;
  219. g.setColour (outlineColour);
  220. g.drawRect (x, y, r - x, b - y, outlineThickness);
  221. }
  222. }
  223. void TabbedComponent::resized()
  224. {
  225. const TabbedButtonBar::Orientation o = getOrientation();
  226. const int indent = edgeIndent + outlineThickness;
  227. BorderSize indents (indent);
  228. if (o == TabbedButtonBar::TabsAtTop)
  229. {
  230. tabs->setBounds (0, 0, getWidth(), tabDepth);
  231. indents.setTop (tabDepth + edgeIndent);
  232. }
  233. else if (o == TabbedButtonBar::TabsAtBottom)
  234. {
  235. tabs->setBounds (0, getHeight() - tabDepth, getWidth(), tabDepth);
  236. indents.setBottom (tabDepth + edgeIndent);
  237. }
  238. else if (o == TabbedButtonBar::TabsAtLeft)
  239. {
  240. tabs->setBounds (0, 0, tabDepth, getHeight());
  241. indents.setLeft (tabDepth + edgeIndent);
  242. }
  243. else if (o == TabbedButtonBar::TabsAtRight)
  244. {
  245. tabs->setBounds (getWidth() - tabDepth, 0, tabDepth, getHeight());
  246. indents.setRight (tabDepth + edgeIndent);
  247. }
  248. const Rectangle bounds (indents.subtractedFrom (Rectangle (0, 0, getWidth(), getHeight())));
  249. for (int i = contentComponents.size(); --i >= 0;)
  250. if (contentComponents.getUnchecked (i) != 0)
  251. contentComponents.getUnchecked (i)->setBounds (bounds);
  252. }
  253. void TabbedComponent::lookAndFeelChanged()
  254. {
  255. for (int i = contentComponents.size(); --i >= 0;)
  256. if (contentComponents.getUnchecked (i) != 0)
  257. contentComponents.getUnchecked (i)->lookAndFeelChanged();
  258. }
  259. void TabbedComponent::changeCallback (const int newCurrentTabIndex,
  260. const String& newTabName)
  261. {
  262. if (panelComponent != 0)
  263. {
  264. panelComponent->setVisible (false);
  265. removeChildComponent (panelComponent);
  266. panelComponent = 0;
  267. }
  268. if (getCurrentTabIndex() >= 0)
  269. {
  270. panelComponent = contentComponents [getCurrentTabIndex()];
  271. if (panelComponent != 0)
  272. {
  273. // do these ops as two stages instead of addAndMakeVisible() so that the
  274. // component has always got a parent when it gets the visibilityChanged() callback
  275. addChildComponent (panelComponent);
  276. panelComponent->setVisible (true);
  277. panelComponent->toFront (true);
  278. }
  279. repaint();
  280. }
  281. resized();
  282. currentTabChanged (newCurrentTabIndex, newTabName);
  283. }
  284. void TabbedComponent::currentTabChanged (const int, const String&)
  285. {
  286. }
  287. void TabbedComponent::popupMenuClickOnTab (const int, const String&)
  288. {
  289. }
  290. END_JUCE_NAMESPACE