def _check_area(self): """ Check if the current layout added areas cover the entire rectangle. Rectangle given by the extreme points for the added areas. """ self._area_rects = [] height = self._rows + 1 area_float_rects = [] delta = 0.0001 for index, area in enumerate(self._areas): # These areas are used with a small delta to ensure if they are # next to each other they will not overlap. rectf = QRectF() rectf.setLeft(area["column"] + delta) rectf.setRight(area["column"] + area["col_span"] - delta) rectf.setTop(height - area["row"] - delta) rectf.setBottom(height - area["row"] - area["row_span"] + delta) rectf.index = index rectf.plugin_ids = area["plugin_ids"] area_float_rects.append(rectf) # These areas are used to calculate the actual total area rect = QRectF() rect.setLeft(area["column"]) rect.setRight(area["column"] + area["col_span"]) rect.setTop(height - area["row"]) rect.setBottom(height - area["row"] - area["row_span"]) rect.index = index rect.plugin_ids = area["plugin_ids"] self._area_rects.append(rect) # Check if areas are overlapping! for rect_1 in area_float_rects: for rect_2 in area_float_rects: if rect_1.index != rect_2.index: if rect_1.intersects(rect_2): raise SpyderAPIError( "Area with plugins {0} is overlapping area " "with plugins {1}".format(rect_1.plugin_ids, rect_2.plugin_ids)) # Check the total area (using corner points) versus the sum of areas total_area = 0 tops = [] rights = [] for index, rect in enumerate(self._area_rects): tops.append(rect.top()) rights.append(rect.right()) area = abs(rect.width() * rect.height()) total_area += area self._areas[index]["area"] = area if total_area != max(rights)*max(tops): raise SpyderAPIError( "Areas are not covering the entire section!\n" "Either an area is missing or col_span/row_span are " "not correctly set!" )
def paintEvent(self, a0: QPaintEvent) -> None: super().paintEvent(a0) painter = QPainter(self) painter.save() painter.setRenderHint(QPainter.Antialiasing) rect = QRectF(self.margin, self.margin, self.width() - self.margin * 2, self.height() - 2 * self.margin) painter.setBrush(Qt.white) painter.setPen(Qt.white) painter.drawRect(rect) painter.restore() painter.save() painter.setRenderHint(QPainter.Antialiasing) pen = QPen() pen.setWidth(3) painter.setPen(pen) path = QPainterPath() height, width = rect.height() + self.margin, rect.width() + self.margin path.moveTo(self.margin, height) path.cubicTo(height * 0.5, width * 0.9, height * 0.9, width * 0.5, height, self.margin) painter.drawPath(path) painter.restore()
def colorBarRect(self, rect): """ Calculate the the rectangle for the color bar :param QRectF rect: Bounding rectangle for all components of the scale :return: Rectangle for the color bar """ cr = QRectF(rect) if self.__data.scaleDraw.orientation() == Qt.Horizontal: cr.setLeft(cr.left() + self.__data.borderDist[0]) cr.setWidth(cr.width() - self.__data.borderDist[1] + 1) else: cr.setTop(cr.top() + self.__data.borderDist[0]) cr.setHeight(cr.height() - self.__data.borderDist[1] + 1) sda = self.__data.scaleDraw.alignment() if sda == QwtScaleDraw.LeftScale: cr.setLeft(cr.right() - self.__data.margin - self.__data.colorBar.width) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.RightScale: cr.setLeft(cr.left() + self.__data.margin) cr.setWidth(self.__data.colorBar.width) elif sda == QwtScaleDraw.BottomScale: cr.setTop(cr.top() + self.__data.margin) cr.setHeight(self.__data.colorBar.width) elif sda == QwtScaleDraw.TopScale: cr.setTop(cr.bottom() - self.__data.margin - self.__data.colorBar.width) cr.setHeight(self.__data.colorBar.width) return cr
def box_rect(self, rect: QtCore.QRectF): self._box_rect = rect # Update the scene rect so that it matches how much space we # currently want for drawing everything. rect.setWidth(rect.width() - 1) self.setSceneRect(rect)
def renderTo(self, plot, dest): """ Render a plot to a file Supported formats are: - pdf: Portable Document Format PDF - ps: Postcript - svg: Scalable Vector Graphics SVG - all image formats supported by Qt, see QImageWriter.supportedImageFormats() Scalable vector graphic formats like PDF or SVG are superior to raster graphics formats. :param qwt.plot.QwtPlot plot: Plot widget :param dest: QPaintDevice, QPrinter or QSvgGenerator instance .. seealso:: :py:meth:`render()`, :py:meth:`qwt.painter.QwtPainter.setRoundingAlignment()` """ if isinstance(dest, QPaintDevice): w = dest.width() h = dest.height() rect = QRectF(0, 0, w, h) elif isinstance(dest, QPrinter): w = dest.width() h = dest.height() rect = QRectF(0, 0, w, h) aspect = rect.width() / rect.height() if aspect < 1.0: rect.setHeight(aspect * rect.width()) elif isinstance(dest, QSvgGenerator): rect = dest.viewBoxF() if rect.isEmpty(): rect.setRect(0, 0, dest.width(), dest.height()) if rect.isEmpty(): rect.setRect(0, 0, 800, 600) else: raise TypeError("Unsupported destination type %s" % type(dest)) p = QPainter(dest) self.render(plot, p, rect)
def qwtDrawStar1Symbols(painter, points, numPoints, symbol): size = symbol.size() painter.setPen(symbol.pen()) sqrt1_2 = np.sqrt(0.5) r = QRectF(0, 0, size.width(), size.height()) for pos in points: r.moveCenter(pos.toPoint()) c = QPointF(r.center()) d1 = r.width() / 2.0 * (1.0 - sqrt1_2) painter.drawLine(r.left() + d1, r.top() + d1, r.right() - d1, r.bottom() - d1) painter.drawLine(r.left() + d1, r.bottom() - d1, r.right() - d1, r.top() + d1) painter.drawLine(c.x(), r.top(), c.x(), r.bottom()) painter.drawLine(r.left(), c.y(), r.right(), c.y())
def qwtDrawSvgSymbols(painter, points, numPoints, renderer, symbol): if renderer is None or not renderer.isValid(): return viewBox = QRectF(renderer.viewBoxF()) if viewBox.isEmpty(): return sz = QSizeF(symbol.size()) if not sz.isValid(): sz = viewBox.size() sx = sz.width() / viewBox.width() sy = sz.height() / viewBox.height() pinPoint = QPointF(viewBox.center()) if symbol.isPinPointEnabled(): pinPoint = symbol.pinPoint() dx = sx * (pinPoint.x() - viewBox.left()) dy = sy * (pinPoint.y() - viewBox.top()) for pos in points: x = pos.x() - dx y = pos.y() - dy renderer.render(painter, QRectF(x, y, sz.width(), sz.height()))
def draw(self, painter): """ Draw the scale :param QPainter painter: Painter """ self.__data.scaleDraw.draw(painter, self.palette()) if (self.__data.colorBar.isEnabled and self.__data.colorBar.width > 0 and self.__data.colorBar.interval.isValid()): self.drawColorBar(painter, self.colorBarRect(self.contentsRect())) r = QRectF(self.contentsRect()) if self.__data.scaleDraw.orientation() == Qt.Horizontal: r.setLeft(r.left() + self.__data.borderDist[0]) r.setWidth(r.width() - self.__data.borderDist[1]) else: r.setTop(r.top() + self.__data.borderDist[0]) r.setHeight(r.height() - self.__data.borderDist[1]) if not self.__data.title.isEmpty(): self.drawTitle(painter, self.__data.scaleDraw.alignment(), r)
def qwtDrawGraphicSymbols(painter, points, numPoint, graphic, symbol): pointRect = QRectF(graphic.controlPointRect()) if pointRect.isEmpty(): return sx = 1.0 sy = 1.0 sz = symbol.size() if sz.isValid(): sx = sz.width() / pointRect.width() sy = sz.height() / pointRect.height() pinPoint = QPointF(pointRect.center()) if symbol.isPinPointEnabled(): pinPoint = symbol.pinPoint() transform = QTransform(painter.transform()) for pos in points: tr = QTransform(transform) tr.translate(pos.x(), pos.y()) tr.scale(sx, sy) tr.translate(-pinPoint.x(), -pinPoint.y()) painter.setTransform(tr) graphic.render(painter) painter.setTransform(transform)
def draw(self, painter, rect, flags, text): """ Draw the text in a clipping rectangle :param QPainter painter: Painter :param QRectF rect: Clipping rectangle :param int flags: Bitwise OR of the flags like in for QPainter::drawText() :param str text: Text to be rendered """ txt = QwtRichTextDocument(text, flags, painter.font()) painter.save() unscaledRect = QRectF(rect) if painter.font().pixelSize() < 0: res = qwtScreenResolution() pd = painter.device() if pd.logicalDpiX() != res.width() or pd.logicalDpiY( ) != res.height(): transform = QTransform() transform.scale( res.width() / float(pd.logicalDpiX()), res.height() / float(pd.logicalDpiY()), ) painter.setWorldTransform(transform, True) invtrans, _ok = transform.inverted() unscaledRect = invtrans.mapRect(rect) txt.setDefaultFont(painter.font()) txt.setPageSize(QSizeF(unscaledRect.width(), QWIDGETSIZE_MAX)) layout = txt.documentLayout() height = layout.documentSize().height() y = unscaledRect.y() if flags & Qt.AlignBottom: y += unscaledRect.height() - height elif flags & Qt.AlignVCenter: y += (unscaledRect.height() - height) / 2 context = QAbstractTextDocumentLayout.PaintContext() context.palette.setColor(QPalette.Text, painter.pen().color()) painter.translate(unscaledRect.x(), y) layout.draw(painter, context) painter.restore()
def create_high_dpi_drop_indicator_pixmap( self, size: QSizeF, area: DockWidgetArea, mode: OverlayMode) -> QPixmap: ''' Create high dpi drop indicator pixmap Parameters ---------- size : QSizeF area : DockWidgetArea mode : OverlayMode Returns ------- value : QPixmap ''' border_color = self.icon_color(IconColor.frame_color) background_color = self.icon_color(IconColor.window_background_color) window = self.public.window() # QT version compatibility (TODO necessary for qtpy?) device_pixel_ratio = (window.devicePixelRatioF() if hasattr(window, 'devicePixelRatioF') else window.devicePixelRatio()) pixmap_size = QSizeF(size * device_pixel_ratio) pm = QPixmap(pixmap_size.toSize()) pm.fill(QColor(0, 0, 0, 0)) p = QPainter(pm) pen = p.pen() shadow_rect = QRectF(pm.rect()) base_rect = QRectF() base_rect.setSize(shadow_rect.size() * 0.7) base_rect.moveCenter(shadow_rect.center()) # Fill shadow_color = self.icon_color(IconColor.shadow_color) if shadow_color.alpha() == 255: shadow_color.setAlpha(64) p.fillRect(shadow_rect, shadow_color) # Drop area rect. p.save() area_rect = QRectF() area_line = QLineF() non_area_rect = QRectF() if area == DockWidgetArea.top: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(), base_rect.height()*.5) non_area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5, base_rect.width(), base_rect.height()*.5) area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight()) elif area == DockWidgetArea.right: area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(), base_rect.width()*.5, base_rect.height()) non_area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width()*.5, base_rect.height()) area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft()) elif area == DockWidgetArea.bottom: area_rect = QRectF(base_rect.x(), shadow_rect.height()*.5, base_rect.width(), base_rect.height()*.5) non_area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(), base_rect.height()*.5) area_line = QLineF(area_rect.topLeft(), area_rect.topRight()) elif area == DockWidgetArea.left: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width()*.5, base_rect.height()) non_area_rect = QRectF(shadow_rect.width()*.5, base_rect.y(), base_rect.width()*.5, base_rect.height()) area_line = QLineF(area_rect.topRight(), area_rect.bottomRight()) baseSize = base_rect.size() if (OverlayMode.container == mode and area != DockWidgetArea.center): base_rect = area_rect p.fillRect(base_rect, background_color) if area_rect.isValid(): pen = p.pen() pen.setColor(border_color) Color = self.icon_color(IconColor.overlay_color) if Color.alpha() == 255: Color.setAlpha(64) p.setBrush(Color) p.setPen(Qt.NoPen) p.drawRect(area_rect) pen = p.pen() pen.setWidth(1) pen.setColor(border_color) pen.setStyle(Qt.DashLine) p.setPen(pen) p.drawLine(area_line) p.restore() p.save() # Draw outer border pen = p.pen() pen.setColor(border_color) pen.setWidth(1) p.setBrush(Qt.NoBrush) p.setPen(pen) p.drawRect(base_rect) # draw window title bar p.setBrush(border_color) frame_rect = QRectF(base_rect.topLeft(), QSizeF(base_rect.width(), baseSize.height()/10)) p.drawRect(frame_rect) p.restore() # Draw arrow for outer container drop indicators if (OverlayMode.container == mode and area != DockWidgetArea.center): arrow_rect = QRectF() arrow_rect.setSize(baseSize) arrow_rect.setWidth(arrow_rect.width()/4.6) arrow_rect.setHeight(arrow_rect.height()/2) arrow_rect.moveCenter(QPointF(0, 0)) arrow = QPolygonF() arrow.append(arrow_rect.topLeft()) arrow.append(QPointF(arrow_rect.right(), arrow_rect.center().y())) arrow.append(arrow_rect.bottomLeft()) p.setPen(Qt.NoPen) p.setBrush(self.icon_color(IconColor.arrow_color)) p.setRenderHint(QPainter.Antialiasing, True) p.translate(non_area_rect.center().x(), non_area_rect.center().y()) if area == DockWidgetArea.top: p.rotate(-90) elif area == DockWidgetArea.right: ... elif area == DockWidgetArea.bottom: p.rotate(90) elif area == DockWidgetArea.left: p.rotate(180) p.drawPolygon(arrow) pm.setDevicePixelRatio(device_pixel_ratio) return pm
class Colorbar(ChartItem): def __init__(self, colormap, v_min, v_max, parent=None): """ Displays the chart_tests item in a legend table. """ super(Colorbar, self).__init__( ) # Pycharm / pyLint inspection error. Please ignore self.setFlags(QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemIgnoresTransformations) self.chartItemFlags = ChartItemFlags.FLAG_NO_LABEL self._picture = None self._bRect = QRectF(0, 0, 200, 200) self.cm = colormap self.v_min = v_min self.v_max = v_max self.font = QFont("Helvetica [Cronyx]", 10, QFont.Normal) self.fontFlags = Qt.TextDontClip | Qt.AlignLeft | Qt.AlignVCenter self.setVisible(True) metrics = QFontMetrics(self.font) runWidth = 0 for entry in [v_min, v_max]: w = metrics.width("{}".format(entry)) if w > runWidth: runWidth = w self._bRect.setWidth(runWidth + 60) self._updatePicture() def _updatePicture(self): self._picture = QPicture() painter = QPainter(self._picture) self._generatePicture(painter) painter.end() def _generatePicture(self, p=QPainter()): p.setPen(QPen(QColor("#aaaaaa"))) p.setBrush(QBrush(QColor(80, 80, 80, 210), Qt.SolidPattern)) p.drawRoundedRect(self._bRect, 2, 2) for n in range(0, 180, 1): v = n / 180.0 a = self.cm(v) color = QColor.fromRgbF(a[0], a[1], a[2]) p.setBrush(QBrush(color)) p.setPen(QPen(color)) p.drawRect(QRect(5, 190 - n, 20, -1)) p.setBrush(QBrush(Qt.transparent)) p.setPen(QPen(QColor("#FFFFFF"))) tickRect = QRectF(32, 6, self._bRect.width() - 32, 11) p.drawText(tickRect, self.fontFlags, "{}".format(self.v_max)) # tickRect = QRectF(32, 94, self._bRect.width() - 32, 11) # p.drawText(tickRect, self.fontFlags, "{}".format(self.v_max - (self.v_max - self.v_min) / 2.)) tickRect = QRectF(32, 184, self._bRect.width() - 32, 11) p.drawText(tickRect, self.fontFlags, "{}".format(self.v_min)) def boundingRect(self): return self._bRect # def shape(self): # path = QPainterPath() # path.addRect(self._bRect) # return path def paint(self, p=QPainter(), o=QStyleOptionGraphicsItem(), widget=None): if self._picture is None: return self._picture.play(p) def __del__(self): _log.debug("Finalizing: {}".format(self))
def activate(self, plot, plotRect, options=0x00): """ Recalculate the geometry of all components. :param qwt.plot.QwtPlot plot: Plot to be layout :param QRectF plotRect: Rectangle where to place the components :param options: Layout options """ self.invalidate() rect = QRectF(plotRect) self.__data.layoutData.init(plot, rect) if (not (options & self.IgnoreLegend) and plot.legend() and not plot.legend().isEmpty()): self.__data.legendRect = self.layoutLegend(options, rect) region = QRegion(rect.toRect()) rect = region.subtracted(QRegion( self.__data.legendRect.toRect())).boundingRect() if self.__data.legendPos == QwtPlot.LeftLegend: rect.setLeft(rect.left() + self.__data.spacing) elif self.__data.legendPos == QwtPlot.RightLegend: rect.setRight(rect.right() - self.__data.spacing) elif self.__data.legendPos == QwtPlot.TopLegend: rect.setTop(rect.top() + self.__data.spacing) elif self.__data.legendPos == QwtPlot.BottomLegend: rect.setBottom(rect.bottom() - self.__data.spacing) # +---+-----------+---+ # | Title | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # +---+-----------+---+ # | | Axis | | # +---+-----------+---+ # | Footer | # +---+-----------+---+ # title, footer and axes include text labels. The height of each # label depends on its line breaks, that depend on the width # for the label. A line break in a horizontal text will reduce # the available width for vertical texts and vice versa. # expandLineBreaks finds the height/width for title, footer and axes # including all line breaks. dimTitle, dimFooter, dimAxes = self.expandLineBreaks(options, rect) if dimTitle > 0: self.__data.titleRect.setRect(rect.left(), rect.top(), rect.width(), dimTitle) rect.setTop(self.__data.titleRect.bottom() + self.__data.spacing) if (self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled != self.__data.layoutData.scale[QwtPlot.yRight].isEnabled): self.__data.titleRect.setX(rect.left() + dimAxes[QwtPlot.yLeft]) self.__data.titleRect.setWidth(rect.width() - dimAxes[QwtPlot.yLeft] - dimAxes[QwtPlot.yRight]) if dimFooter > 0: self.__data.footerRect.setRect(rect.left(), rect.bottom() - dimFooter, rect.width(), dimFooter) rect.setBottom(self.__data.footerRect.top() - self.__data.spacing) if (self.__data.layoutData.scale[QwtPlot.yLeft].isEnabled != self.__data.layoutData.scale[QwtPlot.yRight].isEnabled): self.__data.footerRect.setX(rect.left() + dimAxes[QwtPlot.yLeft]) self.__data.footerRect.setWidth(rect.width() - dimAxes[QwtPlot.yLeft] - dimAxes[QwtPlot.yRight]) self.__data.canvasRect.setRect( rect.x() + dimAxes[QwtPlot.yLeft], rect.y() + dimAxes[QwtPlot.xTop], rect.width() - dimAxes[QwtPlot.yRight] - dimAxes[QwtPlot.yLeft], rect.height() - dimAxes[QwtPlot.xBottom] - dimAxes[QwtPlot.xTop], ) for axis in QwtPlot.AXES: if dimAxes[axis]: dim = dimAxes[axis] scaleRect = self.__data.scaleRect[axis] scaleRect.setRect(*self.__data.canvasRect.getRect()) if axis == QwtPlot.yLeft: scaleRect.setX(self.__data.canvasRect.left() - dim) scaleRect.setWidth(dim) elif axis == QwtPlot.yRight: scaleRect.setX(self.__data.canvasRect.right()) scaleRect.setWidth(dim) elif axis == QwtPlot.xBottom: scaleRect.setY(self.__data.canvasRect.bottom()) scaleRect.setHeight(dim) elif axis == QwtPlot.xTop: scaleRect.setY(self.__data.canvasRect.top() - dim) scaleRect.setHeight(dim) scaleRect = scaleRect.normalized() # +---+-----------+---+ # | <- Axis -> | # +-^-+-----------+-^-+ # | | | | | | # | | | | # | A | | A | # | x | Canvas | x | # | i | | i | # | s | | s | # | | | | # | | | | | | # +-V-+-----------+-V-+ # | <- Axis -> | # +---+-----------+---+ # The ticks of the axes - not the labels above - should # be aligned to the canvas. So we try to use the empty # corners to extend the axes, so that the label texts # left/right of the min/max ticks are moved into them. self.alignScales(options, self.__data.canvasRect, self.__data.scaleRect) if not self.__data.legendRect.isEmpty(): self.__data.legendRect = self.alignLegend(self.__data.canvasRect, self.__data.legendRect)