diff --git a/Userland/Libraries/LibGUI/Variant.cpp b/Userland/Libraries/LibGUI/Variant.cpp index 8649705b07..c257c1b432 100644 --- a/Userland/Libraries/LibGUI/Variant.cpp +++ b/Userland/Libraries/LibGUI/Variant.cpp @@ -1,544 +1,102 @@ /* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2022, Filiph Sandström + * Copyright (c) 2022, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include +#include +#include #include namespace GUI { -char const* to_string(Variant::Type type) -{ - switch (type) { - case Variant::Type::Invalid: - return "Invalid"; - case Variant::Type::Bool: - return "Bool"; - case Variant::Type::Int32: - return "Int32"; - case Variant::Type::Int64: - return "Int64"; - case Variant::Type::UnsignedInt32: - return "UnsignedInt32"; - case Variant::Type::UnsignedInt64: - return "UnsignedInt64"; - case Variant::Type::Float: - return "Float"; - case Variant::Type::String: - return "String"; - case Variant::Type::Bitmap: - return "Bitmap"; - case Variant::Type::Color: - return "Color"; - case Variant::Type::Icon: - return "Icon"; - case Variant::Type::Point: - return "Point"; - case Variant::Type::Size: - return "Size"; - case Variant::Type::Rect: - return "Rect"; - case Variant::Type::Font: - return "Font"; - case Variant::Type::TextAlignment: - return "TextAlignment"; - case Variant::Type::ColorRole: - return "ColorRole"; - case Variant::Type::AlignmentRole: - return "AlignmentRole"; - case Variant::Type::FlagRole: - return "FlagRole"; - case Variant::Type::MetricRole: - return "MetricRole"; - case Variant::Type::PathRole: - return "PathRole"; - } - VERIFY_NOT_REACHED(); -} - -Variant::Variant() -{ - m_value.as_string = nullptr; -} - -Variant::~Variant() -{ - clear(); -} - -void Variant::clear() -{ - switch (m_type) { - case Type::String: - AK::unref_if_not_null(m_value.as_string); - break; - case Type::Bitmap: - AK::unref_if_not_null(m_value.as_bitmap); - break; - case Type::Icon: - AK::unref_if_not_null(m_value.as_icon); - break; - default: - break; - } - m_type = Type::Invalid; - m_value.as_string = nullptr; -} - -Variant::Variant(Gfx::TextAlignment value) - : m_type(Type::TextAlignment) -{ - m_value.as_text_alignment = value; -} - -Variant::Variant(Gfx::ColorRole value) - : m_type(Type::ColorRole) -{ - m_value.as_color_role = value; -} - -Variant::Variant(Gfx::AlignmentRole value) - : m_type(Type::AlignmentRole) -{ - m_value.as_alignment_role = value; -} - -Variant::Variant(Gfx::FlagRole value) - : m_type(Type::FlagRole) -{ - m_value.as_flag_role = value; -} - -Variant::Variant(Gfx::MetricRole value) - : m_type(Type::MetricRole) -{ - m_value.as_metric_role = value; -} - -Variant::Variant(Gfx::PathRole value) - : m_type(Type::PathRole) -{ - m_value.as_path_role = value; -} - -Variant::Variant(i32 value) - : m_type(Type::Int32) -{ - m_value.as_i32 = value; -} - -Variant::Variant(i64 value) - : m_type(Type::Int64) -{ - m_value.as_i64 = value; -} - -Variant::Variant(u32 value) - : m_type(Type::UnsignedInt32) -{ - m_value.as_u32 = value; -} - -Variant::Variant(u64 value) - : m_type(Type::UnsignedInt64) -{ - m_value.as_u64 = value; -} - -Variant::Variant(float value) - : m_type(Type::Float) -{ - m_value.as_float = value; -} - -Variant::Variant(bool value) - : m_type(Type::Bool) -{ - m_value.as_bool = value; -} - -Variant::Variant(char const* cstring) - : Variant(String(cstring)) -{ -} - -Variant::Variant(FlyString const& value) - : Variant(String(value.impl())) -{ -} - -Variant::Variant(StringView value) - : Variant(value.to_string()) -{ -} - -Variant::Variant(String const& value) - : m_type(Type::String) -{ - m_value.as_string = const_cast(value.impl()); - AK::ref_if_not_null(m_value.as_string); -} - Variant::Variant(JsonValue const& value) { - if (value.is_null()) { - m_value.as_string = nullptr; - return; - } + *this = value; +} + +Variant& Variant::operator=(JsonValue const& value) +{ + if (value.is_null()) + return *this; if (value.is_i32()) { - m_type = Type::Int32; - m_value.as_i32 = value.as_i32(); - return; + set(value.as_i32()); + return *this; } if (value.is_u32()) { - m_type = Type::UnsignedInt32; - m_value.as_u32 = value.as_u32(); - return; + set(value.as_u32()); + return *this; } if (value.is_i64()) { - m_type = Type::Int64; - m_value.as_i64 = value.as_i64(); - return; + set(value.as_i64()); + return *this; } if (value.is_u64()) { - m_type = Type::UnsignedInt64; - m_value.as_u64 = value.to_u64(); - return; + set(value.as_u64()); + return *this; } if (value.is_string()) { - m_type = Type::String; - m_value.as_string = value.as_string().impl(); - m_value.as_string->ref(); - return; + set(value.as_string()); + return *this; } if (value.is_bool()) { - m_type = Type::Bool; - m_value.as_bool = value.as_bool(); - return; + set(Detail::Boolean { value.as_bool() }); + return *this; } VERIFY_NOT_REACHED(); } -Variant::Variant(Gfx::Bitmap const& value) - : m_type(Type::Bitmap) -{ - m_value.as_bitmap = const_cast(&value); - AK::ref_if_not_null(m_value.as_bitmap); -} - -Variant::Variant(const GUI::Icon& value) - : m_type(Type::Icon) -{ - m_value.as_icon = &const_cast(value.impl()); - AK::ref_if_not_null(m_value.as_icon); -} - -Variant::Variant(Gfx::Font const& value) - : m_type(Type::Font) -{ - m_value.as_font = &const_cast(value); - AK::ref_if_not_null(m_value.as_font); -} - -Variant::Variant(Color color) - : m_type(Type::Color) -{ - m_value.as_color = color.value(); -} - -Variant::Variant(Gfx::IntPoint const& point) - : m_type(Type::Point) -{ - m_value.as_point = { point.x(), point.y() }; -} - -Variant::Variant(Gfx::IntSize const& size) - : m_type(Type::Size) -{ - m_value.as_size = { size.width(), size.height() }; -} - -Variant::Variant(Gfx::IntRect const& rect) - : m_type(Type::Rect) -{ - m_value.as_rect = (RawRect const&)rect; -} - -Variant& Variant::operator=(Variant const& other) -{ - if (&other == this) - return *this; - clear(); - copy_from(other); - return *this; -} - -Variant& Variant::operator=(Variant&& other) -{ - if (&other == this) - return *this; - clear(); - move_from(move(other)); - return *this; -} - -Variant::Variant(Variant const& other) -{ - copy_from(other); -} - -void Variant::move_from(Variant&& other) -{ - m_type = other.m_type; - m_value = other.m_value; - other.m_type = Type::Invalid; - other.m_value.as_string = nullptr; -} - -void Variant::copy_from(Variant const& other) -{ - VERIFY(!is_valid()); - m_type = other.m_type; - switch (m_type) { - case Type::Bool: - m_value.as_bool = other.m_value.as_bool; - break; - case Type::Int32: - m_value.as_i32 = other.m_value.as_i32; - break; - case Type::Int64: - m_value.as_i64 = other.m_value.as_i64; - break; - case Type::UnsignedInt32: - m_value.as_u32 = other.m_value.as_u32; - break; - case Type::UnsignedInt64: - m_value.as_u64 = other.m_value.as_u64; - break; - case Type::Float: - m_value.as_float = other.m_value.as_float; - break; - case Type::String: - m_value.as_string = other.m_value.as_string; - AK::ref_if_not_null(m_value.as_bitmap); - break; - case Type::Bitmap: - m_value.as_bitmap = other.m_value.as_bitmap; - AK::ref_if_not_null(m_value.as_bitmap); - break; - case Type::Icon: - m_value.as_icon = other.m_value.as_icon; - AK::ref_if_not_null(m_value.as_icon); - break; - case Type::Font: - m_value.as_font = other.m_value.as_font; - AK::ref_if_not_null(m_value.as_font); - break; - case Type::Color: - m_value.as_color = other.m_value.as_color; - break; - case Type::Point: - m_value.as_point = other.m_value.as_point; - break; - case Type::Size: - m_value.as_size = other.m_value.as_size; - break; - case Type::Rect: - m_value.as_rect = other.m_value.as_rect; - break; - case Type::TextAlignment: - m_value.as_text_alignment = other.m_value.as_text_alignment; - break; - case Type::ColorRole: - m_value.as_color_role = other.m_value.as_color_role; - break; - case Type::AlignmentRole: - m_value.as_alignment_role = other.m_value.as_alignment_role; - break; - case Type::FlagRole: - m_value.as_flag_role = other.m_value.as_flag_role; - break; - case Type::MetricRole: - m_value.as_metric_role = other.m_value.as_metric_role; - break; - case Type::PathRole: - m_value.as_path_role = other.m_value.as_path_role; - break; - case Type::Invalid: - break; - } -} - bool Variant::operator==(Variant const& other) const { - if (m_type != other.m_type) - return to_string() == other.to_string(); - switch (m_type) { - case Type::Bool: - return as_bool() == other.as_bool(); - case Type::Int32: - return as_i32() == other.as_i32(); - case Type::Int64: - return as_i64() == other.as_i64(); - case Type::UnsignedInt32: - return as_u32() == other.as_u32(); - case Type::UnsignedInt64: - return as_u64() == other.as_u64(); - case Type::Float: - return as_float() == other.as_float(); - case Type::String: - return as_string() == other.as_string(); - case Type::Bitmap: - return m_value.as_bitmap == other.m_value.as_bitmap; - case Type::Icon: - return m_value.as_icon == other.m_value.as_icon; - case Type::Color: - return m_value.as_color == other.m_value.as_color; - case Type::Point: - return as_point() == other.as_point(); - case Type::Size: - return as_size() == other.as_size(); - case Type::Rect: - return as_rect() == other.as_rect(); - case Type::Font: - return &as_font() == &other.as_font(); - case Type::TextAlignment: - return m_value.as_text_alignment == other.m_value.as_text_alignment; - case Type::ColorRole: - return m_value.as_color_role == other.m_value.as_color_role; - case Type::AlignmentRole: - return m_value.as_alignment_role == other.m_value.as_alignment_role; - case Type::FlagRole: - return m_value.as_flag_role == other.m_value.as_flag_role; - case Type::MetricRole: - return m_value.as_metric_role == other.m_value.as_metric_role; - case Type::PathRole: - return m_value.as_path_role == other.m_value.as_path_role; - case Type::Invalid: - return true; - } - VERIFY_NOT_REACHED(); + return visit([&](T const& own_value) { + return other.visit( + [&](T const& other_value) -> bool { + if constexpr (requires { own_value == other_value; }) + return own_value == other_value; + else if constexpr (IsSame) + return &own_value.impl() == &other_value.impl(); + // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it. + else + return to_string() == other.to_string(); + }, + [&](auto const&) { + // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it. + return to_string() == other.to_string(); + }); + }); } bool Variant::operator<(Variant const& other) const { - if (m_type != other.m_type) - return to_string() < other.to_string(); - switch (m_type) { - case Type::Bool: - return as_bool() < other.as_bool(); - case Type::Int32: - return as_i32() < other.as_i32(); - case Type::Int64: - return as_i64() < other.as_i64(); - case Type::UnsignedInt32: - return as_u32() < other.as_u32(); - case Type::UnsignedInt64: - return as_u64() < other.as_u64(); - case Type::Float: - return as_float() < other.as_float(); - case Type::String: - return as_string() < other.as_string(); - case Type::Bitmap: - // FIXME: Maybe compare bitmaps somehow differently? - return m_value.as_bitmap < other.m_value.as_bitmap; - case Type::Icon: - // FIXME: Maybe compare icons somehow differently? - return m_value.as_icon < other.m_value.as_icon; - case Type::Color: - return m_value.as_color < other.m_value.as_color; - case Type::Point: - case Type::Size: - case Type::Rect: - case Type::Font: - case Type::TextAlignment: - case Type::ColorRole: - case Type::AlignmentRole: - case Type::FlagRole: - case Type::MetricRole: - case Type::PathRole: - // FIXME: Figure out how to compare these. - VERIFY_NOT_REACHED(); - case Type::Invalid: - break; - } - VERIFY_NOT_REACHED(); + return visit([&](T const& own_value) { + return other.visit( + [&](T const& other_value) -> bool { + // FIXME: Maybe compare icons somehow differently? + if constexpr (IsSame) + return &own_value.impl() < &other_value.impl(); + // FIXME: Maybe compare bitmaps somehow differently? + else if constexpr (IsSame>) + return own_value.ptr() < other_value.ptr(); + else if constexpr (IsSame>) + return own_value->name() < other_value->name(); + else if constexpr (requires { own_value < other_value; }) + return own_value < other_value; + // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it. + else + return to_string() < other.to_string(); + }, + [&](auto const&) -> bool { + return to_string() < other.to_string(); // FIXME: Figure out if this silly behaviour is actually used anywhere, then get rid of it. + }); + }); } - -String Variant::to_string() const -{ - switch (m_type) { - case Type::Bool: - return as_bool() ? "true" : "false"; - case Type::Int32: - return String::number(as_i32()); - case Type::Int64: - return String::number(as_i64()); - case Type::UnsignedInt32: - return String::number(as_u32()); - case Type::UnsignedInt64: - return String::number(as_u64()); - case Type::Float: - return String::formatted("{:.2}", as_float()); - case Type::String: - return as_string(); - case Type::Bitmap: - return "[Gfx::Bitmap]"; - case Type::Icon: - return "[GUI::Icon]"; - case Type::Color: - return as_color().to_string(); - case Type::Point: - return as_point().to_string(); - case Type::Size: - return as_size().to_string(); - case Type::Rect: - return as_rect().to_string(); - case Type::Font: - return String::formatted("[Font: {}]", as_font().name()); - case Type::TextAlignment: { - switch (m_value.as_text_alignment) { - case Gfx::TextAlignment::Center: - return "Gfx::TextAlignment::Center"; - case Gfx::TextAlignment::CenterLeft: - return "Gfx::TextAlignment::CenterLeft"; - case Gfx::TextAlignment::CenterRight: - return "Gfx::TextAlignment::CenterRight"; - case Gfx::TextAlignment::TopLeft: - return "Gfx::TextAlignment::TopLeft"; - case Gfx::TextAlignment::TopRight: - return "Gfx::TextAlignment::TopRight"; - default: - VERIFY_NOT_REACHED(); - } - return ""; - } - case Type::ColorRole: - return String::formatted("Gfx::ColorRole::{}", Gfx::to_string(m_value.as_color_role)); - case Type::AlignmentRole: - return String::formatted("Gfx::AlignmentRole::{}", Gfx::to_string(m_value.as_alignment_role)); - case Type::FlagRole: - return String::formatted("Gfx::FlagRole::{}", Gfx::to_string(m_value.as_flag_role)); - case Type::MetricRole: - return String::formatted("Gfx::MetricRole::{}", Gfx::to_string(m_value.as_metric_role)); - case Type::PathRole: - return String::formatted("Gfx::PathRole::{}", Gfx::to_string(m_value.as_path_role)); - case Type::Invalid: - return "[null]"; - } - VERIFY_NOT_REACHED(); -} - } diff --git a/Userland/Libraries/LibGUI/Variant.h b/Userland/Libraries/LibGUI/Variant.h index 7c617263ff..9aed58ead0 100644 --- a/Userland/Libraries/LibGUI/Variant.h +++ b/Userland/Libraries/LibGUI/Variant.h @@ -1,12 +1,14 @@ /* * Copyright (c) 2018-2020, Andreas Kling * Copyright (c) 2022, Filiph Sandström + * Copyright (c) 2022, Ali Mohammad Pur * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once +#include #include #include #include @@ -15,339 +17,205 @@ namespace GUI { -class Variant { +namespace Detail { +struct Boolean { + bool value; +}; +using VariantUnderlyingType = AK::Variant, NonnullRefPtr, GUI::Icon>; +} + +class Variant : public Detail::VariantUnderlyingType { public: - Variant(); - Variant(bool); - Variant(float); - Variant(i32); - Variant(i64); - Variant(u32); - Variant(u64); - Variant(char const*); - Variant(StringView); - Variant(String const&); - Variant(FlyString const&); - Variant(Gfx::Bitmap const&); - Variant(const GUI::Icon&); - Variant(Gfx::IntPoint const&); - Variant(Gfx::IntSize const&); - Variant(Gfx::IntRect const&); - Variant(Gfx::Font const&); - Variant(const Gfx::TextAlignment); - Variant(const Gfx::ColorRole); - Variant(const Gfx::AlignmentRole); - Variant(const Gfx::FlagRole); - Variant(const Gfx::MetricRole); - Variant(const Gfx::PathRole); + using Detail::VariantUnderlyingType::Variant; + using Detail::VariantUnderlyingType::operator=; + Variant(JsonValue const&); - Variant(Color); - - Variant(Variant const&); - Variant& operator=(Variant const&); - - Variant(Variant&&) = delete; - Variant& operator=(Variant&&); - - void clear(); - ~Variant(); - - enum class Type { - Invalid, - Bool, - Int32, - Int64, - UnsignedInt32, - UnsignedInt64, - Float, - String, - Bitmap, - Color, - Icon, - Point, - Size, - Rect, - Font, - TextAlignment, - ColorRole, - AlignmentRole, - FlagRole, - MetricRole, - PathRole, - }; - - bool is_valid() const { return m_type != Type::Invalid; } - bool is_bool() const { return m_type == Type::Bool; } - bool is_i32() const { return m_type == Type::Int32; } - bool is_i64() const { return m_type == Type::Int64; } - bool is_u32() const { return m_type == Type::UnsignedInt32; } - bool is_u64() const { return m_type == Type::UnsignedInt64; } - bool is_float() const { return m_type == Type::Float; } - bool is_string() const { return m_type == Type::String; } - bool is_bitmap() const { return m_type == Type::Bitmap; } - bool is_color() const { return m_type == Type::Color; } - bool is_icon() const { return m_type == Type::Icon; } - bool is_point() const { return m_type == Type::Point; } - bool is_size() const { return m_type == Type::Size; } - bool is_rect() const { return m_type == Type::Rect; } - bool is_font() const { return m_type == Type::Font; } - bool is_text_alignment() const { return m_type == Type::TextAlignment; } - bool is_color_role() const { return m_type == Type::ColorRole; } - bool is_alignment_role() const { return m_type == Type::AlignmentRole; } - bool is_flag_role() const { return m_type == Type::FlagRole; } - bool is_metric_role() const { return m_type == Type::MetricRole; } - bool is_path_role() const { return m_type == Type::PathRole; } - Type type() const { return m_type; } - - bool as_bool() const + Variant& operator=(JsonValue const&); + Variant(bool v) + : Variant(Detail::Boolean { v }) { - VERIFY(type() == Type::Bool); - return m_value.as_bool; } - - bool to_bool() const + Variant& operator=(bool v) { - if (type() == Type::Bool) - return as_bool(); - if (type() == Type::String) - return !!m_value.as_string; - if (type() == Type::Int32) - return m_value.as_i32 != 0; - if (type() == Type::Int64) - return m_value.as_i64 != 0; - if (type() == Type::UnsignedInt32) - return m_value.as_u32 != 0; - if (type() == Type::UnsignedInt64) - return m_value.as_u64 != 0; - if (type() == Type::Rect) - return !as_rect().is_null(); - if (type() == Type::Size) - return !as_size().is_null(); - if (type() == Type::Point) - return !as_point().is_null(); - return is_valid(); - } - - int as_i32() const - { - VERIFY(type() == Type::Int32); - return m_value.as_i32; - } - - int as_i64() const - { - VERIFY(type() == Type::Int64); - return m_value.as_i64; - } - - u32 as_u32() const - { - VERIFY(type() == Type::UnsignedInt32); - return m_value.as_u32; - } - - u64 as_u64() const - { - VERIFY(type() == Type::UnsignedInt64); - return m_value.as_u64; + set(Detail::Boolean { v }); + return *this; } template + Variant(T&& value) requires(IsConstructible) + : Variant(String(forward(value))) + { + } + template + Variant& operator=(T&& v) requires(IsConstructible) + { + set(String(v)); + return *this; + } + + template T> + Variant(T const& value) + : Variant(NonnullRefPtr>(value)) + { + } + template T> + Variant& operator=(T&& value) + { + set(NonnullRefPtr>(forward(value))); + return *this; + } + + ~Variant() = default; + + bool is_valid() const { return !has(); } + bool is_bool() const { return has(); } + bool is_i32() const { return has(); } + bool is_i64() const { return has(); } + bool is_u32() const { return has(); } + bool is_u64() const { return has(); } + bool is_float() const { return has(); } + bool is_string() const { return has(); } + bool is_bitmap() const { return has>(); } + bool is_color() const { return has(); } + bool is_icon() const { return has(); } + bool is_point() const { return has(); } + bool is_size() const { return has(); } + bool is_rect() const { return has(); } + bool is_font() const { return has>(); } + bool is_text_alignment() const { return has(); } + bool is_color_role() const { return has(); } + bool is_alignment_role() const { return has(); } + bool is_flag_role() const { return has(); } + bool is_metric_role() const { return has(); } + bool is_path_role() const { return has(); } + + bool as_bool() const { return get().value; } + + bool to_bool() const + { + return visit( + [](Empty) { return false; }, + [](Detail::Boolean v) { return v.value; }, + [](String const& v) { return !v.is_null(); }, + [](Integral auto v) { return v != 0; }, + [](OneOf auto const& v) { return !v.is_null(); }, + [](Enum auto const&) { return true; }, + [](OneOf, NonnullRefPtr, GUI::Icon> auto const&) { return true; }); + } + + i32 as_i32() const { return get(); } + i64 as_i64() const { return get(); } + u32 as_u32() const { return get(); } + u64 as_u64() const { return get(); } + + template T to_integer() const { - if (is_i32()) - return as_i32(); - if (is_i64()) - return as_i64(); - if (is_bool()) - return as_bool() ? 1 : 0; - if (is_float()) - return (int)as_float(); - if (is_u32()) { - VERIFY(as_u32() <= INT32_MAX); - return static_cast(as_u32()); - } - if (is_u64()) { - VERIFY(as_u64() <= INT64_MAX); - return static_cast(as_u64()); - } - if (is_string()) - return as_string().to_int().value_or(0); - return 0; + return visit( + [](Empty) -> T { return 0; }, + [](Integral auto v) { return static_cast(v); }, + [](FloatingPoint auto v) { return (T)v; }, + [](Detail::Boolean v) -> T { return v.value ? 1 : 0; }, + [](String const& v) { + if constexpr (IsUnsigned) + return v.to_uint().value_or(0u); + else + return v.to_int().value_or(0); + }, + [](Enum auto const&) -> T { return 0; }, + [](OneOf, NonnullRefPtr, GUI::Icon> auto const&) -> T { return 0; }); } - i32 to_i32() const - { - return to_integer(); - } - - i64 to_i64() const - { - return to_integer(); - } - - float as_float() const - { - VERIFY(type() == Type::Float); - return m_value.as_float; - } + i32 to_i32() const { return to_integer(); } + i64 to_i64() const { return to_integer(); } + float as_float() const { return get(); } float as_float_or(float fallback) const { - if (is_float()) - return as_float(); + if (auto const* p = get_pointer()) + return *p; return fallback; } - Gfx::IntPoint as_point() const - { - return { m_value.as_point.x, m_value.as_point.y }; - } - - Gfx::IntSize as_size() const - { - return { m_value.as_size.width, m_value.as_size.height }; - } - - Gfx::IntRect as_rect() const - { - return { as_point(), as_size() }; - } - - String as_string() const - { - VERIFY(type() == Type::String); - return m_value.as_string; - } - - Gfx::Bitmap const& as_bitmap() const - { - VERIFY(type() == Type::Bitmap); - return *m_value.as_bitmap; - } - - GUI::Icon as_icon() const - { - VERIFY(type() == Type::Icon); - return GUI::Icon(*m_value.as_icon); - } - - Color as_color() const - { - VERIFY(type() == Type::Color); - return Color::from_argb(m_value.as_color); - } - - Gfx::Font const& as_font() const - { - VERIFY(type() == Type::Font); - return *m_value.as_font; - } + Gfx::IntPoint as_point() const { return get(); } + Gfx::IntSize as_size() const { return get(); } + Gfx::IntRect as_rect() const { return get(); } + String as_string() const { return get(); } + Gfx::Bitmap const& as_bitmap() const { return *get>(); } + GUI::Icon as_icon() const { return get(); } + Color as_color() const { return get(); } + Gfx::Font const& as_font() const { return *get>(); } Gfx::TextAlignment to_text_alignment(Gfx::TextAlignment default_value) const { - if (type() != Type::TextAlignment) - return default_value; - return m_value.as_text_alignment; + if (auto const* p = get_pointer()) + return *p; + return default_value; } Gfx::ColorRole to_color_role() const { - if (type() != Type::ColorRole) - return Gfx::ColorRole::NoRole; - return m_value.as_color_role; + if (auto const* p = get_pointer()) + return *p; + return Gfx::ColorRole::NoRole; } Gfx::AlignmentRole to_alignment_role() const { - if (type() != Type::AlignmentRole) - return Gfx::AlignmentRole::NoRole; - return m_value.as_alignment_role; + if (auto const* p = get_pointer()) + return *p; + return Gfx::AlignmentRole::NoRole; } Gfx::FlagRole to_flag_role() const { - if (type() != Type::FlagRole) - return Gfx::FlagRole::NoRole; - return m_value.as_flag_role; + if (auto const* p = get_pointer()) + return *p; + return Gfx::FlagRole::NoRole; } Gfx::MetricRole to_metric_role() const { - if (type() != Type::MetricRole) - return Gfx::MetricRole::NoRole; - return m_value.as_metric_role; + if (auto const* p = get_pointer()) + return *p; + return Gfx::MetricRole::NoRole; } Gfx::PathRole to_path_role() const { - if (type() != Type::PathRole) - return Gfx::PathRole::NoRole; - return m_value.as_path_role; + if (auto const* p = get_pointer()) + return *p; + return Gfx::PathRole::NoRole; } Color to_color(Color default_value = {}) const { - if (type() == Type::Color) - return as_color(); - if (type() == Type::String) { - auto color = Color::from_string(as_string()); - if (color.has_value()) - return color.value(); - } + if (auto const* p = get_pointer()) + return *p; + if (auto const* p = get_pointer()) + return Color::from_string(*p).value_or(default_value); return default_value; } - String to_string() const; + String to_string() const + { + return visit( + [](Empty) -> String { return "[null]"; }, + [](Gfx::TextAlignment v) { return String::formatted("Gfx::TextAlignment::{}", Gfx::to_string(v)); }, + [](Gfx::ColorRole v) { return String::formatted("Gfx::ColorRole::{}", Gfx::to_string(v)); }, + [](Gfx::AlignmentRole v) { return String::formatted("Gfx::AlignmentRole::{}", Gfx::to_string(v)); }, + [](Gfx::FlagRole v) { return String::formatted("Gfx::FlagRole::{}", Gfx::to_string(v)); }, + [](Gfx::MetricRole v) { return String::formatted("Gfx::MetricRole::{}", Gfx::to_string(v)); }, + [](Gfx::PathRole v) { return String::formatted("Gfx::PathRole::{}", Gfx::to_string(v)); }, + [](NonnullRefPtr const& font) { return String::formatted("[Font: {}]", font->name()); }, + [](NonnullRefPtr const&) -> String { return "[Gfx::Bitmap]"; }, + [](GUI::Icon const&) -> String { return "[GUI::Icon]"; }, + [](Detail::Boolean v) { return String::formatted("{}", v.value); }, + [](auto const& v) { return String::formatted("{}", v); }); + } bool operator==(Variant const&) const; bool operator<(Variant const&) const; - -private: - void copy_from(Variant const&); - void move_from(Variant&&); - - struct RawPoint { - int x; - int y; - }; - - struct RawSize { - int width; - int height; - }; - - struct RawRect { - RawPoint location; - RawSize size; - }; - - union { - StringImpl* as_string; - Gfx::Bitmap* as_bitmap; - GUI::IconImpl* as_icon; - Gfx::Font* as_font; - bool as_bool; - i32 as_i32; - i64 as_i64; - u32 as_u32; - u64 as_u64; - float as_float; - Gfx::ARGB32 as_color; - Gfx::TextAlignment as_text_alignment; - Gfx::ColorRole as_color_role; - Gfx::AlignmentRole as_alignment_role; - Gfx::FlagRole as_flag_role; - Gfx::MetricRole as_metric_role; - Gfx::PathRole as_path_role; - RawPoint as_point; - RawSize as_size; - RawRect as_rect; - } m_value; - - Type m_type { Type::Invalid }; }; -char const* to_string(Variant::Type); - }