Simple GUI Library
scene.cpp
Go to the documentation of this file.
1/**
2 * @author Nikita Mochalov (github.com/tralf-strues)
3 * @file scene.cpp
4 * @date 2021-11-06
5 *
6 * @copyright Copyright (c) 2021
7 */
8
9#include "sml/events/system_events.h"
10#include "scene/scene.h"
11#include "scene/parent.h"
12
13namespace Sgl
14{
15 Scene::Scene(int32_t width, int32_t height) : m_Width(width), m_Height(height) {}
16
17 void Scene::update()
18 {
19 if (m_Root == nullptr) { return; }
20
21 m_Root->setLayoutX(0);
22 m_Root->setLayoutY(0);
23 m_Root->setLayoutWidth(m_Width);
24 m_Root->setLayoutHeight(m_Height);
25
26 m_Root->layout();
27 m_Root->prerender();
28
29 for (ContextMenu* contextMenu : m_ContextMenus)
30 {
31 contextMenu->setLayoutWidth(contextMenu->computePrefWidth());
32 contextMenu->setLayoutHeight(contextMenu->computePrefHeight());
33
34 Component* source = contextMenu->getSource();
35 if (source == nullptr)
36 {
37 Sml::Rectangle<int32_t> centeredPos = Sml::centerRegion(getLayoutRegion(),
38 contextMenu->getOriginBounds());
39
40 contextMenu->setLayoutX(centeredPos.pos.x);
41 contextMenu->setLayoutY(centeredPos.pos.y);
42 }
43 else
44 {
45 Sml::Vec2i bottomLeftCorner = source->computeScenePos();
46 bottomLeftCorner.y += source->getLayoutHeight();
47
48 contextMenu->setLayoutX(bottomLeftCorner.x);
49 contextMenu->setLayoutY(bottomLeftCorner.y);
50 }
51
52 contextMenu->layout();
53 contextMenu->prerender();
54 }
55 }
56
57 void Scene::render(const Sml::Rectangle<int32_t>& targetRegion)
58 {
59 if (m_Root != nullptr)
60 {
61 m_Root->render(targetRegion);
62 }
63
64 for (ContextMenu* contextMenu : m_ContextMenus)
65 {
66 contextMenu->render(targetRegion);
67 }
68 }
69
70 void Scene::proccessEvent(Sml::Event* event)
71 {
72 assert(event);
73
74 if (event->isInCategory(Sml::MouseEvent::getStaticCategory()))
75 {
76 proccessMouseEvent(dynamic_cast<Sml::MouseEvent*>(event));
77 }
78 else if (event->isInCategory(Sml::KeyEvent::getStaticCategory()))
79 {
80 proccessKeyboardEvent(dynamic_cast<Sml::KeyEvent*>(event));
81 }
82 }
83
84 Sml::EventDispatchChain* Scene::buildEventDispatchChain(Sml::EventDispatchChain* chain)
85 {
86 assert(chain);
87
88 chain->prependDispatcher(&m_Dispatcher);
89 return chain;
90 }
91
92 GuiEventDispatcher* Scene::getEventDispatcher() { return &m_Dispatcher; }
93
94 Sml::Rectangle<int32_t> Scene::getLayoutRegion() const { return {{0, 0}, m_Width, m_Height}; }
95
96 int32_t Scene::getWidth() const { return m_Width; }
97 void Scene::setWidth(int32_t width) { m_Width = width; }
98
99 int32_t Scene::getHeight() const { return m_Height; }
100 void Scene::setHeight(int32_t height) { m_Height = height; }
101
102 Parent* Scene::getRoot() { return m_Root; }
103 void Scene::setRoot(Parent* root) { m_Root = root; m_Root->setScene(this); }
104
105 Component* Scene::getFocusOwner() { return m_FocusOwner; }
106
107 void Scene::requestFocus(Component* component)
108 {
109 if (m_FocusOwner != component)
110 {
111 Component* prevFocus = m_FocusOwner;
112 Component* newFocus = component;
113
114 if (m_FocusOwner != nullptr)
115 {
116 FocusLostEvent focusEvent{newFocus, prevFocus};
117 m_FocusOwner->m_Focused = false;
118 fireEvent(&focusEvent);
119 }
120
121 if (component != nullptr)
122 {
123 FocusReceivedEvent focusEvent{prevFocus, newFocus};
124 component->m_Focused = true;
125 fireEvent(&focusEvent);
126 }
127 }
128
129 m_FocusOwner = component;
130 }
131
132 Component* Scene::getDragOwner() { return m_DragOwner; }
133
134 void Scene::requestDrag(Component* component)
135 {
136 assert(component);
137
138 finishDrag();
139
140 m_DragOwner = component;
141
142 DragStartEvent dragStartEvent{Sml::MouseState::getMouseState().x,
143 Sml::MouseState::getMouseState().y,
144 m_DragOwner};
145 fireEvent(&dragStartEvent);
146 }
147
148 void Scene::finishDrag()
149 {
150 if (m_DragOwner != nullptr)
151 {
152 DragEndEvent dragEndEvent{Sml::MouseState::getMouseState().x,
153 Sml::MouseState::getMouseState().y,
154 m_DragOwner};
155 fireEvent(&dragEndEvent);
156
157 m_DragOwner = nullptr;
158 }
159 }
160
161 void Scene::registerContextMenu(ContextMenu* contextMenu)
162 {
163 assert(contextMenu);
164 m_ContextMenus.push_back(contextMenu);
165 }
166
167 void Scene::detachContextMenu(ContextMenu* contextMenu)
168 {
169 assert(contextMenu);
170 m_ContextMenus.remove(contextMenu);
171 }
172
173 Component* Scene::findHitComponentInContextMenus(int32_t x, int32_t y, ContextMenu** menu)
174 {
175 Component* hitComponent = nullptr;
176 ContextMenu* hitMenu = nullptr;
177
178 for (ContextMenu* contextMenu : m_ContextMenus)
179 {
180 hitComponent = contextMenu->getHitComponent(x, y);
181 if (hitComponent != nullptr)
182 {
183 hitMenu = contextMenu;
184 break;
185 }
186 }
187
188 if (menu != nullptr)
189 {
190 *menu = hitMenu;
191 }
192
193 return hitComponent;
194 }
195
196 Component* Scene::findHitComponentInRoot(int32_t x, int32_t y)
197 {
198 if (m_Root != nullptr)
199 {
200 return m_Root->getHitComponent(x, y);
201 }
202
203 return nullptr;
204 }
205
206 void Scene::updateHoverOwner(Component* newHoverOwner, int32_t mouseX, int32_t mouseY)
207 {
208 if (m_HoverOwner != newHoverOwner)
209 {
210 if (m_HoverOwner != nullptr)
211 {
212 MouseExitedEvent mouseExitedEvent{mouseX, mouseY, m_HoverOwner};
213 m_HoverOwner->m_Hovered = false;
214 fireEvent(&mouseExitedEvent);
215 }
216
217 if (newHoverOwner != nullptr)
218 {
219 MouseEnteredEvent mouseEnteredEvent{mouseX, mouseY, newHoverOwner};
220 newHoverOwner->m_Hovered = true;
221 fireEvent(&mouseEnteredEvent);
222 }
223 }
224
225 m_HoverOwner = newHoverOwner;
226 }
227
228 void Scene::proccessKeyboardEvent(Sml::KeyEvent* keyEvent)
229 {
230 assert(keyEvent);
231
232 // TODO:
233 }
234
235 void Scene::proccessMouseEvent(Sml::MouseEvent* mouseEvent)
236 {
237 assert(mouseEvent);
238
239 if (m_Root == nullptr)
240 {
241 return;
242 }
243
244 ContextMenu* hitMenu = nullptr;
245 Component* newHoverOwner = findHitComponentInContextMenus(mouseEvent->getX(), mouseEvent->getY(),
246 &hitMenu);
247
248 if (newHoverOwner == nullptr)
249 {
250 newHoverOwner = findHitComponentInRoot(mouseEvent->getX(), mouseEvent->getY());
251 }
252
253 updateHoverOwner(newHoverOwner, mouseEvent->getX(), mouseEvent->getY());
254
255 if (mouseEvent->isInCategory(Sml::SystemEventCategory::EVENT_CATEGORY_MOUSE_BUTTON))
256 {
257 finishDrag();
258 }
259
260 if (mouseEvent->getType() == Sml::MouseButtonPressedEvent::getStaticType())
261 {
262 requestFocus(newHoverOwner);
263 }
264
265 if (mouseEvent->getType() == Sml::MouseMovedEvent::getStaticType() && m_DragOwner != nullptr)
266 {
267 Sml::MouseMovedEvent* mouseMovedEvent = dynamic_cast<Sml::MouseMovedEvent*>(mouseEvent);
268 DragMoveEvent dragMoveEvent{mouseMovedEvent->getX(), mouseMovedEvent->getY(),
269 mouseMovedEvent->getDeltaX(), mouseMovedEvent->getDeltaY(),
270 m_DragOwner};
271
272 fireEvent(&dragMoveEvent);
273 }
274
275 if (newHoverOwner != nullptr)
276 {
277 mouseEvent->setTarget(newHoverOwner);
278 fireEvent(mouseEvent);
279 }
280 }
281}
Sml::Event * fireEvent(Sml::Event *event)
Fire the event from the specified.