129 lines
4.2 KiB
C++
129 lines
4.2 KiB
C++
|
/*
|
||
|
src/vscrollpanel.cpp -- Adds a vertical scrollbar around a widget
|
||
|
that is too big to fit into a certain area
|
||
|
|
||
|
NanoGUI was developed by Wenzel Jakob <wenzel@inf.ethz.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/vscrollpanel.h>
|
||
|
#include <nanogui/theme.h>
|
||
|
#include <nanogui/opengl.h>
|
||
|
#include <nanogui/serializer/core.h>
|
||
|
|
||
|
NAMESPACE_BEGIN(nanogui)
|
||
|
|
||
|
VScrollPanel::VScrollPanel(Widget *parent)
|
||
|
: Widget(parent), mChildPreferredHeight(0), mScroll(0.0f) { }
|
||
|
|
||
|
void VScrollPanel::performLayout(NVGcontext *ctx) {
|
||
|
Widget::performLayout(ctx);
|
||
|
|
||
|
if (mChildren.empty())
|
||
|
return;
|
||
|
Widget *child = mChildren[0];
|
||
|
mChildPreferredHeight = child->preferredSize(ctx).y();
|
||
|
child->setPosition(Vector2i(0, 0));
|
||
|
child->setSize(Vector2i(mSize.x()-12, mChildPreferredHeight));
|
||
|
}
|
||
|
|
||
|
Vector2i VScrollPanel::preferredSize(NVGcontext *ctx) const {
|
||
|
if (mChildren.empty())
|
||
|
return Vector2i::Zero();
|
||
|
return mChildren[0]->preferredSize(ctx) + Vector2i(12, 0);
|
||
|
}
|
||
|
|
||
|
bool VScrollPanel::mouseDragEvent(const Vector2i &, const Vector2i &rel,
|
||
|
int, int) {
|
||
|
if (mChildren.empty())
|
||
|
return false;
|
||
|
|
||
|
float scrollh = height() *
|
||
|
std::min(1.0f, height() / (float)mChildPreferredHeight);
|
||
|
|
||
|
mScroll = std::max((float) 0.0f, std::min((float) 1.0f,
|
||
|
mScroll + rel.y() / (float)(mSize.y() - 8 - scrollh)));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool VScrollPanel::scrollEvent(const Vector2i &/* p */, const Vector2f &rel) {
|
||
|
float scrollAmount = rel.y() * (mSize.y() / 20.0f);
|
||
|
float scrollh = height() *
|
||
|
std::min(1.0f, height() / (float)mChildPreferredHeight);
|
||
|
|
||
|
mScroll = std::max((float) 0.0f, std::min((float) 1.0f,
|
||
|
mScroll - scrollAmount / (float)(mSize.y() - 8 - scrollh)));
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool VScrollPanel::mouseButtonEvent(const Vector2i &p, int button, bool down, int modifiers) {
|
||
|
if (mChildren.empty())
|
||
|
return false;
|
||
|
int shift = (int) (mScroll*(mChildPreferredHeight - mSize.y()));
|
||
|
return mChildren[0]->mouseButtonEvent(p + Vector2i(0, shift), button, down, modifiers);
|
||
|
}
|
||
|
|
||
|
bool VScrollPanel::mouseMotionEvent(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
|
||
|
if (mChildren.empty())
|
||
|
return false;
|
||
|
int shift = (int) (mScroll*(mChildPreferredHeight - mSize.y()));
|
||
|
return mChildren[0]->mouseMotionEvent(p + Vector2i(0, shift), rel, button, modifiers);
|
||
|
}
|
||
|
|
||
|
void VScrollPanel::draw(NVGcontext *ctx) {
|
||
|
if (mChildren.empty())
|
||
|
return;
|
||
|
Widget *child = mChildren[0];
|
||
|
mChildPreferredHeight = child->preferredSize(ctx).y();
|
||
|
float scrollh = height() *
|
||
|
std::min(1.0f, height() / (float) mChildPreferredHeight);
|
||
|
|
||
|
nvgSave(ctx);
|
||
|
nvgTranslate(ctx, mPos.x(), mPos.y());
|
||
|
nvgScissor(ctx, 0, 0, mSize.x(), mSize.y());
|
||
|
nvgTranslate(ctx, 0, -mScroll*(mChildPreferredHeight - mSize.y()));
|
||
|
if (child->visible())
|
||
|
child->draw(ctx);
|
||
|
nvgRestore(ctx);
|
||
|
|
||
|
NVGpaint paint = nvgBoxGradient(
|
||
|
ctx, mPos.x() + mSize.x() - 12 + 1, mPos.y() + 4 + 1, 8,
|
||
|
mSize.y() - 8, 3, 4, Color(0, 32), Color(0, 92));
|
||
|
nvgBeginPath(ctx);
|
||
|
nvgRoundedRect(ctx, mPos.x() + mSize.x() - 12, mPos.y() + 4, 8,
|
||
|
mSize.y() - 8, 3);
|
||
|
nvgFillPaint(ctx, paint);
|
||
|
nvgFill(ctx);
|
||
|
|
||
|
paint = nvgBoxGradient(
|
||
|
ctx, mPos.x() + mSize.x() - 12 - 1,
|
||
|
mPos.y() + 4 + (mSize.y() - 8 - scrollh) * mScroll - 1, 8, scrollh,
|
||
|
3, 4, Color(220, 100), Color(128, 100));
|
||
|
|
||
|
nvgBeginPath(ctx);
|
||
|
nvgRoundedRect(ctx, mPos.x() + mSize.x() - 12 + 1,
|
||
|
mPos.x() + 4 + 1 + (mSize.y() - 8 - scrollh) * mScroll, 8 - 2,
|
||
|
scrollh - 2, 2);
|
||
|
nvgFillPaint(ctx, paint);
|
||
|
nvgFill(ctx);
|
||
|
}
|
||
|
|
||
|
void VScrollPanel::save(Serializer &s) const {
|
||
|
Widget::save(s);
|
||
|
s.set("childPreferredHeight", mChildPreferredHeight);
|
||
|
s.set("scroll", mScroll);
|
||
|
}
|
||
|
|
||
|
bool VScrollPanel::load(Serializer &s) {
|
||
|
if (!Widget::load(s)) return false;
|
||
|
if (!s.get("childPreferredHeight", mChildPreferredHeight)) return false;
|
||
|
if (!s.get("scroll", mScroll)) return false;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
NAMESPACE_END(nanogui)
|