147 lines
4.8 KiB
C++
147 lines
4.8 KiB
C++
/*
|
|
nanogui/slider.cpp -- Fractional slider widget with mouse control
|
|
|
|
NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
|
|
The widget drawing code is based on the NanoVG demo application
|
|
by Mikko Mononen.
|
|
|
|
All rights reserved. Use of this source code is governed by a
|
|
BSD-style license that can be found in the LICENSE.txt file.
|
|
*/
|
|
|
|
#include <nanogui/slider.h>
|
|
#include <nanogui/theme.h>
|
|
#include <nanogui/opengl.h>
|
|
#include <nanogui/serializer/core.h>
|
|
|
|
NAMESPACE_BEGIN(nanogui)
|
|
|
|
Slider::Slider(Widget *parent)
|
|
: Widget(parent), mValue(0.0f), mRange(0.f, 1.f),
|
|
mHighlightedRange(0.f, 0.f) {
|
|
mHighlightColor = Color(255, 80, 80, 70);
|
|
}
|
|
|
|
Vector2i Slider::preferredSize(NVGcontext *) const {
|
|
return Vector2i(70, 16);
|
|
}
|
|
|
|
bool Slider::mouseDragEvent(const Vector2i &p, const Vector2i & /* rel */,
|
|
int /* button */, int /* modifiers */) {
|
|
if (!mEnabled)
|
|
return false;
|
|
|
|
const float kr = (int) (mSize.y() * 0.4f), kshadow = 3;
|
|
const float startX = kr + kshadow + mPos.x() - 1;
|
|
const float widthX = mSize.x() - 2 * (kr + kshadow);
|
|
|
|
float value = (p.x() - startX) / widthX;
|
|
value = value * (mRange.second - mRange.first) + mRange.first;
|
|
mValue = std::min(std::max(value, mRange.first), mRange.second);
|
|
if (mCallback)
|
|
mCallback(mValue);
|
|
return true;
|
|
}
|
|
|
|
bool Slider::mouseButtonEvent(const Vector2i &p, int /* button */, bool down, int /* modifiers */) {
|
|
if (!mEnabled)
|
|
return false;
|
|
|
|
const float kr = (int) (mSize.y() * 0.4f), kshadow = 3;
|
|
const float startX = kr + kshadow + mPos.x() - 1;
|
|
const float widthX = mSize.x() - 2 * (kr + kshadow);
|
|
|
|
float value = (p.x() - startX) / widthX;
|
|
value = value * (mRange.second - mRange.first) + mRange.first;
|
|
mValue = std::min(std::max(value, mRange.first), mRange.second);
|
|
if (mCallback)
|
|
mCallback(mValue);
|
|
if (mFinalCallback && !down)
|
|
mFinalCallback(mValue);
|
|
return true;
|
|
}
|
|
|
|
void Slider::draw(NVGcontext* ctx) {
|
|
Vector2f center = mPos.cast<float>() + mSize.cast<float>() * 0.5f;
|
|
float kr = (int) (mSize.y() * 0.4f), kshadow = 3;
|
|
|
|
float startX = kr + kshadow + mPos.x();
|
|
float widthX = mSize.x() - 2*(kr+kshadow);
|
|
|
|
Vector2f knobPos(startX + (mValue - mRange.first) /
|
|
(mRange.second - mRange.first) * widthX,
|
|
center.y() + 0.5f);
|
|
|
|
NVGpaint bg = nvgBoxGradient(
|
|
ctx, startX, center.y() - 3 + 1, widthX, 6, 3, 3,
|
|
Color(0, mEnabled ? 32 : 10), Color(0, mEnabled ? 128 : 210));
|
|
|
|
nvgBeginPath(ctx);
|
|
nvgRoundedRect(ctx, startX, center.y() - 3 + 1, widthX, 6, 2);
|
|
nvgFillPaint(ctx, bg);
|
|
nvgFill(ctx);
|
|
|
|
if (mHighlightedRange.second != mHighlightedRange.first) {
|
|
nvgBeginPath(ctx);
|
|
nvgRoundedRect(ctx, startX + mHighlightedRange.first * mSize.x(),
|
|
center.y() - kshadow + 1,
|
|
widthX *
|
|
(mHighlightedRange.second - mHighlightedRange.first),
|
|
kshadow * 2, 2);
|
|
nvgFillColor(ctx, mHighlightColor);
|
|
nvgFill(ctx);
|
|
}
|
|
|
|
NVGpaint knobShadow =
|
|
nvgRadialGradient(ctx, knobPos.x(), knobPos.y(), kr - kshadow,
|
|
kr + kshadow, Color(0, 64), mTheme->mTransparent);
|
|
|
|
nvgBeginPath(ctx);
|
|
nvgRect(ctx, knobPos.x() - kr - 5, knobPos.y() - kr - 5, kr * 2 + 10,
|
|
kr * 2 + 10 + kshadow);
|
|
nvgCircle(ctx, knobPos.x(), knobPos.y(), kr);
|
|
nvgPathWinding(ctx, NVG_HOLE);
|
|
nvgFillPaint(ctx, knobShadow);
|
|
nvgFill(ctx);
|
|
|
|
NVGpaint knob = nvgLinearGradient(ctx,
|
|
mPos.x(), center.y() - kr, mPos.x(), center.y() + kr,
|
|
mTheme->mBorderLight, mTheme->mBorderMedium);
|
|
NVGpaint knobReverse = nvgLinearGradient(ctx,
|
|
mPos.x(), center.y() - kr, mPos.x(), center.y() + kr,
|
|
mTheme->mBorderMedium,
|
|
mTheme->mBorderLight);
|
|
|
|
nvgBeginPath(ctx);
|
|
nvgCircle(ctx, knobPos.x(), knobPos.y(), kr);
|
|
nvgStrokeColor(ctx, mTheme->mBorderDark);
|
|
nvgFillPaint(ctx, knob);
|
|
nvgStroke(ctx);
|
|
nvgFill(ctx);
|
|
nvgBeginPath(ctx);
|
|
nvgCircle(ctx, knobPos.x(), knobPos.y(), kr/2);
|
|
nvgFillColor(ctx, Color(150, mEnabled ? 255 : 100));
|
|
nvgStrokePaint(ctx, knobReverse);
|
|
nvgStroke(ctx);
|
|
nvgFill(ctx);
|
|
}
|
|
|
|
void Slider::save(Serializer &s) const {
|
|
Widget::save(s);
|
|
s.set("value", mValue);
|
|
s.set("range", mRange);
|
|
s.set("highlightedRange", mHighlightedRange);
|
|
s.set("highlightColor", mHighlightColor);
|
|
}
|
|
|
|
bool Slider::load(Serializer &s) {
|
|
if (!Widget::load(s)) return false;
|
|
if (!s.get("value", mValue)) return false;
|
|
if (!s.get("range", mRange)) return false;
|
|
if (!s.get("highlightedRange", mHighlightedRange)) return false;
|
|
if (!s.get("highlightColor", mHighlightColor)) return false;
|
|
return true;
|
|
}
|
|
|
|
NAMESPACE_END(nanogui)
|