@tool extends TabContainer signal tab_layout_changed(tab) var leaf: DockableLayoutPanel: get: return get_leaf() set(value): set_leaf(value) var show_tabs := true: get: return _show_tabs set(value): _show_tabs = value _handle_tab_visibility() var hide_single_tab := false: get: return _hide_single_tab set(value): _hide_single_tab = value _handle_tab_visibility() var _leaf: DockableLayoutPanel var _show_tabs := true var _hide_single_tab := false func _ready() -> void: drag_to_rearrange_enabled = true func _enter_tree() -> void: active_tab_rearranged.connect(_on_tab_changed) tab_selected.connect(_on_tab_selected) tab_changed.connect(_on_tab_changed) func _exit_tree() -> void: active_tab_rearranged.disconnect(_on_tab_changed) tab_selected.disconnect(_on_tab_selected) tab_changed.disconnect(_on_tab_changed) if is_instance_valid(get_popup()): get_popup().queue_free() func track_nodes(nodes: Array[Control], new_leaf: DockableLayoutPanel) -> void: _leaf = null # avoid using previous leaf in tab_changed signals var min_size := mini(nodes.size(), get_child_count()) # remove spare children for i in range(min_size, get_child_count()): var child := get_child(min_size) as DockableReferenceControl child.reference_to = null remove_child(child) child.queue_free() # add missing children for i in range(min_size, nodes.size()): var ref_control := DockableReferenceControl.new() add_child(ref_control) assert(nodes.size() == get_child_count(), "FIXME") # setup children for i in nodes.size(): var ref_control := get_child(i) as DockableReferenceControl ref_control.reference_to = nodes[i] set_tab_title(i, nodes[i].name) set_leaf(new_leaf) _handle_tab_visibility() func get_child_rect() -> Rect2: var control := get_current_tab_control() return Rect2(position + control.position, control.size) func set_leaf(value: DockableLayoutPanel) -> void: if get_tab_count() > 0 and value: current_tab = clampi(value.current_tab, 0, get_tab_count() - 1) _leaf = value func get_leaf() -> DockableLayoutPanel: return _leaf func get_layout_minimum_size() -> Vector2: return get_combined_minimum_size() func _on_tab_selected(tab: int) -> void: if _leaf: _leaf.current_tab = tab func _on_tab_changed(tab: int) -> void: if not _leaf: return var control := get_tab_control(tab) if not control: return var tab_name := control.name var name_index_in_leaf := _leaf.find_name(tab_name) if name_index_in_leaf != tab: # NOTE: this handles added tabs (index == -1) tab_layout_changed.emit(tab) func _handle_tab_visibility() -> void: if _hide_single_tab and get_tab_count() == 1: tabs_visible = false else: tabs_visible = _show_tabs