Changeset - 73b181155555
[Not reviewed]
default
0 3 0
drewp@bigasterisk.com - 16 years ago 2009-06-29 04:06:17
drewp@bigasterisk.com
curvecalc ui touchups, adjustable pane, curve draw speedup, restructured main layout code
Ignore-this: b0468548ef9f276dea4a8689dc425b24
3 files changed with 159 insertions and 141 deletions:
0 comments (0 inline, 0 general)
bin/curvecalc
Show inline comments
 
@@ -200,12 +200,15 @@ class Subterm:
 
                # returned
 
                return self.submaster * subexpr_eval
 
        except Exception, e:
 
            dispatcher.send("expr_error", sender=self.subexpr, exc=str(e))
 
            return Submaster.Submaster('Error: %s' % str(e), temporary=True)
 

	
 
    def __repr__(self):
 
        return "<Subterm %s %s>" % (self.submaster, self.subexpr)
 

	
 
class Subtermview(tk.Frame):
 
    def __init__(self, master, graph, st, **kw):
 
        self.subterm = st
 
        tk.Frame.__init__(self,master,bd=1,relief='raised',**kw)
 
        l = tk.Label(self,
 
                     text="sub %s" % graph.label(self.subterm.submaster.uri))
 
@@ -268,30 +271,31 @@ class Output:
 
            dispatcher.send("output levels",val=levs)
 
            dmxclient.outputlevels(out.get_dmx_list(),
 
                                   twisted=1,clientid='curvecalc')
 
            self.lastsendtime = now
 
            self.lastsendlevs = levs
 

	
 
def create_status_lines(master):
 
def makeStatusLines(master):
 
    """various labels that listen for dispatcher signals"""
 
    for signame,textfilter in [
 
        ('input time',lambda t: "%.2fs"%t),
 
        ('output levels',
 
         lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v)
 
                                                 for n,v in
 
                                                 levels.items()[:5]
 
                                                 if v>0]),70)),
 
        ('update period',lambda t: "%.1fms"%(t*1000)),
 
        ('update status',lambda t: str(t)),
 
        ]:
 
        l = tk.Label(master,anchor='w',justify='left')
 
        l = tk.Label(master, anchor='w', justify='left', text='%s:' % signame)
 
        l.pack(side='top',fill='x')
 
        dispatcher.connect(lambda val,l=l,sn=signame,tf=textfilter:
 
                           l.config(text=sn+": "+tf(val)),
 
                           signame,weak=0)
 
                           signame, weak=False)
 

	
 
def add_one_subterm(graph, subUri, curveset, subterms, root, master, expr=None):
 
def add_one_subterm(graph, subUri, curveset, subterms, master, expr=None):
 
    subname = graph.label(subUri)
 
    if expr is None:
 
        expr = '%s(t)' % subname
 

	
 
    term = Subterm(Submaster.Submaster(graph=graph, sub=subUri),
 
                   Subexpr(curveset,expr))
 
@@ -299,25 +303,25 @@ def add_one_subterm(graph, subUri, curve
 

	
 
    stv=Subtermview(master, graph, term)
 
    stv.pack(side='top',fill='x')
 

	
 
    return term
 

	
 
def sub_commands_tk(master, curveset, subterms, root, ssv, graph):
 
def makeSubtermCommandRow(master, curveset, subterms, root, ssv, graph):
 
    """
 
    the row that starts with 'reload subs' button
 
    """
 
    f=tk.Frame(master,relief='raised',bd=1)
 
    newname = tk.StringVar()
 

	
 
    def add_cmd(evt):
 
        uri = L9['sub/%s' % newname.get()]
 
        graph.add((uri, RDF.type, L9.Subterm))
 
        graph.add((uri, RDFS.label, Literal(newname.get())))
 
        add_one_subterm(graph, uri,
 
                        curveset, subterms, root, ssv, None)
 
                        curveset, subterms, ssv, None)
 
        if evt.state & 4: # control key modifier
 
            curveset.new_curve(newname.get())
 
        newname.set('')
 

	
 
    def reload_subs():
 
        dispatcher.send('reload all subs')
 
@@ -353,25 +357,23 @@ def createSubtermGraph(song, subterms):
 
        graph.add((uri, RDF.type, L9['Subterm']))
 
        graph.add((uri, RDFS.label, Literal(subterm.submaster.name)))
 
        graph.add((uri, L9['sub'], L9['sub/%s' % subterm.submaster.name]))
 
        graph.add((uri, L9['expression'], Literal(subterm.subexpr.expr)))
 
    return graph
 

	
 
def add_subterms_for_song(graph, song, curveset, subterms, root, master):
 
def add_subterms_for_song(graph, song, curveset, subterms, master):
 
    for st in graph.objects(song, L9['subterm']):
 
        try:
 
            add_one_subterm(graph, graph.value(st, L9['sub']), curveset, subterms,
 
                            root, master, graph.value(st, L9['expression']))
 
            add_one_subterm(graph, graph.value(st, L9['sub']), curveset,
 
                            subterms, master, graph.value(st, L9['expression']))
 
        except rdflib.exceptions.UniquenessError:
 
            print "working around curvecalc save corruption"
 
            # curvecalc put all the expressions on one subterm, which is wrong
 
            for expr in graph.objects(st, L9['expression']):
 
                add_one_subterm(graph, graph.value(st, L9['sub']),
 
                                curveset, subterms,
 
                                root, master,
 
                                expr)
 
                                curveset, subterms, master, expr)
 
                
 

	
 
def graphPathForSubterms(song):
 
    return showconfig.subtermsForSong(showconfig.songFilenameFromURI(song)) + ".n3"
 

	
 
def read_all_subs(graph):
 
@@ -416,17 +418,12 @@ def createHelpLines(root):
 
        line = tk.Label(root, text=helpline, font="Helvetica -12 italic",
 
                        anchor='w')
 
        line.pack(side='top',fill='x')
 

	
 

	
 
def main():
 
    root=tk.Tk()
 
    root.tk_setPalette("gray50")
 
    toplevelat("curvecalc",root)
 
    root.tk_focusFollowsMouse()
 

	
 
    parser = optparse.OptionParser()
 
    parser.set_usage("%prog [opts] songURI")
 
    parser.add_option("--sliders", action='store_true',
 
                      help='use hardware sliders')
 
    parser.add_option("--skip-music", action='store_true',
 
                      help="ignore music and smooth_music curve files")
 
@@ -436,59 +433,73 @@ def main():
 
        song = URIRef(args[0])
 
    except IndexError:
 
        raise SystemExit("song URI is required, e.g. 'http://light9.bigasterisk.com/show/dance2008/song3'")
 

	
 
    log.debug("music")
 
    music=Music()
 

	
 
    zc = Zoomcontrol(root)
 
    zc.pack(side='top',fill='x')
 

	
 
    graph = makeGraph()
 
    curveset = Curveset(sliders=opts.sliders)
 
    csv = Curvesetview(root, curveset)
 
    csv.pack(side='top',fill='both',exp=1)
 
    subterms = []
 

	
 
    subtermArea = tk.Frame(root)
 
    subtermArea.pack(side='top', fill='x')
 

	
 
    sw = tk.ScrolledWindow(subtermArea)
 
    sw.pack(fill='both')
 
    subtermScroll = tk.Frame(sw.subwidget('window'))
 
    subtermScroll.pack(fill='both')
 

	
 
    graph = makeGraph()
 

	
 
    graph.parse(graphPathForSubterms(song), format='n3')
 
    
 
    log.debug("output")
 
    out = Output(subterms, music)
 

	
 
    musicfilename = showconfig.songOnDisk(song)
 
    maxtime = wavelength(musicfilename)
 
    dispatcher.send("max time",maxtime=maxtime)
 
    dispatcher.connect(lambda: maxtime, "get max time",weak=0)
 
    dispatcher.send("show all")
 
    dispatcher.connect(lambda: maxtime, "get max time", weak=False)
 

	
 

	
 
    root=tk.Tk()
 
    root.tk_setPalette("gray50")
 
    toplevelat("curvecalc",root)
 
    root.tk_focusFollowsMouse()
 
    root.title("Curvemaster 3000MX - %s" % graph.label(song))
 

	
 
    if 'fixed top rows':
 
        zc = Zoomcontrol(root)
 
        zc.pack(side='top', fill='x')
 

	
 
    if 'panes':
 
        panes = tk.PanedWindow(root, height=1)
 
        panes.add('curvesetView')
 
        panes.add('subterms')
 
        panes.pack(side='top', fill='both', expand=True)
 

	
 
        csv = Curvesetview(panes.subwidget('curvesetView'), curveset,
 
                           height=400)
 
        csv.pack(fill='both', expand=True)
 

	
 
        subtermArea = tk.Frame(panes.subwidget('subterms'), height=100)
 
        subtermArea.pack(fill='both', expand=True)
 

	
 
        subtermScroll = tk.ScrolledWindow(subtermArea)
 
        subtermScroll.pack(fill='both')
 

	
 
    if 'fixed bottom rows':
 
        makeSubtermCommandRow(root, curveset, subterms, root, subtermArea,
 
                              graph).pack(side='top', fill='x')
 
        makeStatusLines(root)
 

	
 
        helpBox = tk.Frame(root)
 
        createHelpLines(helpBox)
 
        helpBox.pack(side='top', fill='x')
 

	
 
    add_subterms_for_song(graph, song, curveset, subterms,
 
                          subtermScroll.subwidget('window'))
 
    setupKeyBindings(root, song, subterms, curveset)
 

	
 
    # curvesetview must already exist, since this makes 'add_curve'
 
    # signals for all the initial curves
 
    curveset.load(basename=os.path.join(showconfig.curvesDir(),
 
                                        showconfig.songFilenameFromURI(song)),
 
                  skipMusic=opts.skip_music)
 

	
 
    subterms = []
 
    sub_commands_tk(root, curveset, subterms, root, subtermArea,
 
                    graph).pack(side='top',fill='both')
 

	
 
    try:
 
        graph.parse(graphPathForSubterms(song), format='n3')
 
        add_subterms_for_song(graph, song, curveset, subterms, root,
 
                              subtermScroll)
 
    except OSError, e:
 
        print e
 

	
 
    log.debug("output")
 
    out = Output(subterms, music)
 

	
 
    setupKeyBindings(root, song, subterms, curveset)
 

	
 
    create_status_lines(root)
 
    createHelpLines(root)
 
    root.title("Curvemaster 3000MX - %s" % graph.label(song))
 
    
 
    dispatcher.send("max time",maxtime=maxtime)
 
    dispatcher.send("show all")
 

	
 
    tksupport.install(root,ms=20)
 
    log.debug("run")
 
    prof.run(reactor.run, profile=False)
 

	
 
main()
light9/curve.py
Show inline comments
 
@@ -17,12 +17,15 @@ class Curve(object):
 
    """curve does not know its name. see Curveset"""
 
    points = None # x-sorted list of (x,y)
 
    def __init__(self):
 
        self.points = []
 
        self._muted = False
 

	
 
    def __repr__(self):
 
        return "<Curve (%s points)>" % len(self.points)
 

	
 
    def muted():
 
        doc = "Whether to currently send levels (boolean, obviously)"
 
        def fget(self):
 
            return self._muted
 
        def fset(self, val):
 
            self._muted = val
 
@@ -314,19 +317,19 @@ class Curveview(tk.Canvas):
 

	
 
    def current_time(self):
 
        return self._time
 

	
 
    def screen_from_world(self,p):
 
        start,end = self.zoom
 
        ht = self.winfo_height()
 
        return (p[0]-start)/(end-start)*self.winfo_width(), (ht-5)-p[1]*(ht-10)
 
        ht = self.height
 
        return (p[0]-start)/(end-start)*self.width, (ht-5)-p[1]*(ht-10)
 

	
 
    def world_from_screen(self,x,y):
 
        start,end = self.zoom
 
        ht = self.winfo_height()
 
        return x/self.winfo_width()*(end-start)+start, ((ht-5)-y)/(ht-10)
 
        ht = self.height
 
        return x/self.width*(end-start)+start, ((ht-5)-y)/(ht-10)
 
    
 
    def input_time(self, val, forceUpdate=False):
 
        # i tried various things to make this not update like crazy,
 
        # but the timeline was always missing at startup, so i got
 
        # scared that things were getting built in a funny order.        
 
        #if self._time == val:
 
@@ -347,44 +350,45 @@ class Curveview(tk.Canvas):
 
                                 pos[0] + 8, pos[1] + 8,
 
                                 outline='#800000',
 
                                 tags=('knob',))
 
                dispatcher.send("knob out", value=prevKey[1], curve=self.curve)
 
        
 
    def update_curve(self,*args):
 

	
 
        self.width, self.height = self.winfo_width(), self.winfo_height()
 
        
 
        self.zoom = dispatcher.send("zoom area")[0][1]
 
        cp = self.curve.points
 

	
 
        visible_x = (self.world_from_screen(0,0)[0],
 
                     self.world_from_screen(self.winfo_width(),0)[0])
 
                     self.world_from_screen(self.width, 0)[0])
 

	
 
        visible_idxs = self.curve.indices_between(visible_x[0], visible_x[1],
 
                                                  beyond=1)
 
        visible_points = [cp[i] for i in visible_idxs]
 
        
 
        self.delete('curve')
 

	
 
        if self.curve.muted:
 
            self['bg'] = 'grey20'
 
        else:
 
            self['bg'] = 'black'
 

	
 
        if self.winfo_height() < 40:
 
        if self.height < 40:
 
            self._draw_gradient()
 
        else:
 
            self._draw_markers(visible_x)
 
            self._draw_line(visible_points)
 

	
 
            self.dots = {} # idx : canvas rectangle
 

	
 
            if len(visible_points)<50:
 
                self._draw_handle_points(visible_idxs,visible_points)
 

	
 
    def _draw_gradient(self):
 
        gradient_res = 3
 
        for x in range(0,self.winfo_width(),gradient_res):
 
        for x in range(0, self.width, gradient_res):
 
            wx = self.world_from_screen(x,0)[0]
 
            mag = self.curve.eval(wx, allow_muting=False)
 
            if self.curve.muted:
 
                low = (8, 8, 8)
 
                high = (60, 60, 60)
 
            else:
 
@@ -409,17 +413,17 @@ class Curveview(tk.Canvas):
 
            endtime = endtimes[0][1]
 
            mark(endtime,"end %.1f"%endtime)
 
            mark(endtime+10,"post %.1f"%(endtime+10))
 
        
 
    def _draw_one_marker(self,t,label):
 
        x = self.screen_from_world((t,0))[0]
 
        ht = self.winfo_height()
 
        ht = self.height
 
        self.create_line(x,ht,x,ht-20, fill='white',
 
                         tags=('curve',))
 
        self.create_text(x,ht-20,text=label,anchor='s', fill='white',
 
                         tags=('curve',))
 
                         font="arial 7", tags=('curve',))
 

	
 

	
 
    def _draw_line(self,visible_points):
 
        linepts=[]
 
        step=1
 
        linewidth=2
 
@@ -599,12 +603,13 @@ class Sliders(BCF2000):
 
            self.knobCallback(int(name[4:]), value / 127)
 
        if name.startswith("button-knob"):
 
            self.knobButtonCallback(int(name[11:]))
 

	
 
        
 
class Curveset:
 
    
 
    curves = None # curvename : curve
 
    def __init__(self, sliders=False):
 
        """sliders=True means support the hardware sliders"""
 
        self.curves = {} # name : Curve
 
        self.curveName = {} # reverse
 
        self.sliderCurve = {} # slider number (1 based) : curve name
 
@@ -619,23 +624,27 @@ class Curveset:
 
            self.sliderIgnoreInputUntil = {}
 
        else:
 
            self.sliders = None
 
        
 
    def load(self,basename, skipMusic=False):
 
        """find all files that look like basename-curvename and add
 
        curves with their contents"""
 
        curves with their contents
 

	
 
        This fires 'add_curve' dispatcher events to announce the new curves.
 
        """
 
        def sorter(name):
 
            return not name.endswith('music'), name
 
        for filename in sorted(glob.glob("%s-*"%basename), key=sorter):
 
            curvename = filename[filename.rfind('-')+1:]
 
            if skipMusic and curvename in ['music', 'smooth_music']:
 
                continue
 
            c=Curve()
 
            c.load(filename)
 
            curvename = curvename.replace('-','_')
 
            self.add_curve(curvename,c)            
 
            self.add_curve(curvename,c)
 
            
 
    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))
 
            
 
@@ -726,128 +735,126 @@ class Curveset:
 
        except KeyError:
 
            return
 
        self.sliders.valueOut("knob%s" % num, value * 127)
 

	
 
class CurveRow(tk.Frame):
 
    """
 
    one of the repeating curve rows
 
    one of the repeating curve rows (including widgets on the left)
 
    """
 
    def __init__(self, master, name, curve, slider, knobEnabled):
 
        tk.Frame.__init__(self, master, relief='raised', bd=1)
 

	
 
        self.collapsed = tk.IntVar()
 
        self.muted = tk.IntVar()
 

	
 
        labelFont = "arial 8"
 

	
 
        leftside = tk.Frame(self)
 
        leftside.pack(side='left')
 

	
 
        collapsed = tk.IntVar()
 
        self.curveView = Curveview(self, curve, knobEnabled=knobEnabled)
 
        self.curveView.pack(side='left', fill='both', expand=True)
 
        self.curveView.config(height=100)
 

	
 
        txt = "curve '%s'" % name
 
        if len(name) > 7:
 
            txt = name
 
        curve_name_label = tk.Label(leftside,text=txt,font=labelFont,
 
                 width=15)
 
        curve_name_label = tk.Label(leftside, text=txt, font=labelFont,width=15)
 
        curve_name_label.pack(side='left')
 

	
 
        sliderLabel = None
 

	
 
        collapsed_cb = tk.Checkbutton(leftside, text="C",
 
                       font=labelFont, variable=collapsed)
 
                                      font=labelFont, variable=self.collapsed)
 
        collapsed_cb.pack(side='left')
 

	
 
        def toggleCollapsed():
 
            collapsed.set(not collapsed.get())
 

	
 
        self.collapsed.trace('w', self.update_ui_to_collapsed_state)
 
        dispatcher.connect(self.toggleCollapsed, "toggle collapse",
 
                           sender=curve)
 

	
 
        def update_ui_to_collapsed_state(*args):
 
            if collapsed.get():
 
                if sliderLabel:
 
                    sliderLabel.pack_forget()
 
                self.pack(exp=0)
 
            else:
 
                if sliderLabel:
 
                    sliderLabel.pack(side='left')
 
                self.pack(exp=1)
 
        collapsed.trace('w', update_ui_to_collapsed_state)
 
        self.default_bg = leftside['bg']
 
        muted_cb = tk.Checkbutton(leftside, text="M", font=labelFont,
 
                                  variable=self.muted)
 
        muted_cb.pack(side='left')
 
        self.muted.trace('w', self.sync_mute_to_curve)
 
        dispatcher.connect(self.mute_changed, 'mute changed', sender=curve)
 

	
 

	
 
        muted = tk.IntVar()
 
        default_bg = leftside['bg']
 
        muted_cb = tk.Checkbutton(leftside, text="M", font=labelFont,
 
                       variable=muted)
 
        muted_cb.pack(side='left')
 

	
 
        self.sliderLabel = None
 
        if slider is not None:
 
            # slider should have a checkbutton, defaults to off for
 
            # music tracks
 
            sliderLabel = tk.Label(leftside, text="Slider %s" % slider,
 
                                   fg='#800000', font=labelFont)
 
            sliderLabel.pack(side='left')
 
            self.sliderLabel = tk.Label(leftside, text="Slider %s" % slider,
 
                                        fg='#800000', font=labelFont)
 
            self.sliderLabel.pack(side='left')
 

	
 
        cv = Curveview(self, curve,
 
                       knobEnabled=knobEnabled)
 
        cv.pack(side='left',fill='both',exp=1)
 
        # widgets that need recoloring when we tint the row:
 
        self.widgets = [leftside, collapsed_cb, muted_cb,
 
                        curve_name_label, self]
 
        if self.sliderLabel:
 
            self.widgets.append(self.sliderLabel)
 

	
 
        def sync_mute_to_curve(*args):
 
            """send value from Tk var to the master attribute inside Curve"""
 
            new_mute = muted.get()
 
            old_mute = cv.curve.muted
 
            if new_mute == old_mute:
 
                return
 
    def toggleCollapsed(self):
 
        self.collapsed.set(not self.collapsed.get())
 

	
 
            cv.curve.muted = new_mute
 

	
 
        muted.trace('w', sync_mute_to_curve)
 
    def update_ui_to_collapsed_state(self, *args):
 
        if self.collapsed.get():
 
            if self.sliderLabel:
 
                self.sliderLabel.pack_forget()
 
            self.curveView.config(height=25)
 
        else:
 
            if self.sliderLabel:
 
                self.sliderLabel.pack(side='left')
 
            self.curveView.config(height=100)
 

	
 
        def update_mute_look():
 
            if muted.get():
 
                new_bg = 'grey20'
 
            else:
 
                new_bg = default_bg
 
    def sync_mute_to_curve(self, *args):
 
        """send value from Tk var to the master attribute inside Curve"""
 
        new_mute = self.muted.get()
 
        old_mute = self.curveView.curve.muted
 
        if new_mute == old_mute:
 
            return
 

	
 
        self.curveView.curve.muted = new_mute
 

	
 
            widgets = [leftside, collapsed_cb, muted_cb, curve_name_label, self]
 
            if sliderLabel:
 
                widgets.append(sliderLabel)
 
            for widget in widgets:
 
                widget['bg'] = new_bg
 
    def update_mute_look(self):
 
        """set colors on the widgets in the row according to self.muted.get()"""
 
        if self.muted.get():
 
            new_bg = 'grey20'
 
        else:
 
            new_bg = self.default_bg
 

	
 
        def mute_changed():
 
            muted.set(cv.curve.muted)
 
            update_mute_look()
 
        for widget in self.widgets:
 
            widget['bg'] = new_bg
 

	
 
        dispatcher.connect(mute_changed, 'mute changed', sender=cv.curve,
 
                           weak=False)
 

	
 
        dispatcher.connect(toggleCollapsed, "toggle collapse", sender=cv.curve,
 
                           weak=False)
 
    def mute_changed(self):
 
        """call this if curve.muted changed"""
 
        self.muted.set(self.curveView.curve.muted)
 
        self.update_mute_look()
 

	
 

	
 
class Curvesetview(tk.Frame):
 
class Curvesetview(tk.ScrolledWindow):
 
    def __init__(self, master, curveset, **kw):
 
        self.curves = {} # curvename : Curveview
 
        self.curveset = curveset
 
        tk.Frame.__init__(self,master,**kw)
 
        tk.ScrolledWindow.__init__(self,master,**kw)
 
        
 
        f = tk.Frame(self,relief='raised',bd=1)
 
        f = tk.Frame(self.window,relief='raised',bd=1)
 
        f.pack(side='top',fill='x')
 
        tk.Label(f, text="new curve named: (C-N)").pack(side='left')
 
        
 
        self.newcurvename = tk.StringVar()
 

	
 
        def new_curve(event):
 
            self.curveset.new_curve(self.newcurvename.get())
 
            self.newcurvename.set('')
 
        
 
        entry = tk.Entry(f, textvariable=self.newcurvename)
 
        entry.pack(side='left', fill='x',exp=1)        
 
        entry.bind("<Key-Return>", new_curve)
 
        entry.bind("<Key-Return>", self.new_curve)
 

	
 
        def focus_entry():
 
            entry.focus()
 
        
 
        dispatcher.connect(self.add_curve, "add_curve", sender=self.curveset)
 
        dispatcher.connect(focus_entry, "focus new curve", weak=False)
 

	
 
    def new_curve(self, event):
 
        self.curveset.new_curve(self.newcurvename.get())
 
        self.newcurvename.set('')
 
        
 
    def add_curve(self, name, slider=None, knobEnabled=False):
 
        curve = self.curveset.curves[name]
 
        f = CurveRow(self, name, curve, slider, knobEnabled)
 
        f.pack(side='top',fill='both',exp=1)
 
        f = CurveRow(self.window, name, curve, slider, knobEnabled)
 
        f.pack(side='top', fill='both')
 

	
light9/zoomcontrol.py
Show inline comments
 
@@ -170,14 +170,14 @@ class Zoomcontrol(object,tk.Canvas):
 
            if 0<x<self.winfo_width() and x-lastx>30:
 
                txt=str(t)
 
                if lastx==-1000:
 
                    txt=txt+"sec"
 
                self.create_line(x,0,x,15,
 
                                 tags=('tics',))
 
                self.create_text(x,self.winfo_height()-1,anchor='s',
 
                                 text=txt,tags=('tics',),font='6x13')
 
                self.create_text(x, self.winfo_height()-1, anchor='s',
 
                                 text=txt, tags=('tics',), font='arial 7')
 
                lastx = x
 

	
 

	
 
class RegionZoom:
 
    """rigs c-a-b1 to drag out an area to zoom to. also catches other types of drag events, like b1 drag for selecting points
 

	
0 comments (0 inline, 0 general)