Simple C++ UI framework and more...
Revision | 1f497834a6bd2ab8940eca99f16e1ce2bc355757 (tree) |
---|---|
Zeit | 2018-05-16 00:12:51 |
Autor | Starg <starg@user...> |
Commiter | Starg |
Implement widget and renderer
@@ -13,8 +13,6 @@ | ||
13 | 13 | namespace Sirius |
14 | 14 | { |
15 | 15 | |
16 | -class AnimationManager; | |
17 | - | |
18 | 16 | enum class AnimationDirection |
19 | 17 | { |
20 | 18 | Forward, |
@@ -99,28 +97,6 @@ private: | ||
99 | 97 | float m_Value = 0.0f; |
100 | 98 | }; |
101 | 99 | |
102 | -class SIRIUS_DLLEXPORT AnimationBlocker | |
103 | -{ | |
104 | -public: | |
105 | - explicit AnimationBlocker(AnimationManager* pAnimationManager) noexcept : m_pAnimationManager(pAnimationManager) | |
106 | - { | |
107 | - } | |
108 | - | |
109 | - AnimationBlocker(const AnimationBlocker&) = delete; | |
110 | - AnimationBlocker& operator=(const AnimationBlocker&) = delete; | |
111 | - | |
112 | - AnimationBlocker(AnimationBlocker&& rhs) noexcept : m_pAnimationManager(std::exchange(rhs.m_pAnimationManager, nullptr)) | |
113 | - { | |
114 | - } | |
115 | - | |
116 | - AnimationBlocker& operator=(AnimationBlocker&& rhs) = delete; | |
117 | - | |
118 | - ~AnimationBlocker(); | |
119 | - | |
120 | -private: | |
121 | - AnimationManager* m_pAnimationManager; | |
122 | -}; | |
123 | - | |
124 | 100 | class SIRIUS_DLLEXPORT AnimationManager |
125 | 101 | { |
126 | 102 | friend class AnimationBlocker; |
@@ -136,16 +112,16 @@ public: | ||
136 | 112 | void AbortAnimation(Animatable* pAnimatable); |
137 | 113 | void AbortAllAnimations(); |
138 | 114 | void ReverseAnimation(Animatable* pAnimatable); |
115 | + bool IsAnimationRunning(Animatable* pAnimatable) const; | |
139 | 116 | |
140 | 117 | void Process(); |
141 | - bool HasActiveAnimations() const; | |
118 | + bool HasRunningAnimations() const; | |
142 | 119 | |
143 | 120 | bool AreAnimationsBlocked() const; |
144 | - AnimationBlocker BlockAllAnimations(); | |
145 | - | |
146 | -private: | |
121 | + void BlockAllAnimations(); | |
147 | 122 | void UnblockAllAnimations(); |
148 | 123 | |
124 | +private: | |
149 | 125 | struct AnimationInfo |
150 | 126 | { |
151 | 127 | Animatable* pAnimatable; |
@@ -158,6 +134,8 @@ private: | ||
158 | 134 | float RelativeStartTime; |
159 | 135 | }; |
160 | 136 | |
137 | + std::vector<AnimationInfo>::iterator FindAnimationInfoForAnimatable(Animatable* pAnimatable); | |
138 | + std::vector<AnimationInfo>::const_iterator FindAnimationInfoForAnimatable(Animatable* pAnimatable) const; | |
161 | 139 | std::vector<AnimationInfo>::iterator GetAnimationInfoForAnimatable(Animatable* pAnimatable); |
162 | 140 | void AbortAnimation(std::vector<AnimationInfo>::const_iterator it); |
163 | 141 |
@@ -168,4 +146,24 @@ private: | ||
168 | 146 | std::int32_t m_BlockingCount = 0; |
169 | 147 | }; |
170 | 148 | |
149 | +class AnimationBlocker | |
150 | +{ | |
151 | +public: | |
152 | + explicit AnimationBlocker(AnimationManager& animationManager) : m_AnimationManager(animationManager) | |
153 | + { | |
154 | + m_AnimationManager.BlockAllAnimations(); | |
155 | + } | |
156 | + | |
157 | + AnimationBlocker(const AnimationBlocker&) = delete; | |
158 | + AnimationBlocker& operator=(const AnimationBlocker&) = delete; | |
159 | + | |
160 | + ~AnimationBlocker() | |
161 | + { | |
162 | + m_AnimationManager.UnblockAllAnimations(); | |
163 | + } | |
164 | + | |
165 | +private: | |
166 | + AnimationManager& m_AnimationManager; | |
167 | +}; | |
168 | + | |
171 | 169 | } // namespace Sirius |
@@ -5,51 +5,32 @@ | ||
5 | 5 | |
6 | 6 | #include <cstdint> |
7 | 7 | |
8 | -#include <algorithm> | |
9 | -#include <any> | |
8 | +#include <atomic> | |
10 | 9 | #include <chrono> |
11 | -#include <deque> | |
12 | -#include <optional> | |
10 | +#include <future> | |
11 | +#include <memory> | |
12 | +#include <mutex> | |
13 | +#include <type_traits> | |
13 | 14 | #include <utility> |
15 | +#include <variant> | |
14 | 16 | #include <vector> |
15 | 17 | |
16 | 18 | namespace Sirius |
17 | 19 | { |
18 | 20 | |
19 | -class UIContext; | |
20 | 21 | class EventHandler; |
21 | 22 | |
22 | -struct Event | |
23 | -{ | |
24 | - using EventKindType = std::int32_t; | |
25 | - | |
26 | - Event() = default; | |
27 | - | |
28 | - explicit Event(EventKindType kind) : Kind(kind) | |
29 | - { | |
30 | - } | |
31 | - | |
32 | - template<typename TFirst, typename... TRest> | |
33 | - Event(EventKindType kind, TFirst&& first, TRest&&... rest) | |
34 | - : Kind(kind), Argument(std::forward<TFirst>(first), std::forward<TRest>(rest)...) | |
35 | - { | |
36 | - } | |
23 | +// integer type to indicate event id | |
24 | +using EventID = std::intptr_t; | |
37 | 25 | |
38 | - template<typename... T> | |
39 | - Event(EventHandler* p, EventKindType kind, T&&... args) | |
40 | - : pTarget(p), Kind(kind), Argument(std::forward<T>(args)...) | |
41 | - { | |
42 | - } | |
43 | - | |
44 | - Event(const Event&) = default; | |
45 | - Event& operator=(const Event&) = default; | |
46 | - Event(Event&&) = default; | |
47 | - Event& operator=(Event&&) = default; | |
48 | - ~Event() = default; | |
49 | - | |
50 | - EventHandler* pTarget = nullptr; | |
51 | - EventKindType Kind = 0; | |
52 | - std::any Argument; | |
26 | +// base class for event arguments | |
27 | +class EventArgs | |
28 | +{ | |
29 | +public: | |
30 | + EventArgs() = default; | |
31 | + EventArgs(const EventArgs&) = delete; | |
32 | + EventArgs& operator=(const EventArgs&) = delete; | |
33 | + virtual ~EventArgs() = default; | |
53 | 34 | }; |
54 | 35 | |
55 | 36 | class EventListener |
@@ -60,107 +41,339 @@ public: | ||
60 | 41 | EventListener& operator=(const EventListener&) = delete; |
61 | 42 | virtual ~EventListener() = default; |
62 | 43 | |
63 | - // return true to stop further event propagation | |
64 | - virtual bool OnEvent(const Event&) | |
44 | + virtual void OnEvent(const std::shared_ptr<EventHandler>& /* pTarget */, EventID /* id */, EventArgs* /* pArgs */) | |
65 | 45 | { |
66 | - return false; | |
67 | 46 | } |
68 | 47 | }; |
69 | 48 | |
70 | -class SIRIUS_DLLEXPORT EventHandler | |
49 | +class SIRIUS_DLLEXPORT EventListenerManager | |
71 | 50 | { |
72 | 51 | public: |
73 | - explicit EventHandler(UIContext* pUIContext) : m_pUIContext(pUIContext) | |
74 | - { | |
75 | - } | |
76 | - | |
77 | - virtual ~EventHandler() = default; | |
78 | - | |
79 | - bool InvokeEvent(Event ev); | |
80 | - void PostEvent(Event ev); | |
81 | - void PostEventDelayed(Event ev, std::chrono::steady_clock::duration duration); | |
82 | - void PostEventDelayed(Event ev, std::chrono::steady_clock::time_point time); | |
83 | - const Event* PeekFirstEvent(Event::EventKindType kind); | |
84 | - void RemoveEvents(Event::EventKindType kind); | |
85 | - void RemoveAllEvents(); | |
86 | - | |
87 | - // return true to stop further event propagation | |
88 | - virtual bool OnEvent(const Event&); | |
89 | - virtual EventHandler* GetNextEventDestination() const; | |
52 | + EventListenerManager() = default; | |
53 | + EventListenerManager(const EventListenerManager&) = delete; | |
54 | + EventListenerManager& operator=(const EventListenerManager&) = delete; | |
55 | + ~EventListenerManager() = default; | |
90 | 56 | |
91 | - void AddEventListener(EventListener* pEventListener); | |
92 | - void RemoveEventListener(EventListener* pEventListener); | |
93 | - bool HasEventListener(EventListener* pEventListener) const; | |
57 | + void AddEventListener(EventListener* pListener); | |
58 | + void AddEventListenerUnique(std::unique_ptr<EventListener> pListener); | |
59 | + void AddEventListenerShared(std::shared_ptr<EventListener> pListener); | |
60 | + void AddEventListenerWeak(std::weak_ptr<EventListener> pListener); | |
61 | + void RemoveEventListener(EventListener* pListener); | |
62 | + void RemoveAllEventListeners(); | |
94 | 63 | |
95 | -protected: | |
96 | - UIContext* m_pUIContext; // also used by Widget | |
64 | + void InvokeEventListeners(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs); | |
97 | 65 | |
98 | 66 | private: |
99 | - std::vector<EventListener*> m_LocalEventListeners; | |
67 | + std::vector<std::variant<EventListener*, std::unique_ptr<EventListener>, std::shared_ptr<EventListener>, std::weak_ptr<EventListener>>> m_Listeners; | |
100 | 68 | }; |
101 | 69 | |
102 | -class SIRIUS_DLLEXPORT GlobalEventListenerManager | |
70 | +class SIRIUS_DLLEXPORT EventHandler : public EventListenerManager | |
103 | 71 | { |
104 | 72 | public: |
105 | - void AddGlobalEventListener(EventListener* pEventListener); | |
106 | - void RemoveGlobalEventListener(EventListener* pEventListener); | |
107 | - bool HasGlobalEventListener(EventListener* pEventListener) const; | |
108 | - bool InvokeGlobalEventListeners(const Event& ev); | |
73 | + EventHandler() = default; | |
74 | + EventHandler(const EventHandler&) = delete; | |
75 | + EventHandler& operator=(const EventHandler&) = delete; | |
76 | + virtual ~EventHandler() = default; | |
109 | 77 | |
110 | -private: | |
111 | - std::vector<EventListener*> m_GlobalEventListeners; | |
78 | + virtual void OnEvent(EventID /* id */, EventArgs* /* pArgs */) | |
79 | + { | |
80 | + } | |
112 | 81 | }; |
113 | 82 | |
114 | -class SIRIUS_DLLEXPORT EventQueue | |
83 | +enum class DesiredEventLoopTime | |
84 | +{ | |
85 | + Now, | |
86 | + NotSoon | |
87 | +}; | |
88 | + | |
89 | +class SIRIUS_DLLEXPORT EventManager : public EventListenerManager | |
115 | 90 | { |
116 | 91 | public: |
117 | - void PostEvent(Event ev); | |
118 | - void PostEventDelayed(Event ev, std::chrono::steady_clock::time_point time); | |
92 | + EventManager() = default; | |
93 | + EventManager(const EventManager&) = delete; | |
94 | + EventManager& operator=(const EventManager&) = delete; | |
95 | + ~EventManager() = default; | |
96 | + | |
97 | + void InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs = nullptr); | |
98 | + void InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args); | |
99 | + void InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs&& args); | |
100 | + void InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, const std::unique_ptr<EventArgs>& pArgs); | |
101 | + | |
102 | + // Not thread safe | |
103 | + void PostEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, std::unique_ptr<EventArgs> pArgs = nullptr); | |
104 | + // Thread safe | |
105 | + void PostEventThreadSafe(const std::shared_ptr<EventHandler>& pTarget, EventID id, std::unique_ptr<EventArgs> pArgs = nullptr); | |
106 | + | |
107 | + // Not thread safe | |
108 | + void PostEventOnTime( | |
109 | + const std::shared_ptr<EventHandler>& pTarget, | |
110 | + EventID id, | |
111 | + std::chrono::steady_clock::duration duration | |
112 | + ); | |
113 | + | |
114 | + void PostEventOnTime( | |
115 | + const std::shared_ptr<EventHandler>& pTarget, | |
116 | + EventID id, | |
117 | + std::unique_ptr<EventArgs> pArgs, | |
118 | + std::chrono::steady_clock::duration duration | |
119 | + ); | |
120 | + | |
121 | + // Not thread safe | |
122 | + void PostEventOnTime( | |
123 | + const std::shared_ptr<EventHandler>& pTarget, | |
124 | + EventID id, | |
125 | + std::chrono::steady_clock::time_point time | |
126 | + ); | |
127 | + | |
128 | + void PostEventOnTime( | |
129 | + const std::shared_ptr<EventHandler>& pTarget, | |
130 | + EventID id, | |
131 | + std::unique_ptr<EventArgs> pArgs, | |
132 | + std::chrono::steady_clock::time_point time | |
133 | + ); | |
134 | + | |
135 | + // Not thread safe | |
136 | + void PostEventOnTaskComplete( | |
137 | + const std::shared_ptr<EventHandler>& pTarget, | |
138 | + EventID id, | |
139 | + std::future<void> f | |
140 | + ); | |
141 | + | |
142 | + void PostEventOnTaskComplete( | |
143 | + const std::shared_ptr<EventHandler>& pTarget, | |
144 | + EventID id, | |
145 | + std::unique_ptr<EventArgs> pArgs, | |
146 | + std::future<void> f | |
147 | + ); | |
148 | + | |
149 | + // Not thread safe | |
150 | + void PostEventOnFutureReady( | |
151 | + const std::shared_ptr<EventHandler>& pTarget, | |
152 | + EventID id, | |
153 | + std::future<std::unique_ptr<EventArgs>> f | |
154 | + ); | |
155 | + | |
156 | + // Thread safe | |
157 | + void SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs = nullptr); | |
158 | + void SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args); | |
159 | + void SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs&& args); | |
160 | + void SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, const std::unique_ptr<EventArgs>& pArgs); | |
161 | + std::future<std::unique_ptr<EventArgs>> SendEventAsync( | |
162 | + const std::shared_ptr<EventHandler>& pTarget, | |
163 | + EventID id, | |
164 | + std::unique_ptr<EventArgs> pArgs = nullptr | |
165 | + ); | |
166 | + | |
167 | + void RemoveAllEvents(); | |
168 | + | |
169 | + void ProcessEvents(); | |
170 | + std::variant<DesiredEventLoopTime, std::chrono::steady_clock::time_point> GetDesiredEventLoopTime() const; | |
171 | + | |
172 | +private: | |
173 | + struct QueuedEvent | |
174 | + { | |
175 | + QueuedEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, std::unique_ptr<EventArgs> pArgs) | |
176 | + : pHandler(pTarget.get()), pWeakHandler(pTarget), ID(id), pArgs(std::move(pArgs)) | |
177 | + { | |
178 | + } | |
179 | + | |
180 | + QueuedEvent(EventHandler* pHandler, std::weak_ptr<EventHandler> pWeakHandler, EventID id, std::unique_ptr<EventArgs> pArgs) | |
181 | + : pHandler(pHandler), pWeakHandler(std::move(pWeakHandler)), ID(id), pArgs(std::move(pArgs)) | |
182 | + { | |
183 | + } | |
184 | + | |
185 | + EventHandler* pHandler; | |
186 | + std::weak_ptr<EventHandler> pWeakHandler; | |
187 | + EventID ID; | |
188 | + std::unique_ptr<EventArgs> pArgs; | |
189 | + }; | |
190 | + | |
191 | + struct QueuedEventWithTime : QueuedEvent | |
192 | + { | |
193 | + QueuedEventWithTime( | |
194 | + const std::shared_ptr<EventHandler>& pTarget, | |
195 | + EventID id, | |
196 | + std::unique_ptr<EventArgs> pArgs, | |
197 | + std::chrono::steady_clock::time_point fireTime | |
198 | + ) : QueuedEvent(pTarget, id, std::move(pArgs)), FireTime(fireTime) | |
199 | + { | |
200 | + } | |
201 | + | |
202 | + std::chrono::steady_clock::time_point FireTime; | |
203 | + }; | |
119 | 204 | |
120 | - template<typename T> | |
121 | - const Event* PeekFirstEvent(T pred) | |
205 | + struct QueuedEventWithFuture : QueuedEvent | |
122 | 206 | { |
123 | - auto it = std::find_if(m_Events.begin(), m_Events.end(), pred); | |
207 | + QueuedEventWithFuture( | |
208 | + const std::shared_ptr<EventHandler>& pTarget, | |
209 | + EventID id, | |
210 | + std::unique_ptr<EventArgs> pArgs, | |
211 | + std::future<void> f | |
212 | + ) : QueuedEvent(pTarget, id, std::move(pArgs)), Future(std::move(f)) | |
213 | + { | |
214 | + } | |
124 | 215 | |
125 | - if (it != m_Events.end()) | |
216 | + QueuedEventWithFuture( | |
217 | + const std::shared_ptr<EventHandler>& pTarget, | |
218 | + EventID id, | |
219 | + std::future<std::unique_ptr<EventArgs>> f | |
220 | + ) : QueuedEvent(pTarget, id, nullptr), Future(std::move(f)) | |
126 | 221 | { |
127 | - return &*it; | |
128 | 222 | } |
129 | 223 | |
130 | - auto itDelayed = std::find_if(m_DelayedEvents.begin(), m_DelayedEvents.end(), [pred] (auto&& x) { return pred(x.Ev); }); | |
224 | + std::variant<std::future<void>, std::future<std::unique_ptr<EventArgs>>> Future; | |
225 | + }; | |
131 | 226 | |
132 | - if (itDelayed != m_DelayedEvents.end()) | |
227 | + struct SentEvent | |
228 | + { | |
229 | + SentEvent(const std::shared_ptr<EventHandler> pTarget, EventID id, EventArgs* pArgs) | |
230 | + : pHandler(pTarget), ID(id), pArgs(pArgs) | |
231 | + { | |
232 | + } | |
233 | + | |
234 | + SentEvent(const std::shared_ptr<EventHandler> pTarget, EventID id, std::unique_ptr<EventArgs> pArgs) | |
235 | + : pHandler(pTarget), ID(id), pArgs(std::move(pArgs)) | |
133 | 236 | { |
134 | - return &itDelayed->Ev; | |
135 | 237 | } |
136 | 238 | |
137 | - return nullptr; | |
239 | + std::shared_ptr<EventHandler> pHandler; | |
240 | + EventID ID; | |
241 | + std::variant<EventArgs*, std::unique_ptr<EventArgs>> pArgs; | |
242 | + std::promise<std::unique_ptr<EventArgs>> Promise; | |
243 | + }; | |
244 | + | |
245 | + void TryInvokeQueuedEvent(QueuedEvent& ev); | |
246 | + void ProcessEventQueue(); | |
247 | + void ProcessEventQueueWithTime(); | |
248 | + void ProcessEventQueueWithFuture(); | |
249 | + void ProcessSentEvents(); | |
250 | + | |
251 | + std::vector<QueuedEvent> m_EventQueue; | |
252 | + std::vector<QueuedEventWithTime> m_EventQueueWithTime; | |
253 | + std::vector<QueuedEventWithFuture> m_EventQueueWithFuture; | |
254 | + std::vector<SentEvent> m_SentEvents; | |
255 | + | |
256 | + // These atomic and mutex are for m_ThreadSafeEventQueue and m_SentEventQueue. | |
257 | + std::atomic<bool> m_HasItemsInThreadSafeEventQueues; | |
258 | + std::mutex m_MutexForThreadSafeEventQueues; | |
259 | + std::vector<QueuedEvent> m_ThreadSafeEventQueue; | |
260 | + std::vector<SentEvent> m_ThreadSafeSentEventQueue; | |
261 | + | |
262 | + static_assert(std::is_nothrow_move_constructible_v<QueuedEvent>); | |
263 | + static_assert(std::is_nothrow_move_assignable_v<QueuedEvent>); | |
264 | + static_assert(std::is_nothrow_move_constructible_v<SentEvent>); | |
265 | + static_assert(std::is_nothrow_move_assignable_v<SentEvent>); | |
266 | +}; | |
267 | + | |
268 | +// mixin class to define convenience wrapper for InvokeEvent(), etc. | |
269 | +template<typename T> | |
270 | +class EventInvokeUtility | |
271 | +{ | |
272 | +protected: | |
273 | + EventInvokeUtility() = default; | |
274 | + ~EventInvokeUtility() = default; | |
275 | + | |
276 | +public: | |
277 | + void InvokeEvent(EventID id, EventArgs* pArgs = nullptr) | |
278 | + { | |
279 | + CallGetEventManager().InvokeEvent(CallGetEventHandler(), id, pArgs); | |
138 | 280 | } |
139 | 281 | |
140 | - template<typename T> | |
141 | - void RemoveEvents(T pred) | |
282 | + void InvokeEvent(EventID id, EventArgs& args) | |
142 | 283 | { |
143 | - m_Events.erase(std::remove_if(m_Events.begin(), m_Events.end(), pred), m_Events.end()); | |
144 | - m_DelayedEvents.erase( | |
145 | - std::remove_if(m_DelayedEvents.begin(), m_DelayedEvents.end(), [pred] (auto&& x) { return pred(x.Ev); }), | |
146 | - m_DelayedEvents.end() | |
147 | - ); | |
284 | + CallGetEventManager().InvokeEvent(CallGetEventHandler(), id, args); | |
148 | 285 | } |
149 | 286 | |
150 | - void RemoveAllEvents(); | |
287 | + void InvokeEvent(EventID id, EventArgs&& args) | |
288 | + { | |
289 | + CallGetEventManager().InvokeEvent(CallGetEventHandler(), id, args); | |
290 | + } | |
151 | 291 | |
152 | - void ProcessEvents(); | |
153 | - std::optional<std::chrono::steady_clock::time_point> GetNextEventFireTime() const; // returns std::nullopt if nothing is queued | |
292 | + void InvokeEvent(EventID id, const std::unique_ptr<EventArgs>& pArgs) | |
293 | + { | |
294 | + CallGetEventManager().InvokeEvent(CallGetEventHandler(), id, pArgs); | |
295 | + } | |
296 | + | |
297 | + void PostEvent(EventID id, std::unique_ptr<EventArgs> pArgs = nullptr) | |
298 | + { | |
299 | + CallGetEventManager().PostEvent(CallGetEventHandler(), id, std::move(pArgs)); | |
300 | + } | |
301 | + | |
302 | + void PostEventThreadSafe(EventID id, std::unique_ptr<EventArgs> pArgs = nullptr) | |
303 | + { | |
304 | + CallGetEventManager().PostEventThreadSafe(CallGetEventHandler(), id, std::move(pArgs)); | |
305 | + } | |
306 | + | |
307 | + void PostEventOnTime(EventID id, std::chrono::steady_clock::duration duration) | |
308 | + { | |
309 | + CallGetEventManager().PostEventOnTime(CallGetEventHandler(), id, duration); | |
310 | + } | |
311 | + | |
312 | + void PostEventOnTime(EventID id, std::unique_ptr<EventArgs> pArgs, std::chrono::steady_clock::duration duration) | |
313 | + { | |
314 | + CallGetEventManager().PostEventOnTime(CallGetEventHandler(), id, std::move(pArgs), duration); | |
315 | + } | |
316 | + | |
317 | + void PostEventOnTime(EventID id, std::chrono::steady_clock::time_point time) | |
318 | + { | |
319 | + CallGetEventManager().PostEventOnTime(CallGetEventHandler(), id, time); | |
320 | + } | |
321 | + | |
322 | + void PostEventOnTime(EventID id, std::unique_ptr<EventArgs> pArgs, std::chrono::steady_clock::time_point time) | |
323 | + { | |
324 | + CallGetEventManager().PostEventOnTime(CallGetEventHandler(), id, std::move(pArgs), time); | |
325 | + } | |
326 | + | |
327 | + void PostEventOnTaskComplete(EventID id, std::future<void> f) | |
328 | + { | |
329 | + CallGetEventManager().PostEventOnTaskComplete(CallGetEventHandler(), id, std::move(f)); | |
330 | + } | |
331 | + | |
332 | + void PostEventOnTaskComplete(EventID id, std::unique_ptr<EventArgs> pArgs, std::future<void> f) | |
333 | + { | |
334 | + CallGetEventManager().PostEventOnTaskComplete(CallGetEventHandler(), id, std::move(pArgs), std::move(f)); | |
335 | + } | |
336 | + | |
337 | + void PostEventOnFutureReady(EventID id, std::future<std::unique_ptr<EventArgs>> f) | |
338 | + { | |
339 | + CallGetEventManager().PostEventOnFutureReady(CallGetEventHandler(), id, std::move(f)); | |
340 | + } | |
341 | + | |
342 | + void SendEvent(EventID id, EventArgs* pArgs = nullptr) | |
343 | + { | |
344 | + CallGetEventManager().SendEvent(CallGetEventHandler(), id, pArgs); | |
345 | + } | |
346 | + | |
347 | + void SendEvent(EventID id, EventArgs& args) | |
348 | + { | |
349 | + CallGetEventManager().SendEvent(CallGetEventHandler(), id, args); | |
350 | + } | |
351 | + | |
352 | + void SendEvent(EventID id, EventArgs&& args) | |
353 | + { | |
354 | + CallGetEventManager().SendEvent(CallGetEventHandler(), id, args); | |
355 | + } | |
356 | + | |
357 | + void SendEvent(EventID id, const std::unique_ptr<EventArgs>& pArgs) | |
358 | + { | |
359 | + CallGetEventManager().SendEvent(CallGetEventHandler(), id, pArgs); | |
360 | + } | |
361 | + | |
362 | + std::future<std::unique_ptr<EventArgs>> SendEventAsync(EventID id, std::unique_ptr<EventArgs> pArgs = nullptr) | |
363 | + { | |
364 | + return CallGetEventManager().SendEventAsync(CallGetEventHandler(), id, std::move(pArgs)); | |
365 | + } | |
154 | 366 | |
155 | 367 | private: |
156 | - struct DelayedEvent | |
368 | + std::shared_ptr<EventHandler> CallGetEventHandler() | |
157 | 369 | { |
158 | - Event Ev; | |
159 | - std::chrono::steady_clock::time_point FireTime; | |
160 | - }; | |
370 | + return static_cast<T*>(this)->GetEventHandler(); | |
371 | + } | |
161 | 372 | |
162 | - std::deque<Event> m_Events; | |
163 | - std::deque<DelayedEvent> m_DelayedEvents; // must be sorted according to FireTime | |
373 | + EventManager& CallGetEventManager() | |
374 | + { | |
375 | + return static_cast<T*>(this)->GetEventManager(); | |
376 | + } | |
164 | 377 | }; |
165 | 378 | |
166 | 379 | } // namespace Sirius |
@@ -1,210 +0,0 @@ | ||
1 | -// Copyright 2018 Starg | |
2 | -// Distributed under the 3-Clause BSD License. | |
3 | - | |
4 | -#pragma once | |
5 | - | |
6 | -#include <type_traits> | |
7 | -#include <utility> | |
8 | - | |
9 | -namespace Sirius | |
10 | -{ | |
11 | - | |
12 | -template<typename T> | |
13 | -struct Point | |
14 | -{ | |
15 | - Point() noexcept = default; | |
16 | - | |
17 | - Point(T x, T y) noexcept : X(x), Y(y) | |
18 | - { | |
19 | - } | |
20 | - | |
21 | - Point(const Point<T>&) noexcept = default; | |
22 | - Point(Point<T>&&) noexcept = default; | |
23 | - | |
24 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
25 | - Point(const Point<T2>& rhs) noexcept : X(rhs.X), Y(rhs.Y) | |
26 | - { | |
27 | - } | |
28 | - | |
29 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
30 | - Point(Point<T2>&& rhs) noexcept : X(rhs.X), Y(rhs.Y) | |
31 | - { | |
32 | - } | |
33 | - | |
34 | - Point<T>& operator=(const Point<T>&) noexcept = default; | |
35 | - Point<T>& operator=(Point<T>&&) noexcept = default; | |
36 | - | |
37 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
38 | - Point<T>& operator=(const Point<T2>& rhs) noexcept | |
39 | - { | |
40 | - X = rhs.X; | |
41 | - Y = rhs.Y; | |
42 | - return *this; | |
43 | - } | |
44 | - | |
45 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
46 | - Point<T>& operator=(Point<T2>&& rhs) noexcept | |
47 | - { | |
48 | - X = rhs.X; | |
49 | - Y = rhs.Y; | |
50 | - return *this; | |
51 | - } | |
52 | - | |
53 | - void Swap(Point<T>& rhs) noexcept | |
54 | - { | |
55 | - using std::swap; | |
56 | - swap(X, rhs.X); | |
57 | - swap(Y, rhs.Y); | |
58 | - } | |
59 | - | |
60 | - T X; | |
61 | - T Y; | |
62 | -}; | |
63 | - | |
64 | -template<typename T> | |
65 | -void swap(Point<T>& lhs, Point<T>& rhs) noexcept | |
66 | -{ | |
67 | - lhs.Swap(rhs); | |
68 | -} | |
69 | - | |
70 | -template<typename T> | |
71 | -struct Size | |
72 | -{ | |
73 | - Size() noexcept = default; | |
74 | - | |
75 | - Size(T w, T h) noexcept : Width(w), Height(h) | |
76 | - { | |
77 | - } | |
78 | - | |
79 | - Size(const Size<T>&) noexcept = default; | |
80 | - Size(Size<T>&&) noexcept = default; | |
81 | - | |
82 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
83 | - Size(const Size<T2>& rhs) noexcept : Width(rhs.Width), Height(rhs.Height) | |
84 | - { | |
85 | - } | |
86 | - | |
87 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
88 | - Size(Size<T2>&& rhs) noexcept : Width(rhs.Width), Height(rhs.Height) | |
89 | - { | |
90 | - } | |
91 | - | |
92 | - Size<T>& operator=(const Size<T>&) noexcept = default; | |
93 | - Size<T>& operator=(Size<T>&&) noexcept = default; | |
94 | - | |
95 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
96 | - Size<T>& operator=(const Size<T2>& rhs) noexcept | |
97 | - { | |
98 | - Width = rhs.Width; | |
99 | - Height = rhs.Height; | |
100 | - return *this; | |
101 | - } | |
102 | - | |
103 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
104 | - Size<T>& operator=(Size<T2>&& rhs) noexcept | |
105 | - { | |
106 | - Width = rhs.Width; | |
107 | - Height = rhs.Height; | |
108 | - return *this; | |
109 | - } | |
110 | - | |
111 | - void Swap(Size<T>& rhs) noexcept | |
112 | - { | |
113 | - using std::swap; | |
114 | - swap(Width, rhs.Width); | |
115 | - swap(Height, rhs.Height); | |
116 | - } | |
117 | - | |
118 | - T Width; | |
119 | - T Height; | |
120 | -}; | |
121 | - | |
122 | -template<typename T> | |
123 | -void swap(Size<T>& lhs, Size<T>& rhs) noexcept | |
124 | -{ | |
125 | - lhs.Swap(rhs); | |
126 | -} | |
127 | - | |
128 | -template<typename T> | |
129 | -struct Rect | |
130 | -{ | |
131 | - Rect() noexcept = default; | |
132 | - | |
133 | - Rect(const Point<T>& pt1, const Point<T>& pt2) noexcept | |
134 | - : Left(pt1.X), Top(pt1.Y), Right(pt2.X), Bottom(pt2.Y) | |
135 | - { | |
136 | - } | |
137 | - | |
138 | - Rect(const Point<T>& pt, const Size<T>& size) noexcept | |
139 | - : Left(pt.X), Top(pt.Y), Right(pt.X + size.Width), Bottom(pt.Y + size.Height) | |
140 | - { | |
141 | - } | |
142 | - | |
143 | - Rect(const Rect<T>&) noexcept = default; | |
144 | - Rect(Rect<T>&&) noexcept = default; | |
145 | - | |
146 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
147 | - Rect(const Rect<T2>& rhs) noexcept : Left(rhs.Left), Top(rhs.Top), Right(rhs.Right), Bottom(rhs.Bottom) | |
148 | - { | |
149 | - } | |
150 | - | |
151 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
152 | - Rect(Rect<T2>&& rhs) noexcept : Left(rhs.Left), Top(rhs.Top), Right(rhs.Right), Bottom(rhs.Bottom) | |
153 | - { | |
154 | - } | |
155 | - | |
156 | - Rect<T>& operator=(const Rect<T>&) noexcept = default; | |
157 | - Rect<T>& operator=(Rect<T>&&) noexcept = default; | |
158 | - | |
159 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
160 | - Rect<T>& operator=(const Rect<T2>& rhs) noexcept | |
161 | - { | |
162 | - Left = rhs.Left; | |
163 | - Top = rhs.Top; | |
164 | - Right = rhs.Right; | |
165 | - Bottom = rhs.Bottom; | |
166 | - return *this; | |
167 | - } | |
168 | - | |
169 | - template<typename T2, std::enable_if_t<std::is_convertible_v<T2, T>, int> = 0> | |
170 | - Rect<T>& operator=(Rect<T2>&& rhs) noexcept | |
171 | - { | |
172 | - Left = rhs.Left; | |
173 | - Top = rhs.Top; | |
174 | - Right = rhs.Right; | |
175 | - Bottom = rhs.Bottom; | |
176 | - return *this; | |
177 | - } | |
178 | - | |
179 | - void Swap(Rect<T>& rhs) noexcept | |
180 | - { | |
181 | - using std::swap; | |
182 | - swap(Left, rhs.Left); | |
183 | - swap(Top, rhs.Top); | |
184 | - swap(Right, rhs.Right); | |
185 | - swap(Bottom, rhs.Bottom); | |
186 | - } | |
187 | - | |
188 | - T GetWidth() const noexcept | |
189 | - { | |
190 | - return Right - Left; | |
191 | - } | |
192 | - | |
193 | - T GetHeight() const noexcept | |
194 | - { | |
195 | - return Bottom - Top; | |
196 | - } | |
197 | - | |
198 | - T Left; | |
199 | - T Top; | |
200 | - T Right; | |
201 | - T Bottom; | |
202 | -}; | |
203 | - | |
204 | -template<typename T> | |
205 | -void swap(Rect<T>& lhs, Rect<T>& rhs) noexcept | |
206 | -{ | |
207 | - lhs.Swap(rhs); | |
208 | -} | |
209 | - | |
210 | -} // namespace Sirius |
@@ -0,0 +1,25 @@ | ||
1 | +// Copyright 2018 Starg | |
2 | +// Distributed under the 3-Clause BSD License. | |
3 | + | |
4 | +#pragma once | |
5 | + | |
6 | +#define SIRIUS_X86_SIMD_LEVEL_NONE 0 | |
7 | +#define SIRIUS_X86_SIMD_LEVEL_SSE2 1 | |
8 | +#define SIRIUS_X86_SIMD_LEVEL_SSE42 2 // + POPCNT, LZCNT, and BMI | |
9 | +#define SIRIUS_X86_SIMD_LEVEL_AVX2 3 // + FMA | |
10 | + | |
11 | +#ifndef SIRIUS_X86_SIMD_LEVEL | |
12 | + | |
13 | +#if defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) | |
14 | +#define SIRIUS_X86_SIMD_LEVEL SIRIUS_X86_SIMD_LEVEL_SSE42 | |
15 | +#else | |
16 | +#define SIRIUS_X86_SIMD_LEVEL SIRIUS_X86_SIMD_LEVEL_NONE | |
17 | +#endif | |
18 | + | |
19 | +#endif | |
20 | + | |
21 | +#ifdef _MSC_VER | |
22 | +#include <intrin.h> | |
23 | +#elif defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) | |
24 | +#include <x86intrin.h> | |
25 | +#endif |
@@ -0,0 +1,230 @@ | ||
1 | +// Copyright 2018 Starg | |
2 | +// Distributed under the 3-Clause BSD License. | |
3 | + | |
4 | +#pragma once | |
5 | + | |
6 | +#include <cstddef> | |
7 | +#include <cstdint> | |
8 | + | |
9 | +#include <memory> | |
10 | +#include <string> | |
11 | +#include <string_view> | |
12 | +#include <vector> | |
13 | + | |
14 | +#include "sirius/array_view.hpp" | |
15 | +#include "sirius/simpletypes.hpp" | |
16 | + | |
17 | +namespace Sirius | |
18 | +{ | |
19 | + | |
20 | +class Renderer; | |
21 | +class ChildRenderer; | |
22 | + | |
23 | +class RendererListener | |
24 | +{ | |
25 | +public: | |
26 | + virtual ~RendererListener() = default; | |
27 | + | |
28 | + virtual void OnCreateDevice(Renderer* /*pRenderer*/) | |
29 | + { | |
30 | + } | |
31 | + | |
32 | + virtual void OnDestroyDevice(Renderer* /*pRenderer*/) | |
33 | + { | |
34 | + } | |
35 | + | |
36 | + virtual void OnBeginDraw(Renderer* /*pRenderer*/) | |
37 | + { | |
38 | + } | |
39 | + | |
40 | + virtual void OnEndDraw(Renderer* /*pRenderer*/) | |
41 | + { | |
42 | + } | |
43 | +}; | |
44 | + | |
45 | +class Paint | |
46 | +{ | |
47 | +public: | |
48 | + Paint() = default; | |
49 | + | |
50 | + explicit Paint(const Color& c) : m_Color(c) | |
51 | + { | |
52 | + } | |
53 | + | |
54 | + Paint(const Color& c, float strokeWidth) : m_Color(c), m_StrokeWidth(strokeWidth) | |
55 | + { | |
56 | + } | |
57 | + | |
58 | + Paint(const Color& c, std::string_view fontName, float fontSize) | |
59 | + : m_Color(c), m_FontName(fontName), m_FontSize(fontSize) | |
60 | + { | |
61 | + } | |
62 | + | |
63 | + Paint(const Paint&) = default; | |
64 | + Paint& operator=(const Paint&) = default; | |
65 | + Paint(Paint&&) = default; | |
66 | + Paint& operator=(Paint&&) = default; | |
67 | + ~Paint() = default; | |
68 | + | |
69 | + const Color& GetColor() const | |
70 | + { | |
71 | + return m_Color; | |
72 | + } | |
73 | + | |
74 | + void SetColor(const Color& c) | |
75 | + { | |
76 | + m_Color = c; | |
77 | + } | |
78 | + | |
79 | + float GetStrokeWidth() const | |
80 | + { | |
81 | + return m_StrokeWidth; | |
82 | + } | |
83 | + | |
84 | + void SetStrokeWidth(float sw) | |
85 | + { | |
86 | + m_StrokeWidth = sw; | |
87 | + } | |
88 | + | |
89 | + std::string_view GetFontName() const | |
90 | + { | |
91 | + return m_FontName; | |
92 | + } | |
93 | + | |
94 | + void SetFontName(std::string_view fontName) | |
95 | + { | |
96 | + m_FontName = fontName; | |
97 | + } | |
98 | + | |
99 | + float GetFontSize() const | |
100 | + { | |
101 | + return m_FontSize; | |
102 | + } | |
103 | + | |
104 | + void SetFontSize(float fontSize) | |
105 | + { | |
106 | + m_FontSize = fontSize; | |
107 | + } | |
108 | + | |
109 | + float GetFontWeight() const | |
110 | + { | |
111 | + return m_FontWeight; | |
112 | + } | |
113 | + | |
114 | + void SetFontWeight(float weight) | |
115 | + { | |
116 | + m_FontWeight = weight; | |
117 | + } | |
118 | + | |
119 | + bool GetIsItalicFont() const | |
120 | + { | |
121 | + return m_IsItalicFont; | |
122 | + } | |
123 | + | |
124 | + void SetIsItalicFont(bool italic) | |
125 | + { | |
126 | + m_IsItalicFont = italic; | |
127 | + } | |
128 | + | |
129 | +private: | |
130 | + Color m_Color = {}; | |
131 | + float m_StrokeWidth = 1.0f; | |
132 | + std::string m_FontName; | |
133 | + float m_FontSize = 12.0f; | |
134 | + float m_FontWeight = 1.0f; | |
135 | + bool m_IsItalicFont = false; | |
136 | +}; | |
137 | + | |
138 | +enum class PixelFormat | |
139 | +{ | |
140 | + A8R8G8B8 | |
141 | +}; | |
142 | + | |
143 | +class Bitmap | |
144 | +{ | |
145 | +public: | |
146 | + ~Bitmap() = default; | |
147 | + | |
148 | + virtual Vec2<std::uint32_t> GetSize() const = 0; | |
149 | +}; | |
150 | + | |
151 | +class SIRIUS_DLLEXPORT Renderer | |
152 | +{ | |
153 | +public: | |
154 | + virtual ~Renderer() = default; | |
155 | + | |
156 | + void BeginDraw(); | |
157 | + void EndDraw(); | |
158 | + | |
159 | + virtual void Clear(const Color& color) = 0; | |
160 | + virtual void DrawLine(Vec2<float> p1, Vec2<float> p2, const Paint& paint) = 0; | |
161 | + virtual void DrawRect(const Rect<float>& rect, const Paint& paint) = 0; | |
162 | + virtual void FillRect(const Rect<float>& rect, const Paint& paint) = 0; | |
163 | + virtual void DrawPolygon(ArrayView<Vec2<float>> points, const Paint& paint) = 0; | |
164 | + virtual void FillPolygon(ArrayView<Vec2<float>> points, const Paint& paint) = 0; | |
165 | + | |
166 | + virtual void DrawEllipse(const Rect<float>& boundRect, const Paint& paint) = 0; | |
167 | + void DrawEllipse(Vec2<float> center, float radiusX, float radiusY, const Paint& paint); | |
168 | + virtual void FillEllipse(const Rect<float>& boundRect, const Paint& paint) = 0; | |
169 | + void FillEllipse(Vec2<float> center, float radiusX, float radiusY, const Paint& paint); | |
170 | + | |
171 | + virtual void DrawArc(Vec2<float> center, float radius, float angleFrom, float angleTo, const Paint& paint) = 0; | |
172 | + virtual void FillArc(Vec2<float> center, float radius, float angleFrom, float angleTo, const Paint& paint) = 0; | |
173 | + | |
174 | + virtual void DrawBitmap(Bitmap* pBitmap, const Rect<float>& srcRect, const Rect<float>& destRect) = 0; | |
175 | + void DrawBitmap(const std::unique_ptr<Bitmap>& pBitmap, const Rect<float>& srcRect, const Rect<float>& destRect); | |
176 | + | |
177 | + virtual void DrawText(std::string_view text, const Rect<float>& rect, const Paint& paint) = 0; | |
178 | + | |
179 | + virtual Rect<float> GetClipRect() const = 0; | |
180 | + virtual void SetClipRect(const Rect<float>& rect) = 0; | |
181 | + | |
182 | + virtual Vec2<float> GetGlobalTranslation() const = 0; | |
183 | + virtual void SetGlobalTranslation(Vec2<float> globalTranslation) = 0; | |
184 | + | |
185 | + virtual std::unique_ptr<Bitmap> CreateBitmap(ArrayView<std::byte> buffer, Vec2<std::uint32_t> size, PixelFormat format) = 0; | |
186 | + | |
187 | + void AddListener(RendererListener* pListener); | |
188 | + void RemoveListener(RendererListener* pListener); | |
189 | + bool HasListener(RendererListener* pListener) const; | |
190 | + | |
191 | + void InvokeCreateDevice(); | |
192 | + void InvokeDestroyDevice(); | |
193 | + | |
194 | +protected: | |
195 | + virtual void OnBeginDraw() | |
196 | + { | |
197 | + } | |
198 | + | |
199 | + virtual void OnEndDraw() | |
200 | + { | |
201 | + } | |
202 | + | |
203 | +private: | |
204 | + std::vector<RendererListener*> m_Listeners; | |
205 | +}; | |
206 | + | |
207 | +class AutoRestoreRendererStates | |
208 | +{ | |
209 | +public: | |
210 | + explicit AutoRestoreRendererStates(Renderer& renderer) | |
211 | + : m_Renderer(renderer), m_OldClipRect(renderer.GetClipRect()), m_OldTranslation(renderer.GetGlobalTranslation()) | |
212 | + { | |
213 | + } | |
214 | + | |
215 | + AutoRestoreRendererStates(const AutoRestoreRendererStates&) = delete; | |
216 | + AutoRestoreRendererStates& operator=(const AutoRestoreRendererStates&) = delete; | |
217 | + | |
218 | + ~AutoRestoreRendererStates() | |
219 | + { | |
220 | + m_Renderer.SetGlobalTranslation(m_OldTranslation); | |
221 | + m_Renderer.SetClipRect(m_OldClipRect); | |
222 | + } | |
223 | + | |
224 | +private: | |
225 | + Renderer& m_Renderer; | |
226 | + Rect<float> m_OldClipRect; | |
227 | + Vec2<float> m_OldTranslation; | |
228 | +}; | |
229 | + | |
230 | +} // namespace Sirius |
@@ -0,0 +1,211 @@ | ||
1 | +// Copyright 2018 Starg | |
2 | +// Distributed under the 3-Clause BSD License. | |
3 | + | |
4 | +#pragma once | |
5 | + | |
6 | +#include <algorithm> | |
7 | + | |
8 | +namespace Sirius | |
9 | +{ | |
10 | + | |
11 | +template<typename T> | |
12 | +struct Vec2 | |
13 | +{ | |
14 | + constexpr Vec2() noexcept : X(0), Y(0) | |
15 | + { | |
16 | + } | |
17 | + | |
18 | + constexpr Vec2(T x, T y) noexcept : X(x), Y(y) | |
19 | + { | |
20 | + } | |
21 | + | |
22 | + constexpr bool operator==(Vec2<T> rhs) const noexcept | |
23 | + { | |
24 | + return X == rhs.X && Y == rhs.Y; | |
25 | + } | |
26 | + | |
27 | + constexpr bool operator!=(Vec2<T> rhs) const noexcept | |
28 | + { | |
29 | + return !(*this == rhs); | |
30 | + } | |
31 | + | |
32 | + constexpr Vec2<T>& operator+=(Vec2<T> rhs) noexcept | |
33 | + { | |
34 | + X += rhs.X; | |
35 | + Y += rhs.Y; | |
36 | + return *this; | |
37 | + } | |
38 | + | |
39 | + constexpr Vec2<T>& operator-=(Vec2<T> rhs) noexcept | |
40 | + { | |
41 | + X -= rhs.X; | |
42 | + Y -= rhs.Y; | |
43 | + return *this; | |
44 | + } | |
45 | + | |
46 | + constexpr Vec2<T>& operator*=(T f) noexcept | |
47 | + { | |
48 | + X *= f; | |
49 | + Y *= f; | |
50 | + return *this; | |
51 | + } | |
52 | + | |
53 | + constexpr Vec2<T>& operator/=(T f) noexcept | |
54 | + { | |
55 | + X /= f; | |
56 | + Y /= f; | |
57 | + return *this; | |
58 | + } | |
59 | + | |
60 | + Vec2<T> operator+() const noexcept | |
61 | + { | |
62 | + return *this; | |
63 | + } | |
64 | + | |
65 | + Vec2<T> operator-() const noexcept | |
66 | + { | |
67 | + return Vec2<T>(-X, -Y); | |
68 | + } | |
69 | + | |
70 | + Vec2<T> operator+(Vec2<T> rhs) const noexcept | |
71 | + { | |
72 | + return Vec2<T>(X + rhs.X, Y + rhs.Y); | |
73 | + } | |
74 | + | |
75 | + Vec2<T> operator-(Vec2<T> rhs) const noexcept | |
76 | + { | |
77 | + return Vec2<T>(X - rhs.X, Y - rhs.Y); | |
78 | + } | |
79 | + | |
80 | + Vec2<T> operator*(T f) const noexcept | |
81 | + { | |
82 | + return Vec2<T>(X * f, Y * f); | |
83 | + } | |
84 | + | |
85 | + friend Vec2<T> operator*(T f, Vec2<T> rhs) noexcept | |
86 | + { | |
87 | + return Vec2<T>(f * rhs.X, f * rhs.Y); | |
88 | + } | |
89 | + | |
90 | + Vec2<T> operator/(T f) const noexcept | |
91 | + { | |
92 | + return Vec2<T>(X / f, Y / f); | |
93 | + } | |
94 | + | |
95 | + friend Vec2<T> operator/(T f, Vec2<T> rhs) noexcept | |
96 | + { | |
97 | + return Vec2<T>(f / rhs.X, f / rhs.Y); | |
98 | + } | |
99 | + | |
100 | + T X; | |
101 | + T Y; | |
102 | +}; | |
103 | + | |
104 | +template<typename T> | |
105 | +struct Rect | |
106 | +{ | |
107 | + static constexpr Rect FromPoints(Vec2<T> leftTop, Vec2<T> rightBottom) noexcept | |
108 | + { | |
109 | + return Rect(leftTop.X, leftTop.Y, rightBottom.X, rightBottom.Y); | |
110 | + } | |
111 | + | |
112 | + static constexpr Rect FromPointAndSize(Vec2<T> leftTop, Vec2<T> size) noexcept | |
113 | + { | |
114 | + return Rect(leftTop.X, leftTop.Y, leftTop.X + size.X, leftTop.Y + size.Y); | |
115 | + } | |
116 | + | |
117 | + constexpr Rect() noexcept : Left(0), Top(0), Right(0), Bottom(0) | |
118 | + { | |
119 | + } | |
120 | + | |
121 | + constexpr Rect(T left, T top, T right, T bottom) noexcept | |
122 | + : Left(left), Top(top), Right(right), Bottom(bottom) | |
123 | + { | |
124 | + } | |
125 | + | |
126 | + constexpr bool operator==(const Rect<T>& rhs) const noexcept | |
127 | + { | |
128 | + return Left == rhs.Left && Top == rhs.Top && Right == rhs.Right && Bottom == rhs.Bottom; | |
129 | + } | |
130 | + | |
131 | + constexpr bool operator!=(const Rect<T>& rhs) const noexcept | |
132 | + { | |
133 | + return !(*this == rhs); | |
134 | + } | |
135 | + | |
136 | + constexpr bool Includes(Vec2<T> pt) const noexcept | |
137 | + { | |
138 | + return Left <= pt.X && pt.X <= Right && Top <= pt.Y && pt.Y <= Bottom; | |
139 | + } | |
140 | + | |
141 | + constexpr Rect<T> Translate(Vec2<T> offset) const noexcept | |
142 | + { | |
143 | + return Rect<T>(Left + offset.X, Top + offset.Y, Right + offset.X, Bottom + offset.Y); | |
144 | + } | |
145 | + | |
146 | + constexpr Rect<T> Clip(const Rect<T>& rc) const noexcept | |
147 | + { | |
148 | + Vec2<T> leftTop(std::max(Left, rc.Left), std::max(Top, rc.Top)); | |
149 | + return FromPoints( | |
150 | + leftTop, | |
151 | + Vec2<T>(std::max(std::min(Right, rc.Right), leftTop.X), std::max(std::min(Bottom, rc.Bottom), leftTop.Y)) | |
152 | + ); | |
153 | + } | |
154 | + | |
155 | + constexpr T GetWidth() const noexcept | |
156 | + { | |
157 | + return Right - Left; | |
158 | + } | |
159 | + | |
160 | + constexpr T GetHeight() const noexcept | |
161 | + { | |
162 | + return Bottom - Top; | |
163 | + } | |
164 | + | |
165 | + constexpr Vec2<T> GetLeftTop() const noexcept | |
166 | + { | |
167 | + return Vec2<T>(Left, Top); | |
168 | + } | |
169 | + | |
170 | + constexpr Vec2<T> GetRightBottom() const noexcept | |
171 | + { | |
172 | + return Vec2<T>(Right, Bottom); | |
173 | + } | |
174 | + | |
175 | + T Left; | |
176 | + T Top; | |
177 | + T Right; | |
178 | + T Bottom; | |
179 | +}; | |
180 | + | |
181 | +struct Color | |
182 | +{ | |
183 | + constexpr Color() noexcept : Alpha(0.0f), Red(0.0f), Green(0.0f), Blue(0.0f) | |
184 | + { | |
185 | + } | |
186 | + | |
187 | + constexpr Color(float r, float g, float b) noexcept : Alpha(1.0f), Red(r), Green(g), Blue(b) | |
188 | + { | |
189 | + } | |
190 | + | |
191 | + constexpr Color(float a, float r, float g, float b) noexcept : Alpha(a), Red(r), Green(g), Blue(b) | |
192 | + { | |
193 | + } | |
194 | + | |
195 | + constexpr bool operator==(const Color& rhs) const noexcept | |
196 | + { | |
197 | + return Alpha == rhs.Alpha && Red == rhs.Red && Green == rhs.Green && Blue == rhs.Blue; | |
198 | + } | |
199 | + | |
200 | + constexpr bool operator!=(const Color& rhs) const noexcept | |
201 | + { | |
202 | + return !(*this == rhs); | |
203 | + } | |
204 | + | |
205 | + float Alpha; | |
206 | + float Red; | |
207 | + float Green; | |
208 | + float Blue; | |
209 | +}; | |
210 | + | |
211 | +} // namespace Sirius |
@@ -1,42 +0,0 @@ | ||
1 | -// Copyright 2018 Starg | |
2 | -// Distributed under the 3-Clause BSD License. | |
3 | - | |
4 | -#pragma once | |
5 | - | |
6 | -#include <vector> | |
7 | - | |
8 | -#include "sirius/animation.hpp" | |
9 | -#include "sirius/event.hpp" | |
10 | - | |
11 | -namespace Sirius | |
12 | -{ | |
13 | - | |
14 | -class SIRIUS_DLLEXPORT UIContext | |
15 | -{ | |
16 | -public: | |
17 | - UIContext() = default; | |
18 | - UIContext(const UIContext&) = delete; | |
19 | - UIContext& operator=(const UIContext&) = delete; | |
20 | - | |
21 | - GlobalEventListenerManager& GetGlobalEventListenerManager() | |
22 | - { | |
23 | - return m_GlobalEventListenerManager; | |
24 | - } | |
25 | - | |
26 | - EventQueue& GetEventQueue() | |
27 | - { | |
28 | - return m_EventQueue; | |
29 | - } | |
30 | - | |
31 | - AnimationManager& GetAnimationManager() | |
32 | - { | |
33 | - return m_AnimationManager; | |
34 | - } | |
35 | - | |
36 | -private: | |
37 | - GlobalEventListenerManager m_GlobalEventListenerManager; | |
38 | - EventQueue m_EventQueue; | |
39 | - AnimationManager m_AnimationManager; | |
40 | -}; | |
41 | - | |
42 | -} // namespace Sirius |
@@ -0,0 +1,63 @@ | ||
1 | +// Copyright 2018 Starg | |
2 | +// Distributed under the 3-Clause BSD License. | |
3 | + | |
4 | +#pragma once | |
5 | + | |
6 | +#include <memory> | |
7 | +#include <vector> | |
8 | + | |
9 | +#include "sirius/animation.hpp" | |
10 | +#include "sirius/event.hpp" | |
11 | + | |
12 | +namespace Sirius | |
13 | +{ | |
14 | + | |
15 | +class Widget; | |
16 | + | |
17 | +class SIRIUS_DLLEXPORT UIManager | |
18 | +{ | |
19 | +public: | |
20 | + UIManager() = default; | |
21 | + UIManager(const UIManager&) = delete; | |
22 | + UIManager& operator=(const UIManager&) = delete; | |
23 | + ~UIManager() = default; | |
24 | + | |
25 | + EventManager& GetEventManager() | |
26 | + { | |
27 | + return m_EventManager; | |
28 | + } | |
29 | + | |
30 | + AnimationManager& GetAnimationManager() | |
31 | + { | |
32 | + return m_AnimationManager; | |
33 | + } | |
34 | + | |
35 | + std::weak_ptr<Widget> GetFocusedWidget() const | |
36 | + { | |
37 | + return m_pFocusedWidget; | |
38 | + } | |
39 | + | |
40 | + void SetFocusedWidget(std::weak_ptr<Widget> p) | |
41 | + { | |
42 | + m_pFocusedWidget = p; | |
43 | + } | |
44 | + | |
45 | + std::weak_ptr<Widget> GetCapturedWidget() const | |
46 | + { | |
47 | + return m_pCapturedWidget; | |
48 | + } | |
49 | + | |
50 | + void SetCapturedWidget(std::weak_ptr<Widget> p) | |
51 | + { | |
52 | + m_pCapturedWidget = p; | |
53 | + } | |
54 | + | |
55 | +private: | |
56 | + EventManager m_EventManager; | |
57 | + AnimationManager m_AnimationManager; | |
58 | + | |
59 | + std::weak_ptr<Widget> m_pFocusedWidget; | |
60 | + std::weak_ptr<Widget> m_pCapturedWidget; | |
61 | +}; | |
62 | + | |
63 | +} // namespace Sirius |
@@ -3,59 +3,263 @@ | ||
3 | 3 | |
4 | 4 | #pragma once |
5 | 5 | |
6 | +#include <cstdint> | |
7 | + | |
8 | +#include <chrono> | |
9 | +#include <future> | |
10 | +#include <memory> | |
6 | 11 | #include <vector> |
7 | 12 | |
8 | -#include "sirius/array_view.hpp" | |
9 | 13 | #include "sirius/event.hpp" |
10 | -#include "sirius/geometry.hpp" | |
14 | +#include "sirius/simpletypes.hpp" | |
11 | 15 | |
12 | 16 | namespace Sirius |
13 | 17 | { |
14 | 18 | |
15 | -class UIContext; | |
19 | +class UIManager; | |
20 | +class Widget; | |
21 | +class Renderer; | |
16 | 22 | |
17 | 23 | namespace WidgetEvent |
18 | 24 | { |
19 | 25 | |
20 | -//enum : Event::EventKindType | |
21 | -//{ | |
22 | -// | |
23 | -//}; | |
26 | +enum : EventID | |
27 | +{ | |
28 | + // This widget has been added as a child of another widget | |
29 | + // Argument: none | |
30 | + Added = 100, | |
31 | + | |
32 | + // A new child has been added to this widget | |
33 | + // Argument: ChildWidgetEventArgs | |
34 | + ChildAdded, | |
35 | + | |
36 | + // This widget is being removed from the parent | |
37 | + // Argument: none | |
38 | + Remove, | |
39 | + | |
40 | + // A child widget is being removed from this widget | |
41 | + // Argument: ChildWidgetEventArgs | |
42 | + ChildRemove, | |
43 | + | |
44 | + // widget's rect was changed | |
45 | + // Argument: none | |
46 | + RectChanged, | |
47 | + | |
48 | + // widget's opacity was changed | |
49 | + // Argument: none | |
50 | + OpacityChanged, | |
51 | + | |
52 | + // widget's visibility was changed | |
53 | + // Argument: none | |
54 | + VisibilityChanged, | |
55 | + | |
56 | + // widget has been enabled or disabled | |
57 | + // Argument: none | |
58 | + EnabledOrDisabled, | |
59 | + | |
60 | + // widget has gained focus | |
61 | + // Argument: none | |
62 | + FocusSet, | |
63 | + | |
64 | + // widget has lost focus | |
65 | + // Argument: none | |
66 | + FocusKilled | |
67 | +}; | |
68 | + | |
69 | +struct ChildWidgetEventArgs : EventArgs | |
70 | +{ | |
71 | + explicit ChildWidgetEventArgs(std::weak_ptr<Widget> p) : pChildWidget(p) | |
72 | + { | |
73 | + } | |
74 | + | |
75 | + std::weak_ptr<Widget> pChildWidget; | |
76 | +}; | |
24 | 77 | |
25 | 78 | } // namespace WidgetEvent |
26 | 79 | |
27 | -class SIRIUS_DLLEXPORT Widget : public EventHandler | |
80 | +struct ModifierKeyState | |
81 | +{ | |
82 | + bool Alt : 1; | |
83 | + bool Ctrl : 1; | |
84 | + bool Shift : 1; | |
85 | +}; | |
86 | + | |
87 | +struct MouseButtonState | |
88 | +{ | |
89 | + bool Left : 1; | |
90 | + bool Right : 1; | |
91 | + bool Middle : 1; | |
92 | +}; | |
93 | + | |
94 | +enum class MouseButtonKind | |
95 | +{ | |
96 | + Left, | |
97 | + Right, | |
98 | + Middle | |
99 | +}; | |
100 | + | |
101 | +enum class SpecialKey | |
102 | +{ | |
103 | + Enter | |
104 | +}; | |
105 | + | |
106 | +class SIRIUS_DLLEXPORT Widget : public EventHandler, public std::enable_shared_from_this<Widget>, public EventInvokeUtility<Widget> | |
28 | 107 | { |
29 | 108 | public: |
30 | - explicit Widget(UIContext* pUIContext) : EventHandler(pUIContext) | |
109 | + explicit Widget(UIManager& uiManager) : m_UIManager(uiManager) | |
31 | 110 | { |
32 | 111 | } |
33 | 112 | |
34 | - Widget* GetParent() const | |
113 | + Widget(const Widget&) = delete; | |
114 | + Widget& operator=(const Widget&) = delete; | |
115 | + | |
116 | + virtual ~Widget() = default; | |
117 | + | |
118 | + UIManager& GetUIManager() | |
119 | + { | |
120 | + return m_UIManager; | |
121 | + } | |
122 | + | |
123 | + const UIManager& GetUIManager() const | |
124 | + { | |
125 | + return m_UIManager; | |
126 | + } | |
127 | + | |
128 | + EventManager& GetEventManager(); | |
129 | + | |
130 | + std::shared_ptr<Widget> GetEventHandler() | |
131 | + { | |
132 | + return shared_from_this(); | |
133 | + } | |
134 | + | |
135 | + // parent - children | |
136 | + | |
137 | + std::weak_ptr<Widget> GetParent() const | |
35 | 138 | { |
36 | 139 | return m_pParent; |
37 | 140 | } |
38 | 141 | |
39 | - ArrayView<Widget*> GetChildren() const | |
142 | + std::weak_ptr<Widget> GetRoot(); | |
143 | + | |
144 | + std::shared_ptr<Widget> GetChild(std::size_t i) const | |
145 | + { | |
146 | + return m_Children[i]; | |
147 | + } | |
148 | + | |
149 | + std::size_t GetChildCount() const | |
40 | 150 | { |
41 | - return m_Children; | |
151 | + return m_Children.size(); | |
42 | 152 | } |
43 | 153 | |
154 | + void AddChild(std::shared_ptr<Widget> pWidget); | |
155 | + void AddChild(std::shared_ptr<Widget> pWidget, Widget* pWInsertBeforeThisWidget); | |
156 | + void RemoveChild(Widget* pChild); | |
157 | + | |
158 | + // widget state | |
159 | + | |
160 | + bool GetIsVisible() const | |
161 | + { | |
162 | + return m_Flags.IsVisible; | |
163 | + } | |
164 | + | |
165 | + void SetIsVisible(bool b); | |
166 | + | |
167 | + bool GetIsEnabled() const | |
168 | + { | |
169 | + return m_Flags.IsEnabled; | |
170 | + } | |
171 | + | |
172 | + void SetIsEnabled(bool b); | |
173 | + | |
174 | + // in parent's coordinates | |
44 | 175 | Rect<float> GetRect() const |
45 | 176 | { |
46 | 177 | return m_Rect; |
47 | 178 | } |
48 | 179 | |
180 | + void SetRect(const Rect<float>& rect); | |
181 | + | |
49 | 182 | float GetOpacity() const |
50 | 183 | { |
51 | 184 | return m_Opacity; |
52 | 185 | } |
53 | 186 | |
187 | + void SetOpacity(float opacity); | |
188 | + | |
189 | + bool GetWantFocus() const | |
190 | + { | |
191 | + return m_Flags.WantFocus; | |
192 | + } | |
193 | + | |
194 | + void SetWantFocus(bool b) | |
195 | + { | |
196 | + m_Flags.WantFocus = b; | |
197 | + } | |
198 | + | |
199 | + // This function simply returns the value of IsFocusable flag. | |
200 | + // If this returns true, widgets may still be unfocusable for other reasons. | |
201 | + // Call CanFocus() to determine if the widget is actually focusable. | |
202 | + bool GetIsFocusable() const | |
203 | + { | |
204 | + return m_Flags.IsFocusable; | |
205 | + } | |
206 | + | |
207 | + void SetIsFocusable(bool b) | |
208 | + { | |
209 | + m_Flags.IsFocusable = b; | |
210 | + } | |
211 | + | |
212 | + bool CanFocus() const; | |
213 | + bool IsFocused() const; | |
214 | + bool SetFocus(); | |
215 | + | |
216 | + // pt is in parent's coordinate | |
217 | + virtual std::shared_ptr<Widget> FindWidgetAt(Vec2<float> pt); | |
218 | + | |
219 | + virtual void InvokeRender(Renderer& renderer, bool renderFrontToBack = false); | |
220 | + virtual void OnRender(Renderer& renderer); | |
221 | + | |
222 | + // pt is in root coordinates | |
223 | + bool InvokeMouseDown(Vec2<float> pt, MouseButtonKind mouseButtonKind, ModifierKeyState modifierKeyState); | |
224 | + bool InvokeMouseUp(Vec2<float> pt, MouseButtonKind mouseButtonKind, ModifierKeyState modifierKeyState); | |
225 | + bool InvokeMouseMove(Vec2<float> pt, MouseButtonState mouseButtonState, ModifierKeyState modifierKeyState); | |
226 | + | |
227 | + bool InvokeTouchDown(std::uintptr_t id, Vec2<float> pt, ModifierKeyState modifierKeyState); | |
228 | + bool InvokeTouchUp(std::uintptr_t id, Vec2<float> pt, ModifierKeyState modifierKeyState); | |
229 | + bool InvokeTouchMove(std::uintptr_t id, Vec2<float> pt, ModifierKeyState modifierKeyState); | |
230 | + void InvokeTouchCancel(std::uintptr_t id); | |
231 | + | |
232 | + bool InvokePenDown(std::uintptr_t id, Vec2<float> pt, float pressure, float tiltX, float tiltY, MouseButtonKind mouseButtonKind, ModifierKeyState modifierKeyState); | |
233 | + bool InvokePenUp(std::uintptr_t id, Vec2<float> pt, float pressure, float tiltX, float tiltY, MouseButtonKind mouseButtonKind, ModifierKeyState modifierKeyState); | |
234 | + bool InvokePenMove(std::uintptr_t id, Vec2<float> pt, float pressure, float tiltX, float tiltY, MouseButtonState mouseButtonState, ModifierKeyState modifierKeyState); | |
235 | + void InvokePenCancel(std::uintptr_t id); | |
236 | + | |
237 | + bool InvokeWheel(Vec2<float> pt, float deltaX, float deltaY, ModifierKeyState modifierKeyState); | |
238 | + bool InvokeKeyDown(SpecialKey key, ModifierKeyState modifierKeyState); | |
239 | + bool InvokeKeyDown(char32_t key, ModifierKeyState modifierKeyState); | |
240 | + bool InvokeKeyUp(SpecialKey key, ModifierKeyState modifierKeyState); | |
241 | + bool InvokeKeyUp(char32_t key, ModifierKeyState modifierKeyState); | |
242 | + | |
54 | 243 | private: |
55 | - Widget* m_pParent = nullptr; | |
56 | - std::vector<Widget*> m_Children; | |
57 | - Rect<float> m_Rect{}; // (0, 0) is the left-top corner of the parent widget | |
244 | + std::vector<std::shared_ptr<Widget>>::iterator FindChild(Widget* pWidget); | |
245 | + std::vector<std::shared_ptr<Widget>>::const_iterator FindChild(Widget* pWidget) const; | |
246 | + | |
247 | + struct WidgetStateFlags | |
248 | + { | |
249 | + bool IsVisible : 1; | |
250 | + bool IsEnabled : 1; | |
251 | + bool WantFocus : 1; | |
252 | + bool IsFocusable : 1; | |
253 | + }; | |
254 | + | |
255 | + UIManager& m_UIManager; | |
256 | + | |
257 | + std::weak_ptr<Widget> m_pParent; | |
258 | + std::vector<std::shared_ptr<Widget>> m_Children; // sorted in front to back order | |
259 | + | |
260 | + Rect<float> m_Rect = {0.0f, 0.0f, 0.0f, 0.0f}; // in parent's coordinates | |
58 | 261 | float m_Opacity = 1.0f; // [0.0f, 1.0f] |
262 | + WidgetStateFlags m_Flags = {}; | |
59 | 263 | }; |
60 | 264 | |
61 | 265 | } // namespace Sirius |
@@ -7,12 +7,14 @@ add_library( | ||
7 | 7 | ../include/sirius/animation.hpp |
8 | 8 | ../include/sirius/array_view.hpp |
9 | 9 | ../include/sirius/event.hpp |
10 | - ../include/sirius/geometry.hpp | |
11 | - ../include/sirius/uicontext.hpp | |
10 | + ../include/sirius/intrinsics.hpp | |
11 | + ../include/sirius/renderer.hpp | |
12 | + ../include/sirius/simpletypes.hpp | |
13 | + ../include/sirius/uimanager.hpp | |
12 | 14 | ../include/sirius/widget.hpp |
13 | 15 | animation.cpp |
14 | 16 | event.cpp |
15 | - uicontext.cpp | |
17 | + renderer.cpp | |
16 | 18 | widget.cpp |
17 | 19 | ) |
18 | 20 |
@@ -13,14 +13,6 @@ | ||
13 | 13 | namespace Sirius |
14 | 14 | { |
15 | 15 | |
16 | -AnimationBlocker::~AnimationBlocker() | |
17 | -{ | |
18 | - if (m_pAnimationManager) | |
19 | - { | |
20 | - m_pAnimationManager->UnblockAllAnimations(); | |
21 | - } | |
22 | -} | |
23 | - | |
24 | 16 | void AnimationManager::StartAnimation( |
25 | 17 | Animatable* pAnimatable, |
26 | 18 | AnimationCurve animationCurve, |
@@ -29,14 +21,7 @@ void AnimationManager::StartAnimation( | ||
29 | 21 | std::chrono::steady_clock::duration duration |
30 | 22 | ) |
31 | 23 | { |
32 | - auto it = std::find_if( | |
33 | - m_Animations.begin(), | |
34 | - m_Animations.end(), | |
35 | - [pAnimatable] (auto&& x) | |
36 | - { | |
37 | - return x.pAnimatable == pAnimatable; | |
38 | - } | |
39 | - ); | |
24 | + auto it = FindAnimationInfoForAnimatable(pAnimatable); | |
40 | 25 | |
41 | 26 | if (it != m_Animations.end()) |
42 | 27 | { |
@@ -94,6 +79,11 @@ void AnimationManager::ReverseAnimation(Animatable* pAnimatable) | ||
94 | 79 | it->pAnimatable->OnStart(it->Direction, currentValue); |
95 | 80 | } |
96 | 81 | |
82 | +bool AnimationManager::IsAnimationRunning(Animatable* pAnimatable) const | |
83 | +{ | |
84 | + return FindAnimationInfoForAnimatable(pAnimatable) != m_Animations.end(); | |
85 | +} | |
86 | + | |
97 | 87 | void AnimationManager::Process() |
98 | 88 | { |
99 | 89 | auto now = std::chrono::steady_clock::now(); |
@@ -112,7 +102,7 @@ void AnimationManager::Process() | ||
112 | 102 | } |
113 | 103 | } |
114 | 104 | |
115 | -bool AnimationManager::HasActiveAnimations() const | |
105 | +bool AnimationManager::HasRunningAnimations() const | |
116 | 106 | { |
117 | 107 | return !m_Animations.empty(); |
118 | 108 | } |
@@ -122,11 +112,10 @@ bool AnimationManager::AreAnimationsBlocked() const | ||
122 | 112 | return m_BlockingCount != 0; |
123 | 113 | } |
124 | 114 | |
125 | -AnimationBlocker AnimationManager::BlockAllAnimations() | |
115 | +void AnimationManager::BlockAllAnimations() | |
126 | 116 | { |
127 | 117 | AbortAllAnimations(); |
128 | 118 | m_BlockingCount++; |
129 | - return AnimationBlocker(this); | |
130 | 119 | } |
131 | 120 | |
132 | 121 | void AnimationManager::UnblockAllAnimations() |
@@ -134,12 +123,12 @@ void AnimationManager::UnblockAllAnimations() | ||
134 | 123 | m_BlockingCount--; |
135 | 124 | } |
136 | 125 | |
137 | -std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::GetAnimationInfoForAnimatable(Animatable* pAnimatable) | |
126 | +std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::FindAnimationInfoForAnimatable(Animatable* pAnimatable) | |
138 | 127 | { |
139 | 128 | auto it = std::find_if( |
140 | 129 | m_Animations.rbegin(), |
141 | 130 | m_Animations.rend(), |
142 | - [pAnimatable] (auto&& x) | |
131 | + [pAnimatable](auto&& x) | |
143 | 132 | { |
144 | 133 | return x.pAnimatable == pAnimatable; |
145 | 134 | } |
@@ -147,10 +136,45 @@ std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::GetAnim | ||
147 | 136 | |
148 | 137 | if (it == m_Animations.rend()) |
149 | 138 | { |
139 | + return m_Animations.end(); | |
140 | + } | |
141 | + else | |
142 | + { | |
143 | + return std::prev(it.base()); | |
144 | + } | |
145 | +} | |
146 | + | |
147 | +std::vector<AnimationManager::AnimationInfo>::const_iterator AnimationManager::FindAnimationInfoForAnimatable(Animatable* pAnimatable) const | |
148 | +{ | |
149 | + auto it = std::find_if( | |
150 | + m_Animations.rbegin(), | |
151 | + m_Animations.rend(), | |
152 | + [pAnimatable](auto&& x) | |
153 | + { | |
154 | + return x.pAnimatable == pAnimatable; | |
155 | + } | |
156 | + ); | |
157 | + | |
158 | + if (it == m_Animations.rend()) | |
159 | + { | |
160 | + return m_Animations.end(); | |
161 | + } | |
162 | + else | |
163 | + { | |
164 | + return std::prev(it.base()); | |
165 | + } | |
166 | +} | |
167 | + | |
168 | +std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::GetAnimationInfoForAnimatable(Animatable* pAnimatable) | |
169 | +{ | |
170 | + auto it = FindAnimationInfoForAnimatable(pAnimatable); | |
171 | + | |
172 | + if (it == m_Animations.end()) | |
173 | + { | |
150 | 174 | throw std::invalid_argument("Sirius::AnimationManager::GetAnimationInfoForAnimatable(): unregistered Animatable object"); |
151 | 175 | } |
152 | 176 | |
153 | - return std::prev(it.base()); | |
177 | + return it; | |
154 | 178 | } |
155 | 179 | |
156 | 180 | void AnimationManager::AbortAnimation(std::vector<AnimationInfo>::const_iterator it) |
@@ -1,234 +1,474 @@ | ||
1 | 1 | // Copyright 2018 Starg |
2 | 2 | // Distributed under the 3-Clause BSD License. |
3 | 3 | |
4 | -#include "sirius/event.hpp" | |
5 | - | |
6 | 4 | #include <cassert> |
7 | 5 | |
8 | -#include "sirius/uicontext.hpp" | |
6 | +#include <algorithm> | |
7 | +#include <exception> | |
8 | +#include <iterator> | |
9 | + | |
10 | +#include "sirius/event.hpp" | |
9 | 11 | |
10 | 12 | namespace Sirius |
11 | 13 | { |
12 | 14 | |
13 | -bool EventHandler::InvokeEvent(Event ev) | |
15 | +void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs /* = nullptr */) | |
14 | 16 | { |
15 | - if (!ev.pTarget) | |
17 | + // First, invoke local listeners | |
18 | + if (pTarget) | |
16 | 19 | { |
17 | - ev.pTarget = this; | |
20 | + pTarget->InvokeEventListeners(pTarget, id, pArgs); | |
18 | 21 | } |
19 | 22 | |
20 | - // First, invoke local event listeners. | |
21 | - for (auto&& pListener : m_LocalEventListeners) | |
22 | - { | |
23 | - if (pListener->OnEvent(ev)) | |
24 | - { | |
25 | - return true; | |
26 | - } | |
27 | - } | |
23 | + // Next, invoke global listeners | |
24 | + InvokeEventListeners(pTarget, id, pArgs); | |
28 | 25 | |
29 | - // Next, invoke global event listeners. | |
30 | - if (m_pUIContext->GetGlobalEventListenerManager().InvokeGlobalEventListeners(ev)) | |
26 | + // Finally, invoke the handler | |
27 | + if (pTarget) | |
31 | 28 | { |
32 | - return true; | |
29 | + pTarget->OnEvent(id, pArgs); | |
33 | 30 | } |
34 | - | |
35 | - // Finally, dispatch the event. | |
36 | - for (EventHandler* pHandler = ev.pTarget; pHandler; pHandler = pHandler->GetNextEventDestination()) | |
37 | - { | |
38 | - if (pHandler->OnEvent(ev)) | |
39 | - { | |
40 | - return true; | |
41 | - } | |
42 | - } | |
43 | - | |
44 | - return false; | |
45 | 31 | } |
46 | 32 | |
47 | -void EventHandler::PostEvent(Event ev) | |
33 | +void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args) | |
48 | 34 | { |
49 | - if (!ev.pTarget) | |
50 | - { | |
51 | - ev.pTarget = this; | |
52 | - } | |
35 | + InvokeEvent(pTarget, id, std::addressof(args)); | |
36 | +} | |
53 | 37 | |
54 | - m_pUIContext->GetEventQueue().PostEvent(std::move(ev)); | |
38 | +void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs&& args) | |
39 | +{ | |
40 | + InvokeEvent(pTarget, id, std::addressof(args)); | |
55 | 41 | } |
56 | 42 | |
57 | -void EventHandler::PostEventDelayed(Event ev, std::chrono::steady_clock::duration duration) | |
43 | +void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, const std::unique_ptr<EventArgs>& pArgs) | |
58 | 44 | { |
59 | - if (!ev.pTarget) | |
60 | - { | |
61 | - ev.pTarget = this; | |
62 | - } | |
45 | + InvokeEvent(pTarget, id, pArgs.get()); | |
46 | +} | |
63 | 47 | |
64 | - m_pUIContext->GetEventQueue().PostEventDelayed(std::move(ev), std::chrono::steady_clock::now() + duration); | |
48 | +void EventManager::PostEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, std::unique_ptr<EventArgs> pArgs /* = nullptr */) | |
49 | +{ | |
50 | + m_EventQueue.emplace_back(pTarget, id, std::move(pArgs)); | |
65 | 51 | } |
66 | 52 | |
67 | -void EventHandler::PostEventDelayed(Event ev, std::chrono::steady_clock::time_point time) | |
53 | +void EventManager::PostEventThreadSafe(const std::shared_ptr<EventHandler>& pTarget, EventID id, std::unique_ptr<EventArgs> pArgs /* = nullptr */) | |
68 | 54 | { |
69 | - if (!ev.pTarget) | |
70 | - { | |
71 | - ev.pTarget = this; | |
72 | - } | |
55 | + std::scoped_lock lock(m_MutexForThreadSafeEventQueues); | |
56 | + m_ThreadSafeEventQueue.emplace_back(pTarget, id, std::move(pArgs)); | |
57 | + m_HasItemsInThreadSafeEventQueues = true; | |
58 | +} | |
73 | 59 | |
74 | - m_pUIContext->GetEventQueue().PostEventDelayed(std::move(ev), time); | |
60 | +void EventManager::PostEventOnTime( | |
61 | + const std::shared_ptr<EventHandler>& pTarget, | |
62 | + EventID id, | |
63 | + std::chrono::steady_clock::duration duration | |
64 | +) | |
65 | +{ | |
66 | + PostEventOnTime(pTarget, id, nullptr, duration); | |
75 | 67 | } |
76 | 68 | |
77 | -const Event* EventHandler::PeekFirstEvent(Event::EventKindType kind) | |
69 | +void EventManager::PostEventOnTime( | |
70 | + const std::shared_ptr<EventHandler>& pTarget, | |
71 | + EventID id, | |
72 | + std::unique_ptr<EventArgs> pArgs, | |
73 | + std::chrono::steady_clock::duration duration | |
74 | +) | |
78 | 75 | { |
79 | - return m_pUIContext->GetEventQueue().PeekFirstEvent( | |
80 | - [kind, this] (auto&& x) | |
81 | - { | |
82 | - return x.pTarget == this && x.Kind == kind; | |
83 | - } | |
84 | - ); | |
76 | + PostEventOnTime(pTarget, id, std::move(pArgs), std::chrono::steady_clock::now() + duration); | |
85 | 77 | } |
86 | 78 | |
87 | -void EventHandler::RemoveEvents(Event::EventKindType kind) | |
79 | +void EventManager::PostEventOnTime( | |
80 | + const std::shared_ptr<EventHandler>& pTarget, | |
81 | + EventID id, | |
82 | + std::chrono::steady_clock::time_point time | |
83 | +) | |
88 | 84 | { |
89 | - return m_pUIContext->GetEventQueue().RemoveEvents( | |
90 | - [kind, this] (auto&& x) | |
91 | - { | |
92 | - return x.pTarget == this && x.Kind == kind; | |
93 | - } | |
94 | - ); | |
85 | + PostEventOnTime(pTarget, id, nullptr, time); | |
95 | 86 | } |
96 | 87 | |
97 | -void EventHandler::RemoveAllEvents() | |
88 | +void EventManager::PostEventOnTime( | |
89 | + const std::shared_ptr<EventHandler>& pTarget, | |
90 | + EventID id, | |
91 | + std::unique_ptr<EventArgs> pArgs, | |
92 | + std::chrono::steady_clock::time_point time | |
93 | +) | |
98 | 94 | { |
99 | - return m_pUIContext->GetEventQueue().RemoveEvents( | |
100 | - [this] (auto&& x) | |
101 | - { | |
102 | - return x.pTarget == this; | |
103 | - } | |
95 | + m_EventQueueWithTime.emplace_back(pTarget, id, std::move(pArgs), time); | |
96 | + | |
97 | + std::push_heap( | |
98 | + m_EventQueueWithTime.begin(), | |
99 | + m_EventQueueWithTime.end(), | |
100 | + [] (auto&& a, auto&& b) { return a.FireTime > b.FireTime; } | |
104 | 101 | ); |
105 | 102 | } |
106 | 103 | |
107 | -bool EventHandler::OnEvent(const Event&) | |
104 | +void EventManager::PostEventOnTaskComplete( | |
105 | + const std::shared_ptr<EventHandler>& pTarget, | |
106 | + EventID id, | |
107 | + std::future<void> f | |
108 | +) | |
108 | 109 | { |
109 | - return false; | |
110 | + PostEventOnTaskComplete(pTarget, id, nullptr, std::move(f)); | |
110 | 111 | } |
111 | 112 | |
112 | -EventHandler* EventHandler::GetNextEventDestination() const | |
113 | +void EventManager::PostEventOnTaskComplete( | |
114 | + const std::shared_ptr<EventHandler>& pTarget, | |
115 | + EventID id, | |
116 | + std::unique_ptr<EventArgs> pArgs, | |
117 | + std::future<void> f | |
118 | +) | |
113 | 119 | { |
114 | - return nullptr; | |
120 | + m_EventQueueWithFuture.emplace_back(pTarget, id, std::move(pArgs), std::move(f)); | |
115 | 121 | } |
116 | 122 | |
117 | -void EventHandler::AddEventListener(EventListener* pEventListener) | |
123 | +void EventManager::PostEventOnFutureReady( | |
124 | + const std::shared_ptr<EventHandler>& pTarget, | |
125 | + EventID id, | |
126 | + std::future<std::unique_ptr<EventArgs>> f | |
127 | +) | |
118 | 128 | { |
119 | - assert(!HasEventListener(pEventListener)); | |
120 | - m_LocalEventListeners.push_back(pEventListener); | |
129 | + m_EventQueueWithFuture.emplace_back(pTarget, id, std::move(f)); | |
121 | 130 | } |
122 | 131 | |
123 | -void EventHandler::RemoveEventListener(EventListener* pEventListener) | |
132 | +void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs /* = nullptr */) | |
124 | 133 | { |
125 | - auto it = std::find(m_LocalEventListeners.begin(), m_LocalEventListeners.end(), pEventListener); | |
134 | + std::future<std::unique_ptr<EventArgs>> f; | |
126 | 135 | |
127 | - if (it != m_LocalEventListeners.end()) | |
128 | 136 | { |
129 | - m_LocalEventListeners.erase(it); | |
137 | + std::scoped_lock lock(m_MutexForThreadSafeEventQueues); | |
138 | + f = m_ThreadSafeSentEventQueue.emplace_back(pTarget, id, pArgs).Promise.get_future(); | |
130 | 139 | } |
140 | + | |
141 | + f.get(); | |
131 | 142 | } |
132 | 143 | |
133 | -bool EventHandler::HasEventListener(EventListener* pEventListener) const | |
144 | +void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args) | |
134 | 145 | { |
135 | - auto it = std::find(m_LocalEventListeners.begin(), m_LocalEventListeners.end(), pEventListener); | |
136 | - return it != m_LocalEventListeners.end(); | |
146 | + SendEvent(pTarget, id, std::addressof(args)); | |
137 | 147 | } |
138 | 148 | |
139 | -void GlobalEventListenerManager::AddGlobalEventListener(EventListener* pEventListener) | |
149 | +void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs&& args) | |
140 | 150 | { |
141 | - assert(!HasGlobalEventListener(pEventListener)); | |
142 | - m_GlobalEventListeners.push_back(pEventListener); | |
151 | + SendEvent(pTarget, id, std::addressof(args)); | |
143 | 152 | } |
144 | 153 | |
145 | -void GlobalEventListenerManager::RemoveGlobalEventListener(EventListener* pEventListener) | |
154 | +void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, const std::unique_ptr<EventArgs>& pArgs) | |
146 | 155 | { |
147 | - auto it = std::find(m_GlobalEventListeners.begin(), m_GlobalEventListeners.end(), pEventListener); | |
156 | + SendEvent(pTarget, id, pArgs.get()); | |
157 | +} | |
148 | 158 | |
149 | - if (it != m_GlobalEventListeners.end()) | |
159 | +std::future<std::unique_ptr<EventArgs>> EventManager::SendEventAsync( | |
160 | + const std::shared_ptr<EventHandler>& pTarget, | |
161 | + EventID id, | |
162 | + std::unique_ptr<EventArgs> pArgs /* = nullptr */ | |
163 | +) | |
164 | +{ | |
165 | + std::scoped_lock lock(m_MutexForThreadSafeEventQueues); | |
166 | + return m_ThreadSafeSentEventQueue.emplace_back(pTarget, id, std::move(pArgs)).Promise.get_future(); | |
167 | +} | |
168 | + | |
169 | +void EventListenerManager::AddEventListener(EventListener* pListener) | |
170 | +{ | |
171 | + assert(pListener); | |
172 | + m_Listeners.emplace_back(pListener); | |
173 | +} | |
174 | + | |
175 | +void EventListenerManager::AddEventListenerUnique(std::unique_ptr<EventListener> pListener) | |
176 | +{ | |
177 | + assert(pListener); | |
178 | + m_Listeners.emplace_back(std::move(pListener)); | |
179 | +} | |
180 | + | |
181 | +void EventListenerManager::AddEventListenerShared(std::shared_ptr<EventListener> pListener) | |
182 | +{ | |
183 | + assert(pListener); | |
184 | + m_Listeners.emplace_back(std::move(pListener)); | |
185 | +} | |
186 | + | |
187 | +void EventListenerManager::AddEventListenerWeak(std::weak_ptr<EventListener> pListener) | |
188 | +{ | |
189 | + m_Listeners.emplace_back(std::move(pListener)); | |
190 | +} | |
191 | + | |
192 | +void EventListenerManager::RemoveEventListener(EventListener* pListener) | |
193 | +{ | |
194 | + auto it = std::find_if( | |
195 | + m_Listeners.begin(), | |
196 | + m_Listeners.end(), | |
197 | + [pListener] (auto&& v) | |
198 | + { | |
199 | + return std::visit( | |
200 | + [pListener] (auto&& p) | |
201 | + { | |
202 | + using Type = std::decay_t<decltype(p)>; | |
203 | + | |
204 | + if constexpr (std::is_same_v<Type, EventListener*>) | |
205 | + { | |
206 | + return p == pListener; | |
207 | + } | |
208 | + else if constexpr (std::is_same_v<Type, std::weak_ptr<EventListener>>) | |
209 | + { | |
210 | + return p.lock().get() == pListener; | |
211 | + } | |
212 | + else | |
213 | + { | |
214 | + return p.get() == pListener; | |
215 | + } | |
216 | + }, | |
217 | + v | |
218 | + ); | |
219 | + } | |
220 | + ); | |
221 | + | |
222 | + if (it != m_Listeners.end()) | |
150 | 223 | { |
151 | - m_GlobalEventListeners.erase(it); | |
224 | + m_Listeners.erase(it); | |
152 | 225 | } |
153 | 226 | } |
154 | 227 | |
155 | -bool GlobalEventListenerManager::HasGlobalEventListener(EventListener* pEventListener) const | |
228 | +void EventListenerManager::RemoveAllEventListeners() | |
156 | 229 | { |
157 | - auto it = std::find(m_GlobalEventListeners.begin(), m_GlobalEventListeners.end(), pEventListener); | |
158 | - return it != m_GlobalEventListeners.end(); | |
230 | + m_Listeners.clear(); | |
159 | 231 | } |
160 | 232 | |
161 | -bool GlobalEventListenerManager::InvokeGlobalEventListeners(const Event& ev) | |
233 | +void EventListenerManager::InvokeEventListeners(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs) | |
162 | 234 | { |
163 | - for (auto&& pListener : m_GlobalEventListeners) | |
235 | + for (auto it = m_Listeners.begin(); it != m_Listeners.end(); ++it) | |
164 | 236 | { |
165 | - if (pListener->OnEvent(ev)) | |
237 | + bool expired = std::visit( | |
238 | + [&pTarget, id, pArgs] (auto&& p) | |
239 | + { | |
240 | + using Type = std::decay_t<decltype(p)>; | |
241 | + | |
242 | + if constexpr (std::is_same_v<Type, std::weak_ptr<EventListener>>) | |
243 | + { | |
244 | + if (auto pLocked = p.lock()) | |
245 | + { | |
246 | + pLocked->OnEvent(pTarget, id, pArgs); | |
247 | + return false; | |
248 | + } | |
249 | + else | |
250 | + { | |
251 | + return true; | |
252 | + } | |
253 | + } | |
254 | + else | |
255 | + { | |
256 | + p->OnEvent(pTarget, id, pArgs); | |
257 | + return false; | |
258 | + } | |
259 | + }, | |
260 | + *it | |
261 | + ); | |
262 | + | |
263 | + if (expired) | |
166 | 264 | { |
167 | - return true; | |
265 | + it = m_Listeners.erase(it); | |
168 | 266 | } |
169 | 267 | } |
170 | - | |
171 | - return false; | |
172 | 268 | } |
173 | 269 | |
174 | -void EventQueue::PostEvent(Event ev) | |
270 | +void EventManager::RemoveAllEvents() | |
175 | 271 | { |
176 | - m_Events.push_back(std::move(ev)); | |
272 | + if (m_HasItemsInThreadSafeEventQueues) | |
273 | + { | |
274 | + std::scoped_lock lock(m_MutexForThreadSafeEventQueues); | |
275 | + m_ThreadSafeEventQueue.clear(); | |
276 | + m_ThreadSafeSentEventQueue.clear(); | |
277 | + } | |
278 | + | |
279 | + m_EventQueue.clear(); | |
280 | + m_EventQueueWithTime.clear(); | |
281 | + m_EventQueueWithFuture.clear(); | |
177 | 282 | } |
178 | 283 | |
179 | -void EventQueue::PostEventDelayed(Event ev, std::chrono::steady_clock::time_point time) | |
284 | +void EventManager::ProcessEvents() | |
180 | 285 | { |
181 | - auto it = std::upper_bound( | |
182 | - m_DelayedEvents.begin(), | |
183 | - m_DelayedEvents.end(), | |
184 | - time, | |
185 | - [] (auto&& x, auto&& y) | |
286 | + if (m_HasItemsInThreadSafeEventQueues) | |
287 | + { | |
288 | + std::unique_lock lock(m_MutexForThreadSafeEventQueues, std::try_to_lock); | |
289 | + | |
290 | + if (lock.owns_lock()) | |
186 | 291 | { |
187 | - return x < y.FireTime; | |
292 | + m_EventQueue.reserve(m_EventQueue.size() + m_ThreadSafeEventQueue.size()); | |
293 | + std::move(m_ThreadSafeEventQueue.begin(), m_ThreadSafeEventQueue.end(), std::back_inserter(m_EventQueue)); | |
294 | + m_ThreadSafeEventQueue.clear(); | |
295 | + | |
296 | + m_SentEvents.reserve(m_SentEvents.size() + m_ThreadSafeSentEventQueue.size()); | |
297 | + std::move(m_ThreadSafeSentEventQueue.rbegin(), m_ThreadSafeSentEventQueue.rend(), std::back_inserter(m_SentEvents)); | |
298 | + m_ThreadSafeSentEventQueue.clear(); | |
188 | 299 | } |
189 | - ); | |
300 | + } | |
190 | 301 | |
191 | - m_DelayedEvents.insert(it, {std::move(ev), time}); | |
302 | + ProcessEventQueueWithFuture(); | |
303 | + ProcessEventQueue(); | |
304 | + ProcessEventQueueWithTime(); | |
305 | + ProcessSentEvents(); | |
192 | 306 | } |
193 | 307 | |
194 | -void EventQueue::RemoveAllEvents() | |
308 | +std::variant<DesiredEventLoopTime, std::chrono::steady_clock::time_point> EventManager::GetDesiredEventLoopTime() const | |
195 | 309 | { |
196 | - m_Events.clear(); | |
197 | - m_DelayedEvents.clear(); | |
310 | + if (!m_EventQueue.empty() || !m_EventQueueWithFuture.empty() || m_HasItemsInThreadSafeEventQueues) | |
311 | + { | |
312 | + return DesiredEventLoopTime::Now; | |
313 | + } | |
314 | + else if (m_EventQueueWithTime.empty()) | |
315 | + { | |
316 | + return DesiredEventLoopTime::NotSoon; | |
317 | + } | |
318 | + else | |
319 | + { | |
320 | + return m_EventQueueWithTime.front().FireTime; | |
321 | + } | |
198 | 322 | } |
199 | 323 | |
200 | -void EventQueue::ProcessEvents() | |
324 | +void EventManager::TryInvokeQueuedEvent(QueuedEvent& ev) | |
201 | 325 | { |
202 | - while (!m_Events.empty()) | |
326 | + if (!ev.pHandler) | |
203 | 327 | { |
204 | - auto ev = std::move(m_Events.front()); | |
205 | - m_Events.pop_front(); | |
206 | - EventHandler* pHandler = ev.pTarget; | |
207 | - pHandler->InvokeEvent(std::move(ev)); | |
328 | + InvokeEvent({}, ev.ID, ev.pArgs); | |
208 | 329 | } |
330 | + else if (auto pLocked = ev.pWeakHandler.lock()) | |
331 | + { | |
332 | + InvokeEvent(pLocked, ev.ID, ev.pArgs); | |
333 | + } | |
334 | +} | |
335 | + | |
336 | +void EventManager::ProcessEventQueue() | |
337 | +{ | |
338 | + std::size_t i = 0; | |
339 | + std::size_t length = m_EventQueue.size(); | |
340 | + | |
341 | + class AutoEraser | |
342 | + { | |
343 | + public: | |
344 | + AutoEraser(decltype(m_EventQueue)& eventQueue, std::size_t& offset) | |
345 | + : m_EventQueue(eventQueue), m_Offset(offset) | |
346 | + { | |
347 | + } | |
348 | + | |
349 | + ~AutoEraser() | |
350 | + { | |
351 | + m_EventQueue.erase(m_EventQueue.begin(), m_EventQueue.begin() + m_Offset); | |
352 | + } | |
353 | + | |
354 | + private: | |
355 | + decltype(m_EventQueue)& m_EventQueue; | |
356 | + std::size_t& m_Offset; | |
357 | + }; | |
358 | + | |
359 | + AutoEraser ae(m_EventQueue, i); | |
209 | 360 | |
210 | - while (!m_DelayedEvents.empty() && m_DelayedEvents.front().FireTime <= std::chrono::steady_clock::now()) | |
361 | + while (i < length) | |
211 | 362 | { |
212 | - auto ev = std::move(m_DelayedEvents.front().Ev); | |
213 | - m_DelayedEvents.pop_front(); | |
214 | - EventHandler* pHandler = ev.pTarget; | |
215 | - pHandler->InvokeEvent(std::move(ev)); | |
363 | + auto& ev = m_EventQueue[i]; | |
364 | + ++i; | |
365 | + TryInvokeQueuedEvent(ev); | |
216 | 366 | } |
217 | 367 | } |
218 | 368 | |
219 | -std::optional<std::chrono::steady_clock::time_point> EventQueue::GetNextEventFireTime() const | |
369 | +void EventManager::ProcessEventQueueWithTime() | |
220 | 370 | { |
221 | - if (!m_Events.empty()) | |
371 | + auto now = std::chrono::steady_clock::now(); | |
372 | + | |
373 | + while (!m_EventQueueWithTime.empty()) | |
222 | 374 | { |
223 | - return std::chrono::steady_clock::now(); | |
375 | + auto& evt = m_EventQueueWithTime.front(); | |
376 | + | |
377 | + if (evt.FireTime > now) | |
378 | + { | |
379 | + break; | |
380 | + } | |
381 | + | |
382 | + QueuedEvent ev(evt.pHandler, std::move(evt.pWeakHandler), evt.ID, std::move(evt.pArgs)); | |
383 | + | |
384 | + std::pop_heap( | |
385 | + m_EventQueueWithTime.begin(), | |
386 | + m_EventQueueWithTime.end(), | |
387 | + [] (auto&& a, auto&& b) | |
388 | + { | |
389 | + return a.FireTime > b.FireTime; | |
390 | + } | |
391 | + ); | |
392 | + m_EventQueueWithTime.pop_back(); | |
393 | + | |
394 | + TryInvokeQueuedEvent(ev); | |
224 | 395 | } |
225 | - else if (!m_DelayedEvents.empty()) | |
396 | +} | |
397 | + | |
398 | +void EventManager::ProcessEventQueueWithFuture() | |
399 | +{ | |
400 | + for (auto it = m_EventQueueWithFuture.begin(); it != m_EventQueueWithFuture.end(); ++it) | |
226 | 401 | { |
227 | - return m_DelayedEvents.front().FireTime; | |
402 | + using namespace std::chrono_literals; | |
403 | + | |
404 | + std::visit( | |
405 | + [this, &it, &eventQueueWithFuture = m_EventQueueWithFuture] (auto&& f) | |
406 | + { | |
407 | + using Type = std::decay_t<decltype(f)>; | |
408 | + | |
409 | + if (f.wait_for(1ms) != std::future_status::timeout) | |
410 | + { | |
411 | + auto ev = std::move(*it); | |
412 | + it = eventQueueWithFuture.erase(it); | |
413 | + | |
414 | + if constexpr (std::is_same_v<Type, std::future<std::unique_ptr<EventArgs>>>) | |
415 | + { | |
416 | + ev.pArgs = f.get(); | |
417 | + } | |
418 | + | |
419 | + TryInvokeQueuedEvent(ev); | |
420 | + } | |
421 | + }, | |
422 | + it->Future | |
423 | + ); | |
424 | + | |
228 | 425 | } |
229 | - else | |
426 | +} | |
427 | + | |
428 | +void EventManager::ProcessSentEvents() | |
429 | +{ | |
430 | + while (!m_SentEvents.empty()) | |
230 | 431 | { |
231 | - return std::nullopt; | |
432 | + auto ev = std::move(m_SentEvents.back()); | |
433 | + m_SentEvents.pop_back(); | |
434 | + | |
435 | + try | |
436 | + { | |
437 | + InvokeEvent( | |
438 | + ev.pHandler, | |
439 | + ev.ID, | |
440 | + std::visit( | |
441 | + [] (auto&& p) | |
442 | + { | |
443 | + using Type = std::decay_t<decltype(p)>; | |
444 | + | |
445 | + if constexpr (std::is_same_v<Type, EventArgs*>) | |
446 | + { | |
447 | + return p; | |
448 | + } | |
449 | + else | |
450 | + { | |
451 | + return p.get(); | |
452 | + } | |
453 | + }, | |
454 | + ev.pArgs | |
455 | + ) | |
456 | + ); | |
457 | + } | |
458 | + catch (...) | |
459 | + { | |
460 | + ev.Promise.set_exception(std::current_exception()); | |
461 | + continue; | |
462 | + } | |
463 | + | |
464 | + if (auto ppArgs = std::get_if<std::unique_ptr<EventArgs>>(std::addressof(ev.pArgs))) | |
465 | + { | |
466 | + ev.Promise.set_value(std::move(*ppArgs)); | |
467 | + } | |
468 | + else | |
469 | + { | |
470 | + ev.Promise.set_value(nullptr); | |
471 | + } | |
232 | 472 | } |
233 | 473 | } |
234 | 474 |
@@ -0,0 +1,92 @@ | ||
1 | +// Copyright 2018 Starg | |
2 | +// Distributed under the 3-Clause BSD License. | |
3 | + | |
4 | +#include "sirius/renderer.hpp" | |
5 | + | |
6 | +#include <cassert> | |
7 | + | |
8 | +#include <algorithm> | |
9 | + | |
10 | +namespace Sirius | |
11 | +{ | |
12 | + | |
13 | +void Renderer::BeginDraw() | |
14 | +{ | |
15 | + OnBeginDraw(); | |
16 | + | |
17 | + for (auto&& p : m_Listeners) | |
18 | + { | |
19 | + p->OnBeginDraw(this); | |
20 | + } | |
21 | +} | |
22 | + | |
23 | +void Renderer::EndDraw() | |
24 | +{ | |
25 | + for (auto&& p : m_Listeners) | |
26 | + { | |
27 | + p->OnEndDraw(this); | |
28 | + } | |
29 | + | |
30 | + OnEndDraw(); | |
31 | +} | |
32 | + | |
33 | +void Renderer::AddListener(RendererListener* pListener) | |
34 | +{ | |
35 | + assert(!HasListener(pListener)); | |
36 | + m_Listeners.push_back(pListener); | |
37 | +} | |
38 | + | |
39 | +void Renderer::RemoveListener(RendererListener* pListener) | |
40 | +{ | |
41 | + auto it = std::find(m_Listeners.begin(), m_Listeners.end(), pListener); | |
42 | + | |
43 | + if (it != m_Listeners.end()) | |
44 | + { | |
45 | + m_Listeners.erase(it); | |
46 | + } | |
47 | +} | |
48 | + | |
49 | +bool Renderer::HasListener(RendererListener* pListener) const | |
50 | +{ | |
51 | + auto it = std::find(m_Listeners.begin(), m_Listeners.end(), pListener); | |
52 | + return it != m_Listeners.end(); | |
53 | +} | |
54 | + | |
55 | +void Renderer::InvokeCreateDevice() | |
56 | +{ | |
57 | + for (auto&& p : m_Listeners) | |
58 | + { | |
59 | + p->OnCreateDevice(this); | |
60 | + } | |
61 | +} | |
62 | + | |
63 | +void Renderer::InvokeDestroyDevice() | |
64 | +{ | |
65 | + for (auto&& p : m_Listeners) | |
66 | + { | |
67 | + p->OnDestroyDevice(this); | |
68 | + } | |
69 | +} | |
70 | + | |
71 | +void Renderer::DrawEllipse(Vec2<float> center, float radiusX, float radiusY, const Paint& paint) | |
72 | +{ | |
73 | + DrawEllipse( | |
74 | + Rect<float>::FromPoints(Vec2<float>(center.X - radiusX, center.Y - radiusY), Vec2<float>(center.X + radiusX, center.Y + radiusY)), | |
75 | + paint | |
76 | + ); | |
77 | +} | |
78 | + | |
79 | +void Renderer::FillEllipse(Vec2<float> center, float radiusX, float radiusY, const Paint& paint) | |
80 | +{ | |
81 | + FillEllipse( | |
82 | + Rect<float>::FromPoints(Vec2<float>(center.X - radiusX, center.Y - radiusY), Vec2<float>(center.X + radiusX, center.Y + radiusY)), | |
83 | + paint | |
84 | + ); | |
85 | +} | |
86 | + | |
87 | +void Renderer::DrawBitmap(const std::unique_ptr<Bitmap>& pBitmap, const Rect<float>& srcRect, const Rect<float>& destRect) | |
88 | +{ | |
89 | + DrawBitmap(pBitmap.get(), srcRect, destRect); | |
90 | +} | |
91 | + | |
92 | +} // namespace Sirius |
@@ -1,9 +0,0 @@ | ||
1 | -// Copyright 2018 Starg | |
2 | -// Distributed under the 3-Clause BSD License. | |
3 | - | |
4 | -#include "sirius/uicontext.hpp" | |
5 | - | |
6 | -namespace Sirius | |
7 | -{ | |
8 | - | |
9 | -} // namespace Sirius |
@@ -3,7 +3,242 @@ | ||
3 | 3 | |
4 | 4 | #include "sirius/widget.hpp" |
5 | 5 | |
6 | +#include <cassert> | |
7 | + | |
8 | +#include <algorithm> | |
9 | +#include <stdexcept> | |
10 | +#include <utility> | |
11 | + | |
12 | +#include "sirius/renderer.hpp" | |
13 | +#include "sirius/uimanager.hpp" | |
14 | + | |
6 | 15 | namespace Sirius |
7 | 16 | { |
8 | 17 | |
18 | +EventManager& Widget::GetEventManager() | |
19 | +{ | |
20 | + return GetUIManager().GetEventManager(); | |
21 | +} | |
22 | + | |
23 | +std::weak_ptr<Widget> Widget::GetRoot() | |
24 | +{ | |
25 | + auto p = shared_from_this(); | |
26 | + | |
27 | + while (auto pParent = p->m_pParent.lock()) | |
28 | + { | |
29 | + p = pParent; | |
30 | + } | |
31 | + | |
32 | + return p; | |
33 | +} | |
34 | + | |
35 | +void Widget::AddChild(std::shared_ptr<Widget> pWidget) | |
36 | +{ | |
37 | + AddChild(std::move(pWidget), m_Children.empty() ? nullptr : m_Children.front().get()); | |
38 | +} | |
39 | + | |
40 | +void Widget::AddChild(std::shared_ptr<Widget> pWidget, Widget* pInsertBeforeThisWidget) | |
41 | +{ | |
42 | + if (!pWidget) | |
43 | + { | |
44 | + throw std::invalid_argument("Sirius::Widget::AddChild() : pWidget is nullptr"); | |
45 | + } | |
46 | + | |
47 | + if (pInsertBeforeThisWidget) | |
48 | + { | |
49 | + auto it = FindChild(pInsertBeforeThisWidget); | |
50 | + | |
51 | + if (it == m_Children.end()) | |
52 | + { | |
53 | + throw std::invalid_argument("Sirius::Widget::AddChild() : pInsertBeforeThisWidget is not a child of this widget"); | |
54 | + } | |
55 | + | |
56 | + m_Children.insert(it, pWidget); | |
57 | + } | |
58 | + else | |
59 | + { | |
60 | + m_Children.push_back(pWidget); | |
61 | + } | |
62 | + | |
63 | + pWidget->m_pParent = weak_from_this(); | |
64 | + pWidget->InvokeEvent(WidgetEvent::Added, nullptr); | |
65 | + | |
66 | + InvokeEvent(WidgetEvent::ChildAdded, WidgetEvent::ChildWidgetEventArgs(pWidget)); | |
67 | +} | |
68 | + | |
69 | +void Widget::RemoveChild(Widget* pChild) | |
70 | +{ | |
71 | + if (!pChild || FindChild(pChild) == m_Children.end()) | |
72 | + { | |
73 | + throw std::invalid_argument("Sirius::Widget::RemoveChild() : pWChild is not a child of this widget"); | |
74 | + } | |
75 | + | |
76 | + InvokeEvent(WidgetEvent::ChildRemove, WidgetEvent::ChildWidgetEventArgs(pChild->weak_from_this())); | |
77 | + pChild->InvokeEvent(WidgetEvent::Remove, nullptr); | |
78 | + | |
79 | + // ChildRemove/Remove events might have added/removed another widget, so we have to find the child again. | |
80 | + auto it = FindChild(pChild); | |
81 | + | |
82 | + if (it != m_Children.end()) | |
83 | + { | |
84 | + m_Children.erase(it); | |
85 | + } | |
86 | + | |
87 | + pChild->m_pParent.reset(); | |
88 | +} | |
89 | + | |
90 | +void Widget::SetIsVisible(bool b) | |
91 | +{ | |
92 | + if (m_Flags.IsVisible != b) | |
93 | + { | |
94 | + m_Flags.IsVisible = b; | |
95 | + InvokeEvent(WidgetEvent::VisibilityChanged, nullptr); | |
96 | + } | |
97 | +} | |
98 | + | |
99 | +void Widget::SetIsEnabled(bool b) | |
100 | +{ | |
101 | + if (m_Flags.IsEnabled != b) | |
102 | + { | |
103 | + m_Flags.IsEnabled = b; | |
104 | + InvokeEvent(WidgetEvent::EnabledOrDisabled, nullptr); | |
105 | + } | |
106 | +} | |
107 | + | |
108 | +void Widget::SetRect(const Rect<float>& rect) | |
109 | +{ | |
110 | + if (m_Rect != rect) | |
111 | + { | |
112 | + m_Rect = rect; | |
113 | + InvokeEvent(WidgetEvent::RectChanged, nullptr); | |
114 | + } | |
115 | +} | |
116 | + | |
117 | +void Widget::SetOpacity(float opacity) | |
118 | +{ | |
119 | + float clampedOpacity = std::clamp(opacity, 0.0f, 1.0f); | |
120 | + | |
121 | + if (m_Opacity != clampedOpacity) | |
122 | + { | |
123 | + m_Opacity = clampedOpacity; | |
124 | + InvokeEvent(WidgetEvent::OpacityChanged, nullptr); | |
125 | + } | |
126 | +} | |
127 | + | |
128 | +bool Widget::CanFocus() const | |
129 | +{ | |
130 | + return GetIsFocusable() && GetIsEnabled() && GetIsVisible(); | |
131 | +} | |
132 | + | |
133 | +bool Widget::IsFocused() const | |
134 | +{ | |
135 | + return GetUIManager().GetFocusedWidget().lock().get() == this; | |
136 | +} | |
137 | + | |
138 | +bool Widget::SetFocus() | |
139 | +{ | |
140 | + if (!CanFocus()) | |
141 | + { | |
142 | + if (auto pParent = m_pParent.lock()) | |
143 | + { | |
144 | + return pParent->SetFocus(); | |
145 | + } | |
146 | + | |
147 | + return false; | |
148 | + } | |
149 | + | |
150 | + auto pWThis = weak_from_this(); | |
151 | + auto pOldFocus = GetUIManager().GetFocusedWidget().lock(); | |
152 | + | |
153 | + if (pOldFocus) | |
154 | + { | |
155 | + pOldFocus->InvokeEvent(WidgetEvent::FocusKilled); | |
156 | + } | |
157 | + | |
158 | + InvokeEvent(WidgetEvent::FocusSet); | |
159 | + GetUIManager().SetFocusedWidget(pWThis); | |
160 | + return true; | |
161 | +} | |
162 | + | |
163 | +std::shared_ptr<Widget> Widget::FindWidgetAt(Vec2<float> pt) | |
164 | +{ | |
165 | + auto rect = GetRect(); | |
166 | + | |
167 | + if (rect.Includes(pt)) | |
168 | + { | |
169 | + Vec2<float> childPoint(pt.X - rect.Left, pt.Y - rect.Top); | |
170 | + | |
171 | + for (auto&& pChild : m_Children) | |
172 | + { | |
173 | + if (auto pAt = pChild->FindWidgetAt(childPoint)) | |
174 | + { | |
175 | + return pAt; | |
176 | + } | |
177 | + } | |
178 | + | |
179 | + return shared_from_this(); | |
180 | + } | |
181 | + | |
182 | + return nullptr; | |
183 | +} | |
184 | + | |
185 | +void Widget::InvokeRender(Renderer& renderer, bool renderFrontToBack /* = false */) | |
186 | +{ | |
187 | + auto pParent = m_pParent.lock(); | |
188 | + assert(renderer.GetGlobalTranslation() == (pParent ? pParent->m_Rect.GetLeftTop() : Vec2<float>(0, 0))); | |
189 | + | |
190 | + if (GetIsVisible()) | |
191 | + { | |
192 | + AutoRestoreRendererStates arrs(renderer); | |
193 | + Rect<float> rect = GetRect(); | |
194 | + Rect<float> oldClipRect = renderer.GetClipRect(); | |
195 | + renderer.SetClipRect(oldClipRect.Clip(rect.Translate(oldClipRect.GetLeftTop()))); | |
196 | + renderer.SetGlobalTranslation(renderer.GetGlobalTranslation() + Vec2<float>(rect.Left, rect.Top)); | |
197 | + | |
198 | + auto renderChild = [&renderer, renderFrontToBack] (auto&& pWidget) | |
199 | + { | |
200 | + pWidget->InvokeRender(renderer, renderFrontToBack); | |
201 | + }; | |
202 | + | |
203 | + if (renderFrontToBack) | |
204 | + { | |
205 | + std::for_each(m_Children.begin(), m_Children.end(), renderChild); | |
206 | + OnRender(renderer); | |
207 | + } | |
208 | + else | |
209 | + { | |
210 | + OnRender(renderer); | |
211 | + std::for_each(m_Children.rbegin(), m_Children.rend(), renderChild); | |
212 | + } | |
213 | + } | |
214 | +} | |
215 | + | |
216 | +void Widget::OnRender(Renderer&) | |
217 | +{ | |
218 | +} | |
219 | + | |
220 | +std::vector<std::shared_ptr<Widget>>::iterator Widget::FindChild(Widget* pWidget) | |
221 | +{ | |
222 | + return std::find_if( | |
223 | + m_Children.begin(), | |
224 | + m_Children.end(), | |
225 | + [pWidget] (auto&& x) | |
226 | + { | |
227 | + return x.get() == pWidget; | |
228 | + } | |
229 | + ); | |
230 | +} | |
231 | + | |
232 | +std::vector<std::shared_ptr<Widget>>::const_iterator Widget::FindChild(Widget* pWidget) const | |
233 | +{ | |
234 | + return std::find_if( | |
235 | + m_Children.begin(), | |
236 | + m_Children.end(), | |
237 | + [pWidget] (auto&& x) | |
238 | + { | |
239 | + return x.get() == pWidget; | |
240 | + } | |
241 | + ); | |
242 | +} | |
243 | + | |
9 | 244 | } // namespace Sirius |