Files @ d5deeed83228
Branch filter:

Location: light9/light8/ExtSliderMapper.py

drewp
FancyDoubleVar is a DoubleVar where you can temporarily disable the callbacks
FancyDoubleVar is a DoubleVar where you can temporarily disable the callbacks
(at least the ones you made in python)
"""some more of the panels"""
from Tix import *

class SliderMapping:
    def __init__(self, default='disconnected', synced=0, extinputlevel=0, 
                 sublevel=0):
        self.subname = StringVar() # name of submaster we're connected to
        self.subname.set(default)
        self.sublevel = DoubleVar() # scalelevel variable of that submaster
        self.sublevel.set(sublevel)
        self.synced = BooleanVar() # currently synced
        self.synced.set(synced)
        self.extlevel = DoubleVar() # external slider's input
        self.extlevel.set(extinputlevel)
        self.widgets = [] # list of widgets drawn
        self.sublabel = None # the label which represents a sub level.  
                             # we hold on to it so we can change its 
                             # textvariable
        self.statuslabel = None # tells us sync status
        self.lastbgcolor = None # last background color drawn to avoid 
                                # unnecessary redraws
    def sync(self, *args):
        self.synced.set(1)
        self.color_bg()
    def unsync(self, *args):
        self.synced.set(0)
        self.color_bg()
    def issynced(self):
        return self.synced.get()
    def disconnect(self, *args):
        self.set_subname('disconnected') # a bit hack-like
        self.sublabel.configure(text="N/A")
        self.color_bg()
    def isdisconnected(self):
        return self.subname.get() == 'disconnected' # a bit more hack-like
    def check_synced(self, *args):
        'If external level is near than the sublevel, it synces'
        if self.isdisconnected(): 
            self.unsync()
            return

        if abs(self.extlevel.get() - self.sublevel.get()) <= 0.02:
            self.sync()
    def changed_extinput(self, newlevel):
        'When a new external level is received, this incorporates it'
        self.extlevel.set(newlevel)
        self.check_synced()
        self.color_bg()
    def set_subname(self, newname):
        self.subname.set(newname)
        self.unsync()
        self.color_bg()
    def color_bg(self):
        if self.widgets:
            if self.isdisconnected():
                color = 'honeyDew4'
            elif self.issynced():
            # elif abs(self.extlevel.get() - self.sublevel.get()) <= 0.02:
                color = 'honeyDew2'
            else: # unsynced
                color = 'red'

            if self.statuslabel:
                if color == 'honeyDew2': # connected
                    self.statuslabel['text'] = 'Sync'
                else:
                    self.statuslabel['text'] = 'No sync'

            # print "color", color, "lastbgcolor", self.lastbgcolor
            if self.lastbgcolor == color: return
            for widget in self.widgets:
                widget.configure(bg=color)
            self.lastbgcolor = color
    def set_sublevel_var(self, newvar):
        'newvar is one of the variables in scalelevels'
        self.sublevel = newvar
        self.sublevel.trace('w', self.unsync)
        if self.sublabel:
            self.sublabel.configure(textvariable=newvar)
        self.check_synced()
    def get_mapping(self):
        'Get name of submaster currently mapped'
        return self.subname.get()
    def get_level_pair(self):
        'Returns suitable output for ExtSliderMapper.get_levels()'
        return (self.subname.get(), self.extlevel.get())
    def draw_interface(self, master, subnames):
        'Draw interface into master, given a list of submaster names'
        frame = Frame(master)
        c = ComboBox(frame, variable=self.subname)
        c.slistbox.listbox.insert(END, "disconnected")
        for s in subnames:
            c.slistbox.listbox.insert(END, s)
        c.entry.configure(width=12)
        statframe = Frame(frame)

        '''
        cb = Checkbutton(statframe, variable=self.synced, 
            text="Synced")
        cb.grid(columnspan=2, sticky=W)
        '''
        self.statuslabel = Label(statframe, text="No sync")
        self.statuslabel.grid(columnspan=2, sticky=W)
        ilabel = Label(statframe, text="Input", fg='blue')
        ilabel.grid(row=1, sticky=W)
        extlabel = Label(statframe, textvariable=self.extlevel, width=5)
        extlabel.grid(row=1, column=1)
        rlabel = Label(statframe, text="Real")
        rlabel.grid(row=2, sticky=W)
        self.sublabel = Label(statframe, text="N/A", width=5)
        self.sublabel.grid(row=2, column=1)
        statframe.pack(side=BOTTOM, expand=1, fill=X)
        c.pack()
        frame.pack(side=LEFT, expand=1, fill=BOTH)

        self.widgets = [frame, c, statframe, self.statuslabel, ilabel, extlabel,
                        rlabel, self.sublabel]

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

        # don't call setup, let them do that when scalelevels is created
    def setup(self):
        self.subnames = self.sliderlevels.keys()
        self.subnames.sort()
        self.presets = {}
        self.load_presets()

        self.current_preset = StringVar() # name of current preset
        self.current_mappings = []
        for i in range(self.numsliders):
            self.current_mappings.append(SliderMapping())

        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 slidermap in self.current_mappings:
            try:
                v = self.sliderlevels[slidermap.get_mapping()]
                slidermap.set_sublevel_var(v)
            except KeyError:
                pass
                
    def get_levels(self):
        'Called by changelevels, returns a dict of new values for submasters'
        if not self.sliderinput: return {}

        self.load_scalelevels() # freshen our input from the physical sliders

        rawlevels = self.sliderinput.get_levels()
        for rawlev, slidermap in zip(rawlevels, self.current_mappings):
            slidermap.changed_extinput(rawlev)

        '''
        outputlevels = {}
        for m in self.current_mappings:
            if m.issynced():
                k, v = m.get_level_pair()
                outputlevels[k] = v
                m.ignorenextunync()
        return outputlevels
        '''
        return dict([m.get_level_pair()
            for m in self.current_mappings
            if m.issynced()])
    def draw_interface(self):
        self.reallevellabels = []
        subchoiceframe = Frame(self)
        for m in self.current_mappings:
            m.draw_interface(subchoiceframe, self.subnames)
        subchoiceframe.pack()
        
        presetframe = Frame(self)
        Label(presetframe, text="Preset:").pack(side=LEFT)
        self.presetcombo = ComboBox(presetframe, variable=self.current_preset, 
                                    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)
        Button(presetframe, text="Disconnect", padx=0, pady=0, 
                command=self.disconnect_all).pack(side=LEFT)
        presetframe.pack(side=BOTTOM)
    def apply_preset(self, preset):
        if not preset: return
        preset_mapping = self.presets.get(preset)
        if not preset_mapping: return
        for subname, slidermap in zip(preset_mapping, self.current_mappings):
            slidermap.set_subname(subname)
    def delete_preset(self, *args):
        del self.presets[self.current_preset.get()]
        self.presetcombo.slistbox.listbox.delete(0, END)
        self.draw_presets()
        self.save_presets()
    def add_preset(self, *args):
        self.presets[self.current_preset.get()] = [m.get_mapping() 
                for m in self.current_mappings]
        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)
    def disconnect_all(self):
        for m in self.current_mappings:
            m.disconnect()