Fix TabContainer respecting tabbar_background margins

This commit is contained in:
Logan Detrick
2025-05-16 21:58:26 -07:00
parent eb72ce2db4
commit 944295ab04
2 changed files with 70 additions and 63 deletions

View File

@ -32,10 +32,20 @@
#include "scene/theme/theme_db.h" #include "scene/theme/theme_db.h"
Rect2 TabContainer::_get_tab_rect() const {
Rect2 rect;
if (tabs_visible && get_tab_count() > 0) {
rect = Rect2(theme_cache.tabbar_style->get_offset(), tab_bar->get_size());
rect.position.x += is_layout_rtl() ? theme_cache.menu_icon->get_width() : theme_cache.side_margin;
}
return rect;
}
int TabContainer::_get_tab_height() const { int TabContainer::_get_tab_height() const {
int height = 0; int height = 0;
if (tabs_visible && get_tab_count() > 0) { if (tabs_visible && get_tab_count() > 0) {
height = tab_bar->get_minimum_size().height; height = tab_bar->get_minimum_size().height + theme_cache.tabbar_style->get_margin(SIDE_TOP) + theme_cache.tabbar_style->get_margin(SIDE_BOTTOM);
} }
return height; return height;
@ -50,29 +60,27 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position(); Point2 pos = mb->get_position();
Size2 size = get_size(); real_t content_height = get_size().height - _get_tab_height();
real_t content_height = size.height - _get_tab_height();
Rect2 popup_rect = _get_tab_rect();
popup_rect.position.x += is_layout_rtl() ? -theme_cache.menu_icon->get_width() : popup_rect.size.x;
popup_rect.position.y += tabs_position == POSITION_BOTTOM ? content_height : 0;
popup_rect.size.x = theme_cache.menu_icon->get_width();
// Click must be on tabs in the tab header area. // Click must be on tabs in the tab header area.
if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) { if (!tabs_visible || pos.y < popup_rect.position.y || pos.y >= popup_rect.position.y + popup_rect.size.y) {
return;
}
if (tabs_position == POSITION_BOTTOM && pos.y < content_height) {
return; return;
} }
// Handle menu button. // Handle menu button.
if (popup) { if (popup) {
if (is_layout_rtl() ? pos.x < theme_cache.menu_icon->get_width() : pos.x > size.width - theme_cache.menu_icon->get_width()) { if (popup_rect.has_point(pos)) {
emit_signal(SNAME("pre_popup_pressed")); emit_signal(SNAME("pre_popup_pressed"));
Vector2 popup_pos = get_screen_position(); Vector2 popup_pos = get_screen_position();
if (!is_layout_rtl()) { popup_pos.x += popup_rect.position.x + (is_layout_rtl() ? 0 : popup_rect.size.x - popup->get_size().width);
popup_pos.x += size.width - popup->get_size().width; popup_pos.y += popup_rect.position.y + popup_rect.size.y / 2.0;
}
popup_pos.y += _get_tab_height() / 2.0;
if (tabs_position == POSITION_BOTTOM) { if (tabs_position == POSITION_BOTTOM) {
popup_pos.y += content_height;
popup_pos.y -= popup->get_size().height; popup_pos.y -= popup->get_size().height;
popup_pos.y -= theme_cache.menu_icon->get_height() / 2.0; popup_pos.y -= theme_cache.menu_icon->get_height() / 2.0;
} else { } else {
@ -90,17 +98,15 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
if (mm.is_valid()) { if (mm.is_valid()) {
Point2 pos = mm->get_position(); Point2 pos = mm->get_position();
Size2 size = get_size(); real_t content_height = get_size().height - _get_tab_height();
Rect2 popup_rect = _get_tab_rect();
popup_rect.position.x += is_layout_rtl() ? -theme_cache.menu_icon->get_width() : popup_rect.size.x;
popup_rect.position.y += tabs_position == POSITION_BOTTOM ? content_height : 0;
popup_rect.size.x = theme_cache.menu_icon->get_width();
// Mouse must be on tabs in the tab header area. // Mouse must be on tabs in the tab header area.
if (tabs_position == POSITION_TOP && pos.y > _get_tab_height()) { if (!tabs_visible || pos.y < popup_rect.position.y || pos.y >= popup_rect.position.y + popup_rect.size.y) {
if (menu_hovered) {
menu_hovered = false;
queue_redraw();
}
return;
}
if (tabs_position == POSITION_BOTTOM && pos.y < size.height - _get_tab_height()) {
if (menu_hovered) { if (menu_hovered) {
menu_hovered = false; menu_hovered = false;
queue_redraw(); queue_redraw();
@ -109,8 +115,7 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
} }
if (popup) { if (popup) {
if (is_layout_rtl()) { if (popup_rect.has_point(pos)) {
if (pos.x <= theme_cache.menu_icon->get_width()) {
if (!menu_hovered) { if (!menu_hovered) {
menu_hovered = true; menu_hovered = true;
queue_redraw(); queue_redraw();
@ -120,18 +125,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
menu_hovered = false; menu_hovered = false;
queue_redraw(); queue_redraw();
} }
} else {
if (pos.x >= size.width - theme_cache.menu_icon->get_width()) {
if (!menu_hovered) {
menu_hovered = true;
queue_redraw();
return;
}
} else if (menu_hovered) {
menu_hovered = false;
queue_redraw();
}
}
if (menu_hovered) { if (menu_hovered) {
return; return;
@ -201,6 +194,7 @@ void TabContainer::_notification(int p_what) {
case NOTIFICATION_DRAW: { case NOTIFICATION_DRAW: {
RID canvas = get_canvas_item(); RID canvas = get_canvas_item();
Size2 size = get_size(); Size2 size = get_size();
Rect2 tabbar_rect = _get_tab_rect();
// Draw only the tab area if the header is hidden. // Draw only the tab area if the header is hidden.
if (!tabs_visible) { if (!tabs_visible) {
@ -218,12 +212,13 @@ void TabContainer::_notification(int p_what) {
// Draw the popup menu. // Draw the popup menu.
if (get_popup()) { if (get_popup()) {
int x = is_layout_rtl() ? 0 : get_size().width - theme_cache.menu_icon->get_width(); int x = is_layout_rtl() ? tabbar_rect.position.x - theme_cache.menu_icon->get_width() : tabbar_rect.position.x + tabbar_rect.size.x;
header_voffset += tabbar_rect.position.y;
if (menu_hovered) { if (menu_hovered) {
theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_hl_icon->get_height()) / 2)); theme_cache.menu_hl_icon->draw(get_canvas_item(), Point2(x, header_voffset + (tabbar_rect.size.y - theme_cache.menu_hl_icon->get_height()) / 2));
} else { } else {
theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, header_voffset + (header_height - theme_cache.menu_icon->get_height()) / 2)); theme_cache.menu_icon->draw(get_canvas_item(), Point2(x, header_voffset + (tabbar_rect.size.y - theme_cache.menu_icon->get_height()) / 2));
} }
} }
} break; } break;
@ -307,14 +302,17 @@ void TabContainer::_repaint() {
Vector<Control *> controls = _get_tab_controls(); Vector<Control *> controls = _get_tab_controls();
int current = get_current_tab(); int current = get_current_tab();
float top_margin = theme_cache.tabbar_style->get_margin(SIDE_TOP);
float bottom_margin = theme_cache.tabbar_style->get_margin(SIDE_BOTTOM);
// Move the TabBar to the top or bottom. // Move the TabBar to the top or bottom.
// Don't change the left and right offsets since the TabBar will resize and may change tab offset. // Don't change the left and right offsets since the TabBar will resize and may change tab offset.
if (tabs_position == POSITION_BOTTOM) { if (tabs_position == POSITION_BOTTOM) {
tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 1.0, 0.0); tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 1.0, -bottom_margin);
tab_bar->set_anchor_and_offset(SIDE_TOP, 1.0, -_get_tab_height()); tab_bar->set_anchor_and_offset(SIDE_TOP, 1.0, top_margin - _get_tab_height());
} else { } else {
tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 0.0, _get_tab_height()); tab_bar->set_anchor_and_offset(SIDE_TOP, 0.0, top_margin);
tab_bar->set_anchor_and_offset(SIDE_TOP, 0.0, 0.0); tab_bar->set_anchor_and_offset(SIDE_BOTTOM, 0.0, _get_tab_height() - bottom_margin);
} }
updating_visibility = true; updating_visibility = true;
@ -349,46 +347,52 @@ void TabContainer::_repaint() {
void TabContainer::_update_margins() { void TabContainer::_update_margins() {
// Directly check for validity, to avoid errors when quitting. // Directly check for validity, to avoid errors when quitting.
bool has_popup = popup_obj_id.is_valid(); bool has_popup = popup_obj_id.is_valid();
int menu_width = 0;
int left_margin = theme_cache.tabbar_style->get_margin(SIDE_LEFT);
int right_margin = theme_cache.tabbar_style->get_margin(SIDE_RIGHT);
if (is_layout_rtl()) {
SWAP(left_margin, right_margin);
}
if (has_popup) { if (has_popup) {
menu_width = theme_cache.menu_icon->get_width(); right_margin += theme_cache.menu_icon->get_width();
} }
if (get_tab_count() == 0) { if (get_tab_count() == 0) {
tab_bar->set_offset(SIDE_LEFT, 0); tab_bar->set_offset(SIDE_LEFT, left_margin);
tab_bar->set_offset(SIDE_RIGHT, -menu_width); tab_bar->set_offset(SIDE_RIGHT, -right_margin);
return; return;
} }
switch (get_tab_alignment()) { switch (get_tab_alignment()) {
case TabBar::ALIGNMENT_LEFT: { case TabBar::ALIGNMENT_LEFT: {
tab_bar->set_offset(SIDE_LEFT, theme_cache.side_margin); tab_bar->set_offset(SIDE_LEFT, left_margin + theme_cache.side_margin);
tab_bar->set_offset(SIDE_RIGHT, -menu_width); tab_bar->set_offset(SIDE_RIGHT, -right_margin);
} break; } break;
case TabBar::ALIGNMENT_CENTER: { case TabBar::ALIGNMENT_CENTER: {
tab_bar->set_offset(SIDE_LEFT, 0); tab_bar->set_offset(SIDE_LEFT, left_margin);
tab_bar->set_offset(SIDE_RIGHT, -menu_width); tab_bar->set_offset(SIDE_RIGHT, -right_margin);
} break; } break;
case TabBar::ALIGNMENT_RIGHT: { case TabBar::ALIGNMENT_RIGHT: {
tab_bar->set_offset(SIDE_LEFT, 0); tab_bar->set_offset(SIDE_LEFT, left_margin);
if (has_popup) { if (has_popup) {
tab_bar->set_offset(SIDE_RIGHT, -menu_width); tab_bar->set_offset(SIDE_RIGHT, -right_margin);
return; return;
} }
int first_tab_pos = tab_bar->get_tab_rect(0).position.x; 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); 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; int total_tabs_width = left_margin + right_margin + last_tab_rect.position.x - first_tab_pos + last_tab_rect.size.width;
// Calculate if all the tabs would still fit if the margin was present. // 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 + theme_cache.side_margin) > get_size().width))) { if (get_clip_tabs() && (tab_bar->get_offset_buttons_visible() || (get_tab_count() > 1 && (total_tabs_width + theme_cache.side_margin) > get_size().width))) {
tab_bar->set_offset(SIDE_RIGHT, -menu_width); tab_bar->set_offset(SIDE_RIGHT, -right_margin);
} else { } else {
tab_bar->set_offset(SIDE_RIGHT, -theme_cache.side_margin); tab_bar->set_offset(SIDE_RIGHT, -right_margin - theme_cache.side_margin);
} }
} break; } break;
@ -944,6 +948,8 @@ Size2 TabContainer::get_minimum_size() const {
if (tabs_visible) { if (tabs_visible) {
ms = tab_bar->get_minimum_size(); ms = tab_bar->get_minimum_size();
ms.x += theme_cache.tabbar_style->get_margin(SIDE_LEFT) + theme_cache.tabbar_style->get_margin(SIDE_RIGHT);
ms.y += theme_cache.tabbar_style->get_margin(SIDE_TOP) + theme_cache.tabbar_style->get_margin(SIDE_BOTTOM);
if (!get_clip_tabs()) { if (!get_clip_tabs()) {
if (get_popup()) { if (get_popup()) {

View File

@ -99,6 +99,7 @@ private:
HashMap<Node *, RID> tab_panels; HashMap<Node *, RID> tab_panels;
Rect2 _get_tab_rect() const;
int _get_tab_height() const; int _get_tab_height() const;
Vector<Control *> _get_tab_controls() const; Vector<Control *> _get_tab_controls() const;
void _on_theme_changed(); void _on_theme_changed();