Пример #1
0
    def draw_text(self, txt, txtlen, window):
        if ((txtlen>0) and not ((txt == self.cursor_char) and (self._cursor_visible == False))): # If there IS something to print
            if (self.pbuffer_painter[window.id] == None):
                self.brush.setColor(self.ztoq_color[self.cur_bg])
                self.pbuffer_painter[window.id] = QPainter(self.pbuffer[window.id])
                self.pbuffer_painter[window.id].setPen(self.ztoq_color[self.cur_fg])
                self.pbuffer_painter[window.id].setBackground(self.brush)

            painter = self.pbuffer_painter[window.id]

            # @type window ZWindow
            if (window.cursor == None):
                if (window.id == 0): # Main window
                    window.set_cursor_position(1, self.height)
                    window.set_cursor_real_position(2, self.height*(self.linesize-1))
                else:
                    window.set_cursor_position(1, 1)
                    window.set_cursor_real_position(2, self.linesize-1)

            if (txt=='\n'):
                if (window.cursor[1]==self.height):
                    if (window.scrolling):
                        self.scroll(painter)
                    window.set_cursor_position(1, window.cursor[1])
                    window.set_cursor_real_position(2, window.cursor_real_pos[1])
                else:
                    window.set_cursor_position(1, window.cursor[1]+1)
                    window.set_cursor_real_position(2, window.cursor_real_pos[1]+self.linesize)
            else:
                rect = QRectF(window.cursor_real_pos[0], window.cursor_real_pos[1], self.pbuffer[window.id].width()-window.cursor_real_pos[0], self.linesize)

                painter.setFont(self.font())
                #painter.setRenderHint(QPainter.TextAntialiasing)
                if (self._input_buffer_printing == False):
                    painter.setBackgroundMode(Qt.OpaqueMode)
                else:
                    painter.setBackgroundMode(Qt.TransparentMode)
                bounding_rect = painter.boundingRect(rect,txt)
                if (rect.contains(bounding_rect)):
                    #print rect.x(), rect.y(), rect.width(),rect.height(), txt, bounding_rect
                    painter.drawText(bounding_rect, txt)
                    if txt != self.cursor_char:
                        window.set_cursor_position(window.cursor[0]+txtlen, window.cursor[1])
                        window.set_cursor_real_position(rect.x()+bounding_rect.width(), rect.y())
                else: # There is not enough space
                    #print "Not enough space to print:", txt
                    self.scroll(painter)
                    window.set_cursor_position(1, self.height)
                    window.set_cursor_real_position(2, self.height*(self.linesize-1))
                    rect.setX(2)
                    rect.setY(window.cursor_real_pos[1])
                    rect.setWidth(self.pbuffer[window.id].width()-window.cursor_real_pos[0])
                    rect.setHeight(self.linesize)
                    bounding_rect = painter.boundingRect(rect,txt)
                    painter.drawText(bounding_rect, txt)
                    if txt != self.cursor_char:
                        window.set_cursor_position(window.cursor[0]+txtlen, window.cursor[1])
                        window.set_cursor_real_position(rect.x()+bounding_rect.width(), rect.y())
Пример #2
0
 def clean_input_buffer_from_screen(self):
     rect = QRectF()
     rect.setX(self.lastwindow.cursor_real_pos[0])
     rect.setY(self.lastwindow.cursor_real_pos[1])
     rect.setWidth(self.pbuffer[0].width()-self.lastwindow.cursor_real_pos[0]+1)
     rect.setHeight(self.linesize)
     txtbuffer = ''
     for w in self.input_buf:
         txtbuffer += w
     bounding_rect = self.pbuffer_painter[0].boundingRect(rect, txtbuffer)
     if (rect.contains(bounding_rect)): # string fits in this line
         self.pbuffer_painter[0].eraseRect(bounding_rect)
         #self.pbuffer_painter.drawRect(bounding_rect)
         #print 'Erasing rect', bounding_rect
     else:
         self.pbuffer_painter[0].eraseRect(rect)
Пример #3
0
class CanvasPreviewFrame(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self, parent)

        self.fUseCustomPaint = False

        self.fMouseDown = False

        self.fViewBg    = QColor(0, 0, 0)
        self.fViewBrush = QBrush(QColor(75, 75, 255, 30))
        self.fViewPen   = QPen(Qt.blue, 1)

        self.fScale = 1.0
        self.fScene = None
        self.fRealParent = None
        self.fFakeWidth  = 0.0
        self.fFakeHeight = 0.0

        self.fRenderSource = self.getRenderSource()
        self.fRenderTarget = QRectF(0, 0, 0, 0)

        self.fViewPadX = 0.0
        self.fViewPadY = 0.0
        self.fViewRect = [0.0, 0.0, 10.0, 10.0]

    def init(self, scene, realWidth, realHeight, useCustomPaint = False):
        padding = 6

        self.fScene = scene
        self.fFakeWidth  = float(realWidth) / 15
        self.fFakeHeight = float(realHeight) / 15

        self.setMinimumSize(self.fFakeWidth+padding,   self.fFakeHeight+padding)
        self.setMaximumSize(self.fFakeWidth*4+padding, self.fFakeHeight+padding)

        self.fRenderTarget.setWidth(realWidth)
        self.fRenderTarget.setHeight(realHeight)

        if self.fUseCustomPaint != useCustomPaint:
            self.fUseCustomPaint = useCustomPaint
            self.repaint()

    def setRealParent(self, parent):
        self.fRealParent = parent

    def getRenderSource(self):
        xPadding = (float(self.width())  - self.fFakeWidth) / 2.0
        yPadding = (float(self.height()) - self.fFakeHeight) / 2.0
        return QRectF(xPadding, yPadding, self.fFakeWidth, self.fFakeHeight)

    def setViewPosX(self, xp):
        x = self.fFakeWidth*xp
        xRatio = (x / self.fFakeWidth) * self.fViewRect[iWidth] / self.fScale
        self.fViewRect[iX] = x - xRatio + self.fRenderSource.x()
        self.update()

    def setViewPosY(self, yp):
        y = self.fFakeHeight*yp
        yRatio = (y / self.fFakeHeight) * self.fViewRect[iHeight] / self.fScale
        self.fViewRect[iY] = y - yRatio + self.fRenderSource.y()
        self.update()

    def setViewScale(self, scale):
        self.fScale = scale
        QTimer.singleShot(0, self.fRealParent, SLOT("slot_miniCanvasCheckAll()"))

    def setViewSize(self, width, height):
        self.fViewRect[iWidth]  = width  * self.fFakeWidth
        self.fViewRect[iHeight] = height * self.fFakeHeight
        self.update()

    def setViewTheme(self, bgColor, brushColor, penColor):
        brushColor.setAlpha(40)
        penColor.setAlpha(100)
        self.fViewBg    = bgColor
        self.fViewBrush = QBrush(brushColor)
        self.fViewPen   = QPen(penColor, 1)

    def handleMouseEvent(self, eventX, eventY):
        x = float(eventX) - self.fRenderSource.x() - (self.fViewRect[iWidth]  / self.fScale / 2)
        y = float(eventY) - self.fRenderSource.y() - (self.fViewRect[iHeight] / self.fScale / 2)

        maxWidth  = self.fViewRect[iWidth] / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        if x < 0.0:
            x = 0.0
        elif x > self.fFakeWidth - maxWidth:
            x = self.fFakeWidth - maxWidth

        if y < 0.0:
            y = 0.0
        elif y > self.fFakeHeight - maxHeight:
            y = self.fFakeHeight - maxHeight

        self.fViewRect[iX] = x + self.fRenderSource.x()
        self.fViewRect[iY] = y + self.fRenderSource.y()
        self.update()

        self.emit(SIGNAL("miniCanvasMoved(double, double)"), x * self.fScale / self.fFakeWidth, y * self.fScale / self.fFakeHeight)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.fMouseDown = True
            self.setCursor(QCursor(Qt.SizeAllCursor))
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseMoveEvent(self, event):
        if self.fMouseDown:
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseReleaseEvent(self, event):
        if self.fMouseDown:
            self.setCursor(QCursor(Qt.ArrowCursor))
        self.fMouseDown = False
        QFrame.mouseReleaseEvent(self, event)

    def paintEvent(self, event):
        painter = QPainter(self)

        if self.fUseCustomPaint:
            painter.setBrush(self.fViewBg)
            painter.setPen(QColor(12, 12, 12))
            painter.drawRect(0, 0, self.width(), self.height()-2)

            painter.setBrush(QColor(36, 36, 36))
            painter.setPen(QColor(62, 62, 62))
            painter.drawRect(1, 1, self.width()-2, self.height()-4)

            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRect(2, 3, self.width()-5, self.height()-7)

        else:
            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRoundRect(2, 2, self.width()-6, self.height()-6, 3, 3)

        self.fScene.render(painter, self.fRenderSource, self.fRenderTarget, Qt.KeepAspectRatio)

        maxWidth  = self.fViewRect[iWidth]  / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        painter.setBrush(self.fViewBrush)
        painter.setPen(self.fViewPen)
        painter.drawRect(self.fViewRect[iX], self.fViewRect[iY], maxWidth, maxHeight)

        if self.fUseCustomPaint:
            event.accept()
        else:
            QFrame.paintEvent(self, event)

    def resizeEvent(self, event):
        self.fRenderSource = self.getRenderSource()
        if self.fRealParent:
            QTimer.singleShot(0, self.fRealParent, SLOT("slot_miniCanvasCheckAll()"))
        QFrame.resizeEvent(self, event)
Пример #4
0
class CanvasPreviewFrame(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self, parent)

        self.m_mouseDown = False

        self.scale = 1.0
        self.scene = None
        self.real_parent = None
        self.fake_width = 0
        self.fake_height = 0

        self.render_source = self.getRenderSource()
        self.render_target = QRectF(0, 0, 0, 0)

        self.view_pad_x = 0.0
        self.view_pad_y = 0.0
        self.view_rect = [0.0, 0.0, 10.0, 10.0]

    def init(self, scene, real_width, real_height):
        self.scene = scene
        self.fake_width = float(real_width) / 15
        self.fake_height = float(real_height) / 15

        self.setMinimumSize(self.fake_width / 2, self.fake_height)
        self.setMaximumSize(self.fake_width * 4, self.fake_height)

        self.render_target.setWidth(real_width)
        self.render_target.setHeight(real_height)

    def getRenderSource(self):
        x_pad = (self.width() - self.fake_width) / 2
        y_pad = (self.height() - self.fake_height) / 2
        return QRectF(x_pad, y_pad, self.fake_width, self.fake_height)

    def setViewPosX(self, xp):
        x = xp * self.fake_width
        x_ratio = (x / self.fake_width) * self.view_rect[iWidth] / self.scale
        self.view_rect[iX] = x - x_ratio + self.render_source.x()
        self.update()

    def setViewPosY(self, yp):
        y = yp * self.fake_height
        y_ratio = (y / self.fake_height) * self.view_rect[iHeight] / self.scale
        self.view_rect[iY] = y - y_ratio + self.render_source.y()
        self.update()

    def setViewScale(self, scale):
        self.scale = scale
        QTimer.singleShot(0, self.real_parent, SLOT("slot_miniCanvasCheckAll()"))

    def setViewSize(self, width_p, height_p):
        width = width_p * self.fake_width
        height = height_p * self.fake_height
        self.view_rect[iWidth] = width
        self.view_rect[iHeight] = height
        self.update()

    def setRealParent(self, parent):
        self.real_parent = parent

    def handleMouseEvent(self, event_x, event_y):
        x = float(event_x) - self.render_source.x() - (self.view_rect[iWidth] / self.scale / 2)
        y = float(event_y) - self.render_source.y() - (self.view_rect[iHeight] / self.scale / 2)

        max_width = self.view_rect[iWidth] / self.scale
        max_height = self.view_rect[iHeight] / self.scale

        if max_width > self.fake_width:
            max_width = self.fake_width
        if max_height > self.fake_height:
            max_height = self.fake_height

        if x < 0.0:
            x = 0.0
        elif x > self.fake_width - max_width:
            x = self.fake_width - max_width

        if y < 0.0:
            y = 0.0
        elif y > self.fake_height - max_height:
            y = self.fake_height - max_height

        self.view_rect[iX] = x + self.render_source.x()
        self.view_rect[iY] = y + self.render_source.y()
        self.update()

        self.emit(
            SIGNAL("miniCanvasMoved(double, double)"),
            x * self.scale / self.fake_width,
            y * self.scale / self.fake_height,
        )

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.m_mouseDown = True
            self.setCursor(QCursor(Qt.SizeAllCursor))
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseMoveEvent(self, event):
        if self.m_mouseDown:
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseReleaseEvent(self, event):
        if self.m_mouseDown:
            self.setCursor(QCursor(Qt.ArrowCursor))
        self.m_mouseDown = False
        QFrame.mouseReleaseEvent(self, event)

    def paintEvent(self, event):
        painter = QPainter(self)

        painter.setBrush(QBrush(Qt.darkBlue, Qt.DiagCrossPattern))
        painter.drawRect(0, 0, self.width(), self.height())

        self.scene.render(painter, self.render_source, self.render_target, Qt.KeepAspectRatio)

        max_width = self.view_rect[iWidth] / self.scale
        max_height = self.view_rect[iHeight] / self.scale

        if max_width > self.fake_width:
            max_width = self.fake_width
        if max_height > self.fake_height:
            max_height = self.fake_height

        painter.setBrush(QBrush(QColor(75, 75, 255, 30)))
        painter.setPen(QPen(Qt.blue, 2))
        painter.drawRect(self.view_rect[iX], self.view_rect[iY], max_width, max_height)

        QFrame.paintEvent(self, event)

    def resizeEvent(self, event):
        self.render_source = self.getRenderSource()
        if self.real_parent:
            QTimer.singleShot(0, self.real_parent, SLOT("slot_miniCanvasCheckAll()"))
        QFrame.resizeEvent(self, event)
Пример #5
0
 def rebuildDays( self ):
     """
     Rebuilds the interface as a week display.
     """
     time = QTime(0, 0, 0)
     hour = True
     
     x = 6
     y = 6 + 24
     
     w = self.width() - 12 - 25
     
     dh         = 48
     indent     = 58
     text_data  = []
     
     vlines      = []
     hlines      = [QLine(x, y, w, y)]
     time_grids  = []
     
     for i in range(48):
         if ( hour ):
             hlines.append(QLine(x, y, w, y))
             text_data.append((x,
                               y + 6, 
                               indent - 6, 
                               dh, 
                               Qt.AlignRight | Qt.AlignTop,
                               time.toString('hap')))
         else:
             hlines.append(QLine(x + indent, y, w, y))
         
         time_grids.append((time, y, dh / 2))
         
         # move onto the next line
         hour = not hour
         time = time.addSecs(30 * 60)
         y += dh / 2
     
     hlines.append(QLine(x, y, w, y))
     
     h = y
     y = 6 + 24
     
     # load the grid
     vlines.append(QLine(x, y, x, h))
     vlines.append(QLine(x + indent, y, x + indent, h))
     vlines.append(QLine(w, y, w, h))
     
     today     = QDate.currentDate()
     curr_date = self.currentDate()
     
     # load the days
     if ( self.currentMode() == XCalendarScene.Mode.Week ):
         date = self.currentDate()
         day_of_week = date.dayOfWeek()
         if ( day_of_week == 7 ):
             day_of_week = 0
         
         min_date = date.addDays(-day_of_week)
         max_date = date.addDays(6-day_of_week)
         
         self._minimumDate = min_date
         self._maximumDate = max_date
         
         dw    = (w - (x + indent)) / 7.0
         vx    = x + indent
         date  = min_date
         
         for i in range(7):
             vlines.append(QLine(vx, y, vx, h))
             
             text_data.append((vx + 6,
                               6,
                               dw,
                               24,
                               Qt.AlignCenter,
                               date.toString('ddd MM/dd')))
             
             self._dateGrid[date.toJulianDay()] = ((0, i),
                                                   QRectF(vx, y, dw, h - y))
             
             # create the date grid for date time options
             for r, data in enumerate(time_grids):
                 time, ty, th = data
                 dtime = QDateTime(date, time)
                 key = dtime.toTime_t()
                 self._dateTimeGrid[key] = ((r, i), QRectF(vx, ty, dw, th))
             
             if ( date == curr_date ):
                 self._buildData['curr_date'] = QRectF(vx, y, dw, h - 29)
             elif ( date == today ):
                 self._buildData['today'] = QRectF(vx, y, dw, h - 29)
             
             date = date.addDays(1)
             vx += dw
     
     # load a single day
     else:
         date = self.currentDate()
         
         self._maximumDate = date
         self._minimumDate = date
         
         text_data.append((x + indent,
                           6,
                           w,
                           24,
                           Qt.AlignCenter,
                           date.toString('ddd MM/dd')))
         
         self._dateGrid[date.toJulianDay()] = ((0, 0), 
                                               QRectF(x, y, w - x, h - y))
         
         # create the date grid for date time options
         for r, data in enumerate(time_grids):
             time, ty, th = data
             dtime = QDateTime(date, time)
             key = dtime.toTime_t()
             rect = QRectF(x + indent, ty, w - (x + indent), th)
             self._dateTimeGrid[key] = ((r, 0), rect)
     
     self._buildData['grid'] = hlines + vlines
     self._buildData['regular_text'] = text_data
     
     rect = self.sceneRect()
     rect.setHeight(h + 6)
     
     super(XCalendarScene, self).setSceneRect(rect)
 def setHeight(self,h):
     QRectF.setHeight(self,h)
Пример #7
0
class PathHelix(QGraphicsItem):
    """
    PathHelix is the primary "view" of the VirtualHelix data.
    It manages the ui interactions from the user, such as
    dragging breakpoints or crossovers addition/removal,
    and updates the data model accordingly.

    parent should be set to...
    """
    minorGridPen = QPen(styles.minorgridstroke, styles.MINOR_GRID_STROKE_WIDTH)
    minorGridPen.setCosmetic(True)
    majorGridPen = QPen(styles.majorgridstroke, styles.MAJOR_GRID_STROKE_WIDTH)
    majorGridPen.setCosmetic(True)
    
    scafPen = QPen(styles.scafstroke, 2)
    nobrush = QBrush(Qt.NoBrush)
    baseWidth = styles.PATH_BASE_WIDTH

    def __init__(self, vhelix, pathHelixGroup):
        super(PathHelix, self).__init__()
        self.setAcceptHoverEvents(True)  # for pathtools
        self._pathHelixGroup = pathHelixGroup
        self._scafBreakpointHandles = []
        self._stapBreakpointHandles = []
        self._scafXoverHandles = []
        self._stapXoverHandles = []
        self._preXOverHandles = None
        self._segmentPaths = None
        self._loopPaths = None
        self._minorGridPainterPath = None
        self._majorGridPainterPath = None
        self.step = 21  # 32 for Square lattice
        self.setZValue(styles.ZPATHHELIX)
        self.rect = QRectF()
        self._vhelix = None
        self._handle = None
        self._mouseDownBase = None
        self._skipitem = SkipItem()
        self._loopitem = LoopItem()
        self.setVHelix(vhelix)
        if app().ph != None:  # Convenience for the command line -i mode
            app().ph[vhelix.number()] = self
    # end def

    def activeTool(self):
        return self.controller().activeTool()

    def controller(self):
        return self._pathHelixGroup.controller()

    def vhelix(self):
        return self._vhelix

    def undoStack(self):
        return self.vhelix().undoStack()

    def setVHelix(self, newVH):
        if self._vhelix:
            self._vhelix.basesModified.disconnect(self.vhelixBasesModified)
            self._vhelix.vhelixDimensionsModified.disconnect(\
                                             self.vhelixDimensionsModified)
        self._vhelix = newVH
        newVH.basesModified.connect(self.vhelixBasesModified)
        newVH.dimensionsModified.connect(self.vhelixDimensionsModified)
        self.vhelixDimensionsModified()
        self.vhelixBasesModified()

    def handle(self):
        if self._handle:
            return self._handle
        self._handle = PathHelixHandle(self.vhelix(),parent=self._pathHelixGroup)
        return self._handle

    def number(self):
        return self._vhelix.number()

    def row(self):
        return self._vhelix.row()

    def col(self):
        return self._vhelix.col()

    def evenParity(self):
        return self._vhelix.evenParity()

    def vhelixDimensionsModified(self):
        """Sets rect width to reflect number of bases in vhelix. Sets
        rect height to the width of two bases (one for scaffold and
        one for staple)"""
        canvasSize = self._vhelix.part().numBases()
        self.prepareGeometryChange()
        self.rect.setWidth(self.baseWidth * canvasSize)
        self.rect.setHeight(2 * self.baseWidth)
        self._minorGridPainterPath = None
        self._majorGridPainterPath = None

    def boundingRect(self):
        return self.rect

    ################# Crossover Handles #################
    def preXOverHandlesVisible(self):
        return self._preXOverHandles!=None
    
    def setPreXOverHandlesVisible(self, shouldBeVisible):
        areVisible = self._preXOverHandles!=None
        if areVisible and not shouldBeVisible:
            for pch in self._preXOverHandles:
                pch.setParentItem(None)
            self._preXOverHandles = None
        elif not areVisible and shouldBeVisible:
            self._preXOverHandles = handles = []
            for strandType, facingRight in product((StrandType.Scaffold, StrandType.Staple), (True, False)):
                # Get potential crossovers in [neighborVirtualHelix, index] format
                potentialXOvers = self.vhelix().potentialCrossoverList(facingRight, strandType)
                for (neighborVH, fromIdx) in potentialXOvers:
                    pch = PreCrossoverHandle(self, strandType, fromIdx, neighborVH, fromIdx, not facingRight)
                    handles.append(pch)
    
    def makeSelfActiveHelix(self):
        self._pathHelixGroup.setActiveHelix(self)
    
    ################# Loading and Updating State From VHelix #################
    def vhelixBasesModified(self):
        self._endpoints = None  # Clear endpoint drawing cache
        self._segmentPaths = None  # Clear drawing cache of lines
        self._loopPaths = None
        self.update()

    ############################# Drawing ##########################
    def paint(self, painter, option, widget=None):
        # Note that the methods that fetch the paths
        # cache the paths and that those caches are
        # invalidated as the primary mechanism
        # of updating after a change in vhelix's bases
        painter.save()
        painter.setBrush(self.nobrush)
        painter.setPen(self.minorGridPen)
        painter.drawPath(self.minorGridPainterPath())  # Minor grid lines
        painter.setPen(self.majorGridPen)
        painter.drawPath(self.majorGridPainterPath())  # Major grid lines
        painter.setBrush(Qt.NoBrush)
        for paintCommand in self.segmentPaths():
            painter.setPen(paintCommand[0])
            painter.drawPath(paintCommand[1])
        painter.setPen(Qt.NoPen)
        for paintCommand in self.segmentPaths():
            painter.setBrush(paintCommand[2])
            painter.drawPath(paintCommand[3])
        # Now draw loops and skips
        painter.setBrush(Qt.NoBrush)
        for paintCommand in self.loopPaths():
            painter.setPen(paintCommand[0])
            painter.drawPath(paintCommand[1])
            painter.setPen(paintCommand[2])
            painter.drawPath(paintCommand[3])
        painter.restore()

    def minorGridPainterPath(self):
        """
        Returns a QPainterPath object for the minor grid lines.
        The path also includes a border outline and a midline for
        dividing scaffold and staple bases.
        """
        if self._minorGridPainterPath:
            return self._minorGridPainterPath
        path = QPainterPath()
        canvasSize = self._vhelix.part().numBases()
        # border
        path.addRect(0, 0, self.baseWidth * canvasSize, 2 * self.baseWidth)
        # minor tick marks
        for i in range(canvasSize):
            if (i % 7 != 0):
                x = round(self.baseWidth * i) + .5
                path.moveTo(x, 0)
                path.lineTo(x, 2 * self.baseWidth)
        # staple-scaffold divider
        path.moveTo(0, self.baseWidth)
        path.lineTo(self.baseWidth * canvasSize, self.baseWidth)
        self._minorGridPainterPath = path
        return path

    def majorGridPainterPath(self):
        """
        Returns a QPainterPath object for the major grid lines.
        This is separated from the minor grid lines so different
        pens can be used for each.
        """
        if self._majorGridPainterPath:
            return self._majorGridPainterPath
        path = QPainterPath()
        canvasSize = self._vhelix.part().numBases()
        # major tick marks  FIX: 7 is honeycomb-specific
        for i in range(0, canvasSize + 1, 7):
            x = round(self.baseWidth * i) + .5
            path.moveTo(x, .5)
            path.lineTo(x, 2 * self.baseWidth - .5)
        self._majorGridPainterPath = path
        return path

    def segmentPaths(self):
        """Returns an array of (pen, penPainterPath, brush, brushPainterPath)
        for drawing segment lines and handles."""
        if self._segmentPaths:
            return self._segmentPaths
        self._segmentPaths = []
        vh = self.vhelix()
        for strandType in (StrandType.Scaffold, StrandType.Staple):
            top = self.strandIsTop(strandType)
            for [startIndex, startIsXO, endIndex, endIsXO] in\
                                        self._vhelix.getSegments(strandType):
                # Left and right centers for drawing the connecting line
                c1 = self.baseLocation(strandType, startIndex, center=True)
                c2 = self.baseLocation(strandType, endIndex, center=True)
                # Upper left corners for translating the breakpoint handles
                ul1 = self.baseLocation(strandType, startIndex)
                ul2 = self.baseLocation(strandType, endIndex)
                # Now we construct the path to cache
                bp = QPainterPath()
                if not startIsXO:
                    bp.addPath(ppL5.translated(*ul1) if top else\
                                                        ppL3.translated(*ul1))
                if not endIsXO:
                    bp.addPath(ppR3.translated(*ul2) if top else\
                                                        ppR5.translated(*ul2))
                pp = QPainterPath()
                pp.moveTo(*c1)
                pp.lineTo(*c2)
                # Now we combine pen/brush information and push it to the cache
                # _segmentPaths entries take the form:
                # (pen, painterPathToBeDrawnOnlyWithPen,\
                #  brush, paintPathToBeDrawnOnlyWithBrush)
                color = vh.colorOfBase(strandType, startIndex)
                width = styles.PATH_STRAND_STROKE_WIDTH
                pen = QPen(color, width)
                brush = QBrush(color)
                self._segmentPaths.append((pen, pp, brush, bp))
        return self._segmentPaths

    def loopPaths(self):
        """
        Returns an array of:
        (loopPen, loopPainterPath, skipPen, skipPainterPath)
        for drawing loops and skips
        """
        if self._loopPaths:
            return self._loopPaths
        self._loopPaths = []
        vh = self.vhelix()
        lpen = self._loopitem.getPen()
        spen = self._skipitem.getPen()
        for strandType in (StrandType.Scaffold, StrandType.Staple):
            top = self.strandIsTop(strandType)
            lp = QPainterPath()
            sp = QPainterPath()
            count = len(vh._loop(strandType))
            if count > 0:
                for index, loopsize in vh._loop(strandType).iteritems(): 
                    ul = self.baseLocation(strandType, index)
                    if loopsize > 0:
                        path = self._loopitem.getLoop(top)
                        lp.addPath(path.translated(*ul))
                    else:
                        path = self._skipitem.getSkip()
                        sp.addPath(path.translated(*ul))
                # end for
            # end if
            self._loopPaths.append((lpen, lp, spen, sp))
        # end for
        return self._loopPaths
    # end def
    
    def strandIsTop(self, strandType):
        return self.evenParity() and strandType == StrandType.Scaffold\
           or not self.evenParity() and strandType == StrandType.Staple

    def baseAtLocation(self, x, y):
        """Returns the (strandType, index) under the location x,y or None.
        
        It shouldn't be possible to click outside a pathhelix and still call
        this function. However, this sometimes happens if you click exactly
        on the top or bottom edge, resulting in a negative y value.
        """
        baseIdx = int(floor(x / self.baseWidth))
        if baseIdx < 0 or baseIdx >= self.vhelix().numBases():
            return None
        if y < 0:
            y = 0  # HACK: zero out y due to erroneous click
        strandIdx = floor(y * 1. / self.baseWidth)
        if strandIdx < 0 or strandIdx > 1:
            return None
        if self.strandIsTop(StrandType.Scaffold):
            strands = StrandType.Scaffold, StrandType.Staple
        else:
            strands = StrandType.Staple, StrandType.Scaffold
        return (strands[int(strandIdx)], baseIdx)

    def baseLocation(self, strandType, baseIdx, center=False):
        """Returns the coordinates of the upper left corner of the base
        referenced by strandType and baseIdx. If center=True, returns the
        center of the base instead of the upper left corner."""
        if self.strandIsTop(strandType):
            y = 0
        else:
            y = self.baseWidth
        x = baseIdx * self.baseWidth
        if center:
            x += self.baseWidth / 2
            y += self.baseWidth / 2
        return (x, y)
Пример #8
0
    def layout(self,
               scene,
               nodes,
               center=None,
               padX=None,
               padY=None,
               direction=None,
               animationGroup=None):
        """
        Lays out the nodes for this scene based on a block layering algorithm.
        
        :param      scene          | <XNodeScene>
                    nodes          | [<XNode>, ..]
                    center         | <QPointF> || None
                    padX           | <int> || None
                    padY           | <int> || None
                    direction      | <Qt.Direction>
                    animationGroup | <QAnimationGroup> || None
        
        :return     {<XNode>: <QRectF>, ..} | new rects per affected node
        """
        nodes = filter(lambda x: x is not None and x.isVisible(), nodes)

        # make sure we have at least 1 node, otherwise, it is already laid out
        if not nodes or len(nodes) == 1:
            return {}

        # calculate the default padding based on the scene
        if padX == None:
            if direction == Qt.Vertical:
                padX = 2 * scene.cellWidth()
            else:
                padX = 4 * scene.cellWidth()

        if padY == None:
            if direction == Qt.Vertical:
                padY = 4 * scene.cellHeight()
            else:
                padY = 2 * scene.cellWidth()

        # step 1: create a mapping of the connections
        connection_map = self.connectionMap(scene, nodes)

        # step 2: organize the nodes into layers based on their connection chain
        layers = self.generateLayers(scene, nodes, connection_map)
        layers = list(reversed(layers))

        # step 3: calculate the total dimensions for the layout
        bounds = QRectF()

        # step 3.1: compare the nodes together that have common connections
        layer_widths = []
        layer_heights = []
        node_heights = {}
        node_widths = {}

        for layer_index, layer in enumerate(layers):
            layer_w = 0
            layer_h = 0

            layer_node_w = []
            layer_node_h = []

            self.organizeLayer(layer, connection_map)

            for node in layer:
                rect = node.rect()

                layer_node_w.append(rect.width())
                layer_node_h.append(rect.height())

                if direction == Qt.Vertical:
                    layer_w += rect.width()
                    layer_h = max(rect.height(), layer_h)
                else:
                    layer_w = max(rect.width(), layer_w)
                    layer_h += rect.height()

            # update the bounding area
            if direction == Qt.Vertical:
                layer_w += padX * 1 - len(layer)
                bounds.setWidth(max(layer_w, bounds.width()))
                bounds.setHeight(bounds.height() + layer_h)
            else:
                layer_h += padY * 1 - len(layer)
                bounds.setWidth(bounds.width() + layer_w)
                bounds.setHeight(max(layer_h, bounds.height()))

            node_widths[layer_index] = layer_node_w
            node_heights[layer_index] = layer_node_h

            layer_widths.append(layer_w)
            layer_heights.append(layer_h)

        if not center:
            center = scene.sceneRect().center()

        w = bounds.width()
        h = bounds.height()
        bounds.setX(center.x() - bounds.width() / 2.0)
        bounds.setY(center.y() - bounds.height() / 2.0)
        bounds.setWidth(w)
        bounds.setHeight(h)

        # step 4: assign positions for each node by layer
        processed_nodes = {}
        layer_grps = [(i, layer) for i, layer in enumerate(layers)]
        layer_grps.sort(key=lambda x: len(x[1]))

        for layer_index, layer in reversed(layer_grps):
            layer_width = layer_widths[layer_index]
            layer_height = layer_heights[layer_index]

            # determine the starting point for this layer
            if direction == Qt.Vertical:
                offset = layer_index * padY + sum(layer_heights[:layer_index])
                point = QPointF(bounds.x(), offset + bounds.y())
            else:
                offset = layer_index * padX + sum(layer_widths[:layer_index])
                point = QPointF(offset + bounds.x(), bounds.y())

            # assign node positions based on existing connections
            for node_index, node in enumerate(layer):
                max_, min_ = (None, None)
                inputs, outputs = connection_map[node]
                for connected_node in inputs + outputs:
                    if not connected_node in processed_nodes:
                        continue

                    npos = processed_nodes[connected_node]
                    nrect = connected_node.rect()
                    rect = QRectF(npos.x(), npos.y(), nrect.width(),
                                  nrect.height())

                    if direction == Qt.Vertical:
                        if min_ is None:
                            min_ = rect.left()
                        min_ = min(rect.left(), min_)
                        max_ = max(rect.right(), max_)
                    else:
                        if min_ is None:
                            min_ = rect.top()
                        min_ = min(rect.top(), min_)
                        max_ = max(rect.bottom(), max_)

                if direction == Qt.Vertical:
                    off_x = 0
                    off_y = (layer_height - node.rect().height()) / 2.0
                    start_x = (bounds.width() - layer_width)
                    start_y = 0
                else:
                    off_x = (layer_width - node.rect().width()) / 2.0
                    off_y = 0
                    start_x = 0
                    start_y = (bounds.height() - layer_height)

                # align against existing nodes
                if not None in (min_, max):
                    if direction == Qt.Vertical:
                        off_x = (max_ - min_) / 2.0 - node.rect().width() / 2.0
                        point_x = min_ + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = (max_ -
                                 min_) / 2.0 - node.rect().height() / 2.0
                        point_x = point.x() + off_x
                        point_y = min_ + off_y

                # otherwise, align based on its position in the layer
                else:
                    if direction == Qt.Vertical:
                        off_x = sum(node_widths[layer_index][:node_index])
                        off_x += node_index * padX
                        off_x += start_x

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y
                    else:
                        off_y = sum(node_heights[layer_index][:node_index])
                        off_y += node_index * padY
                        off_y += start_y

                        point_x = point.x() + off_x
                        point_y = point.y() + off_y

                if not animationGroup:
                    node.setPos(point_x, point_y)
                else:
                    anim = XNodeAnimation(node, 'setPos')
                    anim.setStartValue(node.pos())
                    anim.setEndValue(QPointF(point_x, point_y))
                    animationGroup.addAnimation(anim)

                processed_nodes[node] = QPointF(point_x, point_y)

                if self._testing:
                    QApplication.processEvents()
                    time.sleep(1)

        return processed_nodes
Пример #9
0
class CanvasPreviewFrame(QFrame):
    def __init__(self, parent):
        QFrame.__init__(self, parent)

        self.fUseCustomPaint = False

        self.fMouseDown = False

        self.fViewBg = QColor(0, 0, 0)
        self.fViewBrush = QBrush(QColor(75, 75, 255, 30))
        self.fViewPen = QPen(Qt.blue, 1)

        self.fScale = 1.0
        self.fScene = None
        self.fRealParent = None
        self.fFakeWidth = 0.0
        self.fFakeHeight = 0.0

        self.fRenderSource = self.getRenderSource()
        self.fRenderTarget = QRectF(0, 0, 0, 0)

        self.fViewPadX = 0.0
        self.fViewPadY = 0.0
        self.fViewRect = [0.0, 0.0, 10.0, 10.0]

    def init(self, scene, realWidth, realHeight, useCustomPaint=False):
        padding = 6

        self.fScene = scene
        self.fFakeWidth = float(realWidth) / 15
        self.fFakeHeight = float(realHeight) / 15

        self.setMinimumSize(self.fFakeWidth + padding,
                            self.fFakeHeight + padding)
        self.setMaximumSize(self.fFakeWidth * 4 + padding,
                            self.fFakeHeight + padding)

        self.fRenderTarget.setWidth(realWidth)
        self.fRenderTarget.setHeight(realHeight)

        if self.fUseCustomPaint != useCustomPaint:
            self.fUseCustomPaint = useCustomPaint
            self.repaint()

    def setRealParent(self, parent):
        self.fRealParent = parent

    def getRenderSource(self):
        xPadding = (float(self.width()) - self.fFakeWidth) / 2.0
        yPadding = (float(self.height()) - self.fFakeHeight) / 2.0
        return QRectF(xPadding, yPadding, self.fFakeWidth, self.fFakeHeight)

    def setViewPosX(self, xp):
        x = self.fFakeWidth * xp
        xRatio = (x / self.fFakeWidth) * self.fViewRect[iWidth] / self.fScale
        self.fViewRect[iX] = x - xRatio + self.fRenderSource.x()
        self.update()

    def setViewPosY(self, yp):
        y = self.fFakeHeight * yp
        yRatio = (y / self.fFakeHeight) * self.fViewRect[iHeight] / self.fScale
        self.fViewRect[iY] = y - yRatio + self.fRenderSource.y()
        self.update()

    def setViewScale(self, scale):
        self.fScale = scale
        QTimer.singleShot(0, self.fRealParent,
                          SLOT("slot_miniCanvasCheckAll()"))

    def setViewSize(self, width, height):
        self.fViewRect[iWidth] = width * self.fFakeWidth
        self.fViewRect[iHeight] = height * self.fFakeHeight
        self.update()

    def setViewTheme(self, bgColor, brushColor, penColor):
        brushColor.setAlpha(40)
        penColor.setAlpha(100)
        self.fViewBg = bgColor
        self.fViewBrush = QBrush(brushColor)
        self.fViewPen = QPen(penColor, 1)

    def handleMouseEvent(self, eventX, eventY):
        x = float(eventX) - self.fRenderSource.x() - (self.fViewRect[iWidth] /
                                                      self.fScale / 2)
        y = float(eventY) - self.fRenderSource.y() - (self.fViewRect[iHeight] /
                                                      self.fScale / 2)

        maxWidth = self.fViewRect[iWidth] / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        if x < 0.0:
            x = 0.0
        elif x > self.fFakeWidth - maxWidth:
            x = self.fFakeWidth - maxWidth

        if y < 0.0:
            y = 0.0
        elif y > self.fFakeHeight - maxHeight:
            y = self.fFakeHeight - maxHeight

        self.fViewRect[iX] = x + self.fRenderSource.x()
        self.fViewRect[iY] = y + self.fRenderSource.y()
        self.update()

        self.emit(SIGNAL("miniCanvasMoved(double, double)"),
                  x * self.fScale / self.fFakeWidth,
                  y * self.fScale / self.fFakeHeight)

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.fMouseDown = True
            self.setCursor(QCursor(Qt.SizeAllCursor))
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseMoveEvent(self, event):
        if self.fMouseDown:
            self.handleMouseEvent(event.x(), event.y())
        event.accept()

    def mouseReleaseEvent(self, event):
        if self.fMouseDown:
            self.setCursor(QCursor(Qt.ArrowCursor))
        self.fMouseDown = False
        QFrame.mouseReleaseEvent(self, event)

    def paintEvent(self, event):
        painter = QPainter(self)

        if self.fUseCustomPaint:
            painter.setBrush(self.fViewBg)
            painter.setPen(QColor(12, 12, 12))
            painter.drawRect(0, 0, self.width(), self.height() - 2)

            painter.setBrush(QColor(36, 36, 36))
            painter.setPen(QColor(62, 62, 62))
            painter.drawRect(1, 1, self.width() - 2, self.height() - 4)

            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRect(2, 3, self.width() - 5, self.height() - 7)

        else:
            painter.setBrush(self.fViewBg)
            painter.setPen(self.fViewBg)
            painter.drawRoundRect(2, 2,
                                  self.width() - 6,
                                  self.height() - 6, 3, 3)

        self.fScene.render(painter, self.fRenderSource, self.fRenderTarget,
                           Qt.KeepAspectRatio)

        maxWidth = self.fViewRect[iWidth] / self.fScale
        maxHeight = self.fViewRect[iHeight] / self.fScale

        if maxWidth > self.fFakeWidth:
            maxWidth = self.fFakeWidth
        if maxHeight > self.fFakeHeight:
            maxHeight = self.fFakeHeight

        painter.setBrush(self.fViewBrush)
        painter.setPen(self.fViewPen)
        painter.drawRect(self.fViewRect[iX], self.fViewRect[iY], maxWidth,
                         maxHeight)

        if self.fUseCustomPaint:
            event.accept()
        else:
            QFrame.paintEvent(self, event)

    def resizeEvent(self, event):
        self.fRenderSource = self.getRenderSource()
        if self.fRealParent:
            QTimer.singleShot(0, self.fRealParent,
                              SLOT("slot_miniCanvasCheckAll()"))
        QFrame.resizeEvent(self, event)
Пример #10
0
    def rebuildDays(self):
        """
        Rebuilds the interface as a week display.
        """
        time = QTime(0, 0, 0)
        hour = True

        x = 6
        y = 6 + 24

        w = self.width() - 12 - 25

        dh = 48
        indent = 58
        text_data = []

        vlines = []
        hlines = [QLine(x, y, w, y)]
        time_grids = []

        for i in range(48):
            if (hour):
                hlines.append(QLine(x, y, w, y))
                text_data.append(
                    (x, y + 6, indent - 6, dh, Qt.AlignRight | Qt.AlignTop,
                     time.toString('hap')))
            else:
                hlines.append(QLine(x + indent, y, w, y))

            time_grids.append((time, y, dh / 2))

            # move onto the next line
            hour = not hour
            time = time.addSecs(30 * 60)
            y += dh / 2

        hlines.append(QLine(x, y, w, y))

        h = y
        y = 6 + 24

        # load the grid
        vlines.append(QLine(x, y, x, h))
        vlines.append(QLine(x + indent, y, x + indent, h))
        vlines.append(QLine(w, y, w, h))

        today = QDate.currentDate()
        curr_date = self.currentDate()

        # load the days
        if (self.currentMode() == XCalendarScene.Mode.Week):
            date = self.currentDate()
            day_of_week = date.dayOfWeek()
            if (day_of_week == 7):
                day_of_week = 0

            min_date = date.addDays(-day_of_week)
            max_date = date.addDays(6 - day_of_week)

            self._minimumDate = min_date
            self._maximumDate = max_date

            dw = (w - (x + indent)) / 7.0
            vx = x + indent
            date = min_date

            for i in range(7):
                vlines.append(QLine(vx, y, vx, h))

                text_data.append((vx + 6, 6, dw, 24, Qt.AlignCenter,
                                  date.toString('ddd MM/dd')))

                self._dateGrid[date.toJulianDay()] = ((0, i),
                                                      QRectF(vx, y, dw, h - y))

                # create the date grid for date time options
                for r, data in enumerate(time_grids):
                    time, ty, th = data
                    dtime = QDateTime(date, time)
                    key = dtime.toTime_t()
                    self._dateTimeGrid[key] = ((r, i), QRectF(vx, ty, dw, th))

                if (date == curr_date):
                    self._buildData['curr_date'] = QRectF(vx, y, dw, h - 29)
                elif (date == today):
                    self._buildData['today'] = QRectF(vx, y, dw, h - 29)

                date = date.addDays(1)
                vx += dw

        # load a single day
        else:
            date = self.currentDate()

            self._maximumDate = date
            self._minimumDate = date

            text_data.append((x + indent, 6, w, 24, Qt.AlignCenter,
                              date.toString('ddd MM/dd')))

            self._dateGrid[date.toJulianDay()] = ((0, 0),
                                                  QRectF(x, y, w - x, h - y))

            # create the date grid for date time options
            for r, data in enumerate(time_grids):
                time, ty, th = data
                dtime = QDateTime(date, time)
                key = dtime.toTime_t()
                rect = QRectF(x + indent, ty, w - (x + indent), th)
                self._dateTimeGrid[key] = ((r, 0), rect)

        self._buildData['grid'] = hlines + vlines
        self._buildData['regular_text'] = text_data

        rect = self.sceneRect()
        rect.setHeight(h + 6)

        super(XCalendarScene, self).setSceneRect(rect)