164 lines
7.0 KiB
Python
164 lines
7.0 KiB
Python
"""Settings, mod export and mod import dialogs."""
|
|
import os
|
|
|
|
from PySide6.QtCore import Qt
|
|
from PySide6.QtWidgets import (QCheckBox, QComboBox, QDialog, QDialogButtonBox, QFileDialog, QFormLayout, QHBoxLayout,
|
|
QLabel, QLineEdit, QListWidget, QListWidgetItem, QPlainTextEdit, QPushButton, QSlider,
|
|
QTreeWidget, QTreeWidgetItem, QVBoxLayout)
|
|
|
|
from ackit.game import find_installs, is_game_dir
|
|
from .audioio import output_devices
|
|
|
|
|
|
def pick_game_dir(parent, start=""):
|
|
"""Folder chooser that explains what to pick (also Proton/Linux paths)."""
|
|
d = QFileDialog.getExistingDirectory(
|
|
parent, "Select the Batman: Arkham City folder (contains BmGame and Binaries)", start or os.path.expanduser("~"))
|
|
return d or None
|
|
|
|
|
|
class SettingsDialog(QDialog):
|
|
def __init__(self, settings, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Settings")
|
|
self.settings = dict(settings)
|
|
f = QFormLayout(self)
|
|
self.game = QLineEdit(settings.get("game_dir") or "")
|
|
b = QPushButton("Browse…")
|
|
b.clicked.connect(self._browse_game)
|
|
row = QHBoxLayout()
|
|
row.addWidget(self.game, 1)
|
|
row.addWidget(b)
|
|
found = find_installs()
|
|
hint = QLabel("Found via Steam: " + ("; ".join(found) if found else "none (Linux/Proton: "
|
|
"~/.steam/steam/steamapps/common/Batman Arkham City GOTY)"))
|
|
hint.setWordWrap(True)
|
|
f.addRow("Game folder", row)
|
|
f.addRow("", hint)
|
|
self.store = QLineEdit(settings.get("store_root") or "")
|
|
self.store.setPlaceholderText("default: in your user data folder")
|
|
b2 = QPushButton("Browse…")
|
|
b2.clicked.connect(lambda: self._browse(self.store))
|
|
row2 = QHBoxLayout()
|
|
row2.addWidget(self.store, 1)
|
|
row2.addWidget(b2)
|
|
f.addRow("Originals store", row2)
|
|
self.full = QCheckBox("Keep one full copy of each audio archive before its first change (safest)")
|
|
self.full.setChecked(settings.get("full_backup", True))
|
|
f.addRow("", self.full)
|
|
self.out = QComboBox()
|
|
self.out.addItem("Default output")
|
|
for d in output_devices():
|
|
self.out.addItem(d.description())
|
|
if settings.get("output_device"):
|
|
i = self.out.findText(settings["output_device"])
|
|
if i >= 0:
|
|
self.out.setCurrentIndex(i)
|
|
f.addRow("Playback device", self.out)
|
|
# appearance
|
|
self.bg_on = QCheckBox("Show the Arkham City wallpaper behind the filters")
|
|
self.bg_on.setChecked(settings.get("background_enabled", True))
|
|
f.addRow("Background", self.bg_on)
|
|
self.opacity = QSlider(Qt.Orientation.Horizontal)
|
|
self.opacity.setRange(0, 100)
|
|
self.opacity.setValue(int(round(float(settings.get("background_opacity", 0.1)) * 100)))
|
|
f.addRow("Background strength", self.opacity)
|
|
self.bg_on.toggled.connect(self.opacity.setEnabled)
|
|
self.opacity.setEnabled(self.bg_on.isChecked())
|
|
bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
bb.accepted.connect(self.accept)
|
|
bb.rejected.connect(self.reject)
|
|
f.addRow(bb)
|
|
self.resize(640, 0)
|
|
|
|
def _browse_game(self):
|
|
d = pick_game_dir(self, self.game.text())
|
|
if d:
|
|
self.game.setText(d)
|
|
|
|
def _browse(self, edit):
|
|
d = QFileDialog.getExistingDirectory(self, "Choose folder", edit.text())
|
|
if d:
|
|
edit.setText(d)
|
|
|
|
def values(self):
|
|
s = dict(self.settings)
|
|
gd = self.game.text().strip()
|
|
s["game_dir"] = gd if is_game_dir(gd) else s.get("game_dir")
|
|
s["store_root"] = self.store.text().strip() or None
|
|
s["full_backup"] = self.full.isChecked()
|
|
s["output_device"] = self.out.currentText() if self.out.currentIndex() > 0 else None
|
|
s["background_enabled"] = self.bg_on.isChecked()
|
|
s["background_opacity"] = self.opacity.value() / 100.0
|
|
return s
|
|
|
|
|
|
class ExportModDialog(QDialog):
|
|
"""Pick which modified sounds go into a .acmod package."""
|
|
|
|
def __init__(self, items, parent=None):
|
|
"""items: [(key, name)]"""
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Export mod package")
|
|
lay = QVBoxLayout(self)
|
|
f = QFormLayout()
|
|
self.title = QLineEdit()
|
|
self.author = QLineEdit()
|
|
self.desc = QPlainTextEdit()
|
|
self.desc.setMaximumHeight(70)
|
|
f.addRow("Title", self.title)
|
|
f.addRow("Author", self.author)
|
|
f.addRow("Description", self.desc)
|
|
lay.addLayout(f)
|
|
lay.addWidget(QLabel("Sounds to include:"))
|
|
self.list = QListWidget()
|
|
for key, name in items:
|
|
it = QListWidgetItem(name)
|
|
it.setData(Qt.ItemDataRole.UserRole, key)
|
|
it.setFlags(it.flags() | Qt.ItemFlag.ItemIsUserCheckable)
|
|
it.setCheckState(Qt.CheckState.Checked)
|
|
self.list.addItem(it)
|
|
lay.addWidget(self.list)
|
|
bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Save | QDialogButtonBox.StandardButton.Cancel)
|
|
bb.accepted.connect(self.accept)
|
|
bb.rejected.connect(self.reject)
|
|
lay.addWidget(bb)
|
|
self.resize(520, 480)
|
|
|
|
def selected_keys(self):
|
|
return [self.list.item(i).data(Qt.ItemDataRole.UserRole) for i in range(self.list.count())
|
|
if self.list.item(i).checkState() == Qt.CheckState.Checked]
|
|
|
|
|
|
class ImportModDialog(QDialog):
|
|
"""Shows how each item of a package matches this game before installing."""
|
|
|
|
def __init__(self, manifest, items, parent=None):
|
|
super().__init__(parent)
|
|
self.setWindowTitle("Import mod package")
|
|
lay = QVBoxLayout(self)
|
|
head = "<b>%s</b>" % (manifest.get("name") or "Mod package")
|
|
if manifest.get("author"):
|
|
head += " by %s" % manifest["author"]
|
|
lab = QLabel(head + ("<br>" + manifest["description"] if manifest.get("description") else ""))
|
|
lab.setWordWrap(True)
|
|
lay.addWidget(lab)
|
|
self.tree = QTreeWidget()
|
|
self.tree.setHeaderLabels(["Sound", "Match", "Note"])
|
|
n_ok = 0
|
|
for im in items:
|
|
note = {"exact": "same sound", "by name": "matched by name (other language) - will be re-encoded",
|
|
"missing": im.note}[im.how]
|
|
QTreeWidgetItem(self.tree, [im.item.get("name") or im.item["target"], im.how, note])
|
|
n_ok += im.how != "missing"
|
|
self.tree.resizeColumnToContents(0)
|
|
lay.addWidget(self.tree)
|
|
lay.addWidget(QLabel("%d of %d sounds will be installed." % (n_ok, len(items))))
|
|
bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel)
|
|
bb.button(QDialogButtonBox.StandardButton.Ok).setText("Install")
|
|
bb.button(QDialogButtonBox.StandardButton.Ok).setEnabled(n_ok > 0)
|
|
bb.accepted.connect(self.accept)
|
|
bb.rejected.connect(self.reject)
|
|
lay.addWidget(bb)
|
|
self.resize(720, 420)
|