summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--DevTools/Playground/main.cpp36
-rw-r--r--Libraries/LibGUI/Widget.cpp28
-rw-r--r--Libraries/LibGUI/Widget.h3
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; }