Loading...
Searching...
No Matches
Core.h
Go to the documentation of this file.
1// Copyright (c) 2025 Dave R. Smith.
2// Malena Framework — Licensed under PolyForm Noncommercial 1.0.0; commercial use requires a paid license. See LICENSE.
3
4//
5// Created by Dave Smith on 10/4/25.
6//
7
8#ifndef MALENA_UICOMPONENTBASE_H
9#define MALENA_UICOMPONENTBASE_H
10
12#include <SFML/Graphics.hpp>
13#include <functional>
14#include <type_traits>
15#include <vector>
16
21
28
30
31namespace ml
32{
51 enum class Layer : int
52 {
54 Content = 100,
55 Overlay = 200,
56 };
57
85 class MALENA_API Core : public virtual Subscribable,
86 public virtual Flaggable,
87 public virtual Positionable,
88 public virtual Clickable,
89 public virtual Hoverable,
90 public virtual Focusable,
91 public virtual Keyable,
92 public virtual Scrollable,
93 // public virtual Draggable,
94 public virtual Updatable,
95 public Unsubscribable
96
97 {
98 public:
100 virtual ~Core();
101
103
104 // ── Enabled state ──────────────────────────────────────────────────
105 // Two-flag model: effective enabled = _selfEnabled && _parentEnabled,
106 // mirrored into Flag::ENABLED (what hit-testing filters on). This keeps
107 // "a component I explicitly disabled stays disabled when its parent is
108 // re-enabled" working.
109 //
110 // To REACT to an enable/disable change (sync visuals/colors, reset a
111 // hover state, close a popup, …), override onEnabledChanged(bool
112 // effective) — it fires on BOTH the direct (setEnabled) and cascade
113 // (setParentEnabled) paths. Do NOT override setEnabled/setParentEnabled
114 // to do that work, or the cascade path silently skips it. Controls do
115 // NOT keep a separate "disabled" flag; disabled is read live from
116 // Flag::ENABLED, so the flag and the visuals can never disagree.
117
121 void setEnabled(bool enabled);
122
127 void setParentEnabled(bool enabled);
128
129 virtual void setVisible(bool visible);
130 virtual void setActive(bool active);
131
135 virtual void onWindowResize(unsigned int /*width*/, unsigned int /*height*/) {}
136 bool isEnabled() const;
137 bool isVisible() const;
138
151
155 static constexpr int DefaultLayer = 100;
156
163 struct Child
164 {
166 int layer;
167 };
168
169 void addComponent(Core& child);
170 void addComponent(Core& child, int layer);
171
203 template<typename E,
204 typename = std::enable_if_t<std::is_enum_v<E>>>
205 void addComponent(Core& child, E layer)
206 {
207 addComponent(child, static_cast<int>(layer));
208 }
209
210 void removeComponent(Core& child);
211
229 Core* topmostMatching(const std::function<bool(Core&)>& accept);
230
242 template<typename... Children>
243 void addComponents(Children&... children)
244 {
245 static_assert((std::is_base_of_v<Core, Children> && ...),
246 "addComponents() requires Core-derived arguments");
247 (addComponent(children), ...);
248 }
249
259 template<typename... Children>
260 void addComponents(int layer, Children&... children)
261 {
262 static_assert((std::is_base_of_v<Core, Children> && ...),
263 "addComponents() requires Core-derived arguments");
264 (addComponent(children, layer), ...);
265 }
266
274 template<typename E, typename... Children,
275 typename = std::enable_if_t<std::is_enum_v<E>>>
276 void addComponents(E layer, Children&... children)
277 {
278 static_assert((std::is_base_of_v<Core, Children> && ...),
279 "addComponents() requires Core-derived arguments");
280 (addComponent(children, static_cast<int>(layer)), ...);
281 }
282
283 static void linkChild(Core* parent, Core* child);
284 static void unlinkAll(Core* core);
285
286 protected:
293 virtual void onEnabledChanged(bool enabled) {}
294
299 const std::vector<Child>& getChildren() const { return _children; }
300
313 void drawChildren(sf::RenderTarget& target, sf::RenderStates states) const;
314
315 private:
316 bool _selfEnabled = true;
317 bool _parentEnabled = true;
318
319 void applyEnabled(bool selfEnabled, bool parentEnabled);
320
321 // ── Per-instance parent/child topology ──────────────────────────────
322 // Replaces the static _childMap. Single-parent: a Core may appear in
323 // at most one parent's _children vector at a time. linkChild silently
324 // moves a child if its previous parent differs.
325 Core* _parent = nullptr;
326 std::vector<Child> _children;
327
328 // Reentrancy guard for cascades that may indirectly trigger
329 // removeComponent / linkChild. Mutations while iterating defer until
330 // the depth returns to zero.
331 int _iterDepth = 0;
332 std::vector<std::function<void()>> _pendingOps;
333
334 void doRemoveChild(Core* child);
335 void runPendingIfDepthZero();
336
337 // Insert a child keeping _children sorted by layer ascending, with
338 // registration order preserved within a layer. O(n) positional insert,
339 // not a full re-sort. Sets the child's _parent. Caller guarantees the
340 // child is not already present.
341 void insertChildSorted(Core& child, int layer);
342
343 static bool isDescendantOf(Core* ancestor, Core* component);
344 friend class AppManager;
345 };
346
347} // namespace ml
348
349#endif // MALENA_UICOMPONENTBASE_H
void addComponents(int layer, Children &... children)
Register multiple child components at a shared layer.
Definition Core.h:260
bool isEffectivelyVisible() const
True only if this component and every ancestor are visible.
virtual void setVisible(bool visible)
void addComponents(E layer, Children &... children)
Variadic shared-layer registration with an enum layer key.
Definition Core.h:276
Core * topmostMatching(const std::function< bool(Core &)> &accept)
Find the front-most (last-painted) node in this subtree that satisfies accept, searching topmost-firs...
void setEnabled(bool enabled)
virtual void setActive(bool active)
void removeComponent(Core &child)
virtual void onEnabledChanged(bool enabled)
Definition Core.h:293
void addComponent(Core &child, E layer)
Register a child at a layer identified by any enum value.
Definition Core.h:205
virtual sf::RenderStates getRenderStates() const
Definition Core.h:102
bool isEnabled() const
void setParentEnabled(bool enabled)
static void linkChild(Core *parent, Core *child)
friend class AppManager
Definition Core.h:344
virtual void onWindowResize(unsigned int, unsigned int)
Definition Core.h:135
void addComponents(Children &... children)
Register multiple child components at the default layer.
Definition Core.h:243
static void unlinkAll(Core *core)
static constexpr int DefaultLayer
Definition Core.h:155
void addComponent(Core &child, int layer)
void addComponent(Core &child)
void drawChildren(sf::RenderTarget &target, sf::RenderStates states) const
virtual ~Core()
const std::vector< Child > & getChildren() const
Definition Core.h:299
bool isVisible() const
Trait that provides system-level boolean flag management.
Definition Flaggable.h:53
Trait that adds keyboard-focus and blur callbacks to any Core object.
Definition Focusable.h:46
Trait that adds mouse-hover and mouse-leave callbacks to any Core object.
Definition Hoverable.h:47
Trait that adds keyboard-input callbacks to any Core object.
Definition Keyable.h:55
Trait that provides position, bounds, and animated movement.
Trait that adds mouse-wheel and raw mouse-button callbacks to any Core object.
Definition Scrollable.h:55
Trait that allows a component to subscribe to and publish framework events.
Trait that gives components the ability to unsubscribe from events.
Trait that adds per-frame update and window lifecycle callbacks to any Core object.
Definition Updatable.h:61
Layer
Framework-provided default layer enum.
Definition Core.h:52
@ Overlay
Definition Core.h:55
@ Background
Definition Core.h:53
@ Content
Definition Core.h:54
#define MALENA_API
Definition Component.h:22
A registered child plus the layer key it draws/iterates under.
Definition Core.h:164
Core * component
Definition Core.h:165