def onShow(self): super(HistoryTool, self).onShow() if self.undoStackWidget.count() != EditorHistory().count(): stack = EditorHistory().getStack() for state in stack: self.undoStackWidget.addEntry(state) self.undoStackWidget.selectEntry(EditorHistory().activeState)
def keyPressEvent(self, event): modifiers = event.modifiers() currentInputAction = InputAction(name="temp", actionType=InputActionType.Keyboard, key=event.key(), modifiers=modifiers) actionSaveVariants = InputManager()["App.Save"] actionNewFileVariants = InputManager()["App.NewFile"] actionLoadVariants = InputManager()["App.Load"] actionSaveAsVariants = InputManager()["App.SaveAs"] if currentInputAction in actionNewFileVariants: EditorHistory().clear() historyTools = self.getRegisteredTools( classNameFilters=["HistoryTool"]) for historyTools in historyTools: historyTools.onClear() self.newFile() EditorHistory().saveState("New file") if currentInputAction in actionSaveVariants: self.save() if currentInputAction in actionLoadVariants: EditorHistory().clear() self.load() if currentInputAction in actionSaveAsVariants: self.save(True)
def __init__(self, parent=None): super(HistoryWidget, self).__init__(parent) self.currentRowChanged.connect(self.onRowChanged) EditorHistory().statePushed.connect(self.addEntry) EditorHistory().stateRemoved.connect(self.onRemoveState) EditorHistory().stateSelected.connect(self.selectEntry) self._data = {}
def mousePressEvent(self, event): super(NodeBoxTreeWidget, self).mousePressEvent(event) item_clicked = self.currentItem() if not item_clicked: event.ignore() return # check if clicked item is a category if item_clicked.bCategory: event.ignore() return # find top level parent rootItem = item_clicked while not rootItem.parent() is None: rootItem = rootItem.parent() packageName = rootItem.text(0) pressed_text = item_clicked.text(0) libName = item_clicked.libName if pressed_text in self.categoryPaths.keys(): event.ignore() return jsonTemplate = NodeBase.jsonTemplate() jsonTemplate['package'] = packageName jsonTemplate['lib'] = libName jsonTemplate['type'] = pressed_text jsonTemplate['name'] = pressed_text jsonTemplate['uuid'] = str(uuid.uuid4()) jsonTemplate['meta']['label'] = pressed_text # TODO: Rewrite self.bGripsEnabled. Node box can be floating window or a tool. # If node box is a tool it onbly can create nodes by dragging and dropping if self.canvas.pressedPin is not None and self.bGripsEnabled: a = self.canvas.mapToScene(self.canvas.mouseReleasePos) jsonTemplate["x"] = a.x() jsonTemplate["y"] = a.y() node = self.canvas.createNode(jsonTemplate) self.canvas.hideNodeBox() pressedPin = self.canvas.pressedPin if pressedPin.direction == PinDirection.Input: for pin in node.UIoutputs.values(): wire = self.canvas.connectPinsInternal(pressedPin, pin) if wire is not None: EditorHistory().saveState("Connect pins", modify=True) break if pressedPin.direction == PinDirection.Output: for pin in node.UIinputs.values(): wire = self.canvas.connectPinsInternal(pin, pressedPin) if wire is not None: EditorHistory().saveState("Connect pins", modify=True) break else: drag = QtGui.QDrag(self) mime_data = QtCore.QMimeData() pressed_text = json.dumps(jsonTemplate) mime_data.setText(pressed_text) drag.setMimeData(mime_data) drag.exec_()
def closeEvent(self, event): self.tick_timer.stop() self.tick_timer.timeout.disconnect() EditorHistory().shutdown() self.canvasWidget.shoutDown() # save editor config settings = ConfigManager().getSettings("APP_STATE") # clear file each time to capture opened dock tools settings.clear() settings.sync() settings.beginGroup('Editor') settings.setValue("geometry", self.saveGeometry()) settings.setValue("state", self.saveState()) settings.endGroup() # save tools state settings.beginGroup('Tools') for tool in self._tools: if isinstance(tool, ShelfTool): settings.beginGroup("ShelfTools") settings.beginGroup(tool.name()) tool.saveState(settings) settings.endGroup() settings.endGroup() if isinstance(tool, DockTool): settings.beginGroup("DockTools") settings.beginGroup(tool.uniqueName()) tool.saveState(settings) settings.endGroup() settings.endGroup() tool.onDestroy() settings.endGroup() settings.sync() # remove temp directory if exists if os.path.exists(self.currentTempDir): shutil.rmtree(self.currentTempDir) # TODO: Use "Borg" pattern to destroy all singletons at once EditorHistory.destroy() GraphManagerSingleton.destroy() ConfigManager.destroy() PreferencesWindow.destroy() PyFlow.appInstance = None QMainWindow.closeEvent(self, event)
def killVar(self, uiVariableWidget): variableGraph = uiVariableWidget._rawVariable.graph variableGraph.killVariable(uiVariableWidget._rawVariable) self.actualize() self.clearProperties() EditorHistory().saveState("Kill variable")
def loadFromData(self, data, clearHistory=False): # check first if all packages we are trying to load are legal missedPackages = set() if not validateGraphDataPackages(data, missedPackages): msg = "This graph can not be loaded. Following packages not found:\n\n" index = 1 for missedPackageName in missedPackages: msg += "{0}. {1}\n".format(index, missedPackageName) index += 1 QMessageBox.critical(self, "Missing dependencies", msg) return if clearHistory: EditorHistory().clear() historyTools = self.getRegisteredTools( classNameFilters=["HistoryTool"]) for historyTools in historyTools: historyTools.onClear() self.newFile(keepRoot=False) # load raw data self.graphManager.get().deserialize(data) self.fileBeenLoaded.emit() self.graphManager.get().selectGraphByName(data["activeGraph"]) self.updateLabel() PathsRegistry().rebuild()
def loadFromFile(self, filePath): with open(filePath, 'r') as f: data = json.load(f) self.loadFromData(data, clearHistory=True) self.currentFileName = filePath EditorHistory().saveState("Open {}".format( os.path.basename(self.currentFileName)))
def __init__(self, parent=None): super(PyFlow, self).__init__(parent=parent) self.edHistory = EditorHistory(self) self.setWindowTitle("PyFlow v{0}".format(currentVersion().__str__())) self.undoStack = QUndoStack(self) self.setContentsMargins(1, 1, 1, 1) self.graphManager = GraphManagerSingleton() self.canvasWidget = CanvasWidget(self.graphManager.get(), self) self.canvasWidget.setObjectName("canvasWidget") self.setCentralWidget(self.canvasWidget) self.setTabPosition(QtCore.Qt.AllDockWidgetAreas, QTabWidget.North) self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks) self.menuBar = QMenuBar(self) self.menuBar.setGeometry(QtCore.QRect(0, 0, 863, 21)) self.menuBar.setObjectName("menuBar") self.setMenuBar(self.menuBar) self.toolBar = QToolBar(self) self.toolBar.setObjectName("toolBar") self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.setWindowIcon(QtGui.QIcon(":/LogoBpApp.png")) self._tools = set() self.currentTempDir = "" self.preferencesWindow = PreferencesWindow(self) self.setMouseTracking(True) self._lastClock = 0.0 self.fps = EDITOR_TARGET_FPS self.tick_timer = QtCore.QTimer() self._current_file_name = 'Untitled' self.populateMenu()
def onImport(self): openPath, selectedFilter = QFileDialog.getOpenFileName(filter="Python node data (*.pynode)") if openPath != "": with open(openPath, 'r') as f: dataString = f.read() self.tryApplyNodeData(dataString) EditorHistory().saveState("Import python node data", modify=True)
def createVariable(self, dataType=str('BoolPin'), accessLevel=AccessLevel.public, uid=None): rawVariable = self.pyFlowInstance.graphManager.get().activeGraph( ).createVariable(dataType=dataType, accessLevel=accessLevel, uid=uid) uiVariable = self.createVariableWrapperAndAddToList(rawVariable) EditorHistory().saveState("Create variable") return uiVariable
def closeEvent(self, event): shouldSave = self.shouldSave() if shouldSave == QMessageBox.Yes: if not self.save(): event.ignore() return elif shouldSave == QMessageBox.Discard: event.ignore() return self.tick_timer.stop() self.tick_timer.timeout.disconnect() EditorHistory().shutdown() self.canvasWidget.shoutDown() # save editor config settings = ConfigManager().getSettings("APP_STATE") # clear file each time to capture opened dock tools settings.clear() settings.sync() settings.beginGroup('Editor') settings.setValue("geometry", self.saveGeometry()) settings.setValue("state", self.saveState()) settings.endGroup() # save tools state settings.beginGroup('Tools') for tool in self._tools: if isinstance(tool, ShelfTool): settings.beginGroup("ShelfTools") settings.beginGroup(tool.name()) tool.saveState(settings) settings.endGroup() settings.endGroup() if isinstance(tool, DockTool): settings.beginGroup("DockTools") settings.beginGroup(tool.uniqueName()) tool.saveState(settings) settings.endGroup() settings.endGroup() tool.onDestroy() settings.endGroup() settings.sync() # remove temp directory if exists if os.path.exists(self.currentTempDir): shutil.rmtree(self.currentTempDir) SingletonDecorator.destroyAll() PyFlow.appInstance = None QMainWindow.closeEvent(self, event)
def keyPressEvent(self, event): modifiers = event.modifiers() currentInputAction = InputAction(name="temp", actionType=InputActionType.Keyboard, key=event.key(), modifiers=modifiers) actionSaveVariants = InputManager()["App.Save"] actionNewFileVariants = InputManager()["App.NewFile"] actionLoadVariants = InputManager()["App.Load"] actionSaveAsVariants = InputManager()["App.SaveAs"] if currentInputAction in actionNewFileVariants: shouldSave = self.shouldSave() if shouldSave == QMessageBox.Yes: self.save() elif shouldSave == QMessageBox.Discard: return EditorHistory().clear() historyTools = self.getRegisteredTools( classNameFilters=["HistoryTool"]) for historyTools in historyTools: historyTools.onClear() self.newFile() EditorHistory().saveState("New file") self.currentFileName = None self.modified = False self.updateLabel() if currentInputAction in actionSaveVariants: self.save() if currentInputAction in actionLoadVariants: shouldSave = self.shouldSave() if shouldSave == QMessageBox.Yes: self.save() elif shouldSave == QMessageBox.Discard: return self.load() if currentInputAction in actionSaveAsVariants: self.save(True)
def assignData(self, data): data["isRoot"] = False data["parentGraphName"] = self._rawNode.rawGraph.parentGraph.name missedPackages = set() if validateGraphDataPackages(data, missedPackages): data["nodes"] = self.canvasRef().makeSerializedNodesUnique( data["nodes"]) self._rawNode.rawGraph.populateFromJson(data) self.canvasRef().createWrappersForGraph(self._rawNode.rawGraph) EditorHistory().saveState("Import compound", modify=True) else: logger.error("Missing dependencies! {0}".format( ",".join(missedPackages)))
def keyPressEvent(self, event): modifiers = event.modifiers() currentInputAction = InputAction(name="temp", actionType=InputActionType.Keyboard, key=event.key(), modifiers=modifiers) actionSaveVariants = InputManager()["App.Save"] actionNewFileVariants = InputManager()["App.NewFile"] actionLoadVariants = InputManager()["App.Load"] actionSaveAsVariants = InputManager()["App.SaveAs"] if currentInputAction in actionNewFileVariants: EditorHistory().clear() self.newFile() EditorHistory().saveState("New file") if currentInputAction in actionSaveVariants: self.save() if currentInputAction in actionLoadVariants: EditorHistory().clear() self.load() if currentInputAction in actionSaveAsVariants: self.save(True)
def onImport(self): openPath, selectedFilter = QFileDialog.getOpenFileName(filter="Subgraph data (*.json)") if openPath != "": with open(openPath, 'r') as f: data = json.load(f) data["isRoot"] = False data["parentGraphName"] = self._rawNode.rawGraph.parentGraph.name missedPackages = set() if validateGraphDataPackages(data, missedPackages): data["nodes"] = self.canvasRef().makeSerializedNodesUnique(data["nodes"]) self._rawNode.rawGraph.populateFromJson(data) self.canvasRef().createWrappersForGraph(self._rawNode.rawGraph) EditorHistory().saveState("Import compound") else: logger.error("Missing dependencies! {0}".format(",".join(missedPackages)))
def __init__(self, parent=None): super(PyFlow, self).__init__(parent=parent) self._modified = False self.setFocusPolicy(QtCore.Qt.StrongFocus) self.currentSoftware = "" self.edHistory = EditorHistory(self) self.edHistory.statePushed.connect(self.historyStatePushed) self.setWindowTitle(winTitle()) self.undoStack = QUndoStack(self) self.setContentsMargins(1, 1, 1, 1) self.graphManager = GraphManagerSingleton() self.canvasWidget = BlueprintCanvasWidget(self.graphManager.get(), self) self.canvasWidget.setObjectName("canvasWidget") self.setCentralWidget(self.canvasWidget) self.setTabPosition(QtCore.Qt.AllDockWidgetAreas, QTabWidget.North) self.setDockOptions(QMainWindow.AnimatedDocks | QMainWindow.AllowNestedDocks) self.menuBar = QMenuBar(self) self.menuBar.setGeometry(QtCore.QRect(0, 0, 863, 21)) self.menuBar.setObjectName("menuBar") self.setMenuBar(self.menuBar) self.toolBar = QToolBar(self) self.toolBar.setObjectName("toolBar") self.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar) self.setWindowIcon(QtGui.QIcon(":/LogoBpApp.png")) self._tools = set() self.currentTempDir = "" self.preferencesWindow = PreferencesWindow(self) self.setMouseTracking(True) self._lastClock = 0.0 self.fps = EDITOR_TARGET_FPS self.tick_timer = QtCore.QTimer() self._currentFileName = '' self.currentFileName = None
def mouseReleaseEvent(self, event): super(HistoryWidget, self).mouseReleaseEvent(event) item = self.currentItem() if item is not None: EditorHistory().selectState(item.state)
def onClear(self): EditorHistory().clear() self.undoStackWidget.clear()
def onStructureChanged(self, name): self._rawVariable.structure = PinStructure[name] self.variablesWidget.pyFlowInstance.onRequestFillProperties( self.createPropertiesWidget) EditorHistory().saveState("Change variable struct", modify=True)
def instance(parent=None): if PyFlow.appInstance is not None: return PyFlow.appInstance settings = ConfigManager().getSettings("APP_STATE") instance = PyFlow(parent) REGISTER_TOOL("PyFlowBase", LoggerTool) a = GET_TOOLS()["PyFlowBase"][0]() a.setAppInstance(instance) instance.registerToolInstance(a) instance.addDockWidget(a.defaultDockArea(), a) a.setAppInstance(instance) a.onShow() try: extraPackagePaths = [] extraPathsString = ConfigManager().getPrefsValue( "PREFS", "General/ExtraPackageDirs") if extraPathsString is not None: extraPathsString = extraPathsString.rstrip(";") extraPathsRaw = extraPathsString.split(";") for rawPath in extraPathsRaw: if os.path.exists(rawPath): extraPackagePaths.append(os.path.normpath(rawPath)) INITIALIZE(additionalPackageLocations=extraPackagePaths) except Exception as e: QMessageBox.critical(None, "Fatal error", str(e)) return instance.startMainLoop() # populate tools canvas = instance.getCanvas() toolbar = instance.getToolbar() geo = settings.value('Editor/geometry') if geo is not None: instance.restoreGeometry(geo) state = settings.value('Editor/state') if state is not None: instance.restoreState(state) settings.beginGroup("Tools") for packageName, registeredToolSet in GET_TOOLS().items(): for ToolClass in registeredToolSet: if issubclass(ToolClass, ShelfTool): ToolInstance = ToolClass() # prevent to be garbage collected instance.registerToolInstance(ToolInstance) ToolInstance.setAppInstance(instance) action = QAction(instance) action.setIcon(ToolInstance.getIcon()) action.setText(ToolInstance.name()) action.setToolTip(ToolInstance.toolTip()) action.setObjectName(ToolInstance.name()) action.triggered.connect(ToolInstance.do) # check if context menu data available menuBuilder = ToolInstance.contextMenuBuilder() if menuBuilder: menuGenerator = ContextMenuGenerator(menuBuilder) menu = menuGenerator.generate() action.setMenu(menu) toolbar.addAction(action) # step to ShelfTools/ToolName group and pass settings inside settings.beginGroup("ShelfTools") settings.beginGroup(ToolClass.name()) ToolInstance.restoreState(settings) settings.endGroup() settings.endGroup() if issubclass(ToolClass, DockTool): menus = instance.menuBar.findChildren(QMenu) pluginsMenuAction = [ m for m in menus if m.title() == "Plugins" ][0].menuAction() toolsMenu = getOrCreateMenu(instance.menuBar, "Tools") instance.menuBar.insertMenu(pluginsMenuAction, toolsMenu) packageSubMenu = getOrCreateMenu(toolsMenu, packageName) toolsMenu.addMenu(packageSubMenu) showToolAction = packageSubMenu.addAction(ToolClass.name()) icon = ToolClass.getIcon() if icon: showToolAction.setIcon(icon) showToolAction.triggered.connect( lambda pkgName=packageName, toolName=ToolClass.name( ): instance.invokeDockToolByName(pkgName, toolName)) settings.beginGroup("DockTools") childGroups = settings.childGroups() for dockToolGroupName in childGroups: # This dock tool data been saved on last shutdown settings.beginGroup(dockToolGroupName) if dockToolGroupName in [ t.uniqueName() for t in instance._tools ]: continue toolName = dockToolGroupName.split("::")[0] instance.invokeDockToolByName(packageName, toolName, settings) settings.endGroup() settings.endGroup() PyFlow.appInstance = instance EditorHistory().saveState("New file") for name, package in GET_PACKAGES().items(): prefsWidgets = package.PrefsWidgets() if prefsWidgets is not None: for categoryName, widgetClass in prefsWidgets.items(): PreferencesWindow().addCategory(categoryName, widgetClass()) PreferencesWindow().selectByName("General") return instance
def setDataType(self, dataType): self.dataType = dataType self._rawVariable.dataType = dataType EditorHistory().saveState("Change variable data type", modify=True)
def accessLevelChanged(x): self._rawVariable.accessLevel = AccessLevel[x] EditorHistory().saveState("Change variable access level", modify=True)
def setHistoryCapacity(): EditorHistory().capacity = self.historyDepth.value()
def setDataType(self, dataType): self.dataType = dataType EditorHistory().saveState("Change variable data type")
def instance(parent=None, software=""): assert ( software != "" ), "Invalid arguments. Please pass you software name as second argument!" instance = PyFlow(parent) settings = ConfigManager().getSettings("APP_STATE") instance.currentSoftware = software SessionDescriptor().software = instance.currentSoftware if software == "standalone": editableStyleSheet(instance) try: extraPackagePaths = [] extraPathsString = ConfigManager().getPrefsValue( "PREFS", "General/ExtraPackageDirs") if extraPathsString is not None: extraPathsString = extraPathsString.rstrip(";") extraPathsRaw = extraPathsString.split(";") for rawPath in extraPathsRaw: if os.path.exists(rawPath): extraPackagePaths.append(os.path.normpath(rawPath)) INITIALIZE(additionalPackageLocations=extraPackagePaths, software=software) except Exception as e: QMessageBox.critical(None, "Fatal error", str(e)) return instance.startMainLoop() # populate tools canvas = instance.getCanvas() toolbar = instance.getToolbar() # populate menus instance.populateMenu() geo = settings.value('Editor/geometry') if geo is not None: instance.restoreGeometry(geo) state = settings.value('Editor/state') if state is not None: instance.restoreState(state) settings.beginGroup("Tools") for packageName, registeredToolSet in GET_TOOLS().items(): for ToolClass in registeredToolSet: if issubclass(ToolClass, ShelfTool): ToolInstance = ToolClass() # prevent to be garbage collected instance.registerToolInstance(ToolInstance) ToolInstance.setAppInstance(instance) action = QAction(instance) action.setIcon(ToolInstance.getIcon()) action.setText(ToolInstance.name()) action.setToolTip(ToolInstance.toolTip()) action.setObjectName(ToolInstance.name()) action.triggered.connect(ToolInstance.do) # check if context menu data available menuBuilder = ToolInstance.contextMenuBuilder() if menuBuilder: menuGenerator = ContextMenuGenerator(menuBuilder) menu = menuGenerator.generate() action.setMenu(menu) toolbar.addAction(action) # step to ShelfTools/ToolName group and pass settings inside settings.beginGroup("ShelfTools") settings.beginGroup(ToolClass.name()) ToolInstance.restoreState(settings) settings.endGroup() settings.endGroup() if issubclass(ToolClass, DockTool): menus = instance.menuBar.findChildren(QMenu) pluginsMenuAction = [ m for m in menus if m.title() == "Plugins" ][0].menuAction() toolsMenu = getOrCreateMenu(instance.menuBar, "Tools") instance.menuBar.insertMenu(pluginsMenuAction, toolsMenu) packageSubMenu = getOrCreateMenu(toolsMenu, packageName) toolsMenu.addMenu(packageSubMenu) showToolAction = packageSubMenu.addAction(ToolClass.name()) icon = ToolClass.getIcon() if icon: showToolAction.setIcon(icon) showToolAction.triggered.connect( lambda pkgName=packageName, toolName=ToolClass.name( ): instance.invokeDockToolByName(pkgName, toolName)) settings.beginGroup("DockTools") childGroups = settings.childGroups() for dockToolGroupName in childGroups: # This dock tool data been saved on last shutdown settings.beginGroup(dockToolGroupName) if dockToolGroupName in [ t.uniqueName() for t in instance._tools ]: settings.endGroup() continue toolName = dockToolGroupName.split("::")[0] instance.invokeDockToolByName(packageName, toolName, settings) settings.endGroup() settings.endGroup() PyFlow.appInstance = instance EditorHistory().saveState("New file") for name, package in GET_PACKAGES().items(): prefsWidgets = package.PrefsWidgets() if prefsWidgets is not None: for categoryName, widgetClass in prefsWidgets.items(): PreferencesWindow().addCategory(categoryName, widgetClass()) PreferencesWindow().selectByName("General") if ConfigManager().loadedDefaults: QMessageBox.information( None, "First-time tips", "Welcome to DepthAI GUI. To use this tool efficiently, please do the following:\n\n1. Maximize the window\n2. Enable NodeBox widget (Tools > PyFlowBase > NodeBox)\n3. Enable Properties widget (Tools > PyFlowBase > Properties)\n\nHave fun!" ) return instance