Line data Source code
1 : /**
2 : Copyright (c) 2024 Stappler LLC <admin@stappler.dev>
3 :
4 : Permission is hereby granted, free of charge, to any person obtaining a copy
5 : of this software and associated documentation files (the "Software"), to deal
6 : in the Software without restriction, including without limitation the rights
7 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 : copies of the Software, and to permit persons to whom the Software is
9 : furnished to do so, subject to the following conditions:
10 :
11 : The above copyright notice and this permission notice shall be included in
12 : all copies or substantial portions of the Software.
13 :
14 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 : THE SOFTWARE.
21 : **/
22 :
23 : #include "MaterialOverlayLayout.h"
24 : #include "MaterialEasing.h"
25 : #include "XLInputListener.h"
26 : #include "XL2dSceneContent.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::xenolith::material2d {
29 :
30 : constexpr static float OverlayHorizontalIncrement = 56.0f;
31 :
32 0 : OverlayLayout::~OverlayLayout() { }
33 :
34 0 : bool OverlayLayout::init(const Vec2 &globalOrigin, Binding b, Surface *node, Size2 targetSize) {
35 0 : if (!SceneLayout2d::init()) {
36 0 : return false;
37 : }
38 :
39 0 : addChildNode(node, ZOrder(1));
40 0 : _surface = node;
41 0 : _surface->setAnchorPoint(Anchor::MiddleTop);
42 :
43 0 : _globalOrigin = globalOrigin;
44 0 : _binding = b;
45 0 : _fullSize = targetSize;
46 :
47 0 : auto l = addInputListener(Rc<InputListener>::create());
48 0 : l->setSwallowEvents(InputListener::makeEventMask({InputEventName::Begin, InputEventName::MouseMove, InputEventName::Scroll}));
49 0 : l->setTouchFilter([this] (const InputEvent &ev, const InputListener::DefaultEventFilter &def) {
50 0 : if (!_surface->isTouched(ev.currentLocation)) {
51 0 : return def(ev);
52 : }
53 0 : return false;
54 : });
55 0 : l->addTapRecognizer([this] (const GestureTap &tap) {
56 0 : if (!_surface->isTouched(tap.location())) {
57 0 : if (_sceneContent) {
58 0 : _sceneContent->popOverlay(this);
59 : }
60 : }
61 0 : return true;
62 0 : }, InputListener::makeButtonMask({InputMouseButton::Touch}), 1);
63 :
64 0 : return true;
65 : }
66 :
67 0 : void OverlayLayout::onContentSizeDirty() {
68 0 : SceneLayout2d::onContentSizeDirty();
69 :
70 0 : if (_initSize != Size2::ZERO) {
71 0 : if (_sceneContent) {
72 0 : _sceneContent->popOverlay(this);
73 : }
74 : } else {
75 0 : _initSize = _contentSize;
76 : }
77 0 : }
78 :
79 0 : void OverlayLayout::onPushTransitionEnded(SceneContent2d *l, bool replace) {
80 0 : SceneLayout2d::onPushTransitionEnded(l, replace);
81 :
82 0 : emplaceNode(_globalOrigin, _binding);
83 0 : retainFocus();
84 0 : }
85 :
86 0 : void OverlayLayout::onPopTransitionBegan(SceneContent2d *l, bool replace) {
87 0 : releaseFocus();
88 0 : SceneLayout2d::onPopTransitionBegan(l, replace);
89 0 : if (_readyCallback) {
90 0 : _readyCallback(false);
91 : }
92 0 : }
93 :
94 0 : Rc<OverlayLayout::Transition> OverlayLayout::makeExitTransition(SceneContent2d *) const {
95 0 : return Rc<Sequence>::create(makeEasing(Rc<ActionProgress>::create(0.2f, [this] (float p) {
96 0 : _surface->setContentSize(progress(_fullSize, Size2(_fullSize.width, 1), p));
97 0 : })), [this] {
98 0 : if (_closeCallback) {
99 0 : _closeCallback();
100 : }
101 0 : });
102 : }
103 :
104 0 : void OverlayLayout::setReadyCallback(Function<void(bool)> &&cb) {
105 0 : _readyCallback = move(cb);
106 0 : }
107 :
108 0 : void OverlayLayout::setCloseCallback(Function<void()> &&cb) {
109 0 : _closeCallback = move(cb);
110 0 : }
111 :
112 0 : void OverlayLayout::emplaceNode(const Vec2 &origin, Binding b) {
113 0 : const float incr = OverlayHorizontalIncrement;
114 0 : auto size = _sceneContent->getContentSize();
115 :
116 0 : switch (b) {
117 0 : case Binding::Relative:
118 0 : _surface->setPositionY(origin.y);
119 0 : if (origin.x < incr / 4) {
120 0 : _surface->setPositionX(incr / 4);
121 0 : _surface->setAnchorPoint(Vec2(0, 1.0f));
122 0 : } else if (origin.x > size.width - incr / 4) {
123 0 : _surface->setPositionX(size.width - incr / 4);
124 0 : _surface->setAnchorPoint(Vec2(1, 1.0f));
125 : } else {
126 0 : float rel = (origin.x - incr / 4) / (size.width - incr / 2);
127 0 : _surface->setPositionX(origin.x);
128 0 : _surface->setAnchorPoint(Vec2(rel, 1.0f));
129 : }
130 0 : break;
131 0 : case Binding::OriginLeft:
132 0 : _surface->setPositionY(origin.y);
133 0 : if (origin.x - incr / 4 < _fullSize.width) {
134 0 : _surface->setAnchorPoint(Vec2(0, 1.0f));
135 0 : _surface->setPositionX(incr / 4);
136 : } else {
137 0 : _surface->setAnchorPoint(Vec2(1, 1.0f));
138 0 : _surface->setPositionX(origin.x);
139 : }
140 0 : break;
141 0 : case Binding::OriginRight:
142 0 : _surface->setPositionY(origin.y);
143 0 : if (size.width - origin.x - incr / 4 < _fullSize.width) {
144 0 : _surface->setAnchorPoint(Vec2(1, 1.0f));
145 0 : _surface->setPositionX(size.width - incr / 4);
146 : } else {
147 0 : _surface->setAnchorPoint(Vec2(0, 1.0f));
148 0 : _surface->setPositionX(origin.x);
149 : }
150 0 : break;
151 0 : case Binding::Anchor:
152 0 : _surface->setPosition(origin);
153 :
154 0 : break;
155 : }
156 :
157 0 : if (b != Binding::Anchor && b != Binding::Relative) {
158 0 : if (_fullSize.height > origin.y - incr / 4) {
159 0 : if (origin.y - incr / 4 < incr * 4) {
160 0 : if (_fullSize.height > incr * 4) {
161 0 : _fullSize.height = incr * 4;
162 : }
163 :
164 0 : _surface->setPositionY(_fullSize.height + incr / 4);
165 : } else {
166 0 : _fullSize.height = origin.y - incr / 4;
167 : }
168 : }
169 0 : } else if (b == Binding::Relative) {
170 0 : if (_fullSize.height > origin.y - incr / 4) {
171 0 : _surface->setAnchorPoint(Vec2(getAnchorPoint().x, (origin.y - incr / 4) / _fullSize.height));
172 : }
173 : }
174 :
175 0 : if (origin.y > size.height - incr / 4) {
176 0 : _surface->setPositionY(size.height - incr / 4);
177 : }
178 :
179 0 : _surface->setContentSize(Size2(_fullSize.width, 1));
180 0 : _surface->runAction(Rc<Sequence>::create(material2d::makeEasing(Rc<ResizeTo>::create(0.2f, _fullSize)), [this] {
181 0 : if (_readyCallback) {
182 0 : _readyCallback(true);
183 : }
184 0 : }));
185 0 : }
186 :
187 : }
|