UX improvements

This commit is contained in:
Lera Elvoé 2023-12-13 18:01:20 +03:00
parent 0d7567e636
commit 6c804851a7
No known key found for this signature in database
5 changed files with 127 additions and 47 deletions

View file

@ -33,6 +33,7 @@ var group_output_node: String
#var group_node: String #var group_node: String
var emit_group_signals: bool = true var emit_group_signals: bool = true
var emit_node_added_signal: bool = true
## Emitted when a node has been added to this deck. ## Emitted when a node has been added to this deck.
signal node_added(node: DeckNode) signal node_added(node: DeckNode)
@ -74,7 +75,9 @@ func add_node_inst(node: DeckNode, assign_id: String = "", assign_to_self: bool
nodes[assign_id] = node nodes[assign_id] = node
node._id = assign_id node._id = assign_id
node_added.emit(node) if emit_node_added_signal:
node_added.emit(node)
if is_group && emit_group_signals: if is_group && emit_group_signals:
node_added_to_group.emit(node, node._id, assign_to_self, self) node_added_to_group.emit(node, node._id, assign_to_self, self)
@ -215,6 +218,7 @@ func group_nodes(nodes_to_group: Array) -> Deck:
midpoint /= nodes_to_group.size() midpoint /= nodes_to_group.size()
emit_node_added_signal = false
var _group_node := add_node_type("group_node") var _group_node := add_node_type("group_node")
_group_node.group_id = group.id _group_node.group_id = group.id
_group_node.group_instance_id = group.instance_id _group_node.group_instance_id = group.instance_id
@ -222,6 +226,8 @@ func group_nodes(nodes_to_group: Array) -> Deck:
_group_node.position.y = midpoint.y _group_node.position.y = midpoint.y
_group_node.position_updated.emit(_group_node.position) _group_node.position_updated.emit(_group_node.position)
#group.group_node = _group_node._id #group.group_node = _group_node._id
node_added.emit(_group_node)
emit_node_added_signal = true
var input_node := group.add_node_type("group_input") var input_node := group.add_node_type("group_input")
var output_node := group.add_node_type("group_output") var output_node := group.add_node_type("group_output")

View file

@ -110,14 +110,18 @@ static func close_all_group_instances(group_id: String) -> void:
decks.erase(group_id) decks.erase(group_id)
## Unloads a deck. ## Unloads a deck. Returns a list of groups that are closed as a result of
static func close_deck(deck_id: String) -> void: ## closing this deck.
static func close_deck(deck_id: String) -> Array:
if decks.get(deck_id) is Deck: if decks.get(deck_id) is Deck:
var deck: Deck = decks[deck_id] as Deck var deck: Deck = decks[deck_id] as Deck
var groups := deck.get_referenced_groups() var groups := deck.get_referenced_groups()
for group in groups: for group in groups:
close_all_group_instances(group) close_all_group_instances(group)
decks.erase(deck_id) decks.erase(deck_id)
return groups
return []
static func send_event(event_name: StringName, event_data: Dictionary = {}) -> void: static func send_event(event_name: StringName, event_data: Dictionary = {}) -> void:

View file

@ -62,7 +62,13 @@ func _ready() -> void:
tab_container.tab_close_requested.connect( tab_container.tab_close_requested.connect(
func(tab: int): func(tab: int):
DeckHolder.close_deck(tab_container.get_tab_metadata(tab)) var groups := DeckHolder.close_deck(tab_container.get_tab_metadata(tab, "id"))
# close tabs associated with this deck's groups
for group in groups:
for c_tab in tab_container.get_tab_count():
if tab_container.get_tab_metadata(c_tab, "id") == group:
tab_container.close_tab(tab)
await get_tree().process_frame
tab_container.close_tab(tab) tab_container.close_tab(tab)
) )
@ -72,7 +78,6 @@ func _ready() -> void:
Connections.twitch.chat_socket.chat_received_rich.connect(Connections._twitch_chat_received) Connections.twitch.chat_socket.chat_received_rich.connect(Connections._twitch_chat_received)
file_popup_menu.set_item_shortcut(FileMenuId.NEW, new_deck_shortcut) file_popup_menu.set_item_shortcut(FileMenuId.NEW, new_deck_shortcut)
file_popup_menu.set_item_shortcut(FileMenuId.OPEN, open_deck_shortcut) file_popup_menu.set_item_shortcut(FileMenuId.OPEN, open_deck_shortcut)
file_popup_menu.set_item_shortcut(FileMenuId.SAVE, save_deck_shortcut) file_popup_menu.set_item_shortcut(FileMenuId.SAVE, save_deck_shortcut)
@ -94,14 +99,16 @@ func _on_file_id_pressed(id: int) -> void:
open_save_dialog("res://") open_save_dialog("res://")
FileMenuId.CLOSE: FileMenuId.CLOSE:
close_current_tab() close_current_tab()
_ when id in range(FileMenuId.RECENTS, FileMenuId.RECENTS + max_recents + 1):
open_deck_at_path(file_popup_menu.get_item_text(id))
## Adds an empty [DeckRendererGraphEdit] with a corresponding [Deck] for it's data. ## Adds an empty [DeckRendererGraphEdit] with a corresponding [Deck] for it's data.
func add_empty_deck() -> void: func add_empty_deck() -> void:
var deck := DeckHolder.add_empty_deck() var deck := DeckHolder.add_empty_deck()
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate() var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
inst.deck = deck inst.deck = deck
tab_container.add_content(inst, "Deck %s" % (tab_container.get_tab_count() + 1)) tab_container.add_content(inst, "<unsaved deck>")
tab_container.set_tab_metadata(tab_container.get_current_tab(), deck.id) tab_container.set_tab_metadata(tab_container.get_current_tab(), "id", deck.id)
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
## Closes the current tab in [member tab_container] ## Closes the current tab in [member tab_container]
@ -135,22 +142,35 @@ func _on_file_dialog_save_file(path: String) -> void:
return return
deck.save_path = path deck.save_path = path
tab_container.set_tab_title(tab_container.get_current_tab(), path.get_file())
# TODO: put this into DeckHolder instead
var json := JSON.stringify(deck.to_dict(), "\t") var json := JSON.stringify(deck.to_dict(), "\t")
var f := FileAccess.open(path, FileAccess.WRITE) var f := FileAccess.open(path, FileAccess.WRITE)
f.store_string(json) f.store_string(json)
add_recent_file(get_active_deck().save_path)
## Connected to [signal FileDialog.open_files] on [member file_dialog]. Opens ## Connected to [signal FileDialog.open_files] on [member file_dialog]. Opens
## the selected paths, instantiating [DeckRenderGraphEdit]s and [Deck]s for each. ## the selected paths, instantiating [DeckRenderGraphEdit]s and [Deck]s for each.
func _on_file_dialog_open_files(paths: PackedStringArray) -> void: func _on_file_dialog_open_files(paths: PackedStringArray) -> void:
for path in paths: for path in paths:
var deck := DeckHolder.open_deck_from_file(path) open_deck_at_path(path)
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
inst.deck = deck
tab_container.add_content(inst, "Deck %s" % (tab_container.get_tab_count() + 1)) func open_deck_at_path(path: String) -> void:
tab_container.set_tab_metadata(tab_container.get_current_tab(), deck.id) for tab in tab_container.get_tab_count():
inst.initialize_from_deck() if tab_container.get_tab_metadata(tab, "path") == path:
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) tab_container.set_current_tab(tab)
add_recent_file(path) return
var deck := DeckHolder.open_deck_from_file(path)
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
inst.deck = deck
tab_container.add_content(inst, path.get_file())
tab_container.set_tab_metadata(tab_container.get_current_tab(), "id", deck.id)
inst.initialize_from_deck()
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
add_recent_file(path)
## Gets the currently active [Deck] from [member tab_container] ## Gets the currently active [Deck] from [member tab_container]
func get_active_deck() -> Deck: func get_active_deck() -> Deck:
@ -167,6 +187,7 @@ func save_active_deck() -> void:
var json := JSON.stringify(get_active_deck().to_dict(), "\t") var json := JSON.stringify(get_active_deck().to_dict(), "\t")
var f := FileAccess.open(get_active_deck().save_path, FileAccess.WRITE) var f := FileAccess.open(get_active_deck().save_path, FileAccess.WRITE)
f.store_string(json) f.store_string(json)
add_recent_file(get_active_deck().save_path)
## Disconnects the [FileDialog] signals if they are already connected. ## Disconnects the [FileDialog] signals if they are already connected.
func disconnect_file_dialog_signals() -> void: func disconnect_file_dialog_signals() -> void:
@ -181,12 +202,16 @@ func disconnect_file_dialog_signals() -> void:
## a corresponding tab to [member tab_container] ## a corresponding tab to [member tab_container]
func _on_deck_renderer_group_enter_requested(group_id: String) -> void: func _on_deck_renderer_group_enter_requested(group_id: String) -> void:
#var group_deck := deck.get_group(group_id) #var group_deck := deck.get_group(group_id)
for tab in tab_container.get_tab_count():
if tab_container.get_tab_metadata(tab, "id") == group_id:
tab_container.set_current_tab(tab)
return
var group_deck := DeckHolder.get_deck(group_id) var group_deck := DeckHolder.get_deck(group_id)
var deck_renderer: DeckRendererGraphEdit = DECK_SCENE.instantiate() var deck_renderer: DeckRendererGraphEdit = DECK_SCENE.instantiate()
deck_renderer.deck = group_deck deck_renderer.deck = group_deck
deck_renderer.initialize_from_deck() deck_renderer.initialize_from_deck()
tab_container.add_content(deck_renderer, "Group %s" % (tab_container.get_tab_count() + 1)) tab_container.add_content(deck_renderer, "(g) %s" % group_id.left(8))
tab_container.set_tab_metadata(tab_container.get_current_tab(), group_id) tab_container.set_tab_metadata(tab_container.get_current_tab(), "id", group_id)
deck_renderer.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) deck_renderer.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
@ -228,7 +253,7 @@ func _on_debug_decks_viewer_item_pressed(deck_id: String, instance_id: String) -
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate() var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
inst.deck = deck inst.deck = deck
tab_container.add_content(inst, "<Deck %s>" % [deck_id.left(8)]) tab_container.add_content(inst, "<Deck %s>" % [deck_id.left(8)])
tab_container.set_tab_metadata(tab_container.get_current_tab(), deck.id) tab_container.set_tab_metadata(tab_container.get_current_tab(), "id", deck.id)
inst.initialize_from_deck() inst.initialize_from_deck()
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
else: else:
@ -236,7 +261,7 @@ func _on_debug_decks_viewer_item_pressed(deck_id: String, instance_id: String) -
var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate() var inst: DeckRendererGraphEdit = DECK_SCENE.instantiate()
inst.deck = deck inst.deck = deck
tab_container.add_content(inst, "<Group %s::%s>" % [deck_id.left(8), instance_id.left(8)]) tab_container.add_content(inst, "<Group %s::%s>" % [deck_id.left(8), instance_id.left(8)])
tab_container.set_tab_metadata(tab_container.get_current_tab(), deck.id) tab_container.set_tab_metadata(tab_container.get_current_tab(), "id", deck.id)
inst.initialize_from_deck() inst.initialize_from_deck()
inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested) inst.group_enter_requested.connect(_on_deck_renderer_group_enter_requested)
@ -257,11 +282,32 @@ func add_recents_to_menu() -> void:
return return
if file_popup_menu.get_item_count() > FileMenuId.RECENTS + 1: if file_popup_menu.get_item_count() > FileMenuId.RECENTS + 1:
for i in range(FileMenuId.RECENTS, file_popup_menu.get_item_count() - FileMenuId.RECENTS + 1): var end := file_popup_menu.get_item_count() - FileMenuId.RECENTS - 1
file_popup_menu.remove_item(i) for i in end:
file_popup_menu.remove_item(file_popup_menu.get_item_count() - 1)
for i in recent_files: var reduce_length := recent_files.any(func(x: String): return x.length() > 35)
file_popup_menu.add_item(i)
for i in recent_files.size():
var file = recent_files[i] as String
if reduce_length:
# shorten the basepath to be the first letter of all folders
var base: String = Array(
file.get_base_dir().split("/", false)
).reduce(
func(a: String, s: String):
return a + s[0] + "/",
"/")
var filename := file.get_file()
file = base.path_join(filename)
file_popup_menu.add_item(file)
var s := Shortcut.new()
var k := InputEventKey.new()
k.keycode = KEY_1 + i
k.ctrl_pressed = true
s.events.append(k)
file_popup_menu.set_item_shortcut(file_popup_menu.get_item_count() - 1, s)
RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_files", recent_files) RendererPersistence.set_value(PERSISTENCE_NAMESPACE, "config", "recent_files", recent_files)
RendererPersistence.commit(PERSISTENCE_NAMESPACE) RendererPersistence.commit(PERSISTENCE_NAMESPACE)

View file

@ -19,6 +19,8 @@ func _ready() -> void:
update_port(port) update_port(port)
position_offset_changed.connect(_on_position_offset_changed) position_offset_changed.connect(_on_position_offset_changed)
node.renamed.connect(_on_node_renamed) node.renamed.connect(_on_node_renamed)
if node.node_type == "group_node":
get_titlebar_hbox().tooltip_text = "Group %s" % node.group_id.left(8)
## Connected to [signal GraphElement.position_offset_updated] and updates the ## Connected to [signal GraphElement.position_offset_updated] and updates the
## [member node]s properties ## [member node]s properties

View file

@ -3,32 +3,34 @@ class_name TabContainerCustom
## Custom Recreation of [TabContainer] for Flexibility ## Custom Recreation of [TabContainer] for Flexibility
## ##
## Allows for more customizability within the [TabBar] thats used mainly. Extra buttons etc. ## Alternative to [TabContainer]. Instead of using the tree hierarchy to add tabs directly,
## tabs must be created by script.
## Reference to the [TabBar] at the top of the Container. ## Reference to the [TabBar] at the top of the container.
@onready var tab_bar: TabBar = %TabBar @onready var tab_bar: TabBar = %TabBar
## Reference to the [Button] at the end of the [TabBar] that's ## Reference to the [Button] at the end of the [TabBar] that's
## used for adding new Tabs ## used for adding new tabs.
@onready var add_tab_button: Button = %Button @onready var add_tab_button: Button = %Button
## Reference to the [MarginContainer] around the Tabs Contents. ## Reference to the [MarginContainer] around the tab's contents.
@onready var content_container: MarginContainer = %ContentContainer @onready var content_container: MarginContainer = %ContentContainer
## Emitted when the add [Button] within [member tab_bar] is pressed ## Emitted when the add [Button] within [member tab_bar] is pressed.
signal add_button_pressed signal add_button_pressed
## Emitted when the current tab in [member tab_bar] is changed. ## Emitted when the current tab in [member tab_bar] is changed.
signal tab_changed(tab: int) signal tab_changed(tab: int)
## Emitted when a tab in [member tab_bar] has been closed. ## Emitted when a tab in [member tab_bar] has been closed.
## See [signal TabBar.tab_close_requested] ## See [signal TabBar.tab_close_requested]
signal tab_closed(tab: int) signal tab_closed(tab: int)
## Emitted when a request to close a tab in the [member tab_bar] has been ## Emitted when a request to close a tab in the [member tab_bar] has been requested.
## requested using [signal TabBar.tab_close_pressed]
signal tab_close_requested(tab: int) signal tab_close_requested(tab: int)
## Emitted when the order of the tabs in [member tab_bar] has been changed. ## Emitted when the order of the tabs in [member tab_bar] has been changed.
signal tab_rearranged(old: int, new: int) signal tab_rearranged(old: int, new: int)
## Holds the previously active tab in [member tab_bar] # Holds the previously active tab in the internal tab_bar
var _previous_active_tab: int = -1 var _previous_active_tab: int = -1
var _tab_metadata: Dictionary #Dictionary[int -> tab idx, Dictionary[String -> key, Variant]]
func _ready() -> void: func _ready() -> void:
tab_bar.tab_selected.connect( tab_bar.tab_selected.connect(
@ -58,44 +60,64 @@ func _ready() -> void:
_previous_active_tab = idx_to _previous_active_tab = idx_to
) )
## Adds the given [Node] as "content" for the given tabs name as a [String] ## Adds the given [Node] as the displayed content for a tab.
func add_content(c: Node, tab_title: String) -> void: func add_content(c: Node, tab_title: String) -> void:
tab_bar.add_tab(tab_title) tab_bar.add_tab(tab_title)
content_container.add_child(c) content_container.add_child(c)
tab_bar.set_current_tab(tab_bar.tab_count - 1) tab_bar.set_current_tab(tab_bar.tab_count - 1)
## Returns the count of tabs in [member tab_bar]
## Updates the tab at index [param tab_idx]'s title to [param title].
func set_tab_title(tab_idx: int, title: String) -> void:
tab_bar.set_tab_title(tab_idx, title)
## Returns the number of tabs.
func get_tab_count() -> int: func get_tab_count() -> int:
return tab_bar.tab_count return tab_bar.tab_count
## Returns [code]true[/code] if [method get_tab_count] returns 0.
## Returns [code]true[/code] if the tab bar has no tabs.
func is_empty() -> bool: func is_empty() -> bool:
return get_tab_count() == 0 return get_tab_count() == 0
## Closes the tab that is at the given [param tab] in [member tab_bar]
## Closes a tab at the index [param tab].
func close_tab(tab: int) -> void: func close_tab(tab: int) -> void:
content_container.get_child(tab).queue_free() content_container.get_child(tab).queue_free()
if !tab_bar.select_previous_available(): if !tab_bar.select_previous_available():
tab_bar.select_next_available() tab_bar.select_next_available()
tab_bar.remove_tab(tab) tab_bar.remove_tab(tab)
_tab_metadata.erase(tab)
tab_closed.emit(tab) tab_closed.emit(tab)
if tab_bar.tab_count == 0: if tab_bar.tab_count == 0:
_previous_active_tab = -1 _previous_active_tab = -1
## Returns the currently selected tab in [member tab_bar]
## Returns the currently selected tab.
func get_current_tab() -> int: func get_current_tab() -> int:
return tab_bar.current_tab return tab_bar.current_tab
## Returns the child of [member content_container] at the given [param idx]
## Sets the current tab to the tab at [param idx].
func set_current_tab(idx: int) -> void:
tab_bar.current_tab = idx
## Returns the child of [member content_container] at the [param idx].
func get_content(idx: int) -> Control: func get_content(idx: int) -> Control:
return content_container.get_child(idx) return content_container.get_child(idx)
## Sets the metadata value for the tab at index [param tab_idx], which can be
## retrieved later using [method TabBar.get_tab_metadata()]
func set_tab_metadata(tab: int, metadata: Variant) -> void:
tab_bar.set_tab_metadata(tab, metadata)
## Returns the metadata value set to the tab at index [param tab_idx] using set_tab_metadata(). ## Sets the metadata value for the tab at index [param tab_idx] at [param key], which can be
## If no metadata was previously set, returns null by default. ## retrieved later using [method get_tab_metadata].
func get_tab_metadata(tab: int) -> Variant: func set_tab_metadata(tab: int, key: String, value: Variant) -> void:
return tab_bar.get_tab_metadata(tab) var m = _tab_metadata.get(tab, {})
m[key] = value
_tab_metadata[tab] = m
## Returns the metadata value set to the tab at index [param tab_idx] using [method set_tab_metadata].
## If no metadata was previously set, returns [code]null[/code] by default.
func get_tab_metadata(tab: int, key: String) -> Variant:
var m = _tab_metadata.get(tab, {})
return m.get(key)