2 ==============================================================================
4 This file is part of the JUCE library.
5 Copyright (c) 2022 - Raw Material Software Limited
7 JUCE is an open source library subject to commercial or open-source
10 By using JUCE, you agree to the terms of both the JUCE 7 End-User License
11 Agreement and JUCE Privacy Policy.
13 End User License Agreement: www.juce.com/juce-7-licence
14 Privacy Policy: www.juce.com/juce-privacy-policy
16 Or: You may also use this code under the terms of the GPL v3 (see
17 www.gnu.org/licenses).
19 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
23 ==============================================================================
29 namespace TabbedComponentHelpers
31 const Identifier
deleteComponentId ("deleteByTabComp_");
33 static void deleteIfNecessary (Component
* comp
)
35 if (comp
!= nullptr && (bool) comp
->getProperties() [deleteComponentId
])
39 static Rectangle
<int> getTabArea (Rectangle
<int>& content
, BorderSize
<int>& outline
,
40 TabbedButtonBar::Orientation orientation
, int tabDepth
)
44 case TabbedButtonBar::TabsAtTop
: outline
.setTop (0); return content
.removeFromTop (tabDepth
);
45 case TabbedButtonBar::TabsAtBottom
: outline
.setBottom (0); return content
.removeFromBottom (tabDepth
);
46 case TabbedButtonBar::TabsAtLeft
: outline
.setLeft (0); return content
.removeFromLeft (tabDepth
);
47 case TabbedButtonBar::TabsAtRight
: outline
.setRight (0); return content
.removeFromRight (tabDepth
);
48 default: jassertfalse
; break;
51 return Rectangle
<int>();
55 //==============================================================================
56 struct TabbedComponent::ButtonBar
: public TabbedButtonBar
58 ButtonBar (TabbedComponent
& tabComp
, TabbedButtonBar::Orientation o
)
59 : TabbedButtonBar (o
), owner (tabComp
)
63 void currentTabChanged (int newCurrentTabIndex
, const String
& newTabName
)
65 owner
.changeCallback (newCurrentTabIndex
, newTabName
);
68 void popupMenuClickOnTab (int tabIndex
, const String
& tabName
)
70 owner
.popupMenuClickOnTab (tabIndex
, tabName
);
73 Colour
getTabBackgroundColour (int tabIndex
)
75 return owner
.tabs
->getTabBackgroundColour (tabIndex
);
78 TabBarButton
* createTabButton (const String
& tabName
, int tabIndex
)
80 return owner
.createTabButton (tabName
, tabIndex
);
83 TabbedComponent
& owner
;
85 JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar
)
88 //==============================================================================
89 TabbedComponent::TabbedComponent (TabbedButtonBar::Orientation orientation
)
91 tabs
.reset (new ButtonBar (*this, orientation
));
92 addAndMakeVisible (tabs
.get());
95 TabbedComponent::~TabbedComponent()
101 //==============================================================================
102 void TabbedComponent::setOrientation (TabbedButtonBar::Orientation orientation
)
104 tabs
->setOrientation (orientation
);
108 TabbedButtonBar::Orientation
TabbedComponent::getOrientation() const noexcept
110 return tabs
->getOrientation();
113 void TabbedComponent::setTabBarDepth (int newDepth
)
115 if (tabDepth
!= newDepth
)
122 TabBarButton
* TabbedComponent::createTabButton (const String
& tabName
, int /*tabIndex*/)
124 return new TabBarButton (tabName
, *tabs
);
127 //==============================================================================
128 void TabbedComponent::clearTabs()
130 if (panelComponent
!= nullptr)
132 panelComponent
->setVisible (false);
133 removeChildComponent (panelComponent
.get());
134 panelComponent
= nullptr;
139 for (int i
= contentComponents
.size(); --i
>= 0;)
140 TabbedComponentHelpers::deleteIfNecessary (contentComponents
.getReference (i
));
142 contentComponents
.clear();
145 void TabbedComponent::addTab (const String
& tabName
,
146 Colour tabBackgroundColour
,
147 Component
* contentComponent
,
148 bool deleteComponentWhenNotNeeded
,
151 contentComponents
.insert (insertIndex
, WeakReference
<Component
> (contentComponent
));
153 if (deleteComponentWhenNotNeeded
&& contentComponent
!= nullptr)
154 contentComponent
->getProperties().set (TabbedComponentHelpers::deleteComponentId
, true);
156 tabs
->addTab (tabName
, tabBackgroundColour
, insertIndex
);
160 void TabbedComponent::setTabName (int tabIndex
, const String
& newName
)
162 tabs
->setTabName (tabIndex
, newName
);
165 void TabbedComponent::removeTab (int tabIndex
)
167 if (isPositiveAndBelow (tabIndex
, contentComponents
.size()))
169 TabbedComponentHelpers::deleteIfNecessary (contentComponents
.getReference (tabIndex
).get());
170 contentComponents
.remove (tabIndex
);
171 tabs
->removeTab (tabIndex
);
175 void TabbedComponent::moveTab (int currentIndex
, int newIndex
, bool animate
)
177 contentComponents
.move (currentIndex
, newIndex
);
178 tabs
->moveTab (currentIndex
, newIndex
, animate
);
181 int TabbedComponent::getNumTabs() const
183 return tabs
->getNumTabs();
186 StringArray
TabbedComponent::getTabNames() const
188 return tabs
->getTabNames();
191 Component
* TabbedComponent::getTabContentComponent (int tabIndex
) const noexcept
193 return contentComponents
[tabIndex
].get();
196 Colour
TabbedComponent::getTabBackgroundColour (int tabIndex
) const noexcept
198 return tabs
->getTabBackgroundColour (tabIndex
);
201 void TabbedComponent::setTabBackgroundColour (int tabIndex
, Colour newColour
)
203 tabs
->setTabBackgroundColour (tabIndex
, newColour
);
205 if (getCurrentTabIndex() == tabIndex
)
209 void TabbedComponent::setCurrentTabIndex (int newTabIndex
, bool sendChangeMessage
)
211 tabs
->setCurrentTabIndex (newTabIndex
, sendChangeMessage
);
214 int TabbedComponent::getCurrentTabIndex() const
216 return tabs
->getCurrentTabIndex();
219 String
TabbedComponent::getCurrentTabName() const
221 return tabs
->getCurrentTabName();
224 void TabbedComponent::setOutline (int thickness
)
226 outlineThickness
= thickness
;
231 void TabbedComponent::setIndent (int indentThickness
)
233 edgeIndent
= indentThickness
;
238 void TabbedComponent::paint (Graphics
& g
)
240 g
.fillAll (findColour (backgroundColourId
));
242 auto content
= getLocalBounds();
243 BorderSize
<int> outline (outlineThickness
);
244 TabbedComponentHelpers::getTabArea (content
, outline
, getOrientation(), tabDepth
);
246 g
.reduceClipRegion (content
);
247 g
.fillAll (tabs
->getTabBackgroundColour (getCurrentTabIndex()));
249 if (outlineThickness
> 0)
251 RectangleList
<int> rl (content
);
252 rl
.subtract (outline
.subtractedFrom (content
));
254 g
.reduceClipRegion (rl
);
255 g
.fillAll (findColour (outlineColourId
));
259 void TabbedComponent::resized()
261 auto content
= getLocalBounds();
262 BorderSize
<int> outline (outlineThickness
);
264 tabs
->setBounds (TabbedComponentHelpers::getTabArea (content
, outline
, getOrientation(), tabDepth
));
265 content
= BorderSize
<int> (edgeIndent
).subtractedFrom (outline
.subtractedFrom (content
));
267 for (auto& c
: contentComponents
)
268 if (auto comp
= c
.get())
269 comp
->setBounds (content
);
272 void TabbedComponent::lookAndFeelChanged()
274 for (auto& c
: contentComponents
)
275 if (auto comp
= c
.get())
276 comp
->lookAndFeelChanged();
279 void TabbedComponent::changeCallback (int newCurrentTabIndex
, const String
& newTabName
)
281 auto* newPanelComp
= getTabContentComponent (getCurrentTabIndex());
283 if (newPanelComp
!= panelComponent
)
285 if (panelComponent
!= nullptr)
287 panelComponent
->setVisible (false);
288 removeChildComponent (panelComponent
);
291 panelComponent
= newPanelComp
;
293 if (panelComponent
!= nullptr)
295 // do these ops as two stages instead of addAndMakeVisible() so that the
296 // component has always got a parent when it gets the visibilityChanged() callback
297 addChildComponent (panelComponent
);
298 panelComponent
->sendLookAndFeelChange();
299 panelComponent
->setVisible (true);
300 panelComponent
->toFront (true);
307 currentTabChanged (newCurrentTabIndex
, newTabName
);
310 void TabbedComponent::currentTabChanged (int, const String
&) {}
311 void TabbedComponent::popupMenuClickOnTab (int, const String
&) {}
313 //==============================================================================
314 std::unique_ptr
<AccessibilityHandler
> TabbedComponent::createAccessibilityHandler()
316 return std::make_unique
<AccessibilityHandler
> (*this, AccessibilityRole::group
);