# (c) 2023-present Eroax # (c) 2023-present Yagich # GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) extends VBoxContainer class_name TabContainerCustom ## Custom Recreation of [TabContainer] for Flexibility ## ## 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. @onready var tab_bar: TabBar = %TabBar ## Reference to the [Button] at the end of the [TabBar] that's ## used for adding new tabs. @onready var add_tab_button: Button = %Button ## Reference to the [MarginContainer] around the tab's contents. @onready var content_container: MarginContainer = %ContentContainer ## Emitted when the add [Button] within [member tab_bar] is pressed. signal add_button_pressed ## Emitted when the current tab in [member tab_bar] is changed. signal tab_changed(tab: int) ## Emitted just before the current tab in [member tab_bar] is changed. signal tab_about_to_change(previous_tab: int) ## Emitted when a tab in [member tab_bar] has been closed. ## See [signal TabBar.tab_close_requested] signal tab_closed(tab: int) ## Emitted when a request to close a tab in the [member tab_bar] has been requested. signal tab_close_requested(tab: int) ## Emitted when the order of the tabs in [member tab_bar] has been changed. signal tab_rearranged(old: int, new: int) # Holds the previously active tab in the internal tab_bar var _previous_active_tab: int = -1 var _tab_metadata: Array[Dictionary] #Array[Dictionary[String -> key, Variant]] func _ready() -> void: tab_bar.tab_selected.connect( func(tab: int): if _previous_active_tab == tab: return tab_about_to_change.emit(_previous_active_tab) if _previous_active_tab > -1: content_container.get_child(_previous_active_tab).visible = false content_container.get_child(tab).visible = true tab_changed.emit(tab) _previous_active_tab = tab ) tab_bar.tab_close_pressed.connect(func(tab: int): tab_close_requested.emit(tab)) add_tab_button.pressed.connect( func(): add_button_pressed.emit() ) tab_bar.active_tab_rearranged.connect( func(idx_to: int): var old := _tab_metadata[_previous_active_tab] var new := _tab_metadata[idx_to] _tab_metadata[idx_to] = old _tab_metadata[_previous_active_tab] = new tab_rearranged.emit(_previous_active_tab, idx_to) content_container.move_child(content_container.get_child(_previous_active_tab), idx_to) _previous_active_tab = idx_to ) ## Adds the given [Node] as the displayed content for a tab. func add_content(c: Node, tab_title: String) -> int: tab_bar.add_tab(tab_title) content_container.add_child(c) #tab_bar.set_current_tab(tab_bar.tab_count - 1) _tab_metadata.append({}) return tab_bar.tab_count - 1 ## 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) func get_tab_title(tab_idx: int) -> String: return tab_bar.get_tab_title(tab_idx) ## Returns the number of tabs. func get_tab_count() -> int: return tab_bar.tab_count ## Returns [code]true[/code] if the tab bar has no tabs. func is_empty() -> bool: return get_tab_count() == 0 ## Closes a tab at the index [param tab]. func close_tab(tab: int) -> void: if not tab_bar.select_previous_available(): tab_bar.select_next_available() content_container.get_child(tab).queue_free() _tab_metadata.remove_at(tab) tab_bar.remove_tab(tab) tab_closed.emit(tab) if tab_bar.tab_count == 0: _previous_active_tab = -1 ## Returns the currently selected tab. func get_current_tab() -> int: return tab_bar.current_tab ## 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: return content_container.get_child(idx) ## Sets the metadata value for the tab at index [param tab_idx] at [param key], which can be ## retrieved later using [method get_tab_metadata]. func set_tab_metadata(tab: int, key: String, value: Variant) -> void: #var m = _tab_metadata.get(tab, {}) #m[key] = value #_tab_metadata[tab] = m var m := _tab_metadata[tab] m[key] = value ## 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, default: Variant = null) -> Variant: #if _tab_metadata.size() - 1 < tab: #return default #if tab < _tab_metadata.size(): #return default assert(tab < _tab_metadata.size()) var m = _tab_metadata[tab] return m.get(key, default)