diff --git a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp index 5eafb9d7e71..f296fdcb001 100644 --- a/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/GMLCompiler/main.cpp @@ -313,6 +313,29 @@ static ErrorOr generate_loader_for_object(GUI::GML::Object const& gml_obje })); generator.appendln(""); + // Object properties + size_t current_object_property_index = 0; + auto next_object_property_name = [&]() { + return String::formatted("{}_property_{}", object_name, current_object_property_index++); + }; + TRY(gml_object.try_for_each_object_property([&](StringView key, NonnullRefPtr value) -> ErrorOr { + if (key == "layout"sv) + return {}; // Layout is handled separately. + + auto property_generator = generator.fork(); + auto property_variable_name = TRY(next_object_property_name()); + property_generator.set("property_variable_name", property_variable_name.bytes_as_string_view()); + property_generator.set("property_class_name", value->name()); + property_generator.set("key", key); + TRY(append(property_generator, "RefPtr<::@property_class_name@> @property_variable_name@;")); + TRY(generate_loader_for_object(*value, property_generator.fork(), property_variable_name, indentation + 1, UseObjectConstructor::Yes)); + + // Set the property on the object. + TRY(append(property_generator, "@object_name@->set_@key@(*@property_variable_name@);")); + property_generator.appendln(""); + return {}; + })); + // Layout if (gml_object.layout_object() != nullptr) { TRY(append(generator, "RefPtr layout;")); @@ -340,10 +363,9 @@ static ErrorOr generate_loader_for_object(GUI::GML::Object const& gml_obje TRY(append(child_generator, "RefPtr<::@child_class_name@> @child_variable_name@;")); TRY(generate_loader_for_object(child, child_generator.fork(), child_variable_name, indentation + 1, UseObjectConstructor::Yes)); - // Handle the current two special cases of child adding. - if (gml_object.name() == "GUI::ScrollableContainerWidget"sv) - TRY(append(child_generator, "static_ptr_cast(@object_name@)->set_widget(@child_variable_name@);")); - else if (gml_object.name() == "GUI::TabWidget"sv) + // Handle the current special case of child adding. + // FIXME: This should be using the proper API for handling object properties. + if (gml_object.name() == "GUI::TabWidget"sv) TRY(append(child_generator, "static_ptr_cast(@object_name@)->add_widget(*@child_variable_name@);")); else TRY(append(child_generator, "TRY(@object_name@->try_add_child(*@child_variable_name@));")); diff --git a/Userland/Libraries/LibGUI/EmojiInputDialog.gml b/Userland/Libraries/LibGUI/EmojiInputDialog.gml index edced878ff4..392fd7879a6 100644 --- a/Userland/Libraries/LibGUI/EmojiInputDialog.gml +++ b/Userland/Libraries/LibGUI/EmojiInputDialog.gml @@ -24,7 +24,7 @@ @GUI::ScrollableContainerWidget { name: "scrollable_container" - @GUI::Widget { + content_widget: @GUI::Widget { name: "emojis" layout: @GUI::VerticalBoxLayout {} } diff --git a/Userland/Libraries/LibGUI/GML/AST.h b/Userland/Libraries/LibGUI/GML/AST.h index 90dd0405b7c..57c11fb93a3 100644 --- a/Userland/Libraries/LibGUI/GML/AST.h +++ b/Userland/Libraries/LibGUI/GML/AST.h @@ -188,6 +188,18 @@ public: } } + template + void for_each_object_property(Callback callback) const + { + for (auto const& child : m_properties) { + if (is(child)) { + auto const& property = static_cast(*child); + if (is(property.value().ptr())) + callback(property.key(), static_ptr_cast(property.value())); + } + } + } + template> Callback> ErrorOr try_for_each_property(Callback callback) const { @@ -201,6 +213,19 @@ public: return {}; } + template> Callback> + ErrorOr try_for_each_object_property(Callback callback) const + { + for (auto const& child : m_properties) { + if (is(child)) { + auto const& property = static_cast(*child); + if (is(property.value().ptr())) + TRY(callback(property.key(), static_ptr_cast(property.value()))); + } + } + return {}; + } + template void for_each_child_object(Callback callback) const { diff --git a/Userland/Libraries/LibGUI/ScrollableContainerWidget.h b/Userland/Libraries/LibGUI/ScrollableContainerWidget.h index 0b6f2f5ea23..3862d65a436 100644 --- a/Userland/Libraries/LibGUI/ScrollableContainerWidget.h +++ b/Userland/Libraries/LibGUI/ScrollableContainerWidget.h @@ -21,6 +21,9 @@ public: GUI::Widget* widget() { return m_widget; } GUI::Widget const* widget() const { return m_widget; } + // GMLCompiler support for the `content_widget` object property. + void set_content_widget(GUI::Widget& widget) { set_widget(&widget); } + protected: virtual void did_scroll() override; virtual void resize_event(GUI::ResizeEvent&) override;