def boundingRect(self): if hasattr(self, "attr"): attr_rect = QRectF(QPointF(0, -self.attr_text_h), QSizeF(self.attr_text_w, self.attr_text_h)) else: attr_rect = QRectF(0, 0, 1, 1) rect = self.rect().adjusted(-5, -5, 5, 5) return rect | attr_rect
def __naturalsh(self) -> QSizeF: """Return the natural size hint (preferred sh with no constraints).""" fm = QFontMetrics(self.font()) spacing = self.__spacing N = len(self.__items) width = self.__width_for_font(self.font()) height = N * fm.height() + max(N - 1, 0) * spacing return QSizeF(width, height)
def sizeHint(self, which, constraint=QSizeF()): if which == Qt.PreferredSize: sh = self.__naturalsh() if 0 < constraint.height() < sh.height(): sh = scaled(sh, constraint, Qt.KeepAspectRatioByExpanding) return sh return super().sizeHint(which, constraint)
def __naturalsh(self): fm = QFontMetrics(self.font()) spacing = self.__spacing N = len(self.__items) width = max((fm.width(text) for text in self.__items), default=0) height = N * fm.height() + (N - 1) * spacing return QSizeF(width, height)
def __init__(self, color, parent): super().__init__(parent) height, width = self.SIZE.height(), self.SIZE.width() self.__circle = QGraphicsEllipseItem(0, 0, height, width) self.__circle.setBrush(QBrush(color)) self.__circle.setPen(QPen(QColor(0, 0, 0, 0))) self.__circle.setParentItem(self) self._size_hint = QSizeF(self.__circle.boundingRect().size())
def adjustSize(self): """Resize to a reasonable size. """ self.__textItem.setTextWidth(-1) self.__textItem.adjustSize() size = self.__textItem.boundingRect().size() left, top, right, bottom = self.textMargins() geom = QRectF(self.pos(), size + QSizeF(left + right, top + bottom)) self.setGeometry(geom)
def paint(self, painter, option, index): # type: (QPainter, QStyleOptionViewItem, QModelIndex) -> None scene = index.data(Qt.DisplayRole) # type: Optional[QGraphicsScene] if scene is None: super().paint(painter, option, index) return painter.save() rect = QRectF(QPointF(option.rect.topLeft()), QSizeF(option.rect.size())) if option.state & QStyle.State_Selected: painter.setPen(QPen(QColor(125, 162, 206, 192))) painter.setBrush(QBrush(QColor(217, 232, 252, 192))) else: painter.setPen(QPen(QColor('#ebebeb'))) painter.drawRoundedRect(rect, 3, 3) painter.restore() painter.setRenderHint(QPainter.Antialiasing) # The sceneRect doesn't automatically shrink to fit contents, so when # drawing smaller tree, remove any excess space aroung the tree scene.setSceneRect(scene.itemsBoundingRect()) # Make sure the tree is centered in the item cell # First, figure out how much we get the bounding rect to the size of # the available painting rect scene_rect = scene.itemsBoundingRect() w_scale = option.rect.width() / scene_rect.width() h_scale = option.rect.height() / scene_rect.height() # In order to keep the aspect ratio, we use the same scale scale = min(w_scale, h_scale) # Figure out the rescaled scene width/height scene_w = scale * scene_rect.width() scene_h = scale * scene_rect.height() # Figure out how much we have to offset the rect so that the scene will # be painted in the centre of the rect offset_w = (option.rect.width() - scene_w) / 2 offset_h = (option.rect.height() - scene_h) / 2 offset = option.rect.topLeft() + QPointF(offset_w, offset_h) # Finally, we have all the data for the new rect in which to render target_rect = QRectF(offset, QSizeF(scene_w, scene_h)) scene.render(painter, target=target_rect, mode=Qt.KeepAspectRatio)
def sizeHint(self, which: Qt.SizeHint, constraint=QSizeF()) -> QSizeF: # reimplemented fm = QFontMetrics(self.font()) spacing = fm.lineSpacing() mleft, mtop, mright, mbottom = self.getContentsMargins() if self._root and which == Qt.PreferredSize: nleaves = len( [node for node in self._items.keys() if not node.branches]) base = max(10, min(spacing * 16, 250)) if self.orientation in [self.Left, self.Right]: return QSizeF(base, spacing * nleaves + mleft + mright) else: return QSizeF(spacing * nleaves + mtop + mbottom, base) elif which == Qt.MinimumSize: return QSizeF(mleft + mright + 10, mtop + mbottom + 10) else: return QSizeF()
def paint(self, painter, option, widget=0): if self._pixmap.isNull(): return rect = self.contentsRect() pixsize = QSizeF(self._pixmap.size()) aspectmode = (Qt.KeepAspectRatio if self._keepAspect else Qt.IgnoreAspectRatio) pixsize.scale(rect.size(), aspectmode) pixrect = QRectF(QPointF(0, 0), pixsize) pixrect.moveCenter(rect.center()) painter.save() painter.setPen(QPen(QColor(0, 0, 0, 50), 3)) painter.drawRoundedRect(pixrect, 2, 2) painter.setRenderHint(QPainter.SmoothPixmapTransform) source = QRectF(QPointF(0, 0), QSizeF(self._pixmap.size())) painter.drawPixmap(pixrect, self._pixmap, source) painter.restore()
def sizeHint(self, which: Qt.SizeHint, constraint=QSizeF(-1, -1)) -> QSizeF: left, top, right, bottom = self.getContentsMargins() extra_margins = QSizeF(left + right, top + bottom) if constraint.width() >= 0: constraint.setWidth( max(constraint.width() - extra_margins.width(), 0.0)) if which == Qt.PreferredSize: if constraint.width() >= 0: rect = QRectF(0, 0, constraint.width(), FLT_MAX) else: rect = QRectF(0, 0, FLT_MAX, FLT_MAX) res = self.__doLayout(rect) sh = reduce(QRectF.united, res, QRectF()).size() return sh + extra_margins if which == Qt.MinimumSize: return reduce(QSizeF.expandedTo, (item.minimumSize() for item in self.__items), QSizeF()) + extra_margins return QSizeF()
class LegendGradient(QGraphicsWidget): """Gradient widget. A gradient square bar that can be used to display continuous values. Parameters ---------- palette : iterable[QColor] parent : QGraphicsWidget orientation : Qt.Orientation Notes ----- .. note:: While the gradient does support any number of colors, any more than 3 is not very readable. This should not be a problem, since Orange only implements 2 or 3 colors. """ # Default sizes (assume gradient is vertical by default) GRADIENT_WIDTH = 20 GRADIENT_HEIGHT = 150 _size_hint = QSizeF(GRADIENT_WIDTH, GRADIENT_HEIGHT) def __init__(self, palette, parent, orientation): super().__init__(parent) self.__gradient = QLinearGradient() num_colors = len(palette) for idx, stop in enumerate(palette): self.__gradient.setColorAt(idx * (1. / (num_colors - 1)), stop) # We need to tell the gradient where it's start and stop points are self.__gradient.setStart(QPointF(0, 0)) if orientation == Qt.Vertical: final_stop = QPointF(0, self.GRADIENT_HEIGHT) else: final_stop = QPointF(self.GRADIENT_HEIGHT, 0) self.__gradient.setFinalStop(final_stop) # Get the appropriate rectangle dimensions based on orientation if orientation == Qt.Vertical: width, height = self.GRADIENT_WIDTH, self.GRADIENT_HEIGHT elif orientation == Qt.Horizontal: width, height = self.GRADIENT_HEIGHT, self.GRADIENT_WIDTH self.__rect_item = QGraphicsRectItem(0, 0, width, height, self) self.__rect_item.setPen(QPen(QColor(0, 0, 0, 0))) self.__rect_item.setBrush(QBrush(self.__gradient)) self._size_hint = QSizeF(self.__rect_item.boundingRect().size()) def sizeHint(self, size_hint, size_constraint=None, *args, **kwargs): return self._size_hint
def __gridlayout(self): assert self.__layoutMode == GraphicsThumbnailGrid.FixedColumnCount width = ((self.size().width() - self.__columnCount * 10) / self.__columnCount) height = (self.size().height() - self.__rowCount * 10) / self.__rowCount for item in self.__thumbnails: label_size = item.label.height() + 1 if item.label is not None else 0 item_size = min(width, height - label_size) item.setThumbnailSize(QSizeF(item_size, item_size)) self.__relayoutGrid(self.__columnCount)
def _resizeToFit(self): widget = self.__centralWidget size = self.__viewportContentSize() vprect = self.viewport().geometry() vprect.setSize(size) margins = self.viewportMargins() vprect = vprect.marginsRemoved(margins) viewrect = self.mapToScene(vprect).boundingRect() targetsize = viewrect.size() maxsize = widget.maximumSize() minsize = widget.minimumSize() targetsize = targetsize.expandedTo(minsize).boundedTo(maxsize) sh = widget.effectiveSizeHint(Qt.PreferredSize) policy = widget.sizePolicy() vpolicy = policy.verticalPolicy() hpolicy = policy.horizontalPolicy() if not self.__fitInView: widget.resize(sh.expandedTo(minsize).boundedTo(maxsize)) return width = adjusted_size( sh.width(), targetsize.width(), minsize.width(), maxsize.width(), hpolicy) height = adjusted_size( sh.height(), targetsize.height(), minsize.height(), maxsize.height(), vpolicy) if policy.hasHeightForWidth(): constr = QSizeF(width, -1) height = adjusted_size( widget.effectiveSizeHint(Qt.PreferredSize, constr).height(), targetsize.height(), widget.effectiveSizeHint(Qt.MinimumSize, constr).height(), widget.effectiveSizeHint(Qt.MaximumSize, constr).height(), QSizePolicy.Fixed ) widget.resize(QSizeF(width, height))
def __gridlayout(self): assert self.__layoutMode == GraphicsThumbnailGrid.FixedColumnCount width = (self.size().width() - self.__columnCount * 10) / self.__columnCount height = (self.size().height() - self.__rowCount * 10) / self.__rowCount item_size = min(width, height) for item in self.__thumbnails: item.setThumbnailSize(QSizeF(item_size, item_size)) self.__relayoutGrid(self.__columnCount)
def sizeHint(self, which: Qt.SizeHint, constraint=QSizeF()) -> QSizeF: """Reimplemented.""" if which == Qt.PreferredSize: sh = self.__naturalsh() if self.__orientation == Qt.Vertical: if 0 < constraint.height() < sh.height(): sh = scaled(sh, constraint, Qt.KeepAspectRatioByExpanding) else: sh = sh.transposed() if 0 < constraint.width() < sh.width(): sh = scaled(sh, constraint, Qt.KeepAspectRatioByExpanding) else: sh = super().sizeHint(which, constraint) return sh
def sizeHint(self, which, constraint=QSizeF()): if which == Qt.PreferredSize: doc = self.document() textwidth = doc.textWidth() if textwidth != constraint.width(): cloned = doc.clone(self) cloned.setTextWidth(constraint.width()) sh = cloned.size() cloned.deleteLater() else: sh = doc.size() return sh else: return super().sizeHint(which, constraint)
def defaultTextGeometry(self, point): """ Return the default text geometry. Used in case the user single clicked in the scene. """ font = self.annotation_item.font() metrics = QFontMetrics(font) spacing = metrics.lineSpacing() margin = self.annotation_item.document().documentMargin() rect = QRectF(QPointF(point.x(), point.y() - spacing - margin), QSizeF(150, spacing + 2 * margin)) return rect
def _rescale(self): if self._root is None: return scale = self._height_scale_factor() base = scale * self._root.value.height crect = self.contentsRect() leaf_count = len(list(leaves(self._root))) if self.orientation in [Left, Right]: drect = QSizeF(base, leaf_count) else: drect = QSizeF(leaf_count, base) eps = np.finfo(np.float64).eps if abs(drect.width()) < eps: sx = 1.0 else: sx = crect.width() / drect.width() if abs(drect.height()) < eps: sy = 1.0 else: sy = crect.height() / drect.height() transform = QTransform().scale(sx, sy) self._transform = transform self._itemgroup.setPos(crect.topLeft()) self._itemgroup.setGeometry(crect) for node_geom in postorder(self._layout): node, _ = node_geom.value item = self._items[node] item.setGeometryData(transform.map(item.sourcePath), transform.map(item.sourceAreaShape)) self._selection_items = None self._update_selection_items()
def __init__(self, parent=None, direction=Qt.LeftToRight, node=None, icon=None, iconSize=None, **args): super().__init__(parent, **args) self.setAcceptedMouseButtons(Qt.NoButton) self.__direction = direction self.setLayout(QGraphicsLinearLayout(Qt.Horizontal)) # Set the maximum size, otherwise the layout can't grow beyond its # sizeHint (and we need it to grow so the widget can grow and keep the # contents centered vertically. self.layout().setMaximumSize(QSizeF(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)) self.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) self.__iconSize = iconSize or QSize(64, 64) self.__icon = icon self.__iconItem = QGraphicsPixmapItem(self) self.__iconLayoutItem = GraphicsItemLayoutItem(item=self.__iconItem) self.__channelLayout = QGraphicsGridLayout() self.channelAnchors = [] if self.__direction == Qt.LeftToRight: self.layout().addItem(self.__iconLayoutItem) self.layout().addItem(self.__channelLayout) channel_alignemnt = Qt.AlignRight else: self.layout().addItem(self.__channelLayout) self.layout().addItem(self.__iconLayoutItem) channel_alignemnt = Qt.AlignLeft self.layout().setAlignment(self.__iconLayoutItem, Qt.AlignCenter) self.layout().setAlignment(self.__channelLayout, Qt.AlignVCenter | channel_alignemnt) self.node: Optional[SchemeNode] = None self.channels: Union[List[InputSignal], List[OutputSignal]] = [] if node is not None: self.setSchemeNode(node)
def pixmapTransform(self) -> QTransform: if self.__pixmap.isNull(): return QTransform() pxsize = QSizeF(self.__pixmap.size()) crect = self.contentsRect() transform = QTransform() transform = transform.translate(crect.left(), crect.top()) if self.__scaleContents: csize = scaled(pxsize, crect.size(), self.__aspectMode) else: csize = pxsize xscale = csize.width() / pxsize.width() yscale = csize.height() / pxsize.height() return transform.scale(xscale, yscale)
def setupScene(self): self.error() if self.data: attr = self.stringAttrs[self.smilesAttr] titleAttr = self.allAttrs[self.titleAttr] assert self.thumbnailView.count() == 0 size = QSizeF(self.imageSize, self.imageSize) for i, inst in enumerate(self.data): if not numpy.isfinite(inst[attr]): # skip missing continue smiles = str(inst[attr]) title = str(inst[titleAttr]) thumbnail = GraphicsThumbnailWidget(QPixmap(), title=title) thumbnail.setThumbnailSize(size) thumbnail.setToolTip(smiles) thumbnail.instance = inst self.thumbnailView.addThumbnail(thumbnail) if self.check_smiles(smiles): pixmap = self.pixmap_from_smiles(smiles) thumbnail.setPixmap(pixmap) self._successcount += 1 else: pixmap = QPixmap() thumbnail.setPixmap(pixmap) thumbnail.setToolTip(thumbnail.toolTip() + "\nInvalid SMILES") self._errcount += 1 future = Future() future.set_result(pixmap) future._reply = None self.items.append(_ImageItem(i, thumbnail, smiles, future)) if any(it.future is not None and not it.future.done() for it in self.items): self.info.setText("Retrieving...\n") else: self._updateStatus()
def __doLayout(self, rect: QRectF) -> Iterable[QRectF]: x = y = 0 rowheight = 0 width = rect.width() spacing_x, spacing_y = self.__spacing first_in_row = True rows: List[List[QRectF]] = [[]] def break_(): nonlocal x, y, rowheight, first_in_row y += rowheight + spacing_y x = 0 rowheight = 0 first_in_row = True rows.append([]) items = [ _FlowLayoutItem(item=item, geom=QRectF(), size=QSizeF()) for item in self.__items ] for flitem in items: item = flitem.item sh = item.effectiveSizeHint(Qt.PreferredSize) if x + sh.width() > width and not first_in_row: break_() r = QRectF(rect.x() + x, rect.y() + y, sh.width(), sh.height()) flitem.geom = r flitem.size = sh flitem.row = len(rows) - 1 rowheight = max(rowheight, sh.height()) x += sh.width() + spacing_x first_in_row = False rows[-1].append(flitem.geom) alignment = Qt.AlignVCenter | Qt.AlignLeft for flitem in items: row = rows[flitem.row] row_rect = reduce(QRectF.united, row, QRectF()) if row_rect.isEmpty(): continue flitem.geom = qrect_aligned_to(flitem.geom, row_rect, alignment & Qt.AlignVertical_Mask) return [fli.geom for fli in items]
def item_at(self, pos, type_or_tuple=None, buttons=0): """Return the item at `pos` that is an instance of the specified type (`type_or_tuple`). If `buttons` (`Qt.MouseButtons`) is given only return the item if it is the top level item that would accept any of the buttons (`QGraphicsItem.acceptedMouseButtons`). """ rect = QRectF(pos, QSizeF(1, 1)) items = self.items(rect) if buttons: items = itertools.dropwhile( lambda item: not item.acceptedMouseButtons() & buttons, items) items = list(items)[:1] if type_or_tuple: items = [i for i in items if isinstance(i, type_or_tuple)] return items[0] if items else None
def export(self, filename=None): pw = QPdfWriter(filename) dpi = QApplication.desktop().logicalDpiX() pw.setResolution(dpi) pw.setPageMargins(QMarginsF(0, 0, 0, 0)) pw.setPageSizeMM(QSizeF(self.getTargetRect().size()) / dpi * 25.4) painter = QPainter(pw) try: self.setExportMode(True, {'antialias': True, 'background': self.background, 'painter': painter}) painter.setRenderHint(QPainter.Antialiasing, True) if QtCore.QT_VERSION >= 0x050D00: painter.setRenderHint(QPainter.LosslessImageRendering, True) self.getScene().render(painter, QRectF(self.getTargetRect()), QRectF(self.getSourceRect())) finally: self.setExportMode(False) painter.end()
def render_drop_shadow_frame(pixmap, shadow_rect, shadow_color, offset, radius, rect_fill_color): pixmap.fill(QColor(0, 0, 0, 0)) scene = QGraphicsScene() rect = QGraphicsRectItem(shadow_rect) rect.setBrush(QColor(rect_fill_color)) rect.setPen(QPen(Qt.NoPen)) scene.addItem(rect) effect = QGraphicsDropShadowEffect(color=shadow_color, blurRadius=radius, offset=offset) rect.setGraphicsEffect(effect) scene.setSceneRect(QRectF(QPointF(0, 0), QSizeF(pixmap.size()))) painter = QPainter(pixmap) scene.render(painter) painter.end() scene.clear() scene.deleteLater() return pixmap
def __init__(self, pixmap, parentItem=None, crop=False, in_subset=True, add_label=False, text="", **kwargs): super().__init__(parentItem, **kwargs) self.setFocusPolicy(Qt.StrongFocus) self._size = QSizeF() layout = QGraphicsLinearLayout(Qt.Vertical, self) layout.setSpacing(1) layout.setContentsMargins(5, 5, 5, 5) self.setContentsMargins(0, 0, 0, 0) self.pixmapWidget = GraphicsPixmapWidget(pixmap, self) self.pixmapWidget.setCrop(crop) self.pixmapWidget.setSubset(in_subset) self.selectionBrush = DEFAULT_SELECTION_BRUSH self.selectionPen = DEFAULT_SELECTION_PEN layout.addItem(self.pixmapWidget) self.label = None if add_label: l1 = ElidedLabel(text) l1.setStyleSheet("background-color: rgba(255, 255, 255, 10);") l1.setAlignment(Qt.AlignCenter) l1.setFixedHeight(16) self.label = l1 gs = QGraphicsScene() w = gs.addWidget(l1) layout.addItem(w) layout.setAlignment(self.pixmapWidget, Qt.AlignCenter) self.setLayout(layout) self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)
def paint(self, painter, option, widget=0): if self._pixmap.isNull(): return rect = self.contentsRect() pixsize = QSizeF(self._pixmap.size()) aspectmode = (Qt.KeepAspectRatio if self._keepAspect else Qt.IgnoreAspectRatio) if self._crop: height, width = pixsize.height(), pixsize.width() diff = abs(height - width) if height > width: y, x = diff / 2, 0 h, w = height - diff, width else: x, y = diff / 2, 0 w, h = width - diff, height source = QRectF(x, y, w, h) pixrect = QRectF(QPointF(0, 0), rect.size()) else: source = QRectF(QPointF(0, 0), pixsize) pixsize.scale(rect.size(), aspectmode) pixrect = QRectF(QPointF(0, 0), pixsize) if self._subset: painter.setOpacity(1.0) else: painter.setOpacity(0.35) pixrect.moveCenter(rect.center()) painter.save() painter.setPen(QPen(QColor(0, 0, 0, 50), 3)) painter.drawRoundedRect(pixrect, 2, 2) painter.setRenderHint(QPainter.SmoothPixmapTransform) painter.drawPixmap(pixrect, self._pixmap, source) painter.restore()
def mouseReleaseEvent(self, event): QGraphicsScene.mouseReleaseEvent(self, event) if event.button() == Qt.LeftButton: modifiers = event.modifiers() path = QPainterPath() # the mouse was moved if self.selectionRect: path.addRect(self.selectionRect.rect()) self.removeItem(self.selectionRect) self.selectionRect = None # the mouse was only clicked - create a selection area of 1x1 size else: rect = QRectF(event.buttonDownScenePos(Qt.LeftButton), QSizeF(1., 1.)).intersected(self.sceneRect()) path.addRect(rect) self.setSelectionArea(path) self.selectionChanged.emit(set(self.selectedItems()), modifiers)
def paint(self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: Optional[QWidget] = None) -> None: if self.__pixmap.isNull(): return pixmap = self.__pixmap crect = self.contentsRect() exposed = option.exposedRect exposedcrect = crect.intersected(exposed) pixmaptransform = self.pixmapTransform() # map exposed rect to exposed pixmap coords assert pixmaptransform.type() <= QTransform.TxRotate pixmaptransform, ok = pixmaptransform.inverted() if not ok: painter.drawPixmap(crect, pixmap, QRectF(QPointF(0, 0), QSizeF(pixmap.size()))) else: exposedpixmap = pixmaptransform.mapRect(exposed) painter.drawPixmap(exposedcrect, pixmap, exposedpixmap)
def sizeHint(self, which, constraint=QSizeF(-1, -1)) -> QSizeF: if which == Qt.PreferredSize: sh = QSizeF(self.__pixmap.size()) if self.__scaleContents: sh = scaled(sh, constraint, self.__aspectMode) return sh elif which == Qt.MinimumSize: if self.__scaleContents: return QSizeF(0, 0) else: return QSizeF(self.__pixmap.size()) elif which == Qt.MaximumSize: if self.__scaleContents: return QSizeF() else: return QSizeF(self.__pixmap.size()) else: # Qt.MinimumDescent return QSizeF()