diff --git a/graph_node_renderer/deck_holder_renderer.gd b/graph_node_renderer/deck_holder_renderer.gd index cfccbe2..b066270 100644 --- a/graph_node_renderer/deck_holder_renderer.gd +++ b/graph_node_renderer/deck_holder_renderer.gd @@ -170,6 +170,7 @@ func add_empty_deck() -> void: inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) inst.dirty_state_changed.connect(_on_deck_renderer_dirty_state_changed.bind(inst)) tab_container.set_current_tab(tab) + bottom_dock.variable_viewer.enable_new_button() ## Closes the current tab in [member tab_container] func close_current_tab() -> void: @@ -185,8 +186,10 @@ func close_tab(tab: int) -> void: if tab_container.get_tab_metadata(c_tab, "id") == group: tab_container.close_tab(c_tab) await get_tree().process_frame - + tab_container.close_tab(tab) + if tab_container.get_tab_count() == 0: + bottom_dock.variable_viewer.disable_new_button() ## Opens [member file_dialog] with the mode [member FileDialog.FILE_MODE_SAVE_FILE] ## as well as getting a weakref to the active [Deck] @@ -254,6 +257,7 @@ func open_deck_at_path(path: String) -> void: recent_path = path.get_base_dir() RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_path", recent_path) tab_container.set_current_tab(tab) + bottom_dock.variable_viewer.enable_new_button() ## Returns the current deck in the [member tab_container]. diff --git a/graph_node_renderer/textures/add_icon.svg b/graph_node_renderer/textures/add_icon.svg new file mode 100644 index 0000000..afad08a --- /dev/null +++ b/graph_node_renderer/textures/add_icon.svg @@ -0,0 +1 @@ + diff --git a/graph_node_renderer/textures/add_icon.svg.import b/graph_node_renderer/textures/add_icon.svg.import new file mode 100644 index 0000000..a14b73d --- /dev/null +++ b/graph_node_renderer/textures/add_icon.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://drxi5ks3mqbnk" +path="res://.godot/imported/add_icon.svg-1a070ac229fd6d9079fc5a70a6dc355a.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://graph_node_renderer/textures/add_icon.svg" +dest_files=["res://.godot/imported/add_icon.svg-1a070ac229fd6d9079fc5a70a6dc355a.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/graph_node_renderer/variable_viewer.gd b/graph_node_renderer/variable_viewer.gd index cdeea34..8b66337 100644 --- a/graph_node_renderer/variable_viewer.gd +++ b/graph_node_renderer/variable_viewer.gd @@ -6,8 +6,10 @@ class_name VariableViewer const REMOVE_ICON = preload("res://graph_node_renderer/textures/remove-icon.svg") +@onready var new_variable_button: Button = %NewVariableButton @onready var variable_tree: Tree = %VariableTree @onready var types_popup: PopupMenu = %TypesPopup + var root: TreeItem var _old_name: String @@ -67,9 +69,9 @@ func _ready() -> void: _: new_value = item.get_meta(&"value") - item.set_meta(&"value", new_value) + #item.set_meta(&"value", new_value) - if item.get_meta(&"container", -1) is int: + if !item.has_meta(&"container"): top_field_edited.emit(_old_name, new_name, new_value) else: var container = item.get_meta(&"container") @@ -83,14 +85,23 @@ func _ready() -> void: var key := new_name (container as Dictionary).erase(_old_name) (container as Dictionary)[key] = new_value + + set_item_value(item, new_value) + ) + variable_tree.nothing_selected.connect(variable_tree.deselect_all) + variable_tree.button_clicked.connect(_on_variable_tree_button_clicked) for i in DeckType.Types.size() - 1: types_popup.add_radio_check_item(DeckType.type_str(i)) types_popup.id_pressed.connect(_on_types_popup_id_pressed) + + new_variable_button.pressed.connect(_on_new_variable_button_pressed) + + disable_new_button() func rebuild_variable_tree(data: Dictionary = {}) -> void: @@ -102,8 +113,8 @@ func rebuild_variable_tree(data: Dictionary = {}) -> void: add_item(i, data[i]) -func add_item(item_name: String, item_value: Variant, parent: TreeItem = root, container: Variant = -1, indexed: bool = false) -> TreeItem: - # the container parameter is -1 instead of null because Object#get_metadata() logs an error +func add_item(item_name: String, item_value: Variant, parent: TreeItem = root, container: Variant = null, indexed: bool = false) -> TreeItem: + # the container parameter is -1 instead of null because Object#get_meta() logs an error # if the default parameter is null var item := variable_tree.create_item(parent) item.set_text(0, item_name) @@ -122,7 +133,7 @@ func add_item(item_name: String, item_value: Variant, parent: TreeItem = root, c if item_value is Array: for i in (item_value as Array).size(): add_item(str(i), item_value[i], item, item_value, true) - item.collapsed = true + #item.collapsed = true item.add_button(2, REMOVE_ICON) return item @@ -131,7 +142,6 @@ func add_item(item_name: String, item_value: Variant, parent: TreeItem = root, c func set_item_value(item: TreeItem, value: Variant) -> void: item.set_meta(&"value", value) var type: DeckType.Types = DeckType.INVERSE_GODOT_TYPES_MAP[typeof(value)] - match type: DeckType.Types.NUMERIC: item.set_cell_mode(1, TreeItem.CELL_MODE_RANGE) @@ -143,6 +153,34 @@ func set_item_value(item: TreeItem, value: Variant) -> void: _: item.set_text(1, str(value)) + if item.has_meta(&"container"): + var container = item.get_meta(&"container") + if container is Array: + var index := item.get_index() + container[index] = value + else: + var key := item.get_text(0) + container[key] = value + + if item.get_parent() != root: + refresh_item_value(item.get_parent()) + + +func refresh_item_value(item: TreeItem) -> void: + var value = item.get_meta(&"value") + var type: DeckType.Types = DeckType.INVERSE_GODOT_TYPES_MAP[typeof(value)] + match type: + DeckType.Types.NUMERIC: + item.set_cell_mode(1, TreeItem.CELL_MODE_RANGE) + item.set_range_config(1, -9999, 9999, 0.0001) + item.set_range(1, value) + DeckType.Types.BOOL: + item.set_cell_mode(1, TreeItem.CELL_MODE_CHECK) + item.set_checked(1, value) + _: + item.set_cell_mode(1, TreeItem.CELL_MODE_STRING) + item.set_text(1, str(value)) + func _on_variable_tree_button_clicked(item: TreeItem, column: int, id: int, mouse_button_index: int) -> void: if mouse_button_index != MOUSE_BUTTON_LEFT: @@ -150,17 +188,16 @@ func _on_variable_tree_button_clicked(item: TreeItem, column: int, id: int, mous # we only have a delete button for now, so assume it is what's clicked - if item.get_meta(&"container", -1) is int: + if !item.has_meta(&"container"): var key := item.get_text(0) top_field_removed.emit(key) item.free() else: var container = item.get_meta(&"container") - + var parent := item.get_parent() # array if item.get_meta(&"indexed", false): var index := item.get_index() - var parent := item.get_parent() (container as Array).remove_at(index) item.free() @@ -172,6 +209,8 @@ func _on_variable_tree_button_clicked(item: TreeItem, column: int, id: int, mous else: (container as Dictionary).erase(item.get_text(0)) item.free() + + refresh_item_value(parent) func _on_types_popup_id_pressed(id: int) -> void: @@ -188,16 +227,54 @@ func _on_types_popup_id_pressed(id: int) -> void: # simple types that can generally be converted between each other var target_type: Variant.Type = DeckType.GODOT_TYPES_MAP[id] new_value = type_convert(current_item.get_meta(&"value"), target_type) - set_item_value(current_item, new_value) DeckType.Types.ARRAY: new_value = [] - set_item_value(current_item, new_value) + for i in current_item.get_children(): + i.free() DeckType.Types.DICTIONARY: new_value = {} - set_item_value(current_item, new_value) + for i in current_item.get_children(): + i.free() + + set_item_value(current_item, new_value) current_item.set_text(2, DeckType.type_str(id)) - if current_item.get_meta(&"container", -1) is int: + if !current_item.has_meta(&"container"): var field_name := current_item.get_text(0) top_field_edited.emit(field_name, field_name, new_value) + + +func _on_new_variable_button_pressed() -> void: + var selected := variable_tree.get_selected() + # TODO: UX impr. - if selected is part of a container, add to that container instead + # (but if selected is a container, prioritize adding to that) + if selected == null || !(selected.get_meta(&"value") is Array || selected.get_meta(&"value") is Dictionary): + # top field + var var_name := "new_variable%s" % variable_tree.get_root().get_child_count() + var new_item := add_item(var_name, "") + top_field_edited.emit(var_name, var_name, "") + new_item.select(0) + else: + var container = selected.get_meta(&"value") + if container is Dictionary: + var var_name := "new_key%s" % (container as Dictionary).size() + var new_item := add_item(var_name, "", selected, container) + new_item.select(0) + container[var_name] = "" + else: + var index := (container as Array).size() + (container as Array).append("") + var new_item := add_item(str(index), "", selected, container, true) + new_item.select(0) + refresh_item_value(selected) + + +func enable_new_button() -> void: + new_variable_button.disabled = false + new_variable_button.tooltip_text = "" + + +func disable_new_button() -> void: + new_variable_button.disabled = true + new_variable_button.tooltip_text = "There is no deck open, so you can not create a new variable.\nOpen a deck first." diff --git a/graph_node_renderer/variable_viewer.tscn b/graph_node_renderer/variable_viewer.tscn index ad1cbb9..c51e402 100644 --- a/graph_node_renderer/variable_viewer.tscn +++ b/graph_node_renderer/variable_viewer.tscn @@ -1,11 +1,12 @@ -[gd_scene load_steps=2 format=3 uid="uid://ovf5nt5pt0oj"] +[gd_scene load_steps=3 format=3 uid="uid://ovf5nt5pt0oj"] [ext_resource type="Script" path="res://graph_node_renderer/variable_viewer.gd" id="1_b5gmj"] +[ext_resource type="Texture2D" uid="uid://drxi5ks3mqbnk" path="res://graph_node_renderer/textures/add_icon.svg" id="2_15lro"] [node name="VariableViewer" type="VBoxContainer"] anchors_preset = -1 -anchor_right = 0.182292 -anchor_bottom = 0.123457 +anchor_right = 0.467014 +anchor_bottom = 0.359568 grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_b5gmj") @@ -27,3 +28,10 @@ hide_root = true [node name="TypesPopup" type="PopupMenu" parent="."] unique_name_in_owner = true + +[node name="NewVariableButton" type="Button" parent="."] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +text = "New" +icon = ExtResource("2_15lro")