summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorTom <tomut@yahoo.com>2021-04-04 15:40:34 -0600
committerAndreas Kling <kling@serenityos.org>2021-05-06 08:50:39 +0200
commit3aaffa2c47e39583848cfe9b7b9f846e5119fe1b (patch)
treeeb5a5535bec0952a95b19b9c494d9c6049896107 /Userland
parent6e101adc28c9c682f023386831d632a477768cb8 (diff)
downloadserenity-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.cpp4
-rw-r--r--Userland/DevTools/HackStudio/HackStudioWidget.cpp8
-rw-r--r--Userland/DevTools/HackStudio/Tool.h1
-rw-r--r--Userland/DevTools/HackStudio/WidgetTool.h4
-rw-r--r--Userland/DevTools/Playground/GMLAutocompleteProvider.cpp30
-rw-r--r--Userland/DevTools/Playground/main.cpp2
-rw-r--r--Userland/Libraries/LibCore/Forward.h1
-rw-r--r--Userland/Libraries/LibCore/Object.cpp40
-rw-r--r--Userland/Libraries/LibCore/Object.h31
-rw-r--r--Userland/Libraries/LibGUI/BoxLayout.cpp4
-rw-r--r--Userland/Libraries/LibGUI/Forward.h1
-rw-r--r--Userland/Libraries/LibGUI/Widget.cpp55
-rw-r--r--Userland/Libraries/LibGUI/Widget.h38
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), [&reg, 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()); }, &registration_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; }