Changeset - 7f1aef5fbddb
[Not reviewed]
default
0 2 1
drewp@bigasterisk.com - 12 years ago 2012-07-19 04:54:29
drewp@bigasterisk.com
session cmdline support. KC saves current row in the session
Ignore-this: 966fcd0308fb9fd2a496ffaaecd7fb19
3 files changed with 66 insertions and 24 deletions:
0 comments (0 inline, 0 general)
bin/keyboardcomposer
Show inline comments
 
@@ -20,6 +20,7 @@ from light9 import dmxclient, showconfig
 
from light9.uihelpers import toplevelat, bindkeys
 
from light9.namespaces import L9
 
from light9.tkdnd import initTkdnd, dragSourceRegister
 
from light9.rdfdb import clientsession
 
from light9.rdfdb.syncedgraph import SyncedGraph
 
from light9.rdfdb.patch import Patch
 

	
 
@@ -62,8 +63,9 @@ class SubmasterBox(Frame):
 
    this object owns the level of the submaster (the rdf graph is the
 
    real authority)
 
    """
 
    def __init__(self, master, sub):
 
    def __init__(self, master, sub, session):
 
        self.sub = sub
 
        self.session = session
 
        bg = sub.graph.value(sub.uri, L9.color, default='#000000')
 
        rgb = webcolors.hex_to_rgb(bg)
 
        hsv = colorsys.rgb_to_hsv(*[x/255 for x in rgb])
 
@@ -115,33 +117,36 @@ class SubmasterBox(Frame):
 
    def updateGraphWithLevel(self, uri, level):
 
        """in our per-session graph, we maintain SubSetting objects like this:
 

	
 
           [a :SubSetting; :sub ?s; :level ?l]
 
           ?session :subSetting [a :SubSetting; :sub ?s; :level ?l]
 
        """
 
        ctx = URIRef("http://example.com/kc/session1")
 
        with self.sub.graph.currentState(context=ctx) as graph:
 

	
 
        with self.sub.graph.currentState() as graph:
 
            adds = set([])
 
            for setting in graph.subjects(RDF.type, L9['SubSetting']):
 
            for setting in graph.objects(self.session, L9['subSetting']):
 
                if graph.value(setting, L9['sub']) == uri:
 
                    break
 
            else:
 
                setting = URIRef("http://example.com/subsetting/%s" %
 
                setting = URIRef(self.session + "/setting/%s" %
 
                                 random.randrange(999999))
 
                adds.update([
 
                    (setting, RDF.type, L9['SubSetting'], ctx),
 
                    (setting, L9['sub'], uri, ctx),
 
                    (self.session, L9['subSetting'], setting, self.session),
 
                    (setting, RDF.type, L9['SubSetting'], self.session),
 
                    (setting, L9['sub'], uri, self.session),
 
                    ])
 
            dels = set([])
 
            for prev in graph.objects(setting, L9['level']):
 
                dels.add((setting, L9['level'], prev, ctx))
 
            adds.add((setting, L9['level'], Literal(level), ctx))
 
                dels.add((setting, L9['level'], prev, self.session))
 
            adds.add((setting, L9['level'], Literal(level), self.session))
 

	
 
            if adds != dels:
 
                self.sub.graph.patch(Patch(delQuads=dels, addQuads=adds))
 

	
 
    def updateLevelFromGraph(self):
 
        """read rdf level, write it to subbox.slider_var"""
 
        
 
        graph = self.sub.graph
 
        for setting in graph.subjects(RDF.type, L9['SubSetting']):
 

	
 
        for setting in graph.objects(self.session, L9['subSetting']):
 
            if graph.value(setting, L9['sub']) == self.sub.uri:
 
                self.pauseTrace = True # don't bounce this update back to server
 
                try:
 
@@ -156,11 +161,12 @@ class SubmasterBox(Frame):
 
        subprocess.Popen(["bin/subcomposer", "--no-geometry", self.name])
 

	
 
class KeyboardComposer(Frame, SubClient):
 
    def __init__(self, root, graph,
 
    def __init__(self, root, graph, session,
 
                 hw_sliders=True):
 
        Frame.__init__(self, root, bg='black')
 
        SubClient.__init__(self)
 
        self.graph = graph
 
        self.session = session
 
        self.submasters = Submasters(graph)
 
        self.subbox = {} # sub uri : SubmasterBox
 
        self.slider_table = {} # coords : SubmasterBox
 
@@ -176,6 +182,7 @@ class KeyboardComposer(Frame, SubClient)
 

	
 
        self.graph.addHandler(self.redraw_sliders)
 
        self.send_levels_loop()
 
        self.graph.addHandler(self.rowFromGraph)
 

	
 
    def make_buttons(self):
 
        self.buttonframe = Frame(self, bg='black')
 
@@ -250,7 +257,7 @@ class KeyboardComposer(Frame, SubClient)
 
                rowcount += 1
 
                col = 0
 

	
 
            subbox = SubmasterBox(row, sub)
 
            subbox = SubmasterBox(row, sub, self.session)
 
            subbox.place(relx=col / 8, rely=0, relwidth=1 / 8, relheight=1)
 
            self.subbox[sub.uri] = self.slider_table[(rowcount, col)] = subbox
 

	
 
@@ -327,16 +334,32 @@ class KeyboardComposer(Frame, SubClient)
 
            diff = -1
 
        self.change_row(self.current_row + diff)
 

	
 
    def change_row(self, row):
 
    def rowFromGraph(self):
 
        self.change_row(int(self.graph.value(self.session, L9['currentRow'], default=0)), fromGraph=True)
 

	
 
    def change_row(self, row, fromGraph=False):
 
        old_row = self.current_row
 
        self.current_row = row
 
        self.current_row = max(0, self.current_row)
 
        self.current_row = min(len(self.rows) - 1, self.current_row)
 
        try:
 
            row = self.rows[self.current_row]
 
        except IndexError:
 
            # if we're mid-load, this row might appear soon. If we
 
            # changed interactively, the user is out of bounds and
 
            # needs to be brought back in
 
            if fromGraph:
 
                return
 
            raise
 

	
 
        self.unhighlight_row(old_row)
 
        self.highlight_row(self.current_row)
 
        row = self.rows[self.current_row]
 
        self.keyhints.pack_configure(before=row)
 

	
 
        if not fromGraph:
 
            self.graph.patchObject(self.session, self.session, L9['currentRow'],
 
                                   Literal(self.current_row))
 

	
 
        for col in range(1, 9):
 
            try:
 
                subbox = self.slider_table[(self.current_row, col - 1)]
 
@@ -421,10 +444,6 @@ class KeyboardComposer(Frame, SubClient)
 
        sub.temporary = 0
 
        sub.save()
 

	
 
    def save(self):
 
        pickle.dump((self.get_levels(), self.current_row),
 
                    file('.keyboardcomposer.savedlevels', 'w'))
 

	
 
    def send_frequent_updates(self):
 
        """called when we get a fade -- send events as quickly as possible"""
 
        if time.time() <= self.stop_frequent_update_time:
 
@@ -518,6 +537,7 @@ if __name__ == "__main__":
 
    parser = OptionParser()
 
    parser.add_option('--no-sliders', action='store_true',
 
                      help="don't attach to hardware sliders")
 
    clientsession.add_option(parser)
 
    parser.add_option('-v', action='store_true', help="log info level")
 
    opts, args = parser.parse_args()
 

	
 
@@ -529,9 +549,12 @@ if __name__ == "__main__":
 
    root = Tk()
 
    initTkdnd(root.tk, 'tkdnd/trunk/')
 
    
 
    tl = toplevelat("Keyboard Composer", existingtoplevel=root)
 
    tl = toplevelat("Keyboard Composer - %s" % opts.session,
 
                    existingtoplevel=root)
 

	
 
    kc = KeyboardComposer(tl, graph, 
 
    session = clientsession.getUri('keyboardcomposer', opts)
 

	
 
    kc = KeyboardComposer(tl, graph, session,
 
                          hw_sliders=not opts.no_sliders)
 
    kc.pack(fill=BOTH, expand=1)
 

	
light9/rdfdb/clientsession.py
Show inline comments
 
new file 100644
 
"""
 
some clients will support the concept of a named session that keeps
 
multiple instances of that client separate
 
"""
 
from rdflib import URIRef
 
from urllib import quote
 

	
 
def add_option(parser):
 
    parser.add_option(
 
        '-s', '--session',
 
        help="name of session used for levels and window position",
 
        default='default')
 

	
 
def getUri(appName, opts):
 
    return URIRef("http://example.com/session/%s/%s" %
 
                  (appName, quote(opts.session, safe='')))
light9/rdfdb/syncedgraph.py
Show inline comments
 
@@ -212,11 +212,14 @@ class SyncedGraph(object):
 
    def patchObject(self, context, subject, predicate, newObject):
 
        """send a patch which removes existing values for (s,p,*,c)
 
        and adds (s,p,newObject,c). Values in other graphs are not affected"""
 
        raise NotImplementedError
 

	
 
        existing = []
 
        
 
        for spo in self._graph.triples((subject, predicate, None),
 
                                     context=context):
 
            existing.append(spo+(context,))
 
        # what layer is supposed to cull out no-op changes?
 
        self.patch(Patch(
 
            delQuads=[],
 
            delQuads=existing,
 
            addQuads=[(subject, predicate, newObject, context)]))
 

	
 
    def addHandler(self, func):
0 comments (0 inline, 0 general)