diff options
author | toofar <toofar@spalge.com> | 2023-03-15 16:40:54 +1300 |
---|---|---|
committer | toofar <toofar@spalge.com> | 2023-03-15 17:07:31 +1300 |
commit | 0f01027570934821678b6a41a768480caa63b625 (patch) | |
tree | 18cb575400f3632ddc794365b7ef976cfbaf850b | |
parent | 30125a2e2e302b79a168db36cb5b3f18ff50f5bd (diff) | |
download | qutebrowser-0f01027570934821678b6a41a768480caa63b625.tar.gz qutebrowser-0f01027570934821678b6a41a768480caa63b625.zip |
Override QTabBar text eilding
The fontMetrics().elidedText(...) call is copied from the base QTabBar
implementation of initStyleOption(). But here we are calling it with a
text_rect from our custom style class. In Qt6 QStyleSheetStyle no longer
calls into our custom Style class for the SE_TabBarTabText SubElement so
it ends up getting a text width from QCommonStyle which is wrong for
vertical tabs (`QCommonStylePrivate::tabLayout()` seems to transpose the
rect, maybe it thinks vertical tabs should have the text running
vertically too).
Also resolves the issue that when tabs.title.alignment is set to center
the leftmost character or two of titles wouldn't be visible when tabs
where small enough that the text got elided. Not 100% sure why but
presumably it wasn't picking up the padding etc logic in our custom
style class.
In the test I don't test the exact elided text when we don't have much
room because it might differ based on what monospace font is picked up
in the tests. So the amount elided might change. Also in the not-elided
one I'm only testing endswith() because the index should be at the start
of the string which I don't really care about.
Fixes: #7313
Fixes: #7205
-rw-r--r-- | qutebrowser/mainwindow/tabwidget.py | 26 | ||||
-rw-r--r-- | tests/unit/mainwindow/test_tabwidget.py | 35 |
2 files changed, 59 insertions, 2 deletions
diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 5e4f519fa..580da64b4 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -405,7 +405,8 @@ class TabBar(QTabBar): def __init__(self, win_id, parent=None): super().__init__(parent) self._win_id = win_id - self.setStyle(TabBarStyle()) + self._our_style = TabBarStyle() + self.setStyle(self._our_style) self.vertical = False self._auto_hide_timer = QTimer() self._auto_hide_timer.setSingleShot(True) @@ -696,6 +697,29 @@ class TabBar(QTabBar): qtutils.ensure_valid(size) return size + def initStyleOption(self, opt, idx): + """Override QTabBar.initStyleOption(). + + Used to calculate styling clues from a widget for the GUI layer. + """ + super().initStyleOption(opt, idx) + + # Re-do the text elision that the base QTabBar does, but using a text + # rectangle computed by out TabBarStyle. With Qt6 the base class ends + # up using QCommonStyle directly for that which has a different opinon + # of how vertical tabs should work. + text_rect = self._our_style.subElementRect( + QStyle.SubElement.SE_TabBarTabText, + opt, + self, + ) + opt.text = self.fontMetrics().elidedText( + self.tabText(idx), + self.elideMode(), + text_rect.width(), + Qt.TextFlag.TextShowMnemonic, + ) + def paintEvent(self, event): """Override paintEvent to draw the tabs like we want to.""" p = QStylePainter(self) diff --git a/tests/unit/mainwindow/test_tabwidget.py b/tests/unit/mainwindow/test_tabwidget.py index db300d7a6..d6289dac6 100644 --- a/tests/unit/mainwindow/test_tabwidget.py +++ b/tests/unit/mainwindow/test_tabwidget.py @@ -23,8 +23,9 @@ import functools import pytest -from qutebrowser.qt.gui import QIcon, QPixmap +from unittest.mock import Mock +from qutebrowser.qt.gui import QIcon, QPixmap from qutebrowser.mainwindow import tabwidget from qutebrowser.utils import usertypes @@ -71,6 +72,38 @@ class TestTabWidget: assert first_size == widget.tabBar().tabSizeHint(i) assert first_size_min == widget.tabBar().minimumTabSizeHint(i) + @pytest.fixture + def paint_spy(self, monkeypatch): + spy = Mock() + monkeypatch.setattr(tabwidget, "QStylePainter", spy) + return spy + + def test_tab_text_edlided_for_narrow_tabs(self, paint_spy, widget, fake_web_tab): + """Make sure text gets elided for narrow tabs.""" + widget.setMaximumWidth(100) + widget.addTab(fake_web_tab(), "one two three four") + + fake_paint_event = Mock() + fake_paint_event.region.return_value.intersects.return_value = True + widget.tabBar().paintEvent(fake_paint_event) + + style_opt = paint_spy.return_value.drawControl.call_args_list[0][0][1] + assert len(style_opt.text) < len(widget.tabBar().tabText(0)) + assert style_opt.text.endswith("…") + assert len(style_opt.text) > len("…") + + def test_tab_text_not_edlided_for_wide_tabs(self, paint_spy, widget, fake_web_tab): + """Make sure text doesn't get elided for wide tabs.""" + widget.setMaximumWidth(200) + widget.addTab(fake_web_tab(), "one two three four") + + fake_paint_event = Mock() + fake_paint_event.region.return_value.intersects.return_value = True + widget.tabBar().paintEvent(fake_paint_event) + + style_opt = paint_spy.return_value.drawControl.call_args_list[0][0][1] + assert style_opt.text.endswith(widget.tabBar().tabText(0)) + @pytest.mark.parametrize("shrink_pinned", [True, False]) @pytest.mark.parametrize("vertical", [True, False]) def test_pinned_size(self, widget, fake_web_tab, config_stub, |