Forráskód Böngészése

Make `TabContainer` use `TabBar` internally

Michael Alexsander 3 éve
szülő
commit
a811ebf699

+ 7 - 0
doc/classes/TabBar.xml

@@ -57,6 +57,13 @@
 				Returns the [Texture2D] for the tab at index [code]tab_idx[/code] or [code]null[/code] if the tab has no [Texture2D].
 			</description>
 		</method>
+		<method name="get_tab_idx_at_point" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="point" type="Vector2" />
+			<description>
+				Returns the index of the tab at local coordinates [code]point[/code]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
+			</description>
+		</method>
 		<method name="get_tab_language" qualifiers="const">
 			<return type="String" />
 			<argument index="0" name="tab_idx" type="int" />

+ 30 - 26
doc/classes/TabContainer.xml

@@ -43,20 +43,6 @@
 				Returns the number of tabs.
 			</description>
 		</method>
-		<method name="get_tab_disabled" qualifiers="const">
-			<return type="bool" />
-			<argument index="0" name="tab_idx" type="int" />
-			<description>
-				Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled.
-			</description>
-		</method>
-		<method name="get_tab_hidden" qualifiers="const">
-			<return type="bool" />
-			<argument index="0" name="tab_idx" type="int" />
-			<description>
-				Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is hidden.
-			</description>
-		</method>
 		<method name="get_tab_icon" qualifiers="const">
 			<return type="Texture2D" />
 			<argument index="0" name="tab_idx" type="int" />
@@ -71,6 +57,13 @@
 				Returns the index of the tab at local coordinates [code]point[/code]. Returns [code]-1[/code] if the point is outside the control boundaries or if there's no tab at the queried position.
 			</description>
 		</method>
+		<method name="get_tab_idx_from_control" qualifiers="const">
+			<return type="int" />
+			<argument index="0" name="control" type="Control" />
+			<description>
+				Returns the index of the tab tied to the given [code]control[/code]. The control must be a child of the [TabContainer].
+			</description>
+		</method>
 		<method name="get_tab_title" qualifiers="const">
 			<return type="String" />
 			<argument index="0" name="tab_idx" type="int" />
@@ -84,11 +77,25 @@
 				Returns the [TabContainer] rearrange group id.
 			</description>
 		</method>
+		<method name="is_tab_disabled" qualifiers="const">
+			<return type="bool" />
+			<argument index="0" name="tab_idx" type="int" />
+			<description>
+				Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is disabled.
+			</description>
+		</method>
+		<method name="is_tab_hidden" qualifiers="const">
+			<return type="bool" />
+			<argument index="0" name="tab_idx" type="int" />
+			<description>
+				Returns [code]true[/code] if the tab at index [code]tab_idx[/code] is hidden.
+			</description>
+		</method>
 		<method name="set_popup">
 			<return type="void" />
 			<argument index="0" name="popup" type="Node" />
 			<description>
-				If set on a [Popup] node instance, a popup menu icon appears in the top-right corner of the [TabContainer]. Clicking it will expand the [Popup] node.
+				If set on a [Popup] node instance, a popup menu icon appears in the top-right corner of the [TabContainer] (setting it to [code]null[/code] will make it go away). Clicking it will expand the [Popup] node.
 			</description>
 		</method>
 		<method name="set_tab_disabled">
@@ -120,7 +127,7 @@
 			<argument index="0" name="tab_idx" type="int" />
 			<argument index="1" name="title" type="String" />
 			<description>
-				Sets a title for the tab at index [code]tab_idx[/code]. Tab titles default to the name of the indexed child node.
+				Sets a custom title for the tab at index [code]tab_idx[/code] (tab titles default to the name of the indexed child node). Set it to blank to make it the child's name again.
 			</description>
 		</method>
 		<method name="set_tabs_rearrange_group">
@@ -135,13 +142,17 @@
 		<member name="all_tabs_in_front" type="bool" setter="set_all_tabs_in_front" getter="is_all_tabs_in_front" default="false">
 			If [code]true[/code], all tabs are drawn in front of the panel. If [code]false[/code], inactive tabs are drawn behind the panel.
 		</member>
+		<member name="clip_tabs" type="bool" setter="set_clip_tabs" getter="get_clip_tabs" default="true">
+			If [code]true[/code], tabs overflowing this node's width will be hidden, displaying two navigation buttons instead. Otherwise, this node's minimum size is updated so that all tabs are visible.
+		</member>
 		<member name="current_tab" type="int" setter="set_current_tab" getter="get_current_tab" default="0">
 			The current tab index. When set, this index's [Control] node's [code]visible[/code] property is set to [code]true[/code] and all others are set to [code]false[/code].
 		</member>
 		<member name="drag_to_rearrange_enabled" type="bool" setter="set_drag_to_rearrange_enabled" getter="get_drag_to_rearrange_enabled" default="false">
 			If [code]true[/code], tabs can be rearranged with mouse drag.
 		</member>
-		<member name="tab_alignment" type="int" setter="set_tab_alignment" getter="get_tab_alignment" enum="TabContainer.AlignmentMode" default="1">
+		<member name="tab_alignment" type="int" setter="set_tab_alignment" getter="get_tab_alignment" enum="TabBar.AlignmentMode" default="1">
+			Sets the position at which tabs will be placed. See [enum TabBar.AlignmentMode] for details.
 		</member>
 		<member name="tabs_visible" type="bool" setter="set_tabs_visible" getter="are_tabs_visible" default="true">
 			If [code]true[/code], tabs are visible. If [code]false[/code], tabs' content and titles are hidden.
@@ -169,14 +180,6 @@
 			</description>
 		</signal>
 	</signals>
-	<constants>
-		<constant name="ALIGNMENT_LEFT" value="0" enum="AlignmentMode">
-		</constant>
-		<constant name="ALIGNMENT_CENTER" value="1" enum="AlignmentMode">
-		</constant>
-		<constant name="ALIGNMENT_RIGHT" value="2" enum="AlignmentMode">
-		</constant>
-	</constants>
 	<theme_items>
 		<theme_item name="font_disabled_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 0.5)">
 			Font color of disabled tabs.
@@ -197,7 +200,8 @@
 			The size of the tab text outline.
 		</theme_item>
 		<theme_item name="side_margin" data_type="constant" type="int" default="8">
-			The space at the left and right edges of the tab bar.
+			The space at the left or right edges of the tab bar, accordingly with the current [member tab_alignment].
+			The margin is ignored with [code]ALIGNMENT_RIGHT[/code] if the tabs are clipped (see [member clip_tabs]) or a popup has been set (see [method set_popup]). The margin is always ignored with [code]ALIGNMENT_CENTER[/code].
 		</theme_item>
 		<theme_item name="font" data_type="font" type="Font">
 			The font used to draw tab names.

+ 1 - 1
editor/action_map_editor.cpp

@@ -611,7 +611,7 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
 	add_child(main_vbox);
 
 	tab_container = memnew(TabContainer);
-	tab_container->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tab_container->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tab_container->set_use_hidden_tabs_for_min_size(true);
 	tab_container->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	tab_container->connect("tab_selected", callable_mp(this, &InputEventConfigurationDialog::_tab_selected));

+ 1 - 1
editor/debugger/editor_debugger_node.cpp

@@ -60,7 +60,7 @@ EditorDebuggerNode::EditorDebuggerNode() {
 	add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), SNAME("EditorStyles"))->get_margin(SIDE_RIGHT));
 
 	tabs = memnew(TabContainer);
-	tabs->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tabs->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tabs->set_tabs_visible(false);
 	tabs->connect("tab_changed", callable_mp(this, &EditorDebuggerNode::_debugger_changed));
 	add_child(tabs);

+ 5 - 5
editor/debugger/script_editor_debugger.cpp

@@ -135,15 +135,15 @@ void ScriptEditorDebugger::debug_continue() {
 void ScriptEditorDebugger::update_tabs() {
 	if (error_count == 0 && warning_count == 0) {
 		errors_tab->set_name(TTR("Errors"));
-		tabs->set_tab_icon(errors_tab->get_index(), Ref<Texture2D>());
+		tabs->set_tab_icon(tabs->get_tab_idx_from_control(errors_tab), Ref<Texture2D>());
 	} else {
 		errors_tab->set_name(TTR("Errors") + " (" + itos(error_count + warning_count) + ")");
 		if (error_count >= 1 && warning_count >= 1) {
-			tabs->set_tab_icon(errors_tab->get_index(), get_theme_icon(SNAME("ErrorWarning"), SNAME("EditorIcons")));
+			tabs->set_tab_icon(tabs->get_tab_idx_from_control(errors_tab), get_theme_icon(SNAME("ErrorWarning"), SNAME("EditorIcons")));
 		} else if (error_count >= 1) {
-			tabs->set_tab_icon(errors_tab->get_index(), get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
+			tabs->set_tab_icon(tabs->get_tab_idx_from_control(errors_tab), get_theme_icon(SNAME("Error"), SNAME("EditorIcons")));
 		} else {
-			tabs->set_tab_icon(errors_tab->get_index(), get_theme_icon(SNAME("Warning"), SNAME("EditorIcons")));
+			tabs->set_tab_icon(tabs->get_tab_idx_from_control(errors_tab), get_theme_icon(SNAME("Warning"), SNAME("EditorIcons")));
 		}
 	}
 }
@@ -1658,7 +1658,7 @@ bool ScriptEditorDebugger::has_capture(const StringName &p_name) {
 
 ScriptEditorDebugger::ScriptEditorDebugger() {
 	tabs = memnew(TabContainer);
-	tabs->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tabs->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("DebuggerPanel"), SNAME("EditorStyles")));
 	tabs->connect("tab_changed", callable_mp(this, &ScriptEditorDebugger::_tab_changed));
 

+ 23 - 16
editor/editor_node.cpp

@@ -313,6 +313,7 @@ void EditorNode::disambiguate_filenames(const Vector<String> p_full_paths, Vecto
 	}
 }
 
+// TODO: This REALLY should be done in a better way than replacing all tabs after almost EVERY action.
 void EditorNode::_update_scene_tabs() {
 	bool show_rb = EditorSettings::get_singleton()->get("interface/scene_tabs/show_script_button");
 
@@ -330,6 +331,9 @@ void EditorNode::_update_scene_tabs() {
 
 	disambiguate_filenames(full_path_names, disambiguated_scene_names);
 
+	// Workaround to ignore the tab_changed signal from the first added tab.
+	scene_tabs->disconnect("tab_changed", callable_mp(this, &EditorNode::_scene_tab_changed));
+
 	scene_tabs->clear_tabs();
 	Ref<Texture2D> script_icon = gui_base->get_theme_icon(SNAME("Script"), SNAME("EditorIcons"));
 	for (int i = 0; i < editor_data.get_edited_scene_count(); i++) {
@@ -388,6 +392,9 @@ void EditorNode::_update_scene_tabs() {
 			scene_tab_add->set_position(Point2(last_tab.position.x + last_tab.size.width + hsep, last_tab.position.y));
 		}
 	}
+
+	// Reconnect after everything is done.
+	scene_tabs->connect("tab_changed", callable_mp(this, &EditorNode::_scene_tab_changed));
 }
 
 void EditorNode::_version_control_menu_option(int p_idx) {
@@ -4226,7 +4233,7 @@ void EditorNode::_dock_floating_close_request(Control *p_control) {
 
 	p_control->get_parent()->remove_child(p_control);
 	dock_slot[window_slot]->add_child(p_control);
-	dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_child_count()));
+	dock_slot[window_slot]->move_child(p_control, MIN((int)window->get_meta("dock_index"), dock_slot[window_slot]->get_tab_count()));
 	dock_slot[window_slot]->set_current_tab(window->get_meta("dock_index"));
 
 	window->queue_delete();
@@ -4466,13 +4473,13 @@ void EditorNode::_dock_select_draw() {
 
 		if (i == dock_select_rect_over) {
 			dock_select->draw_rect(r, used_selected);
-		} else if (dock_slot[i]->get_child_count() == 0) {
+		} else if (dock_slot[i]->get_tab_count() == 0) {
 			dock_select->draw_rect(r, unused);
 		} else {
 			dock_select->draw_rect(r, used);
 		}
 
-		for (int j = 0; j < MIN(3, dock_slot[i]->get_child_count()); j++) {
+		for (int j = 0; j < MIN(3, dock_slot[i]->get_tab_count()); j++) {
 			int xofs = (r.size.width / 3) * j;
 			Color c = used;
 			if (i == dock_popup_selected && (dock_slot[i]->get_current_tab() > 3 || dock_slot[i]->get_current_tab() == j)) {
@@ -4584,7 +4591,7 @@ void EditorNode::_update_dock_slots_visibility() {
 		for (int i = 0; i < DOCK_SLOT_MAX; i++) {
 			int tabs_visible = 0;
 			for (int j = 0; j < dock_slot[i]->get_tab_count(); j++) {
-				if (!dock_slot[i]->get_tab_hidden(j)) {
+				if (!dock_slot[i]->is_tab_hidden(j)) {
 					tabs_visible++;
 				}
 			}
@@ -5648,11 +5655,11 @@ void EditorNode::_feature_profile_changed() {
 	TabContainer *node_tabs = cast_to<TabContainer>(NodeDock::get_singleton()->get_parent());
 	TabContainer *fs_tabs = cast_to<TabContainer>(FileSystemDock::get_singleton()->get_parent());
 	if (profile.is_valid()) {
-		node_tabs->set_tab_hidden(NodeDock::get_singleton()->get_index(), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
+		node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), profile->is_feature_disabled(EditorFeatureProfile::FEATURE_NODE_DOCK));
 		// The Import dock is useless without the FileSystem dock. Ensure the configuration is valid.
 		bool fs_dock_disabled = profile->is_feature_disabled(EditorFeatureProfile::FEATURE_FILESYSTEM_DOCK);
-		fs_tabs->set_tab_hidden(FileSystemDock::get_singleton()->get_index(), fs_dock_disabled);
-		import_tabs->set_tab_hidden(ImportDock::get_singleton()->get_index(), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
+		fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), fs_dock_disabled);
+		import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), fs_dock_disabled || profile->is_feature_disabled(EditorFeatureProfile::FEATURE_IMPORT_DOCK));
 
 		main_editor_buttons[EDITOR_3D]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_3D));
 		main_editor_buttons[EDITOR_SCRIPT]->set_visible(!profile->is_feature_disabled(EditorFeatureProfile::FEATURE_SCRIPT));
@@ -5665,9 +5672,9 @@ void EditorNode::_feature_profile_changed() {
 			_editor_select(EDITOR_2D);
 		}
 	} else {
-		import_tabs->set_tab_hidden(ImportDock::get_singleton()->get_index(), false);
-		node_tabs->set_tab_hidden(NodeDock::get_singleton()->get_index(), false);
-		fs_tabs->set_tab_hidden(FileSystemDock::get_singleton()->get_index(), false);
+		import_tabs->set_tab_hidden(import_tabs->get_tab_idx_from_control(ImportDock::get_singleton()), false);
+		node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false);
+		fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false);
 		ImportDock::get_singleton()->set_visible(true);
 		NodeDock::get_singleton()->set_visible(true);
 		FileSystemDock::get_singleton()->set_visible(true);
@@ -6205,7 +6212,7 @@ EditorNode::EditorNode() {
 		dock_slot[i]->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 		dock_slot[i]->set_popup(dock_select_popup);
 		dock_slot[i]->connect("pre_popup_pressed", callable_mp(this, &EditorNode::_dock_pre_popup), varray(i));
-		dock_slot[i]->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+		dock_slot[i]->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 		dock_slot[i]->set_drag_to_rearrange_enabled(true);
 		dock_slot[i]->set_tabs_rearrange_group(1);
 		dock_slot[i]->connect("tab_changed", callable_mp(this, &EditorNode::_dock_tab_changed));
@@ -6714,23 +6721,23 @@ EditorNode::EditorNode() {
 
 	// Scene: Top left
 	dock_slot[DOCK_SLOT_LEFT_UR]->add_child(SceneTreeDock::get_singleton());
-	dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(SceneTreeDock::get_singleton()->get_index(), TTR("Scene"));
+	dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(dock_slot[DOCK_SLOT_LEFT_UR]->get_tab_idx_from_control(SceneTreeDock::get_singleton()), TTR("Scene"));
 
 	// Import: Top left, behind Scene
 	dock_slot[DOCK_SLOT_LEFT_UR]->add_child(ImportDock::get_singleton());
-	dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(ImportDock::get_singleton()->get_index(), TTR("Import"));
+	dock_slot[DOCK_SLOT_LEFT_UR]->set_tab_title(dock_slot[DOCK_SLOT_LEFT_UR]->get_tab_idx_from_control(ImportDock::get_singleton()), TTR("Import"));
 
 	// FileSystem: Bottom left
 	dock_slot[DOCK_SLOT_LEFT_BR]->add_child(FileSystemDock::get_singleton());
-	dock_slot[DOCK_SLOT_LEFT_BR]->set_tab_title(FileSystemDock::get_singleton()->get_index(), TTR("FileSystem"));
+	dock_slot[DOCK_SLOT_LEFT_BR]->set_tab_title(dock_slot[DOCK_SLOT_LEFT_BR]->get_tab_idx_from_control(FileSystemDock::get_singleton()), TTR("FileSystem"));
 
 	// Inspector: Full height right
 	dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(InspectorDock::get_singleton());
-	dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(InspectorDock::get_singleton()->get_index(), TTR("Inspector"));
+	dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(InspectorDock::get_singleton()), TTR("Inspector"));
 
 	// Node: Full height right, behind Inspector
 	dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(NodeDock::get_singleton());
-	dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(NodeDock::get_singleton()->get_index(), TTR("Node"));
+	dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(dock_slot[DOCK_SLOT_RIGHT_UL]->get_tab_idx_from_control(NodeDock::get_singleton()), TTR("Node"));
 
 	// Hide unused dock slots and vsplits
 	dock_slot[DOCK_SLOT_LEFT_UL]->hide();

+ 1 - 1
editor/editor_settings_dialog.cpp

@@ -662,7 +662,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
 	undo_redo = memnew(UndoRedo);
 
 	tabs = memnew(TabContainer);
-	tabs->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tabs->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tabs->connect("tab_changed", callable_mp(this, &EditorSettingsDialog::_tabs_tab_changed));
 	add_child(tabs);
 

+ 1 - 1
editor/localization_editor.cpp

@@ -477,7 +477,7 @@ LocalizationEditor::LocalizationEditor() {
 	localization_changed = "localization_changed";
 
 	TabContainer *translations = memnew(TabContainer);
-	translations->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	translations->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	translations->set_v_size_flags(Control::SIZE_EXPAND_FILL);
 	add_child(translations);
 

+ 103 - 103
editor/plugins/script_editor_plugin.cpp

@@ -407,8 +407,8 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) {
 		return;
 	}
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -447,8 +447,8 @@ void ScriptEditor::_goto_script_line(REF p_script, int p_line) {
 void ScriptEditor::_set_execution(REF p_script, int p_line) {
 	Ref<Script> script = Object::cast_to<Script>(*p_script);
 	if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
-		for (int i = 0; i < tab_container->get_child_count(); i++) {
-			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+		for (int i = 0; i < tab_container->get_tab_count(); i++) {
+			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 			if (!se) {
 				continue;
 			}
@@ -463,8 +463,8 @@ void ScriptEditor::_set_execution(REF p_script, int p_line) {
 void ScriptEditor::_clear_execution(REF p_script) {
 	Ref<Script> script = Object::cast_to<Script>(*p_script);
 	if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
-		for (int i = 0; i < tab_container->get_child_count(); i++) {
-			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+		for (int i = 0; i < tab_container->get_tab_count(); i++) {
+			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 			if (!se) {
 				continue;
 			}
@@ -480,8 +480,8 @@ void ScriptEditor::_set_breakpoint(REF p_script, int p_line, bool p_enabled) {
 	Ref<Script> script = Object::cast_to<Script>(*p_script);
 	if (script.is_valid() && (script->has_source_code() || script->get_path().is_resource_file())) {
 		// Update if open.
-		for (int i = 0; i < tab_container->get_child_count(); i++) {
-			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+		for (int i = 0; i < tab_container->get_tab_count(); i++) {
+			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 			if (se && se->get_edited_resource()->get_path() == script->get_path()) {
 				se->set_breakpoint(p_line, p_enabled);
 				return;
@@ -509,8 +509,8 @@ void ScriptEditor::_set_breakpoint(REF p_script, int p_line, bool p_enabled) {
 }
 
 void ScriptEditor::_clear_breakpoints() {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (se) {
 			se->clear_breakpoints();
 		}
@@ -547,11 +547,11 @@ Array ScriptEditor::_get_cached_breakpoints_for_script(const String &p_path) con
 
 ScriptEditorBase *ScriptEditor::_get_current_editor() const {
 	int selected = tab_container->get_current_tab();
-	if (selected < 0 || selected >= tab_container->get_child_count()) {
+	if (selected < 0 || selected >= tab_container->get_tab_count()) {
 		return nullptr;
 	}
 
-	return Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
+	return Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(selected));
 }
 
 void ScriptEditor::_update_history_arrows() {
@@ -590,7 +590,7 @@ void ScriptEditor::_go_to_tab(int p_idx) {
 		}
 	}
 
-	Control *c = Object::cast_to<Control>(tab_container->get_child(p_idx));
+	Control *c = Object::cast_to<Control>(tab_container->get_tab_control(p_idx));
 	if (!c) {
 		return;
 	}
@@ -750,11 +750,11 @@ void ScriptEditor::_show_error_dialog(String p_path) {
 
 void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
 	int selected = p_idx;
-	if (selected < 0 || selected >= tab_container->get_child_count()) {
+	if (selected < 0 || selected >= tab_container->get_tab_count()) {
 		return;
 	}
 
-	Node *tselected = tab_container->get_child(selected);
+	Node *tselected = tab_container->get_tab_control(selected);
 
 	ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected);
 	if (current) {
@@ -805,8 +805,8 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) {
 		_save_editor_state(current);
 	}
 	memdelete(tselected);
-	if (idx >= tab_container->get_child_count()) {
-		idx = tab_container->get_child_count() - 1;
+	if (idx >= tab_container->get_tab_count()) {
+		idx = tab_container->get_tab_count() - 1;
 	}
 	if (idx >= 0) {
 		if (history_pos >= 0) {
@@ -836,9 +836,9 @@ void ScriptEditor::_close_discard_current_tab(const String &p_str) {
 }
 
 void ScriptEditor::_close_docs_tab() {
-	int child_count = tab_container->get_child_count();
+	int child_count = tab_container->get_tab_count();
 	for (int i = child_count - 1; i >= 0; i--) {
-		EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+		EditorHelp *se = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 
 		if (se) {
 			_close_tab(i, true, false);
@@ -856,7 +856,7 @@ void ScriptEditor::_copy_script_path() {
 
 void ScriptEditor::_close_other_tabs() {
 	int current_idx = tab_container->get_current_tab();
-	for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+	for (int i = tab_container->get_tab_count() - 1; i >= 0; i--) {
 		if (i != current_idx) {
 			script_close_queue.push_back(i);
 		}
@@ -865,7 +865,7 @@ void ScriptEditor::_close_other_tabs() {
 }
 
 void ScriptEditor::_close_all_tabs() {
-	for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+	for (int i = tab_container->get_tab_count() - 1; i >= 0; i--) {
 		script_close_queue.push_back(i);
 	}
 	_queue_close_tabs();
@@ -877,7 +877,7 @@ void ScriptEditor::_queue_close_tabs() {
 		script_close_queue.pop_front();
 
 		tab_container->set_current_tab(idx);
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(idx));
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(idx));
 		if (se) {
 			// Maybe there are unsaved changes.
 			if (se->is_unsaved()) {
@@ -900,8 +900,8 @@ void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) {
 void ScriptEditor::_resave_scripts(const String &p_str) {
 	apply_scripts();
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -941,8 +941,8 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
 }
 
 void ScriptEditor::_reload_scripts() {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -985,8 +985,8 @@ void ScriptEditor::_reload_scripts() {
 }
 
 void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -1004,8 +1004,8 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
 
 void ScriptEditor::_scene_saved_callback(const String &p_path) {
 	// If scene was saved, mark all built-in scripts from that scene as saved.
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -1048,8 +1048,8 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) {
 	bool need_reload = false;
 	bool use_autoreload = bool(EDITOR_DEF("text_editor/behavior/files/auto_reload_scripts_on_external_change", false));
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (se) {
 			RES edited_res = se->get_edited_resource();
 			if (p_for_script.is_valid() && edited_res.is_valid() && p_for_script != edited_res) {
@@ -1449,7 +1449,7 @@ void ScriptEditor::_menu_option(int p_option) {
 				}
 			} break;
 			case WINDOW_MOVE_DOWN: {
-				if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
+				if (tab_container->get_current_tab() < tab_container->get_tab_count() - 1) {
 					tab_container->move_child(current, tab_container->get_current_tab() + 1);
 					tab_container->set_current_tab(tab_container->get_current_tab() + 1);
 					_update_script_names();
@@ -1495,7 +1495,7 @@ void ScriptEditor::_menu_option(int p_option) {
 					}
 				} break;
 				case WINDOW_MOVE_DOWN: {
-					if (tab_container->get_current_tab() < tab_container->get_child_count() - 1) {
+					if (tab_container->get_current_tab() < tab_container->get_tab_count() - 1) {
 						tab_container->move_child(help, tab_container->get_current_tab() + 1);
 						tab_container->set_current_tab(tab_container->get_current_tab() + 1);
 						_update_script_names();
@@ -1545,9 +1545,9 @@ void ScriptEditor::_show_save_theme_as_dialog() {
 }
 
 bool ScriptEditor::_has_docs_tab() const {
-	const int child_count = tab_container->get_child_count();
+	const int child_count = tab_container->get_tab_count();
 	for (int i = 0; i < child_count; i++) {
-		if (Object::cast_to<EditorHelp>(tab_container->get_child(i))) {
+		if (Object::cast_to<EditorHelp>(tab_container->get_tab_control(i))) {
 			return true;
 		}
 	}
@@ -1555,9 +1555,9 @@ bool ScriptEditor::_has_docs_tab() const {
 }
 
 bool ScriptEditor::_has_script_tab() const {
-	const int child_count = tab_container->get_child_count();
+	const int child_count = tab_container->get_tab_count();
 	for (int i = 0; i < child_count; i++) {
-		if (Object::cast_to<ScriptEditorBase>(tab_container->get_child(i))) {
+		if (Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i))) {
 			return true;
 		}
 	}
@@ -1581,9 +1581,9 @@ void ScriptEditor::_prepare_file_menu() {
 	menu->set_item_disabled(menu->get_item_index(WINDOW_PREV), history_pos <= 0);
 	menu->set_item_disabled(menu->get_item_index(WINDOW_NEXT), history_pos >= history.size() - 1);
 
-	menu->set_item_disabled(menu->get_item_index(FILE_CLOSE), tab_container->get_child_count() < 1);
-	menu->set_item_disabled(menu->get_item_index(CLOSE_ALL), tab_container->get_child_count() < 1);
-	menu->set_item_disabled(menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_child_count() <= 1);
+	menu->set_item_disabled(menu->get_item_index(FILE_CLOSE), tab_container->get_tab_count() < 1);
+	menu->set_item_disabled(menu->get_item_index(CLOSE_ALL), tab_container->get_tab_count() < 1);
+	menu->set_item_disabled(menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_tab_count() <= 1);
 	menu->set_item_disabled(menu->get_item_index(CLOSE_DOCS), !_has_docs_tab());
 
 	menu->set_item_disabled(menu->get_item_index(FILE_RUN), current_is_doc);
@@ -1682,8 +1682,8 @@ bool ScriptEditor::can_take_away_focus() const {
 }
 
 void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 
 		if (se) {
 			Ref<Script> script = se->get_edited_resource();
@@ -1713,8 +1713,8 @@ void ScriptEditor::notify_script_changed(const Ref<Script> &p_script) {
 
 void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
 	Set<String> loaded_scripts;
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -1766,7 +1766,7 @@ void ScriptEditor::_members_overview_selected(int p_idx) {
 }
 
 void ScriptEditor::_help_overview_selected(int p_idx) {
-	Node *current = tab_container->get_child(tab_container->get_current_tab());
+	Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
 	EditorHelp *se = Object::cast_to<EditorHelp>(current);
 	if (!se) {
 		return;
@@ -1782,7 +1782,7 @@ void ScriptEditor::_script_selected(int p_idx) {
 }
 
 void ScriptEditor::ensure_select_current() {
-	if (tab_container->get_child_count() && tab_container->get_current_tab() >= 0) {
+	if (tab_container->get_tab_count() && tab_container->get_current_tab() >= 0) {
 		ScriptEditorBase *se = _get_current_editor();
 		if (se) {
 			se->enable_editor();
@@ -1893,12 +1893,12 @@ void ScriptEditor::_update_members_overview() {
 
 void ScriptEditor::_update_help_overview_visibility() {
 	int selected = tab_container->get_current_tab();
-	if (selected < 0 || selected >= tab_container->get_child_count()) {
+	if (selected < 0 || selected >= tab_container->get_tab_count()) {
 		help_overview->set_visible(false);
 		return;
 	}
 
-	Node *current = tab_container->get_child(tab_container->get_current_tab());
+	Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
 	EditorHelp *se = Object::cast_to<EditorHelp>(current);
 	if (!se) {
 		help_overview->set_visible(false);
@@ -1920,11 +1920,11 @@ void ScriptEditor::_update_help_overview() {
 	help_overview->clear();
 
 	int selected = tab_container->get_current_tab();
-	if (selected < 0 || selected >= tab_container->get_child_count()) {
+	if (selected < 0 || selected >= tab_container->get_tab_count()) {
 		return;
 	}
 
-	Node *current = tab_container->get_child(tab_container->get_current_tab());
+	Node *current = tab_container->get_tab_control(tab_container->get_current_tab());
 	EditorHelp *se = Object::cast_to<EditorHelp>(current);
 	if (!se) {
 		return;
@@ -1947,7 +1947,7 @@ void ScriptEditor::_update_script_colors() {
 
 	for (int i = 0; i < script_list->get_item_count(); i++) {
 		int c = script_list->get_item_metadata(i);
-		Node *n = tab_container->get_child(c);
+		Node *n = tab_container->get_tab_control(c);
 		if (!n) {
 			continue;
 		}
@@ -1990,8 +1990,8 @@ void ScriptEditor::_update_script_names() {
 
 	Vector<_ScriptEditorItemData> sedata;
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (se) {
 			Ref<Texture2D> icon = se->get_theme_icon();
 			String path = se->get_edited_resource()->get_path();
@@ -2080,7 +2080,7 @@ void ScriptEditor::_update_script_names() {
 			}
 		}
 
-		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 		if (eh) {
 			String name = eh->get_class();
 			Ref<Texture2D> icon = get_theme_icon(SNAME("Help"), SNAME("EditorIcons"));
@@ -2172,8 +2172,8 @@ void ScriptEditor::_update_script_names() {
 }
 
 void ScriptEditor::_update_script_connections() {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptTextEditor *ste = Object::cast_to<ScriptTextEditor>(tab_container->get_tab_control(i));
 		if (!ste) {
 			continue;
 		}
@@ -2322,8 +2322,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra
 		WARN_PRINT("Couldn't open external text editor, using internal");
 	}
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2498,8 +2498,8 @@ void ScriptEditor::save_current_script() {
 void ScriptEditor::save_all_scripts() {
 	Vector<String> scenes_to_save;
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2574,8 +2574,8 @@ void ScriptEditor::save_all_scripts() {
 }
 
 void ScriptEditor::apply_scripts() const {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2624,8 +2624,8 @@ RES ScriptEditor::open_file(const String &p_file) {
 }
 
 void ScriptEditor::_editor_stop() {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2641,8 +2641,8 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const
 
 	EditorNode::get_singleton()->push_item(script.ptr());
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2712,8 +2712,8 @@ void ScriptEditor::_editor_settings_changed() {
 		EditorSettings::get_singleton()->load_text_editor_theme();
 	}
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2751,8 +2751,8 @@ void ScriptEditor::_files_moved(const String &p_old_file, const String &p_new_fi
 }
 
 void ScriptEditor::_file_removed(const String &p_removed_file) {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -2815,11 +2815,11 @@ void ScriptEditor::_split_dragged(float) {
 }
 
 Variant ScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
-	if (tab_container->get_child_count() == 0) {
+	if (tab_container->get_tab_count() == 0) {
 		return Variant();
 	}
 
-	Node *cur_node = tab_container->get_child(tab_container->get_current_tab());
+	Node *cur_node = tab_container->get_tab_control(tab_container->get_current_tab());
 
 	HBoxContainer *drag_preview = memnew(HBoxContainer);
 	String preview_name = "";
@@ -2975,7 +2975,7 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
 		if (script_list->get_item_count() > 0) {
 			new_index = script_list->get_item_metadata(script_list->get_item_at_position(p_point));
 		}
-		int num_tabs_before = tab_container->get_child_count();
+		int num_tabs_before = tab_container->get_tab_count();
 		for (int i = 0; i < files.size(); i++) {
 			String file = files[i];
 			if (file.is_empty() || !FileAccess::exists(file)) {
@@ -2988,11 +2988,11 @@ void ScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Co
 
 			RES res = open_file(file);
 			if (res.is_valid()) {
-				if (tab_container->get_child_count() > num_tabs_before) {
-					tab_container->move_child(tab_container->get_child(tab_container->get_child_count() - 1), new_index);
-					num_tabs_before = tab_container->get_child_count();
+				if (tab_container->get_tab_count() > num_tabs_before) {
+					tab_container->move_child(tab_container->get_tab_control(tab_container->get_tab_count() - 1), new_index);
+					num_tabs_before = tab_container->get_tab_count();
 				} else { /* Maybe script was already open */
-					tab_container->move_child(tab_container->get_child(tab_container->get_current_tab()), new_index);
+					tab_container->move_child(tab_container->get_tab_control(tab_container->get_current_tab()), new_index);
 				}
 			}
 		}
@@ -3081,11 +3081,11 @@ void ScriptEditor::_make_script_list_context_menu() {
 	context_menu->clear();
 
 	int selected = tab_container->get_current_tab();
-	if (selected < 0 || selected >= tab_container->get_child_count()) {
+	if (selected < 0 || selected >= tab_container->get_tab_count()) {
 		return;
 	}
 
-	ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected));
+	ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(selected));
 	if (se) {
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save"), FILE_SAVE);
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/save_as"), FILE_SAVE_AS);
@@ -3113,11 +3113,11 @@ void ScriptEditor::_make_script_list_context_menu() {
 	context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_sort"), WINDOW_SORT);
 	context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/toggle_scripts_panel"), TOGGLE_SCRIPTS_PANEL);
 
-	context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_ALL), tab_container->get_child_count() <= 0);
-	context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_child_count() <= 1);
+	context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_ALL), tab_container->get_tab_count() <= 0);
+	context_menu->set_item_disabled(context_menu->get_item_index(CLOSE_OTHER_TABS), tab_container->get_tab_count() <= 1);
 	context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_MOVE_UP), tab_container->get_current_tab() <= 0);
-	context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_MOVE_DOWN), tab_container->get_current_tab() >= tab_container->get_child_count() - 1);
-	context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_SORT), tab_container->get_child_count() <= 1);
+	context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_MOVE_DOWN), tab_container->get_current_tab() >= tab_container->get_tab_count() - 1);
+	context_menu->set_item_disabled(context_menu->get_item_index(WINDOW_SORT), tab_container->get_tab_count() <= 1);
 
 	context_menu->set_position(get_screen_position() + get_local_mouse_position());
 	context_menu->reset_size();
@@ -3181,7 +3181,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
 		}
 
 		if (!script_info.is_empty()) {
-			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(tab_container->get_tab_count() - 1));
+			ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(tab_container->get_tab_count() - 1));
 			if (se) {
 				se->set_edit_state(script_info["state"]);
 			}
@@ -3196,8 +3196,8 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
 		_help_class_open(path);
 	}
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		tab_container->get_child(i)->set_meta("__editor_pass", Variant());
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		tab_container->get_tab_control(i)->set_meta("__editor_pass", Variant());
 	}
 
 	if (p_layout->has_section_key("ScriptEditor", "script_split_offset")) {
@@ -3237,8 +3237,8 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
 	Array scripts;
 	Array helps;
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (se) {
 			String path = se->get_edited_resource()->get_path();
 			if (!path.is_resource_file()) {
@@ -3249,7 +3249,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
 			scripts.push_back(path);
 		}
 
-		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 
 		if (eh) {
 			helps.push_back(eh->get_class());
@@ -3270,8 +3270,8 @@ void ScriptEditor::_help_class_open(const String &p_class) {
 		return;
 	}
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 
 		if (eh && eh->get_class() == p_class) {
 			_go_to_tab(i);
@@ -3296,8 +3296,8 @@ void ScriptEditor::_help_class_open(const String &p_class) {
 void ScriptEditor::_help_class_goto(const String &p_desc) {
 	String cname = p_desc.get_slice(":", 1);
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 
 		if (eh && eh->get_class() == cname) {
 			_go_to_tab(i);
@@ -3323,8 +3323,8 @@ void ScriptEditor::_help_class_goto(const String &p_desc) {
 void ScriptEditor::update_doc(const String &p_name) {
 	ERR_FAIL_COND(!EditorHelp::get_doc_data()->has_doc(p_name));
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_tab_control(i));
 		if (eh && eh->get_class() == p_name) {
 			eh->update_doc();
 			return;
@@ -3333,10 +3333,10 @@ void ScriptEditor::update_doc(const String &p_name) {
 }
 
 void ScriptEditor::_update_selected_editor_menu() {
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
 		bool current = tab_container->get_current_tab() == i;
 
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (se && se->get_edit_menu()) {
 			if (current) {
 				se->get_edit_menu()->show();
@@ -3356,7 +3356,7 @@ void ScriptEditor::_update_selected_editor_menu() {
 		script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
 		script_search_menu->show();
 	} else {
-		if (tab_container->get_child_count() == 0) {
+		if (tab_container->get_tab_count() == 0) {
 			script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_in_files", TTR("Find in Files"), KeyModifierMask::CMD | KeyModifierMask::SHIFT | Key::F), SEARCH_IN_FILES);
 			script_search_menu->show();
 		} else {
@@ -3416,8 +3416,8 @@ void ScriptEditor::_history_back() {
 Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
 	Vector<Ref<Script>> out_scripts = Vector<Ref<Script>>();
 
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}
@@ -3433,8 +3433,8 @@ Vector<Ref<Script>> ScriptEditor::get_open_scripts() const {
 
 Array ScriptEditor::_get_open_script_editors() const {
 	Array script_editors;
-	for (int i = 0; i < tab_container->get_child_count(); i++) {
-		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+	for (int i = 0; i < tab_container->get_tab_count(); i++) {
+		ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_tab_control(i));
 		if (!se) {
 			continue;
 		}

+ 1 - 1
editor/plugins/theme_editor_plugin.cpp

@@ -1887,7 +1887,7 @@ ThemeItemEditorDialog::ThemeItemEditorDialog(ThemeTypeEditor *p_theme_type_edito
 	theme_type_editor = p_theme_type_editor;
 
 	tc = memnew(TabContainer);
-	tc->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tc->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	add_child(tc);
 
 	// Edit Items tab.

+ 1 - 1
editor/plugins/version_control_editor_plugin.cpp

@@ -329,7 +329,7 @@ void VersionControlEditorPlugin::register_editor() {
 	if (!EditorVCSInterface::get_singleton()) {
 		EditorNode::get_singleton()->add_control_to_dock(EditorNode::DOCK_SLOT_RIGHT_UL, version_commit_dock);
 		TabContainer *dock_vbc = (TabContainer *)version_commit_dock->get_parent_control();
-		dock_vbc->set_tab_title(version_commit_dock->get_index(), TTR("Commit"));
+		dock_vbc->set_tab_title(dock_vbc->get_tab_idx_from_control(version_commit_dock), TTR("Commit"));
 
 		Button *vc = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Version Control"), version_control_dock);
 		set_version_control_tool_button(vc);

+ 1 - 1
editor/project_export.cpp

@@ -1055,7 +1055,7 @@ ProjectExportDialog::ProjectExportDialog() {
 	// Subsections.
 
 	sections = memnew(TabContainer);
-	sections->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	sections->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	sections->set_use_hidden_tabs_for_min_size(true);
 	settings_vb->add_child(sections);
 	sections->set_v_size_flags(Control::SIZE_EXPAND_FILL);

+ 1 - 1
editor/project_manager.cpp

@@ -2566,7 +2566,7 @@ ProjectManager::ProjectManager() {
 	tabs = memnew(TabContainer);
 	center_box->add_child(tabs);
 	tabs->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
-	tabs->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tabs->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
 
 	HBoxContainer *projects_hb = memnew(HBoxContainer);

+ 1 - 1
editor/project_settings_editor.cpp

@@ -559,7 +559,7 @@ ProjectSettingsEditor::ProjectSettingsEditor(EditorData *p_data) {
 	data = p_data;
 
 	tab_container = memnew(TabContainer);
-	tab_container->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tab_container->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tab_container->set_use_hidden_tabs_for_min_size(true);
 	add_child(tab_container);
 

+ 1 - 1
editor/rename_dialog.cpp

@@ -114,7 +114,7 @@ RenameDialog::RenameDialog(SceneTreeEditor *p_scene_tree_editor, UndoRedo *p_und
 	vbc->add_child(cbut_collapse_features);
 
 	tabc_features = memnew(TabContainer);
-	tabc_features->set_tab_alignment(TabContainer::ALIGNMENT_LEFT);
+	tabc_features->set_tab_alignment(TabBar::ALIGNMENT_LEFT);
 	tabc_features->set_use_hidden_tabs_for_min_size(true);
 	vbc->add_child(tabc_features);
 

+ 63 - 25
scene/gui/tab_bar.cpp

@@ -552,10 +552,6 @@ void TabBar::set_current_tab(int p_current) {
 		emit_signal(SNAME("tab_selected"), current);
 		return;
 	}
-	// Triggered by dragging a tab from another TabBar to the selected index, to ensure that tab_changed is emitted.
-	if (previous == -1) {
-		previous = current;
-	}
 
 	emit_signal(SNAME("tab_selected"), current);
 
@@ -954,9 +950,17 @@ void TabBar::add_tab(const String &p_str, const Ref<Texture2D> &p_icon) {
 	}
 	update();
 	update_minimum_size();
+
+	if (tabs.size() == 1 && is_inside_tree()) {
+		emit_signal(SNAME("tab_changed"), 0);
+	}
 }
 
 void TabBar::clear_tabs() {
+	if (tabs.is_empty()) {
+		return;
+	}
+
 	tabs.clear();
 	offset = 0;
 	max_drawn_tab = 0;
@@ -971,14 +975,16 @@ void TabBar::clear_tabs() {
 void TabBar::remove_tab(int p_idx) {
 	ERR_FAIL_INDEX(p_idx, tabs.size());
 	tabs.remove_at(p_idx);
-	if (current >= p_idx) {
+
+	bool is_tab_changing = current == p_idx && !tabs.is_empty();
+
+	if (current >= p_idx && current > 0) {
 		current--;
 	}
 
-	if (current < 0) {
+	if (tabs.is_empty()) {
 		offset = 0;
 		max_drawn_tab = 0;
-		current = 0;
 		previous = 0;
 	} else {
 		offset = MIN(offset, tabs.size() - 1);
@@ -986,7 +992,7 @@ void TabBar::remove_tab(int p_idx) {
 
 		_update_cache();
 		_ensure_no_over_offset();
-		if (scroll_to_selected && !tabs.is_empty()) {
+		if (scroll_to_selected) {
 			ensure_tab_visible(current);
 		}
 	}
@@ -994,15 +1000,18 @@ void TabBar::remove_tab(int p_idx) {
 	update();
 	update_minimum_size();
 	notify_property_list_changed();
+
+	if (is_tab_changing && is_inside_tree()) {
+		emit_signal(SNAME("tab_changed"), current);
+	}
 }
 
 Variant TabBar::get_drag_data(const Point2 &p_point) {
 	if (!drag_to_rearrange_enabled) {
-		return Variant();
+		return Control::get_drag_data(p_point); // Allow stuff like TabContainer to override it.
 	}
 
 	int tab_over = get_tab_idx_at_point(p_point);
-
 	if (tab_over < 0) {
 		return Variant();
 	}
@@ -1025,12 +1034,13 @@ Variant TabBar::get_drag_data(const Point2 &p_point) {
 	drag_data["type"] = "tab_element";
 	drag_data["tab_element"] = tab_over;
 	drag_data["from_path"] = get_path();
+
 	return drag_data;
 }
 
 bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
 	if (!drag_to_rearrange_enabled) {
-		return false;
+		return Control::can_drop_data(p_point, p_data); // Allow stuff like TabContainer to override it.
 	}
 
 	Dictionary d = p_data;
@@ -1052,16 +1062,16 @@ bool TabBar::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
 			}
 		}
 	}
+
 	return false;
 }
 
 void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
 	if (!drag_to_rearrange_enabled) {
+		Control::drop_data(p_point, p_data); // Allow stuff like TabContainer to override it.
 		return;
 	}
 
-	int hover_now = get_tab_idx_at_point(p_point);
-
 	Dictionary d = p_data;
 	if (!d.has("type")) {
 		return;
@@ -1069,6 +1079,7 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
 
 	if (String(d["type"]) == "tab_element") {
 		int tab_from_id = d["tab_element"];
+		int hover_now = get_tab_idx_at_point(p_point);
 		NodePath from_path = d["from_path"];
 		NodePath to_path = get_path();
 
@@ -1096,15 +1107,25 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
 					hover_now = get_tab_count();
 				}
 
-				// Workaround to ensure that tab_changed is emitted.
-				if (current == hover_now) {
-					current = -1;
+				from_tabs->remove_tab(tab_from_id);
+				tabs.insert(hover_now, moving_tab);
+
+				if (tabs.size() > 1) {
+					if (current >= hover_now) {
+						current++;
+					}
+					if (previous >= hover_now) {
+						previous++;
+					}
 				}
 
-				tabs.insert(hover_now, moving_tab);
-				from_tabs->remove_tab(tab_from_id);
 				set_current_tab(hover_now);
 				update_minimum_size();
+
+				if (tabs.size() == 1) {
+					emit_signal(SNAME("tab_selected"), 0);
+					emit_signal(SNAME("tab_changed"), 0);
+				}
 			}
 		}
 	}
@@ -1157,17 +1178,33 @@ bool TabBar::get_clip_tabs() const {
 	return clip_tabs;
 }
 
-void TabBar::move_tab(int from, int to) {
-	if (from == to) {
+void TabBar::move_tab(int p_from, int p_to) {
+	if (p_from == p_to) {
 		return;
 	}
 
-	ERR_FAIL_INDEX(from, tabs.size());
-	ERR_FAIL_INDEX(to, tabs.size());
+	ERR_FAIL_INDEX(p_from, tabs.size());
+	ERR_FAIL_INDEX(p_to, tabs.size());
+
+	Tab tab_from = tabs[p_from];
+	tabs.remove_at(p_from);
+	tabs.insert(p_to, tab_from);
 
-	Tab tab_from = tabs[from];
-	tabs.remove_at(from);
-	tabs.insert(to, tab_from);
+	if (current == p_from) {
+		current = p_to;
+	} else if (current > p_from && current <= p_to) {
+		current--;
+	} else if (current < p_from && current >= p_to) {
+		current++;
+	}
+
+	if (previous == p_from) {
+		previous = p_to;
+	} else if (previous > p_from && previous >= p_to) {
+		previous--;
+	} else if (previous < p_from && previous <= p_to) {
+		previous++;
+	}
 
 	_update_cache();
 	_ensure_no_over_offset();
@@ -1466,6 +1503,7 @@ void TabBar::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabBar::is_tab_hidden);
 	ClassDB::bind_method(D_METHOD("remove_tab", "tab_idx"), &TabBar::remove_tab);
 	ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &TabBar::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>()));
+	ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabBar::get_tab_idx_at_point);
 	ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabBar::set_tab_alignment);
 	ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabBar::get_tab_alignment);
 	ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabBar::set_clip_tabs);

+ 3 - 2
scene/gui/tab_bar.h

@@ -126,7 +126,6 @@ protected:
 	Variant get_drag_data(const Point2 &p_point) override;
 	bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
 	void drop_data(const Point2 &p_point, const Variant &p_data) override;
-	int get_tab_idx_at_point(const Point2 &p_point) const;
 
 public:
 	void add_tab(const String &p_str = "", const Ref<Texture2D> &p_icon = Ref<Texture2D>());
@@ -156,13 +155,15 @@ public:
 	void set_tab_button_icon(int p_tab, const Ref<Texture2D> &p_icon);
 	Ref<Texture2D> get_tab_button_icon(int p_tab) const;
 
+	int get_tab_idx_at_point(const Point2 &p_point) const;
+
 	void set_tab_alignment(AlignmentMode p_alignment);
 	AlignmentMode get_tab_alignment() const;
 
 	void set_clip_tabs(bool p_clip_tabs);
 	bool get_clip_tabs() const;
 
-	void move_tab(int from, int to);
+	void move_tab(int p_from, int p_to);
 
 	void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);
 	CloseButtonDisplayPolicy get_tab_close_display_policy() const;

A különbségek nem kerülnek megjelenítésre, a fájl túl nagy
+ 251 - 635
scene/gui/tab_container.cpp


+ 21 - 37
scene/gui/tab_container.h

@@ -33,46 +33,32 @@
 
 #include "scene/gui/container.h"
 #include "scene/gui/popup.h"
-#include "scene/resources/text_line.h"
+#include "scene/gui/tab_bar.h"
 
 class TabContainer : public Container {
 	GDCLASS(TabContainer, Container);
 
-public:
-	enum AlignmentMode {
-		ALIGNMENT_LEFT,
-		ALIGNMENT_CENTER,
-		ALIGNMENT_RIGHT,
-	};
-
-private:
-	int first_tab_cache = 0;
-	int tabs_ofs_cache = 0;
-	int last_tab_cache = 0;
-	int current = 0;
-	int previous = 0;
+	TabBar *tab_bar;
 	bool tabs_visible = true;
 	bool all_tabs_in_front = false;
-	bool buttons_visible_cache = false;
 	bool menu_hovered = false;
-	int highlight_arrow = -1;
-	AlignmentMode alignment = ALIGNMENT_CENTER;
-	int _get_top_margin() const;
 	mutable ObjectID popup_obj_id;
 	bool drag_to_rearrange_enabled = false;
 	bool use_hidden_tabs_for_min_size = false;
-	int tabs_rearrange_group = -1;
+	bool theme_changing = false;
 
-	Vector<Ref<TextLine>> text_buf;
-	Vector<Control *> _get_tabs() const;
-	int _get_tab_width(int p_index) const;
-	bool _theme_changing = false;
+	int _get_top_margin() const;
+	Vector<Control *> _get_tab_controls() const;
 	void _on_theme_changed();
 	void _repaint();
+	void _update_margins();
 	void _on_mouse_exited();
-	void _update_current_tab();
-	void _draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x);
-	void _refresh_texts();
+	void _on_tab_changed(int p_tab);
+	void _on_tab_selected(int p_tab);
+
+	Variant _get_drag_data_fw(const Point2 &p_point, Control *p_from_control);
+	bool _can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const;
+	void _drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control);
 
 protected:
 	void _child_renamed_callback();
@@ -81,17 +67,17 @@ protected:
 	virtual void add_child_notify(Node *p_child) override;
 	virtual void move_child_notify(Node *p_child) override;
 	virtual void remove_child_notify(Node *p_child) override;
+	static void _bind_methods();
 
-	Variant get_drag_data(const Point2 &p_point) override;
-	bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override;
-	void drop_data(const Point2 &p_point, const Variant &p_data) override;
+public:
 	int get_tab_idx_at_point(const Point2 &p_point) const;
+	int get_tab_idx_from_control(Control *p_child) const;
 
-	static void _bind_methods();
+	void set_tab_alignment(TabBar::AlignmentMode p_alignment);
+	TabBar::AlignmentMode get_tab_alignment() const;
 
-public:
-	void set_tab_alignment(AlignmentMode p_alignment);
-	AlignmentMode get_tab_alignment() const;
+	void set_clip_tabs(bool p_clip_tabs);
+	bool get_clip_tabs() const;
 
 	void set_tabs_visible(bool p_visible);
 	bool are_tabs_visible() const;
@@ -106,10 +92,10 @@ public:
 	Ref<Texture2D> get_tab_icon(int p_tab) const;
 
 	void set_tab_disabled(int p_tab, bool p_disabled);
-	bool get_tab_disabled(int p_tab) const;
+	bool is_tab_disabled(int p_tab) const;
 
 	void set_tab_hidden(int p_tab, bool p_hidden);
-	bool get_tab_hidden(int p_tab) const;
+	bool is_tab_hidden(int p_tab) const;
 
 	int get_tab_count() const;
 	void set_current_tab(int p_current);
@@ -139,6 +125,4 @@ public:
 	TabContainer();
 };
 
-VARIANT_ENUM_CAST(TabContainer::AlignmentMode);
-
 #endif // TAB_CONTAINER_H

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott