GUI M8d
This commit is contained in:
parent
e649dea9c1
commit
a07f94c93d
10 changed files with 718 additions and 25 deletions
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../../gui/GraphEditorWidget.h"
|
||||
#include "../../gui/PresetManager.h"
|
||||
#include "../../gui/VolumeWidgets.h"
|
||||
#include "../../gui/WarpGraphModel.h"
|
||||
|
||||
#include <QAction>
|
||||
|
|
@ -963,3 +964,214 @@ TEST_CASE("splitter sizes persist in layout JSON") {
|
|||
|
||||
QFile::remove(path);
|
||||
}
|
||||
|
||||
TEST_CASE("model volume state defaults to 1.0 and unmuted") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100600, "vol-default", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100600);
|
||||
REQUIRE(qtId != 0);
|
||||
|
||||
auto state = model.nodeVolumeState(qtId);
|
||||
REQUIRE(state.volume == Catch::Approx(1.0f));
|
||||
REQUIRE_FALSE(state.mute);
|
||||
}
|
||||
|
||||
TEST_CASE("setNodeVolumeState updates model and calls test helper") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100610, "vol-set", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100610);
|
||||
REQUIRE(qtId != 0);
|
||||
|
||||
WarpGraphModel::NodeVolumeState ns;
|
||||
ns.volume = 0.5f;
|
||||
ns.mute = true;
|
||||
model.setNodeVolumeState(qtId, ns);
|
||||
|
||||
auto state = model.nodeVolumeState(qtId);
|
||||
REQUIRE(state.volume == Catch::Approx(0.5f));
|
||||
REQUIRE(state.mute);
|
||||
|
||||
auto apiState = tc.client->Test_GetNodeVolume(warppipe::NodeId{100610});
|
||||
REQUIRE(apiState.ok());
|
||||
REQUIRE(apiState.value.volume == Catch::Approx(0.5f));
|
||||
REQUIRE(apiState.value.mute);
|
||||
}
|
||||
|
||||
TEST_CASE("nodeVolumeChanged signal emitted on state change") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100620, "vol-signal", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100620);
|
||||
REQUIRE(qtId != 0);
|
||||
|
||||
bool signalFired = false;
|
||||
QObject::connect(&model, &WarpGraphModel::nodeVolumeChanged,
|
||||
[&](QtNodes::NodeId id, WarpGraphModel::NodeVolumeState prev,
|
||||
WarpGraphModel::NodeVolumeState cur) {
|
||||
if (id == qtId) {
|
||||
signalFired = true;
|
||||
REQUIRE(prev.volume == Catch::Approx(1.0f));
|
||||
REQUIRE(cur.volume == Catch::Approx(0.3f));
|
||||
REQUIRE(cur.mute);
|
||||
}
|
||||
});
|
||||
|
||||
WarpGraphModel::NodeVolumeState ns;
|
||||
ns.volume = 0.3f;
|
||||
ns.mute = true;
|
||||
model.setNodeVolumeState(qtId, ns);
|
||||
REQUIRE(signalFired);
|
||||
}
|
||||
|
||||
TEST_CASE("volume widget created for new nodes") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100630, "vol-widget", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100630);
|
||||
REQUIRE(qtId != 0);
|
||||
|
||||
auto widget = model.nodeData(qtId, QtNodes::NodeRole::Widget);
|
||||
REQUIRE(widget.isValid());
|
||||
auto *w = widget.value<QWidget *>();
|
||||
REQUIRE(w != nullptr);
|
||||
auto *vol = qobject_cast<NodeVolumeWidget *>(w);
|
||||
REQUIRE(vol != nullptr);
|
||||
REQUIRE(vol->volume() == 100);
|
||||
REQUIRE_FALSE(vol->isMuted());
|
||||
}
|
||||
|
||||
TEST_CASE("setNodeVolumeState syncs inline widget") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100640, "vol-sync", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100640);
|
||||
auto *w = model.nodeData(qtId, QtNodes::NodeRole::Widget).value<QWidget *>();
|
||||
auto *vol = qobject_cast<NodeVolumeWidget *>(w);
|
||||
REQUIRE(vol != nullptr);
|
||||
|
||||
WarpGraphModel::NodeVolumeState ns;
|
||||
ns.volume = 0.7f;
|
||||
ns.mute = true;
|
||||
model.setNodeVolumeState(qtId, ns);
|
||||
|
||||
REQUIRE(vol->volume() == 70);
|
||||
REQUIRE(vol->isMuted());
|
||||
}
|
||||
|
||||
TEST_CASE("preset saves and loads volume state") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100650, "vol-preset", "Audio/Sink", {}, {}, true)).ok());
|
||||
REQUIRE(tc.client->Test_InsertPort(
|
||||
MakePort(100651, 100650, "FL", true)).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100650);
|
||||
WarpGraphModel::NodeVolumeState ns;
|
||||
ns.volume = 0.6f;
|
||||
ns.mute = true;
|
||||
model.setNodeVolumeState(qtId, ns);
|
||||
|
||||
QString path = QStandardPaths::writableLocation(
|
||||
QStandardPaths::TempLocation) +
|
||||
"/warppipe_test_vol_preset.json";
|
||||
REQUIRE(PresetManager::savePreset(path, tc.client.get(), &model));
|
||||
|
||||
QFile file(path);
|
||||
REQUIRE(file.open(QIODevice::ReadOnly));
|
||||
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
|
||||
file.close();
|
||||
QJsonObject root = doc.object();
|
||||
REQUIRE(root.contains("volumes"));
|
||||
QJsonArray volArr = root["volumes"].toArray();
|
||||
bool found = false;
|
||||
for (const auto &val : volArr) {
|
||||
QJsonObject obj = val.toObject();
|
||||
if (obj["name"].toString() == "vol-preset") {
|
||||
found = true;
|
||||
REQUIRE(obj["volume"].toDouble() == Catch::Approx(0.6));
|
||||
REQUIRE(obj["mute"].toBool());
|
||||
}
|
||||
}
|
||||
REQUIRE(found);
|
||||
|
||||
WarpGraphModel model2(tc.client.get());
|
||||
model2.refreshFromClient();
|
||||
auto qtId2 = model2.qtNodeIdForPw(100650);
|
||||
auto stateBefore = model2.nodeVolumeState(qtId2);
|
||||
REQUIRE(stateBefore.volume == Catch::Approx(1.0f));
|
||||
|
||||
REQUIRE(PresetManager::loadPreset(path, tc.client.get(), &model2));
|
||||
auto stateAfter = model2.nodeVolumeState(qtId2);
|
||||
REQUIRE(stateAfter.volume == Catch::Approx(0.6f));
|
||||
REQUIRE(stateAfter.mute);
|
||||
|
||||
QFile::remove(path);
|
||||
}
|
||||
|
||||
TEST_CASE("volume state cleaned up on node deletion") {
|
||||
auto tc = TestClient::Create();
|
||||
if (!tc.available()) { SUCCEED("PipeWire unavailable"); return; }
|
||||
ensureApp();
|
||||
|
||||
REQUIRE(tc.client->Test_InsertNode(
|
||||
MakeNode(100660, "vol-del", "Audio/Sink")).ok());
|
||||
|
||||
WarpGraphModel model(tc.client.get());
|
||||
model.refreshFromClient();
|
||||
|
||||
auto qtId = model.qtNodeIdForPw(100660);
|
||||
WarpGraphModel::NodeVolumeState ns;
|
||||
ns.volume = 0.4f;
|
||||
model.setNodeVolumeState(qtId, ns);
|
||||
|
||||
REQUIRE(tc.client->Test_RemoveGlobal(100660).ok());
|
||||
model.refreshFromClient();
|
||||
REQUIRE_FALSE(model.nodeExists(qtId));
|
||||
|
||||
auto state = model.nodeVolumeState(qtId);
|
||||
REQUIRE(state.volume == Catch::Approx(1.0f));
|
||||
REQUIRE_FALSE(state.mute);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue