From f720efcc7201c07f3548a0833eb554db4d96504f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lera=20Elvo=C3=A9?= Date: Sun, 26 May 2024 14:13:42 +0000 Subject: [PATCH] lib group storage rework (#162) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit saving decks that use lib groups will no longer save the whole file path to that library (at the expense of the structure needing to be the same) also some ui/ux improvements: - more menus in sidebar remember their collapsed state between deck/node switches - adding a lib group will name the group node appropriately - save dialog properly remembers the most recent path when invoked via ctrl+s and the deck hasn't been saved before Reviewed-on: https://codeberg.org/StreamGraph/StreamGraph/pulls/162 Co-authored-by: Lera ElvoƩ Co-committed-by: Lera ElvoƩ --- classes/deck/deck.gd | 3 +- classes/deck/deck_holder.gd | 16 +++---- classes/deck/node_db.gd | 16 +++++-- classes/deck/nodes/group/group_node.gd | 52 +++++++++++---------- graph_node_renderer/add_node_menu.gd | 19 ++++---- graph_node_renderer/deck_holder_renderer.gd | 12 +++-- graph_node_renderer/sidebar/sidebar.gd | 26 ++++++----- 7 files changed, 85 insertions(+), 59 deletions(-) diff --git a/classes/deck/deck.gd b/classes/deck/deck.gd index eba7a8c..468c856 100644 --- a/classes/deck/deck.gd +++ b/classes/deck/deck.gd @@ -175,6 +175,7 @@ func add_lib_group_node(type: String) -> DeckNode: lib.group_output_node = node._id continue group_node.init_io() + group_node.rename(NodeDB.get_library_descriptor(type).name) return group_node @@ -696,7 +697,7 @@ static func from_dict(data: Dictionary, path: String = "") -> Deck: group = DeckHolder.add_group_from_dict(group_data, group_id, group_instance_id, deck.id) else: group = DeckHolder.add_lib_instance( - node.group_id.get_file().trim_suffix(".deck"), + node.group_id.get_file(), deck.id, node.group_instance_id ) diff --git a/classes/deck/deck_holder.gd b/classes/deck/deck_holder.gd index a918eab..c1210cb 100644 --- a/classes/deck/deck_holder.gd +++ b/classes/deck/deck_holder.gd @@ -153,8 +153,8 @@ static func add_lib_instance(type: String, to_deck: String, instance_id: String var nd: NodeDB.NodeDescriptor = NodeDB.libraries[type] var path := nd.script_path var deck_data: Dictionary - if lib_groups.has(path): - deck_data = (lib_groups[path].values()[0] as Deck).to_dict() + if lib_groups.has(type): + deck_data = (lib_groups[type].values()[0] as Deck).to_dict() else: if not NodeDB.libraries.has(type): return null @@ -165,17 +165,17 @@ static func add_lib_instance(type: String, to_deck: String, instance_id: String deck_data = JSON.parse_string(f.get_as_text()) - var instances := lib_groups.get(path, {}) as Dictionary + var instances := lib_groups.get(type, {}) as Dictionary var deck := Deck.from_dict(deck_data) - deck.id = path + deck.id = type deck.instance_id = instance_id deck.is_group = true deck.is_library = true deck._belonging_to = to_deck instances[instance_id] = deck - lib_groups[path] = instances + lib_groups[type] = instances print_verbose("DeckHolder: added lib group %s::%s, id %s" % [deck.id, deck.instance_id, deck.get_instance_id()]) return deck @@ -296,20 +296,20 @@ static func pre_exit_cleanup() -> void: static func send_event(event_name: StringName, event_data: Dictionary = {}) -> void: for deck_id: String in decks: if decks[deck_id] is Deck: - var deck: Deck = (decks[deck_id] as Deck) + var deck: Deck = decks[deck_id] if not is_instance_valid(deck): continue deck.send_event(event_name, event_data) else: for deck_instance_id: String in decks[deck_id]: - var deck: Deck = (decks[deck_id][deck_instance_id] as Deck) + var deck: Deck = decks[deck_id][deck_instance_id] if not is_instance_valid(deck): continue deck.send_event(event_name, event_data) for lib_group_id: String in lib_groups: for lib_instance_id: String in lib_groups[lib_group_id]: - var deck: Deck = (lib_groups[lib_group_id][lib_instance_id] as Deck) + var deck: Deck = lib_groups[lib_group_id][lib_instance_id] if not is_instance_valid(deck): continue deck.send_event(event_name, event_data) diff --git a/classes/deck/node_db.gd b/classes/deck/node_db.gd index 6f0bc50..dda32d0 100644 --- a/classes/deck/node_db.gd +++ b/classes/deck/node_db.gd @@ -89,7 +89,7 @@ static func create_lib_descriptors(path: String) -> void: if not deck.deck.has("library"): current_file = dir.get_next() continue - var type := current_file.trim_suffix(".deck") + var type := current_file if nodes.has(type): DeckHolder.logger.toast_error("Library group '%s' collides with a node with the same type." % type) current_file = dir.get_next() @@ -113,7 +113,8 @@ static func create_lib_descriptors(path: String) -> void: true, true, ) - libraries[descriptor.type] = descriptor + descriptor.added_by_library = path + libraries[type] = descriptor current_file = dir.get_next() @@ -200,6 +201,10 @@ static func is_library(type: String) -> bool: return libraries.has(type) +static func get_library_descriptor(type: String) -> NodeDescriptor: + return libraries.get(type, null) as NodeDescriptor + + ## Returns a capitalized category string. static func get_category_capitalization(category: String) -> String: return CATEGORY_CAPITALIZATION.get(category, category.capitalize()) @@ -220,8 +225,10 @@ class NodeDescriptor: var category: String ## Whether this [DeckNode] reference will appear when searching. See [member DeckNode.appears_in_search]. var appears_in_search: bool - + ## Whether this describes a library group. var is_library: bool + ## If [member is_library] is [code]true[/code], this is the index that adds this library. + var added_by_library: String ## Stores the path to this node's script for later instantiation. var script_path: String @@ -258,6 +265,7 @@ class NodeDescriptor: "category": category, "appears_in_search": appears_in_search, "is_library": is_library, + "added_by_library": added_by_library, } return d @@ -274,5 +282,5 @@ class NodeDescriptor: data.get("appears_in_search", false), data.get("is_library", false) ) - + nd.added_by_library = data.get("added_by_library", "") return nd diff --git a/classes/deck/nodes/group/group_node.gd b/classes/deck/nodes/group/group_node.gd index e9bd452..2c02ad6 100644 --- a/classes/deck/nodes/group/group_node.gd +++ b/classes/deck/nodes/group/group_node.gd @@ -69,37 +69,41 @@ func make_unique() -> Deck: func setup_connections() -> void: - input_node.ports_updated.connect(recalculate_ports) - output_node.ports_updated.connect(recalculate_ports) + if input_node != null: + input_node.ports_updated.connect(recalculate_ports) + if output_node != null: + output_node.ports_updated.connect(recalculate_ports) func recalculate_ports() -> void: var _values := extra_port_values.duplicate() ports.clear() - for output_port: Port in output_node.get_input_ports().slice(0, output_node.get_input_ports().size() - 1): - var port := add_output_port( - output_port.type, - output_port.label, - output_port.descriptor, - output_port.usage_type, - ) - if _values.size() - 1 < port.index: - continue - - port.set_value(_values[port.index]) + if output_node != null: + for output_port: Port in output_node.get_input_ports().slice(0, output_node.get_input_ports().size() - 1): + var port := add_output_port( + output_port.type, + output_port.label, + output_port.descriptor, + output_port.usage_type, + ) + if _values.size() - 1 < port.index: + continue + + port.set_value(_values[port.index]) - for input_port: Port in input_node.get_output_ports().slice(0, input_node.get_output_ports().size() - 1): - var port := add_input_port( - input_port.type, - input_port.label, - input_port.descriptor, - input_port.usage_type, - ) - if _values.size() - 1 < port.index: - continue - - port.set_value(_values[port.index]) + if input_node != null: + for input_port: Port in input_node.get_output_ports().slice(0, input_node.get_output_ports().size() - 1): + var port := add_input_port( + input_port.type, + input_port.label, + input_port.descriptor, + input_port.usage_type, + ) + if _values.size() - 1 < port.index: + continue + + port.set_value(_values[port.index]) extra_ports.clear() extra_port_values.clear() diff --git a/graph_node_renderer/add_node_menu.gd b/graph_node_renderer/add_node_menu.gd index 0ce3fb1..ebd4ed1 100644 --- a/graph_node_renderer/add_node_menu.gd +++ b/graph_node_renderer/add_node_menu.gd @@ -40,17 +40,17 @@ func add_category(category_name: String) -> void: ## Add an item to a category. -func add_category_item(category: String, item: String, tooltip: String = "", favorite: bool = false, library: bool = false) -> void: +func add_category_item(category: String, item: String, type: String, tooltip: String = "", favorite: bool = false, library: bool = false) -> void: var c: Category = categories[category] - c.add_item(item, tooltip, favorite, library) + c.add_item(item, tooltip, type, favorite, library) ## Wrapper around [method add_category_item] and [method add_category]. Adds an item to a [param category], creating the category if it doesn't exist yet. -func add_item(category: String, item: String, tooltip: String = "", favorite: bool = false, library: bool = false) -> void: +func add_item(category: String, item: String, type: String, tooltip: String = "", favorite: bool = false, library: bool = false) -> void: if not categories.has(category): add_category(category) - add_category_item(category, item, tooltip, favorite, library) + add_category_item(category, item, type, tooltip, favorite, library) ## Get a [AddNodeMenu.Category] node by its' identifier. @@ -74,7 +74,7 @@ func search(text: String) -> void: return for nd in search_results: - add_item(nd.category, nd.name, nd.description, NodeDB.is_node_favorite(nd.type), nd.is_library) + add_item(nd.category, nd.name, nd.type, nd.description, NodeDB.is_node_favorite(nd.type), nd.is_library) var c := get_category(nd.category) c.set_item_metadata(c.get_item_count() - 1, "type", nd.type) c.set_item_metadata(c.get_item_count() - 1, "node_descriptor", weakref(nd)) @@ -231,8 +231,8 @@ class Category extends VBoxContainer: ## Add an item to the category. - func add_item(p_name: String, p_tooltip: String, p_favorite: bool = false, p_library: bool = false) -> void: - var item := CategoryItem.new(p_name, p_tooltip, p_favorite, p_library) + func add_item(p_name: String, p_tooltip: String, p_type: String, p_favorite: bool = false, p_library: bool = false) -> void: + var item := CategoryItem.new(p_name, p_tooltip, p_favorite, p_library, p_type) item.favorite_toggled.connect( func(toggled: bool): item_favorite_button_toggled.emit(item.get_index(), toggled) @@ -321,7 +321,7 @@ class CategoryItem extends HBoxContainer: signal favorite_toggled(toggled: bool) - func _init(p_name: String, p_tooltip: String, p_favorite: bool, p_library: bool) -> void: + func _init(p_name: String, p_tooltip: String, p_favorite: bool, p_library: bool, p_type: String) -> void: fav_button = Button.new() fav_button.icon = FAVORITE_ICON if p_favorite else NON_FAVORITE_ICON fav_button.toggle_mode = true @@ -358,11 +358,14 @@ class CategoryItem extends HBoxContainer: inner_hb.add_child(name_button) if p_library: + var nd := NodeDB.get_library_descriptor(p_type) group_texture_rect = TextureRect.new() group_texture_rect.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED group_texture_rect.custom_minimum_size = Vector2(12, 12) group_texture_rect.texture = GROUP_ICON group_texture_rect.tooltip_text = "This is a library group. It will create a group node." + group_texture_rect.tooltip_text += "\nAdded by %s" % nd.added_by_library + inner_hb.add_child(group_texture_rect) var m := MarginContainer.new() m.add_theme_constant_override(&"margin_right", 6) diff --git a/graph_node_renderer/deck_holder_renderer.gd b/graph_node_renderer/deck_holder_renderer.gd index 15fff0a..7ae6d70 100644 --- a/graph_node_renderer/deck_holder_renderer.gd +++ b/graph_node_renderer/deck_holder_renderer.gd @@ -324,7 +324,7 @@ func close_tab(tab: int) -> void: func open_save_dialog(path: String) -> void: file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE file_dialog.title = "Save a Deck" - file_dialog.current_path = path + file_dialog.current_path = path if not path.is_empty() else recent_path _deck_to_save = weakref(get_active_deck()) file_dialog.popup_centered() file_dialog.file_selected.connect(_on_file_dialog_save_file, CONNECT_ONE_SHOT) @@ -451,7 +451,8 @@ func save_tab(tab: int) -> void: var renderer := tab_container.get_content(tab) as DeckRendererGraphEdit var deck := renderer.deck if deck.save_path.is_empty(): - open_save_dialog("res://") + #open_save_dialog("res://") # what the fuck? + open_save_dialog(tab_container.get_tab_metadata(tab, "path", recent_path)) else: var json := JSON.stringify(deck.to_dict(), "\t") var f := FileAccess.open(deck.save_path, FileAccess.WRITE) @@ -485,7 +486,12 @@ func _on_deck_renderer_group_enter_requested(group_id: String) -> void: var deck_renderer: DeckRendererGraphEdit = DECK_SCENE.instantiate() deck_renderer.deck = group_deck deck_renderer.initialize_from_deck() - var tab := tab_container.add_content(deck_renderer, "(g) %s" % group_id.left(8)) + var title := "" + if group_deck.is_library: + title = "(L) %s" % group_deck.id + else: + title = "(G) %s" % group_id.left(8) + var tab := tab_container.add_content(deck_renderer, title) tab_container.set_tab_metadata(tab, "id", group_id) tab_container.set_tab_metadata(tab, "group", true) deck_renderer.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) diff --git a/graph_node_renderer/sidebar/sidebar.gd b/graph_node_renderer/sidebar/sidebar.gd index f067469..6ad7368 100644 --- a/graph_node_renderer/sidebar/sidebar.gd +++ b/graph_node_renderer/sidebar/sidebar.gd @@ -136,6 +136,8 @@ func set_edited_node(id: String = "") -> void: static func create_menu(title: String, id: String, default_collapsed: bool = false) -> AccordionMenu: + if id.is_empty(): + id = title var res := AccordionMenu.new() res.set_title(title) res.collapsed = collapsed_menus.get(id, default_collapsed) @@ -190,14 +192,15 @@ class DeckInspector: ref = weakref(DeckHolder.get_deck(id)) var deck: Deck = ref.get_ref() as Deck - var lib_menu := AccordionMenu.new() - lib_menu.set_title("Library Group") + #var lib_menu := AccordionMenu.new() + #lib_menu.set_title("Library Group") + var lib_menu := Sidebar.create_menu("Library Group", "lib_group", true) var lib_group_text: String if deck.is_library: lib_group_text = "This deck is open as a library group. You may not edit it here.\nTo edit it, you have to open the file it's in." elif not deck.is_group: - lib_group_text = "You may save this deck as a Library Group to reuse it in future decks.\nYou may edit how it will appear." + lib_group_text = "You may save this deck as a Library Group to reuse it in future decks.\nYou may edit how it will appear in search results." else: lib_group_text = "This deck is a group." @@ -247,8 +250,9 @@ class GroupDescriptorsInspector: func _init(p_deck: Deck) -> void: deck = p_deck - menu = AccordionMenu.new() - menu.set_title("Group Inputs/Outputs") + #menu = AccordionMenu.new() + #menu.set_title("Group Inputs/Outputs") + menu = Sidebar.create_menu("Group Inputs/Outputs", "group_io", true) inputs_menu = Sidebar.create_menu("Inputs", "group_inputs", true) outputs_menu = Sidebar.create_menu("Outputs", "group_outputs", true) @@ -471,14 +475,15 @@ class NodeInspector: func add_port_menu(ports: Array[Port], node: DeckNode) -> void: if ports.is_empty(): return - var ports_menu := AccordionMenu.new() - ports_menu.draw_background = true var is_output := ports[0].port_type == DeckNode.PortType.OUTPUT - ports_menu.set_title("Output Ports" if is_output else "Input Ports") + var ports_menu := Sidebar.create_menu("Output Ports" if is_output else "Input Ports", "", false) + ports_menu.draw_background = true for port in ports: - var acc := AccordionMenu.new() + #var acc := AccordionMenu.new() + var id = "output_%s_menu" if is_output else "input_%s_menu" + var acc := Sidebar.create_menu("Port %s" % port.index_of_type, id % port.index_of_type, true) acc.draw_background = true - acc.set_title("Port %s" % port.index_of_type) + #acc.set_title("Port %s" % port.index_of_type) var label_label := DeckInspector.create_label("Name: %s" % port.label) acc.add_child(label_label) @@ -505,5 +510,4 @@ class NodeInspector: acc.add_child(port_hb) ports_menu.add_child(acc) - ports_menu.collapsed = true nodes.append(ports_menu)