Loading...
Searching...
No Matches
Component.h
Go to the documentation of this file.
1
2// Copyright (c) 2025 Dave R. Smith. All rights reserved.
3// Malena Framework — Proprietary Software. See LICENSE for terms.
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 };
147
148 // =========================================================================
149 // ComponentBase — with manifest
150 // =========================================================================
151
166 template<typename ComponentManifest, typename... Traits>
168 public ComponentCore<ComponentManifest, Traits...>,
169 public ManifestResources<ComponentManifest>
170 {
171 private:
172 // Collect all manifest types from traits for collision checking
173 // (component manifest + each trait's manifest_type if it has one)
174 using _AllManifests = std::tuple<
175 ComponentManifest,
176 typename extract_manifest_or_void<Traits>::type...
177 >;
178
179 // ── Images collision check ────────────────────────────────────────────
180 static_assert(
181 ImageCount<
182 ComponentManifest,
183 typename extract_manifest_or_void<Traits>::type...
184 >::value <= 1,
185 "[Malena] Images alias is ambiguous — two or more manifests in "
186 "this component's inheritance chain both declare an Images enum. "
187 "Use MyManifest::Images::VALUE syntax to qualify explicitly."
188 );
189
190 // ── Fonts collision check ─────────────────────────────────────────────
191 static_assert(
192 FontCount<
193 ComponentManifest,
194 typename extract_manifest_or_void<Traits>::type...
195 >::value <= 1,
196 "[Malena] Fonts alias is ambiguous — two or more manifests in "
197 "this component's inheritance chain both declare a Fonts enum. "
198 "Use MyManifest::Fonts::VALUE syntax to qualify explicitly."
199 );
200
201 // ── Sounds collision check ────────────────────────────────────────────
202 static_assert(
203 SoundCount<
204 ComponentManifest,
205 typename extract_manifest_or_void<Traits>::type...
206 >::value <= 1,
207 "[Malena] Sounds alias is ambiguous — two or more manifests in "
208 "this component's inheritance chain both declare a Sounds enum. "
209 "Use MyManifest::Sounds::VALUE syntax to qualify explicitly."
210 );
211
212 // ── Text collision check ──────────────────────────────────────────────
213 static_assert(
214 TextCount<
215 ComponentManifest,
216 typename extract_manifest_or_void<Traits>::type...
217 >::value <= 1,
218 "[Malena] Text alias is ambiguous — two or more manifests in "
219 "this component's inheritance chain both declare a Text enum. "
220 "Use MyManifest::Text::VALUE syntax to qualify explicitly."
221 );
222
223 public:
225 };
226
227 // =========================================================================
228 // ComponentBase — no manifest
229 // =========================================================================
230
232 template<typename... Traits>
233 struct ComponentBase<void, Traits...> : public sf::Drawable,
234 public ComponentCore<void, Traits...>
235 {
236 };
238
239 // =========================================================================
240 // Component
241 // =========================================================================
242
270 template<typename First = void, typename... Rest>
271 class Component : public std::conditional_t<
272 std::is_base_of_v<Manifest, First>,
273 ComponentBase<First, Rest...>,
274 ComponentBase<void, First, Rest...>
275 > {};
276
278 template<>
279 class Component<void> : public ComponentBase<void> {};
281
282 // =========================================================================
283 // ComponentWith alias
284 // =========================================================================
285
298 template<typename M, typename... Traits>
299 using ComponentWith = Component<M, Traits...>;
300
301} // namespace ml
302
303#endif // MALENA_COMPONENT_H
void onClick(std::function< void()> callback)
Register a no-argument callback invoked when this component is clicked.
Primary base class for all user-facing Malena components.
Definition Component.h:275
Virtual base class for all Malena framework objects.
Definition Core.h:69
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)
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:299
@ 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:170
ml::ManifestResources< ComponentManifest > Resources
Definition Component.h:224
Internal non-drawable layer of the component hierarchy.
Definition Component.h:112
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.