Changeset - 41c6fbe95214
[Not reviewed]
default
0 4 0
drewp@bigasterisk.com - 12 years ago 2013-06-13 21:59:32
drewp@bigasterisk.com
drag sub into curve area to get a curve+subterm and a 0..1 fade at the current play time
Ignore-this: ac77acf1cfbcfbce2f6b77da670b407
4 files changed with 75 insertions and 7 deletions:
0 comments (0 inline, 0 general)
bin/curvecalc
Show inline comments
 
@@ -81,60 +81,90 @@ class Main(object):
 
        
 
        ec = EditChoice(graph, songChoice, label="Editing song:")
 
        wtree.get_object("currentSongEditChoice").add(ec)
 
        ec.show()
 
        
 
        wtree.get_object("subterms").connect("add", self.onSubtermChildAdded)
 
        
 

	
 
        self.refreshCurveView()       
 
        
 
        self.makeStatusLines(wtree.get_object("status"))
 

	
 

	
 
        self.acceptDragsOnCurveViews()
 
        
 
        def connect(w):
 
            w.drag_dest_set(flags=gtk.DEST_DEFAULT_ALL,
 
                            targets=[('text/uri-list', 0, 0)],
 
                            actions=gtk.gdk.ACTION_COPY)
 
            w.connect("drag-data-received", self.onDataReceived)
 
        #connect(mainwin)
 
        # that's not enough- deeper windows don't accept the
 
        # event. 
 
        #mainwin.forall(connect) # not very effective
 

	
 
        wtree.get_object("newSubZone").drag_dest_set(flags=gtk.DEST_DEFAULT_ALL,
 
                            targets=[('text/uri-list', 0, 0)],
 
                            actions=gtk.gdk.ACTION_COPY)
 
        
 
        # this probably isn't rerunning often enough to catch new data
 
        #connect(wtree.get_object("subterms")) # works for that area
 

	
 
        # may not work
 
        wtree.get_object("paned1").set_position(600)
 

	
 
    def acceptDragsOnCurveViews(self):
 
        w = self.wtree.get_object("curves")
 
        w.drag_dest_set(flags=gtk.DEST_DEFAULT_ALL,
 
                        targets=[('text/uri-list', 0, 0)],
 
                        actions=gtk.gdk.ACTION_COPY)
 
        def recv(widget, context, x, y, selection,
 
                       targetType, time):
 
            subUri = URIRef(selection.data.strip())
 
            print "into curves", subUri
 
            with self.graph.currentState(
 
                    tripleFilter=(subUri, RDFS.label, None)) as current:
 
                subName = current.label(subUri)
 

	
 
            try:
 
                self.makeSubterm(subName, withCurve=True,
 
                                 sub=subUri,
 
                                 expr="%s(t)" % subName)
 
            except SubtermExists:
 
                # we're not making sure the expression/etc are
 
                # correct-- user mihgt need to fix things
 
                pass
 
            curveView = self.curvesetView.row(subName).curveView
 
            t = self.lastSeenInputTime # curveView.current_time() # new curve hasn't heard the time yet. this has gotten too messy- everyone just needs to be able to reach the time source
 
            print "time", t
 
            curveView.add_points([(t - .5, 0),
 
                                  (t, 1)])
 
        w.connect("drag-data-received", recv)
 
        
 
    def onDataReceived(self, widget, context, x, y, selection,
 
                       targetType, time):
 
        data = selection.data.strip()
 
        if '?' in data:
 
            self.handleSubtermDrop(data)
 
            return
 
        uri = URIRef(data)
 
        subName = self.graph.label(uri)
 
        
 
        try:
 
            self.makeSubterm(subName, withCurve=True)
 
        except SubtermExists:
 
            pass
 
        curveView = self.curvesetView.row(subName).curveView
 
        t = self.lastSeenInputTime # curveView.current_time() # new curve hasn't heard the time yet. this has gotten too messy- everyone just needs to be able to reach the time source
 
        print "time", t
 
        curveView.add_points([(t - .5, 0),
 
                              (t, 1)])
 

	
 
    def onDragDataInNewSubZone(self, widget, context, x, y, selection,
 
                       targetType, time):
 
        self.makeSubterm(newname="cx", withCurve=True,
 
                         sub=URIRef(selection.data.strip()))
 
        
 
    def handleSubtermDrop(self, data):
 
        params = parse_qsl(data.split('?')[1])
 
        flattened = dict(params)
 
        self.makeSubterm(flattened['subtermName'],
 
@@ -181,49 +211,72 @@ class Main(object):
 

	
 
    def currentSong(self):
 

	
 
        with self.graph.currentState(
 
                tripleFilter=(self.session, L9['currentSong'], None)
 
        ) as current:
 
            return current.value(self.session, L9['currentSong'])
 

	
 
    def songSubtermsContext(self):
 
        return self.currentSong()
 

	
 
    def makeSubterm(self, newname, withCurve=False, expr=None, sub=None):
 
        """
 
        raises SubtermExists if we had a subterm with a sub with the given
 
        name. what about a no-sub term with the same label? who knows
 
        """
 
        assert isinstance(newname, Literal), repr(newname)
 
        if withCurve:
 
            self.curveset.new_curve(newname, renameIfExisting=False)
 
        if newname in self.all_subterm_labels():
 
            raise SubtermExists("have a subterm who sub is named %r" % newname)
 
        with self.graph.currentState() as current:
 
            song = self.currentSong()
 
            for i in range(1000):
 
                uri = song + "/subterm/%d" % i
 
                if (uri, None, None) not in current:
 
                    break
 
            else:
 
                raise ValueError("can't pick a name for the new subterm")
 

	
 
        ctx = self.songSubtermsContext()
 
        quads = [
 
            (uri, RDF.type, L9.Subterm, ctx),
 
            (uri, RDFS.label, Literal(newname), ctx),
 
            (self.currentSong(), L9['subterm'], uri, ctx),
 
            ]
 
        if sub is not None:
 
            quads.append((uri, L9['sub'], sub, ctx))
 
        if expr is not None:
 
            quads.append((uri, L9['expression'], Literal(expr), ctx))
 
        self.graph.patch(Patch(addQuads=quads))
 
            
 
        if withCurve:
 
            self.curveset.new_curve(newname)
 
        return uri
 
                         
 

	
 
    def all_subterm_labels(self):
 
        """
 
        Literal labels of subs in subterms. doesn't currently include labels of the
 
        subterm resources. I'm not sure what I'm going to do with
 
        those.
 
        """
 
        labels = []
 
        with self.graph.currentState() as current:
 
            for st in current.objects(
 
                    current.value(self.session, L9['currentSong']),
 
                    L9['subterm']):
 
                sub = current.value(st, L9['sub'])
 
                if sub is not None:
 
                    labels.append(current.label(sub))
 
        return labels
 
        
 
    def set_subterms_from_graph(self):
 
        """rebuild all the gtktable 'subterms' widgets and the
 
        self.currentSubterms list"""
 
        song = self.graph.value(self.session, L9['currentSong'])
 

	
 
        newList = []
 
        for st in set(self.graph.objects(song, L9['subterm'])):
 
            log.debug("song %s has subterm %s", song, st)
 
            term = Subterm(self.graph, st, self.songSubtermsContext(),
 
                               self.curveset)
 
            newList.append(term)
 
        self.currentSubterms[:] = newList
 
@@ -276,24 +329,25 @@ class Main(object):
 

	
 
    def onZoomAll(self, item):
 
        dispatcher.send("show all")
 

	
 
    def onPlayPause(self, item):
 
        # since the X coord in a curveview affects the handling, one
 
        # of them may be able to pick this up
 
        results = dispatcher.send("onPlayPause")
 
        times = [t for listener, t in results if t is not None]
 
        self.music.playOrPause(t=times[0] if times else None)
 

	
 
    def onSave(self, *args):
 
        # only doing curves still. I hope to eliminate all this.
 
        with self.graph.currentState() as g:
 
            song = g.value(self.session, L9['currentSong'])
 

	
 
            log.info("saving curves for %r", song)
 
            self.curveset.save(basename=os.path.join(
 
                showconfig.curvesDir(),
 
                showconfig.songFilenameFromURI(song)))
 
            log.info("saved")
 

	
 
    def makeStatusLines(self, master):
 
        """various labels that listen for dispatcher signals"""
 
        for row, (signame, textfilter) in enumerate([
light9/curvecalc/curve.py
Show inline comments
 
from __future__ import division
 
import glob, time, logging, ast
 
from bisect import bisect_left,bisect
 
import louie as dispatcher
 
from rdflib import Literal
 

	
 
from bcf2000 import BCF2000
 

	
 
log = logging.getLogger()
 
# todo: move to config, consolidate with ascoltami, musicPad, etc
 
introPad = 4
 
postPad = 4
 

	
 
class Curve(object):
 
    """curve does not know its name. see Curveset"""
 
    def __init__(self):
 
        self.points = [] # x-sorted list of (x,y)
 
@@ -134,25 +135,25 @@ class Sliders(BCF2000):
 
            self.cb(int(name[6:]), value / 127)
 
        if name.startswith("knob"):
 
            self.knobCallback(int(name[4:]), value / 127)
 
        if name.startswith("button-knob"):
 
            self.knobButtonCallback(int(name[11:]))
 

	
 
        
 
class Curveset(object):
 
    
 
    curves = None # curvename : curve
 
    def __init__(self, sliders=False):
 
        """sliders=True means support the hardware sliders"""
 
        self.curves = {} # name : Curve
 
        self.curves = {} # name (str) : Curve
 
        self.curveName = {} # reverse
 
        self.sliderCurve = {} # slider number (1 based) : curve name
 
        self.sliderNum = {} # reverse
 
        if sliders:
 
            self.sliders = Sliders(self.hw_slider_in, self.hw_knob_in, 
 
                                   self.hw_knob_button)
 
            dispatcher.connect(self.curvesToSliders, "curves to sliders")
 
            dispatcher.connect(self.knobOut, "knob out")
 
            self.lastSliderTime = {} # num : time
 
            self.sliderSuppressOutputUntil = {} # num : time
 
            self.sliderIgnoreInputUntil = {}
 
        else:
 
@@ -185,52 +186,58 @@ class Curveset(object):
 
            
 
    def save(self,basename):
 
        """writes a file for each curve with a name
 
        like basename-curvename"""
 
        for name,cur in self.curves.items():
 
            cur.save("%s-%s" % (basename,name))
 
        self.markers.save("%s.markers" % basename)
 

	
 
    def curveNamesInOrder(self):
 
        return sorted(self.curves.keys(), key=self.sorter)
 
            
 
    def add_curve(self,name,curve):
 
        if isinstance(name, Literal):
 
            name = str(name) 
 
        if name in self.curves:
 
            raise ValueError("can't add a second curve named %r" % name)
 
        self.curves[name] = curve
 
        self.curveName[curve] = name
 

	
 
        if self.sliders and name not in ['smooth_music', 'music']:
 
            num = len(self.sliderCurve) + 1
 
            if num <= 8:
 
                self.sliderCurve[num] = name
 
                self.sliderNum[name] = num
 
            else:
 
                num = None
 
        else:
 
            num = None
 
            
 
        dispatcher.send("add_curve", slider=num, knobEnabled=num is not None,
 
                        sender=self, name=name)
 

	
 
    def globalsdict(self):
 
        return self.curves.copy()
 
    
 
    def get_time_range(self):
 
        return 0, dispatcher.send("get max time")[0][1]
 

	
 
    def new_curve(self,name):
 
    def new_curve(self, name, renameIfExisting=True):
 
        if isinstance(name, Literal):
 
            name = str(name)
 
        if name=="":
 
            print "no name given"
 
            return
 
        if not renameIfExisting and name in self.curves:
 
            return
 
        while name in self.curves:
 
           name=name+"-1"
 

	
 
        c = Curve()
 
        s,e = self.get_time_range()
 
        c.points.extend([(s,0), (e,0)])
 
        self.add_curve(name,c)
 

	
 
    def hw_slider_in(self, num, value):
 
        try:
 
            curve = self.curves[self.sliderCurve[num]]
 
        except KeyError:
light9/curvecalc/curvecalc.glade
Show inline comments
 
@@ -662,24 +662,25 @@
 
        </child>
 
      </object>
 
    </child>
 
  </object>
 
  <object class="GtkAccelGroup" id="accelgroup1"/>
 
  <object class="GtkAdjustment" id="adjustment1">
 
    <property name="upper">100</property>
 
    <property name="step_increment">1</property>
 
    <property name="page_increment">10</property>
 
  </object>
 
  <object class="GtkTextBuffer" id="help">
 
    <property name="text">Mousewheel zoom; C-p play/pause music at mouse
 
Drag sub into curve area for new curve+subterm
 
Keys in a selected curve: C to collapse; R to rebuild broken canvas widget; 1..5 add point at time cursor; q,w,e,r,t,y set marker at time cursor
 
Curve point bindings: B1 drag point; C-B1 curve add point; S-B1 sketch points; B1 drag select points
 
Available in functions: nsin/ncos period=amp=1; within(a,b) bef(x) aft(x) compare to time; smoove(x) cubic smoothstep; chan(name); curvename(t) eval curve</property>
 
  </object>
 
  <object class="GtkImage" id="image2">
 
    <property name="visible">True</property>
 
    <property name="can_focus">False</property>
 
    <property name="stock">gtk-refresh</property>
 
  </object>
 
  <object class="GtkListStore" id="liststore1"/>
 
  <object class="GtkDialog" id="newCurve">
 
    <property name="can_focus">False</property>
light9/curvecalc/curveview.py
Show inline comments
 
from __future__ import division
 
import math, time, logging
 
import gtk, goocanvas
 
import louie as dispatcher
 
from rdflib import Literal
 
from light9.curvecalc.zoomcontrol import RegionZoom
 
from light9.curvecalc import cursors
 
from light9.curvecalc.curve import introPad, postPad
 
from light9.dmxchanedit import gradient
 

	
 
log = logging.getLogger()
 
print "curveview.py toplevel"
 
def vlen(v):
 
    return math.sqrt(v[0]*v[0] + v[1]*v[1])
 

	
 
def angle_between(base, p0, p1):
 
    p0 = p0[0] - base[0], p0[1] - base[1]
 
@@ -1174,36 +1175,41 @@ class Curvesetview(object):
 
            if 0 <= inRowX < w and 0 <= inRowY < h:
 
                return r
 
        raise ValueError("no curveRow is under the mouse")
 

	
 
    def focus_entry(self):
 
        self.entry.focus()
 

	
 
    def new_curve(self, event):
 
        self.curveset.new_curve(self.newcurvename.get())
 
        self.newcurvename.set('')
 
        
 
    def add_curve(self, name, slider=None, knobEnabled=False):
 
        if isinstance(name, Literal):
 
            name = str(name)
 
        curve = self.curveset.curves[name]
 
        f = CurveRow(name, curve, self.curveset.markers,
 
                     slider, knobEnabled, self.zoomControl)
 
        self.curvesVBox.pack_start(f.box)
 
        f.box.show_all()
 
        self.allCurveRows.add(f)
 
        f.curveView.goLive()
 

	
 
    def row(self, name):
 
        if isinstance(name, Literal):
 
            name = str(name)
 
        matches = [r for r in self.allCurveRows if r.name == name]
 
        if not matches:
 
            raise ValueError("no curveRow named %r" % name)
 
            raise ValueError("no curveRow named %r. only %s" %
 
                             (name, [r.name for r in self.allCurveRows]))
 
        return matches[0]
 

	
 
    def goLive(self):
 
        """for startup performance, none of the curves redraw
 
        themselves until this is called once (and then they're normal)"""
 
        
 
        for cr in self.allCurveRows:
 
            cr.curveView.goLive()
 

	
 
    def onDelete(self):
 
        for r in self.allCurveRows:
 
            r.onDelete()
0 comments (0 inline, 0 general)