| 
									
										
										
										
											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> | 
					
						
							| 
									
										
										
										
											2022-02-26 09:09:45 -07:00
										 |  |  |  * Copyright (c) 2022, the SerenityOS developers. | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2021-04-22 01:24:48 -07:00
										 |  |  |  * SPDX-License-Identifier: BSD-2-Clause | 
					
						
							| 
									
										
										
										
											2020-01-18 09:38:21 +01:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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>
 | 
					
						
							| 
									
										
										
										
											2021-05-19 14:35:34 +02:00
										 |  |  | #include <AK/OwnPtr.h>
 | 
					
						
							| 
									
										
										
										
											2019-09-21 10:13:34 +02:00
										 |  |  | #include <AK/String.h>
 | 
					
						
							| 
									
										
										
										
											2022-03-16 18:26:15 -06:00
										 |  |  | #include <AK/StringView.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 { | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-10-25 20:20:36 -05:00
										 |  |  | #define REGISTER_ABSTRACT_CORE_OBJECT(namespace_, class_name)                                                                 \
 | 
					
						
							|  |  |  |     namespace Core {                                                                                                          \ | 
					
						
							|  |  |  |     namespace Registration {                                                                                                  \ | 
					
						
							|  |  |  |     Core::ObjectClassRegistration registration_##class_name(#namespace_ "::" #class_name, []() { return RefPtr<Object>(); }); \ | 
					
						
							|  |  |  |     }                                                                                                                         \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  | #define REGISTER_CORE_OBJECT(namespace_, class_name)                                                                                             \
 | 
					
						
							|  |  |  |     namespace Core {                                                                                                                             \ | 
					
						
							|  |  |  |     namespace Registration {                                                                                                                     \ | 
					
						
							|  |  |  |     Core::ObjectClassRegistration registration_##class_name(#namespace_ "::" #class_name, []() { return namespace_::class_name::construct(); }); \ | 
					
						
							|  |  |  |     }                                                                                                                                            \ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class ObjectClassRegistration { | 
					
						
							|  |  |  |     AK_MAKE_NONCOPYABLE(ObjectClassRegistration); | 
					
						
							|  |  |  |     AK_MAKE_NONMOVABLE(ObjectClassRegistration); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2021-10-25 20:19:28 -05:00
										 |  |  |     ObjectClassRegistration(StringView class_name, Function<RefPtr<Object>()> factory, ObjectClassRegistration* parent_class = nullptr); | 
					
						
							| 
									
										
										
										
											2022-02-26 09:09:45 -07:00
										 |  |  |     ~ObjectClassRegistration() = default; | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-16 18:26:15 -06:00
										 |  |  |     StringView class_name() const { return m_class_name; } | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  |     const ObjectClassRegistration* parent_class() const { return m_parent_class; } | 
					
						
							| 
									
										
										
										
											2021-10-25 20:19:28 -05:00
										 |  |  |     RefPtr<Object> construct() const { return m_factory(); } | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  |     bool is_derived_from(const ObjectClassRegistration& base_class) const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     static void for_each(Function<void(const ObjectClassRegistration&)>); | 
					
						
							| 
									
										
										
										
											2021-08-28 02:38:23 -06:00
										 |  |  |     static const ObjectClassRegistration* find(StringView class_name); | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2021-08-28 02:38:23 -06:00
										 |  |  |     StringView m_class_name; | 
					
						
							| 
									
										
										
										
											2021-10-25 20:19:28 -05:00
										 |  |  |     Function<RefPtr<Object>()> m_factory; | 
					
						
							| 
									
										
										
										
											2021-04-04 15:40:34 -06:00
										 |  |  |     ObjectClassRegistration* m_parent_class { nullptr }; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 22:42:11 +02:00
										 |  |  | class InspectorServerConnection; | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-29 15:58:07 +01:00
										 |  |  | enum class TimerShouldFireWhenNotVisible { | 
					
						
							|  |  |  |     No = 0, | 
					
						
							|  |  |  |     Yes | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-23 14:17:05 +01:00
										 |  |  | #define C_OBJECT(klass)                                                                  \
 | 
					
						
							|  |  |  | public:                                                                                  \ | 
					
						
							| 
									
										
										
										
											2022-03-16 18:26:15 -06:00
										 |  |  |     virtual StringView class_name() const override { return #klass; }                    \ | 
					
						
							| 
									
										
										
										
											2021-11-23 14:17:05 +01:00
										 |  |  |     template<typename Klass = klass, class... Args>                                      \ | 
					
						
							|  |  |  |     static NonnullRefPtr<klass> construct(Args&&... args)                                \ | 
					
						
							|  |  |  |     {                                                                                    \ | 
					
						
							|  |  |  |         return adopt_ref(*new Klass(forward<Args>(args)...));                            \ | 
					
						
							|  |  |  |     }                                                                                    \ | 
					
						
							|  |  |  |     template<typename Klass = klass, class... Args>                                      \ | 
					
						
							|  |  |  |     static ErrorOr<NonnullRefPtr<klass>> try_create(Args&&... args)                      \ | 
					
						
							|  |  |  |     {                                                                                    \ | 
					
						
							|  |  |  |         return adopt_nonnull_ref_or_enomem(new (nothrow) 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:                          \ | 
					
						
							| 
									
										
										
										
											2022-03-16 18:26:15 -06:00
										 |  |  |     virtual StringView 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 16:33:24 +04:30
										 |  |  |     IntrusiveListNode<Object> m_all_objects_list_node; | 
					
						
							| 
									
										
										
										
											2019-08-17 11:26:19 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-16 18:26:15 -06:00
										 |  |  |     virtual StringView 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; } | 
					
						
							| 
									
										
										
										
											2021-04-16 19:59:31 +02:00
										 |  |  |     void set_name(String name) { m_name = move(name); } | 
					
						
							| 
									
										
										
										
											2019-07-10 20:33:53 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-04-10 18:29:06 +04:30
										 |  |  |     void for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T>; | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2021-04-10 18:29:06 +04:30
										 |  |  |     T* find_child_of_type_named(const String&) requires IsBaseOf<Object, T>; | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template<typename T> | 
					
						
							| 
									
										
										
										
											2021-04-10 18:29:06 +04:30
										 |  |  |     T* find_descendant_of_type_named(const String&) requires IsBaseOf<Object, T>; | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-24 13:09:51 +01:00
										 |  |  |     ErrorOr<void> try_add_child(Object&); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-08-30 10:43:28 +00:00
										 |  |  |     void deferred_invoke(Function<void()>); | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-16 19:59:31 +02:00
										 |  |  |     bool set_property(String const& name, const JsonValue& value); | 
					
						
							|  |  |  |     JsonValue property(String const& 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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-09 16:30:59 +04:30
										 |  |  |     static IntrusiveList<&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
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-11-24 13:09:51 +01:00
										 |  |  |     template<class T, class... Args> | 
					
						
							|  |  |  |     inline ErrorOr<NonnullRefPtr<T>> try_add(Args&&... args) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         auto child = TRY(T::try_create(forward<Args>(args)...)); | 
					
						
							|  |  |  |         TRY(try_add_child(*child)); | 
					
						
							|  |  |  |         return child; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-13 22:42:11 +02:00
										 |  |  |     void increment_inspector_count(Badge<InspectorServerConnection>); | 
					
						
							|  |  |  |     void decrement_inspector_count(Badge<InspectorServerConnection>); | 
					
						
							| 
									
										
										
										
											2020-03-05 14:40:47 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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> { | 
					
						
							| 
									
										
										
										
											2021-11-16 01:15:21 +01:00
										 |  |  |     ErrorOr<void> format(FormatBuilder& builder, const Core::Object& value) | 
					
						
							| 
									
										
										
										
											2021-01-09 01:00:22 +01:00
										 |  |  |     { | 
					
						
							|  |  |  |         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-04-10 18:29:06 +04:30
										 |  |  | inline void Object::for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T> | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     for_each_child([&](auto& child) { | 
					
						
							| 
									
										
										
										
											2021-04-17 23:01:24 +02:00
										 |  |  |         if (is<T>(child)) | 
					
						
							|  |  |  |             return callback(static_cast<T&>(child)); | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |         return IterationDecision::Continue; | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | template<typename T> | 
					
						
							| 
									
										
										
										
											2021-04-10 18:29:06 +04:30
										 |  |  | T* Object::find_child_of_type_named(const String& name) requires IsBaseOf<Object, T> | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  | { | 
					
						
							|  |  |  |     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> | 
					
						
							| 
									
										
										
										
											2021-04-17 23:01:24 +02:00
										 |  |  | T* Object::find_descendant_of_type_named(String const& name) requires IsBaseOf<Object, T> | 
					
						
							| 
									
										
										
										
											2019-05-27 04:18:24 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2021-04-17 23:01:24 +02:00
										 |  |  |     if (is<T>(*this) && this->name() == name) { | 
					
						
							|  |  |  |         return static_cast<T*>(this); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-01 00:46:51 -07:00
										 |  |  |     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::Center, "Center" },                       \ | 
					
						
							| 
									
										
										
										
											2021-05-21 01:03:02 +01:00
										 |  |  |         { Gfx::TextAlignment::CenterLeft, "CenterLeft" },               \ | 
					
						
							| 
									
										
										
										
											2020-12-28 20:45:04 +01:00
										 |  |  |         { Gfx::TextAlignment::CenterRight, "CenterRight" },             \ | 
					
						
							| 
									
										
										
										
											2022-03-25 12:30:48 +01:00
										 |  |  |         { Gfx::TextAlignment::TopCenter, "TopCenter" },                 \ | 
					
						
							| 
									
										
										
										
											2021-05-21 01:03:02 +01:00
										 |  |  |         { Gfx::TextAlignment::TopLeft, "TopLeft" },                     \ | 
					
						
							| 
									
										
										
										
											2020-12-28 20:45:04 +01:00
										 |  |  |         { Gfx::TextAlignment::TopRight, "TopRight" },                   \ | 
					
						
							| 
									
										
										
										
											2022-03-25 12:30:48 +01:00
										 |  |  |         { Gfx::TextAlignment::BottomCenter, "BottomCenter" },           \ | 
					
						
							| 
									
										
										
										
											2021-05-21 01:03:02 +01:00
										 |  |  |         { Gfx::TextAlignment::BottomLeft, "BottomLeft" },               \ | 
					
						
							| 
									
										
										
										
											2020-12-28 20:45:04 +01:00
										 |  |  |         { Gfx::TextAlignment::BottomRight, "BottomRight" }) | 
					
						
							| 
									
										
										
										
											2021-03-22 19:51:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_FONT_WEIGHT_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     REGISTER_ENUM_PROPERTY(                                          \ | 
					
						
							|  |  |  |         property_name, getter, setter, unsigned,                     \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Thin, "Thin" },                           \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::ExtraLight, "ExtraLight" },               \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Light, "Light" },                         \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Regular, "Regular" },                     \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Medium, "Medium" },                       \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::SemiBold, "SemiBold" },                   \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Bold, "Bold" },                           \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::ExtraBold, "ExtraBold" },                 \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::Black, "Black" },                         \ | 
					
						
							|  |  |  |         { Gfx::FontWeight::ExtraBlack, "ExtraBlack" }) | 
					
						
							| 
									
										
										
										
											2021-07-29 20:06:55 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #define REGISTER_TEXT_WRAPPING_PROPERTY(property_name, getter, setter) \
 | 
					
						
							|  |  |  |     REGISTER_ENUM_PROPERTY(                                            \ | 
					
						
							|  |  |  |         property_name, getter, setter, Gfx::TextWrapping,              \ | 
					
						
							|  |  |  |         { Gfx::TextWrapping::Wrap, "Wrap" },                           \ | 
					
						
							|  |  |  |         { Gfx::TextWrapping::DontWrap, "DontWrap" }) | 
					
						
							| 
									
										
										
										
											2020-02-02 12:34:39 +01:00
										 |  |  | } |