1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 06:07:34 +00:00

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>
This commit is contained in:
Tom 2021-04-04 15:40:34 -06:00 committed by Andreas Kling
parent 6e101adc28
commit 3aaffa2c47
13 changed files with 134 additions and 85 deletions

View file

@ -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 {

View file

@ -78,7 +78,6 @@ class VerticalBoxLayout;
class VerticalSlider;
class WMEvent;
class Widget;
class WidgetClassRegistration;
class Window;
class WindowServerConnection;

View file

@ -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);
}
}

View file

@ -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; }