class IPFSHashExplorerToolBox(GalacteekTab): """ Organizes IPFSHashExplorerWidgets with a QToolBox """ def __init__(self, gWindow, hashRef, maxItems=16, parent=None): super(IPFSHashExplorerToolBox, self).__init__(gWindow) self.rootHash = hashRef self.maxItems = maxItems self.toolbox = QToolBox() self.exLayout = QVBoxLayout() self.exLayout.addWidget(self.toolbox) self.vLayout.addLayout(self.exLayout) if self.rootHash: self.viewHash(self.rootHash) @property def itemsCount(self): return self.toolbox.count() def viewHash(self, hashRef, addClose=False, autoOpenFolders=False): w = self.lookup(hashRef) if w: self.toolbox.setCurrentWidget(w) return True if self.itemsCount > self.maxItems: return False view = IPFSHashExplorerWidget(hashRef, parent=self, addClose=addClose, autoOpenFolders=autoOpenFolders) view.closeRequest.connect(functools.partial(self.remove, view)) view.directoryOpenRequest.connect( lambda cid: self.viewHash(cid, addClose=True)) idx = self.toolbox.addItem(view, getIconIpfsWhite(), hashRef) self.toolbox.setCurrentIndex(idx) view.reFocus() return True def lookup(self, hashRef): for idx in range(self.itemsCount): if self.toolbox.itemText(idx) == hashRef: return self.toolbox.widget(idx) def remove(self, view): idx = self.toolbox.indexOf(view) if idx: self.toolbox.removeItem(idx) # Always display previous index in the stack if self.itemsCount > 0: rIdx = idx - 1 view = self.toolbox.widget(rIdx) if view: self.toolbox.setCurrentWidget(view) view.reFocus()
class NodeManagerWidget(QWidget): signal_new_node = pyqtSignal(Node) def __init__(self, parent: QWidget = None, scene: 'PMGraphicsScene' = None): super().__init__(parent) self.groups = ['simple_calc', 'logic', 'matrix', 'plot', 'io'] self.node_info_dic: Dict[str, List[Dict[str, object]]] = { key: [] for key in self.groups } self.setLayout(QVBoxLayout()) self.top_layout = QHBoxLayout() self.layout().addLayout(self.top_layout) self.button_edit = QPushButton('Edit') self.button_add = QPushButton('Add') self.top_layout.addWidget(self.button_edit) self.top_layout.addWidget(self.button_add) self.button_edit.clicked.connect(self.on_edit) self.button_add.clicked.connect(self.on_add) self.toolbox = QToolBox() self.list_widgets: Dict[str, QListWidget] = {} for text in self.groups: list_widget = QListWidget() list_widget.doubleClicked.connect(self.on_item_double_clicked) self.layout().addWidget(self.toolbox) self.toolbox.addItem(list_widget, text) self.list_widgets[text] = list_widget self.scene: 'PMGraphicsScene' = scene self.load_nodes() def on_add(self): group = self.get_current_list_widget_group() self.add_node_info({ 'text': 'untitled', 'inputs': ['input1'], 'outputs': ['output1'], 'code': '', 'params': [], 'icon': '', 'group': group, 'ports_changeable': [False, False] }) def on_edit(self): list_widget = self.toolbox.currentWidget() curr_row = list_widget.currentRow() if curr_row >= 0: dic = self.node_info_dic[self.toolbox.itemText( self.toolbox.currentIndex())][curr_row] edit_layout = QHBoxLayout() input_widget = QLineEdit() edit_layout.addWidget(input_widget) check_button = QPushButton(text='check') edit_layout.addWidget(check_button) input_widget.setText(repr(dic['params'])) views = [('line_edit', 'text', 'Node Text', dic['text']), ('bool', 'inputs_changeable', 'Input Ports Changeable', dic['ports_changeable'][0]), ('bool', 'outputs_changeable', 'Output Ports Changeble', dic['ports_changeable'][1]), ('text_edit', 'code', 'Input Python Code', dic['code'], 'python'), ('entry_list', 'inputs', 'Set Inputs', [[None] * len(dic['inputs']), dic['inputs']], lambda: None), ('entry_list', 'outputs', 'Set Outputs', [[None] * len(dic['outputs']), dic['outputs']], lambda: None), ('file', 'icon', 'Set Icon', dic['icon']), ('choose_box', 'group', 'Group Name', dic['group'], self.groups)] sp = SettingsPanel(parent=None, views=views) dialog = QDialog(self) def verify(): try: text = input_widget.text() l = eval(text) if isinstance(l, list): dialog2 = QDialog(dialog) sp2 = SettingsPanel(parent=None, views=l) dialog2.setLayout(QHBoxLayout()) dialog2.layout().addWidget(sp2) dialog2.layout().addLayout(edit_layout) dialog2.exec_() except: import traceback traceback.print_exc() check_button.clicked.connect(verify) dialog.setLayout(QVBoxLayout()) dialog.layout().addWidget(sp) dialog.layout().addLayout(edit_layout) dialog.exec_() dic = sp.get_value() params = None try: params = eval(input_widget.text()) except: import traceback traceback.print_exc() group = self.get_current_list_widget_group() if isinstance(params, list): self.node_info_dic[group][curr_row]['params'] = params self.node_info_dic[group][curr_row]['text'] = dic['text'] self.node_info_dic[group][curr_row]['icon'] = dic['icon'] self.node_info_dic[group][curr_row]['code'] = dic['code'] self.node_info_dic[group][curr_row]['inputs'] = dic['inputs'][1] self.node_info_dic[group][curr_row]['outputs'] = dic['outputs'][1] self.node_info_dic[group][curr_row]['group'] = dic['group'] self.node_info_dic[group][curr_row]['ports_changeable'] = [ dic['inputs_changeable'], dic['outputs_changeable'] ] list_widget.item(curr_row).setText(dic['text']) self.save_node_templetes() self.load_nodes() else: return def add_node(self, text: str, inputs: List[str], outputs: List[str], ports_changeable: List[bool], params_str: str = '', icon_path: str = '', func_str: str = ''): """ 添加新的节点 """ node_id = self.scene.new_id() input_ports = [ CustomPort(node_id + ':input:%d' % int(i + 1), text=name, port_type='input') for i, name in enumerate(inputs) ] output_ports = [ CustomPort(node_id + ':output:%d' % int(i + 1), text=name, port_type='output') for i, name in enumerate(outputs) ] node = Node(canvas=self.scene, node_id=node_id, text=text, input_ports=input_ports, output_ports=output_ports, icon_path=icon_path) content = FlowContentForFunction(node) content.set_function(func_str, 'function') content.set_params(params_str) content.ports_changable = ports_changeable node.set_content(content) self.scene.add_node(node) def on_item_double_clicked(self): list_widget: QListWidget = self.toolbox.currentWidget() group = self.get_current_list_widget_group() curr_row = list_widget.currentRow() if curr_row >= 0: node_info = self.node_info_dic[group][curr_row] text: str = node_info.get('text') inputs: List[str] = node_info.get('inputs') outputs: List[str] = node_info.get('outputs') code: str = node_info.get('code') params: str = node_info.get('params') icon_path: str = node_info.get('icon') ports_changeable: List[bool] = node_info.get('ports_changeable') self.add_node(text, inputs, outputs, ports_changeable, params, icon_path, code) def add_node_info(self, info_dic: Dict[str, object]): """ add new infomation of node """ group = self.get_current_list_widget_group() text = info_dic.get('text') self.get_current_list_widget().addItem(text) print(group) self.node_info_dic[group].append(info_dic) pass def get_current_list_widget(self) -> QListWidget: return self.toolbox.currentWidget() def get_current_list_widget_group(self) -> str: return self.toolbox.itemText(self.toolbox.currentIndex()) def load_nodes(self): """ 加载节点 加载节点之后,可以 """ import pandas self.node_info_dic = {key: [] for key in self.groups} df = pandas.read_csv( os.path.join(os.path.dirname(__file__), 'lib', 'test.csv')) # for k in self.node_info_dic: for i in range(df.shape[0]): row = df.loc[i] dic = { 'text': row['text'] if not pandas.isna(row['text']) else '', 'code': row['code'] if not pandas.isna(row['code']) else '', 'inputs': json.loads(row['inputs']), 'outputs': json.loads(row['outputs']), 'params': json.loads(row['params']) } dic['icon'] = row['icon'] if not pandas.isna(row['icon']) else '' dic['group'] = row['group'] if not pandas.isna( row.get('group')) else 'simple_calc' ports_changeable = row.get('ports_changeable') dic['ports_changeable'] = json.loads( ports_changeable) if ports_changeable is not None else [ False, False ] self.node_info_dic[dic['group']].append(dic) self.refresh_list() def save_node_templetes(self): import pandas columns = [ 'text', 'inputs', 'outputs', 'ports_changeable', 'params', 'icon', 'group', 'code' ] content = [] node_infos = [] for k in self.node_info_dic: node_infos += self.node_info_dic[k] for node_info in node_infos: text = node_info.get('text') icon = node_info.get('icon') inputs = json.dumps(node_info.get('inputs')) outputs = json.dumps(node_info.get('outputs')) ports_changeable = json.dumps(node_info.get('ports_changeable')) params = json.dumps(node_info.get('params')) code = node_info.get('code') group = node_info.get('group') content.append([ text, inputs, outputs, ports_changeable, params, icon, group, code ]) df = pandas.DataFrame(content, columns=columns) df.to_csv(os.path.join(os.path.dirname(__file__), 'lib', 'test.csv')) def refresh_list(self): for k in self.node_info_dic: node_infos = self.node_info_dic[k] list_widget = self.list_widgets[k] list_widget.clear() for info in node_infos: list_widget.addItem(info['text'])