diff options
author | Tom <tomut@yahoo.com> | 2021-04-04 15:40:34 -0600 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-05-06 08:50:39 +0200 |
commit | 3aaffa2c47e39583848cfe9b7b9f846e5119fe1b (patch) | |
tree | eb5a5535bec0952a95b19b9c494d9c6049896107 /Userland | |
parent | 6e101adc28c9c682f023386831d632a477768cb8 (diff) | |
download | serenity-3aaffa2c47e39583848cfe9b7b9f846e5119fe1b.zip |
LibGUI: Move widget registration to LibCore
This also moves Widget::load_from_json into Core::Object as a virtual
function in order to allow loading non-widget objects in GML (e.g.
BoxLayout).
Co-authored-by: Gunnar Beutner <gbeutner@serenityos.org>
Diffstat (limited to 'Userland')
-rw-r--r-- | Userland/Applications/SpaceAnalyzer/TreeMapWidget.cpp | 4 | ||||
-rw-r--r-- | Userland/DevTools/HackStudio/HackStudioWidget.cpp | 8 | ||||
-rw-r--r-- | Userland/DevTools/HackStudio/Tool.h | 1 | ||||
-rw-r--r-- | Userland/DevTools/HackStudio/WidgetTool.h | 4 | ||||
-rw-r--r-- | Userland/DevTools/Playground/GMLAutocompleteProvider.cpp | 30 | ||||
-rw-r--r-- | Userland/DevTools/Playground/main.cpp | 2 | ||||
-rw-r--r-- | Userland/Libraries/LibCore/Forward.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibCore/Object.cpp | 40 | ||||
-rw-r--r-- | Userland/Libraries/LibCore/Object.h | 31 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/BoxLayout.cpp | 4 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Forward.h | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Widget.cpp | 55 | ||||
-rw-r--r-- | Userland/Libraries/LibGUI/Widget.h | 38 |
13 files changed, 134 insertions, 85 deletions
diff --git a/Userland/Applications/SpaceAnalyzer/TreeMapWidget.cpp b/Userland/Applications/SpaceAnalyzer/TreeMapWidget.cpp index 2bc94a01e0..00cdf6ee0a 100644 --- a/Userland/Applications/SpaceAnalyzer/TreeMapWidget.cpp +++ b/Userland/Applications/SpaceAnalyzer/TreeMapWidget.cpp @@ -11,10 +11,10 @@ #include <LibGfx/Font.h> #include <WindowServer/WindowManager.h> -namespace SpaceAnalyzer { - REGISTER_WIDGET(SpaceAnalyzer, TreeMapWidget) +namespace SpaceAnalyzer { + TreeMapWidget::TreeMapWidget() : m_viewpoint(0) { diff --git a/Userland/DevTools/HackStudio/HackStudioWidget.cpp b/Userland/DevTools/HackStudio/HackStudioWidget.cpp index 5082480f96..24214c5acc 100644 --- a/Userland/DevTools/HackStudio/HackStudioWidget.cpp +++ b/Userland/DevTools/HackStudio/HackStudioWidget.cpp @@ -799,7 +799,11 @@ void HackStudioWidget::create_form_editor(GUI::Widget& parent) form_widgets_toolbar.add_action(cursor_tool_action); - GUI::WidgetClassRegistration::for_each([&, this](const GUI::WidgetClassRegistration& reg) { + auto& widget_class = *Core::ObjectClassRegistration::find("GUI::Widget"); + + Core::ObjectClassRegistration::for_each([&, this](const Core::ObjectClassRegistration& reg) { + if (!reg.is_derived_from(widget_class)) + return; constexpr size_t gui_namespace_prefix_length = sizeof("GUI::") - 1; auto icon_path = String::formatted("/res/icons/hackstudio/G{}.png", reg.class_name().substring(gui_namespace_prefix_length, reg.class_name().length() - gui_namespace_prefix_length)); @@ -808,7 +812,7 @@ void HackStudioWidget::create_form_editor(GUI::Widget& parent) auto action = GUI::Action::create_checkable(reg.class_name(), Gfx::Bitmap::load_from_file(icon_path), [®, this](auto&) { m_form_editor_widget->set_tool(make<WidgetTool>(*m_form_editor_widget, reg)); - auto widget = reg.construct(); + auto widget = static_ptr_cast<Widget>(reg.construct()); m_form_editor_widget->form_widget().add_child(widget); widget->set_relative_rect(30, 30, 30, 30); m_form_editor_widget->model().update(); diff --git a/Userland/DevTools/HackStudio/Tool.h b/Userland/DevTools/HackStudio/Tool.h index d6ca633ce6..d4899182f6 100644 --- a/Userland/DevTools/HackStudio/Tool.h +++ b/Userland/DevTools/HackStudio/Tool.h @@ -7,6 +7,7 @@ #pragma once #include <AK/Noncopyable.h> +#include <LibCore/Forward.h> #include <LibGUI/Forward.h> namespace HackStudio { diff --git a/Userland/DevTools/HackStudio/WidgetTool.h b/Userland/DevTools/HackStudio/WidgetTool.h index c5e506df99..0421c8416d 100644 --- a/Userland/DevTools/HackStudio/WidgetTool.h +++ b/Userland/DevTools/HackStudio/WidgetTool.h @@ -12,7 +12,7 @@ namespace HackStudio { class WidgetTool final : public Tool { public: - explicit WidgetTool(FormEditorWidget& editor, const GUI::WidgetClassRegistration& meta_class) + explicit WidgetTool(FormEditorWidget& editor, const Core::ObjectClassRegistration& meta_class) : Tool(editor) , m_meta_class(meta_class) { @@ -26,7 +26,7 @@ private: virtual void on_mousemove(GUI::MouseEvent&) override; virtual void on_keydown(GUI::KeyEvent&) override; - const GUI::WidgetClassRegistration& m_meta_class; + const Core::ObjectClassRegistration& m_meta_class; }; } diff --git a/Userland/DevTools/Playground/GMLAutocompleteProvider.cpp b/Userland/DevTools/Playground/GMLAutocompleteProvider.cpp index c5da1523cc..37c78e7fa4 100644 --- a/Userland/DevTools/Playground/GMLAutocompleteProvider.cpp +++ b/Userland/DevTools/Playground/GMLAutocompleteProvider.cpp @@ -102,6 +102,8 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> state = previous_states.take_last(); } + auto& widget_class = *Core::ObjectClassRegistration::find("GUI::Widget"); + Vector<GUI::AutocompleteProvider::Entry> class_entries, identifier_entries; switch (state) { case Free: @@ -110,7 +112,9 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> // Nothing to put here. break; } - GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) { + Core::ObjectClassRegistration::for_each([&](const Core::ObjectClassRegistration& registration) { + if (!registration.is_derived_from(widget_class)) + return; class_entries.empend(String::formatted("@{}", registration.class_name()), 0u); }); break; @@ -122,12 +126,14 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> // TODO: Suggest braces? break; } - GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) { + Core::ObjectClassRegistration::for_each([&](const Core::ObjectClassRegistration& registration) { + if (!registration.is_derived_from(widget_class)) + return; if (registration.class_name().starts_with(class_names.last())) identifier_entries.empend(registration.class_name(), class_names.last().length()); }); break; - case InIdentifier: + case InIdentifier: { if (class_names.is_empty()) break; if (last_seen_token && last_seen_token->m_end.column + 1 != cursor.column() && last_seen_token->m_end.line == cursor.line()) { @@ -135,7 +141,8 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> // TODO: Maybe suggest a colon? break; } - if (auto registration = GUI::WidgetClassRegistration::find(class_names.last())) { + auto registration = Core::ObjectClassRegistration::find(class_names.last()); + if (registration && registration->is_derived_from(widget_class)) { auto instance = registration->construct(); for (auto& it : instance->properties()) { if (it.key.starts_with(identifier_string)) @@ -148,7 +155,8 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> if (identifier_entries.size() == 1 && identifier_entries.first().completion == identifier_string) identifier_entries.clear(); break; - case AfterClassName: + } + case AfterClassName: { if (last_seen_token && last_seen_token->m_end.line == cursor.line()) { if (last_seen_token->m_type != GUI::GMLToken::Type::Identifier || last_seen_token->m_end.column + 1 != cursor.column()) { // Inside braces, but on the same line as some other stuff (and not the continuation of one!) @@ -157,7 +165,8 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> } } if (!class_names.is_empty()) { - if (auto registration = GUI::WidgetClassRegistration::find(class_names.last())) { + auto registration = Core::ObjectClassRegistration::find(class_names.last()); + if (registration && registration->is_derived_from(widget_class)) { auto instance = registration->construct(); for (auto& it : instance->properties()) { if (!it.value->is_readonly()) @@ -165,16 +174,21 @@ void GMLAutocompleteProvider::provide_completions(Function<void(Vector<Entry>)> } } } - GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) { + Core::ObjectClassRegistration::for_each([&](const Core::ObjectClassRegistration& registration) { + if (!registration.is_derived_from(widget_class)) + return; class_entries.empend(String::formatted("@{}", registration.class_name()), 0u); }); break; + } case AfterIdentifier: if (last_seen_token && last_seen_token->m_end.line != cursor.line()) { break; } if (identifier_string == "layout") { - GUI::WidgetClassRegistration::for_each([&](const GUI::WidgetClassRegistration& registration) { + Core::ObjectClassRegistration::for_each([&](const Core::ObjectClassRegistration& registration) { + if (!registration.is_derived_from(widget_class)) + return; if (registration.class_name().contains("Layout")) class_entries.empend(String::formatted("@{}", registration.class_name()), 0u); }); diff --git a/Userland/DevTools/Playground/main.cpp b/Userland/DevTools/Playground/main.cpp index fcd2f15d2c..eb95cddab9 100644 --- a/Userland/DevTools/Playground/main.cpp +++ b/Userland/DevTools/Playground/main.cpp @@ -128,7 +128,7 @@ int main(int argc, char** argv) editor.on_change = [&] { preview.remove_all_children(); - preview.load_from_gml(editor.text(), [](const String& class_name) -> RefPtr<GUI::Widget> { + preview.load_from_gml(editor.text(), [](const String& class_name) -> RefPtr<Core::Object> { return UnregisteredWidget::construct(class_name); }); }; diff --git a/Userland/Libraries/LibCore/Forward.h b/Userland/Libraries/LibCore/Forward.h index ece3631f99..5bd7941640 100644 --- a/Userland/Libraries/LibCore/Forward.h +++ b/Userland/Libraries/LibCore/Forward.h @@ -27,6 +27,7 @@ class NetworkJob; class NetworkResponse; class Notifier; class Object; +class ObjectClassRegistration; class ProcessStatisticsReader; class Socket; class SocketAddress; diff --git a/Userland/Libraries/LibCore/Object.cpp b/Userland/Libraries/LibCore/Object.cpp index fffeeb955f..4c316406fd 100644 --- a/Userland/Libraries/LibCore/Object.cpp +++ b/Userland/Libraries/LibCore/Object.cpp @@ -250,4 +250,44 @@ void Object::set_event_filter(Function<bool(Core::Event&)> filter) m_event_filter = move(filter); } +static HashMap<String, ObjectClassRegistration*>& object_classes() +{ + static HashMap<String, ObjectClassRegistration*>* map; + if (!map) + map = new HashMap<String, ObjectClassRegistration*>; + return *map; +} + +ObjectClassRegistration::ObjectClassRegistration(const String& class_name, Function<NonnullRefPtr<Object>()> factory, ObjectClassRegistration* parent_class) + : m_class_name(class_name) + , m_factory(move(factory)) + , m_parent_class(parent_class) +{ + object_classes().set(class_name, this); +} + +ObjectClassRegistration::~ObjectClassRegistration() +{ +} + +bool ObjectClassRegistration::is_derived_from(const ObjectClassRegistration& base_class) const +{ + if (&base_class == this) + return true; + if (!m_parent_class) + return false; + return m_parent_class->is_derived_from(base_class); +} + +void ObjectClassRegistration::for_each(Function<void(const ObjectClassRegistration&)> callback) +{ + for (auto& it : object_classes()) { + callback(*it.value); + } +} + +const ObjectClassRegistration* ObjectClassRegistration::find(const String& class_name) +{ + return object_classes().get(class_name).value_or(nullptr); +} } diff --git a/Userland/Libraries/LibCore/Object.h b/Userland/Libraries/LibCore/Object.h index c171c395f7..046a1b894f 100644 --- a/Userland/Libraries/LibCore/Object.h +++ b/Userland/Libraries/LibCore/Object.h @@ -19,6 +19,35 @@ namespace Core { +#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: + ObjectClassRegistration(const String& class_name, Function<NonnullRefPtr<Object>()> factory, ObjectClassRegistration* parent_class = nullptr); + ~ObjectClassRegistration(); + + String class_name() const { return m_class_name; } + const ObjectClassRegistration* parent_class() const { return m_parent_class; } + NonnullRefPtr<Object> construct() const { return m_factory(); } + bool is_derived_from(const ObjectClassRegistration& base_class) const; + + static void for_each(Function<void(const ObjectClassRegistration&)>); + static const ObjectClassRegistration* find(const String& class_name); + +private: + String m_class_name; + Function<NonnullRefPtr<Object>()> m_factory; + ObjectClassRegistration* m_parent_class { nullptr }; +}; + class RPCClient; enum class TimerShouldFireWhenNotVisible { @@ -129,6 +158,8 @@ public: void increment_inspector_count(Badge<RPCClient>); void decrement_inspector_count(Badge<RPCClient>); + virtual bool load_from_json(const JsonObject&, RefPtr<Core::Object> (*)(const String&)) { return false; } + protected: explicit Object(Object* parent = nullptr); diff --git a/Userland/Libraries/LibGUI/BoxLayout.cpp b/Userland/Libraries/LibGUI/BoxLayout.cpp index 113e4016a6..8ec88fe4d3 100644 --- a/Userland/Libraries/LibGUI/BoxLayout.cpp +++ b/Userland/Libraries/LibGUI/BoxLayout.cpp @@ -10,8 +10,8 @@ #include <LibGfx/Orientation.h> #include <stdio.h> -REGISTER_WIDGET(GUI, HorizontalBoxLayout) -REGISTER_WIDGET(GUI, VerticalBoxLayout) +REGISTER_CORE_OBJECT(GUI, HorizontalBoxLayout) +REGISTER_CORE_OBJECT(GUI, VerticalBoxLayout) namespace GUI { diff --git a/Userland/Libraries/LibGUI/Forward.h b/Userland/Libraries/LibGUI/Forward.h index 83c97aaaad..00e5e7725b 100644 --- a/Userland/Libraries/LibGUI/Forward.h +++ b/Userland/Libraries/LibGUI/Forward.h @@ -78,7 +78,6 @@ class VerticalBoxLayout; class VerticalSlider; class WMEvent; class Widget; -class WidgetClassRegistration; class Window; class WindowServerConnection; diff --git a/Userland/Libraries/LibGUI/Widget.cpp b/Userland/Libraries/LibGUI/Widget.cpp index 34b2fac31a..8e9da86a51 100644 --- a/Userland/Libraries/LibGUI/Widget.cpp +++ b/Userland/Libraries/LibGUI/Widget.cpp @@ -23,41 +23,10 @@ #include <LibGfx/Palette.h> #include <unistd.h> -REGISTER_WIDGET(GUI, Widget) +REGISTER_CORE_OBJECT(GUI, Widget) namespace GUI { -static HashMap<String, WidgetClassRegistration*>& widget_classes() -{ - static HashMap<String, WidgetClassRegistration*>* map; - if (!map) - map = new HashMap<String, WidgetClassRegistration*>; - return *map; -} - -WidgetClassRegistration::WidgetClassRegistration(const String& class_name, Function<NonnullRefPtr<Widget>()> factory) - : m_class_name(class_name) - , m_factory(move(factory)) -{ - widget_classes().set(class_name, this); -} - -WidgetClassRegistration::~WidgetClassRegistration() -{ -} - -void WidgetClassRegistration::for_each(Function<void(const WidgetClassRegistration&)> callback) -{ - for (auto& it : widget_classes()) { - callback(*it.value); - } -} - -const WidgetClassRegistration* WidgetClassRegistration::find(const String& class_name) -{ - return widget_classes().get(class_name).value_or(nullptr); -} - Widget::Widget() : Core::Object(nullptr) , m_background_role(Gfx::ColorRole::Window) @@ -996,13 +965,13 @@ void Widget::set_override_cursor(Gfx::StandardCursor cursor) bool Widget::load_from_gml(const StringView& gml_string) { - return load_from_gml(gml_string, [](const String& class_name) -> RefPtr<Widget> { + return load_from_gml(gml_string, [](const String& class_name) -> RefPtr<Core::Object> { dbgln("Class '{}' not registered", class_name); return nullptr; }); } -bool Widget::load_from_gml(const StringView& gml_string, RefPtr<Widget> (*unregistered_child_handler)(const String&)) +bool Widget::load_from_gml(const StringView& gml_string, RefPtr<Core::Object> (*unregistered_child_handler)(const String&)) { auto value = parse_gml(gml_string); if (!value.is_object()) @@ -1010,7 +979,7 @@ bool Widget::load_from_gml(const StringView& gml_string, RefPtr<Widget> (*unregi return load_from_json(value.as_object(), unregistered_child_handler); } -bool Widget::load_from_json(const JsonObject& json, RefPtr<Widget> (*unregistered_child_handler)(const String&)) +bool Widget::load_from_json(const JsonObject& json, RefPtr<Core::Object> (*unregistered_child_handler)(const String&)) { json.for_each_member([&](auto& key, auto& value) { set_property(key, value); @@ -1055,16 +1024,16 @@ bool Widget::load_from_json(const JsonObject& json, RefPtr<Widget> (*unregistere return false; } - RefPtr<Widget> child_widget; - if (auto* registration = WidgetClassRegistration::find(class_name.as_string())) { - child_widget = registration->construct(); + RefPtr<Core::Object> child; + if (auto* registration = Core::ObjectClassRegistration::find(class_name.as_string())) { + child = registration->construct(); } else { - child_widget = unregistered_child_handler(class_name.as_string()); - if (!child_widget) - return false; + child = unregistered_child_handler(class_name.as_string()); } - add_child(*child_widget); - child_widget->load_from_json(child_json, unregistered_child_handler); + if (!child) + return false; + add_child(*child); + child->load_from_json(child_json, unregistered_child_handler); } } diff --git a/Userland/Libraries/LibGUI/Widget.h b/Userland/Libraries/LibGUI/Widget.h index b90649af33..2ec342cc53 100644 --- a/Userland/Libraries/LibGUI/Widget.h +++ b/Userland/Libraries/LibGUI/Widget.h @@ -19,9 +19,18 @@ #include <LibGfx/Rect.h> #include <LibGfx/StandardCursor.h> -#define REGISTER_WIDGET(namespace_, class_name) \ - namespace { \ - GUI::WidgetClassRegistration registration_##class_name(#namespace_ "::" #class_name, []() { return namespace_::class_name::construct(); }); \ +namespace Core { +namespace Registration { +extern Core::ObjectClassRegistration registration_Widget; +} +} + +#define REGISTER_WIDGET(namespace_, class_name) \ + namespace Core { \ + namespace Registration { \ + Core::ObjectClassRegistration registration_##class_name( \ + #namespace_ "::" #class_name, []() { return static_ptr_cast<Core::Object>(namespace_::class_name::construct()); }, ®istration_Widget); \ + } \ } namespace GUI { @@ -35,25 +44,6 @@ enum class VerticalDirection { Down }; -class WidgetClassRegistration { - AK_MAKE_NONCOPYABLE(WidgetClassRegistration); - AK_MAKE_NONMOVABLE(WidgetClassRegistration); - -public: - WidgetClassRegistration(const String& class_name, Function<NonnullRefPtr<Widget>()> factory); - ~WidgetClassRegistration(); - - String class_name() const { return m_class_name; } - NonnullRefPtr<Widget> construct() const { return m_factory(); } - - static void for_each(Function<void(const WidgetClassRegistration&)>); - static const WidgetClassRegistration* find(const String& class_name); - -private: - String m_class_name; - Function<NonnullRefPtr<Widget>()> m_factory; -}; - enum class FocusPolicy { NoFocus = 0, TabFocus = 0x1, @@ -281,7 +271,7 @@ public: void set_override_cursor(Gfx::StandardCursor); bool load_from_gml(const StringView&); - bool load_from_gml(const StringView&, RefPtr<Widget> (*unregistered_child_handler)(const String&)); + bool load_from_gml(const StringView&, RefPtr<Core::Object> (*unregistered_child_handler)(const String&)); void set_shrink_to_fit(bool); bool is_shrink_to_fit() const { return m_shrink_to_fit; } @@ -341,7 +331,7 @@ private: void focus_previous_widget(FocusSource, bool siblings_only); void focus_next_widget(FocusSource, bool siblings_only); - bool load_from_json(const JsonObject&, RefPtr<Widget> (*unregistered_child_handler)(const String&)); + virtual bool load_from_json(const JsonObject&, RefPtr<Core::Object> (*unregistered_child_handler)(const String&)) override; // HACK: These are used as property getters for the fixed_* size property aliases. int dummy_fixed_width() { return 0; } |