Source code for node_editor.node_graphics_edge

# -*- coding: utf-8 -*-
"""
A module containing the Graphics representation of an Edge
"""
from qtpy.QtWidgets import QGraphicsPathItem, QWidget, QGraphicsItem
from qtpy.QtGui import QColor, QPen, QPainterPath
from qtpy.QtCore import Qt, QRectF, QPointF

from node_editor.node_graphics_edge_path import GraphicsEdgePathBezier, GraphicsEdgePathDirect, GraphicsEdgePathSquare


[docs]class QDMGraphicsEdge(QGraphicsPathItem): """Base class for Graphics Edge""" def __init__(self, edge:'Edge', parent:QWidget=None): """ :param edge: reference to :class:`~node_editor.node_edge.Edge` :type edge: :class:`~nodeeditor.node_edge.Edge` :param parent: parent widget :type parent: ``QWidget`` :Instance attributes: - **edge** - reference to :class:`~node_editor.node_edge.Edge` - **posSource** - ``[x, y]`` source position in the `Scene` - **posDestination** - ``[x, y]`` destination position in the `Scene` """ super().__init__(parent) self.edge = edge # create instance of our path class self.pathCalculator = self.determineEdgePathClass()(self) # init our flags self._last_selected_state = False self.hovered = False # init our variables self.posSource = [0, 0] self.posDestination = [200, 100] self.initAssets() self.initUI()
[docs] def initUI(self): """Set up this ``QGraphicsPathItem``""" self.setFlag(QGraphicsItem.ItemIsSelectable) self.setAcceptHoverEvents(True) self.setZValue(-1)
[docs] def initAssets(self): """Initialize ``QObjects`` like ``QColor``, ``QPen`` and ``QBrush``""" self._color = self._default_color = QColor("#001000") self._color_selected = QColor("#00ff00") self._color_hovered = QColor("#FF37A6FF") self._pen = QPen(self._color) self._pen_selected = QPen(self._color_selected) self._pen_dragging = QPen(self._color) self._pen_hovered = QPen(self._color_hovered) self._pen_dragging.setStyle(Qt.DashLine) self._pen.setWidthF(3.0) self._pen_selected.setWidthF(3.0) self._pen_dragging.setWidthF(3.0) self._pen_hovered.setWidthF(5.0)
[docs] def createEdgePathCalculator(self): """Create instance of :class:`~node_editor.node_graphics_edge_path.GraphicsEdgePathBase`""" self.pathCalculator = self.determineEdgePathClass()(self) return self.pathCalculator
[docs] def determineEdgePathClass(self): """Decide which GraphicsEdgePath class should be used to calculate path according to edge.edge_type value""" from node_editor.node_edge import EDGE_TYPE_BEZIER, EDGE_TYPE_DIRECT, EDGE_TYPE_SQUARE if self.edge.edge_type == EDGE_TYPE_BEZIER: return GraphicsEdgePathBezier if self.edge.edge_type == EDGE_TYPE_DIRECT: return GraphicsEdgePathDirect if self.edge.edge_type == EDGE_TYPE_SQUARE: return GraphicsEdgePathSquare else: return GraphicsEdgePathBezier
[docs] def makeUnselectable(self): """Used for drag edge to disable click detection over this graphics item""" self.setFlag(QGraphicsItem.ItemIsSelectable, False) self.setAcceptHoverEvents(False)
[docs] def changeColor(self, color): """Change color of the edge from string hex value '#00ff00'""" # print("^Called change color to:", color.red(), color.green(), color.blue(), "on edge:", self.edge) self._color = QColor(color) if type(color) == str else color self._pen = QPen(self._color) self._pen.setWidthF(3.0)
[docs] def setColorFromSockets(self) -> bool: """Change color according to connected sockets. Returns ``True`` if color can be determined""" socket_type_start = self.edge.start_socket.socket_type socket_type_end = self.edge.end_socket.socket_type if socket_type_start != socket_type_end: return False self.changeColor(self.edge.start_socket.grSocket.getSocketColor(socket_type_start))
[docs] def onSelected(self): """Our event handling when the edge was selected""" self.edge.scene.grScene.itemSelected.emit()
[docs] def doSelect(self, new_state:bool=True): """Safe version of selecting the `Graphics Node`. Takes care about the selection state flag used internally :param new_state: ``True`` to select, ``False`` to deselect :type new_state: ``bool`` """ self.setSelected(new_state) self._last_selected_state = new_state if new_state: self.onSelected()
[docs] def mouseReleaseEvent(self, event): """Overridden Qt's method to handle selecting and deselecting this `Graphics Edge`""" super().mouseReleaseEvent(event) if self._last_selected_state != self.isSelected(): self.edge.scene.resetLastSelectedStates() self._last_selected_state = self.isSelected() self.onSelected()
[docs] def hoverEnterEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: """Handle hover effect""" self.hovered = True self.update()
[docs] def hoverLeaveEvent(self, event: 'QGraphicsSceneHoverEvent') -> None: """Handle hover effect""" self.hovered = False self.update()
[docs] def setSource(self, x:float, y:float): """ Set source point :param x: x position :type x: ``float`` :param y: y position :type y: ``float`` """ self.posSource = [x, y]
[docs] def setDestination(self, x:float, y:float): """ Set destination point :param x: x position :type x: ``float`` :param y: y position :type y: ``float`` """ self.posDestination = [x, y]
[docs] def boundingRect(self) -> QRectF: """Defining Qt' bounding rectangle""" return self.shape().boundingRect()
[docs] def shape(self) -> QPainterPath: """Returns ``QPainterPath`` representation of this `Edge` :return: path representation :rtype: ``QPainterPath`` """ return self.calcPath()
[docs] def paint(self, painter, QStyleOptionGraphicsItem, widget=None): """Qt's overridden method to paint this Graphics Edge. Path calculated in :func:`~node_editor.node_graphics_edge.QDMGraphicsEdge.calcPath` method""" self.setPath(self.calcPath()) painter.setBrush(Qt.NoBrush) if self.hovered and self.edge.end_socket is not None: painter.setPen(self._pen_hovered) painter.drawPath(self.path()) if self.edge.end_socket is None: painter.setPen(self._pen_dragging) else: painter.setPen(self._pen if not self.isSelected() else self._pen_selected) painter.drawPath(self.path())
[docs] def intersectsWith(self, p1:QPointF, p2:QPointF) -> bool: """Does this Graphics Edge intersect with the line between point A and point B ? :param p1: point A :type p1: ``QPointF`` :param p2: point B :type p2: ``QPointF`` :return: ``True`` if this `Graphics Edge` intersects :rtype: ``bool`` """ cutpath = QPainterPath(p1) cutpath.lineTo(p2) path = self.calcPath() return cutpath.intersects(path)
[docs] def calcPath(self) -> QPainterPath: """Will handle drawing QPainterPath from Point A to B. Internally there exist self.pathCalculator which is an instance of derived :class:`~node_editor.node_graphics_edge_path.GraphicsEdgePathBase` class containing the actual `calcPath()` function - computing how the edge should look like. :returns: ``QPainterPath`` of the edge connecting `source` and `destination` :rtype: ``QPainterPath`` """ return self.pathCalculator.calcPath()