mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 21:21:17 +01:00
feat: Scripted Enum (#10829) 650a980d41
Adds support for ScriptedEnums (ViewModel enums). This PR does not include enums as Inputs, that will follow subsequently Co-authored-by: Philip Chung <philterdesign@gmail.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
396c65832ecf6122fd9a0976726d6e40bb0b5be1
|
||||
650a980d413d906648698116815311e26ae3199d
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "rive/shapes/paint/image_sampler.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_boolean.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_color.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_enum.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_value.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_viewmodel.hpp"
|
||||
#include "rive/viewmodel/viewmodel_instance_number.hpp"
|
||||
@@ -510,13 +511,22 @@ public:
|
||||
void setValue(bool value);
|
||||
};
|
||||
|
||||
class ScriptedPropertyEnum : public ScriptedProperty
|
||||
{
|
||||
public:
|
||||
ScriptedPropertyEnum(lua_State* L, rcp<ViewModelInstanceEnum> value);
|
||||
static constexpr uint8_t luaTag = LUA_T_COUNT + 19;
|
||||
static constexpr const char* luaName = "Property<enum>";
|
||||
static constexpr bool hasMetatable = true;
|
||||
|
||||
int pushValue();
|
||||
void setValue(const std::string& value);
|
||||
};
|
||||
|
||||
// Make
|
||||
// ScriptedPropertyViewModel
|
||||
// - Nullable ViewModelInstanceValue (ViewModelInstanceViewModel)
|
||||
// - Requires ViewModel to know which properties to expect
|
||||
// ScriptedPropertyEnum
|
||||
// - Nullable ViewModelInstanceValue (ViewModelInstanceEnum)
|
||||
// - Requires DataEnum for expected types
|
||||
// ScriptedPropertyArtboard
|
||||
// - Nullable ViewModelInstanceValue (ViewModelInstanceArtboard)
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#include "rive/lua/rive_lua_libs.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_boolean.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_color.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_enum.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_number.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_string.hpp"
|
||||
#include "rive/viewmodel/viewmodel_property_trigger.hpp"
|
||||
@@ -53,6 +54,12 @@ static void pushViewModelInstanceValue(lua_State* L,
|
||||
L,
|
||||
ref_rcp(propValue->as<ViewModelInstanceBoolean>()));
|
||||
break;
|
||||
case ViewModelInstanceEnumBase::typeKey:
|
||||
lua_newrive<ScriptedPropertyEnum>(
|
||||
L,
|
||||
L,
|
||||
ref_rcp(propValue->as<ViewModelInstanceEnum>()));
|
||||
break;
|
||||
default:
|
||||
lua_pushnil(L);
|
||||
break;
|
||||
@@ -279,6 +286,11 @@ int ScriptedViewModel::pushValue(const char* name, int coreType)
|
||||
m_state,
|
||||
nullptr);
|
||||
break;
|
||||
case ViewModelPropertyEnumBase::typeKey:
|
||||
lua_newrive<ScriptedPropertyEnum>(m_state,
|
||||
m_state,
|
||||
nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -472,6 +484,9 @@ static int property_namecall(lua_State* L)
|
||||
case ScriptedPropertyBoolean::luaTag:
|
||||
name = ScriptedPropertyBoolean::luaName;
|
||||
break;
|
||||
case ScriptedPropertyEnum::luaTag:
|
||||
name = ScriptedPropertyEnum::luaName;
|
||||
break;
|
||||
default:
|
||||
luaL_typeerror(L, 1, name);
|
||||
break;
|
||||
@@ -612,6 +627,40 @@ int ScriptedPropertyBoolean::pushValue()
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScriptedPropertyEnum::ScriptedPropertyEnum(lua_State* L,
|
||||
rcp<ViewModelInstanceEnum> value) :
|
||||
ScriptedProperty(L, std::move(value))
|
||||
{}
|
||||
|
||||
void ScriptedPropertyEnum::setValue(const std::string& value)
|
||||
{
|
||||
if (m_instanceValue)
|
||||
{
|
||||
m_instanceValue->as<ViewModelInstanceEnum>()->value(value);
|
||||
}
|
||||
}
|
||||
|
||||
int ScriptedPropertyEnum::pushValue()
|
||||
{
|
||||
if (m_instanceValue)
|
||||
{
|
||||
auto vmi = m_instanceValue->as<ViewModelInstanceEnum>();
|
||||
auto vmProp = vmi->viewModelProperty()->as<ViewModelPropertyEnum>();
|
||||
if (vmProp != nullptr && vmProp->dataEnum() != nullptr)
|
||||
{
|
||||
auto values = vmProp->dataEnum()->values();
|
||||
uint32_t index = vmi->propertyValue();
|
||||
if (index < values.size())
|
||||
{
|
||||
lua_pushstring(m_state, values[index]->key().c_str());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
lua_pushstring(m_state, "");
|
||||
return 1;
|
||||
}
|
||||
|
||||
ScriptedPropertyList::ScriptedPropertyList(lua_State* L,
|
||||
rcp<ViewModelInstanceList> value) :
|
||||
ScriptedProperty(L, std::move(value))
|
||||
@@ -903,6 +952,51 @@ static int property_boolean_newindex(lua_State* L)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int property_enum_index(lua_State* L)
|
||||
{
|
||||
int atom;
|
||||
const char* key = lua_tostringatom(L, 2, &atom);
|
||||
if (!key)
|
||||
{
|
||||
luaL_typeerrorL(L, 2, lua_typename(L, LUA_TSTRING));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto propertyEnum = lua_torive<ScriptedPropertyEnum>(L, 1);
|
||||
switch (atom)
|
||||
{
|
||||
case (int)LuaAtoms::value:
|
||||
assert(propertyEnum->state() == L);
|
||||
return propertyEnum->pushValue();
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int property_enum_newindex(lua_State* L)
|
||||
{
|
||||
int atom;
|
||||
const char* key = lua_tostringatom(L, 2, &atom);
|
||||
if (!key)
|
||||
{
|
||||
luaL_typeerrorL(L, 2, lua_typename(L, LUA_TSTRING));
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto propertyEnum = lua_torive<ScriptedPropertyEnum>(L, 1);
|
||||
switch (atom)
|
||||
{
|
||||
case (int)LuaAtoms::value:
|
||||
{
|
||||
propertyEnum->setValue(luaL_checkstring(L, 3));
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int luaopen_rive_properties(lua_State* L)
|
||||
{
|
||||
{
|
||||
@@ -995,6 +1089,22 @@ int luaopen_rive_properties(lua_State* L)
|
||||
lua_pop(L, 1); // pop the metatable
|
||||
}
|
||||
|
||||
{
|
||||
lua_register_rive<ScriptedPropertyEnum>(L);
|
||||
|
||||
lua_pushcfunction(L, property_enum_index, nullptr);
|
||||
lua_setfield(L, -2, "__index");
|
||||
|
||||
lua_pushcfunction(L, property_enum_newindex, nullptr);
|
||||
lua_setfield(L, -2, "__newindex");
|
||||
|
||||
lua_pushcfunction(L, property_namecall, nullptr);
|
||||
lua_setfield(L, -2, "__namecall");
|
||||
|
||||
lua_setreadonly(L, -1, true);
|
||||
lua_pop(L, 1); // pop the metatable
|
||||
}
|
||||
|
||||
{
|
||||
lua_register_rive<ScriptedPropertyTrigger>(L);
|
||||
|
||||
@@ -1018,6 +1128,6 @@ int luaopen_rive_properties(lua_State* L)
|
||||
lua_pop(L, 1); // pop the metatable
|
||||
}
|
||||
|
||||
return 8;
|
||||
return 9;
|
||||
}
|
||||
#endif
|
||||
|
||||
BIN
tests/unit_tests/assets/scripted_enum.riv
Normal file
BIN
tests/unit_tests/assets/scripted_enum.riv
Normal file
Binary file not shown.
@@ -478,4 +478,77 @@ end
|
||||
CHECK(vm.console[1] == ("bool changed to true"));
|
||||
CHECK(vm.console[2] == ("bool is true"));
|
||||
CHECK(vm.console[3] == ("bool changed to false"));
|
||||
}
|
||||
|
||||
TEST_CASE("scripted enum can be passed to luau", "[scripting_properties]")
|
||||
{
|
||||
auto file = ReadRiveFile("assets/scripted_enum.riv");
|
||||
|
||||
auto artboard = file->artboard("EnumArtboard")->instance();
|
||||
REQUIRE(artboard != nullptr);
|
||||
auto viewModelInstance =
|
||||
file->createDefaultViewModelInstance(artboard.get());
|
||||
REQUIRE(viewModelInstance != nullptr);
|
||||
artboard->bindViewModelInstance(viewModelInstance);
|
||||
artboard->advance(0.0f);
|
||||
|
||||
CHECK(viewModelInstance->viewModel()->name() == "EnumVM");
|
||||
auto property = viewModelInstance->propertyValue("EnumProp");
|
||||
REQUIRE(property != nullptr);
|
||||
REQUIRE(property->is<rive::ViewModelInstanceEnum>());
|
||||
|
||||
ScriptingTest vm(
|
||||
R"TEST_SRC(
|
||||
function init(vm)
|
||||
print(`enum init to {vm.EnumProp.value}`)
|
||||
vm.EnumProp:addListener(vm.EnumProp, enumChanged)
|
||||
end
|
||||
|
||||
function setValue(vm, value:string)
|
||||
vm.EnumProp.value = value
|
||||
print(`enum is {vm.EnumProp.value}`)
|
||||
end
|
||||
|
||||
function enumChanged(e)
|
||||
print(`enum changed to {e.value}`)
|
||||
end
|
||||
|
||||
)TEST_SRC");
|
||||
auto L = vm.state();
|
||||
|
||||
lua_newrive<ScriptedViewModel>(L,
|
||||
L,
|
||||
ref_rcp(viewModelInstance->viewModel()),
|
||||
viewModelInstance);
|
||||
lua_getglobal(L, "init");
|
||||
lua_pushvalue(L, -2);
|
||||
CHECK(lua_pcall(L, 1, 0, 0) == LUA_OK);
|
||||
|
||||
// Change the enum value via script multiple times
|
||||
lua_getglobal(L, "setValue");
|
||||
lua_pushvalue(L, -2); // vm
|
||||
lua_pushstring(L, "blue");
|
||||
CHECK(lua_pcall(L, 2, 0, 0) == LUA_OK);
|
||||
|
||||
lua_getglobal(L, "setValue");
|
||||
lua_pushvalue(L, -2); // vm
|
||||
lua_pushstring(L, "orange");
|
||||
CHECK(lua_pcall(L, 2, 0, 0) == LUA_OK);
|
||||
|
||||
lua_getglobal(L, "setValue");
|
||||
lua_pushvalue(L, -2); // vm
|
||||
lua_pushstring(L, "red");
|
||||
CHECK(lua_pcall(L, 2, 0, 0) == LUA_OK);
|
||||
|
||||
CHECK(vm.console.size() == 7);
|
||||
CHECK(vm.console[0] == std::string("enum init to ") + std::string("white"));
|
||||
CHECK(vm.console[1] ==
|
||||
std::string("enum changed to ") + std::string("blue"));
|
||||
CHECK(vm.console[2] == std::string("enum is ") + std::string("blue"));
|
||||
CHECK(vm.console[3] ==
|
||||
std::string("enum changed to ") + std::string("orange"));
|
||||
CHECK(vm.console[4] == std::string("enum is ") + std::string("orange"));
|
||||
CHECK(vm.console[5] ==
|
||||
std::string("enum changed to ") + std::string("red"));
|
||||
CHECK(vm.console[6] == std::string("enum is ") + std::string("red"));
|
||||
}
|
||||
Reference in New Issue
Block a user