Loading...
Searching...
No Matches
Component.h
Go to the documentation of this file.
1
2// Copyright (c) 2025 Dave R. Smith.
3// Malena Framework — Licensed under PolyForm Noncommercial 1.0.0; commercial use requires a paid license. See LICENSE.
4
5#ifndef MALENA_COMPONENT_H
6#define MALENA_COMPONENT_H
7
10#include <Malena/Core/Core.h>
18#include <type_traits>
20
21namespace ml
22{
23 // =========================================================================
24 // Manifest collision detection helpers
25 // =========================================================================
26
28
33 template<typename... Ts>
34 struct ImageCount
35 {
36 static constexpr int value = (has_Image<Ts>::value + ... + 0);
37 };
38
42 template<typename... Ts>
43 struct FontCount
44 {
45 static constexpr int value = (has_Font<Ts>::value + ... + 0);
46 };
47
51 template<typename... Ts>
52 struct SoundCount
53 {
54 static constexpr int value = (has_Sound<Ts>::value + ... + 0);
55 };
56
60 template<typename T, typename = void>
61 struct has_Text : std::false_type {};
62 template<typename T>
63 struct has_Text<T, std::void_t<typename T::Text>> : std::true_type {};
64
65 template<typename... Ts>
66 struct TextCount
67 {
68 static constexpr int value = (has_Text<Ts>::value + ... + 0);
69 };
70
75 template<typename T, typename = void>
76 struct extract_manifest_or_void { using type = void; };
77
78 template<typename T>
79 struct extract_manifest_or_void<T, std::void_t<typename T::manifest_type>>
80 { using type = typename T::manifest_type; };
81
83
84 // =========================================================================
85 // HasCoreTraits
86 // =========================================================================
87
89 template<typename... Traits>
90 struct HasCoreTraits : std::disjunction<
91 std::is_same<Traits, Subscribable>...,
92 std::is_same<Traits, Flaggable>...,
93 std::is_same<Traits, Positionable>...
94 > {};
96
97 // =========================================================================
98 // ComponentCore
99 // =========================================================================
100
106 template<typename ComponentManifest = void, typename... Traits>
107 struct ComponentCore : public Core,
108 public Draggable,
109 public Traits...,
110 public GatherFlags <ComponentManifest, Draggable, Traits...>::type,
111 public GatherStates<ComponentManifest, Draggable, Traits...>::type
112 {
113 static_assert(
114 !HasCoreTraits<Traits...>::value,
115 "[Malena] Subscribable, Flaggable, and Positionable are already "
116 "included via Core — do not pass them as traits."
117 );
118
120 {
122 this->onClick([](){});
123 this->onHover([](){});
124 }
125
126 // ── System flags (ml::Flag) ──────────────────────────────────────────
132
133 // ── Custom flags from manifest + traits ──────────────────────────────
134 using GatherFlags<ComponentManifest, Draggable, Traits...>::type::enableFlag;
135 using GatherFlags<ComponentManifest, Draggable, Traits...>::type::disableFlag;
136 using GatherFlags<ComponentManifest, Draggable, Traits...>::type::checkFlag;
137 using GatherFlags<ComponentManifest, Draggable, Traits...>::type::setFlag;
138 using GatherFlags<ComponentManifest, Draggable, Traits...>::type::toggleFlag;
139
140 // ── Custom states from manifest + traits ─────────────────────────────
141 using GatherStates<ComponentManifest, Draggable, Traits...>::type::setState;
142 using GatherStates<ComponentManifest, Draggable, Traits...>::type::getState;
143 using GatherStates<ComponentManifest, Draggable, Traits...>::type::isState;
144 using GatherStates<ComponentManifest, Draggable, Traits...>::type::onStateEnter;
145 using GatherStates<ComponentManifest, Draggable, Traits...>::type::onStateExit;
146 using GatherStates<ComponentManifest, Draggable, Traits...>::type::syncState;
147 };
148
149 // =========================================================================
150 // ComponentBase — with manifest
151 // =========================================================================
152
167 template<typename ComponentManifest, typename... Traits>
169 public ComponentCore<ComponentManifest, Traits...>,
170 public ManifestResources<ComponentManifest>
171 {
172 private:
173 // Collect all manifest types from traits for collision checking
174 // (component manifest + each trait's manifest_type if it has one)
175 using _AllManifests = std::tuple<
176 ComponentManifest,
177 typename extract_manifest_or_void<Traits>::type...
178 >;
179
180 // ── Images collision check ────────────────────────────────────────────
181 static_assert(
182 ImageCount<
183 ComponentManifest,
184 typename extract_manifest_or_void<Traits>::type...
185 >::value <= 1,
186 "[Malena] Images alias is ambiguous — two or more manifests in "
187 "this component's inheritance chain both declare an Images enum. "
188 "Use MyManifest::Images::VALUE syntax to qualify explicitly."
189 );
190
191 // ── Fonts collision check ─────────────────────────────────────────────
192 static_assert(
193 FontCount<
194 ComponentManifest,
195 typename extract_manifest_or_void<Traits>::type...
196 >::value <= 1,
197 "[Malena] Fonts alias is ambiguous — two or more manifests in "
198 "this component's inheritance chain both declare a Fonts enum. "
199 "Use MyManifest::Fonts::VALUE syntax to qualify explicitly."
200 );
201
202 // ── Sounds collision check ────────────────────────────────────────────
203 static_assert(
204 SoundCount<
205 ComponentManifest,
206 typename extract_manifest_or_void<Traits>::type...
207 >::value <= 1,
208 "[Malena] Sounds alias is ambiguous — two or more manifests in "
209 "this component's inheritance chain both declare a Sounds enum. "
210 "Use MyManifest::Sounds::VALUE syntax to qualify explicitly."
211 );
212
213 // ── Text collision check ──────────────────────────────────────────────
214 static_assert(
215 TextCount<
216 ComponentManifest,
217 typename extract_manifest_or_void<Traits>::type...
218 >::value <= 1,
219 "[Malena] Text alias is ambiguous — two or more manifests in "
220 "this component's inheritance chain both declare a Text enum. "
221 "Use MyManifest::Text::VALUE syntax to qualify explicitly."
222 );
223
224 public:
226
234 void draw(sf::RenderTarget& target, sf::RenderStates states) const override
235 {
236 this->drawChildren(target, states);
237 }
238 };
239
240 // =========================================================================
241 // ComponentBase — no manifest
242 // =========================================================================
243
245 template<typename... Traits>
246 struct ComponentBase<void, Traits...> : public sf::Drawable,
247 public ComponentCore<void, Traits...>
248 {
249 void draw(sf::RenderTarget& target, sf::RenderStates states) const override
250 {
251 this->drawChildren(target, states);
252 }
253 };
255
256 // =========================================================================
257 // Component
258 // =========================================================================
259
287 template<typename First = void, typename... Rest>
288 class Component : public std::conditional_t<
289 std::is_base_of_v<Manifest, First>,
290 ComponentBase<First, Rest...>,
291 ComponentBase<void, First, Rest...>
292 > {};
293
295 template<>
296 class Component<void> : public ComponentBase<void> {};
298
299 // =========================================================================
300 // ComponentWith alias
301 // =========================================================================
302
315 template<typename M, typename... Traits>
316 using ComponentWith = Component<M, Traits...>;
317
318} // namespace ml
319
320#endif // MALENA_COMPONENT_H
void onClick(std::function< void()> callback, bool overwrite=true)
Register a no-argument callback invoked when this component is clicked.
Primary base class for all user-facing Malena components.
Definition Component.h:292
void drawChildren(sf::RenderTarget &target, sf::RenderStates states) const
Receiver trait that adds mouse-drag behavior to any Component.
Definition Draggable.h:71
Draggable()=default
static void subscribe(EnumType eventEnum, EventReceiver *component)
Register a component for an enum-keyed event.
Enum-keyed boolean flag store.
Definition FlagManager.h:60
void toggleFlag(State state)
void disableFlag(State state)
void setFlag(State state, bool status)
bool checkFlag(State state) const
void enableFlag(State state)
void onHover(std::function< void()> callback, bool overwrite=true)
Register a no-argument callback invoked when the mouse enters this component's bounds.
Component< M, Traits... > ComponentWith
Alias for Component<M, Traits...>.
Definition Component.h:316
@ DRAG
Component is being dragged.
Definition Event.h:45
Flag
System-level boolean flags available on every ml::Core object.
Definition Flag.h:65
Definition Component.h:22
Intermediate drawable layer — with manifest.
Definition Component.h:171
void draw(sf::RenderTarget &target, sf::RenderStates states) const override
Definition Component.h:234
ml::ManifestResources< ComponentManifest > Resources
Definition Component.h:225
Collects all Flag enums from a component manifest and its traits.
Collects all State enums from a component manifest and its traits.
Unified manifest resource and config accessor.