diff --git a/doc/help/commands.asciidoc b/doc/help/commands.asciidoc index 25c4c463f..6e1ffd647 100644 --- a/doc/help/commands.asciidoc +++ b/doc/help/commands.asciidoc @@ -919,7 +919,7 @@ Close all tabs except for the current one. === tab-pin Pin/Unpin the current/[count]th tab. -Pinning a tab shrinks it to `tabs.width.pinned` size. Attempting to close a pinned tab will cause a confirmation, unless --force is passed. +Pinning a tab shrinks it to the size of its title text. Attempting to close a pinned tab will cause a confirmation, unless --force is passed. ==== count The tab index to pin or unpin diff --git a/doc/help/settings.asciidoc b/doc/help/settings.asciidoc index 95360b6ab..864ffcf2f 100644 --- a/doc/help/settings.asciidoc +++ b/doc/help/settings.asciidoc @@ -238,7 +238,6 @@ |<>|The format to use for the tab title for pinned tabs. The same placeholders like for `tabs.title.format` are defined. |<>|The width of the tab bar if it's vertical, in px or as percentage of the window. |<>|Width of the progress indicator (0 to disable). -|<>|The width for pinned tabs with a horizontal tabbar, in px. |<>|Whether to wrap when changing tabs. |<>|Whether to start a search when something else than a URL is entered. |<>|The page to open if :open -t/-b/-w is used without URL. @@ -2996,14 +2995,6 @@ Type: <> Default: +pass:[3]+ -[[tabs.width.pinned]] -=== tabs.width.pinned -The width for pinned tabs with a horizontal tabbar, in px. - -Type: <> - -Default: +pass:[43]+ - [[tabs.wrap]] === tabs.wrap Whether to wrap when changing tabs. diff --git a/qutebrowser/browser/commands.py b/qutebrowser/browser/commands.py index f1dcc19e8..11efccc11 100644 --- a/qutebrowser/browser/commands.py +++ b/qutebrowser/browser/commands.py @@ -256,7 +256,7 @@ class CommandDispatcher: def tab_pin(self, count=None): """Pin/Unpin the current/[count]th tab. - Pinning a tab shrinks it to `tabs.width.pinned` size. + Pinning a tab shrinks it to the size of its title text. Attempting to close a pinned tab will cause a confirmation, unless --force is passed. diff --git a/qutebrowser/config/configdata.yml b/qutebrowser/config/configdata.yml index 8e931a7c7..b907a2d75 100644 --- a/qutebrowser/config/configdata.yml +++ b/qutebrowser/config/configdata.yml @@ -1191,13 +1191,6 @@ tabs.width.indicator: minval: 0 desc: Width of the progress indicator (0 to disable). -tabs.width.pinned: - default: 43 - type: - name: Int - minval: 10 - desc: The width for pinned tabs with a horizontal tabbar, in px. - tabs.wrap: default: true type: Bool diff --git a/qutebrowser/mainwindow/tabbedbrowser.py b/qutebrowser/mainwindow/tabbedbrowser.py index 13865ba90..7234b13b4 100644 --- a/qutebrowser/mainwindow/tabbedbrowser.py +++ b/qutebrowser/mainwindow/tabbedbrowser.py @@ -272,10 +272,6 @@ class TabbedBrowser(tabwidget.TabWidget): if last_close == 'ignore' and count == 1: return - # If we are removing a pinned tab, decrease count - if tab.data.pinned: - self.tabBar().pinned_count -= 1 - self._remove_tab(tab, add_undo=add_undo) if count == 1: # We just closed the last tab above. diff --git a/qutebrowser/mainwindow/tabwidget.py b/qutebrowser/mainwindow/tabwidget.py index 111be2931..9d1ebd945 100644 --- a/qutebrowser/mainwindow/tabwidget.py +++ b/qutebrowser/mainwindow/tabwidget.py @@ -92,26 +92,16 @@ class TabWidget(QTabWidget): bar.update(bar.tabRect(idx)) def set_tab_pinned(self, tab: QWidget, - pinned: bool, *, loading: bool = False) -> None: + pinned: bool) -> None: """Set the tab status as pinned. Args: tab: The tab to pin pinned: Pinned tab state to set. - loading: Whether to ignore current data state when - counting pinned_count. """ bar = self.tabBar() idx = self.indexOf(tab) - # Only modify pinned_count if we had a change - # always modify pinned_count if we are loading - if tab.data.pinned != pinned or loading: - if pinned: - bar.pinned_count += 1 - elif not pinned: - bar.pinned_count -= 1 - bar.set_tab_data(idx, 'pinned', pinned) tab.data.pinned = pinned self._update_tab_title(idx) @@ -310,7 +300,6 @@ class TabBar(QTabBar): self._on_show_switching_delay_changed() self.setAutoFillBackground(True) self._set_colors() - self.pinned_count = 0 QTimer.singleShot(0, self.maybe_hide) def __repr__(self): @@ -435,18 +424,25 @@ class TabBar(QTabBar): return super().mousePressEvent(e) - def minimumTabSizeHint(self, index): + def minimumTabSizeHint(self, index, ellipsis: bool = True): """Set the minimum tab size to indicator/icon/... text. Args: index: The index of the tab to get a size hint for. - + ellipsis: Whether to use ellipsis to calculate width + instead of the tab's text. Return: - A QSize. + A QSize of the smallest tab size we can make. """ + text = '\u2026' if ellipsis else self.tabText(index) + # Don't ever shorten if text is shorter than the elipsis + text_width = min(self.fontMetrics().width(text), + self.fontMetrics().width(self.tabText(index))) icon = self.tabIcon(index) padding = config.val.tabs.padding + indicator_padding = config.val.tabs.indicator_padding padding_h = padding.left + padding.right + padding_h += indicator_padding.left + indicator_padding.right padding_v = padding.top + padding.bottom if icon.isNull(): icon_size = QSize(0, 0) @@ -454,15 +450,32 @@ class TabBar(QTabBar): extent = self.style().pixelMetric(QStyle.PM_TabBarIconSize, None, self) icon_size = icon.actualSize(QSize(extent, extent)) - padding_h += self.style().pixelMetric( - PixelMetrics.icon_padding, None, self) height = self.fontMetrics().height() + padding_v - width = (self.fontMetrics().width('\u2026') + icon_size.width() + + width = (text_width + icon_size.width() + padding_h + config.val.tabs.width.indicator) return QSize(width, height) - def tabSizeHint(self, index): - """Override tabSizeHint so all tabs are the same size. + def _tab_total_width_pinned(self): + """Get the current total width of pinned tabs. + + This width is calculated assuming no shortening due to ellipsis.""" + return sum(self.minimumTabSizeHint(idx, ellipsis=False).width() + for idx in range(self.count()) + if self._tab_pinned(idx)) + + def _pinnedCount(self) -> int: + """Get the number of pinned tabs.""" + return sum(self._tab_pinned(idx) for idx in range(self.count())) + + def _tab_pinned(self, index: int) -> bool: + """Return True if tab is pinned.""" + try: + return self.tab_data(index, 'pinned') + except KeyError: + return False + + def tabSizeHint(self, index: int): + """Override tabSizeHint to customize qb's tab size. https://wiki.python.org/moin/PyQt/Customising%20tab%20bars @@ -490,43 +503,17 @@ class TabBar(QTabBar): # want to ensure it's valid in this special case. return QSize() else: - try: - pinned = self.tab_data(index, 'pinned') - except KeyError: - pinned = False - - no_pinned_count = self.count() - self.pinned_count - pinned_width = config.val.tabs.width.pinned * self.pinned_count + pinned = self._tab_pinned(index) + no_pinned_count = self.count() - self._pinnedCount() + pinned_width = self._tab_total_width_pinned() no_pinned_width = self.width() - pinned_width if pinned: - size = QSize(config.val.tabs.width.pinned, height) - qtutils.ensure_valid(size) - return size - - # If we *do* have enough space, tabs should occupy the whole window - # width. If there are pinned tabs their size will be subtracted - # from the total window width. - # During shutdown the self.count goes down, - # but the self.pinned_count not - this generates some odd behavior. - # To avoid this we compare self.count against self.pinned_count. - if self.pinned_count > 0 and self.count() > self.pinned_count: - pinned_width = config.val.tabs.width.pinned * self.pinned_count - no_pinned_width = self.width() - pinned_width - width = no_pinned_width / (self.count() - self.pinned_count) + # Give pinned tabs the minimum size they need to display their + # titles, let Qt handle scaling it down if we get too small. + width = self.minimumTabSizeHint(index, ellipsis=False).width() else: - - # Tabs should attempt to occupy the whole window width. If - # there are pinned tabs their size will be subtracted from the - # total window width. During shutdown the self.count goes - # down, but the self.pinned_count not - this generates some odd - # behavior. To avoid this we compare self.count against - # self.pinned_count. If we end up having too little space, we - # set the minimum size below. - if self.pinned_count > 0 and no_pinned_count > 0: - width = no_pinned_width / no_pinned_count - else: - width = self.width() / self.count() + width = no_pinned_width / no_pinned_count # If no_pinned_width is not divisible by no_pinned_count, add a # pixel to some tabs so that there is no ugly leftover space. diff --git a/qutebrowser/misc/sessions.py b/qutebrowser/misc/sessions.py index 7c42b231b..064d8c9e9 100644 --- a/qutebrowser/misc/sessions.py +++ b/qutebrowser/misc/sessions.py @@ -393,8 +393,7 @@ class SessionManager(QObject): if tab.get('active', False): tab_to_focus = i if new_tab.data.pinned: - tabbed_browser.set_tab_pinned( - new_tab, new_tab.data.pinned, loading=True) + tabbed_browser.set_tab_pinned(new_tab, new_tab.data.pinned) if tab_to_focus is not None: tabbed_browser.setCurrentIndex(tab_to_focus) if win.get('active', False):