1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 
29 //==============================================================================
30 /**
31     A component with a TabbedButtonBar along one of its sides.
32 
33     This makes it easy to create a set of tabbed pages, just add a bunch of tabs
34     with addTab(), and this will take care of showing the pages for you when the
35     user clicks on a different tab.
36 
37     @see TabbedButtonBar
38 
39     @tags{GUI}
40 */
41 class JUCE_API  TabbedComponent  : public Component
42 {
43 public:
44     //==============================================================================
45     /** Creates a TabbedComponent, specifying where the tabs should be placed.
46         Once created, add some tabs with the addTab() method.
47     */
48     explicit TabbedComponent (TabbedButtonBar::Orientation orientation);
49 
50     /** Destructor. */
51     ~TabbedComponent() override;
52 
53     //==============================================================================
54     /** Changes the placement of the tabs.
55 
56         This will rearrange the layout to place the tabs along the appropriate
57         side of this component, and will shift the content component accordingly.
58 
59         @see TabbedButtonBar::setOrientation
60     */
61     void setOrientation (TabbedButtonBar::Orientation orientation);
62 
63     /** Returns the current tab placement.
64         @see setOrientation, TabbedButtonBar::getOrientation
65     */
66     TabbedButtonBar::Orientation getOrientation() const noexcept;
67 
68     /** Specifies how many pixels wide or high the tab-bar should be.
69 
70         If the tabs are placed along the top or bottom, this specified the height
71         of the bar; if they're along the left or right edges, it'll be the width
72         of the bar.
73     */
74     void setTabBarDepth (int newDepth);
75 
76     /** Returns the current thickness of the tab bar.
77         @see setTabBarDepth
78     */
getTabBarDepth()79     int getTabBarDepth() const noexcept                         { return tabDepth; }
80 
81     /** Specifies the thickness of an outline that should be drawn around the content component.
82 
83         If this thickness is > 0, a line will be drawn around the three sides of the content
84         component which don't touch the tab-bar, and the content component will be inset by this amount.
85 
86         To set the colour of the line, use setColour (outlineColourId, ...).
87     */
88     void setOutline (int newThickness);
89 
90     /** Specifies a gap to leave around the edge of the content component.
91         Each edge of the content component will be indented by the given number of pixels.
92     */
93     void setIndent (int indentThickness);
94 
95     //==============================================================================
96     /** Removes all the tabs from the bar.
97         @see TabbedButtonBar::clearTabs
98     */
99     void clearTabs();
100 
101     /** Adds a tab to the tab-bar.
102 
103         The component passed in will be shown for the tab. If deleteComponentWhenNotNeeded
104         is true, then the TabbedComponent will take ownership of the component and will delete
105         it when the tab is removed or when this object is deleted.
106 
107         @see TabbedButtonBar::addTab
108     */
109     void addTab (const String& tabName,
110                  Colour tabBackgroundColour,
111                  Component* contentComponent,
112                  bool deleteComponentWhenNotNeeded,
113                  int insertIndex = -1);
114 
115     /** Changes the name of one of the tabs. */
116     void setTabName (int tabIndex, const String& newName);
117 
118     /** Gets rid of one of the tabs. */
119     void removeTab (int tabIndex);
120 
121     /** Moves a tab to a new index in the list.
122         Pass -1 as the index to move it to the end of the list.
123     */
124     void moveTab (int currentIndex, int newIndex, bool animate = false);
125 
126     /** Returns the number of tabs in the bar. */
127     int getNumTabs() const;
128 
129     /** Returns a list of all the tab names in the bar. */
130     StringArray getTabNames() const;
131 
132     /** Returns the content component that was added for the given index.
133         Be careful not to reposition or delete the components that are returned, as
134         this will interfere with the TabbedComponent's behaviour.
135     */
136     Component* getTabContentComponent (int tabIndex) const noexcept;
137 
138     /** Returns the colour of one of the tabs. */
139     Colour getTabBackgroundColour (int tabIndex) const noexcept;
140 
141     /** Changes the background colour of one of the tabs. */
142     void setTabBackgroundColour (int tabIndex, Colour newColour);
143 
144     //==============================================================================
145     /** Changes the currently-selected tab.
146         To deselect all the tabs, pass -1 as the index.
147         @see TabbedButtonBar::setCurrentTabIndex
148     */
149     void setCurrentTabIndex (int newTabIndex, bool sendChangeMessage = true);
150 
151     /** Returns the index of the currently selected tab.
152         @see addTab, TabbedButtonBar::getCurrentTabIndex()
153     */
154     int getCurrentTabIndex() const;
155 
156     /** Returns the name of the currently selected tab.
157         @see addTab, TabbedButtonBar::getCurrentTabName()
158     */
159     String getCurrentTabName() const;
160 
161     /** Returns the current component that's filling the panel.
162         This will return nullptr if there isn't one.
163     */
getCurrentContentComponent()164     Component* getCurrentContentComponent() const noexcept          { return panelComponent.get(); }
165 
166     //==============================================================================
167     /** Callback method to indicate the selected tab has been changed.
168         @see setCurrentTabIndex
169     */
170     virtual void currentTabChanged (int newCurrentTabIndex, const String& newCurrentTabName);
171 
172     /** Callback method to indicate that the user has right-clicked on a tab. */
173     virtual void popupMenuClickOnTab (int tabIndex, const String& tabName);
174 
175     /** Returns the tab button bar component that is being used. */
getTabbedButtonBar()176     TabbedButtonBar& getTabbedButtonBar() const noexcept            { return *tabs; }
177 
178     //==============================================================================
179     /** A set of colour IDs to use to change the colour of various aspects of the component.
180 
181         These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
182         methods.
183 
184         @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
185     */
186     enum ColourIds
187     {
188         backgroundColourId          = 0x1005800,    /**< The colour to fill the background behind the tabs. */
189         outlineColourId             = 0x1005801,    /**< The colour to use to draw an outline around the content.
190                                                          (See setOutline)  */
191     };
192 
193     //==============================================================================
194     /** @internal */
195     void paint (Graphics&) override;
196     /** @internal */
197     void resized() override;
198     /** @internal */
199     void lookAndFeelChanged() override;
200 
201 protected:
202     //==============================================================================
203     /** This creates one of the tab buttons.
204 
205         If you need to use custom tab components, you can override this method and
206         return your own class instead of the default.
207     */
208     virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
209 
210     /** @internal */
211     std::unique_ptr<TabbedButtonBar> tabs;
212 
213 private:
214     //==============================================================================
215     Array<WeakReference<Component>> contentComponents;
216     WeakReference<Component> panelComponent;
217     int tabDepth = 30, outlineThickness = 1, edgeIndent = 0;
218 
219     struct ButtonBar;
220     void changeCallback (int newCurrentTabIndex, const String& newTabName);
221 
222     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent)
223 };
224 
225 } // namespace juce
226