def __grabRegion(self): """ Private method to grab the selected region (i.e. do the snapshot). """ pol = QPolygon(self.__selection) if not pol.isEmpty(): self.__grabbing = True xOffset = self.__pixmap.rect().x() - pol.boundingRect().x() yOffset = self.__pixmap.rect().y() - pol.boundingRect().y() translatedPol = pol.translated(xOffset, yOffset) pixmap2 = QPixmap(pol.boundingRect().size()) pixmap2.fill(Qt.transparent) pt = QPainter() pt.begin(pixmap2) if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff): pt.setRenderHints( QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform, True) pt.setBrush(Qt.black) pt.setPen(QPen(QBrush(Qt.black), 0.5)) pt.drawPolygon(translatedPol) pt.setCompositionMode(QPainter.CompositionMode_SourceIn) else: pt.setClipRegion(QRegion(translatedPol)) pt.setCompositionMode(QPainter.CompositionMode_Source) pt.drawPixmap(pixmap2.rect(), self.__pixmap, pol.boundingRect()) pt.end() self.grabbed.emit(pixmap2)
def paintEvent(self, ev): color = self.palette().color(QPalette.Highlight) painter = QPainter(self) # Filled rectangle. painter.setClipRect(self.rect()) color.setAlpha(50) painter.fillRect(self.rect().adjusted(2,2,-2,-2), color) # Thin rectangle outside. color.setAlpha(150) painter.setPen(color) painter.drawRect(self.rect().adjusted(0,0,-1,-1)) # Pseudo-handles at the corners and sides color.setAlpha(100) pen = QPen(color) pen.setWidth(8) painter.setPen(pen) painter.setBackgroundMode(Qt.OpaqueMode) # Clip at 4 corners region = QRegion(QRect(0,0,20,20)) region += QRect(self.rect().width()-20, 0, 20, 20) region += QRect(self.rect().width()-20, self.rect().height()-20, 20, 20) region += QRect(0, self.rect().height()-20, 20, 20) # Clip middles region += QRect(0, self.rect().height() // 2 - 10, self.rect().width(), 20) region += QRect(self.rect().width() // 2 - 10, 0, 20, self.rect().height()) # Draw thicker rectangles, clipped at corners and sides. painter.setClipRegion(region) painter.drawRect(self.rect())
def paintEvent(self, ev): ### Paint code contributed by Richard Cognot Jun 2012 color = self.palette().color(QPalette.Highlight) painter = QPainter(self) # Filled rectangle. painter.setClipRect(self.rect()) color.setAlpha(50) painter.fillRect(self.rect().adjusted(2,2,-2,-2), color) # Thin rectangle outside. color.setAlpha(150) painter.setPen(color) painter.drawRect(self.rect().adjusted(0,0,-1,-1)) # Pseudo-handles at the corners and sides color.setAlpha(100) pen = QPen(color) pen.setWidth(8) painter.setPen(pen) painter.setBackgroundMode(Qt.OpaqueMode) # Clip at 4 corners region = QRegion(QRect(0,0,20,20)) region += QRect(self.rect().width()-20, 0, 20, 20) region += QRect(self.rect().width()-20, self.rect().height()-20, 20, 20) region += QRect(0, self.rect().height()-20, 20, 20) # Clip middles region += QRect(0, self.rect().height() // 2 - 10, self.rect().width(), 20) region += QRect(self.rect().width() // 2 - 10, 0, 20, self.rect().height()) # Draw thicker rectangles, clipped at corners and sides. painter.setClipRegion(region) painter.drawRect(self.rect())
def draw(self, painter: QPainter): assert self.crop, 'crop must be set' # Compute painter regions for the crop and the blur all_region = QRegion(painter.viewport()) crop_region = QRegion(self.crop) blur_region = all_region.subtracted(crop_region) # Let the QGraphicsBlurEffect only paint in blur_region painter.setClipRegion(blur_region) # Fill with black and set opacity so that the blurred region is drawn darker if self.BLUR_DARKEN > 0.0: painter.fillRect(painter.viewport(), Qt.black) painter.setOpacity(1 - self.BLUR_DARKEN) # Draw the blur effect super().draw(painter) # Restore clipping and opacity painter.setClipping(False) painter.setOpacity(1.0) # Get the source pixmap pixmap, offset = self.sourcePixmap(Qt.DeviceCoordinates, QGraphicsEffect.NoPad) painter.setWorldTransform(QTransform()) # Get the source by adding the offset to the crop location source = self.crop if self.CROP_OFFSET_ENABLED: source = source.translated(self.CROP_OFFSET) painter.drawPixmap(self.crop.topLeft() + offset, pixmap, source)
def render_mask(self, mask): size = QSize(mask.width(), mask.height()) rect = QRect(QPoint(0, 0), size) pixmap = QPixmap(size) painter = QPainter(pixmap) for mask_colour, texture_pixmap in self._palette.items(): qcolour = QColor(*mask_colour) mask_bitmap = mask.createMaskFromColor(qcolour, Qt.MaskOutColor) mask_region = QRegion(mask_bitmap) painter.setClipRegion(mask_region) painter.drawTiledPixmap(rect, texture_pixmap) return pixmap
def mask(self, image: QImage) -> QImage: clip_rect = self._build_clip_rect(image) masked = QImage(self.size, QImage.Format_RGB32) painter = QPainter(masked) painter.setRenderHints(QPainter.Antialiasing, QPainter.SmoothPixmapTransform) painter.setClipRegion(self.clip_region) painter.drawImage(masked.rect(), image, clip_rect) painter.end() return masked
def paintEvent(self, evt): """Visualise update rects.""" super().paintEvent(evt) p = QPainter(self) p.setClipRegion(evt.region()) p.fillRect( 0,0, 10000,10000, QColor.fromHsv( randrange(0,360), randrange(200,256), randrange(200,256), 100 ) )
def paintEvent(self, e): #// Draw the popup here #// You can always pick an image and use drawPixmap to #// draw it in order to make things simpler painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.setClipRegion(e.region()) painter.fillRect(e.rect(), QColor(0, 0, 0, 0)) #// Prepare the popup dimensions roundedRectDimensions = QRectF() roundedRectDimensions.setX(self.rect().x() + self.LR_MARGIN) roundedRectDimensions.setY(self.rect().y() + self.TB_MARGIN) roundedRectDimensions.setWidth(self.rect().width() - self.LR_MARGIN * 2.0) roundedRectDimensions.setHeight(self.rect().height() - self.TB_MARGIN * 2.0) pal = QPalette(self.palette()) painter.setBrush( QBrush( pal.color( QPalette.Window if self.dark_mode else QPalette.Mid))) pen = QPen() pen.setColor( pal.color(QPalette.Light if self.dark_mode else QPalette.Button)) pen.setWidth(3) painter.setPen(pen) #// Draw the popup body painter.drawRoundedRect(roundedRectDimensions, self.LR_MARGIN * 2.0, self.TB_MARGIN * 2.0) painter.setPen(Qt.NoPen) painter.setBrush( QBrush( pal.color( QPalette.BrightText if self.dark_mode else QPalette.Dark))) #// Draw the popup pointer based on relPos self.drawPopupPointer(painter) e.accept()
def __grabRect(self): """ Private method to grab the selected rectangle (i.e. do the snapshot). """ if self.__mode == SnapshotRegionGrabber.Ellipse: ell = QRegion(self.__selection, QRegion.Ellipse) if not ell.isEmpty(): self.__grabbing = True xOffset = self.__pixmap.rect().x() - ell.boundingRect().x() yOffset = self.__pixmap.rect().y() - ell.boundingRect().y() translatedEll = ell.translated(xOffset, yOffset) pixmap2 = QPixmap(ell.boundingRect().size()) pixmap2.fill(Qt.transparent) pt = QPainter() pt.begin(pixmap2) if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff): pt.setRenderHints( QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.SmoothPixmapTransform, True) pt.setBrush(Qt.black) pt.setPen(QPen(QBrush(Qt.black), 0.5)) pt.drawEllipse(translatedEll.boundingRect()) pt.setCompositionMode(QPainter.CompositionMode_SourceIn) else: pt.setClipRegion(translatedEll) pt.setCompositionMode(QPainter.CompositionMode_Source) pt.drawPixmap(pixmap2.rect(), self.__pixmap, ell.boundingRect()) pt.end() self.grabbed.emit(pixmap2) else: r = QRect(self.__selection) if not r.isNull() and r.isValid(): self.__grabbing = True self.grabbed.emit(self.__pixmap.copy(r))
def paintEvent(self, event=None): painter = QPainter(self) if self.box_dim != (0, 0): l, r, t, b = self.get_mouse_coords() painter.setClipRegion( QRegion( QPolygon([ QPoint(0, 0), QPoint(self.screen_dim[0], 0), QPoint(self.screen_dim[0], t), QPoint(l, t), QPoint(l, b), QPoint(r, b), QPoint(r, t), QPoint(self.screen_dim[0], t), QPoint(self.screen_dim[0], self.screen_dim[1]), QPoint(0, self.screen_dim[1]), QPoint(0, 0) ]), Qt.OddEvenFill)) painter.setOpacity(0.4) painter.setBrush(Qt.black) painter.setPen(QPen(Qt.black)) painter.drawRect(self.rect())
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated(-self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText(self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0}, {1} ({2} x {3})".format( self.__locale.toString(self.__selection.x()), self.__locale.toString(self.__selection.y()), self.__locale.toString(self.__selection.width()), self.__locale.toString(self.__selection.height())) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
class PoincareViewModel(QWidget): def __init__(self, parent): super().__init__() self.parent = parent self.centerVertices = [] self.origin = QPointF() self.drawnTiles = defaultdict(defaultdict) self.tiles = [] self.tilesToUpdate = False self.sideCount = 5 self.adjacentCount = 4 self.renderDepth = 4 self.fillMode = True #Formula to calculate distance from center of disk to any vertex of the #initial polygon is from: #http://www.malinc.se/math/noneuclidean/poincaretilingen.php def getCenterVertices(self): p = self.sideCount q = self.adjacentCount dist = (self.diskDiameter/2) * math.sqrt(math.cos(math.pi * (1/p + 1/q)) / math.cos(math.pi * (1/p - 1/q))) alpha = 2*math.pi/p centerVertices = [] for i in range(p): x = self.origin.x() + (dist) * math.cos(i * alpha) y = self.origin.y() + (dist) * math.sin(i * alpha) centerVertices.append(QPointF(x, y)) return centerVertices #Since tiles are indexed by their centers (floating point), we need some leeway #with how 'close' two points need to be to be considered the same def hasBeenDrawn(self, aPoint): precision = 1000 x = round(precision * aPoint.x())/precision y = round(precision * aPoint.y())/precision try: return self.drawnTiles[x][y] except: return None def addDrawnTile(self, aTile): precision = 1000 x = round(precision * aTile.center.x())/precision y = round(precision * aTile.center.y())/precision self.drawnTiles[x][y] = aTile # Breadth-first construction of tiles by reflection about each side, with the # initial tile centered on the origin. This viewmodel is passed to each tile # since the disk's origin and diskDiameter are needed to calculate the arcs that # make up the sides of a tile. def drawTiling(self): self.drawnCount = 0 self.drawnTiles.clear() self.tiles.clear() self.centerVertices.clear() centerTile = Tile(self.getCenterVertices(), self, self.renderDepth) self.addDrawnTile(centerTile) queue = [centerTile] while queue: curTile = queue.pop() curTile.draw(self.painter) self.tiles.append(curTile) if curTile.layer == 1: continue for edge in curTile.edges: #First reflect the center of the current tile to check if the reflected #tile has been drawn before reflectedCenter = edge.reflectPoint(curTile.center) neighbor = self.hasBeenDrawn(reflectedCenter) if neighbor is None: #draw and log the new tile reflectedVertices = edge.reflectTile(curTile) neighbor = Tile(reflectedVertices, self, curTile.layer-1, reflectedCenter) queue.insert(0, neighbor) self.addDrawnTile(neighbor) #construct the list of neighbors if neighbor not in curTile.neighbors: curTile.neighbors.append(neighbor) if curTile not in neighbor.neighbors: neighbor.neighbors.append(curTile) def paintEvent(self, anEvent): self.painter = QPainter(self) self.painter.setRenderHint(QPainter.Antialiasing, on=True) self.diskDiameter = min(self.size().width(), self.size().height()) - 10 self.origin.setX(self.size().width()/2) self.origin.setY(self.size().height()/2) self.painter.setPen(QPen(QColor(122, 0, 127, 255), 3)) radius = self.diskDiameter/2 x = self.origin.x() y = self.origin.y() diskRect = QRect(x - radius, y - radius, self.diskDiameter, self.diskDiameter) self.diskRegion = QRegion(diskRect, QRegion.Ellipse) self.painter.setClipRegion(self.diskRegion) if self.tilesToUpdate: for tile in self.tiles: tile.update(self.painter) self.tilesToUpdate = False else: self.drawTiling() self.painter.setClipping(False) self.painter.setPen(QPen(QColor(5, 0, 127, 255), 3)) self.painter.drawEllipse(diskRect) self.painter.drawPoint(self.origin) self.painter.end() def updateTiles(self): self.tilesToUpdate = True self.update() def areHyperbolicDims(self, p, q): return (p-2)*(q-2) > 4 def setSideCount(self, count): if self.areHyperbolicDims(count, self.adjacentCount): self.sideCount = count self.update() return 0 return -1 def setAdjCount(self, count): if self.areHyperbolicDims(self.sideCount, count): self.adjacentCount = count self.update() return 0 return -1 def setRenderDepth(self, depth): self.renderDepth = depth self.update() def mousePressEvent(self, e): if self.diskRegion.contains(QPoint(e.x(), e.y())): self.parent.controller.clicked(e) def toggleFillMode(self): self.fillMode = not self.fillMode self.update()
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) r = QRect(self.__selection) if not self.__selection.isNull(): grey = QRegion(self.rect()) if self.__mode == SnapshotRegionGrabber.Ellipse: reg = QRegion(r, QRegion.Ellipse) else: reg = QRegion(r) grey = grey.subtracted(reg) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawRect(painter, r, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated( -self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawRect(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText( self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isNull(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. txt = "{0:n}, {1:n} ({2:n} x {3:n})".format( self.__selection.x(), self.__selection.y(), self.__selection.width(), self.__selection.height()) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) if textRect.width() < r.width() - 2 * self.__handleSize and \ textRect.height() < r.height() - 2 * self.__handleSize and \ r.width() > 100 and \ r.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(r.center()) textRect.moveCenter(r.center()) elif r.y() - 3 > textRect.height() and \ r.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft(QPoint(r.x(), r.y() - 3)) textRect.moveBottomLeft(QPoint(r.x() + 2, r.y() - 3)) elif r.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight(QPoint(r.x() - 3, r.y())) textRect.moveTopRight(QPoint(r.x() - 5, r.y())) elif r.bottom() + 3 + textRect.height() < self.rect().bottom() and \ r.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight(QPoint(r.right(), r.bottom() + 3)) textRect.moveTopRight(QPoint(r.right() - 2, r.bottom() + 3)) elif r.right() + textRect.width() + 3 < self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft(QPoint(r.right() + 3, r.bottom())) textRect.moveBottomLeft(QPoint(r.right() + 5, r.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawRect(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (r.height() > self.__handleSize * 2 and r.width() > self.__handleSize * 2) or \ not self.__mouseDown: self.__updateHandles() painter.setPen(Qt.NoPen) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.StrokeMask)) painter.drawRect(self.rect()) handleColor.setAlpha(60) painter.setBrush(handleColor) painter.setClipRegion( self.__handleMask(SnapshotRegionGrabber.FillMask)) painter.drawRect(self.rect())
def paintEvent(self, event): if self._background: painter = QPainter(self) painter.setClipRegion(event.region()) painter.drawPixmap(event.rect(), self._background, event.rect()) painter.end()
def paintEvent(self, evt): """ Protected method handling paint events. @param evt paint event (QPaintEvent) """ if self.__grabbing: # grabWindow() should just get the background return painter = QPainter(self) pal = QPalette(QToolTip.palette()) font = QToolTip.font() handleColor = pal.color(QPalette.Active, QPalette.Highlight) handleColor.setAlpha(160) overlayColor = QColor(0, 0, 0, 160) textColor = pal.color(QPalette.Active, QPalette.Text) textBackgroundColor = pal.color(QPalette.Active, QPalette.Base) painter.drawPixmap(0, 0, self.__pixmap) painter.setFont(font) pol = QPolygon(self.__selection) if not self.__selection.boundingRect().isNull(): # Draw outline around selection. # Important: the 1px-wide outline is *also* part of the # captured free-region pen = QPen(handleColor, 1, Qt.SolidLine, Qt.SquareCap, Qt.BevelJoin) painter.setPen(pen) painter.drawPolygon(pol) # Draw the grey area around the selection. grey = QRegion(self.rect()) grey = grey - QRegion(pol) painter.setClipRegion(grey) painter.setPen(Qt.NoPen) painter.setBrush(overlayColor) painter.drawRect(self.rect()) painter.setClipRect(self.rect()) drawPolygon(painter, pol, handleColor) if self.__showHelp: painter.setPen(textColor) painter.setBrush(textBackgroundColor) self.__helpTextRect = painter.boundingRect( self.rect().adjusted(2, 2, -2, -2), Qt.TextWordWrap, self.__helpText).translated( -self.__desktop.x(), -self.__desktop.y()) self.__helpTextRect.adjust(-2, -2, 4, 2) drawPolygon(painter, self.__helpTextRect, textColor, textBackgroundColor) painter.drawText( self.__helpTextRect.adjusted(3, 3, -3, -3), Qt.TextWordWrap, self.__helpText) if self.__selection.isEmpty(): return # The grabbed region is everything which is covered by the drawn # rectangles (border included). This means that there is no 0px # selection, since a 0px wide rectangle will always be drawn as a line. boundingRect = self.__selection.boundingRect() txt = "{0}, {1} ({2} x {3})".format( self.__locale.toString(boundingRect.x()), self.__locale.toString(boundingRect.y()), self.__locale.toString(boundingRect.width()), self.__locale.toString(boundingRect.height()) ) textRect = painter.boundingRect(self.rect(), Qt.AlignLeft, txt) boundingRect = textRect.adjusted(-4, 0, 0, 0) polBoundingRect = pol.boundingRect() if (textRect.width() < polBoundingRect.width() - 2 * self.__handleSize) and \ (textRect.height() < polBoundingRect.height() - 2 * self.__handleSize) and \ polBoundingRect.width() > 100 and \ polBoundingRect.height() > 100: # center, unsuitable for small selections boundingRect.moveCenter(polBoundingRect.center()) textRect.moveCenter(polBoundingRect.center()) elif polBoundingRect.y() - 3 > textRect.height() and \ polBoundingRect.x() + textRect.width() < self.rect().width(): # on top, left aligned boundingRect.moveBottomLeft( QPoint(polBoundingRect.x(), polBoundingRect.y() - 3)) textRect.moveBottomLeft( QPoint(polBoundingRect.x() + 2, polBoundingRect.y() - 3)) elif polBoundingRect.x() - 3 > textRect.width(): # left, top aligned boundingRect.moveTopRight( QPoint(polBoundingRect.x() - 3, polBoundingRect.y())) textRect.moveTopRight( QPoint(polBoundingRect.x() - 5, polBoundingRect.y())) elif (polBoundingRect.bottom() + 3 + textRect.height() < self.rect().bottom()) and \ polBoundingRect.right() > textRect.width(): # at bottom, right aligned boundingRect.moveTopRight( QPoint(polBoundingRect.right(), polBoundingRect.bottom() + 3)) textRect.moveTopRight( QPoint(polBoundingRect.right() - 2, polBoundingRect.bottom() + 3)) elif polBoundingRect.right() + textRect.width() + 3 < \ self.rect().width(): # right, bottom aligned boundingRect.moveBottomLeft( QPoint(polBoundingRect.right() + 3, polBoundingRect.bottom())) textRect.moveBottomLeft( QPoint(polBoundingRect.right() + 5, polBoundingRect.bottom())) # If the above didn't catch it, you are running on a very # tiny screen... drawPolygon(painter, boundingRect, textColor, textBackgroundColor) painter.drawText(textRect, Qt.AlignHCenter, txt) if (polBoundingRect.height() > self.__handleSize * 2 and polBoundingRect.width() > self.__handleSize * 2) or \ not self.__mouseDown: painter.setBrush(Qt.transparent) painter.setClipRegion(QRegion(pol)) painter.drawPolygon(QPolygon(self.rect()))
def paintEvent(self, event: QPaintEvent): _start = perf_counter() num = self.num_tabs selected = self.selected arrow_width = self._arrow_width height = self.height() width = self._button_width first_width = self._first_button_width button = self._button_path button_box = QRect(0, 0, width + arrow_width, height) first_box = QRect(0, 0, first_width + arrow_width, height) icon_area = QRect(arrow_width + 10, 0, max(48, width / 2), height) text_box = QRect(arrow_width, 0, width - arrow_width, height) text_flags = Qt.AlignCenter | Qt.AlignVCenter states = self.states painter = QPainter(self) region = event.region() painter.setClipRegion(region) #torender = self._tabs_within(event.region()) #print("regions:") #for rect in event.region().rects(): # print(" - ", rect) #painter.setPen(Qt.NoPen) painter.setPen( QPen(Qt.black, 2, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)) titleFont = painter.font() titleFont.setPointSizeF(14) titleFont.setBold(True) painter.setFont(titleFont) painter.translate(num * width + first_width, 0) if region.intersects(painter.transform().mapRect(button_box)): painter.setBrush(states[num].get_color(num == selected)) painter.drawPath(self._last_button_path) for i in reversed(range(num)): painter.translate(-width, 0) if not region.intersects(painter.transform().mapRect(button_box)): continue painter.setBrush(states[i].get_color(i == selected)) painter.drawPath(button) if states[i].state == State.ACTIVE: painter.save() painter.setPen(Qt.NoPen) gw = (width + self._arrow_width) * 2 gradient = QLinearGradient(0, 0, gw, 0) value = self._working_anim.value gradient.setColorAt(max(0.0, value - 0.2), QColor(255, 255, 255, 0)) gradient.setColorAt(value, QColor(255, 255, 255, 180)) gradient.setColorAt(min(1.0, value + 0.2), QColor(255, 255, 255, 0)) brush = QBrush(gradient) brush.setTransform(brush.transform().translate(-gw / 4, 0)) gradient_height = int(height * 0.2) painter.setBrush(brush) #painter.setClipRect(0, 0, width+self._arrow_width, gradient_height) #painter.drawPath(button) #painter.setClipRect(0, height-gradient_height, width+self._arrow_width, gradient_height) painter.drawPath(button) self._active_box = painter.transform().mapRect(button_box) painter.restore() #if states[i].icon: # states[i].icon.paint(painter, icon_area) text = states[i].text if text: _, _, short = text.rpartition('-') painter.drawText(text_box, text_flags, short.capitalize()) if region.intersects(first_box): painter.resetTransform() painter.setBrush(State.UNKNOWN.get_color(-1 == selected)) painter.drawPath(self._first_button_path) if self.is_running: icon = self.style().standardIcon(QStyle.SP_MediaStop) else: icon = self.style().standardIcon(QStyle.SP_MediaPlay) size = min(self._first_button_width, self.height()) * 0.8 painter.translate(5, (self.height() - size) / 2) icon.paint(painter, QRect(0, 0, size, size)) _end = perf_counter() if not self._paint_times: self._paint_times = times = [] else: times = self._paint_times times.append(_end - _start) if len(times) > 60: avg = sum(times) / len(times) * 1000000 print("Average render time %.2fns" % (avg, )) self._paint_times = None
class CaptureWidget(QWidget): captured = pyqtSignal(QPixmap) def __init__(self): """ CapturedWidget __init__ """ super().__init__() self.painter = QPainter() self.setCursor(Qt.CursorShape.CrossCursor) # Make widget stay on top & fullscreen self.setWindowState(Qt.WindowState.WindowFullScreen) self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.FramelessWindowHint | Qt.Tool | Qt.BypassWindowManagerHint) self.screenshot = ScreenGrabber().grab_entire_desktop() self._clipping_state = 0 self._startpos: Optional[QPoint] = None self._endpos: Optional[QPoint] = None self.move(0, 0) self.resize(self.screenshot.size()) def keyPressEvent(self, event: QKeyEvent): """ Keypress event This allows capture widget escape to close, return or enter to capture :param event: QKeyEvent instance :type event: QKeyEvent """ if event.key() == Qt.Key.Key_Escape: self.close() if event.key() in [Qt.Key.Key_Return, Qt.Key.Key_Enter]: if self._startpos is None or self._endpos is None: return screen = QApplication.screenAt(self._startpos) ratio = screen.devicePixelRatio() cropped = self.screenshot.copy( QRect( int(self._startpos.x() * ratio), int(self._startpos.y() * ratio), int((self._endpos.x() - self._startpos.x()) * ratio), int((self._endpos.y() - self._startpos.y()) * ratio), )) # noinspection PyUnresolvedReferences self.captured.emit(cropped) def mousePressEvent(self, event: QMouseEvent): """ Mouse press event, this marks capture start :param event: QMouseEvent instance :type event: QMouseEvent """ self._clipping_state = 1 self._startpos = event.pos() def mouseMoveEvent(self, event: QMouseEvent): """ Mouse move event, this marks capture area :param event: QMouseEvent instance :type event: QMouseEvent """ if self._clipping_state != 1: return self._endpos = event.pos() self.repaint() def mouseReleaseEvent(self, event: QMouseEvent): """ Mouse release event, this marks capture stop :param event: QMouseEvent instance :type event: QMouseEvent """ self._clipping_state = 2 self._endpos = event.pos() self.repaint() def paintEvent(self, event: QPaintEvent): """ Paint event, draw cropped area :param event: QPaintEvent instance :type event: QPaintEvent """ self.painter.begin(self) self.painter.drawPixmap(0, 0, self.screenshot) overlay = QColor(0, 0, 0, 120) self.painter.setBrush(overlay) grey = QRegion(self.rect()) if self._clipping_state != 0: grey = grey.subtracted( QRegion(self._startpos.x(), self._startpos.y(), self._endpos.x() - self._startpos.x(), self._endpos.y() - self._startpos.y())) self.painter.setClipRegion(grey) self.painter.drawRect(0, 0, self.rect().width(), self.rect().height()) self.painter.setClipRegion(QRegion(self.rect())) self.painter.end()