• R/O
  • HTTP
  • SSH
  • HTTPS

コミット

タグ
未設定

よく使われているワード(クリックで追加)

javaandroidc++linuxc#objective-ccocoa誰得qtrubybathyscaphegamephpguicwindows翻訳pythonomegattwitterframeworkbtronarduinovb.net計画中(planning stage)directxpreviewertestゲームエンジンdom

Simple C++ UI framework and more...


コミットメタ情報

リビジョン1f497834a6bd2ab8940eca99f16e1ce2bc355757 (tree)
日時2018-05-16 00:12:51
作者Starg <starg@user...>
コミッターStarg

ログメッセージ

Implement widget and renderer

変更サマリ

差分

--- a/include/sirius/animation.hpp
+++ b/include/sirius/animation.hpp
@@ -13,8 +13,6 @@
1313 namespace Sirius
1414 {
1515
16-class AnimationManager;
17-
1816 enum class AnimationDirection
1917 {
2018 Forward,
@@ -99,28 +97,6 @@ private:
9997 float m_Value = 0.0f;
10098 };
10199
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-
124100 class SIRIUS_DLLEXPORT AnimationManager
125101 {
126102 friend class AnimationBlocker;
@@ -136,16 +112,16 @@ public:
136112 void AbortAnimation(Animatable* pAnimatable);
137113 void AbortAllAnimations();
138114 void ReverseAnimation(Animatable* pAnimatable);
115+ bool IsAnimationRunning(Animatable* pAnimatable) const;
139116
140117 void Process();
141- bool HasActiveAnimations() const;
118+ bool HasRunningAnimations() const;
142119
143120 bool AreAnimationsBlocked() const;
144- AnimationBlocker BlockAllAnimations();
145-
146-private:
121+ void BlockAllAnimations();
147122 void UnblockAllAnimations();
148123
124+private:
149125 struct AnimationInfo
150126 {
151127 Animatable* pAnimatable;
@@ -158,6 +134,8 @@ private:
158134 float RelativeStartTime;
159135 };
160136
137+ std::vector<AnimationInfo>::iterator FindAnimationInfoForAnimatable(Animatable* pAnimatable);
138+ std::vector<AnimationInfo>::const_iterator FindAnimationInfoForAnimatable(Animatable* pAnimatable) const;
161139 std::vector<AnimationInfo>::iterator GetAnimationInfoForAnimatable(Animatable* pAnimatable);
162140 void AbortAnimation(std::vector<AnimationInfo>::const_iterator it);
163141
@@ -168,4 +146,24 @@ private:
168146 std::int32_t m_BlockingCount = 0;
169147 };
170148
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+
171169 } // namespace Sirius
--- a/include/sirius/event.hpp
+++ b/include/sirius/event.hpp
@@ -5,51 +5,32 @@
55
66 #include <cstdint>
77
8-#include <algorithm>
9-#include <any>
8+#include <atomic>
109 #include <chrono>
11-#include <deque>
12-#include <optional>
10+#include <future>
11+#include <memory>
12+#include <mutex>
13+#include <type_traits>
1314 #include <utility>
15+#include <variant>
1416 #include <vector>
1517
1618 namespace Sirius
1719 {
1820
19-class UIContext;
2021 class EventHandler;
2122
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;
3725
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;
5334 };
5435
5536 class EventListener
@@ -60,107 +41,339 @@ public:
6041 EventListener& operator=(const EventListener&) = delete;
6142 virtual ~EventListener() = default;
6243
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 */)
6545 {
66- return false;
6746 }
6847 };
6948
70-class SIRIUS_DLLEXPORT EventHandler
49+class SIRIUS_DLLEXPORT EventListenerManager
7150 {
7251 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;
9056
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();
9463
95-protected:
96- UIContext* m_pUIContext; // also used by Widget
64+ void InvokeEventListeners(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs);
9765
9866 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;
10068 };
10169
102-class SIRIUS_DLLEXPORT GlobalEventListenerManager
70+class SIRIUS_DLLEXPORT EventHandler : public EventListenerManager
10371 {
10472 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;
10977
110-private:
111- std::vector<EventListener*> m_GlobalEventListeners;
78+ virtual void OnEvent(EventID /* id */, EventArgs* /* pArgs */)
79+ {
80+ }
11281 };
11382
114-class SIRIUS_DLLEXPORT EventQueue
83+enum class DesiredEventLoopTime
84+{
85+ Now,
86+ NotSoon
87+};
88+
89+class SIRIUS_DLLEXPORT EventManager : public EventListenerManager
11590 {
11691 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+ };
119204
120- template<typename T>
121- const Event* PeekFirstEvent(T pred)
205+ struct QueuedEventWithFuture : QueuedEvent
122206 {
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+ }
124215
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))
126221 {
127- return &*it;
128222 }
129223
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+ };
131226
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))
133236 {
134- return &itDelayed->Ev;
135237 }
136238
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);
138280 }
139281
140- template<typename T>
141- void RemoveEvents(T pred)
282+ void InvokeEvent(EventID id, EventArgs& args)
142283 {
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);
148285 }
149286
150- void RemoveAllEvents();
287+ void InvokeEvent(EventID id, EventArgs&& args)
288+ {
289+ CallGetEventManager().InvokeEvent(CallGetEventHandler(), id, args);
290+ }
151291
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+ }
154366
155367 private:
156- struct DelayedEvent
368+ std::shared_ptr<EventHandler> CallGetEventHandler()
157369 {
158- Event Ev;
159- std::chrono::steady_clock::time_point FireTime;
160- };
370+ return static_cast<T*>(this)->GetEventHandler();
371+ }
161372
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+ }
164377 };
165378
166379 } // namespace Sirius
--- a/include/sirius/geometry.hpp
+++ /dev/null
@@ -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
--- /dev/null
+++ b/include/sirius/intrinsics.hpp
@@ -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
--- /dev/null
+++ b/include/sirius/renderer.hpp
@@ -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
--- /dev/null
+++ b/include/sirius/simpletypes.hpp
@@ -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
--- a/include/sirius/uicontext.hpp
+++ /dev/null
@@ -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
--- /dev/null
+++ b/include/sirius/uimanager.hpp
@@ -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
--- a/include/sirius/widget.hpp
+++ b/include/sirius/widget.hpp
@@ -3,59 +3,263 @@
33
44 #pragma once
55
6+#include <cstdint>
7+
8+#include <chrono>
9+#include <future>
10+#include <memory>
611 #include <vector>
712
8-#include "sirius/array_view.hpp"
913 #include "sirius/event.hpp"
10-#include "sirius/geometry.hpp"
14+#include "sirius/simpletypes.hpp"
1115
1216 namespace Sirius
1317 {
1418
15-class UIContext;
19+class UIManager;
20+class Widget;
21+class Renderer;
1622
1723 namespace WidgetEvent
1824 {
1925
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+};
2477
2578 } // namespace WidgetEvent
2679
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>
28107 {
29108 public:
30- explicit Widget(UIContext* pUIContext) : EventHandler(pUIContext)
109+ explicit Widget(UIManager& uiManager) : m_UIManager(uiManager)
31110 {
32111 }
33112
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
35138 {
36139 return m_pParent;
37140 }
38141
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
40150 {
41- return m_Children;
151+ return m_Children.size();
42152 }
43153
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
44175 Rect<float> GetRect() const
45176 {
46177 return m_Rect;
47178 }
48179
180+ void SetRect(const Rect<float>& rect);
181+
49182 float GetOpacity() const
50183 {
51184 return m_Opacity;
52185 }
53186
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+
54243 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
58261 float m_Opacity = 1.0f; // [0.0f, 1.0f]
262+ WidgetStateFlags m_Flags = {};
59263 };
60264
61265 } // namespace Sirius
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,12 +7,14 @@ add_library(
77 ../include/sirius/animation.hpp
88 ../include/sirius/array_view.hpp
99 ../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
1214 ../include/sirius/widget.hpp
1315 animation.cpp
1416 event.cpp
15- uicontext.cpp
17+ renderer.cpp
1618 widget.cpp
1719 )
1820
--- a/src/animation.cpp
+++ b/src/animation.cpp
@@ -13,14 +13,6 @@
1313 namespace Sirius
1414 {
1515
16-AnimationBlocker::~AnimationBlocker()
17-{
18- if (m_pAnimationManager)
19- {
20- m_pAnimationManager->UnblockAllAnimations();
21- }
22-}
23-
2416 void AnimationManager::StartAnimation(
2517 Animatable* pAnimatable,
2618 AnimationCurve animationCurve,
@@ -29,14 +21,7 @@ void AnimationManager::StartAnimation(
2921 std::chrono::steady_clock::duration duration
3022 )
3123 {
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);
4025
4126 if (it != m_Animations.end())
4227 {
@@ -94,6 +79,11 @@ void AnimationManager::ReverseAnimation(Animatable* pAnimatable)
9479 it->pAnimatable->OnStart(it->Direction, currentValue);
9580 }
9681
82+bool AnimationManager::IsAnimationRunning(Animatable* pAnimatable) const
83+{
84+ return FindAnimationInfoForAnimatable(pAnimatable) != m_Animations.end();
85+}
86+
9787 void AnimationManager::Process()
9888 {
9989 auto now = std::chrono::steady_clock::now();
@@ -112,7 +102,7 @@ void AnimationManager::Process()
112102 }
113103 }
114104
115-bool AnimationManager::HasActiveAnimations() const
105+bool AnimationManager::HasRunningAnimations() const
116106 {
117107 return !m_Animations.empty();
118108 }
@@ -122,11 +112,10 @@ bool AnimationManager::AreAnimationsBlocked() const
122112 return m_BlockingCount != 0;
123113 }
124114
125-AnimationBlocker AnimationManager::BlockAllAnimations()
115+void AnimationManager::BlockAllAnimations()
126116 {
127117 AbortAllAnimations();
128118 m_BlockingCount++;
129- return AnimationBlocker(this);
130119 }
131120
132121 void AnimationManager::UnblockAllAnimations()
@@ -134,12 +123,12 @@ void AnimationManager::UnblockAllAnimations()
134123 m_BlockingCount--;
135124 }
136125
137-std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::GetAnimationInfoForAnimatable(Animatable* pAnimatable)
126+std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::FindAnimationInfoForAnimatable(Animatable* pAnimatable)
138127 {
139128 auto it = std::find_if(
140129 m_Animations.rbegin(),
141130 m_Animations.rend(),
142- [pAnimatable] (auto&& x)
131+ [pAnimatable](auto&& x)
143132 {
144133 return x.pAnimatable == pAnimatable;
145134 }
@@ -147,10 +136,45 @@ std::vector<AnimationManager::AnimationInfo>::iterator AnimationManager::GetAnim
147136
148137 if (it == m_Animations.rend())
149138 {
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+ {
150174 throw std::invalid_argument("Sirius::AnimationManager::GetAnimationInfoForAnimatable(): unregistered Animatable object");
151175 }
152176
153- return std::prev(it.base());
177+ return it;
154178 }
155179
156180 void AnimationManager::AbortAnimation(std::vector<AnimationInfo>::const_iterator it)
--- a/src/event.cpp
+++ b/src/event.cpp
@@ -1,234 +1,474 @@
11 // Copyright 2018 Starg
22 // Distributed under the 3-Clause BSD License.
33
4-#include "sirius/event.hpp"
5-
64 #include <cassert>
75
8-#include "sirius/uicontext.hpp"
6+#include <algorithm>
7+#include <exception>
8+#include <iterator>
9+
10+#include "sirius/event.hpp"
911
1012 namespace Sirius
1113 {
1214
13-bool EventHandler::InvokeEvent(Event ev)
15+void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs /* = nullptr */)
1416 {
15- if (!ev.pTarget)
17+ // First, invoke local listeners
18+ if (pTarget)
1619 {
17- ev.pTarget = this;
20+ pTarget->InvokeEventListeners(pTarget, id, pArgs);
1821 }
1922
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);
2825
29- // Next, invoke global event listeners.
30- if (m_pUIContext->GetGlobalEventListenerManager().InvokeGlobalEventListeners(ev))
26+ // Finally, invoke the handler
27+ if (pTarget)
3128 {
32- return true;
29+ pTarget->OnEvent(id, pArgs);
3330 }
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;
4531 }
4632
47-void EventHandler::PostEvent(Event ev)
33+void EventManager::InvokeEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args)
4834 {
49- if (!ev.pTarget)
50- {
51- ev.pTarget = this;
52- }
35+ InvokeEvent(pTarget, id, std::addressof(args));
36+}
5337
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));
5541 }
5642
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)
5844 {
59- if (!ev.pTarget)
60- {
61- ev.pTarget = this;
62- }
45+ InvokeEvent(pTarget, id, pArgs.get());
46+}
6347
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));
6551 }
6652
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 */)
6854 {
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+}
7359
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);
7567 }
7668
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+)
7875 {
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);
8577 }
8678
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+)
8884 {
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);
9586 }
9687
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+)
9894 {
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; }
104101 );
105102 }
106103
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+)
108109 {
109- return false;
110+ PostEventOnTaskComplete(pTarget, id, nullptr, std::move(f));
110111 }
111112
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+)
113119 {
114- return nullptr;
120+ m_EventQueueWithFuture.emplace_back(pTarget, id, std::move(pArgs), std::move(f));
115121 }
116122
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+)
118128 {
119- assert(!HasEventListener(pEventListener));
120- m_LocalEventListeners.push_back(pEventListener);
129+ m_EventQueueWithFuture.emplace_back(pTarget, id, std::move(f));
121130 }
122131
123-void EventHandler::RemoveEventListener(EventListener* pEventListener)
132+void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs /* = nullptr */)
124133 {
125- auto it = std::find(m_LocalEventListeners.begin(), m_LocalEventListeners.end(), pEventListener);
134+ std::future<std::unique_ptr<EventArgs>> f;
126135
127- if (it != m_LocalEventListeners.end())
128136 {
129- m_LocalEventListeners.erase(it);
137+ std::scoped_lock lock(m_MutexForThreadSafeEventQueues);
138+ f = m_ThreadSafeSentEventQueue.emplace_back(pTarget, id, pArgs).Promise.get_future();
130139 }
140+
141+ f.get();
131142 }
132143
133-bool EventHandler::HasEventListener(EventListener* pEventListener) const
144+void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs& args)
134145 {
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));
137147 }
138148
139-void GlobalEventListenerManager::AddGlobalEventListener(EventListener* pEventListener)
149+void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs&& args)
140150 {
141- assert(!HasGlobalEventListener(pEventListener));
142- m_GlobalEventListeners.push_back(pEventListener);
151+ SendEvent(pTarget, id, std::addressof(args));
143152 }
144153
145-void GlobalEventListenerManager::RemoveGlobalEventListener(EventListener* pEventListener)
154+void EventManager::SendEvent(const std::shared_ptr<EventHandler>& pTarget, EventID id, const std::unique_ptr<EventArgs>& pArgs)
146155 {
147- auto it = std::find(m_GlobalEventListeners.begin(), m_GlobalEventListeners.end(), pEventListener);
156+ SendEvent(pTarget, id, pArgs.get());
157+}
148158
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())
150223 {
151- m_GlobalEventListeners.erase(it);
224+ m_Listeners.erase(it);
152225 }
153226 }
154227
155-bool GlobalEventListenerManager::HasGlobalEventListener(EventListener* pEventListener) const
228+void EventListenerManager::RemoveAllEventListeners()
156229 {
157- auto it = std::find(m_GlobalEventListeners.begin(), m_GlobalEventListeners.end(), pEventListener);
158- return it != m_GlobalEventListeners.end();
230+ m_Listeners.clear();
159231 }
160232
161-bool GlobalEventListenerManager::InvokeGlobalEventListeners(const Event& ev)
233+void EventListenerManager::InvokeEventListeners(const std::shared_ptr<EventHandler>& pTarget, EventID id, EventArgs* pArgs)
162234 {
163- for (auto&& pListener : m_GlobalEventListeners)
235+ for (auto it = m_Listeners.begin(); it != m_Listeners.end(); ++it)
164236 {
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)
166264 {
167- return true;
265+ it = m_Listeners.erase(it);
168266 }
169267 }
170-
171- return false;
172268 }
173269
174-void EventQueue::PostEvent(Event ev)
270+void EventManager::RemoveAllEvents()
175271 {
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();
177282 }
178283
179-void EventQueue::PostEventDelayed(Event ev, std::chrono::steady_clock::time_point time)
284+void EventManager::ProcessEvents()
180285 {
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())
186291 {
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();
188299 }
189- );
300+ }
190301
191- m_DelayedEvents.insert(it, {std::move(ev), time});
302+ ProcessEventQueueWithFuture();
303+ ProcessEventQueue();
304+ ProcessEventQueueWithTime();
305+ ProcessSentEvents();
192306 }
193307
194-void EventQueue::RemoveAllEvents()
308+std::variant<DesiredEventLoopTime, std::chrono::steady_clock::time_point> EventManager::GetDesiredEventLoopTime() const
195309 {
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+ }
198322 }
199323
200-void EventQueue::ProcessEvents()
324+void EventManager::TryInvokeQueuedEvent(QueuedEvent& ev)
201325 {
202- while (!m_Events.empty())
326+ if (!ev.pHandler)
203327 {
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);
208329 }
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);
209360
210- while (!m_DelayedEvents.empty() && m_DelayedEvents.front().FireTime <= std::chrono::steady_clock::now())
361+ while (i < length)
211362 {
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);
216366 }
217367 }
218368
219-std::optional<std::chrono::steady_clock::time_point> EventQueue::GetNextEventFireTime() const
369+void EventManager::ProcessEventQueueWithTime()
220370 {
221- if (!m_Events.empty())
371+ auto now = std::chrono::steady_clock::now();
372+
373+ while (!m_EventQueueWithTime.empty())
222374 {
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);
224395 }
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)
226401 {
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+
228425 }
229- else
426+}
427+
428+void EventManager::ProcessSentEvents()
429+{
430+ while (!m_SentEvents.empty())
230431 {
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+ }
232472 }
233473 }
234474
--- /dev/null
+++ b/src/renderer.cpp
@@ -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
--- a/src/uicontext.cpp
+++ /dev/null
@@ -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
--- a/src/widget.cpp
+++ b/src/widget.cpp
@@ -3,7 +3,242 @@
33
44 #include "sirius/widget.hpp"
55
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+
615 namespace Sirius
716 {
817
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+
9244 } // namespace Sirius