Add video node visualization
This commit is contained in:
parent
d314ad7dd9
commit
8a8b039dcc
4 changed files with 56 additions and 7 deletions
|
|
@ -1252,6 +1252,8 @@ void GraphEditorWidget::rebuildMixerStrips() {
|
||||||
const WarpNodeData *data = m_model->warpNodeData(nodeId);
|
const WarpNodeData *data = m_model->warpNodeData(nodeId);
|
||||||
if (!data)
|
if (!data)
|
||||||
continue;
|
continue;
|
||||||
|
if (!nodeHasVolume(WarpGraphModel::classifyNode(data->info)))
|
||||||
|
continue;
|
||||||
|
|
||||||
auto *strip = new QWidget();
|
auto *strip = new QWidget();
|
||||||
strip->setStyleSheet(QStringLiteral(
|
strip->setStyleSheet(QStringLiteral(
|
||||||
|
|
|
||||||
|
|
@ -230,6 +230,9 @@ QVariant WarpGraphModel::portData(QtNodes::NodeId nodeId,
|
||||||
const auto &data = it->second;
|
const auto &data = it->second;
|
||||||
|
|
||||||
if (role == QtNodes::PortRole::DataType) {
|
if (role == QtNodes::PortRole::DataType) {
|
||||||
|
WarpNodeType ntype = classifyNode(data.info);
|
||||||
|
if (ntype == WarpNodeType::kVideoSource || ntype == WarpNodeType::kVideoSink)
|
||||||
|
return QString("video");
|
||||||
return QString("audio");
|
return QString("audio");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -479,9 +482,11 @@ void WarpGraphModel::refreshFromClient() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *volumeWidget = new NodeVolumeWidget();
|
if (nodeHasVolume(nodeType)) {
|
||||||
m_volumeWidgets[qtId] = volumeWidget;
|
auto *volumeWidget = new NodeVolumeWidget();
|
||||||
m_volumeStates[qtId] = {};
|
m_volumeWidgets[qtId] = volumeWidget;
|
||||||
|
m_volumeStates[qtId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
Q_EMIT nodeCreated(qtId);
|
Q_EMIT nodeCreated(qtId);
|
||||||
}
|
}
|
||||||
|
|
@ -801,6 +806,12 @@ WarpGraphModel::classifyNode(const warppipe::NodeInfo &info) {
|
||||||
if (mc == "Stream/Output/Audio" || mc == "Stream/Input/Audio") {
|
if (mc == "Stream/Output/Audio" || mc == "Stream/Input/Audio") {
|
||||||
return WarpNodeType::kApplication;
|
return WarpNodeType::kApplication;
|
||||||
}
|
}
|
||||||
|
if (mc == "Video/Source") {
|
||||||
|
return WarpNodeType::kVideoSource;
|
||||||
|
}
|
||||||
|
if (mc == "Video/Sink") {
|
||||||
|
return WarpNodeType::kVideoSink;
|
||||||
|
}
|
||||||
|
|
||||||
return WarpNodeType::kUnknown;
|
return WarpNodeType::kUnknown;
|
||||||
}
|
}
|
||||||
|
|
@ -1071,9 +1082,11 @@ bool WarpGraphModel::loadLayout(const QString &path) {
|
||||||
? m_positions.at(qtId)
|
? m_positions.at(qtId)
|
||||||
: QPointF(0, 0);
|
: QPointF(0, 0);
|
||||||
|
|
||||||
auto *volumeWidget = new NodeVolumeWidget();
|
if (nodeHasVolume(classifyNode(info))) {
|
||||||
m_volumeWidgets[qtId] = volumeWidget;
|
auto *volumeWidget = new NodeVolumeWidget();
|
||||||
m_volumeStates[qtId] = {};
|
m_volumeWidgets[qtId] = volumeWidget;
|
||||||
|
m_volumeStates[qtId] = {};
|
||||||
|
}
|
||||||
|
|
||||||
Q_EMIT nodeCreated(qtId);
|
Q_EMIT nodeCreated(qtId);
|
||||||
}
|
}
|
||||||
|
|
@ -1105,6 +1118,7 @@ void WarpGraphModel::autoArrange() {
|
||||||
Column sources;
|
Column sources;
|
||||||
Column apps;
|
Column apps;
|
||||||
Column sinks;
|
Column sinks;
|
||||||
|
Column video;
|
||||||
|
|
||||||
for (const auto &[qtId, data] : m_nodes) {
|
for (const auto &[qtId, data] : m_nodes) {
|
||||||
WarpNodeType type = classifyNode(data.info);
|
WarpNodeType type = classifyNode(data.info);
|
||||||
|
|
@ -1121,6 +1135,11 @@ void WarpGraphModel::autoArrange() {
|
||||||
apps.ids.push_back(qtId);
|
apps.ids.push_back(qtId);
|
||||||
apps.maxWidth = std::max(apps.maxWidth, w);
|
apps.maxWidth = std::max(apps.maxWidth, w);
|
||||||
break;
|
break;
|
||||||
|
case WarpNodeType::kVideoSource:
|
||||||
|
case WarpNodeType::kVideoSink:
|
||||||
|
video.ids.push_back(qtId);
|
||||||
|
video.maxWidth = std::max(video.maxWidth, w);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
sinks.ids.push_back(qtId);
|
sinks.ids.push_back(qtId);
|
||||||
sinks.maxWidth = std::max(sinks.maxWidth, w);
|
sinks.maxWidth = std::max(sinks.maxWidth, w);
|
||||||
|
|
@ -1146,6 +1165,10 @@ void WarpGraphModel::autoArrange() {
|
||||||
layoutColumn(apps, x);
|
layoutColumn(apps, x);
|
||||||
x += apps.maxWidth + kHorizontalGap * 3;
|
x += apps.maxWidth + kHorizontalGap * 3;
|
||||||
layoutColumn(sinks, x);
|
layoutColumn(sinks, x);
|
||||||
|
if (!video.ids.empty()) {
|
||||||
|
x += sinks.maxWidth + kHorizontalGap * 3;
|
||||||
|
layoutColumn(video, x);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant WarpGraphModel::styleForNode(WarpNodeType type, bool ghost) {
|
QVariant WarpGraphModel::styleForNode(WarpNodeType type, bool ghost) {
|
||||||
|
|
@ -1168,6 +1191,12 @@ QVariant WarpGraphModel::styleForNode(WarpNodeType type, bool ghost) {
|
||||||
case WarpNodeType::kApplication:
|
case WarpNodeType::kApplication:
|
||||||
base = QColor(138, 104, 72);
|
base = QColor(138, 104, 72);
|
||||||
break;
|
break;
|
||||||
|
case WarpNodeType::kVideoSource:
|
||||||
|
base = QColor(120, 80, 130);
|
||||||
|
break;
|
||||||
|
case WarpNodeType::kVideoSink:
|
||||||
|
base = QColor(100, 70, 140);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
base = QColor(86, 94, 108);
|
base = QColor(86, 94, 108);
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,21 @@ enum class WarpNodeType : uint8_t {
|
||||||
kVirtualSink,
|
kVirtualSink,
|
||||||
kVirtualSource,
|
kVirtualSource,
|
||||||
kApplication,
|
kApplication,
|
||||||
|
kVideoSource,
|
||||||
|
kVideoSink,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline bool nodeHasVolume(WarpNodeType type) {
|
||||||
|
switch (type) {
|
||||||
|
case WarpNodeType::kVideoSource:
|
||||||
|
case WarpNodeType::kVideoSink:
|
||||||
|
case WarpNodeType::kUnknown:
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct WarpNodeData {
|
struct WarpNodeData {
|
||||||
warppipe::NodeInfo info;
|
warppipe::NodeInfo info;
|
||||||
std::vector<warppipe::PortInfo> inputPorts;
|
std::vector<warppipe::PortInfo> inputPorts;
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,8 @@
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/catch_approx.hpp>
|
#include <catch2/catch_approx.hpp>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
warppipe::ConnectionOptions TestOptions() {
|
warppipe::ConnectionOptions TestOptions() {
|
||||||
|
|
@ -1093,7 +1095,8 @@ TEST_CASE("setNodeVolumeState syncs inline widget") {
|
||||||
ns.mute = true;
|
ns.mute = true;
|
||||||
model.setNodeVolumeState(qtId, ns);
|
model.setNodeVolumeState(qtId, ns);
|
||||||
|
|
||||||
REQUIRE(vol->volume() == 70);
|
// Cubic scaling: slider = cbrt(0.7) * 100 ≈ 89
|
||||||
|
REQUIRE(vol->volume() == static_cast<int>(std::round(std::cbrt(0.7f) * 100.0f)));
|
||||||
REQUIRE(vol->isMuted());
|
REQUIRE(vol->isMuted());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1139,6 +1142,8 @@ TEST_CASE("preset saves and loads volume state") {
|
||||||
}
|
}
|
||||||
REQUIRE(found);
|
REQUIRE(found);
|
||||||
|
|
||||||
|
tc.client->Test_SetNodeVolume(warppipe::NodeId{100650}, 1.0f, false);
|
||||||
|
|
||||||
WarpGraphModel model2(tc.client.get());
|
WarpGraphModel model2(tc.client.get());
|
||||||
model2.refreshFromClient();
|
model2.refreshFromClient();
|
||||||
auto qtId2 = model2.qtNodeIdForPw(100650);
|
auto qtId2 = model2.qtNodeIdForPw(100650);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue