def openWebsite(self): if not QtGui.QDesktopServices.openUrl( QtCore.QUrl('http://docs.gpilab.com')): QtWidgets.QMessageBox.information( self, 'Documentation', "Documentation can be found at\nhttp://docs.gpilab.com", QtWidgets.QMessageBox.Close)
def __init__(self, graph, destPort, sourcePort): super(EdgeTracer, self).__init__() # show a faux copy of the delete menu menu = QtGui.QMenu() menu.addAction("Delete") # position of pipe end based on port type bindout_y = 5 bindin_y = -1 p1 = self.mapFromItem(sourcePort, 3.5, bindin_y) p2 = self.mapFromItem(destPort, 3.5, bindout_y) pos = graph.mapToGlobal(graph.mapFromScene((p1 - p2) / 2 + p2)) # render the menu without executing it menupixmap = QtGui.QPixmap().grabWidget(menu) # round edges #mask = menupixmap.createMaskFromColor(QtGui.QColor(255, 255, 255), QtCore.Qt.MaskOutColor) #p = QtGui.QPainter(menupixmap) #p.setRenderHint(QtGui.QPainter.Antialiasing) #p.drawRoundedRect(0,0,menupixmap.width(),menupixmap.height(), 5,5) #p.drawPixmap(menupixmap.rect(), mask, mask.rect()) #p.end() # display the menu image (as a dummy menu as its being built) # TODO: this could probably be moved to the FauxMenu self._tracer = QtGui.QLabel() self._tracer.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint) self._tracer.move(pos) self._tracer.setPixmap(menupixmap) self._tracer.show() self._tracer.raise_() # draw a faux selected line line = QtCore.QLineF(p1, p2) self.setPen( QtGui.QPen(QtGui.QColor(QtCore.Qt.red), 2, QtCore.Qt.DashLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) self.setLine(line) self.setZValue(0) # cleanup both menu item and line by removing from scene (parent). self._timer = QtCore.QTimer() self._timer.singleShot(300, lambda: graph.scene().removeItem(self))
def getSize(self): text, ok = QtGui.QInputDialog.getText(self, "Grabber", "Enter pixmap size:", QtGui.QLineEdit.Normal, "%d x %d" % (self.glWidget.width(), self.glWidget.height())) if not ok: return QtCore.QSize() regExp = QtCore.QRegExp("([0-9]+) *x *([0-9]+)") if regExp.exactMatch(text): width = regExp.cap(0).toInt() height = regExp.cap(1).toInt() if width > 0 and width < 2048 and height > 0 and height < 2048: return QtCore.QSize(width, height) return self.glWidget.size()
def dropEvent(self, event): log.debug("dropped in test window") if event.mimeData().hasFormat('application/gpi-widget'): mime = event.mimeData() itemData = mime.data('application/gpi-widget') dataStream = QtCore.QDataStream(itemData, QtCore.QIODevice.ReadOnly) text = QtCore.QByteArray() offset = QtCore.QPoint() dataStream >> text >> offset if self.addWidgetByID(self._graph.getAllNodes(), int(text)): # event.acceptProposedAction() event.accept() else: event.ignore()
def adjust(self): if not self.source or not self.dest: return # position of pipe end based on port type bindout_y = 5 bindin_y = 0 if isinstance(self.source, InPort): line = QtCore.QLineF(self.mapFromItem(self.source, 3.5, bindin_y), self.mapFromItem(self.dest, 3.5, bindout_y)) else: line = QtCore.QLineF(self.mapFromItem(self.source, 3.5, bindout_y), self.mapFromItem(self.dest, 3.5, bindin_y)) self.prepareGeometryChange() self.sourcePoint = line.p1() self.destPoint = line.p2()
def shape(self): # hitbox for selecting path = super(Edge, self).shape() delta = QtCore.QPointF(3, 3) # padding to make it thicker line = QtGui.QPolygonF([ self.sourcePoint + delta, self.destPoint + delta, self.destPoint - delta, self.sourcePoint - delta ]) path.addPolygon(line) return path
def __init__(self, sourcePort, destPort): super(Edge, self).__init__() self.sourcePoint = QtCore.QPointF() self.destPoint = QtCore.QPointF() self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable) self.setCacheMode(QtWidgets.QGraphicsItem.DeviceCoordinateCache) self.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.source = sourcePort self.dest = destPort self.source.addEdge(self) self.dest.addEdge(self) self.adjust() self.setZValue(1) self.setAcceptHoverEvents(True) self._beingHovered = False
def __init__(self, parent=None): super(CanvasScene, self).__init__(parent) self.graph = parent self.line = None self.rubberBand = None self.origin = QtCore.QPointF() # during a port connection this is used to hold # a list of matching port types for highlighting self.portMatches = []
def expandMacro(self): # before expansion save the face position for load/paste purposes self._face_colpos = self._face.getPos() self._src.setPos(self._face.pos()) self._sink.setPos(self._src.pos()) self._face.hide() self._macroedge.show() self._sink.show() self._src.show() self.resetPortParents() for port in self._src.getPorts(): port.updateEdges() for port in self._sink.getPorts(): port.updateEdges() for node in self._encap_nodes: node.setPos(self._src.pos()) node.show() for edge in node.edges(): edge.show() # initialize animation (open jaw) self._anim = QtCore.QParallelAnimationGroup() self._anim.finished.connect(self.jawOpen) anim = QtCore.QPropertyAnimation(self._sink, b"pos") anim.setDuration(300) anim.setEndValue(self._sink_pos + self._src.pos()) self._anim.addAnimation(anim) for node, pos in zip(self._encap_nodes, self._encap_nodepos): anim = QtCore.QPropertyAnimation(node, b"pos") anim.setDuration(300) anim.setEndValue(pos + self._src.pos()) self._anim.addAnimation(anim) self._anim.start()
def adjust(self): if not self.source or not self.dest: return # line = QtCore.QLineF(self.mapFromItem(self.source, 0, 0)+self.source.line().p1(), # self.mapFromItem(self.dest, 0, 0)+self.dest.line().p1()) line = QtCore.QLineF(self.mapFromItem(self.source, 0, 0), self.mapFromItem(self.dest, 0, 0)) self.prepareGeometryChange() self.sourcePoint = line.p1() self.destPoint = line.p2()
def __init__(self, source, dest): super(MacroNodeEdge, self).__init__() self.setZValue(0) self.source = source # PortEdge(pos, self) self.dest = dest # PortEdge(QtCore.QPointF(0, 30)+pos, self) self.arrowSize = 20.0 self.penWidth = 10.0 self.sourcePoint = QtCore.QPointF() self.destPoint = QtCore.QPointF() self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges) self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache) self.setAcceptedMouseButtons(QtCore.Qt.NoButton) self.source.addMacroEdge(self) self.dest.addMacroEdge(self) self.adjust() self.fontHeight = 20
def collapseMacro(self): if self.validateSrcNodes(): return False if self.validateSinkNodes(): return False self.listEncapsulatedNodes() if manager.isDebug(): log.debug("nodes:") for node in self._encap_nodes: log.debug(node.name) self.saveNodePos() self._face.setPos(self._src.pos()) # initialize animation stuff (close jaw) self._anim = QtCore.QParallelAnimationGroup() self._anim.finished.connect(self.jawClosed) anim = QtCore.QPropertyAnimation(self._sink, b"pos") anim.setDuration(300) anim.setEndValue(self._src.pos()) self._anim.addAnimation(anim) for node in self._encap_nodes: anim = QtCore.QPropertyAnimation(node, b"pos") anim.setDuration(300) anim.setEndValue(self._src.pos()) self._anim.addAnimation(anim) self._anim.start() return True
def boundingRect(self): if not self.source or not self.dest: return QtCore.QRectF() penWidth = 2.0 # extra padding for edge text #if self._beingHovered: # extra = (penWidth + 10.0) / 2.0 #else: extra = (penWidth + 30.0) / 2.0 # http://lists.trolltech.com/qt-interest/2000-08/thread00439-0.html # bound = QRect(QPoint(min(p0.x(),p1.x(),p2.x(),p3.x()), # min(p0.y(),p1.y(),p2.y(),p3.y())), # QPoint(max(p0.x(),p1.x(),p2.x(),p3.x()), # mxa(p0.y(),p1.y(),p2.y(),p3.y()))); return QtCore.QRectF( self.sourcePoint, QtCore.QSizeF(self.destPoint.x() - self.sourcePoint.x(), self.destPoint.y() - self.sourcePoint.y())).normalized().adjusted( -extra, -extra, extra, extra)
def mousePressEvent(self, event): # CANVAS SCENE printMouseEvent(self, event) modifiers = getKeyboardModifiers() # allow graphics view panning if self.graph._panning: event.ignore() return # if its not a port, then don't draw a line modmidbutton_event = (event.button() == QtCore.Qt.LeftButton and modifiers == QtCore.Qt.AltModifier) if ((event.button() == QtCore.Qt.LeftButton) or (event.button() == QtCore.Qt.MidButton) or modmidbutton_event) \ and isinstance(self.itemAt(event.scenePos()), Port): event.accept() self.startLineDraw(event) # rubber band select # elif ((event.button() == QtCore.Qt.MidButton) or modmidbutton_event): elif ((event.button() == QtCore.Qt.LeftButton) \ and not isinstance(self.itemAt(event.scenePos()), Node) \ and not isinstance(self.itemAt(event.scenePos()), PortEdge)): event.accept() self.unselectAllItems() # reset select before making another self.origin = event.scenePos() self.rubberBand = QtGui.QGraphicsRectItem( QtCore.QRectF(self.origin, QtCore.QSizeF())) self.rubberBand.setPen( QtGui.QPen(QtCore.Qt.gray, 0, QtCore.Qt.SolidLine)) self.rubberBand.setBrush(QtGui.QBrush(QtCore.Qt.lightGray)) self.rubberBand.setZValue(0) self.addItem(self.rubberBand) else: QtGui.QApplication.restoreOverrideCursor() event.ignore() super(CanvasScene, self).mousePressEvent(event)
def __init__(self, func, title, label, proxy): multiprocessing_context.Process.__init__(self) QtCore.QObject.__init__(self) self._func = func self._title = title self._label = label self._proxy = proxy self._cnt = 0 # Since we don't know when the process finishes # probe at regular intervals. # -it would be nicer to have the process check-in with the GPI # main proc when its done. self._timer = QtCore.QTimer() self._timer.timeout.connect(self.checkProcess) self._timer.start(10) # 10msec update
def searchMenu(self, txt, parent, mousemenu): # this menu needs to be rebuilt everytime a character changes # don't bother if the user just cleared the search if len(txt) == 0: return pos = self._parent.mapToGlobal(self._parent._event_pos + QtCore.QPoint(mousemenu.sizeHint().width(), 0)) # close any existing search menu and assign the new one self.removeSearchPopup() searchMenu = SearchMenu(pos, parent=parent) self.generateNodeSearchActions(str(txt), searchMenu, mousemenu) self._listwdg = searchMenu searchMenu.show()
def expandMacro(self): # before expansion save the face position for load/paste purposes self._face_colpos = self._face.getPos() self._src.setPos(self._face.pos()) self._sink.setPos(self._src.pos()) self._face.hide() self._macroedge.show() self._sink.show() self._src.show() self.resetPortParents() for port in self._src.getPorts(): port.updateEdges() for port in self._sink.getPorts(): port.updateEdges() for node in self._encap_nodes: node.setPos(self._src.pos()) node.show() for edge in node.edges(): edge.show() # initialize animation stuff self._anim_timeline = QtCore.QTimeLine(300) self._anim_timeline.finished.connect(self.jawOpen) self._anim_timeline.setFrameRange(1, 100) self._anim = [] # close jaw self._anim.append(QtGui.QGraphicsItemAnimation()) self._anim[-1].setItem(self._sink) self._anim[-1].setTimeLine(self._anim_timeline) self._anim[-1].setPosAt(1, self._sink_pos + self._src.pos()) for node, pos in zip(self._encap_nodes, self._encap_nodepos): self._anim.append(QtGui.QGraphicsItemAnimation()) self._anim[-1].setItem(node) self._anim[-1].setTimeLine(self._anim_timeline) self._anim[-1].setPosAt(1, pos + self._src.pos()) self._anim_timeline.start()
def _createNewNode(self): # copy node template to this library, and open it up fullpath = self._new_node_path new_node_created = False if os.path.exists(fullpath): log.warn("Didn't create new node at path: " + fullpath + " (file already exists)") else: try: shutil.copyfile(Config.GPI_NEW_NODE_TEMPLATE_FILE, fullpath) except OSError as e: print(e) log.warn("Didn't create new node at path: " + fullpath) else: log.dialog("New node created at path: " + fullpath) new_node_created = True self.rescan() self._list_win.hide() if new_node_created: # instantiate our new node on the canvas canvas = self._parent pos = QtCore.QPoint(0, 0) node = self.findNode_byPath(fullpath) sig = {'sig': 'load', 'subsig': node, 'pos': pos} canvas.addNodeRun(sig) # now open the file for editing (stolen from node.py) if Specs.inOSX(): # OSX users set their launchctl associated file prefs command = "open \"" + fullpath + "\"" subprocess.Popen(command, shell=True) # Linux users set their editor choice # TODO: this should be moved to config elif Specs.inLinux(): editor = 'gedit' if os.environ.has_key("EDITOR"): editor = os.environ["EDITOR"] command = editor + " \"" + fullpath + "\"" subprocess.Popen(command, shell=True) else: log.warn("Quick-Edit unavailable for this OS, aborting...")
def mouseMoveEvent(self, event): # CANVAS SCENE # allow graphics view panning if self.graph._panning: event.ignore() return if self.line: event.accept() self.midLineDraw(event) elif self.rubberBand: event.accept() newRect = QtCore.QRectF(self.origin, event.scenePos()) self.rubberBand.setRect(newRect) else: event.ignore() self.dumpCursorStack() super(CanvasScene, self).mouseMoveEvent(event)
def collapseMacro(self): if self.validateSrcNodes(): return False if self.validateSinkNodes(): return False self.listEncapsulatedNodes() if manager.isDebug(): log.debug("nodes:") for node in self._encap_nodes: log.debug(node.name) self.saveNodePos() self._face.setPos(self._src.pos()) # initialize animation stuff self._anim_timeline = QtCore.QTimeLine(300) self._anim_timeline.finished.connect(self.jawClosed) self._anim_timeline.setFrameRange(1, 100) self._anim = [] # close jaw self._anim.append(QtGui.QGraphicsItemAnimation()) self._anim[-1].setItem(self._sink) self._anim[-1].setTimeLine(self._anim_timeline) self._anim[-1].setPosAt(1, self._src.pos()) for node in self._encap_nodes: self._anim.append(QtGui.QGraphicsItemAnimation()) self._anim[-1].setItem(node) self._anim[-1].setTimeLine(self._anim_timeline) self._anim[-1].setPosAt(1, self._src.pos()) self._anim_timeline.start() return True
def searchMenu(self, txt, parent, mousemenu): # this menu needs to be rebuilt everytime a character changes # don't bother if the user just cleared the search if len(txt) == 0: return pos = self._parent.mapToGlobal(self._parent._event_pos + QtCore.QPoint(mousemenu.sizeHint().width(), 0)) # generate the menu menu = QtGui.QMenu(self._parent) self.generateNodeSearchActions(str(txt), menu, mousemenu) # render the menu without executing it menupixmap = QtGui.QPixmap().grabWidget(menu) # display the menu image (as a dummy menu as its being built) # TODO: this could probably be moved to the FauxMenu self._listwdg = FauxMenu(menu, pos) self._listwdg.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint) self._listwdg.move(pos) self._listwdg.setPixmap(menupixmap) self._listwdg.show() self._listwdg.raise_()
def openLIBDIRSHelp(self): if not QtGui.QDesktopServices.openUrl(QtCore.QUrl('http://docs.gpilab.com/Configuration/#configuration-library-directories')): QtWidgets.QMessageBox.information(self, 'Documentation',"Documentation can be found at\nhttp://docs.gpilab.com", QtWidgets.QMessageBox.Close)
def __init__(self, image_path): # find the limiting desktop dimension (w or h) pm = QtGui.QPixmap.fromImage(QtGui.QImage(image_path)) g = QtGui.QDesktopWidget().availableGeometry() w = g.width() h = g.height() r = float(pm.width()) / pm.height() # aspect ratio if (w <= pm.width()): h = int(w / r) if (h <= pm.height()): w = int(h * r) # the splash is almost useless below 500pts if w < 500: w = 500 # resize the image based on new width if (w != g.width()) or (h != g.height()): pm = pm.scaledToWidth(int(w * 0.8), mode=QtCore.Qt.SmoothTransformation) # scale subsequent parameters based on new image width iw = pm.width() ih = pm.height() super(Splash, self).__init__(pm) # use a timer instead of the EULA self._timer = QtCore.QTimer() self._timer.timeout.connect(self.terms_accepted.emit) self._timer.setSingleShot(True) if not INCLUDE_EULA: self._timer.start(2000) panel = QtGui.QWidget() pal = QtGui.QPalette(QtGui.QColor(255, 255, 255)) # white panel.setAutoFillBackground(True) panel.setPalette(pal) lic = ''' THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ''' self.lic = QtGui.QTextEdit(lic) self.lic.setReadOnly(True) button_title = 'Agree' self.wdg1 = QtGui.QPushButton(button_title, self) self.wdg1.setCheckable(False) self.wdg1.setFixedSize(int(iw * 0.2), int(iw * 0.05)) self.wdg1.clicked[bool].connect(self.accept) button_title = 'Quit' self.wdg2 = QtGui.QPushButton(button_title, self) self.wdg2.setCheckable(False) self.wdg2.setFixedSize(int(iw * 0.2), int(iw * 0.05)) self.wdg2.clicked[bool].connect(self.reject) buf = 'Click Agree to start GPI or Quit to exit.' new_fw = iw * 0.45 for fw_i in range(20, 0, -1): f = QtGui.QFont('gill sans', fw_i) fm = QtGui.QFontMetricsF(f) cfw = fm.width(buf) if cfw < new_fw: break f = QtGui.QFont('gill sans', fw_i) self.prompt = QtGui.QLabel(buf) self.prompt.setAlignment(QtCore.Qt.AlignCenter) self.prompt.setFont(f) wdgLayout = QtGui.QHBoxLayout() #wdgLayout.setContentsMargins(0, 0, 0, 0) # no spaces around this item #wdgLayout.setSpacing(0) #wdgLayout.addSpacerItem(QtGui.QSpacerItem(iw/2,1,hPolicy=QtGui.QSizePolicy.Minimum)) wdgLayout.addWidget(self.prompt) wdgLayout.addWidget(self.wdg1) #wdgLayout.addSpacerItem(QtGui.QSpacerItem(int(iw*0.01),1,hPolicy=QtGui.QSizePolicy.Minimum)) wdgLayout.addWidget(self.wdg2) #wdgLayout.addSpacerItem(QtGui.QSpacerItem(1,1,hPolicy=QtGui.QSizePolicy.MinimumExpanding)) # a small panel vbox_p = QtGui.QVBoxLayout() vbox_p.setContentsMargins(10, 10, 10, 10) vbox_p.setSpacing(10) vbox_p.addWidget(self.lic) vbox_p.addLayout(wdgLayout) panel.setLayout(vbox_p) # white space | panel vbox = QtGui.QVBoxLayout() #vbox.setContentsMargins(0, 0, 0, int(iw*0.02)) # no spaces around this item vbox.setContentsMargins(0, 0, 0, 0) # no spaces around this item vbox.setSpacing(0) vbox.addSpacerItem( QtGui.QSpacerItem(iw, (1 - 0.28) * ih, hPolicy=QtGui.QSizePolicy.Minimum, vPolicy=QtGui.QSizePolicy.Minimum)) #vbox.addWidget(self.lic) vbox.addWidget(panel) #vbox.addLayout(wdgLayout) if INCLUDE_EULA: self.setLayout(vbox) self._accept = False
def paint(self, painter, option, widget): # EDGE if not self.source or not self.dest: return # Draw the line itself. line = QtCore.QLineF(self.sourcePoint, self.destPoint) if line.length() == 0.0: return if self.isSelected( ) or self._beingHovered or self.connectedPortIsHovered(): fade = QtGui.QColor(QtCore.Qt.red) fade.setAlpha(200) #painter.setPen(QtGui.QPen(QtCore.Qt.red, 1, QtCore.Qt.DashLine, painter.setPen( QtGui.QPen(fade, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) elif self.isCyclicConnection(): painter.setPen( QtGui.QPen(QtCore.Qt.red, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) else: fade = QtGui.QColor(QtCore.Qt.black) fade.setAlpha(150) #painter.setPen(QtGui.QPen(QtCore.Qt.black, 2, QtCore.Qt.SolidLine, painter.setPen( QtGui.QPen(fade, 2, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) painter.drawLine(line) x = (line.x1() + line.x2()) / 2.0 y = (line.y1() + line.y2()) / 2.0 xa = (line.x1() - line.x2()) ya = (line.y1() - line.y2()) m = math.sqrt(xa * xa + ya * ya) a = math.atan2(ya, xa) * 180.0 / math.pi buf = self.source.getDataString() if self._beingHovered: f = QtGui.QFont("Times New Roman", 8) else: f = QtGui.QFont("Times New Roman", 6) fm = QtGui.QFontMetricsF(f) bw = fm.width(buf) bw2 = -bw * 0.5 #bh = fm.height() # bezier curves if False: sa = (a + 90.) * 0.5 path = QtGui.QPainterPath(line.p1()) path.cubicTo(x - sa, y - sa, x + sa, y + sa, line.x2(), line.y2()) painter.drawPath(path) # bezier curves, change direction on the angle if False: sa = (a + 90.) * 0.5 if a > 90 or a < -90: path = QtGui.QPainterPath(line.p1()) path.cubicTo(x - sa, y - sa, x + sa, y + sa, line.x2(), line.y2()) painter.drawPath(path) else: path = QtGui.QPainterPath(line.p1()) path.cubicTo(x + sa, y + sa, x - sa, y - sa, line.x2(), line.y2()) painter.drawPath(path) painter.setFont(f) if self._beingHovered: painter.setPen(QtGui.QPen(QtCore.Qt.red, 1)) else: painter.setPen(QtGui.QPen(QtCore.Qt.darkGray, 1)) painter.save() painter.translate(QtCore.QPointF(x, y)) if m > bw * 1.1 or self._beingHovered: if a > 90 or a < -90: painter.rotate(a + 180.0) painter.drawText(QtCore.QPointF(bw2, -2.0), buf) else: painter.rotate(a) painter.drawText(QtCore.QPointF(bw2, -2.0), buf) else: painter.drawText(QtCore.QPointF(bw2, -2.0), '') painter.restore()
def __init__(self, title, parent=None): super().__init__(title, parent) # gpi interface self._collapsables = [] self._subplotSettings = {} #self._subplotPosition = {'right': 0.9, 'bottom': 0.12, 'top': 0.9, 'wspace': 0.2, 'hspace': 0.2, 'left': 0.125} self._subplotPosition = {'right': 0.913, 'bottom': 0.119, 'top': 0.912, 'wspace': 0.2, 'hspace': 0.2, 'left': 0.111} #self._subplot_keepers = ['yscale', 'xscale'] # linear, log self._subplot_keepers = [] self._lineSettings = [] self._line_keepers = ['linewidth', 'linestyle', 'label', 'marker', 'markeredgecolor', 'markerfacecolor', 'markersize', 'color', 'alpha'] # since drawing is slow, don't do it as often, use the timer as a # debouncer self._on_draw_cnt = 0 self._updatetimer = QtCore.QTimer() self._updatetimer.setSingleShot(True) self._updatetimer.timeout.connect(self._on_draw) self._updatetimer.setInterval(10) # plot specific UI side panel # -sets options for plot window so this needs to be run first vbox = QtWidgets.QVBoxLayout() vbox.setContentsMargins(0, 0, 0, 0) # no spaces around this item vbox.setSpacing(0) # AUTOSCALE self._autoscale_btn = gpi.widgets.BasicPushButton(self) self._autoscale_btn.set_toggle(True) self._autoscale_btn.set_button_title('autoscale') self._autoscale_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._autoscale_btn) # GRID self._grid_btn = gpi.widgets.BasicPushButton(self) self._grid_btn.set_toggle(True) self._grid_btn.set_button_title('grid') self._grid_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._grid_btn) # X/Y LIMITS lims = QtWidgets.QGridLayout() self._xl = gpi.widgets.BasicDoubleSpinBox(self) self._xh = gpi.widgets.BasicDoubleSpinBox(self) self._yl = gpi.widgets.BasicDoubleSpinBox(self) self._yh = gpi.widgets.BasicDoubleSpinBox(self) self._xl.valueChanged.connect(self.on_draw) self._xh.valueChanged.connect(self.on_draw) self._yl.valueChanged.connect(self.on_draw) self._yh.valueChanged.connect(self.on_draw) self._xl.set_immediate(True) self._xh.set_immediate(True) self._yl.set_immediate(True) self._yh.set_immediate(True) self._xl.set_label('max') self._xh.set_label('min') self._xl.set_decimals(7) self._xh.set_decimals(7) self._yl.set_decimals(7) self._yh.set_decimals(7) self._xlab = QtWidgets.QLabel('x limits') self._ylab = QtWidgets.QLabel('y limits') #self._maxlab = QtWidgets.QLabel('max') #self._minlab = QtWidgets.QLabel('min') #lims.addWidget(self._maxlab,1,0,1,1) #lims.addWidget(self._minlab,2,0,1,1) lims.addWidget(self._xlab,0,1,1,1,alignment=QtCore.Qt.AlignHCenter) lims.addWidget(self._xh,1,1,1,1,alignment=QtCore.Qt.AlignHCenter) lims.addWidget(self._xl,2,1,1,1,alignment=QtCore.Qt.AlignHCenter) lims.addWidget(self._ylab,0,2,1,1,alignment=QtCore.Qt.AlignHCenter) lims.addWidget(self._yh,1,2,1,1,alignment=QtCore.Qt.AlignHCenter) lims.addWidget(self._yl,2,2,1,1,alignment=QtCore.Qt.AlignHCenter) self._collapsables.append(self._xlab) self._collapsables.append(self._ylab) self._collapsables.append(self._xl) self._collapsables.append(self._xh) self._collapsables.append(self._yl) self._collapsables.append(self._yh) #self._collapsables.append(self._minlab) #self._collapsables.append(self._maxlab) # TICK MARKS ticks = QtWidgets.QGridLayout() self._x_numticks = gpi.widgets.BasicSpinBox(self) self._x_numticks.valueChanged.connect(self.on_draw) self._y_numticks = gpi.widgets.BasicSpinBox(self) self._y_numticks.valueChanged.connect(self.on_draw) self._x_ticks = QtWidgets.QLineEdit() self._y_ticks = QtWidgets.QLineEdit() self._x_ticks.textChanged.connect(lambda txt: self.check_validticks(self._x_ticks)) self._y_ticks.textChanged.connect(lambda txt: self.check_validticks(self._y_ticks)) self._x_ticks.setPlaceholderText('comma separated list of x labels') self._y_ticks.setPlaceholderText('comma separated list of y labels') self._x_ticks.returnPressed.connect(self.on_draw) self._y_ticks.returnPressed.connect(self.on_draw) self._x_numticks.set_immediate(True) self._y_numticks.set_immediate(True) self._x_numticks.set_min(2) self._y_numticks.set_min(2) self._x_numticks.set_max(100) self._y_numticks.set_max(100) self._x_numticks.set_val(5) self._y_numticks.set_val(5) self._x_numticks.set_label('x ticks') self._y_numticks.set_label('y ticks') ticks.addWidget(self._x_numticks, 0,0,1,1) ticks.addWidget(self._y_numticks, 1,0,1,1) ticks.addWidget(self._x_ticks, 0,1,1,1) ticks.addWidget(self._y_ticks, 1,1,1,1) self._collapsables.append(self._x_numticks) self._collapsables.append(self._y_numticks) self._collapsables.append(self._x_ticks) self._collapsables.append(self._y_ticks) # TITLE, XLABEL, YLABEL plotlabels = QtWidgets.QHBoxLayout() self._plot_title = QtWidgets.QLineEdit() self._plot_xlab = QtWidgets.QLineEdit() self._plot_ylab = QtWidgets.QLineEdit() self._plot_title.setPlaceholderText('title') self._plot_xlab.setPlaceholderText('x label') self._plot_ylab.setPlaceholderText('y label') self._plot_title.returnPressed.connect(self.on_draw) self._plot_xlab.returnPressed.connect(self.on_draw) self._plot_ylab.returnPressed.connect(self.on_draw) plotlabels.addWidget(self._plot_title) plotlabels.addWidget(self._plot_xlab) plotlabels.addWidget(self._plot_ylab) self._collapsables.append(self._plot_title) self._collapsables.append(self._plot_xlab) self._collapsables.append(self._plot_ylab) # XSCALE, YSCALE self._xscale_btn = gpi.widgets.BasicPushButton(self) self._xscale_btn.set_toggle(True) self._xscale_btn.set_button_title('log(x)') self._xscale_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._xscale_btn) self._yscale_btn = gpi.widgets.BasicPushButton(self) self._yscale_btn.set_toggle(True) self._yscale_btn.set_button_title('log(y)') self._yscale_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._yscale_btn) scale_options_layout = QtWidgets.QHBoxLayout() scale_options_layout.addWidget(self._xscale_btn) scale_options_layout.addWidget(self._yscale_btn) # LEGEND self._legend_btn = gpi.widgets.BasicPushButton(self) self._legend_btn.set_toggle(True) self._legend_btn.set_button_title('legend') self._legend_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._legend_btn) # HOLD self._hold_btn = gpi.widgets.BasicPushButton(self) self._hold_btn.set_toggle(True) self._hold_btn.set_button_title('hold') #self._hold_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._hold_btn) # MOVE AXES TO ORIGIN # self._origin_axes_btn = gpi.widgets.BasicPushButton(self) # self._origin_axes_btn.set_toggle(True) # self._origin_axes_btn.set_button_title("axes at (0,0)") # self._collapsables.append(self._origin_axes_btn) # RESET self._reset_btn = gpi.widgets.BasicPushButton(self) self._reset_btn.set_toggle(False) self._reset_btn.set_button_title('reset') self._reset_btn.valueChanged.connect(self._init_parms_) self._collapsables.append(self._reset_btn) # X=0, Y=0 self._xeq0_btn = gpi.widgets.BasicPushButton(self) self._xeq0_btn.set_toggle(True) self._xeq0_btn.set_button_title('x=0') self._xeq0_btn.set_val(True) self._xeq0_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._xeq0_btn) self._yeq0_btn = gpi.widgets.BasicPushButton(self) self._yeq0_btn.set_toggle(True) self._yeq0_btn.set_button_title('y=0') self._yeq0_btn.set_val(True) self._yeq0_btn.valueChanged.connect(self.on_draw) self._collapsables.append(self._yeq0_btn) # LINE OPTIONS self._lino_btn = gpi.widgets.BasicPushButton(self) self._lino_btn.set_toggle(False) self._lino_btn.set_button_title('line options') self._lino_btn.valueChanged.connect(self.lineOptionsDialog) self._collapsables.append(self._lino_btn) # SUBPLOT SPACING OPTIONS self._subplotso_btn = gpi.widgets.BasicPushButton(self) self._subplotso_btn.set_toggle(False) self._subplotso_btn.set_button_title('spacing options') self._subplotso_btn.valueChanged.connect(self.subplotSpacingOptions) self._collapsables.append(self._subplotso_btn) self.adj_window = None plot_options_layout = QtWidgets.QHBoxLayout() plot_options_layout.addWidget(self._subplotso_btn) plot_options_layout.addWidget(self._lino_btn) grid_legend_lyt = QtWidgets.QHBoxLayout() grid_legend_lyt.addWidget(self._legend_btn) grid_legend_lyt.addWidget(self._grid_btn) autoscale_scale_lyt = QtWidgets.QHBoxLayout() autoscale_scale_lyt.addWidget(self._autoscale_btn) autoscale_scale_lyt.addWidget(self._xscale_btn) autoscale_scale_lyt.addWidget(self._yscale_btn) autoscale_scale_lyt.addWidget(self._xeq0_btn) autoscale_scale_lyt.addWidget(self._yeq0_btn) # HLINES self._hline1 = QtWidgets.QFrame() self._hline1.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken) self._hline1.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self._collapsables.append(self._hline1) self._hline2 = QtWidgets.QFrame() self._hline2.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken) self._hline2.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self._collapsables.append(self._hline2) self._hline3 = QtWidgets.QFrame() self._hline3.setFrameStyle(QtWidgets.QFrame.HLine | QtWidgets.QFrame.Sunken) self._hline3.setSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) self._collapsables.append(self._hline3) spc = 10 self._spacer1 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._spacer2 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._spacer3 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._spacer4 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._spacer5 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._spacer6 = QtWidgets.QSpacerItem(1,spc,QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding) self._collapsables.append(self._spacer1) self._collapsables.append(self._spacer2) self._collapsables.append(self._spacer3) self._collapsables.append(self._spacer4) self._collapsables.append(self._spacer5) self._collapsables.append(self._spacer6) # panel layout vbox.addLayout(plotlabels) vbox.addSpacerItem(self._spacer1) vbox.addWidget(self._hline1) vbox.addSpacerItem(self._spacer2) vbox.addLayout(lims) #vbox.addLayout(scale_options_layout) #vbox.addWidget(self._autoscale_btn) vbox.addLayout(autoscale_scale_lyt) vbox.addSpacerItem(self._spacer3) vbox.addWidget(self._hline2) vbox.addSpacerItem(self._spacer4) vbox.addLayout(ticks) #vbox.addWidget(self._legend_btn) vbox.addLayout(grid_legend_lyt) vbox.addLayout(plot_options_layout) #vbox.addWidget(self._lino_btn) #vbox.addWidget(self._subplotso_btn) vbox.addSpacerItem(self._spacer5) vbox.addWidget(self._hline3) vbox.addSpacerItem(self._spacer6) vbox.addWidget(self._hold_btn) # vbox.addWidget(self._origin_axes_btn) vbox.insertStretch(-1,1) vbox.addWidget(self._reset_btn) # plot window self._data = None self._plotwindow = self.create_main_frame() # put side panel and plot window together hbox = QtWidgets.QHBoxLayout() hbox.addLayout(vbox) hbox.addLayout(self._plotwindow) hbox.setStretch(0,0) hbox.setStretch(1,11) self.setLayout(hbox) #self._on_draw() # draw once to get initial settings #self.copySubplotSettings() # Don't hide side-panel options by default self.set_collapsed(False) self.set_grid(True) self.set_autoscale(True) # DEFAULTS self._init_parms_()
def triggerHoverLeaveEvent(self): e = QtCore.QEvent(QtCore.QEvent.GraphicsSceneHoverLeave) self.hoverLeaveEvent(e)
def boundingRect(self): adjust = 2.0 maxx = max([i for i, j in self.pointsCoord]) maxy = max([j for i, j in self.pointsCoord]) return QtCore.QRectF((0 - adjust), (0 - adjust), (maxx + adjust), (maxy + adjust))
def __init__(self, nodeWidget, CanvasBackend, portTitle, portNum, intype=None, dtype=None, ndim=None, menuWidget=None): super(Port, self).__init__() self._id = None self.setID() self.node = nodeWidget self.menuWidget = menuWidget # a reference to a module menu widget self.graph = CanvasBackend self.edgeList = [] self.newPos = QtCore.QPointF() self.setFlag(QtGui.QGraphicsItem.ItemSendsGeometryChanges) self.setCacheMode(QtGui.QGraphicsItem.DeviceCoordinateCache) self.setZValue(3) ## TYPE info self._GPIType = intype # basic data type # for NPY arrays self._dtype = dtype # array data type self._ndim = ndim self._obligation = None # inport use only # a link to the data self._data = None # position self.portNum = portNum self.portTitle = portTitle if portTitle is None: self.portTitle = str(portNum) # port shape self.largenessFact = 3.0 self.pointsCoord = [[0.0, 0.0], [7.0, 0.0], [3.5, 5]] self.setTransformOriginPoint(3.5, 5) if isinstance(self, OutPort): self.setTransformOriginPoint(3.5, 0) # self.portShape = trianglePolygon = QtGui.QPolygonF() self.portShape = QtGui.QPolygonF() for i in self.pointsCoord: self.portShape.append(QtCore.QPointF(i[0], i[1])) # box # self.pointsCoord_canvasConnect = [[0.0, 0.0], [7.0, 0.0], [7.0, 5], [0.0, 5]] # bowtie #self.pointsCoord_canvasConnect = [[0.0, 0.0], [7.0, 0.0], [3.5, 2.5], [0.0, 5.0], [7.0, 5.0], [3.5, 2.5]] #self.portShape_canvasConnect = QtGui.QPolygonF() #for i in self.pointsCoord_canvasConnect: # self.portShape_canvasConnect.append(QtCore.QPointF(i[0], i[1])) # box # self.pointsCoord_canvasConnect = [[0.0, 0.0], [7.0, 0.0], [7.0, 5], [0.0, 5]] # bowtie self.pointsCoord_memSave = [[0.0, 0.0], [7.0, 0.0], [3.5, 2.5], [0.0, 5.0], [7.0, 5.0], [3.5, 2.5]] self.portShape_memSave = QtGui.QPolygonF() for i in self.pointsCoord_memSave: self.portShape_memSave.append(QtCore.QPointF(i[0], i[1])) self.setCursor(QtCore.Qt.CrossCursor) self.setAcceptHoverEvents(True) self._beingHovered = False self.updateToolTip() # src or sink self._canvasConnect = False # save memory self._savemem = False
def paint(self, painter, option, widget): if not self.source or not self.dest: return # Draw the line itself. line = QtCore.QLineF(self.sourcePoint, self.destPoint) if line.length() == 0.0: return painter.setPen( QtGui.QPen(QtCore.Qt.gray, self.penWidth, QtCore.Qt.SolidLine, QtCore.Qt.RoundCap, QtCore.Qt.RoundJoin)) painter.drawLine(line) # drawing text x = (line.x1() + line.x2()) / 2.0 y = (line.y1() + line.y2()) / 2.0 xa = (line.x1() - line.x2()) ya = (line.y1() - line.y2()) m = math.sqrt(xa * xa + ya * ya) a = math.atan2(ya, xa) * 180.0 / math.pi buf = "Macro" f = QtGui.QFont("times", 20) fm = QtGui.QFontMetricsF(f) bw = fm.width(buf) bw2 = -bw * 0.5 # bh = fm.height() # Draw the arrows if there's enough room. angle = math.acos(line.dx() / line.length()) if line.dy() >= 0: angle = self.TwoPi - angle sourceArrowP1 = self.sourcePoint + QtCore.QPointF( math.sin(angle + self.Pi / 3) * self.arrowSize, math.cos(angle + self.Pi / 3) * self.arrowSize) sourceArrowP2 = self.sourcePoint + QtCore.QPointF( math.sin(angle + self.Pi - self.Pi / 3) * self.arrowSize, math.cos(angle + self.Pi - self.Pi / 3) * self.arrowSize) destArrowP1 = self.destPoint + QtCore.QPointF( math.sin(angle - self.Pi / 3) * self.arrowSize, math.cos(angle - self.Pi / 3) * self.arrowSize) destArrowP2 = self.destPoint + QtCore.QPointF( math.sin(angle - self.Pi + self.Pi / 3) * self.arrowSize, math.cos(angle - self.Pi + self.Pi / 3) * self.arrowSize) painter.setBrush(QtCore.Qt.gray) painter.drawPolygon( QtGui.QPolygonF([line.p1(), sourceArrowP1, sourceArrowP2])) painter.drawPolygon( QtGui.QPolygonF([line.p2(), destArrowP1, destArrowP2])) # drawing text painter.setFont(f) painter.setPen(QtGui.QPen(QtCore.Qt.darkGray, 1)) painter.save() painter.translate(QtCore.QPointF(x, y)) if m > bw * 1.1: if a > 90 or a < -90: painter.rotate(a + 180.0) painter.drawText(QtCore.QPointF(bw2, -5.0), buf) else: painter.rotate(a) painter.drawText(QtCore.QPointF(bw2, -5.0), buf) else: painter.drawText(QtCore.QPointF(bw2, -5.0), '') painter.restore()
def loadSettings(self, s, nodeList, pos): '''load all settings from a description generated by getSettings() ''' self.setID(s['id']) self.setLabelWdg(s['label']) self.setLabel(s['label']) self.newLayoutWindowFromSettings(s['layoutWindow'], nodeList) if s['collapse']: x = s['face_settings']['pos'][0] + pos[0] y = s['face_settings']['pos'][1] + pos[1] #x = s['src_pos'][0] + pos[0] #y = s['src_pos'][1] + pos[1] self._src.setPos(QtCore.QPointF(x, y)) # need relative jaw pos #x = s['sink_settings']['pos'][0] + pos[0] #y = s['sink_settings']['pos'][1] + pos[1] #self._sink.setPos(QtCore.QPoint(x, y)) x += s['rel_jaw_pos'][0] y += s['rel_jaw_pos'][1] self._sink.setPos(QtCore.QPointF(x, y)) x = s['face_settings']['pos'][0] + pos[0] y = s['face_settings']['pos'][1] + pos[1] self._face.setPos(QtCore.QPointF(x, y)) rel = QtCore.QPointF(x, y) for nid, epos in list(s['nodes_rel_pos'].items()): enode = self.getNodeByID(nodeList, int(nid)) if enode: enode.setPos(rel + QtCore.QPointF(*epos)) log.debug("node found by nid: " + enode.name) log.debug("pos: ") log.debug(str(epos)) log.debug(str(rel)) log.debug(str(QtCore.QPointF(*epos))) log.debug(str(rel + QtCore.QPointF(*epos))) else: log.warn("nid not found: " + str(nid)) else: x = s['src_settings']['pos'][0] + pos[0] y = s['src_settings']['pos'][1] + pos[1] self._src.setPos(QtCore.QPointF(x, y)) x = s['sink_settings']['pos'][0] + pos[0] y = s['sink_settings']['pos'][1] + pos[1] self._sink.setPos(QtCore.QPointF(x, y)) x = s['src_settings']['pos'][0] + pos[0] y = s['src_settings']['pos'][1] + pos[1] self._face.setPos(QtCore.QPointF(x, y)) self._src.setID(s['src_settings']['id']) self._sink.setID(s['sink_settings']['id']) self._face.setID(s['face_settings']['id']) # save expanded positions self._src_exppos = self._src.getPos() self._sink_exppos = self._sink.getPos() self._face_colpos = self._face.getPos() # self.setCollapse(s['collapse']) self._destined_collapse = s['collapse']