Changeset - 71489bb71528
[Not reviewed]
default
0 11 0
dmcc - 22 years ago 2002-07-07 15:40:45

- Meet Fader. He is going to grow up and be a crossfader some day
- Meet Fader. He is going to grow up and be a crossfader some day
(tomarrow)
- Tkinter -> Tix so we can use ScrolledListBox which has a command
- Some improvements to Cue
- Cues need to specify their final values
- Cues are imported by subs. This should be fixed for style points.
- Some other cleanups
11 files changed with 72 insertions and 186 deletions:
0 comments (0 inline, 0 general)
light8/Config.py
Show inline comments
 
from random import randrange
 
from time import time
 
from __future__ import generators,division
 
from Subs import *
 

	
 
from Fader import fader
 

	
 
patch = {
 
    
 
    'side l' : 45, # posts
 
    'side r' : 46,
 
    
 
@@ -257,18 +258,14 @@ subs = {
 
    'sidepost':fulls((45,46)),
 
    'edges':fulls((55,60,49,54,61,66)),
 
    'bank1ctr':fulls(('b22','b23','b24','b25')),
 
    'god' : fulls((6,)),
 
    ('strobe', 'grey'):strobe,
 
    
 
#    'midstage' : dict([(r, 100) for r in range(11, 21)]),
 
#    'backstage' : dict([(r, 100) for r in range(21, 31)]),
 
#    'frontchase' : mr_effect,
 
    'chase' : chase,
 
    'chase2' : chase,
 
#    'random' : randomdimmer,
 
}
 

	
 
subs["ba outrs"] = fulls("b11 b12 b13 b14 b15 b16 b31 b32 b33 b34 b35 b36".split())
 
subs["ba some"] = {'b12':40,'b13':FL,'b14':FL,'b15':40,
 
                   'b32':40,'b33':FL,'b34':FL,'b35':40,}
 
subs['*curtain'] = subs['ba some'].copy()
light8/ConfigDummy.py
Show inline comments
 
from random import randrange
 
from time import time
 
from __future__ import generators,division
 
from Subs import *
 
from Cue import *
 

	
 
f1 = Fade('red', 0, 2, 100)
 
f2 = Fade('green', 1, 3, 50)
 
f3 = Fade('blue', 0, 4, 0)
 
f4 = Fade('clear', 0, 8, 75) 
 
c1 = Cue("Color shift", 0, 10, f1, f2, f3, f4)
 

	
 
cues = [c1]
 

	
 
patch = {
 
    
 
    'side l' : 45, # posts
 
    'side r' : 46,
 
    
 
@@ -238,13 +246,12 @@ def randomdimmer(params, slideradjuster)
 
    while 4:
 
        if time() - curtime > 1:
 
            dim = randrange(1, 64)
 
            curtime = time()
 
        yield {dim : 100, 20 : params.get_param_value('magic')}
 

	
 

	
 
subs = {
 
    'over pit sm' : levs(range(1, 13),(100,0,0,91,77,79,86,55,92,77,59,0)),
 
    'over pit lg' : fulls(range(1, 13)),
 
    ('house', 'black') : { 68:100 },
 
    ('cyc', 'lightBlue'):{42:FL,43:FL},
 
    ('scp hot ctr', 'yellow'):{18:FL},
 
@@ -261,13 +268,13 @@ subs = {
 
    ('strobe', 'grey'):strobe,
 
    
 
#    'midstage' : dict([(r, 100) for r in range(11, 21)]),
 
#    'backstage' : dict([(r, 100) for r in range(21, 31)]),
 
#    'frontchase' : mr_effect,
 
    'chase' : chase,
 
    'chase2' : chase,
 
    # 'chase2' : chase,
 
#    'random' : randomdimmer,
 
}
 

	
 
subs["ba outrs"] = fulls("b11 b12 b13 b14 b15 b16 b31 b32 b33 b34 b35 b36".split())
 
subs["ba some"] = {'b12':40,'b13':FL,'b14':FL,'b15':40,
 
                   'b32':40,'b33':FL,'b34':FL,'b35':40,}
light8/Cue.py
Show inline comments
 
@@ -4,16 +4,22 @@ from util import subsetdict
 

	
 
class Cue:
 
    """Cues are groups of fades.  They can tell you the current levels at a 
 
    given time.  They contain Fades, which are actually children of Cue,
 
    meaning that Cues can contain Cues.  This is similar to the Light9 concept
 
    of Cues and Fades, but without all the Nodes."""
 
    def __init__(self, name, starttime, endtime, *fades):
 
    def __init__(self, name, starttime, endtime=None, dur=None, *fades):
 
        'Create a cue'
 
        if not endtime:
 
            endtime = starttime + dur
 
        else:
 
            dur = endtime - starttime
 

	
 
        self.name = name
 
        self.starttime = starttime
 
        self.dur = dur
 
        self.endtime = endtime
 
        self.fades = fades
 
        self.cuestart = None
 
        self.init_levels = None
 
    def channels_involved(self):
 
        'Return which channels are involved.  This is important for marking.'
 
@@ -35,23 +41,28 @@ class Cue:
 
        d = {}
 
        for fade in self.fades:
 
            fade_d = fade.get_levels(curtime)
 
            for ch, lev in fade_d.items():
 
                d[ch] = max(lev, d.get(ch, 0))
 
        return d
 
    def get_end_levels(self):
 
        'Returns the final levels'
 
        d = {}
 
        for fade in self.fades:
 
            fade_d = fade.get_end_levels()
 
            for ch, lev in fade_d.items():
 
                d[ch] = max(lev, d.get(ch, 0))
 
        return d
 

	
 
class Fade(Cue):
 
    'See Cue.__doc__'
 
    def __init__(self, channel, starttime, endtime=None, endlevel=0, dur=None,
 
                 param=None):
 
        'Only specify an end time or a duration'
 
        if not endtime:
 
            endtime = starttime + dur
 
        else:
 
            dur = endtime - starttime
 
        Cue.__init__(self, "%s -> %f" % (channel, endlevel), starttime, endtime)
 
        'Fades are simple Cues'
 
        Cue.__init__(self, "%s -> %f" % (channel, endlevel), starttime, endtime,
 
            dur)
 
        self.channel = channel
 
        self.endlevel = endlevel
 
        self.dur = dur
 
        self.param = param
 
    def start(self, levels, time):
 
        'Mark the beginning of the fade'
 
@@ -68,12 +79,14 @@ class Fade(Cue):
 
        elif elapsed >= self.endtime:
 
            return {self.channel : self.endlevel}
 
        else:
 
            percent = float(elapsed) / self.dur
 
            return {self.channel : self.init_level + 
 
                percent * (self.endlevel - self.init_level)}
 
    def get_end_levels(self):
 
        return {self.channel : self.endlevel}
 

	
 
if __name__ == '__main__':
 
    f1 = Fade('red', 0, 2, 100)
 
    f2 = Fade('green', 1, 3, 50)
 
    f3 = Fade('blue', 0, 4, 0)
 
    f4 = Fade('clear', 0, 8, 75) 
light8/Fader.py
Show inline comments
 
from Tix import *
 
from time import time # time is on my side
 
from util import subsetdict
 
from FlyingFader import FlyingFader
 
from uihelpers import get_selection
 

	
 
# statuses are:
 
# stopped - no cue is loaded or cue is stopped
 
# running - cue is running, not complete
 
# finished - cue is finished, next is loaded
 

	
 
stdfont = ('Arial', 10)
 

	
 
class Fader(Frame):
 
    'User interface for cue fader'
 
    def __init__(self, master, cues, scalelevels):
 
        self.master = master
 
        self.cues = cues
 
        self.scalelevels = scalelevels
 
        self.time_start = 0
 
        self.init_layout()
 
        self.stop()
 
    def init_layout(self):
 
        Frame.__init__(self, self.master)
 

	
 
        # info variables
 
        self.cuename = StringVar()
 
        self.cuelength = DoubleVar()
 
        self.cuetarget = StringVar()
 

	
 
        # info about a running cue
 
        self.cuestatus = StringVar() # text description
 
        self.cuestatus.set("stopped")
 
        
 
        self.cuepercent = DoubleVar() # percent complete
 
        self.cuepercent.set(0)
 
        self.cuepercent.trace('w', self.update_percent)
 
        self.cuetimeelapse = StringVar() # time elapsed
 
        self.cuetimeelapse.set('0s')
 
        self.cuetimeleft = StringVar() # time left
 
        self.cuetimeleft.set('0s')
 
        self.cueend = StringVar()
 

	
 
        buttonframe = Frame(self)
 
        topframe = Frame(self) # to contain cue list and infoframe
 
        infoframe = Frame(topframe)
 
        topframe.pack()
 

	
 
        self.listbox = ScrolledListBox(topframe, 
 
            command=self.update_selection)
 
        self.listbox.listbox.configure({'exportselection' : 0, 
 
            'selectmode' : EXTENDED})
 
        self.listbox = ScrolledListBox(buttonframe)
 
        self.listbox.listbox.configure({'exportselection' : 0})
 
        for c in self.cues:
 
            self.listbox.listbox.insert(END, c.name)
 
        self.listbox.pack(side=LEFT)
 
        self.listbox.listbox.bind("<<ListboxSelect>>", self.update_selection, 
 
            add=1)
 
        Button(buttonframe, text="Go", command=self.go, font=stdfont,
 
            bg='green').pack(side=LEFT)
 
        Button(buttonframe, text="Stop", command=self.stop, font=stdfont,
 
            bg='red').pack(side=LEFT)
 
        Button(buttonframe, text="Prev", command=self.prev, 
 
            font=stdfont).pack(side=LEFT)
 
        nextbutton = Button(buttonframe, text="Next", command=self.next, 
 
            font=stdfont)
 
        # Button(buttonframe, text="Load", command=self.mark_start, bg='grey80',
 
            # font=stdfont).pack(side=LEFT)
 
        self.listbox.pack(side=TOP)
 
        Button(buttonframe, text="Go", command=self.go).pack(side=LEFT)
 
        Button(buttonframe, text="Halt").pack(side=LEFT)
 
        Button(buttonframe, text="Clear").pack(side=LEFT)
 

	
 
        infoframe = Frame(self)
 
        Label(infoframe, textvariable=self.cuename, 
 
            font=('Arial', 12), bg='lightBlue').grid(columnspan=4, sticky=NE+SW)
 

	
 
            font=('Arial', 12), bg='lightBlue').grid(columnspan=2, sticky=NE+SW)
 
        Label(infoframe, text="Length", font=stdfont, 
 
            bg='lightPink').grid(row=1, sticky=NE+SW)
 
        Label(infoframe, textvariable=self.cuelength, 
 
            font=stdfont).grid(row=1, column=1, columnspan=3, sticky=NE+SW)
 

	
 
            font=stdfont).grid(row=1, column=1, sticky=NE+SW)
 
        Label(infoframe, text="Target", font=stdfont,
 
            bg='lightPink').grid(row=2, sticky=NE+SW)
 
        Label(infoframe, textvariable=self.cuetarget, 
 
            font=stdfont, wraplength=250).grid(row=2, column=1, columnspan=3, 
 
                sticky=NE+SW)
 

	
 
        Label(infoframe, text="Status", font=stdfont,
 
            bg='lightPink').grid(row=3, sticky=NE+SW)
 
        Label(infoframe, textvariable=self.cuestatus, 
 
            font=stdfont).grid(row=3, column=1, columnspan=3, sticky=NE+SW)
 

	
 
        Label(infoframe, text="Time Elapsed", font=stdfont,
 
            bg='lightPink').grid(row=4, sticky=NE+SW)
 
        Label(infoframe, textvariable=self.cuetimeelapse, 
 
            font=stdfont).grid(row=4, column=1, sticky=NE+SW)
 

	
 
        Label(infoframe, text="Time Remain", font=stdfont,
 
            bg='lightPink').grid(row=4, column=2, sticky=NE+SW)
 
        Label(infoframe, textvariable=self.cuetimeleft, 
 
            font=stdfont).grid(row=4, column=3, sticky=NE+SW)
 

	
 
        Label(infoframe, text="Percent Complete", font=stdfont,
 
            bg='lightPink').grid(row=5, column=0, sticky=NE+SW)
 
        self.percentlabel = Label(infoframe, 
 
            font=stdfont)
 
        self.percentlabel.grid(row=5, column=1, columnspan=3, sticky=NE+SW)
 

	
 
        # s = Scale(infoframe, variable=self.cuepercent,
 
        s = Scale(buttonframe, variable=self.cuepercent,
 
                        showvalue=0, length=220,
 
                        width=18, sliderlength=30,
 
                        to=100,res=.1,from_=0,bd=1, font=stdfont,
 
                        orient='horiz')
 
        # s.grid(row=6, columnspan=4, sticky='ew')
 
        nextbutton.pack(side=RIGHT)
 
        s.pack(side=RIGHT, expand=1, fill=X)
 

	
 
        Label(infoframe, textvariable=self.cueend, 
 
            font=stdfont).grid(row=2, column=1, sticky=NE+SW)
 
        infoframe.pack(side=RIGHT, fill=BOTH, expand=1)
 
        buttonframe.pack(side=BOTTOM, expand=1, fill=X)
 
        buttonframe.pack(side=BOTTOM)
 

	
 
        self.listbox.listbox.select_set(0)
 
        self.update_selection()
 
    def mark_start(self):
 
        self.time_start = time()
 
        startlevels = dict([(k, v.get()) for k, v in self.scalelevels.items()])
 
        # print "going to mark with", startlevels
 
        self.current.start(startlevels, self.time_start)
 
    def update_percent(self, *args):
 
        if self.cuestatus.get() != 'running':
 
            self.cuestatus.set("running")
 
            self.mark_start()
 

	
 
        percent = self.cuepercent.get()
 
        self.percentlabel.config(text='%.1f%%' % percent)
 
        percent /= 100
 

	
 
        elapsed = percent * self.current.dur
 
        self.cuetimeelapse.set('%.1fs' % elapsed)
 
        self.cuetimeleft.set('%.1fs' % (self.current.dur - elapsed))
 

	
 
        newlevels = self.current.get_levels(self.time_start + elapsed)
 
        # print "newlevels", newlevels
 
        for ch, lev in newlevels.items():
 
            try:
 
                self.scalelevels[ch].set(lev)
 
            except KeyError:
 
                pass
 

	
 
    def update_selection(self, *args):
 
        self.cuestatus.set('stopped')
 
        selection = get_selection(self.listbox.listbox)
 
    def update_selection(self):
 
        print self.listbox.listbox.curselection()
 
        selection = int(self.listbox.listbox.curselection()[0]) # blech
 
        self.current = self.cues[selection]
 
        self.cuename.set(self.current.name)
 
        self.cuelength.set(self.current.dur)
 
        target = ', '.join(['%s -> %.2f' % (n, lev) 
 
            for n, lev in self.current.get_end_levels().items()])
 
        self.cuetarget.set(target)
 
        self.cuetimeelapse.set('0s')
 
        self.cuetimeleft.set('%.1fs' % self.current.dur)
 
        self.cuepercent.set(0)
 
        self.cueend.set(str(self.current.get_end_levels()))
 
    def go(self):
 
        self.update_selection()
 
        self.cuestatus.set("running")
 
        self.mark_start()
 
        self.running_loop()
 
    def stop(self):
 
        self.cuestatus.set('stopped')
 
    def prev(self):
 
        self.stop()
 
        selection = get_selection(self.listbox.listbox)
 
        if selection != 0:
 
            self.listbox.listbox.select_clear(selection)
 
            self.listbox.listbox.select_set(selection - 1)
 
            self.update_selection()
 
            self.mark_start()
 
    def next(self):
 
        self.stop()
 
        selection = get_selection(self.listbox.listbox)
 
        if selection != self.listbox.listbox.size() - 1:
 
            self.listbox.listbox.select_clear(selection)
 
            self.listbox.listbox.select_set(selection + 1)
 
            self.update_selection()
 
            self.mark_start()
 
    def running_loop(self):
 
        if self.cuestatus.get() == 'stopped':
 
            return
 
        curtime = time()
 
        elapsed = (curtime - self.time_start)
 

	
 
        if elapsed > self.current.dur:
 
            self.cuestatus.set('stopped')
 
            self.cuepercent.set(100)
 

	
 
            # advance cues if okay
 
            self.next()
 
            return
 

	
 
        self.cuepercent.set(100 * elapsed / self.current.dur)
 
        self.after(30, self.running_loop)
 
        print 'Fade to', self.current.name
light8/Subs.py
Show inline comments
 
from Patch import *
 
from time import time
 
from Tkinter import *
 
from Tix import *
 
from types import TupleType
 

	
 
stdfont = ('Arial', 8)
 

	
 
class Param: # abstract
 
    def get_value(self):
 
@@ -213,13 +213,13 @@ class Sub:
 
        # we can accept these new levels; subediting has done all the work
 
        self.levels.update(levels)
 
                
 
    
 

	
 
def reload_data(dummy):
 
    global subs
 
    global subs, cues
 
    if dummy:
 
        import ConfigDummy as Config
 
    else:
 
        import Config
 

	
 
    reload(Config)
 
@@ -231,8 +231,11 @@ def reload_data(dummy):
 
        else:
 
            color = None
 

	
 
        subs[name] = Sub(name, levels, color=color)
 

	
 
    # subs = dict([(name, Sub(levels)) for name, levels in Config.subs.items()])
 

	
 
    cues = Config.cues
 

	
 
def longestsubname():
 
    return max([len(x) for x in subs.keys()])
light8/Xfader.py
Show inline comments
 
from Tkinter import *
 
from Tix import *
 
from __future__ import division
 

	
 
class Xfader(Canvas):
 
    def __init__(self, scalelevelsIn):
 
        global scalelevels
 
        scalelevels=scalelevelsIn
light8/panels.py
Show inline comments
 
"""some of the panels"""
 
from __future__ import nested_scopes
 

	
 
from Tkinter import *
 
from Tix import *
 
from uihelpers import *
 
import Patch
 
from FlyingFader import FlyingFader
 
import Pmw
 

	
 
stdfont = ('Arial', 8)
light8/rsn.py
Show inline comments
 
#!/usr/bin/env python
 
from __future__ import nested_scopes
 

	
 
from Tkinter import *
 
from Tix import *
 
from time import sleep
 
from signal import signal, SIGINT
 
import sys, cPickle
 

	
 
import io
 
from uihelpers import *
 
from panels import *
 
from Xfader import *
 
from subediting import Subediting
 
from Fader import Fader
 
import stage
 

	
 

	
 
if len(sys.argv) >= 2:
 
    DUMMY = 0
 
    print "This is the real thing, baby"
 
    window_title = "Light 8.8 (On Air)"
 
else:
 
    DUMMY = 1
 
@@ -65,13 +67,14 @@ class Lightboard:
 
        s.pack()
 

	
 
        sub_tl = toplevelat(0,0)
 
        effect_tl = toplevelat(462,4)
 

	
 
        self.subpanels = Subpanels(sub_tl, effect_tl, self.scalelevels, Subs, 
 
            self.xfader, self.changelevel, self.subediting, Subs.longestsubname())
 
            self.xfader, self.changelevel, self.subediting, 
 
            Subs.longestsubname())
 

	
 
        leveldisplay_tl = toplevelat(873,400)
 
        leveldisplay_tl.bind('<Escape>', sys.exit)
 

	
 
        self.leveldisplay = Leveldisplay(leveldisplay_tl, self.channel_levels)
 
        for i in range(0,len(self.channel_levels)):
 
@@ -94,12 +97,16 @@ class Lightboard:
 
        leveldisplay_tl.bind('<q>', self.quit)
 
        leveldisplay_tl.bind('<r>', self.refresh)
 

	
 
        self.xfader.setupwidget(xf)
 
        controlpanel.pack()
 

	
 
        cuefader_tl = toplevelat(98, 480)
 
        cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels)
 
        cuefader.pack()
 

	
 
    def refresh(self, *args):
 
        'rebuild interface, reload data'
 
        get_data()
 
        self.buildinterface()
 
        bindkeys(root,'<Escape>', self.quit)
 

	
light8/stage.py
Show inline comments
 
from Tkinter import *
 

	
 
from Tix import *
 

	
 
def printevent(ev):
 
    for k in dir(ev):
 
        if not k.startswith('__'):
 
            print k,getattr(ev,k)
 
    print ""
 

	
 

	
 
textstyle={'font':'arial 7','fill':'white'}
 

	
 

	
 
class Stage(Canvas):
 
    
 
    """a fancy widget that shows light locations (and optionally their
 
    aim locations on an image of the stage. you can select or
 
    multiselect lights and drag them up or down to change their
 
    brightness.
light8/uihelpers.py
Show inline comments
 
"""all the tiny tk helper functions"""
 

	
 
from __future__ import nested_scopes
 
from Tkinter import *
 
from Tix import *
 
from types import StringType
 

	
 
def make_frame(parent):
 
    f = Frame(parent, bd=0)
 
    f.pack(side='left')
 
    return f
 
@@ -11,17 +13,17 @@ def make_frame(parent):
 
def bindkeys(root,key, func):
 
    root.bind(key, func)
 
    for w in root.winfo_children():
 
        w.bind(key, func)
 

	
 
def toplevelat(x,y,w=None,h=None):
 
    tl=Toplevel()
 
    tl = Toplevel()
 
    if w and h:
 
        tl.wm_geometry("%dx%d+%d+%d"%(w,h,x,y))
 
        tl.wm_geometry("%dx%d+%d+%d" % (w,h,x,y))
 
    else:
 
        tl.wm_geometry("+%d+%d"%(x,y))
 
        tl.wm_geometry("+%d+%d" % (x,y))
 
    return tl
 

	
 
def toggle_slider(s):
 
    if s.get() == 0:
 
        s.set(100)
 
    else:
light8/util.py
Show inline comments
 
@@ -12,12 +12,12 @@ def scaledict(d,scl):
 
    # scales all values in dict and returns a new dict
 
    return dict([(k,v*scl) for k,v in d.items()])
 
    
 
# class Setting that scales, maxes        
 

	
 
def subsetdict(d, dkeys, default=0):
 
    'Subset of dictionary d: only the keys in dkeys'
 
    # print 'd', d, 'dkeys', dkeys
 
    """Subset of dictionary d: only the keys in dkeys.  If you plan on omitting
 
    keys, make sure you like the default."""
 
    newd = {} # dirty variables!
 
    for k in dkeys:
 
        newd[k] = d.get(k, default)
 
    return newd
0 comments (0 inline, 0 general)