Changeset - 8fba62df5e39
[Not reviewed]
default
0 1 0
Drew Perttula - 13 years ago 2012-06-14 06:24:39
drewp@bigasterisk.com
selectmanip more controls, hover highlight
Ignore-this: fec790c4c895a987fbd6bcf8dbc836e1
1 file changed with 140 insertions and 20 deletions:
0 comments (0 inline, 0 general)
light9/curvecalc/curveview.py
Show inline comments
 
@@ -77,7 +77,7 @@ class SelectManip(object):
 
    draws itself on the canvas and edits the points when you drag
 
    various parts
 
    """
 
    def __init__(self, parent, getSelectedIndices, getWorldPoint, getScreenPoint, getCanvasSize, setPoints, getWorldTime):
 
    def __init__(self, parent, getSelectedIndices, getWorldPoint, getScreenPoint, getCanvasSize, setPoints, getWorldTime, getWorldValue, getDragRange):
 
        """parent goocanvas group"""
 
        self.getSelectedIndices = getSelectedIndices
 
        self.getWorldPoint = getWorldPoint
 
@@ -85,39 +85,112 @@ class SelectManip(object):
 
        self.getCanvasSize = getCanvasSize
 
        self.setPoints = setPoints
 
        self.getWorldTime = getWorldTime
 
        self.getDragRange = getDragRange
 
        self.getWorldValue = getWorldValue
 
        self.grp = goocanvas.Group(parent=parent)
 
        
 
        self.title = goocanvas.Text(parent=self.grp, text="selectmanip", x=10, y=10, fill_color='white', font="ubuntu 10")
 

	
 
        self.bbox = goocanvas.Rect(parent=self.grp,
 
                                   stroke_color='yellow',
 
                                   fill_color_rgba=0xffff0030,
 
                                   line_width=.7)
 
                                   line_width=0)
 

	
 
        self.xTrans = goocanvas.Polyline(parent=self.grp, close_path=True,
 
                                         fill_color_rgba=0xffffff88,
 
                                         )
 
        self.xTrans.connect("button-press-event", self.onXPress)
 
        self.xTrans.connect("button-release-event", self.onXRelease)
 
        self.xTrans.connect("motion-notify-event", self.onXMotion)
 
        self.centerScale = goocanvas.Polyline(parent=self.grp, close_path=True,
 
                                              fill_color_rgba=0xffffff88,
 
                                         )
 

	
 
        thickLine = lambda: goocanvas.Polyline(parent=self.grp,
 
                                               stroke_color_rgba=0xffffccff,
 
                                               line_width=6)
 
        self.leftScale = thickLine()
 
        self.rightScale = thickLine()
 
        self.topScale = thickLine()
 
        
 
        for grp, name in [(self.xTrans, 'x'),
 
                          (self.leftScale, 'left'),
 
                          (self.rightScale, 'right'),
 
                          (self.topScale, 'top'),
 
                          (self.centerScale, 'centerScale'),
 
                          ]:
 
            grp.connect("button-press-event", self.onPress, name)
 
            grp.connect("button-release-event", self.onRelease, name)
 
            grp.connect("motion-notify-event", self.onMotion, name)
 
            grp.connect("enter-notify-event", self.onEnter, name)
 
            grp.connect("leave-notify-event", self.onLeave, name)
 
            # and hover highlight
 
        self.update()
 

	
 
    def onXPress(self, item, target_item, event):
 
    def onEnter(self, item, target_item, event, param):
 
        self.prevColor = item.props.stroke_color_rgba
 
        item.props.stroke_color_rgba = 0xff0000ff
 
        
 
    def onLeave(self, item, target_item, event, param):
 
        item.props.stroke_color_rgba = self.prevColor
 
        
 
    def onPress(self, item, target_item, event, param):
 
        self.dragStartTime = self.getWorldTime(event.x)
 
        self.origPoints = [self.getWorldPoint(i) for i in
 
                           self.getSelectedIndices()]
 
        idxs = self.getSelectedIndices()
 

	
 
        self.origPoints = [self.getWorldPoint(i) for i in idxs]
 
        self.origMaxValue = max(p[1] for p in self.origPoints)
 
        moveLeft, moveRight = self.getDragRange(idxs)
 

	
 
        if param == 'centerScale':
 
            self.maxPointMove = min(moveLeft, moveRight)
 
        
 
        self.dragRange = (self.dragStartTime - moveLeft,
 
                          self.dragStartTime + moveRight)
 
        return True
 

	
 
    def onXMotion(self, item, target_item, event):
 
    def onMotion(self, item, target_item, event, param):
 
        if hasattr(self, 'dragStartTime'):
 
            dt = self.getWorldTime(event.x) - self.dragStartTime
 
            self.setPoints(
 
                (i, (orig[0] + dt, orig[1]))
 
                for i, orig in zip(self.getSelectedIndices(), self.origPoints))
 
            
 
            origPts = zip(self.getSelectedIndices(), self.origPoints)
 
            left = origPts[0][1][0]
 
            right = origPts[-1][1][0]
 
            width = right - left
 

	
 
            clampLo = left if param == 'right' else self.dragRange[0]
 
            clampHi = right if param == 'left' else self.dragRange[1]
 

	
 
            mouseT = self.getWorldTime(event.x)
 
            clampedT = max(clampLo, min(clampHi, mouseT))
 
            dt = clampedT - self.dragStartTime
 

	
 
    def onXRelease(self, item, target_item, event):
 
        del self.dragStartTime
 
            if param == 'x':
 
                self.setPoints((i, (orig[0] + dt, orig[1]))
 
                               for i, orig in origPts)
 
            elif param == 'left':
 
                self.setPoints((i, (left + dt +
 
                                    (orig[0] - left) / width * (width - dt),
 
                                    orig[1])) for i, orig in origPts)
 
            elif param == 'right':
 
                self.setPoints((i, (left +
 
                                    (orig[0] - left) / width * (width + dt),
 
                                    orig[1])) for i, orig in origPts)
 
            elif param == 'top':
 
                v = self.getWorldValue(event.y)
 
                scl = max(0, min(1 / self.origMaxValue, v / self.origMaxValue))
 
                self.setPoints((i, (orig[0], orig[1] * scl))
 
                               for i, orig in origPts)
 

	
 
            elif param == 'centerScale':
 
                dt = mouseT - self.dragStartTime
 
                rad = width / 2
 
                tMid = left + rad
 
                maxScl = (rad + self.maxPointMove) / rad
 
                newWidth = max(0, min((rad + dt) / rad, maxScl)) * width
 
                self.setPoints((i,
 
                                (tMid +
 
                                 ((orig[0] - left) / width - .5) * newWidth,
 
                                 orig[1])) for i, orig in origPts)
 
                
 

	
 
    def onRelease(self, item, target_item, event, param):
 
        if hasattr(self, 'dragStartTime'):
 
            del self.dragStartTime
 

	
 
    def update(self):
 
        """if the view or selection or selected point positions
 
@@ -133,14 +206,40 @@ class SelectManip(object):
 
        b.height = min(max(p[1] for p in pts) - b.y + margin,
 
                       self.getCanvasSize().height - b.y - 1)
 

	
 
        b.visibility = goocanvas.ITEM_VISIBLE if len(pts) > 1 else goocanvas.ITEM_HIDDEN
 
        multi = (goocanvas.ITEM_VISIBLE if len(pts) > 1 else
 
                 goocanvas.ITEM_INVISIBLE)
 
        b.visibility = multi
 
        self.leftScale.props.visibility = multi
 
        self.rightScale.props.visibility = multi
 
        self.topScale.props.visibility = multi
 
        self.centerScale.props.visibility = multi
 

	
 
        self.title.props.text = "%s %s selected" % (
 
            len(idxs), "point" if len(idxs) == 1 else "points")
 

	
 
        centerX = b.x + b.width / 2
 

	
 
        midY = self.getCanvasSize().height / 2
 
        midY = self.getCanvasSize().height * .5
 
        loY = self.getCanvasSize().height * .8
 

	
 
        self.leftScale.props.points = goocanvas.Points([
 
            (b.x, b.y), (b.x, b.y + b.height)])
 
        self.rightScale.props.points = goocanvas.Points([
 
            (b.x + b.width, b.y), (b.x + b.width, b.y + b.height)])
 

	
 
        self.topScale.props.points = goocanvas.Points([
 
            (b.x, b.y), (b.x + b.width, b.y)])
 

	
 
        self.updateXTrans(centerX, midY)
 

	
 
        self.centerScale.props.points = goocanvas.Points([
 
            (centerX - 5, loY - 5),
 
            (centerX + 5, loY - 5),
 
            (centerX + 5, loY + 5),
 
            (centerX - 5, loY + 5)])
 
            
 

	
 
    def updateXTrans(self, centerX, midY):       
 
        x1 = centerX - 30
 
        x2 = centerX - 20
 
        x3 = centerX + 20
 
@@ -375,12 +474,14 @@ class Curveview(object):
 
        if self.selected_points and not self.selectManip:
 
            self.selectManip = SelectManip(
 
                self.root,
 
                getSelectedIndices=lambda: self.selected_points,
 
                getSelectedIndices=lambda: sorted(self.selected_points),
 
                getWorldPoint=lambda i: self.curve.points[i],
 
                getScreenPoint=lambda i: self.screen_from_world(self.curve.points[i]),
 
                getWorldTime=lambda x: self.world_from_screen(x, 0)[0],
 
                getWorldValue=lambda y: self.world_from_screen(0, y)[1],
 
                getCanvasSize=lambda: self.size,
 
                setPoints=self.setPoints,
 
                getDragRange=self.getDragRange,
 
                )
 
        if not self.selected_points and self.selectManip:
 
            self.selectManip.destroy()
 
@@ -388,6 +489,25 @@ class Curveview(object):
 

	
 
        self.selectionChanged()
 

	
 
    def getDragRange(self, idxs):
 
        """if you're dragging these points, what's the most time you
 
        can move left and right before colliding with another point"""
 
        maxLeft = maxRight = 99999
 
        cp = self.curve.points
 
        for i in idxs:
 
            nextStatic = i
 
            while nextStatic >= 0 and nextStatic in idxs:
 
                nextStatic -= 1
 
            if nextStatic >= 0:
 
                maxLeft = min(maxLeft, cp[i][0] - cp[nextStatic][0])
 

	
 
            nextStatic = i
 
            while nextStatic <= len(cp) - 1 and nextStatic in idxs:
 
                nextStatic += 1
 
            if nextStatic <= len(cp) - 1:
 
                maxRight = min(maxRight, cp[nextStatic][0] - cp[i][0])
 
        return maxLeft, maxRight
 

	
 
    def setPoints(self, updates):
 
        for i, pt in updates:
 
            self.curve.points[i] = pt
0 comments (0 inline, 0 general)