AUI Framework  master
Cross-platform module-based framework for developing C++20 desktop applications
AViewContainerBase.h
1/*
2 * AUI Framework - Declarative UI toolkit for modern C++20
3 * Copyright (C) 2020-2024 Alex2772 and Contributors
4 *
5 * SPDX-License-Identifier: MPL-2.0
6 *
7 * This Source Code Form is subject to the terms of the Mozilla Public
8 * License, v. 2.0. If a copy of the MPL was not distributed with this
9 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 */
11
12#pragma once
13
14#include <AUI/Views.h>
15#include <AUI/View/AView.h>
16#include "AUI/Common/SharedPtr.h"
17#include "AUI/Enum/AOverflow.h"
18#include "AUI/Util/ABitField.h"
19#include <glm/glm.hpp>
20#include "AUI/Layout/ALayout.h"
21#include "AUI/Common/AVector.h"
22#include "AUI/Render/IRenderer.h"
23#include "AUI/Render/RenderHints.h"
24#include "AUI/Render/ARenderContext.h"
25#include "glm/fwd.hpp"
26
27
28AUI_ENUM_FLAG(AViewLookupFlags) {
29 NONE = 0,
30
34 IGNORE_VISIBILITY = 0b1,
35
42 ONLY_ONE_PER_CONTAINER = 0b10,
43
50 ONLY_THAT_CONSUMES_CLICK = 0b100,
51};
52
68class API_AUI_VIEWS AViewContainerBase : public AView {
69public:
70 friend class AView;
71
73 APointerIndex pointerIndex;
74 _weak<AView> targetView;
79 bool isBlockClicksWhenPressed = true;
80 };
81
83 ~AViewContainerBase() override = 0; // this class is intended to be derived; use AViewContainer for trivial
84 // container
85
86
87
88 void render(ARenderContext context) override;
89
90 void onMouseEnter() override;
91
92 void onPointerMove(glm::vec2 pos, const APointerMoveEvent& event) override;
93
94 void onMouseLeave() override;
95
96 void onDpiChanged() override;
97
98 void onClickPrevented() override;
99
100 int getContentMinimumWidth() override;
101
102 int getContentMinimumHeight() override;
103
104 void onPointerPressed(const APointerPressedEvent& event) override;
105
106 void onPointerDoubleClicked(const APointerPressedEvent& event) override;
107
108 void onPointerReleased(const APointerReleasedEvent& event) override;
109
110 void onScroll(const AScrollEvent& event) override;
111
112 bool onGesture(const glm::ivec2& origin, const AGestureEvent& event) override;
113
114 bool consumesClick(const glm::ivec2& pos) override;
115
116 void setSize(glm::ivec2 size) override;
117
118 void setEnabled(bool enabled = true) override;
119
120 auto begin() const {
121 return mViews.cbegin();
122 }
123
124 auto end() const {
125 return mViews.cend();
126 }
127
131 const AVector<_<AView>>& getViews() const {
132 return mViews;
133 }
134
135
139 [[nodiscard]]
140 const _unique<ALayout>& getLayout() const noexcept {
141 return mLayout;
142 }
143
152 [[nodiscard]]
153 virtual _<AView> getViewAt(glm::ivec2 pos, ABitField<AViewLookupFlags> flags = AViewLookupFlags::NONE) const noexcept;
154
161 [[nodiscard]]
162 _<AView> getViewAtRecursive(glm::ivec2 pos, ABitField<AViewLookupFlags> flags = AViewLookupFlags::NONE) const noexcept;
163
173 template<aui::predicate<_<AView>> Callback>
174 bool getViewAtRecursive(glm::ivec2 pos, const Callback& callback, ABitField<AViewLookupFlags> flags = AViewLookupFlags::NONE) {
175 _<AView> possibleOutput; // for case if anyone does not consumesClick
176 auto process = [&](const _<AView>& view) {
177 if (callback(view))
178 return true;
179 if (auto container = _cast<AViewContainerBase>(view)) {
180 if (container->getViewAtRecursive(pos - view->getPosition(), callback, flags)) {
181 return true;
182 }
183 }
184 return false;
185 };
186
187 for (const auto& view : aui::reverse_iterator_wrap(mViews)) {
188 auto targetPos = pos - view->getPosition();
189
190 if (targetPos.x < 0 || targetPos.y < 0 || targetPos.x >= view->getSize().x || targetPos.y >= view->getSize().y) {
191 continue;
192 }
193 if (!flags.test(AViewLookupFlags::IGNORE_VISIBILITY) && !(view->getVisibility() & Visibility::FLAG_CONSUME_CLICKS)) {
194 continue;
195 }
196
197 if (view->consumesClick(targetPos)) {
198 if (flags.test(AViewLookupFlags::IGNORE_VISIBILITY) || !!(view->getVisibility() & Visibility::FLAG_CONSUME_CLICKS)) {
199 if (process(view)) {
200 return true;
201 }
202
203 if (flags.test(AViewLookupFlags::ONLY_ONE_PER_CONTAINER)) {
204 return false;
205 }
206 }
207 } else {
208 if (possibleOutput == nullptr) {
209 possibleOutput = view;
210 }
211 }
212 }
213 if (possibleOutput) {
214 return process(possibleOutput);
215 }
216
217 return false;
218 }
219
226 template<aui::predicate<_<AView>> Callback>
227 bool visitsViewRecursive(Callback&& callback, ABitField<AViewLookupFlags> flags = AViewLookupFlags::NONE) {
228 for (auto it = mViews.rbegin(); it != mViews.rend(); ++it) {
229 auto view = *it;
230 if (flags.test(AViewLookupFlags::IGNORE_VISIBILITY) || !!(view->getVisibility() & Visibility::FLAG_CONSUME_CLICKS)) {
231 if (callback(view))
232 return true;
233 if (auto container = _cast<AViewContainerBase>(view)) {
234 if (container->visitsViewRecursive(callback, flags)) {
235 return true;
236 }
237 }
238 if (flags.test(AViewLookupFlags::ONLY_ONE_PER_CONTAINER)) {
239 break;
240 }
241 }
242 }
243 return false;
244 }
245
246
253 template<typename T>
254 _<T> getViewAtRecursiveOfType(glm::ivec2 pos, ABitField<AViewLookupFlags> flags = AViewLookupFlags::NONE) {
255 _<T> result;
256 getViewAtRecursive(pos, [&] (const _<AView>& v) { return bool(result = _cast<T>(v)); }, flags);
257 return result;
258 }
259
267 if (auto v = target.lock()) {
268 AUI_ASSERT(v->mParent == this);
269 }
270 mFocusChainTarget = std::move(target);
271 }
278 if (auto v = mFocusChainTarget.lock()) {
279 if (v->mParent != this) {
280 mFocusChainTarget.reset();
281 return nullptr;
282 }
283 return v;
284 }
285 return nullptr;
286 }
287
288
289 void applyGeometryToChildrenIfNecessary();
290
291 void onKeyDown(AInput::Key key) override;
292
293 void onKeyRepeat(AInput::Key key) override;
294
295 void onKeyUp(AInput::Key key) override;
296
297 void onCharEntered(char16_t c) override;
298
299 bool capturesFocus() override;
300
305 return mPointerEventsMapping;
306 }
307
308 void forceUpdateLayoutRecursively() override;
309
310 void markMinContentSizeInvalid() override;
311 void markPixelDataInvalid(ARect<int> invalidArea) override;
312
313protected:
314 AVector<_<AView>> mViews;
315 bool mWantsLayoutUpdate = true;
316 glm::ivec2 mLastLayoutUpdateSize{0, 0};
317
318 void drawView(const _<AView>& view, ARenderContext contextOfTheContainer);
319
320 template<typename Iterator>
321 void drawViews(Iterator begin, Iterator end, ARenderContext contextPassedToContainer) {
322 switch (mOverflow) {
323 case AOverflow::VISIBLE: break;
326 contextPassedToContainer.clip(ARect<int>{
327 .p1 = {0, 0},
328 .p2 = getSize(),
329 });
330 }
331
332 for (auto i = begin; i != end; ++i) {
333 drawView(*i, contextPassedToContainer);
334 }
335 }
336
337 void invalidateAllStyles() override;
338 void onViewGraphSubtreeChanged() override;
339 void invalidateAssHelper() override;
340
344 void setViews(AVector<_<AView>> views);
345
353 void addViewCustomLayout(const _<AView>& view);
354
358 void addViews(AVector<_<AView>> views);
359
363 void addView(const _<AView>& view);
364
368 void addView(size_t index, const _<AView>& view);
369
373 void removeView(const _<AView>& view);
374
378 void removeView(AView* view);
379
383 void removeView(size_t index);
384
388 void removeAllViews();
389
394 void setContents(const _<AViewContainer>& container);
395
399 void setLayout(_unique<ALayout> layout);
400
401 void renderChildren(ARenderContext contextPassedToContainer) {
402 drawViews(mViews.begin(), mViews.end(), contextPassedToContainer);
403 }
404
405 virtual void applyGeometryToChildren();
406
407signals:
412
413private:
414 _unique<ALayout> mLayout;
415 bool mSizeSet = false;
416
417
418 struct RepaintTrap {
419 bool triggered = false;
420 };
421 AOptional<RepaintTrap> mRepaintTrap;
422
423 struct ConsumesClickCache {
424 glm::ivec2 position;
425 bool value;
426 };
427
434 AOptional<ConsumesClickCache> mConsumesClickCache;
435
442 _weak<AView> mFocusChainTarget;
443
448 ASmallVector<PointerEventsMapping, 1> mPointerEventsMapping;
449
450 void notifyParentEnabledStateChanged(bool enabled) override;
451 void invalidateCaches();
452
456 _<AView> pointerEventsMapping(APointerIndex index);
457};
Bit field implementation.
Definition: ABitField.h:20
Utility wrapper implementing the stack-allocated (fast) optional idiom.
Definition: AOptional.h:32
Wrapper class that stores either mouse button index or finger index.
Definition: APointerIndex.h:21
Vector-like container consisting of few elements on stack and switches to dynamic allocation vector i...
Definition: ASmallVector.h:34
A std::vector with AUI extensions.
Definition: AVector.h:38
A view that represents a set of views.
Definition: AViewContainerBase.h:68
void setFocusChainTarget(_weak< AView > target)
Set focus chain target.
Definition: AViewContainerBase.h:266
bool getViewAtRecursive(glm::ivec2 pos, const Callback &callback, ABitField< AViewLookupFlags > flags=AViewLookupFlags::NONE)
Acts as AViewContainerBase::getViewAtRecursive but calls a callback instead of returning value.
Definition: AViewContainerBase.h:174
emits childrenChanged
Emitted when addView(s)/removeView/setLayout was called.
Definition: AViewContainerBase.h:411
const _unique< ALayout > & getLayout() const noexcept
Get layout manager of the container.
Definition: AViewContainerBase.h:140
bool visitsViewRecursive(Callback &&callback, ABitField< AViewLookupFlags > flags=AViewLookupFlags::NONE)
Definition: AViewContainerBase.h:227
_< AView > focusChainTarget()
Definition: AViewContainerBase.h:277
const ASmallVector< PointerEventsMapping, 1 > & pointerEventsMapping() const noexcept
Definition: AViewContainerBase.h:304
_< T > getViewAtRecursiveOfType(glm::ivec2 pos, ABitField< AViewLookupFlags > flags=AViewLookupFlags::NONE)
Acts as AViewContainerBase::getViewAtRecursive but finds a view castable to specified template type.
Definition: AViewContainerBase.h:254
const AVector< _< AView > > & getViews() const
Get all views of the container.
Definition: AViewContainerBase.h:131
Base class of all UI objects.
Definition: AView.h:77
virtual int getContentMinimumHeight()
Definition: AView.cpp:252
virtual bool consumesClick(const glm::ivec2 &pos)
Determines whether this AView processes this click or passes it thru.
Definition: AView.cpp:534
virtual bool onGesture(const glm::ivec2 &origin, const AGestureEvent &event)
Definition: AView.cpp:598
virtual void invalidateAssHelper()
Resets mAssHelper.
Definition: AView.cpp:291
virtual void onPointerMove(glm::vec2 pos, const APointerMoveEvent &event)
Handles pointer hover events.
Definition: AView.cpp:343
virtual void onViewGraphSubtreeChanged()
Called when direct or indirect parent has changed.
Definition: AView.cpp:689
virtual void onClickPrevented()
Called on AWindowBase::preventClickOnPointerRelease.
Definition: AView.cpp:674
glm::ivec2 getSize() const noexcept
Size, including content area, border and padding.
Definition: AView.h:370
virtual int getContentMinimumWidth()
Definition: AView.cpp:248
virtual void onPointerPressed(const APointerPressedEvent &event)
Called on pointer (mouse) released event.
Definition: AView.cpp:357
virtual bool capturesFocus()
Definition: AView.cpp:567
virtual void markPixelDataInvalid(ARect< int > invalidArea)
A view requests to redraw it and passes it's coords relative to this.
Definition: AView.cpp:710
virtual void onPointerReleased(const APointerReleasedEvent &event)
Called on pointer (mouse) released event.
Definition: AView.cpp:366
virtual void render(ARenderContext ctx)
Draws this AView. Noone should call this function except rendering routine.
Definition: AView.cpp:142
virtual void invalidateAllStyles()
Invalidates all styles, causing to iterate over all rules in global and parent stylesheets.
Definition: AView.cpp:179
virtual void onScroll(const AScrollEvent &event)
Definition: AView.cpp:407
An std::weak_ptr with AUI extensions.
Definition: SharedPtrTypes.h:177
@ NONE
Image is kept in it's original size.
AUI_ENUM_FLAG(ASide)
Describes sides of a 2D rectangle.
Definition: ASide.h:24
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition: Assert.h:55
@ HIDDEN_FROM_THIS
Like HIDDEN, but view's ASS-styled background is also affected by mask.
@ HIDDEN
Overflowed contents are hidden. Suitable for lists with scroll.
@ VISIBLE
Overflowed contents are visible.
Pointing method move event.
Definition: APointerMoveEvent.h:21
Pointing method press event.
Definition: APointerPressedEvent.h:21
Pointing method press event.
Definition: APointerReleasedEvent.h:19
Axis aligned 2D rectangle.
Definition: ARect.h:24
Render context passed to AView::render.
Definition: ARenderContext.h:43
Pointing method scroll event.
Definition: AScrollEvent.h:20
Definition: AViewContainerBase.h:72
An std::weak_ptr with AUI extensions.
Definition: SharedPtrTypes.h:51
Definition: iterators.h:34