1/*
2 src/popup.cpp -- Simple popup widget which is attached to another given
3 window (can be nested)
4
5 NanoGUI was developed by Wenzel Jakob <wenzel.jakob@epfl.ch>.
6 The widget drawing code is based on the NanoVG demo application
7 by Mikko Mononen.
8
9 All rights reserved. Use of this source code is governed by a
10 BSD-style license that can be found in the LICENSE.txt file.
11*/
12
13#include <nanogui/popup.h>
14#include <nanogui/theme.h>
15#include <nanogui/opengl.h>
16#include <nanogui/serializer/core.h>
17
18NAMESPACE_BEGIN(nanogui)
19
20Popup::Popup(Widget *parent, Window *parentWindow)
21 : Window(parent, ""), mParentWindow(parentWindow),
22 mAnchorPos(Vector2i::Zero()), mAnchorHeight(30), mSide(Side::Right) {
23}
24
25void Popup::performLayout(NVGcontext *ctx) {
26 if (mLayout || mChildren.size() != 1) {
27 Widget::performLayout(ctx);
28 } else {
29 mChildren[0]->setPosition(Vector2i::Zero());
30 mChildren[0]->setSize(mSize);
31 mChildren[0]->performLayout(ctx);
32 }
33 if (mSide == Side::Left)
34 mAnchorPos[0] -= size()[0];
35}
36
37void Popup::refreshRelativePlacement() {
38 mParentWindow->refreshRelativePlacement();
39 mVisible &= mParentWindow->visibleRecursive();
40 mPos = mParentWindow->position() + mAnchorPos - Vector2i(0, mAnchorHeight);
41}
42
43void Popup::draw(NVGcontext* ctx) {
44 refreshRelativePlacement();
45
46 if (!mVisible)
47 return;
48
49 int ds = mTheme->mWindowDropShadowSize, cr = mTheme->mWindowCornerRadius;
50
51 nvgSave(ctx);
52 nvgResetScissor(ctx);
53
54 /* Draw a drop shadow */
55 NVGpaint shadowPaint = nvgBoxGradient(
56 ctx, mPos.x(), mPos.y(), mSize.x(), mSize.y(), cr*2, ds*2,
57 mTheme->mDropShadow, mTheme->mTransparent);
58
59 nvgBeginPath(ctx);
60 nvgRect(ctx, mPos.x()-ds,mPos.y()-ds, mSize.x()+2*ds, mSize.y()+2*ds);
61 nvgRoundedRect(ctx, mPos.x(), mPos.y(), mSize.x(), mSize.y(), cr);
62 nvgPathWinding(ctx, NVG_HOLE);
63 nvgFillPaint(ctx, shadowPaint);
64 nvgFill(ctx);
65
66 /* Draw window */
67 nvgBeginPath(ctx);
68 nvgRoundedRect(ctx, mPos.x(), mPos.y(), mSize.x(), mSize.y(), cr);
69
70 Vector2i base = mPos + Vector2i(0, mAnchorHeight);
71 int sign = -1;
72 if (mSide == Side::Left) {
73 base.x() += mSize.x();
74 sign = 1;
75 }
76
77 nvgMoveTo(ctx, base.x() + 15*sign, base.y());
78 nvgLineTo(ctx, base.x() - 1*sign, base.y() - 15);
79 nvgLineTo(ctx, base.x() - 1*sign, base.y() + 15);
80
81 nvgFillColor(ctx, mTheme->mWindowPopup);
82 nvgFill(ctx);
83 nvgRestore(ctx);
84
85 Widget::draw(ctx);
86}
87
88void Popup::save(Serializer &s) const {
89 Window::save(s);
90 s.set("anchorPos", mAnchorPos);
91 s.set("anchorHeight", mAnchorHeight);
92 s.set("side", mSide);
93}
94
95bool Popup::load(Serializer &s) {
96 if (!Window::load(s)) return false;
97 if (!s.get("anchorPos", mAnchorPos)) return false;
98 if (!s.get("anchorHeight", mAnchorHeight)) return false;
99 if (!s.get("side", mSide)) return false;
100 return true;
101}
102
103NAMESPACE_END(nanogui)
104