This patch contains 3 parts:
- Scaling tabs to fit into a too small tabbed-button-bar is smoother and less jumpy while resizing
- Parameters affecting scaling can be configured and scaling can be disabled completely
- The position and size of the extra tabs button is controlled by the look-and-feel
Perhaps you want to merge this into the official JUCE codebase, jules.
[code]diff -d -r -u old/juce/juce_LookAndFeel.cpp new/juce/juce_LookAndFeel.cpp
— old/juce/juce_LookAndFeel.cpp
+++ new/juce/juce_LookAndFeel.cpp
@@ -2194,6 +2194,32 @@
return db;
}
+int LookAndFeel::positionTabBarExtrasButton (TabbedButtonBar &tabbedButtonBar,
-
int width, int height,
-
int orientation,
-
Button *tabBarExtrasButton)
+{
- int centre;
- const int buttonSize = jmin (tabbedButtonBar.proportionOfWidth (0.7f),
-
tabbedButtonBar.proportionOfHeight (0.7f));
- tabBarExtrasButton->setSize (buttonSize, buttonSize);
- if (orientation == TabbedButtonBar::TabsAtTop || orientation == TabbedButtonBar::TabsAtBottom)
- {
-
centre = width - buttonSize / 2 - 1;
-
tabBarExtrasButton->setCentrePosition (centre, height / 2);
- }
- else
- {
-
centre = height - buttonSize / 2 - 1;
-
tabBarExtrasButton->setCentrePosition (width / 2, centre);
- }
- return centre;
+}
//==============================================================================
void LookAndFeel::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header)
diff -d -r -u old/juce/juce_LookAndFeel.h new/juce/juce_LookAndFeel.h
— old/juce/juce_LookAndFeel.h
+++ new/juce/juce_LookAndFeel.h
@@ -514,6 +514,11 @@
virtual Button* createTabBarExtrasButton();
- virtual int positionTabBarExtrasButton (TabbedButtonBar &tabbedButtonBar,
-
int width, int height,
-
int orientation,
-
Button *tabBarExtrasButton);
- //==============================================================================
virtual void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header);
diff -d -r -u old/juce/juce_TabbedButtonBar.cpp new/juce/juce_TabbedButtonBar.cpp
— old/juce/juce_TabbedButtonBar.cpp
+++ new/juce/juce_TabbedButtonBar.cpp
@@ -183,7 +183,9 @@
TabbedButtonBar::TabbedButtonBar (const Orientation orientation_)
: orientation (orientation_),
currentTabIndex (-1),
-
extraTabsButton (0)
-
extraTabsButton (0),
-
minimumScale (0.7),
-
upscalingEnabled (true)
{
setInterceptsMouseClicks (false, true);
addAndMakeVisible (behindFrontTab = new TabAreaBehindFrontButtonComponent (this));
@@ -368,9 +370,22 @@
resized();
}
+void TabbedButtonBar::setMinimumTabButtonScaleFactor (const double factor)
+{
- jassert (factor >= 0.0 && factor <= 1.0);
- minimumScale = factor;
- resized();
+}
+void TabbedButtonBar::setTabButtonUpscalingEnabled (const bool shouldBeEnabled)
+{
- upscalingEnabled = shouldBeEnabled;
- resized();
+}
void TabbedButtonBar::resized()
{
- const double minimumScale = 0.7;
int depth = getWidth();
int length = getHeight();
@@ -397,10 +412,17 @@
double scale = 1.0;
if (totalLength > length)
-
scale = jmax (minimumScale, length / (double) totalLength);
- {
-
if (upscalingEnabled)
-
scale = jmax (minimumScale, length / (double) totalLength);
-
else
-
scale = jlimit (minimumScale, 1.0, length / (double) totalLength);
- }
- const bool isTooBig = totalLength * scale > length;
- int tabsButtonPos = 0;
-
// subtract 0.5 here to handle rounding errors and suppress flickering popup
-
// of the extra tabs button
-
const bool isTooBig = totalLength * scale - 0.5 > length;
-
int remainingLength = length;
if (isTooBig)
{
@@ -412,19 +434,10 @@
extraTabsButton->setTriggeredOnMouseDown (true);}
-
const int buttonSize = jmin (proportionOfWidth (0.7f), proportionOfHeight (0.7f));
-
extraTabsButton->setSize (buttonSize, buttonSize);
-
if (orientation == TabsAtTop || orientation == TabsAtBottom)
-
{
-
tabsButtonPos = getWidth() - buttonSize / 2 - 1;
-
extraTabsButton->setCentrePosition (tabsButtonPos, getHeight() / 2);
-
}
-
else
-
{
-
tabsButtonPos = getHeight() - buttonSize / 2 - 1;
-
extraTabsButton->setCentrePosition (getWidth() / 2, tabsButtonPos);
-
}
-
remainingLength = getLookAndFeel().positionTabBarExtrasButton (*this,
-
getWidth(), getHeight(),
-
orientation,
-
extraTabsButton); totalLength = 0;
@@ -436,7 +449,7 @@
{
const int newLength = totalLength + tb->getBestTabLength (depth);
-
if (i > 0 && newLength * minimumScale > tabsButtonPos)
-
if (i > 0 && newLength * minimumScale > remainingLength) { totalLength += overlap; break;
@@ -444,11 +457,13 @@
numVisibleButtons = i + 1;
totalLength = newLength - overlap;
-
} }
-
scale = jmax (minimumScale, tabsButtonPos / (double) totalLength);
-
if (upscalingEnabled)
-
scale = jmax (minimumScale, remainingLength / (double) totalLength);
-
else
-
scale = jlimit (minimumScale, 1.0, remainingLength / (double) totalLength);
}
else
{
@@ -458,6 +473,7 @@
int pos = 0;TabBarButton* frontTab = 0;
-
double fraction = 0.0;
for (i = 0; i < tabs.size(); ++i)
{
@@ -465,10 +481,35 @@if (tb != 0) {
-
const int bestLength = roundDoubleToInt (scale * tb->getBestTabLength (depth));
-
// scale the tab length but not the overlap
-
double bestLengthAsDouble = scale * (tb->getBestTabLength (depth) - overlap) + overlap;
-
int bestLength = roundDoubleToInt (bestLengthAsDouble);
-
// don't just drop the fractional part of the tab length but sum
-
// them up and add whole pixel back to the tab length. this results
-
// in less jumpy scaling
-
fraction += bestLengthAsDouble - (double) bestLength;
-
while (fraction >= 1.0)
-
{
-
++bestLength;
-
--fraction;
-
}
-
while (fraction <= -1.0)
-
{
-
--bestLength;
-
++fraction;
-
} if (i < numVisibleButtons) {
-
// make sure the last tabs border matches with the border of the remaining length
-
if (upscalingEnabled && totalLength >= remainingLength && i == numVisibleButtons - 1)
-
{
-
bestLength = remainingLength - pos;
-
}
-
if (orientation == TabsAtTop || orientation == TabsAtBottom) tb->setBounds (pos, 0, bestLength, getHeight()); else
diff -d -r -u old/juce_TabbedButtonBar.h new/juce/juce_TabbedButtonBar.h
— old/juce/juce_TabbedButtonBar.h
+++ new/juce/juce_TabbedButtonBar.h
@@ -238,6 +238,44 @@
*/
void setTabBackgroundColour (const int tabIndex, const Colour& newColour);
-
/** Returns the minimum factor for tab scaling.
-
@see setMinimumTabButtonScaleFactor, setTabButtonUpscalingEnabled
-
*/
-
double getMinimumTabButtonScaleFactor () const throw() { return minimumScale; }
-
/** Changes the minimum factor for tab scaling.
-
If there is not enough space to show all tabs they will be scaled down
-
until they fit all in. The scaling stops at this minimal factor to prevent
-
the tabs from beeing scaled to far down. If the minimal scale factor is
-
reached and not all tabs fit in some tabs will be hidden. This hidden
-
tabs can be accessed via a popup menu.
-
A valid factor is a value from 0.0 to 1.0, with 0.0 tabs can be scaled
-
without lower limit, with 1.0 tabs can't be scaled down.
-
The default factor is 0.7
-
@see getMinimumTabButtonScaleFactor, isTabButtonUpscalingEnabled
-
*/
-
void setMinimumTabButtonScaleFactor (const double factor);
-
/** Returns true if upscaling is enabled.
-
@see setMinimumTabButtonScaleFactor, setTabButtonUpscalingEnabled
-
*/
-
bool isTabButtonUpscalingEnabled () const throw() { return upscalingEnabled; }
-
/** Enabled tab upscaling to fill the free space.
-
When a tab is hidden because there is not enough space to show it the
-
remaining tabs can be scaled up to fill the free space.
-
@see getMinimumTabButtonScaleFactor, isTabButtonUpscalingEnabled
-
*/
-
void setTabButtonUpscalingEnabled (const bool shouldBeEnabled);
-
//==============================================================================
/** @internal /
void resized();
@@ -266,6 +304,8 @@
int currentTabIndex;
Component behindFrontTab;
Button* extraTabsButton; -
double minimumScale;
-
bool upscalingEnabled;
TabBarButton* getTabButton (const int index) const;
[/code]