I have made small changes to the current juce tip to implement scrollbars that automatically disappear after a time interval since the last moment they were moved/used (i.e. like they now behave on MacOS X Lion, Mountain Lion and iOS).
Basically I added a setFadeOut method to ScrollBar that takes the amount of time (in milliseconds) after which the scrollbar should disappear, then tweaked the existing code to nicely incorporate this feature.
In addition, since such scrollbars are useful in order not to take away room in a viewport, I have made the necessary changes in the Viewport class for them to be overlapped to the content when they have a fade out time.
Below is the code for the patch that does this all:
From a549951e976ccfd410fb843975bcb69f963c0410 Mon Sep 17 00:00:00 2001
From: fmarverti@almateq.com
Date: Wed, 17 Oct 2012 12:54:31 +0200
Subject: [PATCH] fading out scrollbars
---
.../juce_gui_basics/layout/juce_ScrollBar.cpp | 58 +++++++++++++++++-----
.../juce_gui_basics/layout/juce_ScrollBar.h | 10 +++-
.../juce_gui_basics/layout/juce_Viewport.cpp | 24 ++++++---
3 files changed, 70 insertions(+), 22 deletions(-)
diff --git a/juce/modules/juce_gui_basics/layout/juce_ScrollBar.cpp b/juce/modules/juce_gui_basics/layout/juce_ScrollBar.cpp
index c8458e5..675b57d 100644
--- a/juce/modules/juce_gui_basics/layout/juce_ScrollBar.cpp
+++ b/juce/modules/juce_gui_basics/layout/juce_ScrollBar.cpp
@@ -23,6 +23,13 @@
==============================================================================
*/
+enum
+{
+ timer_autorepeat = 1,
+ timer_autohide,
+};
+
+
class ScrollBar::ScrollbarButton : public Button
{
public:
@@ -66,7 +73,8 @@ ScrollBar::ScrollBar (const bool vertical_)
minimumDelayInMillisecs (10),
vertical (vertical_),
isDraggingThumb (false),
- autohides (true)
+ autohides (true),
+ fadeOutMilliseconds (0)
{
setRepaintsOnMouseActivity (true);
setFocusContainer (true);
@@ -99,6 +107,9 @@ bool ScrollBar::setCurrentRange (const Range<double>& newRange)
{
const Range<double> constrainedRange (totalRange.constrainRange (newRange));
+ if (fadeOutMilliseconds > 0)
+ startTimer (timer_autohide, fadeOutMilliseconds);
+
if (visibleRange != constrainedRange)
{
visibleRange = constrainedRange;
@@ -243,6 +254,17 @@ bool ScrollBar::autoHides() const noexcept
return autohides;
}
+void ScrollBar::setFadesOut (int milliseconds)
+{
+ fadeOutMilliseconds = milliseconds;
+ updateThumbPosition();
+}
+
+bool ScrollBar::fadesOut () const noexcept
+{
+ return (fadeOutMilliseconds > 0);
+}
+
//==============================================================================
void ScrollBar::paint (Graphics& g)
{
@@ -334,12 +356,12 @@ void ScrollBar::mouseDown (const MouseEvent& e)
if (dragStartMousePos < thumbStart)
{
moveScrollbarInPages (-1);
- startTimer (400);
+ startTimer (timer_autorepeat, 400);
}
else if (dragStartMousePos >= thumbStart + thumbSize)
{
moveScrollbarInPages (1);
- startTimer (400);
+ startTimer (timer_autorepeat, 400);
}
else
{
@@ -367,7 +389,7 @@ void ScrollBar::mouseDrag (const MouseEvent& e)
void ScrollBar::mouseUp (const MouseEvent&)
{
isDraggingThumb = false;
- stopTimer();
+ stopTimer(timer_autorepeat);
repaint();
}
@@ -383,20 +405,32 @@ void ScrollBar::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& whee
setCurrentRange (visibleRange - singleStepSize * increment);
}
-void ScrollBar::timerCallback()
+void ScrollBar::timerCallback(int timerId)
{
- if (isMouseButtonDown())
+ if (timerId == timer_autorepeat)
{
- startTimer (40);
+ if (isMouseButtonDown())
+ {
+ startTimer (timerId, 40);
- if (lastMousePos < thumbStart)
- setCurrentRange (visibleRange - visibleRange.getLength());
- else if (lastMousePos > thumbStart + thumbSize)
- setCurrentRangeStart (visibleRange.getEnd());
+ if (lastMousePos < thumbStart)
+ setCurrentRange (visibleRange - visibleRange.getLength());
+ else if (lastMousePos > thumbStart + thumbSize)
+ setCurrentRangeStart (visibleRange.getEnd());
+ }
+ else
+ {
+ stopTimer (timerId);
+ }
+ }
+ else if (timerId == timer_autohide)
+ {
+ setVisible (false);
+ stopTimer (timerId);
}
else
{
- stopTimer();
+ jassertfalse;
}
}
diff --git a/juce/modules/juce_gui_basics/layout/juce_ScrollBar.h b/juce/modules/juce_gui_basics/layout/juce_ScrollBar.h
index 9c791d9..9b16c0a 100644
--- a/juce/modules/juce_gui_basics/layout/juce_ScrollBar.h
+++ b/juce/modules/juce_gui_basics/layout/juce_ScrollBar.h
@@ -51,7 +51,7 @@ class Viewport;
*/
class JUCE_API ScrollBar : public Component,
private AsyncUpdater,
- private Timer
+ private MultiTimer
{
public:
//==============================================================================
@@ -91,6 +91,11 @@ public:
*/
bool autoHides() const noexcept;
+ void setFadesOut (int milliseconds);
+
+ bool fadesOut() const noexcept;
+
+
//==============================================================================
/** Sets the minimum and maximum values that the bar will move between.
@@ -317,10 +322,11 @@ private:
friend class ScopedPointer<ScrollbarButton>;
ScopedPointer<ScrollbarButton> upButton, downButton;
ListenerList <Listener> listeners;
+ int fadeOutMilliseconds;
void handleAsyncUpdate();
void updateThumbPosition();
- void timerCallback();
+ void timerCallback(int timerId);
friend class Viewport;
diff --git a/juce/modules/juce_gui_basics/layout/juce_Viewport.cpp b/juce/modules/juce_gui_basics/layout/juce_Viewport.cpp
index 889f558..092b536 100644
--- a/juce/modules/juce_gui_basics/layout/juce_Viewport.cpp
+++ b/juce/modules/juce_gui_basics/layout/juce_Viewport.cpp
@@ -185,6 +185,9 @@ void Viewport::updateVisibleArea()
const bool canShowHBar = showHScrollbar && canShowAnyBars;
const bool canShowVBar = showVScrollbar && canShowAnyBars;
+ const bool overlapHBar = horizontalScrollBar.fadesOut();
+ const bool overlapVBar = verticalScrollBar.fadesOut();
+
bool hBarVisible = false, vBarVisible = false;
Rectangle<int> contentArea;
@@ -199,10 +202,10 @@ void Viewport::updateVisibleArea()
hBarVisible = canShowHBar && (hBarVisible || contentComp->getX() < 0 || contentComp->getRight() > contentArea.getWidth());
vBarVisible = canShowVBar && (vBarVisible || contentComp->getY() < 0 || contentComp->getBottom() > contentArea.getHeight());
- if (vBarVisible)
+ if (vBarVisible && !overlapVBar)
contentArea.setWidth (getWidth() - scrollbarWidth);
- if (hBarVisible)
+ if (hBarVisible && !overlapHBar)
contentArea.setHeight (getHeight() - scrollbarWidth);
if (! contentArea.contains (contentComp->getBounds()))
@@ -212,8 +215,11 @@ void Viewport::updateVisibleArea()
}
}
- if (vBarVisible) contentArea.setWidth (getWidth() - scrollbarWidth);
- if (hBarVisible) contentArea.setHeight (getHeight() - scrollbarWidth);
+ if (vBarVisible && !overlapVBar)
+ contentArea.setWidth (getWidth() - scrollbarWidth);
+
+ if (hBarVisible && !overlapHBar)
+ contentArea.setHeight (getHeight() - scrollbarWidth);
if (contentComp == nullptr)
{
@@ -237,7 +243,8 @@ void Viewport::updateVisibleArea()
if (hBarVisible)
{
- horizontalScrollBar.setBounds (0, contentArea.getHeight(), contentArea.getWidth(), scrollbarWidth);
+ horizontalScrollBar.toFront (false);
+ horizontalScrollBar.setBounds (0, overlapHBar ? (getHeight() - scrollbarWidth) : contentArea.getHeight(), contentArea.getWidth(), scrollbarWidth);
horizontalScrollBar.setRangeLimits (0.0, contentBounds.getWidth());
horizontalScrollBar.setCurrentRange (visibleOrigin.x, contentArea.getWidth());
horizontalScrollBar.setSingleStepSize (singleStepX);
@@ -250,7 +257,8 @@ void Viewport::updateVisibleArea()
if (vBarVisible)
{
- verticalScrollBar.setBounds (contentArea.getWidth(), 0, scrollbarWidth, contentArea.getHeight());
+ verticalScrollBar.toFront (false);
+ verticalScrollBar.setBounds (overlapVBar ? (getWidth() - scrollbarWidth) : contentArea.getWidth(), 0, scrollbarWidth, contentArea.getHeight());
verticalScrollBar.setRangeLimits (0.0, contentBounds.getHeight());
verticalScrollBar.setCurrentRange (visibleOrigin.y, contentArea.getHeight());
verticalScrollBar.setSingleStepSize (singleStepY);
@@ -352,8 +360,8 @@ bool Viewport::useMouseWheelMoveIfNeeded (const MouseEvent& e, const MouseWheelD
{
if (! (e.mods.isAltDown() || e.mods.isCtrlDown()))
{
- const bool hasVertBar = verticalScrollBar.isVisible();
- const bool hasHorzBar = horizontalScrollBar.isVisible();
+ const bool hasVertBar = verticalScrollBar.isVisible() || verticalScrollBar.fadesOut ();
+ const bool hasHorzBar = horizontalScrollBar.isVisible() || horizontalScrollBar.fadesOut();
if (hasHorzBar || hasVertBar)
{
--
1.7.12

