summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRĂ©mi Verschelde <remi@verschelde.fr>2022-03-04 12:18:55 +0100
committerGitHub <noreply@github.com>2022-03-04 12:18:55 +0100
commit9d5d20ae6d6d19d4435edf5de1fdb3b13982b108 (patch)
treee43f757c51611b20f0d314a51d3dbe0a5e4aa25a
parent5845b1d3fd9622a133f4c451c836d22de5ca2cdf (diff)
parenta811ebf6993aada1ba5f0f9502976e10fad8b179 (diff)
Merge pull request #58687 from YeldhamDev/the_beast_has_been_slain
-rw-r--r--doc/classes/TabBar.xml7
-rw-r--r--doc/classes/TabContainer.xml56
-rw-r--r--editor/action_map_editor.cpp2
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/debugger/script_editor_debugger.cpp10
-rw-r--r--editor/editor_node.cpp39
-rw-r--r--editor/editor_settings_dialog.cpp2
-rw-r--r--editor/localization_editor.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp206
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp2
-rw-r--r--editor/project_export.cpp2
-rw-r--r--editor/project_manager.cpp2
-rw-r--r--editor/project_settings_editor.cpp2
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--scene/gui/tab_bar.cpp88
-rw-r--r--scene/gui/tab_bar.h5
-rw-r--r--scene/gui/tab_container.cpp1058
-rw-r--r--scene/gui/tab_container.h58
19 files changed, 599 insertions, 948 deletions
diff --git a/doc/classes/TabBar.xml b/doc/classes/TabBar.xml
index 40d6e9f26c..41e1e255ae 100644
--- a/doc/classes/TabBar.xml
+++ b/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" />
diff --git a/doc/classes/TabContainer.xml b/doc/classes/TabContainer.xml
index 3986983155..3f4ec81c95 100644
--- a/doc/classes/TabContainer.xml
+++ b/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.
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 3eab494761..92d53cc005 100644
--- a/editor/action_map_editor.cpp
+++ b/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));
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 1c75b2dff1..d5a4f5d138 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -61,7 +61,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);
diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp
index 645d7608f3..0b9631c816 100644
--- a/editor/debugger/script_editor_debugger.cpp
+++ b/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));
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index cda5e6b537..ddb9c93f04 100644
--- a/editor/editor_node.cpp
+++ b/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();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 18324f9971..75bba64e2e 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/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);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index cd9986d527..a766650cd9 100644
--- a/editor/localization_editor.cpp
+++ b/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);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 30c2b12519..a4a2919034 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/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;
}
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index a03f036b72..74e3372730 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/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.
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index b1d5b348c4..443d5975cd 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/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);
diff --git a/editor/project_export.cpp b/editor/project_export.cpp
index 55a4dc2c67..1a111bcbfc 100644
--- a/editor/project_export.cpp
+++ b/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);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index 87d008d144..79aed36eeb 100644
--- a/editor/project_manager.cpp
+++ b/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);
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 03179733d5..4d708dc7e0 100644
--- a/editor/project_settings_editor.cpp
+++ b/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);
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 46751058d0..93c5b9ad4c 100644
--- a/editor/rename_dialog.cpp
+++ b/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);
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index ce60da762f..0e088a44e5 100644
--- a/scene/gui/tab_bar.cpp
+++ b/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);
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index b428538570..82ae8bce3f 100644
--- a/scene/gui/tab_bar.h
+++ b/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;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 31a5e41086..9953637e4f 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -30,44 +30,17 @@
#include "tab_container.h"
-#include "core/object/message_queue.h"
-#include "core/string/translation.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
int TabContainer::_get_top_margin() const {
- if (!tabs_visible) {
- return 0;
+ int height = 0;
+ if (tabs_visible && get_tab_count() > 0) {
+ height = tab_bar->get_minimum_size().height;
}
- // Respect the minimum tab height.
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
-
- int tab_height = MAX(MAX(tab_unselected->get_minimum_size().height, tab_selected->get_minimum_size().height), tab_disabled->get_minimum_size().height);
-
- // Font height or higher icon wins.
- int content_height = 0;
-
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- content_height = MAX(content_height, text_buf[i]->get_size().y);
-
- Control *c = tabs[i];
- if (!c->has_meta("_tab_icon")) {
- continue;
- }
-
- Ref<Texture2D> tex = c->get_meta("_tab_icon");
- if (!tex.is_valid()) {
- continue;
- }
- content_height = MAX(content_height, tex->get_size().height);
- }
-
- return tab_height + content_height;
+ return height;
}
void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
@@ -113,77 +86,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
-
- // Do not activate tabs when tabs is empty.
- if (get_tab_count() == 0) {
- return;
- }
-
- Vector<Control *> tabs = _get_tabs();
-
- // Handle navigation buttons.
- if (buttons_visible_cache) {
- int popup_ofs = 0;
- if (popup) {
- popup_ofs = menu->get_width();
- }
-
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- if (is_layout_rtl()) {
- if (pos.x < popup_ofs + decrement->get_width()) {
- if (last_tab_cache < tabs.size() - 1) {
- first_tab_cache += 1;
- update();
- }
- return;
- } else if (pos.x < popup_ofs + increment->get_width() + decrement->get_width()) {
- if (first_tab_cache > 0) {
- first_tab_cache -= 1;
- update();
- }
- return;
- }
- } else {
- if (pos.x > size.width - increment->get_width() - popup_ofs && pos.x) {
- if (last_tab_cache < tabs.size() - 1) {
- first_tab_cache += 1;
- update();
- }
- return;
- } else if (pos.x > size.width - increment->get_width() - decrement->get_width() - popup_ofs) {
- if (first_tab_cache > 0) {
- first_tab_cache -= 1;
- update();
- }
- return;
- }
- }
- }
-
- // Activate the clicked tab.
- if (is_layout_rtl()) {
- pos.x = size.width - pos.x;
- }
-
- if (pos.x < tabs_ofs_cache) {
- return;
- }
-
- pos.x -= tabs_ofs_cache;
- for (int i = first_tab_cache; i <= last_tab_cache; i++) {
- if (get_tab_hidden(i)) {
- continue;
- }
- int tab_width = _get_tab_width(i);
- if (pos.x < tab_width) {
- if (!get_tab_disabled(i)) {
- set_current_tab(i);
- }
- break;
- }
- pos.x -= tab_width;
- }
}
Ref<InputEventMouseMotion> mm = p_event;
@@ -194,9 +96,8 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
// Mouse must be on tabs in the tab header area.
if (pos.y > _get_top_margin()) {
- if (menu_hovered || highlight_arrow > -1) {
+ if (menu_hovered) {
menu_hovered = false;
- highlight_arrow = -1;
update();
}
return;
@@ -208,7 +109,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x <= menu->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- highlight_arrow = -1;
update();
return;
}
@@ -220,7 +120,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x >= size.width - menu->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
- highlight_arrow = -1;
update();
return;
}
@@ -234,102 +133,19 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
return;
}
}
-
- // Do not activate tabs when tabs is empty.
- if ((get_tab_count() == 0 || !buttons_visible_cache) && menu_hovered) {
- highlight_arrow = -1;
- update();
- return;
- }
-
- int popup_ofs = 0;
- if (popup) {
- popup_ofs = menu->get_width();
- }
-
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
-
- if (is_layout_rtl()) {
- if (pos.x <= popup_ofs + decrement->get_width()) {
- if (highlight_arrow != 1) {
- highlight_arrow = 1;
- update();
- }
- } else if (pos.x <= popup_ofs + increment->get_width() + decrement->get_width()) {
- if (highlight_arrow != 0) {
- highlight_arrow = 0;
- update();
- }
- } else if (highlight_arrow > -1) {
- highlight_arrow = -1;
- update();
- }
- } else {
- if (pos.x >= size.width - increment->get_width() - popup_ofs) {
- if (highlight_arrow != 1) {
- highlight_arrow = 1;
- update();
- }
- } else if (pos.x >= size.width - increment->get_width() - decrement->get_width() - popup_ofs) {
- if (highlight_arrow != 0) {
- highlight_arrow = 0;
- update();
- }
- } else if (highlight_arrow > -1) {
- highlight_arrow = -1;
- update();
- }
- }
}
}
void TabContainer::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY:
case NOTIFICATION_RESIZED: {
- Vector<Control *> tabs = _get_tabs();
- int side_margin = get_theme_constant(SNAME("side_margin"));
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- int header_width = get_size().width - side_margin * 2;
-
- // Find the width of the header area.
- Popup *popup = get_popup();
- if (popup) {
- header_width -= menu->get_width();
- }
- if (buttons_visible_cache) {
- header_width -= increment->get_width() + decrement->get_width();
- }
- if (popup || buttons_visible_cache) {
- header_width += side_margin;
- }
-
- // Find the width of all tabs after first_tab_cache.
- int all_tabs_width = 0;
- for (int i = first_tab_cache; i < tabs.size(); i++) {
- int tab_width = _get_tab_width(i);
- all_tabs_width += tab_width;
- }
-
- // Check if tabs before first_tab_cache would fit into the header area.
- for (int i = first_tab_cache - 1; i >= 0; i--) {
- int tab_width = _get_tab_width(i);
-
- if (all_tabs_width + tab_width > header_width) {
- break;
- }
-
- all_tabs_width += tab_width;
- first_tab_cache--;
- }
+ _update_margins();
} break;
case NOTIFICATION_DRAW: {
RID canvas = get_canvas_item();
Size2 size = get_size();
- bool rtl = is_layout_rtl();
// Draw only the tab area if the header is hidden.
Ref<StyleBox> panel = get_theme_stylebox(SNAME("panel"));
@@ -338,481 +154,171 @@ void TabContainer::_notification(int p_what) {
return;
}
- Vector<Control *> tabs = _get_tabs();
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> increment_hl = get_theme_icon(SNAME("increment_highlight"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> decrement_hl = get_theme_icon(SNAME("decrement_highlight"));
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
- Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
- Color font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
- Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- int side_margin = get_theme_constant(SNAME("side_margin"));
-
- // Find out start and width of the header area.
- int header_x = side_margin;
- int header_width = size.width - side_margin * 2;
int header_height = _get_top_margin();
- Popup *popup = get_popup();
- if (popup) {
- header_width -= menu->get_width();
- }
-
- // Check if all tabs would fit into the header area.
- int all_tabs_width = 0;
- for (int i = 0; i < tabs.size(); i++) {
- if (get_tab_hidden(i)) {
- continue;
- }
- int tab_width = _get_tab_width(i);
- all_tabs_width += tab_width;
-
- if (all_tabs_width > header_width) {
- // Not all tabs are visible at the same time - reserve space for navigation buttons.
- buttons_visible_cache = true;
- header_width -= decrement->get_width() + increment->get_width();
- break;
- } else {
- buttons_visible_cache = false;
- }
- }
- // With buttons, a right side margin does not need to be respected.
- if (popup || buttons_visible_cache) {
- header_width += side_margin;
- }
-
- if (!buttons_visible_cache) {
- first_tab_cache = 0;
- }
-
- // Go through the visible tabs to find the width they occupy.
- all_tabs_width = 0;
- Vector<int> tab_widths;
- for (int i = first_tab_cache; i < tabs.size(); i++) {
- if (get_tab_hidden(i)) {
- tab_widths.push_back(0);
- continue;
- }
- int tab_width = _get_tab_width(i);
- if (all_tabs_width + tab_width > header_width && tab_widths.size() > 0) {
- break;
- }
- all_tabs_width += tab_width;
- tab_widths.push_back(tab_width);
- }
-
- // Find the offset at which to draw tabs, according to the alignment.
- switch (alignment) {
- case ALIGNMENT_LEFT:
- tabs_ofs_cache = header_x;
- break;
- case ALIGNMENT_CENTER:
- tabs_ofs_cache = header_x + (header_width / 2) - (all_tabs_width / 2);
- break;
- case ALIGNMENT_RIGHT:
- tabs_ofs_cache = header_x + header_width - all_tabs_width;
- break;
- }
-
- if (all_tabs_in_front) {
- // Draw the tab area.
- panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
- }
-
- // Draw unselected tabs in back
- int x = 0;
- int x_current = 0;
- int index = 0;
- for (int i = 0; i < tab_widths.size(); i++) {
- index = i + first_tab_cache;
- if (get_tab_hidden(index)) {
- continue;
- }
-
- int tab_width = tab_widths[i];
- if (index == current) {
- x_current = x;
- } else if (get_tab_disabled(index)) {
- if (rtl) {
- _draw_tab(tab_disabled, font_disabled_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
- } else {
- _draw_tab(tab_disabled, font_disabled_color, index, tabs_ofs_cache + x);
- }
- } else {
- if (rtl) {
- _draw_tab(tab_unselected, font_unselected_color, index, size.width - (tabs_ofs_cache + x) - tab_width);
- } else {
- _draw_tab(tab_unselected, font_unselected_color, index, tabs_ofs_cache + x);
- }
- }
- x += tab_width;
- last_tab_cache = index;
- }
+ panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
- if (!all_tabs_in_front) {
- // Draw the tab area.
- panel->draw(canvas, Rect2(0, header_height, size.width, size.height - header_height));
- }
+ // Draw the popup menu.
+ if (get_popup()) {
+ Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
+ Ref<Texture2D> menu_hl = get_theme_icon(SNAME("menu_highlight"));
- // Draw selected tab in front. Only draw selected tab when it's in visible range.
- if (tabs.size() > 0 && current - first_tab_cache < tab_widths.size() && current >= first_tab_cache) {
- Ref<StyleBox> current_style_box = get_tab_disabled(current) ? tab_disabled : tab_selected;
- if (rtl) {
- _draw_tab(current_style_box, font_selected_color, current, size.width - (tabs_ofs_cache + x_current) - tab_widths[current]);
- } else {
- _draw_tab(current_style_box, font_selected_color, current, tabs_ofs_cache + x_current);
- }
- }
+ int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
- // Draw the popup menu.
- if (rtl) {
- x = 0;
- } else {
- x = get_size().width;
- }
- if (popup) {
- if (!rtl) {
- x -= menu->get_width();
- }
if (menu_hovered) {
menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2));
} else {
menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2));
}
- if (rtl) {
- x += menu->get_width();
- }
- }
-
- // Draw the navigation buttons.
- if (buttons_visible_cache) {
- if (rtl) {
- if (last_tab_cache < tabs.size() - 1) {
- draw_texture(highlight_arrow == 1 ? decrement_hl : decrement, Point2(x, (header_height - increment->get_height()) / 2));
- } else {
- draw_texture(decrement, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- x += increment->get_width();
-
- if (first_tab_cache > 0) {
- draw_texture(highlight_arrow == 0 ? increment_hl : increment, Point2(x, (header_height - decrement->get_height()) / 2));
- } else {
- draw_texture(increment, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- x += decrement->get_width();
- } else {
- x -= increment->get_width();
- if (last_tab_cache < tabs.size() - 1) {
- draw_texture(highlight_arrow == 1 ? increment_hl : increment, Point2(x, (header_height - increment->get_height()) / 2));
- } else {
- draw_texture(increment, Point2(x, (header_height - increment->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
-
- x -= decrement->get_width();
- if (first_tab_cache > 0) {
- draw_texture(highlight_arrow == 0 ? decrement_hl : decrement, Point2(x, (header_height - decrement->get_height()) / 2));
- } else {
- draw_texture(decrement, Point2(x, (header_height - decrement->get_height()) / 2), Color(1, 1, 1, 0.5));
- }
- }
}
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- text_buf.write[i]->clear();
- }
- _theme_changing = true;
+ theme_changing = true;
call_deferred(SNAME("_on_theme_changed")); // Wait until all changed theme.
} break;
}
}
-void TabContainer::_draw_tab(Ref<StyleBox> &p_tab_style, Color &p_font_color, int p_index, float p_x) {
- Control *control = get_tab_control(p_index);
- RID canvas = get_canvas_item();
- Color font_outline_color = get_theme_color(SNAME("font_outline_color"));
- int outline_size = get_theme_constant(SNAME("outline_size"));
- int icon_text_distance = get_theme_constant(SNAME("icon_separation"));
- int tab_width = _get_tab_width(p_index);
- int header_height = _get_top_margin();
-
- // Draw the tab background.
- Rect2 tab_rect(p_x, 0, tab_width, header_height);
- p_tab_style->draw(canvas, tab_rect);
-
- // Draw the tab contents.
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
-
- int x_content = tab_rect.position.x + p_tab_style->get_margin(SIDE_LEFT);
- int top_margin = p_tab_style->get_margin(SIDE_TOP);
- int y_center = top_margin + (tab_rect.size.y - p_tab_style->get_minimum_size().y) / 2;
-
- // Draw the tab icon.
- if (control->has_meta("_tab_icon")) {
- Ref<Texture2D> icon = control->get_meta("_tab_icon");
- if (icon.is_valid()) {
- int y = y_center - (icon->get_height() / 2);
- icon->draw(canvas, Point2i(x_content, y));
- if (!text.is_empty()) {
- x_content += icon->get_width() + icon_text_distance;
- }
- }
- }
-
- // Draw the tab text.
- Point2i text_pos(x_content, y_center - text_buf[p_index]->get_size().y / 2);
- if (outline_size > 0 && font_outline_color.a > 0) {
- text_buf[p_index]->draw_outline(canvas, text_pos, outline_size, font_outline_color);
- }
- text_buf[p_index]->draw(canvas, text_pos, p_font_color);
-}
-
-void TabContainer::_refresh_texts() {
- text_buf.clear();
- Vector<Control *> tabs = _get_tabs();
- bool rtl = is_layout_rtl();
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
- for (int i = 0; i < tabs.size(); i++) {
- Control *control = Object::cast_to<Control>(tabs[i]);
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
-
- Ref<TextLine> name;
- name.instantiate();
- name->set_direction(rtl ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR);
- name->add_string(text, font, font_size, Dictionary(), TranslationServer::get_singleton()->get_tool_locale());
- text_buf.push_back(name);
- }
-}
-
void TabContainer::_on_theme_changed() {
- if (!_theme_changing) {
+ if (!theme_changing) {
return;
}
- _refresh_texts();
-
- update_minimum_size();
+ tab_bar->add_theme_style_override(SNAME("tab_unselected"), get_theme_stylebox(SNAME("tab_unselected")));
+ tab_bar->add_theme_style_override(SNAME("tab_selected"), get_theme_stylebox(SNAME("tab_selected")));
+ tab_bar->add_theme_style_override(SNAME("tab_disabled"), get_theme_stylebox(SNAME("tab_disabled")));
+ tab_bar->add_theme_icon_override(SNAME("increment"), get_theme_icon(SNAME("increment")));
+ tab_bar->add_theme_icon_override(SNAME("increment_highlight"), get_theme_icon(SNAME("increment_highlight")));
+ tab_bar->add_theme_icon_override(SNAME("decrement"), get_theme_icon(SNAME("decrement")));
+ tab_bar->add_theme_icon_override(SNAME("decrement_highlight"), get_theme_icon(SNAME("decrement_highlight")));
+ tab_bar->add_theme_color_override(SNAME("font_selected_color"), get_theme_color(SNAME("font_selected_color")));
+ tab_bar->add_theme_color_override(SNAME("font_unselected_color"), get_theme_color(SNAME("font_unselected_color")));
+ tab_bar->add_theme_color_override(SNAME("font_disabled_color"), get_theme_color(SNAME("font_disabled_color")));
+ tab_bar->add_theme_color_override(SNAME("font_outline_color"), get_theme_color(SNAME("font_outline_color")));
+ tab_bar->add_theme_font_override(SNAME("font"), get_theme_font(SNAME("font")));
+ tab_bar->add_theme_constant_override(SNAME("font_size"), get_theme_constant(SNAME("font_size")));
+ tab_bar->add_theme_constant_override(SNAME("icon_separation"), get_theme_constant(SNAME("icon_separation")));
+ tab_bar->add_theme_constant_override(SNAME("outline_size"), get_theme_constant(SNAME("outline_size")));
+
+ _update_margins();
if (get_tab_count() > 0) {
_repaint();
- update();
+ } else {
+ update_minimum_size();
}
- _theme_changing = false;
+ update();
+
+ theme_changing = false;
}
void TabContainer::_repaint() {
Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ Vector<Control *> controls = _get_tab_controls();
+ int current = get_current_tab();
+
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
+
if (i == current) {
c->show();
c->set_anchors_and_offsets_preset(Control::PRESET_WIDE);
+
if (tabs_visible) {
c->set_offset(SIDE_TOP, _get_top_margin());
}
+
c->set_offset(SIDE_TOP, c->get_offset(SIDE_TOP) + sb->get_margin(SIDE_TOP));
c->set_offset(SIDE_LEFT, c->get_offset(SIDE_LEFT) + sb->get_margin(SIDE_LEFT));
c->set_offset(SIDE_RIGHT, c->get_offset(SIDE_RIGHT) - sb->get_margin(SIDE_RIGHT));
c->set_offset(SIDE_BOTTOM, c->get_offset(SIDE_BOTTOM) - sb->get_margin(SIDE_BOTTOM));
-
} else {
c->hide();
}
}
-}
-
-void TabContainer::_on_mouse_exited() {
- if (menu_hovered || highlight_arrow > -1) {
- menu_hovered = false;
- highlight_arrow = -1;
- update();
- }
-}
-
-int TabContainer::_get_tab_width(int p_index) const {
- ERR_FAIL_INDEX_V(p_index, get_tab_count(), 0);
- Control *control = get_tab_control(p_index);
- if (!control || get_tab_hidden(p_index)) {
- return 0;
- }
-
- // Get the width of the text displayed on the tab.
- Ref<Font> font = get_theme_font(SNAME("font"));
- int font_size = get_theme_font_size(SNAME("font_size"));
- String text = control->has_meta("_tab_name") ? String(atr(String(control->get_meta("_tab_name")))) : String(atr(control->get_name()));
- int width = font->get_string_size(text, font_size).width;
-
- // Add space for a tab icon.
- if (control->has_meta("_tab_icon")) {
- Ref<Texture2D> icon = control->get_meta("_tab_icon");
- if (icon.is_valid()) {
- width += icon->get_width();
- if (!text.is_empty()) {
- width += get_theme_constant(SNAME("icon_separation"));
- }
- }
- }
-
- // Respect a minimum size.
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
- if (get_tab_disabled(p_index)) {
- width += tab_disabled->get_minimum_size().width;
- } else if (p_index == current) {
- width += tab_selected->get_minimum_size().width;
- } else {
- width += tab_unselected->get_minimum_size().width;
- }
- return width;
+ update_minimum_size();
}
-Vector<Control *> TabContainer::_get_tabs() const {
- Vector<Control *> controls;
- for (int i = 0; i < get_child_count(); i++) {
- Control *control = Object::cast_to<Control>(get_child(i));
- if (!control || control->is_set_as_top_level()) {
- continue;
- }
-
- controls.push_back(control);
- }
- return controls;
-}
+void TabContainer::_update_margins() {
+ int menu_width = get_theme_icon(SNAME("menu"))->get_width();
+ int side_margin = get_theme_constant(SNAME("side_margin"));
-void TabContainer::_child_renamed_callback() {
- _refresh_texts();
- update();
-}
+ // Directly check for validity, to avoid errors when quitting.
+ bool has_popup = popup_obj_id.is_valid();
-void TabContainer::add_child_notify(Node *p_child) {
- Container::add_child_notify(p_child);
+ if (get_tab_count() == 0) {
+ tab_bar->set_offset(SIDE_LEFT, 0);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
return;
}
- _refresh_texts();
- call_deferred(SNAME("_repaint"));
- update();
-
- bool first = (_get_tabs().size() == 1);
- if (first) {
- current = 0;
- previous = 0;
- }
-
- p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
- if (first && is_inside_tree()) {
- emit_signal(SNAME("tab_changed"), current);
- }
-}
-
-void TabContainer::move_child_notify(Node *p_child) {
- Container::move_child_notify(p_child);
+ switch (get_tab_alignment()) {
+ case TabBar::ALIGNMENT_LEFT: {
+ tab_bar->set_offset(SIDE_LEFT, side_margin);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } break;
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
- return;
- }
+ case TabBar::ALIGNMENT_CENTER: {
+ tab_bar->set_offset(SIDE_LEFT, 0);
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } break;
- _update_current_tab();
- update();
-}
+ case TabBar::ALIGNMENT_RIGHT: {
+ tab_bar->set_offset(SIDE_LEFT, 0);
-int TabContainer::get_tab_count() const {
- return _get_tabs().size();
-}
-
-void TabContainer::set_current_tab(int p_current) {
- ERR_FAIL_INDEX(p_current, get_tab_count());
+ if (has_popup) {
+ tab_bar->set_offset(SIDE_RIGHT, -menu_width);
+ return;
+ }
- int pending_previous = current;
- current = p_current;
+ int first_tab_pos = tab_bar->get_tab_rect(0).position.x;
+ Rect2 last_tab_rect = tab_bar->get_tab_rect(get_tab_count() - 1);
+ int total_tabs_width = last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width;
- _repaint();
+ // Calculate if all the tabs would still fit if the margin was present.
+ if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + side_margin) > get_size().width))) {
+ tab_bar->set_offset(SIDE_RIGHT, has_popup ? -menu_width : 0);
+ } else {
+ tab_bar->set_offset(SIDE_RIGHT, -side_margin);
+ }
+ } break;
- if (pending_previous == current) {
- emit_signal(SNAME("tab_selected"), current);
- } else {
- previous = pending_previous;
- emit_signal(SNAME("tab_selected"), current);
- emit_signal(SNAME("tab_changed"), current);
+ case TabBar::ALIGNMENT_MAX:
+ break; // Can't happen, but silences warning.
}
-
- update();
-}
-
-int TabContainer::get_current_tab() const {
- return current;
}
-int TabContainer::get_previous_tab() const {
- return previous;
-}
-
-Control *TabContainer::get_tab_control(int p_idx) const {
- Vector<Control *> tabs = _get_tabs();
- if (p_idx >= 0 && p_idx < tabs.size()) {
- return tabs[p_idx];
- } else {
- return nullptr;
+void TabContainer::_on_mouse_exited() {
+ if (menu_hovered) {
+ menu_hovered = false;
+ update();
}
}
-Control *TabContainer::get_current_tab_control() const {
- return get_tab_control(current);
-}
-
-void TabContainer::remove_child_notify(Node *p_child) {
- Container::remove_child_notify(p_child);
+Vector<Control *> TabContainer::_get_tab_controls() const {
+ Vector<Control *> controls;
+ for (int i = 0; i < get_child_count(); i++) {
+ Control *control = Object::cast_to<Control>(get_child(i));
+ if (!control || control->is_set_as_top_level() || control == tab_bar) {
+ continue;
+ }
- Control *c = Object::cast_to<Control>(p_child);
- if (!c || c->is_set_as_top_level()) {
- return;
+ controls.push_back(control);
}
- // Defer the call because tab is not yet removed (remove_child_notify is called right before p_child is actually removed).
- call_deferred(SNAME("_update_current_tab"));
-
- p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
-
- update();
-}
-
-void TabContainer::_update_current_tab() {
- _refresh_texts();
-
- int tc = get_tab_count();
- if (current >= tc) {
- current = tc - 1;
- }
- if (current < 0) {
- current = 0;
- } else {
- set_current_tab(current);
- }
+ return controls;
}
-Variant TabContainer::get_drag_data(const Point2 &p_point) {
+Variant TabContainer::_get_drag_data_fw(const Point2 &p_point, Control *p_from_control) {
if (!drag_to_rearrange_enabled) {
return Variant();
}
int tab_over = get_tab_idx_at_point(p_point);
-
if (tab_over < 0) {
return Variant();
}
@@ -825,18 +331,20 @@ Variant TabContainer::get_drag_data(const Point2 &p_point) {
tf->set_texture(icon);
drag_preview->add_child(tf);
}
+
Label *label = memnew(Label(get_tab_title(tab_over)));
- drag_preview->add_child(label);
set_drag_preview(drag_preview);
+ drag_preview->add_child(label);
Dictionary drag_data;
drag_data["type"] = "tabc_element";
drag_data["tabc_element"] = tab_over;
drag_data["from_path"] = get_path();
+
return drag_data;
}
-bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
+bool TabContainer::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) const {
if (!drag_to_rearrange_enabled) {
return false;
}
@@ -852,7 +360,7 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c
if (from_path == to_path) {
return true;
} else if (get_tabs_rearrange_group() != -1) {
- // drag and drop between other TabContainers
+ // Drag and drop between other TabContainers.
Node *from_node = get_node(from_path);
TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
@@ -860,10 +368,11 @@ bool TabContainer::can_drop_data(const Point2 &p_point, const Variant &p_data) c
}
}
}
+
return false;
}
-void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
+void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from_control) {
if (!drag_to_rearrange_enabled) {
return;
}
@@ -883,85 +392,192 @@ void TabContainer::drop_data(const Point2 &p_point, const Variant &p_data) {
if (hover_now < 0) {
hover_now = get_tab_count() - 1;
}
- move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index());
+
+ move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false));
set_current_tab(hover_now);
} else if (get_tabs_rearrange_group() != -1) {
- // drag and drop between TabContainers
+ // Drag and drop between TabContainers.
Node *from_node = get_node(from_path);
TabContainer *from_tabc = Object::cast_to<TabContainer>(from_node);
if (from_tabc && from_tabc->get_tabs_rearrange_group() == get_tabs_rearrange_group()) {
Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
from_tabc->remove_child(moving_tabc);
- add_child(moving_tabc, false, INTERNAL_MODE_FRONT);
+ add_child(moving_tabc, true);
+
if (hover_now < 0) {
hover_now = get_tab_count() - 1;
}
- move_child(moving_tabc, get_tab_control(hover_now)->get_index());
+
+ move_child(moving_tabc, get_tab_control(hover_now)->get_index(false));
+
set_current_tab(hover_now);
- emit_signal(SNAME("tab_changed"), hover_now);
}
}
}
- update();
}
-int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
- if (get_tab_count() == 0) {
- return -1;
+void TabContainer::_on_tab_changed(int p_tab) {
+ call_deferred(SNAME("_repaint"));
+
+ emit_signal(SNAME("tab_changed"), p_tab);
+}
+
+void TabContainer::_on_tab_selected(int p_tab) {
+ if (p_tab != get_previous_tab()) {
+ call_deferred(SNAME("_repaint"));
}
- // must be on tabs in the tab header area.
- if (p_point.y > _get_top_margin()) {
- return -1;
+ emit_signal(SNAME("tab_selected"), p_tab);
+}
+
+void TabContainer::_child_renamed_callback() {
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ if (!controls[i]->has_meta("_tab_name") && String(controls[i]->get_name()) != get_tab_title(i)) {
+ tab_bar->set_tab_title(i, controls[i]->get_name());
+ return;
+ }
}
+}
- Size2 size = get_size();
- int button_ofs = 0;
- int px = p_point.x;
+void TabContainer::add_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
+ }
+
+ Container::add_child_notify(p_child);
- if (is_layout_rtl()) {
- px = size.width - px;
+ Control *c = Object::cast_to<Control>(p_child);
+ if (!c || c->is_set_as_top_level()) {
+ return;
}
+ c->hide();
+
+ tab_bar->add_tab(p_child->get_name());
- if (px < tabs_ofs_cache) {
- return -1;
+ _update_margins();
+
+ p_child->connect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
+
+ // TabBar won't emit the "tab_changed" signal when not inside the tree.
+ if (!is_inside_tree()) {
+ call_deferred("_repaint");
}
+}
- Popup *popup = get_popup();
- if (popup) {
- Ref<Texture2D> menu = get_theme_icon(SNAME("menu"));
- button_ofs += menu->get_width();
+void TabContainer::move_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
}
- if (buttons_visible_cache) {
- Ref<Texture2D> increment = get_theme_icon(SNAME("increment"));
- Ref<Texture2D> decrement = get_theme_icon(SNAME("decrement"));
- button_ofs += increment->get_width() + decrement->get_width();
+
+ Container::move_child_notify(p_child);
+
+ Control *c = Object::cast_to<Control>(p_child);
+ if (c && !c->is_set_as_top_level()) {
+ int old_idx = -1;
+ String tab_name = c->has_meta("_tab_name") ? String(c->get_meta("_tab_name")) : String(c->get_name());
+
+ // Find the previous tab index of the control.
+ for (int i = 0; i < get_tab_count(); i++) {
+ if (get_tab_title(i) == tab_name) {
+ old_idx = i;
+ break;
+ }
+ }
+
+ tab_bar->move_tab(old_idx, get_tab_idx_from_control(c));
}
- if (px > size.width - button_ofs) {
- return -1;
+}
+
+void TabContainer::remove_child_notify(Node *p_child) {
+ if (p_child == tab_bar) {
+ return;
}
- // get the tab at the point
- Vector<Control *> tabs = _get_tabs();
- px -= tabs_ofs_cache;
- for (int i = first_tab_cache; i <= last_tab_cache; i++) {
- int tab_width = _get_tab_width(i);
- if (px < tab_width) {
+ Container::remove_child_notify(p_child);
+
+ Control *c = Object::cast_to<Control>(p_child);
+ if (!c || c->is_set_as_top_level()) {
+ return;
+ }
+
+ tab_bar->remove_tab(get_tab_idx_from_control(c));
+
+ _update_margins();
+
+ if (p_child->has_meta("_tab_name")) {
+ p_child->remove_meta("_tab_name");
+ }
+ p_child->disconnect("renamed", callable_mp(this, &TabContainer::_child_renamed_callback));
+
+ // TabBar won't emit the "tab_changed" signal when not inside the tree.
+ if (!is_inside_tree()) {
+ call_deferred("_repaint");
+ }
+}
+
+int TabContainer::get_tab_count() const {
+ return tab_bar->get_tab_count();
+}
+
+void TabContainer::set_current_tab(int p_current) {
+ tab_bar->set_current_tab(p_current);
+}
+
+int TabContainer::get_current_tab() const {
+ return tab_bar->get_current_tab();
+}
+
+int TabContainer::get_previous_tab() const {
+ return tab_bar->get_previous_tab();
+}
+
+Control *TabContainer::get_tab_control(int p_idx) const {
+ Vector<Control *> controls = _get_tab_controls();
+ if (p_idx >= 0 && p_idx < controls.size()) {
+ return controls[p_idx];
+ } else {
+ return nullptr;
+ }
+}
+
+Control *TabContainer::get_current_tab_control() const {
+ return get_tab_control(tab_bar->get_current_tab());
+}
+
+int TabContainer::get_tab_idx_at_point(const Point2 &p_point) const {
+ return tab_bar->get_tab_idx_at_point(p_point);
+}
+
+int TabContainer::get_tab_idx_from_control(Control *p_child) const {
+ ERR_FAIL_NULL_V(p_child, -1);
+ ERR_FAIL_COND_V(p_child->get_parent() != this, -1);
+
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ if (controls[i] == p_child) {
return i;
}
- px -= tab_width;
}
+
return -1;
}
-void TabContainer::set_tab_alignment(AlignmentMode p_alignment) {
- ERR_FAIL_INDEX(p_alignment, 3);
- alignment = p_alignment;
- update();
+void TabContainer::set_tab_alignment(TabBar::AlignmentMode p_alignment) {
+ tab_bar->set_tab_alignment(p_alignment);
+ _update_margins();
}
-TabContainer::AlignmentMode TabContainer::get_tab_alignment() const {
- return alignment;
+TabBar::AlignmentMode TabContainer::get_tab_alignment() const {
+ return tab_bar->get_tab_alignment();
+}
+
+void TabContainer::set_clip_tabs(bool p_clip_tabs) {
+ tab_bar->set_clip_tabs(p_clip_tabs);
+}
+
+bool TabContainer::get_clip_tabs() const {
+ return tab_bar->get_clip_tabs();
}
void TabContainer::set_tabs_visible(bool p_visible) {
@@ -970,11 +586,12 @@ void TabContainer::set_tabs_visible(bool p_visible) {
}
tabs_visible = p_visible;
+ tab_bar->set_visible(tabs_visible);
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
- if (p_visible) {
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
+ if (tabs_visible) {
c->set_offset(SIDE_TOP, _get_top_margin());
} else {
c->set_offset(SIDE_TOP, 0);
@@ -996,7 +613,8 @@ void TabContainer::set_all_tabs_in_front(bool p_in_front) {
all_tabs_in_front = p_in_front;
- update();
+ remove_child(tab_bar);
+ add_child(tab_bar, false, all_tabs_in_front ? INTERNAL_MODE_BACK : INTERNAL_MODE_FRONT);
}
bool TabContainer::is_all_tabs_in_front() const {
@@ -1006,95 +624,61 @@ bool TabContainer::is_all_tabs_in_front() const {
void TabContainer::set_tab_title(int p_tab, const String &p_title) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
- child->set_meta("_tab_name", p_title);
- _refresh_texts();
- update();
-}
-String TabContainer::get_tab_title(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, "");
- if (child->has_meta("_tab_name")) {
- return child->get_meta("_tab_name");
+ if (p_title.is_empty()) {
+ tab_bar->set_tab_title(p_tab, String(child->get_name()));
+
+ if (child->has_meta("_tab_name")) {
+ child->remove_meta("_tab_name");
+ }
} else {
- return child->get_name();
+ tab_bar->set_tab_title(p_tab, p_title);
+ child->set_meta("_tab_name", p_title);
}
}
+String TabContainer::get_tab_title(int p_tab) const {
+ return tab_bar->get_tab_title(p_tab);
+}
+
void TabContainer::set_tab_icon(int p_tab, const Ref<Texture2D> &p_icon) {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND(!child);
- child->set_meta("_tab_icon", p_icon);
- update();
+ tab_bar->set_tab_icon(p_tab, p_icon);
}
Ref<Texture2D> TabContainer::get_tab_icon(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, Ref<Texture2D>());
- if (child->has_meta("_tab_icon")) {
- return child->get_meta("_tab_icon");
- } else {
- return Ref<Texture2D>();
- }
+ return tab_bar->get_tab_icon(p_tab);
}
void TabContainer::set_tab_disabled(int p_tab, bool p_disabled) {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND(!child);
- child->set_meta("_tab_disabled", p_disabled);
- update();
+ tab_bar->set_tab_disabled(p_tab, p_disabled);
}
-bool TabContainer::get_tab_disabled(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, false);
- if (child->has_meta("_tab_disabled")) {
- return child->get_meta("_tab_disabled");
- } else {
- return false;
- }
+bool TabContainer::is_tab_disabled(int p_tab) const {
+ return tab_bar->is_tab_disabled(p_tab);
}
void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) {
Control *child = get_tab_control(p_tab);
ERR_FAIL_COND(!child);
- child->set_meta("_tab_hidden", p_hidden);
- update();
- for (int i = 0; i < get_tab_count(); i++) {
- int try_tab = (p_tab + 1 + i) % get_tab_count();
- if (get_tab_disabled(try_tab) || get_tab_hidden(try_tab)) {
- continue;
- }
-
- set_current_tab(try_tab);
- return;
- }
- //assumed no other tab can be switched to, just hide
+ tab_bar->set_tab_hidden(p_tab, p_hidden);
child->hide();
}
-bool TabContainer::get_tab_hidden(int p_tab) const {
- Control *child = get_tab_control(p_tab);
- ERR_FAIL_COND_V(!child, false);
- if (child->has_meta("_tab_hidden")) {
- return child->get_meta("_tab_hidden");
- } else {
- return false;
- }
+bool TabContainer::is_tab_hidden(int p_tab) const {
+ return tab_bar->is_tab_hidden(p_tab);
}
void TabContainer::get_translatable_strings(List<String> *p_strings) const {
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ Vector<Control *> controls = _get_tab_controls();
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
if (!c->has_meta("_tab_name")) {
continue;
}
String name = c->get_meta("_tab_name");
-
if (!name.is_empty()) {
p_strings->push_back(name);
}
@@ -1104,9 +688,26 @@ void TabContainer::get_translatable_strings(List<String> *p_strings) const {
Size2 TabContainer::get_minimum_size() const {
Size2 ms;
- Vector<Control *> tabs = _get_tabs();
- for (int i = 0; i < tabs.size(); i++) {
- Control *c = tabs[i];
+ if (tabs_visible) {
+ ms = tab_bar->get_minimum_size();
+
+ if (!get_clip_tabs()) {
+ if (get_popup()) {
+ ms.x += get_theme_icon(SNAME("menu"))->get_width();
+ }
+
+ int side_margin = get_theme_constant(SNAME("side_margin"));
+ if (side_margin > 0 && get_tab_alignment() != TabBar::ALIGNMENT_CENTER &&
+ (get_tab_alignment() != TabBar::ALIGNMENT_RIGHT || !get_popup())) {
+ ms.x += side_margin;
+ }
+ }
+ }
+
+ Vector<Control *> controls = _get_tab_controls();
+ int max_control_height = 0;
+ for (int i = 0; i < controls.size(); i++) {
+ Control *c = controls[i];
if (!c->is_visible_in_tree() && !use_hidden_tabs_for_min_size) {
continue;
@@ -1114,29 +715,28 @@ Size2 TabContainer::get_minimum_size() const {
Size2 cms = c->get_combined_minimum_size();
ms.x = MAX(ms.x, cms.x);
- ms.y = MAX(ms.y, cms.y);
+ max_control_height = MAX(max_control_height, cms.y);
}
+ ms.y += max_control_height;
- Ref<StyleBox> tab_unselected = get_theme_stylebox(SNAME("tab_unselected"));
- Ref<StyleBox> tab_selected = get_theme_stylebox(SNAME("tab_selected"));
- Ref<StyleBox> tab_disabled = get_theme_stylebox(SNAME("tab_disabled"));
-
- if (tabs_visible) {
- ms.y += MAX(MAX(tab_unselected->get_minimum_size().y, tab_selected->get_minimum_size().y), tab_disabled->get_minimum_size().y);
- ms.y += _get_top_margin();
- }
-
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"));
- ms += sb->get_minimum_size();
+ Size2 panel_ms = get_theme_stylebox(SNAME("panel"))->get_minimum_size();
+ ms.x = MAX(ms.x, panel_ms.x);
+ ms.y += panel_ms.y;
return ms;
}
void TabContainer::set_popup(Node *p_popup) {
- ERR_FAIL_NULL(p_popup);
+ bool had_popup = get_popup();
+
Popup *popup = Object::cast_to<Popup>(p_popup);
popup_obj_id = popup ? popup->get_instance_id() : ObjectID();
- update();
+
+ if (had_popup != bool(popup)) {
+ update();
+ _update_margins();
+ update_minimum_size();
+ }
}
Popup *TabContainer::get_popup() const {
@@ -1151,6 +751,7 @@ Popup *TabContainer::get_popup() const {
popup_obj_id = ObjectID();
}
}
+
return nullptr;
}
@@ -1163,15 +764,16 @@ bool TabContainer::get_drag_to_rearrange_enabled() const {
}
void TabContainer::set_tabs_rearrange_group(int p_group_id) {
- tabs_rearrange_group = p_group_id;
+ tab_bar->set_tabs_rearrange_group(p_group_id);
}
int TabContainer::get_tabs_rearrange_group() const {
- return tabs_rearrange_group;
+ return tab_bar->get_tabs_rearrange_group();
}
void TabContainer::set_use_hidden_tabs_for_min_size(bool p_use_hidden_tabs) {
use_hidden_tabs_for_min_size = p_use_hidden_tabs;
+ update_minimum_size();
}
bool TabContainer::get_use_hidden_tabs_for_min_size() const {
@@ -1195,6 +797,8 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_tab_control", "tab_idx"), &TabContainer::get_tab_control);
ClassDB::bind_method(D_METHOD("set_tab_alignment", "alignment"), &TabContainer::set_tab_alignment);
ClassDB::bind_method(D_METHOD("get_tab_alignment"), &TabContainer::get_tab_alignment);
+ ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &TabContainer::set_clip_tabs);
+ ClassDB::bind_method(D_METHOD("get_clip_tabs"), &TabContainer::get_clip_tabs);
ClassDB::bind_method(D_METHOD("set_tabs_visible", "visible"), &TabContainer::set_tabs_visible);
ClassDB::bind_method(D_METHOD("are_tabs_visible"), &TabContainer::are_tabs_visible);
ClassDB::bind_method(D_METHOD("set_all_tabs_in_front", "is_front"), &TabContainer::set_all_tabs_in_front);
@@ -1204,23 +808,25 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_tab_icon", "tab_idx", "icon"), &TabContainer::set_tab_icon);
ClassDB::bind_method(D_METHOD("get_tab_icon", "tab_idx"), &TabContainer::get_tab_icon);
ClassDB::bind_method(D_METHOD("set_tab_disabled", "tab_idx", "disabled"), &TabContainer::set_tab_disabled);
- ClassDB::bind_method(D_METHOD("get_tab_disabled", "tab_idx"), &TabContainer::get_tab_disabled);
+ ClassDB::bind_method(D_METHOD("is_tab_disabled", "tab_idx"), &TabContainer::is_tab_disabled);
ClassDB::bind_method(D_METHOD("set_tab_hidden", "tab_idx", "hidden"), &TabContainer::set_tab_hidden);
- ClassDB::bind_method(D_METHOD("get_tab_hidden", "tab_idx"), &TabContainer::get_tab_hidden);
+ ClassDB::bind_method(D_METHOD("is_tab_hidden", "tab_idx"), &TabContainer::is_tab_hidden);
ClassDB::bind_method(D_METHOD("get_tab_idx_at_point", "point"), &TabContainer::get_tab_idx_at_point);
+ ClassDB::bind_method(D_METHOD("get_tab_idx_from_control", "control"), &TabContainer::get_tab_idx_from_control);
ClassDB::bind_method(D_METHOD("set_popup", "popup"), &TabContainer::set_popup);
ClassDB::bind_method(D_METHOD("get_popup"), &TabContainer::get_popup);
ClassDB::bind_method(D_METHOD("set_drag_to_rearrange_enabled", "enabled"), &TabContainer::set_drag_to_rearrange_enabled);
ClassDB::bind_method(D_METHOD("get_drag_to_rearrange_enabled"), &TabContainer::get_drag_to_rearrange_enabled);
ClassDB::bind_method(D_METHOD("set_tabs_rearrange_group", "group_id"), &TabContainer::set_tabs_rearrange_group);
ClassDB::bind_method(D_METHOD("get_tabs_rearrange_group"), &TabContainer::get_tabs_rearrange_group);
-
ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size);
ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size);
ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
- ClassDB::bind_method(D_METHOD("_update_current_tab"), &TabContainer::_update_current_tab);
+ ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw);
+ ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw);
+ ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab")));
@@ -1228,16 +834,20 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_alignment", "get_tab_alignment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "tabs_visible"), "set_tabs_visible", "are_tabs_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "all_tabs_in_front"), "set_all_tabs_in_front", "is_all_tabs_in_front");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");
-
- BIND_ENUM_CONSTANT(ALIGNMENT_LEFT);
- BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
- BIND_ENUM_CONSTANT(ALIGNMENT_RIGHT);
}
TabContainer::TabContainer() {
+ tab_bar = memnew(TabBar);
+ tab_bar->set_drag_forwarding(this);
+ add_child(tab_bar, false, INTERNAL_MODE_FRONT);
+ tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
+ tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));
+ tab_bar->connect("tab_selected", callable_mp(this, &TabContainer::_on_tab_selected));
+
connect("mouse_exited", callable_mp(this, &TabContainer::_on_mouse_exited));
}
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index ee1b3fea51..1322f08206 100644
--- a/scene/gui/tab_container.h
+++ b/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