agt 0.0.1
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.
- checksums.yaml +7 -0
- data/LICENSE.md +7 -0
- data/README.md +5 -0
- data/app/assets/javascripts/agt/config.coffee +9 -0
- data/app/assets/javascripts/agt/dom.coffee +12 -0
- data/app/assets/javascripts/agt/function.coffee +317 -0
- data/app/assets/javascripts/agt/geom/circle.coffee +338 -0
- data/app/assets/javascripts/agt/geom/cubic_bezier.coffee +37 -0
- data/app/assets/javascripts/agt/geom/diamond.coffee +241 -0
- data/app/assets/javascripts/agt/geom/ellipsis.coffee +141 -0
- data/app/assets/javascripts/agt/geom/linear_spline.coffee +56 -0
- data/app/assets/javascripts/agt/geom/matrix.coffee +240 -0
- data/app/assets/javascripts/agt/geom/mixins/geometry.coffee +171 -0
- data/app/assets/javascripts/agt/geom/mixins/intersections.coffee +150 -0
- data/app/assets/javascripts/agt/geom/mixins/path.coffee +145 -0
- data/app/assets/javascripts/agt/geom/mixins/proxyable.coffee +9 -0
- data/app/assets/javascripts/agt/geom/mixins/spline.coffee +329 -0
- data/app/assets/javascripts/agt/geom/mixins/surface.coffee +55 -0
- data/app/assets/javascripts/agt/geom/mixins/triangulable.coffee +112 -0
- data/app/assets/javascripts/agt/geom/point.coffee +454 -0
- data/app/assets/javascripts/agt/geom/polygon.coffee +119 -0
- data/app/assets/javascripts/agt/geom/quad_bezier.coffee +43 -0
- data/app/assets/javascripts/agt/geom/quint_bezier.coffee +42 -0
- data/app/assets/javascripts/agt/geom/rectangle.coffee +599 -0
- data/app/assets/javascripts/agt/geom/spiral.coffee +90 -0
- data/app/assets/javascripts/agt/geom/transformation_proxy.coffee +43 -0
- data/app/assets/javascripts/agt/geom/triangle.coffee +442 -0
- data/app/assets/javascripts/agt/impulse.coffee +105 -0
- data/app/assets/javascripts/agt/index.coffee +56 -0
- data/app/assets/javascripts/agt/inflector/inflection.coffee +21 -0
- data/app/assets/javascripts/agt/inflector/inflections.coffee +75 -0
- data/app/assets/javascripts/agt/inflector/inflector.coffee +235 -0
- data/app/assets/javascripts/agt/inheritance.coffee +132 -0
- data/app/assets/javascripts/agt/math.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/activable.coffee +31 -0
- data/app/assets/javascripts/agt/mixins/aliasable.coffee +25 -0
- data/app/assets/javascripts/agt/mixins/alternate_case.coffee +72 -0
- data/app/assets/javascripts/agt/mixins/cloneable.coffee +71 -0
- data/app/assets/javascripts/agt/mixins/delegation.coffee +90 -0
- data/app/assets/javascripts/agt/mixins/disposable.coffee +7 -0
- data/app/assets/javascripts/agt/mixins/equatable.coffee +37 -0
- data/app/assets/javascripts/agt/mixins/formattable.coffee +52 -0
- data/app/assets/javascripts/agt/mixins/globalizable.coffee +175 -0
- data/app/assets/javascripts/agt/mixins/has_ancestors.coffee +47 -0
- data/app/assets/javascripts/agt/mixins/has_collection.coffee +107 -0
- data/app/assets/javascripts/agt/mixins/has_nested_collection.coffee +51 -0
- data/app/assets/javascripts/agt/mixins/memoizable.coffee +64 -0
- data/app/assets/javascripts/agt/mixins/parameterizable.coffee +101 -0
- data/app/assets/javascripts/agt/mixins/poolable.coffee +62 -0
- data/app/assets/javascripts/agt/mixins/sourcable.coffee +45 -0
- data/app/assets/javascripts/agt/mixins/state_machine.coffee +47 -0
- data/app/assets/javascripts/agt/net/router.coffee +165 -0
- data/app/assets/javascripts/agt/object.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/base_action.coffee +7 -0
- data/app/assets/javascripts/agt/particles/actions/die_on_surface.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/force.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/friction.coffee +14 -0
- data/app/assets/javascripts/agt/particles/actions/live.coffee +9 -0
- data/app/assets/javascripts/agt/particles/actions/macro_action.coffee +13 -0
- data/app/assets/javascripts/agt/particles/actions/move.coffee +11 -0
- data/app/assets/javascripts/agt/particles/actions/null_action.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/by_rate.coffee +17 -0
- data/app/assets/javascripts/agt/particles/counters/fixed.coffee +9 -0
- data/app/assets/javascripts/agt/particles/counters/null_counter.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emission.coffee +35 -0
- data/app/assets/javascripts/agt/particles/emitters/null_emitter.coffee +7 -0
- data/app/assets/javascripts/agt/particles/emitters/path.coffee +10 -0
- data/app/assets/javascripts/agt/particles/emitters/ponctual.coffee +9 -0
- data/app/assets/javascripts/agt/particles/emitters/surface.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/explosion.coffee +19 -0
- data/app/assets/javascripts/agt/particles/initializers/life.coffee +16 -0
- data/app/assets/javascripts/agt/particles/initializers/macro_initializer.coffee +10 -0
- data/app/assets/javascripts/agt/particles/initializers/null_initializer.coffee +7 -0
- data/app/assets/javascripts/agt/particles/initializers/particle_sub_system.coffee +12 -0
- data/app/assets/javascripts/agt/particles/initializers/stream.coffee +20 -0
- data/app/assets/javascripts/agt/particles/mixins/randomizable.coffee +10 -0
- data/app/assets/javascripts/agt/particles/particle.coffee +32 -0
- data/app/assets/javascripts/agt/particles/sub_system.coffee +11 -0
- data/app/assets/javascripts/agt/particles/system.coffee +103 -0
- data/app/assets/javascripts/agt/particles/timers/instant.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/limited.coffee +19 -0
- data/app/assets/javascripts/agt/particles/timers/null_timer.coffee +11 -0
- data/app/assets/javascripts/agt/particles/timers/unlimited.coffee +9 -0
- data/app/assets/javascripts/agt/particles/timers/until_death.coffee +11 -0
- data/app/assets/javascripts/agt/promise.coffee +214 -0
- data/app/assets/javascripts/agt/random/random.coffee +100 -0
- data/app/assets/javascripts/agt/random/seeds/lagged_fibonnacci.coffee +53 -0
- data/app/assets/javascripts/agt/random/seeds/linear.coffee +16 -0
- data/app/assets/javascripts/agt/random/seeds/linear_congruential.coffee +23 -0
- data/app/assets/javascripts/agt/random/seeds/math_random.coffee +9 -0
- data/app/assets/javascripts/agt/random/seeds/mersenne_twister.coffee +42 -0
- data/app/assets/javascripts/agt/random/seeds/no_random.coffee +12 -0
- data/app/assets/javascripts/agt/random/seeds/paul_houle.coffee +19 -0
- data/app/assets/javascripts/agt/signal.coffee +272 -0
- data/app/assets/javascripts/agt/sprites/animation.coffee +13 -0
- data/app/assets/javascripts/agt/sprites/sprite.coffee +30 -0
- data/app/assets/javascripts/agt/widgets/hash.coffee +36 -0
- data/app/assets/javascripts/agt/widgets/widgets.coffee +194 -0
- data/app/assets/javascripts/agt/widgets/widgets/checked_input.coffee +7 -0
- data/app/assets/javascripts/agt/widgets/widgets/focus_bubbling.coffee +15 -0
- data/lib/agt.rb +8 -0
- data/lib/agt/version.rb +5 -0
- metadata +173 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
namespace('agt.random')
|
|
2
|
+
# Public:
|
|
3
|
+
class agt.random.LinearCongruential
|
|
4
|
+
@include agt.mixins.Cloneable('seed')
|
|
5
|
+
@include agt.mixins.Sourcable('chancejs.LinearCongruential','seed')
|
|
6
|
+
@include agt.mixins.Formattable('LinearCongruential','seed')
|
|
7
|
+
|
|
8
|
+
### Public ###
|
|
9
|
+
|
|
10
|
+
constructor: (@seed=1) ->
|
|
11
|
+
plantSeed: (@seed=1) ->
|
|
12
|
+
|
|
13
|
+
get: ->
|
|
14
|
+
tmp = @seed
|
|
15
|
+
q = tmp
|
|
16
|
+
q = q << 1
|
|
17
|
+
p = tmp << 32
|
|
18
|
+
m = p + q
|
|
19
|
+
if m & 0x80000000
|
|
20
|
+
m = m & 0x7fffffff
|
|
21
|
+
m++
|
|
22
|
+
@seed = m
|
|
23
|
+
m / 0x80000000
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
namespace('agt.random')
|
|
2
|
+
# Public:
|
|
3
|
+
class agt.random.MersenneTwister
|
|
4
|
+
@include agt.mixins.Cloneable('seed')
|
|
5
|
+
@include agt.mixins.Sourcable('chancejs.MersenneTwister','seed')
|
|
6
|
+
@include agt.mixins.Formattable('MersenneTwister','seed')
|
|
7
|
+
|
|
8
|
+
### Public ###
|
|
9
|
+
|
|
10
|
+
constructor: (seed=0) ->
|
|
11
|
+
@mt = Array 623
|
|
12
|
+
@z = 0
|
|
13
|
+
@y = 0
|
|
14
|
+
|
|
15
|
+
@plantSeed seed
|
|
16
|
+
|
|
17
|
+
plantSeed: (seed=0) ->
|
|
18
|
+
@mt[0] = seed
|
|
19
|
+
@mt[i] = ((0x10dcd * @mt[i-1]) + 1) & 0xFFFFFFFF for i in [1..623]
|
|
20
|
+
|
|
21
|
+
get: ->
|
|
22
|
+
@generateNumbers() if @z >= 623
|
|
23
|
+
@extractNumber(@z++) / 0x80000000
|
|
24
|
+
|
|
25
|
+
### Internal: ###
|
|
26
|
+
|
|
27
|
+
generateNumbers: ->
|
|
28
|
+
@z = 0
|
|
29
|
+
for i in [0..623]
|
|
30
|
+
@y = 0x80000000 & @mt[i] + 0x7FFFFFFF & (@mt[(i + 1) % 623])
|
|
31
|
+
|
|
32
|
+
if @y % 2 is 0
|
|
33
|
+
@mt[i] = @mt[(i + 397) % 623] ^ (@y >> 1)
|
|
34
|
+
else
|
|
35
|
+
@mt[i] = @mt[(i + 397) % 623] ^ (@y >> 1) ^ 0x9908B0DF
|
|
36
|
+
|
|
37
|
+
extractNumber: (i) ->
|
|
38
|
+
@y = @mt[i]
|
|
39
|
+
@y ^= (@y >> 11)
|
|
40
|
+
@y ^= (@y << 7) & 0x9d2c5680
|
|
41
|
+
@y ^= (@y << 15) & 0xefc60000
|
|
42
|
+
@y ^= (@y >> 18)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
namespace('agt.random')
|
|
2
|
+
# Public:
|
|
3
|
+
class agt.random.NoRandom
|
|
4
|
+
@include agt.mixins.Cloneable('seed')
|
|
5
|
+
@include agt.mixins.Sourcable('chancejs.NoRandom','seed')
|
|
6
|
+
@include agt.mixins.Formattable('NoRandom','seed')
|
|
7
|
+
|
|
8
|
+
### Public ###
|
|
9
|
+
|
|
10
|
+
constructor: (@seed=0) ->
|
|
11
|
+
|
|
12
|
+
get: -> @seed
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
namespace('agt.random')
|
|
2
|
+
# Original Implementation License:
|
|
3
|
+
#
|
|
4
|
+
# The Central Randomizer 1.3 (C) 1997 by Paul Houle (paul@honeylocust.com)
|
|
5
|
+
# See: http://www.honeylocust.com/javascript/randomizer.html
|
|
6
|
+
|
|
7
|
+
# Public:
|
|
8
|
+
class agt.random.PaulHoule
|
|
9
|
+
@include agt.mixins.Cloneable('seed')
|
|
10
|
+
@include agt.mixins.Sourcable('chancejs.PaulHoule','seed')
|
|
11
|
+
@include agt.mixins.Formattable('PaulHoule','seed')
|
|
12
|
+
|
|
13
|
+
### Public ###
|
|
14
|
+
|
|
15
|
+
constructor: (@seed) ->
|
|
16
|
+
|
|
17
|
+
get: ->
|
|
18
|
+
@seed = (@seed * 9301 + 49297) % 233280
|
|
19
|
+
@seed / 233280.0
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
# Public: Use a `Signal` object wherever you need to dispatch an event.
|
|
2
|
+
# A `Signal` is a dispatcher that have only one channel.
|
|
3
|
+
#
|
|
4
|
+
# Signals are generally defined as property of an object. And
|
|
5
|
+
# their name generally end with a past tense verb, such as in:
|
|
6
|
+
#
|
|
7
|
+
# ```coffeescript
|
|
8
|
+
# myObject.somethingChanged = new Signal
|
|
9
|
+
# ```
|
|
10
|
+
class agt.Signal
|
|
11
|
+
|
|
12
|
+
### Public ###
|
|
13
|
+
|
|
14
|
+
# Creates a new `Signal` instance.
|
|
15
|
+
# Optionally, a signal can have a specific signature.
|
|
16
|
+
# A signature is a collection of argument names such:
|
|
17
|
+
#
|
|
18
|
+
# ```coffeescript
|
|
19
|
+
# positionChanged = new Signal 'target', 'position'
|
|
20
|
+
# ```
|
|
21
|
+
#
|
|
22
|
+
# If a signature is passed to a signal, every listener
|
|
23
|
+
# added to the signal must then match the signature.
|
|
24
|
+
#
|
|
25
|
+
# ```coffeescript
|
|
26
|
+
# # will be registered
|
|
27
|
+
# positionChanged.add (target, position) ->
|
|
28
|
+
#
|
|
29
|
+
# # will be registered too
|
|
30
|
+
# positionChanged.add (target, position, callback) ->
|
|
31
|
+
#
|
|
32
|
+
# # will not be registered
|
|
33
|
+
# positionChanged.add () -> # will throw an error
|
|
34
|
+
# ```
|
|
35
|
+
#
|
|
36
|
+
# In the case of an asynchronous listener, the callback argument
|
|
37
|
+
# is not considered as being part of the signature.
|
|
38
|
+
constructor: (@signature...) ->
|
|
39
|
+
@listeners = []
|
|
40
|
+
# The `asyncListeners` property stores the number of asynchronous
|
|
41
|
+
# listeners to use a synchronous dispatch when equal to 0.
|
|
42
|
+
@asyncListeners = 0
|
|
43
|
+
|
|
44
|
+
# Registers a listener for this signal to be called with
|
|
45
|
+
# the provided context.
|
|
46
|
+
# The context is the object that can be accessed through `this`
|
|
47
|
+
# inside the listener function body.
|
|
48
|
+
#
|
|
49
|
+
# An optional `priority` argument allow you to force
|
|
50
|
+
# an order of dispatch for a listener.
|
|
51
|
+
#
|
|
52
|
+
# Signals listeners can be asynchronous, in that case the last
|
|
53
|
+
# argument of the listener must be named `callback`. An async
|
|
54
|
+
# listener blocks the dispatch loop until the callback function
|
|
55
|
+
# passed to the listener is triggered.
|
|
56
|
+
#
|
|
57
|
+
# ```coffeescript
|
|
58
|
+
# # sync listener
|
|
59
|
+
# signal.add (a, b, c) ->
|
|
60
|
+
#
|
|
61
|
+
# # async listener
|
|
62
|
+
# signal.add (a, b, c, callback) -> callback()
|
|
63
|
+
# ```
|
|
64
|
+
#
|
|
65
|
+
# A listener can be registered several times, but only
|
|
66
|
+
# if the context object is different each time.
|
|
67
|
+
#
|
|
68
|
+
# In other words, the following is possible:
|
|
69
|
+
#
|
|
70
|
+
# ```coffeescript
|
|
71
|
+
# listener = ->
|
|
72
|
+
# context = {}
|
|
73
|
+
# myObject.signal.add listener
|
|
74
|
+
# myObject.signal.add listener, context
|
|
75
|
+
# ```
|
|
76
|
+
#
|
|
77
|
+
# When the following is not:
|
|
78
|
+
#
|
|
79
|
+
# ```coffeescript
|
|
80
|
+
# listener = ->
|
|
81
|
+
# myObject.signal.add listener
|
|
82
|
+
# myObject.signal.add listener
|
|
83
|
+
# ```
|
|
84
|
+
#
|
|
85
|
+
# listener - The {Function} to call when a signal is emitted.
|
|
86
|
+
# context - The `this` {Object} to call the function with.
|
|
87
|
+
# priority - A priority {Number}, the higher the priority the sooner
|
|
88
|
+
# the listener will be called in the dispatch loop.
|
|
89
|
+
add: (listener, context, priority=0) ->
|
|
90
|
+
@validate listener
|
|
91
|
+
|
|
92
|
+
if not @registered listener, context
|
|
93
|
+
@listeners.push [listener, context, false, priority]
|
|
94
|
+
@asyncListeners++ if @isAsync listener
|
|
95
|
+
|
|
96
|
+
# Listeners are sorted according to their order each time
|
|
97
|
+
# a new listener is added.
|
|
98
|
+
@sortListeners()
|
|
99
|
+
|
|
100
|
+
# Registers a listener for only one call.
|
|
101
|
+
#
|
|
102
|
+
# All the others rules are the same. So you can't add
|
|
103
|
+
# the same listener/context couple twice through the two methods.
|
|
104
|
+
#
|
|
105
|
+
# listener - The {Function} to call when a signal is emitted.
|
|
106
|
+
# context - The `this` {Object} to call the function with.
|
|
107
|
+
# priority - A priority {Number}, the higher the priority the sooner
|
|
108
|
+
# the listener will be called in the dispatch loop.
|
|
109
|
+
addOnce: (listener, context, priority = 0) ->
|
|
110
|
+
@validate listener
|
|
111
|
+
if not @registered listener, context
|
|
112
|
+
@listeners.push [listener, context, true, priority]
|
|
113
|
+
@asyncListeners++ if @isAsync listener
|
|
114
|
+
@sortListeners()
|
|
115
|
+
|
|
116
|
+
# Removes a listener from this signal, but only with the context that
|
|
117
|
+
# was registered with it.
|
|
118
|
+
#
|
|
119
|
+
# In this regards, avoid to register listeners without a context.
|
|
120
|
+
# If later in the application a context is forgotten or invalid
|
|
121
|
+
# when removing a listener from this signal, the listener
|
|
122
|
+
# without context will end up being removed.
|
|
123
|
+
#
|
|
124
|
+
# listener - The {Function} to remove from this signal.
|
|
125
|
+
# context - The `this` {Object} that was registered with the listener.
|
|
126
|
+
remove: (listener, context) ->
|
|
127
|
+
if @registered listener, context
|
|
128
|
+
@asyncListeners-- if @isAsync listener
|
|
129
|
+
@listeners.splice @indexOf(listener, context), 1
|
|
130
|
+
|
|
131
|
+
# Removes all listeners at once.
|
|
132
|
+
#
|
|
133
|
+
# ```coffeescript
|
|
134
|
+
# signal.removeAll()
|
|
135
|
+
# ```
|
|
136
|
+
removeAll: ->
|
|
137
|
+
@listeners = []
|
|
138
|
+
@asyncListeners = 0
|
|
139
|
+
|
|
140
|
+
# Internal: `indexOf` returns the position of the listener/context couple
|
|
141
|
+
# in the listeners array.
|
|
142
|
+
indexOf: (listener, context) ->
|
|
143
|
+
return i for [l,c],i in @listeners when listener is l and context is c
|
|
144
|
+
-1
|
|
145
|
+
|
|
146
|
+
# Returns true if the passed-in listener have been registered with the
|
|
147
|
+
# specified context in this signal.
|
|
148
|
+
#
|
|
149
|
+
# listener - The listener {Function} to verify.
|
|
150
|
+
# context - The context {Object} registered with the listener.
|
|
151
|
+
#
|
|
152
|
+
# Returns a {Boolean}.
|
|
153
|
+
registered: (listener, context) ->
|
|
154
|
+
@indexOf(listener, context) isnt -1
|
|
155
|
+
|
|
156
|
+
# Returns true if the signal has listeners.
|
|
157
|
+
#
|
|
158
|
+
# Returns a {Boolean}.
|
|
159
|
+
hasListeners: -> @listeners.length isnt 0
|
|
160
|
+
|
|
161
|
+
# Internal: The listeners are sorted according to their `priority`.
|
|
162
|
+
# The higher the priority the lower the listener will be
|
|
163
|
+
# in the call order.
|
|
164
|
+
sortListeners: ->
|
|
165
|
+
return if @listeners.length <= 1
|
|
166
|
+
@listeners.sort (a, b) ->
|
|
167
|
+
[pA, pB] = [a[3], b[3]]
|
|
168
|
+
|
|
169
|
+
if pA < pB then 1 else if pB < pA then -1 else 0
|
|
170
|
+
|
|
171
|
+
# Internal: Throws an error if the passed-in listener's signature
|
|
172
|
+
# doesn't match the signal's one.
|
|
173
|
+
#
|
|
174
|
+
# ```coffeescript
|
|
175
|
+
# signal = new Signal 'a', 'b', 'c'
|
|
176
|
+
# signal.validate () -> # false
|
|
177
|
+
# signal.validate (a,b,c) -> # true
|
|
178
|
+
# signal.validate (a,b,c,callback) -> # true
|
|
179
|
+
# ```
|
|
180
|
+
validate: (listener) ->
|
|
181
|
+
if @signature.length > 0
|
|
182
|
+
re = /[^(]+\(([^)]+)\).*$/m
|
|
183
|
+
listenerSignature = Function::toString.call(listener).split('\n').shift()
|
|
184
|
+
signature = listenerSignature.replace(re, '$1')
|
|
185
|
+
args = signature.split /\s*,\s*/g
|
|
186
|
+
|
|
187
|
+
args.shift() if args[0] is ''
|
|
188
|
+
args.pop() if args[args.length-1] is 'callback'
|
|
189
|
+
|
|
190
|
+
s1 = @signature.join()
|
|
191
|
+
s2 = args.join()
|
|
192
|
+
|
|
193
|
+
m = "The listener #{listener} doesn't match the signal's signature #{s1}"
|
|
194
|
+
throw new Error m if s2 isnt s1
|
|
195
|
+
|
|
196
|
+
# Returns `true` if the passed-in `listener` is asynchronous.
|
|
197
|
+
#
|
|
198
|
+
# ```coffeescript
|
|
199
|
+
# signal.isAsync(->) # false
|
|
200
|
+
# signal.isAsync((callback) ->) # true
|
|
201
|
+
# ```
|
|
202
|
+
#
|
|
203
|
+
# listener - The listner {Function} to test.
|
|
204
|
+
#
|
|
205
|
+
# Returns a {Boolean}.
|
|
206
|
+
isAsync: (listener) ->
|
|
207
|
+
Function::toString.call(listener).indexOf('callback)') != -1
|
|
208
|
+
|
|
209
|
+
# Dispatch a signal to the signal listeners.
|
|
210
|
+
# Signals are dispatched to all the listeners. All the arguments
|
|
211
|
+
# passed to the dispatch become the signal's message.
|
|
212
|
+
#
|
|
213
|
+
# ```coffeescript
|
|
214
|
+
# signal.dispatch this, true
|
|
215
|
+
# ```
|
|
216
|
+
#
|
|
217
|
+
# Listeners registered for only one call will be removed after
|
|
218
|
+
# the call.
|
|
219
|
+
#
|
|
220
|
+
# Optionally you can pass a callback argument to the dispatch function.
|
|
221
|
+
# In that case, the callback must be the last argument passed to the
|
|
222
|
+
# `dispatch` function. This function will be called at the end
|
|
223
|
+
# of the dispatch, allowing to execute code after all listeners,
|
|
224
|
+
# even asynchronous, have been triggered.
|
|
225
|
+
#
|
|
226
|
+
# ```coffeescript
|
|
227
|
+
# signal.dispatch this, true, ->
|
|
228
|
+
# # all listeners have finish their execution
|
|
229
|
+
# ```
|
|
230
|
+
#
|
|
231
|
+
# **Note:** As the dispatch function will automatically consider
|
|
232
|
+
# the last argument as the callback if its type is `function`, you should
|
|
233
|
+
# avoid using function as the sole argument or as the last argument
|
|
234
|
+
# for a listener. If that case occurs, consider either re-arranging the
|
|
235
|
+
# arguments order or using a value object to carry the function.
|
|
236
|
+
#
|
|
237
|
+
# args - The arguments to dispatch with the signal.
|
|
238
|
+
# callback - A {Function} to callback when all listeners have been notified.
|
|
239
|
+
dispatch: (args..., callback)->
|
|
240
|
+
unless typeof callback is 'function'
|
|
241
|
+
args.push callback
|
|
242
|
+
callback = null
|
|
243
|
+
|
|
244
|
+
listeners = @listeners.concat()
|
|
245
|
+
# If at leat one listener is async, the whole dispatch process is async
|
|
246
|
+
# otherwise the fast route is used.
|
|
247
|
+
if @asyncListeners > 0
|
|
248
|
+
next = (callback) =>
|
|
249
|
+
if listeners.length
|
|
250
|
+
[listener, context, once, priority] = listeners.shift()
|
|
251
|
+
|
|
252
|
+
if @isAsync listener
|
|
253
|
+
listener.apply context, args.concat =>
|
|
254
|
+
@remove listener, context if once
|
|
255
|
+
next callback
|
|
256
|
+
else
|
|
257
|
+
listener.apply context, args
|
|
258
|
+
@remove listener, context if once
|
|
259
|
+
next callback
|
|
260
|
+
else
|
|
261
|
+
callback?()
|
|
262
|
+
|
|
263
|
+
next callback
|
|
264
|
+
else
|
|
265
|
+
# The fast route is just a loop over the listeners.
|
|
266
|
+
# At that point, if your listener do async stuff, it will
|
|
267
|
+
# not prevent the dispatching until it's done.
|
|
268
|
+
for [listener, context, once, priority] in listeners
|
|
269
|
+
listener.apply context, arguments
|
|
270
|
+
@remove listener, context if once
|
|
271
|
+
|
|
272
|
+
callback?()
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
namespace('agt.sprites')
|
|
2
|
+
|
|
3
|
+
# Public:
|
|
4
|
+
class agt.sprites.Animation
|
|
5
|
+
constructor: (@image,
|
|
6
|
+
@width, @height,
|
|
7
|
+
@rowStart=0, @rowEnd=0,
|
|
8
|
+
@colStart=0, @colEnd=0
|
|
9
|
+
@durations) ->
|
|
10
|
+
@durations = (1000 / 24 for i in [@colStart..@colEnd]) unless @durations?
|
|
11
|
+
@rowLength = @rowEnd - @rowStart + 1
|
|
12
|
+
@colLength = @colEnd - @colStart + 1
|
|
13
|
+
@length = @rowLength * @colLength
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
namespace('agt.sprites')
|
|
2
|
+
|
|
3
|
+
# Public:
|
|
4
|
+
class agt.sprites.Sprite
|
|
5
|
+
constructor: (@animation) ->
|
|
6
|
+
@position = new agt.geom.Point
|
|
7
|
+
@center = new agt.geom.Point
|
|
8
|
+
@frame = 0
|
|
9
|
+
@time = 0
|
|
10
|
+
|
|
11
|
+
animate: (bias) ->
|
|
12
|
+
duration = @animation.durations[@frame]
|
|
13
|
+
if @time > duration
|
|
14
|
+
@frame = (@frame + 1) % @animation.length
|
|
15
|
+
@time = @time % duration
|
|
16
|
+
@time += bias
|
|
17
|
+
|
|
18
|
+
render: (context) ->
|
|
19
|
+
animation = @animation
|
|
20
|
+
col = @frame % animation.colLength
|
|
21
|
+
row = (@frame - col) / animation.colLength
|
|
22
|
+
clipX = (animation.colStart + col) * animation.width
|
|
23
|
+
clipY = (animation.rowStart + row) * animation.height
|
|
24
|
+
|
|
25
|
+
x = @position.x - @center.x
|
|
26
|
+
y = @position.y - @center.y
|
|
27
|
+
|
|
28
|
+
context.drawImage animation.image,
|
|
29
|
+
clipX, clipY, animation.width, animation.height,
|
|
30
|
+
x, y, animation.width, animation.height
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
namespace('agt.widgets')
|
|
2
|
+
|
|
3
|
+
# Public:
|
|
4
|
+
class agt.widgets.Hash
|
|
5
|
+
constructor: ->
|
|
6
|
+
@clear()
|
|
7
|
+
|
|
8
|
+
clear: ->
|
|
9
|
+
@keys = []
|
|
10
|
+
@values = []
|
|
11
|
+
|
|
12
|
+
set: (key, value) ->
|
|
13
|
+
if @hasKey key
|
|
14
|
+
index = @keys.indexOf key
|
|
15
|
+
@keys[index] = key
|
|
16
|
+
@values[index] = value
|
|
17
|
+
else
|
|
18
|
+
@keys.push key
|
|
19
|
+
@values.push value
|
|
20
|
+
|
|
21
|
+
get: (key) -> @values[ @keys.indexOf key ]
|
|
22
|
+
|
|
23
|
+
getKey: (value) -> @keys[ @values.indexOf value ]
|
|
24
|
+
|
|
25
|
+
hasKey: (key) -> @keys.indexOf(key) > 0
|
|
26
|
+
|
|
27
|
+
unset: (key) ->
|
|
28
|
+
index = @keys.indexOf key
|
|
29
|
+
@keys.splice index, 1
|
|
30
|
+
@values.splice index, 1
|
|
31
|
+
|
|
32
|
+
each: (block) -> @values.forEach block
|
|
33
|
+
|
|
34
|
+
eachKey: (block) -> @keys.forEach block
|
|
35
|
+
|
|
36
|
+
eachPair: (block) -> @keys.forEach (key) => block? key, @get key
|