123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316 |
- /*
- ==============================================================================
- This file is part of the JUCE library.
- Copyright (c) 2017 - ROLI Ltd.
- JUCE is an open source library subject to commercial or open-source
- licensing.
- By using JUCE, you agree to the terms of both the JUCE 5 End-User License
- Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
- 27th April 2017).
- End User License Agreement: www.juce.com/juce-5-licence
- Privacy Policy: www.juce.com/juce-5-privacy-policy
- Or: You may also use this code under the terms of the GPL v3 (see
- www.gnu.org/licenses).
- JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
- EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
- DISCLAIMED.
- ==============================================================================
- */
- namespace juce
- {
- namespace TabbedComponentHelpers
- {
- const Identifier deleteComponentId ("deleteByTabComp_");
- static void deleteIfNecessary (Component* comp)
- {
- if (comp != nullptr && (bool) comp->getProperties() [deleteComponentId])
- delete comp;
- }
- static Rectangle<int> getTabArea (Rectangle<int>& content, BorderSize<int>& outline,
- TabbedButtonBar::Orientation orientation, int tabDepth)
- {
- switch (orientation)
- {
- case TabbedButtonBar::TabsAtTop: outline.setTop (0); return content.removeFromTop (tabDepth);
- case TabbedButtonBar::TabsAtBottom: outline.setBottom (0); return content.removeFromBottom (tabDepth);
- case TabbedButtonBar::TabsAtLeft: outline.setLeft (0); return content.removeFromLeft (tabDepth);
- case TabbedButtonBar::TabsAtRight: outline.setRight (0); return content.removeFromRight (tabDepth);
- default: jassertfalse; break;
- }
- return Rectangle<int>();
- }
- }
- //==============================================================================
- struct TabbedComponent::ButtonBar : public TabbedButtonBar
- {
- ButtonBar (TabbedComponent& tabComp, TabbedButtonBar::Orientation o)
- : TabbedButtonBar (o), owner (tabComp)
- {
- }
- void currentTabChanged (int newCurrentTabIndex, const String& newTabName)
- {
- owner.changeCallback (newCurrentTabIndex, newTabName);
- }
- void popupMenuClickOnTab (int tabIndex, const String& tabName)
- {
- owner.popupMenuClickOnTab (tabIndex, tabName);
- }
- Colour getTabBackgroundColour (int tabIndex)
- {
- return owner.tabs->getTabBackgroundColour (tabIndex);
- }
- TabBarButton* createTabButton (const String& tabName, int tabIndex)
- {
- return owner.createTabButton (tabName, tabIndex);
- }
- TabbedComponent& owner;
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonBar)
- };
- //==============================================================================
- TabbedComponent::TabbedComponent (TabbedButtonBar::Orientation orientation)
- {
- tabs.reset (new ButtonBar (*this, orientation));
- addAndMakeVisible (tabs.get());
- }
- TabbedComponent::~TabbedComponent()
- {
- clearTabs();
- tabs.reset();
- }
- //==============================================================================
- void TabbedComponent::setOrientation (TabbedButtonBar::Orientation orientation)
- {
- tabs->setOrientation (orientation);
- resized();
- }
- TabbedButtonBar::Orientation TabbedComponent::getOrientation() const noexcept
- {
- return tabs->getOrientation();
- }
- void TabbedComponent::setTabBarDepth (int newDepth)
- {
- if (tabDepth != newDepth)
- {
- tabDepth = newDepth;
- resized();
- }
- }
- TabBarButton* TabbedComponent::createTabButton (const String& tabName, int /*tabIndex*/)
- {
- return new TabBarButton (tabName, *tabs);
- }
- //==============================================================================
- void TabbedComponent::clearTabs()
- {
- if (panelComponent != nullptr)
- {
- panelComponent->setVisible (false);
- removeChildComponent (panelComponent.get());
- panelComponent = nullptr;
- }
- tabs->clearTabs();
- for (int i = contentComponents.size(); --i >= 0;)
- TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (i));
- contentComponents.clear();
- }
- void TabbedComponent::addTab (const String& tabName,
- Colour tabBackgroundColour,
- Component* contentComponent,
- bool deleteComponentWhenNotNeeded,
- int insertIndex)
- {
- contentComponents.insert (insertIndex, WeakReference<Component> (contentComponent));
- if (deleteComponentWhenNotNeeded && contentComponent != nullptr)
- contentComponent->getProperties().set (TabbedComponentHelpers::deleteComponentId, true);
- tabs->addTab (tabName, tabBackgroundColour, insertIndex);
- resized();
- }
- void TabbedComponent::setTabName (int tabIndex, const String& newName)
- {
- tabs->setTabName (tabIndex, newName);
- }
- void TabbedComponent::removeTab (int tabIndex)
- {
- if (isPositiveAndBelow (tabIndex, contentComponents.size()))
- {
- TabbedComponentHelpers::deleteIfNecessary (contentComponents.getReference (tabIndex).get());
- contentComponents.remove (tabIndex);
- tabs->removeTab (tabIndex);
- }
- }
- void TabbedComponent::moveTab (int currentIndex, int newIndex, bool animate)
- {
- contentComponents.move (currentIndex, newIndex);
- tabs->moveTab (currentIndex, newIndex, animate);
- }
- int TabbedComponent::getNumTabs() const
- {
- return tabs->getNumTabs();
- }
- StringArray TabbedComponent::getTabNames() const
- {
- return tabs->getTabNames();
- }
- Component* TabbedComponent::getTabContentComponent (int tabIndex) const noexcept
- {
- return contentComponents[tabIndex].get();
- }
- Colour TabbedComponent::getTabBackgroundColour (int tabIndex) const noexcept
- {
- return tabs->getTabBackgroundColour (tabIndex);
- }
- void TabbedComponent::setTabBackgroundColour (int tabIndex, Colour newColour)
- {
- tabs->setTabBackgroundColour (tabIndex, newColour);
- if (getCurrentTabIndex() == tabIndex)
- repaint();
- }
- void TabbedComponent::setCurrentTabIndex (int newTabIndex, bool sendChangeMessage)
- {
- tabs->setCurrentTabIndex (newTabIndex, sendChangeMessage);
- }
- int TabbedComponent::getCurrentTabIndex() const
- {
- return tabs->getCurrentTabIndex();
- }
- String TabbedComponent::getCurrentTabName() const
- {
- return tabs->getCurrentTabName();
- }
- void TabbedComponent::setOutline (int thickness)
- {
- outlineThickness = thickness;
- resized();
- repaint();
- }
- void TabbedComponent::setIndent (int indentThickness)
- {
- edgeIndent = indentThickness;
- resized();
- repaint();
- }
- void TabbedComponent::paint (Graphics& g)
- {
- g.fillAll (findColour (backgroundColourId));
- auto content = getLocalBounds();
- BorderSize<int> outline (outlineThickness);
- TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth);
- g.reduceClipRegion (content);
- g.fillAll (tabs->getTabBackgroundColour (getCurrentTabIndex()));
- if (outlineThickness > 0)
- {
- RectangleList<int> rl (content);
- rl.subtract (outline.subtractedFrom (content));
- g.reduceClipRegion (rl);
- g.fillAll (findColour (outlineColourId));
- }
- }
- void TabbedComponent::resized()
- {
- auto content = getLocalBounds();
- BorderSize<int> outline (outlineThickness);
- tabs->setBounds (TabbedComponentHelpers::getTabArea (content, outline, getOrientation(), tabDepth));
- content = BorderSize<int> (edgeIndent).subtractedFrom (outline.subtractedFrom (content));
- for (auto& c : contentComponents)
- if (auto comp = c.get())
- comp->setBounds (content);
- }
- void TabbedComponent::lookAndFeelChanged()
- {
- for (auto& c : contentComponents)
- if (auto comp = c.get())
- comp->lookAndFeelChanged();
- }
- void TabbedComponent::changeCallback (int newCurrentTabIndex, const String& newTabName)
- {
- auto* newPanelComp = getTabContentComponent (getCurrentTabIndex());
- if (newPanelComp != panelComponent)
- {
- if (panelComponent != nullptr)
- {
- panelComponent->setVisible (false);
- removeChildComponent (panelComponent);
- }
- panelComponent = newPanelComp;
- if (panelComponent != nullptr)
- {
- // do these ops as two stages instead of addAndMakeVisible() so that the
- // component has always got a parent when it gets the visibilityChanged() callback
- addChildComponent (panelComponent);
- panelComponent->sendLookAndFeelChange();
- panelComponent->setVisible (true);
- panelComponent->toFront (true);
- }
- repaint();
- }
- resized();
- currentTabChanged (newCurrentTabIndex, newTabName);
- }
- void TabbedComponent::currentTabChanged (int, const String&) {}
- void TabbedComponent::popupMenuClickOnTab (int, const String&) {}
- } // namespace juce
|