def drawValue(self, p: QPainter, baseRect: QRectF, value: float, delta: float): if value == self.m_min: return if self.m_barStyle == self.BarStyle.EXPAND: p.setBrush(self.palette().highlight()) p.setPen(QPen(self.palette().shadow().color(), self.m_dataPenWidth)) radius = (baseRect.height() / 2) / delta p.drawEllipse(baseRect.center(), radius, radius) return if self.m_barStyle == self.BarStyle.LINE: p.setPen(QPen(self.palette().highlight().color(), self.m_dataPenWidth)) p.setBrush(Qt.NoBrush) if value == self.m_max: p.drawEllipse(baseRect.adjusted(self.m_outlinePenWidth / 2, self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2)) else: arcLength = 360 / delta p.drawArc(baseRect.adjusted(self.m_outlinePenWidth / 2, self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2), int(self.m_nullPosition * 16), int(-arcLength * 16)) return dataPath = QPainterPath() dataPath.setFillRule(Qt.WindingFill) if value == self.m_max: dataPath.addEllipse(baseRect) else: arcLength = 360 / delta dataPath.moveTo(baseRect.center()) dataPath.arcTo(baseRect, self.m_nullPosition, -arcLength) dataPath.lineTo(baseRect.center()) p.setBrush(self.palette().highlight()) p.setPen(QPen(self.palette().shadow().color(), self.m_dataPenWidth)) p.drawPath(dataPath)
class SelectionRectangle(QGraphicsItem): def __init__(self, parent=None): super().__init__(parent) self.setZValue(10000) self.mRectangle = QRectF() def setRectangle(self, rectangle): self.prepareGeometryChange() self.mRectangle = rectangle def boundingRect(self): return self.mRectangle.adjusted(-1, -1, 2, 2) def paint(self, painter, option, widget=None): if (self.mRectangle.isNull()): return # Draw a shadow black = QColor(Qt.black) black.setAlpha(128) pen = QPen(black, 2, Qt.DotLine) pen.setCosmetic(True) painter.setPen(pen) painter.drawRect(self.mRectangle.translated(1, 1)) # Draw a rectangle in the highlight color highlight = QApplication.palette().highlight().color() pen.setColor(highlight) highlight.setAlpha(32) painter.setPen(pen) painter.setBrush(highlight) painter.drawRect(self.mRectangle)
class SelectionRectangle(QGraphicsItem): def __init__(self, parent = None): super().__init__(parent) self.setZValue(10000) self.mRectangle = QRectF() def setRectangle(self, rectangle): self.prepareGeometryChange() self.mRectangle = rectangle def boundingRect(self): return self.mRectangle.adjusted(-1, -1, 2, 2) def paint(self, painter, option, widget = None): if (self.mRectangle.isNull()): return # Draw a shadow black = QColor(Qt.black) black.setAlpha(128) pen = QPen(black, 2, Qt.DotLine) pen.setCosmetic(True) painter.setPen(pen) painter.drawRect(self.mRectangle.translated(1, 1)) # Draw a rectangle in the highlight color highlight = QApplication.palette().highlight().color() pen.setColor(highlight) highlight.setAlpha(32) painter.setPen(pen) painter.setBrush(highlight) painter.drawRect(self.mRectangle)
def _hitTest(self, rc: QRectF, mousePos: QPointF) -> Hit: maxdist = 4 if not rc.adjusted(-maxdist, -maxdist, maxdist, maxdist).contains(mousePos): return Hit.NoHit def dist(p1, p2): return (p1 - p2).manhattanLength() if dist(rc.topLeft(), mousePos) < maxdist: return Hit.TopLeft elif dist(rc.topRight(), mousePos) < maxdist: return Hit.TopRight elif dist(rc.bottomRight(), mousePos) < maxdist: return Hit.BottomRight elif dist(rc.bottomLeft(), mousePos) < maxdist: return Hit.BottomLeft elif abs(rc.left() - mousePos.x()) < maxdist: return Hit.Left elif abs(rc.right() - mousePos.x()) < maxdist: return Hit.Right elif abs(rc.top() - mousePos.y()) < maxdist: return Hit.Top elif abs(rc.bottom() - mousePos.y()) < maxdist: return Hit.Bottom elif rc.contains(mousePos): return Hit.Center else: return Hit.NoHit
def paint(self, painter, styleOption, modelIndex): """Paint the Data Edit Cells with support for rich text. Other cells are painted with the base class default. Also paints an error rectangle if the format error flag is set. Arguments: painter -- the painter instance styleOption -- the data for styles and geometry modelIndex -- the index of the cell to be painted """ cell = self.parent().item(modelIndex.row(), modelIndex.column()) if isinstance(cell, DataEditCell): painter.save() doc = cell.doc doc.setTextWidth(styleOption.rect.width()) painter.translate(styleOption.rect.topLeft()) paintRect = QRectF(0, 0, styleOption.rect.width(), styleOption.rect.height()) painter.setClipRect(paintRect) painter.fillRect(paintRect, QApplication.palette().base()) painter.setPen(QPen(QApplication.palette().text(), 1)) painter.drawRect(paintRect.adjusted(0, 0, -1, -1)) doc.drawContents(painter) if cell.errorFlag: path = QPainterPath(QPointF(0, 0)) path.lineTo(0, 10) path.lineTo(10, 0) path.closeSubpath() painter.fillPath(path, QApplication.palette().highlight()) painter.restore() else: super().paint(painter, styleOption, modelIndex)
class Indicator(QGraphicsItem): def __init__(self, data: "InternalData", scene: QGraphicsScene, parent=None): super().__init__(parent) self.rect = QRectF(0, 0, 0, 0) self.data: "InternalData" = data def boundingRect(self): # f*****g PyQt5 binding: return value of boundingRect should be QRectF return QRectF(self.rect.adjusted(-2, -2, 2, 2)) def paint( self, painter: QPainter, option: QStyleOptionGraphicsItem, widget: QWidget = None, ): painter.drawRect(self.rect) b = self.data.bar_data text = (f"open: {b.open}\n" f"high: {b.high}\n" f"low: {b.low}\n" f"close: {b.close}\n" f"date: {self.data.x}") rect = painter.boundingRect(0.0, 0.0, 1000.0, 1000.0, Qt.AlignLeft, text) painter.drawText(self.rect, Qt.AlignLeft, text) self.rect = rect # fixme: scrolling will make this mismatch
def paintEvent(self, event): painter = QPainter(self) if self.pixmap: size = self.pixmap.size() aspect = float(size.width()) / size.height() if aspect > 1: # Image is wider than it is tall - centre vertically left = 0 width = self.width() height = self.height() / aspect top = (self.height() - height) / 2 else: # Image is taller than it is wide - centre horizontally top = 0 height = self.height() width = self.width() * aspect left = (self.width() - width) / 2 painter.drawPixmap(QRect(left, top, width, height), self.pixmap) if self.focus: # self.focus contains coords between 0 and 1 - translate these # to pixels pixels = QRectF(left + self.focus.left() * width, top + self.focus.top() * height, self.focus.width() * width, self.focus.height() * height) # Outer box in white painter.setPen(QPen(Qt.white, 1, Qt.SolidLine)) painter.drawRect(pixels) # Inner box in black painter.setPen(QPen(Qt.black, 1, Qt.SolidLine)) painter.drawRect(pixels.adjusted(1, 1, -1, -1))
class Spinner(QSvgWidget): icon_file = QtDynamicProperty('icon_file', type=unicode) icon_size = QtDynamicProperty('icon_size', type=QSize) icon_crop = QtDynamicProperty('icon_crop', type=int) def __init__(self, parent=None, icon='icons/spinner.svg'): super(Spinner, self).__init__(parent) self._original_viewbox = QRectF() self.icon_crop = 0 self.icon_size = None self.icon_file = Resources.get(icon) def load(self, svg): super(Spinner, self).load(svg) self._original_viewbox = self.renderer().viewBoxF() self._update_viewbox(self.size()) def event(self, event): if event.type() == QEvent.DynamicPropertyChange: if event.propertyName() == 'icon_crop': self._update_viewbox(self.size()) elif event.propertyName() == 'icon_file': self.load(self.icon_file) elif event.propertyName() == 'icon_size': self.updateGeometry() return super(Spinner, self).event(event) def resizeEvent(self, event): super(Spinner, self).resizeEvent(event) self._update_viewbox(event.size()) def sizeHint(self): return self.icon_size or super(Spinner, self).sizeHint() def _update_viewbox(self, size): if self._original_viewbox.isEmpty() or size.isEmpty(): return if self.icon_crop >= 0: adjustment = self.icon_crop else: adjustment = self._original_viewbox.width() * self.icon_crop / ( self._original_viewbox.width() + 2 * self.icon_crop ) # (w - w * w/(w+2b))/2 = wb/(w+2b) viewbox = self._original_viewbox.adjusted(adjustment, adjustment, -adjustment, -adjustment) width = size.width() height = size.height() if height >= width: new_viewbox = QRectF( viewbox.x(), viewbox.y() + viewbox.height() / 2 * (1 - height / width), viewbox.width(), viewbox.height() * height / width) else: new_viewbox = QRectF( viewbox.x() + viewbox.width() / 2 * (1 - width / height), viewbox.y(), viewbox.width() * width / height, viewbox.height()) self.renderer().setViewBox(new_viewbox)
def addBorders(self): self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect(rect, Qt.yellow)) margin = 5.25 * PointSize self.borders.append(self.scene.addRect( rect.adjusted(margin, margin, -margin, -margin), Qt.yellow))
def reconfigureRect(self, top_left, bottom_right, finish=False, padding=80): """ Updates the bounding rect to the size of the childrenBoundingRect. Refreshes the outline and grab_corner locations. Called by partZDimensionsChangedSlot and partPropertyChangedSlot. """ outline = self.outline hasTL = True if top_left else False hasBR = True if bottom_right else False if hasTL ^ hasBR: # called via resizeHandle mouseMove? ptTL = QPointF(*top_left) if top_left else outline.rect().topLeft() ptBR = QPointF(*bottom_right) if bottom_right else outline.rect( ).bottomRight() o_rect = QRectF(ptTL, ptBR) pad_xoffset = self._BOUNDING_RECT_PADDING * 2 new_size = int( (o_rect.width() - _VH_XOFFSET - pad_xoffset) / _BASE_WIDTH) substep = self._model_part.subStepSize() snap_size = new_size - new_size % substep snap_offset = -(new_size % substep) * _BASE_WIDTH self.resize_handle_group.updateText(HandleType.RIGHT, snap_size) if finish: self._model_part.setAllVirtualHelixSizes(snap_size) o_rect = o_rect.adjusted(0, 0, snap_offset, 0) # print("finish", vh_size, new_size, substep, snap_size) self.outline.setRect(o_rect) else: # 1. Temporarily remove children that shouldn't affect size outline.setParentItem(None) self.workplane.setParentItem(None) self.model_bounds_hint.setParentItem(None) self.resize_handle_group.setParentItemAll(None) self.prexover_manager.setParentItem(None) # 2. Get the tight bounding rect self.setRect(self.childrenBoundingRect()) # vh_items only # 3. Restore children like nothing happened outline.setParentItem(self) self.workplane.setParentItem(self) self.model_bounds_hint.setParentItem(self) self.resize_handle_group.setParentItemAll(self) self.prexover_manager.setParentItem(self) self._configureOutline(outline) self.resetPen(self.modelColor(), 0) # cosmetic self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA) self.workplane.reconfigureRect((), ()) self.resize_handle_group.alignHandles(outline.rect()) return outline.rect()
class MapObjectLabel(QGraphicsItem): def __init__(self, object, parent=None): super().__init__(parent) self.mBoundingRect = QRectF() self.mObject = object self.setFlags(QGraphicsItem.ItemIgnoresTransformations | QGraphicsItem.ItemIgnoresParentOpacity) def syncWithMapObject(self, renderer): nameVisible = self.mObject.isVisible() and self.mObject.name() != '' self.setVisible(nameVisible) if (not nameVisible): return metrics = QFontMetricsF(QGuiApplication.font()) boundingRect = metrics.boundingRect(self.mObject.name()) boundingRect.translate(-boundingRect.width() / 2, -labelDistance) boundingRect.adjust(-labelMargin * 2, -labelMargin, labelMargin * 2, labelMargin) pixelPos = renderer.pixelToScreenCoords_(self.mObject.position()) bounds = objectBounds(self.mObject, renderer) # Adjust the bounding box for object rotation transform = QTransform() transform.translate(pixelPos.x(), pixelPos.y()) transform.rotate(self.mObject.rotation()) transform.translate(-pixelPos.x(), -pixelPos.y()) bounds = transform.mapRect(bounds) # Center the object name on the object bounding box pos = QPointF((bounds.left() + bounds.right()) / 2, bounds.top()) self.setPos(pos + self.mObject.objectGroup().offset()) if (self.mBoundingRect != boundingRect): self.prepareGeometryChange() self.mBoundingRect = boundingRect def boundingRect(self): return self.mBoundingRect.adjusted(0, 0, 1, 1) def paint(self, painter, arg2, arg3): color = MapObjectItem.objectColor(self.mObject) painter.setRenderHint(QPainter.Antialiasing) painter.setBrush(Qt.black) painter.setPen(Qt.NoPen) painter.drawRoundedRect(self.mBoundingRect.translated(1, 1), 4, 4) painter.setBrush(color) painter.drawRoundedRect(self.mBoundingRect, 4, 4) textPos = QPointF(-(self.mBoundingRect.width() - labelMargin * 4) / 2, -labelDistance) painter.drawRoundedRect(self.mBoundingRect, 4, 4) painter.setPen(Qt.black) painter.drawText(textPos + QPointF(1, 1), self.mObject.name()) painter.setPen(Qt.white) painter.drawText(textPos, self.mObject.name())
def addBorders(self): '''添加出血框和打印边界框,对scene进行操作同时添加到self.borders这一列表中''' self.borders = [] rect = QRectF(0, 0, PageSize[0], PageSize[1]) self.borders.append(self.scene.addRect( rect, Qt.black)) # addRect px,py,x,y,QPen,QBrush or QRectF,QPen,QBrush # scene.addRect(): Return QGraphicsRectItem;Inherits: QGraphicsItem margin = 5.25 * PointSize self.borders.append( self.scene.addRect(rect.adjusted(margin, margin, -margin, -margin), Qt.red))
class RoundRectItem(QGraphicsObject): def __init__(self, bounds, color, parent=None): super(RoundRectItem, self).__init__(parent) self.fillRect = False self.bounds = QRectF(bounds) self.pix = QPixmap() self.gradient = QLinearGradient() self.gradient.setStart(self.bounds.topLeft()) self.gradient.setFinalStop(self.bounds.bottomRight()) self.gradient.setColorAt(0, color) self.gradient.setColorAt(1, color.darker(200)) self.setCacheMode(QGraphicsItem.ItemCoordinateCache) def setFill(self, fill): self.fillRect = fill self.update() def fill(self): return self.fillRect fill = pyqtProperty(bool, fill, setFill) def paint(self, painter, option, widget): painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 64)) painter.drawRoundedRect(self.bounds.translated(2, 2), 25.0, 25.0) if self.fillRect: painter.setBrush(QApplication.palette().brush(QPalette.Window)) else: painter.setBrush(self.gradient) painter.setPen(QPen(Qt.black, 1)) painter.drawRoundedRect(self.bounds, 25.0, 25.0) if not self.pix.isNull(): painter.scale(1.95, 1.95) painter.drawPixmap(-self.pix.width() / 2, -self.pix.height() / 2, self.pix) def boundingRect(self): return self.bounds.adjusted(0, 0, 2, 2) def pixmap(self): return QPixmap(self.pix) def setPixmap(self, pixmap): self.pix = QPixmap(pixmap) self.update()
class MapObjectLabel(QGraphicsItem): def __init__(self, object, parent = None): super().__init__(parent) self.mBoundingRect = QRectF() self.mObject = object self.setFlags(QGraphicsItem.ItemIgnoresTransformations | QGraphicsItem.ItemIgnoresParentOpacity) def syncWithMapObject(self, renderer): nameVisible = self.mObject.isVisible() and self.mObject.name()!='' self.setVisible(nameVisible) if (not nameVisible): return metrics = QFontMetricsF(QGuiApplication.font()) boundingRect = metrics.boundingRect(self.mObject.name()) boundingRect.translate(-boundingRect.width() / 2, -labelDistance) boundingRect.adjust(-labelMargin*2, -labelMargin, labelMargin*2, labelMargin) pixelPos = renderer.pixelToScreenCoords_(self.mObject.position()) bounds = objectBounds(self.mObject, renderer) # Adjust the bounding box for object rotation transform = QTransform() transform.translate(pixelPos.x(), pixelPos.y()) transform.rotate(self.mObject.rotation()) transform.translate(-pixelPos.x(), -pixelPos.y()) bounds = transform.mapRect(bounds) # Center the object name on the object bounding box pos = QPointF((bounds.left() + bounds.right()) / 2, bounds.top()) self.setPos(pos + self.mObject.objectGroup().offset()) if (self.mBoundingRect != boundingRect): self.prepareGeometryChange() self.mBoundingRect = boundingRect def boundingRect(self): return self.mBoundingRect.adjusted(0, 0, 1, 1) def paint(self, painter, arg2, arg3): color = MapObjectItem.objectColor(self.mObject) painter.setRenderHint(QPainter.Antialiasing) painter.setBrush(Qt.black) painter.setPen(Qt.NoPen) painter.drawRoundedRect(self.mBoundingRect.translated(1, 1), 4, 4) painter.setBrush(color) painter.drawRoundedRect(self.mBoundingRect, 4, 4) textPos = QPointF(-(self.mBoundingRect.width() - labelMargin*4) / 2, -labelDistance) painter.drawRoundedRect(self.mBoundingRect, 4, 4) painter.setPen(Qt.black) painter.drawText(textPos + QPointF(1,1), self.mObject.name()) painter.setPen(Qt.white) painter.drawText(textPos, self.mObject.name())
def syncWithTileLayer(self): self.prepareGeometryChange() renderer = self.mMapDocument.renderer() boundingRect = QRectF(renderer.boundingRect(self.mLayer.bounds())) margins = self.mLayer.drawMargins() map = self.mLayer.map() if map: margins.setTop(margins.top() - map.tileHeight()) margins.setRight(margins.right() - map.tileWidth()) self.mBoundingRect = boundingRect.adjusted(-margins.left(), -margins.top(), margins.right(), margins.bottom())
def drawBase(self, p: QPainter, baseRect: QRectF): if self.m_barStyle == self.BarStyle.DONUT: p.setPen(QPen(self.palette().shadow().color(), self.m_outlinePenWidth)) p.setBrush(self.palette().base()) p.drawEllipse(baseRect) elif self.m_barStyle == self.BarStyle.LINE: p.setPen(QPen(self.palette().base().color(), self.m_outlinePenWidth)) p.setBrush(Qt.NoBrush) p.drawEllipse(baseRect.adjusted(self.m_outlinePenWidth / 2, self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2, -self.m_outlinePenWidth / 2)) elif self.m_barStyle in (self.BarStyle.PIE, self.BarStyle.EXPAND): p.setPen(QPen(self.palette().base().color(), self.m_outlinePenWidth)) p.setBrush(self.palette().base()) p.drawEllipse(baseRect)
class Spinner(QSvgWidget): icon_file = QtDynamicProperty('icon_file', type=unicode) icon_size = QtDynamicProperty('icon_size', type=QSize) icon_crop = QtDynamicProperty('icon_crop', type=int) def __init__(self, parent=None, icon='icons/spinner.svg'): super(Spinner, self).__init__(parent) self._original_viewbox = QRectF() self.icon_crop = 0 self.icon_size = None self.icon_file = Resources.get(icon) def load(self, svg): super(Spinner, self).load(svg) self._original_viewbox = self.renderer().viewBoxF() self._update_viewbox(self.size()) def event(self, event): if event.type() == QEvent.DynamicPropertyChange: if event.propertyName() == 'icon_crop': self._update_viewbox(self.size()) elif event.propertyName() == 'icon_file': self.load(self.icon_file) elif event.propertyName() == 'icon_size': self.updateGeometry() return super(Spinner, self).event(event) def resizeEvent(self, event): super(Spinner, self).resizeEvent(event) self._update_viewbox(event.size()) def sizeHint(self): return self.icon_size or super(Spinner, self).sizeHint() def _update_viewbox(self, size): if self._original_viewbox.isEmpty() or size.isEmpty(): return if self.icon_crop >= 0: adjustment = self.icon_crop else: adjustment = self._original_viewbox.width() * self.icon_crop / (self._original_viewbox.width() + 2*self.icon_crop) # (w - w * w/(w+2b))/2 = wb/(w+2b) viewbox = self._original_viewbox.adjusted(adjustment, adjustment, -adjustment, -adjustment) width = size.width() height = size.height() if height >= width: new_viewbox = QRectF(viewbox.x(), viewbox.y() + viewbox.height()/2 * (1 - height/width), viewbox.width(), viewbox.height() * height/width) else: new_viewbox = QRectF(viewbox.x() + viewbox.width()/2 * (1 - width/height), viewbox.y(), viewbox.width() * width/height, viewbox.height()) self.renderer().setViewBox(new_viewbox)
def paintEvent(self, event): pixmap = self._shadowPixmap widget_rect = QRectF(QPointF(0.0, 0.0), QSizeF(self.size())) frame_rect = QRectF(self.contentsRect()) left, top, right, bottom = self.getContentsMargins() pixmap_rect = QRectF(QPointF(0, 0), QSizeF(pixmap.size())) # Shadow casting rectangle. pixmap_shadow_rect = pixmap_rect.adjusted(left, top, -right, -bottom) source_rects = self._shadowPixmapFragments(pixmap_rect, pixmap_shadow_rect) target_rects = self._shadowPixmapFragments(widget_rect, frame_rect) painter = QPainter(self) for source, target in zip(source_rects, target_rects): painter.drawPixmap(target, pixmap, source) painter.end()
class HandleItem(QGraphicsItem): def __init__(self, position, size=DEFAULT_HANDLE_SIZE, parent=None, color=Qt.green): super(HandleItem, self).__init__(parent) self.setPos(position) self.size = size self.color = color self.idd = DEFAULT_IDMAN.next() # self.setZValue(10) self.setFlags(self.flags() | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges | QGraphicsItem.ItemIsFocusable) self.rect = QRectF(0, 0, size, size) def boundingRect(self): size = self.size return self.rect.adjusted(-size,-size,0,0) def paint(self, painter, option, widget=None): qp = painter qp.setPen(QtGui.QColor(168, 34, 3)) qp.setBrush(QBrush(self.color, Qt.SolidPattern)) # size = self.size qp.drawEllipse(self.boundingRect()) def points(self): return [[self.x(), self.y()]] def mousePressEvent(self, e): pass # if e.button() == 1: # self.parentItem().main.bringToFront(self.parentItem().idd) # if e.button() == 2: # self.parentItem().main.remove(self) def itemChange(self, change, value): if change == QGraphicsItem.ItemPositionChange: self.parentItem().itemChange(ControllableItem.HandlePositionHasChanged, value) return super(HandleItem, self).itemChange(change, value) def setSize(self, size): self.prepareGeometryChange() self.size = size self.rect = QRectF(0,0,size,size) def setColor(self, color): self.color = color self.update()
def reconfigureRect(self, top_left: Vec2T, bottom_right: Vec2T, finish: bool = False, padding: int = 80): """Updates the bounding rect to the size of the childrenBoundingRect. Refreshes the outline and grab_corner locations. Called by ``partZDimensionsChangedSlot`` and ``partPropertyChangedSlot``. """ outline = self.outline hasTL = True if top_left else False hasBR = True if bottom_right else False if hasTL ^ hasBR: # called via resizeHandle mouseMove? ptTL = QPointF(*top_left) if top_left else outline.rect().topLeft() ptBR = QPointF(*bottom_right) if bottom_right else outline.rect().bottomRight() o_rect = QRectF(ptTL, ptBR) pad_xoffset = self._BOUNDING_RECT_PADDING*2 new_size = int((o_rect.width()-_VH_XOFFSET-pad_xoffset)/_BASE_WIDTH) substep = self._model_part.subStepSize() snap_size = new_size - new_size % substep snap_offset = -(new_size % substep)*_BASE_WIDTH self.resize_handle_group.updateText(HandleEnum.RIGHT, snap_size) if finish: self._model_part.setAllVirtualHelixSizes(snap_size) o_rect = o_rect.adjusted(0, 0, snap_offset, 0) # print("finish", vh_size, new_size, substep, snap_size) self.outline.setRect(o_rect) else: # 1. Temporarily remove children that shouldn't affect size outline.setParentItem(None) self.model_bounds_hint.setParentItem(None) self.resize_handle_group.setParentItemAll(None) self.prexover_manager.setParentItem(None) # 2. Get the tight bounding rect self.setRect(self.childrenBoundingRect()) # vh_items only # 3. Restore children like nothing happened outline.setParentItem(self) self.model_bounds_hint.setParentItem(self) self.resize_handle_group.setParentItemAll(self) self.prexover_manager.setParentItem(self) self._configureOutline(outline) self.resetPen(self.modelColor(), 0) # cosmetic self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA) self.resize_handle_group.alignHandles(outline.rect()) return outline.rect()
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): if self.colors: try: item = index.model().data(index) index = self.items.index(item) if item in self.items else int(item) color = self.colors[index] x, y, h = option.rect.x(), option.rect.y(), option.rect.height() rect = QRectF(x + 8, y + h / 2 - 8, 16, 16) painter.fillRect(rect, QColor("black")) rect = rect.adjusted(1, 1, -1, -1) painter.fillRect(rect, QColor(color.red(), color.green(), color.blue(), 255)) except: super().paint(painter, option, index) else: super().paint(painter, option, index)
def paint(self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex): if self.colors: try: item = index.model().data(index) index = self.items.index(item) if item in self.items else int( item) color = self.colors[index] x, y, h = option.rect.x(), option.rect.y(), option.rect.height( ) rect = QRectF(x + 8, y + h / 2 - 8, 16, 16) painter.fillRect(rect, QColor("black")) rect = rect.adjusted(1, 1, -1, -1) painter.fillRect( rect, QColor(color.red(), color.green(), color.blue(), 255)) except: super().paint(painter, option, index) else: super().paint(painter, option, index)
def __init__(self, parent, row, col, num, rect: QRectF, disabled=False): super().__init__(parent=parent) self.rect = rect.adjusted(self.adj, self.adj, -self.adj, -self.adj) self.disabled = disabled self.row = row self.col = col # Create a link to the sudoku game instance. self.game = self.parent.parent.game if num == 0: self.num = '' else: self.num = num self.animations() if not self.disabled: self.setFlags(QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsSelectable) self.setAcceptHoverEvents(True) self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setTransformOriginPoint(self.rect.center())
def paintEvent(self, event): # TODO: Use QPainter.drawPixmapFragments on Qt 4.7 opt = QStyleOption() opt.initFrom(self) pixmap = self.__shadowPixmap shadow_rect = QRectF(opt.rect) widget_rect = QRectF(self.widget().geometry()) widget_rect.moveTo(self.radius_, self.radius_) left = top = right = bottom = self.radius_ pixmap_rect = QRectF(QPointF(0, 0), QSizeF(pixmap.size())) # Shadow casting rectangle in the source pixmap. pixmap_shadow_rect = pixmap_rect.adjusted(left, top, -right, -bottom) source_rects = self.__shadowPixmapFragments(pixmap_rect, pixmap_shadow_rect) target_rects = self.__shadowPixmapFragments(shadow_rect, widget_rect) painter = QPainter(self) for source, target in zip(source_rects, target_rects): painter.drawPixmap(target, pixmap, source) painter.end()
from .virtualhelixitem import VirtualHelixItem from .activesliceitem import ActiveSliceItem from . import slicestyles as styles import cadnano.util as util from cadnano import getReopen from PyQt5.QtCore import QPointF, Qt, QRectF, QEvent, pyqtSignal, pyqtSlot, QObject from PyQt5.QtGui import QBrush, QPainterPath, QPen from PyQt5.QtWidgets import QGraphicsItem, QGraphicsEllipseItem _RADIUS = styles.SLICE_HELIX_RADIUS _DEFAULT_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS) HIGHLIGHT_WIDTH = styles.SLICE_HELIX_MOD_HILIGHT_WIDTH DELTA = (HIGHLIGHT_WIDTH - styles.SLICE_HELIX_STROKE_WIDTH)/2. _HOVER_RECT = _DEFAULT_RECT.adjusted(-DELTA, -DELTA, DELTA, DELTA) _MOD_PEN = QPen(styles.BLUE_STROKE, HIGHLIGHT_WIDTH) class PartItem(QGraphicsItem): _RADIUS = styles.SLICE_HELIX_RADIUS def __init__(self, model_part, parent=None): """ Parent should be either a SliceRootItem, or an AssemblyItem. Invariant: keys in _empty_helix_hash = range(_nrows) x range(_ncols) where x is the cartesian product. Order matters for deselector, probe, and setlattice """ super(PartItem, self).__init__(parent)
class Callout(QGraphicsItem): def __init__(self, chart): super().__init__(chart) self.m_chart = chart self.m_text = "" self.m_textRect = QRectF() self.m_rect = QRectF() self.m_anchor = QPointF() self.m_font = QFont() def boundingRect(self): anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor)) rect = QRectF() rect.setLeft(min(self.m_rect.left(), anchor.x())) rect.setRight(max(self.m_rect.right(), anchor.x())) rect.setTop(min(self.m_rect.top(), anchor.y())) rect.setBottom(max(self.m_rect.bottom(), anchor.y())) return rect def paint(self, painter, option, widget=None): path = QPainterPath() path.addRoundedRect(self.m_rect, 5, 5) anchor = self.mapFromParent(self.m_chart.mapToPosition(self.m_anchor)) if not self.m_rect.contains(anchor): point1 = QPointF() point2 = QPointF() # establish the position of the anchor point in relation to m_rect above = anchor.y() <= self.m_rect.top() aboveCenter = (anchor.y() > self.m_rect.top() and anchor.y() <= self.m_rect.center().y()) belowCenter = (anchor.y() > self.m_rect.center().y() and anchor.y() <= self.m_rect.bottom()) below = anchor.y() > self.m_rect.bottom() onLeft = anchor.x() <= self.m_rect.left() leftOfCenter = (anchor.x() > self.m_rect.left() and anchor.x() <= self.m_rect.center().x()) rightOfCenter = (anchor.x() > self.m_rect.center().x() and anchor.x() <= self.m_rect.right()) onRight = anchor.x() > self.m_rect.right() # get the nearest m_rect corner. x = (onRight + rightOfCenter) * self.m_rect.width() y = (below + belowCenter) * self.m_rect.height() cornerCase = ((above and onLeft) or (above and onRight) or (below and onLeft) or (below and onRight)) vertical = abs(anchor.x() - x) > abs(anchor.y() - y) x1 = (x + leftOfCenter * 10 - rightOfCenter * 20 + cornerCase * int(not vertical) * (onLeft * 10 - onRight * 20)) y1 = (y + aboveCenter * 10 - belowCenter * 20 + cornerCase * int(vertical) * (above * 10 - below * 20)) point1.setX(x1) point1.setY(y1) x2 = (x + leftOfCenter * 20 - rightOfCenter * 10 + cornerCase * int(not vertical) * (onLeft * 20 - onRight * 10)) y2 = (y + aboveCenter * 20 - belowCenter * 10 + cornerCase * int(vertical) * (above * 20 - below * 10)) point2.setX(x2) point2.setY(y2) path.moveTo(point1) path.lineTo(anchor) path.lineTo(point2) path = path.simplified() painter.setBrush(QColor(255, 255, 255)) painter.drawPath(path) painter.drawText(self.m_textRect, self.m_text) def mousePressEvent(self, event): event.setAccepted(True) def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: self.setPos( self.mapToParent(event.pos() - event.buttonDownPos(Qt.LeftButton))) event.setAccepted(True) else: event.setAccepted(False) def setText(self, text): self.m_text = text metrics = QFontMetrics(self.m_font) self.m_textRect = QRectF( metrics.boundingRect(QRect(0, 0, 150, 150), Qt.AlignLeft, self.m_text)) self.m_textRect.translate(5, 5) self.prepareGeometryChange() self.m_rect = self.m_textRect.adjusted(-5, -5, 5, 5) def setAnchor(self, point): self.m_anchor = point def updateGeometry(self): self.prepareGeometryChange() self.setPos( self.m_chart.mapToPosition(self.m_anchor) + QPoint(10, -50))
# extra2 = QPainterPath() # extra2.addEllipse(-0.35*IW, 0.5*IW, 0.7*IW, 0.3*IW) # FWDPXI_PP += extra1 # FWDPXI_PP -= extra2 # REVPXI_PP.moveTo(-0.5*IW, -0.7*IW) # REVPXI_PP.lineTo(0., 0.2*IW) # REVPXI_PP.lineTo(0.5*IW, -0.7*IW) # extra1 = QPainterPath() # extra1.addEllipse(-0.5*IW, -0.9*IW, IW, 0.4*IW) # REVPXI_PP += extra1 _RADIUS = styles.GRID_HELIX_RADIUS _WEDGE_RECT_GAIN = 0.25 WEDGE_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS) WEDGE_RECT = WEDGE_RECT.adjusted(0, 0, _WEDGE_RECT_GAIN, _WEDGE_RECT_GAIN) _WEDGE_RECT_CENTERPT = WEDGE_RECT.center() class PropertyWrapperObject(QObject): """Summary Attributes: animations (dict): Description bondp2 (TYPE): Description item (TYPE): Description pen_alpha (TYPE): Description rotation (TYPE): Description """ def __init__(self, item):
from .virtualhelixitem import VirtualHelixItem from .activesliceitem import ActiveSliceItem from cadnano.gui.views import styles import cadnano.util as util from cadnano import getReopen from PyQt5.QtCore import QPointF, Qt, QRectF, QEvent, pyqtSignal, pyqtSlot, QObject from PyQt5.QtGui import QBrush, QPainterPath, QPen from PyQt5.QtWidgets import QGraphicsItem, QGraphicsEllipseItem _RADIUS = styles.SLICE_HELIX_RADIUS _DEFAULT_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS) HIGHLIGHT_WIDTH = styles.SLICE_HELIX_MOD_HILIGHT_WIDTH DELTA = (HIGHLIGHT_WIDTH - styles.SLICE_HELIX_STROKE_WIDTH) / 2. _HOVER_RECT = _DEFAULT_RECT.adjusted(-DELTA, -DELTA, DELTA, DELTA) _MOD_PEN = QPen(styles.BLUE_STROKE, HIGHLIGHT_WIDTH) class PartItem(QGraphicsItem): _RADIUS = styles.SLICE_HELIX_RADIUS def __init__(self, model_part, parent=None): """ Parent should be either a SliceRootItem, or an AssemblyItem. Invariant: keys in _empty_helix_hash = range(_nrows) x range(_ncols) where x is the cartesian product. Order matters for deselector, probe, and setlattice """
class RoundRectItem(QGraphicsObject): """Base class for most graphic objects in our scene""" def __init__(self, bounds, color=None, parent=None): """ Args: bounds - QRectF, geometry of object color - QColor or None parent - widget to contain this graphic item or None """ super(RoundRectItem, self).__init__(parent) self._fillRect = False self._bounds = QRectF(bounds) self._pix = QPixmap() self._color = color self.setCacheMode(QGraphicsItem.ItemCoordinateCache) def setFill(self, fill: bool): """ Changes the property of how the cell is filled. Args: fill: bool """ self._fillRect = fill self.update() @property def _gradient(self): gradient = QLinearGradient() gradient.setStart( (self._bounds.topLeft() + self._bounds.topRight()) / 2) gradient.setFinalStop( (self._bounds.bottomLeft() + self._bounds.bottomRight()) / 2) gradient.setColorAt(0, self._color) gradient.setColorAt(1, self._color.darker(200)) return gradient def paint(self, painter, option, widget): """Standard Qt paint event.""" if self._color: painter.setPen(Qt.NoPen) painter.setBrush(QColor(0, 0, 0, 64)) painter.drawRoundedRect(self._bounds.translated(2, 2), 25.0, 25.0) if self._fillRect: painter.setBrush(QApplication.palette().brush(QPalette.Window)) else: painter.setBrush(self._gradient) painter.setPen(QPen(Qt.black, 1)) painter.drawRoundedRect(self._bounds, 25.0, 25.0) if not self._pix.isNull(): if self._rounded_pixmap: painter.setRenderHint(QPainter.Antialiasing, True) brush = QBrush( self._pix.scaled(self._bounds.width(), self._bounds.height())) painter.setBrush(brush) painter.drawRoundedRect(self._bounds, 25.0, 25.0) else: painter.scale(self._bounds.width() / self._pix.width(), self._bounds.height() / self._pix.height()) painter.drawPixmap(-self._pix.width() / 2, -self._pix.height() / 2, self._pix) def boundingRect(self): """returns bounding rectangle""" return self._bounds.adjusted(0, 0, 2, 2) def setPixmap(self, pixmap_path: str, rounded_pixmap=False): """ Sets new pixmap for this graphic object. Args: pixmap_path: path to image for pixmap rounded_pixmap: make the picture rounded (used, e.g., for lava in the cells) """ self._rounded_pixmap = rounded_pixmap self._pix = QPixmap(pixmap_path) self.update()
class BboxEditor(QObject): changed = pyqtSignal() def __init__(self, parent=None): super().__init__(parent) self.bbox01 = QRectF() self.bboxDrawing = QRect() self.color = QColor() self.isActive = False self.posPress = QPoint() self.bbox01Press = QRect() self.isDragging = False self.prevWheelEventTimestamp = datetime.datetime.now() self.scalingMultiplier = 1 self.targetRatio = 1 self.stayInside = True def setTargetRatio(self, ratio): self.targetRatio = ratio self.setBbox01(self.bbox01) def setStayInside(self, stay): self.stayInside = stay self.setBbox01(self.bbox01) def bbox01KeepInsideDrawingArea(self): # r = w0*w / h0*h # h0*h = w0*w / r # h0 = w0*w / r / h w = self.bbox01.width() * self.bboxDrawing.width() h = self.bbox01.height() * self.bboxDrawing.height() print('bbox01KeepInsideDrawingArea() bboxDrawing:', self.bboxDrawing, 'w:', w, 'h:', h) if h == 0: return if w / h != self.targetRatio: print('bbox01KeepInsideDrawingArea() bbox01 a:', self.bbox01, 'targetRatio:', self.targetRatio) self.bbox01.setHeight(w / self.targetRatio / self.bboxDrawing.height()) print('bbox01KeepInsideDrawingArea() bbox01 b:', self.bbox01) if self.stayInside: if self.bbox01.width() > 1: self.bbox01.setWidth(1) if self.bbox01.height() > 1: self.bbox01.setHeight(1) if self.bbox01.x() < 0: self.bbox01.translate(-self.bbox01.x(), 0) if self.bbox01.y() < 0: self.bbox01.translate(0, -self.bbox01.y()) if self.bbox01.x() + self.bbox01.width() > 1: self.bbox01.translate( 1 - (self.bbox01.x() + self.bbox01.width()), 0) if self.bbox01.y() + self.bbox01.height() > 1: self.bbox01.translate( 0, 1 - (self.bbox01.y() + self.bbox01.height())) print('bbox01KeepInsideDrawingArea() bbox01 c:', self.bbox01, 'toPixels:', self.bbox01ToPixels()) def bbox01ToPixels(self): r = QRect( self.bboxDrawing.x() + self.bbox01.x() * self.bboxDrawing.width(), self.bboxDrawing.y() + self.bbox01.y() * self.bboxDrawing.height(), self.bbox01.width() * self.bboxDrawing.width(), self.bbox01.width() * self.bboxDrawing.width() / self.targetRatio) #self.bbox01.height()*self.bboxDrawing.height()) print('bbox01ToPixels() r:', r.width(), r.height(), 'bboxDrawing:', self.bboxDrawing, 'bbox01:', self.bbox01) return r def paint(self, qpainter): r = self.bbox01ToPixels() print('paint() bboxDrawing:', self.bboxDrawing, ' bbox01:', self.bbox01, 'r:', r) c = self.color w = 3 if self.isActive else 1 #c.setAlpha(255 if self.isActive else 127) # Outer white rect pen = QPen(QColor(255, 255, 255)) pen.setWidth(w + 2) qpainter.setPen(pen) qpainter.drawRect(r) # Main colored rect pen = QPen(c) pen.setWidth(w) qpainter.setPen(pen) qpainter.drawRect(r) def setColor(self, color): self.color = color self.changed.emit() def setDrawingArea(self, qrect): self.bboxDrawing = qrect self.changed.emit() def setBbox01(self, qrect): self.bbox01 = qrect self.bbox01KeepInsideDrawingArea() self.changed.emit() def getBbox01(self): return self.bbox01 def setActive(self, active): self.isActive = active self.changed.emit() def mouseMoveEvent(self, e): if not self.isActive: return if self.isDragging: diff = e.pos() - self.posPress diff01 = QPointF(diff.x() / self.bboxDrawing.width(), diff.y() / self.bboxDrawing.height()) print('mouseMoveEvent() bbox01:', self.bbox01, 'diff:', diff, 'diff01:', diff01) self.setBbox01(self.bbox01Press.translated(diff01)) def mousePressEvent(self, e): if not self.isActive: return bb = self.bbox01ToPixels() if (e.pos().x() >= bb.topLeft().x()) and \ (e.pos().y() >= bb.topLeft().y()) and \ e.pos().x() <= bb.bottomRight().x() and \ e.pos().y() <= bb.bottomRight().y() \ : self.isDragging = True self.posPress = e.pos() self.bbox01Press = self.bbox01 def mouseReleaseEvent(self, e): if not self.isActive: return self.isDragging = False def wheelEvent(self, e): if not self.isActive: return t_diff = (datetime.datetime.now() - self.prevWheelEventTimestamp).total_seconds() if t_diff < 0.1: self.scalingMultiplier *= 1.5 else: self.scalingMultiplier = 1 print('wheelEvent() t:', self.prevWheelEventTimestamp, '->', datetime.datetime.now(), 't_diff:', t_diff, 'angleDelta:', e.angleDelta(), 'scalingMultiplier:', self.scalingMultiplier) #sign = -1 if e.angleDelta().y() < 0 else 1 #scale = 1 + 0.1*sign scale = 0.01 scale *= self.scalingMultiplier scale += 1 if e.angleDelta().y() > 0: scale = 1 / scale diff_x = (self.bbox01.width() * (1 - scale)) / 2 diff_y = (self.bbox01.height() * (1 - scale)) / 2 print('wheelEvent() scale:', scale, 'diff:', diff_x, diff_y) self.setBbox01(self.bbox01.adjusted(diff_x, diff_y, -diff_x, -diff_y)) self.prevWheelEventTimestamp = datetime.datetime.now() def getBbox01(self): return self.bbox01
class PathNucleicAcidPartItem(QAbstractPartItem): """Summary Attributes: active_virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description findChild (TYPE): Description grab_corner (TYPE): Description prexover_manager (TYPE): Description """ findChild = util.findChild # for debug _BOUNDING_RECT_PADDING = 0 def __init__(self, model_part_instance, viewroot, parent): """parent should always be pathrootitem Args: model_part_instance (TYPE): Description viewroot (TYPE): Description parent (TYPE): Description """ super(PathNucleicAcidPartItem, self).__init__(model_part_instance, viewroot, parent) self._getActiveTool = viewroot.manager.activeToolGetter self.active_virtual_helix_item = None m_p = self._model_part self._controller = NucleicAcidPartItemController(self, m_p) self.prexover_manager = PreXoverManager(self) self._virtual_helix_item_list = [] self._vh_rect = QRectF() self.setAcceptHoverEvents(True) self._initModifierRect() self._proxy_parent = ProxyParentItem(self) self._proxy_parent.setFlag(QGraphicsItem.ItemHasNoContents) self._scale_2_model = m_p.baseWidth()/_BASE_WIDTH self._scale_2_Qt = _BASE_WIDTH / m_p.baseWidth() GC_SIZE = 10 self.grab_corner = GrabCornerItem(GC_SIZE, m_p.getColor(), False, self) # end def def proxy(self): """Summary Returns: TYPE: Description """ return self._proxy_parent # end def def modelColor(self): """Summary Returns: TYPE: Description """ return self._model_part.getProperty('color') # end def def convertToModelZ(self, z): """scale Z-axis coordinate to the model Args: z (TYPE): Description """ return z * self._scale_2_model # end def def convertToQtZ(self, z): """Summary Args: z (TYPE): Description Returns: TYPE: Description """ return z * self._scale_2_Qt # end def def _initModifierRect(self): """docstring for _initModifierRect """ self._can_show_mod_rect = False self._mod_rect = m_r = QGraphicsRectItem(_DEFAULT_RECT, self) m_r.setPen(_MOD_PEN) m_r.hide() # end def def vhItemForIdNum(self, id_num): """Returns the pathview VirtualHelixItem corresponding to id_num Args: id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. """ return self._virtual_helix_item_hash.get(id_num) ### SIGNALS ### ### SLOTS ### def partActiveVirtualHelixChangedSlot(self, part, id_num): """Summary Args: part (TYPE): Description id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. Returns: TYPE: Description """ vhi = self._virtual_helix_item_hash.get(id_num, None) self.setActiveVirtualHelixItem(vhi) self.setPreXoverItemsVisible(vhi) # end def def partActiveBaseInfoSlot(self, part, info): """Summary Args: part (TYPE): Description info (TYPE): Description Returns: TYPE: Description """ pxoig = self.prexover_manager pxoig.deactivateNeighbors() if info and info is not None: id_num, is_fwd, idx, to_vh_id_num = info pxoig.activateNeighbors(id_num, is_fwd, idx) # end def def partZDimensionsChangedSlot(self, model_part, min_id_num, max_id_num, ztf=False): """Summary Args: model_part (Part): The model part min_id_num (TYPE): Description max_id_num (TYPE): Description ztf (bool, optional): Description Returns: TYPE: Description """ if len(self._virtual_helix_item_list) > 0: vhi_hash = self._virtual_helix_item_hash vhi_max = vhi_hash[max_id_num] vhi_rect_max = vhi_max.boundingRect() self._vh_rect.setRight(vhi_rect_max.right() + vhi_max.x()) vhi_min = vhi_hash[min_id_num] vhi_h_rect = vhi_min.handle().boundingRect() self._vh_rect.setLeft((vhi_h_rect.left() - styles.VH_XOFFSET + vhi_min.x())) if ztf: self.scene().views()[0].zoomToFit() self._updateBoundingRect() # end def def partSelectedChangedSlot(self, model_part, is_selected): """Summary Args: model_part (Part): The model part is_selected (TYPE): Description Returns: TYPE: Description """ # print("partSelectedChangedSlot", is_selected) if is_selected: self.resetPen(styles.SELECTED_COLOR, styles.SELECTED_PEN_WIDTH) self.resetBrush(styles.SELECTED_BRUSH_COLOR, styles.SELECTED_ALPHA) else: self.resetPen(self.modelColor()) self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA) def partPropertyChangedSlot(self, model_part, property_key, new_value): """Summary Args: model_part (Part): The model part property_key (TYPE): Description new_value (TYPE): Description Returns: TYPE: Description """ if self._model_part == model_part: self._model_props[property_key] = new_value if property_key == 'color': self._updateBoundingRect() for vhi in self._virtual_helix_item_list: vhi.handle().refreshColor() self.grab_corner.setBrush(getBrushObj(new_value)) elif property_key == 'is_visible': if new_value: self.show() else: self.hide() elif property_key == 'virtual_helix_order': vhi_dict = self._virtual_helix_item_hash new_list = [vhi_dict[id_num] for id_num in new_value] ztf = False self._setVirtualHelixItemList(new_list, zoom_to_fit=ztf) # end def def partVirtualHelicesTranslatedSlot(self, sender, vh_set, left_overs, do_deselect): """Summary Args: sender (obj): Model object that emitted the signal. vh_set (TYPE): Description left_overs (TYPE): Description do_deselect (TYPE): Description Returns: TYPE: Description """ # self.prexover_manager.clearPreXoverItems() # if self.active_virtual_helix_item is not None: # self.active_virtual_helix_item.deactivate() # self.active_virtual_helix_item = None # if self.active_virtual_helix_item is not None: # self.setPreXoverItemsVisible(self.active_virtual_helix_item) pass # end def def partRemovedSlot(self, sender): """docstring for partRemovedSlot Args: sender (obj): Model object that emitted the signal. """ self.parentItem().removePartItem(self) scene = self.scene() scene.removeItem(self) self._model_part = None self._virtual_helix_item_hash = None self._virtual_helix_item_list = None self._controller.disconnectSignals() self._controller = None self.grab_corner = None # end def def partVirtualHelixAddedSlot(self, model_part, id_num, virtual_helix, neighbors): """ When a virtual helix is added to the model, this slot handles the instantiation of a virtualhelix item. Args: model_part (Part): The model part id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. """ # print("NucleicAcidPartItem.partVirtualHelixAddedSlot") vhi = PathVirtualHelixItem(virtual_helix, self, self._viewroot) self._virtual_helix_item_hash[id_num] = vhi vhi_list = self._virtual_helix_item_list # reposition when first VH is added if len(vhi_list) == 0: view = self.window().path_graphics_view p = view.scene_root_item.childrenBoundingRect().bottomLeft() _p = _BOUNDING_RECT_PADDING self.setPos(p.x() + _p*6 + styles.VIRTUALHELIXHANDLEITEM_RADIUS, p.y() + _p*3) # self.setPos(p.x() + _VH_XOFFSET, p.y() + _p*3) vhi_list.append(vhi) ztf = not getBatch() self._setVirtualHelixItemList(vhi_list, zoom_to_fit=ztf) # end def def partVirtualHelixResizedSlot(self, sender, id_num, virtual_helix): """Notifies the virtualhelix at coord to resize. Args: sender (obj): Model object that emitted the signal. id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. """ vhi = self._virtual_helix_item_hash[id_num] # print("resize:", id_num, virtual_helix.getSize()) vhi.resize() # end def def partVirtualHelixRemovingSlot(self, sender, id_num, virtual_helix, neighbors): """Summary Args: sender (obj): Model object that emitted the signal. id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. Returns: TYPE: Description """ self.removeVirtualHelixItem(id_num) # end def def partVirtualHelixRemovedSlot(self, sender, id_num): """ Step 2 of removing a VHI """ ztf = not getBatch() self._setVirtualHelixItemList(self._virtual_helix_item_list, zoom_to_fit=ztf) # end def def partVirtualHelixPropertyChangedSlot(self, sender, id_num, virtual_helix, keys, values): """Summary Args: sender (obj): Model object that emitted the signal. id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. keys (TYPE): Description values (TYPE): Description Returns: TYPE: Description """ if self._model_part == sender: vh_i = self._virtual_helix_item_hash[id_num] vh_i.virtualHelixPropertyChangedSlot(keys, values) # end def def partVirtualHelicesSelectedSlot(self, sender, vh_set, is_adding): """is_adding (bool): adding (True) virtual helices to a selection or removing (False) Args: sender (obj): Model object that emitted the signal. vh_set (TYPE): Description is_adding (TYPE): Description """ vhhi_group = self._viewroot.vhiHandleSelectionGroup() vh_hash = self._virtual_helix_item_hash doc = self._viewroot.document() if is_adding: # print("got the adding slot in path") for id_num in vh_set: vhi = vh_hash[id_num] vhhi = vhi.handle() vhhi.modelSelect(doc) # end for vhhi_group.processPendingToAddList() else: # print("got the removing slot in path") for id_num in vh_set: vhi = vh_hash[id_num] vhhi = vhi.handle() vhhi.modelDeselect(doc) # end for vhhi_group.processPendingToAddList() # end def ### ACCESSORS ### def removeVirtualHelixItem(self, id_num): """Summary Args: id_num (int): VirtualHelix ID number. See `NucleicAcidPart` for description and related methods. Returns: TYPE: Description """ self.setActiveVirtualHelixItem(None) vhi = self._virtual_helix_item_hash[id_num] vhi.virtualHelixRemovedSlot() self._virtual_helix_item_list.remove(vhi) del self._virtual_helix_item_hash[id_num] # end def def window(self): """Summary Returns: TYPE: Description """ return self.parentItem().window() # end def ### PRIVATE METHODS ### def _setVirtualHelixItemList(self, new_list, zoom_to_fit=True): """ Give me a list of VirtualHelixItems and I'll parent them to myself if necessary, position them in a column, adopt their handles, and position them as well. Args: new_list (TYPE): Description zoom_to_fit (bool, optional): Description """ y = 0 # How far down from the top the next PH should be vhi_rect = None vhi_h_rect = None vhi_h_selection_group = self._viewroot.vhiHandleSelectionGroup() for vhi in new_list: _, _, _z = vhi.cnModel().getAxisPoint(0) _z *= self._scale_2_Qt vhi.setPos(_z, y) if vhi_rect is None: vhi_rect = vhi.boundingRect() step = vhi_rect.height() + styles.PATH_HELIX_PADDING # end if # get the VirtualHelixHandleItem vhi_h = vhi.handle() do_reselect = False if vhi_h.parentItem() == vhi_h_selection_group: do_reselect = True vhi_h.tempReparent() # so positioning works if vhi_h_rect is None: vhi_h_rect = vhi_h.boundingRect() vhi_h_x = _z - _VH_XOFFSET vhi_h_y = y + (vhi_rect.height() - vhi_h_rect.height()) / 2 vhi_h.setPos(vhi_h_x, vhi_h_y) y += step self.updateXoverItems(vhi) if do_reselect: vhi_h_selection_group.addToGroup(vhi_h) # end for # this need only adjust top and bottom edges of the bounding rectangle self._vh_rect.setTop(-10) self._vh_rect.setBottom(y) self._virtual_helix_item_list = new_list # now update Z dimension (X in Qt space in the Path view) part = self.part() self.partZDimensionsChangedSlot(part, *part.zBoundsIds(), ztf=zoom_to_fit) # end def def resetPen(self, color, width=0): """Summary Args: color (TYPE): Description width (int, optional): Description Returns: TYPE: Description """ pen = getPenObj(color, width) self.setPen(pen) # end def def resetBrush(self, color, alpha): """Summary Args: color (TYPE): Description alpha (TYPE): Description Returns: TYPE: Description """ brush = getBrushObj(color, alpha=alpha) self.setBrush(brush) # end def def _updateBoundingRect(self): """ Updates the bounding rect to the size of the childrenBoundingRect, and refreshes the addBases and removeBases buttons accordingly. Called by partZDimensionsChangedSlot and partPropertyChangedSlot """ self.setPen(getPenObj(self.modelColor(), 0)) self.resetBrush(styles.DEFAULT_BRUSH_COLOR, styles.DEFAULT_ALPHA) # self.setRect(self.childrenBoundingRect()) _p = _BOUNDING_RECT_PADDING temp_rect = self._vh_rect.adjusted(-_p/2, -_p, _p, -_p/2) self.grab_corner.setTopLeft(temp_rect.topLeft()) self.setRect(temp_rect) # end def ### PUBLIC METHODS ### def setModifyState(self, bool): """Hides the modRect when modify state disabled. Args: bool (TYPE): Description """ self._can_show_mod_rect = bool if bool is False: self._mod_rect.hide() def getOrderedVirtualHelixList(self): """Used for encoding. """ ret = [] for vhi in self._virtual_helix_item_list: ret.append(vhi.coord()) return ret # end def def reorderHelices(self, id_nums, index_delta): """ Reorder helices by moving helices _pathHelixList[first:last] by a distance delta in the list. Notify each PathHelix and PathHelixHandle of its new location. Args: first (TYPE): Description last (TYPE): Description index_delta (TYPE): Description """ vhi_list = self._virtual_helix_item_list helix_numbers = [vhi.idNum() for vhi in vhi_list] first_index = helix_numbers.index(id_nums[0]) last_index = helix_numbers.index(id_nums[-1]) + 1 insert_idxs = [helix_numbers.index(id_num) for id_num in id_nums] for id_num in id_nums: helix_numbers.remove(id_num) if index_delta < 0: # move group earlier in the list new_index = max(0, index_delta + first_index) - len(id_nums) else: # move group later in list new_index = min(len(vhi_list), index_delta + last_index ) - len(id_nums) new_list = helix_numbers[:new_index] + id_nums + helix_numbers[new_index:] # call the method to move the items and store the list self._model_part.setImportedVHelixOrder(new_list, check_batch=False) # end def def setActiveVirtualHelixItem(self, new_active_vhi): """Summary Args: new_active_vhi (TYPE): Description Returns: TYPE: Description """ current_vhi = self.active_virtual_helix_item if new_active_vhi != current_vhi: if current_vhi is not None: current_vhi.deactivate() if new_active_vhi is not None: new_active_vhi.activate() self.active_virtual_helix_item = new_active_vhi # end def def setPreXoverItemsVisible(self, virtual_helix_item): """ self._pre_xover_items list references prexovers parented to other PathHelices such that only the activeHelix maintains the list of visible prexovers Args: virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description """ vhi = virtual_helix_item if vhi is None: return # print("path.setPreXoverItemsVisible", virtual_helix_item.idNum()) part = self.part() info = part.active_base_info if info and virtual_helix_item is not None: id_num, is_fwd, idx, to_vh_id_num = info per_neighbor_hits, pairs = part.potentialCrossoverMap(id_num, idx) self.prexover_manager.activateVirtualHelix(virtual_helix_item, idx, per_neighbor_hits) else: self.prexover_manager.reset() # end def def updateXoverItems(self, virtual_helix_item): """Summary Args: virtual_helix_item (cadnano.gui.views.pathview.virtualhelixitem.VirtualHelixItem): Description Returns: TYPE: Description """ for item in virtual_helix_item.childItems(): if isinstance(item, XoverNode3): item.refreshXover() # end def def updateStatusBar(self, status_string): """Shows status_string in the MainWindow's status bar. Args: status_string (str): The text to be displayed. """ self.window().statusBar().showMessage(status_string) ### COORDINATE METHODS ### def keyPanDeltaX(self): """How far a single press of the left or right arrow key should move the scene (in scene space) """ vhs = self._virtual_helix_item_list return vhs[0].keyPanDeltaX() if vhs else 5 # end def def keyPanDeltaY(self): """How far an an arrow key should move the scene (in scene space) for a single press """ vhs = self._virtual_helix_item_list if not len(vhs) > 1: return 5 dy = vhs[0].pos().y() - vhs[1].pos().y() dummyRect = QRectF(0, 0, 1, dy) return self.mapToScene(dummyRect).boundingRect().height() # end def ### TOOL METHODS ### def mousePressEvent(self, event): """Handler for user mouse press. Args: event (QGraphicsSceneMouseEvent): Contains item, scene, and screen coordinates of the the event, and previous event. """ self._viewroot.clearSelectionsIfActiveTool() return QGraphicsItem.mousePressEvent(self, event) def hoverMoveEvent(self, event): """ Parses a mouseMoveEvent to extract strandSet and base index, forwarding them to approproate tool method as necessary. Args: event (TYPE): Description """ active_tool = self._getActiveTool() tool_method_name = active_tool.methodPrefix() + "HoverMove" if hasattr(self, tool_method_name): getattr(self, tool_method_name)(event.pos()) # end def def pencilToolHoverMove(self, pt): """Pencil the strand is possible. Args: pt (QPointF): mouse cursor location of pencil tool hover. """ active_tool = self._getActiveTool() if not active_tool.isFloatingXoverBegin(): temp_xover = active_tool.floatingXover() temp_xover.updateFloatingFromPartItem(self, pt)
class MovablePolygonVertex(QGraphicsObject): geometryChange = pyqtSignal(object) def __init__(self, parent=None): super(MovablePolygonVertex, self).__init__(parent) self.setZValue(1000) self.isMousePressed = False self.setFlags(QGraphicsItem.ItemIsSelectable | QGraphicsItem.ItemIsFocusable | QGraphicsItem.ItemIsMovable | QGraphicsItem.ItemSendsGeometryChanges) self.setAcceptHoverEvents(True) self.buttonList = [] self.points = [] self.degree = 0 self.setFocus(Qt.ActiveWindowFocusReason) self._boundingRect = QRectF() self._rect = QRectF() def getDegree(self): return self.degree def setPoints(self, ps): self.points.clear() self.degree = len(ps) for point in ps: self.points.append(QPointF(*point)) self.updateResizeHandles() def setRect(self): polygon = QPolygonF(self.points) rect = polygon.boundingRect() self._rect = rect self._boundingRect = rect def prepareGeometryChange(self): self.geometryChange.emit([[p.x(), p.y()] for p in self.points]) super(MovablePolygonVertex, self).prepareGeometryChange() def hoverMoveEvent(self, event): hoverMovePos = event.scenePos() mouseHoverArea = None for item in self.buttonList: if item.contains(hoverMovePos): mouseHoverArea = item break if mouseHoverArea: self.setCursor(QtCore.Qt.PointingHandCursor) return self.setCursor(QtCore.Qt.SizeAllCursor) super(MovablePolygonVertex, self).hoverMoveEvent(event) def hoverEnterEvent(self, event): self.setCursor(QtCore.Qt.SizeAllCursor) super(MovablePolygonVertex, self).hoverEnterEvent(event) def hoverLeaveEvent(self, event): self.setCursor(QtCore.Qt.ArrowCursor) super(MovablePolygonVertex, self).hoverLeaveEvent(event) def mousePressEvent(self, event): self.isMousePressed = True self.mousePressedPos = event.scenePos() self.pressedRectPos = None self.originalPoints = copy.deepcopy(self.points) for i, item in enumerate(self.buttonList): if item.contains(self.mousePressedPos): self.pressedRectPos = i break super(MovablePolygonVertex, self).mousePressEvent(event) def mouseReleaseEvent(self, event): self.isMousePressed = False self.updateResizeHandles() self.prepareGeometryChange() super(MovablePolygonVertex, self).mouseReleaseEvent(event) def paint(self, painter, option, widget): self.updateResizeHandles() self.draw(painter, option, widget, self._rect) for item in self.buttonList: painter.drawRect(item) def draw(self, painter, option, widget, rect): return def boundingRect(self): return self._boundingRect def shape(self): path = QtGui.QPainterPath() path.addRect(self.boundingRect()) return path def mouseMoveEvent(self, event): mouseMovePos = event.scenePos() if self.isMousePressed: if self.pressedRectPos is None: for i, point in enumerate(self.points): newPos = self.originalPoints[i] + (mouseMovePos - self.mousePressedPos) point.setX(newPos.x()) point.setY(newPos.y()) else: newPos = self.originalPoints[self.pressedRectPos] + (mouseMovePos - self.mousePressedPos) self.points[self.pressedRectPos].setX(newPos.x()) self.points[self.pressedRectPos].setY(newPos.y()) self.updateResizeHandles() self.prepareGeometryChange() def updateResizeHandles(self): self.resizeHandleSize = 4.0 self.setRect() self._rect = self._rect.normalized() # FIXME:結構アドホック,複数のビューでシーンを表示してるときには問題が出る. views = self.scene().views() self.offset = self.resizeHandleSize * (views[0].mapToScene(1, 0).x() - views[0].mapToScene(0, 1).x()) self._boundingRect = self._rect.adjusted( -self.offset*2, -self.offset*2, self.offset*2, self.offset*2 ) self.buttonList.clear() for point in self.points: rect = QRectF( point.x()-self.offset, point.y()-self.offset, 2*self.offset, 2*self.offset ) self.buttonList.append(rect)
from PyQt5.QtWidgets import QGraphicsItem, QGraphicsEllipseItem, QGraphicsPathItem from PyQt5.QtWidgets import QGraphicsSimpleTextItem, QGraphicsLineItem from cadnano.enum import LatticeType, Parity, PartType, StrandType from cadnano.gui.controllers.itemcontrollers.virtualhelixitemcontroller import VirtualHelixItemController from cadnano.gui.views.abstractitems.abstractvirtualhelixitem import AbstractVirtualHelixItem from cadnano.virtualhelix import VirtualHelix from cadnano.gui.palette import getColorObj, getNoPen, getPenObj, getBrushObj, getNoBrush from . import slicestyles as styles # set up default, hover, and active drawing styles _RADIUS = styles.SLICE_HELIX_RADIUS _RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS) rect_gain = 0.25 _RECT = _RECT.adjusted(rect_gain, rect_gain, rect_gain, rect_gain) _FONT = styles.SLICE_NUM_FONT _ZVALUE = styles.ZSLICEHELIX+3 _OUT_OF_SLICE_BRUSH_DEFAULT = getBrushObj(styles.OUT_OF_SLICE_FILL) # QBrush(QColor(250, 250, 250)) _USE_TEXT_BRUSH = getBrushObj(styles.USE_TEXT_COLOR) _ROTARYDIAL_STROKE_WIDTH = 1 _ROTARYDIAL_PEN = getPenObj(styles.BLUE_STROKE, _ROTARYDIAL_STROKE_WIDTH) _ROTARYDIAL_BRUSH = getBrushObj('#8099ccff') _ROTARY_DELTA_WIDTH = 10 _HOVER_PEN = getPenObj('#ffffff', 128) _HOVER_BRUSH = getBrushObj('#ffffff', alpha=5)
def paint(self, painter): painter.save() size = min(self.width(), self.height()) self.setWidth(size) self.setHeight(size) rect = QRectF(0, 0, self.width(), self.height()) painter.setRenderHint(QPainter.Antialiasing) pen = painter.pen() pen.setCapStyle(self._pen_style) startAngle = -90 - self._start_angle if RadialBar.DialType.FullDial != self._dial_type: spanAngle = 0 - self._span_angle else: spanAngle = -360 # Draw outer dial painter.save() pen.setWidth(self._dial_width) pen.setColor(self._dial_color) painter.setPen(pen) offset = self._dial_width / 2 if self._dial_type == RadialBar.DialType.MinToMax: painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), startAngle * 16, spanAngle * 16) elif self._dial_type == RadialBar.DialType.FullDial: painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), -90 * 16, -360 * 16) painter.restore() # Draw background painter.save() painter.setBrush(self._background_color) painter.setPen(self._background_color) inner = offset * 2 painter.drawEllipse(rect.adjusted(inner, inner, -inner, -inner)) painter.restore() # Draw progress text with suffix painter.save() painter.setFont(self._text_font) pen.setColor(self._text_color) painter.setPen(pen) if self._show_text: painter.drawText(rect.adjusted(offset, offset, -offset, -offset), Qt.AlignCenter, str(self._value) + self._suffix_text) else: painter.drawText(rect.adjusted(offset, offset, -offset, -offset), Qt.AlignCenter, self._suffix_text) painter.restore() # Draw progress bar painter.save() pen.setWidth(self._dial_width) pen.setColor(self._progress_color) valueAngle = float( float(self._value - self._min_value) / float(self._max_value - self._min_value)) * float( spanAngle) # Map value to angle range painter.setPen(pen) painter.drawArc(rect.adjusted(offset, offset, -offset, -offset), startAngle * 16, valueAngle * 16) painter.restore() painter.restore()
class RectItem(BaseItem): def __init__(self, model_item=None, prefix="", parent=None): BaseItem.__init__(self, model_item, prefix, parent) self._rect = None self._resize = False self._resize_start = None self._resize_start_rect = None self._upper_half_clicked = None self._left_half_clicked = None self._updateRect(self._dataToRect(self._model_item)) LOG.debug("Constructed rect %s for model item %s" % (self._rect, model_item)) def __call__(self, model_item=None, parent=None): item = RectItem(model_item, parent) item.setPen(self.pen()) item.setBrush(self.brush()) return item def _dataToRect(self, model_item): if model_item is None: return QRectF() try: return QRectF(float(model_item[self.prefix() + 'x']), float(model_item[self.prefix() + 'y']), float(model_item[self.prefix() + 'width']), float(model_item[self.prefix() + 'height'])) except KeyError as e: LOG.debug("RectItem: Could not find expected key in item: " + str(e) + ". Check your config!") self.setValid(False) return QRectF() def _updateRect(self, rect): if rect == self._rect: return self.prepareGeometryChange() self._rect = rect self.setPos(rect.topLeft()) def updateModel(self): self._rect = QRectF(self.scenePos(), self._rect.size()) self._model_item.update({ self.prefix() + 'x': float(self._rect.topLeft().x()), self.prefix() + 'y': float(self._rect.topLeft().y()), self.prefix() + 'width': float(self._rect.width()), self.prefix() + 'height': float(self._rect.height()), }) def boundingRect(self): return QRectF(QPointF(0, 0), self._rect.size()) def paint(self, painter, option, widget=None): BaseItem.paint(self, painter, option, widget) pen = self.pen() if self.isSelected(): pen.setStyle(Qt.DashLine) painter.setPen(pen) painter.drawRect(self.boundingRect()) def dataChange(self): rect = self._dataToRect(self._model_item) self._updateRect(rect) def mousePressEvent(self, event): #if event.modifiers() & Qt.ControlModifier != 0: if event.button() & Qt.RightButton != 0: self._resize = True self._resize_start = event.scenePos() self._resize_start_rect = QRectF(self._rect) self._upper_half_clicked = (event.scenePos().y() < self._resize_start_rect.center().y()) self._left_half_clicked = (event.scenePos().x() < self._resize_start_rect.center().x()) event.accept() else: BaseItem.mousePressEvent(self, event) def mouseMoveEvent(self, event): if self._resize: diff = event.scenePos() - self._resize_start if self._left_half_clicked: x = self._resize_start_rect.x() + diff.x() w = self._resize_start_rect.width() - diff.x() else: x = self._resize_start_rect.x() w = self._resize_start_rect.width() + diff.x() if self._upper_half_clicked: y = self._resize_start_rect.y() + diff.y() h = self._resize_start_rect.height() - diff.y() else: y = self._resize_start_rect.y() h = self._resize_start_rect.height() + diff.y() rect = QRectF(QPointF(x, y), QSizeF(w, h)).normalized() self._updateRect(rect) self.updateModel() event.accept() else: BaseItem.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): if self._resize: self._resize = False event.accept() else: BaseItem.mouseReleaseEvent(self, event) def keyPressEvent(self, event): BaseItem.keyPressEvent(self, event) step = 1 if event.modifiers() & Qt.ShiftModifier: step = 5 ds = { Qt.Key_Left: (-step, 0), Qt.Key_Right: (step, 0), Qt.Key_Up: (0, -step), Qt.Key_Down: (0, step), }.get(event.key(), None) if ds is not None: if event.modifiers() & Qt.ControlModifier: rect = self._rect.adjusted(*((0, 0) + ds)) else: rect = self._rect.adjusted(*(ds + ds)) self._updateRect(rect) self.updateModel() event.accept()
# extra2 = QPainterPath() # extra2.addEllipse(-0.35*IW, 0.5*IW, 0.7*IW, 0.3*IW) # FWDPXI_PP += extra1 # FWDPXI_PP -= extra2 # REVPXI_PP.moveTo(-0.5*IW, -0.7*IW) # REVPXI_PP.lineTo(0., 0.2*IW) # REVPXI_PP.lineTo(0.5*IW, -0.7*IW) # extra1 = QPainterPath() # extra1.addEllipse(-0.5*IW, -0.9*IW, IW, 0.4*IW) # REVPXI_PP += extra1 _RADIUS = styles.SLICE_HELIX_RADIUS _WEDGE_RECT_GAIN = 0.25 WEDGE_RECT = QRectF(0, 0, 2 * _RADIUS, 2 * _RADIUS) WEDGE_RECT = WEDGE_RECT.adjusted(0, 0, _WEDGE_RECT_GAIN, _WEDGE_RECT_GAIN) _WEDGE_RECT_CENTERPT = WEDGE_RECT.center() class PropertyWrapperObject(QObject): def __init__(self, item): """Summary Args: item (TYPE): Description """ super(PropertyWrapperObject, self).__init__() self.item = item self.animations = {} def __get_bondP2(self):
def setupGraphics(self): """ Set up the graphics. """ shape_rect = QRectF(-24, -24, 48, 48) self.shapeItem = NodeBodyItem(self) self.shapeItem.setShapeRect(shape_rect) self.shapeItem.setAnimationEnabled(self.__animationEnabled) # Rect for widget's 'ears'. anchor_rect = QRectF(-31, -31, 62, 62) self.inputAnchorItem = SinkAnchorItem(self) input_path = QPainterPath() start_angle = 180 - self.ANCHOR_SPAN_ANGLE / 2 input_path.arcMoveTo(anchor_rect, start_angle) input_path.arcTo(anchor_rect, start_angle, self.ANCHOR_SPAN_ANGLE) self.inputAnchorItem.setAnchorPath(input_path) self.outputAnchorItem = SourceAnchorItem(self) output_path = QPainterPath() start_angle = self.ANCHOR_SPAN_ANGLE / 2 output_path.arcMoveTo(anchor_rect, start_angle) output_path.arcTo(anchor_rect, start_angle, - self.ANCHOR_SPAN_ANGLE) self.outputAnchorItem.setAnchorPath(output_path) self.inputAnchorItem.hide() self.outputAnchorItem.hide() # Title caption item self.captionTextItem = NameTextItem(self) self.captionTextItem.setPlainText("") self.captionTextItem.setPos(0, 33) def iconItem(standard_pixmap): item = GraphicsIconItem(self, icon=standard_icon(standard_pixmap), iconSize=QSize(16, 16)) item.hide() return item self.errorItem = iconItem(QStyle.SP_MessageBoxCritical) self.warningItem = iconItem(QStyle.SP_MessageBoxWarning) self.infoItem = iconItem(QStyle.SP_MessageBoxInformation) ################################ # PyQt 5.10 crashes because of this call (2) #self.backgroundItem = QGraphicsPathItem(self) self.backgroundItem = QGraphicsPathItem(None) ################################ backgroundrect = QPainterPath() backgroundrect.addRoundedRect(anchor_rect.adjusted(-4, -2, 4, 2), 5, 5, mode=Qt.AbsoluteSize) self.backgroundItem.setPen(QPen(Qt.NoPen)) self.backgroundItem.setBrush(QPalette().brush(QPalette.Highlight)) self.backgroundItem.setOpacity(0.5) self.backgroundItem.setPath(backgroundrect) self.backgroundItem.setZValue(-10) self.backgroundItem.setVisible(self.isSelected()) self.prepareGeometryChange() self.__boundingRect = None