diff --git a/.rive_head b/.rive_head index e1626a4a..c880cd35 100644 --- a/.rive_head +++ b/.rive_head @@ -1 +1 @@ -9112280455e25db4649d446601f443c763151649 +f3a89390cb428a5ea841d21de91f9cb2adc312df diff --git a/dev/defs/animation/scripted_listener_action.json b/dev/defs/animation/scripted_listener_action.json new file mode 100644 index 00000000..8ee9d6d3 --- /dev/null +++ b/dev/defs/animation/scripted_listener_action.json @@ -0,0 +1,20 @@ +{ + "name": "ScriptedListenerAction", + "key": { + "int": 646, + "string": "scriptedlisteneraction" + }, + "extends": "animation/listener_action.json", + "properties": { + "scriptAssetId": { + "type": "Id", + "typeRuntime": "uint", + "initialValue": "Core.missingId", + "initialValueRuntime": "-1", + "key": { + "int": 930, + "string": "scriptassetid" + } + } + } +} \ No newline at end of file diff --git a/include/rive/animation/listener_action.hpp b/include/rive/animation/listener_action.hpp index 691ab0fd..a66df47b 100644 --- a/include/rive/animation/listener_action.hpp +++ b/include/rive/animation/listener_action.hpp @@ -12,7 +12,8 @@ public: StatusCode import(ImportStack& importStack) override; virtual void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const = 0; + Vec2D previousPosition, + int pointerId) const = 0; }; } // namespace rive diff --git a/include/rive/animation/listener_align_target.hpp b/include/rive/animation/listener_align_target.hpp index 2a150d6b..aacae882 100644 --- a/include/rive/animation/listener_align_target.hpp +++ b/include/rive/animation/listener_align_target.hpp @@ -9,7 +9,8 @@ class ListenerAlignTarget : public ListenerAlignTargetBase public: void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; }; } // namespace rive diff --git a/include/rive/animation/listener_bool_change.hpp b/include/rive/animation/listener_bool_change.hpp index a6f25c24..2d05804f 100644 --- a/include/rive/animation/listener_bool_change.hpp +++ b/include/rive/animation/listener_bool_change.hpp @@ -12,7 +12,8 @@ public: bool validateNestedInputType(const NestedInput* input) const override; void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; }; } // namespace rive diff --git a/include/rive/animation/listener_fire_event.hpp b/include/rive/animation/listener_fire_event.hpp index 4e4a7d23..40fadbfa 100644 --- a/include/rive/animation/listener_fire_event.hpp +++ b/include/rive/animation/listener_fire_event.hpp @@ -9,7 +9,8 @@ class ListenerFireEvent : public ListenerFireEventBase public: void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; }; } // namespace rive diff --git a/include/rive/animation/listener_number_change.hpp b/include/rive/animation/listener_number_change.hpp index 613d7d3c..619bdfbf 100644 --- a/include/rive/animation/listener_number_change.hpp +++ b/include/rive/animation/listener_number_change.hpp @@ -12,7 +12,8 @@ public: bool validateNestedInputType(const NestedInput* input) const override; void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; }; } // namespace rive diff --git a/include/rive/animation/listener_trigger_change.hpp b/include/rive/animation/listener_trigger_change.hpp index 005f4727..838b332a 100644 --- a/include/rive/animation/listener_trigger_change.hpp +++ b/include/rive/animation/listener_trigger_change.hpp @@ -12,7 +12,8 @@ public: bool validateNestedInputType(const NestedInput* input) const override; void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; }; } // namespace rive diff --git a/include/rive/animation/listener_viewmodel_change.hpp b/include/rive/animation/listener_viewmodel_change.hpp index a58ef49b..6f4c8eb8 100644 --- a/include/rive/animation/listener_viewmodel_change.hpp +++ b/include/rive/animation/listener_viewmodel_change.hpp @@ -11,7 +11,8 @@ public: ~ListenerViewModelChange(); void perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const override; + Vec2D previousPosition, + int pointerId) const override; StatusCode import(ImportStack& importStack) override; private: diff --git a/include/rive/animation/scripted_listener_action.hpp b/include/rive/animation/scripted_listener_action.hpp new file mode 100644 index 00000000..b4643376 --- /dev/null +++ b/include/rive/animation/scripted_listener_action.hpp @@ -0,0 +1,36 @@ +#ifndef _RIVE_SCRIPTED_LISTENER_ACTION_HPP_ +#define _RIVE_SCRIPTED_LISTENER_ACTION_HPP_ +#include "rive/generated/animation/scripted_listener_action_base.hpp" +#include "rive/scripted/scripted_object.hpp" +#include +namespace rive +{ +class ScriptedListenerAction : public ScriptedListenerActionBase, + public ScriptedObject +{ +public: + void perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition, + int pointerId) const override; + void performStateful(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition, + int pointerId) const; + + uint32_t assetId() override { return scriptAssetId(); } + bool addScriptedDirt(ComponentDirt value, bool recurse = false) override + { + return false; + } + ScriptProtocol scriptProtocol() override + { + return ScriptProtocol::listenerAction; + } + Component* component() override { return nullptr; } + StatusCode import(ImportStack& importStack) override; + Core* clone() const override; +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/animation/state_machine_instance.hpp b/include/rive/animation/state_machine_instance.hpp index 840c77e4..641630c7 100644 --- a/include/rive/animation/state_machine_instance.hpp +++ b/include/rive/animation/state_machine_instance.hpp @@ -40,6 +40,7 @@ class DataBind; class BindableProperty; class HitDrawable; class ListenerViewModel; +class ScriptedListenerAction; typedef void (*DataBindChanged)(); #ifdef WITH_RIVE_TOOLS @@ -205,6 +206,7 @@ public: bool hasListeners() { return m_hitComponents.size() > 0; } void clearDataContext(); void internalDataContext(DataContext* dataContext); + ScriptedObject* scriptedObject(const ScriptedObject*); #ifdef TESTING size_t hitComponentsCount() { return m_hitComponents.size(); }; HitComponent* hitComponent(size_t index) @@ -238,6 +240,8 @@ private: std::vector m_reportingListenerViewModels; std::unordered_map m_bindablePropertyInstances; + std::unordered_map + m_scriptedListenerActionsMap; std::unordered_map m_bindableDataBindsToTarget; std::unordered_map diff --git a/include/rive/animation/state_machine_listener.hpp b/include/rive/animation/state_machine_listener.hpp index 27e62f6c..ac1c9a60 100644 --- a/include/rive/animation/state_machine_listener.hpp +++ b/include/rive/animation/state_machine_listener.hpp @@ -31,7 +31,8 @@ public: void performChanges(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const; + Vec2D previousPosition, + int pointerId) const; void decodeViewModelPathIds(Span value) override; void copyViewModelPathIds(const StateMachineListenerBase& object) override; std::vector viewModelPathIdsBuffer() const; diff --git a/include/rive/assets/script_asset.hpp b/include/rive/assets/script_asset.hpp index 8ae0501d..6de03604 100644 --- a/include/rive/assets/script_asset.hpp +++ b/include/rive/assets/script_asset.hpp @@ -25,7 +25,8 @@ enum ScriptProtocol node, layout, converter, - pathEffect + pathEffect, + listenerAction }; #ifdef WITH_RIVE_SCRIPTING diff --git a/include/rive/generated/animation/scripted_listener_action_base.hpp b/include/rive/generated/animation/scripted_listener_action_base.hpp new file mode 100644 index 00000000..9a920330 --- /dev/null +++ b/include/rive/generated/animation/scripted_listener_action_base.hpp @@ -0,0 +1,71 @@ +#ifndef _RIVE_SCRIPTED_LISTENER_ACTION_BASE_HPP_ +#define _RIVE_SCRIPTED_LISTENER_ACTION_BASE_HPP_ +#include "rive/animation/listener_action.hpp" +#include "rive/core/field_types/core_uint_type.hpp" +namespace rive +{ +class ScriptedListenerActionBase : public ListenerAction +{ +protected: + typedef ListenerAction Super; + +public: + static const uint16_t typeKey = 646; + + /// Helper to quickly determine if a core object extends another without + /// RTTI at runtime. + bool isTypeOf(uint16_t typeKey) const override + { + switch (typeKey) + { + case ScriptedListenerActionBase::typeKey: + case ListenerActionBase::typeKey: + return true; + default: + return false; + } + } + + uint16_t coreType() const override { return typeKey; } + + static const uint16_t scriptAssetIdPropertyKey = 930; + +protected: + uint32_t m_ScriptAssetId = -1; + +public: + inline uint32_t scriptAssetId() const { return m_ScriptAssetId; } + void scriptAssetId(uint32_t value) + { + if (m_ScriptAssetId == value) + { + return; + } + m_ScriptAssetId = value; + scriptAssetIdChanged(); + } + + Core* clone() const override; + void copy(const ScriptedListenerActionBase& object) + { + m_ScriptAssetId = object.m_ScriptAssetId; + ListenerAction::copy(object); + } + + bool deserialize(uint16_t propertyKey, BinaryReader& reader) override + { + switch (propertyKey) + { + case scriptAssetIdPropertyKey: + m_ScriptAssetId = CoreUintType::deserialize(reader); + return true; + } + return ListenerAction::deserialize(propertyKey, reader); + } + +protected: + virtual void scriptAssetIdChanged() {} +}; +} // namespace rive + +#endif \ No newline at end of file diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp index f868968c..4a541aed 100644 --- a/include/rive/generated/core_registry.hpp +++ b/include/rive/generated/core_registry.hpp @@ -50,6 +50,7 @@ #include "rive/animation/nested_simple_animation.hpp" #include "rive/animation/nested_state_machine.hpp" #include "rive/animation/nested_trigger.hpp" +#include "rive/animation/scripted_listener_action.hpp" #include "rive/animation/state_machine.hpp" #include "rive/animation/state_machine_bool.hpp" #include "rive/animation/state_machine_component.hpp" @@ -477,6 +478,8 @@ public: return new AnimationState(); case NestedTriggerBase::typeKey: return new NestedTrigger(); + case ScriptedListenerActionBase::typeKey: + return new ScriptedListenerAction(); case KeyedObjectBase::typeKey: return new KeyedObject(); case AnimationBase::typeKey: @@ -1194,6 +1197,9 @@ public: case NestedInputBase::inputIdPropertyKey: object->as()->inputId(value); break; + case ScriptedListenerActionBase::scriptAssetIdPropertyKey: + object->as()->scriptAssetId(value); + break; case KeyedObjectBase::objectIdPropertyKey: object->as()->objectId(value); break; @@ -2737,6 +2743,9 @@ public: return object->as()->animationId(); case NestedInputBase::inputIdPropertyKey: return object->as()->inputId(); + case ScriptedListenerActionBase::scriptAssetIdPropertyKey: + return object->as() + ->scriptAssetId(); case KeyedObjectBase::objectIdPropertyKey: return object->as()->objectId(); case BlendAnimationBase::animationIdPropertyKey: @@ -3725,6 +3734,7 @@ public: case ListenerInputChangeBase::nestedInputIdPropertyKey: case AnimationStateBase::animationIdPropertyKey: case NestedInputBase::inputIdPropertyKey: + case ScriptedListenerActionBase::scriptAssetIdPropertyKey: case KeyedObjectBase::objectIdPropertyKey: case BlendAnimationBase::animationIdPropertyKey: case BlendAnimationDirectBase::inputIdPropertyKey: @@ -4377,6 +4387,8 @@ public: return object->is(); case NestedInputBase::inputIdPropertyKey: return object->is(); + case ScriptedListenerActionBase::scriptAssetIdPropertyKey: + return object->is(); case KeyedObjectBase::objectIdPropertyKey: return object->is(); case BlendAnimationBase::animationIdPropertyKey: diff --git a/include/rive/scripted/scripted_object.hpp b/include/rive/scripted/scripted_object.hpp index 568a1715..c7127165 100644 --- a/include/rive/scripted/scripted_object.hpp +++ b/include/rive/scripted/scripted_object.hpp @@ -33,6 +33,8 @@ protected: #ifdef WITH_RIVE_TOOLS bool hasValidVM(); #endif +private: + DataContext* m_dataContext = nullptr; public: virtual ~ScriptedObject() { scriptDispose(); } @@ -48,7 +50,8 @@ public: void scriptUpdate(); void reinit(); virtual void markNeedsUpdate(); - virtual DataContext* dataContext() { return nullptr; } + virtual DataContext* dataContext() { return m_dataContext; } + void dataContext(DataContext* value) { m_dataContext = value; } #ifdef WITH_RIVE_SCRIPTING virtual bool scriptInit(lua_State* state); lua_State* state() { return m_state; } diff --git a/src/animation/listener_align_target.cpp b/src/animation/listener_align_target.cpp index 415321e6..4cc53e4f 100644 --- a/src/animation/listener_align_target.cpp +++ b/src/animation/listener_align_target.cpp @@ -7,7 +7,8 @@ using namespace rive; void ListenerAlignTarget::perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { auto coreTarget = stateMachineInstance->artboard()->resolve(targetId()); if (coreTarget == nullptr || !coreTarget->is()) diff --git a/src/animation/listener_bool_change.cpp b/src/animation/listener_bool_change.cpp index 20bdf0ea..e1c1c128 100644 --- a/src/animation/listener_bool_change.cpp +++ b/src/animation/listener_bool_change.cpp @@ -26,7 +26,8 @@ bool ListenerBoolChange::validateNestedInputType(const NestedInput* input) const void ListenerBoolChange::perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { if (nestedInputId() != Core::emptyId) { diff --git a/src/animation/listener_fire_event.cpp b/src/animation/listener_fire_event.cpp index bd6d0744..e1821d30 100644 --- a/src/animation/listener_fire_event.cpp +++ b/src/animation/listener_fire_event.cpp @@ -6,7 +6,8 @@ using namespace rive; void ListenerFireEvent::perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { auto coreEvent = stateMachineInstance->artboard()->resolve(eventId()); if (coreEvent == nullptr || !coreEvent->is()) diff --git a/src/animation/listener_number_change.cpp b/src/animation/listener_number_change.cpp index a57d0dfa..c0716d21 100644 --- a/src/animation/listener_number_change.cpp +++ b/src/animation/listener_number_change.cpp @@ -29,7 +29,8 @@ bool ListenerNumberChange::validateNestedInputType( void ListenerNumberChange::perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { if (nestedInputId() != Core::emptyId) { diff --git a/src/animation/listener_trigger_change.cpp b/src/animation/listener_trigger_change.cpp index f8d85846..178d199c 100644 --- a/src/animation/listener_trigger_change.cpp +++ b/src/animation/listener_trigger_change.cpp @@ -30,7 +30,8 @@ bool ListenerTriggerChange::validateNestedInputType( void ListenerTriggerChange::perform(StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { if (nestedInputId() != Core::emptyId) { diff --git a/src/animation/listener_viewmodel_change.cpp b/src/animation/listener_viewmodel_change.cpp index 5244d9c4..c4bd4776 100644 --- a/src/animation/listener_viewmodel_change.cpp +++ b/src/animation/listener_viewmodel_change.cpp @@ -37,7 +37,8 @@ StatusCode ListenerViewModelChange::import(ImportStack& importStack) void ListenerViewModelChange::perform( StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { // Get the bindable property instance from the state machine instance // context diff --git a/src/animation/scripted_listener_action.cpp b/src/animation/scripted_listener_action.cpp new file mode 100644 index 00000000..4b3b959b --- /dev/null +++ b/src/animation/scripted_listener_action.cpp @@ -0,0 +1,86 @@ +#include "rive/animation/scripted_listener_action.hpp" +#include "rive/animation/state_machine_instance.hpp" + +using namespace rive; + +// Note: performStateful is the actual instance of the ScriptedListenerAction +// that will run the script. perform itself will look for the map between the +// stateless and the stateful instances of this class. +void ScriptedListenerAction::performStateful( + StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition, + int pointerId) const +{ +#ifdef WITH_RIVE_SCRIPTING + if (m_state == nullptr) + { + return; + } + // Stack: [] + rive_lua_pushRef(m_state, m_self); + // Stack: [self] + lua_getfield(m_state, -1, "perform"); + + // Stack: [self, field] + lua_pushvalue(m_state, -2); + + // Stack: [self, field, self] + lua_newrive(m_state, pointerId, position); + + // Stack: [self, field, self, pointerEvent] + if (static_cast(rive_lua_pcall(m_state, 2, 0)) == LUA_OK) + { + rive_lua_pop(m_state, 1); + } + else + { + rive_lua_pop(m_state, 2); + } +#endif +} + +void ScriptedListenerAction::perform(StateMachineInstance* stateMachineInstance, + Vec2D position, + Vec2D previousPosition, + int pointerId) const +{ +#ifdef WITH_RIVE_SCRIPTING + auto scriptedObject = stateMachineInstance->scriptedObject(this); + if (scriptedObject != nullptr) + { + auto statefulListenerAction = + static_cast(scriptedObject); + statefulListenerAction->performStateful(stateMachineInstance, + position, + previousPosition, + pointerId); + } +#endif +} + +StatusCode ScriptedListenerAction::import(ImportStack& importStack) +{ + auto result = registerReferencer(importStack); + if (result != StatusCode::Ok) + { + return result; + } + return Super::import(importStack); +} + +Core* ScriptedListenerAction::clone() const +{ + ScriptedListenerAction* twin = + ScriptedListenerActionBase::clone()->as(); + if (m_fileAsset != nullptr) + { + twin->setAsset(m_fileAsset); + } + for (auto prop : m_customProperties) + { + auto clonedValue = prop->clone()->as(); + twin->addProperty(clonedValue); + } + return twin; +} \ No newline at end of file diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp index e7d02ee9..964b7a22 100644 --- a/src/animation/state_machine_instance.cpp +++ b/src/animation/state_machine_instance.cpp @@ -19,6 +19,8 @@ #include "rive/animation/state_machine_trigger.hpp" #include "rive/animation/state_machine.hpp" #include "rive/animation/state_transition.hpp" +#include "rive/animation/listener_action.hpp" +#include "rive/animation/scripted_listener_action.hpp" #include "rive/animation/transition_condition.hpp" #include "rive/animation/transition_comparator.hpp" #include "rive/animation/transition_property_viewmodel_comparator.hpp" @@ -1480,9 +1482,41 @@ StateMachineInstance::StateMachineInstance(const StateMachine* machine, this); m_hitComponents.push_back(std::move(hc)); } + // Initialize local instances of ScriptedListenerActions + for (std::size_t i = 0; i < machine->listenerCount(); i++) + { + auto listener = machine->listener(i); + + for (std::size_t j = 0; j < listener->actionCount(); j++) + { + auto action = listener->action(j); + if (action->is()) + { + auto scriptedListenerAction = + action->as(); + auto scriptedListenerActionClone = + static_cast( + scriptedListenerAction->clone()); + scriptedListenerActionClone->reinit(); + m_scriptedListenerActionsMap[scriptedListenerAction] = + scriptedListenerActionClone; + } + } + } sortHitComponents(); } +ScriptedObject* StateMachineInstance::scriptedObject( + const ScriptedObject* source) +{ + auto itr = m_scriptedListenerActionsMap.find(source); + if (itr != m_scriptedListenerActionsMap.end()) + { + return itr->second; + } + return nullptr; +} + StateMachineInstance::~StateMachineInstance() { unbind(); @@ -1506,6 +1540,12 @@ StateMachineInstance::~StateMachineInstance() delete listenerViewModel; } m_bindablePropertyInstances.clear(); + for (auto& pair : m_scriptedListenerActionsMap) + { + delete pair.second; + pair.second = nullptr; + } + m_scriptedListenerActionsMap.clear(); } void StateMachineInstance::removeEventListeners() @@ -1816,6 +1856,10 @@ void StateMachineInstance::internalDataContext(DataContext* dataContext) { listenerViewModel->bindFromContext(dataContext); } + for (auto& scriptedObjectItr : m_scriptedListenerActionsMap) + { + scriptedObjectItr.second->dataContext(dataContext); + } } void StateMachineInstance::rebind() @@ -1955,7 +1999,8 @@ void StateMachineInstance::notifyListenerViewModels( { listenerViewModel->listener()->performChanges(this, Vec2D(), - Vec2D()); + Vec2D(), + 0); } } } @@ -2011,7 +2056,7 @@ void StateMachineInstance::notifyEventListeners( sourceArtboard->resolve(listener->eventId()); if (listenerEvent == event.event()) { - listener->performChanges(this, Vec2D(), Vec2D()); + listener->performChanges(this, Vec2D(), Vec2D(), 0); break; } } diff --git a/src/animation/state_machine_listener.cpp b/src/animation/state_machine_listener.cpp index 3595f6b4..7b39e3ab 100644 --- a/src/animation/state_machine_listener.cpp +++ b/src/animation/state_machine_listener.cpp @@ -44,11 +44,15 @@ const ListenerAction* StateMachineListener::action(size_t index) const void StateMachineListener::performChanges( StateMachineInstance* stateMachineInstance, Vec2D position, - Vec2D previousPosition) const + Vec2D previousPosition, + int pointerId) const { for (auto& action : m_actions) { - action->perform(stateMachineInstance, position, previousPosition); + action->perform(stateMachineInstance, + position, + previousPosition, + pointerId); } } diff --git a/src/assets/script_asset.cpp b/src/assets/script_asset.cpp index c6eb4f60..1542c463 100644 --- a/src/assets/script_asset.cpp +++ b/src/assets/script_asset.cpp @@ -66,7 +66,8 @@ bool OptionalScriptedMethods::verifyImplementation(ScriptedObject* object, if (scriptProtocol == ScriptProtocol::node || scriptProtocol == ScriptProtocol::layout || scriptProtocol == ScriptProtocol::converter || - scriptProtocol == ScriptProtocol::pathEffect) + scriptProtocol == ScriptProtocol::pathEffect || + scriptProtocol == ScriptProtocol::listenerAction) { if (static_cast(lua_getfield(state, -1, "update")) == LUA_TFUNCTION) diff --git a/src/generated/animation/scripted_listener_action_base.cpp b/src/generated/animation/scripted_listener_action_base.cpp new file mode 100644 index 00000000..6ac036e4 --- /dev/null +++ b/src/generated/animation/scripted_listener_action_base.cpp @@ -0,0 +1,11 @@ +#include "rive/generated/animation/scripted_listener_action_base.hpp" +#include "rive/animation/scripted_listener_action.hpp" + +using namespace rive; + +Core* ScriptedListenerActionBase::clone() const +{ + auto cloned = new ScriptedListenerAction(); + cloned->copy(*this); + return cloned; +} diff --git a/src/listener_group.cpp b/src/listener_group.cpp index dec81ac2..217e6a18 100644 --- a/src/listener_group.cpp +++ b/src/listener_group.cpp @@ -191,7 +191,8 @@ ProcessEventResult ListenerGroup::processEvent( _listener->performChanges( stateMachineInstance, position, - Vec2D(previousPosition->x, previousPosition->y)); + Vec2D(previousPosition->x, previousPosition->y), + pointerId); stateMachineInstance->markNeedsAdvance(); consume(); } @@ -206,7 +207,8 @@ ProcessEventResult ListenerGroup::processEvent( _listener->performChanges( stateMachineInstance, position, - Vec2D(previousPosition->x, previousPosition->y)); + Vec2D(previousPosition->x, previousPosition->y), + pointerId); stateMachineInstance->markNeedsAdvance(); consume(); } @@ -221,7 +223,8 @@ ProcessEventResult ListenerGroup::processEvent( _listener->performChanges( stateMachineInstance, position, - Vec2D(previousPosition->x, previousPosition->y)); + Vec2D(previousPosition->x, previousPosition->y), + pointerId); stateMachineInstance->markNeedsAdvance(); if (!m_hasDragged) { diff --git a/src/lua/lua_state.cpp b/src/lua/lua_state.cpp index 0327364c..bfdd7cb1 100644 --- a/src/lua/lua_state.cpp +++ b/src/lua/lua_state.cpp @@ -14,7 +14,14 @@ static int viewmodel_new(lua_State* L) ViewModel* viewModel = (ViewModel*)lua_touserdata(L, lua_upvalueindex(1)); if (viewModel) { + +#ifdef WITH_RIVE_TOOLS + viewModel->file()->triggerViewModelCreatedCallback(true); +#endif auto instance = viewModel->createInstance(); +#ifdef WITH_RIVE_TOOLS + viewModel->file()->triggerViewModelCreatedCallback(false); +#endif lua_newrive(L, L, ref_rcp(viewModel), instance); return 1; } diff --git a/tests/unit_tests/assets/scripted_listener_action.riv b/tests/unit_tests/assets/scripted_listener_action.riv new file mode 100644 index 00000000..bdb08d84 Binary files /dev/null and b/tests/unit_tests/assets/scripted_listener_action.riv differ diff --git a/tests/unit_tests/runtime/scripting/scripting_listener_action_test.cpp b/tests/unit_tests/runtime/scripting/scripting_listener_action_test.cpp new file mode 100644 index 00000000..38889b88 --- /dev/null +++ b/tests/unit_tests/runtime/scripting/scripting_listener_action_test.cpp @@ -0,0 +1,46 @@ + +#include "catch.hpp" +#include "scripting_test_utilities.hpp" +#include "rive/animation/state_machine_instance.hpp" +#include "rive/lua/rive_lua_libs.hpp" +#include "rive/viewmodel/viewmodel_instance_string.hpp" +#include "rive_file_reader.hpp" + +using namespace rive; + +TEST_CASE("scripted listener action", "[silver]") +{ + rive::SerializingFactory silver; + auto file = ReadRiveFile("assets/scripted_listener_action.riv", &silver); + auto artboard = file->artboardDefault(); + + silver.frameSize(artboard->width(), artboard->height()); + REQUIRE(artboard != nullptr); + auto stateMachine = artboard->stateMachineAt(0); + + auto vmi = file->createViewModelInstance(artboard.get()); + stateMachine->bindViewModelInstance(vmi); + stateMachine->advanceAndApply(0.1f); + + auto renderer = silver.makeRenderer(); + artboard->draw(renderer.get()); + + silver.addFrame(); + + stateMachine->pointerDown(rive::Vec2D(200.0f, 20.0f), 1); + stateMachine->pointerUp(rive::Vec2D(200.0f, 20.0f), 1); + stateMachine->advanceAndApply(0.016f); + artboard->draw(renderer.get()); + + stateMachine->pointerDown(rive::Vec2D(300.0f, 20.0f), 2); + stateMachine->pointerUp(rive::Vec2D(300.0f, 20.0f), 2); + stateMachine->advanceAndApply(0.016f); + artboard->draw(renderer.get()); + + stateMachine->pointerDown(rive::Vec2D(400.0f, 20.0f), 3); + stateMachine->pointerUp(rive::Vec2D(400.0f, 20.0f), 3); + stateMachine->advanceAndApply(0.016f); + artboard->draw(renderer.get()); + + CHECK(silver.matches("scripted_listener_action")); +} \ No newline at end of file diff --git a/tests/unit_tests/silvers/scripted_listener_action.sriv b/tests/unit_tests/silvers/scripted_listener_action.sriv new file mode 100644 index 00000000..961305a1 Binary files /dev/null and b/tests/unit_tests/silvers/scripted_listener_action.sriv differ