/* * Copyright (c) 2018-2021, Andreas Kling * Copyright (c) 2022, the SerenityOS developers. * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace Core { enum class TimerShouldFireWhenNotVisible { No = 0, Yes }; #define C_OBJECT(klass) \ public: \ virtual StringView class_name() const override \ { \ return #klass##sv; \ } \ template \ static NonnullRefPtr construct(Args&&... args) \ { \ return adopt_ref(*new Klass(::forward(args)...)); \ } \ template \ static ErrorOr> try_create(Args&&... args) \ { \ return adopt_nonnull_ref_or_enomem(new (nothrow) Klass(::forward(args)...)); \ } #define C_OBJECT_ABSTRACT(klass) \ public: \ virtual StringView class_name() const override \ { \ return #klass##sv; \ } class EventReceiver : public RefCounted , public Weakable { // NOTE: No C_OBJECT macro for Core::EventReceiver itself. AK_MAKE_NONCOPYABLE(EventReceiver); AK_MAKE_NONMOVABLE(EventReceiver); public: virtual ~EventReceiver(); virtual StringView class_name() const = 0; template bool fast_is() const = delete; virtual bool is_widget() const { return false; } DeprecatedString const& name() const { return m_name; } void set_name(DeprecatedString name) { m_name = move(name); } Vector>& children() { return m_children; } Vector> const& children() const { return m_children; } template void for_each_child(Callback callback) { for (auto& child : m_children) { if (callback(*child) == IterationDecision::Break) return; } } template void for_each_child_of_type(Callback callback) requires IsBaseOf; template T* find_child_of_type_named(StringView) requires IsBaseOf; template ALWAYS_INLINE T* find_child_of_type_named(char const (&string_literal)[N]) requires IsBaseOf { return find_child_of_type_named(StringView { string_literal, N - 1 }); } template T* find_descendant_of_type_named(StringView) requires IsBaseOf; template ALWAYS_INLINE T* find_descendant_of_type_named(char const (&string_literal)[N]) requires IsBaseOf { return find_descendant_of_type_named(StringView { string_literal, N - 1 }); } bool is_ancestor_of(EventReceiver const&) const; EventReceiver* parent() { return m_parent; } EventReceiver const* parent() const { return m_parent; } void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No); void stop_timer(); bool has_timer() const { return m_timer_id; } ErrorOr try_add_child(EventReceiver&); void add_child(EventReceiver&); void insert_child_before(EventReceiver& new_child, EventReceiver& before_child); void remove_child(EventReceiver&); void remove_all_children(); void set_event_filter(Function); void deferred_invoke(Function); void dispatch_event(Core::Event&, EventReceiver* stay_within = nullptr); void remove_from_parent() { if (m_parent) m_parent->remove_child(*this); } template inline T& add(Args&&... args) { auto child = T::construct(forward(args)...); add_child(*child); return child; } template inline ErrorOr> try_add(Args&&... args) { auto child = TRY(T::try_create(forward(args)...)); TRY(try_add_child(*child)); return child; } virtual bool is_visible_for_timer_purposes() const; protected: explicit EventReceiver(EventReceiver* parent = nullptr); virtual void event(Core::Event&); virtual void timer_event(TimerEvent&); virtual void custom_event(CustomEvent&); // NOTE: You may get child events for children that are not yet fully constructed! virtual void child_event(ChildEvent&); private: EventReceiver* m_parent { nullptr }; DeprecatedString m_name; int m_timer_id { 0 }; Vector> m_children; Function m_event_filter; }; } template<> struct AK::Formatter : AK::Formatter { ErrorOr format(FormatBuilder& builder, Core::EventReceiver const& value) { return AK::Formatter::format(builder, "{}({})"sv, value.class_name(), &value); } }; namespace Core { template inline void EventReceiver::for_each_child_of_type(Callback callback) requires IsBaseOf { for_each_child([&](auto& child) { if (is(child)) return callback(static_cast(child)); return IterationDecision::Continue; }); } template T* EventReceiver::find_child_of_type_named(StringView name) requires IsBaseOf { T* found_child = nullptr; for_each_child_of_type([&](auto& child) { if (child.name() == name) { found_child = &child; return IterationDecision::Break; } return IterationDecision::Continue; }); return found_child; } template T* EventReceiver::find_descendant_of_type_named(StringView name) requires IsBaseOf { if (is(*this) && this->name() == name) { return static_cast(this); } T* found_child = nullptr; for_each_child([&](auto& child) { found_child = child.template find_descendant_of_type_named(name); if (found_child) return IterationDecision::Break; return IterationDecision::Continue; }); return found_child; } }