Add support to Listeners for events from nested artboards

- Propagate events up to parent Artboard state machines
- Add Event to Listener types and display in combobox
- Add support for StateMachineListeners to listen for events

Still needs implementation on CPP runtime.

In this example, the rectangles are in a nested artboard. Clicking them fires an event from the nested artboard up to the parent artboard which has a listener which updates an input triggering the animation.

https://github.com/rive-app/rive/assets/186340/22bfb00e-8d1e-46f0-8faa-d2d5e5a1bbfb

Diffs=
1a9dd7e97 Add support to Listeners for events from nested artboards (#5923)

Co-authored-by: Philip Chung <philterdesign@gmail.com>
diff --git a/.rive_head b/.rive_head
index 413d351..fe1cfcf 100644
--- a/.rive_head
+++ b/.rive_head
@@ -1 +1 @@
-52a1a6f8888c9134de8dce0393dd3b0d6757f7de
+1a9dd7e97e623eb30dbec164ae0935b2ad848c1b
diff --git a/dev/defs/animation/state_machine_listener.json b/dev/defs/animation/state_machine_listener.json
index 12a6892..4e99535 100644
--- a/dev/defs/animation/state_machine_listener.json
+++ b/dev/defs/animation/state_machine_listener.json
@@ -15,7 +15,7 @@
         "int": 224,
         "string": "targetid"
       },
-      "description": "Identifier used to track the object use as a target fo this listener."
+      "description": "Identifier used to track the object use as a target for this listener."
     },
     "listenerTypeValue": {
       "type": "uint",
@@ -25,6 +25,17 @@
         "string": "listenertypevalue"
       },
       "description": "Listener type (hover, click, etc)."
+    },
+    "eventId": {
+      "type": "Id",
+      "typeRuntime": "uint",
+      "initialValue": "Core.missingId",
+      "initialValueRuntime": "-1",
+      "key": {
+        "int": 399,
+        "string": "eventid"
+      },
+      "description": "Event id for the associated event, if listenerType is event"
     }
   }
 }
\ 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 cb1d7d8..069d1a7 100644
--- a/include/rive/animation/state_machine_instance.hpp
+++ b/include/rive/animation/state_machine_instance.hpp
@@ -51,6 +51,7 @@
 
     template <typename SMType, typename InstType>
     InstType* getNamedInput(const std::string& name) const;
+    void notifyEventListeners(std::vector<EventReport> events, NestedArtboard* source);
 
 public:
     StateMachineInstance(const StateMachine* machine, ArtboardInstance* instance);
@@ -99,6 +100,12 @@
     /// the backing artboard (explicitly not allowed on Scenes).
     Artboard* artboard() { return m_artboardInstance; }
 
+    void setParentStateMachineInstance(StateMachineInstance* instance) { m_parentStateMachineInstance = instance; }
+    StateMachineInstance* parentStateMachineInstance() { return m_parentStateMachineInstance; }
+
+    void setParentNestedArtboard(NestedArtboard* artboard) { m_parentNestedArtboard = artboard; }
+    NestedArtboard* parentNestedArtboard() { return m_parentNestedArtboard; }
+
     /// Tracks an event that reported, will be cleared at the end of the next advance.
     void reportEvent(Event* event, float secondsDelay = 0.0f);
 
@@ -123,6 +130,8 @@
     StateMachineLayerInstance* m_layers;
     std::vector<std::unique_ptr<HitShape>> m_hitShapes;
     std::vector<NestedArtboard*> m_hitNestedArtboards;
+    StateMachineInstance* m_parentStateMachineInstance = nullptr;
+    NestedArtboard* m_parentNestedArtboard = nullptr;
 };
 } // namespace rive
 #endif
diff --git a/include/rive/generated/animation/state_machine_listener_base.hpp b/include/rive/generated/animation/state_machine_listener_base.hpp
index d4373f4..d02347b 100644
--- a/include/rive/generated/animation/state_machine_listener_base.hpp
+++ b/include/rive/generated/animation/state_machine_listener_base.hpp
@@ -30,10 +30,12 @@
 
     static const uint16_t targetIdPropertyKey = 224;
     static const uint16_t listenerTypeValuePropertyKey = 225;
+    static const uint16_t eventIdPropertyKey = 399;
 
 private:
     uint32_t m_TargetId = 0;
     uint32_t m_ListenerTypeValue = 0;
+    uint32_t m_EventId = -1;
 
 public:
     inline uint32_t targetId() const { return m_TargetId; }
@@ -58,11 +60,23 @@
         listenerTypeValueChanged();
     }
 
+    inline uint32_t eventId() const { return m_EventId; }
+    void eventId(uint32_t value)
+    {
+        if (m_EventId == value)
+        {
+            return;
+        }
+        m_EventId = value;
+        eventIdChanged();
+    }
+
     Core* clone() const override;
     void copy(const StateMachineListenerBase& object)
     {
         m_TargetId = object.m_TargetId;
         m_ListenerTypeValue = object.m_ListenerTypeValue;
+        m_EventId = object.m_EventId;
         StateMachineComponent::copy(object);
     }
 
@@ -76,6 +90,9 @@
             case listenerTypeValuePropertyKey:
                 m_ListenerTypeValue = CoreUintType::deserialize(reader);
                 return true;
+            case eventIdPropertyKey:
+                m_EventId = CoreUintType::deserialize(reader);
+                return true;
         }
         return StateMachineComponent::deserialize(propertyKey, reader);
     }
@@ -83,6 +100,7 @@
 protected:
     virtual void targetIdChanged() {}
     virtual void listenerTypeValueChanged() {}
+    virtual void eventIdChanged() {}
 };
 } // namespace rive
 
diff --git a/include/rive/generated/core_registry.hpp b/include/rive/generated/core_registry.hpp
index 78cdee6..5ca3da9 100644
--- a/include/rive/generated/core_registry.hpp
+++ b/include/rive/generated/core_registry.hpp
@@ -482,6 +482,9 @@
             case StateMachineListenerBase::listenerTypeValuePropertyKey:
                 object->as<StateMachineListenerBase>()->listenerTypeValue(value);
                 break;
+            case StateMachineListenerBase::eventIdPropertyKey:
+                object->as<StateMachineListenerBase>()->eventId(value);
+                break;
             case KeyFrameBase::framePropertyKey:
                 object->as<KeyFrameBase>()->frame(value);
                 break;
@@ -1243,6 +1246,8 @@
                 return object->as<StateMachineListenerBase>()->targetId();
             case StateMachineListenerBase::listenerTypeValuePropertyKey:
                 return object->as<StateMachineListenerBase>()->listenerTypeValue();
+            case StateMachineListenerBase::eventIdPropertyKey:
+                return object->as<StateMachineListenerBase>()->eventId();
             case KeyFrameBase::framePropertyKey:
                 return object->as<KeyFrameBase>()->frame();
             case InterpolatingKeyFrameBase::interpolationTypePropertyKey:
@@ -1741,6 +1746,7 @@
             case KeyedPropertyBase::propertyKeyPropertyKey:
             case StateMachineListenerBase::targetIdPropertyKey:
             case StateMachineListenerBase::listenerTypeValuePropertyKey:
+            case StateMachineListenerBase::eventIdPropertyKey:
             case KeyFrameBase::framePropertyKey:
             case InterpolatingKeyFrameBase::interpolationTypePropertyKey:
             case InterpolatingKeyFrameBase::interpolatorIdPropertyKey:
diff --git a/include/rive/listener_type.hpp b/include/rive/listener_type.hpp
index f128b65..d79f68c 100644
--- a/include/rive/listener_type.hpp
+++ b/include/rive/listener_type.hpp
@@ -9,6 +9,7 @@
     down = 2,
     up = 3,
     move = 4,
+    event = 5,
 };
 }
 #endif
\ No newline at end of file
diff --git a/src/animation/state_machine_instance.cpp b/src/animation/state_machine_instance.cpp
index 54c337b..eeb9562 100644
--- a/src/animation/state_machine_instance.cpp
+++ b/src/animation/state_machine_instance.cpp
@@ -408,6 +408,7 @@
                         break;
                     case ListenerType::enter:
                     case ListenerType::exit:
+                    case ListenerType::event:
                         break;
                 }
             }
@@ -509,6 +510,18 @@
         if (nestedArtboard->hasNestedStateMachines())
         {
             m_hitNestedArtboards.push_back(nestedArtboard);
+            for (auto animation : nestedArtboard->nestedAnimations())
+            {
+                if (animation->is<NestedStateMachine>())
+                {
+                    animation->as<NestedStateMachine>()
+                        ->stateMachineInstance()
+                        ->setParentNestedArtboard(nestedArtboard);
+                    animation->as<NestedStateMachine>()
+                        ->stateMachineInstance()
+                        ->setParentStateMachineInstance(this);
+                }
+            }
         }
     }
 }
@@ -526,6 +539,7 @@
 
 bool StateMachineInstance::advance(float seconds)
 {
+    this->notifyEventListeners(m_reportedEvents, nullptr);
     m_reportedEvents.clear();
     m_needsAdvance = false;
     for (size_t i = 0; i < m_layerCount; i++)
@@ -675,4 +689,37 @@
     auto coreObject = m_artboardInstance->resolve(objectId);
     CallbackData data(this, elapsedSeconds);
     CoreRegistry::setCallback(coreObject, propertyKey, data);
+}
+
+void StateMachineInstance::notifyEventListeners(std::vector<EventReport> events, NestedArtboard* source)
+{
+    if (events.size() > 0)
+    {
+        // We trigger the listeners in order
+        for (size_t i = 0; i < m_machine->listenerCount(); i++)
+        {
+            auto listener = m_machine->listener(i);
+            auto target = artboard()->resolve(listener->targetId());
+            if (listener != nullptr && 
+                listener->listenerType() == ListenerType::event &&
+                (source == nullptr || source == target))
+            {
+                for (const auto event : events)
+                {
+                    auto sourceArtboard = source == nullptr ? artboard() : source->artboard();
+                    auto listenerEvent = sourceArtboard->resolve(listener->eventId());
+                    if (listenerEvent == event.event())
+                    {
+                        listener->performChanges(this, Vec2D());
+                        break;
+                    }
+                }
+            }
+        }
+        // Bubble the event up to parent artboard state machines immediately
+        if (m_parentStateMachineInstance != nullptr)
+        {
+            m_parentStateMachineInstance->notifyEventListeners(events, m_parentNestedArtboard);
+        }
+    }
 }
\ No newline at end of file