Esempio n. 1
0
 def replace(self):
     log.trace("Icon is %r", self._icon)
     self._icon_geometry = rect = self._icon.geometry()
     log.trace("IconRect is : %s,%s | %s,%s",rect.x(), rect.y(), rect.width(), rect.height())
     from PyQt4.QtGui import QApplication, QCursor
     from PyQt4.QtCore import QRect
     desktop = QApplication.desktop()
     log.trace("Screen id is %d", desktop.screenNumber(rect.topLeft()))
     screen = desktop.availableGeometry(desktop.screenNumber(rect.topLeft()))
     pos = screen
     log.trace("AvailableRect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     pos = desktop.screenGeometry(desktop.screenNumber(rect.topLeft()))
     log.trace("ScreenRect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     pos = QCursor.pos()
     log.trace("Cursor is : %s,%s",pos.x(), pos.y())
     if not rect.contains(pos) or (rect.x() == 0 and rect.y() == 0):
         # Avoid any modulo 0
         if rect.width() == 0 or rect.height() == 0:
             rect = QRect(pos.x(), pos.y(), rect.width(), rect.height())
         else:
             rect = QRect(pos.x()-pos.x()%rect.width(), pos.y()-pos.y()%rect.height(), rect.width(), rect.height())
         log.trace("Adjusting X/Y to %d/%d", rect.x(), rect.y())
         pos = rect
         log.trace("New rect is : %s,%s | %s,%s",pos.x(), pos.y(), pos.width(), pos.height())
     x = rect.x() + rect.width() - self.width()
     y = rect.y() - self.height()
     # Prevent the systray to be hidden
     if y < 0:
         y = rect.y() + rect.height()
     if x < 0:
         x = rect.x()
     log.trace("Move systray menu to %d/%d", x, y)
     self.move(x, y)
Esempio n. 2
0
 def paint(self, painter, rect):
     update_rect = rect & self.rect()
     if not update_rect:
         return
     image_rect = QRect(update_rect.topLeft() - self.rect().topLeft(),
                        update_rect.size())
     image = cache.image(self)
     self._waiting = not image
     if image:
         painter.drawImage(update_rect, image, image_rect)
     else:
         # schedule an image to be generated, if done our update() method is called
         cache.generate(self)
         # find suitable image to be scaled from other size
         image = cache.image(self, False)
         if image:
             hscale = float(image.width()) / self.width()
             vscale = float(image.height()) / self.height()
             image_rect = QRectF(image_rect.x() * hscale,
                                 image_rect.y() * vscale,
                                 image_rect.width() * hscale,
                                 image_rect.height() * vscale)
             painter.drawImage(QRectF(update_rect), image, image_rect)
         else:
             # draw blank paper, using the background color of the cache rendering (if set)
             # or from the document itself.
             color = (cache.options(self.document()).paperColor()
                      or cache.options().paperColor()
                      or self.document().paperColor())
             painter.fillRect(update_rect, color)
Esempio n. 3
0
 def paint(self, painter, rect):
     update_rect = rect & self.rect()
     if not update_rect:
         return
     image_rect = QRect(update_rect.topLeft() - self.rect().topLeft(), update_rect.size())
     image = cache.image(self)
     self._waiting = not image
     if image:
         painter.drawImage(update_rect, image, image_rect)
     else:
         # schedule an image to be generated, if done our update() method is called
         cache.generate(self)
         # find suitable image to be scaled from other size
         image = cache.image(self, False)
         if image:
             hscale = float(image.width()) / self.width()
             vscale = float(image.height()) / self.height()
             image_rect = QRectF(image_rect.x() * hscale, image_rect.y() * vscale,
                                 image_rect.width() * hscale, image_rect.height() * vscale)
             painter.drawImage(QRectF(update_rect), image, image_rect)
         else:
             # draw blank paper, using the background color of the cache rendering (if set)
             # or from the document itself.
             color = (cache.options(self.document()).paperColor()
                      or cache.options().paperColor() or self.document().paperColor())
             painter.fillRect(update_rect, color)
Esempio n. 4
0
def read_state(load=True):
    home = os.path.expanduser('~')

    r = QRect(0, 0, 640, 480)
    r.moveCenter(QApplication.desktop().availableGeometry().center())
    geometry = [r.x(), r.y(), r.width(), r.height()]

    state = dict(last_file_parent=home,
                 last_dir_parent=home,
                 last_save=home,
                 geometry=geometry,
                 zoom_factor=1.0,
                 history=[],
                 history_current=-1,
                 scroll_values={})
    try:
        if load and os.path.exists(state_file):
            f = gzip.open(state_file, 'rb')
            try:
                loaded = json.load(f)
                state.update(loaded)
            finally:
                f.close()
    except:
        show_error(_('Failed to load saved application state'))
    return state
Esempio n. 5
0
 def request( self, qrect, along_through=None ):
     assert isinstance(qrect, QRect)
     # Widen request with a 1-pixel halo, to make sure edges on the tile borders are shown.
     qrect = QRect( qrect.x(), qrect.y(), qrect.width()+1, qrect.height()+1 )
     s = rect2slicing(qrect)
     arrayreq = self._arraySource2D.request(s, along_through)
     return SegmentationEdgesItemRequest(arrayreq, self._layer, qrect)
Esempio n. 6
0
 def request( self, qrect, along_through=None ):
     assert isinstance(qrect, QRect)
     # Widen request with a 1-pixel halo, to make sure edges on the tile borders are shown.
     qrect = QRect( qrect.x(), qrect.y(), qrect.width()+1, qrect.height()+1 )
     s = rect2slicing(qrect)
     arrayreq = self._arraySource2D.request(s, along_through)
     return SegmentationEdgesItemRequest(arrayreq, self._layer, qrect)
Esempio n. 7
0
def read_state(load=True):
    home = os.path.expanduser('~')

    r = QRect(0, 0, 640, 480)
    r.moveCenter(QApplication.desktop().availableGeometry().center())
    geometry = [r.x(), r.y(), r.width(), r.height()]

    state = dict(last_file_parent=home,
                 last_dir_parent=home,
                 last_save=home,
                 geometry=geometry,
                 zoom_factor=1.0,
                 history=[],
                 history_current=-1,
                 scroll_values={})
    try:
        if load and os.path.exists(state_file):
            f = gzip.open(state_file, 'rb')
            try:            
                loaded = json.load(f)
                state.update(loaded)
            finally:
                f.close()
    except:
        show_error(_('Failed to load saved application state'))
    return state
Esempio n. 8
0
 def replace(self):
     log.trace("Icon is %r", self._icon)
     self._icon_geometry = rect = self._icon.geometry()
     log.trace("IconRect is : %s,%s | %s,%s", rect.x(), rect.y(),
               rect.width(), rect.height())
     from PyQt4.QtGui import QApplication, QCursor
     from PyQt4.QtCore import QRect
     desktop = QApplication.desktop()
     log.trace("Screen id is %d", desktop.screenNumber(rect.topLeft()))
     screen = desktop.availableGeometry(desktop.screenNumber(
         rect.topLeft()))
     pos = screen
     log.trace("AvailableRect is : %s,%s | %s,%s", pos.x(), pos.y(),
               pos.width(), pos.height())
     pos = desktop.screenGeometry(desktop.screenNumber(rect.topLeft()))
     log.trace("ScreenRect is : %s,%s | %s,%s", pos.x(), pos.y(),
               pos.width(), pos.height())
     pos = QCursor.pos()
     log.trace("Cursor is : %s,%s", pos.x(), pos.y())
     if not rect.contains(pos) or (rect.x() == 0 and rect.y() == 0):
         # Avoid any modulo 0
         if rect.width() == 0 or rect.height() == 0:
             rect = QRect(pos.x(), pos.y(), rect.width(), rect.height())
         else:
             rect = QRect(pos.x() - pos.x() % rect.width(),
                          pos.y() - pos.y() % rect.height(), rect.width(),
                          rect.height())
         log.trace("Adjusting X/Y to %d/%d", rect.x(), rect.y())
         pos = rect
         log.trace("New rect is : %s,%s | %s,%s", pos.x(), pos.y(),
                   pos.width(), pos.height())
     x = rect.x() + rect.width() - self.width()
     y = rect.y() - self.height()
     # Prevent the systray to be hidden
     if y < 0:
         y = rect.y() + rect.height()
     if x < 0:
         x = rect.x()
     log.trace("Move systray menu to %d/%d", x, y)
     self.move(x, y)
Esempio n. 9
0
 def paintVerticalSection(self, painter: QPainter, sectionRect: QRect,
                          logicalLeafIndex: int, hv: QHeaderView,
                          styleOptions: QStyleOptionHeader,
                          leafIndex: QModelIndex):
     oldBO = painter.brushOrigin()
     left = sectionRect.x()
     indexes = QModelIndexList(self.parentIndexes(leafIndex))
     for i in range(indexes.size()):
         realStyleOptions = QStyleOptionHeader(styleOptions)
         if i < indexes.size() - 1 and (
                 realStyleOptions.state & QStyle.State_Sunken
                 or realStyleOptions.state & QStyle.State_On):
             t = QStyle.State(QStyle.State_Sunken | QStyle.State_On)
             realStyleOptions.state = realStyleOptions.state & ~t  #FIXME: parent items are not highlighted
         left = self.paintVerticalCell(painter, hv, indexes[i],
                                       leafIndex, logicalLeafIndex,
                                       realStyleOptions, sectionRect,
                                       left)
     painter.setBrushOrigin(oldBO)
Esempio n. 10
0
File: gui.py Progetto: jianlins/lpfw
 def paint (self, painter, option, index):
     model = index.model()
     item = model.data(index).toPyObject()
     if item == None:
         return
     text = str(item)
     if (len(text) > 6):
         # take only megabytes -->12<--345678
         mb = text[:len(text)-6]
         bytes = text[len(text)-6:]
         painter.setPen (Qt.red)
         painter.drawText (option.rect,Qt.AlignHCenter and Qt.AlignVCenter, mb)
         painter.setPen (Qt.black)
         rect = QRect()
         rect = option.rect
         rect.setX(rect.x()+8*(len(mb)))  
         painter.drawText (rect, Qt.AlignHCenter and Qt.AlignVCenter, bytes)
     else:
         painter.drawText (option.rect, Qt.AlignHCenter and Qt.AlignVCenter, text)
Esempio n. 11
0
 def paint (self, painter, option, index):
     model = index.model()
     item = model.data(index).toPyObject()
     if item == None:
         return
     text = str(item)
     if (len(text) > 6):
         # take only megabytes -->12<--345678
         mb = text[:len(text)-6]
         bytes = text[len(text)-6:]
         painter.setPen (Qt.red)
         painter.drawText (option.rect,Qt.AlignHCenter and Qt.AlignVCenter, mb)
         painter.setPen (Qt.black)
         rect = QRect()
         rect = option.rect
         rect.setX(rect.x()+8*(len(mb)))  
         painter.drawText (rect, Qt.AlignHCenter and Qt.AlignVCenter, bytes)
     else:
         painter.drawText (option.rect, Qt.AlignHCenter and Qt.AlignVCenter, text)
Esempio n. 12
0
class BrushingModel(QObject):
    brushSizeChanged     = pyqtSignal(int)
    brushColorChanged    = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged   = pyqtSignal(int)
    
    minBrushSize       = 1
    maxBrushSize       = 61
    defaultBrushSize   = 3
    defaultDrawnNumber = 1
    defaultColor       = Qt.white
    erasingColor       = Qt.black
    erasingNumber      = 100
    
    def __init__(self):
        QObject.__init__(self)
        self.sliceRect = None
        self.bb    = QRect() #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        
        self.drawOnto = None
        
        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not(self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)
    
    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)
    
    def setDrawnNumber(self, num):
        print "Setting Drawnnumer", num
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)
        
    def getBrushSize(self):
        return self.brushSize
    
    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b-1)
        
    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b+1)
        
    def setBrushColor(self, color):
        self.drawColor = color
        self.brushColorChanged.emit(self.drawColor)
    
    def beginDrawing(self, pos, sliceRect):
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001)
        line = self.moveTo(pos)
        return line

    def endDrawing(self, pos):
        self.moveTo(pos)

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height())))
        painter.end()
        
        ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0]
        labels = numpy.where(ndarr>0,numpy.uint8(self.drawnNumber),numpy.uint8(0))
        labels = labels.swapaxes(0,1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        oldX, oldY = self.pos.x(), self.pos.y()
        x,y = pos.x(), pos.y()
        
        #print "BrushingModel.moveTo(pos=%r)" % (pos) 
        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)

        #update bounding Box 
        if not self.bb.isValid():
            self.bb = QRect(QPoint(x,y), QSize(1,1))
        #grow bounding box
        self.bb.setLeft(  min(self.bb.left(),   max(0,                   x-self.brushSize/2-1) ) )
        self.bb.setRight( max(self.bb.right(),  min(self.sliceRect[0]-1, x+self.brushSize/2+1) ) )
        self.bb.setTop(   min(self.bb.top(),    max(0,                   y-self.brushSize/2-1) ) )
        self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize/2+1) ) )
        
        #update/move position
        self.pos = pos
Esempio n. 13
0
class ImagePatch(object):    
    """
    A tile/patch that makes up the whole 2D scene as displayed in ImageScene2D.
   
    An ImagePatch has a bounding box (self.rect, self.rectF) and
    its image content is either represented by a QImage (in software rendering)
    or via an OpenGL texture.
    
    When the current image content becomes invalid or is currently
    being overwritten, the patch becomes dirty.
    """ 
    
    def __init__(self, rectF):
        assert(type(rectF) == QRectF)
        
        self.rectF  = rectF
        self.rect   = QRect(round(rectF.x()),     round(rectF.y()), \
                            round(rectF.width()), round(rectF.height()))
        self._image  = QImage(self.rect.width(), self.rect.height(), QImage.Format_ARGB32_Premultiplied)
        self.texture = -1
        self.dirty = True
        self.mutex = QMutex()

    @property
    def height(self):
        return self.rect.height()
    
    @property
    def width(self):
        return self.rect.width()

    def drawTexture(self):
        """
        Renders the current context as a texture. 
        Precondition: OpenGL mode and OpenGL context active.
        """
        
        tx = self.rect.x()
        ty = self.rect.y()
        w = self.rect.width()
        h = self.rect.height()
        glBindTexture(GL_TEXTURE_2D, self.texture)
        glBegin(GL_QUADS)
        glTexCoord2f(0.0, 1.0)
        glVertex2f(tx, ty)
        glTexCoord2f(1.0, 1.0)
        glVertex2f(tx + w, ty)
        glTexCoord2f(1.0, 0.0)
        glVertex2f(tx + w, ty + h)
        glTexCoord2f(0.0, 0.0)
        glVertex2f(tx, ty + h)
        glEnd()

    @property
    def image(self):
        return self._image
    
    @image.setter
    def image(self, img):
        self._image = img
        self.dirty = False
Esempio n. 14
0
class XSnapshotWidget(QWidget):
    def __init__(self, parent=None):
        super(XSnapshotWidget, self).__init__(parent)
        
        # define custom properties
        self._region = QRect()
        self._filepath = ''
        
        # define custom properties
        palette = self.palette()
        palette.setColor(palette.Window, QColor('white'))
        self.setPalette(palette)
        self.setWindowOpacity(0.5)
        self.setWindowFlags(Qt.SplashScreen)
        self.setFocus()
    
    def accept(self):
        """
        Prompts the user for the filepath to save and then saves the image.
        """
        filetypes = 'PNG Files (*.png);;JPG Files (*.jpg);;All Files (*.*)'
        filename = QFileDialog.getSaveFileName(None,
                                               'Save Snapshot',
                                               self.filepath(),
                                               filetypes)
        
        if type(filename) == tuple:
            filename = filename[0]
        
        filename = str(filename)
        if not filename:
            self.reject()
        else:
            self.setFilepath(filename)
            self.save()
    
    def filepath(self):
        """
        Returns the filepath that is going to be asved for this snapshot widget.
        
        :return     <str>
        """
        return self._filepath
    
    def hideWindow(self):
        """
        Sets the window to hide/show while taking the snapshot.
        
        :param      window | <QMainWindow> || <QDialog>
        """
        return self._hideWindow
    
    def keyPressEvent(self, event):
        """
        Listens for the escape key to cancel out from this snapshot.
        
        :param      event | <QKeyPressEvent>
        """
        # reject on a cancel
        if event.key() == Qt.Key_Escape:
            self.reject()
        
        super(XSnapshotWidget, self).keyPressEvent(event)
    
    def mousePressEvent(self, event):
        """
        Starts the selection process for this widget and snapshot area.
        
        :param      event | <QMousePressEvent>
        """
        self._region.setX(event.pos().x())
        self._region.setY(event.pos().y())
        super(XSnapshotWidget, self).mousePressEvent(event)
    
    def mouseMoveEvent(self, event):
        """
        Drags the selection view for this widget.
        
        :param      event | <QMouseMoveEvent>
        """
        w = event.pos().x() - self._region.x()
        h = event.pos().y() - self._region.y()
        
        self._region.setWidth(w)
        self._region.setHeight(h)
        self.repaint()
        
        super(XSnapshotWidget, self).mouseMoveEvent(event)
    
    def mouseReleaseEvent(self, event):
        """
        Finishes the selection event.
        
        :param      event | <QMouseReleaseEvent>
        """
        self.accept()
        super(XSnapshotWidget, self).mouseReleaseEvent(event)
    
    def paintEvent(self, event):
        """
        Handles the drawing for this widget and its selection region.
        
        :param      event | <QPaintEvent>
        """
        pen = QPen(Qt.DashLine)
        pen.setColor(QColor('red'))
        painter = QPainter(self)
        painter.setPen(pen)
        clr = QColor('black')
        clr.setAlpha(100)
        painter.setBrush(clr)
        
        painter.drawRect(self._region)
    
    def reject(self):
        """
        Rejects the snapshot and closes the widget.
        """
        if self.hideWindow():
            self.hideWindow().show()
            
        self.close()
        self.deleteLater()
    
    def region(self):
        """
        Returns the selection region defined by the rectangle for snapshoting.
        
        :return     <QRect>
        """
        return self._region
    
    def save(self):
        """
        Saves the snapshot based on the current region.
        """
        # close down the snapshot widget
        if self.hideWindow():
            self.hideWindow().hide()
        
        self.hide()
        QApplication.processEvents()
        time.sleep(1)
        
        # create the pixmap to save
        wid = QApplication.desktop().winId()
        
        if not self._region.isNull():
            x = self._region.x()
            y = self._region.y()
            w = self._region.width()
            h = self._region.height()
        else:
            x = self.x()
            y = self.y()
            w = self.width()
            h = self.height()
        
        pixmap = QPixmap.grabWindow(wid, x, y, w, h)
        pixmap.save(self.filepath())
        
        self.close()
        self.deleteLater()
        if self.hideWindow():
            self.hideWindow().show()
    
    def show(self):
        """
        Shows this widget and hides the specified window if necessary.
        """
        super(XSnapshotWidget, self).show()
        
        if self.hideWindow():
            self.hideWindow().hide()
            QApplication.processEvents()
    
    def setFilepath(self, filepath):
        """
        Sets the filepath that will be saved for this snapshot.
        
        :param      filepath | <str>
        """
        self._filepath = filepath
    
    def setHideWindow(self, window):
        """
        Sets the window that will be hidden while this snapshot is being
        taken.
        
        :param      window | <QMainWindow>
        """
        self._hideWindow = window
    
    def setRegion(self, rect):
        """
        Sets the region rectangle to the inputed rect.
        
        :param      rect | <QRect>
        """
        if rect is not None:
            self._region = rect
    
    @staticmethod
    def capture(rect=None, filepath='', prompt=True, hideWindow=None):
        """
        Prompts the user to capture the screen.
        
        :param      rect     | <QRect>
                    filepath | <str>
                    prompt   | <bool>
        
        :return     (<str> filepath, <bool> accepted)
        """
        widget = XSnapshotWidget(QApplication.desktop())
        widget.setRegion(rect)
        widget.setHideWindow(hideWindow)
        widget.setFilepath(filepath)
        widget.move(1, 1)
        widget.resize(QApplication.desktop().size())
        
        if prompt or not filepath:
            widget.show()
        else:
            widget.save()
Esempio n. 15
0
    def __layout(self):
        # position itself over `widget`
        widget = self.__widget
        if widget is None:
            return

        alignment = self.__alignment
        policy = self.sizePolicy()

        if widget.isWindow():
            bounds = widget.geometry()
        else:

            bounds = QRect(widget.mapToGlobal(QPoint(0, 0)),
                           widget.size())
        if self.isWindow():
            bounds = bounds
        else:
            bounds = QRect(self.parent().mapFromGlobal(bounds.topLeft()),
                           bounds.size())

        sh = self.sizeHint()
        minsh = self.minimumSizeHint()
        minsize = self.minimumSize()
        if minsize.isNull():
            minsize = minsh
        maxsize = bounds.size().boundedTo(self.maximumSize())
        minsize = minsize.boundedTo(maxsize)
        effectivesh = sh.expandedTo(minsize).boundedTo(maxsize)

        hpolicy = policy.horizontalPolicy()
        vpolicy = policy.verticalPolicy()

        def getsize(hint, minimum, maximum, policy):
            if policy == QSizePolicy.Ignored:
                return maximum
            elif policy & QSizePolicy.ExpandFlag:
                return maximum
            else:
                return max(hint, minimum)

        width = getsize(effectivesh.width(), minsize.width(),
                        maxsize.width(), hpolicy)

        heightforw = self.heightForWidth(width)
        if heightforw > 0:
            height = getsize(heightforw, minsize.height(),
                             maxsize.height(), vpolicy)
        else:
            height = getsize(effectivesh.height(), minsize.height(),
                             maxsize.height(), vpolicy)

        size = QSize(width, height)
        if alignment & Qt.AlignLeft:
            x = bounds.x()
        elif alignment & Qt.AlignRight:
            x = bounds.right() - size.width()
        else:
            x = bounds.x() + max(0, bounds.width() - size.width()) // 2

        if alignment & Qt.AlignTop:
            y = bounds.y()
        elif alignment & Qt.AlignBottom:
            y = bounds.bottom() - size.height()
        else:
            y = bounds.y() + max(0, bounds.height() - size.height()) // 2

        geom = QRect(QPoint(x, y), size)
        self.setGeometry(geom)
Esempio n. 16
0
def paintVerticalSection(self, painter: QPainter, sectionRect: QRect, logicalLeafIndex: int, hv: QHeaderView, styleOptions: QStyleOptionHeader, leafIndex: QModelIndex):
oldBO = painter.brushOrigin()
left = sectionRect.x()
indexes = QModelIndexList(self.parentIndexes(leafIndex))
for i in range(indexes.size()):
    realStyleOptions = QStyleOptionHeader(styleOptions)
    if i<indexes.size()-1 and (realStyleOptions.state&QStyle.State_Sunken or realStyleOptions.state&QStyle.State_On):
        t = QStyle.State(QStyle.State_Sunken | QStyle.State_On)
        realStyleOptions.state = realStyleOptions.state&~t #FIXME: parent items are not highlighted
    left=self.paintVerticalCell(painter, hv, indexes[i], leafIndex, logicalLeafIndex, realStyleOptions, sectionRect, left)
painter.setBrushOrigin(oldBO)

def __init__(self, orientation: Qt.Orientation, parent: QWidget):
super().__init__(orientation, parent)
self._pd = self.private_data()
self.sectionResized.connect(self.on_sectionResized)
self.setHighlightSections(self.options.get("highlightSections"))
self.setClickable(self.options.get("clickable"))
self.show() #force to be visible
getattr(parent, "set%sHeader"%("Horizontal", "Vertical")[orientation!=Qt.Horizontal])(self)
self.sectionMoved.connect(self.on_sectionMoved)

def on_sectionMoved(self, logicalIndex, oldVisualIndex, newVisualIndex):
    view, model = self.parent(), self.parent().model()
    if not hasattr(model, "reorder"):
        return #reorder underlying data of models with /reorder/ def only
    if getattr(self, "manual_move", False):
        self.manual_move=False
        return
    self.manual_move=True
    self.moveSection(newVisualIndex, oldVisualIndex) #cancel move
    if model.reorder(oldVisualIndex, newVisualIndex, self.orientation()):
        #Reorder column widths / row heights
        horizontal = self.orientation()==Qt.Horizontal
        itemSize = (view.rowHeight, view.columnWidth)[horizontal]
        setItemSize = (view.setRowHeight, view.setColumnWidth)[horizontal]
        rng = sorted((oldVisualIndex, newVisualIndex))
        options = [(itemSize(i), i) for i in range(rng[0], rng[1]+1)]
        options.insert(newVisualIndex-rng[0], options.pop(oldVisualIndex-rng[0]))
        for i, col in enumerate(range(rng[0], rng[1]+1)):
            setItemSize(col, options[i][0])
        getattr(view, "select"+("Row", "Column")[horizontal])(newVisualIndex) #FIXME: don't select if sorting is enable?
        if self.isSortIndicatorShown():
            sortIndIndex = next((i for i, o in enumerate(options) if o[1]==self.sortIndicatorSection()), None)
            if sortIndIndex is not None: #sort indicator is among sections being reordered
                self.setSortIndicator(sortIndIndex+rng[0], self.sortIndicatorOrder()) #FIXME: does unnecessary sorting
        model.layoutChanged.emit() #update view

def styleOptionForCell(self, logicalInd: int)->QStyleOptionHeader:
opt = QStyleOptionHeader()
self.initStyleOption(opt)
if self.isSortIndicatorShown() and self.sortIndicatorSection()==logicalInd:
    opt.sortIndicator = (QStyleOptionHeader.SortUp, QStyleOptionHeader.SortDown)[self.sortIndicatorOrder()==Qt.AscendingOrder]
if self.window().isActiveWindow():
    opt.state = opt.state|QStyle.State_Active
opt.textAlignment = Qt.AlignCenter
opt.iconAlignment = Qt.AlignVCenter
opt.section = logicalInd
visual = self.visualIndex(logicalInd)
if self.count() == 1:
    opt.position = QStyleOptionHeader.OnlyOneSection
else:
    if visual == 0:
        opt.position = QStyleOptionHeader.Beginning
    else:
        opt.position = QStyleOptionHeader.End if visual==self.count()-1 else QStyleOptionHeader.Middle
if self.isClickable():
    #            if logicalIndex == d.hover:
    #            ...
    if self.highlightSections() and self.selectionModel():
        if self.orientation()==Qt.Horizontal:
            if self.selectionModel().columnIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isColumnSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
        else:
            if self.selectionModel().rowIntersectsSelection(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_On
            if self.selectionModel().isRowSelected(logicalInd, self.rootIndex()):
                opt.state = opt.state|QStyle.State_Sunken
if self.selectionModel():
    previousSelected=False
    if self.orientation()==Qt.Horizontal:
        previousSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual - 1), self.rootIndex())
    else:
        previousSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual - 1), self.rootIndex())
    nextSelected=False
    if self.orientation()==Qt.Horizontal:
        nextSelected = self.selectionModel().isColumnSelected(self.logicalIndex(visual + 1), self.rootIndex())
    else:
        nextSelected = self.selectionModel().isRowSelected(self.logicalIndex(visual + 1), self.rootIndex())
    if previousSelected and nextSelected:
        opt.selectedPosition = QStyleOptionHeader.NextAndPreviousAreSelected
    else:
        if previousSelected:
            opt.selectedPosition = QStyleOptionHeader.PreviousIsSelected
        else:
            if nextSelected:
                opt.selectedPosition = QStyleOptionHeader.NextIsSelected
            else:
                opt.selectedPosition = QStyleOptionHeader.NotAdjacent
return opt

def sectionSizeFromContents(self, logicalIndex: int)->QSize:
if self._pd.headerModel:
    curLeafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if curLeafIndex.isValid():
        styleOption = QStyleOptionHeader(self.styleOptionForCell(logicalIndex))
        s = QSize(self._pd.cellSize(curLeafIndex, self, styleOption))
        curLeafIndex=curLeafIndex.parent()
        while curLeafIndex.isValid():
            if self.orientation() == Qt.Horizontal:
                s.setHeight(s.height()+self._pd.cellSize(curLeafIndex, self, styleOption).height())
            else:
                s.setWidth(s.width()+self._pd.cellSize(curLeafIndex, self, styleOption).width())
            curLeafIndex=curLeafIndex.parent()
        return s
return super().sectionSizeFromContents(logicalIndex)

def paintSection(self, painter: QPainter, rect: QRect, logicalIndex: int):
if rect.isValid():
    leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
    if leafIndex.isValid():
        if self.orientation() == Qt.Horizontal:
            self._pd.paintHorizontalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        else:
            self._pd.paintVerticalSection(painter, rect, logicalIndex, self, self.styleOptionForCell(logicalIndex), leafIndex)
        return
super().paintSection(painter, rect, logicalIndex)

def on_sectionResized(self, logicalIndex: int):
if self.isSectionHidden(logicalIndex):
    return
leafIndex = QModelIndex(self._pd.leafIndex(logicalIndex))
if leafIndex.isValid():
    leafsList = QModelIndexList(self._pd.leafs(self._pd.findRootIndex(leafIndex)))
    for n in range(leafsList.indexOf(leafIndex), 0, -1):
        logicalIndex-=1
        w = self.viewport().width()
        h = self.viewport().height()
        pos = self.sectionViewportPosition(logicalIndex)
        r = QRect(pos, 0, w - pos, h)
        if self.orientation() == Qt.Horizontal:
            if self.isRightToLeft():
                r.setRect(0, 0, pos + self.sectionSize(logicalIndex), h)
        else:
            r.setRect(0, pos, w, h - pos)
        self.viewport().update(r.normalized())

def setModel(self, model):
    super().setModel(model)
    model.layoutChanged.connect(self.layoutChanged)
    self.layoutChanged()

def layoutChanged(self):
    if self.model():
        self._pd.initFromNewModel(self.orientation(), self.model())
        axis = ("column", "row")[self.orientation()!=Qt.Horizontal]
        cnt = getattr(self.model(), axis+"Count")(QModelIndex())
        if cnt:
            self.initializeSections(0, cnt-1)
MultiIndexHeaderView=HierarchicalHeaderView

class DataFrameModel(QtCore.QAbstractTableModel):
    #na_values:least|greatest - for sorting
    options = {"striped": True, "stripesColor": "#fafafa", "na_values": "least",
               "tooltip_min_len": 21}
    def __init__(self, dataframe=None):
        super().__init__()
        self.setDataFrame(dataframe if dataframe is not None else pd.DataFrame())

    def setDataFrame(self, dataframe):
        self.df = dataframe.copy()
        #        self.df_full = self.df
        self.layoutChanged.emit()

    def rowCount(self, parent):
        return len(self.df)

    def columnCount(self, parent):
        return len(self.df.columns)

    def readLevel(self, y=0, xs=0, xe=None, orient=None):
        c = getattr(self.df, ("columns", "index")[orient!=HorizontalHeaderDataRole])
        if not hasattr(c, "levels"): #not MultiIndex
            return [QtGui.QStandardItem(str(i)) for i in c]
        sibl = []
        section_start, v, xe = xs, None, xe or len(c)
        for i in range(xs, xe):
            label = c.labels[y][i]
            if label!=v:
                if y+1<len(c.levels) and i>xs:
                    children = self.readLevel(y+1, section_start, i, orient=orient)
                    sibl[-1].appendRow(children)
                item = QtGui.QStandardItem(str(c.levels[y][label]))
                sibl.append(item)
                section_start = i
                v=label
        if y+1<len(c.levels):
            children = self.readLevel(y+1, section_start, orient=orient)
            sibl[-1].appendRow(children)
        return sibl

    def data(self, index, role):
        row, col = index.row(), index.column()
        if role in (Qt.DisplayRole, Qt.ToolTipRole):
            ret = self.df.iat[row, col]
            if ret is not None and ret==ret: #convert to str except for None, NaN, NaT
                if isinstance(ret, float):
                    ret = "{:n}".format(ret)
                elif isinstance(ret, datetime.date):
                    #FIXME: show microseconds optionally
                    ret = ret.strftime(("%x", "%c")[isinstance(ret, datetime.datetime)])
                else: ret = str(ret)
                if role == Qt.ToolTipRole:
                    if len(ret)<self.options["tooltip_min_len"]: ret = ""
                return ret
        elif role == Qt.BackgroundRole:
            if self.options["striped"] and row%2:
                return QBrush(QColor(self.options["stripesColor"]))
        elif role in (HorizontalHeaderDataRole, VerticalHeaderDataRole):
            hm = QtGui.QStandardItemModel()
            hm.appendRow(self.readLevel(orient=role))
            return hm

    def reorder(self, oldIndex, newIndex, orientation):
        "Reorder columns / rows"
        horizontal = orientation==Qt.Horizontal
        cols = list(self.df.columns if horizontal else self.df.index)
        cols.insert(newIndex, cols.pop(oldIndex))
        self.df = self.df[cols] if horizontal else self.df.T[cols].T
        return True

    #    def filter(self, filt=None):
    #        self.df = self.df_full if filt is None else self.df[filt]
    #        self.layoutChanged.emit()

    def headerData(self, section, orientation, role):
        if role != Qt.DisplayRole: return
        label = getattr(self.df, ("columns", "index")[orientation!=Qt.Horizontal])[section]
        #        return label if type(label) is tuple else label
        return ("\n", " | ")[orientation!=Qt.Horizontal].join(str(i) for i in label) if type(label) is tuple else str(label)

    def dataFrame(self):
        return self.df

    def sort(self, column, order):
        #        print("sort", column, order) #FIXME: double sort after setSortingEnabled(True)
        if len(self.df):
            asc = order==Qt.AscendingOrder
            na_pos = 'first' if (self.options["na_values"]=="least")==asc else 'last'
            self.df.sort_values(self.df.columns[column], ascending=asc,
                                inplace=True, na_position=na_pos)
            self.layoutChanged.emit()

if __name__=="__main__":
    import sys, locale
    locale.setlocale(locale.LC_ALL, '') #system locale settings
    app = QtGui.QApplication(sys.argv)
    form = QtGui.QWidget()
    form.setAttribute(Qt.WA_DeleteOnClose) #http://stackoverflow.com/a/27178019/1119602
    form.setMinimumSize(700, 260)
    view = QtGui.QTableView()
    QtGui.QVBoxLayout(form).addWidget(view)
    form.show()

    #Prepare data
    tuples=[('bar', 'one', 'q'), ('bar', 'two', 'q'), ('baz', 'one', 'q'), ('baz', 'two', 'q'),
            ('foo', 'one', 'q'), ('foo', 'two', 'q'), ('qux', 'one', 'q'), ('qux', 'two', 'q')]
    index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second', 'third'])
    df=pd.DataFrame(pd.np.random.randn(6, 6), index=index[:6], columns=index[:6])
    print("DataFrame:\n%s"%df)

    #Prepare view
    #    oldh, oldv = view.horizontalHeader(), view.verticalHeader()
    #    oldh.setParent(form), oldv.setParent(form) #Save old headers for some reason
    MultiIndexHeaderView(Qt.Horizontal, view)
    MultiIndexHeaderView(Qt.Vertical, view)
    view.horizontalHeader().setMovable(True) #reorder DataFrame columns manually

    #Set data
    view.setModel(DataFrameModel(df))
    view.resizeColumnsToContents()
    view.resizeRowsToContents()

    #Set sorting enabled (after setting model)
    view.setSortingEnabled(True)
    sys.exit(app.exec())
Esempio n. 17
0
class BrushingModel(QObject):
    brushSizeChanged     = pyqtSignal(int)
    brushColorChanged    = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged   = pyqtSignal(int)

    minBrushSize       = 1
    maxBrushSize       = 61
    defaultBrushSize   = 3
    defaultDrawnNumber = 1
    defaultColor       = Qt.white
    erasingColor       = Qt.black
    erasingNumber      = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb    = QRect() #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not(self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b-1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b+1)

    def setBrushColor(self, color):
        self.drawColor = color
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        '''

        pos -- QPointF-like
        '''
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert(self.pos == pos)
            self.moveTo(QPointF(pos.x()+0.0001, pos.y()+0.0001)) # move a little

        tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter, target=QRectF(), source=QRectF(QPointF(self.bb.x(), self.bb.y()), QSizeF(self.bb.width(), self.bb.height())))
        painter.end()

        ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0]
        labels = numpy.where(ndarr>0,numpy.uint8(self.drawnNumber),numpy.uint8(0))
        labels = labels.swapaxes(0,1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0:
            labels[labels.shape[0]//2, labels.shape[1]//2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        #data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x,y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        #update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX,oldY), QSize(1,1))
        #grow bounding box
        self.bb.setLeft(  min(self.bb.left(),   max(0,                   x-self.brushSize/2-1) ) )
        self.bb.setRight( max(self.bb.right(),  min(self.sliceRect[0]-1, x+self.brushSize/2+1) ) )
        self.bb.setTop(   min(self.bb.top(),    max(0,                   y-self.brushSize/2-1) ) )
        self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize/2+1) ) )

        #update/move position
        self.pos = pos
Esempio n. 18
0
class EdittableTimeLine(TimeLine):
    """ Adds items from mouse events. """

    _draw_box = None
    snap_frames = None
    box_color = QColor('yellow')

    def __init__(self, parent=None):
        TimeLine.__init__(self, parent)
        self.setMouseTracking(False)

    def paintEvent(self, e):
        TimeLine.paintEvent(self, e)
        if self._draw_box:
            painter = QPainter(self)
            color = QColor(self.box_color)
            color.setAlpha(100)
            painter.setPen(color)
            color.setAlpha(50)
            painter.setBrush(color)
            painter.drawRect(self._draw_box)

    def snap(self, frame):
        """ snap to the closest multiple of snap_frames """
        after = self.clock.last_beat_frame
        while after < frame:
            after += self.snap_frames
        before = after - self.snap_frames
        if frame - before < after - frame:
            return before
        else:
            return after
            
    def mousePressEvent(self, e):
        self.stop()
        self._draw_box = QRect(e.x(), 0, 15, self.height())
        self.update()
        
    def mouseMoveEvent(self, e):
        x, y = self._draw_box.x(), 0
        w, h = e.x() - self._draw_box.x(), self.height()
        self._draw_box = QRect(x, y ,w, h)
        self.update()

    def mouseDoubleClickEvent(self, e):
        """ add an infinite item """

    def mouseReleaseEvent(self, e):
        if self._draw_box is None:
            return # OS X
        self.start()
        startframe = self.frametime_for_x(self._draw_box.x())
        endframe = self.frametime_for_x(e.x())
        if self.snap_frames:
            startframe = self.snap(startframe)
            endframe = self.snap(endframe)

        item = Item()
        item.starttime = startframe
        item.endtime = endframe
        self.add(item)
        self.emit(SIGNAL('newItem(int, int)'), startframe, endframe)
        self._draw_box = None
        self.update()
Esempio n. 19
0
class BrushingModel(QObject):
    brushSizeChanged     = pyqtSignal(int)
    brushColorChanged    = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged   = pyqtSignal(int)

    minBrushSize       = 1
    maxBrushSize       = 61
    defaultBrushSize   = 3
    defaultDrawnNumber = 1
    defaultColor       = Qt.white
    erasingColor       = Qt.black
    erasingNumber      = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb    = QRect() #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not(self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b-1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b+1)

    def setBrushColor(self, color):
        self.drawColor = color
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        '''

        pos -- QPointF-like
        '''
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert(self.pos == pos)
            self.moveTo(QPointF(pos.x()+0.0001, pos.y()+0.0001)) # move a little

        # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage.
        # We seem to get better results if we do the following:
        # 1) Slightly offset the source window because apparently there is a small shift in the data
        # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x)
        # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image,
        #     applying some threshold to determine if the final pixel is on or off. 

        tempi = QImage(QSize(4*self.bb.width(), 4*self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        # Offset the source window.  At first I thought the right offset was 0.5, because 
        #  that would seem to make sure points are rounded to pixel CENTERS, but 
        #  experimentation indicates that 0.25 is slightly better for some reason...
        source_rect = QRectF( QPointF(self.bb.x()+0.25, self.bb.y()+0.25), 
                              QSizeF(self.bb.width(), self.bb.height()) )
        target_rect = QRectF( QPointF(0,0),
                             QSizeF(4*self.bb.width(), 4*self.bb.height()) )
        self.scene.render(painter, target=target_rect, source=source_rect)
        painter.end()

        # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing
        ndarr = qimage2ndarray.rgb_view(tempi)[:,:,0].astype(int)
        ndarr = ndarr.reshape( (ndarr.shape[0],) + (ndarr.shape[1]//4,) + (4,) )
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr = ndarr.reshape( (ndarr.shape[0],) + (ndarr.shape[1]//4,) + (4,) )
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr //= 4*4

        downsample_threshold = (7./16)*255
        labels = numpy.where(ndarr>=downsample_threshold, numpy.uint8(self.drawnNumber), numpy.uint8(0))
        labels = labels.swapaxes(0,1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(labels) == 0:
            labels[labels.shape[0]//2, labels.shape[1]//2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()), labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        #data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x,y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(QPen( QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        #update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX,oldY), QSize(1,1))
        #grow bounding box
        self.bb.setLeft(  min(self.bb.left(),   max(0,                   x-self.brushSize//2-1) ) )
        self.bb.setRight( max(self.bb.right(),  min(self.sliceRect[0]-1, x+self.brushSize//2+1) ) )
        self.bb.setTop(   min(self.bb.top(),    max(0,                   y-self.brushSize//2-1) ) )
        self.bb.setBottom(max(self.bb.bottom(), min(self.sliceRect[1]-1, y+self.brushSize//2+1) ) )

        #update/move position
        self.pos = pos
Esempio n. 20
0
class BrushingModel(QObject):
    brushSizeChanged = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged = pyqtSignal(int)

    minBrushSize = 1
    maxBrushSize = 61
    defaultBrushSize = 3
    defaultDrawnNumber = 1
    defaultColor = Qt.white
    erasingColor = Qt.black
    erasingNumber = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb = QRect()  #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not (self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b - 1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b + 1)

    def setBrushColor(self, color):
        self.drawColor = color
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        '''

        pos -- QPointF-like
        '''
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved  # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert (self.pos == pos)
            self.moveTo(QPointF(pos.x() + 0.0001,
                                pos.y() + 0.0001))  # move a little

        tempi = QImage(QSize(self.bb.width(), self.bb.height()),
                       QImage.Format_ARGB32_Premultiplied)  #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        self.scene.render(painter,
                          target=QRectF(),
                          source=QRectF(
                              QPointF(self.bb.x(), self.bb.y()),
                              QSizeF(self.bb.width(), self.bb.height())))
        painter.end()

        ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0]
        labels = numpy.where(ndarr > 0, numpy.uint8(self.drawnNumber),
                             numpy.uint8(0))
        labels = labels.swapaxes(0, 1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(
                labels) == 0:
            labels[labels.shape[0] // 2,
                   labels.shape[1] // 2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()),
                                       labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        #data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x, y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(
            QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap,
                 Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        #update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1))
        #grow bounding box
        self.bb.setLeft(min(self.bb.left(), max(0,
                                                x - self.brushSize / 2 - 1)))
        self.bb.setRight(
            max(self.bb.right(),
                min(self.sliceRect[0] - 1, x + self.brushSize / 2 + 1)))
        self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize / 2 - 1)))
        self.bb.setBottom(
            max(self.bb.bottom(),
                min(self.sliceRect[1] - 1, y + self.brushSize / 2 + 1)))

        #update/move position
        self.pos = pos
Esempio n. 21
0
    def paintEvent(self, e):
        """ """
        PKWidget.paintEvent(self, e)

        painter = QPainter(self)
        orig_pen = QPen(painter.pen())
        orig_brush = QBrush(painter.brush())
        orig_font = QFont(painter.font())
        metrics = painter.fontMetrics()
        f_height = metrics.ascent()
        text_flags = Qt.AlignHCenter | Qt.AlignVCenter
        
        region = e.region()
        for item in self._shown:
            font_y = item.y + item.height / 2 + f_height / 2

            item_rect = QRect(0, item.y, self.width(), item.height)
            if not region.contains(item_rect):
                continue

            painter.setFont(orig_font)

            # background
            pen = item.color().dark(110)
            pen.setAlpha(100)
            painter.setBrush(QBrush(item.color()))
            painter.setPen(QPen(pen))
            w = self.width() * (item.progress * .01)
            rect = QRect(0, item.y, w, item.height)
            painter.drawRect(rect)

            # queue pos
            pen = pen.dark(140)
            pen.setAlpha(255)
            painter.setPen(QPen(pen))
            queue_rect = QRect(self.padding, item.y + self.padding,
                               item.height - self.padding * 2,
                               item.height - self.padding * 2)
            painter.drawRoundRect(queue_rect, 35, 35)

            # num
            if not item.num is None:
                painter.setPen(orig_pen)
                painter.setBrush(orig_brush)
                painter.drawText(queue_rect, text_flags, str(item.num))

            # text
            painter.setPen(orig_pen)
            painter.setBrush(orig_brush)
            font = QFont('Utopia, Italic', 14, -1, True)
            painter.setFont(font)
            rect = QRect(item_rect)
            rect.setX(item.height + self.padding * 2)
            rect.setWidth(rect.width() - rect.x())
            painter.drawText(rect, Qt.AlignVCenter | Qt.AlignLeft, item.text)

            # state
            if item.state:
                font = QFont('7th Service Expanded Italic, Italic')
                font.setPointSize(18)
                pen = QColor(orig_pen.color())
                pen.setAlpha(50)
                painter.setPen(QPen(pen))
                painter.setFont(font)
                x = item.x
                y = item.y
                w = self.width()
                h = item.height
                rect = QRect(x, y, w, h)
                flags = Qt.AlignVCenter | Qt.AlignRight
                painter.drawText(rect, flags, item.state+'  ')
Esempio n. 22
0
class BrushingModel(QObject):
    brushSizeChanged = pyqtSignal(int)
    brushColorChanged = pyqtSignal(QColor)
    brushStrokeAvailable = pyqtSignal(QPointF, object)
    drawnNumberChanged = pyqtSignal(int)

    minBrushSize = 1
    maxBrushSize = 61
    defaultBrushSize = 3
    defaultDrawnNumber = 1
    defaultColor = Qt.white
    erasingColor = Qt.black
    erasingNumber = 100

    def __init__(self, parent=None):
        QObject.__init__(self, parent=parent)
        self.sliceRect = None
        self.bb = QRect()  #bounding box enclosing the drawing
        self.brushSize = self.defaultBrushSize
        self.drawColor = self.defaultColor
        self._temp_color = None
        self._temp_number = None
        self.drawnNumber = self.defaultDrawnNumber

        self.pos = None
        self.erasing = False
        self._hasMoved = False

        self.drawOnto = None

        #an empty scene, where we add all drawn line segments
        #a QGraphicsLineItem, and which we can use to then
        #render to an image
        self.scene = QGraphicsScene()

    def toggleErase(self):
        self.erasing = not (self.erasing)
        if self.erasing:
            self.setErasing()
        else:
            self.disableErasing()

    def setErasing(self):
        self.erasing = True
        self._temp_color = self.drawColor
        self._temp_number = self.drawnNumber
        self.setBrushColor(self.erasingColor)
        self.brushColorChanged.emit(self.erasingColor)
        self.setDrawnNumber(self.erasingNumber)

    def disableErasing(self):
        self.erasing = False
        self.setBrushColor(self._temp_color)
        self.brushColorChanged.emit(self.drawColor)
        self.setDrawnNumber(self._temp_number)

    def setBrushSize(self, size):
        self.brushSize = size
        self.brushSizeChanged.emit(self.brushSize)

    def setDrawnNumber(self, num):
        self.drawnNumber = num
        self.drawnNumberChanged.emit(num)

    def getBrushSize(self):
        return self.brushSize

    def brushSmaller(self):
        b = self.brushSize
        if b > self.minBrushSize:
            self.setBrushSize(b - 1)

    def brushBigger(self):
        b = self.brushSize
        if self.brushSize < self.maxBrushSize:
            self.setBrushSize(b + 1)

    def setBrushColor(self, color):
        self.drawColor = color
        self.brushColorChanged.emit(self.drawColor)

    def beginDrawing(self, pos, sliceRect):
        '''

        pos -- QPointF-like
        '''
        self.sliceRect = sliceRect
        self.scene.clear()
        self.bb = QRect()
        self.pos = QPointF(pos.x(), pos.y())
        self._hasMoved = False

    def endDrawing(self, pos):
        has_moved = self._hasMoved  # _hasMoved will change after calling moveTo
        if has_moved:
            self.moveTo(pos)
        else:
            assert (self.pos == pos)
            self.moveTo(QPointF(pos.x() + 0.0001,
                                pos.y() + 0.0001))  # move a little

        # Qt seems to use strange rules for determining which pixels to set when rendering a brush stroke to a QImage.
        # We seem to get better results if we do the following:
        # 1) Slightly offset the source window because apparently there is a small shift in the data
        # 2) Render the scene to an image that is MUCH larger than the scene resolution (4x by 4x)
        # 3) Downsample each 4x4 patch from the large image back to a single pixel in the final image,
        #     applying some threshold to determine if the final pixel is on or off.

        tempi = QImage(QSize(4 * self.bb.width(), 4 * self.bb.height()),
                       QImage.Format_ARGB32_Premultiplied)  #TODO: format
        tempi.fill(0)
        painter = QPainter(tempi)
        # Offset the source window.  At first I thought the right offset was 0.5, because
        #  that would seem to make sure points are rounded to pixel CENTERS, but
        #  experimentation indicates that 0.25 is slightly better for some reason...
        source_rect = QRectF(QPointF(self.bb.x() + 0.25,
                                     self.bb.y() + 0.25),
                             QSizeF(self.bb.width(), self.bb.height()))
        target_rect = QRectF(QPointF(0, 0),
                             QSizeF(4 * self.bb.width(), 4 * self.bb.height()))
        self.scene.render(painter, target=target_rect, source=source_rect)
        painter.end()

        # Now downsample: convert each 4x4 patch into a single pixel by summing and dividing
        ndarr = qimage2ndarray.rgb_view(tempi)[:, :, 0].astype(int)
        ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) +
                              (4, ))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr = ndarr.reshape((ndarr.shape[0], ) + (ndarr.shape[1] // 4, ) +
                              (4, ))
        ndarr = ndarr.sum(axis=-1)
        ndarr = ndarr.transpose()
        ndarr //= 4 * 4

        downsample_threshold = (7. / 16) * 255
        labels = numpy.where(ndarr >= downsample_threshold,
                             numpy.uint8(self.drawnNumber), numpy.uint8(0))
        labels = labels.swapaxes(0, 1)
        assert labels.shape[0] == self.bb.width()
        assert labels.shape[1] == self.bb.height()

        ##
        ## ensure that at least one pixel is label when the brush size is 1
        ##
        ## this happens when the user just clicked without moving
        ## in that case the lineitem will be so tiny, that it won't be rendered
        ## into a single pixel by the code above
        if not has_moved and self.brushSize <= 1 and numpy.count_nonzero(
                labels) == 0:
            labels[labels.shape[0] // 2,
                   labels.shape[1] // 2] = self.drawnNumber

        self.brushStrokeAvailable.emit(QPointF(self.bb.x(), self.bb.y()),
                                       labels)

    def dumpDraw(self, pos):
        res = self.endDrawing(pos)
        self.beginDrawing(pos, self.sliceRect)
        return res

    def moveTo(self, pos):
        #data coordinates
        oldX, oldY = self.pos.x(), self.pos.y()
        x, y = pos.x(), pos.y()

        line = QGraphicsLineItem(oldX, oldY, x, y)
        line.setPen(
            QPen(QBrush(Qt.white), self.brushSize, Qt.SolidLine, Qt.RoundCap,
                 Qt.RoundJoin))
        self.scene.addItem(line)
        self._hasMoved = True

        #update bounding Box
        if not self.bb.isValid():
            self.bb = QRect(QPoint(oldX, oldY), QSize(1, 1))
        #grow bounding box
        self.bb.setLeft(
            min(self.bb.left(), max(0, x - self.brushSize // 2 - 1)))
        self.bb.setRight(
            max(self.bb.right(),
                min(self.sliceRect[0] - 1, x + self.brushSize // 2 + 1)))
        self.bb.setTop(min(self.bb.top(), max(0, y - self.brushSize // 2 - 1)))
        self.bb.setBottom(
            max(self.bb.bottom(),
                min(self.sliceRect[1] - 1, y + self.brushSize // 2 + 1)))

        #update/move position
        self.pos = pos
Esempio n. 23
0
class XSnapshotWidget(QWidget):
    def __init__(self, parent=None):
        super(XSnapshotWidget, self).__init__(parent)

        # define custom properties
        self._region = QRect()
        self._filepath = ''

        # define custom properties
        palette = self.palette()
        palette.setColor(palette.Window, QColor('white'))
        self.setPalette(palette)
        self.setWindowOpacity(0.5)
        self.setWindowFlags(Qt.SplashScreen)
        self.setFocus()

    def accept(self):
        """
        Prompts the user for the filepath to save and then saves the image.
        """
        filetypes = 'PNG Files (*.png);;JPG Files (*.jpg);;All Files (*.*)'
        filename = QFileDialog.getSaveFileName(None, 'Save Snapshot',
                                               self.filepath(), filetypes)

        if type(filename) == tuple:
            filename = filename[0]

        filename = str(filename)
        if not filename:
            self.reject()
        else:
            self.setFilepath(filename)
            self.save()

    def filepath(self):
        """
        Returns the filepath that is going to be asved for this snapshot widget.
        
        :return     <str>
        """
        return self._filepath

    def hideWindow(self):
        """
        Sets the window to hide/show while taking the snapshot.
        
        :param      window | <QMainWindow> || <QDialog>
        """
        return self._hideWindow

    def keyPressEvent(self, event):
        """
        Listens for the escape key to cancel out from this snapshot.
        
        :param      event | <QKeyPressEvent>
        """
        # reject on a cancel
        if event.key() == Qt.Key_Escape:
            self.reject()

        super(XSnapshotWidget, self).keyPressEvent(event)

    def mousePressEvent(self, event):
        """
        Starts the selection process for this widget and snapshot area.
        
        :param      event | <QMousePressEvent>
        """
        self._region.setX(event.pos().x())
        self._region.setY(event.pos().y())
        super(XSnapshotWidget, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        """
        Drags the selection view for this widget.
        
        :param      event | <QMouseMoveEvent>
        """
        w = event.pos().x() - self._region.x()
        h = event.pos().y() - self._region.y()

        self._region.setWidth(w)
        self._region.setHeight(h)
        self.repaint()

        super(XSnapshotWidget, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        """
        Finishes the selection event.
        
        :param      event | <QMouseReleaseEvent>
        """
        self.accept()
        super(XSnapshotWidget, self).mouseReleaseEvent(event)

    def paintEvent(self, event):
        """
        Handles the drawing for this widget and its selection region.
        
        :param      event | <QPaintEvent>
        """
        pen = QPen(Qt.DashLine)
        pen.setColor(QColor('red'))
        painter = QPainter(self)
        painter.setPen(pen)
        clr = QColor('black')
        clr.setAlpha(100)
        painter.setBrush(clr)

        painter.drawRect(self._region)

    def reject(self):
        """
        Rejects the snapshot and closes the widget.
        """
        if self.hideWindow():
            self.hideWindow().show()

        self.close()
        self.deleteLater()

    def region(self):
        """
        Returns the selection region defined by the rectangle for snapshoting.
        
        :return     <QRect>
        """
        return self._region

    def save(self):
        """
        Saves the snapshot based on the current region.
        """
        # close down the snapshot widget
        if self.hideWindow():
            self.hideWindow().hide()

        self.hide()
        QApplication.processEvents()
        time.sleep(1)

        # create the pixmap to save
        wid = QApplication.desktop().winId()

        if not self._region.isNull():
            x = self._region.x()
            y = self._region.y()
            w = self._region.width()
            h = self._region.height()
        else:
            x = self.x()
            y = self.y()
            w = self.width()
            h = self.height()

        pixmap = QPixmap.grabWindow(wid, x, y, w, h)
        pixmap.save(self.filepath())

        self.close()
        self.deleteLater()
        if self.hideWindow():
            self.hideWindow().show()

    def show(self):
        """
        Shows this widget and hides the specified window if necessary.
        """
        super(XSnapshotWidget, self).show()

        if self.hideWindow():
            self.hideWindow().hide()
            QApplication.processEvents()

    def setFilepath(self, filepath):
        """
        Sets the filepath that will be saved for this snapshot.
        
        :param      filepath | <str>
        """
        self._filepath = filepath

    def setHideWindow(self, window):
        """
        Sets the window that will be hidden while this snapshot is being
        taken.
        
        :param      window | <QMainWindow>
        """
        self._hideWindow = window

    def setRegion(self, rect):
        """
        Sets the region rectangle to the inputed rect.
        
        :param      rect | <QRect>
        """
        if rect is not None:
            self._region = rect

    @staticmethod
    def capture(rect=None, filepath='', prompt=True, hideWindow=None):
        """
        Prompts the user to capture the screen.
        
        :param      rect     | <QRect>
                    filepath | <str>
                    prompt   | <bool>
        
        :return     (<str> filepath, <bool> accepted)
        """
        widget = XSnapshotWidget(QApplication.desktop())
        widget.setRegion(rect)
        widget.setHideWindow(hideWindow)
        widget.setFilepath(filepath)
        widget.move(1, 1)
        widget.resize(QApplication.desktop().size())

        if prompt or not filepath:
            widget.show()
        else:
            widget.save()
Esempio n. 24
-37
 def paintEvent(self, event):
     QWidget.paintEvent(self, event)
     width, height = self.width(), self.height()
     polygon = QPolygon()
     for i, rate in enumerate(self.loads):
         x = width - i * self.pointDistance
         y = height - rate * height
         if x < self.boxWidth:
             break
         polygon.append(QPoint(x, y))
     painter = QPainter(self)
     pen = QPen()
     pen.setColor(Qt.darkGreen)
     painter.setPen(pen)
     painter.setRenderHint(QPainter.Antialiasing, True)
     #画网格
     painter.setOpacity(0.5)
     gridSize = self.pointDistance * 4
     deltaX = (width - self.boxWidth) % gridSize + self.boxWidth
     deltaY = height % gridSize
     for i in range(int(width / gridSize)):
         x = deltaX + gridSize * i
         painter.drawLine(x, 0, x, height)
     for j in range(int(height / gridSize)):
         y = j * gridSize + deltaY
         painter.drawLine(self.boxWidth, y, width, y)
     #画折线
     pen.setColor(Qt.darkCyan)
     pen.setWidth(2)
     painter.setPen(pen)
     painter.setOpacity(1)
     painter.drawPolyline(polygon)
     #画展示框
     if len(self.loads) > 0:
         rate = self.loads[0]
     else:
         rate = 1.0
     rect1 = QRect(4, height * 0.05, self.boxWidth - 9, height * 0.7)
     rect2 = QRect(4, height * 0.8, self.boxWidth - 9, height * 0.2)
     centerX = int(rect1.width() / 2) + 1
     pen.setWidth(1)
     for i in range(rect1.height()):
         if i % 4 == 0:
             continue
         if (rect1.height() - i) / rect1.height() > rate:
             pen.setColor(Qt.darkGreen)
         else:
             pen.setColor(Qt.green)
         painter.setPen(pen)
         for j in range(rect1.width()):
             if centerX - 1 <= j <= centerX + 1:
                 continue
             painter.drawPoint(rect1.x() + j, rect1.y() + i)
     pen.setColor(Qt.black)
     painter.setPen(pen)
     painter.drawText(rect2, Qt.AlignHCenter | Qt.AlignVCenter, str(int(rate * 100)) + "%")