From 4fb9090e176c4adfc2058ddf7146acdefe83b1e9 Mon Sep 17 00:00:00 2001 From: AmaiKinono Date: Sat, 12 Oct 2024 00:29:50 +0800 Subject: [PATCH 1/2] Allow custom getter/setter on scoped enum --- Include/RmlUi/Core/DataModelHandle.h | 3 +- Include/RmlUi/Core/DataTypeRegister.h | 10 ++++++ Tests/Source/UnitTests/DataBinding.cpp | 47 ++++++++++++++++++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/Include/RmlUi/Core/DataModelHandle.h b/Include/RmlUi/Core/DataModelHandle.h index 3829d70e0..15e197933 100644 --- a/Include/RmlUi/Core/DataModelHandle.h +++ b/Include/RmlUi/Core/DataModelHandle.h @@ -143,7 +143,8 @@ class RMLUICORE_API DataModelConstructor { template inline bool DataModelConstructor::RegisterScalar(DataTypeGetFunc get_func, DataTypeSetFunc set_func) { - static_assert(!is_builtin_data_scalar::value, + // Though scoped enum is builtin scalar type, we allow custom getter/setter on it. + static_assert(!is_builtin_data_scalar::value || is_scoped_enum::value, "Cannot register scalar data type function. Arithmetic types and String are handled internally and does not need to be registered."); const FamilyId id = Family::Id(); diff --git a/Include/RmlUi/Core/DataTypeRegister.h b/Include/RmlUi/Core/DataTypeRegister.h index b9f55b126..42d8a2759 100644 --- a/Include/RmlUi/Core/DataTypeRegister.h +++ b/Include/RmlUi/Core/DataTypeRegister.h @@ -37,6 +37,16 @@ namespace Rml { +template ::value> +struct is_scoped_enum { + static constexpr bool value = false; +}; + +template +struct is_scoped_enum { + static constexpr bool value = !std::is_convertible::value; +}; + template struct is_builtin_data_scalar { static constexpr bool value = diff --git a/Tests/Source/UnitTests/DataBinding.cpp b/Tests/Source/UnitTests/DataBinding.cpp index 3aa8ee976..c457bcc85 100644 --- a/Tests/Source/UnitTests/DataBinding.cpp +++ b/Tests/Source/UnitTests/DataBinding.cpp @@ -81,6 +81,7 @@ static const String document_rml = R"(

{{ s5.val }}

{{ simple }}

{{ scoped }}

+

{{ scoped_custom }}

Basic

{{ basic.a }}

@@ -212,6 +213,8 @@ enum SimpleEnum { Simple_Zero = 0, Simple_One, Simple_Two }; enum class ScopedEnum : uint64_t { Zero = 0, One, Two }; +enum class ScopedEnumCustom { Zero, One, Two }; + struct Globals { int i0 = 0; int* i1 = new int(1); @@ -220,6 +223,7 @@ struct Globals { SimpleEnum simple = Simple_One; ScopedEnum scoped = ScopedEnum::One; + ScopedEnumCustom scoped_custom = ScopedEnumCustom::One; String s0 = "s0"; String* s1 = new String("s1"); @@ -371,6 +375,45 @@ bool InitializeDataBindings(Context* context) handle.RegisterMember("val", &StringWrap::val); } + constructor.RegisterScalar( + [](const ScopedEnumCustom& value, Rml::Variant& variant) { + if (value == ScopedEnumCustom::Zero) + { + variant = "Zero"; + } + else if (value == ScopedEnumCustom::One) + { + variant = "One"; + } + else if (value == ScopedEnumCustom::Two) + { + variant = "Two"; + } + else + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Invalid value for ScopedEnumCustom type."); + } + }, + [](ScopedEnumCustom& value, const Rml::Variant& variant) { + Rml::String str = variant.Get(); + if (str == "Zero") + { + value = ScopedEnumCustom::Zero; + } + else if (str == "One") + { + value = ScopedEnumCustom::One; + } + else if (str == "Two") + { + value = ScopedEnumCustom::Two; + } + else + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Can't convert '%s' to ScopedEnumCustom.", str.c_str()); + } + }); + { // Globals constructor.Bind("i0", &globals.i0); @@ -387,6 +430,7 @@ bool InitializeDataBindings(Context* context) constructor.Bind("simple", &globals.simple); constructor.Bind("scoped", &globals.scoped); + constructor.Bind("scoped_custom", &globals.scoped_custom); // Invalid: Each of the following should give a compile-time failure. // constructor.Bind("x0", &globals.x0); // constructor.Bind("x1", &globals.x1); @@ -482,6 +526,9 @@ TEST_CASE("data_binding") TestsShell::RenderLoop(); + Element* element = document->GetElementById("scoped_custom"); + CHECK(element->GetInnerRML() == "One"); + document->Close(); TestsShell::ShutdownShell(); From 3ad95a350c8c4263acbf627e0992e20573d17b8e Mon Sep 17 00:00:00 2001 From: AmaiKinono Date: Sat, 12 Oct 2024 00:54:31 +0800 Subject: [PATCH 2/2] Allow custom getter/setter on enum --- Include/RmlUi/Core/DataModelHandle.h | 4 +- Include/RmlUi/Core/DataTypeRegister.h | 10 ----- Tests/Source/UnitTests/DataBinding.cpp | 59 ++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 15 deletions(-) diff --git a/Include/RmlUi/Core/DataModelHandle.h b/Include/RmlUi/Core/DataModelHandle.h index 15e197933..12641e566 100644 --- a/Include/RmlUi/Core/DataModelHandle.h +++ b/Include/RmlUi/Core/DataModelHandle.h @@ -143,8 +143,8 @@ class RMLUICORE_API DataModelConstructor { template inline bool DataModelConstructor::RegisterScalar(DataTypeGetFunc get_func, DataTypeSetFunc set_func) { - // Though scoped enum is builtin scalar type, we allow custom getter/setter on it. - static_assert(!is_builtin_data_scalar::value || is_scoped_enum::value, + // Though enum is builtin scalar type, we allow custom getter/setter on it. + static_assert(!is_builtin_data_scalar::value || std::is_enum::value, "Cannot register scalar data type function. Arithmetic types and String are handled internally and does not need to be registered."); const FamilyId id = Family::Id(); diff --git a/Include/RmlUi/Core/DataTypeRegister.h b/Include/RmlUi/Core/DataTypeRegister.h index 42d8a2759..b9f55b126 100644 --- a/Include/RmlUi/Core/DataTypeRegister.h +++ b/Include/RmlUi/Core/DataTypeRegister.h @@ -37,16 +37,6 @@ namespace Rml { -template ::value> -struct is_scoped_enum { - static constexpr bool value = false; -}; - -template -struct is_scoped_enum { - static constexpr bool value = !std::is_convertible::value; -}; - template struct is_builtin_data_scalar { static constexpr bool value = diff --git a/Tests/Source/UnitTests/DataBinding.cpp b/Tests/Source/UnitTests/DataBinding.cpp index c457bcc85..aca93eeed 100644 --- a/Tests/Source/UnitTests/DataBinding.cpp +++ b/Tests/Source/UnitTests/DataBinding.cpp @@ -79,8 +79,9 @@ static const String document_rml = R"(

{{ s3.val }}

{{ s4.val }}

{{ s5.val }}

-

{{ simple }}

-

{{ scoped }}

+

{{ simple }}

+

{{ simple_custom }}

+

{{ scoped }}

{{ scoped_custom }}

Basic

@@ -211,6 +212,8 @@ struct StringWrap { enum SimpleEnum { Simple_Zero = 0, Simple_One, Simple_Two }; +enum SimpleEnumCustom { Simple_Zero_Custom, Simple_One_Custom, Simple_Two_Custom }; + enum class ScopedEnum : uint64_t { Zero = 0, One, Two }; enum class ScopedEnumCustom { Zero, One, Two }; @@ -222,6 +225,7 @@ struct Globals { SharedPtr i3 = MakeShared(3); SimpleEnum simple = Simple_One; + SimpleEnumCustom simple_custom = Simple_One_Custom; ScopedEnum scoped = ScopedEnum::One; ScopedEnumCustom scoped_custom = ScopedEnumCustom::One; @@ -375,6 +379,45 @@ bool InitializeDataBindings(Context* context) handle.RegisterMember("val", &StringWrap::val); } + constructor.RegisterScalar( + [](const SimpleEnumCustom& value, Rml::Variant& variant) { + if (value == Simple_Zero_Custom) + { + variant = "Zero"; + } + else if (value == Simple_One_Custom) + { + variant = "One"; + } + else if (value == Simple_Two_Custom) + { + variant = "Two"; + } + else + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Invalid value for SimpleEnumCustom type."); + } + }, + [](SimpleEnumCustom& value, const Rml::Variant& variant) { + Rml::String str = variant.Get(); + if (str == "Zero") + { + value = Simple_Zero_Custom; + } + else if (str == "One") + { + value = Simple_One_Custom; + } + else if (str == "Two") + { + value = Simple_Two_Custom; + } + else + { + Rml::Log::Message(Rml::Log::LT_ERROR, "Can't convert '%s' to SimpleEnumCustom.", str.c_str()); + } + }); + constructor.RegisterScalar( [](const ScopedEnumCustom& value, Rml::Variant& variant) { if (value == ScopedEnumCustom::Zero) @@ -429,6 +472,7 @@ bool InitializeDataBindings(Context* context) constructor.Bind("s5", &globals.s5); constructor.Bind("simple", &globals.simple); + constructor.Bind("simple_custom", &globals.simple_custom); constructor.Bind("scoped", &globals.scoped); constructor.Bind("scoped_custom", &globals.scoped_custom); // Invalid: Each of the following should give a compile-time failure. @@ -526,7 +570,16 @@ TEST_CASE("data_binding") TestsShell::RenderLoop(); - Element* element = document->GetElementById("scoped_custom"); + Element* element = document->GetElementById("simple"); + CHECK(element->GetInnerRML() == "1"); + + element = document->GetElementById("simple_custom"); + CHECK(element->GetInnerRML() == "One"); + + element = document->GetElementById("scoped"); + CHECK(element->GetInnerRML() == "1"); + + element = document->GetElementById("scoped_custom"); CHECK(element->GetInnerRML() == "One"); document->Close();