47#include <objc/message.h>
50int VuoRendererComposition::gridOpacity = 0;
74 this->renderMissingAsPresent = renderMissingAsPresent;
75 this->renderNodeActivity =
false;
76 this->renderPortActivity =
false;
96 addNodeInCompositionToCanvas(node);
109 addCableInCompositionToCanvas(cable);
118 addCommentInCompositionToCanvas(comment);
134 setBackgroundBrush(Qt::transparent);
176 if (
getBase()->hasCompiler() && nodeShouldBeGivenUniqueIdentifier)
181 if (nodeShouldBeRendered)
182 addNodeInCompositionToCanvas(n);
193void VuoRendererComposition::addNodeInCompositionToCanvas(
VuoNode *n)
197 if (renderMissingAsPresent)
214 addCableInCompositionToCanvas(c);
222void VuoRendererComposition::addCableInCompositionToCanvas(
VuoCable *c)
255 addCommentInCompositionToCanvas(c);
263void VuoRendererComposition::addCommentInCompositionToCanvas(
VuoComment *c)
289 rc->
setTo(NULL, NULL);
313 QList<QGraphicsItem *> componentsAttached;
318 if (attachments.empty())
319 componentsAttached.append(createAndConnectDrawersToReadOnlyDictionaryInputPorts(node, compiler, createButDoNotAdd));
322 componentsAttached.append(createAndConnectDrawersToListInputPorts(node, compiler, createButDoNotAdd));
324 return componentsAttached;
330QList<QGraphicsItem *> VuoRendererComposition::createAndConnectDrawersToListInputPorts(
VuoRendererNode *node,
VuoCompiler *compiler,
bool createButDoNotAdd)
332 QList<QGraphicsItem *> componentsAttached;
344 componentsAttached.append(cable);
347 componentsAttached.append(makeListNode);
349 if (!createButDoNotAdd)
358 return componentsAttached;
364QList<QGraphicsItem *> VuoRendererComposition::createAndConnectDrawersToReadOnlyDictionaryInputPorts(
VuoRendererNode *node,
VuoCompiler *compiler,
bool createButDoNotAdd)
366 set<VuoRendererNode *> nodesToAdd;
367 set<VuoRendererCable *> cablesToAdd;
370 QList<QGraphicsItem *> componentsAttached;
372 componentsAttached.append(node);
374 componentsAttached.append(cable);
376 if (!createButDoNotAdd)
385 return componentsAttached;
401 rendererCable = NULL;
406 vector<string> itemInitialValues;
410 json_object *js = json_tokener_parse(listInitialValue.c_str());
411 if (json_object_get_type(js) == json_type_array)
413 int itemCount = json_object_array_length(js);
414 for (
int i = 0; i < itemCount; ++i)
416 json_object *itemObject = json_object_array_get_idx(js, i);
417 string itemString = json_object_to_json_string_ext(itemObject, JSON_C_TO_STRING_PLAIN);
418 itemInitialValues.push_back(itemString);
424 unsigned long itemCount = (itemInitialValues.empty() ? 2 : itemInitialValues.size());
432 for (
size_t i = 0; i < itemInitialValues.size(); ++i)
445 return makeListRendererNode;
459 set<VuoRendererNode *> &createdNodes,
460 set<VuoRendererCable *> &createdCables)
462 createdNodes.clear();
463 createdCables.clear();
467 if (!(expressionInputPort && valuesInputPort))
469 VUserLog(
"Error: Cannot create dictionary attachments for a node without 'expression' and 'values' input ports.");
474 const string dictionaryTypeName =
"VuoDictionary_VuoText_VuoReal";
475 const string dictionaryClassName =
"vuo.dictionary.make.VuoText.VuoReal";
476 const string dictionaryKeySourceTypeName =
"VuoMathExpressionList";
496 unsigned long itemCount = inputVariables.size();
505 if (keyListNodeClass && valueListNodeClass && dictionaryNodeClass)
509 QPoint offset(-220, 50);
510 VuoNode *dictionaryNode = compiler->
createNode(dictionaryNodeClass,
"", node->
getX()+offset.x(), node->
getY()+offset.y());
531 for (
size_t i = 0; i < itemCount; ++i)
534 string key =
"\"" + inputVariables[i] +
"\"";
558 vector<string> inputVariables;
560 json_object *js = json_tokener_parse(constant.c_str());
561 json_object *expressionsObject = NULL;
563 if (json_object_object_get_ex(js,
"inputVariables", &expressionsObject))
565 if (json_object_get_type(expressionsObject) == json_type_array)
567 int variableCount = json_object_array_length(expressionsObject);
568 for (
int i = 0; i < variableCount; ++i)
570 json_object *itemObject = json_object_array_get_idx(expressionsObject, i);
571 if (json_object_get_type(itemObject) == json_type_string)
573 const char *variableName = json_object_get_string(itemObject);
574 if (nodeClassName ==
"vuo.math.calculate.list"
575 && (strcasecmp(variableName,
"x") == 0
576 || strcasecmp(variableName,
"i") == 0))
579 inputVariables.push_back(json_object_get_string(itemObject));
586 return inputVariables;
607 if (isPublishedInput)
615 else if (publishedPort != existingPort)
616 VUserLog(
"Error: Unhandled published port name conflict.");
626 else if (publishedPort != existingPort)
627 VUserLog(
"Error: Unhandled published port name conflict.");
639 if (isPublishedInput)
671VuoNode * VuoRendererComposition::createPublishedInputNode()
682VuoNode * VuoRendererComposition::createPublishedOutputNode()
694 auto isNameAvailable = [
this] (
const string &name)
696 return (! name.empty() &&
719 vector<VuoRendererNode *> typecastsCollapsed;
731 return typecastsCollapsed;
764 if (outCables.size() != 1)
767 VuoCable *outCable = *(outCables.begin());
775 for (vector<VuoCable *>::iterator i = inCables.begin(); !incomingDataCable && (i != inCables.end()); ++i)
777 if ((*i)->hasRenderer() && (*i)->getRenderer()->effectivelyCarriesData())
778 incomingDataCable = *i;
780 if (! incomingDataCable)
794 if (! (fromNode && fromPort && toNode && toPort))
829 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
831 cable->
getRenderer()->setCacheMode(defaultCacheMode);
835 foreach (
VuoCable *cable, outCables)
839 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
841 cable->
getRenderer()->setCacheMode(defaultCacheMode);
849 typecastInPort->
getRenderer()->setParentItem(toRN);
902 VuoCable * outCable = *(outCables.begin());
911 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
913 cable->
getRenderer()->setCacheMode(defaultCacheMode);
921 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
923 cable->
getRenderer()->setCacheMode(defaultCacheMode);
930 typecastInPort->
getRenderer()->setParentItem(uncollapsedNode);
947 return uncollapsedNode;
974 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
976 QGraphicsItem::CacheMode normalCacheMode = (*inputPort)->getRenderer()->cacheMode();
977 (*inputPort)->getRenderer()->setCacheMode(QGraphicsItem::NoCache);
979 (*inputPort)->getRenderer()->updateGeometry();
982 (*inputPort)->getRenderer()->setCacheMode(normalCacheMode);
987 QGraphicsItem::CacheMode normalCacheMode = typecastPort->
getChildPort()->cacheMode();
988 typecastPort->
getChildPort()->setCacheMode(QGraphicsItem::NoCache);
993 typecastPort->
getChildPort()->setCacheMode(normalCacheMode);
998 for(vector<VuoPort *>::iterator outputPort = outputPorts.begin(); outputPort != outputPorts.end(); ++outputPort)
1000 QGraphicsItem::CacheMode normalCacheMode = (*outputPort)->getRenderer()->cacheMode();
1001 (*outputPort)->getRenderer()->setCacheMode(QGraphicsItem::NoCache);
1003 (*outputPort)->getRenderer()->updateGeometry();
1006 (*outputPort)->getRenderer()->setCacheMode(normalCacheMode);
1011 QGraphicsItem::CacheMode normalCacheMode = rn->cacheMode();
1012 rn->setCacheMode(QGraphicsItem::NoCache);
1017 rn->setCacheMode(normalCacheMode);
1023 QGraphicsItem::CacheMode normalCacheMode = rc->cacheMode();
1024 rc->setCacheMode(QGraphicsItem::NoCache);
1029 rc->setCacheMode(normalCacheMode);
1060 return this->renderNodeActivity;
1070 return (this->renderNodeActivity && this->renderPortActivity);
1081 QGraphicsScene::drawBackground(painter, rect);
1085 painter->setRenderHint(QPainter::Antialiasing,
true);
1086 painter->setPen(QPen(QColor(255,0,0,128),5));
1087 painter->drawRect(sceneRect());
1088 QVector<QPointF> points;
1089 points << QPointF(0,0);
1090 points << sceneRect().topLeft();
1091 points << sceneRect().center();
1092 points << sceneRect().bottomRight();
1093 foreach (QPointF p, points)
1095 painter->setPen(QPen(QColor(255,0,0,128),5));
1096 painter->drawEllipse(p, 5, 5);
1097 painter->setPen(QColor(255,0,0,128));
1098 painter->drawText(p + QPointF(5,15) - (p == sceneRect().bottomRight() ? QPointF(70,20) : QPointF(0,0)), QString(
"(%1,%2)").arg(p.x()).arg(p.y()));
1100 painter->setRenderHint(QPainter::Antialiasing,
false);
1104 if (gridType != NoGrid)
1109 if (leftmostGridLine < rect.left())
1110 leftmostGridLine += gridSpacing;
1112 if (topmostGridLine < rect.top())
1113 topmostGridLine += gridSpacing;
1118 const int nodeXAlignmentCorrection = -1;
1120 if (gridType == LineGrid)
1122 QVector<QLineF> gridLines;
1123 for (qreal x = leftmostGridLine; x < rect.right(); x += gridSpacing)
1124 gridLines.append(QLineF(x + nodeXAlignmentCorrection, rect.top(), x + nodeXAlignmentCorrection, rect.bottom()));
1125 for (qreal y = topmostGridLine; y < rect.bottom(); y += gridSpacing)
1126 gridLines.append(QLineF(rect.left(), y, rect.right(), y));
1128 painter->setPen(QColor(128, 128, 128, VuoRendererComposition::gridOpacity * 32));
1129 painter->drawLines(gridLines);
1131 else if (gridType == PointGrid)
1133 painter->setRenderHint(QPainter::Antialiasing,
true);
1134 painter->setPen(Qt::NoPen);
1135 painter->setBrush(QColor(128, 128, 128, VuoRendererComposition::gridOpacity * 128));
1137 for (qreal y = topmostGridLine; y < rect.bottom(); y += gridSpacing)
1138 for (qreal x = leftmostGridLine; x < rect.right(); x += gridSpacing)
1140 painter->drawEllipse(QPointF(x + nodeXAlignmentCorrection + .5, y + .5), 1.5,1.5);
1153 if ((this->renderNodeActivity == render) && (this->renderPortActivity == includePortActivity))
1156 this->renderNodeActivity = render;
1157 this->renderPortActivity = includePortActivity;
1165 if (includePortActivity)
1218 foreach (
VuoCable *cable, allCables)
1222 rc->setCacheMode(cacheMode);
1233 return ((
cachingEnabled && !renderNodeActivity)? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
1244 Class poolClass = objc_getClass(
"NSAutoreleasePool");
1245 ((void (*)(id, SEL))objc_msgSend)((
id)poolClass, sel_getUid(
"new"));
1267 string modifiedRelativeResourcePath = modifyResourcePathForBundle(url);
1269 rp->
setConstant(
"\"" + modifiedRelativeResourcePath +
"\"");
1282 map<VuoPort *, string> modifiedPathForPort;
1294 QString origRelativeResourcePath = url;
1296 string modifiedRelativeResourcePath = modifyResourcePathForNewDir(origRelativeResourcePath.toUtf8().constData(), newDir);
1298 if (modifiedRelativeResourcePath != origRelativeResourcePath.toUtf8().constData())
1299 modifiedPathForPort[port] =
"\"" + modifiedRelativeResourcePath +
"\"";
1304 return modifiedPathForPort;
1314 string quotedIconURL =
"\"" + iconURL +
"\"";
1318 QString origRelativeResourcePath = url;
1321 if (!isRelativePath)
1324 return modifyResourcePathForNewDir(origRelativeResourcePath.toUtf8().constData(), newDir);
1351 QString origRelativeResourcePath = url;
1352 QString modifiedRelativeResourcePath = modifyResourcePathForBundle(origRelativeResourcePath.toUtf8().constData()).c_str();
1354 string origRelativeDir, modifiedRelativeDir, file, ext;
1357 string resourceFileName = file;
1360 resourceFileName +=
".";
1361 resourceFileName += ext;
1364 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1365 QDir appDir(QDir(targetResourceDir.c_str()).canonicalPath());
1367 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1368 if (!tmpFilesOnly ||
isTmpFile(sourceFilePath.toUtf8().constData()))
1370 if (!modifiedRelativeDir.empty())
1371 appDir.mkpath(modifiedRelativeDir.c_str());
1373 QString targetFilePath = appDir.filePath(QDir(modifiedRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1379 bundleAuxiliaryFilesForSceneFile(sourceFilePath, targetFilePath);
1389 string quotedIconURL =
"\"" + iconURL +
"\"";
1393 QString origRelativeResourcePath = url;
1395 if (iconHasRelativePath)
1397 QString modifiedRelativeResourcePath = modifyResourcePathForBundle(origRelativeResourcePath.toUtf8().constData()).c_str();
1399 string origRelativeDir, modifiedRelativeDir, file, ext;
1402 string resourceFileName = file;
1405 resourceFileName +=
".";
1406 resourceFileName += ext;
1409 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1410 QDir appDir(QDir(targetResourceDir.c_str()).canonicalPath());
1412 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1413 if (!tmpFilesOnly ||
isTmpFile(sourceFilePath.toUtf8().constData()))
1415 if (!modifiedRelativeDir.empty())
1416 appDir.mkpath(modifiedRelativeDir.c_str());
1418 QString targetFilePath = (!bundledIconPath.isEmpty()? bundledIconPath :
1419 appDir.filePath(QDir(modifiedRelativeDir.c_str()).filePath(resourceFileName.c_str())));
1422 if (QString(ext.c_str()).toLower() ==
"icns")
1424 VDebugLog(
"Copying \"%s\" (app icon)", url);
1430 VDebugLog(
"Converting \"%s\" (app icon)", url);
1431 QPixmap icon(sourceFilePath);
1432 QFile file(targetFilePath);
1433 file.open(QIODevice::WriteOnly);
1434 icon.save(&file,
"ICNS");
1450 QDir parentDir(QDir(QFileInfo(filePath.c_str()).dir()).canonicalPath());
1454 if (parentDir.canonicalPath() == tmpDirPath)
1456 }
while (parentDir.cdUp());
1465string VuoRendererComposition::modifyResourcePathForBundle(
string path)
1472 const QString originalParentDirIndicator =
"/../";
1473 const QString appBundleParentDirIndicator =
"/VuoParentDir/";
1475 QString modifiedPath = QString(
"/").append(path.c_str());
1477 while (modifiedPath.contains(originalParentDirIndicator))
1478 modifiedPath.replace(originalParentDirIndicator, appBundleParentDirIndicator);
1480 modifiedPath.remove(0, 1);
1482 return modifiedPath.toUtf8().constData();
1493string VuoRendererComposition::modifyResourcePathForNewDir(
string path, QDir newDir)
1497 QDir compositionDir(QDir(
getBase()->getDirectory().c_str()).canonicalPath());
1498 if (compositionDir.canonicalPath() == newDir.canonicalPath())
1501 string origRelativeDir, file, ext;
1503 string resourceFileName = file;
1506 resourceFileName +=
".";
1507 resourceFileName += ext;
1510 QString sourceFilePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
1511 string modifiedPath = newDir.relativeFilePath(sourceFilePath).toUtf8().constData();
1513 return modifiedPath;
1524void VuoRendererComposition::bundleAuxiliaryFilesForSceneFile(QString sourceFilePath, QString targetFilePath)
1526 string sourceDirName, targetDirName, file, ext;
1532 QDir sourceDir(sourceDirName.c_str());
1533 QStringList filesWithMatchingBaseName = QStringList() << QString(file.c_str()).append(
"*");
1534 sourceDir.setNameFilters(filesWithMatchingBaseName);
1536 foreach (QString auxiliaryFile, sourceDir.entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot))
1538 QString sourceFile = QString(sourceDirName.c_str()) + QDir::separator() + auxiliaryFile;
1539 QString targetFile = QString(targetDirName.c_str()) + QDir::separator() + auxiliaryFile;
1540 if (!QFileInfo(targetFile).exists())
1542 VDebugLog(
"Copying \"%s\"", QFileInfo(targetFile).fileName().toUtf8().constData());
1548 QStringList textureFolderNames = QStringList() <<
"Textures" <<
"_Textures";
1549 sourceDir.setNameFilters(textureFolderNames);
1550 foreach (QString textureFolderName, sourceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
1552 QString sourceTextureDir = QString(sourceDirName.c_str()) + QDir::separator() + textureFolderName;
1553 QString targetTextureDir = QString(targetDirName.c_str()) + QDir::separator() + textureFolderName;
1554 if (!QFileInfo(targetTextureDir).exists())
1556 VDebugLog(
"Copying \"%s\"", QFileInfo(targetTextureDir).fileName().toUtf8().constData());
1573 QDir dir(path.c_str());
1582 VuoRendererComposition::gridOpacity = opacity;
1590 return VuoRendererComposition::gridOpacity;
1598 VuoRendererComposition::gridType = type;
1607 return QPoint(floor((point.x()/(1.0*gridSpacing))+0.5)*gridSpacing,
1608 floor((point.y()/(1.0*gridSpacing))+0.5)*gridSpacing);