Пример #1
0
 def __init__(self, part,\
                    controller=None,\
                    parent=None):
     super(PathHelixGroup, self).__init__(parent)
     # Subviews, GraphicsItem business
     self.rect = QRectF()  # Set by _set_pathHelixList
     self._label=None; self.label()  # Poke the cache so the label actually exists
     
     # Properties
     self._pathHelixList = []  # Primary property
     self._part = None; self.setPart(part)
     self._controller = controller
     self._activeSliceHandle = ActiveSliceHandle(self)
     self._stapColor = QColor(0, 72, 0)
     self._stapPen = QPen(self._stapColor, 2)
     self.activeHelix = None
     self.loopHandleGroup = LoopHandleGroup(parent=self)
     self.xoverGet = XoverHandle()
     self.setZValue(styles.ZPATHHELIXGROUP)
     
     self.phhSelectionGroup = SelectionItemGroup(\
                                      boxtype=PathHelixHandleSelectionBox,\
                                      constraint='y',\
                                      parent=self)
     self.selectionLock = None
     app().phg = self  # Convenience for the command line -i mode
Пример #2
0
class PathHelixGroup(QGraphicsObject):
    """
    PathHelixGroup maintains data and state for a set of object that provide
    an interface to the schematic view of a DNA part. These objects include
    the PathHelix, PathHelixHandles, and ActiveSliceHandle.
    """
    handleRadius = styles.SLICE_HELIX_RADIUS
    _scafColor = QColor(0, 102, 204)
    _scafPen = QPen(_scafColor, 2)
    _nobrush = QBrush(Qt.NoBrush)
    
    def __init__(self, part,\
                       controller=None,\
                       parent=None):
        super(PathHelixGroup, self).__init__(parent)
        # Subviews, GraphicsItem business
        self.rect = QRectF()  # Set by _set_pathHelixList
        self._label=None; self.label()  # Poke the cache so the label actually exists
        
        # Properties
        self._pathHelixList = []  # Primary property
        self._part = None; self.setPart(part)
        self._controller = controller
        self._activeSliceHandle = ActiveSliceHandle(self)
        self._stapColor = QColor(0, 72, 0)
        self._stapPen = QPen(self._stapColor, 2)
        self.activeHelix = None
        self.loopHandleGroup = LoopHandleGroup(parent=self)
        self.xoverGet = XoverHandle()
        self.setZValue(styles.ZPATHHELIXGROUP)
        
        self.phhSelectionGroup = SelectionItemGroup(\
                                         boxtype=PathHelixHandleSelectionBox,\
                                         constraint='y',\
                                         parent=self)
        self.selectionLock = None
        app().phg = self  # Convenience for the command line -i mode

    def __str__(self):
        return "I am a PHG!"

    def part(self):
        return self._part

    def activeTool(self):
        return controller().activeTool()
    
    def activeHelix(self):
        return self.activeHelix
    
    def setActiveHelix(self, newActivePH):
        neighborVHs = newActivePH.vhelix().neighbors()
        for ph in self._pathHelixList:
            showHandles = ph==newActivePH or ph.vhelix() in neighborVHs
            ph.setPreXOverHandlesVisible(showHandles)

    def setPart(self, newPart):
        if self._part:
            self._part.selectionWillChange.disconnect(self.selectionWillChange)
        newPart.selectionWillChange.connect(self.selectionWillChange)
        self._part = newPart
        if newPart:
            self.selectionWillChange(newPart.selection())

    def controller(self):
        return self._controller

    def activeSliceHandle(self):
        return self._activeSliceHandle

    def label(self):
        if self._label:
            return self._label
        font = QFont("Times", 30, QFont.Bold)
        label = QGraphicsTextItem("Part 1")
        label.setVisible(False)
        label.setFont(font)
        label.setParentItem(self)
        label.setPos(0, -40)
        label.setTextInteractionFlags(Qt.TextEditorInteraction)
        label.inputMethodEvent = None
        self._label = label
        return label

    def displayedVHs(self):
        """Returns the list (ordered top to bottom) of VirtualHelix
        that the receiver is displaying"""
        return [ph.vhelix() for ph in self._pathHelixList]

    displayedVHsChanged = pyqtSignal()
    def setDisplayedVHs(self, vhrefs):
        """Spawns or destroys PathHelix such that displayedVHs
        has the same VirtualHelix in the same order as vhrefs
        (though displayedVHs always returns a list of VirtualHelix
        while setDisplayedVHs can take any vhref)"""
        assert(self.part())  # Can't display VirtualHelix that aren't there!
        new_pathHelixList = []
        vhToPH = dict(((ph.vhelix(), ph) for ph in self._pathHelixList))
        for vhref in vhrefs:
            vh = self.part().getVirtualHelix(vhref)
            ph = vhToPH.get(vh, None)
            if ph == None:
                ph = PathHelix(vh, self)
            new_pathHelixList.append(ph)
        self._set_pathHelixList(new_pathHelixList)
        self.displayedVHsChanged.emit()

    def __pathHelixList(self):
        return self._pathHelixList

    def _set_pathHelixList(self, newList):
        """Give me a list of PathHelix and I'll parent them
        to myself if necessary, position them in a column, adopt
        their handles, and position them as well."""
        y = 0  # How far down from the top the next PH should be
        leftmostExtent = 0
        rightmostExtent = 0
        self.label().setVisible(True)
        for ph in self._pathHelixList:
            if not ph in newList:
                ph.handle().setParentItem(None)
                ph.setParentItem(None)
        for ph in newList:
            ph.setParentItem(self)
            ph.setPos(0, y)
            ph_height = ph.boundingRect().height()
            step = ph_height + styles.PATH_HELIX_PADDING
            phh = ph.handle()
            phh.setParentItem(self)
            phhr = phh.boundingRect()
            phh.setPos(-2 * phhr.width(), y + (ph_height - phhr.height()) / 2)
            leftmostExtent = min(leftmostExtent, -2 * phhr.width())
            rightmostExtent = max(rightmostExtent, ph.boundingRect().width())
            y += step
        # end for
        self.prepareGeometryChange()
        self.geometryChanged.emit()
        self.rect = QRectF(leftmostExtent,\
                           -40,\
                           -leftmostExtent + rightmostExtent,\
                           y + 40)
        self._pathHelixList = newList
        self.vhToPathHelix = dict(((ph.vhelix(), ph) for ph in newList))
        self.scene().views()[0].zoomToFit()

    def paint(self, painter, option, widget=None):
        # painter.save()
        painter.setBrush(self._nobrush)
        self.drawXovers(painter)
        # painter.restore()

    def drawXovers(self, painter):
        """Return a QPainterPath ready to paint the crossovers"""
        for ph in self._pathHelixList:
            painter.setPen(self._scafPen)
            for ((fromhelix, fromindex), (tohelix, toindex)) in \
                             ph.vhelix().get3PrimeXovers(StrandType.Scaffold):
                path = self.xoverGet.getXover(self,\
                                              StrandType.Scaffold,\
                                              ph,\
                                              fromindex,\
                                              self.getPathHelix(tohelix),\
                                              toindex)
                painter.drawPath(path)
            # end for
            painter.setPen(self._stapPen)
            for ((fromhelix, fromindex), (tohelix, toindex)) in \
                               ph.vhelix().get3PrimeXovers(StrandType.Staple):
                path = self.xoverGet.getXover(self,\
                                              StrandType.Staple,\
                                              ph,\
                                              fromindex,\
                                              self.getPathHelix(tohelix),\
                                              toindex)
                color = ph.vhelix().colorOfBase(StrandType.Staple, fromindex)
                self._stapPen.setColor(QColor(color))
                painter.drawPath(path)
            # end for
        # end for
    # end def

    geometryChanged = pyqtSignal()

    def boundingRect(self):
        # rect set only by _set_pathHelixList
        return self.rect

    def moveHelixNumToIdx(self, num, idx):
        """Reinserts helix with number() num such that
        it's at position idx in _pathHelixList"""
        vhs = [vh.number() for vh in self.displayedVHs()]
        vhs.remove(num)
        vhs.insert(idx, num)
        self.setDisplayedVHs(vhs)

    def zoomToFit(self):
        # Auto zoom to center the scene
        thescene = self.scene()
        theview = thescene.views()[0]
        theview.zoomToFit()

    @pyqtSlot(int)
    def helixAddedSlot(self, vhref):
        vhs = self.displayedVHs()
        if vhref in vhs:
            return
        vhs.append(vhref)
        self.setDisplayedVHs(vhs)

    @pyqtSlot(int)
    def helixRemovedSlot(self, vh):
        vhs = self.displayedVHs()
        if not vhref in vhs:
            return
        vhs.remove(vh)
        self.setDisplayedVHs(vh)

    # Slot called when the slice view's (actually the part's) selection changes
    def selectionWillChange(self, newSelection):
        self.setDisplayedVHs(newSelection)

    def getPathHelix(self, vhref):
        """Given the helix number, return a reference to the PathHelix."""
        vh = self.part().getVirtualHelix(vhref)
        for ph in self._pathHelixList:
            if ph.vhelix() == vh:
                return ph
        return None

    def reorderHelices(self, first, last, indexDelta):
        """
        Reorder helices by moving helices _pathHelixList[first:last]
        by a distance delta in the list. Notify each PathHelix and
        PathHelixHandle of its new location.
        """
        vhs = self.displayedVHs()
        vhsToMove = vhs[first:last]
        del vhs[first:last]
        self.setDisplayedVHs(vhs[0:first + indexDelta] +\
                            vhsToMove + vhs[first + indexDelta:-1])