feature(scripting): add support for accessing view models and enum pr… (#11437) 620000211e

feature(scripting): add support for accessing view models and enum properties

Co-authored-by: hernan <hernan@rive.app>
This commit is contained in:
bodymovin
2026-01-13 00:48:26 +00:00
parent b974d1f75a
commit c511795426
7 changed files with 165 additions and 3 deletions

View File

@@ -1 +1 @@
67006966a5ea7000971204e0dd9bc03613f2b9bc
620000211e23da8be6c8603bf69f2b4d682817fd

View File

@@ -13,6 +13,7 @@
#include "rive/math/path_measure.hpp"
#include "rive/shapes/paint/image_sampler.hpp"
#include "rive/shapes/paint/shape_paint.hpp"
#include "rive/viewmodel/data_enum.hpp"
#include "rive/viewmodel/viewmodel_instance_boolean.hpp"
#include "rive/viewmodel/viewmodel_instance_color.hpp"
#include "rive/viewmodel/viewmodel_instance_enum.hpp"
@@ -150,6 +151,9 @@ enum class LuaAtoms : int16_t
getBoolean,
getColor,
getList,
getViewModel,
getEnum,
values,
addListener,
removeListener,
fire,
@@ -702,6 +706,26 @@ public:
void setValue(bool value);
};
class ScriptedEnumValues
{
public:
ScriptedEnumValues(lua_State* L, DataEnum* value) :
m_state(L), m_dataEnum(value)
{}
static constexpr uint8_t luaTag = LUA_T_COUNT + 34;
static constexpr const char* luaName = "EnumValues";
static constexpr bool hasMetatable = true;
void dataEnum(DataEnum* value) { m_dataEnum = value; }
int pushValue(int index);
int pushLength();
const lua_State* state() const { return m_state; }
private:
lua_State* m_state = nullptr;
DataEnum* m_dataEnum = nullptr;
};
class ScriptedPropertyEnum : public ScriptedProperty
{
public:

View File

@@ -7,7 +7,9 @@
#include "rive/viewmodel/viewmodel_property_string.hpp"
#include "rive/viewmodel/viewmodel_property_trigger.hpp"
#include "rive/viewmodel/viewmodel_property_list.hpp"
#include "rive/viewmodel/viewmodel_property_viewmodel.hpp"
#include "rive/viewmodel/viewmodel_instance_list.hpp"
#include "rive/viewmodel/viewmodel_instance_enum.hpp"
#include "rive/viewmodel/viewmodel_instance_list_item.hpp"
#include <math.h>
@@ -16,6 +18,7 @@
using namespace rive;
static void pushViewModelInstanceValue(lua_State* L,
rcp<ViewModel> viewModel,
ViewModelInstanceValue* propValue)
{
switch (propValue->coreType())
@@ -62,6 +65,13 @@ static void pushViewModelInstanceValue(lua_State* L,
L,
ref_rcp(propValue->as<ViewModelInstanceEnum>()));
break;
case ViewModelInstanceViewModelBase::typeKey:
lua_newrive<ScriptedPropertyViewModel>(
L,
L,
viewModel,
ref_rcp(propValue->as<ViewModelInstanceViewModel>()));
break;
default:
lua_pushnil(L);
break;
@@ -309,6 +319,12 @@ int ScriptedViewModel::pushValue(const char* name, int coreType)
m_state,
nullptr);
break;
case ViewModelPropertyViewModelBase::typeKey:
lua_newrive<ScriptedPropertyViewModel>(m_state,
m_state,
nullptr,
nullptr);
break;
}
}
}
@@ -322,7 +338,7 @@ int ScriptedViewModel::pushValue(const char* name, int coreType)
}
else
{
pushViewModelInstanceValue(m_state, propValue);
pushViewModelInstanceValue(m_state, m_viewModel, propValue);
}
}
m_propertyRefs[name] = lua_ref(m_state, -1);
@@ -482,6 +498,23 @@ static int property_namecall_atom(lua_State* L,
list->addItemAt(listItem, index);
return 0;
}
case (int)LuaAtoms::values:
{
auto viewModelInstanceEnum =
property->instanceValue()->as<ViewModelInstanceValue>();
DataEnum* dataEnum = nullptr;
auto viewModelPropertyEnum =
viewModelInstanceEnum->viewModelProperty()
->as<ViewModelPropertyEnum>();
if (viewModelPropertyEnum)
{
dataEnum = viewModelPropertyEnum->dataEnum();
}
lua_newrive<ScriptedEnumValues>(L, L, dataEnum);
return 1;
}
}
error = true;
return 0;
@@ -542,6 +575,21 @@ static int vm_namecall(lua_State* L)
assert(vm->state() == L);
return vm->pushValue(name, ViewModelInstanceListBase::typeKey);
}
case (int)LuaAtoms::getViewModel:
{
size_t namelen = 0;
const char* name = luaL_checklstring(L, 2, &namelen);
assert(vm->state() == L);
return vm->pushValue(name,
ViewModelInstanceViewModelBase::typeKey);
}
case (int)LuaAtoms::getEnum:
{
size_t namelen = 0;
const char* name = luaL_checklstring(L, 2, &namelen);
assert(vm->state() == L);
return vm->pushValue(name, ViewModelInstanceEnumBase::typeKey);
}
case (int)LuaAtoms::instance:
case (int)LuaAtoms::newAtom:
{
@@ -885,6 +933,36 @@ int ScriptedPropertyList::pushValue(int index)
return 1;
}
int ScriptedEnumValues::pushValue(int index)
{
if (m_dataEnum && m_state)
{
auto values = m_dataEnum->values();
if (index >= 0 && index < values.size())
{
auto value = values[index];
lua_pushstring(m_state, value->key().c_str());
return 1;
}
}
lua_pushnil(m_state);
return 1;
}
int ScriptedEnumValues::pushLength()
{
if (m_dataEnum)
{
lua_pushinteger(m_state, (int)m_dataEnum->values().size());
}
else
{
lua_pushinteger(m_state, 0);
}
return 1;
}
static int property_list_index(lua_State* L)
{
int atom;
@@ -907,6 +985,27 @@ static int property_list_index(lua_State* L)
}
}
static int enum_value_length(lua_State* L)
{
auto enumValues = lua_torive<ScriptedEnumValues>(L, 1);
assert(enumValues->state() == L);
return enumValues->pushLength();
}
static int enum_value_index(lua_State* L)
{
int atom;
const char* key = lua_tostringatom(L, 2, &atom);
auto enumValues = lua_torive<ScriptedEnumValues>(L, 1);
// if it's not an atom it should be an index into the array
if (!key)
{
int index = luaL_checkinteger(L, 2);
return enumValues->pushValue(index - 1);
}
return 0;
}
static int property_number_index(lua_State* L)
{
int atom;
@@ -1266,6 +1365,19 @@ int luaopen_rive_properties(lua_State* L)
lua_pop(L, 1); // pop the metatable
}
{
lua_register_rive<ScriptedEnumValues>(L);
lua_pushcfunction(L, enum_value_index, nullptr);
lua_setfield(L, -2, "__index");
lua_pushcfunction(L, enum_value_length, nullptr);
lua_setfield(L, -2, "__len");
lua_setreadonly(L, -1, true);
lua_pop(L, 1); // pop the metatable
}
return 0;
}
#endif

View File

@@ -96,6 +96,9 @@ std::unordered_map<std::string, int16_t> atoms = {
{"getBoolean", (int16_t)LuaAtoms::getBoolean},
{"getColor", (int16_t)LuaAtoms::getColor},
{"getList", (int16_t)LuaAtoms::getList},
{"getViewModel", (int16_t)LuaAtoms::getViewModel},
{"getEnum", (int16_t)LuaAtoms::getEnum},
{"values", (int16_t)LuaAtoms::values},
{"addListener", (int16_t)LuaAtoms::addListener},
{"removeListener", (int16_t)LuaAtoms::removeListener},
{"fire", (int16_t)LuaAtoms::fire},

Binary file not shown.

View File

@@ -551,4 +551,27 @@ end
CHECK(vm.console[5] ==
std::string("enum changed to ") + std::string("red"));
CHECK(vm.console[6] == std::string("enum is ") + std::string("red"));
}
}
TEST_CASE("Access view model properties and enum properties", "[silver]")
{
SerializingFactory silver;
auto file = ReadRiveFile("assets/viewmodel_access.riv", &silver);
auto artboard = file->artboardDefault();
silver.frameSize(artboard->width(), artboard->height());
auto stateMachine = artboard->stateMachineAt(0);
int viewModelId = artboard.get()->viewModelId();
auto vmi = viewModelId == -1
? file->createViewModelInstance(artboard.get())
: file->createViewModelInstance(viewModelId, 0);
stateMachine->bindViewModelInstance(vmi);
auto renderer = silver.makeRenderer();
stateMachine->advanceAndApply(0.016f);
artboard->draw(renderer.get());
CHECK(silver.matches("viewmodel_access"));
}

Binary file not shown.