summaryrefslogtreecommitdiff
path: root/Userland
diff options
context:
space:
mode:
authorFrHun <28605587+frhun@users.noreply.github.com>2022-01-04 18:15:15 +0100
committerLinus Groh <mail@linusgroh.de>2022-06-10 21:26:06 +0100
commit8081a8a5de9ea54b18e21da9786652942f5b8439 (patch)
tree07c95e500eebeb8a4e11a16cb5dba54180525192 /Userland
parentd1d5602132e937e259e7e4a5fd307769100b589c (diff)
downloadserenity-8081a8a5de9ea54b18e21da9786652942f5b8439.zip
LibGUI: Add layout spacer support to GML
This is a bit of a hack, but it is an easy way to finally get spacers into GML. This will translate well if spacers are later to become child objects of the continer widget.
Diffstat (limited to 'Userland')
-rw-r--r--Userland/Applications/CrashReporter/CrashReporterWindow.gml3
-rw-r--r--Userland/Applications/Run/Run.gml3
-rw-r--r--Userland/Applications/Spreadsheet/CondFormatting.gml4
-rw-r--r--Userland/Applications/Welcome/WelcomeWindow.gml4
-rw-r--r--Userland/Demos/WidgetGallery/DemoWizardPage1.gml3
-rw-r--r--Userland/Demos/WidgetGallery/DemoWizardPage2.gml3
-rw-r--r--Userland/Demos/WidgetGallery/GalleryGML/BasicsTab.gml28
-rw-r--r--Userland/Demos/WidgetGallery/GalleryGML/SlidersTab.gml8
-rw-r--r--Userland/Libraries/LibGUI/FilePickerDialog.gml2
-rw-r--r--Userland/Libraries/LibGUI/GML/Parser.cpp84
-rw-r--r--Userland/Libraries/LibGUI/PasswordInputDialog.gml2
-rw-r--r--Userland/Libraries/LibGUI/Widget.cpp41
-rw-r--r--Userland/Services/LoginServer/LoginWindow.gml2
13 files changed, 97 insertions, 90 deletions
diff --git a/Userland/Applications/CrashReporter/CrashReporterWindow.gml b/Userland/Applications/CrashReporter/CrashReporterWindow.gml
index f445776110..59928c04d2 100644
--- a/Userland/Applications/CrashReporter/CrashReporterWindow.gml
+++ b/Userland/Applications/CrashReporter/CrashReporterWindow.gml
@@ -94,8 +94,7 @@
fixed_width: 150
}
- // HACK: We need something like Layout::add_spacer() in GML! :^)
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "close_button"
diff --git a/Userland/Applications/Run/Run.gml b/Userland/Applications/Run/Run.gml
index 5f2fd0ca20..0ac27a4b68 100644
--- a/Userland/Applications/Run/Run.gml
+++ b/Userland/Applications/Run/Run.gml
@@ -41,8 +41,7 @@
layout: @GUI::HorizontalBoxLayout {}
fixed_height: 22
- // HACK: using an empty widget as a spacer
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "ok_button"
diff --git a/Userland/Applications/Spreadsheet/CondFormatting.gml b/Userland/Applications/Spreadsheet/CondFormatting.gml
index 853b39a8eb..934573a1b8 100644
--- a/Userland/Applications/Spreadsheet/CondFormatting.gml
+++ b/Userland/Applications/Spreadsheet/CondFormatting.gml
@@ -16,7 +16,7 @@
spacing: 10
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "add_button"
@@ -30,6 +30,6 @@
fixed_width: 70
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
}
diff --git a/Userland/Applications/Welcome/WelcomeWindow.gml b/Userland/Applications/Welcome/WelcomeWindow.gml
index 6c7ebae2e3..618b58aa73 100644
--- a/Userland/Applications/Welcome/WelcomeWindow.gml
+++ b/Userland/Applications/Welcome/WelcomeWindow.gml
@@ -85,7 +85,7 @@
text: "Next Tip"
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::HorizontalSeparator {
fixed_height: 2
@@ -107,7 +107,7 @@
autosize: true
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "close_button"
diff --git a/Userland/Demos/WidgetGallery/DemoWizardPage1.gml b/Userland/Demos/WidgetGallery/DemoWizardPage1.gml
index 39509577bb..6aea235524 100644
--- a/Userland/Demos/WidgetGallery/DemoWizardPage1.gml
+++ b/Userland/Demos/WidgetGallery/DemoWizardPage1.gml
@@ -28,6 +28,5 @@
}
}
- // Spacer
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
diff --git a/Userland/Demos/WidgetGallery/DemoWizardPage2.gml b/Userland/Demos/WidgetGallery/DemoWizardPage2.gml
index fac8a0c278..542509ca82 100644
--- a/Userland/Demos/WidgetGallery/DemoWizardPage2.gml
+++ b/Userland/Demos/WidgetGallery/DemoWizardPage2.gml
@@ -14,6 +14,5 @@
fixed_height: 28
}
- // Spacer
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
diff --git a/Userland/Demos/WidgetGallery/GalleryGML/BasicsTab.gml b/Userland/Demos/WidgetGallery/GalleryGML/BasicsTab.gml
index e9ba1fa4ca..bc3cf3538e 100644
--- a/Userland/Demos/WidgetGallery/GalleryGML/BasicsTab.gml
+++ b/Userland/Demos/WidgetGallery/GalleryGML/BasicsTab.gml
@@ -92,7 +92,7 @@
@GUI::Widget {
layout: @GUI::VerticalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "normal_button"
@@ -105,7 +105,7 @@
enabled: "false"
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
@GUI::VerticalSeparator {}
@@ -113,7 +113,7 @@
@GUI::Widget {
layout: @GUI::VerticalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "enabled_coolbar_button"
@@ -128,7 +128,7 @@
button_style: "Coolbar"
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
}
@@ -144,7 +144,7 @@
fixed_width: 60
layout: @GUI::VerticalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::RadioButton {
name: "top_radiobutton"
@@ -157,16 +157,16 @@
text: "Radio 2"
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Widget {
fixed_width: 70
layout: @GUI::VerticalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::CheckBox {
name: "top_checkbox"
@@ -179,10 +179,10 @@
enabled: false
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
@GUI::VerticalSeparator {}
@@ -190,7 +190,7 @@
@GUI::Widget {
layout: @GUI::VerticalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "icon_button"
@@ -203,7 +203,7 @@
enabled: "false"
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
}
}
@@ -278,7 +278,7 @@
}
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "font_button"
@@ -295,7 +295,7 @@
text: "Input dialog..."
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
}
diff --git a/Userland/Demos/WidgetGallery/GalleryGML/SlidersTab.gml b/Userland/Demos/WidgetGallery/GalleryGML/SlidersTab.gml
index 790c89b06b..098736b78c 100644
--- a/Userland/Demos/WidgetGallery/GalleryGML/SlidersTab.gml
+++ b/Userland/Demos/WidgetGallery/GalleryGML/SlidersTab.gml
@@ -56,7 +56,7 @@
margins: [0, 8]
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Scrollbar {
name: "enabled_scrollbar"
@@ -67,11 +67,11 @@
value: 50
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::HorizontalSeparator {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Scrollbar {
name: "disabled_scrollbar"
@@ -79,7 +79,7 @@
fixed_width: -1
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
}
@GUI::GroupBox {
diff --git a/Userland/Libraries/LibGUI/FilePickerDialog.gml b/Userland/Libraries/LibGUI/FilePickerDialog.gml
index 94d09891bf..61034bbce0 100644
--- a/Userland/Libraries/LibGUI/FilePickerDialog.gml
+++ b/Userland/Libraries/LibGUI/FilePickerDialog.gml
@@ -80,7 +80,7 @@
fixed_height: 22
layout: @GUI::HorizontalBoxLayout {}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Button {
name: "cancel_button"
diff --git a/Userland/Libraries/LibGUI/GML/Parser.cpp b/Userland/Libraries/LibGUI/GML/Parser.cpp
index 169f24c8b9..394774a5ab 100644
--- a/Userland/Libraries/LibGUI/GML/Parser.cpp
+++ b/Userland/Libraries/LibGUI/GML/Parser.cpp
@@ -42,64 +42,64 @@ static ErrorOr<NonnullRefPtr<Object>> parse_gml_object(Queue<Token>& tokens)
auto class_name = tokens.dequeue();
object->set_name(class_name.m_view);
- if (peek() != Token::Type::LeftCurly)
- return Error::from_string_literal("Expected {{"sv);
+ if (peek() == Token::Type::LeftCurly) {
- tokens.dequeue();
+ tokens.dequeue();
- NonnullRefPtrVector<Comment> pending_comments;
- for (;;) {
- if (peek() == Token::Type::RightCurly) {
- // End of object
- break;
- }
+ NonnullRefPtrVector<Comment> pending_comments;
+ for (;;) {
+ if (peek() == Token::Type::RightCurly) {
+ // End of object
+ break;
+ }
- if (peek() == Token::Type::ClassMarker) {
- // It's a child object.
+ if (peek() == Token::Type::ClassMarker) {
+ // It's a child object.
- while (!pending_comments.is_empty())
- TRY(object->add_sub_object_child(pending_comments.take_first()));
+ while (!pending_comments.is_empty())
+ TRY(object->add_sub_object_child(pending_comments.take_last()));
- TRY(object->add_sub_object_child(TRY(parse_gml_object(tokens))));
- } else if (peek() == Token::Type::Identifier) {
- // It's a property.
+ TRY(object->add_sub_object_child(TRY(parse_gml_object(tokens))));
+ } else if (peek() == Token::Type::Identifier) {
+ // It's a property.
- while (!pending_comments.is_empty())
- TRY(object->add_property_child(pending_comments.take_first()));
+ while (!pending_comments.is_empty())
+ TRY(object->add_property_child(pending_comments.take_last()));
- auto property_name = tokens.dequeue();
+ auto property_name = tokens.dequeue();
- if (property_name.m_view.is_empty())
- return Error::from_string_literal("Expected non-empty property name"sv);
+ if (property_name.m_view.is_empty())
+ return Error::from_string_literal("Expected non-empty property name"sv);
- if (peek() != Token::Type::Colon)
- return Error::from_string_literal("Expected ':'"sv);
+ if (peek() != Token::Type::Colon)
+ return Error::from_string_literal("Expected ':'"sv);
- tokens.dequeue();
+ tokens.dequeue();
- RefPtr<ValueNode> value;
- if (peek() == Token::Type::ClassMarker)
- value = TRY(parse_gml_object(tokens));
- else if (peek() == Token::Type::JsonValue)
- value = TRY(try_make_ref_counted<JsonValueNode>(TRY(JsonValueNode::from_string(tokens.dequeue().m_view))));
+ RefPtr<ValueNode> value;
+ if (peek() == Token::Type::ClassMarker)
+ value = TRY(parse_gml_object(tokens));
+ else if (peek() == Token::Type::JsonValue)
+ value = TRY(try_make_ref_counted<JsonValueNode>(TRY(JsonValueNode::from_string(tokens.dequeue().m_view))));
- auto property = TRY(try_make_ref_counted<KeyValuePair>(property_name.m_view, value.release_nonnull()));
- TRY(object->add_property_child(property));
- } else if (peek() == Token::Type::Comment) {
- pending_comments.append(TRY(Node::from_token<Comment>(tokens.dequeue())));
- } else {
- return Error::from_string_literal("Expected child, property, comment, or }}"sv);
+ auto property = TRY(try_make_ref_counted<KeyValuePair>(property_name.m_view, value.release_nonnull()));
+ TRY(object->add_property_child(property));
+ } else if (peek() == Token::Type::Comment) {
+ pending_comments.append(TRY(Node::from_token<Comment>(tokens.dequeue())));
+ } else {
+ return Error::from_string_literal("Expected child, property, comment, or }}"sv);
+ }
}
- }
- // Insert any left-over comments as sub object children, as these will be serialized last
- while (!pending_comments.is_empty())
- TRY(object->add_sub_object_child(pending_comments.take_first()));
+ // Insert any left-over comments as sub object children, as these will be serialized last
+ while (!pending_comments.is_empty())
+ TRY(object->add_sub_object_child(pending_comments.take_first()));
- if (peek() != Token::Type::RightCurly)
- return Error::from_string_literal("Expected }}"sv);
+ if (peek() != Token::Type::RightCurly)
+ return Error::from_string_literal("Expected }}"sv);
- tokens.dequeue();
+ tokens.dequeue();
+ }
return object;
}
diff --git a/Userland/Libraries/LibGUI/PasswordInputDialog.gml b/Userland/Libraries/LibGUI/PasswordInputDialog.gml
index 7d32d977e8..5bc2b75092 100644
--- a/Userland/Libraries/LibGUI/PasswordInputDialog.gml
+++ b/Userland/Libraries/LibGUI/PasswordInputDialog.gml
@@ -68,7 +68,7 @@
}
}
- @GUI::Widget {}
+ @GUI::Layout::Spacer {}
@GUI::Widget {
shrink_to_fit: true
diff --git a/Userland/Libraries/LibGUI/Widget.cpp b/Userland/Libraries/LibGUI/Widget.cpp
index 251bb6d010..d613aed0bd 100644
--- a/Userland/Libraries/LibGUI/Widget.cpp
+++ b/Userland/Libraries/LibGUI/Widget.cpp
@@ -1131,27 +1131,36 @@ bool Widget::load_from_gml_ast(NonnullRefPtr<GUI::GML::Node> ast, RefPtr<Core::O
object->for_each_child_object_interruptible([&](auto child_data) {
auto class_name = child_data->name();
- RefPtr<Core::Object> child;
- if (auto* registration = Core::ObjectClassRegistration::find(class_name)) {
- child = registration->construct();
- if (!child || !registration->is_derived_from(widget_class)) {
- dbgln("Invalid widget class: '{}'", class_name);
+ // It is very questionable if this pseudo object should exist, but it works fine like this for now.
+ if (class_name == "GUI::Layout::Spacer") {
+ if (!this->layout()) {
+ dbgln("Specified GUI::Layout::Spacer in GML, but the parent has no Layout.");
return IterationDecision::Break;
}
+ this->layout()->add_spacer();
} else {
- child = unregistered_child_handler(class_name);
- }
- if (!child)
- return IterationDecision::Break;
+ RefPtr<Core::Object> child;
+ if (auto* registration = Core::ObjectClassRegistration::find(class_name)) {
+ child = registration->construct();
+ if (!child || !registration->is_derived_from(widget_class)) {
+ dbgln("Invalid widget class: '{}'", class_name);
+ return IterationDecision::Break;
+ }
+ } else {
+ child = unregistered_child_handler(class_name);
+ }
+ if (!child)
+ return IterationDecision::Break;
+ add_child(*child);
- add_child(*child);
- // This is possible as we ensure that Widget is a base class above.
- static_ptr_cast<Widget>(child)->load_from_gml_ast(child_data, unregistered_child_handler);
+ // This is possible as we ensure that Widget is a base class above.
+ static_ptr_cast<Widget>(child)->load_from_gml_ast(child_data, unregistered_child_handler);
- if (is_tab_widget) {
- // FIXME: We need to have the child added before loading it so that it can access us. But the TabWidget logic requires the child to not be present yet.
- remove_child(*child);
- reinterpret_cast<TabWidget*>(this)->add_widget(*static_ptr_cast<Widget>(child));
+ if (is_tab_widget) {
+ // FIXME: We need to have the child added before loading it so that it can access us. But the TabWidget logic requires the child to not be present yet.
+ remove_child(*child);
+ reinterpret_cast<TabWidget*>(this)->add_widget(*static_ptr_cast<Widget>(child));
+ }
}
return IterationDecision::Continue;
diff --git a/Userland/Services/LoginServer/LoginWindow.gml b/Userland/Services/LoginServer/LoginWindow.gml
index a1d2749596..e3219ebe10 100644
--- a/Userland/Services/LoginServer/LoginWindow.gml
+++ b/Userland/Services/LoginServer/LoginWindow.gml
@@ -30,6 +30,8 @@
text_alignment: "CenterLeft"
}
+ @GUI::Layout::Spacer {}
+
@GUI::Button {
name: "log_in"
text: "Log in"