annotate flax/Timeline.py @ 2074:1a96f8647126

big graph & autodep porting to make collector display labels from a syncedgraph
author drewp@bigasterisk.com
date Mon, 23 May 2022 23:32:37 -0700
parents 851cf44cea40
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
1 from TLUtility import make_attributes_from_args, dict_scale, dict_max, \
45b12307c695 Initial revision
drewp
parents:
diff changeset
2 DummyClass, last_less_than, first_greater_than
45b12307c695 Initial revision
drewp
parents:
diff changeset
3 from time import time
206
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
4 import random
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
5 from __future__ import division # "I'm sending you back to future!"
45b12307c695 Initial revision
drewp
parents:
diff changeset
6
45b12307c695 Initial revision
drewp
parents:
diff changeset
7 """
110
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
8 Quote of the Build (from Ghostbusters II)
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
9 Dana: Okay, but after dinner, I don't want you putting any of your old cheap
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
10 moves on me.
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
11 Peter: Ohhhh no! I've got all NEW cheap moves.
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
12 """
45b12307c695 Initial revision
drewp
parents:
diff changeset
13
45b12307c695 Initial revision
drewp
parents:
diff changeset
14 class MissingBlender(Exception):
45b12307c695 Initial revision
drewp
parents:
diff changeset
15 """Raised when a TimedEvent is missing a blender."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
16 def __init__(self, timedevent):
45b12307c695 Initial revision
drewp
parents:
diff changeset
17 make_attributes_from_args('timedevent')
45b12307c695 Initial revision
drewp
parents:
diff changeset
18 Exception.__init__(self, "%r is missing a blender." % \
45b12307c695 Initial revision
drewp
parents:
diff changeset
19 self.timedevent)
45b12307c695 Initial revision
drewp
parents:
diff changeset
20
45b12307c695 Initial revision
drewp
parents:
diff changeset
21 # these are chosen so we can multiply by -1 to reverse the direction,
45b12307c695 Initial revision
drewp
parents:
diff changeset
22 # and multiply direction by the time difference to determine new times.
45b12307c695 Initial revision
drewp
parents:
diff changeset
23 FORWARD = 1
45b12307c695 Initial revision
drewp
parents:
diff changeset
24 BACKWARD = -1
45b12307c695 Initial revision
drewp
parents:
diff changeset
25
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
26 MISSING = 'missing'
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
27
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
28 class TimedEvent:
45b12307c695 Initial revision
drewp
parents:
diff changeset
29 """Container for a Frame which includes a time that it occurs at,
45b12307c695 Initial revision
drewp
parents:
diff changeset
30 and which blender occurs after it."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
31 def __init__(self, time, frame=MISSING, blender=None, level=1.0):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
32 make_attributes_from_args('time', 'frame')
45b12307c695 Initial revision
drewp
parents:
diff changeset
33 self.next_blender = blender
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
34 self.level = level
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
35 def __float__(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
36 return self.time
45b12307c695 Initial revision
drewp
parents:
diff changeset
37 def __cmp__(self, other):
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
38 if other is None:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
39 raise "I can't compare with a None. I am '%s'" % str(self)
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
40 if type(other) in (float, int):
45b12307c695 Initial revision
drewp
parents:
diff changeset
41 return cmp(self.time, other)
45b12307c695 Initial revision
drewp
parents:
diff changeset
42 else:
45b12307c695 Initial revision
drewp
parents:
diff changeset
43 return cmp(self.time, other.time)
45b12307c695 Initial revision
drewp
parents:
diff changeset
44 def __repr__(self):
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
45 return "<TimedEvent %s at %.2f, time=%.2f, next blender=%s>" % \
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
46 (self.frame, self.level, self.time, self.next_blender)
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
47 def get_level(self):
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
48 return self.level
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
49 def __hash__(self):
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
50 return id(self.time) ^ id(self.frame) ^ id(self.next_blender)
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
51
45b12307c695 Initial revision
drewp
parents:
diff changeset
52 class Blender:
45b12307c695 Initial revision
drewp
parents:
diff changeset
53 """Blenders are functions that merge the effects of two LevelFrames."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
54 def __init__(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
55 pass
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
56 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
57 """Return a LevelFrame combining two LevelFrames (startframe and
45b12307c695 Initial revision
drewp
parents:
diff changeset
58 endframe). blendtime is how much of the blend should be performed
45b12307c695 Initial revision
drewp
parents:
diff changeset
59 and will be expressed as a percentage divided by 100, i.e. a float
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
60 between 0.0 and 1.0. time_since_startframe is the time since the
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
61 startframe was on screen in seconds (float).
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
62
45b12307c695 Initial revision
drewp
parents:
diff changeset
63 Very important note: Blenders will *not* be asked for values
45b12307c695 Initial revision
drewp
parents:
diff changeset
64 at end points (i.e. blendtime=0.0 and blendtime=1.0).
45b12307c695 Initial revision
drewp
parents:
diff changeset
65 The LevelFrames will be allowed to specify the values at
45b12307c695 Initial revision
drewp
parents:
diff changeset
66 those times. This is unfortunately for implemementation and
45b12307c695 Initial revision
drewp
parents:
diff changeset
67 simplicity purposes. In other words, if we didn't do this,
45b12307c695 Initial revision
drewp
parents:
diff changeset
68 we could have two blenders covering the same point in time and
45b12307c695 Initial revision
drewp
parents:
diff changeset
69 not know which one to ask for the value. Thus, this saves us
45b12307c695 Initial revision
drewp
parents:
diff changeset
70 a lot of messiness with minimal or no sacrifice."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
71 pass
45b12307c695 Initial revision
drewp
parents:
diff changeset
72 def __str__(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
73 """As a default, we'll just return the name of the class. Subclasses
45b12307c695 Initial revision
drewp
parents:
diff changeset
74 can add parameters on if they want."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
75 return str(self.__class__)
45b12307c695 Initial revision
drewp
parents:
diff changeset
76 def linear_blend(self, startframe, endframe, blendtime):
45b12307c695 Initial revision
drewp
parents:
diff changeset
77 """Utility function to help you produce linear combinations of two
45b12307c695 Initial revision
drewp
parents:
diff changeset
78 blends. blendtime is the percent/100 that the blend should
45b12307c695 Initial revision
drewp
parents:
diff changeset
79 completed. In other words, 0.25 means it should be 0.75 * startframe +
45b12307c695 Initial revision
drewp
parents:
diff changeset
80 0.25 * endframe. This function is included since many blenders are
45b12307c695 Initial revision
drewp
parents:
diff changeset
81 just functions on the percentage and still combine start and end frames
45b12307c695 Initial revision
drewp
parents:
diff changeset
82 in this way."""
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
83 if startframe.frame == endframe.frame:
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
84 level = startframe.level + (blendtime * \
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
85 (endframe.level - startframe.level))
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
86 levels = {startframe.frame : level}
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
87 else:
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
88 levels = {startframe.frame : (1.0 - blendtime) * startframe.level,
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
89 endframe.frame : blendtime * endframe.level}
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
90 return levels
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
91
45b12307c695 Initial revision
drewp
parents:
diff changeset
92 class InstantEnd(Blender):
45b12307c695 Initial revision
drewp
parents:
diff changeset
93 """Instant change from startframe to endframe at the end. In other words,
45b12307c695 Initial revision
drewp
parents:
diff changeset
94 the value returned will be the startframe all the way until the very end
45b12307c695 Initial revision
drewp
parents:
diff changeset
95 of the blend."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
96 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
97 # "What!?" you say, "Why don't you care about blendtime?"
45b12307c695 Initial revision
drewp
parents:
diff changeset
98 # This is because Blenders never be asked for blenders at the endpoints
45b12307c695 Initial revision
drewp
parents:
diff changeset
99 # (after all, they wouldn't be blenders if they were). Please see
45b12307c695 Initial revision
drewp
parents:
diff changeset
100 # 'Very important note' in Blender.__doc__
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
101 return {startframe.frame : startframe.level}
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
102
45b12307c695 Initial revision
drewp
parents:
diff changeset
103 class InstantStart(Blender):
45b12307c695 Initial revision
drewp
parents:
diff changeset
104 """Instant change from startframe to endframe at the beginning. In other
45b12307c695 Initial revision
drewp
parents:
diff changeset
105 words, the value returned will be the startframe at the very beginning
45b12307c695 Initial revision
drewp
parents:
diff changeset
106 and then be endframe at all times afterwards."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
107 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
108 # "What!?" you say, "Why don't you care about blendtime?"
45b12307c695 Initial revision
drewp
parents:
diff changeset
109 # This is because Blenders never be asked for blenders at the endpoints
45b12307c695 Initial revision
drewp
parents:
diff changeset
110 # (after all, they wouldn't be blenders if they were). Please see
45b12307c695 Initial revision
drewp
parents:
diff changeset
111 # 'Very important note' in Blender.__doc__
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
112 return {endframe.frame : endframe.level}
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
113
45b12307c695 Initial revision
drewp
parents:
diff changeset
114 class LinearBlender(Blender):
45b12307c695 Initial revision
drewp
parents:
diff changeset
115 """Linear fade from one frame to another"""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
116 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
117 return self.linear_blend(startframe, endframe, blendtime)
45b12307c695 Initial revision
drewp
parents:
diff changeset
118
45b12307c695 Initial revision
drewp
parents:
diff changeset
119 class ExponentialBlender(Blender):
45b12307c695 Initial revision
drewp
parents:
diff changeset
120 """Exponential fade fron one frame to another. You get to specify
45b12307c695 Initial revision
drewp
parents:
diff changeset
121 the exponent. If my math is correct, exponent=1 means the same thing
45b12307c695 Initial revision
drewp
parents:
diff changeset
122 as LinearBlender."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
123 def __init__(self, exponent):
45b12307c695 Initial revision
drewp
parents:
diff changeset
124 self.exponent = exponent
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
125 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
126 blendtime = blendtime ** self.exponent
45b12307c695 Initial revision
drewp
parents:
diff changeset
127 return self.linear_blend(startframe, endframe, blendtime)
45b12307c695 Initial revision
drewp
parents:
diff changeset
128
45b12307c695 Initial revision
drewp
parents:
diff changeset
129 # 17:02:53 drewp: this makes a big difference for the SmoothBlender
45b12307c695 Initial revision
drewp
parents:
diff changeset
130 # (-x*x*(x-1.5)*2) function
45b12307c695 Initial revision
drewp
parents:
diff changeset
131 class SmoothBlender(Blender):
45b12307c695 Initial revision
drewp
parents:
diff changeset
132 """Drew's "Smoove" Blender function. Hopefully he'll document and
45b12307c695 Initial revision
drewp
parents:
diff changeset
133 parametrize it."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
134 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
135 blendtime = (-1 * blendtime) * blendtime * (blendtime - 1.5) * 2
45b12307c695 Initial revision
drewp
parents:
diff changeset
136 return self.linear_blend(startframe, endframe, blendtime)
45b12307c695 Initial revision
drewp
parents:
diff changeset
137
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
138 class Strobe(Blender):
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
139 "Strobes the frame on the right side between offlevel and onlevel."
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
140 def __init__(self, ontime, offtime, onlevel=1, offlevel=0):
138
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
141 "times are in seconds (floats)"
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
142 make_attributes_from_args('ontime', 'offtime', 'onlevel', 'offlevel')
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
143 self.cycletime = ontime + offtime
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
144 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
145 # time into the current period
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
146 period_time = time_since_startframe % self.cycletime
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
147 if period_time <= self.ontime:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
148 return {endframe.frame : self.onlevel}
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
149 else:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
150 return {endframe.frame : self.offlevel}
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
151
206
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
152 class Sine(Blender):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
153 "Strobes the frame on the right side between offlevel and onlevel."
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
154 def __init__(self, period, onlevel=1, offlevel=0):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
155 "times are in seconds (floats)"
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
156 make_attributes_from_args('period', 'onlevel', 'offlevel')
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
157 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
158 sin = math.sin(time_since_startframe / self.period * 2 * math.pi)
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
159 zerotoone = (sin / 2) + 0.5
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
160 level = offlevel + (zerotoone * (onlevel - offlevel))
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
161 return {endframe.frame : level}
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
162
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
163 class RandomStrobe(Blender):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
164 def __init__(self, minwaitlen=0.1, maxwaitlen=0.6, burstlen=0.14, \
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
165 burstintensity=1, offintensity=0.05, tracklen=500):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
166 "times are in seconds (floats)"
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
167 make_attributes_from_args('burstlen', 'burstintensity', 'offintensity')
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
168 self.burstintervals = []
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
169 timecursor = 0
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
170
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
171 while timecursor < tracklen:
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
172 waitlen = minwaitlen + (random.random() * (maxwaitlen - minwaitlen))
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
173 timecursor += waitlen
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
174 self.burstintervals.append((timecursor, timecursor + burstlen))
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
175 def __call__(self, startframe, endframe, blendtime, time_since_startframe):
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
176 found_burst = 0
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
177 for intstart, intend in self.burstintervals:
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
178 if intstart <= time_since_startframe <= intend:
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
179 found_burst = 1
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
180 break
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
181
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
182 if found_burst:
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
183 return {endframe.frame : self.burstintensity}
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
184 else:
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
185 return {endframe.frame : self.offintensity}
851cf44cea40 rename clientid and allow it as an argument
drewp
parents: 139
diff changeset
186
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
187 class TimelineTrack:
45b12307c695 Initial revision
drewp
parents:
diff changeset
188 """TimelineTrack is a single track in a Timeline. It consists of a
45b12307c695 Initial revision
drewp
parents:
diff changeset
189 list of TimedEvents and a name. Length is automatically the location
45b12307c695 Initial revision
drewp
parents:
diff changeset
190 of the last TimedEvent. To extend the Timeline past that, add an
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
191 EmptyTimedEvent (which doesn't exist :-/)."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
192 def __init__(self, name, *timedevents, **kw):
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
193 if kw.get('default_frame'):
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
194 self.default_frame = kw['default_frame']
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
195 else:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
196 self.default_frame = None
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
197 self.name = name
138
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
198 self.set_events(list(timedevents))
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
199 def set_events(self, events):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
200 """This is given a list of TimedEvents. They need not be sorted."""
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
201 self.events = events
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
202 self._cleaup_events()
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
203 def _cleaup_events(self):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
204 """This makes sure all events are in the right order and have defaults
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
205 filled in if they have missing frames."""
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
206 self.events.sort()
139
83e2c4ceb79a KeyboardComposer: let's get it working again
dmcc
parents: 138
diff changeset
207 self.fill_in_missing_frames()
138
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
208 def add_event(self, event):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
209 """Add a TimedEvent object to this TimelineTrack"""
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
210 self.events.append(event)
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
211 self._cleaup_events(self.events)
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
212 def delete_event(self, event):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
213 """Delete event by TimedEvent object"""
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
214 self.events.remove(event)
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
215 self._cleaup_events(self.events)
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
216 def delete_event_by_name(self, name):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
217 """Deletes all events matching a certain name"""
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
218 self.events = [e for e in self.events if e.name is not name]
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
219 self._cleaup_events(self.events)
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
220 def delete_event_by_time(self, starttime, endtime=None):
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
221 """Deletes all events within a certain time range, inclusive. endtime
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
222 is optional."""
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
223 endtime = endtime or starttime
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
224 self.events = [e for e in self.events
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
225 if e.time >= starttime and e.time <= endtime]
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
226 self._cleaup_events(self.events)
139
83e2c4ceb79a KeyboardComposer: let's get it working again
dmcc
parents: 138
diff changeset
227 def fill_in_missing_frames(self):
138
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
228 """Runs through all events and sets TimedEvent with missing frames to
304152488ed7 Timeline: new methods to make editing easier
dmcc
parents: 135
diff changeset
229 the default frame."""
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
230 for event in self.events:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
231 if event.frame == MISSING:
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
232 event.frame = self.default_frame
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
233 def __str__(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
234 return "<TimelineTrack with events: %r>" % self.events
45b12307c695 Initial revision
drewp
parents:
diff changeset
235 def has_events(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
236 """Whether the TimelineTrack has anything in it. In general,
45b12307c695 Initial revision
drewp
parents:
diff changeset
237 empty level Tracks should be avoided. However, empty function tracks
45b12307c695 Initial revision
drewp
parents:
diff changeset
238 might be common."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
239 return len(self.events)
45b12307c695 Initial revision
drewp
parents:
diff changeset
240 def length(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
241 """Returns the length of this track in pseudosecond time units.
45b12307c695 Initial revision
drewp
parents:
diff changeset
242 This is done by finding the position of the last TimedEvent."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
243 return float(self.events[-1])
45b12307c695 Initial revision
drewp
parents:
diff changeset
244 def get(self, key, direction=FORWARD):
45b12307c695 Initial revision
drewp
parents:
diff changeset
245 """Returns the event at a specific time key. If there is no event
45b12307c695 Initial revision
drewp
parents:
diff changeset
246 at that time, a search will be performed in direction. Also note
45b12307c695 Initial revision
drewp
parents:
diff changeset
247 that if there are multiple events at one time, only the first will
45b12307c695 Initial revision
drewp
parents:
diff changeset
248 be returned. (Probably first in order of adding.) This is not
45b12307c695 Initial revision
drewp
parents:
diff changeset
249 a problem at the present since this method is intended for LevelFrames,
45b12307c695 Initial revision
drewp
parents:
diff changeset
250 which must exist at unique times."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
251 if direction == BACKWARD:
45b12307c695 Initial revision
drewp
parents:
diff changeset
252 func = last_less_than
45b12307c695 Initial revision
drewp
parents:
diff changeset
253 else:
45b12307c695 Initial revision
drewp
parents:
diff changeset
254 func = first_greater_than
45b12307c695 Initial revision
drewp
parents:
diff changeset
255
45b12307c695 Initial revision
drewp
parents:
diff changeset
256 return func(self.events, key)
45b12307c695 Initial revision
drewp
parents:
diff changeset
257 def get_range(self, i, j, direction=FORWARD):
45b12307c695 Initial revision
drewp
parents:
diff changeset
258 """Returns all events between i and j, exclusively. If direction
45b12307c695 Initial revision
drewp
parents:
diff changeset
259 is FORWARD, j will be included. If direction is BACKWARD, i will
45b12307c695 Initial revision
drewp
parents:
diff changeset
260 be included. This is because this is used to find FunctionFrames
45b12307c695 Initial revision
drewp
parents:
diff changeset
261 and we assume that any function frames at the start point (which
45b12307c695 Initial revision
drewp
parents:
diff changeset
262 could be i or j) have been processed."""
110
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
263 return [e for e in self.events if e >= i and e <= j]
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
264
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
265 if direction == FORWARD:
45b12307c695 Initial revision
drewp
parents:
diff changeset
266 return [e for e in self.events if e > i and e <= j]
45b12307c695 Initial revision
drewp
parents:
diff changeset
267 else:
45b12307c695 Initial revision
drewp
parents:
diff changeset
268 return [e for e in self.events if e >= i and e < j]
45b12307c695 Initial revision
drewp
parents:
diff changeset
269 def __getitem__(self, key):
45b12307c695 Initial revision
drewp
parents:
diff changeset
270 """Returns the event at or after a specific time key.
45b12307c695 Initial revision
drewp
parents:
diff changeset
271 For example: timeline[3] will get the first event at time 3.
45b12307c695 Initial revision
drewp
parents:
diff changeset
272
45b12307c695 Initial revision
drewp
parents:
diff changeset
273 If you want to get all events at time 3, you are in trouble, but
45b12307c695 Initial revision
drewp
parents:
diff changeset
274 you could achieve it with something like:
45b12307c695 Initial revision
drewp
parents:
diff changeset
275 timeline.get_range(2.99, 3.01, FORWARD)
45b12307c695 Initial revision
drewp
parents:
diff changeset
276 This is hopefully a bogus problem, since you can't have multiple
45b12307c695 Initial revision
drewp
parents:
diff changeset
277 LevelFrames at the same time."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
278 return self.get(key, direction=FORWARD)
45b12307c695 Initial revision
drewp
parents:
diff changeset
279 def get_surrounding_frames(self, time):
45b12307c695 Initial revision
drewp
parents:
diff changeset
280 """Returns frames before and after a specific time. This returns
45b12307c695 Initial revision
drewp
parents:
diff changeset
281 a 2-tuple: (previousframe, nextframe). If you have chosen the exact
45b12307c695 Initial revision
drewp
parents:
diff changeset
282 time of a frame, it will be both previousframe and nextframe."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
283 return self.get(time, direction=BACKWARD), \
45b12307c695 Initial revision
drewp
parents:
diff changeset
284 self.get(time, direction=FORWARD)
45b12307c695 Initial revision
drewp
parents:
diff changeset
285 def get_levels_at_time(self, time):
45b12307c695 Initial revision
drewp
parents:
diff changeset
286 """Returns a LevelFrame with the levels of this track at that time."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
287 before, after = self.get_surrounding_frames(time)
45b12307c695 Initial revision
drewp
parents:
diff changeset
288
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
289 if not after or before == after:
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
290 return {before.frame : before.level}
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
291 else: # we have a blended value
45b12307c695 Initial revision
drewp
parents:
diff changeset
292 diff = after.time - before.time
45b12307c695 Initial revision
drewp
parents:
diff changeset
293 elapsed = time - before.time
45b12307c695 Initial revision
drewp
parents:
diff changeset
294 percent = elapsed / diff
45b12307c695 Initial revision
drewp
parents:
diff changeset
295 if not before.next_blender:
45b12307c695 Initial revision
drewp
parents:
diff changeset
296 raise MissingBlender, before
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
297 return before.next_blender(before, after, percent, elapsed)
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
298
45b12307c695 Initial revision
drewp
parents:
diff changeset
299 class Timeline:
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
300 def __init__(self, name, tracks, rate=1, direction=FORWARD):
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
301 """
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
302 Most/all of this is old:
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
303
45b12307c695 Initial revision
drewp
parents:
diff changeset
304 You can have multiple FunctionFrames at the same time. Their
45b12307c695 Initial revision
drewp
parents:
diff changeset
305 order is important though, since FunctionFrames will be applied
45b12307c695 Initial revision
drewp
parents:
diff changeset
306 in the order seen in this list. blenders is a list of Blenders.
45b12307c695 Initial revision
drewp
parents:
diff changeset
307 rate is the rate of playback. If set to 1, 1 unit inside the
45b12307c695 Initial revision
drewp
parents:
diff changeset
308 Timeline will be 1 second. direction is the initial direction.
45b12307c695 Initial revision
drewp
parents:
diff changeset
309 If you want to do have looping, place a LoopFunction at the end of
45b12307c695 Initial revision
drewp
parents:
diff changeset
310 the Timeline. Timelines don't have a set length. Their length
45b12307c695 Initial revision
drewp
parents:
diff changeset
311 is bounded by their last frame. You can put an EmptyFrame at
45b12307c695 Initial revision
drewp
parents:
diff changeset
312 some time if you want to extend a Timeline."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
313
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
314 make_attributes_from_args('name', 'tracks', 'rate', 'direction')
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
315 self.current_time = 0
45b12307c695 Initial revision
drewp
parents:
diff changeset
316 self.last_clock_time = None
45b12307c695 Initial revision
drewp
parents:
diff changeset
317 self.stopped = 1
45b12307c695 Initial revision
drewp
parents:
diff changeset
318 def length(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
319 """Length of the timeline in pseudoseconds. This is determined by
45b12307c695 Initial revision
drewp
parents:
diff changeset
320 finding the length of the longest track."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
321 track_lengths = [track.length() for track in self.tracks]
45b12307c695 Initial revision
drewp
parents:
diff changeset
322 return max(track_lengths)
45b12307c695 Initial revision
drewp
parents:
diff changeset
323 def play(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
324 """Activates the timeline. Future calls to tick() will advance the
45b12307c695 Initial revision
drewp
parents:
diff changeset
325 timeline in the appropriate direction."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
326 self.stopped = 0
45b12307c695 Initial revision
drewp
parents:
diff changeset
327 def stop(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
328 """The timeline will no longer continue in either direction, no
45b12307c695 Initial revision
drewp
parents:
diff changeset
329 FunctionFrames will be activated."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
330 self.stopped = 1
45b12307c695 Initial revision
drewp
parents:
diff changeset
331 self.last_clock_time = None
45b12307c695 Initial revision
drewp
parents:
diff changeset
332 def reset(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
333 """Resets the timeline to 0. Does not change the stoppedness of the
45b12307c695 Initial revision
drewp
parents:
diff changeset
334 timeline."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
335 self.current_time = 0
45b12307c695 Initial revision
drewp
parents:
diff changeset
336 def tick(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
337 """Updates the current_time and runs any FunctionFrames that the cursor
45b12307c695 Initial revision
drewp
parents:
diff changeset
338 passed over. This call is ignored if the timeline is stopped."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
339 if self.stopped:
45b12307c695 Initial revision
drewp
parents:
diff changeset
340 return
45b12307c695 Initial revision
drewp
parents:
diff changeset
341
45b12307c695 Initial revision
drewp
parents:
diff changeset
342 last_time = self.current_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
343 last_clock = self.last_clock_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
344
45b12307c695 Initial revision
drewp
parents:
diff changeset
345 # first, determine new time
45b12307c695 Initial revision
drewp
parents:
diff changeset
346 clock_time = time()
45b12307c695 Initial revision
drewp
parents:
diff changeset
347 if last_clock is None:
45b12307c695 Initial revision
drewp
parents:
diff changeset
348 last_clock = clock_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
349 diff = clock_time - last_clock
45b12307c695 Initial revision
drewp
parents:
diff changeset
350 new_time = (self.direction * self.rate * diff) + last_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
351
45b12307c695 Initial revision
drewp
parents:
diff changeset
352 # update the time
45b12307c695 Initial revision
drewp
parents:
diff changeset
353 self.last_clock_time = clock_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
354 self.current_time = new_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
355
110
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
356 # now we make sure we're in bounds (we don't do this before, since it
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
357 # can cause us to skip events that are at boundaries.
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
358 self.current_time = max(self.current_time, 0)
490843093506 all of this stuff is super rough and not well thought out yet.
dmcc
parents: 109
diff changeset
359 self.current_time = min(self.current_time, self.length())
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
360 def reverse_direction(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
361 """Reverses the direction of play for this node"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
362 self.direction = self.direction * -1
45b12307c695 Initial revision
drewp
parents:
diff changeset
363 def set_direction(self, direction):
45b12307c695 Initial revision
drewp
parents:
diff changeset
364 """Sets the direction of playback."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
365 self.direction = direction
45b12307c695 Initial revision
drewp
parents:
diff changeset
366 def set_rate(self, new_rate):
45b12307c695 Initial revision
drewp
parents:
diff changeset
367 """Sets the rate of playback"""
45b12307c695 Initial revision
drewp
parents:
diff changeset
368 self.rate = new_rate
45b12307c695 Initial revision
drewp
parents:
diff changeset
369 def set_time(self, new_time):
45b12307c695 Initial revision
drewp
parents:
diff changeset
370 """Set the time to a new time."""
45b12307c695 Initial revision
drewp
parents:
diff changeset
371 self.current_time = new_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
372 def get_levels(self):
45b12307c695 Initial revision
drewp
parents:
diff changeset
373 """Return the current levels from this timeline. This is done by
45b12307c695 Initial revision
drewp
parents:
diff changeset
374 adding all the non-functional tracks together."""
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
375 levels = [t.get_levels_at_time(self.current_time)
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
376 for t in self.tracks]
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
377 return dict_max(*levels)
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
378
45b12307c695 Initial revision
drewp
parents:
diff changeset
379 if __name__ == '__main__':
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
380 def T(*args, **kw):
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
381 """This used to be a synonym for TimedEvent:
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
382
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
383 T = TimedEvent
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
384
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
385 It now acts the same way, except that it will fill in a default
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
386 blender if you don't. The default blender is a LinearBlender."""
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
387 linear = LinearBlender()
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
388 if 'blender' not in kw:
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
389 kw['blender'] = linear
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
390
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
391 return TimedEvent(*args, **kw)
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
392
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
393 quad = ExponentialBlender(2)
45b12307c695 Initial revision
drewp
parents:
diff changeset
394 invquad = ExponentialBlender(0.5)
45b12307c695 Initial revision
drewp
parents:
diff changeset
395 smoove = SmoothBlender()
45b12307c695 Initial revision
drewp
parents:
diff changeset
396
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
397 track1 = TimelineTrack('red track',
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
398 T(0, 'red', level=0),
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
399 T(4, 'red', blender=quad, level=0.5),
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
400 T(12, 'red', blender=smoove, level=0.7),
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
401 T(15, 'red', level=0.0)) # last TimedEvent doesn't need a blender
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
402 track2 = TimelineTrack('green track',
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
403 T(0, 'green', blender=invquad, level=0.2),
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
404 T(5, 'green', blender=smoove, level=1),
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
405 T(10, 'green', level=0.8),
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
406 T(15, 'green', level=0.6),
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
407 T(20, 'green', level=0.0)) # last TimedEvent doesn't need a blender
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
408 track3 = TimelineTrack('tableau demo',
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
409 T(0, 'blue', level=0.0),
123
41c0ec6cd10a bugfixes, tableau demo
dmcc
parents: 122
diff changeset
410 T(2, 'blue', level=1.0, blender=InstantEnd()),
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
411 T(18, 'blue', level=1.0),
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
412 T(20, 'blue', level=0.0))
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
413
135
5670f66845ce - results of work from 6.13 rehearsal
dmcc
parents: 124
diff changeset
414 tl = Timeline('test', [track1, track2, track3])
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
415
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
416 tl.play()
45b12307c695 Initial revision
drewp
parents:
diff changeset
417
45b12307c695 Initial revision
drewp
parents:
diff changeset
418 import Tix
45b12307c695 Initial revision
drewp
parents:
diff changeset
419 root = Tix.Tk()
45b12307c695 Initial revision
drewp
parents:
diff changeset
420 colorscalesframe = Tix.Frame(root)
45b12307c695 Initial revision
drewp
parents:
diff changeset
421 scalevars = {}
45b12307c695 Initial revision
drewp
parents:
diff changeset
422 # wow, this works out so well, it's almost like I planned it!
45b12307c695 Initial revision
drewp
parents:
diff changeset
423 # (actually, it's probably just Tk being as cool as it usually is)
45b12307c695 Initial revision
drewp
parents:
diff changeset
424 # ps. if this code ever turns into mainstream code for flax, I'll be
45b12307c695 Initial revision
drewp
parents:
diff changeset
425 # pissed (reason: we need to use classes, not this hacked crap!)
45b12307c695 Initial revision
drewp
parents:
diff changeset
426 colors = 'red', 'blue', 'green', 'yellow', 'purple'
45b12307c695 Initial revision
drewp
parents:
diff changeset
427 for color in colors:
45b12307c695 Initial revision
drewp
parents:
diff changeset
428 sv = Tix.DoubleVar()
45b12307c695 Initial revision
drewp
parents:
diff changeset
429 scalevars[color] = sv
122
2ed9bfd1dd0e I totally wrecked Timeline so that it can run the show. (I hope it can
dmcc
parents: 110
diff changeset
430 scale = Tix.Scale(colorscalesframe, from_=1, to_=0, res=0.01, bg=color,
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
431 variable=sv)
45b12307c695 Initial revision
drewp
parents:
diff changeset
432 scale.pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
433
45b12307c695 Initial revision
drewp
parents:
diff changeset
434 def set_timeline_time(time):
45b12307c695 Initial revision
drewp
parents:
diff changeset
435 tl.set_time(float(time))
45b12307c695 Initial revision
drewp
parents:
diff changeset
436 # print 'set_timeline_time', time
45b12307c695 Initial revision
drewp
parents:
diff changeset
437
45b12307c695 Initial revision
drewp
parents:
diff changeset
438 def update_scales():
45b12307c695 Initial revision
drewp
parents:
diff changeset
439 levels = tl.get_levels()
45b12307c695 Initial revision
drewp
parents:
diff changeset
440 for color in colors:
45b12307c695 Initial revision
drewp
parents:
diff changeset
441 scalevars[color].set(levels.get(color, 0))
45b12307c695 Initial revision
drewp
parents:
diff changeset
442
45b12307c695 Initial revision
drewp
parents:
diff changeset
443 colorscalesframe.pack()
124
8de8a2f467db The "T" function now creates TimedEvents with LinearBlenders for you
dmcc
parents: 123
diff changeset
444 time_scale = Tix.Scale(root, from_=0, to_=tl.length(),
0
45b12307c695 Initial revision
drewp
parents:
diff changeset
445 orient=Tix.HORIZONTAL, res=0.01, command=set_timeline_time)
45b12307c695 Initial revision
drewp
parents:
diff changeset
446 time_scale.pack(side=Tix.BOTTOM, fill=Tix.X, expand=1)
45b12307c695 Initial revision
drewp
parents:
diff changeset
447
45b12307c695 Initial revision
drewp
parents:
diff changeset
448 def play_tl():
45b12307c695 Initial revision
drewp
parents:
diff changeset
449 tl.tick()
45b12307c695 Initial revision
drewp
parents:
diff changeset
450 update_scales()
45b12307c695 Initial revision
drewp
parents:
diff changeset
451 time_scale.set(tl.current_time)
45b12307c695 Initial revision
drewp
parents:
diff changeset
452 # print 'time_scale.set', tl.current_time
45b12307c695 Initial revision
drewp
parents:
diff changeset
453 root.after(10, play_tl)
45b12307c695 Initial revision
drewp
parents:
diff changeset
454
45b12307c695 Initial revision
drewp
parents:
diff changeset
455 controlwindow = Tix.Toplevel()
45b12307c695 Initial revision
drewp
parents:
diff changeset
456 Tix.Button(controlwindow, text='Stop',
45b12307c695 Initial revision
drewp
parents:
diff changeset
457 command=lambda: tl.stop()).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
458 Tix.Button(controlwindow, text='Play',
45b12307c695 Initial revision
drewp
parents:
diff changeset
459 command=lambda: tl.play()).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
460 Tix.Button(controlwindow, text='Reset',
45b12307c695 Initial revision
drewp
parents:
diff changeset
461 command=lambda: time_scale.set(0)).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
462 Tix.Button(controlwindow, text='Flip directions',
45b12307c695 Initial revision
drewp
parents:
diff changeset
463 command=lambda: tl.reverse_direction()).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
464 Tix.Button(controlwindow, text='1/2x',
45b12307c695 Initial revision
drewp
parents:
diff changeset
465 command=lambda: tl.set_rate(0.5 * tl.rate)).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
466 Tix.Button(controlwindow, text='2x',
45b12307c695 Initial revision
drewp
parents:
diff changeset
467 command=lambda: tl.set_rate(2 * tl.rate)).pack(side=Tix.LEFT)
45b12307c695 Initial revision
drewp
parents:
diff changeset
468
45b12307c695 Initial revision
drewp
parents:
diff changeset
469 root.after(100, play_tl)
45b12307c695 Initial revision
drewp
parents:
diff changeset
470
45b12307c695 Initial revision
drewp
parents:
diff changeset
471 # Timeline.set_time = trace(Timeline.set_time)
45b12307c695 Initial revision
drewp
parents:
diff changeset
472
45b12307c695 Initial revision
drewp
parents:
diff changeset
473 Tix.mainloop()