summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/gui/tab_bar.cpp100
-rw-r--r--scene/gui/tab_bar.h1
-rw-r--r--scene/gui/tab_container.cpp49
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/default_theme/tabs_drop_mark.svg1
5 files changed, 135 insertions, 20 deletions
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index af314b9545..90689ee1af 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -35,6 +35,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
+#include "scene/main/viewport.h"
Size2 TabBar::get_minimum_size() const {
Size2 ms;
@@ -158,7 +159,13 @@ void TabBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
+ if (get_viewport()->gui_is_dragging() && can_drop_data(pos, get_viewport()->gui_get_drag_data())) {
+ dragging_valid_tab = true;
+ update();
+ }
+
_update_hover();
+
return;
}
@@ -333,6 +340,13 @@ void TabBar::_notification(int p_what) {
}
} break;
+ case NOTIFICATION_DRAG_END: {
+ if (dragging_valid_tab) {
+ dragging_valid_tab = false;
+ update();
+ }
+ } break;
+
case NOTIFICATION_DRAW: {
if (tabs.is_empty()) {
return;
@@ -346,8 +360,6 @@ void TabBar::_notification(int p_what) {
Color font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
Ref<Texture2D> incr = get_theme_icon(SNAME("increment"));
Ref<Texture2D> decr = get_theme_icon(SNAME("decrement"));
- Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
- Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
bool rtl = is_layout_rtl();
Vector2 size = get_size();
@@ -391,7 +403,10 @@ void TabBar::_notification(int p_what) {
}
if (buttons_visible) {
- int vofs = (get_size().height - incr->get_size().height) / 2;
+ Ref<Texture2D> incr_hl = get_theme_icon(SNAME("increment_highlight"));
+ Ref<Texture2D> decr_hl = get_theme_icon(SNAME("decrement_highlight"));
+
+ int vofs = (size.height - incr->get_size().height) / 2;
if (rtl) {
if (missing_right) {
@@ -419,6 +434,39 @@ void TabBar::_notification(int p_what) {
}
}
}
+
+ if (dragging_valid_tab) {
+ int x;
+
+ int tab_hover = get_hovered_tab();
+ if (tab_hover != -1) {
+ Rect2 tab_rect = get_tab_rect(tab_hover);
+
+ x = tab_rect.position.x;
+ if (get_local_mouse_position().x > x + tab_rect.size.width / 2) {
+ x += tab_rect.size.width;
+ }
+ } else {
+ if (rtl ^ (get_local_mouse_position().x < get_tab_rect(0).position.x)) {
+ x = get_tab_rect(0).position.x;
+ if (rtl) {
+ x += get_tab_rect(0).size.width;
+ }
+ } else {
+ Rect2 tab_rect = get_tab_rect(get_tab_count() - 1);
+
+ x = tab_rect.position.x;
+ if (!rtl) {
+ x += tab_rect.size.width;
+ }
+ }
+ }
+
+ Ref<Texture2D> drop_mark = get_theme_icon(SNAME("drop_mark"));
+ Color drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
+
+ drop_mark->draw(get_canvas_item(), Point2(x - drop_mark->get_width() / 2, (size.height - drop_mark->get_height()) / 2), drop_mark_color);
+ }
} break;
}
}
@@ -906,6 +954,8 @@ void TabBar::_on_mouse_exited() {
cb_hover = -1;
hover = -1;
highlight_arrow = -1;
+ dragging_valid_tab = false;
+
update();
}
@@ -1057,13 +1107,29 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
NodePath to_path = get_path();
if (from_path == to_path) {
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
+ if (tab_from_id == hover_now) {
+ return;
+ }
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x <= tab_rect.position.x + tab_rect.size.width / 2)) {
+ if (hover_now > tab_from_id) {
+ hover_now -= 1;
+ }
+ } else if (tab_from_id > hover_now) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1;
}
move_tab(tab_from_id, hover_now);
- emit_signal(SNAME("active_tab_rearranged"), hover_now);
- set_current_tab(hover_now);
+ if (!is_tab_disabled(hover_now)) {
+ emit_signal(SNAME("active_tab_rearranged"), hover_now);
+ set_current_tab(hover_now);
+ }
} else if (get_tabs_rearrange_group() != -1) {
// Drag and drop between Tabs.
@@ -1075,11 +1141,17 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
return;
}
- Tab moving_tab = from_tabs->tabs[tab_from_id];
- if (hover_now < 0) {
- hover_now = get_tab_count();
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x > tab_rect.position.x + tab_rect.size.width / 2)) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < get_tab_rect(0).position.x) ? 0 : get_tab_count();
}
+ Tab moving_tab = from_tabs->tabs[tab_from_id];
from_tabs->remove_tab(tab_from_id);
tabs.insert(hover_now, moving_tab);
@@ -1092,7 +1164,13 @@ void TabBar::drop_data(const Point2 &p_point, const Variant &p_data) {
}
}
- set_current_tab(hover_now);
+ if (!is_tab_disabled(hover_now)) {
+ set_current_tab(hover_now);
+ } else {
+ _update_cache();
+ update();
+ }
+
update_minimum_size();
if (tabs.size() == 1) {
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index e0c4ba85ef..548a2e62af 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -101,6 +101,7 @@ private:
int max_width = 0;
bool scrolling_enabled = true;
bool drag_to_rearrange_enabled = false;
+ bool dragging_valid_tab = false;
bool scroll_to_selected = true;
int tabs_rearrange_group = -1;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index ee61c862b7..1697e743be 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -173,9 +173,9 @@ void TabContainer::_notification(int p_what) {
int x = is_layout_rtl() ? 0 : get_size().width - menu->get_width();
if (menu_hovered) {
- menu_hl->draw(get_canvas_item(), Size2(x, (header_height - menu_hl->get_height()) / 2));
+ menu_hl->draw(get_canvas_item(), Point2(x, (header_height - menu_hl->get_height()) / 2));
} else {
- menu->draw(get_canvas_item(), Size2(x, (header_height - menu->get_height()) / 2));
+ menu->draw(get_canvas_item(), Point2(x, (header_height - menu->get_height()) / 2));
}
}
} break;
@@ -201,6 +201,8 @@ void TabContainer::_on_theme_changed() {
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_icon_override(SNAME("drop_mark"), get_theme_icon(SNAME("drop_mark")));
+ tab_bar->add_theme_color_override(SNAME("drop_mark_color"), get_theme_color(SNAME("drop_mark_color")));
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")));
@@ -384,8 +386,6 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
return;
}
- int hover_now = get_tab_idx_at_point(p_point);
-
Dictionary d = p_data;
if (!d.has("type")) {
return;
@@ -393,11 +393,27 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
if (String(d["type"]) == "tabc_element") {
int tab_from_id = d["tabc_element"];
+ int hover_now = get_tab_idx_at_point(p_point);
NodePath from_path = d["from_path"];
NodePath to_path = get_path();
+
if (from_path == to_path) {
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
+ if (tab_from_id == hover_now) {
+ return;
+ }
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = tab_bar->get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x <= tab_rect.position.x + tab_rect.size.width / 2)) {
+ if (hover_now > tab_from_id) {
+ hover_now -= 1;
+ }
+ } else if (tab_from_id > hover_now) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count() - 1;
}
move_child(get_tab_control(tab_from_id), get_tab_control(hover_now)->get_index(false));
@@ -407,16 +423,31 @@ void TabContainer::_drop_data_fw(const Point2 &p_point, const Variant &p_data, C
} else if (get_tabs_rearrange_group() != -1) {
// 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()) {
+ // Get the tab properties before they get erased by the child removal.
+ String tab_title = from_tabc->get_tab_title(tab_from_id);
+ bool tab_disabled = from_tabc->is_tab_disabled(tab_from_id);
+
+ // Drop the new tab to the left or right depending on where the target tab is being hovered.
+ if (hover_now != -1) {
+ Rect2 tab_rect = tab_bar->get_tab_rect(hover_now);
+ if (is_layout_rtl() ^ (p_point.x > tab_rect.position.x + tab_rect.size.width / 2)) {
+ hover_now += 1;
+ }
+ } else {
+ hover_now = is_layout_rtl() ^ (p_point.x < tab_bar->get_tab_rect(0).position.x) ? 0 : get_tab_count();
+ }
+
Control *moving_tabc = from_tabc->get_tab_control(tab_from_id);
from_tabc->remove_child(moving_tabc);
add_child(moving_tabc, true);
- if (hover_now < 0) {
- hover_now = get_tab_count() - 1;
- }
+ set_tab_title(get_tab_count() - 1, tab_title);
+ set_tab_disabled(get_tab_count() - 1, tab_disabled);
move_child(moving_tabc, get_tab_control(hover_now)->get_index(false));
if (!is_tab_disabled(hover_now)) {
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index da37228ed9..eb71401a3a 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -801,6 +801,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("increment_highlight", "TabContainer", icons["scroll_button_right_hl"]);
theme->set_icon("decrement", "TabContainer", icons["scroll_button_left"]);
theme->set_icon("decrement_highlight", "TabContainer", icons["scroll_button_left_hl"]);
+ theme->set_icon("drop_mark", "TabContainer", icons["tabs_drop_mark"]);
theme->set_icon("menu", "TabContainer", icons["tabs_menu"]);
theme->set_icon("menu_highlight", "TabContainer", icons["tabs_menu_hl"]);
@@ -811,6 +812,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_unselected_color", "TabContainer", control_font_low_color);
theme->set_color("font_disabled_color", "TabContainer", control_font_disabled_color);
theme->set_color("font_outline_color", "TabContainer", Color(1, 1, 1));
+ theme->set_color("drop_mark_color", "TabContainer", Color(1, 1, 1));
theme->set_constant("side_margin", "TabContainer", 8 * scale);
theme->set_constant("icon_separation", "TabContainer", 4 * scale);
@@ -828,6 +830,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("increment_highlight", "TabBar", icons["scroll_button_right_hl"]);
theme->set_icon("decrement", "TabBar", icons["scroll_button_left"]);
theme->set_icon("decrement_highlight", "TabBar", icons["scroll_button_left_hl"]);
+ theme->set_icon("drop_mark", "TabBar", icons["tabs_drop_mark"]);
theme->set_icon("close", "TabBar", icons["close"]);
theme->set_font("font", "TabBar", Ref<Font>());
@@ -837,6 +840,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("font_unselected_color", "TabBar", control_font_low_color);
theme->set_color("font_disabled_color", "TabBar", control_font_disabled_color);
theme->set_color("font_outline_color", "TabBar", Color(1, 1, 1));
+ theme->set_color("drop_mark_color", "TabBar", Color(1, 1, 1));
theme->set_constant("hseparation", "TabBar", 4 * scale);
theme->set_constant("outline_size", "TabBar", 0);
diff --git a/scene/resources/default_theme/tabs_drop_mark.svg b/scene/resources/default_theme/tabs_drop_mark.svg
new file mode 100644
index 0000000000..b1415bec45
--- /dev/null
+++ b/scene/resources/default_theme/tabs_drop_mark.svg
@@ -0,0 +1 @@
+<svg height="32" viewBox="0 0 16 32" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1h6v30h-6z" fill="#d3d3d3"/></svg>