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.
- package/LICENSE.md +21 -0
- package/README.md +120 -0
- package/package.json +59 -0
- package/src/source/RotorFramework.bs +654 -0
- package/src/source/RotorFrameworkTask.bs +278 -0
- package/src/source/base/BaseModel.bs +52 -0
- package/src/source/base/BasePlugin.bs +48 -0
- package/src/source/base/BaseReducer.bs +184 -0
- package/src/source/base/BaseStack.bs +92 -0
- package/src/source/base/BaseViewModel.bs +124 -0
- package/src/source/base/BaseWidget.bs +104 -0
- package/src/source/base/DispatcherCreator.bs +193 -0
- package/src/source/base/DispatcherExternal.bs +260 -0
- package/src/source/base/ListenerForDispatchers.bs +246 -0
- package/src/source/engine/Constants.bs +74 -0
- package/src/source/engine/animator/Animator.bs +334 -0
- package/src/source/engine/builder/Builder.bs +213 -0
- package/src/source/engine/builder/NodePool.bs +236 -0
- package/src/source/engine/builder/PluginAdapter.bs +139 -0
- package/src/source/engine/builder/PostProcessor.bs +331 -0
- package/src/source/engine/builder/Processor.bs +156 -0
- package/src/source/engine/builder/Tree.bs +278 -0
- package/src/source/engine/builder/TreeBase.bs +313 -0
- package/src/source/engine/builder/WidgetCreate.bs +322 -0
- package/src/source/engine/builder/WidgetRemove.bs +72 -0
- package/src/source/engine/builder/WidgetUpdate.bs +113 -0
- package/src/source/engine/providers/Dispatcher.bs +72 -0
- package/src/source/engine/providers/DispatcherProvider.bs +95 -0
- package/src/source/engine/services/I18n.bs +169 -0
- package/src/source/libs/animate/Animate.bs +753 -0
- package/src/source/libs/animate/LICENSE.txt +21 -0
- package/src/source/plugins/DispatcherProviderPlugin.bs +127 -0
- package/src/source/plugins/FieldsPlugin.bs +180 -0
- package/src/source/plugins/FocusPlugin.bs +1522 -0
- package/src/source/plugins/FontStylePlugin.bs +159 -0
- package/src/source/plugins/ObserverPlugin.bs +548 -0
- package/src/source/utils/ArrayUtils.bs +495 -0
- package/src/source/utils/GeneralUtils.bs +181 -0
- 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
|