def deserialize_from_clipboard(self, data): hashmap = {} view = self.scene.gr_scene.views()[0] mouse_scene_pos = view.last_scene_mouse_position minx, miny, maxx, 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()) offset_x = mouse_scene_pos.x() - bbox_center_x offset_y = mouse_scene_pos.y() - bbox_center_y for node_data in data['nodes']: new_node = Node(self.scene) new_node.deserialize(node_data, hashmap, restore_id=False) pos = new_node.pos new_node.set_pos(pos.x() + offset_x, pos.y() + offset_y) 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.history.store_history('Pasted elements in center', set_modified=True)
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 deserialize(self, data, hashmap=None, restore_id=True): self.clear() hashmap = {} if restore_id: self.id = data['id'] for node_data in data['nodes']: Node(self).deserialize(node_data, hashmap, restore_id) for edge_data in data['edges']: Edge(self).deserialize(edge_data, hashmap, restore_id) return True
def addNodes(self): script = os.path.join("resource", "script.tagui") with open(script, 'r') as f: self.file_text = f.read() lines = self.file_text.splitlines() line_number = 0 x = -350 y = -250 nodelist = [] del_key = [ 'py begin', 'py finish', 'echo readmsg', 'read_info(readmsg)', 'echo py_result', 'print(datamsg)' ] while "" in lines: lines.remove("") for line in lines: if line not in del_key and 'py_step' not in line: line = line[0:25] number = line_number + 1 node = str("node") + str(line_number) if line_number == 0: node = Node(self.scene, line, outputs=[1]) elif line_number == len(lines) - 1: node = Node(self.scene, line, inputs=[0]) else: node = Node(self.scene, line, inputs=[0], outputs=[1]) nodelist.append(node) node.setPos(x, y) x = x + 250 y = y + 150 if line_number > 0: edge = str("edge") + str(line_number) edge = Edge(self.scene, nodelist[line_number - 1].outputs[0], nodelist[line_number].inputs[0], edge_type=EDGE_TYPE_BEZIER) line_number = line_number + 1
def edge_drag_end(self, item): self.mode = MODE_NOOP self.drag_edge.remove() self.drag_edge = None if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: # if item.socket.has_edge(): # item.socket.edge.remove() # for edge in item.socket.edges: # edge.remove() if not item.socket.is_multi_edges: item.socket.remove_all_edges() if not self.drag_start_socket.is_multi_edges: self.drag_start_socket.remove_all_edges() # if self.previous_edge is not None: # self.previous_edge.remove() # self.drag_edge.start_socket = self.drag_start_socket # self.drag_edge.end_socket = item.socket # self.drag_edge.start_socket.add_edge(self.drag_edge) # self.drag_edge.end_socket.add_edge(self.drag_edge) # self.drag_edge.update_positions() new_edge = Edge(self.gr_scene.scene, self.drag_start_socket, item.socket, EDGE_TYPE_BEZIER) self.gr_scene.scene.history.store_history( 'Create new edge by dragging', set_modified=True) return True # if self.previous_edge is not None: # self.previous_edge.start_socket.edge = self.previous_edge return False
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.zoomInFactor = 1.25 self.zoomClamp = True 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) 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): # 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 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 super().mousePressEvent(event) def leftMouseButtonRelease(self, event): # get item which we release mouse button on item = self.getItemAtClick(event) # logic if self.mode == MODE_EDGE_DRAG: if self.distanceBetweenClickAndReleaseIsOff(event): res = self.edgeDragEnd(item) if res: 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() super().mouseMoveEvent(event) 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 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) # Added def deleteSelected(self): print("here") for item in self.grScene.selectedItems(): if isinstance(item, QDMGraphicsEdge): item.edge.remove() elif hasattr(item, 'node'): item.node.remove()
class QDMGraphicsView(QGraphicsView): scenePosChanged = Signal(int, int) def __init__(self, gr_scene, parent=None): super(QDMGraphicsView, self).__init__(parent) self.gr_scene = gr_scene self.init_ui() self.setScene(self.gr_scene) self.mode = MODE_NOOP self.editing_flag = False self.rubber_band_dragging_rectangle = False self.zoom_in_factor = 1.25 self.zoom_clamp = True self.zoom = 10 self.zoom_step = 1 self.zoom_range = [0, 10] self.cutline = QDMCutLine() self.gr_scene.addItem(self.cutline) 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(QDMGraphicsView.RubberBandDrag) def mousePressEvent(self, event): if event.button() == Qt.MiddleButton: # 设置中间平移背景 self.middle_mouse_button_press(event) elif event.button() == Qt.LeftButton: self.left_mouse_button_press(event) elif event.button() == Qt.RightButton: self.right_mouse_button_press(event) else: super(QDMGraphicsView, self).mousePressEvent(event) def mouseReleaseEvent(self, event): if event.button() == Qt.MiddleButton: self.middle_mouse_button_release(event) elif event.button() == Qt.LeftButton: self.left_mouse_button_release(event) elif event.button() == Qt.RightButton: self.right_mouse_button_release(event) else: super(QDMGraphicsView, self).mouseReleaseEvent(event) def middle_mouse_button_press(self, event): release_event = QMouseEvent(QEvent.MouseButtonRelease, event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers()) super(QDMGraphicsView, self).mouseReleaseEvent(release_event) self.setDragMode(QGraphicsView.ScrollHandDrag) fake_event = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() | Qt.LeftButton, event.modifiers()) super(QDMGraphicsView, self).mousePressEvent(fake_event) def middle_mouse_button_release(self, event): fake_event = QMouseEvent(event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() & ~Qt.LeftButton, event.modifiers()) super(QDMGraphicsView, self).mouseReleaseEvent(fake_event) self.setDragMode(QGraphicsView.RubberBandDrag) def left_mouse_button_press(self, event): item = self.get_item_at_click(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() fake_event = QMouseEvent( QEvent.MouseButtonPress, event.localPos(), event.screenPos(), Qt.LeftButton, event.buttons() | Qt.LeftButton, event.modifiers() | Qt.ControlModifier) super(QDMGraphicsView, self).mousePressEvent(fake_event) return if isinstance(item, QDMGraphicsSocket): if self.mode == MODE_NOOP: self.mode = MODE_EDGE_DRAG self.edge_drag_start(item) return if self.mode == MODE_EDGE_DRAG: res = self.edge_drag_end(item) if res: return if item is None: if event.modifiers() & Qt.ControlModifier: self.mode = MODE_EDGE_CUT fake_event = QMouseEvent(QEvent.MouseButtonRelease, event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers()) super(QDMGraphicsView, self).mousePressEvent(fake_event) QApplication.setOverrideCursor(Qt.CrossCursor) self.setDragMode(QGraphicsView.NoDrag) return else: self.rubber_band_dragging_rectangle = True super(QDMGraphicsView, self).mousePressEvent(event) def edge_drag_start(self, item): print('start dragging edge') self.drag_start_socket = item.socket self.drag_edge = Edge(self.gr_scene.scene, item.socket, None, EDGE_TYPE_BEZIER) print(self.drag_edge) def edge_drag_end(self, item): self.mode = MODE_NOOP self.drag_edge.remove() self.drag_edge = None if isinstance(item, QDMGraphicsSocket): if item.socket != self.drag_start_socket: # if item.socket.has_edge(): # item.socket.edge.remove() # for edge in item.socket.edges: # edge.remove() if not item.socket.is_multi_edges: item.socket.remove_all_edges() if not self.drag_start_socket.is_multi_edges: self.drag_start_socket.remove_all_edges() # if self.previous_edge is not None: # self.previous_edge.remove() # self.drag_edge.start_socket = self.drag_start_socket # self.drag_edge.end_socket = item.socket # self.drag_edge.start_socket.add_edge(self.drag_edge) # self.drag_edge.end_socket.add_edge(self.drag_edge) # self.drag_edge.update_positions() new_edge = Edge(self.gr_scene.scene, self.drag_start_socket, item.socket, EDGE_TYPE_BEZIER) self.gr_scene.scene.history.store_history( 'Create new edge by dragging', set_modified=True) return True # if self.previous_edge is not None: # self.previous_edge.start_socket.edge = self.previous_edge return False def distance_between_click_and_release_is_off(self, event): new_lmb_release_scene_pos = self.mapToScene(event.pos()) # fixme 这里是不是应该可以直接用press item和release item对比 # fixme 而且socket是不是应该分类两种类型(input output),input类型的不能连input,output类型的不能连output 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 left_mouse_button_release(self, event): item = self.get_item_at_click(event) # 多选设置 if hasattr(item, 'node') or isinstance( item, QDMGraphicsEdge) or item is None: if event.modifiers() & Qt.ShiftModifier: event.ignore() fake_event = QMouseEvent( event.type(), event.localPos(), event.screenPos(), Qt.LeftButton, Qt.NoButton, event.modifiers() | Qt.ControlModifier) super(QDMGraphicsView, self).mouseReleaseEvent(fake_event) return if self.mode == MODE_EDGE_DRAG: if self.distance_between_click_and_release_is_off(event): res = self.edge_drag_end(item) if res: return if self.mode == MODE_EDGE_CUT: self.cut_intersecting_edges() self.cutline.line_points = [] self.cutline.update() QApplication.setOverrideCursor(Qt.ArrowCursor) self.mode = MODE_NOOP self.setDragMode(QGraphicsView.RubberBandDrag) return # if self.dragMode() == QGraphicsView.RubberBandDrag: if self.rubber_band_dragging_rectangle: self.rubber_band_draggin_rectangle = False # self.gr_scene.scene.history.store_history('Selection Changed') current_selected_items = self.gr_scene.selectedItems() if current_selected_items != self.gr_scene.scene._last_selected_items: if not current_selected_items: self.gr_scene.item_deselected.emit() else: self.gr_scene.item_selected.emit() self.gr_scene.scene._last_selected_items = current_selected_items return if item is None: self.gr_scene.item_deselected.emit() super(QDMGraphicsView, self).mouseReleaseEvent(event) def cut_intersecting_edges(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.gr_scene.scene.edges: if edge.gr_edge.intersects_with(p1, p2): edge.remove() self.gr_scene.scene.history.store_history('Delete Cutted edges', set_modified=True) def right_mouse_button_press(self, event): super(QDMGraphicsView, self).mousePressEvent(event) def right_mouse_button_release(self, event): return super(QDMGraphicsView, self).mouseReleaseEvent(event) def get_item_at_click(self, event): pos = event.pos() obj = self.itemAt(pos) return obj def keyPressEvent(self, event): # if event.key() == Qt.Key_Delete: # if not self.editing_flag: # self.delete_selected() # else: # super(QDMGraphicsView, self).keyPressEvent(event) # elif event.key() == Qt.Key_S and event.modifiers() & Qt.ControlModifier: # self.gr_scene.scene.save_to_file('graph.json.txt') # # elif event.key() == Qt.Key_L and event.modifiers() & Qt.ControlModifier: # self.gr_scene.scene.load_from_file('graph.json.txt') # # elif event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier and not event.modifiers() & Qt.ShiftModifier: # self.gr_scene.scene.history.undo() # # elif event.key() == Qt.Key_Z and event.modifiers() & Qt.ControlModifier and event.modifiers() & Qt.ControlModifier: # self.gr_scene.scene.history.redo() # if event.key() == Qt.Key_H: # print(self.gr_scene.scene.history.history_stack) # # else: super(QDMGraphicsView, self).keyPressEvent(event) def delete_selected(self): for item in self.gr_scene.selectedItems(): if isinstance(item, QDMGraphicsEdge): item.edge.remove() elif hasattr(item, 'node'): item.node.remove() self.gr_scene.scene.history.store_history('Delete Selected', set_modified=True) def wheelEvent(self, event): """设置滚轮缩放""" zoom_out_factor = 1 / self.zoom_in_factor if event.angleDelta().y() > 0: zoom_factor = self.zoom_in_factor self.zoom += self.zoom_step else: zoom_factor = zoom_out_factor self.zoom -= self.zoom_step clamped = False if self.zoom < self.zoom_range[0]: self.zoom, clamped = self.zoom_range[0], True if self.zoom > self.zoom_range[-1]: self.zoom, clamped = self.zoom_range[-1], True if not clamped or not self.zoom_clamp: self.scale(zoom_factor, zoom_factor) def mouseMoveEvent(self, event): if self.mode == MODE_EDGE_DRAG: pos = self.mapToScene(event.pos()) self.drag_edge.gr_edge.set_destination(pos.x(), pos.y()) self.drag_edge.gr_edge.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(QDMGraphicsView, self).mouseMoveEvent(event) def debug_modifiers(self, event): out = 'MODES: ' if event.modifiers() & Qt.ShiftModifier: out += 'SHIFT ' if event.modifiers() & Qt.ControlModifier: out += 'CTRL ' if event.modifiers() & Qt.AltModifier: out += 'SHIFT ' return out
def edge_drag_start(self, item): print('start dragging edge') self.drag_start_socket = item.socket self.drag_edge = Edge(self.gr_scene.scene, item.socket, None, EDGE_TYPE_BEZIER) print(self.drag_edge)
import os from PyQt5.QtWidgets import QMdiArea, QWidget, QListWidget, QDockWidget, QAction, QMessageBox, QFileDialog from PyQt5.QtGui import * from PyQt5.QtCore import QSignalMapper, Qt, QFileInfo from node_editor.utils import loadStylessheets from node_editor.node_editor_window import NodeEditorWindow from node_editor.node_editor_widget import NodeEditorWidget from node_editor.utils import dumpException, pp from .calc_sub_window import CalculatorSubWindow from .calc_drag_listbox import QNEDragListbox from .calc_conf import CALC_NODES from node_editor.node_edge import Edge from node_editor.node_edge_validators import * Edge.registerEdgeValidator(edge_validator_debug) Edge.registerEdgeValidator(edge_cannot_connect_two_outputs_or_two_inputs) Edge.registerEdgeValidator(edge_cannot_connect_input_and_output_of_same_node) # images for the dark skin import examples.example_calculator.qss.nodeeditor_dark_resources DEBUG = False class CalculatorWindow(NodeEditorWindow): """Class representing the MainWindow of the application. Instance Attributes: name_company and name_product - used to register the settings """ def initUI(self):