diff --git a/booru_viewer/gui/app.py b/booru_viewer/gui/app.py index d52aa61..1870422 100644 --- a/booru_viewer/gui/app.py +++ b/booru_viewer/gui/app.py @@ -516,7 +516,11 @@ class BooruApp(QMainWindow): self._preview.fullscreen_requested.connect(self._open_fullscreen_preview) self._preview.set_folders_callback(self._db.get_folders) self._fullscreen_window = None - self._preview.setMinimumWidth(300) + # Wide enough that the preview toolbar (Bookmark, Save, BL Tag, + # BL Post, [stretch], Popout) has room to lay out all five buttons + # at their fixed widths plus spacing without clipping the rightmost + # one or compressing the row visually. + self._preview.setMinimumWidth(380) right.addWidget(self._preview) self._dl_progress = QProgressBar() @@ -2946,6 +2950,69 @@ def _apply_windows_dark_mode(app: QApplication) -> None: log.warning(f"Operation failed: {e}") +def _load_user_qss(path: Path) -> str: + """Load a QSS file with optional @palette variable substitution. + + Qt's QSS dialect has no native variables, so we add a tiny preprocessor: + + /* @palette + accent: #cba6f7 + bg: #1e1e2e + text: #cdd6f4 + */ + + QWidget { + background-color: ${bg}; + color: ${text}; + selection-background-color: ${accent}; + } + + The header comment block is parsed for `name: value` pairs and any + `${name}` reference elsewhere in the file is substituted with the + corresponding value before the QSS is handed to Qt. This lets users + recolor a bundled theme by editing the palette block alone, without + hunting through the body for every hex literal. + + Backward compatibility: a file without an @palette block is returned + as-is, so plain hand-written Qt-standard QSS still loads unchanged. + Unknown ${name} references are left in place verbatim and logged as + warnings so typos are visible in the log. + """ + import re + text = path.read_text() + palette_match = re.search(r'/\*\s*@palette\b(.*?)\*/', text, re.DOTALL) + if not palette_match: + return text + + palette: dict[str, str] = {} + for raw_line in palette_match.group(1).splitlines(): + # Strip leading whitespace and any leading * from C-style continuation + line = raw_line.strip().lstrip('*').strip() + if not line or ':' not in line: + continue + key, value = line.split(':', 1) + key = key.strip() + value = value.strip().rstrip(';').strip() + # Allow trailing comments on the same line + if '/*' in value: + value = value.split('/*', 1)[0].strip() + if key and value: + palette[key] = value + + refs = set(re.findall(r'\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}', text)) + missing = refs - palette.keys() + if missing: + log.warning( + f"QSS @palette: unknown vars {sorted(missing)} in {path.name} " + f"— left in place verbatim, fix the @palette block to define them" + ) + + def replace(m): + return palette.get(m.group(1), m.group(0)) + + return re.sub(r'\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}', replace, text) + + def run() -> None: from ..core.config import data_dir @@ -2977,7 +3044,10 @@ def run() -> None: from PySide6.QtCore import QPoint as _QP import re - css_text = custom_css.read_text() + # Run through the @palette preprocessor (see _load_user_qss + # for the dialect). Plain Qt-standard QSS files without an + # @palette block are returned unchanged. + css_text = _load_user_qss(custom_css) # Extract text color for arrows m = re.search(r'QWidget\s*\{[^}]*?(?:^|\s)color\s*:\s*(#[0-9a-fA-F]{3,8})', css_text, re.MULTILINE) diff --git a/booru_viewer/gui/preview.py b/booru_viewer/gui/preview.py index 7879c13..01035ea 100644 --- a/booru_viewer/gui/preview.py +++ b/booru_viewer/gui/preview.py @@ -5,8 +5,8 @@ from __future__ import annotations import logging from pathlib import Path -from PySide6.QtCore import Qt, QPointF, Signal, QTimer -from PySide6.QtGui import QPixmap, QPainter, QWheelEvent, QMouseEvent, QKeyEvent, QMovie +from PySide6.QtCore import Qt, QPointF, Signal, QTimer, Property +from PySide6.QtGui import QPixmap, QPainter, QWheelEvent, QMouseEvent, QKeyEvent, QMovie, QColor from PySide6.QtWidgets import ( QWidget, QVBoxLayout, QHBoxLayout, QLabel, QMainWindow, QStackedWidget, QPushButton, QSlider, QMenu, QInputDialog, QStyle, @@ -23,40 +23,13 @@ def _is_video(path: str) -> bool: return Path(path).suffix.lower() in VIDEO_EXTENSIONS -def _overlay_css(obj_name: str) -> str: - """Generate overlay CSS scoped to a specific object name for specificity.""" - return f""" - QWidget#{obj_name} * {{ - background: transparent; - color: white; - border: none; - }} - QWidget#{obj_name} QPushButton {{ - background: transparent; - color: white; - border: 1px solid rgba(255, 255, 255, 80); - padding: 2px 6px; - }} - QWidget#{obj_name} QPushButton:hover {{ - background: rgba(255, 255, 255, 30); - }} - QWidget#{obj_name} QSlider::groove:horizontal {{ - background: rgba(255, 255, 255, 40); - height: 4px; - }} - QWidget#{obj_name} QSlider::handle:horizontal {{ - background: white; - width: 10px; - margin: -4px 0; - }} - QWidget#{obj_name} QSlider::sub-page:horizontal {{ - background: rgba(255, 255, 255, 120); - }} - QWidget#{obj_name} QLabel {{ - background: transparent; - color: white; - }} - """ +## Overlay styling for the popout's translucent toolbar / controls bar +## now lives in the bundled themes (themes/*.qss). The widgets get their +## object names set in code (FullscreenPreview / VideoPlayer) so theme QSS +## rules can target them via #_slideshow_toolbar / #_slideshow_controls / +## #_preview_controls. Users can override the look by editing the +## overlay_bg slot in their @palette block, or by adding more specific +## QSS rules in their custom.qss. class FullscreenPreview(QMainWindow): @@ -97,30 +70,44 @@ class FullscreenPreview(QMainWindow): self.setCentralWidget(central) - # Floating toolbar — overlays on top of media, translucent + # Floating toolbar — overlays on top of media, translucent. + # Set the object name BEFORE the widget is polished by Qt so that + # the bundled-theme `QWidget#_slideshow_toolbar` selector matches + # on the very first style computation. Setting it later requires + # an explicit unpolish/polish cycle, which we want to avoid. self._toolbar = QWidget(central) + self._toolbar.setObjectName("_slideshow_toolbar") toolbar = QHBoxLayout(self._toolbar) toolbar.setContentsMargins(8, 4, 8, 4) + # Same compact-padding override as the embedded preview toolbar — + # bundled themes' default `padding: 5px 12px` is too wide for these + # short labels in narrow fixed slots. + _tb_btn_style = "padding: 3px 6px;" + self._bookmark_btn = QPushButton("Bookmark") - self._bookmark_btn.setMaximumWidth(80) + self._bookmark_btn.setMaximumWidth(90) + self._bookmark_btn.setStyleSheet(_tb_btn_style) self._bookmark_btn.clicked.connect(self.bookmark_requested) toolbar.addWidget(self._bookmark_btn) self._save_btn = QPushButton("Save") self._save_btn.setMaximumWidth(70) + self._save_btn.setStyleSheet(_tb_btn_style) self._save_btn.clicked.connect(self.save_toggle_requested) toolbar.addWidget(self._save_btn) self._is_saved = False self._bl_tag_btn = QPushButton("BL Tag") - self._bl_tag_btn.setMaximumWidth(60) + self._bl_tag_btn.setMaximumWidth(65) + self._bl_tag_btn.setStyleSheet(_tb_btn_style) self._bl_tag_btn.setToolTip("Blacklist a tag") self._bl_tag_btn.clicked.connect(self._show_bl_tag_menu) toolbar.addWidget(self._bl_tag_btn) self._bl_post_btn = QPushButton("BL Post") - self._bl_post_btn.setMaximumWidth(65) + self._bl_post_btn.setMaximumWidth(70) + self._bl_post_btn.setStyleSheet(_tb_btn_style) self._bl_post_btn.setToolTip("Blacklist this post") self._bl_post_btn.clicked.connect(self.blacklist_post_requested) toolbar.addWidget(self._bl_post_btn) @@ -138,12 +125,28 @@ class FullscreenPreview(QMainWindow): self._toolbar.raise_() - # Reparent video controls bar to central widget so it overlays properly + # Reparent video controls bar to central widget so it overlays properly. + # The translucent overlay styling (background, transparent buttons, + # white-on-dark text) lives in the bundled themes — see the + # `Popout overlay bars` section of any themes/*.qss. The object names + # are what those rules target. + # + # The toolbar's object name is set above, in its constructor block, + # so the first style poll picks it up. The controls bar was already + # polished as a child of VideoPlayer before being reparented here, + # so we have to force an unpolish/polish round-trip after setting + # its object name to make Qt re-evaluate the style with the new + # `#_slideshow_controls` selector. self._video._controls_bar.setParent(central) - self._toolbar.setStyleSheet("QWidget#_slideshow_toolbar { background: rgba(0,0,0,160); }" + _overlay_css("_slideshow_toolbar")) - self._toolbar.setObjectName("_slideshow_toolbar") - self._video._controls_bar.setStyleSheet("QWidget#_slideshow_controls { background: rgba(0,0,0,160); }" + _overlay_css("_slideshow_controls")) self._video._controls_bar.setObjectName("_slideshow_controls") + cb_style = self._video._controls_bar.style() + cb_style.unpolish(self._video._controls_bar) + cb_style.polish(self._video._controls_bar) + # Same trick on the toolbar — it might have been polished by the + # central widget's parent before our object name took effect. + tb_style = self._toolbar.style() + tb_style.unpolish(self._toolbar) + tb_style.polish(self._toolbar) self._video._controls_bar.raise_() self._toolbar.raise_() @@ -889,8 +892,54 @@ class VideoPlayer(QWidget): media_ready = Signal() # emitted when media is loaded and duration is known video_size = Signal(int, int) # (width, height) emitted when video dimensions are known - def __init__(self, parent: QWidget | None = None) -> None: + # QSS-controllable letterbox / pillarbox color. mpv paints the area + # around the video frame in this color instead of the default black, + # so portrait videos in a landscape preview slot (or vice versa) blend + # into the panel theme instead of sitting in a hard black box. + # Set via `VideoPlayer { qproperty-letterboxColor: ${bg}; }` in a theme. + # The class default below is just a fallback; __init__ replaces it + # with the current palette's Window color so systems without a custom + # QSS (e.g. Windows dark/light mode driven entirely by QPalette) get + # a letterbox that automatically matches the OS background. + _letterbox_color = QColor("#000000") + + def _get_letterbox_color(self): return self._letterbox_color + def _set_letterbox_color(self, c): + self._letterbox_color = QColor(c) if isinstance(c, str) else c + self._apply_letterbox_color() + letterboxColor = Property(QColor, _get_letterbox_color, _set_letterbox_color) + + def _apply_letterbox_color(self) -> None: + """Push the current letterbox color into mpv. No-op if mpv hasn't + been initialized yet — _ensure_mpv() calls this after creating the + instance so a QSS-set property still takes effect on first use.""" + if self._mpv is None: + return + try: + self._mpv['background'] = 'color' + self._mpv['background-color'] = self._letterbox_color.name() + except Exception: + pass + + def __init__(self, parent: QWidget | None = None, embed_controls: bool = True) -> None: + """ + embed_controls: When True (default), the transport controls bar is + added to this VideoPlayer's own layout below the video — used by the + popout window which then reparents the bar to its overlay layer. + When False, the controls bar is constructed but never inserted into + any layout, leaving the embedded preview a clean video surface with + no transport controls visible. Use the popout for playback control. + """ super().__init__(parent) + # Initialize the letterbox color from the current palette's Window + # role so dark/light mode (or any system without a custom QSS) + # gets a sensible default that matches the surrounding panel. + # The QSS qproperty-letterboxColor on the bundled themes still + # overrides this — Qt calls the setter during widget polish, + # which happens AFTER __init__ when the widget is shown. + from PySide6.QtGui import QPalette + self._letterbox_color = self.palette().color(QPalette.ColorRole.Window) + layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) @@ -908,8 +957,15 @@ class VideoPlayer(QWidget): controls = QHBoxLayout(self._controls_bar) controls.setContentsMargins(4, 2, 4, 2) + # Compact-padding override matches the top preview toolbar so the + # bottom controls bar reads as part of the same panel rather than + # as a stamped-in overlay. Bundled themes' default `padding: 5px 12px` + # is too wide for short labels in narrow button slots. + _ctrl_btn_style = "padding: 3px 6px;" + self._play_btn = QPushButton("Play") self._play_btn.setMaximumWidth(65) + self._play_btn.setStyleSheet(_ctrl_btn_style) self._play_btn.clicked.connect(self._toggle_play) controls.addWidget(self._play_btn) @@ -936,12 +992,14 @@ class VideoPlayer(QWidget): self._mute_btn = QPushButton("Mute") self._mute_btn.setMaximumWidth(80) + self._mute_btn.setStyleSheet(_ctrl_btn_style) self._mute_btn.clicked.connect(self._toggle_mute) controls.addWidget(self._mute_btn) self._autoplay = True self._autoplay_btn = QPushButton("Auto") self._autoplay_btn.setMaximumWidth(70) + self._autoplay_btn.setStyleSheet(_ctrl_btn_style) self._autoplay_btn.setCheckable(True) self._autoplay_btn.setChecked(True) self._autoplay_btn.setToolTip("Auto-play videos when selected") @@ -951,19 +1009,22 @@ class VideoPlayer(QWidget): self._loop_state = 0 # 0=Loop, 1=Once, 2=Next self._loop_btn = QPushButton("Loop") - self._loop_btn.setMaximumWidth(55) + self._loop_btn.setMaximumWidth(60) + self._loop_btn.setStyleSheet(_ctrl_btn_style) self._loop_btn.setToolTip("Loop: repeat / Once: stop at end / Next: advance") self._loop_btn.clicked.connect(self._cycle_loop) controls.addWidget(self._loop_btn) - # Style controls to match the translucent overlay look - self._controls_bar.setObjectName("_preview_controls") - self._controls_bar.setStyleSheet( - "QWidget#_preview_controls { background: rgba(0,0,0,160); }" + _overlay_css("_preview_controls") - ) - # Add to layout — in preview panel this is part of the normal layout. - # FullscreenPreview reparents it to float as an overlay. - layout.addWidget(self._controls_bar) + # NO styleSheet here. The popout (FullscreenPreview) re-applies its + # own `_slideshow_controls` overlay styling after reparenting the + # bar to its central widget — see FullscreenPreview.__init__ — so + # the popout still gets the floating dark-translucent look. The + # embedded preview leaves the bar unstyled so it inherits the + # panel theme and visually matches the Bookmark/Save/BL Tag bar + # at the top of the panel rather than looking like a stamped-in + # overlay box. + if embed_controls: + layout.addWidget(self._controls_bar) self._eof_pending = False @@ -992,6 +1053,10 @@ class VideoPlayer(QWidget): self._mpv.observe_property('eof-reached', self._on_eof_reached) self._mpv.observe_property('video-params', self._on_video_params) self._pending_video_size: tuple[int, int] | None = None + # Push any QSS-set letterbox color into mpv now that the instance + # exists. The qproperty-letterboxColor setter is a no-op if mpv + # hasn't been initialized yet, so we have to (re)apply on init. + self._apply_letterbox_color() return self._mpv # -- Public API (used by app.py for state sync) -- @@ -1247,24 +1312,37 @@ class ImagePreview(QWidget): tb.setContentsMargins(2, 1, 2, 1) tb.setSpacing(4) + # Compact toolbar buttons. The bundled themes set + # `QPushButton { padding: 5px 12px }` which eats 24px of horizontal + # space — too much for these short labels in fixed-width slots. + # Override with tighter padding inline so the labels (Unbookmark, + # Unsave, BL Tag, BL Post, Popout) fit cleanly under any theme. + # Same pattern as the search-bar score buttons in app.py and the + # settings dialog spinbox +/- buttons. + _tb_btn_style = "padding: 3px 6px;" + self._bookmark_btn = QPushButton("Bookmark") - self._bookmark_btn.setFixedWidth(80) + self._bookmark_btn.setFixedWidth(100) + self._bookmark_btn.setStyleSheet(_tb_btn_style) self._bookmark_btn.clicked.connect(self.bookmark_requested) tb.addWidget(self._bookmark_btn) self._save_btn = QPushButton("Save") - self._save_btn.setFixedWidth(50) + self._save_btn.setFixedWidth(60) + self._save_btn.setStyleSheet(_tb_btn_style) self._save_btn.clicked.connect(self._on_save_clicked) tb.addWidget(self._save_btn) self._bl_tag_btn = QPushButton("BL Tag") - self._bl_tag_btn.setFixedWidth(55) + self._bl_tag_btn.setFixedWidth(60) + self._bl_tag_btn.setStyleSheet(_tb_btn_style) self._bl_tag_btn.setToolTip("Blacklist a tag") self._bl_tag_btn.clicked.connect(self._show_bl_tag_menu) tb.addWidget(self._bl_tag_btn) self._bl_post_btn = QPushButton("BL Post") - self._bl_post_btn.setFixedWidth(60) + self._bl_post_btn.setFixedWidth(65) + self._bl_post_btn.setStyleSheet(_tb_btn_style) self._bl_post_btn.setToolTip("Blacklist this post") self._bl_post_btn.clicked.connect(self.blacklist_post_requested) tb.addWidget(self._bl_post_btn) @@ -1272,7 +1350,8 @@ class ImagePreview(QWidget): tb.addStretch() self._popout_btn = QPushButton("Popout") - self._popout_btn.setFixedWidth(60) + self._popout_btn.setFixedWidth(65) + self._popout_btn.setStyleSheet(_tb_btn_style) self._popout_btn.setToolTip("Open in popout") self._popout_btn.clicked.connect(self.fullscreen_requested) tb.addWidget(self._popout_btn) @@ -1289,12 +1368,31 @@ class ImagePreview(QWidget): self._image_viewer.close_requested.connect(self.close_requested) self._stack.addWidget(self._image_viewer) - # Video player (index 1) - self._video_player = VideoPlayer() + # Video player (index 1). embed_controls=False keeps the + # transport controls bar out of the VideoPlayer's own layout — + # we reparent it below the stack a few lines down so the controls + # sit *under* the media rather than overlaying it. + self._video_player = VideoPlayer(embed_controls=False) self._video_player.setFocusPolicy(Qt.FocusPolicy.NoFocus) self._video_player.play_next.connect(self.play_next_requested) self._stack.addWidget(self._video_player) + # Place the video controls bar in the preview panel's own layout, + # underneath the stack. The bar exists as a child of VideoPlayer + # but is not in any layout (because of embed_controls=False); we + # adopt it here as a sibling of the stack so it lays out cleanly + # below the media rather than floating on top of it. The popout + # uses its own separate VideoPlayer instance and reparents that + # instance's controls bar to its own central widget as an overlay. + self._stack_video_controls = self._video_player._controls_bar + self._stack_video_controls.setParent(self) + layout.addWidget(self._stack_video_controls) + # Only visible when the stack is showing the video player. + self._stack_video_controls.hide() + self._stack.currentChanged.connect( + lambda idx: self._stack_video_controls.setVisible(idx == 1) + ) + # Info label self._info_label = QLabel() self._info_label.setStyleSheet("padding: 2px 6px;") diff --git a/themes/README.md b/themes/README.md index b5670a0..3a93f2d 100644 --- a/themes/README.md +++ b/themes/README.md @@ -7,6 +7,63 @@ Copy any `.qss` file from this folder to your data directory as `custom.qss`: Restart the app after changing themes. +## Recoloring a theme — `@palette` blocks and `${...}` vars + +Qt's QSS dialect has no native variables, so booru-viewer adds a small +preprocessor that runs before the stylesheet is handed to Qt. Each +bundled theme starts with an `@palette` header block listing the colors +the rest of the file uses, and the body references them as `${name}`: + +```css +/* @palette + bg: #1e1e2e + accent: #cba6f7 + text: #cdd6f4 +*/ + +QWidget { + background-color: ${bg}; + color: ${text}; + selection-background-color: ${accent}; +} +``` + +To recolor a theme, **edit the `@palette` block at the top — that's the +only place hex literals appear**. The body picks up the new values +automatically. Save and restart the app. + +The preprocessor is opt-in: a `custom.qss` without an `@palette` block +loads as plain Qt-standard QSS, so existing hand-written themes still +work unchanged. Unknown `${name}` references are left in place verbatim +and a warning is logged so typos are visible. + +### Available palette slots + +The bundled themes define 17 standard color slots. You can add more in +your own `@palette` block (or remove ones you don't reference) — only +slots that the body actually uses need to be defined. + +| Slot | Used for | +|---|---| +| `bg` | Window background, scroll area, menu bar | +| `bg_alt` | Alternate row stripes in lists/trees, disabled inputs | +| `bg_subtle` | Buttons and inputs at rest, dropdown panels, tooltips | +| `bg_hover` | Surfaces under cursor hover, scrollbar handles | +| `bg_active` | Surfaces while pressed, scrollbar handles on hover | +| `text` | Primary foreground text | +| `text_dim` | Secondary text — status bar, group titles, placeholders | +| `text_disabled` | Disabled control text | +| `border` | Subtle dividers between adjacent surfaces | +| `border_strong` | More visible borders, default focus rings | +| `accent` | Selection background, focused borders, checked buttons | +| `accent_text` | Foreground used on top of accent backgrounds | +| `accent_dim` | Softer accent variant for hover-on-accent surfaces | +| `link` | Hyperlinks (info panel source URL) | +| `danger` | Destructive action color (Clear All button etc.) | +| `success` | Positive action color (also Character tag default) | +| `warning` | Warning color (also Artist tag default) | +| `overlay_bg` | Translucent background for the popout's floating top toolbar and bottom transport controls. Should be `rgba(...)` so video shows through. | + ## Included Themes | Theme | File | Preview | diff --git a/themes/catppuccin-mocha.qss b/themes/catppuccin-mocha.qss index a7867d5..77ddcac 100644 --- a/themes/catppuccin-mocha.qss +++ b/themes/catppuccin-mocha.qss @@ -1,41 +1,46 @@ /* booru-viewer — Catppuccin Mocha * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #1e1e2e - * bg_alt #181825 - * bg_subtle #313244 - * bg_hover #45475a - * bg_active #585b70 - * text #cdd6f4 - * text_dim #a6adc8 - * text_disabled #6c7086 - * border #313244 - * border_strong #45475a - * accent #cba6f7 - * accent_text #1e1e2e - * accent_dim #b4befe - * link #89b4fa - * danger #f38ba8 - * success #a6e3a1 - * warning #f9e2af + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #1e1e2e + bg_alt: #181825 + bg_subtle: #313244 + bg_hover: #45475a + bg_active: #585b70 + text: #cdd6f4 + text_dim: #a6adc8 + text_disabled: #6c7086 + border: #313244 + border_strong: #45475a + accent: #cba6f7 + accent_text: #1e1e2e + accent_dim: #b4befe + link: #89b4fa + danger: #f38ba8 + success: #a6e3a1 + warning: #f9e2af + overlay_bg: rgba(30, 30, 46, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #1e1e2e; - color: #cdd6f4; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #cba6f7; - selection-color: #1e1e2e; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #6c7086; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #1e1e2e; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #45475a; - border-color: #cba6f7; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #585b70; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #cba6f7; - color: #1e1e2e; - border-color: #cba6f7; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #b4befe; - border-color: #b4befe; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #181825; - color: #6c7086; - border-color: #313244; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #45475a; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #cdd6f4; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #45475a; - border-color: #45475a; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #585b70; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #cba6f7; - selection-color: #1e1e2e; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #cba6f7; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #181825; - color: #6c7086; - border-color: #313244; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #cba6f7; + border-color: ${accent}; } QComboBox:focus { - border-color: #cba6f7; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; - selection-background-color: #cba6f7; - selection-color: #1e1e2e; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #1e1e2e; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #45475a; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #585b70; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #1e1e2e; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #45475a; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #585b70; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #1e1e2e; - color: #cdd6f4; - border-bottom: 1px solid #313244; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #45475a; - color: #cdd6f4; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #585b70; + background-color: ${bg_active}; } QMenu { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #cba6f7; - color: #1e1e2e; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #6c7086; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #313244; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #1e1e2e; - color: #a6adc8; - border-top: 1px solid #313244; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #313244; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #cba6f7; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #313244; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #cba6f7; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #cba6f7; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #b4befe; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #313244; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #cba6f7; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #313244; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #cba6f7; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #cdd6f4; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #313244; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #cba6f7; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #cba6f7; - border-color: #cba6f7; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #181825; - border-color: #313244; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #313244; - color: #cdd6f4; - border: 1px solid #45475a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #1e1e2e; - alternate-background-color: #181825; - color: #cdd6f4; - border: 1px solid #313244; - selection-background-color: #cba6f7; - selection-color: #1e1e2e; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #45475a; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #cba6f7; - color: #1e1e2e; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #313244; - color: #cdd6f4; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #313244; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #45475a; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #313244; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #313244; - color: #a6adc8; - border: 1px solid #313244; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #1e1e2e; - color: #cdd6f4; - border-color: #45475a; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #45475a; - color: #cdd6f4; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #cdd6f4; - border: 1px solid #313244; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #a6adc8; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #313244; - color: #313244; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #1e1e2e; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #313244; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #cdd6f4; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #313244; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #313244; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #cba6f7; - border: 1px solid #cba6f7; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #f9e2af; - qproperty-tagCharacterColor: #a6e3a1; - qproperty-tagCopyrightColor: #cba6f7; - qproperty-tagSpeciesColor: #f38ba8; - qproperty-tagMetaColor: #a6adc8; - qproperty-tagLoreColor: #a6adc8; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; } diff --git a/themes/everforest.qss b/themes/everforest.qss index be5ceea..bd17985 100644 --- a/themes/everforest.qss +++ b/themes/everforest.qss @@ -1,41 +1,46 @@ /* booru-viewer — Everforest Dark * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #2d353b - * bg_alt #232a2e - * bg_subtle #343f44 - * bg_hover #3d484d - * bg_active #4f585e - * text #d3c6aa - * text_dim #9da9a0 - * text_disabled #7a8478 - * border #343f44 - * border_strong #3d484d - * accent #a7c080 - * accent_text #2d353b - * accent_dim #83c092 - * link #7fbbb3 - * danger #e67e80 - * success #a7c080 - * warning #dbbc7f + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #2d353b + bg_alt: #232a2e + bg_subtle: #343f44 + bg_hover: #3d484d + bg_active: #4f585e + text: #d3c6aa + text_dim: #9da9a0 + text_disabled: #7a8478 + border: #343f44 + border_strong: #3d484d + accent: #a7c080 + accent_text: #2d353b + accent_dim: #83c092 + link: #7fbbb3 + danger: #e67e80 + success: #a7c080 + warning: #dbbc7f + overlay_bg: rgba(45, 53, 59, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #2d353b; - color: #d3c6aa; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #a7c080; - selection-color: #2d353b; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #7a8478; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #2d353b; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #3d484d; - border-color: #a7c080; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #4f585e; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #a7c080; - color: #2d353b; - border-color: #a7c080; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #83c092; - border-color: #83c092; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #232a2e; - color: #7a8478; - border-color: #343f44; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #3d484d; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #d3c6aa; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #3d484d; - border-color: #3d484d; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #4f585e; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #a7c080; - selection-color: #2d353b; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #a7c080; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #232a2e; - color: #7a8478; - border-color: #343f44; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #a7c080; + border-color: ${accent}; } QComboBox:focus { - border-color: #a7c080; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; - selection-background-color: #a7c080; - selection-color: #2d353b; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #2d353b; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #3d484d; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #4f585e; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #2d353b; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #3d484d; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #4f585e; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #2d353b; - color: #d3c6aa; - border-bottom: 1px solid #343f44; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #3d484d; - color: #d3c6aa; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #4f585e; + background-color: ${bg_active}; } QMenu { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #a7c080; - color: #2d353b; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #7a8478; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #343f44; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #2d353b; - color: #9da9a0; - border-top: 1px solid #343f44; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #343f44; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #a7c080; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #343f44; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #a7c080; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #a7c080; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #83c092; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #343f44; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #a7c080; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #343f44; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #a7c080; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #d3c6aa; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #343f44; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #a7c080; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #a7c080; - border-color: #a7c080; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #232a2e; - border-color: #343f44; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #343f44; - color: #d3c6aa; - border: 1px solid #3d484d; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #2d353b; - alternate-background-color: #232a2e; - color: #d3c6aa; - border: 1px solid #343f44; - selection-background-color: #a7c080; - selection-color: #2d353b; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #3d484d; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #a7c080; - color: #2d353b; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #343f44; - color: #d3c6aa; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #343f44; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #3d484d; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #343f44; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #343f44; - color: #9da9a0; - border: 1px solid #343f44; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #2d353b; - color: #d3c6aa; - border-color: #3d484d; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #3d484d; - color: #d3c6aa; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #d3c6aa; - border: 1px solid #343f44; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #9da9a0; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #343f44; - color: #343f44; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #2d353b; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #343f44; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #d3c6aa; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #343f44; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #343f44; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #a7c080; - border: 1px solid #a7c080; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #dbbc7f; - qproperty-tagCharacterColor: #a7c080; - qproperty-tagCopyrightColor: #a7c080; - qproperty-tagSpeciesColor: #e67e80; - qproperty-tagMetaColor: #9da9a0; - qproperty-tagLoreColor: #9da9a0; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; } diff --git a/themes/gruvbox.qss b/themes/gruvbox.qss index 915b11a..cbda47a 100644 --- a/themes/gruvbox.qss +++ b/themes/gruvbox.qss @@ -1,41 +1,46 @@ /* booru-viewer — Gruvbox Dark * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #282828 - * bg_alt #1d2021 - * bg_subtle #3c3836 - * bg_hover #504945 - * bg_active #665c54 - * text #ebdbb2 - * text_dim #d5c4a1 - * text_disabled #928374 - * border #3c3836 - * border_strong #504945 - * accent #d79921 - * accent_text #282828 - * accent_dim #fabd2f - * link #83a598 - * danger #fb4934 - * success #b8bb26 - * warning #fabd2f + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #282828 + bg_alt: #1d2021 + bg_subtle: #3c3836 + bg_hover: #504945 + bg_active: #665c54 + text: #ebdbb2 + text_dim: #d5c4a1 + text_disabled: #928374 + border: #3c3836 + border_strong: #504945 + accent: #d79921 + accent_text: #282828 + accent_dim: #fabd2f + link: #83a598 + danger: #fb4934 + success: #b8bb26 + warning: #fabd2f + overlay_bg: rgba(40, 40, 40, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #282828; - color: #ebdbb2; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #d79921; - selection-color: #282828; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #928374; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #282828; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #504945; - border-color: #d79921; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #665c54; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #d79921; - color: #282828; - border-color: #d79921; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #fabd2f; - border-color: #fabd2f; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #1d2021; - color: #928374; - border-color: #3c3836; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #504945; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #ebdbb2; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #504945; - border-color: #504945; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #665c54; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #d79921; - selection-color: #282828; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #d79921; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #1d2021; - color: #928374; - border-color: #3c3836; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #d79921; + border-color: ${accent}; } QComboBox:focus { - border-color: #d79921; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; - selection-background-color: #d79921; - selection-color: #282828; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #282828; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #504945; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #665c54; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #282828; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #504945; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #665c54; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #282828; - color: #ebdbb2; - border-bottom: 1px solid #3c3836; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #504945; - color: #ebdbb2; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #665c54; + background-color: ${bg_active}; } QMenu { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #d79921; - color: #282828; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #928374; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #3c3836; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #282828; - color: #d5c4a1; - border-top: 1px solid #3c3836; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #3c3836; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #d79921; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #3c3836; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #d79921; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #d79921; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #fabd2f; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #3c3836; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #d79921; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #3c3836; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #d79921; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #ebdbb2; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #3c3836; - border: 1px solid #504945; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #d79921; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #d79921; - border-color: #d79921; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #1d2021; - border-color: #3c3836; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #3c3836; - color: #ebdbb2; - border: 1px solid #504945; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #282828; - alternate-background-color: #1d2021; - color: #ebdbb2; - border: 1px solid #3c3836; - selection-background-color: #d79921; - selection-color: #282828; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #504945; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #d79921; - color: #282828; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #3c3836; - color: #ebdbb2; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #3c3836; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #504945; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #3c3836; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #3c3836; - color: #d5c4a1; - border: 1px solid #3c3836; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #282828; - color: #ebdbb2; - border-color: #504945; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #504945; - color: #ebdbb2; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #ebdbb2; - border: 1px solid #3c3836; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #d5c4a1; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #3c3836; - color: #3c3836; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #282828; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #3c3836; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #ebdbb2; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #3c3836; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #3c3836; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #d79921; - border: 1px solid #d79921; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #fabd2f; - qproperty-tagCharacterColor: #b8bb26; - qproperty-tagCopyrightColor: #d79921; - qproperty-tagSpeciesColor: #fb4934; - qproperty-tagMetaColor: #d5c4a1; - qproperty-tagLoreColor: #d5c4a1; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; } diff --git a/themes/nord.qss b/themes/nord.qss index bc65a1f..7826993 100644 --- a/themes/nord.qss +++ b/themes/nord.qss @@ -1,41 +1,46 @@ /* booru-viewer — Nord * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #2e3440 - * bg_alt #272b36 - * bg_subtle #3b4252 - * bg_hover #434c5e - * bg_active #4c566a - * text #eceff4 - * text_dim #d8dee9 - * text_disabled #4c566a - * border #3b4252 - * border_strong #4c566a - * accent #88c0d0 - * accent_text #2e3440 - * accent_dim #81a1c1 - * link #8fbcbb - * danger #bf616a - * success #a3be8c - * warning #ebcb8b + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #2e3440 + bg_alt: #272b36 + bg_subtle: #3b4252 + bg_hover: #434c5e + bg_active: #4c566a + text: #eceff4 + text_dim: #d8dee9 + text_disabled: #4c566a + border: #3b4252 + border_strong: #4c566a + accent: #88c0d0 + accent_text: #2e3440 + accent_dim: #81a1c1 + link: #8fbcbb + danger: #bf616a + success: #a3be8c + warning: #ebcb8b + overlay_bg: rgba(46, 52, 64, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #2e3440; - color: #eceff4; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #88c0d0; - selection-color: #2e3440; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #4c566a; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #2e3440; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #434c5e; - border-color: #88c0d0; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #4c566a; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #88c0d0; - color: #2e3440; - border-color: #88c0d0; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #81a1c1; - border-color: #81a1c1; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #272b36; - color: #4c566a; - border-color: #3b4252; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #434c5e; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #eceff4; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #434c5e; - border-color: #4c566a; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #4c566a; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #88c0d0; - selection-color: #2e3440; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #88c0d0; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #272b36; - color: #4c566a; - border-color: #3b4252; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #88c0d0; + border-color: ${accent}; } QComboBox:focus { - border-color: #88c0d0; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; - selection-background-color: #88c0d0; - selection-color: #2e3440; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #2e3440; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #434c5e; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #4c566a; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #2e3440; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #434c5e; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #4c566a; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #2e3440; - color: #eceff4; - border-bottom: 1px solid #3b4252; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #434c5e; - color: #eceff4; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #4c566a; + background-color: ${bg_active}; } QMenu { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #88c0d0; - color: #2e3440; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #4c566a; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #3b4252; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #2e3440; - color: #d8dee9; - border-top: 1px solid #3b4252; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #3b4252; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #88c0d0; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #3b4252; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #88c0d0; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #88c0d0; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #81a1c1; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #3b4252; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #88c0d0; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #3b4252; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #88c0d0; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #eceff4; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #3b4252; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #88c0d0; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #88c0d0; - border-color: #88c0d0; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #272b36; - border-color: #3b4252; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #3b4252; - color: #eceff4; - border: 1px solid #4c566a; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #2e3440; - alternate-background-color: #272b36; - color: #eceff4; - border: 1px solid #3b4252; - selection-background-color: #88c0d0; - selection-color: #2e3440; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #434c5e; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #88c0d0; - color: #2e3440; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #3b4252; - color: #eceff4; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #3b4252; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #434c5e; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #3b4252; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #3b4252; - color: #d8dee9; - border: 1px solid #3b4252; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #2e3440; - color: #eceff4; - border-color: #4c566a; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #434c5e; - color: #eceff4; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #eceff4; - border: 1px solid #3b4252; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #d8dee9; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #3b4252; - color: #3b4252; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #2e3440; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #3b4252; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #eceff4; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #3b4252; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #3b4252; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #88c0d0; - border: 1px solid #88c0d0; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #ebcb8b; - qproperty-tagCharacterColor: #a3be8c; - qproperty-tagCopyrightColor: #88c0d0; - qproperty-tagSpeciesColor: #bf616a; - qproperty-tagMetaColor: #d8dee9; - qproperty-tagLoreColor: #d8dee9; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; } diff --git a/themes/solarized-dark.qss b/themes/solarized-dark.qss index 5ae94e9..7b80b60 100644 --- a/themes/solarized-dark.qss +++ b/themes/solarized-dark.qss @@ -1,41 +1,46 @@ /* booru-viewer — Solarized Dark * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #002b36 - * bg_alt #001f27 - * bg_subtle #073642 - * bg_hover #0d4654 - * bg_active #586e75 - * text #93a1a1 - * text_dim #839496 - * text_disabled #586e75 - * border #073642 - * border_strong #0d4654 - * accent #268bd2 - * accent_text #002b36 - * accent_dim #2aa198 - * link #2aa198 - * danger #dc322f - * success #859900 - * warning #b58900 + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #002b36 + bg_alt: #001f27 + bg_subtle: #073642 + bg_hover: #0d4654 + bg_active: #586e75 + text: #93a1a1 + text_dim: #839496 + text_disabled: #586e75 + border: #073642 + border_strong: #0d4654 + accent: #268bd2 + accent_text: #002b36 + accent_dim: #2aa198 + link: #2aa198 + danger: #dc322f + success: #859900 + warning: #b58900 + overlay_bg: rgba(0, 43, 54, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #002b36; - color: #93a1a1; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #268bd2; - selection-color: #002b36; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #586e75; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #002b36; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #0d4654; - border-color: #268bd2; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #586e75; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #268bd2; - color: #002b36; - border-color: #268bd2; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #2aa198; - border-color: #2aa198; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #001f27; - color: #586e75; - border-color: #073642; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #0d4654; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #93a1a1; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #0d4654; - border-color: #0d4654; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #586e75; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #268bd2; - selection-color: #002b36; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #268bd2; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #001f27; - color: #586e75; - border-color: #073642; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #268bd2; + border-color: ${accent}; } QComboBox:focus { - border-color: #268bd2; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; - selection-background-color: #268bd2; - selection-color: #002b36; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #002b36; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #0d4654; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #586e75; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #002b36; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #0d4654; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #586e75; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #002b36; - color: #93a1a1; - border-bottom: 1px solid #073642; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #0d4654; - color: #93a1a1; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #586e75; + background-color: ${bg_active}; } QMenu { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #268bd2; - color: #002b36; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #586e75; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #073642; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #002b36; - color: #839496; - border-top: 1px solid #073642; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #073642; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #268bd2; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #073642; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #268bd2; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #268bd2; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #2aa198; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #073642; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #268bd2; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #073642; - color: #93a1a1; - border: 1px solid #073642; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #268bd2; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #93a1a1; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #073642; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #268bd2; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #268bd2; - border-color: #268bd2; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #001f27; - border-color: #073642; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #073642; - color: #93a1a1; - border: 1px solid #0d4654; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #002b36; - alternate-background-color: #001f27; - color: #93a1a1; - border: 1px solid #073642; - selection-background-color: #268bd2; - selection-color: #002b36; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #0d4654; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #268bd2; - color: #002b36; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #073642; - color: #93a1a1; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #073642; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #0d4654; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #073642; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #073642; - color: #839496; - border: 1px solid #073642; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #002b36; - color: #93a1a1; - border-color: #0d4654; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #0d4654; - color: #93a1a1; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #93a1a1; - border: 1px solid #073642; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #839496; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #073642; - color: #073642; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #002b36; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #073642; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #93a1a1; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #073642; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #073642; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #268bd2; - border: 1px solid #268bd2; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #b58900; - qproperty-tagCharacterColor: #859900; - qproperty-tagCopyrightColor: #268bd2; - qproperty-tagSpeciesColor: #dc322f; - qproperty-tagMetaColor: #839496; - qproperty-tagLoreColor: #839496; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; } diff --git a/themes/tokyo-night.qss b/themes/tokyo-night.qss index e1d59e5..84b1d56 100644 --- a/themes/tokyo-night.qss +++ b/themes/tokyo-night.qss @@ -1,41 +1,46 @@ /* booru-viewer — Tokyo Night * - * Comprehensive Fusion-style QSS. Mimics the visual feel of Qt's Fusion - * style + a dark KDE color scheme: subtle borders, modest corner radius, - * clear hover/pressed/focus states, transparent labels. + * Edit the @palette block below to recolor this theme. The body uses + * ${...} placeholders that the app's _load_user_qss preprocessor + * substitutes at load time. See themes/README.md for the full list of + * placeholder names and what each one is used for. * - * Palette (edit these and the rest of the file together if you fork): - * bg #1a1b26 - * bg_alt #16161e - * bg_subtle #24283b - * bg_hover #292e42 - * bg_active #3b4261 - * text #c0caf5 - * text_dim #a9b1d6 - * text_disabled #565f89 - * border #24283b - * border_strong #292e42 - * accent #7aa2f7 - * accent_text #1a1b26 - * accent_dim #7dcfff - * link #7dcfff - * danger #f7768e - * success #9ece6a - * warning #e0af68 + * The same dialect works in any custom.qss you put in your data dir. */ +/* @palette + bg: #1a1b26 + bg_alt: #16161e + bg_subtle: #24283b + bg_hover: #292e42 + bg_active: #3b4261 + text: #c0caf5 + text_dim: #a9b1d6 + text_disabled: #565f89 + border: #24283b + border_strong: #292e42 + accent: #7aa2f7 + accent_text: #1a1b26 + accent_dim: #7dcfff + link: #7dcfff + danger: #f7768e + success: #9ece6a + warning: #e0af68 + overlay_bg: rgba(26, 27, 38, 200) +*/ + /* ---------- Base ---------- */ QWidget { - background-color: #1a1b26; - color: #c0caf5; + background-color: ${bg}; + color: ${text}; font-size: 13px; - selection-background-color: #7aa2f7; - selection-color: #1a1b26; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QWidget:disabled { - color: #565f89; + color: ${text_disabled}; } /* Labels should never paint an opaque background — they sit on top of @@ -45,115 +50,120 @@ QLabel { } QMainWindow, QDialog { - background-color: #1a1b26; + background-color: ${bg}; } /* ---------- Buttons ---------- */ QPushButton { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 5px 12px; min-height: 18px; } QPushButton:hover { - background-color: #292e42; - border-color: #7aa2f7; + background-color: ${bg_hover}; + border-color: ${accent}; } QPushButton:pressed { - background-color: #3b4261; + background-color: ${bg_active}; } QPushButton:checked { - background-color: #7aa2f7; - color: #1a1b26; - border-color: #7aa2f7; + background-color: ${accent}; + color: ${accent_text}; + border-color: ${accent}; } QPushButton:checked:hover { - background-color: #7dcfff; - border-color: #7dcfff; + background-color: ${accent_dim}; + border-color: ${accent_dim}; } QPushButton:disabled { - background-color: #16161e; - color: #565f89; - border-color: #24283b; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QPushButton:flat { background: transparent; border: none; } QPushButton:flat:hover { - background-color: #292e42; + background-color: ${bg_hover}; } QToolButton { background-color: transparent; - color: #c0caf5; + color: ${text}; border: 1px solid transparent; border-radius: 4px; padding: 4px; } QToolButton:hover { - background-color: #292e42; - border-color: #292e42; + background-color: ${bg_hover}; + border-color: ${border_strong}; } QToolButton:pressed, QToolButton:checked { - background-color: #3b4261; + background-color: ${bg_active}; } /* ---------- Inputs ---------- */ QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - selection-background-color: #7aa2f7; - selection-color: #1a1b26; + /* min-height ensures the painted text fits inside the widget bounds + * even when a parent layout (e.g. QFormLayout inside a QGroupBox) + * compresses the natural sizeHint. Without this, spinboxes in dense + * forms render with the top of the value text clipped. */ + min-height: 20px; + selection-background-color: ${accent}; + selection-color: ${accent_text}; } QLineEdit:focus, QSpinBox:focus, QDoubleSpinBox:focus, QTextEdit:focus, QPlainTextEdit:focus { - border-color: #7aa2f7; + border-color: ${accent}; } QLineEdit:disabled, QSpinBox:disabled, QDoubleSpinBox:disabled, QTextEdit:disabled, QPlainTextEdit:disabled { - background-color: #16161e; - color: #565f89; - border-color: #24283b; + background-color: ${bg_alt}; + color: ${text_disabled}; + border-color: ${border}; } QComboBox { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; border-radius: 4px; padding: 4px 8px; - min-height: 18px; + min-height: 20px; } QComboBox:hover { - border-color: #7aa2f7; + border-color: ${accent}; } QComboBox:focus { - border-color: #7aa2f7; + border-color: ${accent}; } QComboBox::drop-down { border: none; width: 18px; } QComboBox QAbstractItemView { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; - selection-background-color: #7aa2f7; - selection-color: #1a1b26; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; padding: 2px; } @@ -161,19 +171,19 @@ QComboBox QAbstractItemView { /* ---------- Scrollbars ---------- */ QScrollBar:vertical { - background: #1a1b26; + background: ${bg}; width: 10px; border: none; margin: 0; } QScrollBar::handle:vertical { - background: #292e42; + background: ${bg_hover}; border-radius: 4px; min-height: 24px; margin: 1px; } QScrollBar::handle:vertical:hover { - background: #3b4261; + background: ${bg_active}; } QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { @@ -186,19 +196,19 @@ QScrollBar::sub-page:vertical { } QScrollBar:horizontal { - background: #1a1b26; + background: ${bg}; height: 10px; border: none; margin: 0; } QScrollBar::handle:horizontal { - background: #292e42; + background: ${bg_hover}; border-radius: 4px; min-width: 24px; margin: 1px; } QScrollBar::handle:horizontal:hover { - background: #3b4261; + background: ${bg_active}; } QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal { @@ -218,26 +228,26 @@ QScrollArea { /* ---------- Menus ---------- */ QMenuBar { - background-color: #1a1b26; - color: #c0caf5; - border-bottom: 1px solid #24283b; + background-color: ${bg}; + color: ${text}; + border-bottom: 1px solid ${border}; } QMenuBar::item { background: transparent; padding: 4px 10px; } QMenuBar::item:selected { - background-color: #292e42; - color: #c0caf5; + background-color: ${bg_hover}; + color: ${text}; } QMenuBar::item:pressed { - background-color: #3b4261; + background-color: ${bg_active}; } QMenu { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 0; } QMenu::item { @@ -245,15 +255,15 @@ QMenu::item { padding: 5px 24px 5px 24px; } QMenu::item:selected { - background-color: #7aa2f7; - color: #1a1b26; + background-color: ${accent}; + color: ${accent_text}; } QMenu::item:disabled { - color: #565f89; + color: ${text_disabled}; } QMenu::separator { height: 1px; - background: #24283b; + background: ${border}; margin: 4px 8px; } QMenu::icon { @@ -263,9 +273,9 @@ QMenu::icon { /* ---------- Status bar ---------- */ QStatusBar { - background-color: #1a1b26; - color: #a9b1d6; - border-top: 1px solid #24283b; + background-color: ${bg}; + color: ${text_dim}; + border-top: 1px solid ${border}; } QStatusBar::item { border: none; @@ -274,7 +284,7 @@ QStatusBar::item { /* ---------- Splitters ---------- */ QSplitter::handle { - background: #24283b; + background: ${border}; } QSplitter::handle:horizontal { width: 2px; @@ -283,38 +293,35 @@ QSplitter::handle:vertical { height: 2px; } QSplitter::handle:hover { - background: #7aa2f7; + background: ${accent}; } /* ---------- Sliders ---------- */ QSlider::groove:horizontal { - background: #24283b; + background: ${bg_subtle}; height: 4px; - border-radius: 2px; } QSlider::sub-page:horizontal { - background: #7aa2f7; - border-radius: 2px; + background: ${accent}; } QSlider::handle:horizontal { - background: #7aa2f7; + background: ${accent}; width: 12px; height: 12px; margin: -5px 0; - border-radius: 6px; } QSlider::handle:horizontal:hover { - background: #7dcfff; + background: ${accent_dim}; } QSlider::groove:vertical { - background: #24283b; + background: ${bg_subtle}; width: 4px; border-radius: 2px; } QSlider::handle:vertical { - background: #7aa2f7; + background: ${accent}; width: 12px; height: 12px; margin: 0 -5px; @@ -324,15 +331,15 @@ QSlider::handle:vertical { /* ---------- Progress ---------- */ QProgressBar { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #24283b; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border}; border-radius: 3px; text-align: center; height: 6px; } QProgressBar::chunk { - background-color: #7aa2f7; + background-color: ${accent}; border-radius: 3px; } @@ -340,14 +347,14 @@ QProgressBar::chunk { QCheckBox, QRadioButton { background: transparent; - color: #c0caf5; + color: ${text}; spacing: 6px; } QCheckBox::indicator, QRadioButton::indicator { width: 14px; height: 14px; - background-color: #24283b; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + border: 1px solid ${border_strong}; } QCheckBox::indicator { border-radius: 3px; @@ -356,23 +363,23 @@ QRadioButton::indicator { border-radius: 7px; } QCheckBox::indicator:hover, QRadioButton::indicator:hover { - border-color: #7aa2f7; + border-color: ${accent}; } QCheckBox::indicator:checked, QRadioButton::indicator:checked { - background-color: #7aa2f7; - border-color: #7aa2f7; + background-color: ${accent}; + border-color: ${accent}; } QCheckBox::indicator:disabled, QRadioButton::indicator:disabled { - background-color: #16161e; - border-color: #24283b; + background-color: ${bg_alt}; + border-color: ${border}; } /* ---------- Tooltips ---------- */ QToolTip { - background-color: #24283b; - color: #c0caf5; - border: 1px solid #292e42; + background-color: ${bg_subtle}; + color: ${text}; + border: 1px solid ${border_strong}; padding: 4px 6px; border-radius: 3px; } @@ -380,12 +387,12 @@ QToolTip { /* ---------- Item views (lists, trees, tables) ---------- */ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget { - background-color: #1a1b26; - alternate-background-color: #16161e; - color: #c0caf5; - border: 1px solid #24283b; - selection-background-color: #7aa2f7; - selection-color: #1a1b26; + background-color: ${bg}; + alternate-background-color: ${bg_alt}; + color: ${text}; + border: 1px solid ${border}; + selection-background-color: ${accent}; + selection-color: ${accent_text}; outline: none; } QListView::item, QListWidget::item, @@ -396,57 +403,57 @@ QTableView::item, QTableWidget::item { QListView::item:hover, QListWidget::item:hover, QTreeView::item:hover, QTreeWidget::item:hover, QTableView::item:hover, QTableWidget::item:hover { - background-color: #292e42; + background-color: ${bg_hover}; } QListView::item:selected, QListWidget::item:selected, QTreeView::item:selected, QTreeWidget::item:selected, QTableView::item:selected, QTableWidget::item:selected { - background-color: #7aa2f7; - color: #1a1b26; + background-color: ${accent}; + color: ${accent_text}; } QHeaderView::section { - background-color: #24283b; - color: #c0caf5; + background-color: ${bg_subtle}; + color: ${text}; border: none; - border-right: 1px solid #24283b; + border-right: 1px solid ${border}; padding: 4px 8px; } QHeaderView::section:hover { - background-color: #292e42; + background-color: ${bg_hover}; } /* ---------- Tabs ---------- */ QTabWidget::pane { - border: 1px solid #24283b; + border: 1px solid ${border}; top: -1px; } QTabBar::tab { - background: #24283b; - color: #a9b1d6; - border: 1px solid #24283b; + background: ${bg_subtle}; + color: ${text_dim}; + border: 1px solid ${border}; border-bottom: none; padding: 6px 14px; border-top-left-radius: 4px; border-top-right-radius: 4px; } QTabBar::tab:selected { - background: #1a1b26; - color: #c0caf5; - border-color: #292e42; + background: ${bg}; + color: ${text}; + border-color: ${border_strong}; } QTabBar::tab:hover:!selected { - background: #292e42; - color: #c0caf5; + background: ${bg_hover}; + color: ${text}; } /* ---------- Group boxes ---------- */ QGroupBox { background: transparent; - color: #c0caf5; - border: 1px solid #24283b; + color: ${text}; + border: 1px solid ${border}; border-radius: 4px; margin-top: 10px; padding-top: 8px; @@ -455,27 +462,27 @@ QGroupBox::title { subcontrol-origin: margin; subcontrol-position: top left; padding: 0 6px; - color: #a9b1d6; + color: ${text_dim}; } /* ---------- Frames ---------- */ QFrame[frameShape="4"], /* HLine */ QFrame[frameShape="5"] /* VLine */ { - background: #24283b; - color: #24283b; + background: ${border}; + color: ${border}; } /* ---------- Toolbars ---------- */ QToolBar { - background: #1a1b26; + background: ${bg}; border: none; spacing: 4px; padding: 2px; } QToolBar::separator { - background: #24283b; + background: ${border}; width: 1px; margin: 4px 4px; } @@ -483,31 +490,25 @@ QToolBar::separator { /* ---------- Dock widgets ---------- */ QDockWidget { - color: #c0caf5; + color: ${text}; titlebar-close-icon: none; } QDockWidget::title { - background: #24283b; + background: ${bg_subtle}; padding: 4px; - border: 1px solid #24283b; + border: 1px solid ${border}; } /* ---------- Rubber band (multi-select drag rectangle) ---------- */ QRubberBand { - background: #7aa2f7; - border: 1px solid #7aa2f7; + background: ${accent}; + border: 1px solid ${accent}; /* Qt blends rubber band at ~30% so this reads as a translucent * accent-tinted rectangle without needing rgba(). */ } -/* ---------- Popout & preview overlay controls ---------- */ -QWidget#_preview_controls, -QWidget#_slideshow_toolbar, -QWidget#_slideshow_controls { - background: rgba(0, 0, 0, 160); -} /* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */ @@ -519,10 +520,78 @@ ThumbnailWidget { /* ---------- Info panel tag category colors ---------- */ InfoPanel { - qproperty-tagArtistColor: #e0af68; - qproperty-tagCharacterColor: #9ece6a; - qproperty-tagCopyrightColor: #7aa2f7; - qproperty-tagSpeciesColor: #f7768e; - qproperty-tagMetaColor: #a9b1d6; - qproperty-tagLoreColor: #a9b1d6; + qproperty-tagArtistColor: ${warning}; + qproperty-tagCharacterColor: ${success}; + qproperty-tagCopyrightColor: ${accent}; + qproperty-tagSpeciesColor: ${danger}; + qproperty-tagMetaColor: ${text_dim}; + qproperty-tagLoreColor: ${text_dim}; +} + +/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */ + +VideoPlayer { + qproperty-letterboxColor: ${bg}; +} + +/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */ +/* + * The popout window's translucent toolbar (top) and transport controls + * (bottom) float over the video content. The bg color comes from the + * @palette overlay_bg slot. Children get the classic overlay treatment: + * transparent backgrounds, near-white text, hairline borders. + */ + +QWidget#_slideshow_toolbar, +QWidget#_slideshow_controls, +QWidget#_preview_controls { + background: ${overlay_bg}; +} + +QWidget#_slideshow_toolbar *, +QWidget#_slideshow_controls *, +QWidget#_preview_controls * { + background: transparent; + color: white; + border: none; +} + +QWidget#_slideshow_toolbar QPushButton, +QWidget#_slideshow_controls QPushButton, +QWidget#_preview_controls QPushButton { + background: transparent; + color: white; + border: 1px solid rgba(255, 255, 255, 80); + padding: 2px 6px; +} +QWidget#_slideshow_toolbar QPushButton:hover, +QWidget#_slideshow_controls QPushButton:hover, +QWidget#_preview_controls QPushButton:hover { + background: rgba(255, 255, 255, 30); +} + +QWidget#_slideshow_toolbar QSlider::groove:horizontal, +QWidget#_slideshow_controls QSlider::groove:horizontal, +QWidget#_preview_controls QSlider::groove:horizontal { + background: rgba(255, 255, 255, 40); + height: 4px; +} +QWidget#_slideshow_toolbar QSlider::handle:horizontal, +QWidget#_slideshow_controls QSlider::handle:horizontal, +QWidget#_preview_controls QSlider::handle:horizontal { + background: ${accent}; + width: 10px; + margin: -4px 0; +} +QWidget#_slideshow_toolbar QSlider::sub-page:horizontal, +QWidget#_slideshow_controls QSlider::sub-page:horizontal, +QWidget#_preview_controls QSlider::sub-page:horizontal { + background: ${accent}; +} + +QWidget#_slideshow_toolbar QLabel, +QWidget#_slideshow_controls QLabel, +QWidget#_preview_controls QLabel { + background: transparent; + color: white; }