class Editor(QtCore.QObject): """ Editor to handles events""" def __init__(self, parent): super(Editor, self).__init__(parent) self.conn = None self.move = None self.scene = None self.status = parent.status self.movBlk = False self.event = None self.connFromNode = False self.menuIOBlk = QtWidgets.QMenu() #parBlkAction = self.menuIOBlk.addAction('Block I/Os') paramsBlkAction = self.menuIOBlk.addAction('Parameters') propertiesBlkAction = self.menuIOBlk.addAction('Properties') flpBlkAction = self.menuIOBlk.addAction('Flip') nameBlkAction = self.menuIOBlk.addAction('Change Name') cloneBlkAction = self.menuIOBlk.addAction('Clone Block') deleteBlkAction = self.menuIOBlk.addAction('Delete Block') # self.netlistMenu = QtWidgets.QMenu('Netlist') # self.menuIOBlk.addMenu(self.netlistMenu) # netListAction = self.menuIOBlk.addAction('Netlist') #parBlkAction.triggered.connect(self.parBlock) flpBlkAction.triggered.connect(self.flipBlock) nameBlkAction.triggered.connect(self.nameBlock) paramsBlkAction.triggered.connect(self.blockParams) propertiesBlkAction.triggered.connect(self.blockProperties) cloneBlkAction.triggered.connect(self.cloneBlock) deleteBlkAction.triggered.connect(self.deleteBlock) # netListAction.triggered.connect(self.netList) self.subMenuPort = QtWidgets.QMenu() portEditAction = self.subMenuPort.addAction('Edit') portFlipAction = self.subMenuPort.addAction('Flip') portDelAction = self.subMenuPort.addAction('Delete') portTypeAction = self.subMenuPort.addAction('Add/Edit signal type') portEditAction.triggered.connect(self.portEdit) portFlipAction.triggered.connect(self.flipBlock) portDelAction.triggered.connect(self.portDelete) portTypeAction.triggered.connect(self.portAddType) self.subMenuConn = QtWidgets.QMenu() connDelAction = self.subMenuConn.addAction('Delete connection') connInsAction = self.subMenuConn.addAction('Insert node') connLabelAction = self.subMenuConn.addAction('Add/Edit label') connDelAction.triggered.connect(self.deleteConn) connInsAction.triggered.connect(self.insConn) connLabelAction.triggered.connect(self.addConnLabel) self.subMenuText = QtWidgets.QMenu() textCloneAction = self.subMenuText.addAction('Clone') textCloneAction.triggered.connect(self.cloneText) self.subMenuNothing = QtWidgets.QMenu( ) # right mouse menu when nothing on pos nodeInsAction = self.subMenuNothing.addAction('Insert node') nodeInsAction.triggered.connect(self.createNode) def addConnLabel(self): conn = self.scene.item if conn.label: dialog = textLineDialog('Label: ', content=conn.label.text()) else: dialog = textLineDialog('Label: ') ret = dialog.getLabel() if ret: if conn.label: conn.label.setText(ret) else: conn.label = textItem(ret, anchor=3, parent=conn) conn.label.setPos(conn.pos2.x(), conn.pos2.y()) def cloneBlock(self): item = self.scene.item b = item.clone(QtCore.QPointF(100, 100)) # b.name = self.scene.setUniqueName(b) b.setup() def cloneText(self): item = self.scene.item c = Comment('') c.fromData(item.toData()) c.setPos(c.pos() + QtCore.QPointF(100, 100)) self.scene.addItem(c) def deleteBlock(self): item = self.scene.item item.remove() def portDelete(self): self.scene.item.remove() def deleteConn(self): self.scene.item.remove() def flipBlock(self): item = self.scene.item item.flip = not item.flip item.setFlip() def insConn(self): if not self.conn: self.insertConnection(self.event) def install(self, scene): scene.installEventFilter(self) self.scene = scene def itemAt(self, pos, exclude=[], single=True): items = [] radius = 4 * DB / self.parent().view.currentscale allitems = self.scene.items( QtCore.QRectF(pos - QtCore.QPointF(radius, radius), QtCore.QSizeF(2 * radius, 2 * radius))) for item in allitems: if isinstance(item, QtWidgets.QGraphicsItem): items.append(item) for testfunc in exclude: if testfunc(item): items.pop() # remove break if single and items: return items[0] return items def sortedItemsAt(self, pos): blocks, ports, nodes, connections, labels = [], [], [], [], [] radius = 4 * DB / self.parent().view.currentscale allitems = self.scene.items( QtCore.QRectF(pos - QtCore.QPointF(radius, radius), QtCore.QSizeF(2 * radius, 2 * radius))) for item in allitems: for cat, test in [(blocks, isBlock), (nodes, isNode), (connections, isConnection), (labels, isTextItem)]: if test(item): cat.append(item) elif isPort(item): # all ports except nodes ports.append(item) return blocks, ports, nodes, connections, labels def ConnectionAt(self, pos): return self.itemAt(pos, exclude=[isNode, isPort, isBlock], single=True) def nameBlock(self): item = self.scene.item dialog = BlockName_Dialog(self.scene.mainw) dialog.name.setText(item.name) res = dialog.exec_() if res == 1: # item.name = str(dialog.name.text()) item.setLabel(dialog.name.text()) # item.label.setNormal() # w = item.label.boundingRect().width() # item.label.setPos(-w/2, item.h/2+5) self.scene.isInsConn = False self.scene.isConnecting = True def netList(self, type): try: item = self.scene.item fname = 'libraries.library_{}.{}'.format(item.libname, item.blockname) exec('import ' + fname) func = eval(fname + '.netlist' + type) func(item) except: if type == 'myhdl': item = self.scene.item if item.hasDiagram(): views = libraries.getViews(item.blockname, item.libname) fname = 'libraries/library_{}/{}_myhdl.py'.format( item.libname, item.blockname) overwrite = True if 'myhdl' in views: dialog = overWriteNetlist() ret = dialog.exec_() if ret == 0: fname = views['myhdl'] else: overwrite = False if overwrite: import supsisim.netlist content = supsisim.netlist.netlistMyHdl( item.blockname, item.libname, item.properties) if content == False: error('More than 1 label on signal') return f = open(fname, 'w+') f.write(content) f.close() if not 'myhdl' in views: self.addView(item.blockname, item.libname, 'myhdl') self.parent().library.openView('myhdl', item) else: error("file doesn't have a diagram") else: error('netlist not found') def parBlock(self): self.scene.mainw.parBlock() def portAddType(self, event): item = self.scene.item if not isPort(item): error('use on nodes/pins') return if item.signalType: dialog = textLineDialog('Signal type: ', 'Signal type', item.signalType.text()) else: dialog = textLineDialog('Signal type: ', 'Signal type') ret = dialog.getLabel() if ret: item.signalType = textItem(ret, anchor=8, parent=item) item.signalType.setBrush(colors['signalType']) font = item.signalType.font() font.setItalic(True) item.signalType.setFont(font) # item.signalType.setPos(item.pos2.x(),item.pos2.y()) def portEdit(self): item = self.scene.item if not isPort(item): error('not a pin') dd = OrderedDict() dd['Pin_label'] = item.label.text() if item.label else '' options = 'ipin opin iopin node'.split() dd['Pin_type'] = (item.porttype, options) properties = item.properties title = 'Edit Node' if isNode(item) else 'Edit Pin' dialog = propertiesDialog(self.scene.mainw, dd, properties, title=title) dd = dialog.getRet() if dd: item.setType(dd.pop('Pin_type')[0]) item.setLabel(dd.pop('Pin_label')) if dd: item.properties = dd item.setup() def blockProperties(self): item = self.scene.item dialog = propertiesDialog(self.scene.mainw, item.properties, addButton=False) dd = dialog.getRet() if dd: item.properties = dd self.recreateBlock(item) def recreateBlock(self, item, scene=None): if scene is None: scene = self.scene pp = dict() for port in item.ports(): portname = port.label.text() pp[portname] = [] for c in port.connections: if c.port[0] == port and c.port[1] != port: pp[portname].append((0, c.port[1])) elif c.port[0] != port and c.port[1] == port: pp[portname].append((1, c.port[0])) data = item.toData() # store blk item.remove() # also removes connections # recreate with new parameters par = item.parameters prop = item.properties b = getBlock(data['libname'], data['blockname'], scene=scene, param=par, properties=prop, name=data['blockname']) b.fromData(data) b.setLabel() # restore connections to block for port in b.ports(): portname = port.label.text() if portname in pp: for (ix, p) in pp[portname]: if ix == 0: c = Connection(None, scene, port) c.attach(1, p) else: c = Connection(None, scene, p) c.attach(1, port) c.update_path() def blockParams(self): item = self.scene.item dialog = propertiesDialog(self.scene.mainw, item.parameters, addButton=False) ret = dialog.getRet() if ret: # store connections to ports item.parameters = ret # apply new parameters (no effect) self.recreateBlock(item) def insertConnection(self, event): pos = gridPos(event.scenePos()) item = self.ConnectionAt(pos) if item and isConnection(item): self.connectionInsertNode(item, pos) def createNode(self, pos=None): if not isinstance(pos, (QtCore.QPoint, QtCore.QPointF)): pos = gridPos(self.event.scenePos()) newnode = Port(None, self.scene, porttype='node') newnode.setPos(pos) return newnode def connectionStart(self, p): self.conn = Connection(None, self.scene, p) def connectionNext(self, pos): newnode = self.createNode(pos) self.conn.update_path(newnode) # last point self.conn = Connection(None, self.scene, newnode) #new Connection def connectionFinish(self, port): self.conn.update_path(port) self.conn = None self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) self.scene.update() def connectionInsertNode(self, conn, pos): newnode = self.createNode(pos) p = conn.port[1] conn.attach(1, newnode) conn.update_path() newconn = Connection(None, self.scene) newconn.attach(0, newnode) newconn.attach(1, p) newconn.update_path() return newconn def addNetlistMenu(self): blockname = self.scene.item.blockname libname = self.scene.item.libname fname = 'libraries.library_{}.{}'.format(libname, blockname) exec('import ' + fname) in globals(), locals() reload(eval(fname)) attributes = dir(eval(fname)) netlistFunctions = [] for attribute in attributes: if attribute.startswith('netlist'): netlistFunctions.append(attribute.replace('netlist', '')) if not 'myhdl' in netlistFunctions: netlistFunctions.append('myhdl') for type in netlistFunctions: def getFunction(type): def netlistAction(): self.netList(type) return netlistAction netlistAction = getFunction(type) action = self.netlistMenu.addAction(type + " netlist") action.triggered.connect(netlistAction) def mouseDoubleClicked(self, obj, event): pos = gridPos(event.scenePos()) item = self.itemAt(pos, exclude=[isConnection]) if isBlock(item): if 'diagram' in item.getViews(): self.scene.mainw.descend(item) else: views = item.getViews() fname = None if len(views) == 1: viewtype, fname = views.items()[0] elif len(views) > 1: d = selectionDialog(views.keys(), title='Select view') ret = d.getRet() if ret: fname = views[ret] if fname: for tp, (editor, extension) in viewTypes.items(): if fname.endswith(extension): cmd = editor break if cmd: os.system(cmd + " " + fname) else: error( "{} is unkown type\nplease see viewTypes in menu Settings -> Edit settings" .format(source)) return elif isPort(item, tp='ipin opin iopin node'.split()): self.scene.item = item self.portEdit() if self.conn: self.conn.remove() self.conn = None self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) elif isTextItem(item): font, ok = QtWidgets.QFontDialog.getFont(item.font()) if ok: item.setFont(font) def mouseLeftButtonPressed(self, obj, event): pos = gridPos(event.scenePos()) blocks, ports, nodes, connections, labels = self.sortedItemsAt(pos) if self.conn: # connection mode while ports: # try to find in-port port = ports.pop() if isInPort(port): self.connectionFinish(port) return while nodes: # else try to find node node = nodes.pop() self.connectionFinish(node) return # while connections: # conn = connections.pop() # if conn != self.conn: # node = self.connectionInsertNode(conn, pos) # self.connectionFinish(node) # return self.connectionNext(pos) else: # not in connection mode while ports: port = ports.pop() if isOutPort(port) and not port.connections: # Try to create new connection starting at selected output port self.connectionStart(port) return while nodes: node = nodes.pop() if node in self.scene.selectedItems(): node.setFlag(node.ItemIsMovable) else: #starting the connection self.connectionStart(node) self.connFromNode = True def moveMouse(self, obj, event): if self.connFromNode: return pos = gridPos(event.scenePos()) item = self.itemAt(pos) if self.conn: self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) if item and isInPort(item) or isNode(item): if len(item.connections) == 0: self.scene.mainw.view.setCursor(QtCore.Qt.CrossCursor) else: self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) elif item and isNode(item): if len(item.connections) == 0: self.scene.mainw.view.setCursor(QtCore.Qt.CrossCursor) else: self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) self.conn.update_path(pos) #return True elif item: if isBlock(item): items = self.scene.selectedItems() for item in items: if isBlock(item): for thing in item.childItems(): if isPort(thing, 'block'): for conn in thing.connections: conn.update_path() #elif isConnection(item): #self.scene.mainw.view.setCursor(QtCore.Qt.PointingHandCursor) elif isOutPort(item): self.scene.mainw.view.setCursor(QtCore.Qt.CrossCursor) elif isNode(item): if item in self.scene.selectedItems(): self.scene.mainw.view.setCursor( QtCore.Qt.PointingHandCursor) else: self.scene.mainw.view.setCursor(QtCore.Qt.CrossCursor) else: self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) def mouseReleased(self, obj, event): self.connFromNode = False items = self.scene.selectedItems() for item in items: if isBlock(item) or isPort(item) or isComment(item): item.setPos(gridPos(item.pos())) for thing in item.childItems(): if isPort(thing, 'block'): for conn in thing.connections: conn.update_path() def mouseRightButtonPressed(self, obj, event): if self.conn == None: b, p, c, t = [], [], [], [] for i in self.itemAt(event.scenePos(), single=False): if isBlock(i): b.append(i) elif isPort(i): p.append(i) elif isConnection(i): c.append(i) elif isComment(i): t.append(i) item = p.pop() if p else b.pop() if b else c.pop() if c else t.pop( ) if t else None if isBlock(item): self.scene.item = item # self.netlistMenu.clear() # self.addNetlistMenu() self.menuIOBlk.exec_(event.screenPos()) elif isPort(item, ['node', 'ipin', 'opin', 'iopin']): self.scene.item = item self.subMenuPort.exec_(event.screenPos()) elif isConnection(item): self.scene.item = item self.event = event self.subMenuConn.exec_(event.screenPos()) elif isComment(item): self.scene.item = item self.event = event self.subMenuText.exec_(event.screenPos()) else: self.event = event self.subMenuNothing.exec_(event.screenPos()) def eventFilter(self, obj, event): if event.type() == QtCore.QEvent.GraphicsSceneMouseMove: self.moveMouse(obj, event) self.status.showMessage('{:.1f}, {:.1f}'.format( event.scenePos().x(), event.scenePos().y())) elif event.type() == QtCore.QEvent.GraphicsSceneMousePress: if event.button() == QtCore.Qt.LeftButton: self.mouseLeftButtonPressed(obj, event) elif event.button() == QtCore.Qt.RightButton: self.mouseRightButtonPressed(obj, event) elif event.type() == QtCore.QEvent.GraphicsSceneMouseRelease: self.mouseReleased(obj, event) elif event.type() == QtCore.QEvent.GraphicsSceneMouseDoubleClick: self.mouseDoubleClicked(obj, event) if event.type() == QtCore.QEvent.KeyPress: if event.key() == QtCore.Qt.Key_Delete: items = self.scene.selectedItems() for item in items: try: item.remove() except: try: if isComment(item): self.scene.removeItem(item) except: pass if self.conn: self.conn.remove() #self.conn = None if event.key() == QtCore.Qt.Key_Escape: if self.conn != None: self.conn.remove() self.conn = None self.scene.mainw.view.setCursor(QtCore.Qt.ArrowCursor) if event.key() == QtCore.Qt.Key_Control: self.scene.mainw.view.setDragMode( QtWidgets.QGraphicsView.ScrollHandDrag) if event.type() == QtCore.QEvent.KeyRelease and event.key( ) == QtCore.Qt.Key_Control: self.scene.mainw.view.setDragMode( QtWidgets.QGraphicsView.RubberBandDrag) return super(Editor, self).eventFilter(obj, event)
class Editor(QObject): """ Editor to handles events""" def __init__(self, parent): super(Editor, self).__init__(parent) self.mainw = parent self.conn = None self.scene = None self.movBlk = False self.event = None self.state = IDLE self.menuIOBlk = QMenu() parBlkAction = self.menuIOBlk.addAction('Block I/Os') paramsBlkAction = self.menuIOBlk.addAction('Block Parameters') flpBlkAction = self.menuIOBlk.addAction('Flip Block') nameBlkAction = self.menuIOBlk.addAction('Change Name') cloneBlkAction = self.menuIOBlk.addAction('Clone Block') copyBlkAction = self.menuIOBlk.addAction('Copy Block') deleteBlkAction = self.menuIOBlk.addAction('Delete Block') parBlkAction.triggered.connect(self.parBlock) flpBlkAction.triggered.connect(self.flipBlock) nameBlkAction.triggered.connect(self.nameBlock) paramsBlkAction.triggered.connect(self.paramsBlock) cloneBlkAction.triggered.connect(self.cloneBlock) copyBlkAction.triggered.connect(self.copyBlock) deleteBlkAction.triggered.connect(self.deleteBlock) self.subMenuConn = QMenu() connAddAction = self.subMenuConn.addAction('Add connection') connDelAction = self.subMenuConn.addAction('Delete connection') connAddAction.triggered.connect(self.addConn) connDelAction.triggered.connect(self.deleteConn) self.subMenuEditor = QMenu() pasteAction = self.subMenuEditor.addAction('Paste') pasteAction.triggered.connect(self.pasteBlock) # Matrix has two index [state, event] # States: # IDLE 0 # LEFTMOUSEPRESSED 1 # ITEMSELECTED 2 # DRAWFROMOUTPORT 3 # MOVECONN 4 # Events # MOUSEMOVE 0 # LEFTMOUSEPRESSED 1 # RIGHTMOUSEPRESSED 2 # MOUSERELEASED 3 # MOUSEDOUBLECLICK 4 # KEY_DEL 5 # KEY_ESC 6 self.Fun = [[ self.P00, self.P01, self.P02, self.PDM, self.P03, self.P04, self.P05 ], [ self.P06, self.PDM, self.PDM, self.P07, self.PDM, self.PDM, self.PDM ], [ self.P11, self.P01, self.P02, self.PDM, self.P03, self.P04, self.P05 ], [ self.P10, self.P08, self.P09, self.PDM, self.PDM, self.PDM, self.P09 ], [ self.P12, self.PDM, self.PDM, self.P13, self.PDM, self.PDM, self.PDM ]] def install(self, scene): scene.installEventFilter(self) self.scene = scene def parBlock(self): self.scene.DgmToUndo() ok = self.scene.mainw.parBlock() if not ok: self.scene.clearLastUndo() def flipBlock(self): self.scene.DgmToUndo() item = self.scene.item item.flip = not item.flip item.setFlip() def nameBlock(self): self.scene.DgmToUndo() item = self.scene.item dialog = BlockName_Dialog(self.scene.mainw) dialog.name.setText(item.name) res = dialog.exec_() if res == 1: item.name = str(dialog.name.text()) item.label.setPlainText(item.name) w = item.label.boundingRect().width() item.label.setPos(-w / 2, item.h / 2 + 5) else: self.scene.clearLastUndo() def paramsBlock(self): self.scene.DgmToUndo() item = self.scene.item params = item.params.split('|') blk = params[0] blk = blk.replace('Blk', 'Dlg') streV = 'import ' + blk + ' as dlg' try: exec(streV) name = item.name.replace(' ', '_') cmd = 'dlg.' + blk + '(' + str(item.inp) + ',' + str( item.outp) + ',"' + item.params + '"' + ',"' + name + '")' pars = eval(cmd) except: pars = pDlg.parsDialog(item.params) if pars != item.params: item.params = pars else: self.scene.clearLastUndo() def cloneBlock(self): self.scene.DgmToUndo() item = self.scene.item item.clone(QPointF(DP, DP)) def copyBlock(self): root = etree.Element('root') item = self.scene.item item.save(root) msg = etree.tostring(root, pretty_print=True) clipboard = QApplication.clipboard() mimeData = QMimeData() mimeData.setText(msg.decode()) clipboard.setMimeData(mimeData) def pasteBlock(self): self.scene.DgmToUndo() try: msg = QApplication.clipboard().text() root = etree.fromstring(msg) blocks = root.findall('block') meanPosX = 0.0 meanPosY = 0.0 numBlk = 0 for item in blocks: pBlkX = float(item.findtext('posX')) pBlkY = float(item.findtext('posY')) meanPosX = meanPosX + pBlkX meanPosY = meanPosY + pBlkY numBlk += 1 deltaPosX = self.scene.evpos.x() - meanPosX / numBlk deltaPosY = self.scene.evpos.y() - meanPosY / numBlk blocks = root.findall('block') for item in blocks: self.scene.loadBlock(item, deltaPosX, deltaPosY) connections = root.findall('connection') for item in connections: self.scene.loadConn(item, deltaPosX, deltaPosY) try: self.editor.redrawNodes() except: pass except: pass def deleteBlock(self): self.scene.DgmToUndo() item = self.scene.item item.remove() self.removeNodes() self.redrawNodes() def connectInPort(self, item): if len(item.connections) == 0: self.conn.port2 = item self.conn.pos2 = item.scenePos() self.conn.port1.connections.append(self.conn) self.conn.port2.connections.append(self.conn) if len(self.conn.connPoints) == 0: pos1 = QPointF((self.conn.pos2.x() + self.conn.pos1.x()) / 2, self.conn.pos1.y()) pos2 = QPointF((self.conn.pos2.x() + self.conn.pos1.x()) / 2, self.conn.pos2.y()) self.conn.connPoints.append(self.gridPos(pos1)) self.conn.connPoints.append(self.gridPos(pos2)) else: pt = self.conn.connPoints[-1] pos1 = QPointF(pt.x(), self.conn.pos2.y()) self.conn.connPoints.append(self.gridPos(pos1)) self.conn.clean() self.conn.update_path() self.conn = None def deleteConn(self): self.scene.DgmToUndo() self.scene.item.remove() self.removeNodes() self.redrawNodes() def find_exact_pos(self, c, pos): # Find exact point on connection c points = [c.pos1] for el in c.connPoints: points.append(el) points.append(c.pos2) N = len(points) for n in range(0, N - 1): p1 = points[n] p2 = points[n + 1] rect = QRectF(p1 - QPointF(DB, DB), p2 + QPointF(DB, DB)) if rect.contains(pos): if p1.x() == p2.x(): pos.setX(p1.x()) if p1.y() == p2.y(): pos.setY(p1.y()) return n, pos def addConn(self): self.scene.DgmToUndo() c = self.scene.item posMouse = self.gridPos(self.scene.evpos) self.conn = Connection(None, self.scene) self.conn.port1 = c.port1 self.conn.pos1 = c.pos1 try: npos, pos = self.find_exact_pos(c, posMouse) except: return N = len(c.connPoints) if npos == 0: pos = posMouse npt = 0 elif npos == N: pos = posMouse npt = N else: npt = npos for n in range(0, npt): self.conn.connPoints.append(c.connPoints[n]) self.conn.connPoints.append(pos) self.state = DRAWFROMOUTPORT def redrawSelectedItems(self): for item in self.scene.selectedItems(): if isinstance(item, Block): item.setPos(item.scenePos()) for el in item.childItems(): try: for conn in el.connections: conn.update_pos_from_ports() except: pass def clean_points(self, pts, m): N = len(pts) remPt = [] for n in range(1, N - 1): if m == 'x': if pts[n - 1].x() == pts[n].x() == pts[n + 1].x(): remPt.append(pts[n]) elif m == 'y': if pts[n - 1].y() == pts[n].y() == pts[n + 1].y(): remPt.append(pts[n]) for el in remPt: pts.remove(el) return pts def ptInLine(self, pt, p1, p2): rect = QRectF(p1 - QPointF(0.5, 0.5), p2 + QPointF(0.5, 0.5)) if rect.contains(pt): return True else: return False def setNode(self, pts1, pts2): pts1 = self.clean_points(pts1, 'x') pts1 = self.clean_points(pts1, 'y') pts2 = self.clean_points(pts2, 'x') pts2 = self.clean_points(pts2, 'y') n = 0 N = min(len(pts1), len(pts2)) try: while pts1[n] == pts2[n] and n < N: n += 1 p1_prev = pts1[n - 1] p1 = pts1[n] p2_prev = pts2[n - 1] p2 = pts2[n] if self.ptInLine(p1, p2_prev, p2): pos = p1 elif self.ptInLine(p2, p1_prev, p1): pos = p2 else: pos = p1_prev node = Node(None, self.scene) node.setPos(pos) except: pass def redrawNodesFromPort(self, p): N = len(p.connections) for n in range(0, N): pts1 = [p.connections[n].pos1] for el in p.connections[n].connPoints: pts1.append(el) pts1.append(p.connections[n].pos2) for m in range(n + 1, N): pts2 = [p.connections[m].pos1] for el in p.connections[m].connPoints: pts2.append(el) pts2.append(p.connections[m].pos2) self.setNode(pts1, pts2) def redrawNodes(self): for el in self.scene.items(): if isinstance(el, Node): el.remove() for item in self.scene.items(): if isinstance(item, Block): for p in item.childItems(): if isinstance(p, OutPort): if len(p.connections) > 1: self.redrawNodesFromPort(p) def removeNodes(self): for el in self.scene.items(): if isinstance(el, Node): el.remove() def itemAt(self, pos): rect = QRectF(pos + QPointF(-DB, -DB), QSizeF(2 * DB, 2 * DB)) items = self.scene.items(rect) for item in items: if isinstance(self.findBlockAt(pos), Block): return item for item in items: if isinstance(self.findOutPortAt(pos), OutPort): return item for item in items: if isinstance(self.findInPortAt(pos), InPort): return (item) for item in items: if isinstance(self.findConnectionAt(pos), Connection): return (item) return None def itemByDraw(self, pos): rect = QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB)) items = self.scene.items( QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB))) for item in items: if isinstance(item, InPort): return (item) return None def findInPortAt(self, pos): items = self.scene.items( QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB))) for el in items: if isinstance(el, InPort): return el return None def findOutPortAt(self, pos): items = self.scene.items( QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB))) for el in items: if isinstance(el, OutPort): return el return None def findBlockAt(self, pos): items = self.scene.items( QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB))) for el in items: if isinstance(el, Block): return el return None def findConnectionAt(self, pos): items = self.scene.items( QRectF(pos - QPointF(DB, DB), QSizeF(2 * DB, 2 * DB))) for c in items: if isinstance(c, Connection): points = [c.pos1] for el in c.connPoints: points.append(el) points.append(c.pos2) N = len(points) for n in range(0, N - 1): p1 = points[n] p2 = points[n + 1] rect = QRectF(p1 - QPointF(DB, DB), p2 + QPointF(DB, DB)) if rect.contains(pos): return c return None def deleteSelected(self): items = self.scene.selectedItems() self.scene.DgmToUndo() for item in items: try: item.remove() self.editor.removeNodes() self.editor.redrawNodes() except: pass def deselect_all(self): for el in self.scene.items(): el.setSelected(False) def setMouseInitDraw(self, pos): pointer = Qt.ArrowCursor if isinstance(self.findBlockAt(pos), Block): pointer = Qt.ArrowCursor elif isinstance(self.findOutPortAt(pos), OutPort): pointer = Qt.CrossCursor elif isinstance(self.findConnectionAt(pos), Connection): pointer = Qt.PointingHandCursor else: pointer = Qt.ArrowCursor self.scene.mainw.view.setCursor(pointer) def setMouseByDraw(self, item): if isinstance(item, InPort) and len(item.connections) == 0: pointer = Qt.CrossCursor else: pointer = Qt.DragLinkCursor self.scene.mainw.view.setCursor(pointer) def PDM(self, obj, event): # Dummy function - No action pass def P00(self, obj, event): # IDLE + MOUSEMOVE self.setMouseInitDraw(event.scenePos()) item = self.itemAt(event.scenePos()) if item == None: self.deselect_all() else: try: item.setSelected(True) except: pass self.scene.updateDgm() def P01(self, obj, event): # IDLE, ITEMSELECTED + LEFTMOUSEPRESSED item = self.findConnectionAt(event.scenePos()) if item != None: self.scene.currentItem = item self.currentPos = event.scenePos() self.deselect_all() self.scene.DgmToUndo() self.state = MOVECONN else: self.state = LEFTMOUSEPRESSED def P02(self, obj, event): # IDLE, ITEMSELECTED + RIGHTMOUSEPRESSED item = self.findBlockAt(event.scenePos()) self.deselect_all() if isinstance(item, Block): item.setSelected(True) self.scene.item = item self.scene.evpos = event.scenePos() try: self.menuIOBlk.exec_(event.screenPos()) except: pass else: item = self.findConnectionAt(event.scenePos()) if isinstance(item, Connection): self.scene.item = item self.scene.evpos = event.scenePos() try: self.subMenuConn.exec_(event.screenPos()) except: pass if item == None: self.scene.evpos = event.scenePos() self.subMenuEditor.exec_(event.screenPos()) def P03(self, obj, event): # IDLE, ITEMSELECTED + MOUSEDOUBLECLICK item = self.findBlockAt(event.scenePos()) self.deselect_all() if isinstance(item, Block): item.setSelected(True) self.scene.item = item self.scene.evpos = event.scenePos() self.paramsBlock() def P04(self, obj, event): # ITEMSELECTED + KEY_DEL self.deleteSelected() self.state = IDLE self.redrawNodes() def P05(self, obj, event): # ITEMSELECTED + KEY_ESC self.state = IDLE def P06(self, obj, event): # LEFTMOUSEPRESSED + MOUSEMOVE self.redrawSelectedItems() self.removeNodes() item = self.itemAt(event.scenePos()) def P07(self, obj, event): # LEFTMOUSEPRESSED + MOUSERELEASED self.redrawSelectedItems() self.redrawNodes() item = self.itemAt(event.scenePos()) if self.scene.currentItem != None: self.scene.currentItem = None self.deselect_all() try: item.setSelected(True) self.scene.currentItem = item except: pass if self.scene.selectedItems(): self.state = ITEMSELECTED else: self.state = IDLE item = self.findOutPortAt(event.scenePos()) if isinstance(item, OutPort): self.scene.DgmToUndo() self.state = DRAWFROMOUTPORT self.conn = Connection(None, self.scene) self.conn.port1 = item self.conn.pos1 = item.scenePos() self.conn.pos2 = item.scenePos() def P08(self, obj, event): # DRAWFROMOUTPORT + LEFTMOUSEPRESSED item = self.findInPortAt(event.scenePos()) if isinstance(item, InPort): self.connectInPort(item) self.redrawNodes() self.state = IDLE else: pt = self.gridPos(event.scenePos()) self.conn.addPoint(pt) self.conn.pos2 = pt self.conn.update_path() def P09(self, obj, event): # DRAWFROMOUTPORT + RIGHTMOUSEPRESSED, KEY_ESC try: self.conn.remove() self.scene.undoDgm() except: pass self.conn = None self.state = IDLE def P10(self, obj, event): # DRAWFROMOUTPORT + MOUSEMOVE item = self.itemByDraw(event.scenePos()) self.setMouseByDraw(item) self.conn.pos2 = event.scenePos() if isinstance(item, InPort): self.conn.update_path_draw2Port() else: self.conn.update_path_draw2Pt() def P11(self, obj, event): # ITEMSELECTED + MOUSEMOVE self.setMouseInitDraw(event.scenePos()) def P12(self, obj, event): # MOVECONN + MOUSEMOVE item = self.scene.currentItem N = len(item.connPoints) oldPos = self.currentPos newPos = self.gridPos(event.scenePos()) try: npos, pos = self.find_exact_pos(item, oldPos) except: return if npos != 0 and npos != N: ok = item.move(npos, newPos) if ok: self.currentPos = newPos def P13(self, obj, event): # MOVECONN + MOUSERELEASE item = self.scene.currentItem N = len(item.connPoints) oldPos = self.currentPos newPos = self.gridPos(event.scenePos()) try: npos, pos = self.find_exact_pos(item, oldPos) except: return if npos != 0 and npos != N: ok = item.move(npos, newPos) if ok: self.currentPos = newPos self.redrawNodes() self.scene.currentItem = None self.state = IDLE def eventFilter(self, obj, event): ev = -1 if event.type() == QEvent.GraphicsSceneMouseMove: ev = 0 if event.type() == QEvent.GraphicsSceneMousePress: self.mainw.statusLabel.setText('') if event.button() == Qt.LeftButton: ev = 1 if event.button() == Qt.RightButton: ev = 2 if event.type() == QEvent.GraphicsSceneMouseRelease: ev = 3 if event.type() == QEvent.GraphicsSceneMouseDoubleClick: self.mainw.statusLabel.setText('') ev = 4 if event.type() == QEvent.KeyPress: self.mainw.statusLabel.setText('') if event.key() == Qt.Key_Delete: ev = 5 if event.key() == Qt.Key_Escape: ev = 6 if ev != -1: #if ev != 0: #print('state->', self.state, 'event->',ev) fun = self.Fun[self.state][ev] fun(obj, event) return False def gridPos(self, pt): gr = GRID x = gr * ((pt.x() + gr / 2) // gr) y = gr * ((pt.y() + gr / 2) // gr) return QPointF(x, y)