# HG changeset patch # User drewp@bigasterisk.com # Date 2013-01-15 21:02:08 # Node ID 295b867fd810e19fad4b82152a2fed1b87bbf554 # Parent f7ae0faa0a442d2a71df0a9b1a04b486393531ff just whitespace (hopefully) Ignore-this: a364fab649d9e795f703cfe794f07ca6 diff --git a/bin/keyboardcomposer b/bin/keyboardcomposer --- a/bin/keyboardcomposer +++ b/bin/keyboardcomposer @@ -76,11 +76,11 @@ class SubmasterBox(Frame): self.slider_var = DoubleVar() self.pauseTrace = False self.scale = SubScale(self, variable=self.slider_var, width=20) - + self.namelabel = Label(self, font="Arial 7", bg=darkBg, fg='white', pady=0) self.sub.graph.addHandler(self.updateName) - + self.namelabel.pack(side=TOP) levellabel = Label(self, textvariable=self.slider_var, font="Arial 7", bg='black', fg='white', pady=0) @@ -100,7 +100,7 @@ class SubmasterBox(Frame): def cleanup(self): self.slider_var.trace_vdelete('w', self._slider_var_trace) - + def slider_changed(self, *args): self.scale.draw_indicator_colors() @@ -108,7 +108,7 @@ class SubmasterBox(Frame): return self.updateGraphWithLevel(self.sub.uri, self.slider_var.get()) # dispatcher.send("level changed") # in progress - ###self.send_levels() # use dispatcher? + ###self.send_levels() # use dispatcher? # needs fixing: plan is to use dispatcher or a method call to tell a hardware-mapping object who changed, and then it can make io if that's a current hw slider #if rowcount == self.current_row: @@ -171,7 +171,7 @@ class KeyboardComposer(Frame, SubClient) self.subbox = {} # sub uri : SubmasterBox self.slider_table = {} # coords : SubmasterBox self.rows = [] # this holds Tk Frames for each row - + self.current_row = 0 # should come from session graph self.use_hw_sliders = hw_sliders @@ -190,18 +190,18 @@ class KeyboardComposer(Frame, SubClient) self.sliders_status_var = IntVar() self.sliders_status_var.set(self.use_hw_sliders) - self.sliders_checkbutton = Checkbutton(self.buttonframe, + self.sliders_checkbutton = Checkbutton(self.buttonframe, text="Sliders", variable=self.sliders_status_var, command=lambda: self.toggle_slider_connectedness(), bg='black', fg='white') self.sliders_checkbutton.pack(side=LEFT) - self.alltozerobutton = Button(self.buttonframe, text="All to Zero", + self.alltozerobutton = Button(self.buttonframe, text="All to Zero", command=self.alltozero, bg='black', fg='white') self.alltozerobutton.pack(side='left') - self.save_stage_button = Button(self.buttonframe, text="Save", - command=lambda: self.save_current_stage(self.sub_name.get()), + self.save_stage_button = Button(self.buttonframe, text="Save", + command=lambda: self.save_current_stage(self.sub_name.get()), bg='black', fg='white') self.save_stage_button.pack(side=LEFT) self.sub_name = Entry(self.buttonframe, bg='black', fg='white') @@ -222,7 +222,7 @@ class KeyboardComposer(Frame, SubClient) def onLostSub(self, subUri): log.info("lost %s", subUri) self.graph.addHandler(self.draw_sliders) - + def draw_sliders(self): for r in self.rows: r.destroy() @@ -231,7 +231,7 @@ class KeyboardComposer(Frame, SubClient) b.cleanup() self.subbox.clear() self.slider_table.clear() - + self.tk_focusFollowsMouse() rowcount = -1 @@ -240,9 +240,9 @@ class KeyboardComposer(Frame, SubClient) # there are unlikely to be any subs at startup because we # probably haven't been called back with the graph data yet - - withgroups = sorted((self.graph.value(sub.uri, L9['group']), - self.graph.value(sub.uri, L9['order']), + + withgroups = sorted((self.graph.value(sub.uri, L9['group']), + self.graph.value(sub.uri, L9['order']), sub) for sub in self.submasters.get_all_subs()) dispatcher.connect(self.onNewSub, "new submaster") @@ -265,7 +265,7 @@ class KeyboardComposer(Frame, SubClient) col = (col + 1) % 8 last_group = group - + def toggle_slider_connectedness(self): self.use_hw_sliders = not self.use_hw_sliders if self.use_hw_sliders: @@ -297,7 +297,7 @@ class KeyboardComposer(Frame, SubClient) upkey, downkey = (upkey.upper(), downkey.upper()) # another what a hack! - keylabel = Label(keyhintrow, text='%s\n%s' % (upkey, downkey), + keylabel = Label(keyhintrow, text='%s\n%s' % (upkey, downkey), width=1, font=('Arial', 10), bg='red', fg='white', anchor='c') keylabel.pack(side=LEFT, expand=1, fill=X) col += 1 @@ -371,7 +371,7 @@ class KeyboardComposer(Frame, SubClient) self.sliders.valueOut("slider%d" % col, 0) continue self.send_to_hw(subbox.name, col) - + def got_nudger(self, number, direction, full=0): try: subbox = self.slider_table[(self.current_row, number)] @@ -400,10 +400,10 @@ class KeyboardComposer(Frame, SubClient) def send_to_hw(self, subUri, hwNum): if isinstance(self.sliders, DummySliders): return - + v = round(127 * self.slider_vars[subUri].get()) chan = "slider%s" % hwNum - + # workaround for some rounding issue, where we receive one # value and then decide to send back a value that's one step # lower. -5 is a fallback for having no last value. hopefully @@ -411,7 +411,7 @@ class KeyboardComposer(Frame, SubClient) if abs(v - self.sliders.lastValue.get(chan, -5)) <= 1: return self.sliders.valueOut(chan, v) - + def make_row(self): row = Frame(self, bd=2, bg='black') row.pack(expand=1, fill=BOTH) @@ -428,7 +428,7 @@ class KeyboardComposer(Frame, SubClient) row['bg'] = 'black' def get_levels(self): - return dict([(uri, box.slider_var.get()) + return dict([(uri, box.slider_var.get()) for uri, box in self.subbox.items()]) def get_levels_as_sub(self): @@ -479,7 +479,7 @@ class LevelServerHttp(resource.Resource) def render_POST(self, request): arg = postArgGetter(request) - + if request.path == '/fadesub': # fadesub?subname=scoop&level=0&secs=.2 self.name_to_subbox[arg('subname')].scale.fade( @@ -546,6 +546,9 @@ if __name__ == "__main__": graph = SyncedGraph("keyboardcomposer") + # i think this also needs delayed start (like subcomposer has), to have a valid graph + # before setting any stuff from the ui + root = Tk() initTkdnd(root.tk, 'tkdnd/trunk/') @@ -572,7 +575,7 @@ if __name__ == "__main__": log.warn(e) root.protocol('WM_DELETE_WINDOW', reactor.stop) - + tksupport.install(root,ms=10) diff --git a/bin/rdfdb b/bin/rdfdb --- a/bin/rdfdb +++ b/bin/rdfdb @@ -151,7 +151,7 @@ class Client(object): self.sendPatch(Patch( addQuads=self.db.graph.quads(ALLSTMTS), delQuads=[])) - + def sendPatch(self, p): return syncedgraph.sendPatch(self.updateUri, p) @@ -194,7 +194,7 @@ class Db(object): self.watchFile("show/dance2012/patch.n3") finally: self.initialLoad = False - + self.summarizeToLog() def uriFromFile(self, filename): @@ -203,7 +203,7 @@ class Db(object): # back this might not go so well filename = filename[:-len('.n3')] return URIRef(self.topUri + filename) - + def fileForUri(self, ctx): if not ctx.startswith(self.topUri): raise ValueError("don't know what filename to use for %s" % ctx) @@ -214,7 +214,7 @@ class Db(object): gf = GraphFile(self.notifier, inFile, ctx, self.patch, self.getSubgraph) self.graphFiles[ctx] = gf gf.reread() - + def patch(self, p, dueToFileChange=False): """ apply this patch to the master graph then notify everyone about it @@ -259,14 +259,14 @@ class Db(object): outFile = self.fileForUri(ctx) self.graphFiles[ctx] = GraphFile(self.notifier, outFile, ctx, self.patch, self.getSubgraph) - + self.graphFiles[ctx].dirty(g) def clientErrored(self, err, c): err.trap(twisted.internet.error.ConnectError) log.info("connection error- dropping client %r" % c) self.clients.remove(c) - self.sendClientsToAllLivePages() + self.sendClientsToAllLivePages() def summarizeToLog(self): log.info("contexts in graph (%s total stmts):" % len(self.graph)) @@ -289,7 +289,7 @@ class Db(object): for s in self.graph.triples(ALLSTMTS, uri): g.add(s) return g - + def addClient(self, updateUri, label): [self.clients.remove(c) for c in self.clients if c.updateUri == updateUri] @@ -301,12 +301,12 @@ class Db(object): def sendClientsToAllLivePages(self): sendToLiveClients({"clients":[ dict(updateUri=c.updateUri, label=c.label) - for c in self.clients]}) + for c in self.clients]}) class GraphResource(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): - pass - + self.write(self.settings.db.graph.serialize(format='n3')) + class Patches(PrettyErrorHandler, cyclone.web.RequestHandler): def __init__(self, *args, **kw): cyclone.web.RequestHandler.__init__(self, *args, **kw) @@ -319,7 +319,7 @@ class Patches(PrettyErrorHandler, cyclon class GraphClients(PrettyErrorHandler, cyclone.web.RequestHandler): def get(self): pass - + def post(self): upd = self.get_argument("clientUpdate") try: @@ -336,7 +336,7 @@ def sendToLiveClients(d=None, asJson=Non c.sendMessage(j) class Live(cyclone.websocket.WebSocketHandler): - + def connectionMade(self, *args, **kwargs): log.info("websocket opened") liveClients.add(self) @@ -375,10 +375,10 @@ if __name__ == "__main__": raise ValueError("missing --show http://...") db = Db() - + from twisted.python import log as twlog twlog.startLogging(sys.stdout) - + port = 8051 reactor.listenTCP(port, cyclone.web.Application(handlers=[ (r'/live', Live), diff --git a/light9/Submaster.py b/light9/Submaster.py --- a/light9/Submaster.py +++ b/light9/Submaster.py @@ -11,7 +11,7 @@ log = logging.getLogger('submaster') class Submaster(object): "Contain a dictionary of levels, but you didn't need to know that" def __init__(self, name, levels): - """this sub has a name just for debugging. It doesn't get persisted. + """this sub has a name just for debugging. It doesn't get persisted. See PersistentSubmaster. levels is a dict @@ -20,16 +20,16 @@ class Submaster(object): self.levels = levels self.temporary = True - + if not self.temporary: # obsolete dispatcher.connect(log.error, 'reload all subs') - + log.debug("%s initial levels %s", self.name, self.levels) def _editedLevels(self): pass - + def set_level(self, channelname, level, save=True): self.levels[Patch.resolve_name(channelname)] = level self._editedLevels() @@ -42,12 +42,12 @@ class Submaster(object): def get_levels(self): return self.levels - + def no_nonzero(self): return (not self.levels.values()) or not (max(self.levels.values()) > 0) def __mul__(self, scalar): - return Submaster("%s*%s" % (self.name, scalar), + return Submaster("%s*%s" % (self.name, scalar), levels=dict_scale(self.levels, scalar)) __rmul__ = __mul__ def max(self, *othersubs): @@ -64,11 +64,11 @@ class Submaster(object): items.sort() levels = ' '.join(["%s:%.2f" % item for item in items]) return "<'%s': [%s]>" % (getattr(self, 'name', 'no name yet'), levels) - + def __cmp__(self, other): # not sure how useful this is return cmp(self.ident(), other.ident()) - + def __hash__(self): return hash(self.ident()) @@ -89,23 +89,23 @@ class Submaster(object): levels[dmxchan] = max(v, levels[dmxchan]) return levels - + def normalize_patch_names(self): """Use only the primary patch names.""" # possibly busted -- don't use unless you know what you're doing self.set_all_levels(self.levels.copy()) def get_normalized_copy(self): - """Get a copy of this sumbaster that only uses the primary patch + """Get a copy of this sumbaster that only uses the primary patch names. The levels will be the same.""" newsub = Submaster("%s (normalized)" % self.name, {}) newsub.set_all_levels(self.levels) return newsub - + def crossfade(self, othersub, amount): """Returns a new sub that is a crossfade between this sub and - another submaster. - + another submaster. + NOTE: You should only crossfade between normalized submasters.""" otherlevels = othersub.get_levels() keys_set = {} @@ -115,7 +115,7 @@ class Submaster(object): xfaded_sub = Submaster("xfade", {}) for k in all_keys: - xfaded_sub.set_level(k, + xfaded_sub.set_level(k, linear_fade(self.levels.get(k, 0), otherlevels.get(k, 0), amount)) @@ -134,21 +134,21 @@ class PersistentSubmaster(Submaster): def ident(self): return self.uri - + def _editedLevels(self): self.save() - + def setName(self): log.info("sub update name %s %s", self.uri, self.graph.label(self.uri)) self.name = self.graph.label(self.uri) - + def setLevels(self): log.info("sub update levels") oldLevels = getattr(self, 'levels', {}).copy() self.setLevelsFromGraph() if oldLevels != self.levels: log.info("sub %s changed" % self.name) - + def setLevelsFromGraph(self): if hasattr(self, 'levels'): self.levels.clear() @@ -186,7 +186,7 @@ class PersistentSubmaster(Submaster): graph.serialize(showconfig.subFile(self.name), format="nt") - + def linear_fade(start, end, amount): """Fades between two floats by an amount. amount is a float between 0 and 1. If amount is 0, it will return the start value. If it is 1, @@ -221,7 +221,7 @@ class Submasters: def __init__(self, graph): self.submasters = {} self.graph = graph - + graph.addHandler(self.findSubs) def findSubs(self): diff --git a/light9/dmxchanedit.py b/light9/dmxchanedit.py --- a/light9/dmxchanedit.py +++ b/light9/dmxchanedit.py @@ -51,7 +51,7 @@ class Onelevel(tk.Frame): # channel number -- will turn yellow when being altered self.num_lab = tk.Label(self, text=str(self.channelnum), - width=3, bg='grey40', + width=3, bg='grey40', fg='white', font=stdfont, padx=0, pady=0, bd=0, height=1) @@ -62,7 +62,7 @@ class Onelevel(tk.Frame): width=14, font=stdfont, anchor='w', - padx=0, pady=0, bd=0, + padx=0, pady=0, bd=0, height=1, bg='black', fg='white') self.graph.addHandler(self.updateLabel) self.desc_lab.pack(side='left') @@ -78,7 +78,7 @@ class Onelevel(tk.Frame): def updateLabel(self): self.desc_lab.config(text=self.graph.label(self.uri)) - + def setupmousebindings(self): def b1down(ev): self.desc_lab.config(bg='cyan') @@ -106,7 +106,7 @@ class Onelevel(tk.Frame): ('', b3down)): w.bind(e,func) - + def colorlabel(self): """color the level label based on its own text (which is 0..100)""" txt=self.level_lab['text'] or "0" @@ -146,7 +146,7 @@ class Levelbox(tk.Frame): f = tk.Frame(parent, bd=0, bg='black') f.pack(side='left') return f - + columnFrames = [make_frame(self) for x in range(cols)] for i, channel in enumerate(chans): # sort? diff --git a/light9/rdfdb/rdflibpatch.py b/light9/rdfdb/rdflibpatch.py --- a/light9/rdfdb/rdflibpatch.py +++ b/light9/rdfdb/rdflibpatch.py @@ -68,7 +68,7 @@ def serializeQuad(g): for s,p,o,c in g.quads((None,None,None)): out += u"%s %s %s %s .\n" % (s.n3(), p.n3(), - _xmlcharref_encode(o.n3()), + _xmlcharref_encode(o.n3()), c.n3()) return out @@ -110,7 +110,7 @@ class TestGraphFromQuads(unittest.TestCa self.assertEqual(len(g), 1) out = serializeQuad(g) self.assertEqual(out.strip(), self.nqOut.strip()) - + stmt1 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx1') stmt2 = U('http://a'), U('http://b'), U('http://c'), U('http://ctx2') @@ -134,7 +134,7 @@ class TestPatchQuads(unittest.TestCase): patchQuads(g, [stmt1], [stmt1]) quads = list(g.quads((None,None,None))) self.assertEqual(quads, [stmt1]) - + def testPerfectAddRejectsExistingStmt(self): g = ConjunctiveGraph() patchQuads(g, [], [stmt1]) @@ -149,7 +149,7 @@ class TestPatchQuads(unittest.TestCase): def testPerfectDeleteRejectsAbsentStmt(self): g = ConjunctiveGraph() self.assertRaises(ValueError, patchQuads, g, [stmt1], [], perfect=True) - + def testPerfectDeleteAllowsRemovalOfStmtInMultipleContexts(self): g = ConjunctiveGraph() patchQuads(g, [], [stmt1, stmt2]) @@ -159,4 +159,4 @@ class TestPatchQuads(unittest.TestCase): g = ConjunctiveGraph() patchQuads(g, [], [stmt1, stmt1], perfect=True) patchQuads(g, [stmt1, stmt1], [], perfect=True) - + diff --git a/light9/rdfdb/syncedgraph.py b/light9/rdfdb/syncedgraph.py --- a/light9/rdfdb/syncedgraph.py +++ b/light9/rdfdb/syncedgraph.py @@ -71,13 +71,13 @@ class GraphWatchers(object): [(s, p) for s, p, o, c in patch.delQuads]) affectedPredObjs = set([(p, o) for s, p, o, c in patch.addQuads]+ [(p, o) for s, p, o, c in patch.delQuads]) - + ret = set() for (s, p), funcs in self._handlersSp.iteritems(): if (s, p) in affectedSubjPreds: ret.update(funcs) funcs.clear() - + for (p, o), funcs in self._handlersPo.iteritems(): if (p, o) in affectedPredObjs: ret.update(funcs) @@ -94,7 +94,7 @@ class GraphWatchers(object): log.info("whocares:") from pprint import pprint pprint(self._handlersSp) - + class PatchSender(object): """ @@ -134,7 +134,7 @@ class PatchSender(object): p, sendResult = self._patchesToSend.pop(0) else: p, sendResult = self._patchesToSend.pop(0) - + self._currentSendPatchRequest = sendPatch( self.target, p, senderUpdateUri=self.myUpdateResource) self._currentSendPatchRequest.addCallbacks(self._sendPatchDone, @@ -166,7 +166,7 @@ class PatchSender(object): log.error("_sendPatchErr") log.error(e) self._continueSending() - + class SyncedGraph(object): """ @@ -187,7 +187,7 @@ class SyncedGraph(object): """ _graph = self._graph = ConjunctiveGraph() self._watchers = GraphWatchers() - + def onPatch(p): """ central server has sent us a patch @@ -340,7 +340,7 @@ class SyncedGraph(object): for s in self._graph.triples((None, None, None), context): g.add(s) return g - + def __exit__(self, type, val, tb): return @@ -365,7 +365,7 @@ class SyncedGraph(object): # bnode later. This won't work if the receiver stores bnodes # between calls, but probably most of them don't do that (they # work from a starting uri) - + def value(self, subject=None, predicate=RDF.value, object=None, default=None, any=True): if object is not None: @@ -379,7 +379,7 @@ class SyncedGraph(object): func = self._getCurrentFunc() self._watchers.addSubjPredWatcher(func, subject, predicate) return self._graph.objects(subject, predicate) - + def label(self, uri): return self.value(uri, RDFS.label) diff --git a/light9/tkdnd.py b/light9/tkdnd.py --- a/light9/tkdnd.py +++ b/light9/tkdnd.py @@ -122,7 +122,7 @@ def dropTargetRegister(widget, typeList= onDropLeave=hover.restore, onDropPosition=onDropPosition, onDrop=wrappedDrop) - + if typeList is None: typeList = ['*'] widget.tk.call(*(['tkdnd::drop_target', 'register', widget._w]+typeList)) diff --git a/light9/uihelpers.py b/light9/uihelpers.py --- a/light9/uihelpers.py +++ b/light9/uihelpers.py @@ -55,6 +55,7 @@ def toplevelat(name, existingtoplevel=No def savePos(): geo = tl.geometry() + # todo: need a way to filter out the startup window sizes that # weren't set by the user if geo.startswith("1x1") or geo.startswith(("378x85", "378x86")): @@ -80,7 +81,7 @@ def positionOnCurrentDesktop(xform, scre x = int(x) % screenWidth y = int(y) % screenHeight return "%s+%s+%s" % (size, x, y) - + def toggle_slider(s): if s.get() == 0: @@ -88,7 +89,7 @@ def toggle_slider(s): else: s.set(0) -# for lambda callbacks +# for lambda callbacks def printout(t): print t @@ -97,7 +98,7 @@ def printevent(ev): if not k.startswith('__'): print k,getattr(ev,k) print "" - + def eventtoparent(ev,sequence): "passes an event to the parent, screws up TixComboBoxes" @@ -162,13 +163,13 @@ class Togglebutton(Button): def _varchanged(self,*args): self._setstate(self._variable.get()) - + def invoke(self,*ev): if self._variable: self._variable.set(not self.state) else: self._setstate(not self.state) - + if self.oldcommand and self.state: # call command only when state goes to 1 self.oldcommand() return "break" @@ -198,11 +199,11 @@ class FancyDoubleVar(DoubleVar): """ cbname = self._master._register(callback) self._tk.call("trace", "variable", self._name, mode, cbname) - + # we build a list of the trace callbacks (the py functrions and the tcl functionnames) self.callbacklist[cbname] = mode # print "added trace:",callback,cbname - + return cbname trace=trace_variable def disable_traces(self): @@ -210,7 +211,7 @@ class FancyDoubleVar(DoubleVar): # DoubleVar.trace_vdelete(self,v[0],k) self._tk.call("trace", "vdelete", self._name, mode,cb) # but no master delete! - + def recreate_traces(self): for cb,mode in self.callbacklist.items(): # self.trace_variable(v[0],v[1]) @@ -222,15 +223,15 @@ class FancyDoubleVar(DoubleVar): self.delete_named(name) cbname = self.trace_variable('w',callback) # this will register in self.callbacklist too - + self.namedtraces[name] = cbname return cbname - + def delete_named(self, name): if name in self.namedtraces: cbname = self.namedtraces[name] - + self.trace_vdelete('w',cbname) #self._tk.call("trace","vdelete",self._name,'w',cbname) print "FancyDoubleVar: successfully deleted trace named %s" % name