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 | |
18 | NAMESPACE_BEGIN(nanogui) |
19 | |
20 | Popup::(Widget *parent, Window *parentWindow) |
21 | : Window(parent, "" ), mParentWindow(parentWindow), |
22 | mAnchorPos(Vector2i::Zero()), mAnchorHeight(30), mSide(Side::Right) { |
23 | } |
24 | |
25 | void Popup::(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 | |
37 | void Popup::() { |
38 | mParentWindow->refreshRelativePlacement(); |
39 | mVisible &= mParentWindow->visibleRecursive(); |
40 | mPos = mParentWindow->position() + mAnchorPos - Vector2i(0, mAnchorHeight); |
41 | } |
42 | |
43 | void Popup::(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 | |
88 | void Popup::(Serializer &s) const { |
89 | Window::save(s); |
90 | s.set("anchorPos" , mAnchorPos); |
91 | s.set("anchorHeight" , mAnchorHeight); |
92 | s.set("side" , mSide); |
93 | } |
94 | |
95 | bool Popup::(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 | |
103 | NAMESPACE_END(nanogui) |
104 | |