feat: double-click a merge clip to set its join crossfade/curve override + row labels
This commit is contained in:
@@ -4684,6 +4684,7 @@ class MainWindow(QMainWindow):
|
||||
self._merge_list.setSelectionMode(
|
||||
QAbstractItemView.SelectionMode.SingleSelection)
|
||||
self._merge_list.setToolTip("Clips to merge, top to bottom")
|
||||
self._merge_list.itemDoubleClicked.connect(self._on_merge_item_double_clicked)
|
||||
self._merge_temps: set[str] = set()
|
||||
self._spn_crossfade = QDoubleSpinBox()
|
||||
self._spn_crossfade.setRange(0.0, 10.0)
|
||||
@@ -4695,9 +4696,7 @@ class MainWindow(QMainWindow):
|
||||
self._spn_crossfade.valueChanged.connect(
|
||||
lambda v: self._settings.setValue("audio_crossfade", v))
|
||||
self._cmb_curve = QComboBox()
|
||||
for label, name in (("Triangular", "tri"), ("Exponential", "exp"),
|
||||
("Logarithmic", "log"), ("Quarter sine", "qsin"),
|
||||
("Half sine", "hsin")):
|
||||
for label, name in self._MERGE_CURVES:
|
||||
self._cmb_curve.addItem(label, name)
|
||||
self._cmb_curve.setToolTip("Crossfade curve at each join")
|
||||
self._btn_merge_add_sel = QPushButton("+ Selection")
|
||||
@@ -5181,6 +5180,9 @@ class MainWindow(QMainWindow):
|
||||
APP_VERSION = "1.5"
|
||||
_SPLIT_HEADER_H = 22 # deck split-column header height (keep both deck spots in sync)
|
||||
_WAVE_MIN_VIEW = 3.0 # minimum waveform view window (seconds)
|
||||
_MERGE_CURVES = (("Triangular", "tri"), ("Exponential", "exp"),
|
||||
("Logarithmic", "log"), ("Quarter sine", "qsin"),
|
||||
("Half sine", "hsin"))
|
||||
CHANGELOG: list[tuple[str, list[str]]] = [
|
||||
("1.5", [
|
||||
"<b>Interactive waveform</b> — the Audio tab's waveform is now a "
|
||||
@@ -6760,9 +6762,29 @@ class MainWindow(QMainWindow):
|
||||
item.setData(Qt.ItemDataRole.UserRole + 2, None) # crossfade override (None = global)
|
||||
item.setData(Qt.ItemDataRole.UserRole + 3, None) # curve override (None = global)
|
||||
self._merge_list.addItem(item)
|
||||
self._refresh_merge_labels()
|
||||
finally:
|
||||
QApplication.restoreOverrideCursor()
|
||||
|
||||
def _merge_item_label(self, item, index: int, count: int) -> str:
|
||||
name = os.path.basename(item.data(Qt.ItemDataRole.UserRole))
|
||||
dur = item.data(Qt.ItemDataRole.UserRole + 1)
|
||||
base = f"{name} ({dur:.2f}s)" if dur is not None else name
|
||||
if index < count - 1: # has an outgoing join
|
||||
xo = item.data(Qt.ItemDataRole.UserRole + 2)
|
||||
co = item.data(Qt.ItemDataRole.UserRole + 3)
|
||||
if xo is not None or co is not None:
|
||||
xf = xo if xo is not None else self._spn_crossfade.value()
|
||||
cv = co if co is not None else self._cmb_curve.currentData()
|
||||
base += f" ⤲{xf:.2f}s {cv}" # ⤲ join marker
|
||||
return base
|
||||
|
||||
def _refresh_merge_labels(self) -> None:
|
||||
n = self._merge_list.count()
|
||||
for i in range(n):
|
||||
it = self._merge_list.item(i)
|
||||
it.setText(self._merge_item_label(it, i, n))
|
||||
|
||||
def _on_merge_add_file(self) -> None:
|
||||
default_dir = (self._settings.value("audio_extract_dir", "")
|
||||
or os.path.dirname(self._file_path or ""))
|
||||
@@ -6811,11 +6833,45 @@ class MainWindow(QMainWindow):
|
||||
item = self._merge_list.takeItem(row)
|
||||
self._merge_list.insertItem(new, item)
|
||||
self._merge_list.setCurrentRow(new)
|
||||
self._refresh_merge_labels()
|
||||
|
||||
def _merge_remove_selected(self) -> None:
|
||||
row = self._merge_list.currentRow()
|
||||
if row >= 0:
|
||||
self._merge_list.takeItem(row)
|
||||
self._refresh_merge_labels()
|
||||
|
||||
def _apply_merge_override(self, item, crossfade: float, curve: str) -> None:
|
||||
item.setData(Qt.ItemDataRole.UserRole + 2, float(crossfade))
|
||||
item.setData(Qt.ItemDataRole.UserRole + 3, curve)
|
||||
self._refresh_merge_labels()
|
||||
|
||||
def _on_merge_item_double_clicked(self, item) -> None:
|
||||
row = self._merge_list.row(item)
|
||||
if row >= self._merge_list.count() - 1:
|
||||
self._show_status("The last clip has no outgoing join to crossfade", 4000)
|
||||
return
|
||||
dlg = QDialog(self)
|
||||
dlg.setWindowTitle("Join crossfade")
|
||||
form = QFormLayout(dlg)
|
||||
spn = QDoubleSpinBox()
|
||||
spn.setRange(0.0, 10.0); spn.setDecimals(2); spn.setSingleStep(0.1); spn.setSuffix(" s")
|
||||
xo = item.data(Qt.ItemDataRole.UserRole + 2)
|
||||
spn.setValue(float(xo) if xo is not None else self._spn_crossfade.value())
|
||||
cmb = QComboBox()
|
||||
for label, name in self._MERGE_CURVES:
|
||||
cmb.addItem(label, name)
|
||||
co = item.data(Qt.ItemDataRole.UserRole + 3)
|
||||
co = co if co is not None else self._cmb_curve.currentData()
|
||||
idx = cmb.findData(co); cmb.setCurrentIndex(idx if idx >= 0 else 0)
|
||||
form.addRow("Crossfade:", spn)
|
||||
form.addRow("Curve:", cmb)
|
||||
bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok
|
||||
| QDialogButtonBox.StandardButton.Cancel)
|
||||
bb.accepted.connect(dlg.accept); bb.rejected.connect(dlg.reject)
|
||||
form.addRow(bb)
|
||||
if dlg.exec():
|
||||
self._apply_merge_override(item, spn.value(), cmb.currentData())
|
||||
|
||||
def _merge_paths(self) -> list[str]:
|
||||
return [self._merge_list.item(i).data(Qt.ItemDataRole.UserRole)
|
||||
|
||||
Reference in New Issue
Block a user