diff --git a/research_analytics_suite/gui/NodeEditorManager.py b/research_analytics_suite/gui/NodeEditorManager.py index e291d42..70a212f 100644 --- a/research_analytics_suite/gui/NodeEditorManager.py +++ b/research_analytics_suite/gui/NodeEditorManager.py @@ -69,6 +69,11 @@ def add_editor(self, editor_id, width, height, parent): self._editors[editor_id] = editor editor.draw() + def get_editor(self, editor_id): + if editor_id not in self._editors or self._editors.get(editor_id) is None: + return None + return self._editors.get(editor_id) + def add_cross_editor_link(self, output_attr, input_attr, editor_id_from, editor_id_to): self._cross_editor_links.append((output_attr, input_attr, editor_id_from, editor_id_to)) diff --git a/research_analytics_suite/gui/modules/Mapped2DSpace.py b/research_analytics_suite/gui/modules/Mapped2DSpace.py index d3fd494..150e47e 100644 --- a/research_analytics_suite/gui/modules/Mapped2DSpace.py +++ b/research_analytics_suite/gui/modules/Mapped2DSpace.py @@ -49,21 +49,43 @@ async def _update_async(self) -> None: # Placeholder for asynchronous update logic pass - def add_node(self, label, pos=(0, 0)): + def add_node(self, operation_dict, pos=(0, 0)): """ Adds a node to the node editor. Args: - label (str): The label of the node. + operation_dict (dict): The dictionary containing the operation information. pos (tuple): The position of the node. """ node_id = dpg.generate_uuid() - with dpg.node(tag=node_id, parent=self._node_editor_id, label=label, pos=pos): + with dpg.node(tag=node_id, parent=self._node_editor_id, label=operation_dict["name"], pos=pos): input_id = dpg.generate_uuid() output_id = dpg.generate_uuid() - dpg.add_node_attribute(tag=input_id, attribute_type=dpg.mvNode_Attr_Input) - dpg.add_node_attribute(tag=output_id, attribute_type=dpg.mvNode_Attr_Output) + + from research_analytics_suite.gui.modules.UpdatedOperationModule import UpdatedOperationModule + _operation_module = None + + with dpg.node_attribute(attribute_type=dpg.mvNode_Attr_Static, tag=f"{node_id}_name"): + with dpg.group(tag=f"{node_id}_name_group"): + _operation_module = UpdatedOperationModule(operation_dict, 200, 500, + node_id) + _operation_module.draw_upper_region(parent=f"{node_id}_name_group", width=200) + + with dpg.node_attribute(tag=f"{node_id}_details", attribute_type=dpg.mvNode_Attr_Output): + with dpg.group(tag=f"{node_id}_details_group"): + _operation_module.draw_details_region(parent=f"{node_id}_details_group", width=200) + + with dpg.node_attribute(tag=f"{node_id}_middle", attribute_type=dpg.mvNode_Attr_Input): + with dpg.group(tag=f"{node_id}_middle_group"): + _operation_module.draw_middle_region(parent=f"{node_id}_middle_group", width=200) + + with dpg.node_attribute(tag=f"{node_id}_lower", attribute_type=dpg.mvNode_Attr_Static): + with dpg.group(tag=f"{node_id}_lower_group", width=260): + _operation_module.draw_lower_region(parent=f"{node_id}_lower_group", width=200) + self._nodes.append((node_id, input_id, output_id)) + return node_id, input_id, output_id + def link_nodes(self, output_attr, input_attr): """ diff --git a/research_analytics_suite/gui/modules/OperationSlotPreview.py b/research_analytics_suite/gui/modules/OperationSlotPreview.py index e8d0fb0..738392a 100644 --- a/research_analytics_suite/gui/modules/OperationSlotPreview.py +++ b/research_analytics_suite/gui/modules/OperationSlotPreview.py @@ -32,6 +32,9 @@ def __init__(self, operation_dict: dict, width: int, height: int, parent: str): """ super().__init__(width, height, parent) + from research_analytics_suite.gui.NodeEditorManager import NodeEditorManager + self._node_manager = NodeEditorManager() + self._operation_info = operation_dict self._name = self._operation_info["name"] @@ -56,16 +59,17 @@ async def _update_async(self) -> None: def draw(self): with dpg.child_window(tag=self._parent_id, parent=self._parent, width=self.width, height=self.height, no_scrollbar=True, no_scroll_with_mouse=True, border=False): - with dpg.tooltip(parent=self._parent_id, tag=f"tooltip_{self.runtime_id}", ): + with dpg.tooltip(parent=self._parent_id, tag=f"tooltip_{self.runtime_id}"): from research_analytics_suite.gui.modules.UpdatedOperationModule import UpdatedOperationModule - operation_view = UpdatedOperationModule(operation_dict=self._operation_info, width=300, - height=500, parent=f"tooltip_{self.runtime_id}") + operation_view = UpdatedOperationModule(operation_dict=self._operation_info, width=200, + height=100, parent=f"tooltip_{self.runtime_id}") operation_view.draw() with dpg.group(tag=f"slot_preview_{self.runtime_id}", parent=self._parent_id, horizontal=True, horizontal_spacing=10): dpg.add_button(label="+", width=25, height=25, parent=f"slot_preview_{self.runtime_id}", - callback=lambda: print("Add new operation slot"), indent=5) + callback=lambda: self._node_manager.editors["planning_editor"].add_node( + self._operation_info), indent=5) dpg.add_text(default_value=f"{self._name}", parent=f"slot_preview_{self.runtime_id}") # with dpg.child_window(height=30, width=55, no_scrollbar=True, pos=(self.width - 115, 5)): diff --git a/research_analytics_suite/gui/modules/UpdatedOperationModule.py b/research_analytics_suite/gui/modules/UpdatedOperationModule.py index ccfb127..667ce6b 100644 --- a/research_analytics_suite/gui/modules/UpdatedOperationModule.py +++ b/research_analytics_suite/gui/modules/UpdatedOperationModule.py @@ -19,6 +19,7 @@ from research_analytics_suite.gui.GUIBase import GUIBase from research_analytics_suite.operation_manager.operations.core.execution import action_serialized + class UpdatedOperationModule(GUIBase): def __init__(self, operation_dict: dict, width: int, height: int, parent: str): @@ -53,62 +54,63 @@ async def _update_async(self) -> None: pass def draw(self): - with dpg.child_window(tag=self._parent_id, parent=self._parent, width=self.width, height=self.height, - border=False): - # Upper Region - with dpg.group(tag=f"upper_{self._runtime_id}", parent=self._parent_id, width=-1): - with dpg.group(horizontal=True, tag=f"basic_{self._runtime_id}", - parent=f"upper_{self._runtime_id}", horizontal_spacing=20, width=-1): - dpg.add_text(default_value=f"v{self._version}", indent=10) - dpg.add_input_text(default_value=self._name, width=-1) - - with dpg.child_window(label="Details", - parent=f"upper_{self._runtime_id}", border=True, width=-1, height=65, - no_scrollbar=True): - with dpg.group(horizontal=True, width=-1, horizontal_spacing=20, height=-1, - tag=f"details_{self._runtime_id}"): - with dpg.group(parent=f"details_{self._runtime_id}", width=100, height=-1): - dpg.add_text(default_value=self._author, indent=10) - with dpg.group(parent=f"details_{self._runtime_id}", width=100, height=-1): - dpg.add_input_text(default_value=self._github) - dpg.add_input_text(default_value=self._email) - - with dpg.child_window(label="More Details", height=146, width=-1, no_scrollbar=True, - parent=f"upper_{self._runtime_id}", border=True): - with dpg.group(horizontal=True, tag=f"more_details_{self._runtime_id}", width=200, - horizontal_spacing=10): - with dpg.group(label="Description", tag=f"description_{self._runtime_id}"): - dpg.add_text(default_value="Description", indent=10) - dpg.add_input_text(default_value=self._description, multiline=True, width=-1, height=74) - with dpg.group(label="Output", tag=f"output_{self._runtime_id}", width=-1, height=124): - dpg.add_text(default_value="Output", indent=5) - dpg.add_listbox(items=["Type1", "Type2", "Type3", "Type4"], num_items=3, - width=-1) - dpg.add_separator(label="Options") - - with dpg.group(horizontal=True, tag=f"options_{self._runtime_id}", horizontal_spacing=40): - dpg.add_checkbox(label="Loop", default_value=self._is_loop, indent=15) - dpg.add_checkbox(label="CPU", default_value=self._is_cpu_bound) - dpg.add_checkbox(label="Parallel", default_value=self._is_parallel) - - # Middle Region - with dpg.group(horizontal=True, tag=f"middle_{self._runtime_id}", - parent=self._parent_id, height=120, horizontal_spacing=5): - with dpg.child_window(label="Required Inputs", no_scrollbar=True, width=100, - border=True, parent=f"middle_{self._runtime_id}"): - dpg.add_text(default_value="Req. Input", indent=10) - req_input_list = [ - f"{value}" for _, value in self._required_inputs.items()] if self._required_inputs else [] - dpg.add_listbox(items=req_input_list, num_items=3, width=-1) - - with dpg.child_window(label="Inherited Ops", no_scrollbar=True, border=True): - dpg.add_text(default_value="Inherited Ops", indent=10) - dpg.add_listbox(items=self._inheritance, num_items=3, width=-1) - - # Lower Region - with dpg.group(tag=f"action_{self._runtime_id}", parent=self._parent_id): - dpg.add_text(default_value="Action", indent=10) - dpg.add_input_text(default_value=self._action, multiline=True, width=-1, height=-1) + with dpg.group(tag=self._parent_id, parent=self._parent, height=self.height): + self.draw_upper_region(self._parent_id, width=self.width) + self.draw_details_region(self._parent_id, width=self.width) + self.draw_middle_region(self._parent_id, width=self.width) + self.draw_lower_region(self._parent_id, width=self.width) + + def draw_upper_region(self, parent, width=200): + # with dpg.group(tag=f"upper_{self._runtime_id}", parent=parent, width=300): + with dpg.group(horizontal=True, tag=f"basic_{self._runtime_id}", + parent=parent, horizontal_spacing=20, width=width): + dpg.add_text(default_value=f"v{self._version}", indent=10) + dpg.add_input_text(default_value=self._name) + + with dpg.group(horizontal=True, parent=parent, width=width, horizontal_spacing=20, height=65, + tag=f"details_{self._runtime_id}"): + dpg.add_text(default_value=self._author, indent=10) + with dpg.group(height=-1): + dpg.add_input_text(default_value=self._github) + dpg.add_input_text(default_value=self._email) + + def draw_details_region(self, parent, width=200): + with dpg.group(horizontal=True, tag=f"more_details_{self._runtime_id}", width=width*.6, + horizontal_spacing=15, parent=parent): + with dpg.group(label="Description", tag=f"description_{self._runtime_id}"): + dpg.add_text(default_value="Description", indent=10) + dpg.add_text(default_value=self._description, wrap=width//2+30) + + with dpg.group(label="Output", tag=f"output_{self._runtime_id}", parent=f"more_details_{self._runtime_id}", + width=width): + dpg.add_text(default_value="Output", indent=5) + dpg.add_listbox(items=[], num_items=3) + # dpg.add_separator(label="Options", parent=parent) + + with dpg.group(horizontal=True, tag=f"options_{self._runtime_id}", horizontal_spacing=35, parent=parent, + width=width): + dpg.add_checkbox(label="Loop", default_value=self._is_loop, indent=10) + dpg.add_checkbox(label="CPU", default_value=self._is_cpu_bound) + dpg.add_checkbox(label="Parallel", default_value=self._is_parallel) + + def draw_middle_region(self, parent, width=200): + with dpg.group(horizontal=True, tag=f"middle_{self._runtime_id}", + parent=parent, horizontal_spacing=5): + with dpg.group(label="Required Inputs", parent=f"middle_{self._runtime_id}", width=width*.65): + dpg.add_text(default_value="Input", indent=10) + req_input_list = [ + f"{value}" for _, value in self._required_inputs.items()] if self._required_inputs else [] + dpg.add_listbox(items=req_input_list, num_items=3) + + with dpg.group(label="Inherited Ops", width=width*.65): + dpg.add_text(default_value="Inherited Ops", indent=10) + dpg.add_listbox(items=self._inheritance, num_items=3) + + def draw_lower_region(self, parent, width=200): + dpg.add_text(default_value="Action", parent=parent, indent=10) + with dpg.group(parent=parent, tag=f"action_group_{self._runtime_id}"): + dpg.add_input_text(default_value=self._action, multiline=True, tab_input=True, + height=100) async def resize_gui(self, new_width: int, new_height: int) -> None: """Resizes the GUI."""