GUI Milestone 8b
This commit is contained in:
parent
3a8450cb70
commit
4a248e5622
6 changed files with 682 additions and 37 deletions
|
|
@ -361,6 +361,23 @@ void WarpGraphModel::refreshFromClient() {
|
|||
}
|
||||
|
||||
if (m_ghostNodes.erase(qtId)) {
|
||||
std::vector<QtNodes::ConnectionId> gcToRemove;
|
||||
for (auto gcIt = m_ghostConnections.begin();
|
||||
gcIt != m_ghostConnections.end();) {
|
||||
if (gcIt->outNodeId == qtId || gcIt->inNodeId == qtId) {
|
||||
gcToRemove.push_back(*gcIt);
|
||||
gcIt = m_ghostConnections.erase(gcIt);
|
||||
} else {
|
||||
++gcIt;
|
||||
}
|
||||
}
|
||||
for (const auto &gc : gcToRemove) {
|
||||
auto cIt = m_connections.find(gc);
|
||||
if (cIt != m_connections.end()) {
|
||||
m_connections.erase(cIt);
|
||||
Q_EMIT connectionDeleted(gc);
|
||||
}
|
||||
}
|
||||
Q_EMIT nodeUpdated(qtId);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -379,6 +396,25 @@ void WarpGraphModel::refreshFromClient() {
|
|||
|
||||
if (ghostMatch != 0) {
|
||||
m_ghostNodes.erase(ghostMatch);
|
||||
{
|
||||
std::vector<QtNodes::ConnectionId> gcToRemove;
|
||||
for (auto gcIt = m_ghostConnections.begin();
|
||||
gcIt != m_ghostConnections.end();) {
|
||||
if (gcIt->outNodeId == ghostMatch || gcIt->inNodeId == ghostMatch) {
|
||||
gcToRemove.push_back(*gcIt);
|
||||
gcIt = m_ghostConnections.erase(gcIt);
|
||||
} else {
|
||||
++gcIt;
|
||||
}
|
||||
}
|
||||
for (const auto &gc : gcToRemove) {
|
||||
auto cIt = m_connections.find(gc);
|
||||
if (cIt != m_connections.end()) {
|
||||
m_connections.erase(cIt);
|
||||
Q_EMIT connectionDeleted(gc);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_pwToQt.emplace(nodeInfo.id.value, ghostMatch);
|
||||
auto &data = m_nodes[ghostMatch];
|
||||
data.info = nodeInfo;
|
||||
|
|
@ -528,17 +564,73 @@ void WarpGraphModel::refreshFromClient() {
|
|||
for (uint32_t linkId : staleLinkIds) {
|
||||
auto it = m_linkIdToConn.find(linkId);
|
||||
if (it != m_linkIdToConn.end()) {
|
||||
auto connIt = m_connections.find(it->second);
|
||||
if (connIt != m_connections.end()) {
|
||||
QtNodes::ConnectionId connId = it->second;
|
||||
m_connections.erase(connIt);
|
||||
Q_EMIT connectionDeleted(connId);
|
||||
QtNodes::ConnectionId connId = it->second;
|
||||
bool outIsGhost =
|
||||
m_ghostNodes.find(connId.outNodeId) != m_ghostNodes.end();
|
||||
bool inIsGhost =
|
||||
m_ghostNodes.find(connId.inNodeId) != m_ghostNodes.end();
|
||||
|
||||
if (outIsGhost || inIsGhost) {
|
||||
m_ghostConnections.insert(connId);
|
||||
} else {
|
||||
auto connIt = m_connections.find(connId);
|
||||
if (connIt != m_connections.end()) {
|
||||
m_connections.erase(connIt);
|
||||
Q_EMIT connectionDeleted(connId);
|
||||
}
|
||||
}
|
||||
m_linkIdToConn.erase(it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_pendingGhostConnections.empty()) {
|
||||
auto it = m_pendingGhostConnections.begin();
|
||||
while (it != m_pendingGhostConnections.end()) {
|
||||
QtNodes::NodeId outQtId = 0;
|
||||
QtNodes::NodeId inQtId = 0;
|
||||
for (const auto &[qtId, data] : m_nodes) {
|
||||
if (data.info.name == it->outNodeName)
|
||||
outQtId = qtId;
|
||||
if (data.info.name == it->inNodeName)
|
||||
inQtId = qtId;
|
||||
}
|
||||
if (outQtId == 0 || inQtId == 0) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto outNodeIt = m_nodes.find(outQtId);
|
||||
auto inNodeIt = m_nodes.find(inQtId);
|
||||
QtNodes::PortIndex outIdx = -1;
|
||||
QtNodes::PortIndex inIdx = -1;
|
||||
for (size_t i = 0; i < outNodeIt->second.outputPorts.size(); ++i) {
|
||||
if (outNodeIt->second.outputPorts[i].name == it->outPortName) {
|
||||
outIdx = static_cast<QtNodes::PortIndex>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < inNodeIt->second.inputPorts.size(); ++i) {
|
||||
if (inNodeIt->second.inputPorts[i].name == it->inPortName) {
|
||||
inIdx = static_cast<QtNodes::PortIndex>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (outIdx < 0 || inIdx < 0) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
|
||||
QtNodes::ConnectionId connId{outQtId, outIdx, inQtId, inIdx};
|
||||
if (m_connections.find(connId) == m_connections.end()) {
|
||||
m_connections.insert(connId);
|
||||
m_ghostConnections.insert(connId);
|
||||
Q_EMIT connectionCreated(connId);
|
||||
}
|
||||
it = m_pendingGhostConnections.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
m_refreshing = false;
|
||||
}
|
||||
|
||||
|
|
@ -644,6 +736,12 @@ WarpGraphModel::classifyNode(const warppipe::NodeInfo &info) {
|
|||
}
|
||||
|
||||
void WarpGraphModel::saveLayout(const QString &path) const {
|
||||
ViewState vs{};
|
||||
saveLayout(path, vs);
|
||||
}
|
||||
|
||||
void WarpGraphModel::saveLayout(const QString &path,
|
||||
const ViewState &viewState) const {
|
||||
QJsonArray nodesArray;
|
||||
for (const auto &[qtId, data] : m_nodes) {
|
||||
auto posIt = m_positions.find(qtId);
|
||||
|
|
@ -657,9 +755,85 @@ void WarpGraphModel::saveLayout(const QString &path) const {
|
|||
nodesArray.append(nodeObj);
|
||||
}
|
||||
|
||||
QJsonArray ghostsArray;
|
||||
for (const auto &ghostId : m_ghostNodes) {
|
||||
auto nodeIt = m_nodes.find(ghostId);
|
||||
if (nodeIt == m_nodes.end()) {
|
||||
continue;
|
||||
}
|
||||
const auto &data = nodeIt->second;
|
||||
QJsonObject ghostObj;
|
||||
ghostObj["name"] = QString::fromStdString(data.info.name);
|
||||
ghostObj["description"] = QString::fromStdString(data.info.description);
|
||||
ghostObj["media_class"] = QString::fromStdString(data.info.media_class);
|
||||
ghostObj["application_name"] =
|
||||
QString::fromStdString(data.info.application_name);
|
||||
|
||||
auto posIt = m_positions.find(ghostId);
|
||||
if (posIt != m_positions.end()) {
|
||||
ghostObj["x"] = posIt->second.x();
|
||||
ghostObj["y"] = posIt->second.y();
|
||||
}
|
||||
|
||||
QJsonArray inPorts;
|
||||
for (const auto &port : data.inputPorts) {
|
||||
QJsonObject p;
|
||||
p["id"] = static_cast<int>(port.id.value);
|
||||
p["name"] = QString::fromStdString(port.name);
|
||||
inPorts.append(p);
|
||||
}
|
||||
ghostObj["input_ports"] = inPorts;
|
||||
|
||||
QJsonArray outPorts;
|
||||
for (const auto &port : data.outputPorts) {
|
||||
QJsonObject p;
|
||||
p["id"] = static_cast<int>(port.id.value);
|
||||
p["name"] = QString::fromStdString(port.name);
|
||||
outPorts.append(p);
|
||||
}
|
||||
ghostObj["output_ports"] = outPorts;
|
||||
|
||||
ghostsArray.append(ghostObj);
|
||||
}
|
||||
|
||||
QJsonArray ghostConnsArray;
|
||||
for (const auto &conn : m_ghostConnections) {
|
||||
auto outIt = m_nodes.find(conn.outNodeId);
|
||||
auto inIt = m_nodes.find(conn.inNodeId);
|
||||
if (outIt == m_nodes.end() || inIt == m_nodes.end()) {
|
||||
continue;
|
||||
}
|
||||
auto outIdx = static_cast<size_t>(conn.outPortIndex);
|
||||
auto inIdx = static_cast<size_t>(conn.inPortIndex);
|
||||
if (outIdx >= outIt->second.outputPorts.size() ||
|
||||
inIdx >= inIt->second.inputPorts.size()) {
|
||||
continue;
|
||||
}
|
||||
QJsonObject connObj;
|
||||
connObj["out_node"] =
|
||||
QString::fromStdString(outIt->second.info.name);
|
||||
connObj["out_port"] =
|
||||
QString::fromStdString(outIt->second.outputPorts[outIdx].name);
|
||||
connObj["in_node"] =
|
||||
QString::fromStdString(inIt->second.info.name);
|
||||
connObj["in_port"] =
|
||||
QString::fromStdString(inIt->second.inputPorts[inIdx].name);
|
||||
ghostConnsArray.append(connObj);
|
||||
}
|
||||
|
||||
QJsonObject root;
|
||||
root["version"] = 1;
|
||||
root["version"] = 2;
|
||||
root["nodes"] = nodesArray;
|
||||
root["ghosts"] = ghostsArray;
|
||||
root["ghost_connections"] = ghostConnsArray;
|
||||
|
||||
if (viewState.valid) {
|
||||
QJsonObject viewObj;
|
||||
viewObj["scale"] = viewState.scale;
|
||||
viewObj["center_x"] = viewState.centerX;
|
||||
viewObj["center_y"] = viewState.centerY;
|
||||
root["view"] = viewObj;
|
||||
}
|
||||
|
||||
QFileInfo fi(path);
|
||||
QDir dir = fi.absoluteDir();
|
||||
|
|
@ -673,6 +847,15 @@ void WarpGraphModel::saveLayout(const QString &path) const {
|
|||
}
|
||||
}
|
||||
|
||||
void WarpGraphModel::clearSavedPositions() {
|
||||
m_savedPositions.clear();
|
||||
m_positions.clear();
|
||||
}
|
||||
|
||||
WarpGraphModel::ViewState WarpGraphModel::savedViewState() const {
|
||||
return m_savedViewState;
|
||||
}
|
||||
|
||||
bool WarpGraphModel::loadLayout(const QString &path) {
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
|
|
@ -685,7 +868,8 @@ bool WarpGraphModel::loadLayout(const QString &path) {
|
|||
}
|
||||
|
||||
QJsonObject root = doc.object();
|
||||
if (root["version"].toInt() != 1) {
|
||||
int version = root["version"].toInt();
|
||||
if (version < 1 || version > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -698,7 +882,97 @@ bool WarpGraphModel::loadLayout(const QString &path) {
|
|||
double y = obj["y"].toDouble();
|
||||
m_savedPositions[name] = QPointF(x, y);
|
||||
}
|
||||
return !m_savedPositions.empty();
|
||||
|
||||
m_savedViewState = {};
|
||||
if (root.contains("view")) {
|
||||
QJsonObject viewObj = root["view"].toObject();
|
||||
m_savedViewState.scale = viewObj["scale"].toDouble(1.0);
|
||||
m_savedViewState.centerX = viewObj["center_x"].toDouble();
|
||||
m_savedViewState.centerY = viewObj["center_y"].toDouble();
|
||||
m_savedViewState.valid = true;
|
||||
}
|
||||
|
||||
if (root.contains("ghosts")) {
|
||||
QJsonArray ghostsArray = root["ghosts"].toArray();
|
||||
for (const auto &val : ghostsArray) {
|
||||
QJsonObject obj = val.toObject();
|
||||
std::string name = obj["name"].toString().toStdString();
|
||||
|
||||
bool alreadyExists = false;
|
||||
for (const auto &[_, data] : m_nodes) {
|
||||
if (data.info.name == name) {
|
||||
alreadyExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (alreadyExists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
warppipe::NodeInfo info;
|
||||
info.id = warppipe::NodeId{0};
|
||||
info.name = name;
|
||||
info.description = obj["description"].toString().toStdString();
|
||||
info.media_class = obj["media_class"].toString().toStdString();
|
||||
info.application_name =
|
||||
obj["application_name"].toString().toStdString();
|
||||
|
||||
WarpNodeData data;
|
||||
data.info = info;
|
||||
|
||||
for (const auto &pval : obj["input_ports"].toArray()) {
|
||||
QJsonObject p = pval.toObject();
|
||||
warppipe::PortInfo port;
|
||||
port.id = warppipe::PortId{
|
||||
static_cast<uint32_t>(p["id"].toInt())};
|
||||
port.node = info.id;
|
||||
port.name = p["name"].toString().toStdString();
|
||||
port.is_input = true;
|
||||
data.inputPorts.push_back(port);
|
||||
}
|
||||
for (const auto &pval : obj["output_ports"].toArray()) {
|
||||
QJsonObject p = pval.toObject();
|
||||
warppipe::PortInfo port;
|
||||
port.id = warppipe::PortId{
|
||||
static_cast<uint32_t>(p["id"].toInt())};
|
||||
port.node = info.id;
|
||||
port.name = p["name"].toString().toStdString();
|
||||
port.is_input = false;
|
||||
data.outputPorts.push_back(port);
|
||||
}
|
||||
|
||||
QtNodes::NodeId qtId = newNodeId();
|
||||
m_nodes.emplace(qtId, std::move(data));
|
||||
m_ghostNodes.insert(qtId);
|
||||
|
||||
if (obj.contains("x") && obj.contains("y")) {
|
||||
m_positions.emplace(qtId, QPointF(obj["x"].toDouble(),
|
||||
obj["y"].toDouble()));
|
||||
}
|
||||
m_savedPositions[name] =
|
||||
m_positions.count(qtId)
|
||||
? m_positions.at(qtId)
|
||||
: QPointF(0, 0);
|
||||
|
||||
Q_EMIT nodeCreated(qtId);
|
||||
}
|
||||
}
|
||||
|
||||
if (root.contains("ghost_connections")) {
|
||||
m_pendingGhostConnections.clear();
|
||||
QJsonArray gcArray = root["ghost_connections"].toArray();
|
||||
for (const auto &val : gcArray) {
|
||||
QJsonObject obj = val.toObject();
|
||||
PendingGhostConnection pgc;
|
||||
pgc.outNodeName = obj["out_node"].toString().toStdString();
|
||||
pgc.outPortName = obj["out_port"].toString().toStdString();
|
||||
pgc.inNodeName = obj["in_node"].toString().toStdString();
|
||||
pgc.inPortName = obj["in_port"].toString().toStdString();
|
||||
m_pendingGhostConnections.push_back(std::move(pgc));
|
||||
}
|
||||
}
|
||||
|
||||
return !m_savedPositions.empty() || !m_ghostNodes.empty();
|
||||
}
|
||||
|
||||
void WarpGraphModel::autoArrange() {
|
||||
|
|
@ -788,7 +1062,6 @@ QVariant WarpGraphModel::styleForNode(WarpNodeType type, bool ghost) {
|
|||
style.FontColorFaded = QColor(120, 128, 142);
|
||||
style.ConnectionPointColor = QColor(140, 148, 160);
|
||||
style.FilledConnectionPointColor = QColor(180, 140, 80);
|
||||
style.Opacity = 0.6f;
|
||||
} else {
|
||||
style.GradientColor0 = base.lighter(120);
|
||||
style.GradientColor1 = base.lighter(108);
|
||||
|
|
@ -799,9 +1072,9 @@ QVariant WarpGraphModel::styleForNode(WarpNodeType type, bool ghost) {
|
|||
style.FontColorFaded = QColor(160, 168, 182);
|
||||
style.ConnectionPointColor = QColor(200, 208, 220);
|
||||
style.FilledConnectionPointColor = QColor(255, 165, 0);
|
||||
style.Opacity = 1.0f;
|
||||
}
|
||||
|
||||
style.Opacity = 1.0f;
|
||||
style.SelectedBoundaryColor = QColor(255, 165, 0);
|
||||
style.PenWidth = 1.3f;
|
||||
style.HoveredPenWidth = 2.4f;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue