Initial release
This commit is contained in:
@@ -0,0 +1,416 @@
|
||||
// This file is part of VSTGUI. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this
|
||||
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
|
||||
|
||||
#include "cscrollbar.h"
|
||||
#include "../cvstguitimer.h"
|
||||
#include "../animation/animations.h"
|
||||
#include "../animation/timingfunctions.h"
|
||||
#include "../cframe.h"
|
||||
#include "../cgraphicspath.h"
|
||||
#include "../cdrawcontext.h"
|
||||
#include "../events.h"
|
||||
#include "../algorithm.h"
|
||||
|
||||
namespace VSTGUI {
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CScrollbar::CScrollbar (const CRect& size, IControlListener* listener, int32_t tag, ScrollbarDirection direction, const CRect& scrollSize)
|
||||
: CControl (size, listener, tag, nullptr)
|
||||
, direction (direction)
|
||||
, scrollSize (scrollSize)
|
||||
, scrollerArea (size)
|
||||
, stepValue (0.1f)
|
||||
, scrollerLength (0)
|
||||
, overlayStyle (false)
|
||||
, mouseIsInside (false)
|
||||
, drawer (nullptr)
|
||||
{
|
||||
setTransparency (true);
|
||||
setWheelInc (0.05f);
|
||||
scrollerArea.inset (2, 2);
|
||||
calculateScrollerLength ();
|
||||
frameColor (0, 0, 0, 255);
|
||||
scrollerColor (0, 0, 255, 255);
|
||||
backgroundColor (255, 255, 255, 200);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CScrollbar::CScrollbar (const CScrollbar& v)
|
||||
: CControl (v)
|
||||
, direction (v.direction)
|
||||
, scrollSize (v.scrollSize)
|
||||
, scrollerArea (v.scrollerArea)
|
||||
, stepValue (v.stepValue)
|
||||
, scrollerLength (v.scrollerLength)
|
||||
, frameColor (v.frameColor)
|
||||
, scrollerColor (v.scrollerColor)
|
||||
, backgroundColor (v.backgroundColor)
|
||||
, overlayStyle (v.overlayStyle)
|
||||
, mouseIsInside (false)
|
||||
, drawer (v.drawer)
|
||||
{
|
||||
calculateScrollerLength ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setViewSize (const CRect &newSize, bool invalid)
|
||||
{
|
||||
scrollerArea = newSize;
|
||||
scrollerArea.inset (2, 2);
|
||||
CControl::setViewSize (newSize, invalid);
|
||||
calculateScrollerLength ();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setScrollSize (const CRect& ssize)
|
||||
{
|
||||
if (scrollSize != ssize)
|
||||
{
|
||||
scrollSize = ssize;
|
||||
calculateScrollerLength ();
|
||||
setDirty (true);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::calculateScrollerLength ()
|
||||
{
|
||||
CCoord newScrollerLength;
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
double factor = scrollSize.getWidth () > 0. ? getViewSize ().getWidth () / scrollSize.getWidth () : 0.;
|
||||
if (factor >= 1.f)
|
||||
factor = 0;
|
||||
newScrollerLength = (CCoord) (getViewSize ().getWidth () * factor);
|
||||
}
|
||||
else
|
||||
{
|
||||
double factor = scrollSize.getHeight () > 0 ? getViewSize ().getHeight () / scrollSize.getHeight () : 0.;
|
||||
if (factor >= 1.f)
|
||||
factor = 0;
|
||||
newScrollerLength = (CCoord) (getViewSize ().getHeight () * factor);
|
||||
}
|
||||
if (newScrollerLength < minScrollerLenght && newScrollerLength > 0.)
|
||||
newScrollerLength = minScrollerLenght;
|
||||
if (newScrollerLength != scrollerLength)
|
||||
{
|
||||
scrollerLength = newScrollerLength;
|
||||
setDirty (true);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CRect CScrollbar::getScrollerRect ()
|
||||
{
|
||||
CRect sr (scrollerArea);
|
||||
CCoord l = (direction == kHorizontal) ? scrollerArea.getWidth () : scrollerArea.getHeight ();
|
||||
CCoord scrollerOffset = (CCoord)(getValueNormalized () * (l - scrollerLength));
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
sr.setWidth (scrollerLength);
|
||||
sr.offset (scrollerOffset, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
sr.setHeight (scrollerLength);
|
||||
sr.offset (0, scrollerOffset);
|
||||
}
|
||||
return sr;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::doStepping ()
|
||||
{
|
||||
CRect sr = getScrollerRect ();
|
||||
if (timer)
|
||||
{
|
||||
if (!getViewSize ().pointInside (startPoint) || sr.pointInside (startPoint))
|
||||
return;
|
||||
}
|
||||
bool dir = (direction == kHorizontal && startPoint.x < sr.left) || (direction == kVertical && startPoint.y < sr.top);
|
||||
float newValue = getValueNormalized ();
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
if (dir)
|
||||
newValue -= (float)scrollerLength / (float)scrollerArea.getWidth ();
|
||||
else
|
||||
newValue += (float)scrollerLength / (float)scrollerArea.getWidth ();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dir)
|
||||
newValue -= (float)scrollerLength / (float)scrollerArea.getHeight ();
|
||||
else
|
||||
newValue += (float)scrollerLength / (float)scrollerArea.getHeight ();
|
||||
}
|
||||
newValue = clampNorm (newValue);
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMessageResult CScrollbar::notify (CBaseObject* sender, IdStringPtr message)
|
||||
{
|
||||
if (message == CVSTGUITimer::kMsgTimer && timer)
|
||||
{
|
||||
doStepping ();
|
||||
timer->setFireTime (80);
|
||||
return kMessageNotified;
|
||||
}
|
||||
return kMessageUnknown;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::setOverlayStyle (bool state)
|
||||
{
|
||||
if (overlayStyle != state)
|
||||
{
|
||||
overlayStyle = state;
|
||||
setAlphaValue (overlayStyle ? 0.001f : 1.f);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::setMinScrollerLength (CCoord length)
|
||||
{
|
||||
if (minScrollerLenght != length)
|
||||
{
|
||||
minScrollerLenght = length;
|
||||
calculateScrollerLength ();
|
||||
setDirty ();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseEntered (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (overlayStyle && scrollerLength != 0)
|
||||
{
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (1.f), new Animation::LinearTimingFunction (100));
|
||||
}
|
||||
mouseIsInside = true;
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseExited (CPoint& where, const CButtonState& buttons)
|
||||
{
|
||||
if (overlayStyle && scrollerLength != 0)
|
||||
{
|
||||
Animation::ITimingFunction* timingFunction = nullptr;
|
||||
if (getAlphaValue () == 1.f)
|
||||
{
|
||||
auto* interpolTimingFunction = new Animation::InterpolationTimingFunction (400);
|
||||
interpolTimingFunction->addPoint (300.f/400.f, 1.f);
|
||||
timingFunction = interpolTimingFunction;
|
||||
}
|
||||
else
|
||||
timingFunction = new Animation::LinearTimingFunction (100);
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction);
|
||||
}
|
||||
mouseIsInside = false;
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseDown (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons != kLButton || scrollerLength == 0)
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
|
||||
startPoint = where;
|
||||
scrollerRect = getScrollerRect ();
|
||||
scrolling = scrollerRect.pointInside (where);
|
||||
if (scrolling)
|
||||
{
|
||||
scrollerRect = getScrollerRect ();
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
else if (scrollerArea.pointInside (where))
|
||||
{
|
||||
doStepping ();
|
||||
timer = makeOwned<CVSTGUITimer> (this, 250, true);
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseDownEventHandledButDontNeedMovedOrUpEvents;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseUp (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
timer = nullptr;
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseMoved (CPoint &where, const CButtonState& buttons)
|
||||
{
|
||||
if (buttons & kLButton)
|
||||
{
|
||||
if (scrolling)
|
||||
{
|
||||
float newValue = 0.f;
|
||||
CPoint newPoint (where);
|
||||
newPoint.x -= startPoint.x - scrollerRect.left;
|
||||
newPoint.y -= startPoint.y - scrollerRect.top;
|
||||
if (direction == kHorizontal)
|
||||
{
|
||||
newValue = (float)((float)(newPoint.x - scrollerArea.left) / ((float)scrollerArea.getWidth () - scrollerRect.getWidth ()));
|
||||
}
|
||||
else
|
||||
{
|
||||
newValue = (float)((float)(newPoint.y - scrollerArea.top) / ((float)scrollerArea.getHeight () - scrollerRect.getHeight ()));
|
||||
}
|
||||
newValue = clampNorm (newValue);
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CPoint old (startPoint);
|
||||
startPoint = where;
|
||||
CRect scollerRect = getScrollerRect ();
|
||||
if (getViewSize ().pointInside (where) && scollerRect.pointInside (old) && !scrollerRect.pointInside (startPoint))
|
||||
doStepping ();
|
||||
}
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
return kMouseEventNotHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
CMouseEventResult CScrollbar::onMouseCancel ()
|
||||
{
|
||||
timer = nullptr;
|
||||
return kMouseEventHandled;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::onVisualChange ()
|
||||
{
|
||||
if (isAttached () && overlayStyle && !mouseIsInside)
|
||||
{
|
||||
if (scrollerLength != 0)
|
||||
{
|
||||
auto timingFunction = new Animation::InterpolationTimingFunction (1100);
|
||||
timingFunction->addPoint (1000.f/1100.f, 0);
|
||||
addAnimation ("AlphaValueAnimation", new Animation::AlphaValueAnimation (0.001f), timingFunction);
|
||||
setAlphaValue (1.f);
|
||||
}
|
||||
else
|
||||
{
|
||||
removeAnimation ("AlphaValueAnimation");
|
||||
setAlphaValue (0.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void CScrollbar::onMouseWheelEvent (MouseWheelEvent& event)
|
||||
{
|
||||
if (scrollerLength == 0 || !getMouseEnabled ())
|
||||
return;
|
||||
|
||||
if (!event.modifiers.empty () && !(event.modifiers.has (ModifierKey::Shift) &&
|
||||
event.flags & MouseWheelEvent::DirectionInvertedFromDevice))
|
||||
return;
|
||||
|
||||
float distance = 0.f;
|
||||
if (direction == kHorizontal)
|
||||
distance = static_cast<float> (event.deltaX);
|
||||
else
|
||||
distance = static_cast<float> (event.deltaY);
|
||||
|
||||
if (distance == 0.f)
|
||||
return;
|
||||
|
||||
if (event.flags & MouseWheelEvent::DirectionInvertedFromDevice)
|
||||
distance *= -1;
|
||||
|
||||
float newValue = getValueNormalized ();
|
||||
if (event.modifiers.has (ModifierKey::Shift))
|
||||
newValue -= 0.1f * distance * getWheelInc ();
|
||||
else
|
||||
newValue -= distance * getWheelInc ();
|
||||
newValue = clampNorm (newValue);
|
||||
|
||||
if (newValue != getValueNormalized ())
|
||||
{
|
||||
setValueNormalized (newValue);
|
||||
onVisualChange ();
|
||||
valueChanged ();
|
||||
invalid ();
|
||||
}
|
||||
event.consumed = true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::drawBackground (CDrawContext* pContext)
|
||||
{
|
||||
CRect r (getViewSize ());
|
||||
if (drawer)
|
||||
drawer->drawScrollbarBackground (pContext, r, direction, this);
|
||||
else
|
||||
{
|
||||
pContext->setDrawMode (kAliasing);
|
||||
pContext->setLineWidth (1);
|
||||
pContext->setFillColor (backgroundColor);
|
||||
pContext->setFrameColor (frameColor);
|
||||
pContext->setLineStyle (kLineSolid);
|
||||
pContext->drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::drawScroller (CDrawContext* pContext, const CRect& size)
|
||||
{
|
||||
CRect r (size);
|
||||
if (drawer)
|
||||
drawer->drawScrollbarScroller (pContext, r, direction, this);
|
||||
else
|
||||
{
|
||||
pContext->setLineWidth (1);
|
||||
pContext->setFillColor (scrollerColor);
|
||||
pContext->setFrameColor (frameColor);
|
||||
|
||||
CCoord wideness = (direction == kVertical ? getWidth() : getHeight()) / 2 - 2;
|
||||
auto path = (wideness > 2) ? owned (pContext->createGraphicsPath ()) : nullptr;
|
||||
if (path)
|
||||
{
|
||||
if (wideness > 4)
|
||||
wideness = 4;
|
||||
pContext->setDrawMode (kAntiAliasing|kNonIntegralMode);
|
||||
path->addRoundRect (r, wideness);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathFilled);
|
||||
pContext->drawGraphicsPath (path, CDrawContext::kPathStroked);
|
||||
}
|
||||
else
|
||||
{
|
||||
pContext->setDrawMode (kAliasing|kNonIntegralMode);
|
||||
pContext->drawRect (r, kDrawFilledAndStroked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
void CScrollbar::draw (CDrawContext* pContext)
|
||||
{
|
||||
drawBackground (pContext);
|
||||
if (scrollerLength > 0)
|
||||
{
|
||||
CRect sr = getScrollerRect ();
|
||||
drawScroller (pContext, sr);
|
||||
}
|
||||
setDirty (false);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user