mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:47:44 +00:00
Playground: Show placeholders for unregistered widgets
With this, Playground can be used to interactively edit e.g. DisplaySettingsWindow.gml.
This commit is contained in:
parent
1b2364846f
commit
009c753a12
3 changed files with 56 additions and 11 deletions
|
@ -40,11 +40,43 @@
|
||||||
#include <LibGUI/Menu.h>
|
#include <LibGUI/Menu.h>
|
||||||
#include <LibGUI/MenuBar.h>
|
#include <LibGUI/MenuBar.h>
|
||||||
#include <LibGUI/MessageBox.h>
|
#include <LibGUI/MessageBox.h>
|
||||||
|
#include <LibGUI/Painter.h>
|
||||||
#include <LibGUI/Splitter.h>
|
#include <LibGUI/Splitter.h>
|
||||||
#include <LibGUI/TextEditor.h>
|
#include <LibGUI/TextEditor.h>
|
||||||
#include <LibGUI/Window.h>
|
#include <LibGUI/Window.h>
|
||||||
#include <string.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 {
|
class GMLAutocompleteProvider final : public virtual GUI::AutocompleteProvider {
|
||||||
public:
|
public:
|
||||||
GMLAutocompleteProvider() { }
|
GMLAutocompleteProvider() { }
|
||||||
|
@ -292,7 +324,9 @@ int main(int argc, char** argv)
|
||||||
|
|
||||||
editor.on_change = [&] {
|
editor.on_change = [&] {
|
||||||
preview.remove_all_children();
|
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();
|
auto menubar = GUI::MenuBar::construct();
|
||||||
|
|
|
@ -953,14 +953,22 @@ void Widget::set_override_cursor(Gfx::StandardCursor cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Widget::load_from_gml(const StringView& gml_string)
|
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);
|
auto value = parse_gml(gml_string);
|
||||||
if (!value.is_object())
|
if (!value.is_object())
|
||||||
return false;
|
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) {
|
json.for_each_member([&](auto& key, auto& value) {
|
||||||
set_property(key, value);
|
set_property(key, value);
|
||||||
|
@ -1004,15 +1012,17 @@ bool Widget::load_from_json(const JsonObject& json)
|
||||||
dbgln("No class name in entry");
|
dbgln("No class name in entry");
|
||||||
return false;
|
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);
|
add_child(*child_widget);
|
||||||
child_widget->load_from_json(child_json);
|
child_widget->load_from_json(child_json, unregistered_child_handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -298,6 +298,7 @@ public:
|
||||||
void set_override_cursor(Gfx::StandardCursor);
|
void set_override_cursor(Gfx::StandardCursor);
|
||||||
|
|
||||||
bool load_from_gml(const StringView&);
|
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);
|
void set_shrink_to_fit(bool);
|
||||||
bool is_shrink_to_fit() const { return m_shrink_to_fit; }
|
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_previous_widget(FocusSource, bool siblings_only);
|
||||||
void focus_next_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.
|
// HACK: These are used as property getters for the fixed_* size property aliases.
|
||||||
int dummy_fixed_width() { return 0; }
|
int dummy_fixed_width() { return 0; }
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue