Simple GUI Library
parent.cpp
Go to the documentation of this file.
1/**
2 * @author Nikita Mochalov (github.com/tralf-strues)
3 * @file parent.cpp
4 * @date 2021-11-06
5 *
6 * @copyright Copyright (c) 2021
7 */
8
9#include "scene/utils.h"
10#include "scene/parent.h"
11
12namespace Sgl
13{
14 Component* Parent::getHitComponent(int32_t x, int32_t y)
15 {
16 if (!isInteractable()) { return nullptr; }
17
18 for (auto child = m_Children.rbegin(); child != m_Children.rend(); ++child)
19 {
20 if (!(*child)->isInteractable())
21 {
22 continue;
23 }
24
25 Component* hitted = (*child)->getHitComponent(x - getLayoutX(), y - getLayoutY());
26
27 if (hitted != nullptr)
28 {
29 return hitted;
30 }
31 }
32
33 return nullptr;
34 }
35
36 void Parent::render(const Sml::Rectangle<int32_t>& targetRegion)
37 {
38 if (!isVisible())
39 {
40 return;
41 }
42
43 renderShadow(targetRegion);
44
45 Sml::Rectangle<int32_t> translatedTargetRegion = getLayoutBounds();
46 translatedTargetRegion.pos += targetRegion.pos;
47
48 if (m_Snapshot != nullptr)
49 {
50 Sml::Rectangle<int32_t> originBounds = getOriginBounds();
51 renderTexture(*m_Snapshot, &translatedTargetRegion, &originBounds);
52 }
53
54 for (Component* child : getChildren())
55 {
56 if (child->isVisible())
57 {
58 child->render(translatedTargetRegion);
59 }
60 }
61 }
62
63 // TODO: layout only if NEEDS_LAYOUT or DIRTY_BRANCH
64 void Parent::layout()
65 {
66 layoutChildren();
67
68 for (Component* child : m_Children)
69 {
70 child->layout();
71 }
72
73 m_NeedLayoutPass = false;
74 }
75
76 void Parent::prerender()
77 {
78 for (Component* child : m_Children)
79 {
80 child->prerender();
81 }
82
83 updateSnapshotSize();
84
85 Sml::Renderer::getInstance().pushSetTarget(m_Snapshot);
86
87 Sml::Renderer::getInstance().setColor(Sml::COLOR_TRANSPARENT);
88 Sml::Renderer::getInstance().clear();
89 prerenderSelf();
90
91 Sml::Renderer::getInstance().popTarget();
92
93 updateShadow();
94 }
95
96 bool Parent::containsComponent(Component* component)
97 {
98 assert(component);
99
100 if (component == this)
101 {
102 return true;
103 }
104
105 for (auto child : m_Children)
106 {
107 if (child->containsComponent(component))
108 {
109 return true;
110 }
111 }
112
113 return false;
114 }
115
116 void Parent::prerenderSelf(){}
117
118 void Parent::layoutChildren()
119 {
120 for (Component* component : m_Children)
121 {
122 component->setLayoutWidth(component->computePrefWidth());
123 component->setLayoutHeight(component->computePrefHeight());
124 }
125 }
126
127 bool Parent::isResizable() const { return true; }
128
130 {
131 assert(child);
132
133 for (auto existingChild : m_Children)
134 {
135 if (existingChild == child)
136 {
137 return;
138 }
139 }
140
141 m_Children.push_back(child);
142 child->setParent(this);
143 child->setScene(getScene());
144 }
145
147 {
148 assert(child);
149 assert(child->getParent() == this);
150
151 m_Children.remove(child);
152 child->setParent(nullptr);
153 }
154
156 {
157 m_Children.clear();
158 }
159
160 std::list<Component*>& Parent::getChildren() { return m_Children; }
161 const std::list<Component*>& Parent::getChildrenReadonly() const { return m_Children; }
162
163 Sml::Texture* Parent::getSnapshot() { return m_Snapshot; }
164
165 bool Parent::needLayoutPass() const { return m_NeedLayoutPass; }
166 void Parent::requestLayoutPass() { m_NeedLayoutPass = true; }
167
168 const Background* Parent::getBackground() const { return m_Background; }
169 void Parent::setBackground(const Background* background) { m_Background = background; }
170
171 const Border* Parent::getBorder() const { return m_Border; }
172 void Parent::setBorder(const Border* border) { m_Border = border; }
173
174 Insets Parent::getInsets() const
175 {
176 return (m_Border == nullptr ? Insets::EMPTY : m_Border->getThickness()) + getPadding();
177 }
178
179 Sml::Rectangle<int32_t> Parent::getContentArea() const
180 {
181 Insets insets = getInsets();
182 Sml::Rectangle<int32_t> contentArea = getOriginBounds();
183 contentArea.pos += {insets.left, insets.top};
184 contentArea.width -= insets.left + insets.right;
185 contentArea.height -= insets.top + insets.bottom;
186
187 return contentArea;
188 }
189
190 Insets Parent::getPadding() const { return m_Padding; }
191 void Parent::setPadding(const Insets& padding) { m_Padding = padding; }
192
193 void Parent::setPrefWidth (int32_t width) { m_PrefWidth = width; }
194 void Parent::setPrefHeight(int32_t height) { m_PrefHeight = height; }
195
196 void Parent::setMinWidth (int32_t width) { m_MinWidth = width; }
197 void Parent::setMinHeight(int32_t height) { m_MinHeight = height; }
198
199 void Parent::setMaxWidth (int32_t width) { m_MaxWidth = width; }
200 void Parent::setMaxHeight(int32_t height) { m_MaxHeight = height; }
201
202 int32_t Parent::getPrefWidth() const { return m_PrefWidth; }
203 int32_t Parent::getPrefHeight() const { return m_PrefHeight; }
204
205 int32_t Parent::getMinWidth() const { return m_MinWidth; }
206 int32_t Parent::getMinHeight() const { return m_MinHeight; }
207
208 int32_t Parent::getMaxWidth() const { return m_MaxWidth; }
209 int32_t Parent::getMaxHeight() const { return m_MaxHeight; }
210
211 #define CHECK_ENABLED_SIZE(size) if (size != USE_COMPUTED_SIZE) { return size; }
212
213 int32_t Parent::computePrefWidth(int32_t height) const
214 {
215 CHECK_ENABLED_SIZE(m_PrefWidth);
216 return computeCustomPrefWidth(height);
217 }
218
219 int32_t Parent::computePrefHeight(int32_t width) const
220 {
221 CHECK_ENABLED_SIZE(m_PrefHeight);
222 return computeCustomPrefHeight(width);
223 }
224
225 int32_t Parent::computeMinWidth(int32_t height) const
226 {
227 CHECK_ENABLED_SIZE(m_MinWidth);
228 return computeCustomMinWidth(height);
229 }
230
231 int32_t Parent::computeMinHeight(int32_t width) const
232 {
233 CHECK_ENABLED_SIZE(m_MinHeight);
234 return computeCustomMinHeight(width);
235 }
236
237 int32_t Parent::computeMaxWidth(int32_t height) const
238 {
239 CHECK_ENABLED_SIZE(m_MaxWidth);
240 return computeCustomMaxWidth(height);
241 }
242
243 int32_t Parent::computeMaxHeight(int32_t width) const
244 {
245 CHECK_ENABLED_SIZE(m_MaxHeight);
246 return computeCustomMaxHeight(width);
247 }
248
249 int32_t Parent::computeCustomPrefWidth(int32_t height) const
250 {
251 COMPONENT_COMPUTE_DIMENSION(Pref, Width, height, X, m_Children, m_PrefWidth,
252 getInsets().left + getInsets().right);
253 }
254 int32_t Parent::computeCustomPrefHeight(int32_t width) const
255 {
256 COMPONENT_COMPUTE_DIMENSION(Pref, Height, width, Y, m_Children, m_PrefHeight,
257 getInsets().top + getInsets().bottom);
258 }
259
260 int32_t Parent::computeCustomMinWidth(int32_t height) const { return computePrefWidth(height); }
261 int32_t Parent::computeCustomMinHeight(int32_t width) const { return computePrefHeight(width); }
262
263 int32_t Parent::computeCustomMaxWidth(int32_t height) const { return UNLIMITED_SIZE; }
264 int32_t Parent::computeCustomMaxHeight(int32_t width) const { return UNLIMITED_SIZE; }
265
266 void Parent::updateSnapshotSize()
267 {
268 int32_t width = m_LayoutBounds.width;
269 int32_t height = m_LayoutBounds.height;
270
271 if (width <= 0 || height <= 0)
272 {
273 return;
274 }
275
276 if (m_Snapshot == nullptr)
277 {
278 m_Snapshot = new Sml::Texture(width, height);
279 }
280 else if (static_cast<int32_t>(m_Snapshot->getWidth()) < width ||
281 static_cast<int32_t>(m_Snapshot->getHeight()) < height)
282 {
283 delete m_Snapshot;
284 m_Snapshot = new Sml::Texture(width, height);
285 }
286 }
287
288 void Parent::setSceneInSceneTree(Scene* scene)
289 {
290 Component::setSceneInSceneTree(scene);
291
292 for (Component* child : m_Children)
293 {
294 child->setScene(scene);
295 }
296 }
297}
void addChild(Component *child)
Convenience method for adding a child to Parent.
Definition: parent.cpp:129
void removeChildren()
Definition: parent.cpp:155
void removeChild(Component *child)
Convenience method for removing a child to Parent.
Definition: parent.cpp:146