xybrid/xybrid/data/graph.cpp

146 lines
4.5 KiB
C++

#include "graph.h"
using namespace Xybrid::Data;
#include "config/pluginregistry.h"
using namespace Xybrid::Config;
#include "data/project.h"
#include "uisocket.h"
#include "mainwindow.h"
#include "util/strings.h"
#include <QCborMap>
#include <QCborArray>
#include <QMetaType>
#include <QMetaEnum>
namespace {
std::shared_ptr<PluginInfo> inf;
bool c = PluginRegistry::enqueueRegistration([] {
auto i = std::make_shared<PluginInfo>();
i->id = "graph";
i->displayName = "Subgraph";
i->createInstance = []{ return std::make_shared<Graph>(); };
PluginRegistry::registerPlugin(i);
inf = i;
});
}
//std::string Graph::pluginName() const { return "Subgraph"; }
Graph::Graph() {
plugin = inf; // harder bind
}
// propagate
void Graph::reset() { for (auto c : children) c->reset(); }
void Graph::saveData(QCborMap& m) {
// graph properties
// ... maybe there will be some at some point
std::unordered_map<Node*, int> indices;
{ /* children */ } {
QCborArray c;
int idx = 0;
for (auto ch : children) {
if (!ch->plugin) continue;
indices[ch.get()] = idx++;
QCborMap chm;
chm.insert(QString("id"), QString::fromStdString(ch->plugin->id));
if (!ch->name.empty()) chm.insert(QString("name"), QString::fromStdString(ch->name));
chm.insert(QString("x"), ch->x);
chm.insert(QString("y"), ch->y);
ch->saveData(chm);
c << chm;
}
m.insert(QString("children"), c);
}
{ /* connections */ } {
// mapped from output to input
// array { oIdx, dataType, pIdx, iIdx, dataType, pIdx }
QCborArray cn;
for (auto ch : children) {
if (!ch->plugin) continue; // already skipped over
int idx = indices[ch.get()];
for (auto dt : ch->outputs) {
for (auto op : dt.second) {
auto o = op.second;
o->cleanConnections(); // let's just do some groundskeeping here
for (auto iw : o->connections) {
auto i = iw.lock();
QCborArray c;
c << idx;
c << Util::enumName(o->dataType());
c << o->index;
c << indices[i->owner.lock().get()];
c << Util::enumName(i->dataType());
c << i->index;
cn << c;
}
}
}
}
m.insert(QString("connections"), cn);
}
}
void Graph::loadData(QCborMap& m) {
auto g = std::static_pointer_cast<Graph>(shared_from_this());
// graph properties (none)
{ /* children */ } {
QCborArray c = m.value("children").toArray();
for (auto chmv : c) {
auto chm = chmv.toMap();
auto ch = PluginRegistry::createInstance(chm.value("id").toString().toStdString());
ch->parentTo(g);
ch->name = chm.value("name").toString().toStdString();
ch->x = static_cast<int>(chm.value("x").toInteger());
ch->y = static_cast<int>(chm.value("y").toInteger());
ch->loadData(chm);
}
}
{ /* connections */ } {
QCborArray cn = m.value("connections").toArray();
auto pmt = QMetaType::metaObjectForType(QMetaType::type("Xybrid::Data::Port"));
auto dtm = pmt->enumerator(pmt->indexOfEnumerator("DataType"));
for (auto cv : cn) {
auto c = cv.toArray();
if (c.empty()) continue;
auto on = children[static_cast<size_t>(c[0].toInteger())];
auto in = children[static_cast<size_t>(c[3].toInteger())];
auto op = on->port(Port::Output, static_cast<Port::DataType>(dtm.keyToValue(c[1].toString().toStdString().c_str())), static_cast<uint8_t>(c[2].toInteger()));
auto ip = in->port(Port::Input, static_cast<Port::DataType>(dtm.keyToValue(c[4].toString().toStdString().c_str())), static_cast<uint8_t>(c[5].toInteger()));
if (op && ip) op->connect(ip);
}
}
}
void Graph::onParent(std::shared_ptr<Graph>) {
// propagate project pointer
for (auto c : children) {
c->project = project;
// let this handle the recursion for us, since this is all this function does
if (c->plugin == inf) c->onParent(c->parent.lock());
}
}
void Graph::onDoubleClick() {
emit project->socket->openGraph(this);
}