def initUI(self): self.setGeometry(200, 200, 800, 800) self.layout = QVBoxLayout() self.layout.setContentsMargins(0, 0, 0, 0) self.setLayout(self.layout) self.scene = Scene() self.grScene = self.scene.grScene self.view = QDMGraphicsView(self.grScene, self) self.layout.addWidget(self.view) node1 = Node(self.scene, "First Node", inputs=[1, 1, 1], outputs=[1]) # 数字代表 socket 类型, socket index 按数组顺序 node2 = Node(self.scene, "Second Node", inputs=[1, 1, 1], outputs=[1]) node3 = Node(self.scene, "Third Node", inputs=[1, 1, 1], outputs=[1]) node1.setPos(-350, 100) node2.setPos(-75, 0) node3.setPos(200, -100) edge1 = Edge(self.scene, node1.outputs[0], node2.inputs[0], EDGE_TYPE_BEZIER) edge2 = Edge(self.scene, node2.outputs[0], node3.inputs[1], EDGE_TYPE_BEZIER) self.setWindowTitle("Node Editor") self.show()
def addNodes(self): node1 = Node(self.scene, "My Awesome Node 1", inputs=[0, 0, 0], outputs=[1]) 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, -150) 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)
def edgeDragStart(self, item): print("Start drag edge") # self.dragEdge 是临时边 self.previousEdge = item.socket.edge self.last_start_socket = item.socket self.dragEdge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER)
def edgeDragStart(self, item:'QGraphicsItem'): 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 self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart ~ dragEdge:', self.drag_edge) except Exception as e: dumpException(e)
def edgeDragStart(self, item): if DEBUG: print('View::edgeDragStart - Start Dragging edge') if DEBUG: print('View::edgeDragStart - assign Start Socket to:', item.socket) self.previousEdge = item.socket.edge self.last_start_socket = item.socket self.dragEdge = Edge(self.graphics_scene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart - dragEdge:', self.dragEdge)
def addNodes(self): node1 = Node(self.scene, "Skeleton", inputs=[0], outputs=[1]) node2 = Node(self.scene, "Muscle", inputs=[0], outputs=[1]) node3 = Node(self.scene, "Fascia/Fat", inputs=[0], outputs=[1]) node1.setPos(-350, -250) node2.setPos(-75, -0) node3.setPos(200, -150) edge1 = Edge(self.scene, node1.outputs[0], node2.inputs[0], edgeType=EDGE_TYPE_BEZIER) edge2 = Edge(self.scene, node2.outputs[0], node3.inputs[0], edgeType=EDGE_TYPE_BEZIER)
def edgeDragEnd(self, item): """ return True if skip the rest of the code """ self.mode = MODE_NOOP self.drag_edge.remove() self.drag_edge = None if type(item) is QDMGraphicsSocket: if item.socket != self.drag_start_socket: # if we released dragging on a socket (other then the beginning socket) # we wanna keep all the edges comming from target socket if not item.socket.is_multi_edges: item.socket.removeAllEdges() # we wanna keep all the edges comming from start socket if not self.drag_start_socket.is_multi_edges: self.drag_start_socket.removeAllEdges() new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) self.grScene.scene.history.storeHistory( "Created new edge by dragging", setModified=True) return True return False
def addNodes(self): node1 = Node(self.scene, "Dataset Path", inputs=[0], outputs=[1]) node2 = Node(self.scene, "Image Settings", inputs=[1], outputs=[1]) node3 = Node(self.scene, "Train", inputs=[0], outputs=[1]) node4 = Node(self.scene, "GPU", inputs=[0], outputs=[1]) node5 = Node(self.scene, "Batch", inputs=[0], outputs=[1]) node6 = Node(self.scene, "Dimensions", inputs=[0], outputs=[1]) node7 = Node(self.scene, "GAN", inputs=[0, 1, 2, 3, 4, 5, 5, 5, 5, 7], outputs=[2]) node8 = Node(self.scene, "Start", inputs=[0], outputs=[0]) node9 = Node(self.scene, "Output", inputs=[0], outputs=[1]) node1.setPos(-450, -150) node2.setPos(-200, -150) node3.setPos(-450, 200) node4.setPos(-450, 350) node5.setPos(-450, 500) node6.setPos(-200, 200) node7.setPos(150, -150) node8.setPos(400, -150) node9.setPos(400, 250) edge1 = Edge(self.scene, node1.outputs[0], node2.inputs[0], edge_type=EDGE_TYPE_BEZIER) edge2 = Edge(self.scene, node2.outputs[0], node7.inputs[0], edge_type=EDGE_TYPE_BEZIER) edge3 = Edge(self.scene, node3.outputs[0], node7.inputs[1], edge_type=EDGE_TYPE_BEZIER) edge4 = Edge(self.scene, node4.outputs[0], node7.inputs[2], edge_type=EDGE_TYPE_BEZIER) edge5 = Edge(self.scene, node5.outputs[0], node7.inputs[3], edge_type=EDGE_TYPE_BEZIER) edge6 = Edge(self.scene, node6.outputs[0], node7.inputs[4], edge_type=EDGE_TYPE_BEZIER) edge7 = Edge(self.scene, node7.outputs[0], node8.inputs[0], edge_type=EDGE_TYPE_BEZIER) edge8 = Edge(self.scene, node7.outputs[0], node9.inputs[0], edge_type=EDGE_TYPE_BEZIER) self.scene.history.storeInitialHistoryStamp()
def deserializeFromClipboard(self, data:dict): hashmap = {} view = self.scene.getView() mouse_scene_pos = view.last_scene_mouse_position minx, maxx, miny, maxy = 10000000,-10000000, 10000000,-10000000 for node_data in data['nodes']: 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 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) mousex, mousey = mouse_scene_pos.x(), mouse_scene_pos.y() created_nodes = [] self.scene.setSilentSelectionEvents() self.scene.doDeselectItems() for node_data in data['nodes']: new_node = self.scene.getNodeClassFromData(node_data)(self.scene) new_node.deserialize(node_data, hashmap, restore_id=False) created_nodes.append(new_node) 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) 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) self.scene.history.storeHistory("Pasted elements in scene", setModified=True) return created_nodes
def deserializeFromClipboard(self, data): 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 = 0,0,0,0 for node_data in data['nodes']: 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 bbox_center_x = (minx + maxx) / 2 bbox_center_y = (miny + maxy) / 2 # center = view.mapToScene(view.rect().center()) # calculate tehe offset of the newly creating nodes offset_x = mouse_scene_pos.x() - bbox_center_x offset_y = mouse_scene_pos.y() - bbox_center_y # create each node for node_data in data['nodes']: new_node = self.scene.getNodeClassFromData(node_data)(self.scene) new_node.deserialize(node_data, hashmap, restore_id=False) # readjust the new node's position pos = new_node.pos new_node.setPos(pos.x() + offset_x, pos.y() + offset_y) # 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) # store history self.scene.history.storeHistory("Pasted elements in scene", setModified = True)
def addNodes(self): node1 = Node(self.scene, "Monte Carlo Driver", inputs=[1, 2, 3], outputs=[4]) node2 = Node(self.scene, "Dihedral Mutator", inputs=[3], outputs=[1]) node3 = Node(self.scene, "Energy Function", inputs=[], outputs=[2]) node1.setPos(200, -150) node2.setPos(-350, 0) node3.setPos(-75, -250) edge1 = Edge(self.scene, node3.outputs[0], node1.inputs[1], edge_type=EDGE_TYPE_BEZIER) edge2 = Edge(self.scene, node2.outputs[0], node1.inputs[0], edge_type=EDGE_TYPE_BEZIER) self.scene.history.storeInitialHistoryStamp()
def deserialize(self, data, hashmap={}, restore_id=True): self.clear() hashmap = {} if restore_id: self.id = data['id'] # create nodes for node_data in data['nodes']: self.getNodeClassFromData(node_data)(self).deserialize( node_data, hashmap, restore_id) # create edges for edge_data in data['edges']: Edge(self).deserialize(edge_data, hashmap, restore_id) return True
def deserialize(self, data: dict, hashmap: dict = {}, restore_id: bool = True) -> bool: hashmap = {} if restore_id: self.id = data['id'] all_nodes = self.nodes.copy() for node_data in data['nodes']: 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) else: found.deserialize(node_data, hashmap, restore_id) found.onDeserialized(node_data) all_nodes.remove(found) while all_nodes != []: node = all_nodes.pop() node.remove() all_edges = self.edges.copy() for edge_data in data['edges']: 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) else: found.deserialize(edge_data, hashmap, restore_id) all_edges.remove(found) while all_edges != []: edge = all_edges.pop() edge.remove() return True
def edgeDragEnd(self, item:'QGraphicsItem'): self.mode = MODE_NOOP if DEBUG: print('View::edgeDragEnd ~ End dragging edge') self.drag_edge.remove(silent=True) self.drag_edge = None try: if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: for socket in (item.socket, self.drag_start_socket): if not socket.is_multi_edges: if socket.is_input: socket.removeAllEdges(silent=True) else: socket.removeAllEdges(silent=False) new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) if DEBUG: print("View::edgeDragEnd ~ created new edge:", new_edge, "connecting", new_edge.start_socket, "<-->", new_edge.end_socket) for socket in [self.drag_start_socket, item.socket]: 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
class QDMGraphicsView(QGraphicsView): scenePosChanged = pyqtSignal(int, int) def __init__(self, grScene:'QDMGraphicsScene', parent:'QWidget'=None): 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] self.cutline = QDMCutLine() self.grScene.addItem(self.cutline) self._drag_enter_listeners = [] self._drop_listeners = [] def initUI(self): 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) self.setAcceptDrops(True) def dragEnterEvent(self, event:QDragEnterEvent): for callback in self._drag_enter_listeners: callback(event) def dropEvent(self, event:QDropEvent): for callback in self._drop_listeners: callback(event) def addDragEnterListener(self, callback:'function'): self._drag_enter_listeners.append(callback) def addDropListener(self, callback:'function'): self._drop_listeners.append(callback) def mousePressEvent(self, event:QMouseEvent): 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): 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): item = self.getItemAtClick(event) 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) 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): 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): item = self.getItemAtClick(event) self.last_lmb_click_scene_pos = self.mapToScene(event.pos()) 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): item = self.getItemAtClick(event) try: 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 if item is None: self.grScene.itemsDeselected.emit() except: dumpException() super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event:QMouseEvent): super().mousePressEvent(event) def rightMouseButtonRelease(self, event:QMouseEvent): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event:QMouseEvent): scenepos = self.mapToScene(event.pos()) if self.mode == MODE_EDGE_DRAG: 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): super().keyPressEvent(event) def cutIntersectingEdges(self): for ix in range(len(self.cutline.line_points) - 1): p1 = self.cutline.line_points[ix] p2 = self.cutline.line_points[ix + 1] 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): 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): 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': pos = event.pos() obj = self.itemAt(pos) return obj def edgeDragStart(self, item:'QGraphicsItem'): 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 self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart ~ dragEdge:', self.drag_edge) except Exception as e: dumpException(e) def edgeDragEnd(self, item:'QGraphicsItem'): self.mode = MODE_NOOP if DEBUG: print('View::edgeDragEnd ~ End dragging edge') self.drag_edge.remove(silent=True) self.drag_edge = None try: if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: for socket in (item.socket, self.drag_start_socket): if not socket.is_multi_edges: if socket.is_input: socket.removeAllEdges(silent=True) else: socket.removeAllEdges(silent=False) new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) if DEBUG: print("View::edgeDragEnd ~ created new edge:", new_edge, "connecting", new_edge.start_socket, "<-->", new_edge.end_socket) for socket in [self.drag_start_socket, item.socket]: 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: 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): zoomOutFactor = 1 / self.zoomInFactor 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 if not clamped or self.zoomClamp is False: self.scale(zoomFactor, zoomFactor)
class ShotGraphicsView(QGraphicsView): def __init__(self, graphics_scene, parent=None): super().__init__(parent) self.graphics_scene = graphics_scene self.__init_ui__() self.setScene(self.graphics_scene) self.mode = MODE_NOOPERATION self.zoomInFactor = 1.25 self.zoomClamp = True self.zoom = 10 self.zoomStep = 1 self.zoomRange = [0, 15] def __init_ui__(self): 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) def mousePressEvent(self, event): 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): 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): 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): fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & Qt.LeftButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) self.setDragMode(QGraphicsView.NoDrag) def leftMouseButtonPress(self, event): item = self.getItemAtClick(event) self.last_lmb_click_scene_pos = self.mapToScene(event.pos()) if DEBUG: print("LMB Click on", item, self.debug_modifiers(event)) if hasattr(item, "node") or isinstance( item, NodeGraphicsEdge) 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 type(item) is NodeGraphicsSocket: if self.mode == MODE_NOOPERATION: self.mode = MODE_EDGE_DRAG self.edgeDragStart(item) return if self.mode == MODE_EDGE_DRAG: res = self.edgeDragEnd(item) if res: return super().mousePressEvent(event) def leftMouseButtonRelease(self, event): item = self.getItemAtClick(event) if hasattr(item, "node") or isinstance( item, NodeGraphicsEdge) or item is None: if event.modifiers() & Qt.ShiftModifier: if DEBUG: print("LMB Release + Shift on", item) 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: self.distanceBetweenClickAndReleaseIsOff(event) if self.distanceBetweenClickAndReleaseIsOff: res = self.edgeDragEnd(item) if res: return super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event): super().mousePressEvent(event) item = self.getItemAtClick(event) def rightMouseButtonRelease(self, event): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event): if self.mode == MODE_EDGE_DRAG: pos = self.mapToScene(event.pos()) self.dragEdge.graphic_edge.setDestination(pos.x(), pos.y()) self.dragEdge.graphic_edge.update() super().mouseMoveEvent(event) def keyPressEvent(self, event): if event.key() == Qt.Key_Delete: self.deleteSelected() else: super().keyPressEvent(event) def deleteSelected(self): for item in self.graphics_scene.selectedItems(): if isinstance(item, NodeGraphicsEdge): item.edge.remove() elif hasattr(item, 'node'): item.node.remove() def debug_modifiers(self, event): out = "MODS: " if event.modifiers() & Qt.ShiftModifier: out += "SHIFT " if event.modifiers() & Qt.ControlModifier: out += "CTRL " if event.modifiers() & Qt.AltModifier: out += "ATL " return out def getItemAtClick(self, event): pos = event.pos() obj = self.itemAt(pos) return obj def edgeDragStart(self, item): if DEBUG: print('View::edgeDragStart - Start Dragging edge') if DEBUG: print('View::edgeDragStart - assign Start Socket to:', item.socket) self.previousEdge = item.socket.edge self.last_start_socket = item.socket self.dragEdge = Edge(self.graphics_scene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart - dragEdge:', self.dragEdge) def edgeDragEnd(self, item): self.mode = MODE_NOOPERATION if type(item) is NodeGraphicsSocket: if item.socket != self.last_start_socket: if DEBUG: print('View::edgeDragEnd - previous edge', self.previousEdge) if item.socket.hasEdge(): item.socket.edge.remove() if DEBUG: print('View::edgeDragEnd - End Dragging edge', item.socket) if self.previousEdge is not None: self.previousEdge.remove() if DEBUG: print('View::edgeDragEnd - previous edge removed') self.dragEdge.start_socket = self.last_start_socket self.dragEdge.end_socket = item.socket self.dragEdge.start_socket.setConnectedEdge(self.dragEdge) self.dragEdge.end_socket.setConnectedEdge(self.dragEdge) if DEBUG: print( 'View::edgeDragEnd - reassigned start & end sockets to drag edge' ) self.dragEdge.updatePositions() return True if DEBUG: print('View::edgeDragEnd - End dragging edge') self.dragEdge.remove() self.dragEdge = None if DEBUG: print('View::edgeDragEnd - about to set socket to previous edge:', self.previousEdge) if self.previousEdge is not None: self.previousEdge.start_socket.edge = self.previousEdge if DEBUG: print('View::edgeDragEnd - everything done') def distanceBetweenClickAndReleaseIsOff(self, event): 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): # 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)
def edgeDragStart(self, item): self.drag_start_socket = item.socket self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER)
class QDMGraphicsView(QGraphicsView): def __init__(self, grScene, parent=None): super().__init__(parent) self.grScene = grScene self.initUI() self.setScene(grScene) self.mode = MODE_NOOP self.zoonInFactor = 1.25 self.zoomClamp = False # Useless self.zoom = 10 self.zoomStep = 1 self.zoomRange = [0, 10] def initUI(self): 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) def mousePressEvent(self, event): 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): 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): # 中键拖动面板 # 先释放左键 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): fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & -Qt.LeftButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) self.setDragMode(QGraphicsView.NoDrag) def edgeDragStart(self, item): print("Start drag edge") # self.dragEdge 是临时边 self.previousEdge = item.socket.edge self.last_start_socket = item.socket self.dragEdge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) def edgeDragEnd(self, item): self.mode = MODE_NOOP print("End drag edge") if type(item) is QDMGraphicsSocket: print("Assign End socket") if item.socket.hasEdge(): self.tempEdge = item.socket.edge item.socket.edge.remove() print(self.tempEdge != self.previousEdge) if self.previousEdge is not None and self.tempEdge != self.previousEdge: # 可能重复连接,是同一条边,那就不要remove两次 self.previousEdge.remove() self.tempEdge = None self.dragEdge.end_socket = item.socket self.dragEdge.start_socket.setConnectedEdge(self.dragEdge) self.dragEdge.end_socket.setConnectedEdge(self.dragEdge) self.dragEdge.updatePositions() return True self.dragEdge.remove() # 清理 grEdge 和当前 edge self.dragEdge = None if self.previousEdge is not None: self.previousEdge.start_socket.edge = self.previousEdge # 在 edgeDragStart 生成新的 Edge 时修改了 start_socket.edge,需要恢复 return False def distanceBetweenClickAndReleaseIsOff(self, event): new_lmb_release_scene_pos = self.mapToScene( event.pos()) # 用来和 MousePress 时对比判断鼠标移动距离 dist_scene_pos = new_lmb_release_scene_pos - self.last_lmb_click_scene_pos dist_scene_pos_len = dist_scene_pos.x() * dist_scene_pos.x( ) + dist_scene_pos.y() * dist_scene_pos.y() return dist_scene_pos_len > EDGE_DRAG_START_THRESHOLD * EDGE_DRAG_START_THRESHOLD def leftMouseButtonPress(self, event): item = self.getItemAtClick(event) self.last_lmb_click_scene_pos = self.mapToScene(event.pos()) # 单击 socket 开始生成一条新的边 # 进入 EDGE_DRAG 模式 if type(item) is QDMGraphicsSocket: if self.mode == MODE_NOOP: self.mode = MODE_EDGE_DRAG self.edgeDragStart(item) return # 在 EDGE_DRAG 模式下单击左键退出模式,如果终点是socket,就把边放上去 if self.mode == MODE_EDGE_DRAG: if self.edgeDragEnd(item): return super().mousePressEvent(event) def leftMouseButtonRelease(self, event): item = self.getItemAtClick(event) # 如果在 EDGE_DRAG 模式下,抬起左键时,如果在 socket 上就生成新的连接 if self.mode == MODE_EDGE_DRAG: if self.distanceBetweenClickAndReleaseIsOff(event): # 只有鼠标移出一段距离才会assign socket,防止连到自己 print("ReleaseOff") if self.edgeDragEnd(item): return print("No ReleaseOff") super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event): super().mousePressEvent(event) def rightMouseButtonRelease(self, event): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event): if self.mode == MODE_EDGE_DRAG: pos = self.mapToScene(event.pos()) self.dragEdge.grEdge.setDestination(pos.x(), pos.y()) self.dragEdge.grEdge.update() # redraw super().mouseMoveEvent(event) def wheelEvent(self, event): # 滚轮缩放整体面板 zoomOutFactor = 1. / self.zoonInFactor oldPos = self.mapToScene(event.pos()) if event.angleDelta().y() > 0: zoomFactor = self.zoonInFactor self.zoom += self.zoomStep else: zoomFactor = zoomOutFactor self.zoom -= self.zoomStep if self.zoom < self.zoomRange[0]: self.zoom = self.zoomRange[0] zoomFactor = 1.0 elif self.zoom > self.zoomRange[1]: self.zoom = self.zoomRange[1] zoomFactor = 1.0 self.scale(zoomFactor, zoomFactor) def getItemAtClick(self, event): pos = event.pos() obj = self.itemAt(pos) return obj
class QDMGraphicsView(QGraphicsView): def __init__(self, grScene, parent=None): super().__init__(parent) self.grScene = grScene self.initUI() self.setScene(self.grScene) self.mode = MODE_NOOP self.editingFlag = False 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) def initUI(self): """ smooth out the Pixels in the Lines, Text etc. """ self.setRenderHints(QPainter.Antialiasing | QPainter.HighQualityAntialiasing | QPainter.TextAntialiasing | QPainter.SmoothPixmapTransform) self.setViewportUpdateMode( QGraphicsView.FullViewportUpdate ) # Fix the problem that the Lines under the Rect getting smaller # hide scrollbar self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) # set the Center under the Mouse for scrolling in/out self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setDragMode(QGraphicsView.RubberBandDrag) def mousePressEvent(self, event): 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): 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) """ Drag around """ def middleMouseButtonPress(self, event): 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): fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & ~Qt.LeftButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) self.setDragMode(QGraphicsView.NoDrag) def leftMouseButtonPress(self, event): # 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: if DEBUG: print("LMB + Shift on", item) 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 type(item) is 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 super().mousePressEvent(event) def leftMouseButtonRelease(self, event): # get item which we release mouse button on item = self.getItemAtClick(event) # 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 super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event): super().mousePressEvent(event) item = self.getItemAtClick(event) if DEBUG: if isinstance(item, QDMGraphicsEdge): print('RMB DEBUG:', item.edge, ' connecting sockets:', item.edge.start_socket, '<-->', item.edge.end_socket) if type(item) is QDMGraphicsSocket: print('RMB DEBUG:', item.socket, 'has edge:', item.socket.edge) if item is None: print('SCENE:') print(' Nodes:') for node in self.grScene.scene.nodes: print(' ', node) print(' Edges:') for edge in self.grScene.scene.edges: print(' ', edge) def rightMouseButtonRelease(self, event): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event): if self.mode == MODE_EDGE_DRAG: pos = self.mapToScene(event.pos()) self.dragEdge.grEdge.setDestination(pos.x(), pos.y()) self.dragEdge.grEdge.update() if self.mode == MODE_EDGE_CUT: pos = self.mapToScene(event.pos()) self.cutline.line_points.append(pos) self.cutline.update() super().mouseMoveEvent(event) def keyPressEvent(self, event): if event.key() == Qt.Key_Delete: self.deleteSelected() if not self.editingFlag: self.deleteSelected() else: super().keyPressEvent(event) else: super().keyPressEvent(event) # that not everthing is overwritten def cutIntersectingEdges(self): for ix in range(len(self.cutline.line_points) - 1): p1 = self.cutline.line_points[ix] p2 = self.cutline.line_points[ix + 1] for edge in self.grScene.scene.edges: if edge.grEdge.intersectsWith(p1, p2): edge.remove() def deleteSelected(self): for item in self.grScene.selectedItems(): if isinstance(item, QDMGraphicsEdge): item.edge.remove() elif hasattr(item, 'node'): item.node.remove() def debug_modifiers(self, event): 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): """ return the object on which we've clicked/release mouse button """ pos = event.pos() obj = self.itemAt(pos) return obj def edgeDragStart(self, item): if DEBUG: print('View::edgeDragStart ~ Start dragging edge') if DEBUG: print('View::edgeDragStart ~ assign Start Socket to:', item.socket) self.previousEdge = item.socket.edge self.last_start_socket = item.socket self.dragEdge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) if DEBUG: print('View::edgeDragStart ~ dragEdge:', self.dragEdge) def edgeDragEnd(self, item): """ return True if skip the rest of the code """ self.mode = MODE_NOOP if type(item) is QDMGraphicsSocket: if item.socket != self.last_start_socket: if DEBUG: print('View::edgeDragEnd ~ previous edge:', self.previousEdge) if item.socket.hasEdge(): item.socket.edge.remove() if DEBUG: print('View::edgeDragEnd ~ assign End Socket', item.socket) if self.previousEdge is not None: self.previousEdge.remove() if DEBUG: print('View::edgeDragEnd ~ previous edge removed') self.dragEdge.start_socket = self.last_start_socket self.dragEdge.end_socket = item.socket self.dragEdge.start_socket.setConnectedEdge(self.dragEdge) self.dragEdge.end_socket.setConnectedEdge(self.dragEdge) if DEBUG: print( 'View::edgeDragEnd ~ reassigned start & end sockets to drag edge' ) self.dragEdge.updatePositions() return True if DEBUG: print('View::edgeDragEnd ~ End dragging edge') self.dragEdge.remove() self.dragEdge = None if DEBUG: print('View::edgeDragEnd ~ about to set socket to previous edge:', self.previousEdge) if self.previousEdge is not None: self.previousEdge.start_socket.edge = self.previousEdge if DEBUG: print('View::edgeDragEnd ~ everything done.') return False def distanceBetweenClickAndReleaseIsOff(self, event): """ measures if we are too far from the last LMB click scene position """ 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): # 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)
class QDMGraphicsView(QGraphicsView): scenePosChanged = pyqtSignal(int, int) def __init__(self, grScene, parent=None): super().__init__(parent) self.grScene = grScene self.initUI() self.setScene(self.grScene) self.mode = MODE_NOOP self.editingFlag = False self.rubberBandDraggingRectangle = False 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 = [] def initUI(self): 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): for callback in self._drag_enter_listeners: callback(event) def dropEvent(self, event): for callback in self._drop_listeners: callback(event) def addDragEnterListener(self, callback): self._drag_enter_listeners.append(callback) def addDropListener(self, callback): self._drop_listeners.append(callback) def mousePressEvent(self, event): 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): 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): item = self.getItemAtClick(event) # 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) QApplication.setOverrideCursor(Qt.ClosedHandCursor) 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): fakeEvent = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & ~Qt.LeftButton, event.modifiers()) super().mouseReleaseEvent(fakeEvent) self.setDragMode(QGraphicsView.RubberBandDrag) QApplication.restoreOverrideCursor() def leftMouseButtonPress(self, event): # 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()) # 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 type(item) is 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): # get item which we release mouse button on item = self.getItemAtClick(event) # 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() super().mouseReleaseEvent(event) def rightMouseButtonPress(self, event): super().mousePressEvent(event) def rightMouseButtonRelease(self, event): super().mouseReleaseEvent(event) def mouseMoveEvent(self, event): if self.mode == MODE_EDGE_DRAG: pos = self.mapToScene(event.pos()) self.drag_edge.grEdge.setDestination(pos.x(), pos.y()) self.drag_edge.grEdge.update() if self.mode == MODE_EDGE_CUT: pos = self.mapToScene(event.pos()) self.cutline.line_points.append(pos) self.cutline.update() self.last_scene_mouse_position = self.mapToScene(event.pos()) self.scenePosChanged.emit(int(self.last_scene_mouse_position.x()), int(self.last_scene_mouse_position.y())) super().mouseMoveEvent(event) def keyPressEvent(self, event): # 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.txt") # elif event.key() == Qt.Key_L and event.modifiers() & Qt.ControlModifier: # self.grScene.scene.loadFromFile("graph.json.txt") # 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() # else: super().keyPressEvent(event) def cutIntersectingEdges(self): for ix in range(len(self.cutline.line_points) - 1): p1 = self.cutline.line_points[ix] p2 = self.cutline.line_points[ix + 1] 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): 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): # ? 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): """ return the object on which we've clicked/release mouse button """ pos = event.pos() obj = self.itemAt(pos) return obj def edgeDragStart(self, item): self.drag_start_socket = item.socket self.drag_edge = Edge(self.grScene.scene, item.socket, None, EDGE_TYPE_BEZIER) def edgeDragEnd(self, item): """ return True if skip the rest of the code """ self.mode = MODE_NOOP self.drag_edge.remove() self.drag_edge = None if type(item) is QDMGraphicsSocket: if item.socket != self.drag_start_socket: # if we released dragging on a socket (other then the beginning socket) # we wanna keep all the edges comming from target socket if not item.socket.is_multi_edges: item.socket.removeAllEdges() # we wanna keep all the edges comming from start socket if not self.drag_start_socket.is_multi_edges: self.drag_start_socket.removeAllEdges() new_edge = Edge(self.grScene.scene, self.drag_start_socket, item.socket, edge_type=EDGE_TYPE_BEZIER) self.grScene.scene.history.storeHistory( "Created new edge by dragging", setModified=True) return True return False def distanceBetweenClickAndReleaseIsOff(self, event): """ measures if we are too far from the last LMB click scene position """ 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): # 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)