diff --git a/bin/gyrocontroller b/bin/gyrocontroller deleted file mode 100644 --- a/bin/gyrocontroller +++ /dev/null @@ -1,195 +0,0 @@ -#!/usr/bin/env python -# vi: syntax=python - -import run_local -from light9.Submaster import Submasters, Submaster, combine_subdict, \ - get_sub_by_name -from light9.subclient import SubClient -import light9.Patch as Patch - -import Tix as Tk - -# TODO: move to Utility? -class circcycle: - """Like itertools.cycle, but with a prev() method too. You lose - all iterator benefits by using this, since it will store the whole - sequence/iterator in memory. Also, do not run this on an infinite - iterator, as it tuple'ifies the input.""" - def __init__(self, sequence): - self.sequence = tuple(sequence) - self.index = None - def __iter__(self): - return self - def change_index(self, delta): - if self.index is None: - if delta > 0: - self.index = (-1 + delta) % len(self.sequence) - elif delta < 0: - self.index = delta % len(self.sequence) - else: - self.index = (self.index + delta) % len(self.sequence) - def next(self): - self.change_index(1) - return self.sequence[self.index] - def prev(self): - self.change_index(-1) - return self.sequence[self.index] - -class AbstractSimpleController(SubClient): - """Simple controller with minimal input and output: - - Input is 4 directions and 3 buttons. - Output is an integer and a color and maybe more. - - Left + B1/right + B1: prev/next sub - Y-axis + B3: set current level - B2: toggle keep/solo mode - Triple-B2: clear kept levels""" - def __init__(self, subnames): - SubClient.__init__(self) - self.subnames = subnames - self.refresh() - def get_sub(self, name): - return get_sub_by_name(name, self.submasters) - def refresh(self): - # reload subs from disk - self.submasters = Submasters() - self.all_subs = circcycle(self.subnames) - self.current_sub = self.get_sub(self.all_subs.next()) - self.current_level = 1.0 - self.kept_levels = {} # subname : level [0..1] - self.keep_solo_mode = 'solo' # either 'keep' or 'solo' - def clear_kept_levels(self): - self.kept_levels.clear() - def next(self): - if self.keep_solo_mode == 'keep': - self.kept_levels[self.current_sub] = self.current_level - - self.current_sub = self.get_sub(self.all_subs.next()) - def prev(self): - if self.keep_solo_mode == 'keep': - self.kept_levels[self.current_sub] = self.current_level - - self.current_sub = self.get_sub(self.all_subs.prev()) - def toggle_keep_mode(self): - if self.keep_solo_mode == 'keep': - self.kept_levels[self.current_sub] = self.current_level - self.keep_solo_mode = 'solo' - else: - self.keep_solo_mode = 'keep' - - def get_levels_as_sub(self): - if self.keep_solo_mode == 'keep': - # send all levels in self.kept_levels - self.kept_levels[self.current_sub] = self.current_level - levelsub = combine_subdict(self.kept_levels) - else: - levelsub = self.current_sub * self.current_level - - return levelsub - -class TkGyro(Tk.Canvas, AbstractSimpleController): - def __init__(self, master, subnames): - Tk.Canvas.__init__(self, master, bg='black', bd=0, highlightthickness=0, - confine=None) - AbstractSimpleController.__init__(self, subnames) - height = int(self.winfo_screenheight()) - width = int(self.winfo_screenwidth()) - self.left = self.create_rectangle((0, 0, width / 2, height), - tags='left', fill='black') - self.right = self.create_rectangle((width / 2, 0, width, height), - tags='right', fill='black') - self.levelbar = self.create_rectangle(0, 0, width, 5, tags='level', - fill='yellow', state='disabled', outline='') - - # the text is disabled so that it doesn't receive events - self.modetext = self.create_text((width / 2, height / 2), - font='Courier 200', fill='white', text=self.keep_solo_mode, - state='disabled') - self.flashtextafter = '' # current after timer for displaying text - - def setfill(item, color): - self.itemconfig(item, fill=color) - def setlevel(evt): - if evt.state & 0x400 or evt.num == 3: - y = (height - evt.y) / float(height) - self.flash_text('<%d>' % (y * 100)) - self.current_level = y - self.coords(self.levelbar, 0, evt.y, width, evt.y + 5) - self.send_levels() - - data = ((self.left, 'left', 'blue', self.prev), - (self.right, 'right', 'red', self.next)) - for item, tag, color, method in data: - self.tag_bind(tag, '', - lambda evt, item=item, color=color: setfill(item, color)) - self.tag_bind(tag, '', - lambda evt, item=item, color=color: setfill(item, 'black')) - self.tag_bind(tag, '', - lambda evt, item=item, color=color: setfill(item, 'green'), '+') - self.tag_bind(tag, '', - lambda evt, item=item, color=color: setfill(item, color), '+') - self.tag_bind(tag, '', - lambda evt, method=method: method(), '+') - - # B2+drag sets current level, double-B2 resets kept levels - self.tag_bind('all', '', setlevel, '+') - self.tag_bind('all', '', setlevel, '+') - self.tag_bind('all', '', - lambda evt: self.clear_kept_levels()) - # B3 toggles between keep and solo mode - self.tag_bind('all', '', lambda evt: self.toggle_keep_mode()) - - self.send_levels_loop() - def toggle_keep_mode(self): - AbstractSimpleController.toggle_keep_mode(self) - self.show_current_mode() - self.send_levels() - def show_current_mode(self): - if self.keep_solo_mode == 'keep': - self.keep_solo_mode = 'keep' - else: - self.keep_solo_mode = '' - - self.itemconfig(self.modetext, text=self.keep_solo_mode) - def clear_kept_levels(self): - AbstractSimpleController.clear_kept_levels(self) - self.flash_text('cleared') - self.send_levels() - def flash_text(self, text): - self.itemconfig(self.modetext, text=text) - self.after_cancel(self.flashtextafter) - self.flashtextafter = self.after(2000, self.show_current_mode) - def next(self): - AbstractSimpleController.next(self) - self.flash_text(self.current_sub.name) - self.send_levels() - def prev(self): - AbstractSimpleController.prev(self) - self.flash_text(self.current_sub.name) - self.send_levels() - -if __name__ == "__main__": - import sys, fileinput - subnames = sys.argv[1:] - if not subnames: - subnames = [line.strip() for line in fileinput.input()] - - root = Tk.Tk() - # these are hints to Fvwm2 if you add this to your .fvwm2rc: - # Style "*NOTITLE*" NoTitle - # Style "*NOBORDER*" BorderWidth 0, NoHandles - # Style "*ONTOP*" StaysOnTop Sticky - # hopefully, there's a better way to do this within Tk - root.title("NOTITLE NOBORDER ONTOP") - root.wm_geometry('%sx%s' % (root.winfo_screenwidth(), - root.winfo_screenheight())) - - gyro = TkGyro(root, subnames) - gyro.pack(fill='both', expand=1) - def quit(event): - gyro.send_zeroes() - root.destroy() - root.bind('', quit) - root.maxsize(root.winfo_screenwidth(), root.winfo_screenheight()) - Tk.mainloop() diff --git a/light9/subclient.py b/light9/subclient.py --- a/light9/subclient.py +++ b/light9/subclient.py @@ -1,7 +1,5 @@ from light9 import dmxclient -from light9.Submaster import Submaster -# later, this stuff will talk to a SubServer class SubClient: def __init__(self): """assumed that your init saves self.graph""" @@ -11,20 +9,8 @@ class SubClient: """Subclasses must implement this method and return a Submaster object.""" - def get_dmx_list(self): - maxes = self.get_levels_as_sub() - return maxes.get_dmx_list() - - def send_sub(self, sub): - levels = sub.get_dmx_list() - dmxclient.outputlevels(levels) - def send_levels(self): - self.graph.addHandler(self._send_levels_handler) - - def _send_levels_handler(self): - levels = self.get_dmx_list() - dmxclient.outputlevels(levels) + self.graph.addHandler(self._send_sub) def send_levels_loop(self, delay=1000): """This function assumes that we are an instance of a Tk object @@ -32,5 +18,7 @@ class SubClient: self.graph.addHandler(self.send_levels) self.after(delay, self.send_levels_loop, delay) - def send_zeroes(self): - self.send_sub(Submaster('empty', {}, temporary=1)) + def _send_sub(self): + maxes = self.get_levels_as_sub() + levels = maxes.get_dmx_list() + dmxclient.outputlevels(levels)