Skip to content

Commit

Permalink
Nested linear animations report events up to parent artboards
Browse files Browse the repository at this point in the history
Previously, only nested state machines could report events so that listeners in parent artboards could listen for them. This PR adds event reporting for nested simple animations. Had to refactor some stuff to genericize in order for both state machines and linear animations to have similar functionality.

I'm not sure if its possible, or desirable, for nested remap animations to have the same functionality, but that is not included in this PR.

Diffs=
097b68f56 Nested linear animations report events up to parent artboards (#7310)
34e186b32 more renames for harfbuzz (#7398)
b88272290 mark shape as dirty after flagged as target (#7396)
a10b1e61e don’t defer updates when a shape/path is used for hit detect (#7392)

Co-authored-by: Philip Chung <[email protected]>
  • Loading branch information
philter and philter committed Jun 11, 2024
1 parent bf94e7d commit 42665e4
Show file tree
Hide file tree
Showing 9 changed files with 102 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .rive_head
Original file line number Diff line number Diff line change
@@ -1 +1 @@
9abd6ee16ca1290488f2bd950844e7730ee92c6e
097b68f5616951d83b0c5b28345e6bfc9f0b1a5b
2 changes: 1 addition & 1 deletion lib/rive.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ library rive;

export 'package:rive/src/asset.dart';
export 'package:rive/src/asset_loader.dart';
export 'package:rive/src/controllers/linear_animation_controller.dart';
export 'package:rive/src/controllers/one_shot_controller.dart';
export 'package:rive/src/controllers/simple_controller.dart';
export 'package:rive/src/controllers/state_machine_controller.dart';
export 'package:rive/src/extensions.dart';
export 'package:rive/src/rive.dart';
export 'package:rive/src/rive_core/animation/linear_animation.dart';
export 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
export 'package:rive/src/rive_core/animation/loop.dart';
export 'package:rive/src/rive_core/animation/state_machine.dart';
export 'package:rive/src/rive_core/artboard.dart';
Expand Down
47 changes: 47 additions & 0 deletions lib/src/controllers/linear_animation_controller.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:rive/src/core/core.dart';
import 'package:rive/src/rive_core/animation/keyed_object.dart';
import 'package:rive/src/rive_core/animation/linear_animation_instance.dart'
as core;
import 'package:rive/src/rive_core/event.dart';
import 'package:rive/src/runtime_mounted_artboard.dart';
export 'package:rive/src/runtime_mounted_artboard.dart';

/// An AnimationController which controls a StateMachine and provides access to
/// the inputs of the StateMachine.
class LinearAnimationInstance extends core.LinearAnimationInstance
with RuntimeEventReporter, KeyedCallbackReporter {
final _runtimeEventListeners = <OnRuntimeEvent>{};
late CoreContext? context;

LinearAnimationInstance(animation,
{double speedMultiplier = 1.0, this.context})
: super(animation, speedMultiplier: speedMultiplier);

@override
void addRuntimeEventListener(OnRuntimeEvent callback) =>
_runtimeEventListeners.add(callback);

@override
void removeRuntimeEventListener(OnRuntimeEvent callback) =>
_runtimeEventListeners.remove(callback);

@override
void reportEvent(Event event) {
_runtimeEventListeners.toList().forEach((callback) {
callback(event);
});
}

@override
void reportKeyedCallback(
int objectId, int propertyKey, double elapsedSeconds) {
var coreObject = context?.resolve(objectId);
if (coreObject != null) {
RiveCoreContext.setCallback(
coreObject,
propertyKey,
CallbackData(this, delay: elapsedSeconds),
);
}
}
}
12 changes: 7 additions & 5 deletions lib/src/controllers/state_machine_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import 'package:rive/src/rive_core/animation/state_machine_input.dart' as core;
import 'package:rive/src/rive_core/animation/state_machine_number.dart';
import 'package:rive/src/rive_core/animation/state_machine_trigger.dart';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/event.dart';
import 'package:rive/src/rive_core/state_machine_controller.dart' as core;
import 'package:rive/src/runtime_mounted_artboard.dart';
export 'package:rive/src/runtime_mounted_artboard.dart';

/// [StateMachine]s supports three input types. The StateMachine mostly
/// abstracts types by allowing the programmer to query for an input of a
Expand Down Expand Up @@ -109,12 +110,10 @@ class SMITrigger extends SMIInput<bool> {
void advance() => change(false);
}

/// Callback signature for events firing.
typedef OnRuntimeEvent = void Function(Event);

/// An AnimationController which controls a StateMachine and provides access to
/// the inputs of the StateMachine.
class StateMachineController extends core.StateMachineController {
class StateMachineController extends core.StateMachineController
with RuntimeEventReporter {
final List<SMIInput> _inputs = <SMIInput>[];

/// A list of inputs available in the StateMachine.
Expand Down Expand Up @@ -215,8 +214,11 @@ class StateMachineController extends core.StateMachineController {
}
}

@override
void addRuntimeEventListener(OnRuntimeEvent callback) =>
_runtimeEventListeners.add(callback);

@override
void removeRuntimeEventListener(OnRuntimeEvent callback) =>
_runtimeEventListeners.remove(callback);

Expand Down
2 changes: 1 addition & 1 deletion lib/src/extensions.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
/// Extensions to the runtime core classes
import 'package:collection/collection.dart';
import 'package:rive/src/controllers/linear_animation_controller.dart';
import 'package:rive/src/controllers/state_machine_controller.dart';
import 'package:rive/src/rive_core/animation/linear_animation.dart';
import 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/state_machine_controller.dart' as core;

Expand Down
5 changes: 5 additions & 0 deletions lib/src/rive_core/animation/linear_animation_instance.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import 'package:rive/src/core/core.dart';
import 'package:rive/src/rive_core/animation/keyed_object.dart';
import 'package:rive/src/rive_core/animation/linear_animation.dart';
import 'package:rive/src/rive_core/animation/loop.dart';
import 'package:rive/src/rive_core/event.dart';

class LinearAnimationInstance {
final LinearAnimation animation;
Expand Down Expand Up @@ -216,4 +217,8 @@ class LinearAnimationInstance {
_didLoop = didLoop;
return keepGoing;
}

// Used by runtime to report events from linear animations in nested artboards
// when not played in state machine
void reportEvent(Event event) {}
}
4 changes: 4 additions & 0 deletions lib/src/rive_core/event.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:rive/src/generated/event_base.dart';
import 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/component.dart';
import 'package:rive/src/rive_core/container_component.dart';
Expand Down Expand Up @@ -50,6 +51,9 @@ class Event extends EventBase {
var controller = data.context as StateMachineController;
_secondsDelay = data.delay;
controller.reportEvent(this);
} else if (data.context is LinearAnimationInstance) {
var animation = data.context as LinearAnimationInstance;
animation.reportEvent(this);
}
}
}
35 changes: 24 additions & 11 deletions lib/src/runtime_mounted_artboard.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ import 'package:rive/src/rive_core/event.dart';
import 'package:rive/src/rive_core/nested_artboard.dart';
import 'package:rive_common/math.dart';

/// Callback signature for events firing.
typedef OnRuntimeEvent = void Function(Event);

abstract class RuntimeEventReporter {
void addRuntimeEventListener(OnRuntimeEvent callback);
void removeRuntimeEventListener(OnRuntimeEvent callback);
}

class RuntimeMountedArtboard extends MountedArtboard {
NestedArtboard nestedArtboard;
final RuntimeArtboard artboardInstance;
StateMachineController? controller;
final Set<RuntimeEventReporter> _runtimeEventListeners = {};
Size originalArtboardInstanceSize = const Size(0, 0);

// The callback used for bubbling events up from nested artboards
Expand All @@ -24,7 +32,7 @@ class RuntimeMountedArtboard extends MountedArtboard {

@override
void dispose() {
controller = null;
_runtimeEventListeners.clear();
eventCallback = null;
}

Expand Down Expand Up @@ -83,9 +91,9 @@ class RuntimeMountedArtboard extends MountedArtboard {
bool advance(double seconds, {bool nested = true}) =>
artboardInstance.advance(seconds, nested: nested);

void addEventListener(StateMachineController listener) {
controller = listener;
controller?.addRuntimeEventListener(_handleRuntimeEvent);
void addEventListener(RuntimeEventReporter listener) {
_runtimeEventListeners.add(listener);
listener.addRuntimeEventListener(_handleRuntimeEvent);
// Pass an event callback into the child nested artboard's
// mounted artboard so we get an event bubbled up to us
artboardInstance.activeNestedArtboards.forEach((artboard) {
Expand All @@ -96,8 +104,10 @@ class RuntimeMountedArtboard extends MountedArtboard {
});
}

void removeEventListener() {
controller?.removeRuntimeEventListener(_handleRuntimeEvent);
void removeEventListeners() {
_runtimeEventListeners.forEach(
(listener) => listener.removeRuntimeEventListener(_handleRuntimeEvent));
_runtimeEventListeners.clear();
}

void _handleRuntimeEvent(Event event) {
Expand All @@ -107,9 +117,12 @@ class RuntimeMountedArtboard extends MountedArtboard {
}

void _handleNestedEvent(Event event, NestedArtboard target) {
if (controller?.hasListenerWithTarget(target) ?? false) {
controller?.reportNestedEvent(event, target);
controller?.isActive = true;
}
_runtimeEventListeners.forEach((listener) {
if (listener is StateMachineController &&
listener.hasListenerWithTarget(target)) {
listener.reportNestedEvent(event, target);
listener.isActive = true;
}
});
}
}
20 changes: 12 additions & 8 deletions lib/src/runtime_nested_artboard.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import 'package:flutter/rendering.dart';
import 'package:rive/src/controllers/state_machine_controller.dart';
import 'package:rive/rive.dart';
import 'package:rive/src/core/core.dart';
import 'package:rive/src/rive_core/animation/linear_animation_instance.dart';
import 'package:rive/src/rive_core/animation/nested_linear_animation.dart';
import 'package:rive/src/rive_core/animation/nested_state_machine.dart';
import 'package:rive/src/rive_core/artboard.dart';
import 'package:rive/src/rive_core/nested_artboard.dart';
import 'package:rive/src/rive_core/state_machine_controller.dart'
as state_machine_core;
import 'package:rive/src/runtime_mounted_artboard.dart';
import 'package:rive_common/math.dart';

extension NestedArtboardRuntimeExtension on NestedArtboard {
Expand Down Expand Up @@ -53,9 +49,16 @@ class RuntimeNestedArtboard extends NestedArtboard {
if (animation is NestedLinearAnimation) {
var animationId = animation.animationId;
if (animationId >= 0 && animationId < runtimeLinearAnimations.length) {
final linearAnimationInstance = LinearAnimationInstance(
runtimeLinearAnimations[animationId],
context:
(mountedArtboard as RuntimeMountedArtboard).artboardInstance);
animation.linearAnimationInstance =
RuntimeNestedLinearAnimationInstance(LinearAnimationInstance(
runtimeLinearAnimations[animationId]));
RuntimeNestedLinearAnimationInstance(linearAnimationInstance);
if (mountedArtboard is RuntimeMountedArtboard) {
(mountedArtboard as RuntimeMountedArtboard)
.addEventListener(linearAnimationInstance);
}
}
} else if (animation is NestedStateMachine) {
var animationId = animation.animationId;
Expand Down Expand Up @@ -91,7 +94,8 @@ class RuntimeNestedLinearAnimationInstance

@override
bool advance(double elapsedSeconds) {
linearAnimation.advance(elapsedSeconds * speed);
linearAnimation.advance(elapsedSeconds * speed,
callbackReporter: linearAnimation);
return linearAnimation.keepGoing;
}

Expand Down

0 comments on commit 42665e4

Please sign in to comment.