| 
							- /*
 -   ==============================================================================
 - 
 -    This file is part of the JUCE 6 technical preview.
 -    Copyright (c) 2017 - ROLI Ltd.
 - 
 -    You may use this code under the terms of the GPL v3
 -    (see www.gnu.org/licenses).
 - 
 -    For this technical preview, this file is not subject to commercial licensing.
 - 
 -    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 ScrollBar::ScrollbarButton  : public Button
 - {
 - public:
 -     ScrollbarButton (int direc, ScrollBar& s)
 -         : Button (String()), direction (direc), owner (s)
 -     {
 -         setWantsKeyboardFocus (false);
 -     }
 - 
 -     void paintButton (Graphics& g, bool over, bool down) override
 -     {
 -         getLookAndFeel().drawScrollbarButton (g, owner, getWidth(), getHeight(),
 -                                               direction, owner.isVertical(), over, down);
 -     }
 - 
 -     void clicked() override
 -     {
 -         owner.moveScrollbarInSteps ((direction == 1 || direction == 2) ? 1 : -1);
 -     }
 - 
 -     using Button::clicked;
 - 
 -     int direction;
 - 
 - private:
 -     ScrollBar& owner;
 - 
 -     JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScrollbarButton)
 - };
 - 
 - 
 - //==============================================================================
 - ScrollBar::ScrollBar (bool shouldBeVertical)  : vertical (shouldBeVertical)
 - {
 -     setRepaintsOnMouseActivity (true);
 -     setFocusContainer (true);
 - }
 - 
 - ScrollBar::~ScrollBar()
 - {
 -     upButton.reset();
 -     downButton.reset();
 - }
 - 
 - //==============================================================================
 - void ScrollBar::setRangeLimits (Range<double> newRangeLimit, NotificationType notification)
 - {
 -     if (totalRange != newRangeLimit)
 -     {
 -         totalRange = newRangeLimit;
 -         setCurrentRange (visibleRange, notification);
 -         updateThumbPosition();
 -     }
 - }
 - 
 - void ScrollBar::setRangeLimits (double newMinimum, double newMaximum, NotificationType notification)
 - {
 -     jassert (newMaximum >= newMinimum); // these can't be the wrong way round!
 -     setRangeLimits (Range<double> (newMinimum, newMaximum), notification);
 - }
 - 
 - bool ScrollBar::setCurrentRange (Range<double> newRange, NotificationType notification)
 - {
 -     auto constrainedRange = totalRange.constrainRange (newRange);
 - 
 -     if (visibleRange != constrainedRange)
 -     {
 -         visibleRange = constrainedRange;
 - 
 -         updateThumbPosition();
 - 
 -         if (notification != dontSendNotification)
 -             triggerAsyncUpdate();
 - 
 -         if (notification == sendNotificationSync)
 -             handleUpdateNowIfNeeded();
 - 
 -         return true;
 -     }
 - 
 -     return false;
 - }
 - 
 - void ScrollBar::setCurrentRange (double newStart, double newSize, NotificationType notification)
 - {
 -     setCurrentRange (Range<double> (newStart, newStart + newSize), notification);
 - }
 - 
 - void ScrollBar::setCurrentRangeStart (double newStart, NotificationType notification)
 - {
 -     setCurrentRange (visibleRange.movedToStartAt (newStart), notification);
 - }
 - 
 - void ScrollBar::setSingleStepSize (double newSingleStepSize) noexcept
 - {
 -     singleStepSize = newSingleStepSize;
 - }
 - 
 - bool ScrollBar::moveScrollbarInSteps (int howManySteps, NotificationType notification)
 - {
 -     return setCurrentRange (visibleRange + howManySteps * singleStepSize, notification);
 - }
 - 
 - bool ScrollBar::moveScrollbarInPages (int howManyPages, NotificationType notification)
 - {
 -     return setCurrentRange (visibleRange + howManyPages * visibleRange.getLength(), notification);
 - }
 - 
 - bool ScrollBar::scrollToTop (NotificationType notification)
 - {
 -     return setCurrentRange (visibleRange.movedToStartAt (getMinimumRangeLimit()), notification);
 - }
 - 
 - bool ScrollBar::scrollToBottom (NotificationType notification)
 - {
 -     return setCurrentRange (visibleRange.movedToEndAt (getMaximumRangeLimit()), notification);
 - }
 - 
 - void ScrollBar::setButtonRepeatSpeed (int newInitialDelay,
 -                                       int newRepeatDelay,
 -                                       int newMinimumDelay)
 - {
 -     initialDelayInMillisecs = newInitialDelay;
 -     repeatDelayInMillisecs  = newRepeatDelay;
 -     minimumDelayInMillisecs = newMinimumDelay;
 - 
 -     if (upButton != nullptr)
 -     {
 -         upButton  ->setRepeatSpeed (newInitialDelay, newRepeatDelay, newMinimumDelay);
 -         downButton->setRepeatSpeed (newInitialDelay, newRepeatDelay, newMinimumDelay);
 -     }
 - }
 - 
 - //==============================================================================
 - void ScrollBar::addListener (Listener* listener)
 - {
 -     listeners.add (listener);
 - }
 - 
 - void ScrollBar::removeListener (Listener* listener)
 - {
 -     listeners.remove (listener);
 - }
 - 
 - void ScrollBar::handleAsyncUpdate()
 - {
 -     auto start = visibleRange.getStart(); // (need to use a temp variable for VC7 compatibility)
 -     listeners.call ([=] (Listener& l) { l.scrollBarMoved (this, start); });
 - }
 - 
 - //==============================================================================
 - void ScrollBar::updateThumbPosition()
 - {
 -     auto minimumScrollBarThumbSize = getLookAndFeel().getMinimumScrollbarThumbSize (*this);
 - 
 -     int newThumbSize = roundToInt (totalRange.getLength() > 0 ? (visibleRange.getLength() * thumbAreaSize) / totalRange.getLength()
 -                                                               : thumbAreaSize);
 - 
 -     if (newThumbSize < minimumScrollBarThumbSize)
 -         newThumbSize = jmin (minimumScrollBarThumbSize, thumbAreaSize - 1);
 - 
 -     if (newThumbSize > thumbAreaSize)
 -         newThumbSize = thumbAreaSize;
 - 
 -     int newThumbStart = thumbAreaStart;
 - 
 -     if (totalRange.getLength() > visibleRange.getLength())
 -         newThumbStart += roundToInt (((visibleRange.getStart() - totalRange.getStart()) * (thumbAreaSize - newThumbSize))
 -                                          / (totalRange.getLength() - visibleRange.getLength()));
 - 
 -     Component::setVisible (getVisibility());
 - 
 -     if (thumbStart != newThumbStart  || thumbSize != newThumbSize)
 -     {
 -         auto repaintStart = jmin (thumbStart, newThumbStart) - 4;
 -         auto repaintSize = jmax (thumbStart + thumbSize, newThumbStart + newThumbSize) + 8 - repaintStart;
 - 
 -         if (vertical)
 -             repaint (0, repaintStart, getWidth(), repaintSize);
 -         else
 -             repaint (repaintStart, 0, repaintSize, getHeight());
 - 
 -         thumbStart = newThumbStart;
 -         thumbSize = newThumbSize;
 -     }
 - }
 - 
 - void ScrollBar::setOrientation (bool shouldBeVertical)
 - {
 -     if (vertical != shouldBeVertical)
 -     {
 -         vertical = shouldBeVertical;
 - 
 -         if (upButton != nullptr)
 -         {
 -             upButton->direction    = vertical ? 0 : 3;
 -             downButton->direction  = vertical ? 2 : 1;
 -         }
 - 
 -         updateThumbPosition();
 -     }
 - }
 - 
 - void ScrollBar::setAutoHide (bool shouldHideWhenFullRange)
 - {
 -     autohides = shouldHideWhenFullRange;
 -     updateThumbPosition();
 - }
 - 
 - bool ScrollBar::autoHides() const noexcept
 - {
 -     return autohides;
 - }
 - 
 - //==============================================================================
 - void ScrollBar::paint (Graphics& g)
 - {
 -     if (thumbAreaSize > 0)
 -     {
 -         auto& lf = getLookAndFeel();
 - 
 -         auto thumb = (thumbAreaSize > lf.getMinimumScrollbarThumbSize (*this))
 -                        ? thumbSize : 0;
 - 
 -         if (vertical)
 -             lf.drawScrollbar (g, *this, 0, thumbAreaStart, getWidth(), thumbAreaSize,
 -                               vertical, thumbStart, thumb, isMouseOver(), isMouseButtonDown());
 -         else
 -             lf.drawScrollbar (g, *this, thumbAreaStart, 0, thumbAreaSize, getHeight(),
 -                               vertical, thumbStart, thumb, isMouseOver(), isMouseButtonDown());
 -     }
 - }
 - 
 - void ScrollBar::lookAndFeelChanged()
 - {
 -     setComponentEffect (getLookAndFeel().getScrollbarEffect());
 - 
 -     if (isVisible())
 -         resized();
 - }
 - 
 - void ScrollBar::resized()
 - {
 -     auto length = vertical ? getHeight() : getWidth();
 - 
 -     auto& lf = getLookAndFeel();
 -     bool buttonsVisible = lf.areScrollbarButtonsVisible();
 -     int buttonSize = 0;
 - 
 -     if (buttonsVisible)
 -     {
 -         if (upButton == nullptr)
 -         {
 -             upButton  .reset (new ScrollbarButton (vertical ? 0 : 3, *this));
 -             downButton.reset (new ScrollbarButton (vertical ? 2 : 1, *this));
 - 
 -             addAndMakeVisible (upButton.get());
 -             addAndMakeVisible (downButton.get());
 - 
 -             setButtonRepeatSpeed (initialDelayInMillisecs, repeatDelayInMillisecs, minimumDelayInMillisecs);
 -         }
 - 
 -         buttonSize = jmin (lf.getScrollbarButtonSize (*this), length / 2);
 -     }
 -     else
 -     {
 -         upButton.reset();
 -         downButton.reset();
 -     }
 - 
 -     if (length < 32 + lf.getMinimumScrollbarThumbSize (*this))
 -     {
 -         thumbAreaStart = length / 2;
 -         thumbAreaSize = 0;
 -     }
 -     else
 -     {
 -         thumbAreaStart = buttonSize;
 -         thumbAreaSize = length - 2 * buttonSize;
 -     }
 - 
 -     if (upButton != nullptr)
 -     {
 -         auto r = getLocalBounds();
 - 
 -         if (vertical)
 -         {
 -             upButton->setBounds (r.removeFromTop (buttonSize));
 -             downButton->setBounds (r.removeFromBottom (buttonSize));
 -         }
 -         else
 -         {
 -             upButton->setBounds (r.removeFromLeft (buttonSize));
 -             downButton->setBounds (r.removeFromRight (buttonSize));
 -         }
 -     }
 - 
 -     updateThumbPosition();
 - }
 - 
 - void ScrollBar::parentHierarchyChanged()
 - {
 -     lookAndFeelChanged();
 - }
 - 
 - void ScrollBar::mouseDown (const MouseEvent& e)
 - {
 -     isDraggingThumb = false;
 -     lastMousePos = vertical ? e.y : e.x;
 -     dragStartMousePos = lastMousePos;
 -     dragStartRange = visibleRange.getStart();
 - 
 -     if (dragStartMousePos < thumbStart)
 -     {
 -         moveScrollbarInPages (-1);
 -         startTimer (400);
 -     }
 -     else if (dragStartMousePos >= thumbStart + thumbSize)
 -     {
 -         moveScrollbarInPages (1);
 -         startTimer (400);
 -     }
 -     else
 -     {
 -         isDraggingThumb = (thumbAreaSize > getLookAndFeel().getMinimumScrollbarThumbSize (*this))
 -                             && (thumbAreaSize > thumbSize);
 -     }
 - }
 - 
 - void ScrollBar::mouseDrag (const MouseEvent& e)
 - {
 -     auto mousePos = vertical ? e.y : e.x;
 - 
 -     if (isDraggingThumb && lastMousePos != mousePos && thumbAreaSize > thumbSize)
 -     {
 -         auto deltaPixels = mousePos - dragStartMousePos;
 - 
 -         setCurrentRangeStart (dragStartRange
 -                                 + deltaPixels * (totalRange.getLength() - visibleRange.getLength())
 -                                     / (thumbAreaSize - thumbSize));
 -     }
 - 
 -     lastMousePos = mousePos;
 - }
 - 
 - void ScrollBar::mouseUp (const MouseEvent&)
 - {
 -     isDraggingThumb = false;
 -     stopTimer();
 -     repaint();
 - }
 - 
 - void ScrollBar::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel)
 - {
 -     float increment = 10.0f * (vertical ? wheel.deltaY : wheel.deltaX);
 - 
 -     if (increment < 0)
 -         increment = jmin (increment, -1.0f);
 -     else if (increment > 0)
 -         increment = jmax (increment, 1.0f);
 - 
 -     setCurrentRange (visibleRange - singleStepSize * increment);
 - }
 - 
 - void ScrollBar::timerCallback()
 - {
 -     if (isMouseButtonDown())
 -     {
 -         startTimer (40);
 - 
 -         if (lastMousePos < thumbStart)
 -             setCurrentRange (visibleRange - visibleRange.getLength());
 -         else if (lastMousePos > thumbStart + thumbSize)
 -             setCurrentRangeStart (visibleRange.getEnd());
 -     }
 -     else
 -     {
 -         stopTimer();
 -     }
 - }
 - 
 - bool ScrollBar::keyPressed (const KeyPress& key)
 - {
 -     if (isVisible())
 -     {
 -         if (key == KeyPress::upKey || key == KeyPress::leftKey)    return moveScrollbarInSteps (-1);
 -         if (key == KeyPress::downKey || key == KeyPress::rightKey) return moveScrollbarInSteps (1);
 -         if (key == KeyPress::pageUpKey)                            return moveScrollbarInPages (-1);
 -         if (key == KeyPress::pageDownKey)                          return moveScrollbarInPages (1);
 -         if (key == KeyPress::homeKey)                              return scrollToTop();
 -         if (key == KeyPress::endKey)                               return scrollToBottom();
 -     }
 - 
 -     return false;
 - }
 - 
 - void ScrollBar::setVisible (bool shouldBeVisible)
 - {
 -     if (userVisibilityFlag != shouldBeVisible)
 -     {
 -         userVisibilityFlag = shouldBeVisible;
 -         Component::setVisible (getVisibility());
 -     }
 - }
 - 
 - bool ScrollBar::getVisibility() const noexcept
 - {
 -     if (! userVisibilityFlag)
 -         return false;
 - 
 -     return (! autohides) || (totalRange.getLength() > visibleRange.getLength()
 -                                     && visibleRange.getLength() > 0.0);
 - }
 - 
 - } // namespace juce
 
 
  |