def getOr(x, y): global count nodeXinitial = x.getInitial() nodeXfinal = x.getFinal() nodeYinitial = y.getInitial() nodeYfinal = y.getFinal() nodeXinitial.category = 'incremental' nodeXfinal.category = 'incremental' nodeYinitial.category = 'incremental' nodeYfinal.category = 'incremental' for y in y.getNodes(): x.addNode(y) node_initial = Node(count, 'initial') count += 1 node_final = Node(count, 'final') count += 1 node_initial.addEdge(Edge(node_initial, nodeXinitial, 'ε')) node_initial.addEdge(Edge(node_initial, nodeYinitial, 'ε')) nodeXfinal.addEdge(Edge(nodeXfinal, node_final, 'ε')) nodeYfinal.addEdge(Edge(nodeYfinal, node_final, 'ε')) x.addNode(node_initial) x.addNode(node_final) return x
def get_or(x, y): global count node_xinitial = x.get_initial() node_xfinal = x.get_final() node_yinitial = y.get_initial() node_yfinal = y.get_final() node_xinitial.category = 'incremental' node_xfinal.category = 'incremental' node_yinitial.category = 'incremental' node_yfinal.category = 'incremental' for y in y.nodes: x.add_node(y) node_initial = Node(count, 'initial') count += 1 node_final = Node(count, 'final') count += 1 node_initial.add_edge(Edge(node_initial, node_xinitial, EMPTY_STATE)) node_initial.add_edge(Edge(node_initial, node_yinitial, EMPTY_STATE)) node_xfinal.add_edge(Edge(node_xfinal, node_final, EMPTY_STATE)) node_yfinal.add_edge(Edge(node_yfinal, node_final, EMPTY_STATE)) x.add_node(node_initial) x.add_node(node_final) return x
def addNodes(self): """Testing method to create 3 `Nodes` with 3 `Edges` connecting them""" node1 = Node(self.scene, "My Awesome Node 1", inputs=[0, 0, 0], outputs=[1, 5]) node2 = Node(self.scene, "My Awesome Node 2", inputs=[3, 3, 3], outputs=[1]) node3 = Node(self.scene, "My Awesome Node 3", inputs=[2, 2, 2], outputs=[1]) node1.setPos(-350, -250) node2.setPos(-75, 0) node3.setPos(200, -200) edge1 = Edge(self.scene, node1.outputs[0], node2.inputs[0], edge_type=EDGE_TYPE_BEZIER) edge2 = Edge(self.scene, node2.outputs[0], node3.inputs[0], edge_type=EDGE_TYPE_BEZIER) edge3 = Edge(self.scene, node1.outputs[0], node3.inputs[2], edge_type=EDGE_TYPE_BEZIER) self.scene.history.storeInitialHistoryStamp()
def get_plus(x): node_xinitial = x.get_initial() node_xfinal = x.get_final() node_xfinal.add_edge(Edge(node_xfinal, node_xinitial, EMPTY_STATE)) return get_initial_final(x)
def findEdges(lines, nodes, keys, required): edges = Edges() i = 0 while i < (len(lines)): line = lines[i].strip() if "<edge" in line: length, osmids, oneway, name, path, highway, service, tunnel, access = 0, 0, False, "", "", "", "", "", "" node1, node2 = __getNodesFromLine(line, nodes) while "</edge" not in line: i += 1 line = lines[i].strip() if keys["length"] in line: length = round(float(line[16:-7]), 3) if keys["oneway"] in line: oneway = __str2bool(line[16:-7]) if keys["osmid_edge"] in line: osmids = __getEdgesIdsFromLine(line) if keys["name"] in line: name = line[15:-7] if keys["path"] in line: path = line[16:-7] if keys["highway"] in line: highway = line[16:-7] if keys["service"] in line: service = line[16:-7] if keys["tunnel"] in line: tunnel = line[16:-7] if keys["access"] in line: access = line[16:-7] edges.addEdge( Edge(node1, node2, osmids, length, oneway, name, path, highway, service, tunnel, access, required)) i += 1 return (edges)
def getPlus(x): nodeXinitial = x.getInitial() nodeXfinal = x.getFinal() nodeXfinal.addEdge(Edge(nodeXfinal, nodeXinitial, 'ε')) return getInitialFinal(x)
def edgeDragStart(self, item: 'QGraphicsItem'): """Code handling the start of dragging an `Edge` operation""" try: if DEBUG: print('View::edgeDragStart ~ Start dragging edge') if DEBUG: print('View::edgeDragStart ~ assign Start Socket to:', item.socket) self.drag_start_socket = item.socket if self.drag_start_socket.is_input == False: self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart ~ dragEdge:', self.drag_edge) else: self.drag_edge = None except Exception as e: dumpException(e)
def edgeDragEnd(self, item: 'QGraphicsItem'): """Code handling the end of dragging an `Edge` operation. In this code return True if skip the rest of the mouse event processing :param item: Item in the `Graphics Scene` where we ended dragging an `Edge` :type item: ``QGraphicsItem`` """ self.mode = MODE_NOOP if DEBUG: print('View::edgeDragEnd ~ End dragging edge') if self.drag_edge is not None: self.drag_edge.remove( silent=True) # don't notify sockets about removing drag_edge self.drag_edge = None try: if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: # if we released dragging on a socket (other then the beginning socket) ## First remove old edges / send notifications for socket in (item.socket, self.drag_start_socket): if not socket.is_multi_edges: if socket.is_input: # print("removing SILENTLY edges from input socket (is_input and !is_multi_edges) [DragStart]:", item.socket.edges) socket.removeAllEdges(silent=True) else: socket.removeAllEdges(silent=False) ## Create new Edge if item.socket.is_input: new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) else: print("wrong end socket") if DEBUG: print("View::edgeDragEnd ~ created new edge:", new_edge, "connecting", new_edge.start_socket, "<-->", new_edge.end_socket) ## Send notifications for the new edge # for socket in [self.drag_start_socket, item.socket]: # @TODO: Add possibility (ie when an input edge was replaced) to be silent and don't trigger change # socket.node.onEdgeConnectionChanged(new_edge) #if socket.is_input: socket.node.onInputChanged(socket) self.grScene.scene.history.storeHistory( "Created new edge by dragging", setModified=True) return True except Exception as e: dumpException(e) if DEBUG: print('View::edgeDragEnd ~ everything done.') return False
def getInitialFinal(graph): global count initial = graph.getInitial() initial.category = 'incremental' final = graph.getFinal() final.category = 'incremental' node_initial = Node(count, 'initial') count += 1 node_initial.addEdge(Edge(node_initial, initial, 'ε')) node_final = Node(count, 'final') count += 1 node_final.addEdge(Edge(final, node_final, 'ε')) graph.addNode(node_initial) graph.addNode(node_final) return graph
def get_initial_final(graph): global count initial = graph.get_initial() initial.category = 'incremental' final = graph.get_final() final.category = 'incremental' node_initial = Node(count, 'initial') count += 1 node_initial.add_edge(Edge(node_initial, initial, EMPTY_STATE)) node_final = Node(count, 'final') count += 1 final.add_edge(Edge(final, node_final, EMPTY_STATE)) graph.add_node(node_initial) graph.add_node(node_final) return graph
def getPoint(x, y): nodeXfinal = x.getFinal() nodeYinitial = y.getInitial() nodeXfinal.category = 'incremental' nodeXfinal.addEdge(Edge(nodeXfinal, nodeYinitial, 'ε')) nodeYinitial.category = 'incremental' for yn in y.getNodes(): x.addNode(yn) return getInitialFinal(x)
def get_point(x, y): node_xfinal = x.get_final() node_yinitial = y.get_initial() node_xfinal.category = 'incremental' node_xfinal.add_edge(Edge(node_xfinal, node_yinitial, EMPTY_STATE)) node_yinitial.category = 'incremental' for yn in y.nodes: x.add_node(yn) return get_initial_final(x)
def get_cline(x): global count node_xinitial = x.get_initial() node_xinitial.category = 'incremental' node_xfinal = x.get_final() node_xfinal.category = 'incremental' node_xfinal.add_edge(Edge(node_xfinal, node_xinitial, EMPTY_STATE)) node_initial = Node(count, 'initial') count += 1 node_final = Node(count, 'final') count += 1 node_initial.add_edge(Edge(node_initial, node_xinitial, EMPTY_STATE)) node_initial.add_edge(Edge(node_initial, node_final, EMPTY_STATE)) node_xfinal.add_edge(Edge(node_xfinal, node_final, EMPTY_STATE)) x.add_node(node_initial) x.add_node(node_final) return x
def getCline(x): global count nodeXinitial = x.getInitial() nodeXinitial.category = 'incremental' nodeXfinal = x.getFinal() nodeXfinal.category = 'incremental' nodeXfinal.addEdge(Edge(nodeXfinal, nodeXinitial, 'ε')) node_initial = Node(count, 'initial') count += 1 node_final = Node(count, 'final') count += 1 node_initial.addEdge(Edge(node_initial, nodeXinitial, 'ε')) node_initial.addEdge(Edge(node_initial, node_final, 'ε')) nodeXfinal.addEdge(Edge(nodeXfinal, node_final, 'ε')) x.addNode(node_initial) x.addNode(node_final) return x
def get_graph_letter(letter): global count graph = Graph() node1 = Node(count, 'initial') count += 1 node2 = Node(count, 'final') count += 1 node1.add_edge(Edge(node1, node2, letter)) graph.add_node(node1) graph.add_node(node2) return get_initial_final(graph)
def getGraphLetter(letter): global count graph = Graph() node1 = Node(count, 'initial') count += 1 node2 = Node(count, 'final') count += 1 node1.addEdge(Edge(node1, node2, letter)) graph.addNode(node1) graph.addNode(node2) return getInitialFinal(graph)
from classes.node import Node from classes.edge import Edge from classes.bases.graph_like import GraphLike from classes.node_feature_extractor import NodeFeatureExtractor from classes.graph_vectorizer import GraphVectorizer from classes.path_completion import PathCompletion import pprint as pp n1 = Node(1, "A") n2 = Node(2, "B") n3 = Node(3, "C") n4 = Node(4, "D") n5 = Node(5, "B") nodes = [n1, n2, n3, n4, n5] e1 = Edge(n1, n2, "A->B") e2 = Edge(n2, n3, "B->C") e3 = Edge(n3, n1, "C->A") e4 = Edge(n3, n4, "C->D") e5 = Edge(n5, n3, "B->C") e6 = Edge(n5, n4, "B->D") e7 = Edge(n1, n5, "A->B") edges = [e1, e2, e3, e4, e5, e6, e7] g = GraphLike() for node in nodes: print(node) g.add_node(node) for edge in edges: print(edge)
def deserializeFromClipboard(self, data: dict): """ Deserializes data from Clipboard. :param data: ``dict`` data for deserialization to the :class:`nodeeditor.node_scene.Scene`. :type data: ``dict`` """ hashmap = {} # calculate mouse pointer - scene position view = self.scene.getView() mouse_scene_pos = view.last_scene_mouse_position # calculate selected objects bbox and center minx, maxx, miny, maxy = 10000000, -10000000, 10000000, -10000000 for node_data in data['vertices']: x, y = node_data['pos_x'], node_data['pos_y'] if x < minx: minx = x if x > maxx: maxx = x if y < miny: miny = y if y > maxy: maxy = y # add width and height of a node maxx -= 180 maxy += 100 relbboxcenterx = (minx + maxx) / 2 - minx relbboxcentery = (miny + maxy) / 2 - miny if DEBUG_PASTING: print(" *** PASTA:") print("Copied boudaries:\n\tX:", minx, maxx, " Y:", miny, maxy) print("\tbbox_center:", relbboxcenterx, relbboxcentery) # calculate the offset of the newly creating vertices mousex, mousey = mouse_scene_pos.x(), mouse_scene_pos.y() # create each node created_nodes = [] self.scene.setSilentSelectionEvents() self.scene.doDeselectItems() for node_data in data['vertices']: new_node = self.scene.getNodeClassFromData(node_data)(self.scene) new_node.deserialize(node_data, hashmap, restore_id=False) created_nodes.append(new_node) # readjust the new nodeeditor's position # new node's current position posx, posy = new_node.pos.x(), new_node.pos.y() newx, newy = mousex + posx - minx, mousey + posy - miny new_node.setPos(newx, newy) new_node.doSelect() if DEBUG_PASTING: print("** PASTA SUM:") print("\tMouse pos:", mousex, mousey) print("\tnew node pos:", posx, posy) print("\tFINAL:", newx, newy) # create each edge if 'edges' in data: for edge_data in data['edges']: new_edge = Edge(self.scene) new_edge.deserialize(edge_data, hashmap, restore_id=False) self.scene.setSilentSelectionEvents(False) # store history self.scene.history.storeHistory("Pasted elements in scene", setModified=True) return created_nodes
def deserialize(self, data: dict, hashmap: dict = {}, restore_id: bool = True) -> bool: hashmap = {} if restore_id: self.id = data['id'] # -- deserialize NODES ## Instead of recreating all the vertices, reuse existing ones... # get list of all current vertices: all_nodes = self.nodes.copy() # go through deserialized vertices: for node_data in data['vertices']: # can we find this node in the scene? found = False for node in all_nodes: if node.id == node_data['id']: found = node break if not found: new_node = self.getNodeClassFromData(node_data)(self) new_node.deserialize(node_data, hashmap, restore_id) new_node.onDeserialized(node_data) # print("New node for", node_data['title']) else: found.deserialize(node_data, hashmap, restore_id) found.onDeserialized(node_data) all_nodes.remove(found) # print("Reused", node_data['title']) # remove vertices which are left in the scene and were NOT in the serialized data! # that means they were not in the graph before... while all_nodes != []: node = all_nodes.pop() node.remove() # -- deserialize EDGES ## Instead of recreating all the edges, reuse existing ones... # get list of all current edges: all_edges = self.edges.copy() # go through deserialized edges: for edge_data in data['edges']: # can we find this node in the scene? found = False for edge in all_edges: if edge.id == edge_data['id']: found = edge break if not found: new_edge = Edge(self).deserialize(edge_data, hashmap, restore_id) # print("New edge for", edge_data) else: found.deserialize(edge_data, hashmap, restore_id) all_edges.remove(found) # remove vertices which are left in the scene and were NOT in the serialized data! # that means they were not in the graph before... while all_edges != []: edge = all_edges.pop() edge.remove() return True
class QDMGraphicsView(QGraphicsView): """Class representing NodeEditor's `Graphics View`""" #: pyqtSignal emitted when cursor position on the `Scene` has changed scenePosChanged = pyqtSignal(int, int) def __init__(self, grScene: 'QDMGraphicsScene', parent: 'QWidget' = None): """ :param grScene: reference to the :class:`~nodeeditor.node_graphics_scene.QDMGraphicsScene` :type grScene: :class:`~nodeeditor.node_graphics_scene.QDMGraphicsScene` :param parent: parent widget :type parent: ``QWidget`` :Instance Attributes: - **grScene** - reference to the :class:`~nodeeditor.node_graphics_scene.QDMGraphicsScene` - **mode** - state of the `Graphics View` - **zoomInFactor**- ``float`` - zoom step scaling, default 1.25 - **zoomClamp** - ``bool`` - do we clamp zooming or is it infinite? - **zoom** - current zoom step - **zoomStep** - ``int`` - the relative zoom step when zooming in/out - **zoomRange** - ``[min, max]`` """ super().__init__(parent) self.grScene = grScene self.initUI() self.setScene(self.grScene) self.mode = MODE_NOOP self.editingFlag = False self.rubberBandDraggingRectangle = False self.last_scene_mouse_position = QPoint(0, 0) self.zoomInFactor = 1.25 self.zoomClamp = True self.zoom = 10 self.zoomStep = 1 self.zoomRange = [0, 10] # cutline self.cutline = QDMCutLine() self.grScene.addItem(self.cutline) # listeners self._drag_enter_listeners = [] self._drop_listeners = [] self._tool_listeners = [] def initUI(self): """Set up this ``QGraphicsView``""" self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setDragMode(QGraphicsView.RubberBandDrag) # enable dropping self.setAcceptDrops(True) def dragEnterEvent(self, event: QDragEnterEvent): """Trigger our registered `Drag Enter` events""" for callback in self._drag_enter_listeners: callback(event) def dropEvent(self, event: QDropEvent): """Trigger our registered `Drop` events""" for callback in self._drop_listeners: callback(event) def addDragEnterListener(self, callback: 'function'): """ Register callback for `Drag Enter` event :param callback: callback function """ self._drag_enter_listeners.append(callback) def addDropListener(self, callback: 'function'): """ Register callback for `Drop` event :param callback: callback function """ self._drop_listeners.append(callback) def addToolListener(self, callback: 'function'): self._tool_listeners.append(callback) def mousePressEvent(self, event: QMouseEvent): """Dispatch Qt's mousePress event to corresponding function below""" if event.button() == Qt.MiddleButton: self.middleMouseButtonPress(event) elif event.button() == Qt.LeftButton: self.leftMouseButtonPress(event) elif event.button() == Qt.RightButton: self.rightMouseButtonPress(event) else: super().mousePressEvent(event) def mouseReleaseEvent(self, event: QMouseEvent): """Dispatch Qt's mouseRelease event to corresponding function below""" if event.button() == Qt.MiddleButton: self.middleMouseButtonRelease(event) elif event.button() == Qt.LeftButton: self.leftMouseButtonRelease(event) elif event.button() == Qt.RightButton: self.rightMouseButtonRelease(event) else: super().mouseReleaseEvent(event) def middleMouseButtonPress(self, event: QMouseEvent): """When Middle mouse button was pressed""" item = self.getItemAtClick(event) # debug print out if DEBUG_MMB_SCENE_ITEMS: if isinstance(item, QDMGraphicsEdge): print( "MMB DEBUG:", item.edge, "\n\t", item.edge.grEdge if item.edge.grEdge is not None else None) if isinstance(item, QDMGraphicsSocket): print("MMB DEBUG:", item.socket, "socket_type:", item.socket.socket_type, "has edges:", "no" if item.socket.edges == [] else "") if item.socket.edges: for edge in item.socket.edges: print("\t", edge) if DEBUG_MMB_SCENE_ITEMS and (item is None): print("SCENE:") print(" Nodes:") for node in self.grScene.scene.nodes: print("\t", node) print(" Edges:") for edge in self.grScene.scene.edges: print("\t", edge, "\n\t\tgrEdge:", edge.grEdge if edge.grEdge is not None else None) if event.modifiers() & Qt.CTRL: print(" Graphic Items in GraphicScene:") for item in self.grScene.items(): print(' ', item) # faking events for enable MMB dragging the scene releaseEvent = QMouseEvent(QEvent.MouseButtonRelease, event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers()) super().mouseReleaseEvent(releaseEvent) self.setDragMode(QGraphicsView.ScrollHandDrag) fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() | Qt.LeftButton, event.modifiers()) super().mousePressEvent(fakeEvent) def middleMouseButtonRelease(self, event: QMouseEvent): """When Middle mouse button was released""" fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & ~Qt.LeftButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) self.setDragMode(QGraphicsView.RubberBandDrag) def leftMouseButtonPress(self, event: QMouseEvent): """When Left mouse button was pressed""" # get item which we clicked on item = self.getItemAtClick(event) # we store the position of last LMB click self.last_lmb_click_scene_pos = self.mapToScene(event.pos()) # if DEBUG: print("LMB Click on", item, self.debug_modifiers(event)) # logic if hasattr(item, "node") or isinstance( item, QDMGraphicsEdge) or item is None: if event.modifiers() & Qt.ShiftModifier: event.ignore() fakeEvent = QMouseEvent(QEvent.MouseButtonPress, event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() | Qt.LeftButton, event.modifiers() | Qt.ControlModifier) super().mousePressEvent(fakeEvent) return if isinstance(item, QDMGraphicsSocket): if self.mode == MODE_NOOP: self.mode = MODE_EDGE_DRAG self.edgeDragStart(item) return if self.mode == MODE_EDGE_DRAG: res = self.edgeDragEnd(item) if res: return if item is None: if event.modifiers() & Qt.ControlModifier: self.mode = MODE_EDGE_CUT fakeEvent = QMouseEvent(QEvent.MouseButtonRelease, event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) QApplication.setOverrideCursor(Qt.CrossCursor) return else: self.rubberBandDraggingRectangle = True super().mousePressEvent(event) def leftMouseButtonRelease(self, event: QMouseEvent): """When Left mouse button was released""" # get item which we release mouse button on item = self.getItemAtClick(event) try: # logic if hasattr(item, "node") or isinstance( item, QDMGraphicsEdge) or item is None: if event.modifiers() & Qt.ShiftModifier: event.ignore() fakeEvent = QMouseEvent( event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers() | Qt.ControlModifier) super().mouseReleaseEvent(fakeEvent) return if self.mode == MODE_EDGE_DRAG: if self.distanceBetweenClickAndReleaseIsOff(event): res = self.edgeDragEnd(item) if res: return if self.mode == MODE_EDGE_CUT: self.cutIntersectingEdges() self.cutline.line_points = [] self.cutline.update() QApplication.setOverrideCursor(Qt.ArrowCursor) self.mode = MODE_NOOP return if self.rubberBandDraggingRectangle: self.rubberBandDraggingRectangle = False current_selected_items = self.grScene.selectedItems() if current_selected_items != self.grScene.scene._last_selected_items: if current_selected_items == []: self.grScene.itemsDeselected.emit() else: self.grScene.itemSelected.emit() self.grScene.scene._last_selected_items = current_selected_items return # otherwise deselect everything if item is None: self.grScene.itemsDeselected.emit() except: dumpException() super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event: QMouseEvent): """When Right mouse button was pressed""" super().mousePressEvent(event) def rightMouseButtonRelease(self, event: QMouseEvent): """When Right mouse button was release""" ## cannot be because with dragging RMB we spawn Create New Node Context Menu ## However, you could use this if you want to cancel with RMB # if self.mode == MODE_EDGE_DRAG: # self.cancelDragEdge(event) # return super().mouseReleaseEvent(event) def mouseMoveEvent(self, event: QMouseEvent): """Overriden Qt's ``mouseMoveEvent`` handling Scene/View logic""" scenepos = self.mapToScene(event.pos()) if self.mode == MODE_EDGE_DRAG: # according to sentry: 'NoneType' object has no attribute 'grEdge' if self.drag_edge is not None and self.drag_edge.grEdge is not None: self.drag_edge.grEdge.setDestination(scenepos.x(), scenepos.y()) self.drag_edge.grEdge.update() # else: # print(">>> Want to update self.drag_edge grEdge, but it's None!!!") if self.mode == MODE_EDGE_CUT and self.cutline is not None: self.cutline.line_points.append(scenepos) self.cutline.update() self.last_scene_mouse_position = scenepos self.scenePosChanged.emit(int(scenepos.x()), int(scenepos.y())) super().mouseMoveEvent(event) def keyPressEvent(self, event: QKeyEvent): """ .. note:: This overriden Qt's method was used for handling key shortcuts, before we implemented propper ``QWindow`` with Actions and Menu. Still the commented code serves as an example how to handle key presses without Qt's framework for Actions and shortcuts. There can be also found an example how to solve the problem when Node does contain Text/LineEdit and we press `Delete` key (also serving to delete `Node`) :param event: Qt's Key event :type event: ``QKeyEvent`` :return: """ # Use this code below if you wanna have shortcuts in this widget. # You want to use this, when you don't have a window which handles these shortcuts for you # if event.key() == Qt.Key_Delete: # if not self.editingFlag: # self.deleteSelected() # else: # super().keyPressEvent(event) # elif event.key() == Qt.Key_S and event.modifiers() & Qt.ControlModifier: # self.grScene.scene.saveToFile("graph.json") # elif event.key() == Qt.Key_L and event.modifiers() & Qt.ControlModifier: # self.grScene.scene.loadFromFile("graph.json") # elif event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier and not event.modifiers() & Qt.ShiftModifier: # self.grScene.scene.history.undo() # elif event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier and event.modifiers() & Qt.ShiftModifier: # self.grScene.scene.history.redo() # elif event.key() == Qt.Key_H: # print("HISTORY: len(%d)" % len(self.grScene.scene.history.history_stack), # " -- current_step", self.grScene.scene.history.history_current_step) # ix = 0 # for item in self.grScene.scene.history.history_stack: # print("#", ix, "--", item['desc']) # ix += 1 # else: super().keyPressEvent(event) def cutIntersectingEdges(self): """Compare which `Edges` intersect with current `Cut line` and delete them safely""" for ix in range(len(self.cutline.line_points) - 1): p1 = self.cutline.line_points[ix] p2 = self.cutline.line_points[ix + 1] # @TODO: we could collect all touched vertices, and notify them once after all edges removed # we could cut 3 edges leading to a single nodeeditor this will notify it 3x # maybe we could use some Notifier class with methods collect() and dispatch() for edge in self.grScene.scene.edges: if edge.grEdge.intersectsWith(p1, p2): edge.remove() self.grScene.scene.history.storeHistory("Delete cutted edges", setModified=True) def deleteSelected(self): """Shortcut for safe deleting every object selected in the `Scene`.""" for item in self.grScene.selectedItems(): if isinstance(item, QDMGraphicsEdge): item.edge.remove() elif hasattr(item, 'node'): item.node.remove() self.grScene.scene.history.storeHistory("Delete selected", setModified=True) def debug_modifiers(self, event): """Helper function get string if we hold Ctrl, Shift or Alt modifier keys""" out = "MODS: " if event.modifiers() & Qt.ShiftModifier: out += "SHIFT " if event.modifiers() & Qt.ControlModifier: out += "CTRL " if event.modifiers() & Qt.AltModifier: out += "ALT " return out def getItemAtClick(self, event: QEvent) -> 'QGraphicsItem': """Return the object on which we've clicked/release mouse button :param event: Qt's mouse or key event :type event: ``QEvent`` :return: ``QGraphicsItem`` which the mouse event happened or ``None`` """ pos = event.pos() obj = self.itemAt(pos) return obj def edgeDragStart(self, item: 'QGraphicsItem'): """Code handling the start of dragging an `Edge` operation""" try: if DEBUG: print('View::edgeDragStart ~ Start dragging edge') if DEBUG: print('View::edgeDragStart ~ assign Start Socket to:', item.socket) self.drag_start_socket = item.socket if self.drag_start_socket.is_input == False: self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart ~ dragEdge:', self.drag_edge) else: self.drag_edge = None except Exception as e: dumpException(e) def edgeDragEnd(self, item: 'QGraphicsItem'): """Code handling the end of dragging an `Edge` operation. In this code return True if skip the rest of the mouse event processing :param item: Item in the `Graphics Scene` where we ended dragging an `Edge` :type item: ``QGraphicsItem`` """ self.mode = MODE_NOOP if DEBUG: print('View::edgeDragEnd ~ End dragging edge') if self.drag_edge is not None: self.drag_edge.remove( silent=True) # don't notify sockets about removing drag_edge self.drag_edge = None try: if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: # if we released dragging on a socket (other then the beginning socket) ## First remove old edges / send notifications for socket in (item.socket, self.drag_start_socket): if not socket.is_multi_edges: if socket.is_input: # print("removing SILENTLY edges from input socket (is_input and !is_multi_edges) [DragStart]:", item.socket.edges) socket.removeAllEdges(silent=True) else: socket.removeAllEdges(silent=False) ## Create new Edge if item.socket.is_input: new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) else: print("wrong end socket") if DEBUG: print("View::edgeDragEnd ~ created new edge:", new_edge, "connecting", new_edge.start_socket, "<-->", new_edge.end_socket) ## Send notifications for the new edge # for socket in [self.drag_start_socket, item.socket]: # @TODO: Add possibility (ie when an input edge was replaced) to be silent and don't trigger change # socket.node.onEdgeConnectionChanged(new_edge) #if socket.is_input: socket.node.onInputChanged(socket) self.grScene.scene.history.storeHistory( "Created new edge by dragging", setModified=True) return True except Exception as e: dumpException(e) if DEBUG: print('View::edgeDragEnd ~ everything done.') return False def distanceBetweenClickAndReleaseIsOff(self, event: QMouseEvent) -> bool: """ Measures if we are too far from the last Mouse button click scene position. This is used for detection if we release too far after we clicked on a `Socket` :param event: Qt's mouse event :type event: ``QMouseEvent`` :return: ``True`` if we released too far from where we clicked before """ new_lmb_release_scene_pos = self.mapToScene(event.pos()) dist_scene = new_lmb_release_scene_pos - self.last_lmb_click_scene_pos edge_drag_threshold_sq = EDGE_DRAG_START_THRESHOLD * EDGE_DRAG_START_THRESHOLD return (dist_scene.x() * dist_scene.x() + dist_scene.y() * dist_scene.y()) > edge_drag_threshold_sq def wheelEvent(self, event: QWheelEvent): """overriden Qt's ``wheelEvent``. This handles zooming""" # calculate our zoom Factor zoomOutFactor = 1 / self.zoomInFactor # calculate zoom if event.angleDelta().y() > 0: zoomFactor = self.zoomInFactor self.zoom += self.zoomStep else: zoomFactor = zoomOutFactor self.zoom -= self.zoomStep clamped = False if self.zoom < self.zoomRange[0]: self.zoom, clamped = self.zoomRange[0], True if self.zoom > self.zoomRange[1]: self.zoom, clamped = self.zoomRange[1], True # set scene scale if not clamped or self.zoomClamp is False: self.scale(zoomFactor, zoomFactor)