diff --git a/Userland/Libraries/LibGUI/TabWidget.cpp b/Userland/Libraries/LibGUI/TabWidget.cpp index 4c791929c5..db76058f59 100644 --- a/Userland/Libraries/LibGUI/TabWidget.cpp +++ b/Userland/Libraries/LibGUI/TabWidget.cpp @@ -213,6 +213,11 @@ void TabWidget::paint_event(PaintEvent& event) painter.draw_scaled_bitmap(icon_rect, *icon, icon->rect()); text_rect.set_x(icon_rect.right() + 1 + 4); text_rect.intersect(button_rect); + + // We want to be in perfect alignment with the icon rect at all times. + auto icon_rect_difference = icon_rect.top() - text_rect.top(); + text_rect.set_top(text_rect.top() + icon_rect_difference); + text_rect.set_height(text_rect.height() - icon_rect_difference); }; for (size_t i = 0; i < m_tabs.size(); ++i) { @@ -221,17 +226,21 @@ void TabWidget::paint_event(PaintEvent& event) bool hovered = i == m_hovered_tab_index; auto button_rect = this->button_rect(i); Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), false, hovered, m_tabs[i].widget->is_enabled(), m_tab_position == TabPosition::Top, window()->is_active()); - auto tab_button_content_rect = button_rect.translated(4, m_tab_position == TabPosition::Top ? 1 : 0); + + // First we get rid of the 1px sheen on the left, then the 2px shadow + // on the right. Finally we shrink 3px from each side. + auto tab_button_content_rect = button_rect.shrunken(2, 0); + tab_button_content_rect.set_width(tab_button_content_rect.width() - 1); + tab_button_content_rect.shrink(6, 0); + if (m_tab_position == TabPosition::Top) { + tab_button_content_rect.set_top(tab_button_content_rect.top() + 1); + tab_button_content_rect.set_height(tab_button_content_rect.height() - 1); + } paint_tab_icon_if_needed(m_tabs[i].icon, button_rect, tab_button_content_rect); - tab_button_content_rect.set_width(tab_button_content_rect.width() - (m_close_button_enabled ? 16 : 2)); + tab_button_content_rect.set_width(tab_button_content_rect.width() - (m_close_button_enabled ? 16 : 0)); - Gfx::IntRect text_rect { 0, 0, min(tab_button_content_rect.width(), font().width(m_tabs[i].title)), font().glyph_height() }; - text_rect.inflate(6, 4); - text_rect.align_within(tab_button_content_rect, m_text_alignment); - text_rect.intersect(tab_button_content_rect); - - painter.draw_text(text_rect, m_tabs[i].title, Gfx::TextAlignment::CenterLeft, palette().button_text(), Gfx::TextElision::Right); + painter.draw_text(tab_button_content_rect, m_tabs[i].title, m_text_alignment, palette().button_text(), Gfx::TextElision::Right); } for (size_t i = 0; i < m_tabs.size(); ++i) { @@ -240,19 +249,28 @@ void TabWidget::paint_event(PaintEvent& event) bool hovered = i == m_hovered_tab_index; auto button_rect = this->button_rect(i); Gfx::StylePainter::paint_tab_button(painter, button_rect, palette(), true, hovered, m_tabs[i].widget->is_enabled(), m_tab_position == TabPosition::Top, window()->is_active()); - auto tab_button_content_rect = button_rect.translated(4, m_tab_position == TabPosition::Top ? 1 : 0); + + // First we get rid of the 1px sheen on the left, then the 2px shadow + // on the right. Finally we shrink 3px from each side. + auto tab_button_content_rect = button_rect.shrunken(2, 0); + tab_button_content_rect.set_width(tab_button_content_rect.width() - 1); + tab_button_content_rect.shrink(6, 0); + if (m_tab_position == TabPosition::Top) { + tab_button_content_rect.set_top(tab_button_content_rect.top() + 1); + tab_button_content_rect.set_height(tab_button_content_rect.height() - 1); + } + paint_tab_icon_if_needed(m_tabs[i].icon, button_rect, tab_button_content_rect); - tab_button_content_rect.set_width(tab_button_content_rect.width() - (m_close_button_enabled ? 16 : 2)); + tab_button_content_rect.set_width(tab_button_content_rect.width() - (m_close_button_enabled ? 16 : 0)); - Gfx::IntRect text_rect { 0, 0, min(tab_button_content_rect.width(), font().width(m_tabs[i].title)), font().glyph_height() }; - text_rect.inflate(6, 4); - text_rect.align_within(tab_button_content_rect, m_text_alignment); - text_rect.intersect(tab_button_content_rect); - - painter.draw_text(text_rect, m_tabs[i].title, Gfx::TextAlignment::CenterLeft, palette().button_text(), Gfx::TextElision::Right); + painter.draw_text(tab_button_content_rect, m_tabs[i].title, m_text_alignment, palette().button_text(), Gfx::TextElision::Right); if (is_focused()) { - painter.draw_focus_rect(text_rect, palette().focus_outline()); + Gfx::IntRect focus_rect { 0, 0, min(tab_button_content_rect.width(), font().width(m_tabs[i].title)), font().glyph_height() }; + focus_rect.align_within(tab_button_content_rect, m_text_alignment); + focus_rect.inflate(6, 4); + + painter.draw_focus_rect(focus_rect, palette().focus_outline()); } if (m_tab_position == TabPosition::Top) { @@ -339,7 +357,18 @@ Gfx::IntRect TabWidget::close_button_rect(size_t index) const int TabWidget::TabData::width(const Gfx::Font& font) const { - return 16 + font.width(title) + (icon ? (16 + 4) : 0); + auto width = 16 + font.width(title) + (icon ? (16 + 4) : 0); + // NOTE: This needs to always be an odd number, because the button rect + // includes 3px of light and shadow on the left and right edges. If + // the button rect width is not an odd number, the area left for the + // text and the focus rect has an odd number of pixels, and this + // causes the text (and subsequently the focus rect) to not be aligned + // to the center perfectly. + if (width % 2 == 0) { + width++; + } + + return width; } void TabWidget::mousedown_event(MouseEvent& event)