UI overhaul: icon buttons, video controls, popout anchor, layout flip, compact top bar
- Preview/popout toolbar: icon buttons (☆/★, ↓/✕, ⊘, ⊗, ⧉) with QSS object names (#_tb_bookmark, #_tb_save, etc.) for theme targeting - Video controls: QPainter-drawn icons for play/pause, volume/mute; text labels for loop/once/next and autoplay - Popout anchor setting: resize pivot (center/tl/tr/bl/br) controls which corner stays fixed on aspect change, works on all platforms - Hyprland monitor reserved areas: reads waybar exclusive zones from hyprctl monitors -j for correct edge positioning - Layout flip setting: swap grid and preview sides - Compact top bar: AdjustToContents combos, tighter spacing, named containers (#_top_bar, #_nav_bar) for QSS targeting - Reduced main window minimum size from 900x600 to 740x400 - Trimmed bundled QSS: removed 12 unused widget selectors, added popout overlay font-weight/size, regenerated all 12 theme files - Updated themes/README.md with icon button reference
This commit is contained in:
parent
d7b3c304d7
commit
93459dfff6
@ -119,6 +119,8 @@ QWidget#_slideshow_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover {
|
QWidget#_slideshow_controls QPushButton:hover {
|
||||||
|
|||||||
@ -63,7 +63,7 @@ class BooruApp(QMainWindow):
|
|||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.setWindowTitle("booru-viewer")
|
self.setWindowTitle("booru-viewer")
|
||||||
self.setMinimumSize(900, 600)
|
self.setMinimumSize(740, 400)
|
||||||
self.resize(1200, 800)
|
self.resize(1200, 800)
|
||||||
|
|
||||||
self._db = Database()
|
self._db = Database()
|
||||||
@ -224,17 +224,22 @@ class BooruApp(QMainWindow):
|
|||||||
layout.setSpacing(6)
|
layout.setSpacing(6)
|
||||||
|
|
||||||
# Top bar: site selector + rating + search
|
# Top bar: site selector + rating + search
|
||||||
top = QHBoxLayout()
|
_top_bar = QWidget()
|
||||||
|
_top_bar.setObjectName("_top_bar")
|
||||||
|
top = QHBoxLayout(_top_bar)
|
||||||
|
top.setContentsMargins(0, 0, 0, 0)
|
||||||
|
top.setSpacing(3)
|
||||||
|
|
||||||
self._site_combo = QComboBox()
|
self._site_combo = QComboBox()
|
||||||
self._site_combo.setMinimumWidth(150)
|
self._site_combo.setMinimumWidth(80)
|
||||||
|
self._site_combo.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
|
||||||
self._site_combo.currentIndexChanged.connect(self._on_site_changed)
|
self._site_combo.currentIndexChanged.connect(self._on_site_changed)
|
||||||
top.addWidget(self._site_combo)
|
top.addWidget(self._site_combo)
|
||||||
|
|
||||||
# Rating filter
|
# Rating filter
|
||||||
self._rating_combo = QComboBox()
|
self._rating_combo = QComboBox()
|
||||||
self._rating_combo.addItems(["All", "General", "Sensitive", "Questionable", "Explicit"])
|
self._rating_combo.addItems(["All", "General", "Sensitive", "Questionable", "Explicit"])
|
||||||
self._rating_combo.setMinimumWidth(100)
|
self._rating_combo.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
|
||||||
self._rating_combo.currentTextChanged.connect(self._on_rating_changed)
|
self._rating_combo.currentTextChanged.connect(self._on_rating_changed)
|
||||||
top.addWidget(self._rating_combo)
|
top.addWidget(self._rating_combo)
|
||||||
|
|
||||||
@ -242,23 +247,17 @@ class BooruApp(QMainWindow):
|
|||||||
self._media_filter = QComboBox()
|
self._media_filter = QComboBox()
|
||||||
self._media_filter.addItems(["All", "Animated", "Video", "GIF", "Audio"])
|
self._media_filter.addItems(["All", "Animated", "Video", "GIF", "Audio"])
|
||||||
self._media_filter.setToolTip("Filter by media type")
|
self._media_filter.setToolTip("Filter by media type")
|
||||||
self._media_filter.setFixedWidth(90)
|
self._media_filter.setSizeAdjustPolicy(QComboBox.SizeAdjustPolicy.AdjustToContents)
|
||||||
top.addWidget(self._media_filter)
|
top.addWidget(self._media_filter)
|
||||||
|
|
||||||
# Score filter — type the value directly. Spinbox arrows hidden
|
# Score filter
|
||||||
# since the field is small enough to type into and the +/- buttons
|
score_label = QLabel("Score\u2265")
|
||||||
# were just visual noise. setFixedHeight(23) overrides Qt's
|
|
||||||
# QSpinBox sizeHint which still reserves vertical space for the
|
|
||||||
# arrow buttons internally even when `setButtonSymbols(NoButtons)`
|
|
||||||
# is set, leaving the spinbox 3px taller than the surrounding
|
|
||||||
# combos/inputs/buttons in the top toolbar (26 vs 23).
|
|
||||||
score_label = QLabel("Score≥")
|
|
||||||
top.addWidget(score_label)
|
top.addWidget(score_label)
|
||||||
self._score_spin = QSpinBox()
|
self._score_spin = QSpinBox()
|
||||||
self._score_spin.setRange(0, 99999)
|
self._score_spin.setRange(0, 99999)
|
||||||
self._score_spin.setValue(0)
|
self._score_spin.setValue(0)
|
||||||
self._score_spin.setFixedWidth(40)
|
self._score_spin.setFixedWidth(36)
|
||||||
self._score_spin.setFixedHeight(23)
|
self._score_spin.setFixedHeight(21)
|
||||||
self._score_spin.setButtonSymbols(QSpinBox.ButtonSymbols.NoButtons)
|
self._score_spin.setButtonSymbols(QSpinBox.ButtonSymbols.NoButtons)
|
||||||
top.addWidget(self._score_spin)
|
top.addWidget(self._score_spin)
|
||||||
|
|
||||||
@ -267,8 +266,8 @@ class BooruApp(QMainWindow):
|
|||||||
self._page_spin = QSpinBox()
|
self._page_spin = QSpinBox()
|
||||||
self._page_spin.setRange(1, 99999)
|
self._page_spin.setRange(1, 99999)
|
||||||
self._page_spin.setValue(1)
|
self._page_spin.setValue(1)
|
||||||
self._page_spin.setFixedWidth(40)
|
self._page_spin.setFixedWidth(36)
|
||||||
self._page_spin.setFixedHeight(23) # match the surrounding 23px row
|
self._page_spin.setFixedHeight(21)
|
||||||
self._page_spin.setButtonSymbols(QSpinBox.ButtonSymbols.NoButtons)
|
self._page_spin.setButtonSymbols(QSpinBox.ButtonSymbols.NoButtons)
|
||||||
top.addWidget(self._page_spin)
|
top.addWidget(self._page_spin)
|
||||||
|
|
||||||
@ -277,10 +276,15 @@ class BooruApp(QMainWindow):
|
|||||||
self._search_bar.autocomplete_requested.connect(self._search_ctrl.request_autocomplete)
|
self._search_bar.autocomplete_requested.connect(self._search_ctrl.request_autocomplete)
|
||||||
top.addWidget(self._search_bar, stretch=1)
|
top.addWidget(self._search_bar, stretch=1)
|
||||||
|
|
||||||
layout.addLayout(top)
|
layout.addWidget(_top_bar)
|
||||||
|
|
||||||
# Nav bar
|
# Nav bar
|
||||||
nav = QHBoxLayout()
|
_nav_bar = QWidget()
|
||||||
|
_nav_bar.setObjectName("_nav_bar")
|
||||||
|
nav = QHBoxLayout(_nav_bar)
|
||||||
|
nav.setContentsMargins(0, 0, 0, 0)
|
||||||
|
nav.setSpacing(3)
|
||||||
|
|
||||||
self._browse_btn = QPushButton("Browse")
|
self._browse_btn = QPushButton("Browse")
|
||||||
self._browse_btn.setCheckable(True)
|
self._browse_btn.setCheckable(True)
|
||||||
self._browse_btn.setChecked(True)
|
self._browse_btn.setChecked(True)
|
||||||
@ -294,11 +298,10 @@ class BooruApp(QMainWindow):
|
|||||||
|
|
||||||
self._library_btn = QPushButton("Library")
|
self._library_btn = QPushButton("Library")
|
||||||
self._library_btn.setCheckable(True)
|
self._library_btn.setCheckable(True)
|
||||||
self._library_btn.setFixedWidth(80)
|
|
||||||
self._library_btn.clicked.connect(lambda: self._switch_view(2))
|
self._library_btn.clicked.connect(lambda: self._switch_view(2))
|
||||||
nav.addWidget(self._library_btn)
|
nav.addWidget(self._library_btn)
|
||||||
|
|
||||||
layout.addLayout(nav)
|
layout.addWidget(_nav_bar)
|
||||||
|
|
||||||
# Main content
|
# Main content
|
||||||
self._splitter = QSplitter(Qt.Orientation.Horizontal)
|
self._splitter = QSplitter(Qt.Orientation.Horizontal)
|
||||||
@ -359,7 +362,7 @@ class BooruApp(QMainWindow):
|
|||||||
# BL Post, [stretch], Popout) has room to lay out all five buttons
|
# BL Post, [stretch], Popout) has room to lay out all five buttons
|
||||||
# at their fixed widths plus spacing without clipping the rightmost
|
# at their fixed widths plus spacing without clipping the rightmost
|
||||||
# one or compressing the row visually.
|
# one or compressing the row visually.
|
||||||
self._preview.setMinimumWidth(380)
|
self._preview.setMinimumWidth(200)
|
||||||
right.addWidget(self._preview)
|
right.addWidget(self._preview)
|
||||||
|
|
||||||
self._dl_progress = QProgressBar()
|
self._dl_progress = QProgressBar()
|
||||||
@ -405,6 +408,10 @@ class BooruApp(QMainWindow):
|
|||||||
|
|
||||||
self._splitter.addWidget(right)
|
self._splitter.addWidget(right)
|
||||||
|
|
||||||
|
# Flip layout: preview on the left, grid on the right
|
||||||
|
if self._db.get_setting_bool("flip_layout"):
|
||||||
|
self._splitter.insertWidget(0, right)
|
||||||
|
|
||||||
# Restore the persisted main-splitter sizes if present, otherwise
|
# Restore the persisted main-splitter sizes if present, otherwise
|
||||||
# fall back to the historic default. The sizes are saved as a
|
# fall back to the historic default. The sizes are saved as a
|
||||||
# comma-separated string in the settings table — same format as
|
# comma-separated string in the settings table — same format as
|
||||||
|
|||||||
@ -6,12 +6,91 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from PySide6.QtCore import Qt, QTimer, Signal, Property
|
from PySide6.QtCore import Qt, QTimer, Signal, Property, QPoint
|
||||||
from PySide6.QtGui import QColor
|
from PySide6.QtGui import QColor, QIcon, QPixmap, QPainter, QPen, QBrush, QPolygon, QPainterPath
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSlider, QStyle,
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSlider, QStyle,
|
||||||
|
QApplication,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _paint_icon(shape: str, color: QColor, size: int = 16) -> QIcon:
|
||||||
|
"""Paint a media control icon using the given color."""
|
||||||
|
pix = QPixmap(size, size)
|
||||||
|
pix.fill(Qt.GlobalColor.transparent)
|
||||||
|
p = QPainter(pix)
|
||||||
|
p.setRenderHint(QPainter.RenderHint.Antialiasing)
|
||||||
|
p.setPen(Qt.PenStyle.NoPen)
|
||||||
|
p.setBrush(color)
|
||||||
|
s = size
|
||||||
|
|
||||||
|
if shape == "play":
|
||||||
|
p.drawPolygon(QPolygon([QPoint(3, 2), QPoint(3, s - 2), QPoint(s - 2, s // 2)]))
|
||||||
|
|
||||||
|
elif shape == "pause":
|
||||||
|
w = max(2, s // 4)
|
||||||
|
p.drawRect(2, 2, w, s - 4)
|
||||||
|
p.drawRect(s - 2 - w, 2, w, s - 4)
|
||||||
|
|
||||||
|
elif shape == "volume":
|
||||||
|
# Speaker cone
|
||||||
|
p.drawPolygon(QPolygon([
|
||||||
|
QPoint(1, s // 2 - 2), QPoint(4, s // 2 - 2),
|
||||||
|
QPoint(8, 2), QPoint(8, s - 2),
|
||||||
|
QPoint(4, s // 2 + 2), QPoint(1, s // 2 + 2),
|
||||||
|
]))
|
||||||
|
# Sound waves
|
||||||
|
p.setPen(QPen(color, 1.5))
|
||||||
|
p.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
path = QPainterPath()
|
||||||
|
path.arcMoveTo(8, 3, 6, s - 6, 45)
|
||||||
|
path.arcTo(8, 3, 6, s - 6, 45, -90)
|
||||||
|
p.drawPath(path)
|
||||||
|
|
||||||
|
elif shape == "muted":
|
||||||
|
p.drawPolygon(QPolygon([
|
||||||
|
QPoint(1, s // 2 - 2), QPoint(4, s // 2 - 2),
|
||||||
|
QPoint(8, 2), QPoint(8, s - 2),
|
||||||
|
QPoint(4, s // 2 + 2), QPoint(1, s // 2 + 2),
|
||||||
|
]))
|
||||||
|
p.setPen(QPen(color, 2))
|
||||||
|
p.drawLine(10, 4, s - 2, s - 4)
|
||||||
|
p.drawLine(10, s - 4, s - 2, 4)
|
||||||
|
|
||||||
|
elif shape == "loop":
|
||||||
|
p.setPen(QPen(color, 1.5))
|
||||||
|
p.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
path = QPainterPath()
|
||||||
|
path.arcMoveTo(2, 2, s - 4, s - 4, 30)
|
||||||
|
path.arcTo(2, 2, s - 4, s - 4, 30, 300)
|
||||||
|
p.drawPath(path)
|
||||||
|
# Arrowhead
|
||||||
|
p.setPen(Qt.PenStyle.NoPen)
|
||||||
|
p.setBrush(color)
|
||||||
|
end = path.currentPosition().toPoint()
|
||||||
|
p.drawPolygon(QPolygon([
|
||||||
|
end, QPoint(end.x() - 4, end.y() - 3), QPoint(end.x() + 1, end.y() - 4),
|
||||||
|
]))
|
||||||
|
|
||||||
|
elif shape == "once":
|
||||||
|
p.setPen(QPen(color, 2))
|
||||||
|
p.setBrush(Qt.BrushStyle.NoBrush)
|
||||||
|
mid = s // 2
|
||||||
|
p.drawLine(mid, 3, mid, s - 3)
|
||||||
|
p.drawLine(mid - 2, 5, mid, 3)
|
||||||
|
|
||||||
|
elif shape == "next":
|
||||||
|
p.drawPolygon(QPolygon([QPoint(2, 2), QPoint(2, s - 2), QPoint(s - 5, s // 2)]))
|
||||||
|
p.drawRect(s - 4, 2, 2, s - 4)
|
||||||
|
|
||||||
|
elif shape == "auto":
|
||||||
|
mid = s // 2
|
||||||
|
p.drawPolygon(QPolygon([QPoint(1, 3), QPoint(1, s - 3), QPoint(mid - 1, s // 2)]))
|
||||||
|
p.drawPolygon(QPolygon([QPoint(mid, 3), QPoint(mid, s - 3), QPoint(s - 2, s // 2)]))
|
||||||
|
|
||||||
|
p.end()
|
||||||
|
return QIcon(pix)
|
||||||
|
|
||||||
import mpv as mpvlib
|
import mpv as mpvlib
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -119,15 +198,22 @@ class VideoPlayer(QWidget):
|
|||||||
controls = QHBoxLayout(self._controls_bar)
|
controls = QHBoxLayout(self._controls_bar)
|
||||||
controls.setContentsMargins(4, 2, 4, 2)
|
controls.setContentsMargins(4, 2, 4, 2)
|
||||||
|
|
||||||
# Compact-padding override matches the top preview toolbar so the
|
_btn_sz = 24
|
||||||
# bottom controls bar reads as part of the same panel rather than
|
_fg = self.palette().buttonText().color()
|
||||||
# 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: 2px 6px;"
|
|
||||||
|
|
||||||
self._play_btn = QPushButton("Play")
|
def _icon_btn(shape: str, name: str, tip: str) -> QPushButton:
|
||||||
self._play_btn.setMaximumWidth(65)
|
btn = QPushButton()
|
||||||
self._play_btn.setStyleSheet(_ctrl_btn_style)
|
btn.setObjectName(name)
|
||||||
|
btn.setIcon(_paint_icon(shape, _fg))
|
||||||
|
btn.setFixedSize(_btn_sz, _btn_sz)
|
||||||
|
btn.setToolTip(tip)
|
||||||
|
return btn
|
||||||
|
|
||||||
|
self._icon_fg = _fg
|
||||||
|
self._play_icon = _paint_icon("play", _fg)
|
||||||
|
self._pause_icon = _paint_icon("pause", _fg)
|
||||||
|
|
||||||
|
self._play_btn = _icon_btn("play", "_ctrl_play", "Play / Pause (Space)")
|
||||||
self._play_btn.clicked.connect(self._toggle_play)
|
self._play_btn.clicked.connect(self._toggle_play)
|
||||||
controls.addWidget(self._play_btn)
|
controls.addWidget(self._play_btn)
|
||||||
|
|
||||||
@ -152,28 +238,29 @@ class VideoPlayer(QWidget):
|
|||||||
self._vol_slider.valueChanged.connect(self._set_volume)
|
self._vol_slider.valueChanged.connect(self._set_volume)
|
||||||
controls.addWidget(self._vol_slider)
|
controls.addWidget(self._vol_slider)
|
||||||
|
|
||||||
self._mute_btn = QPushButton("Mute")
|
self._vol_icon = _paint_icon("volume", _fg)
|
||||||
self._mute_btn.setMaximumWidth(80)
|
self._muted_icon = _paint_icon("muted", _fg)
|
||||||
self._mute_btn.setStyleSheet(_ctrl_btn_style)
|
|
||||||
|
self._mute_btn = _icon_btn("volume", "_ctrl_mute", "Mute / Unmute")
|
||||||
self._mute_btn.clicked.connect(self._toggle_mute)
|
self._mute_btn.clicked.connect(self._toggle_mute)
|
||||||
controls.addWidget(self._mute_btn)
|
controls.addWidget(self._mute_btn)
|
||||||
|
|
||||||
self._autoplay = True
|
self._autoplay = True
|
||||||
self._autoplay_btn = QPushButton("Auto")
|
self._auto_icon = _paint_icon("auto", _fg)
|
||||||
self._autoplay_btn.setMaximumWidth(70)
|
self._autoplay_btn = _icon_btn("auto", "_ctrl_autoplay", "Auto-play videos when selected")
|
||||||
self._autoplay_btn.setStyleSheet(_ctrl_btn_style)
|
|
||||||
self._autoplay_btn.setCheckable(True)
|
self._autoplay_btn.setCheckable(True)
|
||||||
self._autoplay_btn.setChecked(True)
|
self._autoplay_btn.setChecked(True)
|
||||||
self._autoplay_btn.setToolTip("Auto-play videos when selected")
|
|
||||||
self._autoplay_btn.clicked.connect(self._toggle_autoplay)
|
self._autoplay_btn.clicked.connect(self._toggle_autoplay)
|
||||||
self._autoplay_btn.hide()
|
self._autoplay_btn.hide()
|
||||||
controls.addWidget(self._autoplay_btn)
|
controls.addWidget(self._autoplay_btn)
|
||||||
|
|
||||||
|
self._loop_icons = {
|
||||||
|
0: _paint_icon("loop", _fg),
|
||||||
|
1: _paint_icon("once", _fg),
|
||||||
|
2: _paint_icon("next", _fg),
|
||||||
|
}
|
||||||
self._loop_state = 0 # 0=Loop, 1=Once, 2=Next
|
self._loop_state = 0 # 0=Loop, 1=Once, 2=Next
|
||||||
self._loop_btn = QPushButton("Loop")
|
self._loop_btn = _icon_btn("loop", "_ctrl_loop", "Loop / Once / Next")
|
||||||
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)
|
self._loop_btn.clicked.connect(self._cycle_loop)
|
||||||
controls.addWidget(self._loop_btn)
|
controls.addWidget(self._loop_btn)
|
||||||
|
|
||||||
@ -295,7 +382,7 @@ class VideoPlayer(QWidget):
|
|||||||
self._pending_mute = val
|
self._pending_mute = val
|
||||||
if self._mpv:
|
if self._mpv:
|
||||||
self._mpv.mute = val
|
self._mpv.mute = val
|
||||||
self._mute_btn.setText("Unmute" if val else "Mute")
|
self._mute_btn.setIcon(self._muted_icon if val else self._vol_icon)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def autoplay(self) -> bool:
|
def autoplay(self) -> bool:
|
||||||
@ -314,8 +401,9 @@ class VideoPlayer(QWidget):
|
|||||||
@loop_state.setter
|
@loop_state.setter
|
||||||
def loop_state(self, val: int) -> None:
|
def loop_state(self, val: int) -> None:
|
||||||
self._loop_state = val
|
self._loop_state = val
|
||||||
labels = ["Loop", "Once", "Next"]
|
tips = ["Loop: repeat", "Once: stop at end", "Next: advance"]
|
||||||
self._loop_btn.setText(labels[val])
|
self._loop_btn.setIcon(self._loop_icons[val])
|
||||||
|
self._loop_btn.setToolTip(tips[val])
|
||||||
self._autoplay_btn.setVisible(val == 2)
|
self._autoplay_btn.setVisible(val == 2)
|
||||||
self._apply_loop_to_mpv()
|
self._apply_loop_to_mpv()
|
||||||
|
|
||||||
@ -386,7 +474,7 @@ class VideoPlayer(QWidget):
|
|||||||
m.pause = False
|
m.pause = False
|
||||||
else:
|
else:
|
||||||
m.pause = True
|
m.pause = True
|
||||||
self._play_btn.setText("Pause" if not m.pause else "Play")
|
self._play_btn.setIcon(self._pause_icon if not m.pause else self._play_icon)
|
||||||
self._poll_timer.start()
|
self._poll_timer.start()
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
@ -397,17 +485,17 @@ class VideoPlayer(QWidget):
|
|||||||
self._time_label.setText("0:00")
|
self._time_label.setText("0:00")
|
||||||
self._duration_label.setText("0:00")
|
self._duration_label.setText("0:00")
|
||||||
self._seek_slider.setRange(0, 0)
|
self._seek_slider.setRange(0, 0)
|
||||||
self._play_btn.setText("Play")
|
self._play_btn.setIcon(self._play_icon)
|
||||||
|
|
||||||
def pause(self) -> None:
|
def pause(self) -> None:
|
||||||
if self._mpv:
|
if self._mpv:
|
||||||
self._mpv.pause = True
|
self._mpv.pause = True
|
||||||
self._play_btn.setText("Play")
|
self._play_btn.setIcon(self._play_icon)
|
||||||
|
|
||||||
def resume(self) -> None:
|
def resume(self) -> None:
|
||||||
if self._mpv:
|
if self._mpv:
|
||||||
self._mpv.pause = False
|
self._mpv.pause = False
|
||||||
self._play_btn.setText("Pause")
|
self._play_btn.setIcon(self._pause_icon)
|
||||||
|
|
||||||
# -- Internal controls --
|
# -- Internal controls --
|
||||||
|
|
||||||
@ -415,11 +503,12 @@ class VideoPlayer(QWidget):
|
|||||||
if not self._mpv:
|
if not self._mpv:
|
||||||
return
|
return
|
||||||
self._mpv.pause = not self._mpv.pause
|
self._mpv.pause = not self._mpv.pause
|
||||||
self._play_btn.setText("Play" if self._mpv.pause else "Pause")
|
self._play_btn.setIcon(self._play_icon if self._mpv.pause else self._pause_icon)
|
||||||
|
|
||||||
def _toggle_autoplay(self, checked: bool = True) -> None:
|
def _toggle_autoplay(self, checked: bool = True) -> None:
|
||||||
self._autoplay = self._autoplay_btn.isChecked()
|
self._autoplay = self._autoplay_btn.isChecked()
|
||||||
self._autoplay_btn.setText("Autoplay" if self._autoplay else "Manual")
|
self._autoplay_btn.setIcon(self._auto_icon if self._autoplay else self._play_icon)
|
||||||
|
self._autoplay_btn.setToolTip("Autoplay on" if self._autoplay else "Autoplay off")
|
||||||
|
|
||||||
def _cycle_loop(self) -> None:
|
def _cycle_loop(self) -> None:
|
||||||
self.loop_state = (self._loop_state + 1) % 3
|
self.loop_state = (self._loop_state + 1) % 3
|
||||||
@ -463,7 +552,7 @@ class VideoPlayer(QWidget):
|
|||||||
if self._mpv:
|
if self._mpv:
|
||||||
self._mpv.mute = not self._mpv.mute
|
self._mpv.mute = not self._mpv.mute
|
||||||
self._pending_mute = bool(self._mpv.mute)
|
self._pending_mute = bool(self._mpv.mute)
|
||||||
self._mute_btn.setText("Unmute" if self._mpv.mute else "Mute")
|
self._mute_btn.setIcon(self._muted_icon if self._mpv.mute else self._vol_icon)
|
||||||
|
|
||||||
# -- mpv callbacks (called from mpv thread) --
|
# -- mpv callbacks (called from mpv thread) --
|
||||||
|
|
||||||
@ -528,9 +617,9 @@ class VideoPlayer(QWidget):
|
|||||||
|
|
||||||
# Pause state
|
# Pause state
|
||||||
paused = self._mpv.pause
|
paused = self._mpv.pause
|
||||||
expected_text = "Play" if paused else "Pause"
|
expected_icon = self._play_icon if paused else self._pause_icon
|
||||||
if self._play_btn.text() != expected_text:
|
if self._play_btn.icon().cacheKey() != expected_icon.cacheKey():
|
||||||
self._play_btn.setText(expected_text)
|
self._play_btn.setIcon(expected_icon)
|
||||||
|
|
||||||
# Video size (set by observer on mpv thread, emitted here on main thread)
|
# Video size (set by observer on mpv thread, emitted here on main thread)
|
||||||
if self._pending_video_size is not None:
|
if self._pending_video_size is not None:
|
||||||
|
|||||||
@ -171,8 +171,48 @@ def _dispatch_batch(cmds: list[str]) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def get_monitor_available_rect(monitor_id: int | None = None) -> tuple[int, int, int, int] | None:
|
||||||
|
"""Return (x, y, w, h) of a monitor's usable area, accounting for
|
||||||
|
exclusive zones (Waybar, etc.) via the ``reserved`` field.
|
||||||
|
|
||||||
|
Falls back to the first monitor if *monitor_id* is None or not found.
|
||||||
|
Returns None if not on Hyprland or the query fails.
|
||||||
|
"""
|
||||||
|
if not _on_hyprland():
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
result = subprocess.run(
|
||||||
|
["hyprctl", "monitors", "-j"],
|
||||||
|
capture_output=True, text=True, timeout=1,
|
||||||
|
)
|
||||||
|
monitors = json.loads(result.stdout)
|
||||||
|
if not monitors:
|
||||||
|
return None
|
||||||
|
mon = None
|
||||||
|
if monitor_id is not None:
|
||||||
|
mon = next((m for m in monitors if m.get("id") == monitor_id), None)
|
||||||
|
if mon is None:
|
||||||
|
mon = monitors[0]
|
||||||
|
mx = mon.get("x", 0)
|
||||||
|
my = mon.get("y", 0)
|
||||||
|
mw = mon.get("width", 0)
|
||||||
|
mh = mon.get("height", 0)
|
||||||
|
# reserved: [left, top, right, bottom]
|
||||||
|
res = mon.get("reserved", [0, 0, 0, 0])
|
||||||
|
left, top, right, bottom = res[0], res[1], res[2], res[3]
|
||||||
|
return (
|
||||||
|
mx + left,
|
||||||
|
my + top,
|
||||||
|
mw - left - right,
|
||||||
|
mh - top - bottom,
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"get_window",
|
"get_window",
|
||||||
|
"get_monitor_available_rect",
|
||||||
"resize",
|
"resize",
|
||||||
"resize_and_move",
|
"resize_and_move",
|
||||||
]
|
]
|
||||||
|
|||||||
@ -8,19 +8,45 @@ from typing import NamedTuple
|
|||||||
class Viewport(NamedTuple):
|
class Viewport(NamedTuple):
|
||||||
"""Where and how large the user wants popout content to appear.
|
"""Where and how large the user wants popout content to appear.
|
||||||
|
|
||||||
Three numbers, no aspect. Aspect is a property of the currently-
|
Three numbers + an anchor mode, no aspect. Aspect is a property of
|
||||||
displayed post and is recomputed from actual content on every
|
the currently-displayed post and is recomputed from actual content
|
||||||
navigation. The viewport stays put across navigations; the window
|
on every navigation. The viewport stays put across navigations; the
|
||||||
rect is a derived projection (Viewport, content_aspect) → (x,y,w,h).
|
window rect is a derived projection (Viewport, content_aspect) →
|
||||||
|
(x,y,w,h).
|
||||||
|
|
||||||
`long_side` is the binding edge length: for landscape it becomes
|
`long_side` is the binding edge length: for landscape it becomes
|
||||||
width, for portrait it becomes height. Symmetric across the two
|
width, for portrait it becomes height. Symmetric across the two
|
||||||
orientations, which is the property that breaks the
|
orientations, which is the property that breaks the
|
||||||
width-anchor ratchet that the previous `_fit_to_content` had.
|
width-anchor ratchet that the previous `_fit_to_content` had.
|
||||||
|
|
||||||
|
`anchor` controls which point of the window stays fixed across
|
||||||
|
navigations as the window size changes with aspect ratio:
|
||||||
|
``"center"`` (default) pins the window center; ``"tl"``/``"tr"``/
|
||||||
|
``"bl"``/``"br"`` pin the corresponding corner. The window
|
||||||
|
grows/shrinks away from the anchored corner. The user can drag the
|
||||||
|
window anywhere — the anchor only affects resize direction, not
|
||||||
|
screen position.
|
||||||
|
|
||||||
|
`center_x`/`center_y` hold the anchor point coordinates (center
|
||||||
|
of the window in center mode, the pinned corner in corner modes).
|
||||||
"""
|
"""
|
||||||
center_x: float
|
center_x: float
|
||||||
center_y: float
|
center_y: float
|
||||||
long_side: float
|
long_side: float
|
||||||
|
anchor: str = "center"
|
||||||
|
|
||||||
|
|
||||||
|
def anchor_point(x: float, y: float, w: float, h: float, anchor: str) -> tuple[float, float]:
|
||||||
|
"""Extract the anchor point from a window rect based on anchor mode."""
|
||||||
|
if anchor == "tl":
|
||||||
|
return (x, y)
|
||||||
|
if anchor == "tr":
|
||||||
|
return (x + w, y)
|
||||||
|
if anchor == "bl":
|
||||||
|
return (x, y + h)
|
||||||
|
if anchor == "br":
|
||||||
|
return (x + w, y + h)
|
||||||
|
return (x + w / 2, y + h / 2)
|
||||||
|
|
||||||
|
|
||||||
# Maximum drift between our last-dispatched window rect and the current
|
# Maximum drift between our last-dispatched window rect and the current
|
||||||
|
|||||||
@ -54,7 +54,7 @@ from .state import (
|
|||||||
WindowMoved,
|
WindowMoved,
|
||||||
WindowResized,
|
WindowResized,
|
||||||
)
|
)
|
||||||
from .viewport import Viewport, _DRIFT_TOLERANCE
|
from .viewport import Viewport, _DRIFT_TOLERANCE, anchor_point
|
||||||
|
|
||||||
|
|
||||||
# Adapter logger — separate from the popout's main `booru` logger so
|
# Adapter logger — separate from the popout's main `booru` logger so
|
||||||
@ -121,10 +121,11 @@ class FullscreenPreview(QMainWindow):
|
|||||||
privacy_requested = Signal()
|
privacy_requested = Signal()
|
||||||
closed = Signal()
|
closed = Signal()
|
||||||
|
|
||||||
def __init__(self, grid_cols: int = 3, show_actions: bool = True, monitor: str = "", parent=None) -> None:
|
def __init__(self, grid_cols: int = 3, show_actions: bool = True, monitor: str = "", anchor: str = "center", parent=None) -> None:
|
||||||
super().__init__(parent, Qt.WindowType.Window)
|
super().__init__(parent, Qt.WindowType.Window)
|
||||||
self.setWindowTitle("booru-viewer — Popout")
|
self.setWindowTitle("booru-viewer — Popout")
|
||||||
self._grid_cols = grid_cols
|
self._grid_cols = grid_cols
|
||||||
|
self._anchor = anchor
|
||||||
|
|
||||||
# Central widget — media fills the entire window
|
# Central widget — media fills the entire window
|
||||||
central = QWidget()
|
central = QWidget()
|
||||||
@ -181,10 +182,6 @@ class FullscreenPreview(QMainWindow):
|
|||||||
toolbar.setContentsMargins(8, 4, 8, 4)
|
toolbar.setContentsMargins(8, 4, 8, 4)
|
||||||
|
|
||||||
# Same compact-padding override as the embedded preview toolbar —
|
# 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: 2px 6px;"
|
|
||||||
|
|
||||||
# Bookmark folders for the popout's Bookmark-as submenu — wired
|
# Bookmark folders for the popout's Bookmark-as submenu — wired
|
||||||
# by app.py via set_bookmark_folders_callback after construction.
|
# by app.py via set_bookmark_folders_callback after construction.
|
||||||
self._bookmark_folders_callback = None
|
self._bookmark_folders_callback = None
|
||||||
@ -195,30 +192,29 @@ class FullscreenPreview(QMainWindow):
|
|||||||
# are independent name spaces and need separate callbacks.
|
# are independent name spaces and need separate callbacks.
|
||||||
self._folders_callback = None
|
self._folders_callback = None
|
||||||
|
|
||||||
self._bookmark_btn = QPushButton("Bookmark")
|
_tb_sz = 24
|
||||||
self._bookmark_btn.setMaximumWidth(90)
|
|
||||||
self._bookmark_btn.setStyleSheet(_tb_btn_style)
|
def _icon_btn(text: str, name: str, tip: str) -> QPushButton:
|
||||||
|
btn = QPushButton(text)
|
||||||
|
btn.setObjectName(name)
|
||||||
|
btn.setFixedSize(_tb_sz, _tb_sz)
|
||||||
|
btn.setToolTip(tip)
|
||||||
|
return btn
|
||||||
|
|
||||||
|
self._bookmark_btn = _icon_btn("\u2606", "_tb_bookmark", "Bookmark (B)")
|
||||||
self._bookmark_btn.clicked.connect(self._on_bookmark_clicked)
|
self._bookmark_btn.clicked.connect(self._on_bookmark_clicked)
|
||||||
toolbar.addWidget(self._bookmark_btn)
|
toolbar.addWidget(self._bookmark_btn)
|
||||||
|
|
||||||
self._save_btn = QPushButton("Save")
|
self._save_btn = _icon_btn("\u2193", "_tb_save", "Save to library (S)")
|
||||||
self._save_btn.setMaximumWidth(70)
|
|
||||||
self._save_btn.setStyleSheet(_tb_btn_style)
|
|
||||||
self._save_btn.clicked.connect(self._on_save_clicked)
|
self._save_btn.clicked.connect(self._on_save_clicked)
|
||||||
toolbar.addWidget(self._save_btn)
|
toolbar.addWidget(self._save_btn)
|
||||||
self._is_saved = False
|
self._is_saved = False
|
||||||
|
|
||||||
self._bl_tag_btn = QPushButton("BL Tag")
|
self._bl_tag_btn = _icon_btn("\u2298", "_tb_bl_tag", "Blacklist a tag")
|
||||||
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)
|
self._bl_tag_btn.clicked.connect(self._show_bl_tag_menu)
|
||||||
toolbar.addWidget(self._bl_tag_btn)
|
toolbar.addWidget(self._bl_tag_btn)
|
||||||
|
|
||||||
self._bl_post_btn = QPushButton("BL Post")
|
self._bl_post_btn = _icon_btn("\u2297", "_tb_bl_post", "Blacklist this post")
|
||||||
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)
|
self._bl_post_btn.clicked.connect(self.blacklist_post_requested)
|
||||||
toolbar.addWidget(self._bl_post_btn)
|
toolbar.addWidget(self._bl_post_btn)
|
||||||
|
|
||||||
@ -642,10 +638,11 @@ class FullscreenPreview(QMainWindow):
|
|||||||
|
|
||||||
def update_state(self, bookmarked: bool, saved: bool) -> None:
|
def update_state(self, bookmarked: bool, saved: bool) -> None:
|
||||||
self._is_bookmarked = bookmarked
|
self._is_bookmarked = bookmarked
|
||||||
self._bookmark_btn.setText("Unbookmark" if bookmarked else "Bookmark")
|
self._bookmark_btn.setText("\u2605" if bookmarked else "\u2606") # ★ / ☆
|
||||||
self._bookmark_btn.setMaximumWidth(90 if bookmarked else 80)
|
self._bookmark_btn.setToolTip("Unbookmark (B)" if bookmarked else "Bookmark (B)")
|
||||||
self._is_saved = saved
|
self._is_saved = saved
|
||||||
self._save_btn.setText("Unsave" if saved else "Save")
|
self._save_btn.setText("\u2715" if saved else "\u2193") # ✕ / ⤓
|
||||||
|
self._save_btn.setToolTip("Unsave from library" if saved else "Save to library (S)")
|
||||||
|
|
||||||
# ------------------------------------------------------------------
|
# ------------------------------------------------------------------
|
||||||
# Public method interface (commit 15)
|
# Public method interface (commit 15)
|
||||||
@ -1054,7 +1051,8 @@ class FullscreenPreview(QMainWindow):
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _compute_window_rect(
|
def _compute_window_rect(
|
||||||
viewport: Viewport, content_aspect: float, screen
|
viewport: Viewport, content_aspect: float, screen,
|
||||||
|
avail_override: tuple[int, int, int, int] | None = None,
|
||||||
) -> tuple[int, int, int, int]:
|
) -> tuple[int, int, int, int]:
|
||||||
"""Project a viewport onto a window rect for the given content aspect.
|
"""Project a viewport onto a window rect for the given content aspect.
|
||||||
|
|
||||||
@ -1064,6 +1062,16 @@ class FullscreenPreview(QMainWindow):
|
|||||||
if either would exceed its 0.90-of-screen ceiling, preserving
|
if either would exceed its 0.90-of-screen ceiling, preserving
|
||||||
aspect exactly. Pure function — no side effects, no widget
|
aspect exactly. Pure function — no side effects, no widget
|
||||||
access, all inputs explicit so it's trivial to reason about.
|
access, all inputs explicit so it's trivial to reason about.
|
||||||
|
|
||||||
|
``viewport.center_x``/``center_y`` hold the anchor point — the
|
||||||
|
window center in ``"center"`` mode, or the pinned corner in
|
||||||
|
corner modes. The anchor stays fixed; the window grows/shrinks
|
||||||
|
away from it.
|
||||||
|
|
||||||
|
*avail_override* is an (x, y, w, h) tuple that replaces
|
||||||
|
``screen.availableGeometry()`` — used on Hyprland where Qt
|
||||||
|
doesn't see Waybar's exclusive zone but ``hyprctl monitors -j``
|
||||||
|
reports it via the ``reserved`` array.
|
||||||
"""
|
"""
|
||||||
if content_aspect >= 1.0: # landscape or square
|
if content_aspect >= 1.0: # landscape or square
|
||||||
w = viewport.long_side
|
w = viewport.long_side
|
||||||
@ -1072,19 +1080,37 @@ class FullscreenPreview(QMainWindow):
|
|||||||
h = viewport.long_side
|
h = viewport.long_side
|
||||||
w = viewport.long_side * content_aspect
|
w = viewport.long_side * content_aspect
|
||||||
|
|
||||||
avail = screen.availableGeometry()
|
if avail_override:
|
||||||
cap_w = avail.width() * 0.90
|
ax, ay, aw, ah = avail_override
|
||||||
cap_h = avail.height() * 0.90
|
else:
|
||||||
|
_a = screen.availableGeometry()
|
||||||
|
ax, ay, aw, ah = _a.x(), _a.y(), _a.width(), _a.height()
|
||||||
|
cap_w = aw * 0.90
|
||||||
|
cap_h = ah * 0.90
|
||||||
scale = min(1.0, cap_w / w, cap_h / h)
|
scale = min(1.0, cap_w / w, cap_h / h)
|
||||||
w *= scale
|
w *= scale
|
||||||
h *= scale
|
h *= scale
|
||||||
|
|
||||||
x = viewport.center_x - w / 2
|
anchor = viewport.anchor
|
||||||
y = viewport.center_y - h / 2
|
if anchor == "tl":
|
||||||
|
x = viewport.center_x
|
||||||
|
y = viewport.center_y
|
||||||
|
elif anchor == "tr":
|
||||||
|
x = viewport.center_x - w
|
||||||
|
y = viewport.center_y
|
||||||
|
elif anchor == "bl":
|
||||||
|
x = viewport.center_x
|
||||||
|
y = viewport.center_y - h
|
||||||
|
elif anchor == "br":
|
||||||
|
x = viewport.center_x - w
|
||||||
|
y = viewport.center_y - h
|
||||||
|
else:
|
||||||
|
x = viewport.center_x - w / 2
|
||||||
|
y = viewport.center_y - h / 2
|
||||||
|
|
||||||
# Nudge onto screen if the projected rect would land off-edge.
|
# Nudge onto screen if the window would land off-edge.
|
||||||
x = max(avail.x(), min(x, avail.right() - w))
|
x = max(ax, min(x, ax + aw - w))
|
||||||
y = max(avail.y(), min(y, avail.bottom() - h))
|
y = max(ay, min(y, ay + ah - h))
|
||||||
|
|
||||||
return (round(x), round(y), round(w), round(h))
|
return (round(x), round(y), round(w), round(h))
|
||||||
|
|
||||||
@ -1110,18 +1136,20 @@ class FullscreenPreview(QMainWindow):
|
|||||||
if win and win.get("at") and win.get("size"):
|
if win and win.get("at") and win.get("size"):
|
||||||
wx, wy = win["at"]
|
wx, wy = win["at"]
|
||||||
ww, wh = win["size"]
|
ww, wh = win["size"]
|
||||||
|
ax, ay = anchor_point(wx, wy, ww, wh, self._anchor)
|
||||||
return Viewport(
|
return Viewport(
|
||||||
center_x=wx + ww / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=wy + wh / 2,
|
|
||||||
long_side=float(max(ww, wh)),
|
long_side=float(max(ww, wh)),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
if floating is None:
|
if floating is None:
|
||||||
rect = self.geometry()
|
rect = self.geometry()
|
||||||
if rect.width() > 0 and rect.height() > 0:
|
if rect.width() > 0 and rect.height() > 0:
|
||||||
|
ax, ay = anchor_point(rect.x(), rect.y(), rect.width(), rect.height(), self._anchor)
|
||||||
return Viewport(
|
return Viewport(
|
||||||
center_x=rect.x() + rect.width() / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=rect.y() + rect.height() / 2,
|
|
||||||
long_side=float(max(rect.width(), rect.height())),
|
long_side=float(max(rect.width(), rect.height())),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@ -1162,10 +1190,11 @@ class FullscreenPreview(QMainWindow):
|
|||||||
if self._first_fit_pending and self._pending_size and self._pending_position_restore:
|
if self._first_fit_pending and self._pending_size and self._pending_position_restore:
|
||||||
pw, ph = self._pending_size
|
pw, ph = self._pending_size
|
||||||
px, py = self._pending_position_restore
|
px, py = self._pending_position_restore
|
||||||
|
ax, ay = anchor_point(px, py, pw, ph, self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=px + pw / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=py + ph / 2,
|
|
||||||
long_side=float(max(pw, ph)),
|
long_side=float(max(pw, ph)),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
return self._viewport
|
return self._viewport
|
||||||
|
|
||||||
@ -1192,10 +1221,11 @@ class FullscreenPreview(QMainWindow):
|
|||||||
)
|
)
|
||||||
if drift > _DRIFT_TOLERANCE:
|
if drift > _DRIFT_TOLERANCE:
|
||||||
# External move/resize detected. Adopt current as intent.
|
# External move/resize detected. Adopt current as intent.
|
||||||
|
ax, ay = anchor_point(cur_x, cur_y, cur_w, cur_h, self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=cur_x + cur_w / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=cur_y + cur_h / 2,
|
|
||||||
long_side=float(max(cur_w, cur_h)),
|
long_side=float(max(cur_w, cur_h)),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
|
|
||||||
return self._viewport
|
return self._viewport
|
||||||
@ -1260,7 +1290,10 @@ class FullscreenPreview(QMainWindow):
|
|||||||
# the one-shots would lose the saved position; leaving them
|
# the one-shots would lose the saved position; leaving them
|
||||||
# set lets a subsequent fit retry.
|
# set lets a subsequent fit retry.
|
||||||
return
|
return
|
||||||
x, y, w, h = self._compute_window_rect(viewport, aspect, screen)
|
avail_rect = None
|
||||||
|
if on_hypr and win:
|
||||||
|
avail_rect = hyprland.get_monitor_available_rect(win.get("monitor"))
|
||||||
|
x, y, w, h = self._compute_window_rect(viewport, aspect, screen, avail_override=avail_rect)
|
||||||
# Identical-rect skip. If the computed rect is exactly what
|
# Identical-rect skip. If the computed rect is exactly what
|
||||||
# we last dispatched, the window is already in that state and
|
# we last dispatched, the window is already in that state and
|
||||||
# there's nothing for hyprctl (or setGeometry) to do. Skipping
|
# there's nothing for hyprctl (or setGeometry) to do. Skipping
|
||||||
@ -1472,19 +1505,21 @@ class FullscreenPreview(QMainWindow):
|
|||||||
x, y = win["at"]
|
x, y = win["at"]
|
||||||
w, h = win["size"]
|
w, h = win["size"]
|
||||||
self._windowed_geometry = QRect(x, y, w, h)
|
self._windowed_geometry = QRect(x, y, w, h)
|
||||||
|
ax, ay = anchor_point(x, y, w, h, self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=x + w / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=y + h / 2,
|
|
||||||
long_side=float(max(w, h)),
|
long_side=float(max(w, h)),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._windowed_geometry = self.frameGeometry()
|
self._windowed_geometry = self.frameGeometry()
|
||||||
rect = self._windowed_geometry
|
rect = self._windowed_geometry
|
||||||
if rect.width() > 0 and rect.height() > 0:
|
if rect.width() > 0 and rect.height() > 0:
|
||||||
|
ax, ay = anchor_point(rect.x(), rect.y(), rect.width(), rect.height(), self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=rect.x() + rect.width() / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=rect.y() + rect.height() / 2,
|
|
||||||
long_side=float(max(rect.width(), rect.height())),
|
long_side=float(max(rect.width(), rect.height())),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
self.showFullScreen()
|
self.showFullScreen()
|
||||||
|
|
||||||
@ -1581,10 +1616,11 @@ class FullscreenPreview(QMainWindow):
|
|||||||
return
|
return
|
||||||
rect = self.geometry()
|
rect = self.geometry()
|
||||||
if rect.width() > 0 and rect.height() > 0:
|
if rect.width() > 0 and rect.height() > 0:
|
||||||
|
ax, ay = anchor_point(rect.x(), rect.y(), rect.width(), rect.height(), self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=rect.x() + rect.width() / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=rect.y() + rect.height() / 2,
|
|
||||||
long_side=float(max(rect.width(), rect.height())),
|
long_side=float(max(rect.width(), rect.height())),
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
# Parallel state machine dispatch for the same event.
|
# Parallel state machine dispatch for the same event.
|
||||||
self._dispatch_and_apply(WindowResized(rect=(
|
self._dispatch_and_apply(WindowResized(rect=(
|
||||||
@ -1611,11 +1647,12 @@ class FullscreenPreview(QMainWindow):
|
|||||||
rect = self.geometry()
|
rect = self.geometry()
|
||||||
if rect.width() > 0 and rect.height() > 0:
|
if rect.width() > 0 and rect.height() > 0:
|
||||||
# Move-only update: keep the existing long_side, just
|
# Move-only update: keep the existing long_side, just
|
||||||
# update the center to where the window now sits.
|
# update the anchor point to where the window now sits.
|
||||||
|
ax, ay = anchor_point(rect.x(), rect.y(), rect.width(), rect.height(), self._anchor)
|
||||||
self._viewport = Viewport(
|
self._viewport = Viewport(
|
||||||
center_x=rect.x() + rect.width() / 2,
|
center_x=ax, center_y=ay,
|
||||||
center_y=rect.y() + rect.height() / 2,
|
|
||||||
long_side=self._viewport.long_side,
|
long_side=self._viewport.long_side,
|
||||||
|
anchor=self._anchor,
|
||||||
)
|
)
|
||||||
# Parallel state machine dispatch for the same event.
|
# Parallel state machine dispatch for the same event.
|
||||||
self._dispatch_and_apply(WindowMoved(rect=(
|
self._dispatch_and_apply(WindowMoved(rect=(
|
||||||
|
|||||||
@ -90,7 +90,8 @@ class PopoutController:
|
|||||||
cols = self._app._grid._flow.columns
|
cols = self._app._grid._flow.columns
|
||||||
show_actions = self._app._stack.currentIndex() != 2
|
show_actions = self._app._stack.currentIndex() != 2
|
||||||
monitor = self._app._db.get_setting("slideshow_monitor")
|
monitor = self._app._db.get_setting("slideshow_monitor")
|
||||||
self._fullscreen_window = FullscreenPreview(grid_cols=cols, show_actions=show_actions, monitor=monitor, parent=self._app)
|
anchor = self._app._db.get_setting("popout_anchor") or "center"
|
||||||
|
self._fullscreen_window = FullscreenPreview(grid_cols=cols, show_actions=show_actions, monitor=monitor, anchor=anchor, parent=self._app)
|
||||||
self._fullscreen_window.navigate.connect(self.navigate)
|
self._fullscreen_window.navigate.connect(self.navigate)
|
||||||
self._fullscreen_window.play_next_requested.connect(self._app._on_video_end_next)
|
self._fullscreen_window.play_next_requested.connect(self._app._on_video_end_next)
|
||||||
from ..core.config import library_folders
|
from ..core.config import library_folders
|
||||||
|
|||||||
@ -64,50 +64,34 @@ class ImagePreview(QWidget):
|
|||||||
tb.setContentsMargins(4, 1, 4, 1)
|
tb.setContentsMargins(4, 1, 4, 1)
|
||||||
tb.setSpacing(4)
|
tb.setSpacing(4)
|
||||||
|
|
||||||
# Compact toolbar buttons. The bundled themes set
|
_tb_sz = 24
|
||||||
# `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: 2px 6px;"
|
|
||||||
|
|
||||||
self._bookmark_btn = QPushButton("Bookmark")
|
def _icon_btn(text: str, name: str, tip: str) -> QPushButton:
|
||||||
self._bookmark_btn.setFixedWidth(100)
|
btn = QPushButton(text)
|
||||||
self._bookmark_btn.setStyleSheet(_tb_btn_style)
|
btn.setObjectName(name)
|
||||||
|
btn.setFixedSize(_tb_sz, _tb_sz)
|
||||||
|
btn.setToolTip(tip)
|
||||||
|
return btn
|
||||||
|
|
||||||
|
self._bookmark_btn = _icon_btn("\u2606", "_tb_bookmark", "Bookmark (B)")
|
||||||
self._bookmark_btn.clicked.connect(self._on_bookmark_clicked)
|
self._bookmark_btn.clicked.connect(self._on_bookmark_clicked)
|
||||||
tb.addWidget(self._bookmark_btn)
|
tb.addWidget(self._bookmark_btn)
|
||||||
|
|
||||||
self._save_btn = QPushButton("Save")
|
self._save_btn = _icon_btn("\u2193", "_tb_save", "Save to library (S)")
|
||||||
# 75 fits "Unsave" (6 chars) cleanly across every bundled theme.
|
|
||||||
# The previous 60 was tight enough that some themes clipped the
|
|
||||||
# last character on library files where the label flips to Unsave.
|
|
||||||
self._save_btn.setFixedWidth(75)
|
|
||||||
self._save_btn.setStyleSheet(_tb_btn_style)
|
|
||||||
self._save_btn.clicked.connect(self._on_save_clicked)
|
self._save_btn.clicked.connect(self._on_save_clicked)
|
||||||
tb.addWidget(self._save_btn)
|
tb.addWidget(self._save_btn)
|
||||||
|
|
||||||
self._bl_tag_btn = QPushButton("BL Tag")
|
self._bl_tag_btn = _icon_btn("\u2298", "_tb_bl_tag", "Blacklist a tag")
|
||||||
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)
|
self._bl_tag_btn.clicked.connect(self._show_bl_tag_menu)
|
||||||
tb.addWidget(self._bl_tag_btn)
|
tb.addWidget(self._bl_tag_btn)
|
||||||
|
|
||||||
self._bl_post_btn = QPushButton("BL Post")
|
self._bl_post_btn = _icon_btn("\u2297", "_tb_bl_post", "Blacklist this post")
|
||||||
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)
|
self._bl_post_btn.clicked.connect(self.blacklist_post_requested)
|
||||||
tb.addWidget(self._bl_post_btn)
|
tb.addWidget(self._bl_post_btn)
|
||||||
|
|
||||||
tb.addStretch()
|
tb.addStretch()
|
||||||
|
|
||||||
self._popout_btn = QPushButton("Popout")
|
self._popout_btn = _icon_btn("\u29c9", "_tb_popout", "Popout")
|
||||||
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)
|
self._popout_btn.clicked.connect(self.fullscreen_requested)
|
||||||
tb.addWidget(self._popout_btn)
|
tb.addWidget(self._popout_btn)
|
||||||
|
|
||||||
@ -239,12 +223,13 @@ class ImagePreview(QWidget):
|
|||||||
|
|
||||||
def update_bookmark_state(self, bookmarked: bool) -> None:
|
def update_bookmark_state(self, bookmarked: bool) -> None:
|
||||||
self._is_bookmarked = bookmarked
|
self._is_bookmarked = bookmarked
|
||||||
self._bookmark_btn.setText("Unbookmark" if bookmarked else "Bookmark")
|
self._bookmark_btn.setText("\u2605" if bookmarked else "\u2606") # ★ / ☆
|
||||||
self._bookmark_btn.setFixedWidth(90 if bookmarked else 80)
|
self._bookmark_btn.setToolTip("Unbookmark (B)" if bookmarked else "Bookmark (B)")
|
||||||
|
|
||||||
def update_save_state(self, saved: bool) -> None:
|
def update_save_state(self, saved: bool) -> None:
|
||||||
self._is_saved = saved
|
self._is_saved = saved
|
||||||
self._save_btn.setText("Unsave" if saved else "Save")
|
self._save_btn.setText("\u2715" if saved else "\u2193") # ✕ / ⤓
|
||||||
|
self._save_btn.setToolTip("Unsave from library" if saved else "Save to library (S)")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -197,6 +197,11 @@ class SettingsDialog(QDialog):
|
|||||||
self._search_history.setChecked(self._db.get_setting_bool("search_history_enabled"))
|
self._search_history.setChecked(self._db.get_setting_bool("search_history_enabled"))
|
||||||
form.addRow("", self._search_history)
|
form.addRow("", self._search_history)
|
||||||
|
|
||||||
|
# Flip layout
|
||||||
|
self._flip_layout = QCheckBox("Preview on left (restart required)")
|
||||||
|
self._flip_layout.setChecked(self._db.get_setting_bool("flip_layout"))
|
||||||
|
form.addRow("", self._flip_layout)
|
||||||
|
|
||||||
# Slideshow monitor
|
# Slideshow monitor
|
||||||
from PySide6.QtWidgets import QApplication
|
from PySide6.QtWidgets import QApplication
|
||||||
self._monitor_combo = QComboBox()
|
self._monitor_combo = QComboBox()
|
||||||
@ -210,6 +215,16 @@ class SettingsDialog(QDialog):
|
|||||||
self._monitor_combo.setCurrentIndex(idx)
|
self._monitor_combo.setCurrentIndex(idx)
|
||||||
form.addRow("Popout monitor:", self._monitor_combo)
|
form.addRow("Popout monitor:", self._monitor_combo)
|
||||||
|
|
||||||
|
# Popout anchor — resize pivot point
|
||||||
|
self._popout_anchor = QComboBox()
|
||||||
|
self._popout_anchor.addItems(["Center", "Top-left", "Top-right", "Bottom-left", "Bottom-right"])
|
||||||
|
_anchor_map = {"center": "Center", "tl": "Top-left", "tr": "Top-right", "bl": "Bottom-left", "br": "Bottom-right"}
|
||||||
|
current_anchor = self._db.get_setting("popout_anchor") or "center"
|
||||||
|
idx = self._popout_anchor.findText(_anchor_map.get(current_anchor, "Center"))
|
||||||
|
if idx >= 0:
|
||||||
|
self._popout_anchor.setCurrentIndex(idx)
|
||||||
|
form.addRow("Popout anchor:", self._popout_anchor)
|
||||||
|
|
||||||
# File dialog platform (Linux only)
|
# File dialog platform (Linux only)
|
||||||
self._file_dialog_combo = None
|
self._file_dialog_combo = None
|
||||||
if not IS_WINDOWS:
|
if not IS_WINDOWS:
|
||||||
@ -791,7 +806,10 @@ class SettingsDialog(QDialog):
|
|||||||
self._db.set_setting("infinite_scroll", "1" if self._infinite_scroll.isChecked() else "0")
|
self._db.set_setting("infinite_scroll", "1" if self._infinite_scroll.isChecked() else "0")
|
||||||
self._db.set_setting("unbookmark_on_save", "1" if self._unbookmark_on_save.isChecked() else "0")
|
self._db.set_setting("unbookmark_on_save", "1" if self._unbookmark_on_save.isChecked() else "0")
|
||||||
self._db.set_setting("search_history_enabled", "1" if self._search_history.isChecked() else "0")
|
self._db.set_setting("search_history_enabled", "1" if self._search_history.isChecked() else "0")
|
||||||
|
self._db.set_setting("flip_layout", "1" if self._flip_layout.isChecked() else "0")
|
||||||
self._db.set_setting("slideshow_monitor", self._monitor_combo.currentText())
|
self._db.set_setting("slideshow_monitor", self._monitor_combo.currentText())
|
||||||
|
_anchor_rmap = {"Center": "center", "Top-left": "tl", "Top-right": "tr", "Bottom-left": "bl", "Bottom-right": "br"}
|
||||||
|
self._db.set_setting("popout_anchor", _anchor_rmap.get(self._popout_anchor.currentText(), "center"))
|
||||||
self._db.set_setting("library_dir", self._library_dir.text().strip())
|
self._db.set_setting("library_dir", self._library_dir.text().strip())
|
||||||
self._db.set_setting("library_filename_template", self._library_filename_template.text().strip())
|
self._db.set_setting("library_filename_template", self._library_filename_template.text().strip())
|
||||||
self._db.set_setting("max_cache_mb", str(self._max_cache.value()))
|
self._db.set_setting("max_cache_mb", str(self._max_cache.value()))
|
||||||
|
|||||||
@ -118,15 +118,7 @@ QPushButton:pressed { background-color: ${bg_active}; }
|
|||||||
QPushButton:checked { background-color: ${accent}; } /* Active tab (Browse/Bookmarks/Library), Autoplay, Loop toggles */
|
QPushButton:checked { background-color: ${accent}; } /* Active tab (Browse/Bookmarks/Library), Autoplay, Loop toggles */
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note:** Qt's QSS does not support the CSS `content` property, so you cannot replace button text (e.g. "Play" → "") via stylesheet alone. However, you can use a Nerd Font to change how unicode characters render:
|
**Note:** Qt's QSS does not support the CSS `content` property, so you cannot replace button text (e.g. swap icon symbols) via stylesheet alone. The toolbar icon buttons use hardcoded Unicode symbols — to change which symbols appear, modify the Python source directly (see `preview_pane.py` and `popout/window.py`).
|
||||||
|
|
||||||
```css
|
|
||||||
QPushButton {
|
|
||||||
font-family: "JetBrainsMono Nerd Font", monospace;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To use icon buttons, you would need to modify the Python source code directly — the button labels are set in `preview.py` via `QPushButton("Play")` etc.
|
|
||||||
|
|
||||||
### Text Inputs
|
### Text Inputs
|
||||||
|
|
||||||
@ -312,11 +304,34 @@ QWidget#_slideshow_controls QPushButton {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Preview Toolbar
|
### Preview & Popout Toolbar Icon Buttons
|
||||||
|
|
||||||
The preview panel has an action toolbar (Bookmark, Save, BL Tag, BL Post, Popout) that appears above the media when a post is active. This toolbar uses the app's default button styling.
|
The preview and popout toolbars use 24x24 icon buttons with Unicode symbols. Each button has an object name for QSS targeting:
|
||||||
|
|
||||||
The toolbar does not have a named object ID — it inherits the app's `QPushButton` styles directly.
|
| Object Name | Symbol | Action |
|
||||||
|
|-------------|--------|--------|
|
||||||
|
| `#_tb_bookmark` | ☆ / ★ | Bookmark / Unbookmark |
|
||||||
|
| `#_tb_save` | ⤓ / ✕ | Save / Unsave |
|
||||||
|
| `#_tb_bl_tag` | ⊘ | Blacklist a tag |
|
||||||
|
| `#_tb_bl_post` | ⊗ | Blacklist this post |
|
||||||
|
| `#_tb_popout` | ⧉ | Open popout (preview only) |
|
||||||
|
|
||||||
|
```css
|
||||||
|
/* Style all toolbar icon buttons */
|
||||||
|
QPushButton#_tb_bookmark,
|
||||||
|
QPushButton#_tb_save,
|
||||||
|
QPushButton#_tb_bl_tag,
|
||||||
|
QPushButton#_tb_bl_post,
|
||||||
|
QPushButton#_tb_popout {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid ${border};
|
||||||
|
color: ${text};
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
The same object names are used in both the preview pane and the popout overlay, so one rule targets both. The symbols themselves are hardcoded in Python — QSS can style the buttons but cannot change which symbol is displayed.
|
||||||
|
|
||||||
### Progress Bar (Download)
|
### Progress Bar (Download)
|
||||||
|
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #1e1e2e
|
bg: #1e1e2e
|
||||||
bg_alt: #181825
|
bg_alt: #181825
|
||||||
bg_subtle: #313244
|
bg_subtle: #313244
|
||||||
bg_hover: #45475a
|
bg_hover: #45475a
|
||||||
bg_active: #585b70
|
bg_active: #585b70
|
||||||
text: #cdd6f4
|
text: #cdd6f4
|
||||||
text_dim: #a6adc8
|
text_dim: #a6adc8
|
||||||
text_disabled: #6c7086
|
text_disabled: #6c7086
|
||||||
border: #313244
|
border: #313244
|
||||||
border_strong: #45475a
|
border_strong: #45475a
|
||||||
accent: #cba6f7
|
accent: #cba6f7
|
||||||
accent_text: #1e1e2e
|
accent_text: #1e1e2e
|
||||||
accent_dim: #b4befe
|
accent_dim: #b4befe
|
||||||
link: #89b4fa
|
link: #89b4fa
|
||||||
danger: #f38ba8
|
danger: #f38ba8
|
||||||
success: #a6e3a1
|
success: #a6e3a1
|
||||||
warning: #f9e2af
|
warning: #f9e2af
|
||||||
overlay_bg: rgba(30, 30, 46, 200)
|
overlay_bg: rgba(30, 30, 46, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #1e1e2e
|
bg: #1e1e2e
|
||||||
bg_alt: #181825
|
bg_alt: #181825
|
||||||
bg_subtle: #313244
|
bg_subtle: #313244
|
||||||
bg_hover: #45475a
|
bg_hover: #45475a
|
||||||
bg_active: #585b70
|
bg_active: #585b70
|
||||||
text: #cdd6f4
|
text: #cdd6f4
|
||||||
text_dim: #a6adc8
|
text_dim: #a6adc8
|
||||||
text_disabled: #6c7086
|
text_disabled: #6c7086
|
||||||
border: #313244
|
border: #313244
|
||||||
border_strong: #45475a
|
border_strong: #45475a
|
||||||
accent: #cba6f7
|
accent: #cba6f7
|
||||||
accent_text: #1e1e2e
|
accent_text: #1e1e2e
|
||||||
accent_dim: #b4befe
|
accent_dim: #b4befe
|
||||||
link: #89b4fa
|
link: #89b4fa
|
||||||
danger: #f38ba8
|
danger: #f38ba8
|
||||||
success: #a6e3a1
|
success: #a6e3a1
|
||||||
warning: #f9e2af
|
warning: #f9e2af
|
||||||
overlay_bg: rgba(30, 30, 46, 200)
|
overlay_bg: rgba(30, 30, 46, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* booru-viewer — Everforest Dark
|
/* booru-viewer — Everforest
|
||||||
*
|
*
|
||||||
* Edit the @palette block below to recolor this rounded variant. The body uses
|
* Edit the @palette block below to recolor this rounded variant. The body uses
|
||||||
* ${...} placeholders that the app's _load_user_qss preprocessor
|
* ${...} placeholders that the app's _load_user_qss preprocessor
|
||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #2d353b
|
bg: #2d353b
|
||||||
bg_alt: #232a2e
|
bg_alt: #232a2e
|
||||||
bg_subtle: #343f44
|
bg_subtle: #343f44
|
||||||
bg_hover: #3d484d
|
bg_hover: #3d484d
|
||||||
bg_active: #4f585e
|
bg_active: #4f585e
|
||||||
text: #d3c6aa
|
text: #d3c6aa
|
||||||
text_dim: #9da9a0
|
text_dim: #9da9a0
|
||||||
text_disabled: #7a8478
|
text_disabled: #7a8478
|
||||||
border: #343f44
|
border: #343f44
|
||||||
border_strong: #3d484d
|
border_strong: #3d484d
|
||||||
accent: #a7c080
|
accent: #a7c080
|
||||||
accent_text: #2d353b
|
accent_text: #2d353b
|
||||||
accent_dim: #83c092
|
accent_dim: #83c092
|
||||||
link: #7fbbb3
|
link: #7fbbb3
|
||||||
danger: #e67e80
|
danger: #e67e80
|
||||||
success: #a7c080
|
success: #a7c080
|
||||||
warning: #dbbc7f
|
warning: #dbbc7f
|
||||||
overlay_bg: rgba(45, 53, 59, 200)
|
overlay_bg: rgba(45, 53, 59, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* booru-viewer — Everforest Dark
|
/* booru-viewer — Everforest
|
||||||
*
|
*
|
||||||
* Edit the @palette block below to recolor this square variant. The body uses
|
* Edit the @palette block below to recolor this square variant. The body uses
|
||||||
* ${...} placeholders that the app's _load_user_qss preprocessor
|
* ${...} placeholders that the app's _load_user_qss preprocessor
|
||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #2d353b
|
bg: #2d353b
|
||||||
bg_alt: #232a2e
|
bg_alt: #232a2e
|
||||||
bg_subtle: #343f44
|
bg_subtle: #343f44
|
||||||
bg_hover: #3d484d
|
bg_hover: #3d484d
|
||||||
bg_active: #4f585e
|
bg_active: #4f585e
|
||||||
text: #d3c6aa
|
text: #d3c6aa
|
||||||
text_dim: #9da9a0
|
text_dim: #9da9a0
|
||||||
text_disabled: #7a8478
|
text_disabled: #7a8478
|
||||||
border: #343f44
|
border: #343f44
|
||||||
border_strong: #3d484d
|
border_strong: #3d484d
|
||||||
accent: #a7c080
|
accent: #a7c080
|
||||||
accent_text: #2d353b
|
accent_text: #2d353b
|
||||||
accent_dim: #83c092
|
accent_dim: #83c092
|
||||||
link: #7fbbb3
|
link: #7fbbb3
|
||||||
danger: #e67e80
|
danger: #e67e80
|
||||||
success: #a7c080
|
success: #a7c080
|
||||||
warning: #dbbc7f
|
warning: #dbbc7f
|
||||||
overlay_bg: rgba(45, 53, 59, 200)
|
overlay_bg: rgba(45, 53, 59, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* booru-viewer — Gruvbox Dark
|
/* booru-viewer — Gruvbox
|
||||||
*
|
*
|
||||||
* Edit the @palette block below to recolor this rounded variant. The body uses
|
* Edit the @palette block below to recolor this rounded variant. The body uses
|
||||||
* ${...} placeholders that the app's _load_user_qss preprocessor
|
* ${...} placeholders that the app's _load_user_qss preprocessor
|
||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #282828
|
bg: #282828
|
||||||
bg_alt: #1d2021
|
bg_alt: #1d2021
|
||||||
bg_subtle: #3c3836
|
bg_subtle: #3c3836
|
||||||
bg_hover: #504945
|
bg_hover: #504945
|
||||||
bg_active: #665c54
|
bg_active: #665c54
|
||||||
text: #ebdbb2
|
text: #ebdbb2
|
||||||
text_dim: #d5c4a1
|
text_dim: #d5c4a1
|
||||||
text_disabled: #928374
|
text_disabled: #928374
|
||||||
border: #3c3836
|
border: #3c3836
|
||||||
border_strong: #504945
|
border_strong: #504945
|
||||||
accent: #d79921
|
accent: #d79921
|
||||||
accent_text: #282828
|
accent_text: #282828
|
||||||
accent_dim: #fabd2f
|
accent_dim: #fabd2f
|
||||||
link: #83a598
|
link: #83a598
|
||||||
danger: #fb4934
|
danger: #fb4934
|
||||||
success: #b8bb26
|
success: #b8bb26
|
||||||
warning: #fabd2f
|
warning: #fabd2f
|
||||||
overlay_bg: rgba(40, 40, 40, 200)
|
overlay_bg: rgba(40, 40, 40, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
/* booru-viewer — Gruvbox Dark
|
/* booru-viewer — Gruvbox
|
||||||
*
|
*
|
||||||
* Edit the @palette block below to recolor this square variant. The body uses
|
* Edit the @palette block below to recolor this square variant. The body uses
|
||||||
* ${...} placeholders that the app's _load_user_qss preprocessor
|
* ${...} placeholders that the app's _load_user_qss preprocessor
|
||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #282828
|
bg: #282828
|
||||||
bg_alt: #1d2021
|
bg_alt: #1d2021
|
||||||
bg_subtle: #3c3836
|
bg_subtle: #3c3836
|
||||||
bg_hover: #504945
|
bg_hover: #504945
|
||||||
bg_active: #665c54
|
bg_active: #665c54
|
||||||
text: #ebdbb2
|
text: #ebdbb2
|
||||||
text_dim: #d5c4a1
|
text_dim: #d5c4a1
|
||||||
text_disabled: #928374
|
text_disabled: #928374
|
||||||
border: #3c3836
|
border: #3c3836
|
||||||
border_strong: #504945
|
border_strong: #504945
|
||||||
accent: #d79921
|
accent: #d79921
|
||||||
accent_text: #282828
|
accent_text: #282828
|
||||||
accent_dim: #fabd2f
|
accent_dim: #fabd2f
|
||||||
link: #83a598
|
link: #83a598
|
||||||
danger: #fb4934
|
danger: #fb4934
|
||||||
success: #b8bb26
|
success: #b8bb26
|
||||||
warning: #fabd2f
|
warning: #fabd2f
|
||||||
overlay_bg: rgba(40, 40, 40, 200)
|
overlay_bg: rgba(40, 40, 40, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #2e3440
|
bg: #2e3440
|
||||||
bg_alt: #272b36
|
bg_alt: #272b36
|
||||||
bg_subtle: #3b4252
|
bg_subtle: #3b4252
|
||||||
bg_hover: #434c5e
|
bg_hover: #434c5e
|
||||||
bg_active: #4c566a
|
bg_active: #4c566a
|
||||||
text: #eceff4
|
text: #eceff4
|
||||||
text_dim: #d8dee9
|
text_dim: #d8dee9
|
||||||
text_disabled: #4c566a
|
text_disabled: #4c566a
|
||||||
border: #3b4252
|
border: #3b4252
|
||||||
border_strong: #4c566a
|
border_strong: #4c566a
|
||||||
accent: #88c0d0
|
accent: #88c0d0
|
||||||
accent_text: #2e3440
|
accent_text: #2e3440
|
||||||
accent_dim: #81a1c1
|
accent_dim: #81a1c1
|
||||||
link: #8fbcbb
|
link: #8fbcbb
|
||||||
danger: #bf616a
|
danger: #bf616a
|
||||||
success: #a3be8c
|
success: #a3be8c
|
||||||
warning: #ebcb8b
|
warning: #ebcb8b
|
||||||
overlay_bg: rgba(46, 52, 64, 200)
|
overlay_bg: rgba(46, 52, 64, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #2e3440
|
bg: #2e3440
|
||||||
bg_alt: #272b36
|
bg_alt: #272b36
|
||||||
bg_subtle: #3b4252
|
bg_subtle: #3b4252
|
||||||
bg_hover: #434c5e
|
bg_hover: #434c5e
|
||||||
bg_active: #4c566a
|
bg_active: #4c566a
|
||||||
text: #eceff4
|
text: #eceff4
|
||||||
text_dim: #d8dee9
|
text_dim: #d8dee9
|
||||||
text_disabled: #4c566a
|
text_disabled: #4c566a
|
||||||
border: #3b4252
|
border: #3b4252
|
||||||
border_strong: #4c566a
|
border_strong: #4c566a
|
||||||
accent: #88c0d0
|
accent: #88c0d0
|
||||||
accent_text: #2e3440
|
accent_text: #2e3440
|
||||||
accent_dim: #81a1c1
|
accent_dim: #81a1c1
|
||||||
link: #8fbcbb
|
link: #8fbcbb
|
||||||
danger: #bf616a
|
danger: #bf616a
|
||||||
success: #a3be8c
|
success: #a3be8c
|
||||||
warning: #ebcb8b
|
warning: #ebcb8b
|
||||||
overlay_bg: rgba(46, 52, 64, 200)
|
overlay_bg: rgba(46, 52, 64, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #002b36
|
bg: #002b36
|
||||||
bg_alt: #001f27
|
bg_alt: #001f27
|
||||||
bg_subtle: #073642
|
bg_subtle: #073642
|
||||||
bg_hover: #0d4654
|
bg_hover: #0d4654
|
||||||
bg_active: #586e75
|
bg_active: #586e75
|
||||||
text: #93a1a1
|
text: #93a1a1
|
||||||
text_dim: #839496
|
text_dim: #839496
|
||||||
text_disabled: #586e75
|
text_disabled: #586e75
|
||||||
border: #073642
|
border: #073642
|
||||||
border_strong: #0d4654
|
border_strong: #0d4654
|
||||||
accent: #268bd2
|
accent: #268bd2
|
||||||
accent_text: #002b36
|
accent_text: #002b36
|
||||||
accent_dim: #2aa198
|
accent_dim: #2aa198
|
||||||
link: #2aa198
|
link: #2aa198
|
||||||
danger: #dc322f
|
danger: #dc322f
|
||||||
success: #859900
|
success: #859900
|
||||||
warning: #b58900
|
warning: #b58900
|
||||||
overlay_bg: rgba(0, 43, 54, 200)
|
overlay_bg: rgba(0, 43, 54, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #002b36
|
bg: #002b36
|
||||||
bg_alt: #001f27
|
bg_alt: #001f27
|
||||||
bg_subtle: #073642
|
bg_subtle: #073642
|
||||||
bg_hover: #0d4654
|
bg_hover: #0d4654
|
||||||
bg_active: #586e75
|
bg_active: #586e75
|
||||||
text: #93a1a1
|
text: #93a1a1
|
||||||
text_dim: #839496
|
text_dim: #839496
|
||||||
text_disabled: #586e75
|
text_disabled: #586e75
|
||||||
border: #073642
|
border: #073642
|
||||||
border_strong: #0d4654
|
border_strong: #0d4654
|
||||||
accent: #268bd2
|
accent: #268bd2
|
||||||
accent_text: #002b36
|
accent_text: #002b36
|
||||||
accent_dim: #2aa198
|
accent_dim: #2aa198
|
||||||
link: #2aa198
|
link: #2aa198
|
||||||
danger: #dc322f
|
danger: #dc322f
|
||||||
success: #859900
|
success: #859900
|
||||||
warning: #b58900
|
warning: #b58900
|
||||||
overlay_bg: rgba(0, 43, 54, 200)
|
overlay_bg: rgba(0, 43, 54, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #1a1b26
|
bg: #1a1b26
|
||||||
bg_alt: #16161e
|
bg_alt: #16161e
|
||||||
bg_subtle: #24283b
|
bg_subtle: #24283b
|
||||||
bg_hover: #292e42
|
bg_hover: #292e42
|
||||||
bg_active: #3b4261
|
bg_active: #3b4261
|
||||||
text: #c0caf5
|
text: #c0caf5
|
||||||
text_dim: #a9b1d6
|
text_dim: #a9b1d6
|
||||||
text_disabled: #565f89
|
text_disabled: #565f89
|
||||||
border: #24283b
|
border: #24283b
|
||||||
border_strong: #292e42
|
border_strong: #292e42
|
||||||
accent: #7aa2f7
|
accent: #7aa2f7
|
||||||
accent_text: #1a1b26
|
accent_text: #1a1b26
|
||||||
accent_dim: #7dcfff
|
accent_dim: #7dcfff
|
||||||
link: #7dcfff
|
link: #7dcfff
|
||||||
danger: #f7768e
|
danger: #f7768e
|
||||||
success: #9ece6a
|
success: #9ece6a
|
||||||
warning: #e0af68
|
warning: #e0af68
|
||||||
overlay_bg: rgba(26, 27, 38, 200)
|
overlay_bg: rgba(26, 27, 38, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -92,49 +89,26 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -315,19 +289,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
border-radius: 2px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
border-radius: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -343,33 +304,28 @@ QProgressBar::chunk {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
|
||||||
QCheckBox::indicator {
|
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
QRadioButton::indicator {
|
QCheckBox::indicator:hover {
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -384,9 +340,9 @@ QToolTip {
|
|||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -395,35 +351,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -448,7 +387,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -465,63 +404,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -531,18 +421,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -553,19 +443,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -588,6 +472,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
@ -9,26 +9,25 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* @palette
|
/* @palette
|
||||||
bg: #1a1b26
|
bg: #1a1b26
|
||||||
bg_alt: #16161e
|
bg_alt: #16161e
|
||||||
bg_subtle: #24283b
|
bg_subtle: #24283b
|
||||||
bg_hover: #292e42
|
bg_hover: #292e42
|
||||||
bg_active: #3b4261
|
bg_active: #3b4261
|
||||||
text: #c0caf5
|
text: #c0caf5
|
||||||
text_dim: #a9b1d6
|
text_dim: #a9b1d6
|
||||||
text_disabled: #565f89
|
text_disabled: #565f89
|
||||||
border: #24283b
|
border: #24283b
|
||||||
border_strong: #292e42
|
border_strong: #292e42
|
||||||
accent: #7aa2f7
|
accent: #7aa2f7
|
||||||
accent_text: #1a1b26
|
accent_text: #1a1b26
|
||||||
accent_dim: #7dcfff
|
accent_dim: #7dcfff
|
||||||
link: #7dcfff
|
link: #7dcfff
|
||||||
danger: #f7768e
|
danger: #f7768e
|
||||||
success: #9ece6a
|
success: #9ece6a
|
||||||
warning: #e0af68
|
warning: #e0af68
|
||||||
overlay_bg: rgba(26, 27, 38, 200)
|
overlay_bg: rgba(26, 27, 38, 200)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* ---------- Base ---------- */
|
/* ---------- Base ---------- */
|
||||||
|
|
||||||
QWidget {
|
QWidget {
|
||||||
@ -43,8 +42,6 @@ QWidget:disabled {
|
|||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Labels should never paint an opaque background — they sit on top of
|
|
||||||
* other widgets in many places (toolbars, info panels, overlays). */
|
|
||||||
QLabel {
|
QLabel {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
@ -91,47 +88,25 @@ QPushButton:flat:hover {
|
|||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
|
|
||||||
QToolButton {
|
|
||||||
background-color: transparent;
|
|
||||||
color: ${text};
|
|
||||||
border: 1px solid transparent;
|
|
||||||
padding: 4px;
|
|
||||||
}
|
|
||||||
QToolButton:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
border-color: ${border_strong};
|
|
||||||
}
|
|
||||||
QToolButton:pressed, QToolButton:checked {
|
|
||||||
background-color: ${bg_active};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Inputs ---------- */
|
/* ---------- Inputs ---------- */
|
||||||
|
|
||||||
QLineEdit, QSpinBox, QDoubleSpinBox, QTextEdit, QPlainTextEdit {
|
QLineEdit, QSpinBox, QTextEdit {
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
/* 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: 16px;
|
min-height: 16px;
|
||||||
selection-background-color: ${accent};
|
selection-background-color: ${accent};
|
||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
}
|
}
|
||||||
QLineEdit:focus,
|
QLineEdit:focus,
|
||||||
QSpinBox:focus,
|
QSpinBox:focus,
|
||||||
QDoubleSpinBox:focus,
|
QTextEdit:focus {
|
||||||
QTextEdit:focus,
|
|
||||||
QPlainTextEdit:focus {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QLineEdit:disabled,
|
QLineEdit:disabled,
|
||||||
QSpinBox:disabled,
|
QSpinBox:disabled,
|
||||||
QDoubleSpinBox:disabled,
|
QTextEdit:disabled {
|
||||||
QTextEdit:disabled,
|
|
||||||
QPlainTextEdit:disabled {
|
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
color: ${text_disabled};
|
color: ${text_disabled};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
@ -309,17 +284,6 @@ QSlider::handle:horizontal:hover {
|
|||||||
background: ${accent_dim};
|
background: ${accent_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
QSlider::groove:vertical {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
width: 4px;
|
|
||||||
}
|
|
||||||
QSlider::handle:vertical {
|
|
||||||
background: ${accent};
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
margin: 0 -5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Progress ---------- */
|
/* ---------- Progress ---------- */
|
||||||
|
|
||||||
QProgressBar {
|
QProgressBar {
|
||||||
@ -333,32 +297,27 @@ QProgressBar::chunk {
|
|||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Checkboxes & radio buttons ---------- */
|
/* ---------- Checkboxes ---------- */
|
||||||
|
|
||||||
QCheckBox, QRadioButton {
|
QCheckBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
color: ${text};
|
color: ${text};
|
||||||
spacing: 6px;
|
spacing: 6px;
|
||||||
}
|
}
|
||||||
QCheckBox::indicator, QRadioButton::indicator {
|
QCheckBox::indicator {
|
||||||
width: 14px;
|
width: 14px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
background-color: ${bg_subtle};
|
background-color: ${bg_subtle};
|
||||||
border: 1px solid ${border_strong};
|
border: 1px solid ${border_strong};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator {
|
QCheckBox::indicator:hover {
|
||||||
}
|
|
||||||
QRadioButton::indicator {
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
QCheckBox::indicator:hover, QRadioButton::indicator:hover {
|
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:checked, QRadioButton::indicator:checked {
|
QCheckBox::indicator:checked {
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
border-color: ${accent};
|
border-color: ${accent};
|
||||||
}
|
}
|
||||||
QCheckBox::indicator:disabled, QRadioButton::indicator:disabled {
|
QCheckBox::indicator:disabled {
|
||||||
background-color: ${bg_alt};
|
background-color: ${bg_alt};
|
||||||
border-color: ${border};
|
border-color: ${border};
|
||||||
}
|
}
|
||||||
@ -372,9 +331,9 @@ QToolTip {
|
|||||||
padding: 4px 6px;
|
padding: 4px 6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Item views (lists, trees, tables) ---------- */
|
/* ---------- Lists ---------- */
|
||||||
|
|
||||||
QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
QListView, QListWidget {
|
||||||
background-color: ${bg};
|
background-color: ${bg};
|
||||||
alternate-background-color: ${bg_alt};
|
alternate-background-color: ${bg_alt};
|
||||||
color: ${text};
|
color: ${text};
|
||||||
@ -383,35 +342,18 @@ QListView, QListWidget, QTreeView, QTreeWidget, QTableView, QTableWidget {
|
|||||||
selection-color: ${accent_text};
|
selection-color: ${accent_text};
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
QListView::item, QListWidget::item,
|
QListView::item, QListWidget::item {
|
||||||
QTreeView::item, QTreeWidget::item,
|
|
||||||
QTableView::item, QTableWidget::item {
|
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
QListView::item:hover, QListWidget::item:hover,
|
QListView::item:hover, QListWidget::item:hover {
|
||||||
QTreeView::item:hover, QTreeWidget::item:hover,
|
|
||||||
QTableView::item:hover, QTableWidget::item:hover {
|
|
||||||
background-color: ${bg_hover};
|
background-color: ${bg_hover};
|
||||||
}
|
}
|
||||||
QListView::item:selected, QListWidget::item:selected,
|
QListView::item:selected, QListWidget::item:selected {
|
||||||
QTreeView::item:selected, QTreeWidget::item:selected,
|
|
||||||
QTableView::item:selected, QTableWidget::item:selected {
|
|
||||||
background-color: ${accent};
|
background-color: ${accent};
|
||||||
color: ${accent_text};
|
color: ${accent_text};
|
||||||
}
|
}
|
||||||
|
|
||||||
QHeaderView::section {
|
/* ---------- Tabs (settings dialog) ---------- */
|
||||||
background-color: ${bg_subtle};
|
|
||||||
color: ${text};
|
|
||||||
border: none;
|
|
||||||
border-right: 1px solid ${border};
|
|
||||||
padding: 4px 8px;
|
|
||||||
}
|
|
||||||
QHeaderView::section:hover {
|
|
||||||
background-color: ${bg_hover};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Tabs ---------- */
|
|
||||||
|
|
||||||
QTabWidget::pane {
|
QTabWidget::pane {
|
||||||
border: 1px solid ${border};
|
border: 1px solid ${border};
|
||||||
@ -436,7 +378,7 @@ QTabBar::tab:hover:!selected {
|
|||||||
color: ${text};
|
color: ${text};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Group boxes ---------- */
|
/* ---------- Group boxes (settings dialog) ---------- */
|
||||||
|
|
||||||
QGroupBox {
|
QGroupBox {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -452,63 +394,14 @@ QGroupBox::title {
|
|||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Frames ---------- */
|
/* ---------- Rubber band (multi-select drag) ---------- */
|
||||||
|
|
||||||
QFrame[frameShape="4"], /* HLine */
|
|
||||||
QFrame[frameShape="5"] /* VLine */ {
|
|
||||||
background: ${border};
|
|
||||||
color: ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Toolbars ---------- */
|
|
||||||
|
|
||||||
QToolBar {
|
|
||||||
background: ${bg};
|
|
||||||
border: none;
|
|
||||||
spacing: 4px;
|
|
||||||
padding: 2px;
|
|
||||||
}
|
|
||||||
QToolBar::separator {
|
|
||||||
background: ${border};
|
|
||||||
width: 1px;
|
|
||||||
margin: 4px 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Dock widgets ---------- */
|
|
||||||
|
|
||||||
QDockWidget {
|
|
||||||
color: ${text};
|
|
||||||
titlebar-close-icon: none;
|
|
||||||
}
|
|
||||||
QDockWidget::title {
|
|
||||||
background: ${bg_subtle};
|
|
||||||
padding: 4px;
|
|
||||||
border: 1px solid ${border};
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ---------- Rubber band (multi-select drag rectangle) ---------- */
|
|
||||||
|
|
||||||
QRubberBand {
|
QRubberBand {
|
||||||
background: ${accent};
|
background: ${accent};
|
||||||
border: 1px solid ${accent};
|
border: 1px solid ${accent};
|
||||||
/* Qt blends rubber band at ~30% so this reads as a translucent
|
|
||||||
* accent-tinted rectangle without needing rgba(). */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ---------- Library count label states ---------- */
|
/* ---------- Library count label states ---------- */
|
||||||
/*
|
|
||||||
* The library tab's count label switches between three visual states
|
|
||||||
* depending on what refresh() found. The state is exposed as a Qt
|
|
||||||
* dynamic property `libraryCountState` so users can override these
|
|
||||||
* rules in their custom.qss without touching the Python.
|
|
||||||
*
|
|
||||||
* normal N files — default text color, no rule needed
|
|
||||||
* empty no items — dim text (no items found, search miss)
|
|
||||||
* error bad/unreachable — danger color + bold (real error)
|
|
||||||
*/
|
|
||||||
|
|
||||||
QLabel[libraryCountState="empty"] {
|
QLabel[libraryCountState="empty"] {
|
||||||
color: ${text_dim};
|
color: ${text_dim};
|
||||||
@ -518,18 +411,18 @@ QLabel[libraryCountState="error"] {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Thumbnail dot indicators (Qt properties on ThumbnailWidget) ---------- */
|
/* ---------- Thumbnail indicators ---------- */
|
||||||
|
|
||||||
ThumbnailWidget {
|
ThumbnailWidget {
|
||||||
qproperty-savedColor: #22cc22; /* green dot: saved to library — universal "confirmed" feel */
|
qproperty-savedColor: #22cc22;
|
||||||
qproperty-bookmarkedColor: #ffcc00; /* yellow star: bookmarked */
|
qproperty-bookmarkedColor: #ffcc00;
|
||||||
qproperty-selectionColor: ${accent};
|
qproperty-selectionColor: ${accent};
|
||||||
qproperty-multiSelectColor: ${accent_dim};
|
qproperty-multiSelectColor: ${accent_dim};
|
||||||
qproperty-hoverColor: ${accent};
|
qproperty-hoverColor: ${accent};
|
||||||
qproperty-idleColor: ${border_strong};
|
qproperty-idleColor: ${border_strong};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Info panel tag category colors ---------- */
|
/* ---------- Info panel tag colors ---------- */
|
||||||
|
|
||||||
InfoPanel {
|
InfoPanel {
|
||||||
qproperty-tagArtistColor: ${warning};
|
qproperty-tagArtistColor: ${warning};
|
||||||
@ -540,19 +433,13 @@ InfoPanel {
|
|||||||
qproperty-tagLoreColor: ${text_dim};
|
qproperty-tagLoreColor: ${text_dim};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Video player letterbox / pillarbox color (mpv background) ---------- */
|
/* ---------- Video player letterbox ---------- */
|
||||||
|
|
||||||
VideoPlayer {
|
VideoPlayer {
|
||||||
qproperty-letterboxColor: ${bg};
|
qproperty-letterboxColor: ${bg};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- Popout overlay bars (slideshow toolbar + slideshow controls + embedded preview controls) ---------- */
|
/* ---------- Popout overlay bars ---------- */
|
||||||
/*
|
|
||||||
* 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_toolbar,
|
||||||
QWidget#_slideshow_controls,
|
QWidget#_slideshow_controls,
|
||||||
@ -575,6 +462,8 @@ QWidget#_preview_controls QPushButton {
|
|||||||
color: white;
|
color: white;
|
||||||
border: 1px solid rgba(255, 255, 255, 80);
|
border: 1px solid rgba(255, 255, 255, 80);
|
||||||
padding: 2px 6px;
|
padding: 2px 6px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
QWidget#_slideshow_toolbar QPushButton:hover,
|
QWidget#_slideshow_toolbar QPushButton:hover,
|
||||||
QWidget#_slideshow_controls QPushButton:hover,
|
QWidget#_slideshow_controls QPushButton:hover,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user