Skip to content

Commit 568e35a

Browse files
committed
* Adding Keyframe checkbox to Settings menu as "Use keyframes for preview images" option (default enabled)
* Adding preview time slider to overlay at bottom of preview image * Adding time display next to preview slider in H:MM:SS format
1 parent 5131e26 commit 568e35a

6 files changed

Lines changed: 105 additions & 61 deletions

File tree

fastflix/ui_styles.py

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,19 @@
99
from fastflix.ui_constants import FONTS
1010

1111

12+
# Onyx theme color constants
13+
ONYX_COLORS = {
14+
"primary": "#567781", # Blue accent (borders, selected tabs)
15+
"input_bg": "#4a555e", # Input field backgrounds
16+
"dropdown_bg": "#4e6172", # Dropdown backgrounds
17+
"text": "#ffffff", # White text
18+
"text_muted": "#b5b5b5", # Muted/disabled text
19+
"background": "#4f5962", # Main background
20+
"overlay": "rgba(0, 0, 0, 50)", # Overlay backgrounds
21+
"dark_bg": "#1d2023", # Dark background (dropdown menus)
22+
}
23+
24+
1225
def get_scaled_stylesheet(theme: str) -> str:
1326
"""Generate a scaled stylesheet based on the current theme and scale factors."""
1427
font_size = scaler.scale_font(FONTS.LARGE)
@@ -23,10 +36,10 @@ def get_scaled_stylesheet(theme: str) -> str:
2336
QPushButton {{ border-radius: {border_radius}px; }}
2437
QLineEdit {{
2538
background-color: #4a555e;
26-
color: black;
39+
color: white;
2740
border-radius: {border_radius}px;
2841
}}
29-
QTextEdit {{ background-color: #4a555e; color: black; }}
42+
QTextEdit {{ background-color: #4a555e; color: white; }}
3043
QTabBar::tab {{ background-color: #4f5962; }}
3144
QComboBox {{ border-radius: {border_radius}px; }}
3245
QScrollArea {{ border: 1px solid #919191; }}
@@ -54,3 +67,44 @@ def get_menubar_stylesheet() -> str:
5467
"""Generate scaled stylesheet for the menu bar."""
5568
font_size = scaler.scale_font(FONTS.LARGE)
5669
return f"font-size: {font_size}px"
70+
71+
72+
def get_onyx_combobox_style() -> str:
73+
"""Standard combobox/dropdown style for onyx theme."""
74+
return (
75+
f"background-color: {ONYX_COLORS['input_bg']}; "
76+
f"color: {ONYX_COLORS['text']}; "
77+
f"border: 1px solid {ONYX_COLORS['input_bg']}; "
78+
"border-radius: 0px;"
79+
)
80+
81+
82+
def get_onyx_button_style() -> str:
83+
"""Standard button style for onyx theme."""
84+
return (
85+
f"background-color: {ONYX_COLORS['input_bg']}; "
86+
f"color: {ONYX_COLORS['text']}; "
87+
f"border: 1px solid {ONYX_COLORS['input_bg']}; "
88+
"border-radius: 0px;"
89+
)
90+
91+
92+
def get_onyx_disposition_style(enabled: bool = True) -> str:
93+
"""Style for disposition dropdowns in audio/subtitle panels.
94+
95+
Args:
96+
enabled: Whether the disposition is enabled (colored) or disabled (default)
97+
"""
98+
if enabled:
99+
return f"border-color: {ONYX_COLORS['input_bg']}; background-color: {ONYX_COLORS['input_bg']}"
100+
return ""
101+
102+
103+
def get_onyx_label_style(muted: bool = False) -> str:
104+
"""Style for labels in onyx theme.
105+
106+
Args:
107+
muted: Whether to use muted text color
108+
"""
109+
color = ONYX_COLORS["text_muted"] if muted else ONYX_COLORS["text"]
110+
return f"color: {color}"

fastflix/widgets/main.py

Lines changed: 16 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
from fastflix.exceptions import FastFlixInternalException, FlixError
2525
from fastflix.ui_scale import scaler
2626
from fastflix.ui_constants import WIDTHS, HEIGHTS, ICONS
27+
from fastflix.ui_styles import ONYX_COLORS, get_onyx_combobox_style, get_onyx_button_style
2728
from fastflix.flix import (
2829
detect_hdr10_plus,
2930
detect_interlaced,
@@ -300,16 +301,7 @@ def __init__(self, parent, app: FastFlixApp):
300301
spacer.setFixedHeight(scaler.scale(HEIGHTS.SPACER_SMALL))
301302
self.grid.addWidget(spacer, 8, 0, 1, 14)
302303

303-
# Add separator line above tabs for onyx theme
304-
if self.app.fastflix.config.theme == "onyx":
305-
tab_separator = QtWidgets.QFrame()
306-
tab_separator.setFrameShape(QtWidgets.QFrame.HLine)
307-
tab_separator.setFixedHeight(1)
308-
tab_separator.setStyleSheet("background-color: #567781;")
309-
self.grid.addWidget(tab_separator, 9, 0, 1, 14)
310-
self.grid.addWidget(self.video_options, 10, 0, 10, 14)
311-
else:
312-
self.grid.addWidget(self.video_options, 9, 0, 10, 14)
304+
self.grid.addWidget(self.video_options, 9, 0, 10, 14)
313305

314306
self.grid.setSpacing(5)
315307
self.paused = False
@@ -559,9 +551,7 @@ def init_video_area(self):
559551
self.widgets.output_type_combo.addItems(self.current_encoder.video_extensions)
560552
self.widgets.output_type_combo.setFixedHeight(scaler.scale(HEIGHTS.COMBO_BOX))
561553
if self.app.fastflix.config.theme == "onyx":
562-
self.widgets.output_type_combo.setStyleSheet(
563-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
564-
)
554+
self.widgets.output_type_combo.setStyleSheet(get_onyx_combobox_style())
565555
self.widgets.output_type_combo.currentIndexChanged.connect(lambda: self.page_update(build_thumbnail=False))
566556

567557
output_layout.addWidget(self.widgets.output_type_combo)
@@ -628,9 +618,7 @@ def init_options_tabs(self):
628618
self.widgets.resolution_drop_down.addItems(list(resolutions.keys()))
629619
self.widgets.resolution_drop_down.currentIndexChanged.connect(self.update_resolution)
630620
if self.app.fastflix.config.theme == "onyx":
631-
self.widgets.resolution_drop_down.setStyleSheet(
632-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
633-
)
621+
self.widgets.resolution_drop_down.setStyleSheet(get_onyx_combobox_style())
634622
res_row.addWidget(self.widgets.resolution_drop_down)
635623

636624
self.widgets.resolution_custom = QtWidgets.QLineEdit()
@@ -675,19 +663,15 @@ def init_options_tabs(self):
675663
time_reset.setToolTip(t("Reset start and end times"))
676664
time_reset.clicked.connect(self.reset_time)
677665
if self.app.fastflix.config.theme == "onyx":
678-
time_reset.setStyleSheet(
679-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
680-
)
666+
time_reset.setStyleSheet(get_onyx_button_style())
681667
self.buttons.append(time_reset)
682668

683669
self.widgets.fast_time = QtWidgets.QComboBox()
684670
self.widgets.fast_time.addItems([t("Fast"), t("Exact")])
685671
self.widgets.fast_time.setCurrentIndex(0)
686672
self.widgets.fast_time.setFixedHeight(scaler.scale(22))
687673
if self.app.fastflix.config.theme == "onyx":
688-
self.widgets.fast_time.setStyleSheet(
689-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
690-
)
674+
self.widgets.fast_time.setStyleSheet(get_onyx_combobox_style())
691675
self.widgets.fast_time.setToolTip(
692676
t(
693677
"uses [fast] seek to a rough position ahead of timestamp, "
@@ -744,18 +728,14 @@ def init_options_tabs(self):
744728
auto_crop.setToolTip(t("Automatically detect black borders"))
745729
auto_crop.clicked.connect(self.get_auto_crop)
746730
if self.app.fastflix.config.theme == "onyx":
747-
auto_crop.setStyleSheet(
748-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
749-
)
731+
auto_crop.setStyleSheet(get_onyx_button_style())
750732
self.buttons.append(auto_crop)
751733
reset = QtWidgets.QPushButton(t("Reset"))
752734
reset.setFixedHeight(scaler.scale(22))
753735
reset.setToolTip(t("Reset crop"))
754736
reset.clicked.connect(self.reset_crop)
755737
if self.app.fastflix.config.theme == "onyx":
756-
reset.setStyleSheet(
757-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
758-
)
738+
reset.setStyleSheet(get_onyx_button_style())
759739
self.buttons.append(reset)
760740
col1.addWidget(auto_crop)
761741
col1.addWidget(reset)
@@ -982,9 +962,7 @@ def init_flip(self):
982962
self.widgets.flip.setIconSize(scaler.scale_size(ICONS.MEDIUM, ICONS.MEDIUM))
983963
self.widgets.flip.currentIndexChanged.connect(lambda: self.page_update())
984964
if self.app.fastflix.config.theme == "onyx":
985-
self.widgets.flip.setStyleSheet(
986-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
987-
)
965+
self.widgets.flip.setStyleSheet(get_onyx_combobox_style())
988966
return self.widgets.flip
989967

990968
def get_flips(self) -> Tuple[bool, bool]:
@@ -1023,9 +1001,7 @@ def init_rotate(self):
10231001
self.widgets.rotate.setIconSize(scaler.scale_size(ICONS.MEDIUM, ICONS.MEDIUM))
10241002
self.widgets.rotate.currentIndexChanged.connect(lambda: self.page_update())
10251003
if self.app.fastflix.config.theme == "onyx":
1026-
self.widgets.rotate.setStyleSheet(
1027-
"background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px;"
1028-
)
1004+
self.widgets.rotate.setStyleSheet(get_onyx_combobox_style())
10291005
return self.widgets.rotate
10301006

10311007
def change_output_types(self):
@@ -1220,7 +1196,7 @@ def _update_scaled_sizes(self):
12201196
)
12211197
border_width = scaler.scale(2)
12221198
margin = scaler.scale(7)
1223-
self.setStyleSheet(f"border: {border_width}px solid #567781; margin: {margin}px;")
1199+
self.setStyleSheet(f"border: {border_width}px solid {ONYX_COLORS['primary']}; margin: {margin}px;")
12241200

12251201
def _on_scale_changed(self, factors):
12261202
"""Called when scale factors change."""
@@ -1563,18 +1539,11 @@ def build_crop(self) -> Union[Crop, None]:
15631539
self.widgets.crop.right.setStyleSheet("color: red")
15641540
# error_message(f"{t('Invalid Crop')}: {err}")
15651541
return None
1566-
self.widgets.crop.left.setStyleSheet(
1567-
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
1568-
)
1569-
self.widgets.crop.right.setStyleSheet(
1570-
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
1571-
)
1572-
self.widgets.crop.top.setStyleSheet(
1573-
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
1574-
)
1575-
self.widgets.crop.bottom.setStyleSheet(
1576-
"color: black" if self.app.fastflix.config.theme != "dark" else "color: white"
1577-
)
1542+
crop_text_color = "color: white" if self.app.fastflix.config.theme in ("dark", "onyx") else "color: black"
1543+
self.widgets.crop.left.setStyleSheet(crop_text_color)
1544+
self.widgets.crop.right.setStyleSheet(crop_text_color)
1545+
self.widgets.crop.top.setStyleSheet(crop_text_color)
1546+
self.widgets.crop.bottom.setStyleSheet(crop_text_color)
15781547
return crop
15791548

15801549
def disable_all(self):

fastflix/widgets/panels/advanced_panel.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from fastflix.models.video import VideoSettings
1212
from fastflix.resources import get_icon
1313
from fastflix.models.profiles import AdvancedOptions
14+
from fastflix.ui_styles import get_onyx_label_style
1415
from fastflix.flix import ffmpeg_valid_color_primaries, ffmpeg_valid_color_transfers, ffmpeg_valid_color_space
1516

1617
logger = logging.getLogger("fastflix")
@@ -138,7 +139,7 @@ def add_row_label(self, label, row_number):
138139
label = QtWidgets.QLabel(label)
139140
label.setFixedWidth(100)
140141
if self.app.fastflix.config.theme == "onyx":
141-
label.setStyleSheet("color: #b5b5b5")
142+
label.setStyleSheet(get_onyx_label_style(muted=True))
142143
self.layout.addWidget(label, row_number, 0, alignment=QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
143144

144145
def init_fps(self):
@@ -356,7 +357,7 @@ def init_hw_message(self):
356357
self.last_row += 1
357358
label = QtWidgets.QLabel("ʘ " + t("Not supported by rigaya's hardware encoders"))
358359
if self.app.fastflix.config.theme == "onyx":
359-
label.setStyleSheet("color: #b5b5b5")
360+
label.setStyleSheet(get_onyx_label_style(muted=True))
360361

361362
self.layout.addWidget(label, self.last_row, 0, 1, 2)
362363

fastflix/widgets/panels/audio_panel.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from fastflix.resources import get_icon
1515
from fastflix.ui_scale import scaler
1616
from fastflix.ui_constants import HEIGHTS, WIDTHS
17+
from fastflix.ui_styles import get_onyx_disposition_style
1718
from fastflix.shared import no_border, error_message, yes_no_message, clear_list
1819
from fastflix.widgets.panels.abstract_list import FlixList
1920
from fastflix.audio_processing import apply_audio_filters
@@ -341,18 +342,18 @@ def update_track(self, conversion=None, bitrate=None, downmix=None, title=None):
341342
def check_conversion_button(self):
342343
audio_track: AudioTrack = self.app.fastflix.current_video.audio_tracks[self.index]
343344
if audio_track.conversion_codec:
344-
self.widgets.conversion.setStyleSheet("border-color: #4a555e; background-color: #4a555e")
345+
self.widgets.conversion.setStyleSheet(get_onyx_disposition_style(enabled=True))
345346
self.widgets.conversion.setText(t("Conversion") + f": {audio_track.conversion_codec}")
346347
else:
347-
self.widgets.conversion.setStyleSheet("")
348+
self.widgets.conversion.setStyleSheet(get_onyx_disposition_style(enabled=False))
348349
self.widgets.conversion.setText(t("Conversion"))
349350

350351
def check_dis_button(self):
351352
audio_track: AudioTrack = self.app.fastflix.current_video.audio_tracks[self.index]
352353
if any(audio_track.dispositions.values()):
353-
self.widgets.disposition.setStyleSheet("border-color: #4a555e; background-color: #4a555e")
354+
self.widgets.disposition.setStyleSheet(get_onyx_disposition_style(enabled=True))
354355
else:
355-
self.widgets.disposition.setStyleSheet("")
356+
self.widgets.disposition.setStyleSheet(get_onyx_disposition_style(enabled=False))
356357

357358

358359
class AudioList(FlixList):

fastflix/widgets/panels/subtitle_panel.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from fastflix.resources import loading_movie, get_icon
1414
from fastflix.shared import error_message, no_border, clear_list
1515
from fastflix.ui_scale import scaler
16+
from fastflix.ui_styles import get_onyx_disposition_style
1617
from fastflix.widgets.background_tasks import ExtractSubtitleSRT
1718
from fastflix.widgets.panels.abstract_list import FlixList
1819
from fastflix.widgets.windows.disposition import Disposition
@@ -262,9 +263,9 @@ def page_update(self):
262263
def check_dis_button(self):
263264
track: SubtitleTrack = self.app.fastflix.current_video.subtitle_tracks[self.index]
264265
if any(track.dispositions.values()):
265-
self.widgets.disposition.setStyleSheet("border-color: #4a555e; background-color: #4a555e")
266+
self.widgets.disposition.setStyleSheet(get_onyx_disposition_style(enabled=True))
266267
else:
267-
self.widgets.disposition.setStyleSheet("")
268+
self.widgets.disposition.setStyleSheet(get_onyx_disposition_style(enabled=False))
268269

269270

270271
class SubtitleList(FlixList):

fastflix/widgets/video_options.py

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,13 @@
44
import logging
55
from typing import TYPE_CHECKING
66

7-
from PySide6 import QtGui, QtWidgets
7+
from PySide6 import QtCore, QtGui, QtWidgets
88

99
from fastflix.language import t
1010
from fastflix.models.fastflix_app import FastFlixApp
1111
from fastflix.resources import get_icon
1212
from fastflix.ui_scale import scaler
13+
from fastflix.ui_styles import ONYX_COLORS, get_onyx_combobox_style
1314
from fastflix.shared import DEVMODE, error_message
1415
from fastflix.widgets.panels.advanced_panel import AdvancedPanel
1516
from fastflix.widgets.panels.audio_panel import AudioList
@@ -64,13 +65,13 @@ def __init__(self, parent, app: FastFlixApp, available_audio_encoders):
6465
self.setStyleSheet(
6566
"QTabBar{ font-size: 13px; } "
6667
"QTabBar::tab{ border-top: 2px solid transparent; } "
67-
"QTabBar::tab:selected{ border-top: 2px solid #567781; } "
68+
f"QTabBar::tab:selected{{ border-top: 2px solid {ONYX_COLORS['primary']}; }} "
6869
"QLineEdit{ color: white; } "
6970
"QTextEdit{ color: white; } "
7071
"QPlainTextEdit{ color: white; } "
71-
"QComboBox{ min-height: 1.1em; background-color: #4a555e; color: white; border: 1px solid #4a555e; border-radius: 0px; }"
72+
f"QComboBox{{ min-height: 1.1em; {get_onyx_combobox_style()} }}"
7273
"QComboBox:hover{ background-color: #6a8a96; } "
73-
"QComboBox QAbstractItemView{ background-color: #1d2023; border: 2px solid #4a555e; } "
74+
f"QComboBox QAbstractItemView{{ background-color: {ONYX_COLORS['dark_bg']}; border: 2px solid {ONYX_COLORS['input_bg']}; }} "
7475
)
7576

7677
self.setIconSize(scaler.scale_size(20, 20))
@@ -92,6 +93,23 @@ def __init__(self, parent, app: FastFlixApp, available_audio_encoders):
9293
if DEVMODE:
9394
self.addTab(self.debug, QtGui.QIcon(get_icon("info", app.fastflix.config.theme)), "Debug")
9495

96+
# Add separator line below tabs for onyx theme
97+
self.tab_separator = None
98+
if self.app.fastflix.config.theme == "onyx":
99+
self.tab_separator = QtWidgets.QFrame(self)
100+
self.tab_separator.setFrameShape(QtWidgets.QFrame.HLine)
101+
self.tab_separator.setFixedHeight(3)
102+
self.tab_separator.setStyleSheet(f"background-color: {ONYX_COLORS['primary']};")
103+
self.tab_separator.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents)
104+
self.tab_separator.raise_()
105+
106+
def resizeEvent(self, event):
107+
super().resizeEvent(event)
108+
if self.tab_separator:
109+
# Position the separator right below the tab bar
110+
tab_bar_height = self.tabBar().height()
111+
self.tab_separator.setGeometry(0, tab_bar_height, self.width(), 3)
112+
95113
def resetTabIcons(self):
96114
for index, icon_name in icons.items():
97115
self.setTabIcon(index, QtGui.QIcon(get_icon(icon_name, self.app.fastflix.config.theme)))

0 commit comments

Comments
 (0)