diff --git a/booru_viewer/gui/library.py b/booru_viewer/gui/library.py index fef3f0b..6aa1fce 100644 --- a/booru_viewer/gui/library.py +++ b/booru_viewer/gui/library.py @@ -76,8 +76,10 @@ class LibraryView(QWidget): top.addWidget(self._folder_combo) self._sort_combo = QComboBox() - self._sort_combo.addItems(["Date", "Name", "Size"]) - self._sort_combo.setFixedWidth(80) + self._sort_combo.addItems(["Date", "Post ID", "Size"]) + # 75 is the tight floor: 68 clipped the trailing D under the + # bundled themes (font metrics ate more than the math suggested). + self._sort_combo.setFixedWidth(75) self._sort_combo.currentTextChanged.connect(lambda _: self.refresh()) top.addWidget(self._sort_combo) @@ -252,8 +254,16 @@ class LibraryView(QWidget): def _sort_files(self) -> None: mode = self._sort_combo.currentText() - if mode == "Name": - self._files.sort(key=lambda p: p.name.lower()) + if mode == "Post ID": + # Numeric sort by post id (filename stem). Library files are + # named {post_id}.{ext} in normal usage; anything with a + # non-digit stem (someone manually dropped a file in) sorts + # to the end alphabetically so the numeric ordering of real + # posts isn't disrupted by stray names. + def _key(p: Path) -> tuple: + stem = p.stem + return (0, int(stem)) if stem.isdigit() else (1, stem.lower()) + self._files.sort(key=_key) elif mode == "Size": self._files.sort(key=lambda p: p.stat().st_size, reverse=True) else: diff --git a/booru_viewer/gui/preview.py b/booru_viewer/gui/preview.py index 8911e64..0189c1a 100644 --- a/booru_viewer/gui/preview.py +++ b/booru_viewer/gui/preview.py @@ -380,11 +380,37 @@ class FullscreenPreview(QMainWindow): return None # not Hyprland return bool(win.get("floating")) - def _fit_to_content(self, content_w: int, content_h: int) -> None: - """Size window to fit content. Width preserved, height from aspect ratio, clamped to screen.""" + def _fit_to_content(self, content_w: int, content_h: int, _retry: int = 0) -> None: + """Size window to fit content. Width preserved, height from aspect ratio, clamped to screen. + + Distinguishes "not on Hyprland" (Qt drives geometry, no aspect + lock available) from "on Hyprland but the window isn't visible + to hyprctl yet" (the very first call after a popout open races + the wm:openWindow event — `hyprctl clients -j` returns no entry + for our title for ~tens of ms). The latter case used to fall + through to a plain Qt resize and skip the keep_aspect_ratio + setprop entirely, so the *first* image popout always opened + without aspect locking and only subsequent navigations got the + right shape. Now we retry with a short backoff when on Hyprland + and the window isn't found, capped so a real "not Hyprland" + signal can't loop. + """ if self.isFullScreen() or content_w <= 0 or content_h <= 0: return - floating = self._is_hypr_floating() + import os + on_hypr = bool(os.environ.get("HYPRLAND_INSTANCE_SIGNATURE")) + if on_hypr: + win = self._hyprctl_get_window() + if win is None: + if _retry < 5: + QTimer.singleShot( + 40, + lambda: self._fit_to_content(content_w, content_h, _retry + 1), + ) + return + floating = bool(win.get("floating")) + else: + floating = None if floating is False: self._hyprctl_resize(0, 0) # tiled: just set keep_aspect_ratio return @@ -789,7 +815,14 @@ class ImageViewer(QWidget): return scale_w = vw / pw scale_h = vh / ph - self._zoom = min(scale_w, scale_h, 1.0) + # No 1.0 cap — scale up to fill the available view, matching how + # the video player fills its widget. In the popout the window is + # already aspect-locked to the image's aspect, so scaling up + # produces a clean fill with no letterbox. In the embedded + # preview the user can drag the splitter past the image's native + # size; letting it scale up there fills the pane the same way + # the popout does. + self._zoom = min(scale_w, scale_h) self._offset = QPointF( (vw - pw * self._zoom) / 2, (vh - ph * self._zoom) / 2, diff --git a/themes/catppuccin-mocha-rounded.qss b/themes/catppuccin-mocha-rounded.qss index 182e739..07e3ecc 100644 --- a/themes/catppuccin-mocha-rounded.qss +++ b/themes/catppuccin-mocha-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/catppuccin-mocha-square.qss b/themes/catppuccin-mocha-square.qss index 782ac11..963063c 100644 --- a/themes/catppuccin-mocha-square.qss +++ b/themes/catppuccin-mocha-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/everforest-rounded.qss b/themes/everforest-rounded.qss index ea70778..ed678ce 100644 --- a/themes/everforest-rounded.qss +++ b/themes/everforest-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/everforest-square.qss b/themes/everforest-square.qss index c412e7b..1bc2769 100644 --- a/themes/everforest-square.qss +++ b/themes/everforest-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/gruvbox-rounded.qss b/themes/gruvbox-rounded.qss index 703b7ab..add390a 100644 --- a/themes/gruvbox-rounded.qss +++ b/themes/gruvbox-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/gruvbox-square.qss b/themes/gruvbox-square.qss index 87a09a8..3653d4a 100644 --- a/themes/gruvbox-square.qss +++ b/themes/gruvbox-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/nord-rounded.qss b/themes/nord-rounded.qss index 9dfc95c..96f6d58 100644 --- a/themes/nord-rounded.qss +++ b/themes/nord-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/nord-square.qss b/themes/nord-square.qss index 5a93e41..21791bc 100644 --- a/themes/nord-square.qss +++ b/themes/nord-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/solarized-dark-rounded.qss b/themes/solarized-dark-rounded.qss index 5c131d7..07e107a 100644 --- a/themes/solarized-dark-rounded.qss +++ b/themes/solarized-dark-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/solarized-dark-square.qss b/themes/solarized-dark-square.qss index 8c3225f..8d6a17b 100644 --- a/themes/solarized-dark-square.qss +++ b/themes/solarized-dark-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/tokyo-night-rounded.qss b/themes/tokyo-night-rounded.qss index 20bca9b..60e1637 100644 --- a/themes/tokyo-night-rounded.qss +++ b/themes/tokyo-night-rounded.qss @@ -60,7 +60,7 @@ QPushButton { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -145,7 +145,7 @@ QComboBox { color: ${text}; border: 1px solid ${border_strong}; border-radius: 4px; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -156,7 +156,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle}; diff --git a/themes/tokyo-night-square.qss b/themes/tokyo-night-square.qss index c500f35..9728361 100644 --- a/themes/tokyo-night-square.qss +++ b/themes/tokyo-night-square.qss @@ -59,7 +59,7 @@ QPushButton { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 8px; + padding: 2px 6px; min-height: 17px; } QPushButton:hover { @@ -141,7 +141,7 @@ QComboBox { background-color: ${bg_subtle}; color: ${text}; border: 1px solid ${border_strong}; - padding: 2px 6px; + padding: 2px 4px; min-height: 16px; } QComboBox:hover { @@ -152,7 +152,7 @@ QComboBox:focus { } QComboBox::drop-down { border: none; - width: 18px; + width: 14px; } QComboBox QAbstractItemView { background-color: ${bg_subtle};