54 #include <ApplicationServices/ApplicationServices.h>
55 #include <objc/objc-runtime.h>
58 const qreal VuoEditorComposition::nodeMoveRate = 15;
59 const qreal VuoEditorComposition::nodeMoveRateMultiplier = 4;
61 const qreal VuoEditorComposition::showEventsModeUpdateInterval = 1000/20.;
62 const int VuoEditorComposition::initialChangeNodeSuggestionCount = 10;
73 VuoEditorComposition_Pro();
76 this->window = window;
78 inputEditorManager = NULL;
79 activeProtocol = NULL;
81 runningComposition = NULL;
82 runningCompositionActiveDriver = NULL;
83 runningCompositionLibraries = NULL;
84 stopRequested =
false;
85 duplicateOnNextMouseMove =
false;
86 duplicationDragInProgress =
false;
87 duplicationCancelled =
false;
88 cursorPosBeforeDuplicationDragMove = QPointF(0,0);
89 cableInProgress = NULL;
90 cableInProgressWasNew =
false;
91 cableInProgressShouldBeWireless =
false;
92 portWithDragInitiated = NULL;
93 cableWithYankInitiated = NULL;
94 menuSelectionInProgress =
false;
95 previousNearbyItem = NULL;
96 dragStickinessDisabled =
false;
97 ignoreApplicationStateChangeEvents =
false;
98 popoverEventsEnabled =
true;
99 runCompositionQueue = dispatch_queue_create(
"org.vuo.editor.run", NULL);
100 activePortPopoversQueue = dispatch_queue_create(
"org.vuo.editor.popovers", NULL);
102 errorMarkingUpdatesEnabled =
true;
103 triggerPortToRefire =
"";
105 contextMenuDeleteSelected =
new QAction(NULL);
106 contextMenuHideSelectedCables =
new QAction(NULL);
107 contextMenuRenameSelected =
new QAction(NULL);
108 contextMenuRefactorSelected =
new QAction(NULL);
109 contextMenuPublishPort =
new QAction(NULL);
110 contextMenuDeleteCables =
new QAction(NULL);
111 contextMenuHideCables =
new QAction(NULL);
112 contextMenuUnhideCables =
new QAction(NULL);
113 contextMenuFireEvent =
new QAction(NULL);
114 contextMenuAddInputPort =
new QAction(NULL);
115 contextMenuRemoveInputPort =
new QAction(NULL);
116 contextMenuSetPortConstant =
new QAction(NULL);
117 contextMenuEditSelectedComments =
new QAction(NULL);
119 contextMenuChangeNode = NULL;
121 contextMenuFireEvent->setText(tr(
"Fire Event"));
122 contextMenuHideSelectedCables->setText(tr(
"Hide"));
123 contextMenuRenameSelected->setText(tr(
"Rename…"));
124 contextMenuRefactorSelected->setText(tr(
"Package as Subcomposition"));
125 contextMenuAddInputPort->setText(tr(
"Add Input Port"));
126 contextMenuRemoveInputPort->setText(tr(
"Remove Input Port"));
127 contextMenuSetPortConstant->setText(tr(
"Edit Value…"));
128 contextMenuEditSelectedComments->setText(tr(
"Edit…"));
135 connect(contextMenuDeleteCables, &QAction::triggered,
this, &VuoEditorComposition::deleteConnectedCables);
136 connect(contextMenuHideCables, &QAction::triggered,
this, &VuoEditorComposition::hideConnectedCables);
137 connect(contextMenuUnhideCables, &QAction::triggered,
this, &VuoEditorComposition::unhideConnectedCables);
138 connect(contextMenuFireEvent, &QAction::triggered,
this,
static_cast<void (
VuoEditorComposition::*)()
>(&VuoEditorComposition::fireTriggerPortEvent));
139 connect(contextMenuAddInputPort, &QAction::triggered,
this, &VuoEditorComposition::addInputPort);
140 connect(contextMenuRemoveInputPort, &QAction::triggered,
this, &VuoEditorComposition::removeInputPort);
141 connect(contextMenuEditSelectedComments, &QAction::triggered,
this, &VuoEditorComposition::editSelectedComments);
146 connect(contextMenuSetPortConstant, &QAction::triggered,
this, &VuoEditorComposition::setPortConstant, Qt::QueuedConnection);
151 QSignalMapper *contextMenuThrottlingMapper =
new QSignalMapper(
this);
152 connect(contextMenuThrottlingMapper,
static_cast<void (QSignalMapper::*)(
int)
>(&QSignalMapper::mapped),
this, &VuoEditorComposition::setTriggerThrottling);
154 QList<QPair<QString, enum VuoPortClass::EventThrottling> > throttlingNamesAndIndices;
158 for (QList<QPair<QString, enum VuoPortClass::EventThrottling> >::iterator i = throttlingNamesAndIndices.begin(); i != throttlingNamesAndIndices.end(); ++i)
160 QString name = i->first;
162 QAction *action =
new QAction(name,
this);
164 contextMenuThrottlingActions.append(action);
166 contextMenuThrottlingMapper->setMapping(action, index);
167 connect(action, &QAction::triggered, contextMenuThrottlingMapper,
static_cast<void (QSignalMapper::*)()
>(&QSignalMapper::map));
184 QSignalMapper *contextMenuTintsMapper =
new QSignalMapper(
this);
187 QList<QPair<QString, enum VuoNode::TintColor> > tintNamesAndIndices;
188 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Yellow"), VuoNode::TintYellow));
189 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Tangerine"), VuoNode::TintTangerine));
190 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Orange"), VuoNode::TintOrange));
191 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Magenta"), VuoNode::TintMagenta));
192 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Violet"), VuoNode::TintViolet));
193 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Blue"), VuoNode::TintBlue));
194 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Cyan"), VuoNode::TintCyan));
195 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Green"), VuoNode::TintGreen));
196 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"Lime"), VuoNode::TintLime));
197 tintNamesAndIndices.append(QPair<QString, enum VuoNode::TintColor>(tr(
"None"), VuoNode::TintNone));
199 for (QList<QPair<QString, enum VuoNode::TintColor> >::iterator i = tintNamesAndIndices.begin(); i != tintNamesAndIndices.end(); ++i)
201 QString name = i->first;
203 QAction *action =
new QAction(name,
this);
207 QColor fill(0,0,0,0);
209 if (index != VuoNode::TintNone)
219 p.drawEllipse(3, 3, 10, 10);
221 action->setIcon(*icon);
225 contextMenuTintActions.append(action);
227 contextMenuTintsMapper->setMapping(action, index);
228 connect(action, &QAction::triggered, contextMenuTintsMapper,
static_cast<void (QSignalMapper::*)()
>(&QSignalMapper::map));
233 this->refreshComponentAlphaLevelTimer =
new QTimer(
this);
234 this->refreshComponentAlphaLevelTimer->setObjectName(
"VuoEditorComposition::refreshComponentAlphaLevelTimer");
235 refreshComponentAlphaLevelTimer->setInterval(showEventsModeUpdateInterval);
237 setShowEventsMode(
false);
253 connect(static_cast<VuoEditor *>(qApp), &VuoEditor::focusChanged,
this, &VuoEditorComposition::updatePopoversForActiveWindowChange, Qt::QueuedConnection);
255 setPopoversHideOnDeactivate(
true);
258 setPopoversHideOnDeactivate(
false);
261 populateNodeAndPortIdentifierMappings();
269 this->compiler = compiler;
277 this->moduleManager = moduleManager;
286 return moduleManager;
296 this->inputEditorManager = inputEditorManager;
306 return this->inputEditorManager;
321 setCustomConstantsForNewNode(rn);
337 __block
bool isAllowed =
true;
340 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyIfInstalledAsSubcomposition(
this, ^
void (
VuoEditorComposition *currComposition,
string compositionPath) {
342 bool nodeIsThisComposition = (compositionModuleKey == nodeClass->
getBase()->
getClassName());
345 auto iter = std::find_if(dependencies.begin(), dependencies.end(), [=](
const string &d){
return d == compositionModuleKey; });
346 bool nodeContainsThisComposition = (iter != dependencies.end());
348 isAllowed = ! (nodeIsThisComposition || nodeContainsThisComposition);
356 nodeClass->
newNode(modelNode) :
357 compiler->
createNode(nodeClass, title, x, y));
375 vector<string> inputPortClassNames;
376 vector<string> outputPortClassNames;
381 inputPortClassNames.push_back(portClass->
getName());
384 outputPortClassNames.push_back(portClass->
getName());
388 dummyNodeClass->
newNode(modelNode) :
397 void VuoEditorComposition::setCustomConstantsForNewNode(
VuoRendererNode *newNode)
405 QString currentYear = QString::number(QDateTime::currentDateTime().date().year());
429 disablePortPopovers(rn);
451 map<VuoCable *, VuoPort *> cablesToTransferFromPort;
452 map<VuoCable *, VuoPort *> cablesToTransferToPort;
453 set<VuoCable *> cablesToRemove;
457 vector<VuoRendererNode *> collapsedTypecasts;
459 for (vector<VuoPort *>::iterator inputPort = oldInputPorts.begin(); inputPort != oldInputPorts.end(); ++inputPort)
465 collapsedTypecasts.push_back(typecastNode);
473 for (vector<VuoRendererNode *>::iterator i = collapsedTypecasts.begin(); i != collapsedTypecasts.end(); ++i)
481 for (map<VuoCable *, VuoPort *>::iterator i = cablesToTransferFromPort.begin(); i != cablesToTransferFromPort.end(); ++i)
482 i->first->getRenderer()->setFrom(newNode, i->second);
483 for (map<VuoCable *, VuoPort *>::iterator i = cablesToTransferToPort.begin(); i != cablesToTransferToPort.end(); ++i)
484 i->first->getRenderer()->setTo(newNode, i->second);
485 foreach (
VuoCable *cable, cablesToRemove)
500 VuoType *oldDataType = static_cast<VuoCompilerPort *>(oldInputPort->getCompiler())->getDataVuoType();
501 VuoType *newDataType = static_cast<VuoCompilerPort *>(newInputPort->
getCompiler())->getDataVuoType();
502 if (! (oldDataType == newDataType && oldDataType && ! dynamic_cast<VuoGenericType *>(oldDataType)) )
506 string oldConstantValue;
508 oldConstantValue = oldInputPort->getRenderer()->getConstantAsString();
510 oldConstantValue = oldInputPort->getRawInitialValue();
519 for (vector<VuoRendererNode *>::iterator i = collapsedTypecasts.begin(); i != collapsedTypecasts.end(); ++i)
532 disablePortPopovers(oldNode);
549 registerNodeID(newNode);
598 set<VuoRendererNode *> &createdNodes,
599 set<VuoRendererCable *> &createdCables)
613 foreach (QGraphicsItem *component, addedComponents)
616 if (rn && !createButDoNotAdd)
620 return addedComponents;
631 set<string> selectedNodeIDs;
638 set<string> selectedCommentIDs;
645 set<string> selectedCableIDs;
655 foreach (QGraphicsItem *item, items())
657 if (dynamic_cast<VuoRendererNode *>(item))
659 string currentNodeID = (dynamic_cast<VuoRendererNode *>(item)->getBase()->hasCompiler()?
660 dynamic_cast<VuoRendererNode *>(item)->getBase()->getCompiler()->getGraphvizIdentifier() :
662 if (!currentNodeID.empty() && (selectedNodeIDs.find(currentNodeID) != selectedNodeIDs.end()))
663 item->setSelected(
true);
666 if (dynamic_cast<VuoRendererComment *>(item))
668 string currentCommentID = (dynamic_cast<VuoRendererComment *>(item)->getBase()->hasCompiler()?
669 dynamic_cast<VuoRendererComment *>(item)->getBase()->getCompiler()->getGraphvizIdentifier() :
671 if (!currentCommentID.empty() && (selectedCommentIDs.find(currentCommentID) != selectedCommentIDs.end()))
672 item->setSelected(
true);
675 else if (dynamic_cast<VuoRendererCable *>(item))
677 string currentCableID = (dynamic_cast<VuoRendererCable *>(item)->getBase()->hasCompiler()?
678 dynamic_cast<VuoRendererCable *>(item)->getBase()->getCompiler()->getGraphvizDeclaration() :
680 if (!currentCableID.empty() && (selectedCableIDs.find(currentCableID) != selectedCableIDs.end()))
681 item->setSelected(
true);
704 if ((portName ==
"expression") &&
724 if (commandDescription.empty())
727 commandDescription =
"Reset";
729 commandDescription =
"Delete";
732 QList<QGraphicsItem *> selectedCompositionComponents = selectedItems();
741 if (commandDescription.empty())
742 commandDescription =
"Delete";
744 QList<QGraphicsItem *> selectedNodes;
746 selectedNodes.append(node);
780 nodeWithGraphvizIdentifier.clear();
781 portWithStaticIdentifier.clear();
782 staticIdentifierForPort.clear();
788 void VuoEditorComposition::insertNode()
790 QAction *sender = (QAction *)QObject::sender();
791 QPair<QPointF, QString> pair = sender->data().value<QPair<QPointF, QString> >();
793 QList<QGraphicsItem *> newNodes;
800 newNodes.append(newNode);
808 void VuoEditorComposition::insertComment()
810 QAction *sender = (QAction *)QObject::sender();
811 QPointF scenePos = sender->data().value<QPointF>();
819 void VuoEditorComposition::insertSubcomposition()
821 QAction *sender = (QAction *)QObject::sender();
822 QPointF scenePos = sender->data().value<QPointF>();
833 QAction *sender = (QAction *)QObject::sender();
848 void VuoEditorComposition::deleteConnectedCables()
850 QAction *sender = (QAction *)QObject::sender();
853 QList<QGraphicsItem *> cablesToRemove;
884 void VuoEditorComposition::hideConnectedCables()
886 QAction *sender = (QAction *)QObject::sender();
888 set<VuoRendererCable *> cablesToHide;
919 void VuoEditorComposition::unhideConnectedCables()
921 QAction *sender = (QAction *)QObject::sender();
923 set<VuoRendererCable *> cablesToUnhide;
952 void VuoEditorComposition::fireTriggerPortEvent()
954 QAction *sender = (QAction *)QObject::sender();
956 fireTriggerPortEvent(port->
getBase());
972 if (triggerPortToRefire.empty() ||
973 (portWithStaticIdentifier.find(triggerPortToRefire) == portWithStaticIdentifier.end()))
976 return portWithStaticIdentifier[triggerPortToRefire];
985 if (portID != this->triggerPortToRefire)
987 this->triggerPortToRefire = portID;
996 void VuoEditorComposition::setPortConstant()
998 QAction *sender = (QAction *)QObject::sender();
1009 void VuoEditorComposition::setPortConstantToValue(
VuoRendererPort *port,
string value)
1019 void VuoEditorComposition::specializeGenericPortType()
1021 QAction *sender = (QAction *)QObject::sender();
1022 QList<QVariant> portAndSpecializedType= sender->data().toList();
1024 QString specializedTypeName = portAndSpecializedType[1].toString();
1031 if (port && !dynamic_cast<VuoGenericType *>(port->
getDataType()))
1036 emit
specializePort(port, specializedTypeName.toUtf8().constData());
1043 void VuoEditorComposition::unspecializePortType()
1045 QAction *sender = (QAction *)QObject::sender();
1049 if (port && dynamic_cast<VuoGenericType *>(port->
getDataType()))
1067 map<VuoPort *, VuoNode *> nodeForPort;
1068 map<VuoPort *, set<VuoCable *> > cablesForPort;
1070 for (set<VuoNode *>::iterator i = nodes.begin(); i != nodes.end(); ++i)
1075 vector<VuoPort *> ports;
1076 ports.insert(ports.end(), inputPorts.begin(), inputPorts.end());
1077 ports.insert(ports.end(), outputPorts.begin(), outputPorts.end());
1079 for (vector<VuoPort *>::iterator j = ports.begin(); j != ports.end(); ++j)
1083 nodeForPort[port] = node;
1085 cablesForPort[port].insert(cables.begin(), cables.end());
1091 portToUnspecialize,
true);
1092 map<VuoNode *, set<VuoPort *> > portsToUnspecializeForNode;
1093 for (
VuoPort *connectedPort : connectedPotentiallyGenericPorts)
1095 VuoNode *node = nodeForPort[connectedPort];
1099 if (isPortCurrentlyRevertible(connectedPort->getRenderer()))
1100 portsToUnspecializeForNode[node].insert(connectedPort);
1103 for (map<
VuoNode *, set<VuoPort *> >::iterator i = portsToUnspecializeForNode.begin(); i != portsToUnspecializeForNode.end(); ++i)
1106 set<VuoPort *> ports = i->second;
1109 set<VuoPortClass *> portClasses;
1110 for (set<VuoPort *>::iterator j = ports.begin(); j != ports.end(); ++j)
1111 portClasses.insert((*j)->getClass());
1114 nodesToReplace[node] = unspecializedNodeClassName;
1118 for (set<VuoPort *>::iterator j = ports.begin(); j != ports.end(); ++j)
1121 set<VuoCable *> connectedCables = cablesForPort[port];
1122 for (set<VuoCable *>::iterator k = connectedCables.begin(); k != connectedCables.end(); ++k)
1126 bool areEndsCompatible =
false;
1129 areEndsCompatible =
true;
1134 if (portOnOtherEnd && isPortCurrentlyRevertible(portOnOtherEnd->
getRenderer()))
1136 VuoNode *nodeOnOtherEnd = nodeForPort[portOnOtherEnd];
1139 if (specializedNodeClassOnOtherEnd)
1142 if (! typeOnOtherEnd || dynamic_cast<VuoGenericType *>(typeOnOtherEnd))
1143 areEndsCompatible =
true;
1148 if (! areEndsCompatible && (cable != cableInProgress))
1149 cablesToDelete.insert(cable);
1158 void VuoEditorComposition::fireTriggerPortEvent(
VuoPort *port)
1166 string runningTriggerPortIdentifier =
"";
1167 bool isTriggerPort =
false;
1168 if (dynamic_cast<VuoCompilerTriggerPort *>(port->
getCompiler()))
1174 runningTriggerPortIdentifier = staticIdentifierForPort[port];
1175 isTriggerPort =
true;
1193 runningTriggerPortIdentifier.c_str());
1196 bool manuallyFirableInputPortChanged = (oldManuallyFirableInputPort != newManuallyFirableInputPort);
1199 auto fireIfRunning = ^void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
1201 dispatch_async(topLevelComposition->runCompositionQueue, ^{
1202 if (topLevelComposition->isRunningThreadUnsafe())
1204 topLevelComposition->runner->fireTriggerPortEvent(thisCompositionIdentifier, runningTriggerPortIdentifier);
1209 if (! (this->showEventsMode && isTriggerPort) )
1210 this->animatePort(port->getRenderer());
1215 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier) {
1216 if (
this == topLevelComposition || ! manuallyFirableInputPortChanged)
1220 if (! newSnapshot.empty() && manuallyFirableInputPortChanged)
1221 updateRunningComposition(oldSnapshot, newSnapshot);
1223 fireIfRunning(topLevelComposition, thisCompositionIdentifier);
1229 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyIfInstalledAsSubcomposition(
this, ^
void (
VuoEditorComposition *currComposition,
string compositionPath) {
1231 moduleManager->doNextTimeNodeClassIsLoaded(nodeClassName, ^{
1232 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier) {
1233 fireIfRunning(topLevelComposition, thisCompositionIdentifier);
1237 if (! newSnapshot.empty())
1238 updateRunningComposition(oldSnapshot, newSnapshot);
1243 setTriggerPortToRefire(port);
1249 void VuoEditorComposition::setTriggerThrottling(
int eventThrottling)
1251 QSignalMapper *signalMapper = (QSignalMapper *)QObject::sender();
1252 QAction *sender = (QAction *)signalMapper->mapping(eventThrottling);
1261 void VuoEditorComposition::addInputPort()
1263 QAction *sender = (QAction *)QObject::sender();
1272 void VuoEditorComposition::removeInputPort()
1274 QAction *sender = (QAction *)QObject::sender();
1283 void VuoEditorComposition::swapNode()
1285 QAction *sender = (QAction *)QObject::sender();
1286 QList<QVariant> nodeAndReplacementType= sender->data().toList();
1287 VuoRendererNode *node = static_cast<VuoRendererNode *>(nodeAndReplacementType[0].value<void *>());
1288 QString newNodeClassName = nodeAndReplacementType[1].toString();
1308 for (set<VuoRendererNode *>::iterator i = selectedNodes.begin(); i != selectedNodes.end(); ++i)
1310 if (!dynamic_cast<VuoRendererInputAttachment *>(*i))
1318 void VuoEditorComposition::editSelectedComments()
1322 for (set<VuoRendererComment *>::iterator i = selectedComments.begin(); i != selectedComments.end(); ++i)
1331 set<VuoRendererCable *> internalCables;
1333 for (QList<QGraphicsItem *>::iterator i = subcompositionComponents.begin(); i != subcompositionComponents.end(); ++i)
1335 QGraphicsItem *compositionComponent = *i;
1336 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(compositionComponent);
1340 for (set<VuoCable *>::iterator cable = connectedCables.begin(); cable != connectedCables.end(); ++cable)
1342 VuoNode *fromNode = (*cable)->getFromNode();
1343 VuoNode *toNode = (*cable)->getToNode();
1345 if (fromNode && toNode && subcompositionComponents.contains(fromNode->
getRenderer()) && subcompositionComponents.contains(toNode->
getRenderer()))
1346 internalCables.insert((*cable)->getRenderer());
1351 return internalCables;
1359 return cableInProgress;
1368 return cableInProgressWasNew;
1376 return menuSelectionInProgress;
1384 QList<QGraphicsItem *> compositionComponents = items();
1385 for (QList<QGraphicsItem *>::iterator i = compositionComponents.begin(); i != compositionComponents.end(); ++i)
1387 QGraphicsItem *compositionComponent = *i;
1389 VuoRendererCable *rc = dynamic_cast<VuoRendererCable *>(compositionComponent);
1391 compositionComponent->setSelected(
true);
1400 QList<QGraphicsItem *> compositionComponents = items();
1401 for (QList<QGraphicsItem *>::iterator i = compositionComponents.begin(); i != compositionComponents.end(); ++i)
1403 QGraphicsItem *compositionComponent = *i;
1404 VuoRendererComment *rcomment = dynamic_cast<VuoRendererComment *>(compositionComponent);
1406 rcomment->setSelected(
true);
1415 QList<QGraphicsItem *> compositionComponents = items();
1416 for (QList<QGraphicsItem *>::iterator i = compositionComponents.begin(); i != compositionComponents.end(); ++i)
1418 QGraphicsItem *compositionComponent = *i;
1419 compositionComponent->setSelected(
false);
1426 void VuoEditorComposition::openSelectedEditableNodes()
1431 QString actionText, sourcePath;
1444 moveItemsBy(selectedNodes, selectedComments, dx, dy,
false);
1450 void VuoEditorComposition::moveNodesBy(set<VuoRendererNode *> nodes, qreal dx, qreal dy,
bool movedByDragging)
1452 set<VuoRendererComment *> comments;
1453 moveItemsBy(nodes, comments, dx, dy, movedByDragging);
1459 void VuoEditorComposition::moveCommentsBy(set<VuoRendererComment *> comments, qreal dx, qreal dy,
bool movedByDragging)
1461 set<VuoRendererNode *> nodes;
1462 moveItemsBy(nodes, comments, dx, dy, movedByDragging);
1468 void VuoEditorComposition::moveItemsBy(set<VuoRendererNode *> nodes, set<VuoRendererComment *> comments, qreal dx, qreal dy,
bool movedByDragging)
1470 emit
itemsMoved(nodes, comments, dx, dy, movedByDragging);
1472 for (set<VuoRendererNode *>::iterator it = nodes.begin(); it != nodes.end(); ++it)
1473 (*it)->updateConnectedCableGeometry();
1479 void VuoEditorComposition::resizeCommentBy(
VuoRendererComment *comment, qreal dx, qreal dy)
1489 QList<QGraphicsItem *> selectedCompositionComponents = selectedItems();
1490 set<VuoRendererNode *> selectedNodes;
1491 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
1493 QGraphicsItem *compositionComponent = *i;
1494 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(compositionComponent);
1496 selectedNodes.insert(rn);
1499 return selectedNodes;
1507 QList<QGraphicsItem *> selectedCompositionComponents = selectedItems();
1508 set<VuoRendererComment *> selectedComments;
1509 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
1511 QGraphicsItem *compositionComponent = *i;
1514 selectedComments.insert(rc);
1517 return selectedComments;
1525 QList<QGraphicsItem *> selectedCompositionComponents = selectedItems();
1526 set<VuoRendererCable *> selectedCables;
1527 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
1529 QGraphicsItem *compositionComponent = *i;
1530 VuoRendererCable *rc = dynamic_cast<VuoRendererCable *>(compositionComponent);
1532 selectedCables.insert(rc);
1535 return selectedCables;
1543 const QMimeData *mimeData =
event->mimeData();
1544 bool disablePortHoverHighlighting =
true;
1547 if (mimeData->hasFormat(
"text/uri-list"))
1549 QList<QUrl> urls = mimeData->urls();
1552 VuoRendererPort *portAtDropLocation = dynamic_cast<VuoRendererPort *>(nearbyItem);
1553 if (portAtDropLocation)
1555 if ((urls.size() == 1) && portAtDropLocation->isConstant() &&
1556 (portAtDropLocation->getDataType()->getModuleKey() ==
"VuoText"))
1557 disablePortHoverHighlighting =
false;
1559 event->setDropAction(Qt::IgnoreAction);
1563 bool dragIncludesDroppableFile =
false;
1564 foreach (QUrl url, urls)
1578 if (isSupportedDragNDropFile)
1580 dragIncludesDroppableFile =
true;
1585 if (!dragIncludesDroppableFile)
1586 event->setDropAction(Qt::IgnoreAction);
1593 else if (mimeData->hasFormat(
"text/plain") || mimeData->hasFormat(
"text/scsv"))
1594 event->acceptProposedAction();
1598 event->setDropAction(Qt::IgnoreAction);
1602 updateHoverHighlighting(event->scenePos(), disablePortHoverHighlighting);
1610 event->acceptProposedAction();
1626 const QMimeData *mimeData =
event->mimeData();
1629 if (mimeData->hasFormat(
"text/uri-list"))
1637 if (topCompositionPath.empty())
1639 QDir compositionDir(QDir(topCompositionPath.c_str()).canonicalPath());
1644 QList<QGraphicsItem *> newNodes;
1645 QList<QUrl> urls = mimeData->urls();
1648 VuoRendererPort *portAtDropLocation = dynamic_cast<VuoRendererPort *>(nearbyItem);
1649 if (portAtDropLocation)
1651 if ((urls.size() == 1) && portAtDropLocation->isConstant() &&
1652 (portAtDropLocation->getDataType()->getModuleKey() ==
"VuoText"))
1654 QString filePath = (useAbsoluteFilePaths? urls[0].path() : compositionDir.relativeFilePath(urls[0].path()));
1655 string constantValue =
"\"" + string(filePath.toUtf8().constData()) +
"\"";
1666 const int ySpacingForNewNodes = 11;
1667 int yOffsetForPreviousNewNode = -1 * ySpacingForNewNodes;
1669 foreach (QUrl url, urls)
1671 QStringList targetNodeClassNames;
1674 targetNodeClassNames +=
"vuo.image.fetch";
1678 targetNodeClassNames +=
"vuo.video.play";
1680 targetNodeClassNames +=
"vuo.video.decodeImage";
1683 targetNodeClassNames +=
"vuo.scene.fetch";
1685 targetNodeClassNames +=
"vuo.audio.file.play";
1687 targetNodeClassNames +=
"vuo.image.project.dome";
1689 targetNodeClassNames +=
"vuo.rss.fetch";
1691 targetNodeClassNames +=
"vuo.tree.fetch.json";
1693 targetNodeClassNames +=
"vuo.tree.fetch.xml";
1695 targetNodeClassNames +=
"vuo.table.fetch";
1697 targetNodeClassNames +=
"vuo.data.fetch";
1699 targetNodeClassNames +=
"vuo.app.launch";
1701 targetNodeClassNames +=
"vuo.file.list";
1703 QString selectedNodeClassName =
"";
1704 if (targetNodeClassNames.size() == 1)
1705 selectedNodeClassName = targetNodeClassNames[0];
1706 else if (targetNodeClassNames.size() > 1)
1708 QMenu nodeMenu(views()[0]->viewport());
1709 nodeMenu.setSeparatorsCollapsible(
false);
1711 foreach (QString nodeClassName, targetNodeClassNames)
1714 string nodeTitle = (nodeClass? nodeClass->
getBase()->
getDefaultTitle() : nodeClassName.toUtf8().constData());
1716 QAction *nodeAction = nodeMenu.addAction(tr(
"Insert \"%1\" Node").arg(nodeTitle.c_str()));
1717 nodeAction->setData(nodeClassName);
1720 menuSelectionInProgress =
true;
1721 QAction *selectedNode = nodeMenu.exec(QCursor::pos());
1722 menuSelectionInProgress =
false;
1724 selectedNodeClassName = (selectedNode? selectedNode->data().toString().toUtf8().constData() :
"");
1727 if (!selectedNodeClassName.isEmpty())
1730 event->scenePos().x(),
1731 event->scenePos().y() + yOffsetForPreviousNewNode + ySpacingForNewNodes);
1740 QString filePath = (useAbsoluteFilePaths? url.path() : compositionDir.relativeFilePath(url.path()));
1743 newNodes.append(newNode);
1745 yOffsetForPreviousNewNode += newNode->
boundingRect().height();
1746 yOffsetForPreviousNewNode += ySpacingForNewNodes;
1752 if (newNodes.size() > 0)
1764 else if (mimeData->hasFormat(
"text/scsv"))
1766 event->setDropAction(Qt::CopyAction);
1769 QByteArray scsvData =
event->mimeData()->data(
"text/scsv");
1770 QString scsvText = QString::fromUtf8(scsvData);
1771 QStringList nodeClassNames = scsvText.split(
';');
1776 int snapDelta = nextYPos - startPos.y();
1778 QList<QGraphicsItem *> newNodes;
1779 for (QStringList::iterator i = nodeClassNames.begin(); i != nodeClassNames.end(); ++i)
1787 int prevYPos = nextYPos;
1790 if (nextYPos <= prevYPos+newNode->boundingRect().height())
1793 newNodes.append((QGraphicsItem *)newNode);
1801 else if (mimeData->hasFormat(
"text/plain"))
1803 event->setDropAction(Qt::CopyAction);
1806 QList<QGraphicsItem *> newNodes;
1807 QStringList dropItems =
event->mimeData()->text().split(
'\n');
1808 QString nodeClassName = dropItems[0];
1812 QPoint hotSpot = (dropItems.size() >= 3? QPoint(dropItems[1].toInt(), dropItems[2].toInt()) : QPoint(0,0));
1814 event->scenePos().x()-hotSpot.x()+1,
1817 newNodes.append(newNode);
1832 if (dynamic_cast<VuoRendererPort *>(nearbyItem))
1834 QGraphicsScene::sendEvent(nearbyItem, event);
1839 QGraphicsScene::mouseDoubleClickEvent(event);
1847 QPointF scenePos =
event->scenePos();
1850 if (event->button() == Qt::LeftButton)
1855 if (duplicationCancelled)
1857 QGraphicsItem *itemClickedDirectly = itemAt(scenePos, views()[0]->transform());
1858 if (dynamic_cast<VuoRendererNode *>(itemClickedDirectly) ||
1859 dynamic_cast<VuoRendererCable *>(itemClickedDirectly) ||
1860 dynamic_cast<VuoRendererComment *>(itemClickedDirectly)
1863 duplicationCancelled =
false;
1864 correctForCancelledDuplication(event);
1875 mousePressEventNonLeftButton(event);
1884 bool eventHandled =
false;
1889 VuoRendererPort *currentPort = dynamic_cast<VuoRendererPort *>(nearbyItem);
1892 VuoRendererCable *currentCable = dynamic_cast<VuoRendererCable *>(nearbyItem);
1898 cableYankedDirectly = currentCable;
1906 if ((event->modifiers() & Qt::ControlModifier) && (currentPort->
getInput() || isTriggerPort))
1907 fireTriggerPortEvent(currentPort->
getBase());
1911 portWithDragInitiated = currentPort;
1912 cableWithYankInitiated = cableYankedDirectly;
1916 eventHandled =
true;
1923 duplicateOnNextMouseMove =
true;
1924 duplicationDragInProgress =
true;
1930 QGraphicsScene::mousePressEvent(event);
1931 eventHandled =
true;
1935 if (dynamic_cast<VuoRendererCable *>(nearbyItem))
1937 if (event->modifiers() & Qt::ControlModifier)
1938 nearbyItem->setSelected(! nearbyItem->isSelected());
1943 nearbyItem->setSelected(
true);
1947 eventHandled =
true;
1952 QGraphicsScene::mousePressEvent(event);
1959 void VuoEditorComposition::mousePressEventNonLeftButton(QGraphicsSceneMouseEvent *event)
1968 if (event->button() == Qt::RightButton)
1970 QGraphicsSceneContextMenuEvent
contextMenuEvent(QEvent::GraphicsSceneContextMenu);
1979 QGraphicsScene::mousePressEvent(event);
1990 void VuoEditorComposition::correctForCancelledDuplication(QGraphicsSceneMouseEvent *event)
1994 QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
1995 pressEvent.setScenePos(event->scenePos());
1996 pressEvent.setButton(Qt::LeftButton);
1997 QApplication::sendEvent(
this, &pressEvent);
1999 QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
2000 releaseEvent.setScenePos(event->scenePos());
2001 releaseEvent.setButton(Qt::LeftButton);
2002 QApplication::sendEvent(
this, &releaseEvent);
2014 Qt::KeyboardModifiers modifiers =
event->modifiers();
2015 bool optionKeyPressed = (modifiers & Qt::AltModifier);
2016 bool shiftKeyPressed = (modifiers & Qt::ShiftModifier);
2027 bool creatingNewCable =
false;
2028 bool disconnectingExistingCable =
false;
2029 bool duplicatingExistingCable =
false;
2043 fromPort = fixedPort;
2044 fromNode = fixedNode;
2045 creatingNewCable =
true;
2057 creatingNewCable =
true;
2064 if (optionKeyPressed)
2066 duplicatingExistingCable =
true;
2070 disconnectingExistingCable =
true;
2078 if (creatingNewCable)
2091 cableInProgressWasNew =
true;
2092 cableInProgressShouldBeWireless =
false;
2099 highlightEligibleEndpointsForCable(cableInProgress);
2104 else if (disconnectingExistingCable)
2107 if (cableYankedDirectly)
2108 cableInProgress = cableYankedDirectly->
getBase();
2114 cableInProgressWasNew =
false;
2125 highlightEligibleEndpointsForCable(cableInProgress);
2127 cableInProgress->
getRenderer()->setSelected(
true);
2130 else if (duplicatingExistingCable)
2134 if (cableYankedDirectly)
2135 cableToDuplicate = cableYankedDirectly->
getBase();
2152 cableInProgressWasNew =
true;
2153 cableInProgressShouldBeWireless = cableToDuplicate->
hasCompiler() &&
2161 highlightEligibleEndpointsForCable(cableInProgress);
2163 cableInProgress->
getRenderer()->setSelected(
true);
2168 cableInProgress->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
2181 if (event->button() == Qt::LeftButton)
2183 portWithDragInitiated = NULL;
2184 cableWithYankInitiated = NULL;
2185 duplicateOnNextMouseMove =
false;
2186 duplicationDragInProgress =
false;
2187 dragStickinessDisabled =
false;
2194 bool cableDragEnding = cableInProgress;
2195 if (cableDragEnding)
2196 concludeCableDrag(event);
2208 if ((event->modifiers() == Qt::NoModifier) &&
2209 (QLineF(event->screenPos(),
event->buttonDownScreenPos(Qt::LeftButton)).length() < QApplication::startDragDistance()))
2216 enablePopoverForNode(typecastNode);
2221 enableInactivePopoverForPort(port);
2227 if (!cableDragEnding && !node)
2231 if (!cableDragEnding)
2232 QGraphicsScene::mouseReleaseEvent(event);
2238 QGraphicsScene::mouseReleaseEvent(event);
2248 void VuoEditorComposition::concludeCableDrag(QGraphicsSceneMouseEvent *event)
2256 concludePublishedCableDrag(event);
2260 if (hasFeedbackErrors())
2278 bool completedCableConnection =
false;
2281 VuoCable *dataCableToDisplace = NULL;
2285 string typecastToInsert =
"";
2289 string specializedTypeName =
"";
2306 bool draggingPreviouslyPublishedCable = (!cableInProgressWasNew &&
2307 (dynamic_cast<VuoRendererPublishedPort *>(fixedPort) ||
2308 ((cableInProgress->
getToPort() == NULL) &&
2311 if (fixedPort && targetPort)
2319 if (recreatingSameConnection)
2329 bool preexistingCableWithMatchingDataCarryingStatus = (preexistingCable?
2331 cableInProgressExpectedToCarryData) :
2337 if (preexistingCable && !preexistingCableWithMatchingDataCarryingStatus &&
2348 if (!preexistingCableWithMatchingDataCarryingStatus &&
2350 selectBridgingSolution(fixedPort, targetPort,
true, &portToSpecialize, specializedTypeName, typecastToInsert)))
2361 targetPort = adjustedTargetPort;
2365 if (cableInProgressExpectedToCarryData &&
2367 (*typecastOutPort->
getConnectedCables(
true).begin())->getRenderer()->effectivelyCarriesData())
2368 typecastNodeToDelete = uncollapsedTypecast;
2373 if (preexistingCable)
2374 cableToReplace = preexistingCable;
2378 if (cableInProgressExpectedToCarryData)
2382 for (vector<VuoCable *>::iterator cable = previousConnectedCables.begin(); (! dataCableToDisplace) && (cable != previousConnectedCables.end()); ++cable)
2383 if ((((*cable)->getRenderer()->effectivelyCarriesData()) && (*cable) != cableToReplace))
2384 dataCableToDisplace = *cable;
2391 if (publishedDataConnections.size() > 0)
2392 portToUnpublish = targetPort;
2396 completedCableConnection =
true;
2400 else if (!preexistingCableWithMatchingDataCarryingStatus &&
2402 selectBridgingSolution(targetPort, fixedPort,
false, &portToSpecialize, specializedTypeName, typecastToInsert)))
2405 completedCableConnection =
true;
2410 if (completedCableConnection)
2414 if (draggingPreviouslyPublishedCable)
2433 cableInProgressCopy->
setFrom(cableInProgressFromNode, cableInProgressFromPort);
2434 cableInProgressCopy->
setTo(cableInProgressToNode, cableInProgressToPort);
2441 cableInProgress = cableInProgressCopy;
2442 cableInProgressWasNew =
true;
2446 pair<VuoRendererCable *, VuoRendererCable *> cableArgs = std::make_pair((dataCableToDisplace? dataCableToDisplace->
getRenderer() : NULL),
2447 (cableToReplace? cableToReplace->
getRenderer() : NULL));
2448 pair<string, string> typeArgs = std::make_pair(typecastToInsert, specializedTypeName);
2449 pair<VuoRendererPort *, VuoRendererPort *> portArgs = std::make_pair(portToUnpublish, portToSpecialize);
2454 typecastNodeToDelete,
2461 if (cableInProgress)
2465 cableInProgress = NULL;
2479 void VuoEditorComposition::concludePublishedCableDrag(QGraphicsSceneMouseEvent *event)
2489 string typecastToInsert =
"";
2493 string specializedTypeName =
"";
2510 if (internalInputPort)
2513 forceEventOnlyPublication =
true;
2519 if (internalInputPort &&
2525 internalInputPort->
getBase()) &&
2528 if (recreatingSameConnection)
2536 ||
selectBridgingSolution(publishedInputPort, internalInputPort,
true, &portToSpecialize, specializedTypeName, typecastToInsert))
2541 bool cableToReplaceHasMatchingDataCarryingStatus = (cableToReplace?
2543 cableInProgressExpectedToCarryData) :
2548 if (cableToReplace && cableToReplaceHasMatchingDataCarryingStatus)
2554 else if (cableToReplace && !cableToReplaceHasMatchingDataCarryingStatus &&
2570 if (cableToReplace && !cableToReplaceHasMatchingDataCarryingStatus)
2572 QList<QGraphicsItem *> removedComponents;
2573 removedComponents.append(cableToReplace->
getRenderer());
2582 if (typecastPort && typecastPort->scene())
2590 if (cableInProgressExpectedToCarryData &&
2592 (*typecastOutPort->
getConnectedCables(
true).begin())->getRenderer()->effectivelyCarriesData())
2594 QList<QGraphicsItem *> removedComponents;
2595 removedComponents.append(uncollapsedTypecast);
2601 dynamic_cast<VuoPublishedPort *>(publishedInputPort->
getBase()),
2602 forceEventOnlyPublication,
2603 (portToSpecialize? portToSpecialize->
getBase() : NULL),
2604 specializedTypeName,
2630 if (internalOutputPort)
2633 forceEventOnlyPublication =
true;
2639 if (internalOutputPort &&
2640 publishedOutputPort)
2646 ||
selectBridgingSolution(internalOutputPort, publishedOutputPort,
false, &portToSpecialize, specializedTypeName, typecastToInsert))
2649 dynamic_cast<VuoPublishedPort *>(publishedOutputPort->
getBase()),
2650 forceEventOnlyPublication,
2651 portToSpecialize? portToSpecialize->
getBase() : NULL,
2652 specializedTypeName,
2671 if (! cableInProgress)
2674 if (cableInProgressWasNew)
2678 QList<QGraphicsItem *> removedComponents;
2679 removedComponents.append(cableInProgress->
getRenderer());
2683 cableInProgress = NULL;
2696 cableInProgress->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
2701 cableInProgress = NULL;
2703 else if (cableInProgress)
2718 bool leftMouseButtonPressed = (
event->buttons() & Qt::LeftButton);
2734 if (cableInProgress || (! leftMouseButtonPressed))
2735 updateHoverHighlighting(event->scenePos());
2739 if (leftMouseButtonPressed)
2742 if ((! dragStickinessDisabled) && (QLineF(event->screenPos(),
event->buttonDownScreenPos(Qt::LeftButton)).length() < QApplication::startDragDistance()))
2746 dragStickinessDisabled =
true;
2750 if (portWithDragInitiated || cableWithYankInitiated)
2752 initiateCableDrag(portWithDragInitiated, cableWithYankInitiated, event);
2753 portWithDragInitiated = NULL;
2754 cableWithYankInitiated = NULL;
2759 if (cableInProgress)
2769 else if (duplicationDragInProgress)
2771 if (duplicateOnNextMouseMove)
2774 duplicateOnNextMouseMove =
false;
2781 QPointF delta = newPos - cursorPosBeforeDuplicationDragMove;
2783 cursorPosBeforeDuplicationDragMove = newPos;
2787 QGraphicsScene::mouseMoveEvent(event);
2792 QGraphicsScene::mouseMoveEvent(event);
2800 void VuoEditorComposition::updateHoverHighlighting(QPointF scenePos,
bool disablePortHoverHighlighting)
2812 bool hoveringOverNodeHeader =
false;
2813 if (cableInProgress)
2822 hoveringOverNodeHeader =
true;
2828 if (! hoveringOverNodeHeader)
2831 if (dynamic_cast<VuoRendererNode *>(item) && !makeListDrawer)
2834 node = dynamic_cast<VuoRendererNode *>(item);
2839 if (item != previousNearbyItem)
2841 VuoRendererPort *previousPort = dynamic_cast<VuoRendererPort *>(previousNearbyItem);
2842 VuoRendererNode *previousNode = dynamic_cast<VuoRendererNode *>(previousNearbyItem);
2847 if (previousNearbyItem)
2855 if (! cableInProgress)
2861 else if (typecastPort && !disablePortHoverHighlighting)
2863 else if (port && !disablePortHoverHighlighting)
2866 if (!cableInProgress)
2877 if (cableInProgress)
2880 cableInProgress->getFromPort()->getRenderer() :
2881 cableInProgress->getToPort()->getRenderer());
2883 QList< QPair<VuoRendererPort *, bool> > updatedPorts;
2884 if (hoveringOverNodeHeader)
2885 updatedPorts.append( QPair<VuoRendererPort *, bool>(port,
true) );
2886 if (previousNode && previousPort)
2887 updatedPorts.append( QPair<VuoRendererPort *, bool>(previousPort, !cableInProgress->getRenderer()->effectivelyCarriesData()) );
2889 QPair<VuoRendererPort *, bool> p;
2890 foreach (p, updatedPorts)
2895 if (typecastParentPort)
2896 updatedPort = typecastParentPort;
2898 updateEligibilityHighlightingForPort(updatedPort, fixedPort, p.second);
2901 updateEligibilityHighlightingForNode(potentialDrawer);
2908 if (targetPort || previousTargetPort)
2910 if (cableInProgress)
2911 cableInProgress->getRenderer()->setFloatingEndpointAboveEventPort(targetPort && (!targetPort->
getDataType() || hoveringOverNodeHeader));
2916 previousNearbyItem = item;
2924 else if (port && !disablePortHoverHighlighting)
2927 if (!cableInProgress)
2933 else if (makeListDrawer)
2943 if (previousNearbyItem)
2945 VuoRendererCable *cable = dynamic_cast<VuoRendererCable *>(previousNearbyItem);
2946 VuoRendererPort *port = dynamic_cast<VuoRendererPort *>(previousNearbyItem);
2948 VuoRendererNode *node = dynamic_cast<VuoRendererNode *>(previousNearbyItem);
2961 else if (typecastPort)
2970 previousNearbyItem = NULL;
2979 if ((event->key() != Qt::Key_Alt) && (event->key() != Qt::Key_Shift) && (event->key() != Qt::Key_Escape))
2982 Qt::KeyboardModifiers modifiers =
event->modifiers();
2983 qreal adjustedNodeMoveRate = nodeMoveRate;
2984 if (modifiers & Qt::ShiftModifier)
2986 adjustedNodeMoveRate *= nodeMoveRateMultiplier;
2989 switch (event->key()) {
2990 case Qt::Key_Backspace:
2995 case Qt::Key_Delete:
3007 if (modifiers & Qt::ControlModifier)
3008 openSelectedEditableNodes();
3025 if (cableInProgress)
3027 cableInProgress->getRenderer()->updateGeometry();
3028 cableInProgress->getCompiler()->setAlwaysEventOnly(
true);
3029 highlightEligibleEndpointsForCable(cableInProgress);
3031 VuoRendererPort *hoveredPort = dynamic_cast<VuoRendererPort *>(previousNearbyItem);
3039 case Qt::Key_Return:
3042 QGraphicsScene::keyPressEvent(event);
3044 if (!event->isAccepted())
3051 if (selectedComments.empty() && !selectedNodes.empty())
3058 case Qt::Key_Escape:
3060 if (duplicateOnNextMouseMove || duplicationDragInProgress)
3064 duplicateOnNextMouseMove =
false;
3065 duplicationDragInProgress =
false;
3066 duplicationCancelled =
true;
3068 else if (cableInProgress)
3077 QGraphicsScene::keyPressEvent(event);
3088 switch (event->key()) {
3091 if (cableInProgress)
3093 cableInProgress->getRenderer()->updateGeometry();
3094 cableInProgress->getCompiler()->setAlwaysEventOnly(
false);
3095 highlightEligibleEndpointsForCable(cableInProgress);
3097 VuoRendererPort *hoveredPort = dynamic_cast<VuoRendererPort *>(previousNearbyItem);
3107 QGraphicsScene::keyReleaseEvent(event);
3116 void VuoEditorComposition::addActionToMenuAndMapper(QMenu *menu, QSignalMapper *mapper, QString name,
int index)
3118 QAction *action =
new QAction(name,
this);
3119 menu->addAction(action);
3120 mapper->setMapping(action, index);
3121 connect(action, &QAction::triggered, mapper,
static_cast<void (QSignalMapper::*)()
>(&QSignalMapper::map));
3133 contextMenu.setSeparatorsCollapsible(
false);
3138 QAction *insertNodeSection =
new QAction(tr(
"Insert Node"), NULL);
3139 insertNodeSection->setEnabled(
false);
3140 contextMenu.addAction(insertNodeSection);
3142 QString spacer(
" ");
3146 QMenu *shareMenu =
new QMenu(&contextMenu);
3147 shareMenu->setSeparatorsCollapsible(
false);
3148 shareMenu->setTitle(spacer + tr(
"Share"));
3149 contextMenu.addMenu(shareMenu);
3152 QAction *action =
new QAction(tr(
"Share Value"), NULL);
3153 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.data.share"))));
3154 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3155 shareMenu->addAction(action);
3159 QAction *action =
new QAction(tr(
"Share List"), NULL);
3160 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.data.share.list"))));
3161 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3162 shareMenu->addAction(action);
3166 QAction *action =
new QAction(tr(
"Share Event"), NULL);
3167 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.event.share"))));
3168 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3169 shareMenu->addAction(action);
3175 QMenu *holdMenu =
new QMenu(&contextMenu);
3176 holdMenu->setSeparatorsCollapsible(
false);
3177 holdMenu->setTitle(spacer + tr(
"Hold"));
3178 contextMenu.addMenu(holdMenu);
3181 QAction *action =
new QAction(tr(
"Hold Value"), NULL);
3182 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.data.hold2"))));
3183 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3184 holdMenu->addAction(action);
3188 QAction *action =
new QAction(tr(
"Hold List"), NULL);
3189 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.data.hold.list2"))));
3190 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3191 holdMenu->addAction(action);
3197 QMenu *allowMenu =
new QMenu(&contextMenu);
3198 allowMenu->setSeparatorsCollapsible(
false);
3199 allowMenu->setTitle(spacer + tr(
"Allow"));
3200 contextMenu.addMenu(allowMenu);
3203 QAction *action =
new QAction(tr(
"Allow First Event"), NULL);
3204 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.event.allowFirst"))));
3205 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3206 allowMenu->addAction(action);
3210 QAction *action =
new QAction(tr(
"Allow First Value"), NULL);
3211 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.event.allowFirstValue"))));
3212 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3213 allowMenu->addAction(action);
3217 QAction *action =
new QAction(tr(
"Allow Periodic Events"), NULL);
3218 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.time.allowPeriodic"))));
3219 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3220 allowMenu->addAction(action);
3224 QAction *action =
new QAction(tr(
"Allow Changes"), NULL);
3225 action->setData(qVariantFromValue(qMakePair(event->scenePos(), QStringLiteral(
"vuo.event.allowChanges2"))));
3226 connect(action, &QAction::triggered,
this, &VuoEditorComposition::insertNode);
3227 allowMenu->addAction(action);
3231 contextMenu.addSeparator();
3233 QAction *contextMenuInsertComment =
new QAction(NULL);
3234 contextMenuInsertComment->setText(tr(
"Insert Comment"));
3235 contextMenuInsertComment->setData(qVariantFromValue(event->scenePos()));
3236 connect(contextMenuInsertComment, &QAction::triggered,
this, &VuoEditorComposition::insertComment);
3237 contextMenu.addAction(contextMenuInsertComment);
3239 QAction *contextMenuInsertSubcomposition =
new QAction(NULL);
3240 contextMenuInsertSubcomposition->setText(tr(
"Insert Subcomposition"));
3241 contextMenuInsertSubcomposition->setData(qVariantFromValue(event->scenePos()));
3242 connect(contextMenuInsertSubcomposition, &QAction::triggered,
this, &VuoEditorComposition::insertSubcomposition);
3243 contextMenu.addAction(contextMenuInsertSubcomposition);
3248 QAction *contextMenuDeleteSelectedSnapshot =
new QAction(NULL);
3251 if (dynamic_cast<VuoRendererPort *>(item))
3255 if (port->
isConstant() && inputEditorManager)
3259 if (inputEditorLoadedForPortDataType)
3261 contextMenuSetPortConstant->setData(qVariantFromValue((
void *)port));
3262 contextMenu.addAction(contextMenuSetPortConstant);
3264 inputEditorLoadedForPortDataType->deleteLater();
3270 contextMenuPublishPort->setText(tr(
"Publish Port"));
3271 contextMenuPublishPort->setData(qVariantFromValue((
void *)port));
3272 contextMenu.addAction(contextMenuPublishPort);
3277 vector<VuoRendererPublishedPort *> externalPublishedPorts = port->
getPublishedPorts();
3278 bool hasExternalPublishedPortWithMultipleInternalPorts =
false;
3279 bool hasExternalPublishedPortBelongingToActiveProtocol =
false;
3283 hasExternalPublishedPortWithMultipleInternalPorts =
true;
3285 if (dynamic_cast<VuoPublishedPort *>(externalPort->
getBase())->isProtocolPort())
3286 hasExternalPublishedPortBelongingToActiveProtocol =
true;
3293 if (!hasExternalPublishedPortWithMultipleInternalPorts &&!hasExternalPublishedPortBelongingToActiveProtocol)
3295 contextMenuPublishPort->setText(tr(
"Delete Published Port"));
3296 contextMenuPublishPort->setData(qVariantFromValue((
void *)port));
3297 contextMenu.addAction(contextMenuPublishPort);
3301 bool isTriggerPort = dynamic_cast<VuoCompilerTriggerPort *>(port->
getBase()->
getCompiler());
3302 if (isTriggerPort || port->
getInput())
3304 __block
bool isTopLevelCompositionRunning =
false;
3305 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
3307 isTopLevelCompositionRunning = topLevelComposition->
isRunning();
3310 if (isTopLevelCompositionRunning)
3312 contextMenuFireEvent->setData(qVariantFromValue((
void *)port));
3313 contextMenu.addAction(contextMenuFireEvent);
3319 QMenu *contextMenuThrottling =
new QMenu(&contextMenu);
3320 contextMenuThrottling->setSeparatorsCollapsible(
false);
3321 contextMenuThrottling->setTitle(tr(
"Set Event Throttling"));
3323 foreach (QAction *action, contextMenuThrottlingActions)
3325 contextMenuThrottling->addAction(action);
3326 action->setData(qVariantFromValue((
void *)port));
3327 action->setCheckable(
true);
3328 action->setChecked( i++ == port->getBase()->getEventThrottling() );
3330 contextMenu.addMenu(contextMenuThrottling);
3335 if (genericDataType || isPortCurrentlyRevertible(port))
3337 QMenu *contextMenuSpecializeGenericType =
new QMenu(&contextMenu);
3338 contextMenuSpecializeGenericType->setSeparatorsCollapsible(
false);
3339 contextMenuSpecializeGenericType->setTitle(tr(
"Set Data Type"));
3340 contextMenuSpecializeGenericType->setToolTipsVisible(
true);
3342 QAction *unspecializeAction = contextMenuSpecializeGenericType->addAction(tr(
"Generic"));
3347 contextMenuSpecializeGenericType->addSeparator();
3349 unspecializeAction->setData(qVariantFromValue((
void *)port));
3350 unspecializeAction->setCheckable(
true);
3351 unspecializeAction->setChecked(genericDataType);
3353 contextMenu.addMenu(contextMenuSpecializeGenericType);
3356 set<string> compatibleTypes;
3357 set<string> compatibleTypesInIsolation;
3360 if (genericDataType)
3362 VuoCompilerPortClass *portClass = static_cast<VuoCompilerPortClass *>(port->getBase()->getClass()->getCompiler());
3363 genericTypeFromPortClass = static_cast<VuoGenericType *>(portClass->
getDataVuoType());
3368 compatibleTypes = set<string>(compatibleTypesVector.begin(), compatibleTypesVector.end());
3374 compatibleTypes.insert(compatibleTypeNames.begin(), compatibleTypeNames.end());
3379 else if (isPortCurrentlyRevertible(port))
3381 map<VuoNode *, string> nodesToReplace;
3382 set<VuoCable *> cablesToDelete;
3384 if (cablesToDelete.size() >= 1)
3390 port->getUnderlyingParentNode()->getBase()->getNodeClass()->getCompiler());
3391 genericTypeFromPortClass = dynamic_cast<VuoGenericType *>( specializedNodeClass->
getOriginalPortType(port->getBase()->getClass()) );
3392 compatibleTypes = getRespecializationOptionsForPortInNetwork(port);
3396 if (genericTypeFromPortClass)
3408 if (genericHostPortDataType)
3409 genericTypeFromPortClass = static_cast<VuoGenericType *>(portClass->
getDataVuoType());
3410 else if (isPortCurrentlyRevertible(hostPort->
getRenderer()))
3414 genericTypeFromPortClass = dynamic_cast<VuoGenericType *>( specializedNodeClass->
getOriginalPortType(portClass->
getBase()) );
3420 vector<string> compatibleTypesInIsolationVector;
3421 if (genericTypeFromPortClass)
3428 foreach (
string type, compatibleTypesInIsolationVector)
3435 const int maxTypeCountForFlatMenuDisplay = 10;
3436 if (compatibleTypesInIsolation.size() <= maxTypeCountForFlatMenuDisplay)
3438 QList<QAction *> actions =
getCompatibleTypesForMenu(port, compatibleTypesInIsolation, compatibleTypes,
false,
"", contextMenuSpecializeGenericType);
3446 QList<QAction *> actions =
getCompatibleTypesForMenu(port, compatibleTypesInIsolation, compatibleTypes,
true,
"", contextMenuSpecializeGenericType);
3451 QList<QAction *> allNodeSetActionsToAdd;
3452 for (map<
string, set<VuoCompilerType *> >::iterator i = loadedTypesForNodeSet.begin(); i != loadedTypesForNodeSet.end(); ++i)
3454 string nodeSetName = i->first;
3455 if (!nodeSetName.empty())
3456 allNodeSetActionsToAdd +=
getCompatibleTypesForMenu(port, compatibleTypesInIsolation, compatibleTypes,
true, nodeSetName, contextMenuSpecializeGenericType);
3459 if ((contextMenuSpecializeGenericType->actions().size() > 0) && (allNodeSetActionsToAdd.size() > 0))
3460 contextMenuSpecializeGenericType->addSeparator();
3465 foreach (QAction *action, contextMenuSpecializeGenericType->actions())
3467 QMenu *specializeSubmenu = action->menu();
3468 if (specializeSubmenu)
3470 foreach (QAction *specializeSubaction, specializeSubmenu->actions())
3471 connect(specializeSubaction, &QAction::triggered,
this, &VuoEditorComposition::specializeGenericPortType);
3473 else if (action == unspecializeAction)
3474 connect(action, &QAction::triggered,
this, &VuoEditorComposition::unspecializePortType);
3476 connect(action, &QAction::triggered,
this, &VuoEditorComposition::specializeGenericPortType);
3483 int numVisibleDirectlyConnectedCables = 0;
3484 int numHidableDirectlyConnectedCables = 0;
3485 int numUnhidableDirectlyConnectedCables = 0;
3491 numVisibleDirectlyConnectedCables++;
3493 numHidableDirectlyConnectedCables++;
3497 numUnhidableDirectlyConnectedCables++;
3500 int numVisibleChildPortConnectedCables = 0;
3501 int numHidableChildPortConnectedCables = 0;
3502 int numUnhidableChildPortConnectedCables = 0;
3512 numVisibleChildPortConnectedCables++;
3515 numHidableChildPortConnectedCables++;
3518 numUnhidableChildPortConnectedCables++;
3523 int numVisibleConnectedCables = numVisibleDirectlyConnectedCables + numVisibleChildPortConnectedCables;
3526 int numHidableConnectedCables = numHidableDirectlyConnectedCables + numHidableChildPortConnectedCables;
3529 int numUnhidableConnectedCables = numUnhidableDirectlyConnectedCables + numUnhidableChildPortConnectedCables;
3531 if ((!
renderHiddenCables && ((numHidableConnectedCables >= 1) || (numUnhidableConnectedCables >= 1)))
3532 || (numVisibleConnectedCables >= 1))
3534 if (!contextMenu.actions().empty() && !contextMenu.actions().last()->isSeparator())
3535 contextMenu.addSeparator();
3540 if (numHidableConnectedCables >= 1)
3545 int numApparentlyHidableConnectedCables = numVisibleConnectedCables + numUnhidableConnectedCables;
3546 contextMenuHideCables->setText(numApparentlyHidableConnectedCables > 1?
"Hide Cables" :
"Hide Cable");
3547 contextMenuHideCables->setData(qVariantFromValue((
void *)port));
3548 contextMenu.addAction(contextMenuHideCables);
3551 if (numUnhidableConnectedCables >= 1)
3553 int numApparentlyUnhidableConnectedCables = numVisibleConnectedCables + numUnhidableConnectedCables;
3554 contextMenuUnhideCables->setText(numApparentlyUnhidableConnectedCables > 1?
"Unhide Cables" :
"Unhide Cable");
3555 contextMenuUnhideCables->setData(qVariantFromValue((
void *)port));
3556 contextMenu.addAction(contextMenuUnhideCables);
3560 if (numVisibleConnectedCables >= 1)
3562 contextMenuDeleteCables->setText(numVisibleConnectedCables > 1?
"Delete Cables" :
"Delete Cable");
3563 contextMenuDeleteCables->setData(qVariantFromValue((
void *)port));
3564 contextMenu.addAction(contextMenuDeleteCables);
3571 if (! item->isSelected())
3574 item->setSelected(
true);
3577 QList<QGraphicsItem *> selectedComponents = selectedItems();
3578 bool onlyCommentsSelected =
true;
3579 bool onlyCablesSelected =
true;
3580 bool selectionContainsMissingNode =
false;
3581 foreach (QGraphicsItem *item, selectedComponents)
3583 if (!dynamic_cast<VuoRendererComment *>(item))
3584 onlyCommentsSelected =
false;
3586 if (!dynamic_cast<VuoRendererCable *>(item))
3587 onlyCablesSelected =
false;
3589 if (dynamic_cast<VuoRendererNode *>(item) && !dynamic_cast<VuoRendererNode *>(item)->
getBase()->hasCompiler())
3590 selectionContainsMissingNode =
true;
3593 contextMenuDeleteSelectedSnapshot->setText(contextMenuDeleteSelected->text());
3601 if (onlyCommentsSelected)
3602 contextMenu.addAction(contextMenuEditSelectedComments);
3607 contextMenu.addSeparator();
3610 contextMenu.addAction(contextMenuRefactorSelected);
3612 contextMenu.addSeparator();
3615 contextMenu.addAction(contextMenuDeleteSelectedSnapshot);
3625 contextMenu.addAction(contextMenuHideSelectedCables);
3628 contextMenu.addAction(contextMenuDeleteSelectedSnapshot);
3632 else if (dynamic_cast<VuoRendererNode *>(item))
3637 if (dynamic_cast<VuoRendererInputDrawer *>(node) &&
3641 if (dynamic_cast<VuoRendererInputListDrawer *>(node))
3643 contextMenuAddInputPort->setData(qVariantFromValue((
void *)node));
3644 contextMenuRemoveInputPort->setData(qVariantFromValue((
void *)node));
3647 contextMenuRemoveInputPort->setEnabled(listItemCount >= 1);
3649 contextMenu.addAction(contextMenuAddInputPort);
3650 contextMenu.addAction(contextMenuRemoveInputPort);
3652 contextMenu.addSeparator();
3656 contextMenu.addAction(contextMenuDeleteSelectedSnapshot);
3663 if (nodeClass->
hasCompiler() && dynamic_cast<VuoCompilerSpecializedNodeClass *>(nodeClass->
getCompiler()))
3665 string originalGenericNodeClassName = dynamic_cast<VuoCompilerSpecializedNodeClass *>(nodeClass->
getCompiler())->getOriginalGenericNodeClassName();
3667 if (originalGenericNodeClass)
3668 nodeClass = originalGenericNodeClass->
getBase();
3671 QString actionText, sourcePath;
3675 int numSelectedNonAttachmentNodes = 0;
3676 QList<QGraphicsItem *> selectedComponents = selectedItems();
3677 foreach (QGraphicsItem *item, selectedComponents)
3679 if (dynamic_cast<VuoRendererNode *>(item) && !dynamic_cast<VuoRendererInputAttachment *>(item))
3680 numSelectedNonAttachmentNodes++;
3683 if ((numSelectedNonAttachmentNodes == 1) && nodeClassIsEditable)
3686 QAction *editAction =
new QAction(NULL);
3687 editAction->setText(actionText);
3688 editAction->setData(qVariantFromValue(node));
3691 contextMenu.addAction(editAction);
3692 contextMenu.addSeparator();
3697 contextMenu.addAction(contextMenuRenameSelected);
3702 contextMenu.addSeparator();
3705 if (numSelectedNonAttachmentNodes == 1)
3707 if (contextMenuChangeNode)
3708 contextMenuChangeNode->deleteLater();
3711 contextMenuChangeNode->setSeparatorsCollapsible(
false);
3712 contextMenuChangeNode->setTitle(tr(
"Change To"));
3715 if (!contextMenuChangeNode->actions().isEmpty())
3716 contextMenu.addMenu(contextMenuChangeNode);
3720 if (!selectionContainsMissingNode)
3721 contextMenu.addAction(contextMenuRefactorSelected);
3723 if ((numSelectedNonAttachmentNodes == 1) && (nodeClassIsEditable || nodeClassIs3rdParty))
3727 if (!modulePath.isEmpty())
3729 QString enclosingDirUrl =
"file://" + QFileInfo(modulePath).dir().absolutePath();
3730 QAction *openEnclosingFolderAction =
new QAction(NULL);
3731 openEnclosingFolderAction->setText(
"Show in Finder");
3732 openEnclosingFolderAction->setData(qVariantFromValue(enclosingDirUrl));
3734 contextMenu.addAction(openEnclosingFolderAction);
3738 if (!contextMenu.actions().empty() && !contextMenu.actions().last()->isSeparator())
3739 contextMenu.addSeparator();
3742 contextMenu.addAction(contextMenuDeleteSelectedSnapshot);
3748 if (!contextMenu.actions().isEmpty())
3753 menuSelectionInProgress =
true;
3754 contextMenu.exec(event->screenPos());
3755 menuSelectionInProgress =
false;
3758 delete contextMenuDeleteSelectedSnapshot;
3766 QAction *sender = (QAction *)QObject::sender();
3778 vector<string> typeOptions;
3780 map<string, VuoCompilerType *> loadedTypes = compiler->
getTypes();
3781 for (map<string, VuoCompilerType *>::iterator i = loadedTypes.begin(); i != loadedTypes.end(); ++i)
3786 (i->first !=
"VuoMathExpressionList"))
3788 typeOptions.push_back(i->first);
3800 set<string> VuoEditorComposition::getRespecializationOptionsForPortInNetwork(
VuoRendererPort *port)
3803 return set<string>();
3810 vector<string> compatibleInnerTypeNames;
3811 vector<string> compatibleTypeNames;
3812 for (
VuoPort *connectedPort : connectedGenericPorts)
3817 if (specializedNodeClass)
3820 genericTypeFromPortClass = dynamic_cast<VuoGenericType *>( specializedNodeClass->
getOriginalPortType(portClass) );
3825 vector<string> innermostCompatibleTypeNamesForPort;
3826 for (vector<string>::iterator k = compatibleTypeNamesForPort.begin(); k != compatibleTypeNamesForPort.end(); ++k)
3829 if (! innermostCompatibleTypeNamesForPort.empty())
3831 if (compatibleInnerTypeNames.empty())
3832 compatibleInnerTypeNames = innermostCompatibleTypeNamesForPort;
3835 for (
int k = compatibleInnerTypeNames.size() - 1; k >= 0; --k)
3836 if (find(innermostCompatibleTypeNamesForPort.begin(), innermostCompatibleTypeNamesForPort.end(), compatibleInnerTypeNames[k]) ==
3837 innermostCompatibleTypeNamesForPort.end())
3838 compatibleInnerTypeNames.erase(compatibleInnerTypeNames.begin() + k);
3847 string typeNameForPort = genericTypeFromPortClass->
getModuleKey();
3851 for (vector<string>::iterator k = compatibleInnerTypeNames.begin(); k != compatibleInnerTypeNames.end(); ++k)
3852 compatibleTypeNames.push_back(prefix + *k);
3854 if (compatibleTypeNames.empty())
3864 return set<string>(compatibleTypeNames.begin(), compatibleTypeNames.end());
3887 set<string> compatibleTypesInIsolation,
3888 set<string> compatibleTypesInContext,
3889 bool limitToNodeSet,
3893 QList<QAction *> actionsToAddToMenu;
3895 map<string, VuoCompilerType *> allTypes = compiler->
getTypes();
3897 QList<VuoCompilerType *> compatibleTypesForNodeSetDisplay;
3898 foreach (
string typeName, compatibleTypesInIsolation)
3901 if ((!limitToNodeSet || (loadedTypesForNodeSet[nodeSetName].find(type) != loadedTypesForNodeSet[nodeSetName].end())) &&
3904 (typeName !=
"VuoUrl" && typeName !=
"VuoList_VuoUrl"
3906 && typeName !=
"VuoInteraction" && typeName !=
"VuoList_VuoInteraction"
3907 && typeName !=
"VuoInteractionType" && typeName !=
"VuoList_VuoInteractionType"
3908 && typeName !=
"VuoUuid" && typeName !=
"VuoList_VuoUuid"
3910 && typeName !=
"VuoIconPosition" && typeName !=
"VuoList_VuoIconPosition"
3911 && typeName !=
"VuoMesh" && typeName !=
"VuoList_VuoMesh"
3912 && typeName !=
"VuoWindowProperty" && typeName !=
"VuoList_VuoWindowProperty"
3913 && typeName !=
"VuoWindowReference" && typeName !=
"VuoList_VuoWindowReference"))
3914 compatibleTypesForNodeSetDisplay.append(type);
3917 if (!compatibleTypesForNodeSetDisplay.isEmpty())
3919 QMenu *contextMenuNodeSetTypes = NULL;
3920 QList<QAction *> actionsToAddToNodeSetSubmenu;
3921 bool enabledContentAdded =
false;
3924 if (!nodeSetName.empty())
3926 contextMenuNodeSetTypes =
new QMenu(menu);
3927 contextMenuNodeSetTypes->setSeparatorsCollapsible(
false);
3929 contextMenuNodeSetTypes->setToolTipsVisible(
true);
3930 actionsToAddToMenu.append(contextMenuNodeSetTypes->menuAction());
3936 QList<QVariant> portAndSpecializedType;
3937 portAndSpecializedType.append(qVariantFromValue((
void *)genericPort));
3938 portAndSpecializedType.append(typeName.c_str());
3940 QAction *specializeAction;
3944 if (!nodeSetName.empty())
3946 specializeAction =
new QAction(typeTitle, contextMenuNodeSetTypes);
3947 actionsToAddToNodeSetSubmenu.append(specializeAction);
3953 specializeAction =
new QAction(typeTitle, menu);
3954 actionsToAddToMenu.append(specializeAction);
3957 specializeAction->setData(QVariant(portAndSpecializedType));
3958 specializeAction->setCheckable(
true);
3959 specializeAction->setChecked(genericPort && (genericPort->getDataType()->getModuleKey() == type->
getBase()->
getModuleKey()));
3961 if (compatibleTypesInContext.find(typeName) == compatibleTypesInContext.end())
3963 specializeAction->setEnabled(
false);
3965 specializeAction->setToolTip(tr(
"To change to this type, disconnect the cable from this port and from this node's other ports of the same type."));
3968 enabledContentAdded =
true;
3971 if (contextMenuNodeSetTypes)
3975 if (!enabledContentAdded)
3976 contextMenuNodeSetTypes->setEnabled(
false);
3980 QList<QAction *> actionListWithPromotions = promoteSingletonsFromSubmenus(actionsToAddToMenu);
3981 return actionListWithPromotions;
3988 QList<QAction *> VuoEditorComposition::promoteSingletonsFromSubmenus(QList<QAction *> actionList)
3990 QList<QAction *> modifiedActionList;
3991 foreach (QAction *action, actionList)
3993 if (action->menu() && (action->menu()->actions().size() == 1))
3995 QAction *singleSubaction = action->menu()->actions().first();
3996 action->menu()->removeAction(singleSubaction);
3997 modifiedActionList.append(singleSubaction);
4000 modifiedActionList.append(action);
4003 return modifiedActionList;
4011 std::sort(actionList.begin(), actionList.end(), nodeSetMenuActionLessThan);
4012 foreach (QAction *action, actionList)
4013 menu->addAction(action);
4019 void VuoEditorComposition::updatePopoversForActiveWindowChange(QWidget *old, QWidget *now)
4032 void VuoEditorComposition::updatePopoversForApplicationStateChange(
bool active)
4034 if (ignoreApplicationStateChangeEvents)
4038 if (activeWindow && (activeWindow->
getComposition() ==
this) && (!activeWindow->isMinimized()))
4052 return findNearbyComponent(scenePos, VuoEditorComposition::targetTypePort, limitPortCollisionRange);
4060 QGraphicsItem *item =
findNearbyComponent(scenePos, VuoEditorComposition::targetTypeNodeHeader);
4061 return dynamic_cast<VuoRendererNode *>(item);
4078 bool limitPortCollisionRange)
4084 bool ignoreComments;
4088 case VuoEditorComposition::targetTypePort:
4090 ignoreCables =
true;
4092 ignorePorts =
false;
4093 ignoreComments =
true;
4096 case VuoEditorComposition::targetTypeNodeHeader:
4098 ignoreCables =
true;
4101 ignoreComments =
true;
4106 ignoreCables =
false;
4107 ignoreNodes =
false;
4108 ignorePorts =
false;
4109 ignoreComments =
false;
4117 QGraphicsItem *topmostItemUnderCursor = itemAt(scenePos, views()[0]->transform());
4118 if (topmostItemUnderCursor && (!topmostItemUnderCursor->isEnabled()))
4119 topmostItemUnderCursor = NULL;
4123 QRectF searchRect(scenePos.x()-0.5*rectLength, scenePos.y()-0.5*rectLength, rectLength, rectLength);
4124 QList<QGraphicsItem *> itemsInRange = items(searchRect);
4125 for (QList<QGraphicsItem *>::iterator i = itemsInRange.begin(); i != itemsInRange.end(); ++i)
4127 if (!(*i)->isEnabled())
4134 bool makeListDragHandle =
4137 if (makeListDragHandle &&
4138 ((! topmostItemUnderCursor) ||
4139 (topmostItemUnderCursor == makeListDrawer) ||
4140 (topmostItemUnderCursor->zValue() < makeListDrawer->zValue())))
4142 return makeListDrawer;
4153 ((! topmostItemUnderCursor) ||
4154 (topmostItemUnderCursor == port) ||
4156 (topmostItemUnderCursor->zValue() < port->zValue()))
4158 ((! limitPortCollisionRange) ||
4172 ((! topmostItemUnderCursor) ||
4173 (topmostItemUnderCursor == cable) ||
4174 (topmostItemUnderCursor->zValue() < cable->zValue())))
4181 if (! ignoreComments)
4184 if (!comment && dynamic_cast<VuoRendererComment *>((*i)->parentItem()))
4185 comment = dynamic_cast<VuoRendererComment *>((*i)->parentItem());
4188 ((! topmostItemUnderCursor) ||
4189 (topmostItemUnderCursor == (*i)) ||
4190 (topmostItemUnderCursor->zValue() < (*i)->zValue())))
4197 if (targetType == VuoEditorComposition::targetTypeNodeHeader)
4200 if (node && ! dynamic_cast<VuoRendererInputDrawer *>(node))
4203 headerRect = node->mapToScene(headerRect).
boundingRect();
4204 if (headerRect.intersects(searchRect) && scenePos.y() <= headerRect.bottom())
4215 if (dynamic_cast<VuoRendererNode *>(topmostItemUnderCursor))
4216 return topmostItemUnderCursor;
4220 if (dynamic_cast<VuoRendererPort *>(topmostItemUnderCursor))
4221 return ((
VuoRendererPort *)(topmostItemUnderCursor))->getRenderedParentNode();
4238 if (! cableInProgress)
4241 VuoPort *fromPort = cableInProgress->getFromPort();
4242 VuoPort *toPort = cableInProgress->getToPort();
4243 VuoPort *fixedPort = (fromPort? fromPort: toPort);
4245 if (dynamic_cast<VuoRendererPort *>(fixedPort->
getRenderer())->getUnderlyingParentNode() == node)
4258 vector<VuoRendererPort *> portList;
4273 if (portList.size() > firstPortIndex)
4275 targetPort = portList[firstPortIndex];
4281 for (
int i = firstPortIndex; i < portList.size(); ++i)
4285 firstPortWithoutWall = portList[i];
4289 if (firstPortWithoutWall)
4290 targetPort = firstPortWithoutWall;
4299 if (portList.size() > firstPortIndex)
4300 targetPort = portList[firstPortIndex];
4321 QRectF boundingRect;
4322 foreach (QGraphicsItem *item, items())
4326 boundingRect |= item->sceneBoundingRect();
4329 return boundingRect;
4338 QRectF boundingRect;
4340 foreach (QGraphicsItem *item, selectedItems())
4344 boundingRect |= item->sceneBoundingRect();
4347 return boundingRect;
4356 QRectF boundingRect;
4358 foreach (QGraphicsItem *item, selectedItems())
4362 boundingRect |= item->mapToScene(item->childrenBoundingRect()).boundingRect();
4372 boundingRect |= drawer->mapToScene(drawer->childrenBoundingRect()).boundingRect();
4377 return boundingRect;
4386 VuoPort *port = portWithStaticIdentifier[portID];
4413 if (dynamic_cast<VuoCompilerInputEventPort *>(port))
4417 if (updateInRunningComposition)
4422 else if (dynamic_cast<VuoCompilerPublishedPort *>(port))
4424 dynamic_cast<VuoCompilerPublishedPort *>(port)->setInitialValue(newValue);
4426 if (updateInRunningComposition)
4452 if (!errorMarkingUpdatesEnabled)
4455 errorMarkingUpdatesEnabled =
false;
4472 set<VuoCompilerCable *> potentialCables;
4474 if (targetPort && cableInProgress)
4480 if (cableInProgress->getFromNode())
4482 fromNode = cableInProgress->getFromNode();
4483 fromPort = cableInProgress->getFromPort();
4485 toPort = targetPort->
getBase();
4490 fromPort = targetPort->
getBase();
4491 toNode = cableInProgress->getToNode();
4492 toPort = cableInProgress->getToPort();
4497 potentialCable->
setAlwaysEventOnly(! cableInProgress->getRenderer()->effectivelyCarriesData() ||
4498 cableInProgress->getRenderer()->isFloatingEndpointAboveEventPort());
4502 potentialCables.insert(potentialCable);
4513 VUserLog(
"%s: Showing error popover: %s",
4521 set<VuoRendererNode *> nodesToMark;
4522 set<VuoRendererCable *> cablesToMark;
4524 set<VuoNode *> problemNodes = issue.
getNodes();
4525 foreach (
VuoNode *node, problemNodes)
4529 set<VuoCable *> problemCables = issue.
getCables();
4530 foreach (
VuoCable *cable, problemCables)
4532 VuoCable *cableToMark = (cable->
getCompiler() == potentialCable ? cableInProgress : cable);
4538 errorMark->addMarkedComponents(nodesToMark, cablesToMark);
4541 errorPopovers.insert(errorPopover);
4545 QRectF viewportRect = views()[0]->mapToScene(views()[0]->viewport()->rect()).boundingRect();
4549 if (targetPort && cableInProgress && nodesToMark.find(targetPort->
getRenderedParentNode()) != nodesToMark.end())
4553 else if (! nodesToMark.empty())
4556 qreal topY = viewportRect.bottom();
4562 QPointF scenePos = node->scenePos();
4563 if (viewportRect.contains(scenePos) && (scenePos.y() < topY))
4565 topmostVisibleNode = node;
4566 topY = scenePos.y();
4570 if (topmostVisibleNode)
4571 nearbyNode = topmostVisibleNode;
4580 VUserLog(
"Warning: no nearby node (no marked nodes).");
4585 const QPoint offsetFromNode(0,10);
4586 QPoint popoverTopLeftInScene = (nearbyNode?
4587 (nearbyNode->scenePos().toPoint() +
4590 QPoint(viewportRect.center().x() - 0.5*errorPopover->sizeHint().width(),
4591 viewportRect.center().y() - 0.5*errorPopover->sizeHint().height()));
4595 const int margin = 5;
4596 popoverTopLeftInScene = (QPoint(fmin(popoverTopLeftInScene.x(), viewportRect.bottomRight().x() - errorPopover->sizeHint().width() - margin),
4597 fmin(popoverTopLeftInScene.y(), viewportRect.bottomRight().y() - errorPopover->sizeHint().height() - margin)));
4599 popoverTopLeftInScene = (QPoint(fmax(popoverTopLeftInScene.x(), viewportRect.topLeft().x() + margin),
4600 fmax(popoverTopLeftInScene.y(), viewportRect.topLeft().y() + margin)));
4602 QPoint popoverTopLeftInView = views()[0]->mapFromScene(popoverTopLeftInScene);
4603 QPoint popoverTopLeftGlobal = views()[0]->mapToGlobal(popoverTopLeftInView);
4605 errorPopover->move(popoverTopLeftGlobal);
4606 errorPopover->show();
4614 delete potentialCable;
4616 errorMarkingUpdatesEnabled =
true;
4622 bool VuoEditorComposition::hasFeedbackErrors(
void)
4624 return this->errorMark;
4632 if (hasFeedbackErrors())
4641 void VuoEditorComposition::buildComposition(
string compositionSnapshot,
const set<string> &dependenciesUninstalled)
4647 if (! dependenciesUninstalled.empty())
4649 vector<string> dependenciesRemovedVec(dependenciesUninstalled.begin(), dependenciesUninstalled.end());
4651 throw VuoException(
"Some modules that the composition needs were uninstalled: " + dependenciesStr);
4654 delete runningComposition;
4655 runningComposition = NULL;
4659 if (runningCompositionActiveDriver)
4663 string dir, file, ext;
4665 linkedCompositionPath = dir + file +
".dylib";
4670 compiler->
compileComposition(runningComposition, compiledCompositionPath,
true, issues);
4674 remove(compiledCompositionPath.c_str());
4680 delete runningComposition;
4681 runningComposition = NULL;
4693 bool VuoEditorComposition::isRunningThreadUnsafe(
void)
4695 return runner != NULL && ! stopRequested && ! runner->
isStopped();
4705 __block
bool running;
4706 dispatch_sync(runCompositionQueue, ^{
4707 running = isRunningThreadUnsafe();
4733 if (matchingComposition->showEventsMode)
4737 stopRequested =
false;
4738 dispatch_async(runCompositionQueue, ^{
4743 buildComposition(compositionSnapshot);
4757 if (matchingComposition->showEventsMode)
4758 this->runner->subscribeToEventTelemetry(matchingCompositionIdentifier);
4760 dispatch_sync(activePortPopoversQueue, ^{
4761 for (
auto i : matchingComposition->activePortPopovers)
4763 string portID = i.first;
4764 updateDataInPortPopoverFromRunningTopLevelComposition(matchingComposition, matchingCompositionIdentifier, portID);
4785 stopRequested =
true;
4786 dispatch_async(runCompositionQueue, ^{
4795 linkedCompositionPath =
"";
4796 runningCompositionLibraries = NULL;
4798 delete runningComposition;
4799 runningComposition = NULL;
4809 if (matchingComposition->showEventsMode)
4812 dispatch_sync(activePortPopoversQueue, ^{
4813 for (
auto i : matchingComposition->activePortPopovers)
4815 VuoPortPopover *popover = i.second;
4816 popover->setCompositionRunning(false);
4839 dispatch_async(runCompositionQueue, ^{
4840 if (isRunningThreadUnsafe())
4849 string oldBuiltCompositionSnapshot = oldCompositionSnapshot;
4851 if (previouslyActiveDriver)
4858 buildComposition(newCompositionSnapshot, dependenciesUninstalled);
4860 string compositionDiff = diffInfo->
diff(oldBuiltCompositionSnapshot, runningComposition, compiler);
4863 catch (exception &e)
4865 VUserLog(
"Composition stopped itself: %s", e.what());
4870 VUserLog(
"Composition stopped itself.");
4876 dispatch_async(dispatch_get_main_queue(), ^{
4895 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyIfInstalledAsSubcomposition(
this, reloadSubcompositionIfUnsaved);
4904 VuoPort *port = portWithStaticIdentifier[runningPortID];
4913 if (
this == topLevelComposition)
4915 dispatch_async(runCompositionQueue, ^{
4916 if (isRunningThreadUnsafe())
4918 json_object *constantObject = json_tokener_parse(constant.c_str());
4919 runner->
setInputPortValue(thisCompositionIdentifier, runningPortID, constantObject);
4924 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this,
updateRunningComposition);
4927 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyIfInstalledAsSubcomposition(
this, ^(
VuoEditorComposition *currComposition,
string subcompositionPath)
4929 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToAllOtherTopLevelCompositions(
this, ^(
VuoEditorComposition *topLevelComposition)
4946 string constant = dynamic_cast<VuoCompilerPublishedPort *>(port->
getCompiler())->getInitialValue();
4955 map<VuoPort *, string>::iterator i = staticIdentifierForPort.find(port->
getBase());
4956 if (i == staticIdentifierForPort.end())
4958 string runningPortIdentifier = i->second;
4963 if (
this == topLevelComposition)
4965 dispatch_async(runCompositionQueue, ^{
4966 if (isRunningThreadUnsafe())
4968 json_object *constantObject = json_tokener_parse(constant.c_str());
4969 runner->
setInputPortValue(thisCompositionIdentifier, runningPortIdentifier, constantObject);
4974 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this,
updateRunningComposition);
4977 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyIfInstalledAsSubcomposition(
this, ^(
VuoEditorComposition *currComposition,
string subcompositionPath)
4979 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToAllOtherTopLevelCompositions(
this, ^(
VuoEditorComposition *topLevelComposition)
4992 dispatch_async(runCompositionQueue, ^{
4993 if (isRunningThreadUnsafe())
4995 json_object *constantObject = json_tokener_parse(constant.c_str());
4997 foreach (
string subcompositionIdentifier, subcompositionIdentifiers)
4999 runner->
setInputPortValue(subcompositionIdentifier, portIdentifier, constantObject);
5010 dispatch_async(runCompositionQueue, ^{
5011 if (isRunningThreadUnsafe())
5016 json_object *constantObject = json_tokener_parse(constant.c_str());
5017 map<VuoRunner::Port *, json_object *> m;
5018 m[publishedPort] = constantObject;
5031 return contextMenuDeleteSelected;
5041 QMenu *contextMenuTints =
new QMenu(parent);
5042 contextMenuTints->setSeparatorsCollapsible(
false);
5043 contextMenuTints->setTitle(tr(
"Tint"));
5044 foreach (QAction *tintAction, contextMenuTintActions)
5045 contextMenuTints->addAction(tintAction);
5046 contextMenuTints->insertSeparator(contextMenuTintActions.last());
5048 return contextMenuTints;
5054 void VuoEditorComposition::expandChangeNodeMenu()
5056 QAction *sender = (QAction *)QObject::sender();
5057 VuoRendererNode *node = static_cast<VuoRendererNode *>(sender->data().value<
void *>());
5061 int currentMatchesListed = contextMenuChangeNode->actions().size()-1;
5062 if (currentMatchesListed <= initialChangeNodeSuggestionCount)
5065 int verticalSpacePerItem = 21;
5069 int targetMatches = availableVerticalSpace/verticalSpacePerItem - 2;
5078 contextMenuChangeNode->exec();
5093 map<string, VuoCompilerNodeClass *> nodeClassesMap = compiler->
getNodeClasses();
5094 vector<VuoCompilerNodeClass *> loadedNodeClasses;
5095 for (map<string, VuoCompilerNodeClass *>::iterator i = nodeClassesMap.begin(); i != nodeClassesMap.end(); ++i)
5096 loadedNodeClasses.push_back(i->second);
5099 vector<string> bestMatches;
5100 map<string, double> matchScores;
5101 matchScores[
""] = 0;
5103 int targetMatchCount = (matchLimit > 0? matchLimit : loadedNodeClasses.size());
5104 for (
int i = 0; i < targetMatchCount; ++i)
5105 bestMatches.push_back(
"");
5108 bool overflow =
false;
5111 string originalGenericNodeClassName;
5112 if (nodeClass->
hasCompiler() && dynamic_cast<VuoCompilerSpecializedNodeClass *>(nodeClass->
getCompiler()))
5113 originalGenericNodeClassName = dynamic_cast<VuoCompilerSpecializedNodeClass *>(nodeClass->
getCompiler())->getOriginalGenericNodeClassName();
5115 originalGenericNodeClassName = nodeClass->
getClassName();
5120 if (loadedNodeClassName == originalGenericNodeClassName)
5123 bool canSwapNondestructively = canSwapWithoutBreakingCables(node, loadedNodeClass->
getBase());
5124 double matchScore = (canSwapNondestructively? calculateNodeSimilarity(nodeClass, loadedNodeClass->
getBase()) : 0);
5125 int highestIndexWithCompetitiveScore = -1;
5126 for (
int i = targetMatchCount-1; (i >= 0) && (highestIndexWithCompetitiveScore == -1); --i)
5127 if (matchScore <= matchScores[bestMatches[i] ])
5128 highestIndexWithCompetitiveScore = i;
5130 if (highestIndexWithCompetitiveScore < targetMatchCount-1)
5132 if (matchScores[bestMatches[targetMatchCount-1] ] > 0)
5135 for (
int j = targetMatchCount-2; j > highestIndexWithCompetitiveScore; --j)
5136 bestMatches[j+1] = bestMatches[j];
5138 bestMatches[highestIndexWithCompetitiveScore+1] = loadedNodeClassName;
5139 matchScores[loadedNodeClassName] = matchScore;
5143 for (
int i = 0; i < targetMatchCount; ++i)
5145 if (matchScores[bestMatches[i] ] > 0)
5150 matchDisplayText += QString(
" (%1)").arg(bestMatches[i].c_str());
5152 QAction *changeAction = menu->addAction(matchDisplayText);
5154 QList<QVariant> currentNodeAndNewClass;
5155 currentNodeAndNewClass.append(qVariantFromValue((
void *)node));
5156 currentNodeAndNewClass.append(bestMatches[i].c_str());
5157 changeAction->setData(QVariant(currentNodeAndNewClass));
5158 connect(changeAction, &QAction::triggered,
this, &VuoEditorComposition::swapNode);
5165 QAction *showMoreAction = menu->addAction(tr(
"More…"));
5166 showMoreAction->setData(qVariantFromValue(static_cast<void *>(node)));
5167 connect(showMoreAction, &QAction::triggered,
this, &VuoEditorComposition::expandChangeNodeMenu);
5178 map<string, int> requiredInputs;
5179 bool inputEventSourceRequired =
false;
5182 bool hasDrawerWithNoIncomingCables =
false;
5183 bool hasDrawerWithNoIncomingDataCables =
false;
5190 hasDrawerWithNoIncomingCables =
true;
5191 hasDrawerWithNoIncomingDataCables =
true;
5192 vector<VuoRendererPort *> childPorts = inputDrawer->
getDrawerPorts();
5196 hasDrawerWithNoIncomingCables =
false;
5198 hasDrawerWithNoIncomingDataCables =
false;
5203 if (!hasDrawerWithNoIncomingDataCables)
5204 requiredInputs[typeKey] = ((requiredInputs.find(typeKey) == requiredInputs.end())? 1 : requiredInputs[typeKey]+1);
5208 if (hasIncomingCables && !hasDrawerWithNoIncomingCables)
5209 inputEventSourceRequired =
true;
5213 map<string, int> requiredOutputs;
5214 bool outputEventSourceRequired =
false;
5220 requiredOutputs[typeKey] = ((requiredOutputs.find(typeKey) == requiredOutputs.end())? 1 : requiredOutputs[typeKey]+1);
5224 outputEventSourceRequired =
true;
5228 bool inputEventSourceAvailable =
false;
5229 map<string, int> availableInputs;
5233 static_cast<VuoCompilerPortClass *>(inputPortClass->
getCompiler())->getDataVuoType() : NULL);
5237 availableInputs[typeKey] = ((availableInputs.find(typeKey) == availableInputs.end())? 1 : availableInputs[typeKey]+1);
5242 inputEventSourceAvailable =
true;
5245 bool outputEventSourceAvailable =
false;
5246 map<string, int> availableOutputs;
5250 static_cast<VuoCompilerPortClass *>(outputPortClass->
getCompiler())->getDataVuoType() : NULL);
5254 availableOutputs[typeKey] = ((availableOutputs.find(typeKey) == availableOutputs.end())? 1 : availableOutputs[typeKey]+1);
5259 outputEventSourceAvailable =
true;
5262 for (std::map<string,int>::iterator it=requiredInputs.begin(); it!=requiredInputs.end(); ++it)
5264 string typeKey = it->first;
5265 int typeRequiredCount = it->second;
5266 if (availableInputs[typeKey] < typeRequiredCount)
5271 for (std::map<string,int>::iterator it=requiredOutputs.begin(); it!=requiredOutputs.end(); ++it)
5273 string typeKey = it->first;
5274 int typeRequiredCount = it->second;
5275 if (availableOutputs[typeKey] < typeRequiredCount)
5279 if (inputEventSourceRequired && !inputEventSourceAvailable)
5282 if (outputEventSourceRequired && !outputEventSourceAvailable)
5292 bool VuoEditorComposition::isPortCurrentlyRevertible(
VuoRendererPort *port)
5298 if (!specializedNodeClass)
5303 if (!originalGenericType)
5312 if (hostPort && (!isPortCurrentlyRevertible(hostPort->
getRenderer())))
5339 string publishedPortName = ((! name.empty())?
5350 bool performedMerge =
false;
5353 publishedPort = (isPublishedInput ?
5357 if (publishedPort && dynamic_cast<VuoRendererPublishedPort *>(publishedPort->
getRenderer())->canAccommodateInternalPort(port->
getRenderer(), forceEventOnlyPublication))
5359 if (isPublishedInput && portType && type && !forceEventOnlyPublication)
5367 performedMerge =
true;
5374 if (! performedMerge)
5377 if (isPublishedInput && type)
5387 dynamic_cast<VuoRendererPublishedPort *>(publishedPort->
getRenderer()) :
5392 if (! existingPublishedCable)
5398 if (mergePerformed != NULL)
5399 *mergePerformed = performedMerge;
5401 return rendererPublishedPort;
5413 if (creatingPublishedInputCable)
5416 VuoPort *fromPort = externalPort;
5419 VuoPort *toPort = internalPort;
5426 publishedCable->
setFrom(fromNode, fromPort);
5433 VuoPort *fromPort = internalPort;
5436 VuoPort *toPort = externalPort;
5443 publishedCable->
setTo(toNode, toPort);
5446 if (forceEventOnlyPublication)
5449 return publishedCable;
5465 vector<VuoPublishedPort *> publishedPortsToAdd;
5466 map<VuoPublishedPort *, string> publishedPortsToRename;
5469 VuoProtocol *previousActiveProtocol = this->activeProtocol;
5470 bool removingPreviousProtocol = previousActiveProtocol && (previousActiveProtocol != protocol);
5472 bool portChangesMadeDuringProtocolRemoval =
false;
5473 if (removingPreviousProtocol)
5476 if (portChangesMadeDuringProtocolRemoval && !useUndoStack)
5478 VUserLog(
"Warning: Unexpected combination: Removing protocol ports, but useUndoStack=false");
5479 useUndoStack =
true;
5483 this->activeProtocol = protocol;
5488 for (vector<pair<string, string> >::iterator i = protocolInputs.begin(); i != protocolInputs.end(); ++i)
5490 string portName = i->first;
5491 string portType = i->second;
5493 bool compositionHadCompatiblePort =
false;
5495 if (preexistingPublishedPort)
5497 VuoType *preexistingType = static_cast<VuoCompilerPortClass *>(preexistingPublishedPort->
getClass()->
getCompiler())->getDataVuoType();
5499 bool portTypesMatch = ((preexistingType && (preexistingType->
getModuleKey() == portType)) ||
5500 (!preexistingType && (portType ==
"")));
5503 compositionHadCompatiblePort =
true;
5508 compositionHadCompatiblePort =
false;
5513 if (!compositionHadCompatiblePort)
5522 publishedPortsToAdd.push_back(publishedPort);
5529 for (vector<pair<string, string> >::iterator i = protocolOutputs.begin(); i != protocolOutputs.end(); ++i)
5531 string portName = i->first;
5532 string portType = i->second;
5534 bool compositionHadCompatiblePort =
false;
5536 if (preexistingPublishedPort)
5538 VuoType *preexistingType = static_cast<VuoCompilerPortClass *>(preexistingPublishedPort->
getClass()->
getCompiler())->getDataVuoType();
5539 bool portTypesMatch = ((preexistingType && (preexistingType->
getModuleKey() == portType)) ||
5540 (!preexistingType && (portType ==
"")));
5543 compositionHadCompatiblePort =
true;
5548 compositionHadCompatiblePort =
false;
5553 if (!compositionHadCompatiblePort)
5562 publishedPortsToAdd.push_back(publishedPort);
5570 bool undoStackMacroBegunAlready = (removingPreviousProtocol && portChangesMadeDuringProtocolRemoval);
5571 if (!publishedPortsToRename.empty() || !publishedPortsToAdd.empty() || undoStackMacroBegunAlready)
5573 set<VuoPublishedPort *> publishedPortsToRemove;
5574 bool beginUndoStackMacro = !undoStackMacroBegunAlready;
5575 bool endUndoStackMacro =
true;
5576 emit
protocolPortChangesRequested(publishedPortsToRename, publishedPortsToRemove, publishedPortsToAdd, beginUndoStackMacro, endUndoStackMacro);
5590 string VuoEditorComposition::getNonProtocolVariantForPortName(
string portName)
5592 string modifiedPortName = portName;
5593 if (modifiedPortName.length() > 0)
5594 modifiedPortName[0] = toupper(modifiedPortName[0]);
5595 modifiedPortName =
"some" + modifiedPortName;
5597 return modifiedPortName;
5621 set<VuoPublishedPort *> publishedPortsToRemove;
5622 map<VuoPublishedPort *, string> publishedPortsToRename;
5625 for (vector<pair<string, string> >::iterator i = protocolInputs.begin(); i != protocolInputs.end(); ++i)
5627 string portName = i->first;
5628 string portType = i->second;
5631 if (preexistingPublishedPort)
5633 bool portCompatibleAcrossProtocolTransition =
false;
5634 if (replacementProtocol)
5637 for (vector<pair<string, string> >::iterator i = protocolInputs.begin(); i != protocolInputs.end() && !portCompatibleAcrossProtocolTransition; ++i)
5639 string replacementPortName = i->first;
5640 string replacementPortType = i->second;
5642 if ((portName == replacementPortName) && (portType == replacementPortType))
5643 portCompatibleAcrossProtocolTransition =
true;
5648 publishedPortsToRemove.insert(preexistingPublishedPort);
5649 else if (!portCompatibleAcrossProtocolTransition)
5655 for (vector<pair<string, string> >::iterator i = protocolOutputs.begin(); i != protocolOutputs.end(); ++i)
5657 string portName = i->first;
5658 string portType = i->second;
5661 if (preexistingPublishedPort)
5663 bool portCompatibleAcrossProtocolTransition =
false;
5664 if (replacementProtocol)
5667 for (vector<pair<string, string> >::iterator i = protocolOutputs.begin(); i != protocolOutputs.end() && !portCompatibleAcrossProtocolTransition; ++i)
5669 string replacementPortName = i->first;
5670 string replacementPortType = i->second;
5672 if ((portName == replacementPortName) && (portType == replacementPortType))
5673 portCompatibleAcrossProtocolTransition =
true;
5678 publishedPortsToRemove.insert(preexistingPublishedPort);
5679 else if (!portCompatibleAcrossProtocolTransition)
5686 if (!publishedPortsToRemove.empty())
5687 publishedPortsToRename.clear();
5689 bool portChangesRequired = (!publishedPortsToRename.empty() || !publishedPortsToRemove.empty());
5690 if (portChangesRequired)
5692 vector<VuoPublishedPort *> publishedPortsToAdd;
5693 bool beginUndoStackMacro =
true;
5694 bool endUndoStackMacro = !replacementProtocol;
5695 emit
protocolPortChangesRequested(publishedPortsToRename, publishedPortsToRemove, publishedPortsToAdd, beginUndoStackMacro, endUndoStackMacro);
5700 return portChangesRequired;
5711 if ((activeProtocol != protocol) || !activeProtocol)
5714 activeProtocol = NULL;
5717 for (vector<pair<string, string> >::iterator i = protocolInputs.begin(); i != protocolInputs.end(); ++i)
5719 string portName = i->first;
5720 string portType = i->second;
5723 if (preexistingPublishedPort)
5728 for (vector<pair<string, string> >::iterator i = protocolOutputs.begin(); i != protocolOutputs.end(); ++i)
5730 string portName = i->first;
5731 string portType = i->second;
5734 if (preexistingPublishedPort)
5747 return activeProtocol;
5756 if (!activeProtocol)
5759 return static_cast<VuoEditor *>(qApp)->getBuiltInDriverForProtocol(activeProtocol);
5770 portWithStaticIdentifier[staticPortIdentifier] = publishedPort;
5771 staticIdentifierForPort[publishedPort] = staticPortIdentifier;
5794 return removalResult;
5804 if (dynamic_cast<VuoPublishedPort *>(publishedPort->
getBase())->isProtocolPort())
5810 portWithStaticIdentifier[staticPortIdentifier] = publishedPort->
getBase();
5811 staticIdentifierForPort[publishedPort->
getBase()] = staticPortIdentifier;
5823 void VuoEditorComposition::highlightEligibleEndpointsForCable(
VuoCable *cable)
5836 highlightInternalPortsConnectableToPort(fixedPort, cable->
getRenderer());
5848 QList<QGraphicsItem *> compositionComponents = items();
5849 for (QList<QGraphicsItem *>::iterator i = compositionComponents.begin(); i != compositionComponents.end(); ++i)
5851 QGraphicsItem *compositionComponent = *i;
5852 VuoRendererNode *rn = dynamic_cast<VuoRendererNode *>(compositionComponent);
5857 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
5858 updateEligibilityHighlightingForPort((*inputPort)->getRenderer(), port, !cable->
effectivelyCarriesData());
5862 for(vector<VuoPort *>::iterator outputPort = outputPorts.begin(); outputPort != outputPorts.end(); ++outputPort)
5863 updateEligibilityHighlightingForPort((*outputPort)->getRenderer(), port, !cable->
effectivelyCarriesData());
5867 VuoRendererCable *rc = dynamic_cast<VuoRendererCable *>(compositionComponent);
5868 if (rc && rc != cable)
5870 QGraphicsItem::CacheMode normalCacheMode = rc->cacheMode();
5871 rc->setCacheMode(QGraphicsItem::NoCache);
5888 rc->setCacheMode(normalCacheMode);
5893 for (QList<QGraphicsItem *>::iterator i = compositionComponents.begin(); i != compositionComponents.end(); ++i)
5894 updateEligibilityHighlightingForNode(dynamic_cast<VuoRendererNode *>(*i));
5901 void VuoEditorComposition::updateEligibilityHighlightingForPort(
VuoRendererPort *portToHighlight,
5903 bool eventOnlyConnection)
5905 QGraphicsItem::CacheMode normalCacheMode = portToHighlight->cacheMode();
5906 portToHighlight->setCacheMode(QGraphicsItem::NoCache);
5914 if (typecastPortToHighlight)
5917 portToHighlight->setCacheMode(normalCacheMode);
5919 if (typecastPortToHighlight)
5920 updateEligibilityHighlightingForPort(typecastPortToHighlight->
getChildPort(), fixedPort, eventOnlyConnection);
5936 VuoRendererPublishedPort *externalPublishedPortToHighlight = dynamic_cast<VuoRendererPublishedPort *>(portToHighlight);
5940 bool forwardConnection;
5943 fromPort = fixedPort;
5944 toPort = portToHighlight;
5945 forwardConnection =
true;
5949 fromPort = portToHighlight;
5951 forwardConnection =
false;
5954 bool directConnectionPossible;
5958 if (fixedExternalPublishedPort && externalPublishedPortToHighlight)
5959 directConnectionPossible =
false;
5960 else if (fixedExternalPublishedPort && !externalPublishedPortToHighlight)
5962 else if (!fixedExternalPublishedPort && externalPublishedPortToHighlight)
5968 if (directConnectionPossible)
5972 else if (fixedPort == portToHighlight)
5995 bool VuoEditorComposition::canConnectDirectlyWithRespecializationNondestructively(
VuoRendererPort *fromPort,
5997 bool eventOnlyConnection,
5998 bool forwardConnection)
6001 string respecializedTypeName =
"";
6003 return canConnectDirectlyWithRespecializationNondestructively(fromPort,
6005 eventOnlyConnection,
6007 &portToRespecialize,
6008 respecializedTypeName);
6021 bool VuoEditorComposition::canConnectDirectlyWithRespecializationNondestructively(
VuoRendererPort *fromPort,
6023 bool eventOnlyConnection,
6024 bool forwardConnection,
6026 string &respecializedTypeName)
6028 *portToRespecialize = NULL;
6029 respecializedTypeName =
"";
6031 bool canConnectWithRespecialization = canConnectDirectlyWithRespecialization(fromPort,
6033 eventOnlyConnection,
6036 respecializedTypeName);
6037 if (!canConnectWithRespecialization)
6040 if (canConnectWithRespecialization && !portToRespecialize)
6043 bool nondestructive = portCanBeUnspecializedNondestructively((*portToRespecialize)->getBase());
6044 if (!nondestructive)
6046 *portToRespecialize = NULL;
6047 respecializedTypeName =
"";
6049 return nondestructive;
6057 bool VuoEditorComposition::portCanBeUnspecializedNondestructively(
VuoPort *portToUnspecialize)
6059 map<VuoNode *, string> nodesToReplace;
6060 set<VuoCable *> cablesToDelete;
6065 if (cablesToDelete.empty())
6068 else if ((cablesToDelete.size() == 1) && ((*(cablesToDelete.begin()))->getToPort() == portToUnspecialize))
6093 bool VuoEditorComposition::canConnectDirectlyWithRespecialization(
VuoRendererPort *fromPort,
6095 bool eventOnlyConnection,
6096 bool forwardConnection,
6098 string &respecializedTypeName)
6102 *portToRespecialize = NULL;
6103 respecializedTypeName =
"";
6113 bool fromPortIsEnabledOutput = (fromPort && fromPort->
getOutput() && fromPort->isEnabled());
6114 bool toPortIsEnabledInput = (toPort && toPort->
getInput() && toPort->isEnabled());
6116 if (!(fromPortIsEnabledOutput && toPortIsEnabledInput))
6122 if (!(currentFromDataType && currentToDataType))
6129 VuoGenericType *currentFromGenericType = dynamic_cast<VuoGenericType *>(currentFromDataType);
6130 VuoGenericType *currentToGenericType = dynamic_cast<VuoGenericType *>(currentToDataType);
6137 if (fromSpecializedNodeClass)
6140 originalFromGenericType = dynamic_cast<VuoGenericType *>( fromSpecializedNodeClass->
getOriginalPortType(portClass) );
6149 if (toSpecializedNodeClass)
6152 originalToGenericType = dynamic_cast<VuoGenericType *>( toSpecializedNodeClass->
getOriginalPortType(portClass) );
6158 bool fromPortIsGeneric = currentFromGenericType;
6159 bool fromPortIsSpecialized = originalFromGenericType && !currentFromGenericType && isPortCurrentlyRevertible(fromPort);
6160 bool fromPortIsStatic = (!fromPortIsGeneric && !fromPortIsSpecialized);
6162 bool toPortIsGeneric = currentToGenericType;
6163 bool toPortIsSpecialized = originalToGenericType && !currentToGenericType && isPortCurrentlyRevertible(toPort);
6164 bool toPortIsStatic = (!toPortIsGeneric && !toPortIsSpecialized);
6167 set<string> compatibleTypes;
6168 string specializedType =
"";
6172 if ((fromPortIsStatic && toPortIsSpecialized) || (fromPortIsSpecialized && toPortIsStatic))
6176 portToTryToRespecialize = (fromPortIsSpecialized? fromPort : toPort);
6180 else if ((fromPortIsSpecialized || toPortIsSpecialized) && !fromPortIsStatic && !toPortIsStatic)
6183 bool dragSourceIsGeneric = (forwardConnection? fromPortIsGeneric : toPortIsGeneric);
6185 VuoRendererPort *dragDestination = (forwardConnection? toPort : fromPort);
6186 bool dragDestinationIsGeneric = (forwardConnection? toPortIsGeneric : fromPortIsGeneric);
6203 if (!dragSourceIsGeneric && !dragDestinationIsGeneric)
6206 portToTryToRespecialize = dragDestination;
6214 if (portToTryToRespecialize)
6215 compatibleTypes = getRespecializationOptionsForPortInNetwork(portToTryToRespecialize);
6217 bool portsAreCompatible = (compatibleTypes.find(specializedType) != compatibleTypes.end());
6219 if (portsAreCompatible)
6221 *portToRespecialize = portToTryToRespecialize;
6222 respecializedTypeName = specializedType;
6225 return portsAreCompatible;
6234 void VuoEditorComposition::updateEligibilityHighlightingForNode(
VuoRendererNode *node)
6249 QGraphicsItem::CacheMode normalCacheMode = drawer->cacheMode();
6250 drawer->setCacheMode(QGraphicsItem::NoCache);
6255 drawer->setCacheMode(normalCacheMode);
6264 QGraphicsItem::CacheMode normalCacheMode = hostPort->cacheMode();
6265 hostPort->setCacheMode(QGraphicsItem::NoCache);
6270 hostPort->setCacheMode(normalCacheMode);
6304 bool toPortIsDragDestination,
6306 string &specializedTypeName,
6307 string &typecastToInsert)
6309 *portToSpecialize = NULL;
6310 specializedTypeName =
"";
6312 map<string, VuoRendererPort *> portToSpecializeForTypecast;
6313 map<string, string> specializedTypeNameForTypecast;
6315 vector<string> candidateTypecasts =
findBridgingSolutions(fromPort, toPort, toPortIsDragDestination, portToSpecializeForTypecast, specializedTypeNameForTypecast);
6316 bool solutionSelected = selectBridgingSolutionFromOptions(candidateTypecasts, portToSpecializeForTypecast, specializedTypeNameForTypecast, typecastToInsert);
6318 if (!solutionSelected)
6321 if (portToSpecializeForTypecast.find(typecastToInsert) != portToSpecializeForTypecast.end())
6322 *portToSpecialize = portToSpecializeForTypecast[typecastToInsert];
6323 if (specializedTypeNameForTypecast.find(typecastToInsert) != specializedTypeNameForTypecast.end())
6324 specializedTypeName = specializedTypeNameForTypecast[typecastToInsert];
6347 bool VuoEditorComposition::selectBridgingSolutionFromOptions(vector<string> suitableTypecasts,
6348 map<string, VuoRendererPort *> portToSpecializeForTypecast,
6349 map<string, string> specializedTypeNameForTypecast,
6350 string &selectedTypecast)
6352 if (suitableTypecasts.empty())
6354 selectedTypecast =
"";
6358 else if (suitableTypecasts.size() == 1)
6360 selectedTypecast = suitableTypecasts[0];
6365 return promptForBridgingSelectionFromOptions(suitableTypecasts, portToSpecializeForTypecast, specializedTypeNameForTypecast, selectedTypecast);
6375 bool fromPortIsEnabledOutput = (fromPort && fromPort->
getOutput() && fromPort->isEnabled());
6376 bool toPortIsEnabledInput = (toPort && toPort->
getInput() && toPort->isEnabled());
6378 if (!(fromPortIsEnabledOutput && toPortIsEnabledInput &&
6385 VuoType *inType = (candidateFromType? candidateFromType : static_cast<VuoCompilerPortClass *>(fromPort->
getBase()->
getClass()->
getCompiler())->getDataVuoType());
6398 if (toNodeUsesIndex)
6424 bool toPortIsDragDestination)
6426 map<string, VuoRendererPort *> portToSpecializeForTypecast;
6427 map<string, string> specializedTypeNameForTypecast;
6428 return findBridgingSolutions(fromPort, toPort, toPortIsDragDestination, portToSpecializeForTypecast, specializedTypeNameForTypecast);
6442 bool toPortIsDragDestination,
6443 map<string, VuoRendererPort *> &portToSpecializeForTypecast,
6444 map<string, string> &specializedTypeNameForTypecast)
6446 portToSpecializeForTypecast.clear();
6447 specializedTypeNameForTypecast.clear();
6448 vector<string> suitableTypecasts;
6452 if (dynamic_cast<VuoRendererPublishedPort *>(fromPort) && dynamic_cast<VuoRendererPublishedPort *>(toPort))
6453 return suitableTypecasts;
6458 string specializedTypeName =
"";
6461 suitableTypecasts.push_back(
"");
6462 portToSpecializeForTypecast[
""] = portToSpecialize;
6463 specializedTypeNameForTypecast[
""] = specializedTypeName;
6465 return suitableTypecasts;
6472 if (!(currentFromDataType && currentToDataType))
6473 return suitableTypecasts;
6477 return suitableTypecasts;
6479 VuoGenericType *currentFromGenericType = dynamic_cast<VuoGenericType *>(currentFromDataType);
6480 VuoGenericType *currentToGenericType = dynamic_cast<VuoGenericType *>(currentToDataType);
6487 if (fromSpecializedNodeClass)
6490 originalFromGenericType = dynamic_cast<VuoGenericType *>( fromSpecializedNodeClass->
getOriginalPortType(portClass) );
6499 if (toSpecializedNodeClass)
6502 originalToGenericType = dynamic_cast<VuoGenericType *>( toSpecializedNodeClass->
getOriginalPortType(portClass) );
6510 bool fromPortIsGeneric = currentFromGenericType;
6511 bool fromPortIsSpecialized = originalFromGenericType && !currentFromGenericType && isPortCurrentlyRevertible(fromPort);
6512 bool fromPortIsStatic = (!fromPortIsGeneric && !fromPortIsSpecialized);
6514 bool toPortIsGeneric = currentToGenericType;
6515 bool toPortIsSpecialized = originalToGenericType && !currentToGenericType && isPortCurrentlyRevertible(toPort);
6516 bool toPortIsStatic = (!toPortIsGeneric && !toPortIsSpecialized);
6519 if (fromPortIsGeneric && toPortIsGeneric)
6520 return suitableTypecasts;
6523 else if (fromPortIsStatic && toPortIsStatic)
6525 if (portsPassSanityCheckToTypeconvert(fromPort, toPort))
6527 return suitableTypecasts;
6532 bool specializeToPort =
true;
6533 if (toPortIsGeneric)
6534 specializeToPort =
true;
6535 else if (fromPortIsGeneric)
6536 specializeToPort =
false;
6537 else if (fromPortIsSpecialized && toPortIsStatic)
6538 specializeToPort =
false;
6539 else if (fromPortIsStatic && toPortIsSpecialized)
6540 specializeToPort =
true;
6541 else if (fromPortIsSpecialized && toPortIsSpecialized)
6542 specializeToPort = toPortIsDragDestination;
6546 set<string> compatibleTypes;
6547 if (specializeToPort && (toPortIsGeneric || (toPortIsSpecialized && portCanBeUnspecializedNondestructively(toPort->
getBase()))))
6548 compatibleTypes = getRespecializationOptionsForPortInNetwork(toPort);
6549 else if (!specializeToPort && (fromPortIsGeneric || (fromPortIsSpecialized && portCanBeUnspecializedNondestructively(fromPort->
getBase()))))
6550 compatibleTypes = getRespecializationOptionsForPortInNetwork(fromPort);
6556 foreach (
string compatibleTypeName, compatibleTypes)
6559 VuoType *candidateFromType = specializeToPort? currentFromDataType : compatibleSpecializedType->
getBase();
6560 VuoType *candidateToType = specializeToPort? compatibleSpecializedType->
getBase() : currentToDataType;
6562 if (compatibleSpecializedType && portsPassSanityCheckToTypeconvert(fromPort,
6568 if (candidateFromType == candidateToType)
6570 suitableTypecasts.push_back(
"");
6571 portToSpecializeForTypecast[
""] = specializeToPort? toPort : fromPort;
6572 specializedTypeNameForTypecast[
""] = compatibleSpecializedType->
getBase()->
getModuleKey();
6576 foreach (
string typecast, suitableTypecastsForCurrentTypes)
6578 suitableTypecasts.push_back(typecast);
6579 portToSpecializeForTypecast[typecast] = specializeToPort? toPort : fromPort;
6580 specializedTypeNameForTypecast[typecast] = compatibleSpecializedType->
getBase()->
getModuleKey();
6585 return suitableTypecasts;
6600 bool VuoEditorComposition::promptForBridgingSelectionFromOptions(vector<string> suitableTypecasts,
6601 map<string, VuoRendererPort *> portToSpecializeForTypecast,
6602 map<string, string> specializedTypeNameForTypecast,
6603 string &selectedTypecast)
6605 QMenu typecastMenu(views()[0]->viewport());
6606 typecastMenu.setSeparatorsCollapsible(
false);
6607 QString spacer(
" ");
6610 set <pair<VuoRendererPort *, string> > specializationDetails;
6611 vector<string> typeconversionOptionsRequiringNoSpecialization;
6612 foreach (
string typecastClassName, suitableTypecasts)
6614 VuoRendererPort *portToSpecialize = portToSpecializeForTypecast[typecastClassName];
6615 string specializedTypeName = specializedTypeNameForTypecast[typecastClassName];
6616 specializationDetails.insert(std::make_pair(portToSpecialize,
6617 specializedTypeName));
6619 bool portAlreadyHasTargetType = (!portToSpecialize || (portToSpecialize->
getDataType() && (portToSpecialize->
getDataType()->
getModuleKey() == specializedTypeName)));
6620 if (portAlreadyHasTargetType)
6621 typeconversionOptionsRequiringNoSpecialization.push_back(typecastClassName);
6627 if ((std::find(suitableTypecasts.begin(), suitableTypecasts.end(),
"") != suitableTypecasts.end()))
6629 QString menuText = getDisplayTextForSpecializationOption(portToSpecializeForTypecast[
""], specializedTypeNameForTypecast[
""]);
6630 QAction *typecastAction = typecastMenu.addAction(menuText);
6631 typecastAction->setData(QVariant(
""));
6635 bool includingTypeconvertWithNoSpecializationHeader =
false;
6636 if (typeconversionOptionsRequiringNoSpecialization.size() >= 1)
6638 if (typecastMenu.actions().size() >= 1)
6639 typecastMenu.addSeparator();
6641 VuoRendererPort *portToSpecialize = portToSpecializeForTypecast[typeconversionOptionsRequiringNoSpecialization[0] ];
6642 string specializedTypeName = specializedTypeNameForTypecast[typeconversionOptionsRequiringNoSpecialization[0] ];
6644 if (portToSpecialize && !specializedTypeName.empty())
6646 QString menuText = getDisplayTextForSpecializationOption(portToSpecialize, specializedTypeName);
6647 QAction *typecastAction = typecastMenu.addAction(menuText);
6648 typecastAction->setEnabled(
false);
6649 includingTypeconvertWithNoSpecializationHeader =
true;
6653 foreach (
string typecastClassName, typeconversionOptionsRequiringNoSpecialization)
6659 typecastAction->setData(QVariant(typecastClassName.c_str()));
6664 for (set<pair<VuoRendererPort *, string> >::iterator i = specializationDetails.begin(); i != specializationDetails.end(); ++i)
6667 string specializedTypeName = i->second;
6670 if ((std::find(suitableTypecasts.begin(), suitableTypecasts.end(),
"") != suitableTypecasts.end()) &&
6671 (portToSpecializeForTypecast[
""] == portToSpecialize) &&
6672 (specializedTypeNameForTypecast[
""] == specializedTypeName))
6678 bool portAlreadyHasTargetType = (!portToSpecialize || (portToSpecialize->
getDataType() && (portToSpecialize->
getDataType()->
getModuleKey() == specializedTypeName)));
6679 if (portAlreadyHasTargetType)
6684 if (typecastMenu.actions().size() >= 1)
6685 typecastMenu.addSeparator();
6687 QString menuText = getDisplayTextForSpecializationOption(portToSpecialize, specializedTypeName);
6688 QAction *typecastAction = typecastMenu.addAction(menuText);
6689 typecastAction->setEnabled(
false);
6692 foreach (
string typecastClassName, suitableTypecasts)
6694 if ((portToSpecializeForTypecast[typecastClassName] == portToSpecialize) &&
6695 (specializedTypeNameForTypecast[typecastClassName] == specializedTypeName))
6701 typecastAction->setData(QVariant(typecastClassName.c_str()));
6707 menuSelectionInProgress =
true;
6708 QAction *selectedTypecastAction = typecastMenu.exec(QCursor::pos());
6709 menuSelectionInProgress =
false;
6711 selectedTypecast = (selectedTypecastAction? selectedTypecastAction->data().toString().toUtf8().constData() :
"");
6712 return selectedTypecastAction;
6718 QString VuoEditorComposition::getDisplayTextForSpecializationOption(
VuoRendererPort *portToSpecialize,
string specializedTypeName)
6720 if (!portToSpecialize || specializedTypeName.empty())
6723 bool isInput = portToSpecialize && portToSpecialize->
getInput();
6724 QString typeDisplayName = compiler->
getType(specializedTypeName)?
6726 specializedTypeName.c_str();
6728 bool portAlreadyHasTargetType = (!portToSpecialize || (portToSpecialize->
getDataType() && (portToSpecialize->
getDataType()->
getModuleKey() == specializedTypeName)));
6730 QString displayText;
6731 if (portAlreadyHasTargetType)
6736 displayText = tr(
"Keep Input Port as %1");
6741 displayText = tr(
"Keep Output Port as %1");
6749 displayText = tr(
"Change Input Port to %1");
6754 displayText = tr(
"Change Output Port to %1");
6758 return displayText.arg(typeDisplayName);
6772 string runningPortIdentifier = staticIdentifierForPort[port];
6777 dispatch_sync(topLevelComposition->runCompositionQueue, ^{
6778 if (topLevelComposition->isRunningThreadUnsafe())
6780 portValue = isInput ?
6781 topLevelComposition->runner->getInputPortValue(thisCompositionIdentifier, runningPortIdentifier) :
6782 topLevelComposition->runner->getOutputPortValue(thisCompositionIdentifier, runningPortIdentifier);
6786 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, getPortValue);
6794 string VuoEditorComposition::getIdentifierForRunningPort(
VuoPort *runningPort)
6796 return static_cast<VuoCompilerPort *>(runningPort->
getCompiler())->getIdentifier();
6810 if (dynamic_cast<VuoPublishedPort *>(staticPort))
6811 return dynamic_cast<VuoPublishedPort *>(staticPort)->getClass()->getName();
6817 string nodeIdentifier =
"";
6827 if (staticPort->
hasCompiler() && !nodeIdentifier.empty())
6829 dynamic_cast<VuoCompilerPort *>(staticPort->
getCompiler())->setNodeIdentifier(nodeIdentifier);
6830 return static_cast<VuoCompilerPort *>(staticPort->
getCompiler())->getIdentifier();
6841 return portWithStaticIdentifier[portID];
6853 if (dynamic_cast<VuoRendererPublishedPort *>(port->
getRenderer()))
6867 if (candidateInputPort == port)
6871 if (candidateOutputPort == port)
6887 map<string, VuoPortPopover *>::iterator popover = activePortPopovers.find(portID);
6888 if (popover != activePortPopovers.end())
6889 return popover->second;
6902 void VuoEditorComposition::enableInactivePopoverForPort(
VuoRendererPort *rp)
6904 string portID = staticIdentifierForPort[rp->
getBase()];
6905 bool popoverJustClosedAtLastEvent = portsWithPopoversClosedAtLastEvent.find(portID) != portsWithPopoversClosedAtLastEvent.end();
6906 if (!popoverJustClosedAtLastEvent)
6915 if (!popoverEventsEnabled)
6919 string portID = staticIdentifierForPort[port];
6921 VUserLog(
"%s: Open popover for %s",
6925 dispatch_sync(runCompositionQueue, ^{
6927 dispatch_sync(activePortPopoversQueue, ^{
6929 if (activePortPopovers.find(portID) == activePortPopovers.end())
6937 VUserLog(
"%s: Detach popover for %s",
6950 const int cutoffMargin = 16;
6951 QRectF viewportRect = views()[0]->mapToScene(views()[0]->viewport()->rect()).
boundingRect();
6952 if (portLeftInScene.x() + popover->size().width() + cutoffMargin > viewportRect.right())
6953 portLeftInScene = QPoint(viewportRect.right() - popover->size().width() - cutoffMargin, portLeftInScene.y());
6954 if (portLeftInScene.y() + popover->size().height() + cutoffMargin > viewportRect.bottom())
6955 portLeftInScene = QPoint(portLeftInScene.x(), viewportRect.bottom() - popover->size().height() - cutoffMargin);
6957 QPoint popoverLeftInView = views()[0]->mapFromScene(portLeftInScene);
6959 const QPoint offset = QPoint(12, 6);
6961 QPoint popoverTopLeft = popoverLeftInView + offset;
6962 popover->move(popoverTopLeft);
6965 activePortPopovers[portID] = popover;
6967 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
6981 if (popoverEventsEnabled && !dynamic_cast<VuoRendererInputDrawer *>(rn))
6994 VUserLog(
"%s: Close popover for %s",
6999 map<string, VuoPortPopover *>::iterator i = activePortPopovers.find(portID);
7000 if (i != activePortPopovers.end())
7002 popover = i->second;
7003 activePortPopovers.erase(i);
7012 VuoPort *port = portWithStaticIdentifier[portID];
7018 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
7019 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
7021 dispatch_async(topLevelComposition->runCompositionQueue, ^{
7022 if (topLevelComposition->isRunningThreadUnsafe())
7025 topLevelComposition->runner->unsubscribeFromInputPortTelemetry(thisCompositionIdentifier, portID) :
7026 topLevelComposition->runner->unsubscribeFromOutputPortTelemetry(thisCompositionIdentifier, portID));
7036 void VuoEditorComposition::disablePopoverForPortThreadSafe(
string portID)
7038 dispatch_sync(activePortPopoversQueue, ^{
7048 disablePortPopovers();
7059 errorPopover->hide();
7060 errorPopover->deleteLater();
7063 errorPopovers.clear();
7072 dispatch_sync(activePortPopoversQueue, ^{
7073 map<string, VuoPortPopover *> popoversToDisable = activePortPopovers;
7074 for (map<string, VuoPortPopover *>::iterator i = popoversToDisable.begin(); i != popoversToDisable.end(); ++i)
7076 string portID = i->first;
7077 VuoPort *port = portWithStaticIdentifier[portID];
7089 dispatch_sync(activePortPopoversQueue, ^{
7090 map<string, VuoPortPopover *> popoversToDisable = activePortPopovers;
7091 for (map<string, VuoPortPopover *>::iterator i = popoversToDisable.begin(); i != popoversToDisable.end(); ++i)
7093 string portID = i->first;
7094 VuoPort *port = portWithStaticIdentifier[portID];
7107 if (recordWhichPopoversClosed)
7108 portsWithPopoversClosedAtLastEvent.clear();
7110 dispatch_sync(activePortPopoversQueue, ^{
7111 map<string, VuoPortPopover *> popoversToDisable = activePortPopovers;
7112 for (map<string, VuoPortPopover *>::iterator i = popoversToDisable.begin(); i != popoversToDisable.end(); ++i)
7114 string portID = i->first;
7115 VuoPort *port = portWithStaticIdentifier[portID];
7122 portsWithPopoversClosedAtLastEvent.insert(portID);
7134 moveDetachedPortPopoversBy(dx, dy);
7135 moveErrorPopoversBy(dx, dy);
7141 void VuoEditorComposition::moveErrorPopoversBy(
int dx,
int dy)
7144 errorPopover->move(errorPopover->pos().x()+dx, errorPopover->pos().y()+dy);
7150 void VuoEditorComposition::moveDetachedPortPopoversBy(
int dx,
int dy)
7152 dispatch_sync(activePortPopoversQueue, ^{
7153 map<string, VuoPortPopover *> portPopovers = activePortPopovers;
7154 for (map<string, VuoPortPopover *>::iterator i = portPopovers.begin(); i != portPopovers.end(); ++i)
7158 popover->move(popover->pos().x()+dx, popover->pos().y()+dy);
7166 void VuoEditorComposition::setPopoversHideOnDeactivate(
bool shouldHide)
7168 dispatch_sync(activePortPopoversQueue, ^{
7169 auto portPopovers = activePortPopovers;
7170 for (
auto i : portPopovers)
7176 objc_msgSend(nsWindow, sel_getUid(
"setHidesOnDeactivate:"), shouldHide);
7188 dispatch_sync(activePortPopoversQueue, ^{
7189 for (map<string, VuoPortPopover *>::iterator i = activePortPopovers.begin(); i != activePortPopovers.end(); ++i)
7191 string portID = i->first;
7192 VuoPort *port = portWithStaticIdentifier[portID];
7196 QMetaObject::invokeMethod(popover,
"updateTextAndResize", Qt::QueuedConnection);
7213 string popoverCompositionIdentifier,
7216 VuoPort *port = popoverComposition->portWithStaticIdentifier[portID];
7224 dispatch_async(popoverComposition->activePortPopoversQueue, ^{
7225 VuoPortPopover *popover = popoverComposition->getActivePopoverForPort(portID);
7228 QMetaObject::invokeMethod(popover,
"updateCachedDataValue", Qt::QueuedConnection, Q_ARG(QString, portSummary.c_str()));
7229 QMetaObject::invokeMethod(popover,
"setCompositionRunning", Qt::QueuedConnection, Q_ARG(bool, true), Q_ARG(bool, false));
7243 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
7245 dispatch_sync(topLevelComposition->runCompositionQueue, ^{
7246 if (topLevelComposition->isRunningThreadUnsafe())
7247 topLevelComposition->updateDataInPortPopoverFromRunningTopLevelComposition(this, thisCompositionIdentifier, portID);
7257 bool receivedEvent,
bool receivedData,
string dataSummary)
7261 dispatch_sync(matchingComposition->activePortPopoversQueue, ^{
7262 VuoPortPopover *popover = matchingComposition->getActivePopoverForPort(portIdentifier);
7266 if (receivedEvent && receivedData)
7267 QMetaObject::invokeMethod(popover,
"updateLastEventTimeAndCachedDataValue", Qt::QueuedConnection, Q_ARG(QString, dataSummary.c_str()));
7268 else if (receivedEvent)
7269 QMetaObject::invokeMethod(popover,
"updateLastEventTime", Qt::QueuedConnection);
7270 else if (receivedData)
7271 QMetaObject::invokeMethod(popover,
"updateCachedDataValue", Qt::QueuedConnection, Q_ARG(QString, dataSummary.c_str()));
7275 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedCompositionWithIdentifier(
this, compositionIdentifier, updatePortDisplay);
7283 bool sentEvent,
bool sentData,
string dataSummary)
7287 dispatch_sync(matchingComposition->activePortPopoversQueue, ^{
7288 VuoPort *port = matchingComposition->portWithStaticIdentifier[portIdentifier];
7289 VuoPortPopover *popover = matchingComposition->getActivePopoverForPort(portIdentifier);
7293 if (sentEvent && sentData)
7294 QMetaObject::invokeMethod(popover,
"updateLastEventTimeAndCachedDataValue", Qt::QueuedConnection, Q_ARG(QString, dataSummary.c_str()));
7296 QMetaObject::invokeMethod(popover,
"updateLastEventTime", Qt::QueuedConnection);
7298 QMetaObject::invokeMethod(popover,
"updateCachedDataValue", Qt::QueuedConnection, Q_ARG(QString, dataSummary.c_str()));
7301 if (matchingComposition->showEventsMode && sentEvent)
7303 if (port && dynamic_cast<VuoCompilerTriggerPort *>(port->getCompiler()) && port->hasRenderer())
7305 port->getRenderer()->setFiredEvent();
7306 matchingComposition->animatePort(port->getRenderer());
7311 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedCompositionWithIdentifier(
this, compositionIdentifier, updatePortDisplay);
7322 dispatch_async(matchingComposition->runCompositionQueue, ^{
7323 if (matchingComposition->isRunningThreadUnsafe())
7325 dispatch_sync(matchingComposition->activePortPopoversQueue, ^{
7326 VuoPortPopover *popover = matchingComposition->getActivePopoverForPort(portIdentifier);
7328 QMetaObject::invokeMethod(popover,
"incrementDroppedEventCount", Qt::QueuedConnection);
7333 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedCompositionWithIdentifier(
this, compositionIdentifier, updatePortDisplay);
7344 if (matchingComposition->showEventsMode)
7346 dispatch_async(this->runCompositionQueue, ^{
7347 if (this->isRunningThreadUnsafe())
7349 map<string, VuoNode *>::iterator i = matchingComposition->nodeWithGraphvizIdentifier.find(nodeIdentifier);
7350 if (i != nodeWithGraphvizIdentifier.end())
7352 VuoNode *nodeInBaseComposition = i->second;
7360 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedCompositionWithIdentifier(
this, compositionIdentifier, updateNodeDisplay);
7371 if (matchingComposition->showEventsMode)
7373 dispatch_async(this->runCompositionQueue, ^{
7374 if (this->isRunningThreadUnsafe())
7376 map<string, VuoNode *>::iterator i = matchingComposition->nodeWithGraphvizIdentifier.find(nodeIdentifier);
7377 if (i != nodeWithGraphvizIdentifier.end())
7379 VuoNode *nodeInBaseComposition = i->second;
7387 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedCompositionWithIdentifier(
this, compositionIdentifier, updateNodeDisplay);
7416 return showEventsMode;
7424 this->showEventsMode = showEventsMode;
7432 dispatch_sync(topLevelComposition->runCompositionQueue, ^{
7433 if (topLevelComposition->isRunningThreadUnsafe())
7434 topLevelComposition->runner->subscribeToEventTelemetry(thisCompositionIdentifier);
7437 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, subscribe);
7445 dispatch_sync(topLevelComposition->runCompositionQueue, ^{
7446 if (topLevelComposition->isRunningThreadUnsafe())
7447 topLevelComposition->runner->unsubscribeFromEventTelemetry(thisCompositionIdentifier);
7450 static_cast<VuoEditor *>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(
this, unsubscribe);
7486 QGraphicsItemAnimation * VuoEditorComposition::setUpAnimationForPort(QGraphicsItemAnimation *animation,
VuoRendererPort *port)
7494 animatedPort->setZValue(VuoRendererItem::triggerAnimationZValue);
7497 animation->setItem(animatedPort);
7498 animation->setScaleAt(0.0, 1, 1);
7499 animation->setScaleAt(0.999, 3, 3);
7500 animation->setScaleAt(1.0, 1, 1);
7502 QTimeLine *animationTimeline = animation->timeLine();
7503 animationTimeline->setFrameRange(0, 100);
7504 animationTimeline->setUpdateInterval(showEventsModeUpdateInterval);
7505 animationTimeline->setCurveShape(QTimeLine::LinearCurve);
7507 preparedAnimations.insert(animation);
7508 animationForTimeline[animation->timeLine()] = animation;
7510 connect(animationTimeline, &QTimeLine::valueChanged,
this, &VuoEditorComposition::updatePortAnimation);
7511 connect(animationTimeline, &QTimeLine::finished,
this, &VuoEditorComposition::endPortAnimation);
7521 dispatch_async(dispatch_get_main_queue(), ^{
7522 QGraphicsItemAnimation *animation = getAvailableAnimationForPort(port);
7528 if (animation->timeLine()->state() == QTimeLine::Running)
7529 animation->timeLine()->setCurrentTime(0);
7533 animatedPort->setPos(port->pos());
7534 animatedPort->setVisible(
true);
7535 animation->timeLine()->start();
7544 QGraphicsItemAnimation * VuoEditorComposition::getAvailableAnimationForPort(
VuoRendererPort *port)
7546 vector<QGraphicsItemAnimation *> animations = port->
getAnimations();
7548 QGraphicsItemAnimation *mostAdvancedAnimation = NULL;
7549 qreal maxPercentAdvanced = -1;
7551 for (
int i = 0; i < animations.size(); ++i)
7553 QGraphicsItemAnimation *animation = animations[i];
7554 bool animationPrepared = (preparedAnimations.find(animation) != preparedAnimations.end());
7555 bool animationRunning = (animation->timeLine()->state() == QTimeLine::Running);
7557 if (! animationPrepared)
7558 return setUpAnimationForPort(animation, port);
7560 else if (! animationRunning)
7565 qreal percentAdvanced = animation->timeLine()->currentValue();
7566 if (percentAdvanced > maxPercentAdvanced)
7568 mostAdvancedAnimation = animation;
7569 maxPercentAdvanced = percentAdvanced;
7575 return (maxPercentAdvanced >= 0.5? mostAdvancedAnimation : NULL);
7583 void VuoEditorComposition::updatePortAnimation(qreal value)
7585 QTimeLine *animationTimeline = (QTimeLine *)sender();
7586 QGraphicsItemAnimation *animation = animationForTimeline[animationTimeline];
7588 const qreal multiplier = 1000.;
7596 void VuoEditorComposition::endPortAnimation(
void)
7598 QTimeLine *animationTimeline = (QTimeLine *)sender();
7599 QGraphicsItemAnimation *animation = animationForTimeline[animationTimeline];
7601 animatedPort->setVisible(
false);
7607 void VuoEditorComposition::setDisableDragStickiness(
bool disable)
7609 this->dragStickinessDisabled = disable;
7617 this->ignoreApplicationStateChangeEvents = ignore;
7627 this->popoverEventsEnabled = enable;
7636 nodeWithGraphvizIdentifier.clear();
7637 portWithStaticIdentifier.clear();
7638 staticIdentifierForPort.clear();
7641 registerNodeID(node);
7646 portWithStaticIdentifier[staticPortIdentifier] = publishedPort;
7647 staticIdentifierForPort[publishedPort] = staticPortIdentifier;
7650 foreach (
VuoPort *publishedPort,
getBase()->getPublishedOutputPorts())
7653 portWithStaticIdentifier[staticPortIdentifier] = publishedPort;
7654 staticIdentifierForPort[publishedPort] = staticPortIdentifier;
7661 void VuoEditorComposition::registerNodeID(
VuoNode *node)
7669 portWithStaticIdentifier[staticPortIdentifier] = port;
7670 staticIdentifierForPort[port] = staticPortIdentifier;
7676 portWithStaticIdentifier[staticPortIdentifier] = port;
7677 staticIdentifierForPort[port] = staticPortIdentifier;
7687 refreshComponentAlphaLevelTimer->start();
7695 refreshComponentAlphaLevelTimer->stop();
7718 if (!activeProtocol)
7725 if (!
getBase()->getCompiler()->getCachedGraph()->mayEventsReachPublishedOutputPorts())
7727 QString errorHeadline = tr(
"<b>This composition doesn't send any images to <code>outputImage</code>.</b>");
7728 QString errorDetails = tr(
"<p>To export, your composition should use the data and events from the published input ports "
7729 "to output a stream of images through the <code>outputImage</code> published output port.</p>");
7731 if (isExportingMovie)
7732 errorDetails.append(
"<p>Alternatively, you can record a realtime movie by running the composition and selecting File > Start Recording.</p>");
7735 QMessageBox messageBox(window);
7736 messageBox.setWindowFlags(Qt::Sheet);
7737 messageBox.setWindowModality(Qt::WindowModal);
7739 messageBox.setTextFormat(Qt::RichText);
7741 messageBox.setStandardButtons(QMessageBox::Help | QMessageBox::Ok);
7742 messageBox.setButtonText(QMessageBox::Help, tr(
"Open an Example"));
7743 messageBox.setButtonText(QMessageBox::Ok, tr(
"OK"));
7744 messageBox.setDefaultButton(QMessageBox::Ok);
7746 messageBox.setText(errorHeadline);
7747 messageBox.setInformativeText(
"<style>p{" + fonts->
getCSS(fonts->
dialogBodyFont()) +
"}</style>" + errorDetails);
7749 if (messageBox.exec() == QMessageBox::Help)
7751 map<QString, QString> examples = static_cast<VuoEditor *>(qApp)->getExampleCompositionsForProtocol(activeProtocol);
7752 map<QString, QString>::iterator i = examples.begin();
7753 if (i != examples.end())
7783 string dir, file, ext;
7797 if (! customizedName.empty())
7798 return QString::fromStdString(customizedName);
7816 string fileNameContentPart = (fileNameParts.size() >= 2 && fileNameParts[fileNameParts.size()-1] ==
"vuo"?
7817 fileNameParts[fileNameParts.size()-2] :
7818 (fileNameParts.size() >= 1? fileNameParts[fileNameParts.size()-1] :
""));
7821 if (QRegExp(
"\\s").indexIn(fileNameContentPart.c_str()) != -1)
7823 string formattedName = fileNameContentPart;
7824 if (formattedName.size() >= 1)
7825 formattedName[0] = toupper(formattedName[0]);
7827 return QString(formattedName.c_str());
7841 QStringList wordsInName = nodeSetName.split(QRegularExpression(
"\\."));
7842 if (wordsInName.size() < 2 || wordsInName[0] !=
"vuo")
7848 map<QString, QString> wordsToReformat;
7849 wordsToReformat[
"artnet"] =
"Art-Net";
7850 wordsToReformat[
"bcf2000"] =
"BCF2000";
7851 wordsToReformat[
"hid"] =
"HID";
7852 wordsToReformat[
"midi"] =
"MIDI";
7853 wordsToReformat[
"osc"] =
"OSC";
7854 wordsToReformat[
"rss"] =
"RSS";
7855 wordsToReformat[
"ui"] =
"UI";
7856 wordsToReformat[
"url"] =
"URL";
7858 QString nodeSetDisplayName =
"";
7859 for (
int i = 1; i < wordsInName.size(); ++i)
7861 QString currentWord = wordsInName[i];
7862 if (currentWord.size() >= 1)
7864 if (wordsToReformat.find(currentWord.toLower()) != wordsToReformat.end())
7865 currentWord = wordsToReformat.at(currentWord.toLower());
7867 currentWord[0] = currentWord[0].toUpper();
7869 nodeSetDisplayName += currentWord;
7871 if (i < wordsInName.size()-1)
7872 nodeSetDisplayName +=
" ";
7875 return nodeSetDisplayName;
7888 string formattedTypeName =
"";
7896 formattedTypeName =
"List of " + formattedInnerTypeName +
" elements";
7902 return formattedTypeName.c_str();
7921 return "Transform2D";
7923 return "Transform3D";
7931 bool VuoEditorComposition::nodeSetMenuActionLessThan(QAction *action1, QAction *action2)
7933 QString item1Text = action1->text();
7934 QString item2Text = action2->text();
7937 const QString listPrefix =
"List of ";
7938 const QString builtInTypePrefix =
"Vuo";
7940 if (item1Text.startsWith(listPrefix))
7942 item1Text.remove(0, listPrefix.length());
7943 if (item1Text.startsWith(builtInTypePrefix))
7944 item1Text.remove(0, builtInTypePrefix.length());
7947 if (item2Text.startsWith(listPrefix))
7949 item2Text.remove(0, listPrefix.length());
7950 if (item2Text.startsWith(builtInTypePrefix))
7951 item2Text.remove(0, builtInTypePrefix.length());
7955 return (item1Text.compare(item2Text, Qt::CaseInsensitive) < 0);
7962 bool VuoEditorComposition::itemHigherOnCanvas(QGraphicsItem *item1, QGraphicsItem *item2)
7964 qreal item1Y = item1->scenePos().y();
7965 qreal item2Y = item2->scenePos().y();
7967 qreal item1X = item1->scenePos().x();
7968 qreal item2X = item2->scenePos().x();
7970 if (item1Y == item2Y)
7971 return (item1X < item2X);
7973 return item1Y < item2Y;
7985 vector<string> node1Keywords = node1->
getKeywords();
7986 vector<string> node2Keywords = node2->
getKeywords();
7998 node1Keywords.push_back(nodeTitleToken.toLower().toUtf8().constData());
8002 node2Keywords.push_back(nodeTitleToken.toLower().toUtf8().constData());
8004 set<string> node1KeywordSet(node1Keywords.begin(), node1Keywords.end());
8005 set<string> node2KeywordSet(node2Keywords.begin(), node2Keywords.end());
8007 set<string> nodeKeywordsIntersection;
8008 std::set_intersection(node1KeywordSet.begin(), node1KeywordSet.end(),
8009 node2KeywordSet.begin(), node2KeywordSet.end(),
8010 std::inserter(nodeKeywordsIntersection, nodeKeywordsIntersection.end()));
8012 set<string> nodeKeywordsUnion = node1KeywordSet;
8013 nodeKeywordsUnion.insert(node2KeywordSet.begin(), node2KeywordSet.end());
8016 if (nodeKeywordsUnion.size() == 0)
8020 double nodeSimilarity = nodeKeywordsIntersection.size()/(1.0*nodeKeywordsUnion.size());
8022 return nodeSimilarity;
8041 VuoEditorComposition::~VuoEditorComposition()
8043 dispatch_sync(runCompositionQueue, ^{});
8044 dispatch_release(runCompositionQueue);
8046 preparedAnimations.clear();
8047 animationForTimeline.clear();
8073 vector<VuoRendererPort *> sortedPortsToPublish;
8074 foreach (
string portID, portsToPublish)
8078 sortedPortsToPublish.push_back(port->
getRenderer());
8080 std::sort(sortedPortsToPublish.begin(), sortedPortsToPublish.end(), itemHigherOnCanvas);
8082 map<string, string> publishedPortNames;
8089 string publishedPortName = (!specializedPublishedPortName.empty()?
8090 specializedPublishedPortName :
8099 return publishedPortNames;
8127 void VuoEditorComposition::repositionPopover()
8129 VuoPortPopover *popover = static_cast<VuoPortPopover *>(QObject::sender());
8132 const int cutoffMargin = 16;
8133 if (popover->pos().x()+popover->size().width()+cutoffMargin > views()[0]->viewport()->rect().right())
8134 popover->move(QPoint(views()[0]->viewport()->rect().right()-popover->size().width()-cutoffMargin, popover->pos().y()));
8136 if (popover->pos().y()+popover->size().height()+cutoffMargin > views()[0]->viewport()->rect().bottom())
8137 popover->move(QPoint(popover->pos().x(), views()[0]->viewport()->rect().bottom()-popover->size().height()-cutoffMargin));