Game line names across languages; RSubtitle; editor in three columns
This commit is contained in:
@@ -4,7 +4,7 @@ import os
|
||||
import numpy as np
|
||||
from PySide6.QtCore import Qt, QTimer, Signal
|
||||
from PySide6.QtGui import QFont
|
||||
from PySide6.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QFileDialog, QGridLayout, QGroupBox,
|
||||
from PySide6.QtWidgets import (QCheckBox, QComboBox, QDoubleSpinBox, QFileDialog, QGridLayout, QGroupBox, QSplitter,
|
||||
QHBoxLayout, QLabel, QMessageBox, QProgressBar, QPushButton, QSlider,
|
||||
QVBoxLayout, QWidget)
|
||||
|
||||
@@ -60,9 +60,11 @@ class EditorPanel(QWidget):
|
||||
return w
|
||||
|
||||
def _build(self):
|
||||
"""Header on top; below, side by side (resizable): LISTEN | REPLACE (with the apply buttons) | SUBTITLE."""
|
||||
self.setObjectName("EditorPanel")
|
||||
lay = QVBoxLayout(self)
|
||||
lay.setContentsMargins(10, 8, 10, 8)
|
||||
lay.setContentsMargins(10, 6, 10, 6)
|
||||
lay.setSpacing(4)
|
||||
self.title = QLabel()
|
||||
self.title.setObjectName("EditorTitle")
|
||||
self.title.setTextInteractionFlags(Qt.TextInteractionFlag.TextSelectableByMouse)
|
||||
@@ -71,18 +73,21 @@ class EditorPanel(QWidget):
|
||||
f.setBold(True)
|
||||
f.setLetterSpacing(QFont.SpacingType.PercentageSpacing, 104)
|
||||
self.title.setFont(f)
|
||||
lay.addWidget(self.title)
|
||||
self.state = QLabel()
|
||||
self.state.setWordWrap(True)
|
||||
head = QHBoxLayout()
|
||||
head.addWidget(self.title, 1)
|
||||
head.addWidget(self.state, 0, Qt.AlignmentFlag.AlignRight | Qt.AlignmentFlag.AlignVCenter)
|
||||
lay.addLayout(head)
|
||||
self.meta = QLabel()
|
||||
self.meta.setWordWrap(True)
|
||||
self.meta.setObjectName("Muted")
|
||||
self.state = QLabel()
|
||||
self.state.setWordWrap(True)
|
||||
lay.addWidget(self.meta)
|
||||
lay.addWidget(self.state)
|
||||
|
||||
# listen ----------------------------------------------------------------------------------
|
||||
g = QGroupBox("LISTEN")
|
||||
gl = QGridLayout(g)
|
||||
gl.setVerticalSpacing(4)
|
||||
self.wf_orig = self._wave("orig")
|
||||
self.wf_inst = self._wave("inst")
|
||||
self.b_play_orig = self._btn("Original", "play", lambda: self.play("orig"), "Play the original (Space)", icons.STEEL)
|
||||
@@ -92,8 +97,6 @@ class EditorPanel(QWidget):
|
||||
icons.ACCENT)
|
||||
self.cb_loop = self._btn("Loop", "loop", None, "Repeat playback")
|
||||
self.cb_loop.setCheckable(True)
|
||||
self.vol_icon = QLabel()
|
||||
self.vol_icon.setPixmap(icons.icon("play", icons.MUTED).pixmap(14, 14))
|
||||
self.sl_vol = QSlider(Qt.Orientation.Horizontal)
|
||||
self.sl_vol.setRange(0, 100)
|
||||
self.sl_vol.setValue(80)
|
||||
@@ -103,39 +106,46 @@ class EditorPanel(QWidget):
|
||||
self.lbl_time = QLabel("0:00.00")
|
||||
self.lbl_time.setObjectName("Muted")
|
||||
gl.addWidget(QLabel("Original"), 0, 0)
|
||||
gl.addWidget(self.wf_orig, 0, 1, 1, 6)
|
||||
gl.addWidget(self.wf_orig, 0, 1)
|
||||
self.lbl_inst = QLabel("Installed")
|
||||
gl.addWidget(self.lbl_inst, 1, 0)
|
||||
gl.addWidget(self.wf_inst, 1, 1, 1, 6)
|
||||
gl.addWidget(self.wf_inst, 1, 1)
|
||||
row = QHBoxLayout()
|
||||
for w in (self.b_play_orig, self.b_play_inst, self.b_stop, self.b_ab, self.cb_loop, QLabel(" Volume"),
|
||||
self.sl_vol, self.lbl_time):
|
||||
for w in (self.b_play_orig, self.b_play_inst, self.b_stop):
|
||||
row.addWidget(w)
|
||||
row.addStretch(1)
|
||||
gl.addLayout(row, 2, 0, 1, 7)
|
||||
gl.addLayout(row, 2, 0, 1, 2)
|
||||
row = QHBoxLayout()
|
||||
for w in (self.b_ab, self.cb_loop, QLabel("Volume"), self.sl_vol, self.lbl_time):
|
||||
row.addWidget(w)
|
||||
row.addStretch(1)
|
||||
gl.addLayout(row, 3, 0, 1, 2)
|
||||
gl.setColumnStretch(1, 1)
|
||||
lay.addWidget(g)
|
||||
gl.setRowStretch(4, 1)
|
||||
self.wf_orig.seekRequested.connect(lambda t: self.play("orig", t))
|
||||
self.wf_inst.seekRequested.connect(lambda t: self.play("inst", t))
|
||||
listen = g
|
||||
|
||||
# replace ---------------------------------------------------------------------------------
|
||||
g = QGroupBox("REPLACE")
|
||||
rl = QVBoxLayout(g)
|
||||
rl.setSpacing(4)
|
||||
src = QHBoxLayout()
|
||||
self.b_load = self._btn("Load file…", "open", self.load_file_dialog,
|
||||
"WAV, FLAC, OGG, OPUS, MP3, AIFF (M4A/WMA need ffmpeg installed) (Ctrl+O)")
|
||||
self.cmb_in = QComboBox()
|
||||
self.cmb_in.setMinimumWidth(180)
|
||||
self.cmb_in.setMinimumWidth(110)
|
||||
self.cmb_in.setMaximumWidth(200)
|
||||
self.cmb_in.setToolTip("Recording device")
|
||||
self.b_rec = self._btn("Record", "record", self.toggle_record, "Record from the selected input")
|
||||
self.meter = QProgressBar()
|
||||
self.meter.setRange(0, 100)
|
||||
self.meter.setTextVisible(False)
|
||||
self.meter.setMaximumWidth(120)
|
||||
self.meter.setMaximumWidth(60)
|
||||
self.meter.setToolTip("Input level")
|
||||
self.lbl_rec = QLabel("")
|
||||
self.lbl_rec.setObjectName("Muted")
|
||||
for w in (self.b_load, QLabel(" or"), self.cmb_in, self.b_rec, self.meter, self.lbl_rec):
|
||||
for w in (self.b_load, self.cmb_in, self.b_rec, self.meter, self.lbl_rec):
|
||||
src.addWidget(w)
|
||||
src.addStretch(1)
|
||||
rl.addLayout(src)
|
||||
@@ -144,71 +154,82 @@ class EditorPanel(QWidget):
|
||||
self.wf_new.seekRequested.connect(lambda t: self.play("new", t))
|
||||
self.wf_new.selectionChanged.connect(self._selection)
|
||||
rl.addWidget(self.wf_new)
|
||||
proc = QHBoxLayout()
|
||||
self.sp_a = QDoubleSpinBox()
|
||||
self.sp_b = QDoubleSpinBox()
|
||||
for s_ in (self.sp_a, self.sp_b):
|
||||
s_.setDecimals(2)
|
||||
s_.setSuffix(" s")
|
||||
s_.setRange(0, 36000)
|
||||
s_.setMaximumWidth(92)
|
||||
s_.valueChanged.connect(self._changed)
|
||||
self.sp_gain = QDoubleSpinBox()
|
||||
self.sp_gain.setRange(-40, 40)
|
||||
self.sp_gain.setSuffix(" dB")
|
||||
self.sp_gain.setMaximumWidth(92)
|
||||
self.sp_gain.valueChanged.connect(self._changed)
|
||||
self.cb_norm = QCheckBox("Normalize")
|
||||
self.cb_match = QCheckBox("Match original loudness")
|
||||
self.cb_match = QCheckBox("Match loudness")
|
||||
self.cb_match.setToolTip("Match the loudness of the original sound")
|
||||
self.cb_norm.toggled.connect(self._changed)
|
||||
self.cb_match.toggled.connect(self._changed)
|
||||
self.b_silence = self._btn("Trim silence", None, self.trim_silence, "Cut silence at the start and end")
|
||||
self.b_play_new = self._btn("Replacement", "play", lambda: self.play("new"), "Play the processed replacement",
|
||||
icons.ACCENT)
|
||||
for w in (QLabel("Keep from"), self.sp_a, QLabel("to"), self.sp_b, self.b_silence, QLabel(" Gain"),
|
||||
self.sp_gain, self.cb_norm, self.cb_match, self.b_play_new):
|
||||
proc = QHBoxLayout()
|
||||
for w in (QLabel("Keep"), self.sp_a, QLabel("to"), self.sp_b, self.b_silence, self.b_play_new):
|
||||
proc.addWidget(w)
|
||||
proc.addStretch(1)
|
||||
rl.addLayout(proc)
|
||||
proc = QHBoxLayout()
|
||||
for w in (QLabel("Gain"), self.sp_gain, self.cb_norm, self.cb_match):
|
||||
proc.addWidget(w)
|
||||
proc.addStretch(1)
|
||||
rl.addLayout(proc)
|
||||
info = QHBoxLayout()
|
||||
self.lbl_new = QLabel()
|
||||
self.lbl_new.setWordWrap(True)
|
||||
self.lbl_new.setObjectName("Muted")
|
||||
self.lbl_new.setWordWrap(True)
|
||||
self.warn_icon = QLabel()
|
||||
self.warn_icon.setPixmap(icons.icon("warning", icons.ACCENT).pixmap(18, 18))
|
||||
self.warn_icon.hide()
|
||||
self.lbl_warn = QLabel()
|
||||
self.lbl_warn.setWordWrap(True)
|
||||
self.lbl_warn.setStyleSheet("color: %s;" % icons.ACCENT)
|
||||
self.lbl_new.setWordWrap(False)
|
||||
info.addWidget(self.lbl_new, 0, Qt.AlignmentFlag.AlignTop)
|
||||
info.addSpacing(12)
|
||||
info.addWidget(self.lbl_new, 1, Qt.AlignmentFlag.AlignTop)
|
||||
info.addWidget(self.warn_icon, 0, Qt.AlignmentFlag.AlignTop)
|
||||
info.addWidget(self.lbl_warn, 1)
|
||||
rl.addLayout(info)
|
||||
lay.addWidget(g)
|
||||
|
||||
# apply -----------------------------------------------------------------------------------
|
||||
# apply (belongs to the replacement) ------------------------------------------------------
|
||||
act = QHBoxLayout()
|
||||
self.b_apply = self._btn("Apply to game", "apply", self.apply,
|
||||
"Encode the replacement and install it in the game files (Ctrl+S)", "#ffffff")
|
||||
self.b_apply.setObjectName("Primary")
|
||||
self.b_revert = self._btn("Revert to original", "revert", self.revert, "Put the game's original back")
|
||||
self.b_export = self._btn("Save as WAV…", "save", self.export_wav,
|
||||
self.b_revert = self._btn("Revert", "revert", self.revert, "Put the game's original back")
|
||||
self.b_export = self._btn("Save WAV…", "save", self.export_wav,
|
||||
"Save the original (or the replacement) as a WAV file")
|
||||
self.busy = Spinner(16)
|
||||
self.lbl_busy = QLabel()
|
||||
for w in (self.b_apply, self.b_revert, self.b_export, self.busy, self.lbl_busy):
|
||||
act.addWidget(w)
|
||||
act.addStretch(1)
|
||||
lay.addLayout(act)
|
||||
rl.addStretch(1)
|
||||
rl.addLayout(act)
|
||||
replace = g
|
||||
|
||||
# subtitle of this sound (edited side by side with the audio) -------------------------------
|
||||
from .textpanel import SubtitleBox
|
||||
gs = QGroupBox("Subtitle")
|
||||
gs = QGroupBox("SUBTITLE")
|
||||
gsl = QVBoxLayout(gs)
|
||||
self.subtitle = SubtitleBox(self.ctx, gs)
|
||||
gsl.addWidget(self.subtitle)
|
||||
lay.addWidget(gs)
|
||||
lay.addStretch(1)
|
||||
gsl.addStretch(1)
|
||||
|
||||
self.columns = QSplitter(Qt.Orientation.Horizontal)
|
||||
self.columns.setChildrenCollapsible(False)
|
||||
for w, stretch in ((listen, 3), (replace, 4), (gs, 3)):
|
||||
self.columns.addWidget(w)
|
||||
self.columns.setStretchFactor(self.columns.count() - 1, stretch)
|
||||
lay.addWidget(self.columns, 1)
|
||||
|
||||
self.recorder.level.connect(lambda v: self.meter.setValue(int(min(1.0, v) * 100)))
|
||||
self.recorder.elapsed.connect(lambda t: self.lbl_rec.setText("recording %s" % fmt_s(t)))
|
||||
|
||||
Reference in New Issue
Block a user