1 // Written in the D programming language.
2 
3 /**
4 DLANGUI library.
5 
6 This module contains popup widgets implementation.
7 
8 
9 
10 Synopsis:
11 
12 ----
13 import dlangui.widgets.popup;
14 
15 ----
16 
17 Copyright: Vadim Lopatin, 2014
18 License:   $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
19 Authors:   $(WEB coolreader.org, Vadim Lopatin)
20 */
21 module dlangui.widgets.popup;
22 
23 import dlangui.widgets.widget;
24 import dlangui.widgets.layouts;
25 import dlangui.platforms.common.platform;
26 
27 /// popup alignment option flags
28 enum PopupAlign : uint {
29     /// center popup around anchor widget center
30     Center = 1,
31     /// place popup below anchor widget close to lower bound
32     Below = 2,
33     /// place popup below anchor widget close to right bound (when no space enough, align near left bound)
34     Right = 4,
35 }
36 
37 struct PopupAnchor {
38     Widget widget;
39     uint  alignment = PopupAlign.Center;
40 }
41 
42 /// popup behavior flags - for PopupWidget.flags property
43 enum PopupFlags : uint {
44     /// close popup when mouse button clicked outside of its bounds
45     CloseOnClickOutside = 1,
46 }
47 
48 /// popup widget container
49 class PopupWidget : LinearLayout {
50     protected PopupAnchor _anchor;
51     protected bool _modal;
52 
53     protected uint _flags;
54     protected void delegate(PopupWidget popup) _onPopupCloseListener;
55     /// popup close listener (called right before closing)
56     @property void delegate(PopupWidget popup) onPopupCloseListener() { return _onPopupCloseListener; }
57     /// set popup close listener (to call right before closing)
58     @property PopupWidget onPopupCloseListener(void delegate(PopupWidget popup) listener) { _onPopupCloseListener = listener; return this; }
59 
60     /// returns popup behavior flags (combination of PopupFlags)
61     @property uint flags() { return _flags; }
62     /// set popup behavior flags (combination of PopupFlags)
63     @property PopupWidget flags(uint flags) { _flags = flags; return this; }
64 
65     /// access to popup anchor
66     @property ref PopupAnchor anchor() { return _anchor; }
67     /// returns true if popup is modal
68     bool modal() { return _modal; }
69     /// set modality flag
70     PopupWidget modal(bool modal) { _modal = modal; return this; }
71 
72     /// Measure widget according to desired width and height constraints. (Step 1 of two phase layout).
73     override void measure(int parentWidth, int parentHeight) { 
74         super.measure(parentWidth, parentHeight);
75     }
76 	/// close and destroy popup
77 	void close() {
78 		window.removePopup(this);
79 	}
80 
81     /// just call on close listener
82     void onClose() {
83         if (_onPopupCloseListener !is null)
84             _onPopupCloseListener(this);
85     }
86 
87     /// Set widget rectangle to specified value and layout widget contents. (Step 2 of two phase layout).
88     override void layout(Rect rc) {
89         if (visibility == Visibility.Gone) {
90             return;
91         }
92         int w = measuredWidth;
93         int h = measuredHeight;
94         if (w > rc.width)
95             w = rc.width;
96         if (h > rc.height)
97             h = rc.height;
98 
99         Rect anchorrc;
100         if (anchor.widget !is null)
101             anchorrc = anchor.widget.pos;
102         else
103             anchorrc = rc;
104 
105         Rect r;
106         Point anchorPt;
107 
108         if (anchor.alignment & PopupAlign.Center) {
109             // center around center of anchor widget
110             r.left = anchorrc.middlex - w / 2;
111             r.top = anchorrc.middley - h / 2;
112         } else if (anchor.alignment & PopupAlign.Below) {
113             r.left = anchorrc.left;
114             r.top = anchorrc.bottom;
115         } else if (anchor.alignment & PopupAlign.Right) {
116             r.left = anchorrc.right;
117             r.top = anchorrc.top;
118         }
119         r.right = r.left + w;
120         r.bottom = r.top + h;
121         r.moveToFit(rc);
122         super.layout(r);
123     }
124 
125     this(Widget content, Window window) {
126         _window = window;
127         //styleId = "POPUP_MENU";
128         addChild(content);
129     }
130 
131     /// called for mouse activity outside shown popup bounds
132     bool onMouseEventOutside(MouseEvent event) {
133         if (visibility != Visibility.Visible)
134             return false;
135         if (_flags & PopupFlags.CloseOnClickOutside) {
136             if (event.action == MouseAction.ButtonDown) {
137                 // clicked outside - close popup
138                 close();
139                 return false;
140             }
141         }
142         return false;
143     }
144 }