@@ -98,6 +98,10 @@ Size2 TabBar::get_minimum_size() const {
98
98
if (ms.width - ofs > style->get_minimum_size ().width ) {
99
99
ms.width -= theme_cache.h_separation ;
100
100
}
101
+
102
+ if (i < tabs.size () - 1 ) {
103
+ ms.width += theme_cache.tab_separation ;
104
+ }
101
105
}
102
106
103
107
if (clip_tabs) {
@@ -430,9 +434,12 @@ void TabBar::_notification(int p_what) {
430
434
int limit_minus_buttons = size.width - theme_cache.increment_icon ->get_width () - theme_cache.decrement_icon ->get_width ();
431
435
432
436
int ofs = tabs[offset].ofs_cache ;
437
+ int tab_separation_offset = 0 ;
433
438
434
439
// Draw unselected tabs in the back.
435
440
for (int i = offset; i <= max_drawn_tab; i++) {
441
+ tab_separation_offset = (i - offset) * theme_cache.tab_separation ;
442
+
436
443
if (tabs[i].hidden ) {
437
444
continue ;
438
445
}
@@ -452,16 +459,21 @@ void TabBar::_notification(int p_what) {
452
459
col = theme_cache.font_unselected_color ;
453
460
}
454
461
455
- _draw_tab (sb, col, i, rtl ? size.width - ofs - tabs[i].size_cache : ofs, false );
462
+ _draw_tab (sb, col, i, rtl ? ( size.width - ofs - tab_separation_offset - tabs[i].size_cache ) : ( ofs + tab_separation_offset) , false );
456
463
}
457
464
458
465
ofs += tabs[i].size_cache ;
459
466
}
460
467
461
468
// Draw selected tab in the front, but only if it's visible.
462
469
if (current >= offset && current <= max_drawn_tab && !tabs[current].hidden ) {
470
+ tab_separation_offset = (current - offset) * theme_cache.tab_separation ;
471
+ if (tab_alignment == ALIGNMENT_LEFT && (current - offset) > 1 ) {
472
+ tab_separation_offset = theme_cache.tab_separation ;
473
+ }
474
+
463
475
Ref<StyleBox> sb = tabs[current].disabled ? theme_cache.tab_disabled_style : theme_cache.tab_selected_style ;
464
- float x = rtl ? size.width - tabs[current].ofs_cache - tabs[current].size_cache : tabs[current].ofs_cache ;
476
+ float x = rtl ? ( size.width - tabs[current].ofs_cache - tab_separation_offset - tabs[current].size_cache ) : ( tabs[current].ofs_cache + tab_separation_offset) ;
465
477
466
478
_draw_tab (sb, theme_cache.font_selected_color , current, x, has_focus ());
467
479
}
@@ -499,13 +511,41 @@ void TabBar::_notification(int p_what) {
499
511
if (dragging_valid_tab) {
500
512
int x;
501
513
502
- int tab_hover = get_hovered_tab ();
503
- if (tab_hover != -1 ) {
504
- Rect2 tab_rect = get_tab_rect (tab_hover);
505
-
506
- x = tab_rect.position .x ;
507
- if (get_local_mouse_position ().x > x + tab_rect.size .width / 2 ) {
508
- x += tab_rect.size .width ;
514
+ int closest_tab = get_closest_tab_idx_to_point (get_local_mouse_position ());
515
+ if (closest_tab != -1 ) {
516
+ Rect2 tab_rect = get_tab_rect (closest_tab);
517
+
518
+ // Calculate midpoint between tabs.
519
+ if (rtl) {
520
+ if (get_local_mouse_position ().x > tab_rect.position .x + tab_rect.size .width / 2 ) {
521
+ if (closest_tab > 0 ) { // On right side of closest_tab and not first tab.
522
+ Rect2 next_tab_rect = get_tab_rect (closest_tab - 1 );
523
+ x = (tab_rect.position .x + tab_rect.size .width + next_tab_rect.position .x ) / 2 ;
524
+ } else { // First tab, will appear on right edge.
525
+ x = tab_rect.position .x + tab_rect.size .width ;
526
+ }
527
+ } else {
528
+ if (closest_tab < max_drawn_tab) { // On left side of closest_tab and not last tab.
529
+ Rect2 prev_tab_rect = get_tab_rect (closest_tab + 1 );
530
+ x = (tab_rect.position .x + prev_tab_rect.position .x + prev_tab_rect.size .width ) / 2 ;
531
+ } else { // Last tab, will appear on left edge.
532
+ x = tab_rect.position .x ;
533
+ }
534
+ }
535
+ } else if (get_local_mouse_position ().x > tab_rect.position .x + tab_rect.size .width / 2 ) {
536
+ if (closest_tab < max_drawn_tab) { // On right side of closest_tab and not last tab.
537
+ Rect2 next_tab_rect = get_tab_rect (closest_tab + 1 );
538
+ x = (tab_rect.position .x + tab_rect.size .width + next_tab_rect.position .x ) / 2 ;
539
+ } else { // Last tab, will appear on right edge.
540
+ x = tab_rect.position .x + tab_rect.size .width ;
541
+ }
542
+ } else {
543
+ if (closest_tab > 0 ) { // On left side of closest_tab and not first tab.
544
+ Rect2 prev_tab_rect = get_tab_rect (closest_tab - 1 );
545
+ x = (tab_rect.position .x + prev_tab_rect.position .x + prev_tab_rect.size .width ) / 2 ;
546
+ } else { // First tab, will appear on left edge.
547
+ x = tab_rect.position .x ;
548
+ }
509
549
}
510
550
} else {
511
551
if (rtl ^ (get_local_mouse_position ().x < get_tab_rect (0 ).position .x )) {
@@ -1053,19 +1093,25 @@ void TabBar::_update_cache(bool p_update_hover) {
1053
1093
}
1054
1094
1055
1095
w += tabs[i].size_cache ;
1096
+ if ((i - offset) > 0 ) {
1097
+ w += theme_cache.tab_separation ;
1098
+ }
1056
1099
1057
1100
// Check if all tabs would fit inside the area.
1058
1101
if (clip_tabs && i > offset && (w > limit || (offset > 0 && w > limit_minus_buttons))) {
1059
1102
tabs.write [i].ofs_cache = 0 ;
1060
1103
1061
1104
w -= tabs[i].size_cache ;
1105
+ w -= theme_cache.tab_separation ;
1106
+
1062
1107
max_drawn_tab = i - 1 ;
1063
1108
1064
1109
while (w > limit_minus_buttons && max_drawn_tab > offset) {
1065
1110
tabs.write [max_drawn_tab].ofs_cache = 0 ;
1066
1111
1067
1112
if (!tabs[max_drawn_tab].hidden ) {
1068
1113
w -= tabs[max_drawn_tab].size_cache ;
1114
+ w -= theme_cache.tab_separation ;
1069
1115
}
1070
1116
1071
1117
max_drawn_tab--;
@@ -1303,7 +1349,7 @@ void TabBar::_handle_drop_data(const String &p_type, const Point2 &p_point, cons
1303
1349
1304
1350
if (String (d[" type" ]) == p_type) {
1305
1351
int tab_from_id = d[" tab_index" ];
1306
- int hover_now = get_tab_idx_at_point (p_point);
1352
+ int hover_now = get_closest_tab_idx_to_point (p_point);
1307
1353
NodePath from_path = d[" from_path" ];
1308
1354
NodePath to_path = get_path ();
1309
1355
@@ -1398,6 +1444,24 @@ int TabBar::get_tab_idx_at_point(const Point2 &p_point) const {
1398
1444
return hover_now;
1399
1445
}
1400
1446
1447
+ int TabBar::get_closest_tab_idx_to_point (const Point2 &p_point) const {
1448
+ int closest_tab = get_tab_idx_at_point (p_point); // See if we're hovering over a tab first.
1449
+
1450
+ if (closest_tab == -1 ) { // Didn't find a tab, so get the closest one.
1451
+ float closest_distance = FLT_MAX;
1452
+ for (int i = offset; i <= max_drawn_tab; i++) {
1453
+ Vector2 center = get_tab_rect (i).get_center ();
1454
+ float distance = center.distance_to (p_point);
1455
+ if (distance < closest_distance) {
1456
+ closest_distance = distance;
1457
+ closest_tab = i;
1458
+ }
1459
+ }
1460
+ }
1461
+
1462
+ return closest_tab;
1463
+ }
1464
+
1401
1465
void TabBar::set_tab_alignment (AlignmentMode p_alignment) {
1402
1466
ERR_FAIL_INDEX (p_alignment, ALIGNMENT_MAX);
1403
1467
@@ -1647,10 +1711,14 @@ void TabBar::ensure_tab_visible(int p_idx) {
1647
1711
1648
1712
Rect2 TabBar::get_tab_rect (int p_tab) const {
1649
1713
ERR_FAIL_INDEX_V (p_tab, tabs.size (), Rect2 ());
1714
+ int tab_separation_offset = (p_tab - offset) * theme_cache.tab_separation ;
1715
+ if (tab_alignment == ALIGNMENT_LEFT && (p_tab - offset) > 1 ) {
1716
+ tab_separation_offset = theme_cache.tab_separation ;
1717
+ }
1650
1718
if (is_layout_rtl ()) {
1651
- return Rect2 (get_size ().width - tabs[p_tab].ofs_cache - tabs[p_tab].size_cache , 0 , tabs[p_tab].size_cache , get_size ().height );
1719
+ return Rect2 (get_size ().width - tabs[p_tab].ofs_cache - tab_separation_offset - tabs[p_tab].size_cache , 0 , tabs[p_tab].size_cache , get_size ().height );
1652
1720
} else {
1653
- return Rect2 (tabs[p_tab].ofs_cache , 0 , tabs[p_tab].size_cache , get_size ().height );
1721
+ return Rect2 (tabs[p_tab].ofs_cache + tab_separation_offset , 0 , tabs[p_tab].size_cache , get_size ().height );
1654
1722
}
1655
1723
}
1656
1724
@@ -1847,6 +1915,7 @@ void TabBar::_bind_methods() {
1847
1915
BIND_ENUM_CONSTANT (CLOSE_BUTTON_MAX);
1848
1916
1849
1917
BIND_THEME_ITEM (Theme::DATA_TYPE_CONSTANT, TabBar, h_separation);
1918
+ BIND_THEME_ITEM (Theme::DATA_TYPE_CONSTANT, TabBar, tab_separation);
1850
1919
BIND_THEME_ITEM (Theme::DATA_TYPE_CONSTANT, TabBar, icon_max_width);
1851
1920
1852
1921
BIND_THEME_ITEM_CUSTOM (Theme::DATA_TYPE_STYLEBOX, TabBar, tab_unselected_style, " tab_unselected" );
0 commit comments