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 setData( self, x, height, width=0.8, bottom=None, *, align="center", fillcolor=None, edgecolor=None, ) -> None: # assume vertical cbook._check_in_list(["center", "edge"], align=align) y = bottom if y is None: y = 0 x, height, width, y = np.broadcast_arrays(np.atleast_1d(x), height, width, y) if align == "center": try: left = x - width / 2 except TypeError as e: raise TypeError( f"the dtypes of parameters x ({x.dtype}) " f"and width ({width.dtype}) " f"are incompatible" ) from e elif align == "edge": left = x else: raise RuntimeError(f"unknown align mode {align}") bottom = y # prepare to draw if edgecolor is None: edgecolor = (128, 128, 128) # getConfigOption("foreground") pen = mkPen(edgecolor) if fillcolor is None: fillcolor = (128, 128, 128) brush = mkBrush(fillcolor) self.qpicture = QPicture() self.path = QPainterPath() p = QPainter(self.qpicture) p.setPen(pen) p.setBrush(brush) # draw rects = zip(left, bottom, width, height) for l, b, w, h in rects: rect = QRectF(l, b, w, h) p.drawRect(rect) self.path.addRect(rect) p.end() self.prepareGeometryChange()
def paintEvent(self, event): """Paint the colorbox. If no color, display a checkerboard pattern. Parameters ---------- event : qtpy.QtCore.QEvent Event from the Qt context. """ painter = QPainter(self) if self.layer._selected_color is None: for i in range(self._height // 4): for j in range(self._height // 4): if (i % 2 == 0 and j % 2 == 0) or ( i % 2 == 1 and j % 2 == 1 ): painter.setPen(QColor(230, 230, 230)) painter.setBrush(QColor(230, 230, 230)) else: painter.setPen(QColor(25, 25, 25)) painter.setBrush(QColor(25, 25, 25)) painter.drawRect(i * 4, j * 4, 5, 5) else: color = 255 * self.layer._selected_color color = color.astype(int) painter.setPen(QColor(*list(color))) painter.setBrush(QColor(*list(color))) painter.drawRect(0, 0, self._height, self._height)
def paintEvent(self, event: QPaintEvent): painter = QPainter(self) painter.drawImage(self.rect(), self.image) if self.show_frame: painter.save() pen = QPen() pen.setWidth(2) pen.setColor(QColor("black")) painter.setPen(pen) rect = QRect(1, 1, self.width() - 2, self.height() - 2) painter.drawRect(rect) pen.setColor(QColor("white")) painter.setPen(pen) rect = QRect(3, 3, self.width() - 6, self.height() - 6) painter.drawRect(rect) painter.restore() if self.show_arrow: painter.save() triangle = QPolygonF() dist = 4 point1 = QPoint(self.width() - self.triangle_width, 0) size = QSize(20, self.height() // 2) rect = QRect(point1, size) painter.fillRect(rect, QColor("white")) triangle.append(point1 + QPoint(dist, dist)) triangle.append(point1 + QPoint(size.width() - dist, dist)) triangle.append(point1 + QPoint(size.width() // 2, size.height() - dist)) painter.setBrush(Qt.black) painter.drawPolygon(triangle, Qt.WindingFill) painter.restore()
def paintEvent(self, a0: QPaintEvent) -> None: super().paintEvent(a0) painter = QPainter(self) painter.save() painter.setRenderHint(QPainter.Antialiasing) pen2 = QPen() rect = QRectF(self.margin, self.height() / 2, self.width() - self.margin * 2, self.height() / 2 - self.margin) rect2 = QRectF(3 * self.margin, 2 * self.margin, self.width() - self.margin * 6, self.height()) pen2.setWidth(6) painter.setPen(pen2) painter.drawArc(rect2, 0, 180 * 16) pen2.setWidth(3) pen2.setColor(Qt.white) painter.setPen(pen2) painter.drawArc(rect2, 0, 180 * 16) painter.fillRect(rect, Qt.white) pen2.setWidth(2) pen2.setColor(Qt.black) painter.setPen(pen2) painter.drawRect(rect) painter.restore()
def paintEvent(self, evt): # get the widget dimensions orig_width = self.width() orig_height = self.height() # fill perc % of the widget perc = 1 width = int(orig_width * perc) height = int(orig_height * perc) # get the starting origin x_orig = int((orig_width - width) / 2) # we want to start at the bottom and draw up. y_orig = orig_height - int((orig_height - height) / 2) # a running x-position running_pos = x_orig # calculate to number of bars nbars = len(self.counts) # calculate the bar widths, this compilcation is # necessary because integer trunction severly cripples # the layout. remainder = width % nbars bar_width = [int(width / nbars)] * nbars for i in range(remainder): bar_width[i] += 1 paint = QPainter() paint.begin(self) # determine the scaling factor max_val = np.max(self.counts) scale = 1. * height / max_val # determine if we have a colormap and drop into the appopriate # loop. if hasattr(self.colormap[0], '__iter__'): # assume we have a colormap for i in range(len(self.counts)): bar_height = self.counts[i] r, g, b = self.colormap[i] paint.setPen(QColor(r, g, b)) paint.setBrush(QColor(r, g, b)) paint.drawRect(running_pos, y_orig, bar_width[i], -bar_height) running_pos += bar_width[i] else: # we have a tuple r, g, b = self.colormap paint.setPen(QColor(r, g, b)) paint.setBrush(QColor(r, g, b)) for i in range(len(self.counts)): bar_height = self.counts[i] * scale paint.drawRect(running_pos, y_orig, bar_width[i], -bar_height) running_pos += bar_width[i] paint.end()
class PyDMBitIndicator(QWidget): """ A QWidget which draws a colored circle or rectangle Parameters ---------- parent : QWidget The parent widget for the Label """ def __init__(self, parent=None, circle=False): super(PyDMBitIndicator, self).__init__(parent) self.setAutoFillBackground(True) self.circle = circle self._painter = QPainter() self._brush = QBrush(Qt.SolidPattern) self._pen = QPen(Qt.SolidLine) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self._painter.begin(self) opt = QStyleOption() opt.initFrom(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, self._painter, self) self._painter.setRenderHint(QPainter.Antialiasing) self._painter.setBrush(self._brush) self._painter.setPen(self._pen) if self.circle: rect = self.rect() w = rect.width() h = rect.height() r = min(w, h) / 2.0 - 2.0 * max(self._pen.widthF(), 1.0) self._painter.drawEllipse(QPoint(w / 2.0, h / 2.0), r, r) else: self._painter.drawRect(self.rect()) self._painter.end() def setColor(self, color): """ Property for the color to be used when drawing Parameters ---------- QColor """ self._brush.setColor(color) self.update() def minimumSizeHint(self): fm = QFontMetrics(self.font()) return QSize(fm.height(), fm.height())
class PyDMBitIndicator(QWidget): """ A QWidget which draws a colored circle or rectangle Parameters ---------- parent : QWidget The parent widget for the Label """ def __init__(self, parent=None, circle=False): super(PyDMBitIndicator, self).__init__(parent) self.setAutoFillBackground(True) self.circle = circle self._painter = QPainter() self._brush = QBrush(Qt.SolidPattern) self._pen = QPen(Qt.SolidLine) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self._painter.begin(self) opt = QStyleOption() opt.initFrom(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, self._painter, self) self._painter.setRenderHint(QPainter.Antialiasing) self._painter.setBrush(self._brush) self._painter.setPen(self._pen) if self.circle: rect = event.rect() w = rect.width() h = rect.height() r = min(w, h) / 2.0 - 2.0 * max(self._pen.widthF(), 1.0) self._painter.drawEllipse(QPoint(w / 2.0, h / 2.0), r, r) else: self._painter.drawRect(event.rect()) self._painter.end() def setColor(self, color): """ Property for the color to be used when drawing Parameters ---------- QColor """ self._brush.setColor(color) self.update() def minimumSizeHint(self): fm = QFontMetrics(self.font()) return QSize(fm.height(), fm.height())
def paintEvent(self, event): super(DetailedProgress, self).paintEvent(event) if not self._current_progress: return painter = QPainter(self) width = self.width() height = self.height() aspect_ratio = float(width) / height nr_realizations = max([iens for iens, _, _ in self._current_progress]) + 1 fm_size = max( [len(progress) for _, progress, _ in self._current_progress]) self.grid_height = math.ceil(math.sqrt(nr_realizations / aspect_ratio)) self.grid_width = math.ceil(self.grid_height * aspect_ratio) sub_grid_size = math.ceil(math.sqrt(fm_size)) cell_height = height / self.grid_height cell_width = width / self.grid_width foreground_image = QImage(self.grid_width * sub_grid_size, self.grid_height * sub_grid_size, QImage.Format_ARGB32) foreground_image.fill(QColor(0, 0, 0, 0)) for index, (iens, progress, _) in enumerate(self._current_progress): y = int(iens / self.grid_width) x = int(iens - (y * self.grid_width)) self.draw_window(x * sub_grid_size, y * sub_grid_size, progress, foreground_image) painter.drawImage(self.contentsRect(), foreground_image) for index, (iens, progress, state) in enumerate(self._current_progress): y = int(iens / self.grid_width) x = int(iens - (y * self.grid_width)) painter.setPen(QColor(80, 80, 80)) painter.drawText(int(x * cell_width), int(y * cell_height), int(cell_width), int(cell_height), int(Qt.AlignHCenter | Qt.AlignVCenter), str(iens)) if iens == self.selected_realization: pen = QPen(QColor(240, 240, 240)) elif (self.has_realization_failed(progress)): pen = QPen(QColor(*self.state_colors['Failure'])) elif (state == JobStatusType.JOB_QUEUE_RUNNING): pen = QPen(QColor(*self.state_colors['Running'])) else: pen = QPen(QColor(80, 80, 80)) thickness = 4 pen.setWidth(thickness) painter.setPen(pen) painter.drawRect( int(x * cell_width) + (thickness // 2), int(y * cell_height) + (thickness // 2), int(cell_width) - (thickness - 1), int(cell_height) - (thickness - 1))
def paintEvent(self, a0: QPaintEvent) -> None: super().paintEvent(a0) painter = QPainter(self) painter.save() painter.setPen(QColor("white")) painter.setBrush(QColor("white")) painter.drawRect(self.rect() - self.margin) icon: QIcon = qta.icon("mdi.chart-bell-curve-cumulative") icon.paint(painter, self.rect()) painter.restore()
def paintEvent(self, a0: QPaintEvent) -> None: super().paintEvent(a0) painter = QPainter(self) painter.save() painter.setPen(QColor("white")) painter.setBrush(QColor("white")) painter.drawRect(self.rect() - self.margin) icon: QIcon = qta.icon("fa5s.lock") icon.paint(painter, self.rect() - self.margin * 2) painter.restore()
def square_pixmap(size): """Create a white/black hollow square pixmap. For use as labels cursor.""" pixmap = QPixmap(QSize(size, size)) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) painter.setPen(Qt.white) painter.drawRect(0, 0, size - 1, size - 1) painter.setPen(Qt.black) painter.drawRect(1, 1, size - 3, size - 3) painter.end() return pixmap
def paint(self, painter: QPainter, _option, _widget: QWidget): # set color depending on wether the value belongs to the scenario if self.id in self.map.appdata.project.scen_values.keys(): painter.setPen(Qt.magenta) painter.setBrush(Qt.magenta) else: painter.setPen(Qt.darkGray) painter.drawRect(-15, -15, 20, 20) painter.setPen(Qt.darkGray) painter.drawLine(-5, 0, -5, -10) painter.drawLine(0, -5, -10, -5)
def setData(self, x: np.ndarray = None, y: np.ndarray = None, z: np.ndarray = None): self.x, self.y, self.z = validate(x, y, z) shapeChanged = False if self.qpicture is None: shapeChanged = True elif (x is None) and (y is None) and (z is not None): if (z.shape[0] != self.x[:, 1][-1]) or (z.shape[1] != self.y[0][-1]): shapeChanged = True elif (x is not None) and (y is not None) and (z is not None): if np.any(self.x != x) or np.any(self.y != y): shapeChanged = True # initialize painting self.qpicture = QPicture() p = QPainter(self.qpicture) p.setPen( mkPen( self.edgecolors if self.edgecolors is not None else QColor(0, 0, 0, 0) ) ) if self.antialiasing: p.setRenderHint(QPainter.HighQualityAntialiasing) # transform self.z = np.ma.masked_array(self.z, mask=~np.isfinite(self.z)) norm = self.z - self.z.min() norm /= norm.max() norm *= len(self.lut) - 1 norm = norm.astype(int) # plot for yi in range(norm.shape[0]): for xi in range(norm.shape[1]): if norm.mask[yi, xi]: continue # TODO: support bad colors c = self.lut[norm[yi, xi]] p.setBrush(mkBrush(c)) rect = QRectF( QPointF(self.x[yi + 1, xi + 1], self.y[yi + 1, xi + 1]), QPointF(self.x[yi, xi], self.y[yi, xi]), ) p.drawRect(rect) # finish painting p.end() self.update() self.prepareGeometryChange() if shapeChanged: self.informViewBoundsChanged()
def paintEvent(self, paintevent): """Paints the box""" painter = QPainter(self) rect = self.contentsRect() rect.setWidth(rect.width() - 1) rect.setHeight(rect.height() - 1) painter.drawRect(rect) rect.setX(rect.x() + 1) rect.setY(rect.y() + 1) painter.fillRect(rect, self.color)
def paintEvent(self, event): """Paint the background, range bar and splitters. Parameters ---------- event : qtpy.QEvent Event from the Qt context. """ painter, w, h = QPainter(self), self.width(), self.height() half_width = self.slider_width / 2 halfdiff = int(w / 2 - half_width) # Background painter.setPen(self.background_color) painter.setBrush(self.background_color) painter.drawRoundedRect(halfdiff, 0, self.slider_width, h, 2, 2) # Range Bar painter.setPen(self.bar_color) painter.setBrush(self.bar_color) if self.collapsed: painter.drawRect( halfdiff, h - self.display_max, self.slider_width, self.display_max, ) else: painter.drawRect( halfdiff, h - self.display_max, self.slider_width, self.display_max - self.display_min, ) painter.setRenderHints(QPainter.Antialiasing) # Splitters painter.setPen(self.handle_border_color) painter.setBrush(self.handle_color) painter.drawEllipse( int(w / 2 - self.handle_radius), h - self.display_min - self.handle_radius, self.handle_width, self.handle_width, ) # upper painter.drawEllipse( int(w / 2 - self.handle_radius), h - self.display_max - self.handle_radius, self.handle_width, self.handle_width, ) # lower
def paintEvent(self, event): QPushButton.paintEvent(self, event) color = self.color() padding = self.padding() rect = event.rect() painter = QPainter() painter.begin(self) painter.setBrush(QBrush(color)) painter.setPen(Qt.NoPen) rect.adjust(padding, padding, -1 - padding, -1 - padding) painter.drawRect(rect) painter.end()
def paintEvent(self, e: QPaintEvent): ''' Paintevent Parameters ---------- e : QPaintEvent Unused ''' #pylint: disable=unused-argument # Draw rect based on location if not self.d.drop_preview_enabled: self.d.drop_area_rect = QRect() return r = self.rect() da = self.drop_area_under_cursor() factor = (3 if OverlayMode.container == self.d.mode else 2) if da == DockWidgetArea.top: r.setHeight(r.height()/factor) elif da == DockWidgetArea.right: r.setX(r.width() * (1 - 1./factor)) elif da == DockWidgetArea.bottom: r.setY(r.height() * (1 - 1./factor)) elif da == DockWidgetArea.left: r.setWidth(r.width()/factor) elif da == DockWidgetArea.center: r = self.rect() else: return painter = QPainter(self) color = self.palette().color(QPalette.Active, QPalette.Highlight) pen = painter.pen() pen.setColor(color.darker(120)) pen.setStyle(Qt.SolidLine) pen.setWidth(1) pen.setCosmetic(True) painter.setPen(pen) color = color.lighter(130) color.setAlpha(64) painter.setBrush(color) painter.drawRect(r.adjusted(0, 0, -1, -1)) self.d.drop_area_rect = r
def paint(self, painter: QPainter, style: QStyleOptionViewItem, model: QModelIndex): if model.data() not in image_dict: image_dict[model.data()] = create_colormap_image( model.data(), self.color_dict) rect = QRect(style.rect.x(), style.rect.y() + 2, style.rect.width(), style.rect.height() - 4) painter.drawImage(rect, image_dict[model.data()]) if int(style.state & QStyle.State_HasFocus): painter.save() pen = QPen() pen.setWidth(5) painter.setPen(pen) painter.drawRect(rect) painter.restore()
def paintEvent(self, event): """ Override from QWidget, needed to get stylesheets working :param event: paint event """ # _log.debug("Tab: paint event.") opt = QStyleOption() opt.initFrom(self) painter = QPainter(self) self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self) if CONFIG.debug_layout: painter.setPen(QPen(Qt.red, 1.0)) painter.drawRect(self.rect().adjusted(0, 0, -1, -1)) painter.setPen(QPen(Qt.black, 1.0)) painter.drawText(QPointF(5, 12), str(self))
def qwtDrawBackground(painter, canvas): painter.save() borderClip = canvas.borderPath(canvas.rect()) if not borderClip.isEmpty(): painter.setClipPath(borderClip, Qt.IntersectClip) brush = canvas.palette().brush(canvas.backgroundRole()) if brush.style() == Qt.TexturePattern: pm = QPixmap(canvas.size()) QwtPainter.fillPixmap(canvas, pm) painter.drawPixmap(0, 0, pm) elif brush.gradient(): rects = [] if brush.gradient().coordinateMode() == QGradient.ObjectBoundingMode: rects += [canvas.rect()] else: rects += [painter.clipRegion().boundingRect()] useRaster = False if painter.paintEngine().type() == QPaintEngine.X11: useRaster = True if useRaster: format_ = QImage.Format_RGB32 stops = brush.gradient().stops() for stop in stops: if stop.second.alpha() != 255: format_ = QImage.Format_ARGB32 break image = QImage(canvas.size(), format_) pntr = QPainter(image) pntr.setPen(Qt.NoPen) pntr.setBrush(brush) for rect in rects: pntr.drawRect(rect) pntr.end() painter.drawImage(0, 0, image) else: painter.setPen(Qt.NoPen) painter.setBrush(brush) for rect in rects: painter.drawRect(rect) else: painter.setPen(Qt.NoPen) painter.setBrush(brush) painter.drawRect(painter.clipRegion().boundingRect()) painter.restore()
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex) -> None: super().paint(painter, option, index) cellState: CellState = index.data(Qt.BackgroundRole) if cellState == CellState.Invalid: padding = 0 x = option.rect.x() + padding y = option.rect.y() + padding w = option.rect.width() - 1 - padding h = option.rect.height() - 1 - padding pen = QPen() pen.setColor(QColor(*(Color.Red).value)) pen.setWidth(1) painter.setPen(pen) painter.drawRect(QRect(x, y, w, h))
def get_font_array(sz, chars=DEFAULT_CHARS): from qtpy.QtGui import QFont, QPainter, QColor font = QFont() font.setFixedPitch(True) font.setPixelSize(int(sz)) font.setStyleStrategy(QFont.NoAntialias) dummy = QImage(10, 10, QImage.Format_ARGB32) pnt = QPainter(dummy) pnt.setFont(font) metric = pnt.fontMetrics() rct = metric.boundingRect(chars) pnt.end() h = rct.height() w = rct.width() img = QImage(w, h, QImage.Format_ARGB32) paint = QPainter() paint.begin(img) paint.setFont(font) paint.setBrush(QColor(255, 255, 255)) paint.setPen(QColor(255, 255, 255)) paint.drawRect(0, 0, w + 1, h + 1) paint.setPen(QColor(0, 0, 0)) paint.setBrush(QColor(0, 0, 0)) paint.drawText(0, paint.fontMetrics().ascent(), chars) paint.end() try: try: # PyQt4 (at least until Qt 4.8) data = img.bits().asstring(img.numBytes()) except AttributeError: if PYSIDE2: # PySide2 data = bytes(img.bits()) else: # PyQt5 data = img.bits().asstring(img.byteCount()) except SystemError: # PyQt4 (4.11.3) and PyQt5 (5.3.2) on Python 3 return npy = np.frombuffer(data, np.uint8) npy.shape = img.height(), int(img.bytesPerLine() / 4), 4 return npy[:, :, 0]
def paintEvent(self, event): """Override Qt method.""" painter = QPainter(self) painter.setOpacity(self.current_opacity) max_width = ( SASS_VARIABLES.WIDGET_CONTENT_TOTAL_WIDTH - 2 * SASS_VARIABLES.WIDGET_CONTENT_PADDING - 2 * SASS_VARIABLES.WIDGET_CONTENT_MARGIN ) # Hover top br = self.label_icon.rect().bottomRight() tl = self.label_icon.rect().topLeft() + QPoint(1, 1) y = br.y() + self.label_text.height() - 2 # br_new = QPoint(br.x() + 2, y) - QPoint(1, 1) br_new = QPoint(max_width - 1, y) - QPoint(1, 1) rect_hover = QRect(tl, br_new) # 2 is the border pen = QPen(Qt.NoPen) brush = QBrush(Qt.SolidPattern) brush.setColor(QColor('#fff')) painter.setBrush(brush) painter.setPen(pen) painter.drawRect(rect_hover) font = self.font() font.setPointSize(10) painter.setFont(font) pen = QPen() pen.setColor(QColor('black')) painter.setPen(pen) td = self.text_document td.setPageSize(QSizeF(rect_hover.size())) td.setHtml(self.summary) td.drawContents(painter) self.raise_()
def paintEvent(self, event): qp = QPainter() qp.begin(self) w = self.width() h = self.height() # paint background qp.setBrush(self.color_background) qp.drawRect(0, 0, w, h) # paint angle bar qp.setBrush(self.color_anglebar) angle_zero_pos = w // 2 angle_bar_width = int(angle_zero_pos * self.rotate_angle / 360) if self.rotate_clockwise: qp.drawRect(angle_zero_pos, 0, angle_bar_width, h) else: qp.drawRect(angle_zero_pos - angle_bar_width, 0, angle_bar_width, h) qp.end()
class BaseCanvas(QWidget, metaclass=QABCMeta): """The subclass can draw a blank canvas more easier.""" @abstractmethod def __init__(self, parent: QWidget): """Set the parameters for drawing.""" super(BaseCanvas, self).__init__(parent) self.setSizePolicy( QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)) self.setFocusPolicy(Qt.StrongFocus) self.setMouseTracking(True) self.painter = QPainter() # Origin coordinate self.ox = self.width() / 2 self.oy = self.height() / 2 # Canvas zoom rate self.zoom = 1. # Joint size self.joint_size = 5 # Canvas line width self.link_width = 3 self.path_width = 3 # Font size self.font_size = 15 # Show point mark or dimension self.show_ticks = _TickMark.SHOW self.show_point_mark = True self.show_dimension = True # Path track self.path = _PathOption() # Path solving self.ranges: Dict[str, QRectF] = {} self.target_path: Dict[int, Sequence[_Coord]] = {} self.show_target_path = False # Background self.background = QImage() self.background_opacity = 1. self.background_scale = 1. self.background_offset = QPointF(0, 0) # Monochrome mode self.monochrome = False # Grab mode self.__grab_mode = False def switch_grab(self) -> None: """Start grab mode.""" self.__grab_mode = not self.__grab_mode @staticmethod def zoom_factor(width: int, height: int, x_right: float, x_left: float, y_top: float, y_bottom: float) -> float: """Calculate the zoom factor.""" x_diff = x_left - x_right y_diff = y_top - y_bottom x_diff = x_diff if x_diff else 1. y_diff = y_diff if y_diff else 1. if width / x_diff < height / y_diff: return width / x_diff else: return height / y_diff @abstractmethod def paintEvent(self, event: QPaintEvent) -> None: """Using a QPainter under 'self', so just change QPen or QBrush before painting. """ if not self.__grab_mode: self.painter.begin(self) self.painter.fillRect(event.rect(), QBrush(Qt.white)) # Translation self.painter.translate(self.ox, self.oy) # Background if not self.background.isNull(): rect = self.background.rect() self.painter.setOpacity(self.background_opacity) self.painter.drawImage( QRectF( self.background_offset * self.zoom, QSizeF(rect.width(), rect.height()) * self.background_scale * self.zoom), self.background, QRectF(rect)) self.painter.setOpacity(1) # Show frame pen = QPen(Qt.blue) pen.setWidth(1) self.painter.setPen(pen) self.painter.setFont(QFont("Arial", self.font_size)) # Draw origin lines if self.show_ticks not in {_TickMark.SHOW, _TickMark.SHOW_NUM}: return pen.setColor(Qt.gray) self.painter.setPen(pen) x_l = -self.ox x_r = self.width() - self.ox self.painter.drawLine(QPointF(x_l, 0), QPointF(x_r, 0)) y_t = self.height() - self.oy y_b = -self.oy self.painter.drawLine(QPointF(0, y_b), QPointF(0, y_t)) def indexing(v: float) -> int: """Draw tick.""" return int(v / self.zoom - v / self.zoom % 5) # Draw tick for x in range(indexing(x_l), indexing(x_r) + 1, 5): if x == 0: continue is_ten = x % 10 == 0 end = QPointF(x * self.zoom, -10 if is_ten else -5) self.painter.drawLine(QPointF(x, 0) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(0, 3), f"{x}") for y in range(indexing(y_b), indexing(y_t) + 1, 5): if y == 0: continue is_ten = y % 10 == 0 end = QPointF(10 if is_ten else 5, y * self.zoom) self.painter.drawLine(QPointF(0, y) * self.zoom, end) if self.show_ticks == _TickMark.SHOW_NUM and is_ten: self.painter.drawText(end + QPointF(3, 0), f"{-y}") # Please to call the "end" method when ending paint event. def draw_circle(self, p: QPointF, r: float) -> None: """Draw circle.""" self.painter.drawEllipse(p, r, r) def draw_point(self, i: int, cx: float, cy: float, fixed: bool, color: Optional[Tuple[int, int, int]], mul: int = 1) -> None: """Draw a joint.""" if self.monochrome or color is None: color = Qt.black else: color = QColor(*color) pen = QPen(color) pen.setWidth(2) self.painter.setPen(pen) x = cx * self.zoom y = cy * -self.zoom if fixed: # Draw a triangle below self.painter.drawPolygon( QPointF(x, y), QPointF(x - self.joint_size, y + 2 * self.joint_size), QPointF(x + self.joint_size, y + 2 * self.joint_size)) r = self.joint_size for _ in range(1 if mul < 1 else mul): self.draw_circle(QPointF(x, y), r) r += 5 if not self.show_point_mark: return pen.setColor(Qt.darkGray) pen.setWidth(2) self.painter.setPen(pen) text = f"[Point{i}]" if self.show_dimension: text += f":({cx:.02f}, {cy:.02f})" self.painter.drawText(QPointF(x, y) + QPointF(6, -6), text) def draw_ranges(self) -> None: """Draw rectangle ranges.""" pen = QPen() pen.setWidth(5) for i, (tag, rect) in enumerate(self.ranges.items()): range_color = QColor(color_num(i + 1)) range_color.setAlpha(30) self.painter.setBrush(range_color) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) cx = rect.x() * self.zoom cy = rect.y() * -self.zoom if rect.width(): self.painter.drawRect( QRectF(QPointF(cx, cy), QSizeF(rect.width(), rect.height()) * self.zoom)) else: self.draw_circle(QPointF(cx, cy), 3) range_color.setAlpha(255) pen.setColor(range_color) self.painter.setPen(pen) self.painter.drawText(QPointF(cx, cy) + QPointF(6, -6), tag) self.painter.setBrush(Qt.NoBrush) def draw_target_path(self) -> None: """Draw solving path.""" pen = QPen() pen.setWidth(self.path_width) for i, n in enumerate(sorted(self.target_path)): path = self.target_path[n] if self.monochrome: line, dot = target_path_style(0) else: line, dot = target_path_style(i + 1) pen.setColor(line) self.painter.setPen(pen) if len(path) == 1: x, y = path[0] p = QPointF(x, -y) * self.zoom self.painter.drawText(p + QPointF(6, -6), f"P{n}") pen.setColor(dot) self.painter.setPen(pen) self.draw_circle(p, self.joint_size) else: painter_path = QPainterPath() for j, (x, y) in enumerate(path): p = QPointF(x, -y) * self.zoom self.draw_circle(p, self.joint_size) if j == 0: self.painter.drawText(p + QPointF(6, -6), f"P{n}") painter_path.moveTo(p) else: x2, y2 = path[j - 1] self.__draw_arrow(x, -y, x2, -y2, zoom=True) painter_path.lineTo(p) pen.setColor(line) self.painter.setPen(pen) self.painter.drawPath(painter_path) for x, y in path: pen.setColor(dot) self.painter.setPen(pen) self.draw_circle( QPointF(x, -y) * self.zoom, self.joint_size) self.painter.setBrush(Qt.NoBrush) def __draw_arrow(self, x1: float, y1: float, x2: float, y2: float, *, zoom: bool = False, text: str = '') -> None: """Front point -> Back point""" if zoom: x1 *= self.zoom y1 *= self.zoom x2 *= self.zoom y2 *= self.zoom a = atan2(y2 - y1, x2 - x1) x1 = (x1 + x2) / 2 - 7.5 * cos(a) y1 = (y1 + y2) / 2 - 7.5 * sin(a) first_point = QPointF(x1, y1) self.painter.drawLine( first_point, QPointF(x1 + 15 * cos(a + radians(20)), y1 + 15 * sin(a + radians(20)))) self.painter.drawLine( first_point, QPointF(x1 + 15 * cos(a - radians(20)), y1 + 15 * sin(a - radians(20)))) if not text: return # Font font = self.painter.font() font_copy = QFont(font) font.setBold(True) font.setPointSize(font.pointSize() + 8) self.painter.setFont(font) # Color pen = self.painter.pen() color = pen.color() pen.setColor(color.darker()) self.painter.setPen(pen) self.painter.drawText(first_point, text) pen.setColor(color) self.painter.setPen(pen) self.painter.setFont(font_copy) def draw_curve(self, path: Sequence[_Coord]) -> None: """Draw path as curve.""" if len(set(path)) < 2: return painter_path = QPainterPath() error = False for i, (x, y) in enumerate(path): if isnan(x): error = True self.painter.drawPath(painter_path) painter_path = QPainterPath() else: p = QPointF(x, -y) * self.zoom if i == 0: painter_path.moveTo(p) self.draw_circle(p, 2) continue if error: painter_path.moveTo(p) error = False else: painter_path.lineTo(p) self.painter.drawPath(painter_path) def draw_dot(self, path: Sequence[_Coord]) -> None: """Draw path as dots.""" if len(set(path)) < 2: return for i, (x, y) in enumerate(path): if isnan(x): continue p = QPointF(x, -y) * self.zoom if i == 0: self.draw_circle(p, 2) else: self.painter.drawPoint(p) def solution_polygon( self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> Tuple[List[QPointF], QColor]: """Get solution polygon.""" if func == 'PLLP': color = QColor(121, 171, 252) params = [args[0], args[-1]] elif func == 'PLAP': color = QColor(249, 84, 216) params = [args[0]] else: if func == 'PLPP': color = QColor(94, 255, 185) else: # PXY color = QColor(249, 175, 27) params = [args[0]] params.append(target) tmp_list = [] for name in params: try: index = int(name.replace('P', '')) except ValueError: continue else: vpoint = pos[index] tmp_list.append(QPointF(vpoint.cx, -vpoint.cy) * self.zoom) return tmp_list, color def draw_solution(self, func: str, args: Sequence[str], target: str, pos: Sequence[VPoint]) -> None: """Draw the solution triangle.""" points, color = self.solution_polygon(func, args, target, pos) color.setAlpha(150) pen = QPen(color) pen.setWidth(self.joint_size) self.painter.setPen(pen) def draw_arrow(index: int, text: str) -> None: """Draw arrow.""" self.__draw_arrow(points[-1].x(), points[-1].y(), points[index].x(), points[index].y(), text=text) draw_arrow(0, args[1]) if func == 'PLLP': draw_arrow(1, args[2]) color.setAlpha(30) self.painter.setBrush(QBrush(color)) self.painter.drawPolygon(QPolygonF(points)) self.painter.setBrush(Qt.NoBrush) @Slot(int) def set_show_ticks(self, show: int): """Set the appearance of tick mark.""" self.show_ticks = _TickMark(show + 1) self.update() @Slot(bool) def set_monochrome_mode(self, monochrome: bool) -> None: """Set monochrome mode.""" self.monochrome = monochrome self.update()
def paintEvent(self, event: QPaintEvent): name = self.choose.currentText() if self.widgets_dict[name].has_elements() and event.rect().top() == 0 and event.rect().left() == 0: painter = QPainter(self) painter.drawRect(event.rect())
def crosshair_pixmap(): """Create a cross cursor with white/black hollow square pixmap in the middle. For use as points cursor.""" size = 25 pixmap = QPixmap(QSize(size, size)) pixmap.fill(Qt.transparent) painter = QPainter(pixmap) # Base measures width = 1 center = 3 # Must be odd! rect_size = center + 2 * width square = rect_size + width * 4 pen = QPen(Qt.white, 1) pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin) painter.setPen(pen) # # Horizontal rectangle painter.drawRect(0, (size - rect_size) // 2, size - 1, rect_size - 1) # Vertical rectangle painter.drawRect((size - rect_size) // 2, 0, rect_size - 1, size - 1) # Square painter.drawRect( (size - square) // 2, (size - square) // 2, square - 1, square - 1 ) pen = QPen(Qt.black, 2) pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin) painter.setPen(pen) # # Square painter.drawRect( (size - square) // 2 + 2, (size - square) // 2 + 2, square - 4, square - 4, ) pen = QPen(Qt.black, 3) pen.setJoinStyle(Qt.PenJoinStyle.MiterJoin) painter.setPen(pen) # # # Horizontal lines mid_vpoint = QPoint(2, size // 2) painter.drawLine( mid_vpoint, QPoint(((size - center) // 2) - center + 1, size // 2) ) mid_vpoint = QPoint(size - 3, size // 2) painter.drawLine( mid_vpoint, QPoint(((size - center) // 2) + center + 1, size // 2) ) # # # Vertical lines mid_hpoint = QPoint(size // 2, 2) painter.drawLine( QPoint(size // 2, ((size - center) // 2) - center + 1), mid_hpoint ) mid_hpoint = QPoint(size // 2, size - 3) painter.drawLine( QPoint(size // 2, ((size - center) // 2) + center + 1), mid_hpoint ) painter.end() return pixmap
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area There is two cases: - The scroll bar is moving, in which case paint all flags. - The scroll bar is not moving, only paint flags corresponding to visible lines. """ # The area in which the slider handle of the scrollbar may move. groove_rect = self.get_scrollbar_groove_rect() # The scrollbar's scale factor ratio between pixel span height and # value span height scale_factor = groove_rect.height() / self.get_scrollbar_value_height() # The vertical offset of the scroll flag area relative to the # top of the text editor. offset = groove_rect.y() # Note that we calculate the pixel metrics required to draw the flags # here instead of using the convenience methods of the ScrollFlagArea # for performance reason. rect_x = ceil(self.FLAGS_DX / 2) rect_w = self.WIDTH - self.FLAGS_DX rect_h = self.FLAGS_DY # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) editor = self.editor # Define compute_flag_ypos to position the flags: # Paint flags for the entire document last_line = editor.document().lastBlock().firstLineNumber() # The 0.5 offset is used to align the flags with the center of # their corresponding text edit block before scaling. first_y_pos = self.value_to_position(0.5, scale_factor, offset) - self.FLAGS_DY / 2 last_y_pos = self.value_to_position(last_line + 0.5, scale_factor, offset) - self.FLAGS_DY / 2 def compute_flag_ypos(block): line_number = block.firstLineNumber() if editor.verticalScrollBar().maximum() == 0: geometry = editor.blockBoundingGeometry(block) pos = geometry.y() + geometry.height() / 2 + self.FLAGS_DY / 2 elif last_line != 0: frac = line_number / last_line pos = first_y_pos + frac * (last_y_pos - first_y_pos) else: pos = first_y_pos return ceil(pos) # All the lists of block numbers for flags dict_flag_lists = { "occurrence": editor.occurrences, "found_results": editor.found_results } dict_flag_lists.update(self._dict_flag_list) for flag_type in dict_flag_lists: painter.setBrush(self._facecolors[flag_type]) painter.setPen(self._edgecolors[flag_type]) for block_number in dict_flag_lists[flag_type]: # Find the block block = editor.document().findBlockByNumber(block_number) if not block.isValid(): continue # paint if everything else is fine rect_y = compute_flag_ypos(block) painter.drawRect(rect_x, rect_y, rect_w, rect_h) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down if self.slider: cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = editor.rect().contains( editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if is_over_self or (alt and is_over_editor): painter.setPen(self._slider_range_color) painter.setBrush(self._slider_range_brush) x, y, width, height = self.make_slider_range( cursor_pos, scale_factor, offset, groove_rect) painter.drawRect(x, y, width, height) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
class QScale(QFrame): """ A bar-shaped indicator for scalar value. Configurable features include indicator type (bar/pointer), scale tick marks and orientation (horizontal/vertical). Parameters ---------- parent : QWidget The parent widget for the Scale """ def __init__(self, parent=None): super(QScale, self).__init__(parent) self._value = 1 self._lower_limit = -5 self._upper_limit = 5 self.position = None # unit: pixel self._bg_color = QColor('darkgray') self._bg_size_rate = 0.8 # from 0 to 1 self._indicator_color = QColor('black') self._pointer_width_rate = 0.05 self._barIndicator = False self._num_divisions = 10 self._show_ticks = True self._tick_pen = QPen() self._tick_color = QColor('black') self._tick_width = 0 self._tick_size_rate = 0.1 # from 0 to 1 self._painter = QPainter() self._painter_rotation = None self._painter_translation_y = None self._painter_translation_x = None self._painter_scale_x = None self._flip_traslation_y = None self._flip_scale_y = None self._widget_width = self.width() self._widget_height = self.height() self._orientation = Qt.Horizontal self._inverted_appearance = False self._flip_scale = False self._scale_height = 35 self._origin_at_zero = False self._origin_position = 0 self.set_position() def adjust_transformation(self): """ This method sets parameters for the widget transformations (needed to for orientation, flipping and appearance inversion). """ self.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) # Unset fixed size if self._orientation == Qt.Horizontal: self._widget_width = self.width() self._widget_height = self.height() self._painter_translation_y = 0 self._painter_rotation = 0 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setFixedHeight(self._scale_height) elif self._orientation == Qt.Vertical: # Invert dimensions for paintEvent() self._widget_width = self.height() self._widget_height = self.width() self._painter_translation_y = self._widget_width self._painter_rotation = -90 self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.setFixedWidth(self._scale_height) if self._inverted_appearance: self._painter_translation_x = self._widget_width self._painter_scale_x = -1 else: self._painter_translation_x = 0 self._painter_scale_x = 1 if self._flip_scale: self._flip_traslation_y = self._widget_height self._flip_scale_y = -1 else: self._flip_traslation_y = 0 self._flip_scale_y = 1 def set_tick_pen(self): """ Define pen style for drawing scale tick marks. """ self._tick_pen.setColor(self._tick_color) self._tick_pen.setWidth(self._tick_width) def draw_ticks(self): """ Draw tick marks on the scale. """ if not self._show_ticks: return self.set_tick_pen() self._painter.setPen(self._tick_pen) division_size = self._widget_width / self._num_divisions tick_y0 = self._widget_height tick_yf = (1 - self._tick_size_rate)*self._widget_height for i in range(self._num_divisions+1): x = i*division_size self._painter.drawLine(x, tick_y0, x, tick_yf) # x1, y1, x2, y2 def draw_bar(self): """ Draw a bar as indicator of current value. """ self.set_origin() self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) bar_width = self.position - self._origin_position bar_height = self._bg_size_rate * self._widget_height self._painter.drawRect(self._origin_position, 0, bar_width, bar_height) def draw_pointer(self): """ Draw a pointer as indicator of current value. """ self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) pointer_width = self._pointer_width_rate * self._widget_width pointer_height = self._bg_size_rate * self._widget_height points = [ QPoint(self.position, 0), QPoint(self.position + 0.5*pointer_width, 0.5*pointer_height), QPoint(self.position, pointer_height), QPoint(self.position - 0.5*pointer_width, 0.5*pointer_height) ] self._painter.drawPolygon(QPolygon(points)) def draw_indicator(self): """ Draw the selected indicator for current value. """ if self._barIndicator: self.draw_bar() else: self.draw_pointer() def draw_background(self): """ Draw the background of the scale. """ self._painter.setPen(Qt.transparent) self._painter.setBrush(self._bg_color) bg_width = self._widget_width bg_height = self._bg_size_rate * self._widget_height self._painter.drawRect(0, 0, bg_width, bg_height) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self.adjust_transformation() self._painter.begin(self) self._painter.translate(0, self._painter_translation_y) # Draw vertically if needed self._painter.rotate(self._painter_rotation) self._painter.translate(self._painter_translation_x, 0) # Invert appearance if needed self._painter.scale(self._painter_scale_x, 1) self._painter.translate(0, self._flip_traslation_y) # Invert scale if needed self._painter.scale(1, self._flip_scale_y) self._painter.setRenderHint(QPainter.Antialiasing) self.draw_background() self.draw_ticks() self.draw_indicator() self._painter.end() def calculate_position_for_value(self, value): """ Calculate the position (pixel) in which the pointer should be drawn for a given value. """ if value < self._lower_limit or value > self._upper_limit or \ self._upper_limit - self._lower_limit == 0: proportion = -1 # Invalid else: proportion = (value - self._lower_limit) / (self._upper_limit - self._lower_limit) position = int(proportion * self._widget_width) return position def set_origin(self): """ Set the position (pixel) in which the origin should be drawn. """ if self._origin_at_zero: self._origin_position = self.calculate_position_for_value(0) else: self._origin_position = 0 def set_position(self): """ Set the position (pixel) in which the pointer should be drawn. """ self.position = self.calculate_position_for_value(self._value) def update_indicator(self): """ Update the position and the drawing of indicator. """ self.set_position() self.repaint() def set_value(self, value): """ Set a new current value for the indicator. """ self._value = value self.update_indicator() def set_upper_limit(self, new_limit): """ Set the scale upper limit. Parameters ---------- new_limit : float The upper limit of the scale. """ self._upper_limit = new_limit def set_lower_limit(self, new_limit): """ Set the scale lower limit. Parameters ---------- new_limit : float The lower limit of the scale. """ self._lower_limit = new_limit def get_show_ticks(self): return self._show_ticks def set_show_ticks(self, checked): if self._show_ticks != bool(checked): self._show_ticks = checked self.repaint() def get_orientation(self): return self._orientation def set_orientation(self, orientation): self._orientation = orientation self.adjust_transformation() self.repaint() def get_flip_scale(self): return self._flip_scale def set_flip_scale(self, checked): self._flip_scale = bool(checked) self.adjust_transformation() self.repaint() def get_inverted_appearance(self): return self._inverted_appearance def set_inverted_appearance(self, inverted): self._inverted_appearance = inverted self.adjust_transformation() self.repaint() def get_bar_indicator(self): return self._barIndicator def set_bar_indicator(self, checked): if self._barIndicator != bool(checked): self._barIndicator = checked self.repaint() def get_background_color(self): return self._bg_color def set_background_color(self, color): self._bg_color = color self.repaint() def get_indicator_color(self): return self._indicator_color def set_indicator_color(self, color): self._indicator_color = color self.repaint() def get_tick_color(self): return self._tick_color def set_tick_color(self, color): self._tick_color = color self.repaint() def get_background_size_rate(self): return self._bg_size_rate def set_background_size_rate(self, rate): if rate >= 0 and rate <=1 and self._bg_size_rate != rate: self._bg_size_rate = rate self.repaint() def get_tick_size_rate(self): return self._tick_size_rate def set_tick_size_rate(self, rate): if rate >= 0 and rate <=1 and self._tick_size_rate != rate: self._tick_size_rate = rate self.repaint() def get_num_divisions(self): return self._num_divisions def set_num_divisions(self, divisions): if isinstance(divisions, int) and divisions > 0 and self._num_divisions != divisions: self._num_divisions = divisions self.repaint() def get_scale_height(self): return self._scale_height def set_scale_height(self, value): self._scale_height = int(value) self.adjust_transformation() self.repaint() def get_origin_at_zero(self): return self._origin_at_zero def set_origin_at_zero(self, checked): if self._origin_at_zero != bool(checked): self._origin_at_zero = checked self.repaint()
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # Paint warnings and todos block = self.editor.document().firstBlock() for line_number in range(self.editor.document().blockCount()+1): data = block.userData() if data: if data.code_analysis: # Paint the warnings color = self.editor.warning_color for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(line_number)) if data.todo: # Paint the todos self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(line_number)) if data.breakpoint: # Paint the breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(line_number)) block = block.next() # Paint the occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: painter.drawRect(make_flag(line_number)) # Paint the found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: painter.drawRect(make_flag(line_number)) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = self.editor.rect().contains( self.editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if ((is_over_self or (alt and is_over_editor)) and self.slider): pen_color = QColor(Qt.gray) pen_color.setAlphaF(.85) painter.setPen(pen_color) brush_color = QColor(Qt.gray) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(self.make_slider_range(cursor_pos)) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect # Fill the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) # Paint warnings and todos block = self.editor.document().firstBlock() for line_number in range(self.editor.document().blockCount() + 1): data = block.userData() if data: if data.code_analysis: # Paint the warnings color = self.editor.warning_color for source, code, severity, message in data.code_analysis: error = severity == DiagnosticSeverity.ERROR if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(line_number)) if data.todo: # Paint the todos self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(line_number)) if data.breakpoint: # Paint the breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(line_number)) block = block.next() # Paint the occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: painter.drawRect(make_flag(line_number)) # Paint the found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: painter.drawRect(make_flag(line_number)) # Paint the slider range if not self._unit_testing: alt = QApplication.queryKeyboardModifiers() & Qt.AltModifier else: alt = self._alt_key_is_down cursor_pos = self.mapFromGlobal(QCursor().pos()) is_over_self = self.rect().contains(cursor_pos) is_over_editor = self.editor.rect().contains( self.editor.mapFromGlobal(QCursor().pos())) # We use QRect.contains instead of QWidget.underMouse method to # determined if the cursor is over the editor or the flag scrollbar # because the later gives a wrong result when a mouse button # is pressed. if ((is_over_self or (alt and is_over_editor)) and self.slider): pen_color = QColor(Qt.gray) pen_color.setAlphaF(.85) painter.setPen(pen_color) brush_color = QColor(Qt.gray) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(self.make_slider_range(cursor_pos)) self._range_indicator_is_visible = True else: self._range_indicator_is_visible = False
def paintEvent(self, event): """ Override Qt method. Painting the scroll flag area """ make_flag = self.make_flag_qrect make_slider = self.make_slider_range # Filling the whole painting area painter = QPainter(self) painter.fillRect(event.rect(), self.editor.sideareas_color) block = self.editor.document().firstBlock() # Painting warnings and todos for line_number in range(1, self.editor.document().blockCount()+1): data = block.userData() if data: position = self.value_to_position(line_number) if data.code_analysis: # Warnings color = self.editor.warning_color for _message, error in data.code_analysis: if error: color = self.editor.error_color break self.set_painter(painter, color) painter.drawRect(make_flag(position)) if data.todo: # TODOs self.set_painter(painter, self.editor.todo_color) painter.drawRect(make_flag(position)) if data.breakpoint: # Breakpoints self.set_painter(painter, self.editor.breakpoint_color) painter.drawRect(make_flag(position)) block = block.next() # Occurrences if self.editor.occurrences: self.set_painter(painter, self.editor.occurrence_color) for line_number in self.editor.occurrences: position = self.value_to_position(line_number) painter.drawRect(make_flag(position)) # Found results if self.editor.found_results: self.set_painter(painter, self.editor.found_results_color) for line_number in self.editor.found_results: position = self.value_to_position(line_number) painter.drawRect(make_flag(position)) # Painting the slider range pen_color = QColor(Qt.white) pen_color.setAlphaF(.8) painter.setPen(pen_color) brush_color = QColor(Qt.white) brush_color.setAlphaF(.5) painter.setBrush(QBrush(brush_color)) painter.drawRect(make_slider(self.editor.firstVisibleBlock().blockNumber()))
class QScale(QFrame): """ A bar-shaped indicator for scalar value. Configurable features include indicator type (bar/pointer), scale tick marks and orientation (horizontal/vertical). Parameters ---------- parent : QWidget The parent widget for the Scale """ def __init__(self, parent=None): super(QScale, self).__init__(parent) self._value = 1 self._lower_limit = -5 self._upper_limit = 5 self.position = None # unit: pixel self._bg_color = QColor('darkgray') self._bg_size_rate = 0.8 # from 0 to 1 self._indicator_color = QColor('black') self._pointer_width_rate = 0.05 self._barIndicator = False self._num_divisions = 10 self._show_ticks = True self._tick_pen = QPen() self._tick_color = QColor('black') self._tick_width = 0 self._tick_size_rate = 0.1 # from 0 to 1 self._painter = QPainter() self._painter_rotation = None self._painter_translation_y = None self._painter_translation_x = None self._painter_scale_x = None self._flip_traslation_y = None self._flip_scale_y = None self._widget_width = self.width() self._widget_height = self.height() self._orientation = Qt.Horizontal self._inverted_appearance = False self._flip_scale = False self._scale_height = 35 self._origin_at_zero = False self._origin_position = 0 self.set_position() def adjust_transformation(self): """ This method sets parameters for the widget transformations (needed to for orientation, flipping and appearance inversion). """ self.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX) # Unset fixed size if self._orientation == Qt.Horizontal: self._widget_width = self.width() self._widget_height = self.height() self._painter_translation_y = 0 self._painter_rotation = 0 self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self.setFixedHeight(self._scale_height) elif self._orientation == Qt.Vertical: # Invert dimensions for paintEvent() self._widget_width = self.height() self._widget_height = self.width() self._painter_translation_y = self._widget_width self._painter_rotation = -90 self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Expanding) self.setFixedWidth(self._scale_height) if self._inverted_appearance: self._painter_translation_x = self._widget_width self._painter_scale_x = -1 else: self._painter_translation_x = 0 self._painter_scale_x = 1 if self._flip_scale: self._flip_traslation_y = self._widget_height self._flip_scale_y = -1 else: self._flip_traslation_y = 0 self._flip_scale_y = 1 def set_tick_pen(self): """ Define pen style for drawing scale tick marks. """ self._tick_pen.setColor(self._tick_color) self._tick_pen.setWidth(self._tick_width) def draw_ticks(self): """ Draw tick marks on the scale. """ if not self._show_ticks: return self.set_tick_pen() self._painter.setPen(self._tick_pen) division_size = self._widget_width / self._num_divisions tick_y0 = self._widget_height tick_yf = (1 - self._tick_size_rate) * self._widget_height for i in range(self._num_divisions + 1): x = i * division_size self._painter.drawLine(x, tick_y0, x, tick_yf) # x1, y1, x2, y2 def draw_bar(self): """ Draw a bar as indicator of current value. """ self.set_origin() self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) bar_width = self.position - self._origin_position bar_height = self._bg_size_rate * self._widget_height self._painter.drawRect(self._origin_position, 0, bar_width, bar_height) def draw_pointer(self): """ Draw a pointer as indicator of current value. """ self.set_position() if self.position < 0 or self.position > self._widget_width: return self._painter.setPen(Qt.transparent) self._painter.setBrush(self._indicator_color) pointer_width = self._pointer_width_rate * self._widget_width pointer_height = self._bg_size_rate * self._widget_height points = [ QPoint(self.position, 0), QPoint(self.position + 0.5 * pointer_width, 0.5 * pointer_height), QPoint(self.position, pointer_height), QPoint(self.position - 0.5 * pointer_width, 0.5 * pointer_height) ] self._painter.drawPolygon(QPolygon(points)) def draw_indicator(self): """ Draw the selected indicator for current value. """ if self._barIndicator: self.draw_bar() else: self.draw_pointer() def draw_background(self): """ Draw the background of the scale. """ self._painter.setPen(Qt.transparent) self._painter.setBrush(self._bg_color) bg_width = self._widget_width bg_height = self._bg_size_rate * self._widget_height self._painter.drawRect(0, 0, bg_width, bg_height) def paintEvent(self, event): """ Paint events are sent to widgets that need to update themselves, for instance when part of a widget is exposed because a covering widget was moved. Parameters ---------- event : QPaintEvent """ self.adjust_transformation() self._painter.begin(self) self._painter.translate( 0, self._painter_translation_y) # Draw vertically if needed self._painter.rotate(self._painter_rotation) self._painter.translate(self._painter_translation_x, 0) # Invert appearance if needed self._painter.scale(self._painter_scale_x, 1) self._painter.translate( 0, self._flip_traslation_y) # Invert scale if needed self._painter.scale(1, self._flip_scale_y) self._painter.setRenderHint(QPainter.Antialiasing) self.draw_background() self.draw_ticks() self.draw_indicator() self._painter.end() def calculate_position_for_value(self, value): """ Calculate the position (pixel) in which the pointer should be drawn for a given value. """ if value is None or value < self._lower_limit or value > self._upper_limit or \ self._upper_limit - self._lower_limit == 0: proportion = -1 # Invalid else: proportion = (value - self._lower_limit) / (self._upper_limit - self._lower_limit) position = int(proportion * self._widget_width) return position def set_origin(self): """ Set the position (pixel) in which the origin should be drawn. """ if self._origin_at_zero: self._origin_position = self.calculate_position_for_value(0) else: self._origin_position = 0 def set_position(self): """ Set the position (pixel) in which the pointer should be drawn. """ self.position = self.calculate_position_for_value(self._value) def update_indicator(self): """ Update the position and the drawing of indicator. """ self.set_position() self.repaint() def set_value(self, value): """ Set a new current value for the indicator. """ self._value = value self.update_indicator() def set_upper_limit(self, new_limit): """ Set the scale upper limit. Parameters ---------- new_limit : float The upper limit of the scale. """ self._upper_limit = new_limit def set_lower_limit(self, new_limit): """ Set the scale lower limit. Parameters ---------- new_limit : float The lower limit of the scale. """ self._lower_limit = new_limit def get_show_ticks(self): return self._show_ticks def set_show_ticks(self, checked): if self._show_ticks != bool(checked): self._show_ticks = checked self.repaint() def get_orientation(self): return self._orientation def set_orientation(self, orientation): self._orientation = orientation self.adjust_transformation() self.repaint() def get_flip_scale(self): return self._flip_scale def set_flip_scale(self, checked): self._flip_scale = bool(checked) self.adjust_transformation() self.repaint() def get_inverted_appearance(self): return self._inverted_appearance def set_inverted_appearance(self, inverted): self._inverted_appearance = inverted self.adjust_transformation() self.repaint() def get_bar_indicator(self): return self._barIndicator def set_bar_indicator(self, checked): if self._barIndicator != bool(checked): self._barIndicator = checked self.repaint() def get_background_color(self): return self._bg_color def set_background_color(self, color): self._bg_color = color self.repaint() def get_indicator_color(self): return self._indicator_color def set_indicator_color(self, color): self._indicator_color = color self.repaint() def get_tick_color(self): return self._tick_color def set_tick_color(self, color): self._tick_color = color self.repaint() def get_background_size_rate(self): return self._bg_size_rate def set_background_size_rate(self, rate): if rate >= 0 and rate <= 1 and self._bg_size_rate != rate: self._bg_size_rate = rate self.repaint() def get_tick_size_rate(self): return self._tick_size_rate def set_tick_size_rate(self, rate): if rate >= 0 and rate <= 1 and self._tick_size_rate != rate: self._tick_size_rate = rate self.repaint() def get_num_divisions(self): return self._num_divisions def set_num_divisions(self, divisions): if isinstance( divisions, int) and divisions > 0 and self._num_divisions != divisions: self._num_divisions = divisions self.repaint() def get_scale_height(self): return self._scale_height def set_scale_height(self, value): self._scale_height = int(value) self.adjust_transformation() self.repaint() def get_origin_at_zero(self): return self._origin_at_zero def set_origin_at_zero(self, checked): if self._origin_at_zero != bool(checked): self._origin_at_zero = checked self.repaint()
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