mirror of
https://github.com/rive-app/rive-cpp.git
synced 2026-01-18 13:11:19 +01:00
295 lines
10 KiB
C++
295 lines
10 KiB
C++
#ifndef _RIVE_STATE_MACHINE_INSTANCE_HPP_
|
|
#define _RIVE_STATE_MACHINE_INSTANCE_HPP_
|
|
|
|
#include <string>
|
|
#include <stddef.h>
|
|
#include <vector>
|
|
#include <unordered_map>
|
|
#include "rive/animation/linear_animation_instance.hpp"
|
|
#include "rive/animation/state_instance.hpp"
|
|
#include "rive/animation/state_transition.hpp"
|
|
#include "rive/core/field_types/core_callback_type.hpp"
|
|
#include "rive/hit_result.hpp"
|
|
#include "rive/listener_type.hpp"
|
|
#include "rive/nested_animation.hpp"
|
|
#include "rive/scene.hpp"
|
|
#include "rive/data_bind/data_bind_container.hpp"
|
|
#include "rive/input/focusable.hpp"
|
|
|
|
namespace rive
|
|
{
|
|
class StateMachine;
|
|
class LayerState;
|
|
class SMIInput;
|
|
class ArtboardInstance;
|
|
class SMIBool;
|
|
class SMINumber;
|
|
class SMITrigger;
|
|
class Shape;
|
|
class StateMachineLayerInstance;
|
|
class HitComponent;
|
|
class HitShape;
|
|
class ListenerGroup;
|
|
class NestedArtboard;
|
|
class NestedEventListener;
|
|
class NestedEventNotifier;
|
|
class Event;
|
|
class KeyedProperty;
|
|
class EventReport;
|
|
class DataBind;
|
|
class BindableProperty;
|
|
class HitDrawable;
|
|
class ListenerViewModel;
|
|
class ScriptedListenerAction;
|
|
typedef void (*DataBindChanged)();
|
|
|
|
#ifdef WITH_RIVE_TOOLS
|
|
class StateMachineInstance;
|
|
typedef void (*InputChanged)(StateMachineInstance*, uint64_t);
|
|
#endif
|
|
|
|
class StateMachineInstance : public Scene,
|
|
public NestedEventNotifier,
|
|
public NestedEventListener,
|
|
public DataBindContainer
|
|
{
|
|
friend class SMIInput;
|
|
friend class KeyedProperty;
|
|
friend class HitComponent;
|
|
friend class StateMachineLayerInstance;
|
|
|
|
private:
|
|
/// Provide a hitListener if you want to process a down or an up for the
|
|
/// pointer position too.
|
|
HitResult updateListeners(Vec2D position,
|
|
ListenerType hitListener,
|
|
int pointerId = 0,
|
|
float timeStamp = 0);
|
|
|
|
template <typename SMType, typename InstType>
|
|
InstType* getNamedInput(const std::string& name) const;
|
|
void notifyEventListeners(const std::vector<EventReport>& events,
|
|
NestedArtboard* source);
|
|
void sortHitComponents();
|
|
double randomValue();
|
|
StateTransition* findRandomTransition(
|
|
StateInstance* stateFromInstance,
|
|
StateMachineLayerInstance* layerInstance);
|
|
StateTransition* findAllowedTransition(
|
|
StateInstance* stateFromInstance,
|
|
StateMachineLayerInstance* layerInstance);
|
|
|
|
bool m_ownsDataContext = false;
|
|
DataContext* m_DataContext = nullptr;
|
|
void addToHitLookup(Component* target,
|
|
bool isLayoutComponent,
|
|
std::unordered_map<Component*, HitDrawable*>& hitLookup,
|
|
ListenerGroup* listenerGroup,
|
|
bool isOpaque);
|
|
|
|
public:
|
|
StateMachineInstance(const StateMachine* machine,
|
|
ArtboardInstance* instance);
|
|
StateMachineInstance(StateMachineInstance const&) = delete;
|
|
~StateMachineInstance() override;
|
|
|
|
void markNeedsAdvance();
|
|
// Advance the state machine by the specified time. Returns true if the
|
|
// state machine will continue to animate after this advance.
|
|
bool advance(float seconds, bool newFrame);
|
|
|
|
bool advance(float seconds) { return advance(seconds, true); }
|
|
|
|
// Returns true when the StateMachineInstance has more data to process.
|
|
bool needsAdvance() const;
|
|
|
|
void resetState();
|
|
|
|
// Returns a pointer to the instance's stateMachine
|
|
const StateMachine* stateMachine() const { return m_machine; }
|
|
|
|
size_t inputCount() const override { return m_inputInstances.size(); }
|
|
SMIInput* input(size_t index) const override;
|
|
SMIBool* getBool(const std::string& name) const override;
|
|
SMINumber* getNumber(const std::string& name) const override;
|
|
SMITrigger* getTrigger(const std::string& name) const override;
|
|
void bindViewModelInstance(
|
|
rcp<ViewModelInstance> viewModelInstance) override;
|
|
void dataContext(DataContext* dataContext);
|
|
DataContext* dataContext() const { return m_DataContext; }
|
|
void rebind() override;
|
|
|
|
size_t currentAnimationCount() const;
|
|
const LinearAnimationInstance* currentAnimationByIndex(size_t index) const;
|
|
|
|
// The number of state changes that occurred across all layers on the
|
|
// previous advance.
|
|
std::size_t stateChangedCount() const;
|
|
|
|
// Returns the state name for states that changed in layers on the
|
|
// previously called advance. If the index of out of range, it returns
|
|
// the empty string.
|
|
const LayerState* stateChangedByIndex(size_t index) const;
|
|
|
|
bool advanceAndApply(float secs) override;
|
|
void advancedDataContext();
|
|
void reset();
|
|
std::string name() const override;
|
|
HitResult pointerMove(Vec2D position,
|
|
float timeStamp = 0,
|
|
int pointerId = 0) override;
|
|
HitResult pointerDown(Vec2D position, int pointerId = 0) override;
|
|
HitResult pointerUp(Vec2D position, int pointerId = 0) override;
|
|
HitResult pointerExit(Vec2D position, int pointerId = 0) override;
|
|
HitResult dragStart(Vec2D position,
|
|
float timeStamp = 0,
|
|
bool disablePointer = true,
|
|
int pointerId = 0);
|
|
HitResult dragEnd(Vec2D position, float timeStamp = 0, int pointerId = 0);
|
|
|
|
bool keyInput(Key value,
|
|
KeyModifiers modifiers,
|
|
bool isPressed,
|
|
bool isRepeat);
|
|
bool textInput(const std::string& text);
|
|
|
|
bool tryChangeState();
|
|
bool hitTest(Vec2D position) const;
|
|
|
|
float durationSeconds() const override { return -1; }
|
|
Loop loop() const override { return Loop::oneShot; }
|
|
bool isTranslucent() const override { return true; }
|
|
|
|
/// Allow anything referencing a concrete StateMachineInstace access to
|
|
/// the backing artboard (explicitly not allowed on Scenes).
|
|
Artboard* artboard() const { 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; }
|
|
void notify(const std::vector<EventReport>& events,
|
|
NestedArtboard* context) override;
|
|
void notifyListenerViewModels(
|
|
const std::vector<ListenerViewModel*>& events);
|
|
|
|
/// Tracks an event that reported, will be cleared at the end of the next
|
|
/// advance.
|
|
void reportEvent(Event* event, float secondsDelay = 0.0f) override;
|
|
|
|
void applyEvents();
|
|
|
|
void reportListenerViewModel(ListenerViewModel*);
|
|
|
|
/// Gets the number of events that reported since the last advance.
|
|
std::size_t reportedEventCount() const;
|
|
|
|
/// Gets a reported event at an index < reportedEventCount().
|
|
const EventReport reportedEventAt(std::size_t index) const;
|
|
bool playsAudio() override { return true; }
|
|
BindableProperty* bindablePropertyInstance(
|
|
BindableProperty* bindableProperty) const;
|
|
DataBind* bindableDataBindToSource(
|
|
BindableProperty* bindableProperty) const;
|
|
DataBind* bindableDataBindToTarget(
|
|
BindableProperty* bindableProperty) const;
|
|
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)
|
|
{
|
|
if (index < m_hitComponents.size())
|
|
{
|
|
return m_hitComponents[index].get();
|
|
}
|
|
return nullptr;
|
|
}
|
|
const LayerState* layerState(size_t index);
|
|
#endif
|
|
void enablePointerEvents(int pointerId = 0);
|
|
void disablePointerEvents(int pointerId = 0);
|
|
|
|
private:
|
|
std::vector<EventReport> m_reportedEvents;
|
|
std::vector<EventReport> m_reportingEvents;
|
|
const StateMachine* m_machine;
|
|
bool m_needsAdvance = false;
|
|
std::vector<SMIInput*> m_inputInstances; // we own each pointer
|
|
size_t m_layerCount;
|
|
StateMachineLayerInstance* m_layers;
|
|
std::vector<std::unique_ptr<HitComponent>> m_hitComponents;
|
|
std::vector<std::unique_ptr<ListenerGroup>> m_listenerGroups;
|
|
StateMachineInstance* m_parentStateMachineInstance = nullptr;
|
|
NestedArtboard* m_parentNestedArtboard = nullptr;
|
|
std::vector<DataBind*> m_dataBinds;
|
|
std::vector<ListenerViewModel*> m_listenerViewModels;
|
|
std::vector<ListenerViewModel*> m_reportedListenerViewModels;
|
|
std::vector<ListenerViewModel*> m_reportingListenerViewModels;
|
|
std::unordered_map<BindableProperty*, BindableProperty*>
|
|
m_bindablePropertyInstances;
|
|
std::unordered_map<const ScriptedObject*, ScriptedObject*>
|
|
m_scriptedListenerActionsMap;
|
|
std::unordered_map<BindableProperty*, DataBind*>
|
|
m_bindableDataBindsToTarget;
|
|
std::unordered_map<BindableProperty*, DataBind*>
|
|
m_bindableDataBindsToSource;
|
|
uint8_t m_drawOrderChangeCounter = 0;
|
|
void unbind();
|
|
void removeEventListeners();
|
|
|
|
#ifdef WITH_RIVE_TOOLS
|
|
public:
|
|
void onInputChanged(InputChanged callback)
|
|
{
|
|
m_inputChangedCallback = callback;
|
|
}
|
|
void onDataBindChanged(DataBindChanged callback);
|
|
InputChanged m_inputChangedCallback = nullptr;
|
|
#endif
|
|
};
|
|
|
|
class HitComponent
|
|
{
|
|
public:
|
|
Component* component() const { return m_component; }
|
|
HitComponent(Component* component,
|
|
StateMachineInstance* stateMachineInstance) :
|
|
m_component(component), m_stateMachineInstance(stateMachineInstance)
|
|
{}
|
|
virtual ~HitComponent() {}
|
|
virtual HitResult processEvent(Vec2D position,
|
|
ListenerType hitType,
|
|
bool canHit,
|
|
float timeStamp = 0,
|
|
int pointerId = 0) = 0;
|
|
virtual void prepareEvent(Vec2D position,
|
|
ListenerType hitType,
|
|
int pointerId) = 0;
|
|
virtual bool hitTest(Vec2D position) const = 0;
|
|
virtual void enablePointerEvents(int pointerId = 0) {}
|
|
virtual void disablePointerEvents(int pointerId = 0) {}
|
|
#ifdef TESTING
|
|
int earlyOutCount = 0;
|
|
#endif
|
|
|
|
protected:
|
|
Component* m_component;
|
|
StateMachineInstance* m_stateMachineInstance;
|
|
};
|
|
|
|
} // namespace rive
|
|
#endif
|