|
- /*
- ==============================================================================
-
- This file is part of the JUCE library.
- Copyright (c) 2020 - Raw Material Software Limited
-
- 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 6 End-User License
- Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
-
- End User License Agreement: www.juce.com/juce-6-licence
- Privacy Policy: www.juce.com/juce-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
- {
-
- class TabbedButtonBar;
-
-
- //==============================================================================
- /** In a TabbedButtonBar, this component is used for each of the buttons.
-
- If you want to create a TabbedButtonBar with custom tab components, derive
- your component from this class, and override the TabbedButtonBar::createTabButton()
- method to create it instead of the default one.
-
- @see TabbedButtonBar
-
- @tags{GUI}
- */
- class JUCE_API TabBarButton : public Button
- {
- public:
- //==============================================================================
- /** Creates the tab button. */
- TabBarButton (const String& name, TabbedButtonBar& ownerBar);
-
- /** Destructor. */
- ~TabBarButton() override;
-
- /** Returns the bar that contains this button. */
- TabbedButtonBar& getTabbedButtonBar() const { return owner; }
-
- //==============================================================================
- /** When adding an extra component to the tab, this indicates which side of
- the text it should be placed on. */
- enum ExtraComponentPlacement
- {
- beforeText,
- afterText
- };
-
- /** Sets an extra component that will be shown in the tab.
-
- This optional component will be positioned inside the tab, either to the left or right
- of the text. You could use this to implement things like a close button or a graphical
- status indicator. If a non-null component is passed-in, the TabbedButtonBar will take
- ownership of it and delete it when required.
- */
- void setExtraComponent (Component* extraTabComponent,
- ExtraComponentPlacement extraComponentPlacement);
-
- /** Returns the custom component, if there is one. */
- Component* getExtraComponent() const noexcept { return extraComponent.get(); }
-
- /** Returns the placement of the custom component, if there is one. */
- ExtraComponentPlacement getExtraComponentPlacement() const noexcept { return extraCompPlacement; }
-
- /** Returns an area of the component that's safe to draw in.
-
- This deals with the orientation of the tabs, which affects which side is
- touching the tabbed box's content component.
- */
- Rectangle<int> getActiveArea() const;
-
- /** Returns the area of the component that should contain its text. */
- Rectangle<int> getTextArea() const;
-
- /** Returns this tab's index in its tab bar. */
- int getIndex() const;
-
- /** Returns the colour of the tab. */
- Colour getTabBackgroundColour() const;
-
- /** Returns true if this is the frontmost (selected) tab. */
- bool isFrontTab() const;
-
- //==============================================================================
- /** Chooses the best length for the tab, given the specified depth.
-
- If the tab is horizontal, this should return its width, and the depth
- specifies its height. If it's vertical, it should return the height, and
- the depth is actually its width.
- */
- virtual int getBestTabLength (int depth);
-
- //==============================================================================
- /** @internal */
- void paintButton (Graphics&, bool, bool) override;
- /** @internal */
- void clicked (const ModifierKeys&) override;
- /** @internal */
- bool hitTest (int x, int y) override;
- /** @internal */
- void resized() override;
- /** @internal */
- void childBoundsChanged (Component*) override;
-
- protected:
- friend class TabbedButtonBar;
- TabbedButtonBar& owner;
- int overlapPixels = 0;
-
- std::unique_ptr<Component> extraComponent;
- ExtraComponentPlacement extraCompPlacement = afterText;
-
- private:
- using Button::clicked;
- void calcAreas (Rectangle<int>&, Rectangle<int>&) const;
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabBarButton)
- };
-
-
- //==============================================================================
- /**
- A vertical or horizontal bar containing tabs that you can select.
-
- You can use one of these to generate things like a dialog box that has
- tabbed pages you can flip between. Attach a ChangeListener to the
- button bar to be told when the user changes the page.
-
- An easier method than doing this is to use a TabbedComponent, which
- contains its own TabbedButtonBar and which takes care of the layout
- and other housekeeping.
-
- @see TabbedComponent
-
- @tags{GUI}
- */
- class JUCE_API TabbedButtonBar : public Component,
- public ChangeBroadcaster
- {
- public:
- //==============================================================================
- /** The placement of the tab-bar
- @see setOrientation, getOrientation
- */
- enum Orientation
- {
- TabsAtTop,
- TabsAtBottom,
- TabsAtLeft,
- TabsAtRight
- };
-
- //==============================================================================
- /** Creates a TabbedButtonBar with a given orientation.
- You can change the orientation later if you need to.
- */
- TabbedButtonBar (Orientation orientation);
-
- /** Destructor. */
- ~TabbedButtonBar() override;
-
- //==============================================================================
- /** Changes the bar's orientation.
-
- This won't change the bar's actual size - you'll need to do that yourself,
- but this determines which direction the tabs go in, and which side they're
- stuck to.
- */
- void setOrientation (Orientation orientation);
-
- /** Returns the bar's current orientation.
- @see setOrientation
- */
- Orientation getOrientation() const noexcept { return orientation; }
-
- /** Returns true if the orientation is TabsAtLeft or TabsAtRight. */
- bool isVertical() const noexcept { return orientation == TabsAtLeft || orientation == TabsAtRight; }
-
- /** Returns the thickness of the bar, which may be its width or height, depending on the orientation. */
- int getThickness() const noexcept { return isVertical() ? getWidth() : getHeight(); }
-
- /** Changes the minimum scale factor to which the tabs can be compressed when trying to
- fit a lot of tabs on-screen.
- */
- void setMinimumTabScaleFactor (double newMinimumScale);
-
- //==============================================================================
- /** Deletes all the tabs from the bar.
- @see addTab
- */
- void clearTabs();
-
- /** Adds a tab to the bar.
- Tabs are added in left-to-right reading order.
- If this is the first tab added, it'll also be automatically selected.
- */
- void addTab (const String& tabName,
- Colour tabBackgroundColour,
- int insertIndex);
-
- /** Changes the name of one of the tabs. */
- void setTabName (int tabIndex, const String& newName);
-
- /** Gets rid of one of the tabs. */
- void removeTab (int tabIndex, bool animate = false);
-
- /** Moves a tab to a new index in the list.
- Pass -1 as the index to move it to the end of the list.
- */
- void moveTab (int currentIndex, int newIndex, bool animate = false);
-
- /** Returns the number of tabs in the bar. */
- int getNumTabs() const;
-
- /** Returns a list of all the tab names in the bar. */
- StringArray getTabNames() const;
-
- /** Changes the currently selected tab.
- This will send a change message and cause a synchronous callback to
- the currentTabChanged() method. (But if the given tab is already selected,
- nothing will be done).
-
- To deselect all the tabs, use an index of -1.
- */
- void setCurrentTabIndex (int newTabIndex, bool sendChangeMessage = true);
-
- /** Returns the name of the currently selected tab.
- This could be an empty string if none are selected.
- */
- String getCurrentTabName() const;
-
- /** Returns the index of the currently selected tab.
- This could return -1 if none are selected.
- */
- int getCurrentTabIndex() const noexcept { return currentTabIndex; }
-
- /** Returns the button for a specific tab.
- The button that is returned may be deleted later by this component, so don't hang
- on to the pointer that is returned. A null pointer may be returned if the index is
- out of range.
- */
- TabBarButton* getTabButton (int index) const;
-
- /** Returns the index of a TabBarButton if it belongs to this bar. */
- int indexOfTabButton (const TabBarButton* button) const;
-
- /** Returns the final bounds of this button if it is currently being animated. */
- Rectangle<int> getTargetBounds (TabBarButton* button) const;
-
- //==============================================================================
- /** Callback method to indicate the selected tab has been changed.
- @see setCurrentTabIndex
- */
- virtual void currentTabChanged (int newCurrentTabIndex,
- const String& newCurrentTabName);
-
- /** Callback method to indicate that the user has right-clicked on a tab. */
- virtual void popupMenuClickOnTab (int tabIndex, const String& tabName);
-
- /** Returns the colour of a tab.
- This is the colour that was specified in addTab().
- */
- Colour getTabBackgroundColour (int tabIndex);
-
- /** Changes the background colour of a tab.
- @see addTab, getTabBackgroundColour
- */
- void setTabBackgroundColour (int tabIndex, Colour newColour);
-
- //==============================================================================
- /** A set of colour IDs to use to change the colour of various aspects of the component.
-
- These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
- methods.
-
- @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
- */
- enum ColourIds
- {
- tabOutlineColourId = 0x1005812, /**< The colour to use to draw an outline around the tabs. */
- tabTextColourId = 0x1005813, /**< The colour to use to draw the tab names. If this isn't specified,
- the look and feel will choose an appropriate colour. */
- frontOutlineColourId = 0x1005814, /**< The colour to use to draw an outline around the currently-selected tab. */
- frontTextColourId = 0x1005815, /**< The colour to use to draw the currently-selected tab name. If
- this isn't specified, the look and feel will choose an appropriate
- colour. */
- };
-
- //==============================================================================
- /** This abstract base class is implemented by LookAndFeel classes to provide
- window drawing functionality.
- */
- struct JUCE_API LookAndFeelMethods
- {
- virtual ~LookAndFeelMethods() = default;
-
- virtual int getTabButtonSpaceAroundImage() = 0;
- virtual int getTabButtonOverlap (int tabDepth) = 0;
- virtual int getTabButtonBestWidth (TabBarButton&, int tabDepth) = 0;
- virtual Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) = 0;
-
- virtual void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0;
- virtual Font getTabButtonFont (TabBarButton&, float height) = 0;
- virtual void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0;
- virtual void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) = 0;
- virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) = 0;
-
- virtual void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown) = 0;
- virtual void fillTabButtonShape (TabBarButton&, Graphics&, const Path& path, bool isMouseOver, bool isMouseDown) = 0;
-
- virtual Button* createTabBarExtrasButton() = 0;
- };
-
- //==============================================================================
- /** @internal */
- void paint (Graphics&) override;
- /** @internal */
- void resized() override;
- /** @internal */
- void lookAndFeelChanged() override;
-
- protected:
- //==============================================================================
- /** This creates one of the tabs.
-
- If you need to use custom tab components, you can override this method and
- return your own class instead of the default.
- */
- virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
-
- private:
- struct TabInfo
- {
- std::unique_ptr<TabBarButton> button;
- String name;
- Colour colour;
- };
-
- OwnedArray<TabInfo> tabs;
-
- Orientation orientation;
- double minimumScale = 0.7;
- int currentTabIndex = -1;
-
- class BehindFrontTabComp;
- std::unique_ptr<BehindFrontTabComp> behindFrontTab;
- std::unique_ptr<Button> extraTabsButton;
-
- void showExtraItemsMenu();
- void updateTabPositions (bool animate);
-
- JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedButtonBar)
- };
-
- } // namespace juce
|