| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2021-03-28 11:16:33 +02:00
										 |  |  |  * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org> | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Redistribution and use in source and binary forms, with or without | 
					
						
							|  |  |  |  * modification, are permitted provided that the following conditions are met: | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 1. Redistributions of source code must retain the above copyright notice, this | 
					
						
							|  |  |  |  *    list of conditions and the following disclaimer. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 2. Redistributions in binary form must reproduce the above copyright notice, | 
					
						
							|  |  |  |  *    this list of conditions and the following disclaimer in the documentation | 
					
						
							|  |  |  |  *    and/or other materials provided with the distribution. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | 
					
						
							|  |  |  |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
					
						
							|  |  |  |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 
					
						
							|  |  |  |  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | 
					
						
							|  |  |  |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | 
					
						
							|  |  |  |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | 
					
						
							|  |  |  |  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | 
					
						
							|  |  |  |  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
					
						
							|  |  |  |  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
					
						
							|  |  |  |  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | #pragma once
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-14 22:29:06 +01:00
										 |  |  | #include <AK/Forward.h>
 | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  | #include <AK/HashMap.h>
 | 
					
						
							| 
									
										
										
										
											2019-08-17 11:26:19 +02:00
										 |  |  | #include <AK/IntrusiveList.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  | #include <AK/Noncopyable.h>
 | 
					
						
							|  |  |  | #include <AK/NonnullRefPtrVector.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-21 10:13:34 +02:00
										 |  |  | #include <AK/String.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-26 17:16:35 +02:00
										 |  |  | #include <AK/TypeCasts.h>
 | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | #include <AK/Weakable.h>
 | 
					
						
							| 
									
										
										
										
											2020-02-14 22:29:06 +01:00
										 |  |  | #include <LibCore/Forward.h>
 | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  | #include <LibCore/Property.h>
 | 
					
						
							| 
									
										
										
										
											2019-08-18 20:36:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | namespace Core { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  | class RPCClient; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-29 15:58:07 +01:00
										 |  |  | enum class TimerShouldFireWhenNotVisible { | 
					
						
							|  |  |  |     No = 0, | 
					
						
							|  |  |  |     Yes | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-21 10:13:34 +02:00
										 |  |  | #define C_OBJECT(klass)                                                \
 | 
					
						
							|  |  |  | public:                                                                \ | 
					
						
							|  |  |  |     virtual const char* class_name() const override { return #klass; } \ | 
					
						
							|  |  |  |     template<class... Args>                                            \ | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  |     static inline NonnullRefPtr<klass> construct(Args&&... args)       \ | 
					
						
							| 
									
										
										
										
											2019-09-21 10:13:34 +02:00
										 |  |  |     {                                                                  \ | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  |         return adopt(*new klass(forward<Args>(args)...));              \ | 
					
						
							| 
									
										
										
										
											2019-09-21 10:13:34 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-12-29 15:58:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define C_OBJECT_ABSTRACT(klass) \
 | 
					
						
							|  |  |  | public:                          \ | 
					
						
							|  |  |  |     virtual const char* class_name() const override { return #klass; } | 
					
						
							| 
									
										
										
										
											2019-07-25 19:49:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | class Object | 
					
						
							|  |  |  |     : public RefCounted<Object> | 
					
						
							|  |  |  |     , public Weakable<Object> { | 
					
						
							|  |  |  |     // NOTE: No C_OBJECT macro for Core::Object itself.
 | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-26 21:52:24 +02:00
										 |  |  |     AK_MAKE_NONCOPYABLE(Object); | 
					
						
							|  |  |  |     AK_MAKE_NONMOVABLE(Object); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-08-17 11:26:19 +02:00
										 |  |  |     IntrusiveListNode m_all_objects_list_node; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-16 16:04:19 -04:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     virtual ~Object(); | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-25 19:49:28 +02:00
										 |  |  |     virtual const char* class_name() const = 0; | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-10 20:33:53 +02:00
										 |  |  |     const String& name() const { return m_name; } | 
					
						
							|  |  |  |     void set_name(const StringView& name) { m_name = name; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     NonnullRefPtrVector<Object>& children() { return m_children; } | 
					
						
							|  |  |  |     const NonnullRefPtrVector<Object>& children() const { return m_children; } | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-27 03:52:19 +02:00
										 |  |  |     template<typename Callback> | 
					
						
							|  |  |  |     void for_each_child(Callback callback) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-09-22 00:17:53 +02:00
										 |  |  |         for (auto& child : m_children) { | 
					
						
							|  |  |  |             if (callback(child) == IterationDecision::Break) | 
					
						
							| 
									
										
										
										
											2019-05-27 03:52:19 +02:00
										 |  |  |                 return; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     template<typename T, typename Callback> | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |     void for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T>::value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							|  |  |  |     T* find_child_of_type_named(const String&) requires IsBaseOf<Object, T>::value; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							|  |  |  |     T* find_descendant_of_type_named(const String&) requires IsBaseOf<Object, T>::value; | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     bool is_ancestor_of(const Object&) const; | 
					
						
							| 
									
										
										
										
											2019-09-20 20:37:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     Object* parent() { return m_parent; } | 
					
						
							|  |  |  |     const Object* parent() const { return m_parent; } | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-29 15:58:07 +01:00
										 |  |  |     void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No); | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     void stop_timer(); | 
					
						
							|  |  |  |     bool has_timer() const { return m_timer_id; } | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     void add_child(Object&); | 
					
						
							|  |  |  |     void insert_child_before(Object& new_child, Object& before_child); | 
					
						
							|  |  |  |     void remove_child(Object&); | 
					
						
							| 
									
										
										
										
											2020-12-27 17:14:44 +01:00
										 |  |  |     void remove_all_children(); | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-28 11:16:33 +02:00
										 |  |  |     void set_event_filter(Function<bool(Core::Event&)>); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-19 00:01:02 +01:00
										 |  |  |     void dump_tree(int indent = 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     void deferred_invoke(Function<void(Object&)>); | 
					
						
							| 
									
										
										
										
											2019-04-07 14:36:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-02-25 21:10:47 +01:00
										 |  |  |     void save_to(JsonObject&); | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     bool set_property(const StringView& name, const JsonValue& value); | 
					
						
							| 
									
										
										
										
											2021-01-04 13:41:13 +01:00
										 |  |  |     JsonValue property(const StringView& name) const; | 
					
						
							| 
									
										
										
										
											2020-12-30 13:58:38 +03:30
										 |  |  |     const HashMap<String, NonnullOwnPtr<Property>>& properties() const { return m_properties; } | 
					
						
							| 
									
										
										
										
											2019-08-18 20:36:37 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     static IntrusiveList<Object, &Object::m_all_objects_list_node>& all_objects(); | 
					
						
							| 
									
										
										
										
											2019-08-17 11:26:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     void dispatch_event(Core::Event&, Object* stay_within = nullptr); | 
					
						
							| 
									
										
										
										
											2019-09-20 20:37:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-09-22 00:41:01 +02:00
										 |  |  |     void remove_from_parent() | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         if (m_parent) | 
					
						
							|  |  |  |             m_parent->remove_child(*this); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-23 07:13:09 +01:00
										 |  |  |     template<class T, class... Args> | 
					
						
							| 
									
										
										
										
											2020-03-04 19:07:55 +01:00
										 |  |  |     inline T& add(Args&&... args) | 
					
						
							| 
									
										
										
										
											2020-02-23 07:13:09 +01:00
										 |  |  |     { | 
					
						
							| 
									
										
										
										
											2020-03-04 19:07:55 +01:00
										 |  |  |         auto child = T::construct(forward<Args>(args)...); | 
					
						
							|  |  |  |         add_child(*child); | 
					
						
							|  |  |  |         return child; | 
					
						
							| 
									
										
										
										
											2020-02-23 07:13:09 +01:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-29 15:58:07 +01:00
										 |  |  |     virtual bool is_visible_for_timer_purposes() const; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  |     bool is_being_inspected() const { return m_inspector_count; } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void increment_inspector_count(Badge<RPCClient>); | 
					
						
							|  |  |  |     void decrement_inspector_count(Badge<RPCClient>); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 16:12:06 +01:00
										 |  |  | protected: | 
					
						
							| 
									
										
										
										
											2021-01-01 16:02:16 +01:00
										 |  |  |     explicit Object(Object* parent = nullptr); | 
					
						
							| 
									
										
										
										
											2019-07-25 19:49:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  |     void register_property(const String& name, Function<JsonValue()> getter, Function<bool(const JsonValue&)> setter = nullptr); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-28 11:24:22 +02:00
										 |  |  |     virtual void event(Core::Event&); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     virtual void timer_event(TimerEvent&); | 
					
						
							|  |  |  |     virtual void custom_event(CustomEvent&); | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-27 09:31:46 +02:00
										 |  |  |     // NOTE: You may get child events for children that are not yet fully constructed!
 | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     virtual void child_event(ChildEvent&); | 
					
						
							| 
									
										
										
										
											2019-07-27 09:31:46 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 17:16:35 +02:00
										 |  |  |     virtual void did_begin_inspection() { } | 
					
						
							|  |  |  |     virtual void did_end_inspection() { } | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-15 16:12:06 +01:00
										 |  |  | private: | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     Object* m_parent { nullptr }; | 
					
						
							| 
									
										
										
										
											2019-07-10 20:33:53 +02:00
										 |  |  |     String m_name; | 
					
						
							| 
									
										
										
										
											2019-01-31 17:31:23 +01:00
										 |  |  |     int m_timer_id { 0 }; | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  |     unsigned m_inspector_count { 0 }; | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  |     HashMap<String, NonnullOwnPtr<Property>> m_properties; | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  |     NonnullRefPtrVector<Object> m_children; | 
					
						
							| 
									
										
										
										
											2021-03-28 11:16:33 +02:00
										 |  |  |     Function<bool(Core::Event&)> m_event_filter; | 
					
						
							| 
									
										
										
										
											2019-01-20 04:49:48 +01:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-05-27 04:06:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-15 21:07:36 +02:00
										 |  |  | template<> | 
					
						
							| 
									
										
										
										
											2021-01-09 01:00:22 +01:00
										 |  |  | struct AK::Formatter<Core::Object> : AK::Formatter<FormatString> { | 
					
						
							|  |  |  |     void format(FormatBuilder& builder, const Core::Object& value) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return AK::Formatter<FormatString>::format(builder, "{}({})", value.class_name(), &value); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-10-15 21:07:36 +02:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-26 17:16:35 +02:00
										 |  |  | namespace Core { | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | template<typename T, typename Callback> | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  | inline void Object::for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T>::value | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     for_each_child([&](auto& child) { | 
					
						
							|  |  |  |         if (auto* child_as_t = dynamic_cast<T*>(&child); child_as_t) | 
					
						
							|  |  |  |             return callback(*child_as_t); | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | T* Object::find_child_of_type_named(const String& name) requires IsBaseOf<Object, T>::value | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     T* found_child = nullptr; | 
					
						
							|  |  |  |     for_each_child_of_type<T>([&](auto& child) { | 
					
						
							|  |  |  |         if (child.name() == name) { | 
					
						
							|  |  |  |             found_child = &child; | 
					
						
							|  |  |  |             return IterationDecision::Break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     return found_child; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							|  |  |  | T* Object::find_descendant_of_type_named(const String& name) requires IsBaseOf<Object, T>::value | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |     auto* this_as_t = dynamic_cast<T*>(this); | 
					
						
							|  |  |  |     if (this_as_t && this->name() == name) | 
					
						
							|  |  |  |         return this_as_t; | 
					
						
							|  |  |  |     T* found_child = nullptr; | 
					
						
							| 
									
										
										
										
											2019-05-28 11:53:16 +02:00
										 |  |  |     for_each_child([&](auto& child) { | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |         found_child = child.template find_descendant_of_type_named<T>(name); | 
					
						
							|  |  |  |         if (found_child) | 
					
						
							|  |  |  |             return IterationDecision::Break; | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |     return found_child; | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2019-07-14 10:59:26 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  | #define REGISTER_INT_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     register_property(                                       \ | 
					
						
							|  |  |  |         property_name,                                       \ | 
					
						
							|  |  |  |         [this] { return this->getter(); },                   \ | 
					
						
							|  |  |  |         [this](auto& value) {                                \ | 
					
						
							|  |  |  |             this->setter(value.template to_number<int>());   \ | 
					
						
							|  |  |  |             return true;                                     \ | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_BOOL_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     register_property(                                        \ | 
					
						
							|  |  |  |         property_name,                                        \ | 
					
						
							|  |  |  |         [this] { return this->getter(); },                    \ | 
					
						
							|  |  |  |         [this](auto& value) {                                 \ | 
					
						
							|  |  |  |             this->setter(value.to_bool());                    \ | 
					
						
							|  |  |  |             return true;                                      \ | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_STRING_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     register_property(                                          \ | 
					
						
							|  |  |  |         property_name,                                          \ | 
					
						
							|  |  |  |         [this] { return this->getter(); },                      \ | 
					
						
							|  |  |  |         [this](auto& value) {                                   \ | 
					
						
							|  |  |  |             this->setter(value.to_string());                    \ | 
					
						
							|  |  |  |             return true;                                        \ | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_READONLY_STRING_PROPERTY(property_name, getter) \
 | 
					
						
							|  |  |  |     register_property(                                           \ | 
					
						
							|  |  |  |         property_name,                                           \ | 
					
						
							|  |  |  |         [this] { return this->getter(); },                       \ | 
					
						
							| 
									
										
										
										
											2021-01-10 16:29:28 -07:00
										 |  |  |         {}); | 
					
						
							| 
									
										
										
										
											2020-09-15 21:33:37 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_RECT_PROPERTY(property_name, getter, setter)          \
 | 
					
						
							|  |  |  |     register_property(                                                 \ | 
					
						
							|  |  |  |         property_name,                                                 \ | 
					
						
							|  |  |  |         [this] {                                                       \ | 
					
						
							|  |  |  |             auto rect = this->getter();                                \ | 
					
						
							|  |  |  |             JsonObject rect_object;                                    \ | 
					
						
							|  |  |  |             rect_object.set("x", rect.x());                            \ | 
					
						
							|  |  |  |             rect_object.set("y", rect.y());                            \ | 
					
						
							|  |  |  |             rect_object.set("width", rect.width());                    \ | 
					
						
							|  |  |  |             rect_object.set("height", rect.height());                  \ | 
					
						
							|  |  |  |             return rect_object;                                        \ | 
					
						
							|  |  |  |         },                                                             \ | 
					
						
							|  |  |  |         [this](auto& value) {                                          \ | 
					
						
							|  |  |  |             if (!value.is_object())                                    \ | 
					
						
							|  |  |  |                 return false;                                          \ | 
					
						
							|  |  |  |             Gfx::IntRect rect;                                         \ | 
					
						
							|  |  |  |             rect.set_x(value.as_object().get("x").to_i32());           \ | 
					
						
							|  |  |  |             rect.set_y(value.as_object().get("y").to_i32());           \ | 
					
						
							|  |  |  |             rect.set_width(value.as_object().get("width").to_i32());   \ | 
					
						
							|  |  |  |             rect.set_height(value.as_object().get("height").to_i32()); \ | 
					
						
							|  |  |  |             setter(rect);                                              \ | 
					
						
							|  |  |  |             return true;                                               \ | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_SIZE_PROPERTY(property_name, getter, setter)          \
 | 
					
						
							|  |  |  |     register_property(                                                 \ | 
					
						
							|  |  |  |         property_name,                                                 \ | 
					
						
							|  |  |  |         [this] {                                                       \ | 
					
						
							|  |  |  |             auto size = this->getter();                                \ | 
					
						
							|  |  |  |             JsonObject size_object;                                    \ | 
					
						
							|  |  |  |             size_object.set("width", size.width());                    \ | 
					
						
							|  |  |  |             size_object.set("height", size.height());                  \ | 
					
						
							|  |  |  |             return size_object;                                        \ | 
					
						
							|  |  |  |         },                                                             \ | 
					
						
							|  |  |  |         [this](auto& value) {                                          \ | 
					
						
							|  |  |  |             if (!value.is_object())                                    \ | 
					
						
							|  |  |  |                 return false;                                          \ | 
					
						
							|  |  |  |             Gfx::IntSize size;                                         \ | 
					
						
							|  |  |  |             size.set_width(value.as_object().get("width").to_i32());   \ | 
					
						
							|  |  |  |             size.set_height(value.as_object().get("height").to_i32()); \ | 
					
						
							|  |  |  |             setter(size);                                              \ | 
					
						
							|  |  |  |             return true;                                               \ | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 12:58:21 +01:00
										 |  |  | #define REGISTER_ENUM_PROPERTY(property_name, getter, setter, EnumType, ...) \
 | 
					
						
							|  |  |  |     register_property(                                                       \ | 
					
						
							|  |  |  |         property_name,                                                       \ | 
					
						
							|  |  |  |         [this]() -> JsonValue {                                              \ | 
					
						
							|  |  |  |             struct {                                                         \ | 
					
						
							|  |  |  |                 EnumType enum_value;                                         \ | 
					
						
							|  |  |  |                 String string_value;                                         \ | 
					
						
							|  |  |  |             } options[] = { __VA_ARGS__ };                                   \ | 
					
						
							|  |  |  |             auto enum_value = getter();                                      \ | 
					
						
							|  |  |  |             for (size_t i = 0; i < array_size(options); ++i) {               \ | 
					
						
							|  |  |  |                 auto& option = options[i];                                   \ | 
					
						
							|  |  |  |                 if (enum_value == option.enum_value)                         \ | 
					
						
							|  |  |  |                     return option.string_value;                              \ | 
					
						
							|  |  |  |             }                                                                \ | 
					
						
							|  |  |  |             return JsonValue();                                              \ | 
					
						
							|  |  |  |         },                                                                   \ | 
					
						
							|  |  |  |         [this](auto& value) {                                                \ | 
					
						
							|  |  |  |             struct {                                                         \ | 
					
						
							|  |  |  |                 EnumType enum_value;                                         \ | 
					
						
							|  |  |  |                 String string_value;                                         \ | 
					
						
							|  |  |  |             } options[] = { __VA_ARGS__ };                                   \ | 
					
						
							| 
									
										
										
										
											2021-03-18 20:01:09 +03:00
										 |  |  |             if (!value.is_string())                                          \ | 
					
						
							|  |  |  |                 return false;                                                \ | 
					
						
							| 
									
										
										
										
											2020-12-28 12:58:21 +01:00
										 |  |  |             auto string_value = value.as_string();                           \ | 
					
						
							|  |  |  |             for (size_t i = 0; i < array_size(options); ++i) {               \ | 
					
						
							|  |  |  |                 auto& option = options[i];                                   \ | 
					
						
							|  |  |  |                 if (string_value == option.string_value) {                   \ | 
					
						
							|  |  |  |                     setter(option.enum_value);                               \ | 
					
						
							|  |  |  |                     return true;                                             \ | 
					
						
							|  |  |  |                 }                                                            \ | 
					
						
							|  |  |  |             }                                                                \ | 
					
						
							|  |  |  |             return false;                                                    \ | 
					
						
							|  |  |  |         }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-28 20:45:04 +01:00
										 |  |  | #define REGISTER_TEXT_ALIGNMENT_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     REGISTER_ENUM_PROPERTY(                                             \ | 
					
						
							|  |  |  |         property_name, getter, setter, Gfx::TextAlignment,              \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::TopLeft, "TopLeft" },                     \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::CenterLeft, "CenterLeft" },               \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::Center, "Center" },                       \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::CenterRight, "CenterRight" },             \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::TopRight, "TopRight" },                   \ | 
					
						
							|  |  |  |         { Gfx::TextAlignment::BottomRight, "BottomRight" }) | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | } |