From 2020fe6f8fa6fb4b69fc4660ff41022d371cf455 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Thu, 20 Feb 2025 10:42:29 +0100 Subject: [PATCH] [selection control] extract to own class, add signals and buttons --- fixtracks/widgets/selection_control.py | 248 +++++++++++++++++++++++++ 1 file changed, 248 insertions(+) create mode 100644 fixtracks/widgets/selection_control.py diff --git a/fixtracks/widgets/selection_control.py b/fixtracks/widgets/selection_control.py new file mode 100644 index 0000000..19e75f8 --- /dev/null +++ b/fixtracks/widgets/selection_control.py @@ -0,0 +1,248 @@ +import logging +import numpy as np + +from PySide6.QtCore import Qt, Signal, QSize +from PySide6.QtGui import QFont +from PySide6.QtWidgets import QWidget, QLabel, QPushButton, QSizePolicy +from PySide6.QtWidgets import QGridLayout, QVBoxLayout + + +class SelectionControls(QWidget): + fwd = Signal(float) + back = Signal(float) + assignOne = Signal() + assignTwo = Signal() + assignOther = Signal() + accept = Signal() + unaccept = Signal() + delete = Signal() + revertall = Signal() + + def __init__(self, parent = None,): + super().__init__(parent) + font = QFont() + font.setBold(True) + font.setPointSize(10) + fullstep = 1.0 + halfstep = 0.5 + quarterstep = 0.25 + + backBtn = QPushButton("|<<") + backBtn.setFont(font) + backBtn.setShortcut(Qt.Key.Key_Left) + backBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + backBtn.setToolTip(f"Go back to previous window ({backBtn.shortcut().toString()})") + backBtn.clicked.connect(lambda: self.on_Back(fullstep)) + halfstepBackBtn = QPushButton("<<") + halfstepBackBtn.setFont(font) + halfstepBackBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + halfstepBackBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Left) + halfstepBackBtn.setToolTip(f"Go back by half a window ({halfstepBackBtn.shortcut().toString()})") + halfstepBackBtn.clicked.connect(lambda: self.on_Back(halfstep)) + quarterstepBackBtn = QPushButton("<") + quarterstepBackBtn.setFont(font) + quarterstepBackBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Left) + quarterstepBackBtn.setToolTip(f"Go back by a quarter window ({quarterstepBackBtn.shortcut().toString()})") + quarterstepBackBtn.clicked.connect(lambda: self.on_Back(quarterstep)) + quarterstepBackBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + + + fwdBtn = QPushButton(">>|") + fwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + fwdBtn.setShortcut(Qt.Key.Key_Right) + fwdBtn.setFont(font) + fwdBtn.setToolTip(f"Proceed to next window ({fwdBtn.shortcut().toString()})") + fwdBtn.clicked.connect(lambda: self.on_Fwd(fullstep)) + halfstepFwdBtn = QPushButton(">>") + halfstepFwdBtn.setFont(font) + halfstepFwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + halfstepFwdBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Right) + halfstepFwdBtn.setToolTip(f"Proceed by half a window ({halfstepFwdBtn.shortcut().toString()})") + halfstepFwdBtn.clicked.connect(lambda: self.on_Fwd(halfstep)) + quarterstepFwdBtn = QPushButton(">") + quarterstepFwdBtn.setFont(font) + quarterstepFwdBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Right) + quarterstepFwdBtn.setToolTip(f"Proceed by a quarter window ({quarterstepFwdBtn.shortcut().toString()})") + quarterstepFwdBtn.clicked.connect(lambda: self.on_Fwd(quarterstep)) + quarterstepFwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + + assignOneBtn = QPushButton("Track One") + assignOneBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + assignOneBtn.setStyleSheet("QPushButton { background-color: orange; }") + assignOneBtn.setShortcut("Ctrl+1") + assignOneBtn.setToolTip(f"Assign current selection to Track One ({assignOneBtn.shortcut().toString()})") + assignOneBtn.setFont(font) + assignOneBtn.clicked.connect(self.on_TrackOne) + + assignTwoBtn = QPushButton("Track Two") + assignTwoBtn.setShortcut("Ctrl+2") + assignTwoBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + assignTwoBtn.setStyleSheet("QPushButton { background-color: green; }") + assignTwoBtn.setToolTip(f"Assign current selection to Track Two ({assignTwoBtn.shortcut().toString()})") + assignTwoBtn.setFont(font) + assignTwoBtn.clicked.connect(self.on_TrackTwo) + + assignOtherBtn = QPushButton("Other") + assignOtherBtn.setShortcut("Ctrl+0") + assignOtherBtn.setFont(font) + assignOtherBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + # assignOtherBtn.setStyleSheet("QPushButton { background-color: gray; }") + assignOtherBtn.setToolTip(f"Assign current selection to Unassigned ({assignOtherBtn.shortcut().toString()})") + assignOtherBtn.clicked.connect(self.on_TrackOther) + + acceptBtn = QPushButton("accept") + acceptBtn.setFont(font) + acceptBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + # acceptBtn.setStyleSheet("QPushButton { background-color: red; }") + acceptBtn.setToolTip(f"Accept assignments of current selection as TRUE") + acceptBtn.clicked.connect(self.on_Accept) + + unacceptBtn = QPushButton("un-accept") + unacceptBtn.setFont(font) + unacceptBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + # acceptBtn.setStyleSheet("QPushButton { background-color: red; }") + unacceptBtn.setToolTip(f"Revoke current selection TRUE status") + unacceptBtn.clicked.connect(self.on_Unaccept) + + deleteBtn = QPushButton("delete") + deleteBtn.setFont(font) + deleteBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + deleteBtn.setStyleSheet("QPushButton { background-color: red; }") + deleteBtn.setToolTip(f"DANGERZONE! Delete current selection of detections!") + deleteBtn.clicked.connect(self.on_Delete) + + revertBtn = QPushButton("revert assignments") + revertBtn.setFont(font) + revertBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + revertBtn.setStyleSheet("QPushButton { background-color: red; }") + revertBtn.setToolTip(f"DANGERZONE! Remove ALL assignments!") + revertBtn.clicked.connect(self.on_RevertAll) + + self.tone_selection = QLabel("0") + self.ttwo_selection = QLabel("0") + self.tother_selection = QLabel("0") + self.startframe = QLabel("0") + self.endframe = QLabel("0") + self._total = 0 + + grid = QGridLayout() + grid.addWidget(backBtn, 0, 0, 3, 2) + grid.addWidget(fwdBtn, 0, 6, 3, 2) + grid.addWidget(halfstepBackBtn, 3, 0, 2, 2) + grid.addWidget(halfstepFwdBtn, 3, 6, 2, 2) + grid.addWidget(quarterstepBackBtn, 5, 0, 2, 2) + grid.addWidget(quarterstepFwdBtn, 5, 6, 2, 2) + + cwLabel = QLabel("Current window:") + cwLabel.setFont(font) + grid.addWidget(cwLabel, 0, 2, 1, 4) + grid.addWidget(QLabel("start:"), 1, 2, 1, 2) + grid.addWidget(self.startframe, 1, 4, 1, 2, Qt.AlignmentFlag.AlignRight) + grid.addWidget(QLabel("end:"), 2, 2, 1, 2) + grid.addWidget(self.endframe, 2, 4, 1, 2, Qt.AlignmentFlag.AlignRight) + + csLabel = QLabel("Current selection:") + csLabel.setFont(font) + grid.addWidget(csLabel, 3, 2, 1, 4) + grid.addWidget(QLabel("track One:"), 4, 2, 1, 2) + grid.addWidget(self.tone_selection, 4, 4, 1, 2, Qt.AlignmentFlag.AlignRight) + grid.addWidget(QLabel("track Two:"), 5, 2, 1, 2) + grid.addWidget(self.ttwo_selection, 5, 4, 1, 2, Qt.AlignmentFlag.AlignRight) + grid.addWidget(QLabel("Unassigned:"), 6, 2, 1, 2) + grid.addWidget(self.tother_selection, 6, 4, 1, 2, Qt.AlignmentFlag.AlignRight) + + grid.addWidget(assignOneBtn, 7, 0, 1, 3) + grid.addWidget(assignOtherBtn, 7, 3, 1, 2) + grid.addWidget(assignTwoBtn, 7, 5, 1, 3) + grid.addWidget(acceptBtn, 8, 0, 1, 4) + grid.addWidget(unacceptBtn, 8, 4, 1, 4) + grid.addWidget(deleteBtn, 9, 0, 1, 4) + grid.addWidget(revertBtn, 9, 4, 1, 4) + + grid.setColumnStretch(0, 1) + grid.setColumnStretch(7, 1) + self.setLayout(grid) + self.setMaximumSize(QSize(400, 300)) + + def setWindow(self, start:int=0, end:int=0): + self.startframe.setText(f"{start:.0f}") + self.endframe.setText(f"{end:g}") + + def _updateNumbers(self, track): + labels = {1: self.tone_selection, 2: self.ttwo_selection, 3: self.tother_selection} + for k in labels: + if k == track: + labels[k].setText(str(self._total)) + else: + labels[k].setText("0") + + def on_Fwd(self, stepsize): + logging.debug("SelectionControls: forward step by %.2f", stepsize) + self.fwd.emit(stepsize) + + def on_Back(self, stepsize): + logging.debug("SelectionControls: backward step by %.2f", stepsize) + self.back.emit(stepsize) + + def on_TrackOne(self): + logging.debug("SelectionControl: TrackONEBtn") + self.assignOne.emit() + self._updateNumbers(1) + + def on_TrackTwo(self): + logging.debug("SelectionControl: TrackTWOBtn") + self.assignTwo.emit() + self._updateNumbers(2) + + def on_TrackOther(self): + logging.debug("SelectionControl: TrackOtherBtn") + self.assignOther.emit() + self._updateNumbers(3) + + def on_Accept(self): + logging.debug("SelectionControl: accept AssignmentBtn") + self.accept.emit() + + def on_Unaccept(self): + logging.debug("SelectionControl: revoke user assignmentBtn") + self.unaccept.emit() + + def on_RevertAll(self): + logging.debug("SelectionControl: revert Btn") + self.revertall.emit() + + def on_Delete(self): + logging.debug("SelectionControl: delete Btn") + self.delete.emit() + + def setSelectedTracks(self, tracks): + logging.debug("SelectionControl: setSelectedTracks") + if tracks is not None: + tone = np.sum(tracks == 1) + ttwo = np.sum(tracks == 2) + else: + tone = 0 + ttwo = 0 + + self.tone_selection.setText(str(tone)) + self.ttwo_selection.setText(str(ttwo)) + self.tother_selection.setText(str(len(tracks) - tone - ttwo if tracks is not None else 0)) + self._total = len(tracks) if tracks is not None else 0 + + +def main(): + from PySide6.QtWidgets import QApplication + logging.basicConfig(level=logging.DEBUG, force=True) + + app = QApplication([]) + window = QWidget() + window.setMinimumSize(200, 200) + layout = QVBoxLayout() + controls = SelectionControls() + layout.addWidget(controls) + window.setLayout(layout) + window.show() + app.exec() + +if __name__ == "__main__": + main()