refactor: populate Crop & Scan tabs; menu-only buttons hidden; drop settings row

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-13 11:54:10 +02:00
parent c55693094d
commit d1fb35af8e
2 changed files with 72 additions and 29 deletions
+45 -29
View File
@@ -4318,30 +4318,9 @@ class MainWindow(QMainWindow):
self._transport_row = transport_row
self._rebuild_subprofile_buttons()
# Row 2 — annotation + output path widgets now live in the Export tab
# of the control deck (_build_export_tab); path_row is no longer mounted.
# Row 3 — crop & scan controls (encode/clip controls moved to the
# Export tab via _build_export_tab; crop/scan move to their own tabs
# in a later stage and stay mounted here until then).
settings_row = QHBoxLayout()
settings_row.addWidget(QLabel("Portrait:"))
settings_row.addWidget(self._cmb_portrait)
settings_row.addWidget(self._chk_rand_portrait)
settings_row.addWidget(self._chk_rand_square)
settings_row.addWidget(self._chk_track)
settings_row.addWidget(self._cmb_scan_model)
settings_row.addWidget(self._btn_model_history)
settings_row.addWidget(self._btn_scan)
settings_row.addWidget(self._btn_speech)
settings_row.addWidget(self._btn_scan_mode)
settings_row.addWidget(self._btn_hide_subcats)
settings_row.addWidget(self._btn_auto_export)
settings_row.addWidget(self._spn_auto_fuse)
settings_row.addWidget(self._sld_threshold)
settings_row.addWidget(self._btn_train)
settings_row.addWidget(self._btn_scan_all)
settings_row.addStretch()
# Row 2/3 — annotation, output path, crop and scan controls all live in
# the control deck's tabs now (_build_export_tab / _build_crop_tab /
# _build_scan_tab); path_row and settings_row are no longer mounted.
right = QWidget()
right_layout = QVBoxLayout(right)
@@ -4354,7 +4333,8 @@ class MainWindow(QMainWindow):
right_layout.addLayout(transport_row)
right_layout.addWidget(self._build_control_deck())
self._build_export_tab()
right_layout.addLayout(settings_row)
self._build_crop_tab()
self._build_scan_tab()
# Left: queue header + playlist
self._btn_open = QPushButton("+ Open Files")
@@ -4405,6 +4385,21 @@ class MainWindow(QMainWindow):
self._build_menubar()
self._build_status_bar()
# Reverse-sync the Scan tab's Review toggle back to the View ▸ Review
# mode action (the forward sync was wired in _build_menubar). Done here
# because _act_review only exists after _build_menubar(). setChecked
# does not re-emit on an unchanged value, so this cannot loop.
self._btn_scan_mode.toggled.connect(self._act_review.setChecked)
# Menu-only buttons (Train, Scan All, Sub) are reached via the menu bar
# now, but other code still references them (enable/disable, text). Keep
# the objects, re-parent to the window, and hide so they are not stray
# top-level windows.
for _b in (self._btn_train, self._btn_scan_all, self._btn_hide_subcats):
_b.setParent(self); _b.hide()
# Pin the deck height (after all tabs are populated) so switching tabs
# doesn't resize the video.
self._control_deck.setFixedHeight(self._control_deck.sizeHint().height())
# Root: horizontal splitter
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(left)
@@ -4511,6 +4506,28 @@ class MainWindow(QMainWindow):
g.addWidget(QLabel("Workers:"), 4, 0); g.addWidget(self._spn_workers, 4, 1)
g.addWidget(self._btn_reexport, 4, 5)
def _build_crop_tab(self) -> None:
from PyQt6.QtWidgets import QGridLayout
g = QGridLayout(self._tab_crop)
g.setContentsMargins(8, 6, 8, 6); g.setHorizontalSpacing(8); g.setVerticalSpacing(6)
g.addWidget(QLabel("Portrait:"), 0, 0); g.addWidget(self._cmb_portrait, 0, 1)
g.addWidget(self._chk_rand_portrait, 1, 0, 1, 2)
g.addWidget(self._chk_rand_square, 2, 0, 1, 2)
g.addWidget(self._chk_track, 3, 0, 1, 2)
g.setRowStretch(4, 1); g.setColumnStretch(2, 1)
def _build_scan_tab(self) -> None:
from PyQt6.QtWidgets import QGridLayout, QHBoxLayout
g = QGridLayout(self._tab_scan)
g.setContentsMargins(8, 6, 8, 6); g.setHorizontalSpacing(8); g.setVerticalSpacing(6)
model_row = QHBoxLayout()
model_row.addWidget(self._cmb_scan_model, 1); model_row.addWidget(self._btn_model_history)
g.addWidget(QLabel("Model:"), 0, 0); g.addLayout(model_row, 0, 1, 1, 3)
g.addWidget(self._btn_scan, 1, 0); g.addWidget(self._btn_auto_export, 1, 1)
g.addWidget(self._btn_speech, 1, 2); g.addWidget(self._btn_scan_mode, 1, 3)
g.addWidget(self._spn_auto_fuse, 2, 0); g.addWidget(self._sld_threshold, 2, 1)
g.setColumnStretch(3, 1)
# ── Menu bar ─────────────────────────────────────────────
def _build_menubar(self) -> None:
@@ -6070,6 +6087,7 @@ class MainWindow(QMainWindow):
def _show_subcat_menu(self) -> None:
from PyQt6.QtWidgets import QMenu, QWidgetAction, QCheckBox, QWidget, QVBoxLayout, QPushButton, QHBoxLayout
from PyQt6.QtGui import QCursor
menu = QMenu(self)
menu.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
base = os.path.basename(self._txt_folder.text())
@@ -6090,8 +6108,7 @@ class MainWindow(QMainWindow):
folders = sorted(folder_set)
if not folders:
menu.addAction("(no subcategories)").setEnabled(False)
menu.exec(self._btn_hide_subcats.mapToGlobal(
self._btn_hide_subcats.rect().bottomLeft()))
menu.exec(QCursor.pos())
return
container = QWidget()
@@ -6144,8 +6161,7 @@ class MainWindow(QMainWindow):
wa = QWidgetAction(menu)
wa.setDefaultWidget(container)
menu.addAction(wa)
menu.exec(self._btn_hide_subcats.mapToGlobal(
self._btn_hide_subcats.rect().bottomLeft()))
menu.exec(QCursor.pos())
def _disable_all_subcats(self) -> None:
"""Disable every enabled subcategory at once (across all videos)."""
+27
View File
@@ -27,3 +27,30 @@ def win(app):
def test_window_constructs(win):
assert win.windowTitle().startswith("8-cut")
def test_status_bar_exists(win):
assert win.statusBar() is not None
def test_workers_spinbox_in_export_tab(win):
from PyQt6.QtWidgets import QSpinBox
assert win._spn_workers in win._tab_export.findChildren(QSpinBox)
def test_scan_button_in_scan_tab(win):
from PyQt6.QtWidgets import QPushButton
assert win._btn_scan in win._tab_scan.findChildren(QPushButton)
def test_portrait_combo_in_crop_tab(win):
from PyQt6.QtWidgets import QComboBox
assert win._cmb_portrait in win._tab_crop.findChildren(QComboBox)
def test_menu_only_buttons_not_in_deck(win):
from PyQt6.QtWidgets import QPushButton
deck_btns = win._control_deck.findChildren(QPushButton)
assert win._btn_train not in deck_btns
assert win._btn_scan_all not in deck_btns
assert win._btn_hide_subcats not in deck_btns