reactphysics3d/testbed/nanogui/src/vscrollpanel.cpp

129 lines
4.2 KiB
C++
Raw Normal View History

/*
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)