Files @ 4b542d321c8f
Branch filter:

Location: light9/bin/gyrocontroller - annotation

Drew Perttula
effectnode runs multiple lines of code in dependency order
Ignore-this: 45e7a4f332c6b1e15eefb7bd8a3ed657
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
3b73f0a58a54
3b73f0a58a54
a92b6d1ac072
460bc5ebcaaf
89cd37c4314b
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
6f6d9235e8a0
89cd37c4314b
89cd37c4314b
89cd37c4314b
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
89cd37c4314b
1546c423b467
6f6d9235e8a0
89cd37c4314b
1546c423b467
6f6d9235e8a0
89cd37c4314b
a92b6d1ac072
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
97c08a1c4351
97c08a1c4351
97c08a1c4351
89cd37c4314b
a92b6d1ac072
89cd37c4314b
89cd37c4314b
97c08a1c4351
3b73f0a58a54
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
97c08a1c4351
89cd37c4314b
89cd37c4314b
97c08a1c4351
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
97c08a1c4351
89cd37c4314b
89cd37c4314b
89cd37c4314b
89cd37c4314b
97c08a1c4351
6f6d9235e8a0
6f6d9235e8a0
60b6471fb0d2
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
a92b6d1ac072
89cd37c4314b
89cd37c4314b
89cd37c4314b
97c08a1c4351
a92b6d1ac072
89cd37c4314b
a92b6d1ac072
89cd37c4314b
a92b6d1ac072
89cd37c4314b
6f6d9235e8a0
6f6d9235e8a0
e543deec6678
e543deec6678
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
97c08a1c4351
97c08a1c4351
6f6d9235e8a0
c9940e4e68d6
6f6d9235e8a0
6f6d9235e8a0
c9940e4e68d6
c9940e4e68d6
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
97c08a1c4351
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
97c08a1c4351
6f6d9235e8a0
6f6d9235e8a0
97c08a1c4351
97c08a1c4351
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
c9940e4e68d6
c9940e4e68d6
c9940e4e68d6
97c08a1c4351
97c08a1c4351
c9940e4e68d6
c9940e4e68d6
97c08a1c4351
c9940e4e68d6
c9940e4e68d6
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
89cd37c4314b
c9940e4e68d6
c9940e4e68d6
c9940e4e68d6
c9940e4e68d6
c9940e4e68d6
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
c9940e4e68d6
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
6f6d9235e8a0
c9940e4e68d6
6f6d9235e8a0
97c08a1c4351
97c08a1c4351
97c08a1c4351
97c08a1c4351
e50e87f1103f
6f6d9235e8a0
#!/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, '<Enter>', 
                lambda evt, item=item, color=color: setfill(item, color))
            self.tag_bind(tag, '<Leave>', 
                lambda evt, item=item, color=color: setfill(item, 'black'))
            self.tag_bind(tag, '<ButtonPress-1>', 
                lambda evt, item=item, color=color: setfill(item, 'green'), '+')
            self.tag_bind(tag, '<ButtonRelease-1>', 
                lambda evt, item=item, color=color: setfill(item, color), '+')
            self.tag_bind(tag, '<Button-1>', 
                lambda evt, method=method: method(), '+')

        # B2+drag sets current level, double-B2 resets kept levels
        self.tag_bind('all', '<Motion>', setlevel, '+')
        self.tag_bind('all', '<ButtonPress-3>', setlevel, '+')
        self.tag_bind('all', '<Triple-Button-2>', 
            lambda evt: self.clear_kept_levels())
        # B3 toggles between keep and solo mode
        self.tag_bind('all', '<Button-2>', 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('<Key-q>', quit)
    root.maxsize(root.winfo_screenwidth(), root.winfo_screenheight())
    Tk.mainloop()