Source code for node_editor.node_edge_rerouting

# -*- coding: utf-8 -*-
"""
A module containing the Edge Rerouting functionality
"""


DEBUG_REROUTING = True


[docs]class EdgeRerouting: def __init__(self, grView: 'QGraphicsView'): self.grView = grView self.start_socket = None # store where we started re-routing the edges self.rerouting_edges = [] # edges representing the re-routing (dashed edges) self.is_rerouting = False # are we currently re-routing? self.first_mb_release = False # flag for detecting if we already clicked with the rerouting LMB release
[docs] def print(self, *args): """Helper function to better control debug printing to console for this feature""" if DEBUG_REROUTING: print("REROUTING:", *args)
[docs] def getEdgeClass(self): """Helper function to get the Edge class. Using what the Scene class provides""" return self.grView.grScene.scene.getEdgeClass()
[docs] def getAffectedEdges(self) -> list: """ Get a list of all edges connected to the `self.start_socket` where we started the re-routing :return: List of all edges affected by the rerouting started from this `self.start_socket` :class:`~node_editor.node_socket.Socket` :rtype: ``list`` """ if self.start_socket is None: return [] # no starting socket assigned, so no edges for us # return edges connected to the socket return self.start_socket.edges.copy()
[docs] def setAffectedEdgesVisible(self, visibility: bool=True): """ Show/Hide all edges connected to the `self.start_socket` where we started the re-routing :param visibility: ``True`` if all the affected :class:`~node_editor.node_edge.Edge` (s) should be shown or hidden :type visibility: ``bool`` """ for edge in self.getAffectedEdges(): if visibility: edge.grEdge.show() else: edge.grEdge.hide()
[docs] def resetRerouting(self): """Reset to default state. Init this feature internal variables""" self.is_rerouting = False self.start_socket = None self.first_mb_release = False
# holding all rerouting edges should be empty at this point... # self.rerouting_edges = []
[docs] def clearReroutingEdges(self): """Remove the helping dashed edges from the :class:`~node_editor.node_scene.Scene`""" self.print("clean called") while self.rerouting_edges != []: edge = self.rerouting_edges.pop() self.print("\twant to clean:", edge) edge.remove()
[docs] def updateScenePos(self, x: float, y: float): """ Update position of all the rerouting edges (dashed ones). Called from mouseMove event to update to new mouse position :param x: new X position :type x: ``float`` :param y: new Y position :type y: ``float`` """ if self.is_rerouting: for edge in self.rerouting_edges: if edge and edge.grEdge: edge.grEdge.setDestination(x, y) edge.grEdge.update()
[docs] def startRerouting(self, socket: 'Socket'): """ Method to start the re-routing. Called from the grView's state machine. :param socket: :class:`~node_editor.node_socket.Socket` where we started the re-routing :type socket: :class:`~nodeeditor.node_socket.Socket` """ self.print("startRerouting", socket) self.is_rerouting = True self.start_socket = socket self.print("numEdges:", len(self.getAffectedEdges())) self.setAffectedEdgesVisible(visibility=False) start_position = self.start_socket.node.getSocketScenePosition(self.start_socket) for edge in self.getAffectedEdges(): other_socket = edge.getOtherSocket(self.start_socket) new_edge = self.getEdgeClass()(self.start_socket.node.scene, edge_type=edge.edge_type) new_edge.start_socket = other_socket new_edge.grEdge.setSource(*other_socket.node.getSocketScenePosition(other_socket)) new_edge.grEdge.setDestination(*start_position) new_edge.grEdge.update() self.rerouting_edges.append(new_edge)
[docs] def stopRerouting(self, target: 'Socket'=None): """ Method for stopping the re-routing :param target: Target where we ended the rerouting (usually released mouse button). Provide ``Socket`` or ``None`` to cancel :type target: :class:`~nodeeditor.node_socket.Socket` or ``None`` """ self.print("stopRerouting on:", target, "no change" if target==self.start_socket else "") if self.start_socket is not None: # reset start socket highlight self.start_socket.grSocket.isHighlighted = False # collect all affected (node, edge) tuples in the meantime.. if necessary affected_nodes = [] if target is None or target == self.start_socket: # canceling -> no change self.setAffectedEdgesVisible(visibility=True) else: # validate edges before doing anything else valid_edges, invalid_edges = self.getAffectedEdges(), [] for edge in self.getAffectedEdges(): start_sock = edge.getOtherSocket(self.start_socket) if not edge.validateEdge(start_sock, target): # not valid edge self.print("This edge rerouting is not valid!", edge) invalid_edges.append(edge) # remove the invalidated edges from the list for invalid_edge in invalid_edges: valid_edges.remove(invalid_edge) # reconnect to new socket self.print("should reconnect from:", self.start_socket, "-->", target) self.setAffectedEdgesVisible(visibility=True) for edge in valid_edges: for node in [edge.start_socket.node, edge.end_socket.node]: if node not in affected_nodes: affected_nodes.append((node, edge)) if target.is_input: target.removeAllEdges(silent=True) if edge.end_socket == self.start_socket: edge.end_socket = target else: edge.start_socket = target edge.updatePositions() # hide rerouting edges self.clearReroutingEdges() # Send notifications for all affected nodes for affected_node, edge in affected_nodes: affected_node.onEdgeConnectionChanged(edge) if edge.start_socket in affected_node.inputs: affected_node.onInputChanged(edge.start_socket) if edge.end_socket in affected_node.inputs: affected_node.onInputChanged(edge.end_socket) # store history stamp self.start_socket.node.scene.history.storeHistory("Rerouted edges", setModified=True) # reset variables of this rerouting state self.resetRerouting()