rotor-framework 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +120 -0
  3. package/package.json +59 -0
  4. package/src/source/RotorFramework.bs +654 -0
  5. package/src/source/RotorFrameworkTask.bs +278 -0
  6. package/src/source/base/BaseModel.bs +52 -0
  7. package/src/source/base/BasePlugin.bs +48 -0
  8. package/src/source/base/BaseReducer.bs +184 -0
  9. package/src/source/base/BaseStack.bs +92 -0
  10. package/src/source/base/BaseViewModel.bs +124 -0
  11. package/src/source/base/BaseWidget.bs +104 -0
  12. package/src/source/base/DispatcherCreator.bs +193 -0
  13. package/src/source/base/DispatcherExternal.bs +260 -0
  14. package/src/source/base/ListenerForDispatchers.bs +246 -0
  15. package/src/source/engine/Constants.bs +74 -0
  16. package/src/source/engine/animator/Animator.bs +334 -0
  17. package/src/source/engine/builder/Builder.bs +213 -0
  18. package/src/source/engine/builder/NodePool.bs +236 -0
  19. package/src/source/engine/builder/PluginAdapter.bs +139 -0
  20. package/src/source/engine/builder/PostProcessor.bs +331 -0
  21. package/src/source/engine/builder/Processor.bs +156 -0
  22. package/src/source/engine/builder/Tree.bs +278 -0
  23. package/src/source/engine/builder/TreeBase.bs +313 -0
  24. package/src/source/engine/builder/WidgetCreate.bs +322 -0
  25. package/src/source/engine/builder/WidgetRemove.bs +72 -0
  26. package/src/source/engine/builder/WidgetUpdate.bs +113 -0
  27. package/src/source/engine/providers/Dispatcher.bs +72 -0
  28. package/src/source/engine/providers/DispatcherProvider.bs +95 -0
  29. package/src/source/engine/services/I18n.bs +169 -0
  30. package/src/source/libs/animate/Animate.bs +753 -0
  31. package/src/source/libs/animate/LICENSE.txt +21 -0
  32. package/src/source/plugins/DispatcherProviderPlugin.bs +127 -0
  33. package/src/source/plugins/FieldsPlugin.bs +180 -0
  34. package/src/source/plugins/FocusPlugin.bs +1522 -0
  35. package/src/source/plugins/FontStylePlugin.bs +159 -0
  36. package/src/source/plugins/ObserverPlugin.bs +548 -0
  37. package/src/source/utils/ArrayUtils.bs +495 -0
  38. package/src/source/utils/GeneralUtils.bs +181 -0
  39. package/src/source/utils/NodeUtils.bs +180 -0
@@ -0,0 +1,246 @@
1
+ ' =====================================================================
2
+ ' Intent Interface - Standard interface for MVI intents
3
+ '
4
+ ' Properties:
5
+ ' - type: Intent type identifier (e.g., "FETCH_DATA", "UPDATE_USER")
6
+ ' - payload: Optional data associated with intent
7
+ '
8
+ ' Example:
9
+ ' { type: "INCREMENT", payload: { amount: 1 } }
10
+ ' =====================================================================
11
+ interface Intent
12
+ type as string
13
+ payload as object
14
+ end interface
15
+
16
+ namespace Rotor
17
+
18
+ ' =====================================================================
19
+ ' ListenerForDispatchers - Base class for dispatcher state change listener management
20
+ '
21
+ ' Provides listener registration, notification, and lifecycle management
22
+ ' for both internal and external dispatchers.
23
+ '
24
+ ' Listener Features:
25
+ ' - State mapping: mapStateToProps for updating widget props
26
+ ' - Conditional updates: shouldUpdate/allowUpdate for optimization
27
+ ' - Callbacks: callback (no args) or callbackWithState (receives state)
28
+ ' - One-time listeners: once flag for auto-removal after first trigger
29
+ '
30
+ ' Update Flow:
31
+ ' 1. Check shouldUpdate/allowUpdate condition
32
+ ' 2. If true: Map state to props (if configured)
33
+ ' 3. Invoke callback functions
34
+ ' 4. Remove 'once' listeners
35
+ ' =====================================================================
36
+ class ListenerForDispatchers
37
+
38
+ ' =============================================================
39
+ ' MEMBER VARIABLES
40
+ ' =============================================================
41
+
42
+ listeners = [] ' Array of listener configurations
43
+
44
+ ' =============================================================
45
+ ' LISTENER NOTIFICATION
46
+ ' =============================================================
47
+
48
+ ' ---------------------------------------------------------------------
49
+ ' notifyListeners - Notifies all registered listeners of state change
50
+ '
51
+ ' Process flow:
52
+ ' 1. For each listener, check shouldUpdate/allowUpdate condition
53
+ ' 2. If condition passes:
54
+ ' - Map state to props (if mapStateToProps configured)
55
+ ' - Or deep extend props with state (default behavior)
56
+ ' - Invoke callback (if configured)
57
+ ' - Invoke callbackWithState (if configured)
58
+ ' - Remove listener if 'once' flag is true
59
+ ' 3. Skip listener if condition fails
60
+ '
61
+ ' @param {object} state - New state to notify listeners about
62
+ '
63
+ sub notifyListeners(state as object)
64
+ listenerCount = m.listeners.Count()
65
+ listenerIndex = 0
66
+
67
+ ' Iterate through all listeners
68
+ while listenerIndex < listenerCount
69
+ listener = m.listeners[listenerIndex]
70
+ scope = listener.listenerScope
71
+
72
+ ' Determine if listener should be notified
73
+ if Rotor.Utils.isFunction(listener.shouldUpdate)
74
+ ' Widget/ViewModel: Check shouldUpdate(props, state)
75
+ shouldUpdate = Rotor.Utils.callbackScoped(listener.shouldUpdate, scope, scope.props, state)
76
+ else if Rotor.Utils.isFunction(listener.allowUpdate)
77
+ ' Task thread: Check allowUpdate(state)
78
+ shouldUpdate = Rotor.Utils.callbackScoped(listener.allowUpdate, scope, state)
79
+ else
80
+ ' Default: always update
81
+ shouldUpdate = true
82
+ end if
83
+
84
+ if shouldUpdate
85
+ ' Map state to props
86
+ if Rotor.Utils.isFunction(listener.mapStateToProps)
87
+ ' Custom mapping: mapStateToProps(props, state)
88
+ listener.mapStateToProps(scope.props, state)
89
+ else if Rotor.Utils.isAssociativeArray(scope.props)
90
+ ' Default: deep extend props with state
91
+ Rotor.Utils.deepExtendAA(scope.props, state)
92
+ end if
93
+
94
+ ' Invoke callback without state
95
+ callback = listener.callback
96
+ if callback <> invalid
97
+ Rotor.Utils.callbackScoped(callback, scope)
98
+ end if
99
+
100
+ ' Invoke callback with state
101
+ callbackWithState = listener.callbackWithState
102
+ if callbackWithState <> invalid
103
+ Rotor.Utils.callbackScoped(callbackWithState, scope, state)
104
+ end if
105
+
106
+ ' Handle 'once' listeners (auto-remove after trigger)
107
+ if listener?.once = true
108
+ listener.listenerScope = invalid
109
+ listener.callback = invalid
110
+ m.listeners.Delete(listenerIndex)
111
+ listenerCount--
112
+ else
113
+ listenerIndex++
114
+ end if
115
+ else
116
+ ' Skip this listener (condition not met)
117
+ listenerIndex++
118
+ end if
119
+ end while
120
+ end sub
121
+
122
+ ' =============================================================
123
+ ' LISTENER REGISTRATION
124
+ ' =============================================================
125
+
126
+ ' ---------------------------------------------------------------------
127
+ ' addListener - Registers a new state change listener
128
+ '
129
+ ' Listener Configuration:
130
+ ' - listenerId: Identifier for grouping related listeners
131
+ ' - listenerScope: Scope (m) where callbacks are executed
132
+ ' - mapStateToProps: Optional function(props, state) for custom state mapping
133
+ ' - shouldUpdate: Optional function(props, state) for Widget/ViewModel update checks
134
+ ' - allowUpdate: Optional function(state) for task thread update checks
135
+ ' - callback: Optional function() invoked on state change
136
+ ' - callbackWithState: Optional function(state) invoked with new state
137
+ ' - once: Optional boolean (default false) - auto-remove after first trigger
138
+ '
139
+ ' @param {object} listenerConfig - Listener configuration object
140
+ ' @param {string} listenerId - Listener identifier for batch operations
141
+ ' @param {object} listenerScope - Scope where callbacks are executed
142
+ '
143
+ sub addListener(listenerConfig as object, listenerId as string, listenerScope as object)
144
+ ' Debug validation: ensure props exists when using widget-specific features
145
+ #if debug
146
+ hasPropsMapper = Rotor.Utils.isFunction(listenerConfig.mapStateToProps)
147
+ hasPropsUpdateChecker = Rotor.Utils.isFunction(listenerConfig.shouldUpdate)
148
+ isPropsAA = Rotor.Utils.isAssociativeArray(listenerScope.props)
149
+ if not isPropsAA and (hasPropsMapper or hasPropsUpdateChecker)
150
+ throw { message: "props does not exist in caller scope. `mapStateToProps` and `shouldUpdate` only can be used in Widgets and ViewModels. Use allowUpdate instead." }
151
+ end if
152
+ #end if
153
+
154
+ ' Register listener
155
+ m.listeners.push({
156
+ listenerId: listenerId,
157
+ listenerScope: listenerScope,
158
+
159
+ mapStateToProps: listenerConfig?.mapStateToProps,
160
+ shouldUpdate: listenerConfig?.shouldUpdate,
161
+ allowUpdate: listenerConfig?.allowUpdate,
162
+ callback: listenerConfig?.callback,
163
+ callbackWithState: listenerConfig?.callbackWithState,
164
+ once: listenerConfig?.once ?? false
165
+ })
166
+ end sub
167
+
168
+ ' =============================================================
169
+ ' LISTENER REMOVAL
170
+ ' =============================================================
171
+
172
+ ' ---------------------------------------------------------------------
173
+ ' removeAllListenersByListenerId - Removes all listeners with matching ID
174
+ '
175
+ ' Iterates backwards through listener array for safe removal during iteration.
176
+ '
177
+ ' @param {string} listenerId - Listener identifier to remove
178
+ '
179
+ sub removeAllListenersByListenerId(listenerId as string)
180
+ listenerCount = m.listeners.Count()
181
+ listenerIndex = listenerCount - 1
182
+
183
+ ' Iterate backwards for safe removal
184
+ while listenerIndex >= 0 and listenerCount > 0
185
+ if m.listeners[listenerIndex].listenerId = listenerId
186
+ ' Clear listener references
187
+ m.listeners[listenerIndex].Clear()
188
+ m.listeners.delete(listenerIndex)
189
+ listenerCount--
190
+ end if
191
+ listenerIndex--
192
+ end while
193
+ end sub
194
+
195
+ ' =============================================================
196
+ ' STATE MAPPING HELPERS
197
+ ' =============================================================
198
+
199
+ ' ---------------------------------------------------------------------
200
+ ' runMapStateToProps - Executes mapStateToProps function with validation
201
+ '
202
+ ' This helper is used by getState() methods to apply optional state mapping.
203
+ ' Only works in render thread contexts where props exist.
204
+ '
205
+ ' @param {object} state - Current state
206
+ ' @param {dynamic} mapStateToProps - Optional mapping function(props, state)
207
+ ' @param {object} callerScope - Caller scope containing props
208
+ '
209
+ sub runMapStateToProps(state as object, mapStateToProps = invalid as dynamic, callerScope = invalid as object)
210
+ if Rotor.Utils.isFunction(mapStateToProps)
211
+ if Rotor.Utils.isAssociativeArray(callerScope?.props)
212
+ ' Execute mapping: updates props in-place
213
+ mapStateToProps(callerScope.props, state)
214
+ else
215
+ ' Debug validation: props must exist for mapping
216
+ #if debug
217
+ throw { message: "Props does not exist in caller scope. `mapStateToProps` can only be used in Widgets and ViewModels (render thread). In task threads, use `getState()` without mapStateToProps and access state directly." }
218
+ #end if
219
+ end if
220
+ end if
221
+ end sub
222
+
223
+ ' =============================================================
224
+ ' CLEANUP
225
+ ' =============================================================
226
+
227
+ ' ---------------------------------------------------------------------
228
+ ' destroy - Cleans up all listeners
229
+ '
230
+ ' Invalidates all listener references and clears listener array.
231
+ '
232
+ sub destroy()
233
+ ' Clear all listener references
234
+ if m.listeners.Count() > 0
235
+ for each listener in m.listeners
236
+ listener.listenerScope = invalid
237
+ listener.callback = invalid
238
+ end for
239
+ end if
240
+
241
+ m.listeners.Clear()
242
+ end sub
243
+
244
+ end class
245
+
246
+ end namespace
@@ -0,0 +1,74 @@
1
+ ' =====================================================================
2
+ ' Constants - Framework-wide constant definitions and enumerations
3
+ '
4
+ ' Defines direction types, segment types, lifecycle hook types,
5
+ ' hook priority types, and thread synchronization types.
6
+ ' =====================================================================
7
+
8
+ namespace Rotor
9
+
10
+ namespace Const
11
+
12
+ const GROUP_CONFIG_KEY = "group"
13
+
14
+ enum Direction
15
+ UP = "up"
16
+ RIGHT = "right"
17
+ DOWN = "down"
18
+ LEFT = "left"
19
+ BACK = "back"
20
+ end enum
21
+
22
+ enum Segment
23
+ TOP = "top"
24
+ RIGHT = "right"
25
+ BOTTOM = "bottom"
26
+ LEFT = "left"
27
+ end enum
28
+
29
+ enum PluginLifeCycleHookType
30
+ BEFORE_MOUNT = "beforeMount"
31
+ AFTER_MOUNTED = "afterMounted"
32
+ BEFORE_UPDATE = "beforeUpdate"
33
+ AFTER_UPDATED = "afterUpdated"
34
+ BEFORE_DESTROY = "beforeDestroy"
35
+ end enum
36
+
37
+ enum LifeCycleHookType
38
+ APPEND_CHILD = "appendChild"
39
+ REINDEX_CHILD = "reindexChild"
40
+ BEFORE_MOUNT = "beforeMount"
41
+ MOUNTED = "mounted"
42
+ AFTER_MOUNTED = "afterMounted"
43
+ BEFORE_UPDATE = "beforeUpdate"
44
+ UPDATED = "updated"
45
+ VIEWMODEL_STATE_UPDATE = "VIEWMODEL_STATE_UPDATE"
46
+ AFTER_UPDATED = "afterUpdated"
47
+ BEFORE_DESTROY = "beforeDestroy"
48
+ REMOVE_CHILD = "removeChild"
49
+ DELETE_WIDGET = "deleteWidget"
50
+ end enum
51
+
52
+
53
+ enum HookPriorityTypes
54
+ ROOT = "rootBuffer"
55
+ DEFAULT = "defaultBuffer"
56
+ end enum
57
+
58
+ enum ThreadSyncType
59
+ TASK_SYNCING = "taskSyncing"
60
+ REGISTER_EXTERNAL_DISPATCHER = "registerExternalDispatcher"
61
+ DESTROY = "destroy"
62
+ TASK_SYNCED = "taskSynced"
63
+ SYNC_COMPLETED = "sync_completed"
64
+ DISPATCH = "dispatch"
65
+ end enum
66
+
67
+ enum ThreadType
68
+ RENDER = "render"
69
+ TASK = "task"
70
+ end enum
71
+
72
+ end namespace
73
+
74
+ end namespace
@@ -0,0 +1,334 @@
1
+
2
+ import "../../libs/animate/Animate.bs" ' https://github.com/haystacknews/animate
3
+
4
+
5
+ namespace Rotor
6
+
7
+ ' ---------------------------------------------------------------------
8
+ ' animatorParamsIntegrationHelper - Helper function to parse and normalize animator parameters
9
+ '
10
+ ' @param {object} params - Animator parameters with target or targets field
11
+ ' @returns {object} Parsed parameters with normalized targets array
12
+ ' @throws {object} Error if no targets are specified
13
+ '
14
+ function animatorParamsIntegrationHelper(params) as object
15
+ if params.target <> invalid
16
+ targets = params.target
17
+ params.delete("target")
18
+ else if params.targets <> invalid
19
+ targets = params.targets
20
+ params.delete("targets")
21
+ else
22
+ throw { message: "[ANIMATOR][ERROR] Animator params don't specify targets." }
23
+ end if
24
+ parsedTargets = []
25
+ for each target in Rotor.Utils.ensureArray(targets)
26
+ if Rotor.Utils.isAssociativeArray(target) and target.doesExist("node")
27
+ node = target.node
28
+ node.id = `${target.id}-${target.HID}`
29
+ parsedTargets.push(node)
30
+ else
31
+ parsedTargets.push(target)
32
+ end if
33
+ end for
34
+
35
+ params.targets = parsedTargets
36
+
37
+ return params
38
+ end function
39
+
40
+ ' ---------------------------------------------------------------------
41
+ ' animationStateObserver - Sets up state observation for animator nodes
42
+ '
43
+ ' @param {object} params - Observer configuration parameters
44
+ '
45
+ sub animationStateObserver(params = {} as object)
46
+
47
+ globalScope = GetGlobalAA()
48
+ animatorObservber = globalScope.rotor_framework_helper.frameworkInstance.animatorProvider.animatorObservber
49
+ animatorObservber.detach(m.animNode)
50
+
51
+ observerParams = {
52
+ fieldId: "state",
53
+ infoFields: [],
54
+ callback: sub(state)
55
+ print "[WARNING] You have not specified callback for animation stateObserver"
56
+ end sub,
57
+ parsePayload: function(payload)
58
+ return payload.state
59
+ end function
60
+ }
61
+ observerParams.append(params)
62
+ ' mandatory field
63
+ observerParams.infoFields.unshift("isRotorAnimatorNode")
64
+
65
+ animatorObservber.attach(m.animNode, observerParams, m.scope)
66
+
67
+ end sub
68
+
69
+ ' =====================================================================
70
+ ' Animator - Manages animation instances and provides factory methods
71
+ '
72
+ ' Manages animation instances and provides factory methods for creating
73
+ ' single animations and timelines. Integrates with the Animate library
74
+ ' and provides state observation capabilities for animations.
75
+ ' =====================================================================
76
+ class Animator
77
+
78
+ animatorObservber as Rotor.ObserverPlugin
79
+
80
+ ' ---------------------------------------------------------------------
81
+ ' new - Initializes the animator with observer plugin
82
+ '
83
+ sub new()
84
+ m.animatorObservber = new Rotor.ObserverPlugin("rotorAnimatorObserver")
85
+ m.animatorObservber.init()
86
+ end sub
87
+
88
+ ' ---------------------------------------------------------------------
89
+ ' getFactory - Creates an animator factory instance for the given ID and scope
90
+ '
91
+ ' @param {string} animatorId - Unique identifier for the animator
92
+ ' @param {object} scope - Optional scope object for the animator (default: invalid)
93
+ ' @returns {object} Animator factory instance with control methods
94
+ '
95
+ function getFactory(animatorId as string, scope = invalid as object) as object
96
+
97
+ ' Get Animator by animatorScopedId
98
+ animatorInstance = {
99
+
100
+ animatorId: animatorId,
101
+ scope: scope,
102
+
103
+ ' ---------------------------------------------------------------------
104
+ ' create - Creates a single animation instance
105
+ '
106
+ ' @param {object} params - Animation parameters (target, duration, easing, etc.)
107
+ ' @returns {object} Animation control object with play method
108
+ '
109
+ create: function(params)
110
+
111
+ ' destroy before create
112
+ if m.scope?.animators?[m.animatorId] <> invalid
113
+ ' unobserve
114
+ animNode = m.scope.animators[m.animatorId].animNode
115
+ globalScope = GetGlobalAA()
116
+ animatorObservber = globalScope.rotor_framework_helper.frameworkInstance.animatorProvider.animatorObservber
117
+ animatorObservber.detach(animNode)
118
+ ' remove
119
+ m.scope.animators[m.animatorId].animNode = invalid
120
+ m.scope.animators.delete(m.animatorId)
121
+ end if
122
+
123
+ m.scope.animators = {}
124
+ m.scope.animators[m.animatorId] = {}
125
+
126
+ parsedParams = Rotor.animatorParamsIntegrationHelper(params)
127
+ animNode = animate.create(parsedParams)
128
+
129
+ m.scope.animators[m.animatorId].animNode = animNode
130
+ m.scope.animators[m.animatorId].animNode.addField("isRotorAnimatorNode", "boolean", false) ' may use by observer
131
+ m.scope.animators[m.animatorId].animNode.isRotorAnimatorNode = true
132
+ m.scope.animators[m.animatorId].animNode.addField("animatorType", "string", false)
133
+ m.scope.animators[m.animatorId].animNode.animatorType = "singleAnimation"
134
+
135
+ return {
136
+
137
+ scope: m.scope,
138
+ animatorId: m.animatorId,
139
+
140
+ play: function()
141
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
142
+ animNode.control = "start"
143
+ return {
144
+ scope: m.scope,
145
+ animNode: animNode,
146
+ observeState: Rotor.animationStateObserver
147
+ }
148
+ end function
149
+
150
+ }
151
+
152
+ end function,
153
+
154
+ ' ---------------------------------------------------------------------
155
+ ' timeline - Creates a timeline for multiple sequential/parallel animations
156
+ '
157
+ ' @param {object} params - Timeline parameters
158
+ ' @returns {object} Timeline control object with add, getAnimation, and play methods
159
+ '
160
+ timeline: function(params)
161
+
162
+ ' destroy before create
163
+ if m.scope?.animators?[m.animatorId] <> invalid
164
+ ' unobserve
165
+ animNode = m.scope.animators[m.animatorId].animNode
166
+ globalScope = GetGlobalAA()
167
+ animatorObservber = globalScope.rotor_framework_helper.frameworkInstance.animatorProvider.animatorObservber
168
+ animatorObservber.detach(animNode)
169
+ ' remove
170
+ m.scope.animators[m.animatorId].animNode = invalid
171
+ m.scope.animators.delete(m.animatorId)
172
+ end if
173
+
174
+ m.scope.animators = {}
175
+ m.scope.animators[m.animatorId] = {}
176
+
177
+ return {
178
+
179
+ scope: m.scope,
180
+ animatorId: m.animatorId,
181
+
182
+ timeline: animate.timeline(params),
183
+
184
+ add: function(params)
185
+
186
+ parsedParams = Rotor.animatorParamsIntegrationHelper(params)
187
+ m.timeline.add(parsedParams)
188
+
189
+ return m
190
+ end function,
191
+
192
+ getAnimation: function()
193
+ m.scope.animators[m.animatorId].animNode = m.timeline.getAnimation()
194
+ m.scope.animators[m.animatorId].animNode.addField("isRotorAnimatorNode", "boolean", false) ' may use by observer
195
+ m.scope.animators[m.animatorId].animNode.isRotorAnimatorNode = true
196
+ m.scope.animators[m.animatorId].animNode.addField("animatorType", "string", false)
197
+ m.scope.animators[m.animatorId].animNode.animatorType = "parallelAnimation"
198
+
199
+ return m
200
+ end function,
201
+
202
+ play: function()
203
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
204
+ ' Auto getAnimation and then play
205
+ if animNode = invalid
206
+ m.getAnimation()
207
+ end if
208
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
209
+ animNode.control = "start"
210
+ return {
211
+ scope: m.scope,
212
+ animNode: animNode,
213
+ observeState: Rotor.animationStateObserver
214
+ }
215
+ end function
216
+
217
+ }
218
+ end function
219
+
220
+ }
221
+
222
+ return {
223
+ animatorInstance: animatorInstance,
224
+ animatorId: animatorId,
225
+ scope: scope,
226
+
227
+ getState: function()
228
+ return m.scope?.animators?[m.animatorId]?.animNode?.state
229
+ end function,
230
+
231
+ isRunning: function()
232
+ return m.getState() = "running"
233
+ end function,
234
+
235
+ isStopped: function()
236
+ return m.getState() = "stopped"
237
+ end function,
238
+
239
+ isPaused: function()
240
+ return m.getState() = "paused"
241
+ end function,
242
+
243
+ play: function()
244
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
245
+ ' Auto getAnimation and then play
246
+ if animNode = invalid
247
+ m.getAnimation()
248
+ end if
249
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
250
+ if animNode <> invalid
251
+ animNode.control = "start"
252
+ end if
253
+ return {
254
+ scope: m.scope,
255
+ animNode: animNode,
256
+ observeState: Rotor.animationStateObserver
257
+ }
258
+ end function,
259
+
260
+ stop: sub()
261
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
262
+ if animNode <> invalid
263
+ m.scope.animators[m.animatorId].animNode.control = "stop"
264
+ end if
265
+ end sub,
266
+
267
+ pause: sub()
268
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
269
+ if animNode <> invalid
270
+ m.scope.animators[m.animatorId].animNode.control = "pause"
271
+ end if
272
+ end sub,
273
+
274
+ finish: sub()
275
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
276
+ if animNode <> invalid
277
+ animNode.control = "finish"
278
+ end if
279
+ end sub,
280
+
281
+ getAnimNode: function()
282
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
283
+ return animNode
284
+ end function,
285
+
286
+ getInterpolators: function()
287
+ animNode = m.scope?.animators?[m.animatorId]?.animNode
288
+ if animNode <> invalid
289
+ if m.scope.animators[m.animatorId].animNode.animatorType = "parallelAnimation"
290
+ interpolators = []
291
+ for each subAnim in animNode.getChildCount()
292
+ interpolators.push(subAnim.getChildren(-1, 0))
293
+ end for
294
+ else ' singleAnimator
295
+ interpolators = animNode.getChildren(-1, 0)
296
+ end if
297
+ return interpolators
298
+ else
299
+ return invalid
300
+ end if
301
+ end function,
302
+
303
+ destroy: sub()
304
+ if m.scope?.animators?[m.animatorId] <> invalid
305
+ m.unobserveState()
306
+ m.scope.animators[m.animatorId].animNode = invalid
307
+ m.scope.animators.delete(m.animatorId)
308
+ end if
309
+ end sub,
310
+
311
+ unobserveState: sub()
312
+ animNode = m.scope.animators[m.animatorId].animNode
313
+ globalScope = GetGlobalAA()
314
+ animatorObservber = globalScope.rotor_framework_helper.frameworkInstance.animatorProvider.animatorObservber
315
+ animatorObservber.detach(animNode)
316
+ end sub,
317
+
318
+ ' Create with self destroy
319
+ create: function(params) as object
320
+ return m.animatorInstance.create(params)
321
+ end function,
322
+
323
+ ' Cerate timeline with self destroy
324
+ timeline: function(params) as object
325
+ return m.animatorInstance.timeline(params)
326
+ end function
327
+ }
328
+
329
+
330
+ end function
331
+
332
+ end class
333
+
334
+ end namespace