Simple GUI Library
component.cpp
Go to the documentation of this file.
1/**
2 * @author Nikita Mochalov (github.com/tralf-strues)
3 * @file component.cpp
4 * @date 2021-11-06
5 *
6 * @copyright Copyright (c) 2021
7 */
8
9#include "scene/parent.h"
10#include "scene/scene.h"
11
12namespace Sgl
13{
14 Component* Component::getHitComponent(int32_t x, int32_t y)
15 {
16 if (Sml::isPointInsideRectangle({x, y}, getLayoutBounds()))
17 {
18 return this;
19 }
20
21 return nullptr;
22 }
23
24 void Component::layout() {}
25 void Component::prerender() {}
26
27 bool Component::containsComponent(Component* component)
28 {
29 assert(component);
30 return this == component;
31 }
32
33 Sml::EventDispatchChain* Component::buildEventDispatchChain(Sml::EventDispatchChain* chain)
34 {
35 assert(chain);
36
37 chain->prependDispatcher(&m_Dispatcher);
38
39 if (m_Parent == nullptr)
40 {
41 return chain;
42 }
43
44 return m_Parent->buildEventDispatchChain(chain);
45 }
46
47 bool Component::isVisible() const { return GET_BIT(static_cast<uint32_t>(m_Visibility), 1) == 1; }
48
49 void Component::setVisible(bool visible)
50 {
51 uint32_t mask = static_cast<uint32_t>(m_Visibility);
52
53 if (visible)
54 {
55 mask |= 1 << 1;
56 }
57 else
58 {
59 mask &= ~(1 << 1);
60 }
61
62 m_Visibility = static_cast<Visibility>(mask);
63 }
64
65 bool Component::isInteractable() const { return GET_BIT(static_cast<uint32_t>(m_Visibility), 0) == 1; }
66
67 void Component::setInteractable(bool interactable)
68 {
69 uint32_t mask = static_cast<uint32_t>(m_Visibility);
70
71 if (interactable)
72 {
73 mask |= 1 << 0;
74 }
75 else
76 {
77 mask &= ~(1 << 0);
78 }
79
80 m_Visibility = static_cast<Visibility>(mask);
81 }
82
83 Component::Visibility Component::getVisibility() const { return m_Visibility; }
84 void Component::setVisibility(Visibility visibility) { m_Visibility = visibility; }
85
86 bool Component::isFocused() const { return m_Focused; }
87 bool Component::isHovered() const { return m_Hovered; }
88
89 void Component::requestFocus()
90 {
91 assert(getScene());
92
93 getScene()->requestFocus(this);
94 }
95
96 void Component::requestDrag()
97 {
98 assert(getScene());
99
100 getScene()->requestDrag(this);
101 }
102
103 const Shadow& Component::getShadow() const
104 {
105 return m_Shadow;
106 }
107
108 void Component::setShadow(const ShadowSpecification* specification)
109 {
110 m_Shadow.setSpecification(specification);
111 }
112
113 GuiEventDispatcher* Component::getEventDispatcher()
114 {
115 return &m_Dispatcher;
116 }
117
118 Scene* Component::getScene()
119 {
120 return m_Scene;
121 }
122
123 void Component::setScene(Scene* scene)
124 {
125 setSceneInSceneTree(scene);
126 }
127
128 const Parent* Component::getParent() const
129 {
130 return m_Parent;
131 }
132
133 Parent* Component::getModifiableParent()
134 {
135 return m_Parent;
136 }
137
138 void Component::setParent(Parent* parent)
139 {
140 m_Parent = parent;
141
142 if (m_Parent != nullptr)
143 {
144 m_Scene = m_Parent->getScene();
145 }
146 }
147
148 Sml::Vec2i Component::computeLocalToScenePos(const Sml::Vec2i& localPos) const
149 {
150 if (getParent() == nullptr) { return localPos; }
151 return getParent()->computeLocalToScenePos(localPos + getLayoutPos());
152 }
153
154 Sml::Vec2i Component::computeSceneToLocalPos(const Sml::Vec2i& scenePos) const
155 {
156 if (getParent() == nullptr) { return scenePos - getLayoutPos(); }
157 return getParent()->computeSceneToLocalPos(scenePos - getLayoutPos());
158 }
159
160 Sml::Rectangle<int32_t> Component::getOriginBounds() const
161 {
162 return Sml::Rectangle<int32_t>{{0, 0}, getLayoutWidth(), getLayoutHeight()};
163 }
164
165 const Sml::Rectangle<int32_t>& Component::getLayoutBounds() const
166 {
167 return m_LayoutBounds;
168 }
169
170 const Sml::Vec2i& Component::getLayoutPos() const
171 {
172 return m_LayoutBounds.pos;
173 }
174
175 int32_t Component::getLayoutX() const
176 {
177 return m_LayoutBounds.pos.x;
178 }
179
180 int32_t Component::getLayoutY() const
181 {
182 return m_LayoutBounds.pos.y;
183 }
184
185 int32_t Component::getLayoutWidth() const
186 {
187 return m_LayoutBounds.width;
188 }
189
190 int32_t Component::getLayoutHeight() const
191 {
192 return m_LayoutBounds.height;
193 }
194
195 void Component::setLayoutX(int32_t x)
196 {
197 m_LayoutBounds.pos.x = x;
198 }
199
200 void Component::setLayoutY(int32_t y)
201 {
202 m_LayoutBounds.pos.y = y;
203 }
204
205 void Component::setLayoutWidth(int32_t width)
206 {
207 m_LayoutBounds.width = width;
208 }
209
210 void Component::setLayoutHeight(int32_t height)
211 {
212 m_LayoutBounds.height = height;
213 }
214
215 Sml::Vec2i Component::computeScenePos()
216 {
217 Sml::Vec2i scenePos = getLayoutBounds().pos;
218
219 const Component* parent = getParent();
220 while (parent != nullptr)
221 {
222 scenePos += parent->getLayoutBounds().pos;
223 parent = parent->getParent();
224 }
225
226 return scenePos;
227 }
228
229 void Component::updateShadow()
230 {
231 if (getLayoutWidth() == 0 || getLayoutHeight() == 0 || m_Shadow.getSpecification() == nullptr || !isVisible())
232 {
233 return;
234 }
235
236 Sml::Renderer& renderer = Sml::Renderer::getInstance();
237
238 Sml::Texture* renderedComponent = new Sml::Texture(m_LayoutBounds.width, m_LayoutBounds.height);
239
240 renderer.pushSetTarget(renderedComponent);
241
242 Sml::Vec2i savedLayoutPos = m_LayoutBounds.pos;
243 m_LayoutBounds.pos = {0, 0};
244 render(getOriginBounds());
245 m_LayoutBounds.pos = savedLayoutPos;
246
247 renderer.popTarget();
248
249 m_Shadow.update(renderedComponent, getLayoutBounds());
250
251 delete renderedComponent;
252 }
253
254 void Component::renderShadow(const Sml::Rectangle<int32_t>& targetRegion)
255 {
256 if (isVisible())
257 {
258 m_Shadow.render(getLayoutBounds(), targetRegion);
259 }
260 }
261
262 void Component::setSceneInSceneTree(Scene* scene)
263 {
264 m_Scene = scene;
265 }
266}
Visibility
Used to determine if Component should be rendered and targeted by events.
Definition: component.h:36