46 #include <objc/message.h>
49 int VuoRendererComposition::gridOpacity = 0;
73 this->renderMissingAsPresent = renderMissingAsPresent;
74 this->renderNodeActivity =
false;
75 this->renderPortActivity =
false;
95 addNodeInCompositionToCanvas(node);
108 addCableInCompositionToCanvas(cable);
117 addCommentInCompositionToCanvas(comment);
133 setBackgroundBrush(Qt::transparent);
175 if (
getBase()->hasCompiler() && nodeShouldBeGivenUniqueIdentifier)
180 if (nodeShouldBeRendered)
181 addNodeInCompositionToCanvas(n);
192 void VuoRendererComposition::addNodeInCompositionToCanvas(
VuoNode *n)
196 if (renderMissingAsPresent)
213 addCableInCompositionToCanvas(c);
221 void VuoRendererComposition::addCableInCompositionToCanvas(
VuoCable *c)
254 addCommentInCompositionToCanvas(c);
262 void VuoRendererComposition::addCommentInCompositionToCanvas(
VuoComment *c)
288 rc->
setTo(NULL, NULL);
312 QList<QGraphicsItem *> componentsAttached;
317 if (attachments.empty())
318 componentsAttached.append(createAndConnectDrawersToReadOnlyDictionaryInputPorts(node, compiler, createButDoNotAdd));
321 componentsAttached.append(createAndConnectDrawersToListInputPorts(node, compiler, createButDoNotAdd));
323 return componentsAttached;
329 QList<QGraphicsItem *> VuoRendererComposition::createAndConnectDrawersToListInputPorts(
VuoRendererNode *node,
VuoCompiler *compiler,
bool createButDoNotAdd)
331 QList<QGraphicsItem *> componentsAttached;
343 componentsAttached.append(cable);
346 componentsAttached.append(makeListNode);
348 if (!createButDoNotAdd)
357 return componentsAttached;
363 QList<QGraphicsItem *> VuoRendererComposition::createAndConnectDrawersToReadOnlyDictionaryInputPorts(
VuoRendererNode *node,
VuoCompiler *compiler,
bool createButDoNotAdd)
365 set<VuoRendererNode *> nodesToAdd;
366 set<VuoRendererCable *> cablesToAdd;
369 QList<QGraphicsItem *> componentsAttached;
371 componentsAttached.append(node);
373 componentsAttached.append(cable);
375 if (!createButDoNotAdd)
384 return componentsAttached;
400 rendererCable = NULL;
405 vector<string> itemInitialValues;
409 json_object *js = json_tokener_parse(listInitialValue.c_str());
410 if (json_object_get_type(js) == json_type_array)
412 int itemCount = json_object_array_length(js);
413 for (
int i = 0; i < itemCount; ++i)
415 json_object *itemObject = json_object_array_get_idx(js, i);
416 string itemString = json_object_to_json_string_ext(itemObject, JSON_C_TO_STRING_PLAIN);
417 itemInitialValues.push_back(itemString);
423 unsigned long itemCount = (itemInitialValues.empty() ? 2 : itemInitialValues.size());
431 for (
size_t i = 0; i < itemInitialValues.size(); ++i)
444 return makeListRendererNode;
458 set<VuoRendererNode *> &createdNodes,
459 set<VuoRendererCable *> &createdCables)
461 createdNodes.clear();
462 createdCables.clear();
466 if (!(expressionInputPort && valuesInputPort))
468 VUserLog(
"Error: Cannot create dictionary attachments for a node without 'expression' and 'values' input ports.");
473 const string dictionaryTypeName =
"VuoDictionary_VuoText_VuoReal";
474 const string dictionaryClassName =
"vuo.dictionary.make.VuoText.VuoReal";
475 const string dictionaryKeySourceTypeName =
"VuoMathExpressionList";
495 unsigned long itemCount = inputVariables.size();
504 if (keyListNodeClass && valueListNodeClass && dictionaryNodeClass)
508 QPoint offset(-220, 50);
509 VuoNode *dictionaryNode = compiler->
createNode(dictionaryNodeClass,
"", node->
getX()+offset.x(), node->
getY()+offset.y());
530 for (
size_t i = 0; i < itemCount; ++i)
533 string key =
"\"" + inputVariables[i] +
"\"";
557 vector<string> inputVariables;
559 json_object *js = json_tokener_parse(constant.c_str());
562 if (json_object_object_get_ex(js,
"inputVariables", &expressionsObject))
564 if (json_object_get_type(expressionsObject) == json_type_array)
566 int variableCount = json_object_array_length(expressionsObject);
567 for (
int i = 0; i < variableCount; ++i)
569 json_object *itemObject = json_object_array_get_idx(expressionsObject, i);
570 if (json_object_get_type(itemObject) == json_type_string)
572 const char *variableName = json_object_get_string(itemObject);
573 if (nodeClassName ==
"vuo.math.calculate.list"
574 && (strcasecmp(variableName,
"x") == 0
575 || strcasecmp(variableName,
"i") == 0))
578 inputVariables.push_back(json_object_get_string(itemObject));
585 return inputVariables;
606 if (isPublishedInput)
614 else if (publishedPort != existingPort)
615 VUserLog(
"Error: Unhandled published port name conflict.");
625 else if (publishedPort != existingPort)
626 VUserLog(
"Error: Unhandled published port name conflict.");
638 if (isPublishedInput)
670 VuoNode * VuoRendererComposition::createPublishedInputNode()
681 VuoNode * VuoRendererComposition::createPublishedOutputNode()
693 auto isNameAvailable = [
this] (
const string &name)
695 return (! name.empty() &&
718 vector<VuoRendererNode *> typecastsCollapsed;
730 return typecastsCollapsed;
763 if (outCables.size() != 1)
766 VuoCable *outCable = *(outCables.begin());
774 for (vector<VuoCable *>::iterator i = inCables.begin(); !incomingDataCable && (i != inCables.end()); ++i)
776 if ((*i)->hasRenderer() && (*i)->getRenderer()->effectivelyCarriesData())
777 incomingDataCable = *i;
779 if (! incomingDataCable)
793 if (! (fromNode && fromPort && toNode && toPort))
828 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
830 cable->
getRenderer()->setCacheMode(defaultCacheMode);
834 foreach (
VuoCable *cable, outCables)
838 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
840 cable->
getRenderer()->setCacheMode(defaultCacheMode);
848 typecastInPort->
getRenderer()->setParentItem(toRN);
901 VuoCable * outCable = *(outCables.begin());
910 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
912 cable->
getRenderer()->setCacheMode(defaultCacheMode);
920 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
922 cable->
getRenderer()->setCacheMode(defaultCacheMode);
929 typecastInPort->
getRenderer()->setParentItem(uncollapsedNode);
946 return uncollapsedNode;
973 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
975 QGraphicsItem::CacheMode normalCacheMode = (*inputPort)->getRenderer()->cacheMode();
976 (*inputPort)->getRenderer()->setCacheMode(QGraphicsItem::NoCache);
978 (*inputPort)->getRenderer()->updateGeometry();
981 (*inputPort)->getRenderer()->setCacheMode(normalCacheMode);
986 QGraphicsItem::CacheMode normalCacheMode = typecastPort->
getChildPort()->cacheMode();
987 typecastPort->
getChildPort()->setCacheMode(QGraphicsItem::NoCache);
992 typecastPort->
getChildPort()->setCacheMode(normalCacheMode);
997 for(vector<VuoPort *>::iterator outputPort = outputPorts.begin(); outputPort != outputPorts.end(); ++outputPort)
999 QGraphicsItem::CacheMode normalCacheMode = (*outputPort)->getRenderer()->cacheMode();
1000 (*outputPort)->getRenderer()->setCacheMode(QGraphicsItem::NoCache);
1002 (*outputPort)->getRenderer()->updateGeometry();
1005 (*outputPort)->getRenderer()->setCacheMode(normalCacheMode);
1010 QGraphicsItem::CacheMode normalCacheMode = rn->cacheMode();
1011 rn->setCacheMode(QGraphicsItem::NoCache);
1016 rn->setCacheMode(normalCacheMode);
1022 QGraphicsItem::CacheMode normalCacheMode = rc->cacheMode();
1023 rc->setCacheMode(QGraphicsItem::NoCache);
1028 rc->setCacheMode(normalCacheMode);
1059 return this->renderNodeActivity;
1069 return (this->renderNodeActivity && this->renderPortActivity);
1080 QGraphicsScene::drawBackground(painter, rect);
1084 painter->setRenderHint(QPainter::Antialiasing,
true);
1085 painter->setPen(QPen(QColor(255,0,0,128),5));
1086 painter->drawRect(sceneRect());
1087 QVector<QPointF> points;
1088 points << QPointF(0,0);
1089 points << sceneRect().topLeft();
1090 points << sceneRect().center();
1091 points << sceneRect().bottomRight();
1092 foreach (QPointF p, points)
1094 painter->setPen(QPen(QColor(255,0,0,128),5));
1095 painter->drawEllipse(p, 5, 5);
1096 painter->setPen(QColor(255,0,0,128));
1097 painter->drawText(p + QPointF(5,15) - (p == sceneRect().bottomRight() ? QPointF(70,20) : QPointF(0,0)), QString(
"(%1,%2)").arg(p.x()).arg(p.y()));
1099 painter->setRenderHint(QPainter::Antialiasing,
false);
1103 if (gridType != NoGrid)
1108 if (leftmostGridLine < rect.left())
1109 leftmostGridLine += gridSpacing;
1111 if (topmostGridLine < rect.top())
1112 topmostGridLine += gridSpacing;
1117 const int nodeXAlignmentCorrection = -1;
1119 if (gridType == LineGrid)
1121 QVector<QLineF> gridLines;
1122 for (qreal x = leftmostGridLine; x < rect.right(); x += gridSpacing)
1123 gridLines.append(QLineF(x + nodeXAlignmentCorrection, rect.top(), x + nodeXAlignmentCorrection, rect.bottom()));
1124 for (qreal y = topmostGridLine; y < rect.bottom(); y += gridSpacing)
1125 gridLines.append(QLineF(rect.left(), y, rect.right(), y));
1127 painter->setPen(QColor(128, 128, 128, VuoRendererComposition::gridOpacity * 32));
1128 painter->drawLines(gridLines);
1130 else if (gridType == PointGrid)
1132 painter->setRenderHint(QPainter::Antialiasing,
true);
1133 painter->setPen(Qt::NoPen);
1134 painter->setBrush(QColor(128, 128, 128, VuoRendererComposition::gridOpacity * 128));
1136 for (qreal y = topmostGridLine; y < rect.bottom(); y += gridSpacing)
1137 for (qreal x = leftmostGridLine; x < rect.right(); x += gridSpacing)
1139 painter->drawEllipse(QPointF(x + nodeXAlignmentCorrection + .5, y + .5), 1.5,1.5);
1152 if ((this->renderNodeActivity == render) && (this->renderPortActivity == includePortActivity))
1155 this->renderNodeActivity = render;
1156 this->renderPortActivity = includePortActivity;
1164 if (includePortActivity)
1217 foreach (
VuoCable *cable, allCables)
1221 rc->setCacheMode(cacheMode);
1232 return ((
cachingEnabled && !renderNodeActivity)? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
1243 Class poolClass = objc_getClass(
"NSAutoreleasePool");
1244 ((void (*)(id, SEL))objc_msgSend)((
id)poolClass, sel_getUid(
"new"));
1267 string modifiedRelativeResourcePath = modifyResourcePathForBundle(url);
1268 rp->
setConstant(
"\"" + modifiedRelativeResourcePath +
"\"");
1282 map<VuoPort *, string> modifiedPathForPort;
1295 QString origRelativeResourcePath = url;
1296 string modifiedRelativeResourcePath = modifyResourcePathForNewDir(origRelativeResourcePath.toUtf8().constData(), newDir);
1298 if (modifiedRelativeResourcePath != origRelativeResourcePath.toUtf8().constData())
1299 modifiedPathForPort[port] =
"\"" + modifiedRelativeResourcePath +
"\"";
1305 return modifiedPathForPort;
1315 string quotedIconURL =
"\"" + iconURL +
"\"";
1320 QString origRelativeResourcePath = url;
1323 if (!isRelativePath)
1326 return modifyResourcePathForNewDir(origRelativeResourcePath.toUtf8().constData(), newDir);
1354 QString origRelativeResourcePath = url;
1355 QString modifiedRelativeResourcePath = modifyResourcePathForBundle(origRelativeResourcePath.toUtf8().constData()).c_str();
1357 string origRelativeDir, modifiedRelativeDir, file, ext;
1360 string resourceFileName = file;
1363 resourceFileName +=
".";
1364 resourceFileName += ext;
1367 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1368 QDir appDir(QDir(targetResourceDir.c_str()).canonicalPath());
1370 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1371 if (!tmpFilesOnly ||
isTmpFile(sourceFilePath.toUtf8().constData()))
1373 if (!modifiedRelativeDir.empty())
1374 appDir.mkpath(modifiedRelativeDir.c_str());
1376 QString targetFilePath = appDir.filePath(QDir(modifiedRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1382 bundleAuxiliaryFilesForSceneFile(sourceFilePath, targetFilePath);
1392 string quotedIconURL =
"\"" + iconURL +
"\"";
1397 QString origRelativeResourcePath = url;
1399 if (iconHasRelativePath)
1401 QString modifiedRelativeResourcePath = modifyResourcePathForBundle(origRelativeResourcePath.toUtf8().constData()).c_str();
1403 string origRelativeDir, modifiedRelativeDir, file, ext;
1406 string resourceFileName = file;
1409 resourceFileName +=
".";
1410 resourceFileName += ext;
1413 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1414 QDir appDir(QDir(targetResourceDir.c_str()).canonicalPath());
1416 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1417 if (!tmpFilesOnly ||
isTmpFile(sourceFilePath.toUtf8().constData()))
1419 if (!modifiedRelativeDir.empty())
1420 appDir.mkpath(modifiedRelativeDir.c_str());
1422 QString targetFilePath = (!bundledIconPath.isEmpty()? bundledIconPath :
1423 appDir.filePath(QDir(modifiedRelativeDir.c_str()).filePath(resourceFileName.c_str())));
1426 if (QString(ext.c_str()).toLower() ==
"icns")
1428 VDebugLog(
"Copying \"%s\" (app icon)", url);
1434 VDebugLog(
"Converting \"%s\" (app icon)", url);
1435 QPixmap icon(sourceFilePath);
1436 QFile file(targetFilePath);
1437 file.open(QIODevice::WriteOnly);
1438 icon.save(&file,
"ICNS");
1454 QDir parentDir(QDir(QFileInfo(filePath.c_str()).dir()).canonicalPath());
1458 if (parentDir.canonicalPath() == tmpDirPath)
1460 }
while (parentDir.cdUp());
1469 string VuoRendererComposition::modifyResourcePathForBundle(
string path)
1476 const QString originalParentDirIndicator =
"/../";
1477 const QString appBundleParentDirIndicator =
"/VuoParentDir/";
1479 QString modifiedPath = QString(
"/").append(path.c_str());
1481 while (modifiedPath.contains(originalParentDirIndicator))
1482 modifiedPath.replace(originalParentDirIndicator, appBundleParentDirIndicator);
1484 modifiedPath.remove(0, 1);
1486 return modifiedPath.toUtf8().constData();
1497 string VuoRendererComposition::modifyResourcePathForNewDir(
string path, QDir newDir)
1501 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1502 if (compositionDir.canonicalPath() == newDir.canonicalPath())
1505 string origRelativeDir, file, ext;
1507 string resourceFileName = file;
1510 resourceFileName +=
".";
1511 resourceFileName += ext;
1514 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1515 string modifiedPath = newDir.relativeFilePath(sourceFilePath).toUtf8().constData();
1517 return modifiedPath;
1528 void VuoRendererComposition::bundleAuxiliaryFilesForSceneFile(QString sourceFilePath, QString targetFilePath)
1530 string sourceDirName, targetDirName, file, ext;
1536 QDir sourceDir(sourceDirName.c_str());
1537 QStringList filesWithMatchingBaseName = QStringList() << QString(file.c_str()).append(
"*");
1538 sourceDir.setNameFilters(filesWithMatchingBaseName);
1540 foreach (QString auxiliaryFile, sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot))
1542 QString sourceFile = QString(sourceDirName.c_str()) + QDir::separator() + auxiliaryFile;
1543 QString targetFile = QString(targetDirName.c_str()) + QDir::separator() + auxiliaryFile;
1544 if (!QFileInfo(targetFile).exists())
1546 VDebugLog(
"Copying \"%s\"", QFileInfo(targetFile).fileName().toUtf8().constData());
1552 QStringList textureFolderNames = QStringList() <<
"Textures" <<
"_Textures";
1553 sourceDir.setNameFilters(textureFolderNames);
1554 foreach (QString textureFolderName, sourceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
1556 QString sourceTextureDir = QString(sourceDirName.c_str()) + QDir::separator() + textureFolderName;
1557 QString targetTextureDir = QString(targetDirName.c_str()) + QDir::separator() + textureFolderName;
1558 if (!QFileInfo(targetTextureDir).exists())
1560 VDebugLog(
"Copying \"%s\"", QFileInfo(targetTextureDir).fileName().toUtf8().constData());
1577 QDir dir(path.c_str());
1586 VuoRendererComposition::gridOpacity = opacity;
1594 return VuoRendererComposition::gridOpacity;
1602 VuoRendererComposition::gridType = type;
1611 return QPoint(floor((point.x()/(1.0*gridSpacing))+0.5)*gridSpacing,
1612 floor((point.y()/(1.0*gridSpacing))+0.5)*gridSpacing);