def onExportToPackage(self): # check if category is not empty if self._rawNode._rawGraph.category == '': QMessageBox.information( None, "Warning", "Category is not set! Please step into compound and type category name." ) return packageNames = list(GET_PACKAGES().keys()) selectedPackageName, accepted = QInputDialog.getItem(None, "Select", "Select package", packageNames, editable=False) if accepted: packagePath = GET_PACKAGE_PATH(selectedPackageName) compoundsDir = os.path.join(packagePath, "Compounds") if not os.path.isdir(compoundsDir): os.mkdir(compoundsDir) self.onExport(root=compoundsDir) # refresh node box app = self.canvasRef().getApp() nodeBoxes = app.getRegisteredTools( classNameFilters=["NodeBoxTool"]) for nodeBox in nodeBoxes: nodeBox.refresh()
def populateMenu(self): fileMenu = self.menuBar.addMenu("File") newFileAction = fileMenu.addAction("New file") newFileAction.setIcon(QtGui.QIcon(":/new_file_icon.png")) newFileAction.triggered.connect(self.newFile) loadAction = fileMenu.addAction("Load") loadAction.setIcon(QtGui.QIcon(":/folder_open_icon.png")) loadAction.triggered.connect(self.load) saveAction = fileMenu.addAction("Save") saveAction.setIcon(QtGui.QIcon(":/save_icon.png")) saveAction.triggered.connect(self.save) saveAsAction = fileMenu.addAction("Save as") saveAsAction.setIcon(QtGui.QIcon(":/save_as_icon.png")) saveAsAction.triggered.connect(lambda: self.save(True)) IOMenu = fileMenu.addMenu("Custom IO") for packageName, package in GET_PACKAGES().items(): # exporters exporters = None try: exporters = package.GetExporters() except: continue pkgMenu = IOMenu.addMenu(packageName) for exporterName, exporterClass in exporters.items(): fileFormatMenu = pkgMenu.addMenu(exporterClass.displayName()) fileFormatMenu.setToolTip(exporterClass.toolTip()) if exporterClass.createExporterMenu(): exportAction = fileFormatMenu.addAction("Export") exportAction.triggered.connect( lambda checked=False, app=self, exporter=exporterClass: exporter.doExport(app)) if exporterClass.createImporterMenu(): importAction = fileFormatMenu.addAction("Import") importAction.triggered.connect( lambda checked=False, app=self, exporter=exporterClass: exporter.doImport(app)) editMenu = self.menuBar.addMenu("Edit") preferencesAction = editMenu.addAction("Preferences") preferencesAction.setIcon(QtGui.QIcon(":/options_icon.png")) preferencesAction.triggered.connect(self.showPreferencesWindow) pluginsMenu = self.menuBar.addMenu("Plugins") packagePlugin = pluginsMenu.addAction("Create package...") packagePlugin.triggered.connect(PackageWizard.run) helpMenu = self.menuBar.addMenu("Help") helpMenu.addAction("Homepage").triggered.connect( lambda _=False, url= "https://wonderworks-software.github.io/PyFlow/": QtGui. QDesktopServices.openUrl(url)) helpMenu.addAction("Docs").triggered.connect( lambda _=False, url="https://pyflow.readthedocs.io/en/latest/": QtGui.QDesktopServices.openUrl(url))
def populateMenu(self): fileMenu = self.menuBar.addMenu("File") newFileAction = fileMenu.addAction("New file") newFileAction.setIcon(QtGui.QIcon(":/new_file_icon.png")) newFileAction.triggered.connect(self.newFile) loadAction = fileMenu.addAction("Load") loadAction.setIcon(QtGui.QIcon(":/folder_open_icon.png")) loadAction.triggered.connect(self.load) saveAction = fileMenu.addAction("Save") saveAction.setIcon(QtGui.QIcon(":/save_icon.png")) saveAction.triggered.connect(self.save) saveAsAction = fileMenu.addAction("Save as") saveAsAction.setIcon(QtGui.QIcon(":/save_as_icon.png")) saveAsAction.triggered.connect(lambda: self.save(True)) IOMenu = fileMenu.addMenu("Custom IO") for packageName, package in GET_PACKAGES().items(): # exporters exporters = None try: exporters = package.GetExporters() except: continue pkgMenu = IOMenu.addMenu(packageName) for exporterName, exporterClass in exporters.items(): fileFormatMenu = pkgMenu.addMenu(exporterClass.displayName()) fileFormatMenu.setToolTip(exporterClass.toolTip()) if exporterClass.createExporterMenu(): exportAction = fileFormatMenu.addAction("Export") exportAction.triggered.connect( lambda checked=False, app=self, exporter=exporterClass: exporter.doExport(app)) if exporterClass.createImporterMenu(): importAction = fileFormatMenu.addAction("Import") importAction.triggered.connect( lambda checked=False, app=self, exporter=exporterClass: exporter.doImport(app)) editMenu = self.menuBar.addMenu("Edit") preferencesAction = editMenu.addAction("Preferences") preferencesAction.setIcon(QtGui.QIcon(":/options_icon.png")) preferencesAction.triggered.connect(self.showPreferencesWindow) pluginsMenu = self.menuBar.addMenu("Plugins") packagePlugin = pluginsMenu.addAction("Create package...") packagePlugin.triggered.connect(PackageWizard.run) helpMenu = self.menuBar.addMenu("Help") shortcutsAction = helpMenu.addAction("Shortcuts") shortcutsAction.setIcon(QtGui.QIcon(":/shortcuts_icon.png")) shortcutsAction.triggered.connect(self.shortcuts_info)
def onExportToPackage(self): packageNames = list(GET_PACKAGES().keys()) selectedPackageName, accepted = QInputDialog.getItem(None, "Select", "Select package", packageNames, editable=False) if accepted: packagePath = GET_PACKAGE_PATH(selectedPackageName) pyNodesDir = os.path.join(packagePath, "PyNodes") if not os.path.isdir(pyNodesDir): os.mkdir(pyNodesDir) self.onExport(root=pyNodesDir) # refresh node boxes app = self.canvasRef().getApp() nodeBoxes = app.getRegisteredTools(classNameFilters=["NodeBoxTool"]) for nodeBox in nodeBoxes: nodeBox.refresh()
def getInputWidget(dataType, dataSetter, defaultValue, widgetVariant=DEFAULT_WIDGET_VARIANT, **kwds): ''' factory method ''' # try to find factory in other packages first for pkgName, pkg in GET_PACKAGES().items(): # skip self if pkgName == PACKAGE_NAME: continue try: widget = pkg.PinsInputWidgetFactory()(dataType, dataSetter, defaultValue, widgetVariant=widgetVariant, **kwds) if widget is not None: return widget except Exception as e: print("Failed to override input widget. Package - {0}".format(pkgName), e) continue if dataType == 'FloatPin': if kwds is not None and "pinAnnotations" in kwds: if kwds["pinAnnotations"] is not None and "ValueRange" in kwds["pinAnnotations"]: return FloatInputWidget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) return FloatInputWidgetSimple(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) if dataType == 'IntPin': if kwds is not None and "pinAnnotations" in kwds: if kwds["pinAnnotations"] is not None and "ValueRange" in kwds["pinAnnotations"]: return IntInputWidget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) return IntInputWidgetSimple(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) if dataType == 'StringPin': if widgetVariant == DEFAULT_WIDGET_VARIANT: return StringInputWidget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) elif widgetVariant == "PathWidget": return PathInputWidget(mode="all", dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) elif widgetVariant == "FilePathWidget": return PathInputWidget(mode="file", dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) elif widgetVariant == "FolderPathWidget": return PathInputWidget(mode="directory", dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) elif widgetVariant == "EnumWidget": return EnumInputWidget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) elif widgetVariant == "ObjectPathWIdget": return ObjectPathWIdget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) if dataType == 'BoolPin': return BoolInputWidget(dataSetCallback=dataSetter, defaultValue=defaultValue, **kwds) if dataType == 'ExecPin': return ExecInputWidget(dataSetCallback=dataSetter, defaultValue=None, **kwds) if dataType == 'AnyPin': return NoneInputWidget(dataSetCallback=dataSetter, defaultValue=None, **kwds)
def validateGraphDataPackages(graphData, missedPackages=set()): """Checks if packages used in serialized data accessible Missed packages will be added to output set :param graphData: Serialized graph :type graphData: dict :param missedPackages: Package names that missed :type missedPackages: str :rtype: bool """ existingPackages = GET_PACKAGES().keys() graphPackages = fetchPackageNames(graphData) for pkg in graphPackages: if pkg not in existingPackages: missedPackages.add(pkg) return len(missedPackages) == 0
def loadFromData(self, data, fpath=""): # check first if all packages we are trying to load are legal existingPackages = GET_PACKAGES().keys() graphPackages = PyFlow.fetchPackageNames(data) missedPackages = set() for pkg in graphPackages: if pkg not in existingPackages: missedPackages.add(pkg) if len(missedPackages) > 0: 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 self.newFile(keepRoot=False) # load raw data self.graphManager.get().deserialize(data) self.fileBeenLoaded.emit() self.graphManager.get().selectGraphByName(data["activeGraph"])
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 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
def refresh(self, pattern='', pinDirection=None, pinStructure=PinStructure.Single): self.clear() self.categoryPaths = {} dataType = None if self.canvas.pressedPin is not None: dataType = self.canvas.pressedPin.dataType for package_name, package in GET_PACKAGES().items(): # annotated functions for libName, lib in package.GetFunctionLibraries().items(): foos = lib.getFunctions() for name, foo in foos.items(): foo = foo libName = foo.__annotations__["lib"] fooArgNames = getargspec(foo).args fooInpTypes = set() fooOutTypes = set() fooInpStructs = set() fooOutStructs = set() if foo.__annotations__['nodeType'] == NodeTypes.Callable: fooInpTypes.add('ExecPin') fooOutTypes.add('ExecPin') fooInpStructs.add(PinStructure.Single) fooOutStructs.add(PinStructure.Single) # consider return type if not None if foo.__annotations__['return'] is not None: fooOutTypes.add(foo.__annotations__['return'][0]) fooOutStructs.add( findStructFromValue( foo.__annotations__['return'][1])) for index in range(len(fooArgNames)): dType = foo.__annotations__[fooArgNames[index]] # if tuple - this means ref pin type (output) + default value # eg: (3, True) - bool with True default val fooInpTypes.add(dType[0]) fooInpStructs.add(findStructFromValue(dType[1])) nodeCategoryPath = "{0}|{1}".format( package_name, foo.__annotations__['meta']['Category']) keywords = foo.__annotations__['meta']['Keywords'] checkString = name + nodeCategoryPath + ''.join(keywords) if pattern.lower() in checkString.lower(): # create all nodes items if clicked on canvas if dataType is None: self.suggestionsEnabled = False self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) else: self.suggestionsEnabled = True if pinDirection == PinDirection.Output: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in fooInpStructs if dataType in fooInpTypes and ( pinStructure in fooInpStructs or hasMultiPins): self.insertNode( nodeCategoryPath, name, foo.__doc__, libName) elif dataType in fooInpTypes: self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) else: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in fooOutStructs if dataType in fooOutTypes and ( pinStructure in fooOutStructs or hasMultiPins): self.insertNode( nodeCategoryPath, name, foo.__doc__, libName) elif dataType in fooOutTypes: self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) # class based nodes for node_class in package.GetNodeClasses().values(): if node_class.__name__ in ('setVar', 'getVar'): continue nodeCategoryPath = "{0}|{1}".format(package_name, node_class.category()) checkString = node_class.__name__ + nodeCategoryPath + ''.join( node_class.keywords()) if pattern.lower() not in checkString.lower(): continue if dataType is None: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) else: # if pressed pin is output pin # filter by nodes input types hints = node_class.pinTypeHints() if pinDirection == PinDirection.Output: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in hints.inputStructs if dataType in hints.inputTypes and ( pinStructure in hints.inputStructs or hasMultiPins): self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) elif dataType in hints.inputTypes: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) else: # if pressed pin is input pin # filter by nodes output types if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in hints.outputStructs if dataType in hints.outputTypes and ( pinStructure in hints.outputStructs or hasMultiPins): self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) elif dataType in hints.outputTypes: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) # expand all categories if dataType is not None: for categoryItem in self.categoryPaths.values(): categoryItem.setExpanded(True) self.sortItems(0, QtCore.Qt.AscendingOrder)
def refresh(self, pattern='', pinDirection=None, pinStructure=PinStructure.Single): self.clear() self.categoryPaths = {} dataType = None if self.canvas.pressedPin is not None: dataType = self.canvas.pressedPin.dataType for package_name, package in GET_PACKAGES().items(): # annotated functions for libName, lib in package.GetFunctionLibraries().items(): foos = lib.getFunctions() for name, foo in foos.items(): foo = foo libName = foo.__annotations__["lib"] fooArgNames = getargspec(foo).args fooInpTypes = set() fooOutTypes = set() fooInpStructs = set() fooOutStructs = set() if foo.__annotations__['nodeType'] == NodeTypes.Callable: fooInpTypes.add('ExecPin') fooOutTypes.add('ExecPin') fooInpStructs.add(PinStructure.Single) fooOutStructs.add(PinStructure.Single) # consider return type if not None if foo.__annotations__['return'] is not None: fooOutTypes.add(foo.__annotations__['return'][0]) fooOutStructs.add( findStructFromValue( foo.__annotations__['return'][1])) for index in range(len(fooArgNames)): dType = foo.__annotations__[fooArgNames[index]] # if tuple - this means ref pin type (output) + default value # eg: (3, True) - bool with True default val fooInpTypes.add(dType[0]) fooInpStructs.add(findStructFromValue(dType[1])) nodeCategoryPath = "{0}|{1}".format( package_name, foo.__annotations__['meta']['Category']) keywords = foo.__annotations__['meta']['Keywords'] checkString = name + nodeCategoryPath + ''.join(keywords) if pattern.lower() in checkString.lower(): # create all nodes items if clicked on canvas if dataType is None: self.suggestionsEnabled = False self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) else: self.suggestionsEnabled = True if pinDirection == PinDirection.Output: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in fooInpStructs if dataType in fooInpTypes and ( pinStructure in fooInpStructs or hasMultiPins): self.insertNode( nodeCategoryPath, name, foo.__doc__, libName) elif dataType in fooInpTypes: self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) else: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in fooOutStructs if dataType in fooOutTypes and ( pinStructure in fooOutStructs or hasMultiPins): self.insertNode( nodeCategoryPath, name, foo.__doc__, libName) elif dataType in fooOutTypes: self.insertNode(nodeCategoryPath, name, foo.__doc__, libName) # class based nodes for node_class in package.GetNodeClasses().values(): if node_class.__name__ in ('setVar', 'getVar'): continue nodeCategoryPath = "{0}|{1}".format(package_name, node_class.category()) checkString = node_class.__name__ + nodeCategoryPath + ''.join( node_class.keywords()) if pattern.lower() not in checkString.lower(): continue if dataType is None: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) else: # if pressed pin is output pin # filter by nodes input types hints = node_class.pinTypeHints() if pinDirection == PinDirection.Output: if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in hints.inputStructs if dataType in hints.inputTypes and ( pinStructure in hints.inputStructs or hasMultiPins): self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) elif dataType in hints.inputTypes: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) else: # if pressed pin is input pin # filter by nodes output types if pinStructure != PinStructure.Multi: hasMultiPins = PinStructure.Multi in hints.outputStructs if dataType in hints.outputTypes and ( pinStructure in hints.outputStructs or hasMultiPins): self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) elif dataType in hints.outputTypes: self.insertNode(nodeCategoryPath, node_class.__name__, node_class.description()) # populate exported py nodes packagePath = GET_PACKAGE_PATH(package_name) pyNodesRoot = os.path.join(packagePath, "PyNodes") if os.path.exists(pyNodesRoot): for path, dirs, files in os.walk(pyNodesRoot): for f in files: pyNodeName, extension = os.path.splitext(f) if extension == ".pynode": p = os.path.normpath(path) folders = p.split(os.sep) index = folders.index("PyNodes") categorySuffix = '|'.join(folders[index:]) category = "{0}|{1}".format( package_name, categorySuffix) self.insertNode(category, pyNodeName, bPyNode=True) # populate exported compounds compoundNodesRoot = os.path.join(packagePath, "Compounds") if os.path.exists(compoundNodesRoot): for path, dirs, files in os.walk(compoundNodesRoot): for f in files: _, extension = os.path.splitext(f) if extension == ".compound": compoundsRoot = os.path.normpath(path) fullCompoundPath = os.path.join(compoundsRoot, f) with open(fullCompoundPath, 'r') as compoundFile: data = json.load(compoundFile) compoundCategoryName = data["category"] compoundNodeName = data["name"] category = "{0}|{1}|{2}".format( package_name, "Compounds", compoundCategoryName) self.insertNode(category, compoundNodeName, bCompoundNode=True) # expand all categories if dataType is not None: for categoryItem in self.categoryPaths.values(): categoryItem.setExpanded(True) self.sortItems(0, QtCore.Qt.AscendingOrder)
def getNodesClasses(): packages = GET_PACKAGES() return packages
def createNode(packageName, nodeClass, nodeName, **kvargs): packages = GET_PACKAGES() classNodes = packages[packageName].GetNodeClasses() node = classNodes[nodeClass](nodeName, **kvargs) return node
def createFunction(packageName, libName, functionName): packages = GET_PACKAGES() lib = packages[packageName].GetFunctionLibraries()[libName] defFoos = lib.getFunctions() fun = NodeBase.initializeFromFunction(defFoos[functionName]) return fun