1 module nanogui.popupbutton;
2 /*
3     nanogui/popupbutton.h -- Button which launches a popup widget
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 import nanogui.button;
14 import nanogui.popup;
15 import nanogui.entypo;
16 import nanogui.widget;
17 import nanogui.window;
18 import nanogui.common;
19 
20 /**
21  * Button which launches a popup widget.
22  *
23  * Remark:
24  *     This class overrides `nanogui.Widget.mIconExtraScale`` to be `0.8f`,
25  *     which affects all subclasses of this Widget.  Subclasses must explicitly
26  *     set a different value if needed (e.g., in their constructor).
27  */
28 class PopupButton : Button
29 {
30 public:
31     this(Widget parent, string caption = "Untitled",
32                 int buttonIcon = 0)
33     {
34         super(parent, caption, buttonIcon);
35 
36         mChevronIcon = mTheme.mPopupChevronRightIcon;
37 
38         flags(Flags.ToggleButton | Flags.PopupButton);
39 
40         Window parentWindow = window;
41         mPopup = new Popup(parentWindow.parent, window);
42         mPopup.size(Vector2i(320, 250));
43         mPopup.visible(false);
44 
45         mIconExtraScale = 0.8f;// widget override
46     }
47 
48     final void chevronIcon(int icon) { mChevronIcon = icon; }
49     final dchar chevronIcon() const { return mChevronIcon; }
50 
51     final void side(Popup.Side popupSide);
52     final Popup.Side side() const { return mPopup.side(); }
53 
54     final Popup popup() { return mPopup; }
55     final auto popup() const { return mPopup; }
56 
57     override void draw(ref NanoContext ctx)
58     {
59         if (!mEnabled && mPushed)
60             mPushed = false;
61 
62         mPopup.visible(mPushed);
63         Button.draw(ctx);
64 
65         if (mChevronIcon != dchar.init)
66         {
67             auto icon = mChevronIcon;
68             auto textColor =
69                 mTextColor.w == 0 ? mTheme.mTextColor : mTextColor;
70 
71             ctx.fontSize((mFontSize < 0 ? mTheme.mButtonFontSize : mFontSize) * icon_scale());
72             ctx.fontFace("icons");
73             ctx.fillColor(mEnabled ? textColor : mTheme.mDisabledTextColor);
74             auto algn = NVGTextAlign();
75             algn.left = true;
76             algn.middle = true;
77             ctx.textAlign(algn);
78 
79             float iw = ctx.textBounds(0, 0, [icon], null);
80             auto iconPos = Vector2f(0, mPos.y + mSize.y * 0.5f - 1);
81 
82             if (mPopup.side == Popup.Side.Right)
83                 iconPos[0] = mPos.x + mSize.x - iw - 8;
84             else
85                 iconPos[0] = mPos.x + 8;
86 
87             ctx.text(iconPos.x, iconPos.y, [icon]);
88         }
89     }
90     override Vector2i preferredSize(NanoContext ctx) const
91     {
92         return Button.preferredSize(ctx) + Vector2i(15, 0);
93     }
94     override void performLayout(NanoContext ctx)
95     {
96         Widget.performLayout(ctx);
97 
98         const Window parentWindow = window;
99 
100         int posY = absolutePosition.y - parentWindow.position.y + mSize.y/2;
101         if (mPopup.side == Popup.Side.Right)
102             mPopup.anchorPos(Vector2i(parentWindow.width + 15, posY));
103         else
104             mPopup.anchorPos(Vector2i(0 - 15, posY));
105     }
106 
107     //virtual void save(Serializer &s) const override;
108     //virtual bool load(Serializer &s) override;
109 protected:
110     Popup mPopup;
111     dchar mChevronIcon;
112 }