Parcourir la source

LibGUI: Port rest of the classes to property deserializers

Dan Klishch il y a 1 an
Parent
commit
1f4b15dcaa

+ 1 - 1
Userland/Libraries/LibGUI/BoxLayout.cpp

@@ -22,7 +22,7 @@ BoxLayout::BoxLayout(Orientation orientation, Margins margins, int spacing)
     , m_orientation(orientation)
 {
     register_property(
-        "orientation", [this] { return m_orientation == Gfx::Orientation::Vertical ? "Vertical" : "Horizontal"; }, nullptr);
+        "orientation"sv, [this] { return m_orientation == Gfx::Orientation::Vertical ? "Vertical" : "Horizontal"; }, nullptr, nullptr);
 }
 
 UISize BoxLayout::preferred_size() const

+ 4 - 2
Userland/Libraries/LibGUI/Layout.cpp

@@ -21,7 +21,8 @@ Layout::Layout(Margins initial_margins, int spacing)
     REGISTER_INT_PROPERTY("spacing", spacing, set_spacing);
     REGISTER_MARGINS_PROPERTY("margins", margins, set_margins);
 
-    register_property("entries",
+    register_property(
+        "entries"sv,
         [this] {
             JsonArray entries_array;
             for (auto& entry : m_entries) {
@@ -37,7 +38,8 @@ Layout::Layout(Margins initial_margins, int spacing)
                 entries_array.must_append(move(entry_object));
             }
             return entries_array;
-        });
+        },
+        nullptr, nullptr);
 }
 
 Layout::~Layout() = default;

+ 12 - 27
Userland/Libraries/LibGUI/Margins.h

@@ -139,30 +139,15 @@ private:
 
 #define REGISTER_MARGINS_PROPERTY(property_name, getter, setter) \
     register_property(                                           \
-        property_name, [this]() {                                  \
-            auto m = getter();                                     \
-            JsonObject margins_object;                             \
-            margins_object.set("left", m.left());                  \
-            margins_object.set("right", m.right());                \
-            margins_object.set("top", m.top());                    \
-            margins_object.set("bottom", m.bottom());              \
-            return margins_object; },                             \
-        [this](auto& value) {                                    \
-            if (!value.is_array())                               \
-                return false;                                    \
-            auto size = value.as_array().size();                 \
-            if (size == 0 || size > 4)                           \
-                return false;                                    \
-            int m[4];                                            \
-            for (size_t i = 0; i < size; ++i)                    \
-                m[i] = value.as_array().at(i).to_i32();          \
-            if (size == 1)                                       \
-                setter({ m[0] });                                \
-            else if (size == 2)                                  \
-                setter({ m[0], m[1] });                          \
-            else if (size == 3)                                  \
-                setter({ m[0], m[1], m[2] });                    \
-            else                                                 \
-                setter({ m[0], m[1], m[2], m[3] });              \
-            return true;                                         \
-        });
+        property_name##sv,                                       \
+        [this]() {                                               \
+            auto m = getter();                                   \
+            JsonObject margins_object;                           \
+            margins_object.set("left", m.left());                \
+            margins_object.set("right", m.right());              \
+            margins_object.set("top", m.top());                  \
+            margins_object.set("bottom", m.bottom());            \
+            return margins_object;                               \
+        },                                                       \
+        ::GUI::PropertyDeserializer<::GUI::Margins> {},          \
+        [this](auto const& value) { return setter(value); });

+ 72 - 0
Userland/Libraries/LibGUI/PropertyDeserializer.cpp

@@ -7,6 +7,9 @@
 #include "PropertyDeserializer.h"
 #include <AK/JsonObject.h>
 #include <AK/String.h>
+#include <LibGUI/Margins.h>
+#include <LibGUI/UIDimensions.h>
+#include <LibGfx/Color.h>
 #include <LibGfx/Rect.h>
 
 namespace GUI {
@@ -114,4 +117,73 @@ ErrorOr<Gfx::IntSize> PropertyDeserializer<Gfx::IntSize>::operator()(JsonValue c
     return size;
 }
 
+template<>
+ErrorOr<GUI::Margins> PropertyDeserializer<GUI::Margins>::operator()(JsonValue const& value) const
+{
+    if (!value.is_array() || value.as_array().size() < 1 || value.as_array().size() > 4)
+        return Error::from_string_literal("Expected non-empty array with up to 4 integers");
+
+    auto const& array = value.as_array();
+    auto size = array.size();
+
+    int m[4];
+
+    for (size_t i = 0; i < size; ++i) {
+        auto const& margin = array[i];
+        if (!margin.is_integer<i32>())
+            return Error::from_string_literal("Margin value should be an integer");
+        m[i] = margin.to_i32();
+    }
+
+    if (size == 1)
+        return GUI::Margins { m[0] };
+    else if (size == 2)
+        return GUI::Margins { m[0], m[1] };
+    else if (size == 3)
+        return GUI::Margins { m[0], m[1], m[2] };
+    else
+        return GUI::Margins { m[0], m[1], m[2], m[3] };
+}
+
+template<>
+ErrorOr<UIDimension> PropertyDeserializer<UIDimension>::operator()(JsonValue const& value) const
+{
+    auto result = UIDimension::construct_from_json_value(value);
+    if (result.has_value())
+        return result.release_value();
+    return Error::from_string_literal("Value is not a valid UIDimension");
+}
+
+template<>
+ErrorOr<UISize> PropertyDeserializer<UISize>::operator()(JsonValue const& value) const
+{
+    if (!value.is_object() || !value.as_object().has("width"sv) || !value.as_object().has("height"sv))
+        return Error::from_string_literal("Object with keys \"width\" and \"height\" is expected");
+
+    auto const& object = value.as_object();
+
+    auto const& width = object.get("width"sv).value();
+    auto result_width = GUI::UIDimension::construct_from_json_value(width);
+    if (!result_width.has_value())
+        return Error::from_string_literal("width is not a valid UIDimension");
+
+    auto const& height = object.get("height"sv).value();
+    auto result_height = GUI::UIDimension::construct_from_json_value(height);
+    if (!result_height.has_value())
+        return Error::from_string_literal("height is not a valid UIDimension");
+
+    return UISize { result_width.value(), result_height.value() };
+}
+
+template<>
+ErrorOr<Color> PropertyDeserializer<Color>::operator()(JsonValue const& value) const
+{
+    if (value.is_string()) {
+        auto c = Color::from_string(value.as_string());
+        if (c.has_value())
+            return c.release_value();
+    }
+    return Error::from_string_literal("Color is expected");
+}
+
 };

+ 1 - 12
Userland/Libraries/LibGUI/TabWidget.cpp

@@ -37,18 +37,7 @@ TabWidget::TabWidget()
         { TabPosition::Bottom, "Bottom" },
         { TabPosition::Left, "Left" },
         { TabPosition::Right, "Right" }, );
-
-    register_property(
-        "text_alignment",
-        [this] { return Gfx::to_string(text_alignment()); },
-        [this](auto& value) {
-            auto alignment = Gfx::text_alignment_from_string(value.to_byte_string());
-            if (alignment.has_value()) {
-                set_text_alignment(alignment.value());
-                return true;
-            }
-            return false;
-        });
+    REGISTER_TEXT_ALIGNMENT_PROPERTY("text_alignment", text_alignment, set_text_alignment);
 }
 
 ErrorOr<void> TabWidget::try_add_widget(Widget& widget)

+ 27 - 41
Userland/Libraries/LibGUI/UIDimensions.h

@@ -296,58 +296,44 @@ inline auto clamp<GUI::UIDimension>(GUI::UIDimension const& input, GUI::UIDimens
 
 }
 
-#define REGISTER_UI_DIMENSION_PROPERTY(property_name, getter, setter)         \
-    register_property(                                                        \
-        property_name,                                                        \
-        [this] {                                                              \
-            return this->getter().as_json_value();                            \
-        },                                                                    \
-        [this](auto& value) {                                                 \
-            auto result = GUI::UIDimension::construct_from_json_value(value); \
-            if (result.has_value())                                           \
-                this->setter(result.value());                                 \
-            return result.has_value();                                        \
-        });
+#define REGISTER_UI_DIMENSION_PROPERTY(property_name, getter, setter) \
+    register_property(                                                \
+        property_name##sv,                                            \
+        [this] {                                                      \
+            return this->getter().as_json_value();                    \
+        },                                                            \
+        ::GUI::PropertyDeserializer<::GUI::UIDimension> {},           \
+        [this](auto const& value) { return setter(value); });
 
 #define REGISTER_READONLY_UI_DIMENSION_PROPERTY(property_name, getter) \
     register_property(                                                 \
-        property_name,                                                 \
+        property_name##sv,                                             \
         [this] {                                                       \
             return this->getter().as_json_value();                     \
-        });
-
-#define REGISTER_UI_SIZE_PROPERTY(property_name, getter, setter)               \
-    register_property(                                                         \
-        property_name,                                                         \
-        [this] {                                                               \
-            auto size = this->getter();                                        \
-            JsonObject size_object;                                            \
-            size_object.set("width"sv, size.width().as_json_value());          \
-            size_object.set("height"sv, size.height().as_json_value());        \
-            return size_object;                                                \
-        },                                                                     \
-        [this](auto& value) {                                                  \
-            if (!value.is_object())                                            \
-                return false;                                                  \
-            auto result_width = GUI::UIDimension::construct_from_json_value(   \
-                value.as_object().get("width"sv).value_or({}));                \
-            auto result_height = GUI::UIDimension::construct_from_json_value(  \
-                value.as_object().get("height"sv).value_or({}));               \
-            if (result_width.has_value() && result_height.has_value()) {       \
-                GUI::UISize size(result_width.value(), result_height.value()); \
-                setter(size);                                                  \
-                return true;                                                   \
-            }                                                                  \
-            return false;                                                      \
-        });
+        },                                                             \
+        nullptr, nullptr);
+
+#define REGISTER_UI_SIZE_PROPERTY(property_name, getter, setter)        \
+    register_property(                                                  \
+        property_name##sv,                                              \
+        [this] {                                                        \
+            auto size = this->getter();                                 \
+            JsonObject size_object;                                     \
+            size_object.set("width"sv, size.width().as_json_value());   \
+            size_object.set("height"sv, size.height().as_json_value()); \
+            return size_object;                                         \
+        },                                                              \
+        ::GUI::PropertyDeserializer<::GUI::UISize> {},                  \
+        [this](auto const& value) { return setter(value); });
 
 #define REGISTER_READONLY_UI_SIZE_PROPERTY(property_name, getter)     \
     register_property(                                                \
-        property_name,                                                \
+        property_name##sv,                                            \
         [this] {                                                      \
             auto size = this->getter();                               \
             JsonObject size_object;                                   \
             size_object.set("width", size.width().as_json_value());   \
             size_object.set("height", size.height().as_json_value()); \
             return size_object;                                       \
-        });
+        },                                                            \
+        nullptr, nullptr);

+ 40 - 116
Userland/Libraries/LibGUI/Widget.cpp

@@ -45,12 +45,12 @@ Widget::Widget()
     REGISTER_DEPRECATED_STRING_PROPERTY("name", name, set_name);
 
     register_property(
-        "address", [this] { return FlatPtr(this); },
-        [](auto&) { return false; });
+        "address"sv, [this] { return FlatPtr(this); },
+        nullptr, nullptr);
 
     register_property(
-        "parent", [this] { return FlatPtr(this->parent()); },
-        [](auto&) { return false; });
+        "parent"sv, [this] { return FlatPtr(this->parent()); },
+        nullptr, nullptr);
 
     REGISTER_RECT_PROPERTY("relative_rect", relative_rect, set_relative_rect);
     REGISTER_BOOL_PROPERTY("fill_with_background_color", fill_with_background_color, set_fill_with_background_color);
@@ -90,119 +90,52 @@ Widget::Widget()
 
     REGISTER_BOOL_PROPERTY("font_fixed_width", is_font_fixed_width, set_font_fixed_width)
     register_property(
-        "font_type", [this] { return m_font->is_fixed_width() ? "FixedWidth" : "Normal"; },
-        [this](auto& value) {
-            if (value.to_byte_string() == "FixedWidth") {
-                set_font_fixed_width(true);
-                return true;
+        "font_type"sv, [this] { return m_font->is_fixed_width() ? "FixedWidth" : "Normal"; },
+        [](JsonValue const& value) -> ErrorOr<bool> {
+            if (value.is_string()) {
+                auto string = value.as_string();
+                if (string == "FixedWidth")
+                    return true;
+                if (string == "Normal")
+                    return false;
             }
-            if (value.to_byte_string() == "Normal") {
-                set_font_fixed_width(false);
-                return true;
-            }
-            return false;
-        });
+            return Error::from_string_literal("\"FixedWidth\" or \"Normal\" is expected");
+        },
+        [this](auto const& value) { return set_font_fixed_width(value); });
 
-    register_property(
-        "focus_policy", [this]() -> JsonValue {
-        auto policy = focus_policy();
-        if (policy == GUI::FocusPolicy::ClickFocus)
-            return "ClickFocus";
-        if (policy == GUI::FocusPolicy::NoFocus)
-            return "NoFocus";
-        if (policy == GUI::FocusPolicy::TabFocus)
-            return "TabFocus";
-        if (policy == GUI::FocusPolicy::StrongFocus)
-            return "StrongFocus";
-        return JsonValue(); },
-        [this](auto& value) {
-            if (!value.is_string())
-                return false;
-            if (value.as_string() == "ClickFocus") {
-                set_focus_policy(GUI::FocusPolicy::ClickFocus);
-                return true;
-            }
-            if (value.as_string() == "NoFocus") {
-                set_focus_policy(GUI::FocusPolicy::NoFocus);
-                return true;
-            }
-            if (value.as_string() == "TabFocus") {
-                set_focus_policy(GUI::FocusPolicy::TabFocus);
-                return true;
-            }
-            if (value.as_string() == "StrongFocus") {
-                set_focus_policy(GUI::FocusPolicy::StrongFocus);
-                return true;
-            }
-            return false;
-        });
-
-    register_property(
-        "foreground_color", [this]() -> JsonValue { return palette().color(foreground_role()).to_byte_string(); },
-        [this](auto& value) {
-            auto c = Color::from_string(value.to_byte_string());
-            if (c.has_value()) {
-                auto _palette = palette();
-                _palette.set_color(foreground_role(), c.value());
-                set_palette(_palette);
-                return true;
-            }
-            return false;
-        });
+    REGISTER_ENUM_PROPERTY("focus_policy", focus_policy, set_focus_policy, GUI::FocusPolicy,
+        { GUI::FocusPolicy::ClickFocus, "ClickFocus" },
+        { GUI::FocusPolicy::NoFocus, "NoFocus" },
+        { GUI::FocusPolicy::TabFocus, "TabFocus" },
+        { GUI::FocusPolicy::StrongFocus, "StrongFocus" });
 
     register_property(
-        "background_color", [this]() -> JsonValue { return palette().color(background_role()).to_byte_string(); },
-        [this](JsonValue const& value) {
-            auto color_str = String::from_byte_string(value.to_byte_string());
-            if (color_str.is_error())
-                return false;
-
-            return set_background_color(color_str.release_value());
+        "foreground_color"sv,
+        [this]() { return palette().color(foreground_role()).to_byte_string(); },
+        ::GUI::PropertyDeserializer<Color> {},
+        [this](Gfx::Color const& color) {
+            auto _palette = palette();
+            _palette.set_color(foreground_role(), color);
+            set_palette(_palette);
         });
 
     register_property(
-        "foreground_role", [this]() -> JsonValue { return Gfx::to_string(foreground_role()); },
-        [this](auto& value) {
-            if (!value.is_string())
-                return false;
-            auto str = value.as_string();
-            if (str == "NoRole") {
-                set_foreground_role(Gfx::ColorRole::NoRole);
-                return true;
-            }
-#undef __ENUMERATE_COLOR_ROLE
-#define __ENUMERATE_COLOR_ROLE(role)               \
-    else if (str == #role)                         \
-    {                                              \
-        set_foreground_role(Gfx::ColorRole::role); \
-        return true;                               \
-    }
-            ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE)
-#undef __ENUMERATE_COLOR_ROLE
-            return false;
+        "background_color"sv,
+        [this]() { return palette().color(background_role()).to_byte_string(); },
+        ::GUI::PropertyDeserializer<Color> {},
+        [this](Gfx::Color const& color) {
+            set_background_color(color);
         });
 
-    register_property(
-        "background_role", [this]() -> JsonValue { return Gfx::to_string(background_role()); },
-        [this](auto& value) {
-            if (!value.is_string())
-                return false;
-            auto str = value.as_string();
-            if (str == "NoRole") {
-                set_background_role(Gfx::ColorRole::NoRole);
-                return true;
-            }
+#define __ENUMERATE_COLOR_ROLE(role) \
+    { Gfx::ColorRole::role, #role },
+    REGISTER_ENUM_PROPERTY("foreground_role", foreground_role, set_foreground_role, Gfx::ColorRole,
+        { Gfx::ColorRole::NoRole, "NoRole" },
+        ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE));
+    REGISTER_ENUM_PROPERTY("background_role", background_role, set_background_role, Gfx::ColorRole,
+        { Gfx::ColorRole::NoRole, "NoRole" },
+        ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE));
 #undef __ENUMERATE_COLOR_ROLE
-#define __ENUMERATE_COLOR_ROLE(role)               \
-    else if (str == #role)                         \
-    {                                              \
-        set_background_role(Gfx::ColorRole::role); \
-        return true;                               \
-    }
-            ENUMERATE_COLOR_ROLES(__ENUMERATE_COLOR_ROLE)
-#undef __ENUMERATE_COLOR_ROLE
-            return false;
-        });
 }
 
 Widget::~Widget() = default;
@@ -1082,15 +1015,6 @@ void Widget::set_foreground_role(ColorRole role)
     update();
 }
 
-bool Widget::set_background_color(String color_str)
-{
-    auto color = Color::from_string(color_str.to_byte_string());
-    if (!color.has_value())
-        return false;
-    set_background_color(color.release_value());
-    return true;
-}
-
 void Widget::set_background_color(Gfx::Color color)
 {
     auto _palette = palette();

+ 0 - 1
Userland/Libraries/LibGUI/Widget.h

@@ -254,7 +254,6 @@ public:
     Gfx::ColorRole foreground_role() const { return m_foreground_role; }
     void set_foreground_role(Gfx::ColorRole);
 
-    bool set_background_color(String);
     void set_background_color(Gfx::Color);
 
     void set_autofill(bool b) { set_fill_with_background_color(b); }

+ 5 - 9
Userland/Libraries/LibGUI/Window.cpp

@@ -85,16 +85,12 @@ Window::Window(Core::EventReceiver* parent)
     m_floating_rect = { -5000, -5000, 0, 0 };
     m_title_when_windowless = "GUI::Window";
 
-    register_property(
-        "title",
-        [this] { return title(); },
-        [this](auto& value) {
-            set_title(value.to_byte_string());
-            return true;
-        });
+    REGISTER_DEPRECATED_STRING_PROPERTY("title", title, set_title)
 
-    register_property("visible", [this] { return is_visible(); });
-    register_property("active", [this] { return is_active(); });
+    register_property(
+        "visible"sv, [this] { return is_visible(); }, nullptr, nullptr);
+    register_property(
+        "active"sv, [this] { return is_active(); }, nullptr, nullptr);
 
     REGISTER_BOOL_PROPERTY("minimizable", is_minimizable, set_minimizable);
     REGISTER_BOOL_PROPERTY("resizable", is_resizable, set_resizable);