diff --git a/light8/ExternalInput.py b/light8/ExternalInput.py --- a/light8/ExternalInput.py +++ b/light8/ExternalInput.py @@ -1,20 +1,10 @@ -import thread, SocketServer, socket - - -currentlevels = [0,0,0,0] - +import thread, SocketServer class NetSliderHandler(SocketServer.StreamRequestHandler): def handle(self): data = self.rfile.readline(1000) - currentlevels[:] = [round(self.bounds(float(x)/255),3) for x in list(data.split())] - def bounds(self,x): - # the last .1 both ways shall not do anything - x=x*1.1-.05 - x=min(1,max(0,x)) - return x -def start_server(levelstorage=0): +def start_server(levelstorage): server = SocketServer.TCPServer( ('', socket.getservbyname('rlslider', 'tcp')), NetSliderHandler) @@ -33,8 +23,7 @@ class ExternalSliders: def update(self, *args): self.level_storage[:] = args def get_levels(self): - return currentlevels -# import math, time -# return [max(0, math.sin(time.time() + i)) for i in range(4)] # bogus + import math, time + return [max(0, math.sin(time.time() + i)) for i in range(4)] # bogus # return self.level_storage diff --git a/light8/Lightboard.py b/light8/Lightboard.py --- a/light8/Lightboard.py +++ b/light8/Lightboard.py @@ -1,18 +1,15 @@ from __future__ import nested_scopes from Tix import * -import random from signal import signal, SIGINT -import sys, cPickle +import sys, cPickle, random -import io from uihelpers import * from panels import * from Xfader import * from subediting import Subediting from Fader import Fader -import stage -import Subs, Patch +import io, stage, Subs, Patch, ExternalInput class Pickles: def __init__(self, scalelevels, subs=None, windowpos=None): @@ -31,7 +28,8 @@ class Lightboard: self.channel_levels = [] self.scalelevels = {} - self.xfader = Xfader(self.scalelevels) # doesn't draw any UI yet-- look for self.xfader.setupwidget() + # doesn't draw any UI yet-- look for self.xfader.setupwidget() + self.xfader = Xfader(self.scalelevels) self.oldlevels = [None] * 68 # never replace this; just clear it self.subediting = Subediting(currentoutputlevels=self.oldlevels) @@ -46,22 +44,27 @@ class Lightboard: for w in self.master.winfo_children(): w.destroy() - stage_tl = toplevelat('stage', self.windowpos) + stage_tl = toplevelat('stage') s = stage.Stage(stage_tl) stage.createlights(s) s.setsubediting(self.subediting) s.pack() self.stage = s # save it - sub_tl = toplevelat('sub', self.windowpos) - scene_tl = toplevelat('scenes',self.windowpos) - effect_tl = toplevelat('effect', self.windowpos) + sub_tl = toplevelat('sub') + scene_tl = toplevelat('scenes') + effect_tl = toplevelat('effect') + + mapping_tl = toplevelat('mapping') + self.slidermapper = ExtSliderMapper(mapping_tl, self.scalelevels, + ExternalInput.ExternalSliders()) + self.slidermapper.pack() self.subpanels = Subpanels(sub_tl, effect_tl, scene_tl, self, self.scalelevels, Subs, self.xfader, self.changelevel, self.subediting, Subs.longestsubname()) - leveldisplay_tl = toplevelat('leveldisplay', self.windowpos) + leveldisplay_tl = toplevelat('leveldisplay') leveldisplay_tl.bind('', sys.exit) self.leveldisplay = Leveldisplay(leveldisplay_tl, self.channel_levels) @@ -86,7 +89,7 @@ class Lightboard: self.xfader.setupwidget(xf) controlpanel.pack() - cuefader_tl = toplevelat('cuefader', self.windowpos) + cuefader_tl = toplevelat('cuefader') cuefader = Fader(cuefader_tl, Subs.cues, self.scalelevels) cuefader.pack() @@ -149,6 +152,11 @@ class Lightboard: levels[ch-1] = max(levels[ch-1], fadelev) levels = [int(l) for l in levels] + + # load levels from external sliders + extlevels = self.slidermapper.get_levels() + for name, val in extlevels.items(): + self.scalelevels[name].set(val) for lev,lab,oldlev,numlab in zip(levels, self.channel_levels, self.oldlevels, @@ -202,6 +210,7 @@ class Lightboard: print "EOFrror: Couldn't load prefs (%s): %s" % (filename,e) except Exception,e: print "Couldn't load prefs (%s): %s" % (filename,e) + self.slidermapper.setup() def backgroundloop(self, *args): self.master.after(50, self.backgroundloop, ()) diff --git a/light8/panels.py b/light8/panels.py --- a/light8/panels.py +++ b/light8/panels.py @@ -5,7 +5,6 @@ from Tix import * from uihelpers import * import Patch from FlyingFader import FlyingFader -import Pmw stdfont = ('Arial', 8) monofont = ('Courier', 8) @@ -22,16 +21,16 @@ class Controlpanel(Frame): ('Clear X', lambda: xfader.clearallbuttons('x')), ('On -> Y', lambda: xfader.grab('y')), ('Clear Y', lambda: xfader.clearallbuttons('y'))): - # ('Jostle', jostle_cb)): Button(controlpanel, text=txt, command=cmd).pack(side='top', fill='x') + # jostle button Checkbutton(controlpanel, text="Jostle", command=jostle_cb).pack(side=TOP, fill=X) class Console: def __init__(self,lightboard): print "Light 8: Everything's under control" - t=toplevelat('console', lightboard.windowpos) + t=toplevelat('console') self.frame = Frame(t) self.entry=Entry(self.frame) self.entry.pack(expand=1, fill='x') @@ -80,6 +79,142 @@ class Leveldisplay: # channel_levels is an output - changelevel will use it to access # these labels +class ExtSliderMapper(Frame): + def __init__(self, parent, sliderlevels, sliderinput, filename='slidermapping', + numsliders=4): + 'Slider levels is scalelevels, sliderinput is an ExternalInput object' + Frame.__init__(self, parent) + self.parent = parent + self.sliderlevels = sliderlevels + self.sliderinput = sliderinput + self.filename = filename + self.numsliders = numsliders + self.file = None + + # self.setup() + def setup(self): + self.subnames = self.sliderlevels.keys() + self.subnames.sort() + self.presets = {} + self.load_presets() + + self.current_mapping_name = StringVar() + self.current_mapping = [] + self.attached = [] + self.levels_read = [] + for i in range(self.numsliders): + self.current_mapping.append(StringVar()) + self.attached.append(BooleanVar()) + self.levels_read.append(DoubleVar()) + + self.reallevellabels = [] + self.draw_interface() + def load_presets(self): + self.file = open(self.filename, 'r') + lines = self.file.readlines() + for l in lines: + tokens = l[:-1].split('\t') + name = tokens.pop(0) + self.presets[name] = tokens + self.file.close() + def save_presets(self): + self.file = open(self.filename, 'w') + self.file.seek(0) + preset_names = self.presets.keys() + preset_names.sort() + for p in preset_names: + s = '\t'.join([p] + self.presets[p]) + '\n' + self.file.write(s) + self.file.close() + def load_scalelevels(self): + for m, rll in zip(self.current_mapping, self.reallevellabels): + try: + v = self.sliderlevels[m.get()] + rll.configure(textvariable=v) + except KeyError: + pass + + def get_levels(self): + 'To be called by changelevels, I think' + if not self.current_mapping_name: return {} + if not self.sliderinput: return {} + + self.load_scalelevels() + + rawlevels = self.sliderinput.get_levels() + for rawlev, levlabvar in zip(rawlevels, self.levels_read): + levlabvar.set(rawlev) + outputlevels = {} + return dict([(name.get(), lev) + for name, lev, att in zip(self.current_mapping, + rawlevels, + self.attached) + if att.get()]) + + def draw_interface(self): + self.reallevellabels = [] + subchoiceframe = Frame(self) + for i, mapping, isattached, lev in zip(range(self.numsliders), + self.current_mapping, + self.attached, + self.levels_read): + f = Frame(subchoiceframe) + # Label(f, text="Slider %d" % (i+1)).pack(side=LEFT) + c = ComboBox(f, variable=mapping) + for s in self.subnames: + c.slistbox.listbox.insert(END, s) + c.entry.configure(width=12) + statframe = Frame(f) + Checkbutton(statframe, variable=isattached, + text="Attached").grid(columnspan=2, sticky=W) + Label(statframe, text="Input", fg='red').grid(row=1, sticky=W) + Label(statframe, textvariable=lev, fg='red', width=5).grid(row=1, column=1) + Label(statframe, text="Real").grid(row=2, sticky=W) + l = Label(statframe, text="N/A", width=5) + l.grid(row=2, column=1) + self.reallevellabels.append(l) + statframe.pack(side=BOTTOM, expand=1, fill=X) + c.pack() + f.pack(side=LEFT) + subchoiceframe.pack() + + presetframe = Frame(self) + Label(presetframe, text="Preset:").pack(side=LEFT) + self.presetcombo = ComboBox(presetframe, variable=self.current_mapping_name, + editable=1, command=self.apply_preset) + self.draw_presets() + self.presetcombo.pack(side=LEFT) + Button(presetframe, text="Add", padx=0, pady=0, + command=self.add_preset).pack(side=LEFT) + Button(presetframe, text="Delete", padx=0, pady=0, + command=self.delete_preset).pack(side=LEFT) + presetframe.pack(side=BOTTOM) + def apply_preset(self, preset): + if not preset: return + mapping = self.presets.get(preset) + if not mapping: return + for name, var, att in zip(mapping, self.current_mapping, self.attached): + var.set(name) + att.set(0) # detach all sliders + def delete_preset(self, *args): + del self.presets[self.current_mapping_name.get()] + self.presetcombo.slistbox.listbox.delete(0, END) + self.draw_presets() + self.save_presets() + def add_preset(self, *args): + self.presets[self.current_mapping_name.get()] = [m.get() + for m in self.current_mapping] + self.presetcombo.slistbox.listbox.delete(0, END) + self.draw_presets() + self.save_presets() + def draw_presets(self): + preset_names = self.presets.keys() + preset_names.sort() + for p in preset_names: + self.presetcombo.slistbox.listbox.insert(END, p) + + + class Subpanels: def __init__(self, scenesparent, effectsparent, scenes, lightboard, scalelevels, Subs, xfader, @@ -195,3 +330,11 @@ class Subpanels: xfader.registerbutton(name,axis,cvar) +if __name__ == '__main__': + print "testing external sliders" + root = Tk() + fakesliderlevels = dict([('sub%d' % n, DoubleVar()) for n in range(12)]) + esm = ExtSliderMapper(root, fakesliderlevels, None) + esm.pack() + + mainloop() diff --git a/light8/uihelpers.py b/light8/uihelpers.py --- a/light8/uihelpers.py +++ b/light8/uihelpers.py @@ -26,21 +26,12 @@ def bindkeys(root,key, func): for w in root.winfo_children(): w.bind(key, func) -# def toplevelat(x,y,w=None,h=None): -def toplevelat(name, windowpos=None): +def toplevelat(name): tl = Toplevel() - tl.wm_geometry(windowlocations[name]) + if name in windowlocations: + tl.wm_geometry(windowlocations[name]) - # if name in windowpos: - # tkname, geom = windowpos[name] - # tl.wm_geometry(geom) - # windowpos[name] = str(tl), geom - - # if w and h: - # tl.wm_geometry("%dx%d+%d+%d" % (w,h,x,y)) - # else: - # tl.wm_geometry("+%d+%d" % (x,y)) return tl def toggle_slider(s):