diff options
-rw-r--r-- | DevTools/Playground/main.cpp | 36 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.cpp | 28 | ||||
-rw-r--r-- | Libraries/LibGUI/Widget.h | 3 |
3 files changed, 56 insertions, 11 deletions
diff --git a/DevTools/Playground/main.cpp b/DevTools/Playground/main.cpp index 4e586964c8..8ed1cdbda8 100644 --- a/DevTools/Playground/main.cpp +++ b/DevTools/Playground/main.cpp @@ -40,11 +40,43 @@ #include <LibGUI/Menu.h> #include <LibGUI/MenuBar.h> #include <LibGUI/MessageBox.h> +#include <LibGUI/Painter.h> #include <LibGUI/Splitter.h> #include <LibGUI/TextEditor.h> #include <LibGUI/Window.h> #include <string.h> +namespace { + +class UnregisteredWidget final : public GUI::Widget { + C_OBJECT(UnregisteredWidget); + +private: + UnregisteredWidget(const String& class_name); + + virtual void paint_event(GUI::PaintEvent& event) override; + + String m_text; +}; + +UnregisteredWidget::UnregisteredWidget(const String& class_name) +{ + StringBuilder builder; + builder.append(class_name); + builder.append("\nnot registered"); + m_text = builder.to_string(); +} + +void UnregisteredWidget::paint_event(GUI::PaintEvent& event) +{ + GUI::Painter painter(*this); + painter.add_clip_rect(event.rect()); + painter.fill_rect(event.rect(), Gfx::Color::DarkRed); + painter.draw_text(rect(), m_text, Gfx::TextAlignment::Center, Color::White); +} + +} + class GMLAutocompleteProvider final : public virtual GUI::AutocompleteProvider { public: GMLAutocompleteProvider() { } @@ -292,7 +324,9 @@ int main(int argc, char** argv) editor.on_change = [&] { preview.remove_all_children(); - preview.load_from_gml(editor.text()); + preview.load_from_gml(editor.text(), [](const String& class_name) -> RefPtr<GUI::Widget> { + return UnregisteredWidget::construct(class_name); + }); }; auto menubar = GUI::MenuBar::construct(); diff --git a/Libraries/LibGUI/Widget.cpp b/Libraries/LibGUI/Widget.cpp index 0a83919af5..1da1b220e1 100644 --- a/Libraries/LibGUI/Widget.cpp +++ b/Libraries/LibGUI/Widget.cpp @@ -954,13 +954,21 @@ 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> { + dbgln("Class '{}' not registered", class_name); + return nullptr; + }); +} + +bool Widget::load_from_gml(const StringView& gml_string, RefPtr<Widget> (*unregistered_child_handler)(const String&)) +{ auto value = parse_gml(gml_string); if (!value.is_object()) return false; - return load_from_json(value.as_object()); + return load_from_json(value.as_object(), unregistered_child_handler); } -bool Widget::load_from_json(const JsonObject& json) +bool Widget::load_from_json(const JsonObject& json, RefPtr<Widget> (*unregistered_child_handler)(const String&)) { json.for_each_member([&](auto& key, auto& value) { set_property(key, value); @@ -1004,15 +1012,17 @@ bool Widget::load_from_json(const JsonObject& json) dbgln("No class name in entry"); return false; } - auto* registration = WidgetClassRegistration::find(class_name.as_string()); - if (!registration) { - dbg() << "Class '" << class_name.as_string() << "' not registered"; - return false; - } - auto child_widget = registration->construct(); + RefPtr<Widget> child_widget; + if (auto* registration = WidgetClassRegistration::find(class_name.as_string())) { + child_widget = registration->construct(); + } else { + child_widget = unregistered_child_handler(class_name.as_string()); + if (!child_widget) + return false; + } add_child(*child_widget); - child_widget->load_from_json(child_json); + child_widget->load_from_json(child_json, unregistered_child_handler); } } diff --git a/Libraries/LibGUI/Widget.h b/Libraries/LibGUI/Widget.h index 4eb84c6aff..1f14ef14d4 100644 --- a/Libraries/LibGUI/Widget.h +++ b/Libraries/LibGUI/Widget.h @@ -298,6 +298,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&)); void set_shrink_to_fit(bool); bool is_shrink_to_fit() const { return m_shrink_to_fit; } @@ -350,7 +351,7 @@ private: void focus_previous_widget(FocusSource, bool siblings_only); void focus_next_widget(FocusSource, bool siblings_only); - bool load_from_json(const JsonObject&); + bool load_from_json(const JsonObject&, RefPtr<Widget> (*unregistered_child_handler)(const String&)); // HACK: These are used as property getters for the fixed_* size property aliases. int dummy_fixed_width() { return 0; } |