11 #include "ui_VuoEditorWindow.h"
83 #include <objc/objc-runtime.h>
92 const qreal VuoEditorWindow::viewportStepRate = 1;
93 const qreal VuoEditorWindow::viewportStepRateMultiplier = 5;
94 const qreal VuoEditorWindow::zoomRate = 1.2;
95 const qreal VuoEditorWindow::pastedComponentOffset = 20;
96 const qreal VuoEditorWindow::compositionMargin = 20;
110 const string &compositionAsString,
115 string nodeClassToHighlight) :
118 doneInitializing =
false;
121 this->compiler =
new VuoCompiler(compositionPath.toStdString());
123 this->compositionUpgradedSinceLastSave =
false;
124 this->protocolComplianceReevaluationPending =
false;
125 this->ignoreItemMoveSignals =
false;
126 this->closing =
false;
127 this->containedPrepopulatedContent = (!compositionAsString.empty() || activeProtocol);
128 this->publishedPortNearCursorPreviously =
false;
129 this->zoomOutToFitOnNextShowEvent = nodeClassToHighlight.empty();
130 this->includeInRecentFileMenu =
true;
144 ui->newComposition->setShortcut(QKeySequence(
"Ctrl+N"));
145 ui->openComposition->setShortcut(QKeySequence(
"Ctrl+O"));
146 ui->saveComposition->setShortcut(QKeySequence(
"Ctrl+S"));
147 ui->saveCompositionAs->setShortcut(QKeySequence(
"Ctrl+Shift+S"));
148 ui->closeComposition->setShortcut(QKeySequence(
"Ctrl+W"));
149 ui->selectAll->setShortcut(QKeySequence(
"Ctrl+A"));
150 ui->selectNone->setShortcut(QKeySequence(
"Ctrl+Shift+A"));
151 ui->cutCompositionComponents->setShortcut(QKeySequence(
"Ctrl+X"));
152 ui->copyCompositionComponents->setShortcut(QKeySequence(
"Ctrl+C"));
153 ui->duplicateCompositionComponents->setShortcut(QKeySequence(
"Ctrl+D"));
154 ui->paste->setShortcut(QKeySequence(
"Ctrl+V"));
155 ui->deleteCompositionComponents->setShortcut(QKeySequence(
"Backspace"));
156 ui->zoomIn->setShortcut(QKeySequence(
"Ctrl+="));
157 ui->zoomOut->setShortcut(QKeySequence(
"Ctrl+-"));
158 ui->zoom11->setShortcut(QKeySequence(
"Ctrl+0"));
159 isZoomedToFit =
false;
160 addAction(ui->stopComposition);
161 ui->showNodeLibrary->setShortcut(QKeySequence(
"Ctrl+Return"));
176 ui->menuView->addSeparator();
180 ui->menuView->addAction(editor->darkInterfaceAction);
187 QMenu *menuGrid =
new QMenu(ui->menuBar);
188 menuGrid->setSeparatorsCollapsible(
false);
189 menuGrid->setTitle(tr(
"&Grid"));
192 menuGrid->addSeparator();
198 ui->menuView->addMenu(menuGrid);
201 QMenu *menuCanvasTransparency =
new QMenu(ui->menuBar);
202 menuCanvasTransparency->setSeparatorsCollapsible(
false);
203 menuCanvasTransparency->setTitle(tr(
"&Canvas Transparency"));
204 ((
VuoEditor *)qApp)->populateCanvasTransparencyMenu(menuCanvasTransparency);
207 ui->menuView->addMenu(menuCanvasTransparency);
210 menuNewCompositionWithTemplate =
new QMenu(tr(
"New Composition from Template"));
211 menuNewCompositionWithTemplate->setSeparatorsCollapsible(
false);
212 ((
VuoEditor *)qApp)->populateNewCompositionWithTemplateMenu(menuNewCompositionWithTemplate);
215 QMenu *menuNewShader =
new QMenu(tr(
"New Shader"));
216 menuNewShader->setSeparatorsCollapsible(
false);
217 ((
VuoEditor *)qApp)->populateNewShaderMenu(menuNewShader);
220 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
222 if (ui->menuFile->actions().at(menuFileIndex) == ui->newComposition)
224 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuNewCompositionWithTemplate);
225 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuNewShader);
238 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
239 if (ui->menuFile->actions().at(menuFileIndex) == ui->openComposition)
241 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuOpenRecent);
242 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuOpenExample);
250 menuProtocols =
new QMenu(tr(
"Protocols"));
251 menuProtocols->setSeparatorsCollapsible(
false);
252 populateProtocolsMenu(menuProtocols);
255 ui->menuEdit->insertMenu(ui->compositionInformation, menuProtocols);
258 ((
VuoEditor *)qApp)->populateHelpMenu(ui->menuHelp);
264 connect(ui->menuHelp, &QMenu::aboutToShow, [editor,
this] { editor->populateHelpMenu(ui->menuHelp); });
277 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->addComposition(
this);
279 if (!compositionAsString.empty())
281 string dir, file, extension;
291 ui->graphicsView->setScene(composition);
292 ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
293 ui->graphicsView->setMouseTracking(
true);
294 composition->installEventFilter(
this);
295 ui->graphicsView->viewport()->installEventFilter(
this);
299 connect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
303 connect(ui->refactor, &QAction::triggered,
this, &VuoEditorWindow::refactorSelectedItems);
308 raiseDocumentAction =
new QAction(
this);
309 raiseDocumentAction->setCheckable(
true);
316 inputEditorSession =
nullptr;
331 undoStack =
new QUndoStack(
this);
332 connect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
334 undoAction = undoStack->createUndoAction(
this);
335 undoAction->setText(tr(
"Undo"));
336 undoAction->setShortcut(QKeySequence::Undo);
338 redoAction = undoStack->createRedoAction(
this);
339 redoAction->setText(tr(
"Redo"));
340 redoAction->setShortcut(QKeySequence::Redo);
343 metadataEditor->setWindowModality(Qt::WindowModal);
344 connect(metadataEditor, &VuoMetadataEditor::finished,
this, &VuoEditorWindow::editMetadata);
346 searchBox =
new VuoSearchBox(composition,
this, Qt::Widget);
347 searchBox->setVisible(
false);
350 canvasDragEnabled =
false;
351 canvasDragInProgress =
false;
352 scrollInProgress =
false;
353 timeOfLastScroll = 0;
354 consumeNextMouseReleaseToCanvas =
false;
355 lastLeftMousePressHadOptionModifier =
false;
356 rubberBandSelectionInProgress =
false;
357 previousDragMoveWasOverSidebar =
false;
358 duplicationMacroInProgress =
false;
359 itemDragMacroInProgress =
false;
363 commentResizeMacroInProgress =
false;
364 commentBeingResized = NULL;
367 forwardingEventsToCanvas =
false;
369 ui->menuEdit->insertAction(ui->menuEdit->actions()[0], redoAction);
370 ui->menuEdit->insertAction(redoAction, undoAction);
373 ui->menuEdit->insertMenu(ui->changeNodePlaceholder, contextMenuTints);
375 menuChangeNode =
new QMenu(ui->menuEdit);
376 menuChangeNode->setTitle(tr(
"Change To"));
379 connect(ui->menuEdit, &QMenu::aboutToShow,
this, &VuoEditorWindow::updateChangeNodeMenu);
381 foreach (QMenu *menu, ui->menuBar->findChildren<QMenu*>())
382 menu->setSeparatorsCollapsible(
false);
428 setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
429 setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
431 connect(ui->toggleNodeLibraryDocking, &QAction::triggered,
this, &VuoEditorWindow::toggleNodeLibraryDockedState);
433 QActionGroup* toggleDisplay=
new QActionGroup(
this);
434 toggleDisplay->addAction(ui->actionShowNodeNames);
435 toggleDisplay->addAction(ui->actionShowNodeClassNames);
440 inputPortSidebar->setVisible(
false);
441 outputPortSidebar->setVisible(
false);
445 connect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
446 connect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
451 connect(inputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
452 connect(outputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
462 connect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
463 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
464 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
465 connect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
466 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
467 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
468 connect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
470 connect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
471 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
476 connect(composition, SIGNAL(portPublicationRequested(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
481 connect(composition, SIGNAL(publishedPortModified()), inputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
482 connect(composition, SIGNAL(publishedPortModified()), outputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
489 connect(inputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
490 connect(outputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
509 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
510 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
511 connect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
512 connect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
514 connect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()), Qt::QueuedConnection);
517 VuoEditorWindow_Pro();
520 coalescedOldCompositionSnapshot =
"";
521 coalescedNewCompositionSnapshot =
"";
522 coalescedDiffInfo =
nullptr;
530 initializeNodeLibrary(this->compiler, nodeLibraryDisplayMode, nodeLibraryState, floater);
536 connect(composition, &VuoEditorComposition::changed,
this, &VuoEditorWindow::ensureSceneRectContainsRegion);
539 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::updateSelectedComponentMenuItems);
548 ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
550 ui->graphicsView->setAttribute(Qt::WA_NoBackground,
true);
551 ui->graphicsView->setAttribute(Qt::WA_OpaquePaintEvent);
552 ui->graphicsView->setAttribute(Qt::WA_NoSystemBackground);
556 nl->setAttribute(Qt::WA_NoBackground,
true);
557 nl->setAttribute(Qt::WA_OpaquePaintEvent);
558 nl->setAttribute(Qt::WA_NoSystemBackground);
565 if (compositionAsString.empty())
581 if (compositionAsString.empty())
592 evaluateCompositionForProtocolPromotion();
601 setPublishedPortSidebarVisibility(displayPublishedPorts);
606 doneInitializing =
true;
608 updateCanvasOpacity();
610 string dir, file, ext;
616 setWindowTitle(documentIdentifier +
"[*]");
618 toolbar->updateTitle();
628 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
629 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
630 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
638 setWindowFilePath(documentIdentifier);
650 if (!nodeClassToHighlight.empty())
654 updateRefireAction();
657 QMetaObject::invokeMethod(
this,
"showUpdateHelpDialog", Qt::QueuedConnection);
660 VuoEditorWindow::~VuoEditorWindow()
664 disconnect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
665 disconnect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
678 disconnect(ui->graphicsView, SIGNAL(viewResized()), outputPortSidebar, SLOT(externalMoveEvent()));
680 disconnect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
681 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
682 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
683 disconnect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
684 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
685 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
686 disconnect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
697 disconnect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
701 disconnect(ui->menuEdit, &QMenu::aboutToShow,
this, &VuoEditorWindow::updateChangeNodeMenu);
705 disconnect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
707 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
708 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
709 disconnect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
710 disconnect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
711 disconnect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()));
713 disconnect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
714 disconnect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
720 transitionNodeLibraryConnections(nl, NULL);
724 delete metadataPanel;
730 map<string, string> constantPortIdentifiersAndValues;
731 string revertedSourceCode;
736 catch (std::exception
const &e)
746 for (
VuoPort *port : node->getInputPorts())
748 if (port->hasCompiler())
759 delete revertedComposition;
764 topLevelComposition->getModuleManager()->doNextTimeNodeClassIsLoaded(nodeClassName, ^{
766 for (
auto i : constantPortIdentifiersAndValues)
767 topLevelComposition->updateInternalPortConstantInSubcompositionInstances(subcompositionPath, i.first, i.second);
776 composition->deleteLater();
783 dispatch_sync(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{});
790 void VuoEditorWindow::showUpdateHelpDialog()
794 bool foundCommunityNode =
false;
799 foundCommunityNode =
true;
804 if (foundCommunityNode)
806 QString summary = tr(
"This composition was created in an earlier version of Vuo. It might behave differently now.");
807 QString details = tr(
"<p><a href=\"%1\">How do I update my compositions from Vuo 1.x to Vuo 2.0?</a></p>")
808 .arg(
"https://vuo.org/node/2376");
809 QString checkboxLabel = tr(
"Show this window when opening compositions.");
810 QString settingsKey =
"showUpdateHelp";
822 updateSelectedComponentMenuItems();
823 updateToolbarElementUI();
826 ui->compositionInformation->setEnabled(
true);
831 ui->stopComposition->setEnabled(
false);
832 ui->restartComposition->setEnabled(
false);
836 ui->runComposition->setEnabled(
false);
837 ui->stopComposition->setEnabled(
true);
838 ui->restartComposition->setEnabled(
true);
840 else if (toolbar && toolbar->
isRunning())
842 ui->runComposition->setEnabled(
false);
843 ui->stopComposition->setEnabled(
true);
844 ui->restartComposition->setEnabled(
true);
848 ui->runComposition->setEnabled(
true);
849 ui->stopComposition->setEnabled(
false);
850 ui->restartComposition->setEnabled(
false);
859 auto found = std::find_if(openWindows.begin(), openWindows.end(), [](
VuoEditorWindow *w){ return w->metadataEditor->isVisible(); });
860 bool isCompositionInformationOpen = (found != openWindows.end());
861 quitAction->setEnabled(! isCompositionInformationOpen);
864 QString savedPath = windowFilePath();
865 string savedDir, savedFile, savedExt;
869 ui->saveComposition->setEnabled(enableSaveMenuItem);
872 bool hasErrors =
true;
873 if (! alreadyInstalledAsUserSubcomposition)
884 ui->saveComposition->setText(tr(
"Save"));
885 ui->saveCompositionAs->setText(tr(
"Save As…"));
886 ui->installSubcomposition->setEnabled(!alreadyInstalledAsUserSubcomposition && !hasErrors);
888 tr(
"Move to User Library") :
889 tr(
"Save to User Library"));
892 updateProtocolsMenu(menuProtocols);
899 ui->actionShowNodeNames->setChecked(
true);
901 ui->actionShowNodeClassNames->setChecked(
true);
903 ui->toggleNodeLibraryDocking->setEnabled(!nl->isHidden());
904 ui->toggleNodeLibraryDocking->setText(nl->isFloating() ? tr(
"Attach to Editor Window") : tr(
"Detach from Editor Window"));
907 if (inputPortSidebar && outputPortSidebar)
909 bool publishedPortSidebarsDisplayed = (! inputPortSidebar->isHidden());
910 ui->showPublishedPorts->setText(publishedPortSidebarsDisplayed ? tr(
"Hide Published Ports") : tr(
"Show Published Ports"));
911 ui->graphicsView->setVerticalScrollBarPolicy(publishedPortSidebarsDisplayed? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
915 ui->findNext->setEnabled(displaySearchTraversalOptions);
916 ui->findPrevious->setEnabled(displaySearchTraversalOptions);
919 undoAction->setEnabled(!cableDragInProgress && undoStack->canUndo());
920 redoAction->setEnabled(!cableDragInProgress && undoStack->canRedo());
923 if (!showingHiddenCables)
925 ui->showHiddenCables->setText(tr(
"Show Hidden Cables"));
933 ui->showHiddenCables->setText(tr(
"Hide Hidden Cables"));
937 ui->showHiddenCables->setEnabled(
true);
943 ui->exportMovie->setEnabled(
false);
944 ui->exportMacScreenSaver->setEnabled(
false);
945 ui->exportMacFFGL->setEnabled(
false);
946 ui->exportFxPlug->setEnabled(
false);
953 ui->menuWindow->clear();
954 static_cast<VuoEditor *
>(qApp)->populateWindowMenu(ui->menuWindow,
this);
965 if (editorWindow && editorWindow !=
this)
966 editorWindow->updateRefireAction();
976 void VuoEditorWindow::updateToolbarElementUI()
981 ui->zoom11->setEnabled(! ui->graphicsView->transform().isIdentity());
982 ui->zoomToFit->setEnabled(! isZoomedToFit);
983 ui->showEvents->setText(composition->
getShowEventsMode() ? tr(
"Hide Events") : tr(
"Show Events"));
989 void VuoEditorWindow::updateRefireAction()
991 __block
bool isTopLevelCompositionRunning =
false;
992 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(composition, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
994 isTopLevelCompositionRunning = topLevelComposition->
isRunning();
997 ui->refireEvent->setEnabled(isTopLevelCompositionRunning ? (
bool)composition->
getTriggerPortToRefire() :
false);
1003 void VuoEditorWindow::updateWindowForNewCableDrag()
1014 void VuoEditorWindow::updateCursor()
1016 QCursor updatedCursor = (canvasDragInProgress? Qt::ClosedHandCursor :
1017 (canvasDragEnabled? Qt::OpenHandCursor :
1022 setCursor(Qt::ArrowCursor);
1024 setCursor(updatedCursor);
1036 foreach (QWidget *widget, qApp->topLevelWidgets())
1039 if (w && w->isVisible() && !w->containedPrepopulatedContent && (w->windowFilePath() ==
"") && (!w->isWindowModified()))
1051 if ((!nodes.empty() || !comments.empty()) && !ignoreItemMoveSignals)
1054 if (movedByDragging && !duplicationMacroInProgress)
1056 itemDragMacroInProgress =
true;
1060 QGraphicsItem *firstItem = (!nodes.empty()?
static_cast<QGraphicsItem *
>(*nodes.begin()) :
1061 static_cast<QGraphicsItem *
>(*comments.begin()));
1063 if (std::find(itemsBeingDragged.begin(), itemsBeingDragged.end(), firstItem) == itemsBeingDragged.end())
1064 itemsBeingDragged.push_back(firstItem);
1066 if (firstItem == itemsBeingDragged[0])
1073 if (!itemDragMacroInProgress)
1074 undoStack->push(
new VuoCommandMove(nodes, comments, dx, dy,
this, movedByDragging));
1084 commentResizeMacroInProgress =
true;
1085 commentBeingResized = comment;
1086 commentResizeDx += dx;
1087 commentResizeDy += dy;
1096 if ((target == composition) && (! components.empty()))
1097 undoStack->push(
new VuoCommandAdd(components,
this,
"Add"));
1104 string VuoEditorWindow::getMaximumSubcompositionFromSelection(
bool includePublishedPorts,
bool includeHeader)
1106 QList<QGraphicsItem *> selectedComponents = composition->selectedItems();
1109 QList<QGraphicsItem *> selectedComponentsWithAttachments;
1110 foreach (QGraphicsItem *item, selectedComponents)
1112 selectedComponentsWithAttachments.append(item);
1117 foreach (QGraphicsItem *attachment, dependentAttachments)
1118 selectedComponentsWithAttachments.push_back(attachment);
1122 QList<QGraphicsItem *> selectedNonStrandedCompositionComponents;
1124 QStringList nodeDeclarations;
1125 vector<VuoRendererNode *> nodesToCopy;
1126 vector<QGraphicsItem *> potentialTypecastNodesToCopy;
1127 map<string, bool> nodeRepresented;
1128 vector<VuoRendererComment *> commentsToCopy;
1130 for (QList<QGraphicsItem *>::iterator i = selectedComponentsWithAttachments.begin(); i != selectedComponentsWithAttachments.end(); ++i)
1134 bool strandedAttachment = (attachment && isStrandedAttachment(attachment, selectedComponentsWithAttachments));
1140 nodesToCopy.push_back(rn);
1142 selectedNonStrandedCompositionComponents.append(rn);
1147 for (vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1158 commentsToCopy.push_back(rcomment);
1162 selectedNonStrandedCompositionComponents.append(QList<QGraphicsItem *>::fromVector(QVector<QGraphicsItem *>::fromStdVector(potentialTypecastNodesToCopy)));
1166 for (vector<QGraphicsItem *>::iterator node = potentialTypecastNodesToCopy.begin(); node != potentialTypecastNodesToCopy.end(); ++node)
1168 bool inputCableCopied =
false;
1169 bool childPortIsPublished =
false;
1170 vector<VuoPort *> inputPorts = ((
VuoRendererNode *)(*node))->getBase()->getInputPorts();
1171 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1173 vector<VuoCable *> inputCables = (*inputPort)->getConnectedCables(
true);
1174 for (vector<VuoCable *>::iterator inputCable = inputCables.begin(); inputCable != inputCables.end(); ++inputCable)
1176 if (std::find(internalCableSet.begin(), internalCableSet.end(), (*inputCable)->getRenderer()) != internalCableSet.end())
1177 inputCableCopied =
true;
1178 if ((*inputCable)->isPublished())
1179 childPortIsPublished =
true;
1185 if (inputCableCopied || (childPortIsPublished && includePublishedPorts))
1187 if (! nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()])
1190 nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()] =
true;
1197 set<VuoCable *> connectedCables = ((
VuoRendererNode *)(*node))->getConnectedCables(
false);
1198 for (set<VuoCable *>::iterator cable = connectedCables.begin(); cable != connectedCables.end(); ++cable)
1199 internalCableSet.erase((*cable)->getRenderer());
1203 vector<VuoRendererCable *> cablesToCopy(internalCableSet.begin(), internalCableSet.end());
1204 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1206 set<VuoNode *> baseNodesToCopy;
1207 for (vector<VuoRendererNode *>::iterator i = nodesToCopy.begin(); i != nodesToCopy.end(); ++i)
1208 baseNodesToCopy.insert( (*i)->getBase() );
1209 set<VuoCable *> baseCablesToCopy;
1210 for (vector<VuoRendererCable *>::iterator i = cablesToCopy.begin(); i != cablesToCopy.end(); ++i)
1211 baseCablesToCopy.insert( (*i)->getBase() );
1212 set<VuoComment *> baseCommentsToCopy;
1213 for (vector<VuoRendererComment *>::iterator i = commentsToCopy.begin(); i != commentsToCopy.end(); ++i)
1214 baseCommentsToCopy.insert( (*i)->getBase() );
1217 set<VuoPublishedPort *> subcompositionPublishedInputPortSet;
1218 set<VuoPublishedPort *> subcompositionPublishedOutputPortSet;
1220 if (includePublishedPorts)
1226 if (baseNodesToCopy.find(cable->
getToNode()) != baseNodesToCopy.end())
1228 subcompositionPublishedInputPortSet.insert(publishedInputPort);
1229 baseCablesToCopy.insert(cable);
1238 if (baseNodesToCopy.find(cable->
getFromNode()) != baseNodesToCopy.end())
1240 subcompositionPublishedOutputPortSet.insert(publishedOutputPort);
1241 baseCablesToCopy.insert(cable);
1248 vector<VuoPublishedPort *> subcompositionPublishedInputPorts;
1250 if (subcompositionPublishedInputPortSet.find(port) != subcompositionPublishedInputPortSet.end())
1251 subcompositionPublishedInputPorts.push_back(port);
1253 vector<VuoPublishedPort *> subcompositionPublishedOutputPorts;
1255 if (subcompositionPublishedOutputPortSet.find(port) != subcompositionPublishedOutputPortSet.end())
1256 subcompositionPublishedOutputPorts.push_back(port);
1261 subcompositionPublishedInputPorts,
1262 subcompositionPublishedOutputPorts,
1265 -viewportTopLeft.x(),
1266 -viewportTopLeft.y());
1268 return outputCompositionText;
1279 if (!(renderedHostNode && renderedHostNode->
hasRenderer() && selectedItems.contains(renderedHostNode->
getRenderer())))
1283 foreach (
VuoNode *coattachment, coattachments)
1300 QClipboard *clipboard = QApplication::clipboard();
1301 QMimeData *mimeData =
new QMimeData();
1308 mimeData->setText(getMaximumSubcompositionFromSelection(
false,
true).c_str());
1312 clipboard->setMimeData(mimeData);
1325 pasteCompositionComponents();
1326 else if (!clipboardText.isEmpty())
1336 void VuoEditorWindow::pasteCompositionComponents()
1338 QClipboard *clipboard = QApplication::clipboard();
1339 const QMimeData *mimeData = clipboard->mimeData();
1344 int publishedCablesBeforePaste = 0;
1350 if (mimeData->hasFormat(
"text/plain"))
1354 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
1356 bool pasteAtCursorLoc = ((cursorPos != cursorPosAtLastComponentCopy) && viewportRect.contains(cursorPos));
1358 QString compositionText = mimeData->text();
1359 mergeCompositionComponentsFromString(compositionText.toUtf8().constData(), pasteAtCursorLoc, !pasteAtCursorLoc,
"Paste");
1365 int publishedCablesAfterPaste = 0;
1372 if ((publishedPortsAfterPaste > publishedPortsBeforePaste) || (publishedCablesAfterPaste > publishedCablesBeforePaste))
1373 setPublishedPortSidebarVisibility(
true);
1385 if (! duplicationMacroInProgress)
1387 undoStack->beginMacro(tr(
"Duplication"));
1388 duplicationMacroInProgress =
true;
1391 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1392 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
false,
"Duplication");
1395 composition->clearSelection();
1396 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1397 (*i)->setSelected(
true);
1409 string genericNodeClassName;
1413 genericNodeClassName = currentNodeClass->
getClassName();
1415 if ((genericNodeClassName == nodeClass) && node->
hasRenderer())
1420 QRectF selectedItemsRect;
1421 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
1422 selectedItemsRect |= selectedComponent->sceneBoundingRect();
1424 if (!selectedItemsRect.isNull())
1425 ui->graphicsView->centerOn(selectedItemsRect.center());
1435 void VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem()
1437 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1438 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
true,
"Duplication");
1441 composition->clearSelection();
1442 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1443 (*i)->setSelected(
true);
1452 resetUndoStackMacros();
1455 undoAction->trigger();
1466 composition->
clear();
1467 instantiateNewCompositionComponentsFromString(snapshot);
1477 void VuoEditorWindow::instantiateNewCompositionComponentsFromString(
string compositionText)
1498 composition->
addCable(cable,
false);
1529 QList<QGraphicsItem *> VuoEditorWindow::mergeCompositionComponentsFromString(
string compositionText,
bool pasteAtCursorLoc,
bool pasteWithOffset,
string commandDescription)
1532 QList<QGraphicsItem *> pastedComponents = QList<QGraphicsItem *>();
1534 QPointF startPos = (pasteWithOffset? QPointF(pastedComponentOffset, pastedComponentOffset) : QPointF(0,0));
1539 if (pastedNode->getNodeClass()->hasCompiler())
1541 VuoNode *allowedNode = composition->
createBaseNode(pastedNode->getNodeClass()->getCompiler(), pastedNode);
1544 pastedComposition->
replaceNode(pastedNode, allowedNode);
1551 set<VuoNode *> pastedNodes = pastedComposition->
getBase()->
getNodes();
1552 for (
VuoNode *node : pastedNodes)
1555 pastedComponents.append(rn);
1562 pastedComponents.append(rc);
1565 qreal minX = std::numeric_limits<qreal>::max();
1566 qreal minY = std::numeric_limits<qreal>::max();
1568 if (pasteAtCursorLoc)
1571 for (
VuoNode *node : pastedNodes)
1577 if (node->
getX() < minX)
1578 minX = node->
getX();
1580 if (node->
getY() < minY)
1581 minY = node->
getY();
1586 if (comment->
getX() < minX)
1587 minX = comment->
getX();
1589 if (comment->
getY() < minY)
1590 minY = comment->
getY();
1597 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1598 startPos += viewportTopLeft;
1602 this->ignoreItemMoveSignals =
true;
1603 for (
VuoNode *node : pastedNodes)
1605 node->
setX(startPos.x() + node->
getX());
1606 node->
setY(startPos.y() + node->
getY());
1613 comment->
setX(startPos.x() + comment->
getX());
1614 comment->
setY(startPos.y() + comment->
getY());
1618 this->ignoreItemMoveSignals =
false;
1621 for (
VuoCable *cable : pastedCables)
1626 pastedComponents.append(rc);
1634 map<VuoPublishedPort *, vector<pair<VuoPort *, bool> > > connectionsForPublishedPort;
1635 map<VuoPublishedPort *, bool> publishedPortHadConnectedDataCable;
1639 bool foundConnectedDataCable =
false;
1641 foreach (
VuoCable *cable, publishedInputCables)
1647 bool cableCarriesData = (compilerToPort && compilerToPort->
getDataVuoType() && !alwaysEventOnly);
1648 if (cableCarriesData)
1649 foundConnectedDataCable =
true;
1651 connectionsForPublishedPort[publishedInput].push_back(make_pair(toPort, alwaysEventOnly));
1654 cable->
setTo(NULL, NULL);
1657 publishedPortHadConnectedDataCable[publishedInput] = foundConnectedDataCable;
1662 bool foundConnectedDataCable =
false;
1663 vector<VuoCable *> publishedOutputCables = publishedOutput->
getConnectedCables(
true);
1664 foreach (
VuoCable *cable, publishedOutputCables)
1670 bool cableCarriesData = (compilerFromPort && compilerFromPort->
getDataVuoType() && !alwaysEventOnly);
1671 if (cableCarriesData)
1672 foundConnectedDataCable =
true;
1674 connectionsForPublishedPort[publishedOutput].push_back(make_pair(fromPort, alwaysEventOnly));
1677 cable->
setTo(NULL, NULL);
1680 publishedPortHadConnectedDataCable[publishedOutput] = foundConnectedDataCable;
1685 undoStack->beginMacro(tr(commandDescription.c_str()));
1688 componentsPasted(pastedComponents, commandDescription);
1691 vector<VuoPublishedPort *> unmergedPublishedInputPorts;
1697 string pastedPublishedPortName = publishedInputPort->
getClass()->
getName();
1701 publishedPortHadConnectedDataCable[publishedInputPort]))
1703 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedInputPort];
1704 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1706 VuoPort *connectedPort = i->first;
1707 bool forceEventOnlyPublication = i->second;
1713 unmergedPublishedInputPorts.push_back(publishedInputPort);
1717 foreach (
VuoPublishedPort *unmergedPublishedInputPort, unmergedPublishedInputPorts)
1721 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedInputPort];
1722 if (!internalConnections.empty())
1724 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1726 VuoPort *connectedPort = i->first;
1727 bool forceEventOnlyPublication = i->second;
1735 unmergedPublishedInputPort->
getClass()->
setName(uniquePublishedPortName);
1742 vector<VuoPublishedPort *> unmergedPublishedOutputPorts;
1748 string pastedPublishedPortName = publishedOutputPort->
getClass()->
getName();
1752 publishedPortHadConnectedDataCable[publishedOutputPort]))
1754 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedOutputPort];
1755 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1757 VuoPort *connectedPort = i->first;
1758 bool forceEventOnlyPublication = i->second;
1764 unmergedPublishedOutputPorts.push_back(publishedOutputPort);
1768 foreach (
VuoPublishedPort *unmergedPublishedOutputPort, unmergedPublishedOutputPorts)
1772 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedOutputPort];
1773 if (!internalConnections.empty())
1775 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1777 VuoPort *connectedPort = i->first;
1778 bool forceEventOnlyPublication = i->second;
1786 unmergedPublishedOutputPort->
getClass()->
setName(uniquePublishedPortName);
1792 delete pastedComposition;
1794 undoStack->endMacro();
1796 return pastedComponents;
1803 void VuoEditorWindow::componentsPasted(QList<QGraphicsItem *> components,
string commandDescription)
1805 if (components.empty())
1809 undoStack->push(
new VuoCommandAdd(components,
this, commandDescription));
1812 composition->clearSelection();
1813 for (QList<QGraphicsItem *>::iterator i = components.begin(); i != components.end(); ++i)
1814 (*i)->setSelected(
true);
1848 pair<VuoRendererCable *, VuoRendererCable *> cableArgs,
1850 pair<string, string> typeArgs,
1851 pair<VuoRendererPort *, VuoRendererPort *> portArgs)
1858 string typecastToInsert = typeArgs.first;
1859 string specializedTypeName = typeArgs.second;
1877 set<VuoRendererNode *> emptyNodeSet;
1878 set<VuoRendererComment *> emptyCommentSet;
1879 undoStack->push(
new VuoCommandMove(emptyNodeSet, emptyCommentSet, 0, 0,
this,
false));
1883 cableInProgress->
setTo(NULL, NULL);
1887 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
1889 VuoPort *typecastInPort = NULL;
1890 VuoPort *typecastOutPort = NULL;
1891 if (!typecastToInsert.empty())
1893 typecastNodeToAdd = composition->
createNode(typecastToInsert.c_str(),
"",
1894 targetPort->scenePos().x()+100,
1895 targetPort->scenePos().y()+100);
1897 typecastRelatedComponentsToAdd.append(typecastNodeToAdd);
1903 if (!(typecastInPort && typecastInPort->
hasRenderer() && typecastOutPort && typecastOutPort->
hasRenderer()))
1917 if (portToSpecialize)
1922 if (currentlyGeneric)
1927 if (!specializedNode)
1930 if (portToSpecialize == targetPort)
1938 unadjustedToPort = targetPort;
1942 unadjustedFromPort = targetPort;
1964 if (attachedDrawer && cableWillCarryData)
1966 QList<QGraphicsItem *> drawerRelatedComponentsToRemove;
1967 drawerRelatedComponentsToRemove.append(attachedDrawer);
1968 bool disableAutomaticAttachmentInsertion =
true;
1969 undoStack->push(
new VuoCommandRemove(drawerRelatedComponentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
1974 if (typecastNodeToDelete)
1976 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
1977 typecastRelatedComponentsToRemove.append(typecastNodeToDelete);
1978 typecastRelatedComponentsToRemove.append(dataCableToDisplace);
1980 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
"",
true));
1982 dataCableToDisplace = NULL;
1988 QList<QGraphicsItem *> componentsToReplace = QList<QGraphicsItem *>();
1989 componentsToReplace.append(cableToReplace);
1990 undoStack->push(
new VuoCommandRemove(componentsToReplace,
this, inputEditorManager,
"",
false));
1993 if (! typecastToInsert.empty())
2010 adjustedTargetPort = typecastInPort->
getRenderer();
2013 incomingTypecastCable = cableInProgress;
2027 adjustedTargetPort = typecastOutPort->
getRenderer();
2030 incomingTypecastCable = newCableConnectingTypecast;
2033 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2036 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2039 undoStack->push(
new VuoCommandConnect(cableInProgress, adjustedTargetPort, dataCableToDisplace, portToUnpublish,
this, inputEditorManager));
2043 if (targetPort->
getInput() && previousToPort && (previousToPort != targetPort->
getBase()))
2046 if (previousTypecastToPort)
2053 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
2054 typecastRelatedComponentsToRemove.append(uncollapsedTypecastToPort);
2055 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
""));
2075 if (compatibleSpecializedTypes.size() == 1)
2077 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2089 if (! components.empty())
2090 undoStack->push(
new VuoCommandRemove(components,
this, inputEditorManager, commandDescription));
2117 newNodeClass = compiler->
getNodeClass(newMakeListNodeClassName);
2123 string commandText = (inputPortCountDelta == -1?
"Remove Input Port" : (inputPortCountDelta == 1?
"Add Input Port" :
""));
2126 if (adjustmentedRequestedByDragging)
2131 if (oldMakeListNode)
2133 if (composition->mouseGrabberItem() == oldMakeListNode)
2134 oldMakeListNode->ungrabMouse();
2139 if (newMakeListNode)
2142 newMakeListNode->grabMouse();
2155 if (!newNodeCompilerClass)
2185 string commandText =
"Port Specialization";
2187 if (encapsulateInMacro)
2188 undoStack->beginMacro(tr(commandText.c_str()));
2198 newNode = specializeSinglePort(port, innermostSpecializedTypeName);
2202 map<VuoRendererNode *, VuoRendererNode *> nodesToSpecialize;
2203 nodesToSpecialize[originalNode] = newNode;
2206 foreach (
VuoPort *networkedPort, networkedGenericPorts)
2210 VuoRendererNode *mostRecentVersionOfNetworkedNode = originalNetworkedNode;
2211 VuoPort *mostRecentVersionOfNetworkedPort = networkedPort;
2212 map<VuoRendererNode *, VuoRendererNode *>::iterator i = nodesToSpecialize.find(originalNetworkedNode);
2213 if (i != nodesToSpecialize.end())
2216 if (!specializedNode)
2219 tr(
"Couldn't specialize node '%1' to type '%2'.")
2220 .arg(QString::fromStdString(originalNetworkedNode->
getBase()->
getTitle()),
2221 QString::fromStdString(specializedTypeName)).toStdString(),
2222 tr(
"The node might have failed to compile. Check the console log for details.").toStdString());
2228 mostRecentVersionOfNetworkedNode = specializedNode;
2229 mostRecentVersionOfNetworkedPort = networkedPortInSpecializedNode;
2233 if (specializedTypeName != originalTypeName)
2237 VuoRendererNode *newNetworkedNode = specializeSinglePort(mostRecentVersionOfNetworkedPort->
getRenderer(), innermostSpecializedTypeName);
2238 nodesToSpecialize[originalNetworkedNode] = newNetworkedNode;
2241 bool preserveDanglingCables =
true;
2242 undoStack->push(
new VuoCommandReplaceNode(nodesToSpecialize,
this, commandText, preserveDanglingCables));
2250 if (encapsulateInMacro)
2251 undoStack->endMacro();
2268 if (!specializableNodeClass)
2303 QString commandText = tr(
"Port Specialization");
2304 bool preserveDanglingCables =
true;
2305 bool resetConstantValues =
false;
2307 if (encapsulateInMacro)
2308 undoStack->beginMacro(commandText);
2314 map<VuoNode *, string> nodesToReplace;
2315 set<VuoCable *> cablesToDelete;
2319 QList<QGraphicsItem *> rendererCablesToDelete;
2320 foreach (
VuoCable *cableToDelete, cablesToDelete)
2326 rendererCablesToDelete.append(cableToDelete->
getRenderer());
2329 undoStack->push(
new VuoCommandRemove(rendererCablesToDelete,
this, inputEditorManager, commandText.toStdString()));
2334 nodesToReplace.clear();
2337 map<VuoRendererNode *, VuoRendererNode *> nodesToUnspecialize;
2340 for (map<VuoNode *, string>::iterator i = nodesToReplace.begin(); i != nodesToReplace.end(); ++i)
2342 VuoNode *nodeToRevert = i->first;
2343 string revertedNodeClass = i->second;
2346 nodesToUnspecialize[nodeToRevert->
getRenderer()] = revertedNode;
2348 if (nodeToRevert->
getRenderer() == originalParentNode)
2349 unspecializedParentNode = revertedNode;
2352 undoStack->push(
new VuoCommandReplaceNode(nodesToUnspecialize,
this, commandText.toStdString(), preserveDanglingCables, resetConstantValues));
2354 if (encapsulateInMacro)
2355 undoStack->endMacro();
2357 return unspecializedParentNode;
2388 string commandText =
"Port Re-specialization";
2391 if (encapsulateInMacro)
2392 undoStack->beginMacro(tr(commandText.c_str()));
2403 if (encapsulateInMacro)
2404 undoStack->endMacro();
2406 return specializedParentNode;
2418 if (!revertedNodeClass)
2431 undoStack->beginMacro(tr(
"Tint"));
2433 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
2434 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
2445 undoStack->endMacro();
2451 void VuoEditorWindow::hideSelectedInternalCables()
2459 void VuoEditorWindow::hideCables(set<VuoRendererCable *> cables)
2461 undoStack->beginMacro(tr(
"Hide"));
2466 undoStack->endMacro();
2473 void VuoEditorWindow::unhideCables(set<VuoRendererCable *> cables)
2475 bool publishedCableToUnhide =
false;
2476 undoStack->beginMacro(tr(
"Unhide"));
2481 publishedCableToUnhide =
true;
2486 if ((inputPortSidebar->isHidden() || outputPortSidebar->isHidden()) && publishedCableToUnhide)
2487 on_showPublishedPorts_triggered();
2489 undoStack->endMacro();
2496 void VuoEditorWindow::createIsolatedExternalPublishedPort(
string typeName,
bool isInput)
2499 if (!typeName.empty() && !type)
2502 undoStack->beginMacro(tr(
"Add Published Port"));
2508 showPublishedPortNameEditor(rpp,
true);
2510 undoStack->endMacro();
2519 bool isPublishedOutput = port->
getInput();
2520 (isPublishedOutput? outputPortSidebar : inputPortSidebar)->updatePortList();
2521 string newName = (isPublishedOutput? outputPortSidebar : inputPortSidebar)->showPublishedPortNameEditor(port);
2523 if (originalName != newName)
2524 changePublishedPortName(port, newName, useUndoStack);
2533 internalPortPublished(internalPort, forceEventOnlyPublication, externalPort->
getClass()->
getName(),
true, portToSpecialize, specializedTypeName, typecastToInsert, useUndoStackMacro);
2550 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2551 on_showPublishedPorts_triggered();
2561 vector<VuoRendererPublishedPort *> preexistingPublishedPorts = targetPort->
getPublishedPorts();
2568 if (useUndoStackMacro)
2569 undoStack->beginMacro(tr(
"Publish Port"));
2572 if (portToSpecialize && portToSpecialize->
hasRenderer())
2577 if (currentlyGeneric)
2582 if (specializedNode && (portToSpecialize == targetPort->
getBase()))
2593 bool publishedCableExpectedToHaveData =
false;
2594 bool publishedPortExpectedToBeMerged =
false;
2605 if (publishedPortWithTargetName &&
2608 publishedPortExpectedToBeMerged =
true;
2610 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType && type);
2614 if (!publishedPortExpectedToBeMerged)
2616 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType);
2628 if (publishedCableExpectedToHaveData)
2634 QList<QGraphicsItem *> componentsToRemove;
2635 componentsToRemove.append(attachedDrawer);
2636 bool disableAutomaticAttachmentInsertion =
true;
2637 undoStack->push(
new VuoCommandRemove(componentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
2644 for (vector<VuoCable *>::iterator cable = connectedCables.begin(); (! displacedCable) && (cable != connectedCables.end()); ++cable)
2645 if ((*cable)->getRenderer()->effectivelyCarriesData())
2646 displacedCable = (*cable)->getRenderer();
2653 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
2654 if (! typecastToInsert.empty())
2658 targetPort->scenePos().x()+100,
2659 targetPort->scenePos().y()+100);
2661 typecastRelatedComponentsToAdd.append(typecast);
2680 adjustedTargetPort = typecastInPort->
getRenderer();
2695 adjustedTargetPort = typecastOutPort->
getRenderer();
2700 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2702 bool disableAutomaticAttachmentInsertion =
true;
2703 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2706 undoStack->push(
new VuoCommandPublishPort(adjustedTargetPort->
getBase(), displacedCable,
this, forceEventOnlyPublication, name, merge));
2718 if (compatibleSpecializedTypes.size() == 1)
2720 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2725 if (useUndoStackMacro)
2726 undoStack->endMacro();
2735 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2736 on_showPublishedPorts_triggered();
2738 undoStack->beginMacro(tr(
"Delete"));
2742 bool isPublishedInput = !port->
getInput();
2743 if (isPublishedInput)
2746 QList<QGraphicsItem *> removedDataCables;
2747 foreach (
VuoCable *cable, publishedInputCables)
2753 if (!removedDataCables.empty())
2754 undoStack->push(
new VuoCommandRemove(removedDataCables,
this, inputEditorManager,
"Delete"));
2758 undoStack->endMacro();
2767 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2768 on_showPublishedPorts_triggered();
2770 undoStack->beginMacro(tr(
"Delete"));
2775 QList<QGraphicsItem *> makeListComponents = createAnyNecessaryMakeListComponents(port);
2776 if (! makeListComponents.empty())
2777 undoStack->push(
new VuoCommandAdd(makeListComponents,
this,
""));
2780 undoStack->endMacro();
2788 set<VuoPublishedPort *> publishedPortsToRemove,
2789 vector<VuoPublishedPort *> publishedPortsToAdd,
2790 bool beginUndoStackMacro,
2791 bool endUndoStackMacro)
2794 undoStack->beginMacro(tr(
"Protocol Port Modification"));
2797 for (map<VuoPublishedPort *, string>::iterator i = publishedPortsToRename.begin(); i != publishedPortsToRename.end(); ++i)
2800 string name = i->second;
2813 undoStack->endMacro();
2819 void VuoEditorWindow::resetUndoStackMacros()
2821 if (itemDragMacroInProgress)
2823 itemDragMacroInProgress =
false;
2825 set<VuoRendererNode *> draggedNodeSet;
2826 set<VuoRendererComment *> draggedCommentSet;
2828 foreach (QGraphicsItem *item, itemsBeingDragged)
2836 undoStack->push(
new VuoCommandMove(draggedNodeSet, draggedCommentSet, itemDragDx, itemDragDy,
this,
true));
2838 itemsBeingDragged.clear();
2844 if (commentResizeMacroInProgress)
2846 commentResizeMacroInProgress =
false;
2848 if (commentBeingResized && ((commentResizeDx != 0) || (commentResizeDy != 0)))
2851 commentBeingResized = NULL;
2853 commentResizeDx = 0;
2854 commentResizeDy = 0;
2857 if (duplicationMacroInProgress)
2859 undoStack->endMacro();
2860 duplicationMacroInProgress =
false;
2869 if (
event->type() == QEvent::Show)
2871 if (zoomOutToFitOnNextShowEvent)
2874 zoomOutToFitOnNextShowEvent =
false;
2878 QMetaObject::invokeMethod(composition,
"updateFeedbackErrors", Qt::QueuedConnection);
2883 if (canvasDragInProgress && (
event->type() == QEvent::MouseMove))
2888 else if (
event->type() == QEvent::WindowActivate)
2895 else if (
event->type() == QEvent::WindowDeactivate)
2898 if (
event->type() == QEvent::WindowStateChange)
2909 else if (
event->type() == QEvent::MouseButtonPress)
2912 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
2913 if (leftMouseButtonPressed)
2916 if (!inputPortSidebar->isHidden())
2919 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
2922 if (publishedPortNearCursor)
2924 QGraphicsSceneMouseEvent mouseEvent;
2925 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
2926 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
2929 forwardingEventsToCanvas =
true;
2939 restoreDefaultLeftDockedWidgetWidths();
2942 else if (
event->type() == QEvent::MouseMove)
2945 if (forwardingEventsToCanvas)
2947 QMouseEvent mouseEvent(QEvent::MouseMove,
2948 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2949 static_cast<QMouseEvent *
>(
event)->screenPos(),
2950 static_cast<QMouseEvent *
>(
event)->button(),
2951 static_cast<QMouseEvent *
>(
event)->buttons(),
2952 static_cast<QMouseEvent *
>(
event)->modifiers());
2954 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2961 else if (
event->type() == QEvent::MouseButtonRelease)
2964 if (forwardingEventsToCanvas)
2966 QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
2967 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2968 static_cast<QMouseEvent *
>(
event)->screenPos(),
2969 static_cast<QMouseEvent *
>(
event)->button(),
2970 static_cast<QMouseEvent *
>(
event)->buttons(),
2971 static_cast<QMouseEvent *
>(
event)->modifiers());
2973 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2975 forwardingEventsToCanvas =
false;
2981 return QMainWindow::event(
event);
2991 const double scrollTimeoutSeconds = 0.5;
2994 VDebugLog(
"Turning canvas interactivity back on even though we didn't receive a Qt::ScrollEnd event, since there hasn't been a scroll event in %g seconds.", scrollTimeoutSeconds);
2995 ui->graphicsView->setInteractive(
true);
2996 scrollInProgress =
false;
3003 if ((canvasDragEnabled || canvasDragInProgress) && (
object == composition) && (
3004 event->type() == QEvent::GraphicsSceneMouseMove ||
3005 event->type() == QEvent::GraphicsSceneMousePress ||
3006 event->type() == QEvent::GraphicsSceneMouseDoubleClick ||
3007 event->type() == QEvent::GraphicsSceneContextMenu ||
3008 event->type() == QEvent::KeyPress))
3013 if ((
object == composition) &&
3014 (
event->type() == QEvent::GraphicsSceneMousePress) &&
3017 consumeNextMouseReleaseToCanvas =
true;
3020 if ((
object == composition) &&
3021 (
event->type() == QEvent::GraphicsSceneMouseRelease) &&
3022 consumeNextMouseReleaseToCanvas)
3024 consumeNextMouseReleaseToCanvas =
false;
3028 if (
event->type() == QEvent::Wheel
3029 && ui->graphicsView->rubberBandRect().isNull()
3030 && !ui->graphicsView->pinchZoomInProgress())
3033 QWheelEvent *wheelEvent =
static_cast<QWheelEvent *
>(
event);
3034 if (wheelEvent->phase() == Qt::ScrollBegin)
3036 ui->graphicsView->setInteractive(
false);
3037 scrollInProgress =
true;
3039 else if (wheelEvent->phase() == Qt::ScrollEnd)
3041 ui->graphicsView->setInteractive(
true);
3042 scrollInProgress =
false;
3047 const double lagLimit = .1;
3052 QInputEvent *filteredInputEvent = (QInputEvent *)(
event);
3053 Qt::KeyboardModifiers modifiersOtherThanShift = (filteredInputEvent->modifiers() & ~Qt::ShiftModifier);
3054 filteredInputEvent->setModifiers(modifiersOtherThanShift);
3055 object->removeEventFilter(
this);
3056 QApplication::sendEvent(
object, filteredInputEvent);
3057 object->installEventFilter(
this);
3065 else if (
event->type() == QEvent::MouseButtonPress)
3067 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
3068 if (leftMouseButtonPressed)
3074 if (canvasDragEnabled && leftMouseButtonPressed && (
object == ui->graphicsView->viewport()))
3076 initiateCanvasDrag();
3082 else if (leftMouseButtonPressed)
3085 if (!inputPortSidebar->isHidden())
3088 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3091 if (publishedPortNearCursor)
3093 QGraphicsSceneMouseEvent mouseEvent;
3094 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
3095 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
3103 else if ((
event->type() == QEvent::MouseMove) &&
3104 canvasDragInProgress &&
3105 (
object == ui->graphicsView->viewport()))
3112 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3113 canvasDragInProgress &&
3114 (((QMouseEvent *)(
event))->button() == Qt::LeftButton) &&
3115 (
object == ui->graphicsView->viewport()))
3117 concludeCanvasDrag();
3124 else if ((((
event->type() == QEvent::MouseButtonRelease) &&
3125 (((QMouseEvent *)(
event))->button() == Qt::LeftButton)) ||
3126 ((
event->type() == QEvent::MouseMove) &&
3127 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton)))
3131 QPoint cursorPosition = ((QMouseEvent *)(
event))->globalPos();
3133 QRect inputPortSidebarRect = inputPortSidebar->geometry();
3134 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()));
3136 QRect outputPortSidebarRect = outputPortSidebar->geometry();
3137 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
3140 if (!inputPortSidebar->isHidden())
3144 if (!outputPortSidebar->isHidden())
3148 if ((
event->type() == QEvent::MouseMove) &&
3149 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton))
3151 bool dragOverInputPortSidebar = ((! inputPortSidebar->isHidden()) && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor));
3152 bool dragOverOutputPortSidebar = ((! outputPortSidebar->isHidden()) && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor));
3154 if (dragOverInputPortSidebar || dragOverOutputPortSidebar)
3156 if (!previousDragMoveWasOverSidebar)
3159 if (dragOverInputPortSidebar)
3161 else if (dragOverOutputPortSidebar)
3164 previousDragMoveWasOverSidebar =
true;
3169 if (previousDragMoveWasOverSidebar)
3177 previousDragMoveWasOverSidebar =
false;
3182 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3183 (((QMouseEvent *)(
event))->button() == Qt::LeftButton))
3188 if (cableInProgress && !inputPortSidebar->isHidden() && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor))
3192 else if (cableInProgress && !outputPortSidebar->isHidden() && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor))
3196 object->removeEventFilter(
this);
3197 QApplication::sendEvent(
object,
event);
3198 object->installEventFilter(
this);
3207 if (!inputPortSidebar->isHidden())
3213 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3219 if (publishedPortNearCursor)
3221 if (!publishedPortNearCursorPreviously)
3227 if (publishedPortNearCursorPreviously)
3233 object->removeEventFilter(
this);
3234 QApplication::sendEvent(
object,
event);
3235 object->installEventFilter(
this);
3238 publishedPortNearCursorPreviously = publishedPortNearCursor;
3244 else if (
event->type() == QEvent::KeyPress)
3246 QKeyEvent *keyEvent = (QKeyEvent *)(
event);
3249 if (keyEvent->key() == Qt::Key_Escape)
3253 if ((composition->selectedItems().isEmpty()) &&
3254 ((keyEvent->key() == Qt::Key_Up) ||
3255 (keyEvent->key() == Qt::Key_Down) ||
3256 (keyEvent->key() == Qt::Key_Left) ||
3257 (keyEvent->key() == Qt::Key_Right)))
3263 else if ((
object == composition) && (keyEvent->key() == Qt::Key_Space))
3270 object->removeEventFilter(
this);
3271 QApplication::sendEvent(
object,
event);
3272 object->installEventFilter(
this);
3280 else if (
event->type() == QEvent::ContextMenu)
3285 return QMainWindow::eventFilter(
object,
event);
3293 return scrollInProgress;
3301 return itemDragMacroInProgress;
3317 return latestDragTime;
3325 void VuoEditorWindow::enableCanvasDrag()
3327 this->canvasDragEnabled =
true;
3337 void VuoEditorWindow::disableCanvasDrag()
3339 this->canvasDragEnabled =
false;
3346 void VuoEditorWindow::initiateCanvasDrag()
3348 this->canvasDragInProgress =
true;
3349 QPoint currentCursorPos = QCursor::pos();
3350 this->lastCursorLocationDuringCanvasDrag = currentCursorPos;
3352 int xNegativeScrollPotential = ui->graphicsView->horizontalScrollBar()->value() - ui->graphicsView->horizontalScrollBar()->minimum();
3353 int yNegativeScrollPotential = ui->graphicsView->verticalScrollBar()->value() - ui->graphicsView->verticalScrollBar()->minimum();
3355 int xPositiveScrollPotential = ui->graphicsView->horizontalScrollBar()->maximum() - ui->graphicsView->horizontalScrollBar()->value();
3356 int yPositiveScrollPotential = ui->graphicsView->verticalScrollBar()->maximum() - ui->graphicsView->verticalScrollBar()->value();
3359 this->canvasDragMinCursorPos = QPoint(currentCursorPos.x() - xPositiveScrollPotential, currentCursorPos.y() - yPositiveScrollPotential);
3360 this->canvasDragMaxCursorPos = QPoint(currentCursorPos.x() + xNegativeScrollPotential, currentCursorPos.y() + yNegativeScrollPotential);
3368 void VuoEditorWindow::concludeCanvasDrag()
3370 this->canvasDragInProgress =
false;
3371 this->lastCursorLocationDuringCanvasDrag = QPoint();
3380 Qt::KeyboardModifiers modifiers =
event->modifiers();
3381 qreal adjustedViewportStepRate = viewportStepRate;
3382 if (modifiers & Qt::ShiftModifier)
3384 adjustedViewportStepRate *= viewportStepRateMultiplier;
3387 if (
event->key() == Qt::Key_Escape)
3391 else if (arePublishedPortSidebarsVisible())
3392 on_showPublishedPorts_triggered();
3393 else if (isFullScreen())
3398 if (composition->hasFocus())
3400 switch (
event->key())
3404 const int y = ui->graphicsView->verticalScrollBar()->value() -
3405 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3406 ui->graphicsView->verticalScrollBar()->setValue(y);
3411 const int y = ui->graphicsView->verticalScrollBar()->value() +
3412 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3413 ui->graphicsView->verticalScrollBar()->setValue(y);
3418 const int x = ui->graphicsView->horizontalScrollBar()->value() -
3419 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3420 ui->graphicsView->horizontalScrollBar()->setValue(x);
3425 const int x = ui->graphicsView->horizontalScrollBar()->value() +
3426 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3427 ui->graphicsView->horizontalScrollBar()->setValue(x);
3441 composition->sendEvent(nearbyPort,
event);
3445 QMainWindow::keyPressEvent(
event);
3458 switch (
event->key())
3462 disableCanvasDrag();
3467 QMainWindow::keyReleaseEvent(
event);
3478 if (canvasDragInProgress)
3480 QPoint oldPos = lastCursorLocationDuringCanvasDrag;
3481 QPoint currentCursorPos = QCursor::pos();
3485 QPoint effectiveNewPos = QPoint( fmax(canvasDragMinCursorPos.x(), fmin(canvasDragMaxCursorPos.x(), currentCursorPos.x())),
3486 fmax(canvasDragMinCursorPos.y(), fmin(canvasDragMaxCursorPos.y(), currentCursorPos.y())));
3489 int dx = -1 * (effectiveNewPos - oldPos).x();
3490 int dy = -1 * (effectiveNewPos - oldPos).y();
3494 lastCursorLocationDuringCanvasDrag.setX(effectiveNewPos.x());
3496 int xScrollbarMin = ui->graphicsView->horizontalScrollBar()->minimum();
3497 int xScrollbarMax = ui->graphicsView->horizontalScrollBar()->maximum();
3498 int xScrollbarOldValue = ui->graphicsView->horizontalScrollBar()->value();
3499 int xScrollbarNewValue = fmax(xScrollbarMin, fmin(xScrollbarMax, xScrollbarOldValue + dx));
3501 if (xScrollbarNewValue != xScrollbarOldValue)
3502 ui->graphicsView->horizontalScrollBar()->setValue(xScrollbarNewValue);
3507 lastCursorLocationDuringCanvasDrag.setY(effectiveNewPos.y());
3509 int yScrollbarMin = ui->graphicsView->verticalScrollBar()->minimum();
3510 int yScrollbarMax = ui->graphicsView->verticalScrollBar()->maximum();
3511 int yScrollbarOldValue = ui->graphicsView->verticalScrollBar()->value();
3512 int yScrollbarNewValue = fmax(yScrollbarMin, fmin(yScrollbarMax, yScrollbarOldValue + dy));
3515 if (yScrollbarNewValue != yScrollbarOldValue)
3516 ui->graphicsView->verticalScrollBar()->setValue(yScrollbarNewValue);
3520 QMainWindow::mouseMoveEvent(
event);
3528 ownedNodeLibrary =
new VuoNodeLibrary(nodeLibraryCompiler,
this, nodeLibraryDisplayMode);
3531 nl = ownedNodeLibrary;
3532 transitionNodeLibraryConnections(NULL, nl);
3536 addDockWidget(Qt::LeftDockWidgetArea, nl);
3539 nodeLibraryMinimumWidth = nl->minimumWidth();
3540 nodeLibraryMaximumWidth = nl->maximumWidth();
3546 void VuoEditorWindow::on_compositionInformation_triggered()
3548 metadataEditor->
show();
3563 void VuoEditorWindow::on_zoomIn_triggered()
3565 ui->graphicsView->scale(zoomRate,zoomRate);
3568 QRectF selectedItemsRect;
3569 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3570 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3572 if (!selectedItemsRect.isNull())
3573 ui->graphicsView->centerOn(selectedItemsRect.center());
3575 isZoomedToFit =
false;
3576 updateToolbarElementUI();
3582 void VuoEditorWindow::on_zoomOut_triggered()
3584 ui->graphicsView->scale(1/zoomRate,1/zoomRate);
3585 isZoomedToFit =
false;
3586 updateToolbarElementUI();
3592 void VuoEditorWindow::on_zoom11_triggered()
3594 bool zoomingIn = (ui->graphicsView->transform().m11() <= 1.0);
3595 ui->graphicsView->setTransform(QTransform());
3600 QRectF selectedItemsRect;
3601 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3602 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3604 if (!selectedItemsRect.isNull())
3605 ui->graphicsView->centerOn(selectedItemsRect.center());
3608 isZoomedToFit =
false;
3609 updateToolbarElementUI();
3619 QRectF itemsBoundingRect = itemsTightBoundingRect.adjusted(-VuoEditorWindow::compositionMargin,
3620 -VuoEditorWindow::compositionMargin,
3621 VuoEditorWindow::compositionMargin,
3622 VuoEditorWindow::compositionMargin);
3623 ui->graphicsView->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
3625 isZoomedToFit =
true;
3626 updateToolbarElementUI();
3637 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
3640 if ((viewportRect.width() < itemsTightBoundingRect.width()) || (viewportRect.height() < itemsTightBoundingRect.height()))
3644 else if (!viewportRect.contains(itemsTightBoundingRect))
3645 ui->graphicsView->ensureVisible(itemsTightBoundingRect, VuoEditorWindow::compositionMargin, VuoEditorWindow::compositionMargin);
3648 void VuoEditorWindow::viewportFitReset()
3650 isZoomedToFit =
false;
3652 updateToolbarElementUI();
3655 void VuoEditorWindow::on_saveComposition_triggered()
3657 QString savedPath = windowFilePath();
3659 on_saveCompositionAs_triggered();
3663 saveFile(savedPath);
3667 void VuoEditorWindow::on_saveCompositionAs_triggered()
3669 string savedPath = saveCompositionAs().toUtf8().constData();
3670 if (savedPath.empty())
3680 QString VuoEditorWindow::saveCompositionAs()
3683 QFileDialog d(
this, Qt::Sheet);
3687 d.setDirectory(windowFilePath());
3696 d.setAcceptMode(QFileDialog::AcceptSave);
3706 QString savedPath =
"";
3707 if (d.exec() == QDialog::Accepted)
3709 savedPath = d.selectedFiles()[0];
3710 string dir, file, ext;
3713 saveFileAs(savedPath);
3727 bool VuoEditorWindow::saveFileAs(
const QString & savePath)
3729 string dir, file, ext;
3733 QDir newCompositionDir(QFileInfo(savePath).absoluteDir().canonicalPath());
3739 if (!installingAsSubcomposition && (!modifiedPortConstantRelativePaths.empty() || iconPathChanged))
3747 map<VuoPort *, string> pathsToUpdate;
3748 QString copiedFileDetails =
"";
3749 QString updatedPathDetails =
"";
3752 for (map <VuoPort *, string>::iterator i = modifiedPortConstantRelativePaths.begin(); i != modifiedPortConstantRelativePaths.end(); ++i)
3755 string modifiedPath = i->second;
3759 string origRelativeDir, file, ext;
3761 string resourceFileName = file;
3764 resourceFileName +=
".";
3765 resourceFileName += ext;
3767 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3771 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3774 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath,
VuoText_makeFromString(modifiedPath.c_str())));
3775 pathsToUpdate[port] = modifiedPath;
3780 if (iconPathChanged)
3785 string origRelativeDir, file, ext;
3787 string resourceFileName = file;
3790 resourceFileName +=
".";
3791 resourceFileName += ext;
3793 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3797 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3799 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath, modifiedIconPath.c_str()));
3802 bool copyFiles = (!copiedFileDetails.isEmpty());
3803 bool updatePaths = (!updatedPathDetails.isEmpty());
3805 const QString updateSummary =
"<p>" + tr(
"You're saving your composition to a different folder.") +
"</p>"
3809 ? tr(
"Do you want to copy the example files used by your composition?")
3811 : tr(
"Do you want to update the paths to files in your composition?"))
3814 QString updateDetails =
"";
3817 updateDetails += tr(
"The following file(s) will be copied",
"", modifiedPortConstantRelativePaths.size()) +
":\n\n" + copiedFileDetails +
"\n";
3821 updateDetails += tr(
"The following path(s) will be updated",
"", pathsToUpdate.size()) +
":\n\n" + updatedPathDetails;
3823 QMessageBox messageBox(
this);
3824 messageBox.setWindowFlags(Qt::Sheet);
3825 messageBox.setWindowModality(Qt::WindowModal);
3826 messageBox.setTextFormat(Qt::RichText);
3827 messageBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok);
3828 messageBox.setButtonText(QMessageBox::Discard, (copyFiles? tr(
"Leave files in place") : tr(
"Leave paths unchanged")));
3829 messageBox.setButtonText(QMessageBox::Ok, (copyFiles? tr(
"Copy files") : tr(
"Update paths")));
3830 messageBox.setDefaultButton(QMessageBox::Ok);
3831 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
3833 messageBox.setText(updateSummary);
3834 messageBox.setDetailedText(updateDetails);
3837 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Discard))->setAutoDefault(
false);
3838 messageBox.button(QMessageBox::Discard)->setFocus();
3840 if (messageBox.exec() == QMessageBox::Ok)
3845 bool tmpFilesOnly =
true;
3846 composition->
bundleResourceFiles(newCompositionDir.canonicalPath().toUtf8().constData(), tmpFilesOnly);
3851 undoStack->beginMacro(tr(
"File Path Updates"));
3854 for (map <VuoPort *, string>::iterator i = pathsToUpdate.begin(); i != pathsToUpdate.end(); ++i)
3857 string modifiedPath = i->second;
3860 setPortConstant(port->
getRenderer(), modifiedPath);
3865 if (iconPathChanged)
3870 metadataCopy->
setName(customizedCompositionName);
3877 undoStack->endMacro();
3882 return saveFile(savePath);
3885 string VuoEditorWindow::on_installSubcomposition_triggered()
3889 string nodeClassName = installSubcomposition(
"");
3892 oldTitle.toUtf8().data(),
3893 ui->installSubcomposition->text().toUtf8().data(),
3894 nodeClassName.c_str());
3896 if (!nodeClassName.empty())
3897 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
3899 return nodeClassName;
3906 string VuoEditorWindow::installSubcomposition(
string parentCompositionPath)
3908 string currentCompositionPath = windowFilePath().toUtf8().constData();
3911 QString operationTitle;
3912 string installedSubcompositionDir;
3913 if (parentCompositionPath.empty())
3915 if (currentCompositionExists)
3916 operationTitle = tr(
"Move Subcomposition to User Library");
3918 operationTitle = tr(
"Save Subcomposition to User Library");
3925 operationTitle = tr(
"Save Subcomposition to User Library");
3930 operationTitle = tr(
"Save Subcomposition to System Library");
3935 operationTitle = tr(
"Save Subcomposition to Composition-Local Library");
3941 string nodeClassName;
3951 QString defaultNodeCategory =
static_cast<VuoEditor *
>(qApp)->getDefaultSubcompositionPrefix();
3955 defaultNodeDisplayName);
3956 QString currentNodeCategory =
static_cast<VuoEditor *
>(qApp)->getSubcompositionPrefix();
3959 defaultNodeDisplayName, defaultNodeCategory,
3960 currentNodeDisplayName, currentNodeCategory);
3965 QString nodeDisplayName = d.nodeTitle();
3966 QString nodeCategory = d.nodeCategory();
3968 if (nodeCategory != currentNodeCategory)
3969 static_cast<VuoEditor *
>(qApp)->updateSubcompositionPrefix(nodeCategory);
3974 newMetadata->
setName(nodeDisplayName.toUtf8().constData());
3984 int documentIdentifierInstanceNum = 1;
3988 std::ostringstream oss;
3989 oss << ++documentIdentifierInstanceNum;
3993 bool saveSucceeded = saveFileAs(copiedCompositionPath.c_str());
3994 if (! saveSucceeded)
4009 if (compositionName.isEmpty())
4013 QString thirdPartyCategory = category.remove(QRegExp(
"^(vuo\\.?)+", Qt::CaseInsensitive));
4016 if (category.isEmpty())
4019 return category +
"." + compositionName;
4032 if (displayName.empty())
4037 CFStringRef cfs = CFStringCreateWithCString(NULL, displayName.c_str(), kCFStringEncodingUTF8);
4040 CFMutableStringRef cfsm = CFStringCreateMutableCopy(NULL, 0, cfs);
4041 CFStringTransform(cfsm, NULL, kCFStringTransformToLatin,
false);
4042 CFStringTransform(cfsm, NULL, kCFStringTransformStripCombiningMarks,
false);
4043 CFStringTransform(cfsm, NULL, kCFStringTransformStripDiacritics,
false);
4044 CFStringTransform(cfsm, NULL, CFSTR(
"ASCII"),
false);
4057 void VuoEditorWindow::editMetadata(
int dialogResult)
4059 if (dialogResult == QDialog::Accepted)
4066 string VuoEditorWindow::generateCurrentDefaultCopyright()
4068 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
4069 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
4070 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
4071 const string currentYear = QDate::currentDate().toString(
"yyyy").toUtf8().constData();
4073 const string copyright =
"Copyright © " + currentYear +
" " + userProfileLink;
4080 bool VuoEditorWindow::confirmReplacingFile(
string path)
4083 QFileInfo fileInfo(QString::fromStdString(path));
4084 QMessageBox d(
this);
4085 d.setWindowFlags(Qt::Sheet);
4086 d.setWindowModality(Qt::WindowModal);
4088 d.setTextFormat(Qt::RichText);
4089 d.setText(tr(
"<b>“%1” already exists. Do you want to replace it?</b>").arg(fileInfo.fileName()));
4091 + tr(
"<p>A %1 with the same name already exists in the “%2” folder.</p><p>Replacing it will overwrite its current contents.<br></p>")
4093 .arg(fileInfo.dir().dirName()));
4094 d.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
4095 d.setDefaultButton(QMessageBox::Cancel);
4096 d.setButtonText(QMessageBox::Yes, tr(
"Replace"));
4097 d.setIcon(QMessageBox::Warning);
4100 static_cast<QPushButton *
>(d.button(QMessageBox::Yes))->setAutoDefault(
false);
4101 d.button(QMessageBox::Yes)->setFocus();
4103 return d.exec() == QMessageBox::Yes;
4112 addDockWidget(Qt::TopDockWidgetArea, searchBox);
4113 searchBox->setFocus();
4123 if (!searchBox->isHidden())
4132 if (!searchBox->isHidden())
4142 bool VuoEditorWindow::saveFile(
const QString & savePath)
4148 bool saveAborted =
false;
4149 QString failureDetails =
"";
4150 QString modifiedSavePath = savePath;
4152 if (!savePath.endsWith(expectedFileExtension))
4154 modifiedSavePath.append(expectedFileExtension);
4158 failureDetails =
"A file or folder with the same name already exists.";
4162 QString existingPath = windowFilePath();
4163 bool saveSucceeded = !saveAborted && saveFile(modifiedSavePath, existingPath);
4172 setWindowFilePath(modifiedSavePath);
4174 toolbar->updateTitle();
4176 compositionUpgradedSinceLastSave =
false;
4177 undoStack->setClean();
4178 setCompositionModified(
false);
4181 string newDir, file, ext;
4184 if (compositionDirChanged)
4187 QStringList compositionLocalModules;
4188 for (
const string &dependency : compiler->getDependenciesForComposition(
getComposition()->getBase()->getCompiler()))
4190 compositionLocalModules.append(QString::fromStdString(dependency));
4192 if (! compositionLocalModules.empty())
4194 compositionLocalModules.sort();
4196 QString summary = QString(
"<p>You're saving your composition to a different folder.</p>")
4197 .append(
"<p>Where do you want to install the composition's local nodes?</p>");
4199 QString details = QString(
"The following nodes will be moved or copied:\n\n")
4200 .append(compositionLocalModules.join(
"\n"))
4203 QMessageBox messageBox(
this);
4204 messageBox.setWindowFlags(Qt::Sheet);
4205 messageBox.setWindowModality(Qt::WindowModal);
4206 messageBox.setTextFormat(Qt::RichText);
4207 messageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
4208 messageBox.setButtonText(QMessageBox::No,
"Move to User Library");
4209 messageBox.setButtonText(QMessageBox::Yes,
"Copy to new Composition Library");
4210 messageBox.setDefaultButton(QMessageBox::Yes);
4211 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
4213 messageBox.setText(summary);
4214 messageBox.setDetailedText(details);
4217 static_cast<QPushButton *
>(messageBox.button(QMessageBox::No))->setAutoDefault(
false);
4218 messageBox.button(QMessageBox::No)->setFocus();
4220 int ret = messageBox.exec();
4223 QDir oldModulesDir = QDir(QString::fromStdString(oldModulesDirPath));
4225 string newModulesDirPath = (ret == QMessageBox::Yes ?
4229 QDir newModulesDir(QString::fromStdString(newModulesDirPath));
4232 foreach (QString moduleFileName, oldModulesDir.entryList(QDir::Files))
4236 if (compositionLocalModules.contains(QString::fromStdString(moduleKey)))
4238 string oldModulePath = oldModulesDir.filePath(moduleFileName).toStdString();
4239 string newModulePath = newModulesDir.filePath(moduleFileName).toStdString();
4244 if (ret == QMessageBox::Yes)
4257 if (includeInRecentFileMenu)
4258 static_cast<VuoEditor *
>(qApp)->addFileToAllOpenRecentFileMenus(modifiedSavePath);
4263 if (failureDetails.isEmpty())
4264 failureDetails = strerror(error);
4266 QMessageBox fileSaveFailureDialog(
this);
4267 fileSaveFailureDialog.setWindowFlags(Qt::Sheet);
4268 fileSaveFailureDialog.setWindowModality(Qt::WindowModal);
4270 QString errorMessage = tr(
"The composition could not be saved at “%1”.").arg(modifiedSavePath);
4271 fileSaveFailureDialog.setText(tr(errorMessage.toUtf8().constData()));
4272 fileSaveFailureDialog.setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4273 fileSaveFailureDialog.setInformativeText(failureDetails);
4274 fileSaveFailureDialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
4275 fileSaveFailureDialog.setButtonText(QMessageBox::Save, tr(
"Save As…"));
4276 fileSaveFailureDialog.setIcon(QMessageBox::Warning);
4278 switch(fileSaveFailureDialog.exec()) {
4279 case QMessageBox::Save:
4280 on_saveCompositionAs_triggered();
4282 case QMessageBox::Cancel:
4289 return saveSucceeded;
4295 void VuoEditorWindow::populateProtocolsMenu(QMenu *m)
4299 QAction *protocolAction =
new QAction(
this);
4300 protocolAction->setText(VuoEditor::tr(protocol->
getName().c_str()));
4301 protocolAction->setData(qVariantFromValue(
static_cast<void *
>(protocol)));
4302 protocolAction->setCheckable(
true);
4303 connect(protocolAction, &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
4304 m->addAction(protocolAction);
4311 void VuoEditorWindow::updateProtocolsMenu(QMenu *m)
4313 foreach (QAction *protocolAction, m->actions())
4316 protocolAction->setChecked(composition->
getActiveProtocol() == currentProtocol);
4324 void VuoEditorWindow::changeActiveProtocol(
void)
4326 QAction *sender = (QAction *)QObject::sender();
4332 selectedProtocol->
getName().c_str());
4335 toggleActiveStatusForProtocol(selectedProtocol);
4337 setPublishedPortSidebarVisibility(
true);
4345 void VuoEditorWindow::toggleActiveStatusForProtocol(
VuoProtocol *protocol)
4356 void VuoEditorWindow::updateActiveProtocolDisplay(
void)
4367 void VuoEditorWindow::evaluateCompositionForProtocolPromotion()
4373 string compositionAsString = composition->
takeSnapshot();
4393 bool VuoEditorWindow::saveFile(
const QString & savePath, QString & existingPath)
4395 string existingCompositionFooter =
"";
4398 if (! existingPath.isEmpty())
4400 ifstream existingFile(existingPath.toUtf8().constData());
4403 bool graphvizStatementListEndFound =
false;
4404 for (
char c = existingFile.get(); existingFile.good(); c = existingFile.get())
4406 if (existingFile.good())
4410 existingCompositionFooter =
"";
4411 graphvizStatementListEndFound =
true;
4413 else if (graphvizStatementListEndFound)
4414 existingCompositionFooter += c;
4417 existingFile.close();
4428 existingCompositionFooter);
4430 string dir, file, ext;
4431 string finalSavePath = savePath.toUtf8().constData();
4442 mode_t currentUMask = umask(0);
4443 umask(currentUMask);
4445 chmod(tmpSavePath.c_str(), 0666 & ~currentUMask);
4448 ofstream savedFile(tmpSavePath.c_str(), ios::trunc);
4449 savedFile << outputComposition;
4456 bool saveSucceeded = ((! savedFile.fail()) && (! rename(tmpSavePath.c_str(), finalSavePath.c_str())));
4462 this->metadataPanel->
update();
4467 return saveSucceeded;
4473 void VuoEditorWindow::undoStackCleanStateChanged(
bool clean)
4477 setCompositionModified(
true);
4482 else if (clean && !compositionUpgradedSinceLastSave)
4483 setCompositionModified(
false);
4489 void VuoEditorWindow::setCompositionModified(
bool modified)
4491 setWindowModified(modified);
4505 composition->
run(snapshot);
4520 composition->
stop();
4543 void VuoEditorWindow::showBuildActivityIndicator()
4552 void VuoEditorWindow::hideBuildActivityIndicator(QString buildError)
4554 if (! buildError.isEmpty())
4558 updateRefireAction();
4560 QString details =
"";
4561 if (buildError.contains(
"Nodes not installed", Qt::CaseInsensitive))
4562 details =
"This composition contains nodes that aren't installed.";
4564 VuoErrorDialog::show(
this, tr(
"There was a problem running the composition."), details, buildError);
4570 updateRefireAction();
4577 void VuoEditorWindow::hideStopActivityIndicator()
4581 updateRefireAction();
4584 void VuoEditorWindow::on_openUserModulesFolder_triggered()
4589 void VuoEditorWindow::on_openSystemModulesFolder_triggered()
4608 void VuoEditorWindow::on_showPublishedPorts_triggered(
void)
4610 setPublishedPortSidebarVisibility(!arePublishedPortSidebarsVisible());
4620 if (!arePublishedPortSidebarsVisible())
4621 on_showPublishedPorts_triggered();
4627 bool VuoEditorWindow::arePublishedPortSidebarsVisible()
4629 return !inputPortSidebar->isHidden() && !outputPortSidebar->isHidden();
4635 void VuoEditorWindow::on_showHiddenCables_triggered(
void)
4638 if (!previouslyShowingHiddenCables)
4641 on_showPublishedPorts_triggered();
4652 void VuoEditorWindow::on_showEvents_triggered(
void)
4654 VUserLog(
"%s: %s Show Events mode",
4665 void VuoEditorWindow::closePublishedPortSidebars()
4667 setPublishedPortSidebarVisibility(
false);
4673 void VuoEditorWindow::conditionallyShowPublishedPortSidebars(
bool visible)
4676 setPublishedPortSidebarVisibility(
true);
4682 void VuoEditorWindow::setPublishedPortSidebarVisibility(
bool visible)
4690 if (nl && (! nl->isHidden()) && (! nl->isFloating()))
4691 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4694 addDockWidget(Qt::LeftDockWidgetArea, inputPortSidebar);
4696 addDockWidget(Qt::RightDockWidgetArea, outputPortSidebar);
4705 if (! nl->isFloating())
4707 nl->setMinimumWidth(nl->width());
4708 nl->setMaximumWidth(nl->minimumWidth());
4712 inputPortSidebar->setVisible(visible);
4713 outputPortSidebar->setVisible(visible);
4715 updatePublishedCableGeometry();
4719 if (!nl->isHidden() && !nl->isFloating())
4732 void VuoEditorWindow::updatePublishedCableGeometry()
4741 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
4743 cable->
getRenderer()->setCacheMode(defaultCacheMode);
4750 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
4751 ui->graphicsView->viewport()->update();
4759 void VuoEditorWindow::updatePublishedPortOrder(vector<VuoPublishedPort *> ports,
bool isInput)
4769 bool foundNonProtocolPort =
false;
4773 foundNonProtocolPort =
true;
4776 if (foundNonProtocolPort)
4788 void VuoEditorWindow::displayDockedNodeLibrary()
4790 addDockWidget(Qt::LeftDockWidgetArea, nl);
4792 bool publishedPortsDisplayed = (inputPortSidebar && (! inputPortSidebar->isHidden()));
4793 if (publishedPortsDisplayed)
4794 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4796 nl->setFloating(
false);
4797 nl->
fixWidth(publishedPortsDisplayed);
4809 inputPortSidebar->setMinimumWidth(inputPortSidebar->width());
4810 inputPortSidebar->setMaximumWidth(inputPortSidebar->minimumWidth());
4812 if (visibility == VuoNodeLibrary::nodeLibraryDocked)
4815 displayDockedNodeLibrary();
4819 else if (visibility == VuoNodeLibrary::nodeLibraryFloating)
4828 if (ownedNodeLibrary == floater)
4830 if (! nl->isFloating())
4832 nl->setFloating(
true);
4845 ownedNodeLibrary->setVisible(
false);
4851 else if (visibility == VuoNodeLibrary::nodeLibraryHidden)
4854 nl->setVisible(
false);
4870 bool compositionHasOtherCustomizedMetadata = (
4874 bool compositionHasBeenSaved = !windowFilePath().isEmpty();
4875 if (compositionHasCustomizedDescription || compositionHasCustomizedCopyright || compositionHasOtherCustomizedMetadata || compositionHasBeenSaved)
4877 dispatch_async(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{
4878 QMetaObject::invokeMethod(nl,
"displayPopoverInPane", Qt::QueuedConnection, Q_ARG(QWidget *, metadataPanel));
4899 if (inputEditorSession
4908 if (isWindowModified())
4910 auto mb =
new QMessageBox(
this);
4911 mb->setWindowFlags(Qt::Sheet);
4912 mb->setWindowModality(Qt::WindowModal);
4917 QString details = tr(
"Your changes will be lost if you don’t save them.");
4918 mb->setText(tr(message.toUtf8().constData()));
4919 mb->setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4920 mb->setInformativeText(tr(details.toUtf8().constData()));
4923 mb->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
4924 mb->setDefaultButton(QMessageBox::Save);
4927 static_cast<QPushButton *
>(mb->button(QMessageBox::Discard))->setAutoDefault(
false);
4928 mb->button(QMessageBox::Discard)->setFocus();
4930 if (windowFilePath().isEmpty())
4931 mb->setButtonText(QMessageBox::Save, tr(
"Save As…"));
4933 connect(mb, &QMessageBox::buttonClicked,
this, [=](QAbstractButton *button){
4934 auto editor =
static_cast<VuoEditor *
>(qApp);
4935 auto role = mb->buttonRole(button);
4936 if (role == QMessageBox::AcceptRole)
4938 on_saveComposition_triggered();
4939 if (isWindowModified())
4940 editor->cancelQuit();
4944 editor->continueQuit(
this);
4947 else if (role == QMessageBox::DestructiveRole)
4950 editor->continueQuit(
this);
4953 editor->cancelQuit();
4964 static_cast<VuoEditor *
>(qApp)->continueQuit(
this);
4971 void VuoEditorWindow::acceptCloseEvent()
4979 VuoEditorWindow::deleteLater();
4987 static_cast<VuoEditor *
>(qApp)->addFileToRecentlyClosedList(windowFilePath());
4994 void VuoEditorWindow::updateSelectedComponentMenuItems()
4996 string cutCommandText = tr(
"Cut").toStdString();
4997 string copyCommandText = tr(
"Copy").toStdString();
4998 string duplicateCommandText = tr(
"Duplicate").toStdString();
4999 string deleteCommandText = tr(
"Delete").toStdString();
5000 string resetCommandText = tr(
"Reset").toStdString();
5002 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
5004 int selectedNodesFound = 0;
5005 int selectedCablesFound = 0;
5006 int selectedListsFound = 0;
5007 int selectedCommentsFound = 0;
5009 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
5010 (! (selectedNodesFound && selectedCablesFound)) &&
5011 (i != selectedCompositionComponents.end());
5014 QGraphicsItem *compositionComponent = *i;
5022 selectedListsFound++;
5025 selectedNodesFound++;
5028 selectedCablesFound++;
5031 selectedCommentsFound++;
5034 int distinctComponentTypesFound = 0;
5035 if (selectedListsFound)
5036 distinctComponentTypesFound++;
5037 if (selectedNodesFound)
5038 distinctComponentTypesFound++;
5039 if (selectedCablesFound)
5040 distinctComponentTypesFound++;
5041 if (selectedCommentsFound)
5042 distinctComponentTypesFound++;
5044 if (selectedListsFound && (distinctComponentTypesFound == 1))
5046 string selectedListText =
"Selected List";
5047 string selectedListsText =
"Selected Lists";
5049 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5050 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5051 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5053 if (selectedListsFound > 1)
5055 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListsText).c_str()));
5060 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListText).c_str()));
5066 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5067 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5068 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5069 ui->deleteCompositionComponents->setText(tr(deleteCommandText.c_str()));
5073 bool enableSelectedComponentDeleteMenuItem = (!selectedCompositionComponents.isEmpty());
5074 bool enableSelectedComponentCutMenuItem = (!selectedCompositionComponents.isEmpty() &&
5075 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5076 bool enableSelectedComponentDuplicateMenuItem = ((selectedNodesFound || selectedCommentsFound) &&
5077 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5080 bool enableCopyMenuItem = (copyAppliesToNodeLibraryDocumentation || enableSelectedComponentDuplicateMenuItem);
5082 ui->cutCompositionComponents->setEnabled(enableSelectedComponentCutMenuItem);
5083 ui->copyCompositionComponents->setEnabled(enableCopyMenuItem);
5084 ui->duplicateCompositionComponents->setEnabled(enableSelectedComponentDuplicateMenuItem);
5085 ui->deleteCompositionComponents->setEnabled(enableSelectedComponentDeleteMenuItem);
5087 ui->renameNodes->setEnabled(selectedNodesFound);
5088 ui->refactor->setEnabled(selectedNodesFound || selectedCommentsFound);
5089 contextMenuTints->setEnabled(selectedNodesFound || selectedCommentsFound);
5096 void VuoEditorWindow::updateChangeNodeMenu()
5098 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
5100 int selectedNodesFound = 0;
5101 int selectedCommentsFound = 0;
5105 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
5106 (selectedNodesFound <= 1) && !selectedCommentsFound &&
5107 (i != selectedCompositionComponents.end());
5110 QGraphicsItem *compositionComponent = *i;
5119 selectedNodesFound++;
5123 selectedCommentsFound++;
5127 ui->menuEdit->removeAction(menuChangeNode->menuAction());
5129 bool menuChangeNodeDisplayed =
false;
5130 if ((selectedNodesFound == 1) && !selectedCommentsFound)
5133 if (!menuChangeNode->actions().isEmpty())
5135 ui->menuEdit->insertMenu(ui->refactor, menuChangeNode);
5136 menuChangeNode->setEnabled(
true);
5137 menuChangeNodeDisplayed =
true;
5142 ui->changeNodePlaceholder->setVisible(!menuChangeNodeDisplayed);
5151 const QString compositionIndicatorText =
"digraph";
5152 return (text.toCaseFolded().contains(compositionIndicatorText.toCaseFolded()));
5159 void VuoEditorWindow::ensureSceneRectContainsRegion(
const QList<QRectF> ®ion)
5169 bool regionContained =
true;
5170 QRectF sceneRect = composition->sceneRect();
5171 foreach (QRectF rect, region)
5173 if (!sceneRect.contains(rect))
5175 regionContained =
false;
5180 if (!regionContained)
5190 void VuoEditorWindow::updateSceneRect()
5199 const int horizontalMargin = 0.2 * ui->graphicsView->geometry().width();
5200 const int verticalMargin = 0.2 * ui->graphicsView->geometry().height();
5202 int horizontalScrollBarHeight = ui->graphicsView->horizontalScrollBar()->sizeHint().height();
5203 int verticalScrollBarWidth = ui->graphicsView->verticalScrollBar()->sizeHint().width();
5205 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
5206 QRectF itemsBoundingRect = composition->
internalItemsBoundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5207 QRectF viewportItemsUnionRect;
5211 if (viewportRect.left() <= itemsBoundingRect.left() && viewportRect.right() >= itemsBoundingRect.right())
5213 viewportItemsUnionRect.setLeft(viewportRect.left());
5214 viewportItemsUnionRect.setRight(viewportRect.right());
5219 else if (abs(viewportRect.left() - itemsBoundingRect.left()) > abs(itemsBoundingRect.right() - viewportRect.right()))
5221 viewportItemsUnionRect.setRight(itemsBoundingRect.right());
5222 viewportItemsUnionRect.setLeft(itemsBoundingRect.right() - max(itemsBoundingRect.width(), viewportRect.width()));
5229 viewportItemsUnionRect.setLeft(itemsBoundingRect.left());
5230 viewportItemsUnionRect.setRight(itemsBoundingRect.left() + max(itemsBoundingRect.width(), viewportRect.width()));
5235 if (viewportRect.top() <= itemsBoundingRect.top() && viewportRect.bottom() >= itemsBoundingRect.bottom())
5237 viewportItemsUnionRect.setTop(viewportRect.top());
5238 viewportItemsUnionRect.setBottom(viewportRect.bottom());
5243 else if (abs(viewportRect.top() - itemsBoundingRect.top()) > abs(itemsBoundingRect.bottom() - viewportRect.bottom()))
5245 viewportItemsUnionRect.setBottom(itemsBoundingRect.bottom());
5246 viewportItemsUnionRect.setTop(itemsBoundingRect.bottom() - max(itemsBoundingRect.height(), viewportRect.height()));
5253 viewportItemsUnionRect.setTop(itemsBoundingRect.top());
5254 viewportItemsUnionRect.setBottom(itemsBoundingRect.top() + max(itemsBoundingRect.height(), viewportRect.height()));
5257 int viewportItemsUnionRectAdjustedWidth = viewportItemsUnionRect.width();
5258 int viewportItemsUnionRectAdjustedHeight = viewportItemsUnionRect.height();
5260 if ((viewportItemsUnionRect.width() > viewportRect.width()) &&
5261 (viewportItemsUnionRect.width() <= viewportRect.width() + verticalScrollBarWidth))
5264 viewportItemsUnionRectAdjustedWidth = viewportRect.width() + verticalScrollBarWidth + 1;
5267 viewportItemsUnionRectAdjustedHeight -= horizontalScrollBarHeight;
5270 if ((viewportItemsUnionRect.height() > viewportRect.height()) &&
5271 (viewportItemsUnionRect.height() <= viewportRect.height() + horizontalScrollBarHeight))
5274 viewportItemsUnionRectAdjustedHeight = viewportRect.height() + horizontalScrollBarHeight + 1;
5277 viewportItemsUnionRectAdjustedWidth -= verticalScrollBarWidth;
5280 QRectF viewportItemsUnionRectAdjusted(viewportItemsUnionRect.topLeft().x(),
5281 viewportItemsUnionRect.topLeft().y(),
5282 viewportItemsUnionRectAdjustedWidth,
5283 viewportItemsUnionRectAdjustedHeight);
5287 if ((QApplication::mouseButtons() & Qt::LeftButton))
5288 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(composition->sceneRect());
5290 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(viewportRect);
5295 if (!cableBeingDragged)
5296 composition->setSceneRect(viewportItemsUnionRectAdjusted);
5299 if (cableBeingDragged)
5310 QRect inputPortSidebarRect = inputPortSidebar->geometry();
5311 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()+QPoint(1,0)));
5313 QRect outputPortSidebarRect = outputPortSidebar->geometry();
5314 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
5316 QRect viewportRectGlobal = ui->graphicsView->viewport()->geometry();
5317 viewportRectGlobal.moveTopLeft(ui->graphicsView->viewport()->parentWidget()->mapToGlobal(viewportRectGlobal.topLeft()));
5319 QRect noAutoscrollZone = QRect();
5320 if (!inputPortSidebar->isHidden())
5321 noAutoscrollZone |= inputPortSidebarRect;
5322 if (!outputPortSidebar->isHidden())
5323 noAutoscrollZone |= outputPortSidebarRect;
5324 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
5325 noAutoscrollZone |= viewportRectGlobal;
5327 QPoint cursorPosition = QCursor::pos();
5328 bool cursorWithinNoAutoscrollZone = noAutoscrollZone.contains(cursorPosition);
5329 bool cursorWithinNoAutoscrollZoneLeft = (cursorWithinNoAutoscrollZone &&
5330 ((cursorPosition.x() - noAutoscrollZone.left()) < (noAutoscrollZone.right() - cursorPosition.x())));
5334 bool autoscrollWouldBringSourceNodeCloser =
false;
5338 QRectF fixedNodeBoundingRect = fixedNode->
boundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5339 bool fixedNodeVisible = ((fixedNodeBoundingRect.left()+fixedNode->scenePos().x() >= viewportRect.left()) &&
5340 (fixedNodeBoundingRect.right()+fixedNode->scenePos().x() <= viewportRect.right()));
5342 autoscrollWouldBringSourceNodeCloser = (!fixedNodeVisible && (cursorWithinNoAutoscrollZoneLeft ==
5343 (fixedNodeBoundingRect.left()+fixedNode->scenePos().x() < viewportRect.left())));
5346 bool enableCableDragAutoscroll = (!cursorWithinNoAutoscrollZone || autoscrollWouldBringSourceNodeCloser);
5347 if (enableCableDragAutoscroll)
5349 ui->graphicsView->ensureVisible(cableFloatingEndpointSceneLoc.x(),
5350 cableFloatingEndpointSceneLoc.y(),
5352 VuoEditorWindow::compositionMargin);
5361 void VuoEditorWindow::updateRubberBandSelectionMode(QRect rubberBandRect, QPointF fromScenePoint, QPointF toScenePoint)
5363 bool rubberBandSelectionPreviouslyInProgress = this->rubberBandSelectionInProgress;
5364 bool rubberBandSelectionNowInProgress = !(rubberBandRect.isNull() && fromScenePoint.isNull() && toScenePoint.isNull());
5366 bool beginningRubberBandSelection = (!rubberBandSelectionPreviouslyInProgress && rubberBandSelectionNowInProgress);
5367 bool endingRubberBandSelection = (rubberBandSelectionPreviouslyInProgress && !rubberBandSelectionNowInProgress);
5369 if (beginningRubberBandSelection)
5377 if (!lastLeftMousePressHadOptionModifier)
5384 else if (endingRubberBandSelection)
5390 if (!lastLeftMousePressHadOptionModifier)
5398 this->rubberBandSelectionInProgress = rubberBandSelectionNowInProgress;
5404 void VuoEditorWindow::setPortConstant(
VuoRendererPort *port,
string value)
5419 showInputEditor(port,
true);
5425 void VuoEditorWindow::showInputEditor(
VuoRendererPort *port,
bool forwardTabTraversal)
5430 sidebar = (publishedPort->
getInput() ? outputPortSidebar : inputPortSidebar);
5433 map<VuoRendererPort *, pair<string, string> > originalAndFinalValueForPort = inputEditorSession->
execute(port, forwardTabTraversal);
5435 delete inputEditorSession;
5436 inputEditorSession =
nullptr;
5438 bool startedUndoStackMacro =
false;
5439 for (
auto i : originalAndFinalValueForPort)
5442 string originalEditingSessionValue = i.second.first;
5443 string finalEditingSessionValue = i.second.second;
5447 if (finalEditingSessionValue != originalEditingSessionValue)
5456 if (!startedUndoStackMacro)
5458 undoStack->beginMacro(tr(
"Set Port Constant"));
5459 startedUndoStackMacro =
true;
5479 if (startedUndoStackMacro)
5480 undoStack->endMacro();
5499 QPoint nodeTitleRightCenterInView = ui->graphicsView->mapFromScene(nodeTitleRightCenterInScene);
5500 QPoint nodeTitleRightCenterGlobal = ui->graphicsView->mapToGlobal(nodeTitleRightCenterInView);
5504 int scaledWidth = ui->graphicsView->transform().m11() * nodeWidth;
5505 titleEditor->
setWidth(scaledWidth);
5509 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5511 json_object *originalValueAsJson = json_object_new_string(originalValue.c_str());
5512 json_object *newValueAsJson = titleEditor->
show(nodeTitleRightCenterGlobal, originalValueAsJson, details);
5513 string newValue = json_object_get_string(newValueAsJson);
5514 json_object_put(originalValueAsJson);
5515 json_object_put(newValueAsJson);
5521 if (newValue != originalValue)
5536 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5538 json_object *originalTextAsJson = json_tokener_parse(originalText.c_str());
5544 int scaledWidth = ui->graphicsView->transform().m11() * commentWidth;
5545 commentEditor->
setWidth(scaledWidth);
5549 int scaledHeight = ui->graphicsView->transform().m11() * commentHeight;
5554 QPointF commentTextRightCenterInScene = comment->scenePos() + commentBoundingRect.topRight() + QPointF(0, commentBoundingRect.height()/2.0);
5555 QPoint commentTextRightCenterInView = ui->graphicsView->mapFromScene(commentTextRightCenterInScene);
5556 QPoint commentTextRightCenterGlobal = ui->graphicsView->mapToGlobal(commentTextRightCenterInView);
5558 json_object *newTextAsJson = commentEditor->
show(commentTextRightCenterGlobal, originalTextAsJson, details);
5560 string newText = json_object_to_json_string_ext(newTextAsJson, JSON_C_TO_STRING_PLAIN);
5561 json_object_put(originalTextAsJson);
5562 json_object_put(newTextAsJson);
5564 if (newText != originalText)
5573 comment->setSelected(
true);
5599 void VuoEditorWindow::openEditableSourceForNode(
VuoRendererNode *node)
5606 if (originalGenericNodeClass)
5607 nodeClass = originalGenericNodeClass->
getBase();
5610 QString actionText, sourcePath;
5617 QMainWindow *window =
static_cast<VuoEditor *
>(qApp)->openFileWithName(sourcePath,
false);
5621 if (compositionWindow)
5627 static_cast<VuoEditor *
>(qApp)->openUrl(
"file://" + sourcePath);
5636 this->includeInRecentFileMenu = include;
5643 void VuoEditorWindow::on_insertComment_triggered()
5651 void VuoEditorWindow::insertCommentAtPos(QPointF targetScenePos)
5663 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5664 componentsToAdd.append(comment);
5665 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Comment"));
5668 showCommentEditor(comment);
5674 void VuoEditorWindow::on_insertSubcomposition_triggered()
5687 bool VuoEditorWindow::ensureThisParentCompositionSaved()
5691 QMessageBox messageBox(
this);
5692 messageBox.setWindowFlags(Qt::Sheet);
5693 messageBox.setWindowModality(Qt::WindowModal);
5694 messageBox.setStandardButtons(QMessageBox::Cancel | QMessageBox::Save);
5695 messageBox.setDefaultButton(QMessageBox::Save);
5696 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
5698 messageBox.setText(tr(
"Save before packaging"));
5699 messageBox.setInformativeText(tr(
"Please save this composition so Vuo knows where to save your new subcomposition."));
5700 messageBox.setButtonText(QMessageBox::Save, tr(
"Save As…"));
5703 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Cancel))->setAutoDefault(
false);
5704 messageBox.button(QMessageBox::Cancel)->setFocus();
5707 if (messageBox.exec() != QMessageBox::Save)
5711 on_saveCompositionAs_triggered();
5720 void VuoEditorWindow::insertSubcompositionAtPos(QPointF targetScenePos)
5726 if (!ensureThisParentCompositionSaved())
5732 string subcompositionContent =
"digraph G {}";
5733 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent);
5734 if (!subcompositionWindow)
5743 string nodeClassName = subcompositionWindow->installSubcomposition(windowFilePath().toUtf8().constData());
5744 if (!nodeClassName.empty())
5750 targetScenePos.y());
5751 if (!subcompositionNode)
5757 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5759 subcompositionNode);
5762 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5763 componentsToAdd.append(subcompositionNode);
5764 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Subcomposition"));
5776 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
5786 void VuoEditorWindow::refactorSelectedItems()
5792 if (!ensureThisParentCompositionSaved())
5798 string subcompositionContent = getMaximumSubcompositionFromSelection(
false,
false);
5800 QPoint selectedItemsAvgPos = QPoint(0,0);
5801 int selectedItemCount = 0;
5803 set<string> portsToPublish;
5804 __block map<int, string> inputCablesToRestoreFromPort;
5805 __block map<int, string> inputCablesToRestoreToPort;
5806 __block map<int, bool> inputCablesToRestoreEventOnly;
5807 __block map<int, string> outputCablesToRestoreFromPort;
5808 __block map<int, string> outputCablesToRestoreToPort;
5809 __block map<int, bool> outputCablesToRestoreEventOnly;
5811 QList<QGraphicsItem *> selectedItems = composition->selectedItems();
5812 foreach (QGraphicsItem *item, selectedItems)
5823 foreach (
VuoCable *cable, incomingCables)
5831 int cableNum = inputCablesToRestoreEventOnly.size();
5846 bool typecastHasInternalInput =
false;
5847 bool typecastHasExternalInput =
false;
5848 foreach (
VuoCable *typecastInCable, incomingCables)
5852 typecastHasInternalInput =
true;
5854 typecastHasExternalInput =
true;
5860 if (!typecastHasInternalInput)
5863 VuoPort *typecastHostPort = port;
5867 int cableNum = inputCablesToRestoreEventOnly.size();
5870 inputCablesToRestoreEventOnly[cableNum] =
false;
5877 else if (typecastHasExternalInput && typecastHasInternalInput)
5881 foreach (
VuoCable *typecastInCable, incomingCables)
5887 int cableNum = inputCablesToRestoreEventOnly.size();
5890 inputCablesToRestoreEventOnly[cableNum] =
false;
5911 bool connectedTypecastIsExternal =
false;
5918 connectedTypecastIsExternal = ((outCables.size() < 1) || !outCables[0]->getToNode() ||
5919 !outCables[0]->getToNode()->hasRenderer() ||
5920 !outCables[0]->getToNode()->getRenderer()->isSelected());
5921 if (connectedTypecastIsExternal)
5929 int cableNum = outputCablesToRestoreEventOnly.size();
5937 selectedItemsAvgPos += item->scenePos().toPoint();
5938 selectedItemCount++;
5943 selectedItemsAvgPos += item->scenePos().toPoint();
5944 selectedItemCount++;
5948 selectedItemsAvgPos /= selectedItemCount;
5950 string parentCompositionPath = windowFilePath().toStdString();
5953 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent, subcompositionDir);
5959 string nodeClassName = subcompositionWindow->installSubcomposition(parentCompositionPath);
5960 if (!nodeClassName.empty())
5965 selectedItemsAvgPos.x(),
5966 selectedItemsAvgPos.y());
5967 if (!subcompositionNode)
5974 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5976 subcompositionNode);
5978 undoStack->beginMacro(tr(
"Package as Subcomposition"));
5981 QList<QGraphicsItem *> itemsToRemove;
5983 itemsToRemove.append(node);
5985 itemsToRemove.append(comment);
5987 undoStack->push(
new VuoCommandRemove(itemsToRemove,
this, inputEditorManager,
"Package as Subcomposition",
true));
5990 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5991 componentsToAdd.append(subcompositionNode);
5992 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"",
true));
5995 QList<QGraphicsItem *> inputCablesToRestore;
5996 for (
int i = 0; i < inputCablesToRestoreEventOnly.size(); ++i)
6003 if (fromNode && fromPort && toNode && toPort &&
6015 inputCablesToRestore.append(cable);
6023 inputCablesToRestoreEventOnly[i],
6024 inputCablesToRestoreFromPort[i],
6031 QList<QGraphicsItem *> outputCablesToRestore;
6032 for (
int i = 0; i < outputCablesToRestoreEventOnly.size(); ++i)
6039 if (fromNode && fromPort && toNode && toPort &&
6051 outputCablesToRestore.append(cable);
6059 outputCablesToRestoreEventOnly[i],
6060 outputCablesToRestoreToPort[i],
6067 undoStack->push(
new VuoCommandAdd(inputCablesToRestore,
this));
6068 undoStack->push(
new VuoCommandAdd(outputCablesToRestore,
this));
6072 string compositionIdentifier =
static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->getCompositionIdentifier(composition);
6074 set<VuoCompilerNode *> nodesMoved;
6075 for (QGraphicsItem *item : itemsToRemove)
6084 string compositionSnapshot = composition->
takeSnapshot();
6087 diffInfo->
addRefactoring(compositionIdentifier, nodesMoved, subcompositionMovedTo);
6091 undoStack->endMacro();
6104 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
6123 return raiseDocumentAction;
6131 return ui->showEvents;
6155 return ui->zoomToFit;
6193 return ownedNodeLibrary;
6212 transitionNodeLibraryConnections(this->nl, library);
6222 transitionNodeLibraryConnections((previousFloaterDestroyed? NULL : this->nl), this->ownedNodeLibrary);
6223 this->nl = this->ownedNodeLibrary;
6231 return ui->menuFile;
6239 return menuOpenRecent;
6264 disconnect(oldLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6265 disconnect(oldLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6268 disconnect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), oldLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6283 connect(newLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6284 connect(newLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6287 connect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), newLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6303 void VuoEditorWindow::restoreDefaultLeftDockedWidgetWidths()
6307 nl->setMinimumWidth(nodeLibraryMinimumWidth);
6308 nl->setMaximumWidth(nodeLibraryMaximumWidth);
6311 if (inputPortSidebar && outputPortSidebar)
6313 inputPortSidebar->setMinimumWidth(outputPortSidebar->minimumWidth());
6314 inputPortSidebar->setMaximumWidth(outputPortSidebar->maximumWidth());
6324 QPoint positionChange =
event->pos() -
event->oldPos();
6325 composition->
movePopoversBy(positionChange.x(), positionChange.y());
6327 QMainWindow::moveEvent(
event);
6338 toolbar->updateTitle();
6341 QMainWindow::resizeEvent(
event);
6349 QList<QGraphicsItem *> VuoEditorWindow::createAnyNecessaryMakeListComponents(
VuoPort *port)
6351 QList<QGraphicsItem *> makeListComponents;
6360 makeListComponents.append(makeListNode);
6361 makeListComponents.append(makeListCable);
6364 return makeListComponents;
6370 void VuoEditorWindow::updateGrid()
6372 QGraphicsView::CacheMode defaultViewportCacheMode = ui->graphicsView->cacheMode();
6374 ui->graphicsView->setCacheMode(QGraphicsView::CacheNone);
6375 ui->graphicsView->viewport()->update();
6377 ui->graphicsView->setCacheMode(defaultViewportCacheMode);
6383 void VuoEditorWindow::updateCanvasOpacity()
6385 int opacity =
static_cast<VuoEditor *
>(qApp)->getCanvasOpacity();
6392 void VuoEditorWindow::updateColor(
bool isDark)
6395 QString backgroundColor = colors->
canvasFill().name();
6396 QString scrollBarColor = isDark ?
"#505050" :
"#dfdfdf";
6397 QString dockwidgetTitleBackgroundColor = isDark ?
"#919191" :
"#efefef";
6399 QFile f(
":/Vuo.qss");
6400 f.open(QFile::ReadOnly | QFile::Text);
6402 QString styles = ts.readAll();
6406 QFile f(
":/pro/VuoDark.qss");
6407 f.open(QFile::ReadOnly | QFile::Text);
6409 styles += ts.readAll();
6412 if (doneInitializing)
6413 setStyleSheet(VUO_QSTRINGIFY(
6414 QMainWindow::separator {
6415 background-color: %1;
6422 .arg(dockwidgetTitleBackgroundColor)
6426 ui->graphicsView->setStyleSheet(styles);
6428 ui->graphicsView->setStyleSheet(VUO_QSTRINGIFY(
6434 QScrollBar::handle {
6441 QAbstractScrollArea::corner,
6443 QScrollBar::sub-line,
6445 QScrollBar::sub-page {
6450 .arg(backgroundColor)
6451 .arg(scrollBarColor)
6455 if (doneInitializing)
6467 void VuoEditorWindow::coalescedUpdateRunningComposition()
6469 if (coalescedOldCompositionSnapshot.empty() != coalescedNewCompositionSnapshot.empty())
6472 foreach (
string nodeID, coalescedNodesToUnlink)
6473 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->unlinkNodeInSupercompositionFromSubcomposition(composition, nodeID);
6475 if (!coalescedOldCompositionSnapshot.empty() && !coalescedNewCompositionSnapshot.empty())
6476 composition->
updateRunningComposition(coalescedOldCompositionSnapshot, coalescedNewCompositionSnapshot, coalescedDiffInfo);
6478 foreach (
string portID, coalescedInternalPortConstantsToSync)
6481 foreach (
string portID, coalescedPublishedPortConstantsToSync)
6484 foreach (
string nodeID, coalescedNodesToRelink)
6485 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->relinkNodeInSupercompositionToSubcomposition(composition, nodeID);
6487 coalescedOldCompositionSnapshot =
"";
6488 coalescedNewCompositionSnapshot =
"";
6489 coalescedInternalPortConstantsToSync.clear();
6490 coalescedPublishedPortConstantsToSync.clear();
6491 coalescedNodesToUnlink.clear();
6492 coalescedNodesToRelink.clear();
6493 coalescedDiffInfo =
nullptr;
6502 if (diffInfo && coalescedDiffInfo)
6503 coalescedUpdateRunningComposition();
6505 if (coalescedOldCompositionSnapshot.empty())
6506 coalescedOldCompositionSnapshot = oldCompositionSnapshot;
6508 coalescedNewCompositionSnapshot = newCompositionSnapshot;
6509 coalescedDiffInfo = diffInfo;
6517 coalescedInternalPortConstantsToSync.push_back(portID);
6525 coalescedPublishedPortConstantsToSync.push_back(portID);
6533 coalescedNodesToUnlink.push_back(nodeID);
6541 coalescedNodesToRelink.push_back(nodeID);
6549 void VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests()
6551 if (protocolComplianceReevaluationPending)
6553 evaluateCompositionForProtocolPromotion();
6554 protocolComplianceReevaluationPending =
false;
6566 void VuoEditorWindow::registerProtocolComplianceEvaluationRequest()
6568 this->protocolComplianceReevaluationPending =
true;
6576 return ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(QCursor::pos()));
6584 return metadataPanel;
6598 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
6599 double targetX = min(max(origPos.x(), viewportRect.left()+leftMargin), viewportRect.right()-rightMargin);
6600 double targetY = min(max(origPos.y(), viewportRect.top()+topMargin), viewportRect.bottom()-bottomMargin);
6603 bool targetPositionClearOfCoincidentNodes =
false;
6604 while (!targetPositionClearOfCoincidentNodes)
6606 QGraphicsItem *preexistingItem = composition->itemAt(QPoint(targetX, targetY), composition->views()[0]->transform());
6607 if (
dynamic_cast<VuoRendererNode *
>(preexistingItem) && (preexistingItem->scenePos() == QPoint(targetX, targetY)))
6609 targetX += pastedComponentOffset;
6610 targetY += pastedComponentOffset;
6613 targetPositionClearOfCoincidentNodes =
true;
6616 return QPointF(targetX, targetY);
6622 void VuoEditorWindow::toggleNodeLibraryDockedState()
6626 bool floatLibrary = !nl->isFloating();
6627 nl->setFloating(floatLibrary);
6628 nl->
fixWidth(!floatLibrary && !inputPortSidebar->isHidden());
6638 undoStack->beginMacro(tr(commandName.toUtf8().constData()));
6646 undoStack->endMacro();