#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 #include #include #include namespace { std::shared_ptr inf; bool c = PluginRegistry::enqueueRegistration([] { auto i = std::make_shared(); i->id = "graph"; i->displayName = "Subgraph"; i->createInstance = []{ return std::make_shared(); }; 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 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(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(chm.value("x").toInteger()); ch->y = static_cast(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(c[0].toInteger())]; auto in = children[static_cast(c[3].toInteger())]; auto op = on->port(Port::Output, static_cast(dtm.keyToValue(c[1].toString().toStdString().c_str())), static_cast(c[2].toInteger())); auto ip = in->port(Port::Input, static_cast(dtm.keyToValue(c[4].toString().toStdString().c_str())), static_cast(c[5].toInteger())); if (op && ip) op->connect(ip); } } } void Graph::onParent(std::shared_ptr) { // 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); }