import 'package:flutter/foundation.dart'; import 'package:rive/rive.dart'; import 'package:rive/src/rive_core/artboard.dart'; import 'package:rive/src/rive_core/component.dart'; import 'package:rive/src/rive_core/event.dart'; import 'package:rive/src/core/core.dart'; /// Adds getters for linear animations and state machines extension RuntimeArtboardGetters on RuntimeArtboard { /// Returns an iterable of linear animations in the artboard Iterable get linearAnimations => animations.whereType(); /// Returns an iterable of state machines in the artboard Iterable get stateMachines => animations.whereType(); } /// This artboard type is purely for use by the runtime system and should not be /// directly referenced. Use the Artboard type for any direct interactions with /// an artboard, and use extension methods to add functionality to Artboard. class RuntimeArtboard extends Artboard implements CoreContext { final _redraw = Event(); ChangeNotifier get redraw => _redraw; /// Note that objects must be nullable as some may not resolve during load due /// to format differences. final List _objects = []; Iterable get objects => _objects; final Set _needDependenciesBuilt = {}; @override T? addObject(T? object) { object?.context = this; object?.id = _objects.length; _objects.add(object); return object; } @override void removeObject(T object) { _objects.remove(object); } @override void markDependencyOrderDirty() {} @override bool markDependenciesDirty(covariant Core object) { if (object is Component) { _needDependenciesBuilt.add(object); return true; } return false; } void clean() { if (_needDependenciesBuilt.isNotEmpty) { // Copy it in case it is changed during the building (meaning this process // needs to recurse). Set needDependenciesBuilt = Set.from(_needDependenciesBuilt); _needDependenciesBuilt.clear(); // First resolve the artboards for (final component in needDependenciesBuilt) { component.resolveArtboard(); } // Then build the dependencies for (final component in needDependenciesBuilt) { component.buildDependencies(); } sortDependencies(); computeDrawOrder(); } } @override T? resolve(int id) { if (id >= _objects.length || id < 0) { return null; } var object = _objects[id]; if (object is T) { return object as T; } return null; } @override T resolveWithDefault(int id, T defaultValue) { if (id >= _objects.length) { return defaultValue; } var object = _objects[id]; if (object is T) { return object as T; } return defaultValue; } @override Core? makeCoreInstance(int typeKey) => RiveCoreContext.makeCoreInstance(typeKey); @override void dirty(void Function() dirt) { // TODO: Schedule a debounced callback for next frame } @override void markNeedsAdvance() { _redraw.notify(); } @override Artboard instance() { var artboard = RuntimeArtboard(); artboard.context = artboard; artboard.copy(this); artboard._objects.add(artboard); // First copy the objects ensuring onAddedDirty can later find them in the // _objects list. for (final object in _objects.skip(1)) { Core? clone = object?.clone(); artboard.addObject(clone); } // Then run the onAddedDirty loop. for (final object in artboard.objects.skip(1)) { if (object is Component && object.parentId == ComponentBase.parentIdInitialValue) { object.parent = artboard; } object?.onAddedDirty(); } animations.forEach(artboard.animations.add); for (final object in artboard.objects.toList(growable: false)) { if (object == null) { continue; } object.onAdded(); InternalCoreHelper.markValid(object); } artboard.clean(); return artboard; } }