11 #include "ui_VuoEditorWindow.h"
86 #include <objc/objc-runtime.h>
87 #undef check // Prevent macro defined in AssertMacros.h from overriding VuoCompilerComposition::check
95 const qreal VuoEditorWindow::viewportStepRate = 1;
96 const qreal VuoEditorWindow::viewportStepRateMultiplier = 5;
97 const qreal VuoEditorWindow::zoomRate = 1.2;
98 const qreal VuoEditorWindow::pastedComponentOffset = 20;
99 const qreal VuoEditorWindow::compositionMargin = 20;
113 const string &compositionAsString,
118 string nodeClassToHighlight) :
121 doneInitializing =
false;
124 this->compiler =
new VuoCompiler(compositionPath.toStdString());
126 this->compositionUpgradedSinceLastSave =
false;
127 this->protocolComplianceReevaluationPending =
false;
128 this->ignoreItemMoveSignals =
false;
129 this->closing =
false;
130 this->containedPrepopulatedContent = (!compositionAsString.empty() || activeProtocol);
131 this->publishedPortNearCursorPreviously =
false;
132 this->zoomOutToFitOnNextShowEvent = nodeClassToHighlight.empty();
133 this->includeInRecentFileMenu =
true;
147 ui->newComposition->setShortcut(QKeySequence(
"Ctrl+N"));
148 ui->openComposition->setShortcut(QKeySequence(
"Ctrl+O"));
149 ui->saveComposition->setShortcut(QKeySequence(
"Ctrl+S"));
150 ui->saveCompositionAs->setShortcut(QKeySequence(
"Ctrl+Shift+S"));
151 ui->closeComposition->setShortcut(QKeySequence(
"Ctrl+W"));
152 ui->selectAll->setShortcut(QKeySequence(
"Ctrl+A"));
153 ui->selectNone->setShortcut(QKeySequence(
"Ctrl+Shift+A"));
154 ui->cutCompositionComponents->setShortcut(QKeySequence(
"Ctrl+X"));
155 ui->copyCompositionComponents->setShortcut(QKeySequence(
"Ctrl+C"));
156 ui->duplicateCompositionComponents->setShortcut(QKeySequence(
"Ctrl+D"));
157 ui->paste->setShortcut(QKeySequence(
"Ctrl+V"));
158 ui->deleteCompositionComponents->setShortcut(QKeySequence(
"Backspace"));
159 ui->zoomIn->setShortcut(QKeySequence(
"Ctrl+="));
160 ui->zoomOut->setShortcut(QKeySequence(
"Ctrl+-"));
161 ui->zoom11->setShortcut(QKeySequence(
"Ctrl+0"));
162 isZoomedToFit =
false;
163 addAction(ui->stopComposition);
164 ui->showNodeLibrary->setShortcut(QKeySequence(
"Ctrl+Return"));
179 ui->menuView->addSeparator();
183 ui->menuView->addAction(editor->darkInterfaceAction);
190 QMenu *menuGrid =
new QMenu(ui->menuBar);
191 menuGrid->setSeparatorsCollapsible(
false);
192 menuGrid->setTitle(tr(
"&Grid"));
195 menuGrid->addSeparator();
201 ui->menuView->addMenu(menuGrid);
204 QMenu *menuCanvasTransparency =
new QMenu(ui->menuBar);
205 menuCanvasTransparency->setSeparatorsCollapsible(
false);
206 menuCanvasTransparency->setTitle(tr(
"&Canvas Transparency"));
207 ((
VuoEditor *)qApp)->populateCanvasTransparencyMenu(menuCanvasTransparency);
210 ui->menuView->addMenu(menuCanvasTransparency);
213 menuNewCompositionWithTemplate =
new QMenu(tr(
"New Composition from Template"));
214 menuNewCompositionWithTemplate->setSeparatorsCollapsible(
false);
215 ((
VuoEditor *)qApp)->populateNewCompositionWithTemplateMenu(menuNewCompositionWithTemplate);
218 QMenu *menuNewShader =
new QMenu(tr(
"New Shader"));
219 menuNewShader->setSeparatorsCollapsible(
false);
220 ((
VuoEditor *)qApp)->populateNewShaderMenu(menuNewShader);
223 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
225 if (ui->menuFile->actions().at(menuFileIndex) == ui->newComposition)
227 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuNewCompositionWithTemplate);
228 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuNewShader);
241 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
242 if (ui->menuFile->actions().at(menuFileIndex) == ui->openComposition)
244 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuOpenRecent);
245 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuOpenExample);
253 menuProtocols =
new QMenu(tr(
"Protocols"));
254 menuProtocols->setSeparatorsCollapsible(
false);
255 populateProtocolsMenu(menuProtocols);
258 ui->menuEdit->insertMenu(ui->compositionInformation, menuProtocols);
261 ((
VuoEditor *)qApp)->populateHelpMenu(ui->menuHelp);
267 connect(ui->menuHelp, &QMenu::aboutToShow, [editor,
this] { editor->populateHelpMenu(ui->menuHelp); });
280 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->addComposition(
this);
282 if (!compositionAsString.empty())
284 string dir, file, extension;
294 ui->graphicsView->setScene(composition);
295 ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
296 ui->graphicsView->setMouseTracking(
true);
297 composition->installEventFilter(
this);
298 ui->graphicsView->viewport()->installEventFilter(
this);
302 connect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
306 connect(ui->refactor, &QAction::triggered,
this, &VuoEditorWindow::refactorSelectedItems);
311 raiseDocumentAction =
new QAction(
this);
312 raiseDocumentAction->setCheckable(
true);
319 inputEditorSession =
nullptr;
334 undoStack =
new QUndoStack(
this);
335 connect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
337 undoAction = undoStack->createUndoAction(
this);
338 undoAction->setText(tr(
"Undo"));
339 undoAction->setShortcut(QKeySequence::Undo);
341 redoAction = undoStack->createRedoAction(
this);
342 redoAction->setText(tr(
"Redo"));
343 redoAction->setShortcut(QKeySequence::Redo);
346 metadataEditor->setWindowModality(Qt::WindowModal);
347 connect(metadataEditor, &VuoMetadataEditor::finished,
this, &VuoEditorWindow::editMetadata);
349 searchBox =
new VuoSearchBox(composition,
this, Qt::Widget);
350 searchBox->setVisible(
false);
353 canvasDragEnabled =
false;
354 canvasDragInProgress =
false;
355 scrollInProgress =
false;
356 timeOfLastScroll = 0;
357 consumeNextMouseReleaseToCanvas =
false;
358 lastLeftMousePressHadOptionModifier =
false;
359 rubberBandSelectionInProgress =
false;
360 previousDragMoveWasOverSidebar =
false;
361 duplicationMacroInProgress =
false;
362 itemDragMacroInProgress =
false;
366 commentResizeMacroInProgress =
false;
367 commentBeingResized = NULL;
370 forwardingEventsToCanvas =
false;
372 ui->menuEdit->insertAction(ui->menuEdit->actions()[0], redoAction);
373 ui->menuEdit->insertAction(redoAction, undoAction);
376 ui->menuEdit->insertMenu(ui->changeNodePlaceholder, contextMenuTints);
378 menuChangeNode =
new QMenu(ui->menuEdit);
379 menuChangeNode->setTitle(tr(
"Change To"));
383 foreach (QMenu *menu, ui->menuBar->findChildren<QMenu*>())
384 menu->setSeparatorsCollapsible(
false);
430 setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
431 setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
433 connect(ui->toggleNodeLibraryDocking, &QAction::triggered,
this, &VuoEditorWindow::toggleNodeLibraryDockedState);
435 QActionGroup* toggleDisplay=
new QActionGroup(
this);
436 toggleDisplay->addAction(ui->actionShowNodeNames);
437 toggleDisplay->addAction(ui->actionShowNodeClassNames);
442 inputPortSidebar->setVisible(
false);
443 outputPortSidebar->setVisible(
false);
447 connect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
448 connect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
453 connect(inputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
454 connect(outputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
464 connect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
465 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
466 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
467 connect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
468 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
469 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
470 connect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
472 connect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
473 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
478 connect(composition, SIGNAL(portPublicationRequested(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
483 connect(composition, SIGNAL(publishedPortModified()), inputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
484 connect(composition, SIGNAL(publishedPortModified()), outputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
491 connect(inputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
492 connect(outputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
511 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
512 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
513 connect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
514 connect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
516 connect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()), Qt::QueuedConnection);
519 VuoEditorWindow_Pro();
522 coalescedOldCompositionSnapshot =
"";
523 coalescedNewCompositionSnapshot =
"";
524 coalescedDiffInfo =
nullptr;
532 initializeNodeLibrary(this->compiler, nodeLibraryDisplayMode, nodeLibraryState, floater);
538 connect(composition, &VuoEditorComposition::changed,
this, &VuoEditorWindow::ensureSceneRectContainsRegion);
541 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::updateSelectedComponentMenuItems);
550 ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
552 ui->graphicsView->setAttribute(Qt::WA_NoBackground,
true);
553 ui->graphicsView->setAttribute(Qt::WA_OpaquePaintEvent);
554 ui->graphicsView->setAttribute(Qt::WA_NoSystemBackground);
558 nl->setAttribute(Qt::WA_NoBackground,
true);
559 nl->setAttribute(Qt::WA_OpaquePaintEvent);
560 nl->setAttribute(Qt::WA_NoSystemBackground);
567 if (compositionAsString.empty())
583 if (compositionAsString.empty())
594 evaluateCompositionForProtocolPromotion();
603 setPublishedPortSidebarVisibility(displayPublishedPorts);
608 doneInitializing =
true;
610 updateCanvasOpacity();
612 string dir, file, ext;
618 setWindowTitle(documentIdentifier +
"[*]");
620 toolbar->updateTitle();
630 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
631 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
632 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
640 setWindowFilePath(documentIdentifier);
652 if (!nodeClassToHighlight.empty())
656 updateRefireAction();
659 QMetaObject::invokeMethod(
this,
"showUpdateHelpDialog", Qt::QueuedConnection);
662 VuoEditorWindow::~VuoEditorWindow()
666 disconnect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
667 disconnect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
680 disconnect(ui->graphicsView, SIGNAL(viewResized()), outputPortSidebar, SLOT(externalMoveEvent()));
682 disconnect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
683 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
684 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
685 disconnect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
686 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
687 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
688 disconnect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
699 disconnect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
706 disconnect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
708 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
709 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
710 disconnect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
711 disconnect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
712 disconnect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()));
714 disconnect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
715 disconnect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
721 transitionNodeLibraryConnections(nl, NULL);
725 delete metadataPanel;
731 map<string, string> constantPortIdentifiersAndValues;
732 string revertedSourceCode;
737 catch (std::exception
const &e)
747 for (
VuoPort *port : node->getInputPorts())
749 if (port->hasCompiler())
760 delete revertedComposition;
765 topLevelComposition->getModuleManager()->doNextTimeNodeClassIsLoaded(nodeClassName, ^{
767 for (
auto i : constantPortIdentifiersAndValues)
768 topLevelComposition->updateInternalPortConstantInSubcompositionInstances(subcompositionPath, i.first, i.second);
777 composition->deleteLater();
783 id nsView = (id)winId();
784 id nsWindow = objc_msgSend(nsView, sel_getUid(
"window"));
785 objc_msgSend(nsWindow, sel_getUid(
"close"));
792 dispatch_sync(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{});
799 void VuoEditorWindow::showUpdateHelpDialog()
803 bool foundCommunityNode =
false;
808 foundCommunityNode =
true;
813 if (foundCommunityNode)
815 QString summary = tr(
"This composition was created in an earlier version of Vuo. It might behave differently now.");
816 QString details = tr(
"<p><a href=\"%1\">How do I update my compositions from Vuo 1.x to Vuo 2.0?</a></p>")
817 .arg(
"https://vuo.org/node/2376");
818 QString checkboxLabel = tr(
"Show this window when opening compositions.");
819 QString settingsKey =
"showUpdateHelp";
831 updateSelectedComponentMenuItems();
832 updateToolbarElementUI();
835 ui->compositionInformation->setEnabled(
true);
840 ui->stopComposition->setEnabled(
false);
841 ui->restartComposition->setEnabled(
false);
845 ui->runComposition->setEnabled(
false);
846 ui->stopComposition->setEnabled(
true);
847 ui->restartComposition->setEnabled(
true);
849 else if (toolbar && toolbar->
isRunning())
851 ui->runComposition->setEnabled(
false);
852 ui->stopComposition->setEnabled(
true);
853 ui->restartComposition->setEnabled(
true);
857 ui->runComposition->setEnabled(
true);
858 ui->stopComposition->setEnabled(
false);
859 ui->restartComposition->setEnabled(
false);
868 auto found = std::find_if(openWindows.begin(), openWindows.end(), [](
VuoEditorWindow *w){ return w->metadataEditor->isVisible(); });
869 bool isCompositionInformationOpen = (found != openWindows.end());
870 quitAction->setEnabled(! isCompositionInformationOpen);
873 QString savedPath = windowFilePath();
874 string savedDir, savedFile, savedExt;
878 ui->saveComposition->setEnabled(enableSaveMenuItem);
881 bool hasErrors =
true;
882 if (! alreadyInstalledAsUserSubcomposition)
893 ui->saveComposition->setText(tr(
"Save"));
894 ui->saveCompositionAs->setText(tr(
"Save As…"));
895 ui->installSubcomposition->setEnabled(!alreadyInstalledAsUserSubcomposition && !hasErrors);
897 tr(
"Move to User Library") :
898 tr(
"Save to User Library"));
901 updateProtocolsMenu(menuProtocols);
908 ui->actionShowNodeNames->setChecked(
true);
910 ui->actionShowNodeClassNames->setChecked(
true);
912 ui->toggleNodeLibraryDocking->setEnabled(!nl->isHidden());
913 ui->toggleNodeLibraryDocking->setText(nl->isFloating() ? tr(
"Attach to Editor Window") : tr(
"Detach from Editor Window"));
916 if (inputPortSidebar && outputPortSidebar)
918 bool publishedPortSidebarsDisplayed = (! inputPortSidebar->isHidden());
919 ui->showPublishedPorts->setText(publishedPortSidebarsDisplayed ? tr(
"Hide Published Ports") : tr(
"Show Published Ports"));
920 ui->graphicsView->setVerticalScrollBarPolicy(publishedPortSidebarsDisplayed? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
924 ui->findNext->setEnabled(displaySearchTraversalOptions);
925 ui->findPrevious->setEnabled(displaySearchTraversalOptions);
928 undoAction->setEnabled(!cableDragInProgress && undoStack->canUndo());
929 redoAction->setEnabled(!cableDragInProgress && undoStack->canRedo());
932 if (!showingHiddenCables)
934 ui->showHiddenCables->setText(tr(
"Show Hidden Cables"));
942 ui->showHiddenCables->setText(tr(
"Hide Hidden Cables"));
946 ui->showHiddenCables->setEnabled(
true);
952 ui->exportMovie->setEnabled(
false);
953 ui->exportMacScreenSaver->setEnabled(
false);
954 ui->exportMacFFGL->setEnabled(
false);
955 ui->exportFxPlug->setEnabled(
false);
962 ui->menuWindow->clear();
963 static_cast<VuoEditor *
>(qApp)->populateWindowMenu(ui->menuWindow,
this);
974 if (editorWindow && editorWindow !=
this)
975 editorWindow->updateRefireAction();
985 void VuoEditorWindow::updateToolbarElementUI()
990 ui->zoom11->setEnabled(! ui->graphicsView->transform().isIdentity());
991 ui->zoomToFit->setEnabled(! isZoomedToFit);
992 ui->showEvents->setText(composition->
getShowEventsMode() ? tr(
"Hide Events") : tr(
"Show Events"));
998 void VuoEditorWindow::updateRefireAction()
1000 __block
bool isTopLevelCompositionRunning =
false;
1001 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(composition, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
1003 isTopLevelCompositionRunning = topLevelComposition->
isRunning();
1006 ui->refireEvent->setEnabled(isTopLevelCompositionRunning ? composition->
getTriggerPortToRefire() :
false);
1012 void VuoEditorWindow::updateWindowForNewCableDrag()
1023 void VuoEditorWindow::updateCursor()
1025 QCursor updatedCursor = (canvasDragInProgress? Qt::ClosedHandCursor :
1026 (canvasDragEnabled? Qt::OpenHandCursor :
1031 setCursor(Qt::ArrowCursor);
1033 setCursor(updatedCursor);
1045 foreach (QWidget *widget, qApp->topLevelWidgets())
1048 if (w && w->isVisible() && !w->containedPrepopulatedContent && (w->windowFilePath() ==
"") && (!w->isWindowModified()))
1060 if ((!nodes.empty() || !comments.empty()) && !ignoreItemMoveSignals)
1063 if (movedByDragging && !duplicationMacroInProgress)
1065 itemDragMacroInProgress =
true;
1069 QGraphicsItem *firstItem = (!nodes.empty()?
static_cast<QGraphicsItem *
>(*nodes.begin()) :
1070 static_cast<QGraphicsItem *
>(*comments.begin()));
1072 if (std::find(itemsBeingDragged.begin(), itemsBeingDragged.end(), firstItem) == itemsBeingDragged.end())
1073 itemsBeingDragged.push_back(firstItem);
1075 if (firstItem == itemsBeingDragged[0])
1082 if (!itemDragMacroInProgress)
1083 undoStack->push(
new VuoCommandMove(nodes, comments, dx, dy,
this, movedByDragging));
1093 commentResizeMacroInProgress =
true;
1094 commentBeingResized = comment;
1095 commentResizeDx += dx;
1096 commentResizeDy += dy;
1105 if ((target == composition) && (! components.empty()))
1106 undoStack->push(
new VuoCommandAdd(components,
this,
"Add"));
1113 string VuoEditorWindow::getMaximumSubcompositionFromSelection(
bool includePublishedPorts,
bool includeHeader)
1117 foreach (QGraphicsItem *item, composition->selectedItems())
1121 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
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 = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
1134 bool strandedAttachment = (attachment && isStrandedAttachment(attachment, selectedCompositionComponents));
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);
1324 if (containsLikelyVuoComposition(clipboardText))
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();
3396 if (composition->hasFocus())
3398 switch (
event->key())
3402 const int y = ui->graphicsView->verticalScrollBar()->value() -
3403 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3404 ui->graphicsView->verticalScrollBar()->setValue(y);
3409 const int y = ui->graphicsView->verticalScrollBar()->value() +
3410 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3411 ui->graphicsView->verticalScrollBar()->setValue(y);
3416 const int x = ui->graphicsView->horizontalScrollBar()->value() -
3417 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3418 ui->graphicsView->horizontalScrollBar()->setValue(x);
3423 const int x = ui->graphicsView->horizontalScrollBar()->value() +
3424 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3425 ui->graphicsView->horizontalScrollBar()->setValue(x);
3439 composition->sendEvent(nearbyPort,
event);
3443 QMainWindow::keyPressEvent(
event);
3456 switch (
event->key())
3460 disableCanvasDrag();
3465 QMainWindow::keyReleaseEvent(
event);
3476 if (canvasDragInProgress)
3478 QPoint oldPos = lastCursorLocationDuringCanvasDrag;
3479 QPoint currentCursorPos = QCursor::pos();
3483 QPoint effectiveNewPos = QPoint( fmax(canvasDragMinCursorPos.x(), fmin(canvasDragMaxCursorPos.x(), currentCursorPos.x())),
3484 fmax(canvasDragMinCursorPos.y(), fmin(canvasDragMaxCursorPos.y(), currentCursorPos.y())));
3487 int dx = -1 * (effectiveNewPos - oldPos).x();
3488 int dy = -1 * (effectiveNewPos - oldPos).y();
3492 lastCursorLocationDuringCanvasDrag.setX(effectiveNewPos.x());
3494 int xScrollbarMin = ui->graphicsView->horizontalScrollBar()->minimum();
3495 int xScrollbarMax = ui->graphicsView->horizontalScrollBar()->maximum();
3496 int xScrollbarOldValue = ui->graphicsView->horizontalScrollBar()->value();
3497 int xScrollbarNewValue = fmax(xScrollbarMin, fmin(xScrollbarMax, xScrollbarOldValue + dx));
3499 if (xScrollbarNewValue != xScrollbarOldValue)
3500 ui->graphicsView->horizontalScrollBar()->setValue(xScrollbarNewValue);
3505 lastCursorLocationDuringCanvasDrag.setY(effectiveNewPos.y());
3507 int yScrollbarMin = ui->graphicsView->verticalScrollBar()->minimum();
3508 int yScrollbarMax = ui->graphicsView->verticalScrollBar()->maximum();
3509 int yScrollbarOldValue = ui->graphicsView->verticalScrollBar()->value();
3510 int yScrollbarNewValue = fmax(yScrollbarMin, fmin(yScrollbarMax, yScrollbarOldValue + dy));
3513 if (yScrollbarNewValue != yScrollbarOldValue)
3514 ui->graphicsView->verticalScrollBar()->setValue(yScrollbarNewValue);
3518 QMainWindow::mouseMoveEvent(
event);
3526 ownedNodeLibrary =
new VuoNodeLibrary(nodeLibraryCompiler,
this, nodeLibraryDisplayMode);
3529 nl = ownedNodeLibrary;
3530 transitionNodeLibraryConnections(NULL, nl);
3534 addDockWidget(Qt::LeftDockWidgetArea, nl);
3537 nodeLibraryMinimumWidth = nl->minimumWidth();
3538 nodeLibraryMaximumWidth = nl->maximumWidth();
3544 void VuoEditorWindow::on_compositionInformation_triggered()
3546 metadataEditor->
show();
3561 void VuoEditorWindow::on_zoomIn_triggered()
3563 ui->graphicsView->scale(zoomRate,zoomRate);
3566 QRectF selectedItemsRect;
3567 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3568 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3570 if (!selectedItemsRect.isNull())
3571 ui->graphicsView->centerOn(selectedItemsRect.center());
3573 isZoomedToFit =
false;
3574 updateToolbarElementUI();
3580 void VuoEditorWindow::on_zoomOut_triggered()
3582 ui->graphicsView->scale(1/zoomRate,1/zoomRate);
3583 isZoomedToFit =
false;
3584 updateToolbarElementUI();
3590 void VuoEditorWindow::on_zoom11_triggered()
3592 bool zoomingIn = (ui->graphicsView->transform().m11() <= 1.0);
3593 ui->graphicsView->setTransform(QTransform());
3598 QRectF selectedItemsRect;
3599 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3600 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3602 if (!selectedItemsRect.isNull())
3603 ui->graphicsView->centerOn(selectedItemsRect.center());
3606 isZoomedToFit =
false;
3607 updateToolbarElementUI();
3617 QRectF itemsBoundingRect = itemsTightBoundingRect.adjusted(-VuoEditorWindow::compositionMargin,
3618 -VuoEditorWindow::compositionMargin,
3619 VuoEditorWindow::compositionMargin,
3620 VuoEditorWindow::compositionMargin);
3621 ui->graphicsView->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
3623 isZoomedToFit =
true;
3624 updateToolbarElementUI();
3635 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
3638 if ((viewportRect.width() < itemsTightBoundingRect.width()) || (viewportRect.height() < itemsTightBoundingRect.height()))
3642 else if (!viewportRect.contains(itemsTightBoundingRect))
3643 ui->graphicsView->ensureVisible(itemsTightBoundingRect, VuoEditorWindow::compositionMargin, VuoEditorWindow::compositionMargin);
3646 void VuoEditorWindow::viewportFitReset()
3648 isZoomedToFit =
false;
3650 updateToolbarElementUI();
3653 void VuoEditorWindow::on_saveComposition_triggered()
3655 QString savedPath = windowFilePath();
3657 on_saveCompositionAs_triggered();
3661 saveFile(savedPath);
3665 void VuoEditorWindow::on_saveCompositionAs_triggered()
3667 string savedPath = saveCompositionAs().toUtf8().constData();
3668 if (savedPath.empty())
3678 QString VuoEditorWindow::saveCompositionAs()
3681 QFileDialog d(
this, Qt::Sheet);
3685 d.setDirectory(windowFilePath());
3694 d.setAcceptMode(QFileDialog::AcceptSave);
3704 QString savedPath =
"";
3705 if (d.exec() == QDialog::Accepted)
3707 savedPath = d.selectedFiles()[0];
3708 string dir, file, ext;
3711 saveFileAs(savedPath);
3725 bool VuoEditorWindow::saveFileAs(
const QString & savePath)
3727 string dir, file, ext;
3731 QDir newCompositionDir(QFileInfo(savePath).absoluteDir().canonicalPath());
3737 if (!installingAsSubcomposition && (!modifiedPortConstantRelativePaths.empty() || iconPathChanged))
3745 map<VuoPort *, string> pathsToUpdate;
3746 QString copiedFileDetails =
"";
3747 QString updatedPathDetails =
"";
3750 for (map <VuoPort *, string>::iterator i = modifiedPortConstantRelativePaths.begin(); i != modifiedPortConstantRelativePaths.end(); ++i)
3753 string modifiedPath = i->second;
3757 string origRelativeDir, file, ext;
3759 string resourceFileName = file;
3762 resourceFileName +=
".";
3763 resourceFileName += ext;
3765 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3769 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3772 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath,
VuoText_makeFromString(modifiedPath.c_str())));
3773 pathsToUpdate[port] = modifiedPath;
3778 if (iconPathChanged)
3783 string origRelativeDir, file, ext;
3785 string resourceFileName = file;
3788 resourceFileName +=
".";
3789 resourceFileName += ext;
3791 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3795 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3797 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath, modifiedIconPath.c_str()));
3800 bool copyFiles = (!copiedFileDetails.isEmpty());
3801 bool updatePaths = (!updatedPathDetails.isEmpty());
3803 const QString updateSummary =
"<p>" + tr(
"You're saving your composition to a different folder.") +
"</p>"
3807 ? tr(
"Do you want to copy the example files used by your composition?")
3809 : tr(
"Do you want to update the paths to files in your composition?"))
3812 QString updateDetails =
"";
3815 updateDetails += tr(
"The following file(s) will be copied",
"", modifiedPortConstantRelativePaths.size()) +
":\n\n" + copiedFileDetails +
"\n";
3819 updateDetails += tr(
"The following path(s) will be updated",
"", pathsToUpdate.size()) +
":\n\n" + updatedPathDetails;
3821 QMessageBox messageBox(
this);
3822 messageBox.setWindowFlags(Qt::Sheet);
3823 messageBox.setWindowModality(Qt::WindowModal);
3824 messageBox.setTextFormat(Qt::RichText);
3825 messageBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok);
3826 messageBox.setButtonText(QMessageBox::Discard, (copyFiles? tr(
"Leave files in place") : tr(
"Leave paths unchanged")));
3827 messageBox.setButtonText(QMessageBox::Ok, (copyFiles? tr(
"Copy files") : tr(
"Update paths")));
3828 messageBox.setDefaultButton(QMessageBox::Ok);
3829 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
3831 messageBox.setText(updateSummary);
3832 messageBox.setDetailedText(updateDetails);
3835 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Discard))->setAutoDefault(
false);
3836 messageBox.button(QMessageBox::Discard)->setFocus();
3838 if (messageBox.exec() == QMessageBox::Ok)
3843 bool tmpFilesOnly =
true;
3844 composition->
bundleResourceFiles(newCompositionDir.canonicalPath().toUtf8().constData(), tmpFilesOnly);
3849 undoStack->beginMacro(tr(
"File Path Updates"));
3852 for (map <VuoPort *, string>::iterator i = pathsToUpdate.begin(); i != pathsToUpdate.end(); ++i)
3855 string modifiedPath = i->second;
3858 setPortConstant(port->
getRenderer(), modifiedPath);
3863 if (iconPathChanged)
3868 metadataCopy->
setName(customizedCompositionName);
3875 undoStack->endMacro();
3880 return saveFile(savePath);
3883 string VuoEditorWindow::on_installSubcomposition_triggered()
3887 string nodeClassName = installSubcomposition(
"");
3890 oldTitle.toUtf8().data(),
3891 ui->installSubcomposition->text().toUtf8().data(),
3892 nodeClassName.c_str());
3894 if (!nodeClassName.empty())
3895 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
3897 return nodeClassName;
3904 string VuoEditorWindow::installSubcomposition(
string parentCompositionPath)
3906 string currentCompositionPath = windowFilePath().toUtf8().constData();
3909 QString operationTitle;
3910 string installedSubcompositionDir;
3911 if (parentCompositionPath.empty())
3913 if (currentCompositionExists)
3914 operationTitle = tr(
"Move Subcomposition to User Library");
3916 operationTitle = tr(
"Save Subcomposition to User Library");
3923 operationTitle = tr(
"Save Subcomposition to User Library");
3928 operationTitle = tr(
"Save Subcomposition to System Library");
3933 operationTitle = tr(
"Save Subcomposition to Composition-Local Library");
3939 string nodeClassName;
3949 QString defaultNodeCategory =
static_cast<VuoEditor *
>(qApp)->getDefaultSubcompositionPrefix();
3953 defaultNodeDisplayName);
3954 QString currentNodeCategory =
static_cast<VuoEditor *
>(qApp)->getSubcompositionPrefix();
3957 defaultNodeDisplayName, defaultNodeCategory,
3958 currentNodeDisplayName, currentNodeCategory);
3963 QString nodeDisplayName = d.nodeTitle();
3964 QString nodeCategory = d.nodeCategory();
3966 if (nodeCategory != currentNodeCategory)
3967 static_cast<VuoEditor *
>(qApp)->updateSubcompositionPrefix(nodeCategory);
3972 newMetadata->
setName(nodeDisplayName.toUtf8().constData());
3982 int documentIdentifierInstanceNum = 1;
3986 std::ostringstream oss;
3987 oss << ++documentIdentifierInstanceNum;
3991 bool saveSucceeded = saveFileAs(copiedCompositionPath.c_str());
3992 if (! saveSucceeded)
4007 if (compositionName.isEmpty())
4011 QString thirdPartyCategory = category.remove(QRegExp(
"^(vuo\\.?)+", Qt::CaseInsensitive));
4014 if (category.isEmpty())
4017 return category +
"." + compositionName;
4030 if (displayName.empty())
4035 CFStringRef cfs = CFStringCreateWithCString(NULL, displayName.c_str(), kCFStringEncodingUTF8);
4038 CFMutableStringRef cfsm = CFStringCreateMutableCopy(NULL, 0, cfs);
4039 CFStringTransform(cfsm, NULL, kCFStringTransformToLatin,
false);
4040 CFStringTransform(cfsm, NULL, kCFStringTransformStripCombiningMarks,
false);
4041 CFStringTransform(cfsm, NULL, kCFStringTransformStripDiacritics,
false);
4042 CFStringTransform(cfsm, NULL, CFSTR(
"ASCII"),
false);
4055 void VuoEditorWindow::editMetadata(
int dialogResult)
4057 if (dialogResult == QDialog::Accepted)
4064 string VuoEditorWindow::generateCurrentDefaultCopyright()
4066 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
4067 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
4068 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
4069 const string currentYear = QDate::currentDate().toString(
"yyyy").toUtf8().constData();
4071 const string copyright =
"Copyright © " + currentYear +
" " + userProfileLink;
4078 bool VuoEditorWindow::confirmReplacingFile(
string path)
4081 QFileInfo fileInfo(QString::fromStdString(path));
4082 QMessageBox d(
this);
4083 d.setWindowFlags(Qt::Sheet);
4084 d.setWindowModality(Qt::WindowModal);
4086 d.setTextFormat(Qt::RichText);
4087 d.setText(tr(
"<b>“%1” already exists. Do you want to replace it?</b>").arg(fileInfo.fileName()));
4089 + 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>")
4091 .arg(fileInfo.dir().dirName()));
4092 d.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
4093 d.setDefaultButton(QMessageBox::Cancel);
4094 d.setButtonText(QMessageBox::Yes, tr(
"Replace"));
4095 d.setIcon(QMessageBox::Warning);
4098 static_cast<QPushButton *
>(d.button(QMessageBox::Yes))->setAutoDefault(
false);
4099 d.button(QMessageBox::Yes)->setFocus();
4101 return d.exec() == QMessageBox::Yes;
4110 addDockWidget(Qt::TopDockWidgetArea, searchBox);
4111 searchBox->setFocus();
4121 if (!searchBox->isHidden())
4130 if (!searchBox->isHidden())
4140 bool VuoEditorWindow::saveFile(
const QString & savePath)
4146 bool saveAborted =
false;
4147 QString failureDetails =
"";
4148 QString modifiedSavePath = savePath;
4150 if (!savePath.endsWith(expectedFileExtension))
4152 modifiedSavePath.append(expectedFileExtension);
4156 failureDetails =
"A file or folder with the same name already exists.";
4160 QString existingPath = windowFilePath();
4161 bool saveSucceeded = !saveAborted && saveFile(modifiedSavePath, existingPath);
4170 setWindowFilePath(modifiedSavePath);
4172 toolbar->updateTitle();
4174 compositionUpgradedSinceLastSave =
false;
4175 undoStack->setClean();
4176 setCompositionModified(
false);
4179 string newDir, file, ext;
4182 if (compositionDirChanged)
4185 QStringList compositionLocalModules;
4186 for (
const string &dependency : compiler->getDependenciesForComposition(
getComposition()->getBase()->getCompiler()))
4188 compositionLocalModules.append(QString::fromStdString(dependency));
4190 if (! compositionLocalModules.empty())
4192 compositionLocalModules.sort();
4194 QString summary = QString(
"<p>You're saving your composition to a different folder.</p>")
4195 .append(
"<p>Where do you want to install the composition's local nodes?</p>");
4197 QString details = QString(
"The following nodes will be moved or copied:\n\n")
4198 .append(compositionLocalModules.join(
"\n"))
4201 QMessageBox messageBox(
this);
4202 messageBox.setWindowFlags(Qt::Sheet);
4203 messageBox.setWindowModality(Qt::WindowModal);
4204 messageBox.setTextFormat(Qt::RichText);
4205 messageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
4206 messageBox.setButtonText(QMessageBox::No,
"Move to User Library");
4207 messageBox.setButtonText(QMessageBox::Yes,
"Copy to new Composition Library");
4208 messageBox.setDefaultButton(QMessageBox::Yes);
4209 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
4211 messageBox.setText(summary);
4212 messageBox.setDetailedText(details);
4215 static_cast<QPushButton *
>(messageBox.button(QMessageBox::No))->setAutoDefault(
false);
4216 messageBox.button(QMessageBox::No)->setFocus();
4218 int ret = messageBox.exec();
4221 QDir oldModulesDir = QDir(QString::fromStdString(oldModulesDirPath));
4223 string newModulesDirPath = (ret == QMessageBox::Yes ?
4227 QDir newModulesDir(QString::fromStdString(newModulesDirPath));
4230 foreach (QString moduleFileName, oldModulesDir.entryList(QDir::Files))
4234 if (compositionLocalModules.contains(QString::fromStdString(moduleKey)))
4236 string oldModulePath = oldModulesDir.filePath(moduleFileName).toStdString();
4237 string newModulePath = newModulesDir.filePath(moduleFileName).toStdString();
4242 if (ret == QMessageBox::Yes)
4255 if (includeInRecentFileMenu)
4256 static_cast<VuoEditor *
>(qApp)->addFileToAllOpenRecentFileMenus(modifiedSavePath);
4261 if (failureDetails.isEmpty())
4262 failureDetails = strerror(error);
4264 QMessageBox fileSaveFailureDialog(
this);
4265 fileSaveFailureDialog.setWindowFlags(Qt::Sheet);
4266 fileSaveFailureDialog.setWindowModality(Qt::WindowModal);
4268 QString errorMessage = tr(
"The composition could not be saved at “%1”.").arg(modifiedSavePath);
4269 fileSaveFailureDialog.setText(tr(errorMessage.toUtf8().constData()));
4270 fileSaveFailureDialog.setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4271 fileSaveFailureDialog.setInformativeText(failureDetails);
4272 fileSaveFailureDialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
4273 fileSaveFailureDialog.setButtonText(QMessageBox::Save, tr(
"Save As…"));
4274 fileSaveFailureDialog.setIcon(QMessageBox::Warning);
4276 switch(fileSaveFailureDialog.exec()) {
4277 case QMessageBox::Save:
4278 on_saveCompositionAs_triggered();
4280 case QMessageBox::Cancel:
4287 return saveSucceeded;
4293 void VuoEditorWindow::populateProtocolsMenu(QMenu *m)
4297 QAction *protocolAction =
new QAction(
this);
4298 protocolAction->setText(VuoEditor::tr(protocol->
getName().c_str()));
4299 protocolAction->setData(qVariantFromValue(
static_cast<void *
>(protocol)));
4300 protocolAction->setCheckable(
true);
4301 connect(protocolAction, &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
4302 m->addAction(protocolAction);
4309 void VuoEditorWindow::updateProtocolsMenu(QMenu *m)
4311 foreach (QAction *protocolAction, m->actions())
4314 protocolAction->setChecked(composition->
getActiveProtocol() == currentProtocol);
4322 void VuoEditorWindow::changeActiveProtocol(
void)
4324 QAction *sender = (QAction *)QObject::sender();
4330 selectedProtocol->
getName().c_str());
4333 toggleActiveStatusForProtocol(selectedProtocol);
4341 void VuoEditorWindow::toggleActiveStatusForProtocol(
VuoProtocol *protocol)
4352 void VuoEditorWindow::updateActiveProtocolDisplay(
void)
4356 setPublishedPortSidebarVisibility(
true);
4364 void VuoEditorWindow::evaluateCompositionForProtocolPromotion()
4370 string compositionAsString = composition->
takeSnapshot();
4390 bool VuoEditorWindow::saveFile(
const QString & savePath, QString & existingPath)
4392 string existingCompositionFooter =
"";
4395 if (! existingPath.isEmpty())
4397 ifstream existingFile(existingPath.toUtf8().constData());
4400 bool graphvizStatementListEndFound =
false;
4401 for (
char c = existingFile.get(); existingFile.good(); c = existingFile.get())
4403 if (existingFile.good())
4407 existingCompositionFooter =
"";
4408 graphvizStatementListEndFound =
true;
4410 else if (graphvizStatementListEndFound)
4411 existingCompositionFooter += c;
4414 existingFile.close();
4425 existingCompositionFooter);
4427 string dir, file, ext;
4428 string finalSavePath = savePath.toUtf8().constData();
4439 mode_t currentUMask = umask(0);
4440 umask(currentUMask);
4442 chmod(tmpSavePath.c_str(), 0666 & ~currentUMask);
4445 ofstream savedFile(tmpSavePath.c_str(), ios::trunc);
4446 savedFile << outputComposition;
4453 bool saveSucceeded = ((! savedFile.fail()) && (! rename(tmpSavePath.c_str(), finalSavePath.c_str())));
4459 this->metadataPanel->
update();
4464 return saveSucceeded;
4470 void VuoEditorWindow::undoStackCleanStateChanged(
bool clean)
4474 setCompositionModified(
true);
4479 else if (clean && !compositionUpgradedSinceLastSave)
4480 setCompositionModified(
false);
4486 void VuoEditorWindow::setCompositionModified(
bool modified)
4488 setWindowModified(modified);
4502 composition->
run(snapshot);
4517 composition->
stop();
4540 void VuoEditorWindow::showBuildActivityIndicator()
4549 void VuoEditorWindow::hideBuildActivityIndicator(QString buildError)
4551 if (! buildError.isEmpty())
4555 updateRefireAction();
4557 QString details =
"";
4558 if (buildError.contains(
"Nodes not installed", Qt::CaseInsensitive))
4559 details =
"This composition contains nodes that aren't installed.";
4561 VuoErrorDialog::show(
this, tr(
"There was a problem running the composition."), details, buildError);
4567 updateRefireAction();
4574 void VuoEditorWindow::hideStopActivityIndicator()
4578 updateRefireAction();
4581 void VuoEditorWindow::on_openUserModulesFolder_triggered()
4586 void VuoEditorWindow::on_openSystemModulesFolder_triggered()
4605 void VuoEditorWindow::on_showPublishedPorts_triggered(
void)
4607 setPublishedPortSidebarVisibility(!arePublishedPortSidebarsVisible());
4617 if (!arePublishedPortSidebarsVisible())
4618 on_showPublishedPorts_triggered();
4624 bool VuoEditorWindow::arePublishedPortSidebarsVisible()
4626 return !inputPortSidebar->isHidden() && !outputPortSidebar->isHidden();
4632 void VuoEditorWindow::on_showHiddenCables_triggered(
void)
4635 if (!previouslyShowingHiddenCables)
4638 on_showPublishedPorts_triggered();
4649 void VuoEditorWindow::on_showEvents_triggered(
void)
4651 VUserLog(
"%s: %s Show Events mode",
4662 void VuoEditorWindow::closePublishedPortSidebars()
4664 setPublishedPortSidebarVisibility(
false);
4670 void VuoEditorWindow::conditionallyShowPublishedPortSidebars(
bool visible)
4673 setPublishedPortSidebarVisibility(
true);
4679 void VuoEditorWindow::setPublishedPortSidebarVisibility(
bool visible)
4687 if (nl && (! nl->isHidden()) && (! nl->isFloating()))
4688 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4691 addDockWidget(Qt::LeftDockWidgetArea, inputPortSidebar);
4693 addDockWidget(Qt::RightDockWidgetArea, outputPortSidebar);
4702 if (! nl->isFloating())
4704 nl->setMinimumWidth(nl->width());
4705 nl->setMaximumWidth(nl->minimumWidth());
4709 inputPortSidebar->setVisible(visible);
4710 outputPortSidebar->setVisible(visible);
4712 updatePublishedCableGeometry();
4716 if (!nl->isHidden() && !nl->isFloating())
4729 void VuoEditorWindow::updatePublishedCableGeometry()
4738 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
4740 cable->
getRenderer()->setCacheMode(defaultCacheMode);
4747 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
4748 ui->graphicsView->viewport()->update();
4756 void VuoEditorWindow::updatePublishedPortOrder(vector<VuoPublishedPort *> ports,
bool isInput)
4766 bool foundNonProtocolPort =
false;
4770 foundNonProtocolPort =
true;
4773 if (foundNonProtocolPort)
4785 void VuoEditorWindow::displayDockedNodeLibrary()
4787 addDockWidget(Qt::LeftDockWidgetArea, nl);
4789 bool publishedPortsDisplayed = (inputPortSidebar && (! inputPortSidebar->isHidden()));
4790 if (publishedPortsDisplayed)
4791 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4793 nl->setFloating(
false);
4794 nl->
fixWidth(publishedPortsDisplayed);
4806 inputPortSidebar->setMinimumWidth(inputPortSidebar->width());
4807 inputPortSidebar->setMaximumWidth(inputPortSidebar->minimumWidth());
4809 if (visibility == VuoNodeLibrary::nodeLibraryDocked)
4812 displayDockedNodeLibrary();
4816 else if (visibility == VuoNodeLibrary::nodeLibraryFloating)
4825 if (ownedNodeLibrary == floater)
4827 if (! nl->isFloating())
4829 nl->setFloating(
true);
4842 ownedNodeLibrary->setVisible(
false);
4848 else if (visibility == VuoNodeLibrary::nodeLibraryHidden)
4851 nl->setVisible(
false);
4867 bool compositionHasOtherCustomizedMetadata = (
4871 bool compositionHasBeenSaved = !windowFilePath().isEmpty();
4872 if (compositionHasCustomizedDescription || compositionHasCustomizedCopyright || compositionHasOtherCustomizedMetadata || compositionHasBeenSaved)
4874 dispatch_async(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{
4875 QMetaObject::invokeMethod(nl,
"displayPopoverInPane", Qt::QueuedConnection, Q_ARG(QWidget *, metadataPanel));
4896 if (inputEditorSession
4905 if (isWindowModified())
4907 auto mb =
new QMessageBox(
this);
4908 mb->setWindowFlags(Qt::Sheet);
4909 mb->setWindowModality(Qt::WindowModal);
4914 QString details = tr(
"Your changes will be lost if you don’t save them.");
4915 mb->setText(tr(message.toUtf8().constData()));
4916 mb->setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4917 mb->setInformativeText(tr(details.toUtf8().constData()));
4920 mb->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
4921 mb->setDefaultButton(QMessageBox::Save);
4924 static_cast<QPushButton *
>(mb->button(QMessageBox::Discard))->setAutoDefault(
false);
4925 mb->button(QMessageBox::Discard)->setFocus();
4927 if (windowFilePath().isEmpty())
4928 mb->setButtonText(QMessageBox::Save, tr(
"Save As…"));
4930 connect(mb, &QMessageBox::buttonClicked,
this, [=](QAbstractButton *button){
4931 auto editor =
static_cast<VuoEditor *
>(qApp);
4932 auto role = mb->buttonRole(button);
4933 if (role == QMessageBox::AcceptRole)
4935 on_saveComposition_triggered();
4936 if (isWindowModified())
4937 editor->cancelQuit();
4941 editor->continueQuit(
this);
4944 else if (role == QMessageBox::DestructiveRole)
4947 editor->continueQuit(
this);
4950 editor->cancelQuit();
4961 static_cast<VuoEditor *
>(qApp)->continueQuit(
this);
4968 void VuoEditorWindow::acceptCloseEvent()
4976 VuoEditorWindow::deleteLater();
4984 static_cast<VuoEditor *
>(qApp)->addFileToRecentlyClosedList(windowFilePath());
4991 void VuoEditorWindow::updateSelectedComponentMenuItems()
4993 string cutCommandText = tr(
"Cut").toStdString();
4994 string copyCommandText = tr(
"Copy").toStdString();
4995 string duplicateCommandText = tr(
"Duplicate").toStdString();
4996 string deleteCommandText = tr(
"Delete").toStdString();
4997 string resetCommandText = tr(
"Reset").toStdString();
4999 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
5001 int selectedNodesFound = 0;
5002 int selectedCablesFound = 0;
5003 int selectedListsFound = 0;
5004 int selectedCommentsFound = 0;
5008 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
5009 (! (selectedNodesFound && selectedCablesFound)) &&
5010 (i != selectedCompositionComponents.end());
5013 QGraphicsItem *compositionComponent = *i;
5021 selectedListsFound++;
5026 selectedNodesFound++;
5030 selectedCablesFound++;
5033 selectedCommentsFound++;
5036 int distinctComponentTypesFound = 0;
5037 if (selectedListsFound)
5038 distinctComponentTypesFound++;
5039 if (selectedNodesFound)
5040 distinctComponentTypesFound++;
5041 if (selectedCablesFound)
5042 distinctComponentTypesFound++;
5043 if (selectedCommentsFound)
5044 distinctComponentTypesFound++;
5046 if (selectedListsFound && (distinctComponentTypesFound == 1))
5048 string selectedListText =
"Selected List";
5049 string selectedListsText =
"Selected Lists";
5051 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5052 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5053 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5055 if (selectedListsFound > 1)
5057 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListsText).c_str()));
5062 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListText).c_str()));
5068 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5069 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5070 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5071 ui->deleteCompositionComponents->setText(tr(deleteCommandText.c_str()));
5075 bool enableSelectedComponentDeleteMenuItem = (!selectedCompositionComponents.isEmpty());
5076 bool enableSelectedComponentCutMenuItem = (!selectedCompositionComponents.isEmpty() &&
5077 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5078 bool enableSelectedComponentDuplicateMenuItem = ((selectedNodesFound || selectedCommentsFound) &&
5079 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5082 bool enableCopyMenuItem = (copyAppliesToNodeLibraryDocumentation || enableSelectedComponentDuplicateMenuItem);
5084 ui->cutCompositionComponents->setEnabled(enableSelectedComponentCutMenuItem);
5085 ui->copyCompositionComponents->setEnabled(enableCopyMenuItem);
5086 ui->duplicateCompositionComponents->setEnabled(enableSelectedComponentDuplicateMenuItem);
5087 ui->deleteCompositionComponents->setEnabled(enableSelectedComponentDeleteMenuItem);
5089 ui->renameNodes->setEnabled(selectedNodesFound);
5090 ui->refactor->setEnabled(selectedNodesFound || selectedCommentsFound);
5091 contextMenuTints->setEnabled(selectedNodesFound || selectedCommentsFound);
5094 ui->menuEdit->removeAction(menuChangeNode->menuAction());
5096 bool menuChangeNodeDisplayed =
false;
5097 if ((selectedNodesFound == 1) && !selectedCommentsFound)
5100 if (menuChangeNode->actions().size() > 0)
5102 ui->menuEdit->insertMenu(ui->refactor, menuChangeNode);
5103 menuChangeNode->setEnabled(
true);
5104 menuChangeNodeDisplayed =
true;
5109 ui->changeNodePlaceholder->setVisible(!menuChangeNodeDisplayed);
5116 bool VuoEditorWindow::containsLikelyVuoComposition(QString text)
5118 const QString compositionIndicatorText =
"digraph";
5119 return (text.toCaseFolded().contains(compositionIndicatorText.toCaseFolded()));
5126 void VuoEditorWindow::ensureSceneRectContainsRegion(
const QList<QRectF> ®ion)
5136 bool regionContained =
true;
5137 QRectF sceneRect = composition->sceneRect();
5138 foreach (QRectF rect, region)
5140 if (!sceneRect.contains(rect))
5142 regionContained =
false;
5147 if (!regionContained)
5157 void VuoEditorWindow::updateSceneRect()
5166 const int horizontalMargin = 0.2 * ui->graphicsView->geometry().width();
5167 const int verticalMargin = 0.2 * ui->graphicsView->geometry().height();
5169 int horizontalScrollBarHeight = ui->graphicsView->horizontalScrollBar()->sizeHint().height();
5170 int verticalScrollBarWidth = ui->graphicsView->verticalScrollBar()->sizeHint().width();
5172 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
5173 QRectF itemsBoundingRect = composition->
internalItemsBoundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5174 QRectF viewportItemsUnionRect;
5178 if (viewportRect.left() <= itemsBoundingRect.left() && viewportRect.right() >= itemsBoundingRect.right())
5180 viewportItemsUnionRect.setLeft(viewportRect.left());
5181 viewportItemsUnionRect.setRight(viewportRect.right());
5186 else if (abs(viewportRect.left() - itemsBoundingRect.left()) > abs(itemsBoundingRect.right() - viewportRect.right()))
5188 viewportItemsUnionRect.setRight(itemsBoundingRect.right());
5189 viewportItemsUnionRect.setLeft(itemsBoundingRect.right() - max(itemsBoundingRect.width(), viewportRect.width()));
5196 viewportItemsUnionRect.setLeft(itemsBoundingRect.left());
5197 viewportItemsUnionRect.setRight(itemsBoundingRect.left() + max(itemsBoundingRect.width(), viewportRect.width()));
5202 if (viewportRect.top() <= itemsBoundingRect.top() && viewportRect.bottom() >= itemsBoundingRect.bottom())
5204 viewportItemsUnionRect.setTop(viewportRect.top());
5205 viewportItemsUnionRect.setBottom(viewportRect.bottom());
5210 else if (abs(viewportRect.top() - itemsBoundingRect.top()) > abs(itemsBoundingRect.bottom() - viewportRect.bottom()))
5212 viewportItemsUnionRect.setBottom(itemsBoundingRect.bottom());
5213 viewportItemsUnionRect.setTop(itemsBoundingRect.bottom() - max(itemsBoundingRect.height(), viewportRect.height()));
5220 viewportItemsUnionRect.setTop(itemsBoundingRect.top());
5221 viewportItemsUnionRect.setBottom(itemsBoundingRect.top() + max(itemsBoundingRect.height(), viewportRect.height()));
5224 int viewportItemsUnionRectAdjustedWidth = viewportItemsUnionRect.width();
5225 int viewportItemsUnionRectAdjustedHeight = viewportItemsUnionRect.height();
5227 if ((viewportItemsUnionRect.width() > viewportRect.width()) &&
5228 (viewportItemsUnionRect.width() <= viewportRect.width() + verticalScrollBarWidth))
5231 viewportItemsUnionRectAdjustedWidth = viewportRect.width() + verticalScrollBarWidth + 1;
5234 viewportItemsUnionRectAdjustedHeight -= horizontalScrollBarHeight;
5237 if ((viewportItemsUnionRect.height() > viewportRect.height()) &&
5238 (viewportItemsUnionRect.height() <= viewportRect.height() + horizontalScrollBarHeight))
5241 viewportItemsUnionRectAdjustedHeight = viewportRect.height() + horizontalScrollBarHeight + 1;
5244 viewportItemsUnionRectAdjustedWidth -= verticalScrollBarWidth;
5247 QRectF viewportItemsUnionRectAdjusted(viewportItemsUnionRect.topLeft().x(),
5248 viewportItemsUnionRect.topLeft().y(),
5249 viewportItemsUnionRectAdjustedWidth,
5250 viewportItemsUnionRectAdjustedHeight);
5254 if ((QApplication::mouseButtons() & Qt::LeftButton))
5255 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(composition->sceneRect());
5257 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(viewportRect);
5262 if (!cableBeingDragged)
5263 composition->setSceneRect(viewportItemsUnionRectAdjusted);
5266 if (cableBeingDragged)
5277 QRect inputPortSidebarRect = inputPortSidebar->geometry();
5278 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()+QPoint(1,0)));
5280 QRect outputPortSidebarRect = outputPortSidebar->geometry();
5281 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
5283 QRect viewportRectGlobal = ui->graphicsView->viewport()->geometry();
5284 viewportRectGlobal.moveTopLeft(ui->graphicsView->viewport()->parentWidget()->mapToGlobal(viewportRectGlobal.topLeft()));
5286 QRect noAutoscrollZone = QRect();
5287 if (!inputPortSidebar->isHidden())
5288 noAutoscrollZone |= inputPortSidebarRect;
5289 if (!outputPortSidebar->isHidden())
5290 noAutoscrollZone |= outputPortSidebarRect;
5291 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
5292 noAutoscrollZone |= viewportRectGlobal;
5294 QPoint cursorPosition = QCursor::pos();
5295 bool cursorWithinNoAutoscrollZone = noAutoscrollZone.contains(cursorPosition);
5296 bool cursorWithinNoAutoscrollZoneLeft = (cursorWithinNoAutoscrollZone &&
5297 ((cursorPosition.x() - noAutoscrollZone.left()) < (noAutoscrollZone.right() - cursorPosition.x())));
5301 bool autoscrollWouldBringSourceNodeCloser =
false;
5305 QRectF fixedNodeBoundingRect = fixedNode->
boundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5306 bool fixedNodeVisible = ((fixedNodeBoundingRect.left()+fixedNode->scenePos().x() >= viewportRect.left()) &&
5307 (fixedNodeBoundingRect.right()+fixedNode->scenePos().x() <= viewportRect.right()));
5309 autoscrollWouldBringSourceNodeCloser = (!fixedNodeVisible && (cursorWithinNoAutoscrollZoneLeft ==
5310 (fixedNodeBoundingRect.left()+fixedNode->scenePos().x() < viewportRect.left())));
5313 bool enableCableDragAutoscroll = (!cursorWithinNoAutoscrollZone || autoscrollWouldBringSourceNodeCloser);
5314 if (enableCableDragAutoscroll)
5316 ui->graphicsView->ensureVisible(cableFloatingEndpointSceneLoc.x(),
5317 cableFloatingEndpointSceneLoc.y(),
5319 VuoEditorWindow::compositionMargin);
5328 void VuoEditorWindow::updateRubberBandSelectionMode(QRect rubberBandRect, QPointF fromScenePoint, QPointF toScenePoint)
5330 bool rubberBandSelectionPreviouslyInProgress = this->rubberBandSelectionInProgress;
5331 bool rubberBandSelectionNowInProgress = !(rubberBandRect.isNull() && fromScenePoint.isNull() && toScenePoint.isNull());
5333 bool beginningRubberBandSelection = (!rubberBandSelectionPreviouslyInProgress && rubberBandSelectionNowInProgress);
5334 bool endingRubberBandSelection = (rubberBandSelectionPreviouslyInProgress && !rubberBandSelectionNowInProgress);
5336 if (beginningRubberBandSelection)
5344 if (!lastLeftMousePressHadOptionModifier)
5351 else if (endingRubberBandSelection)
5357 if (!lastLeftMousePressHadOptionModifier)
5365 this->rubberBandSelectionInProgress = rubberBandSelectionNowInProgress;
5371 void VuoEditorWindow::setPortConstant(
VuoRendererPort *port,
string value)
5386 showInputEditor(port,
true);
5392 void VuoEditorWindow::showInputEditor(
VuoRendererPort *port,
bool forwardTabTraversal)
5397 sidebar = (publishedPort->
getInput() ? outputPortSidebar : inputPortSidebar);
5400 map<VuoRendererPort *, pair<string, string> > originalAndFinalValueForPort = inputEditorSession->
execute(port, forwardTabTraversal);
5402 delete inputEditorSession;
5403 inputEditorSession =
nullptr;
5405 bool startedUndoStackMacro =
false;
5406 for (
auto i : originalAndFinalValueForPort)
5409 string originalEditingSessionValue = i.second.first;
5410 string finalEditingSessionValue = i.second.second;
5414 if (finalEditingSessionValue != originalEditingSessionValue)
5423 if (!startedUndoStackMacro)
5425 undoStack->beginMacro(tr(
"Set Port Constant"));
5426 startedUndoStackMacro =
true;
5442 if (inputVariablesBeforeEditing != inputVariablesAfterEditing)
5448 QList<QGraphicsItem *> attachmentsToRemove;
5455 attachmentsToRemove.append(attachment);
5467 if (oldValueList && oldDictionary && oldKeyList)
5469 set<VuoRendererNode *> nodesToAdd;
5470 set<VuoRendererCable *> cablesToAdd;
5488 undoStack->push(
new VuoCommandReplaceNode(oldValueList, newValueList,
this,
"Set Port Constant",
false,
false));
5489 undoStack->push(
new VuoCommandReplaceNode(oldKeyList, newKeyList,
this,
"Set Port Constant",
false,
true));
5490 undoStack->push(
new VuoCommandReplaceNode(oldDictionary, newDictionary,
this,
"Set Port Constant",
false,
true));
5494 cable->
setFrom(
nullptr,
nullptr);
5495 cable->
setTo(
nullptr,
nullptr);
5514 if (startedUndoStackMacro)
5515 undoStack->endMacro();
5534 QPoint nodeTitleRightCenterInView = ui->graphicsView->mapFromScene(nodeTitleRightCenterInScene);
5535 QPoint nodeTitleRightCenterGlobal = ui->graphicsView->mapToGlobal(nodeTitleRightCenterInView);
5539 int scaledWidth = ui->graphicsView->transform().m11() * nodeWidth;
5540 titleEditor->
setWidth(scaledWidth);
5544 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5546 json_object *originalValueAsJson = json_object_new_string(originalValue.c_str());
5547 json_object *newValueAsJson = titleEditor->
show(nodeTitleRightCenterGlobal, originalValueAsJson, details);
5548 string newValue = json_object_get_string(newValueAsJson);
5549 json_object_put(originalValueAsJson);
5550 json_object_put(newValueAsJson);
5556 if (newValue != originalValue)
5571 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5573 json_object *originalTextAsJson = json_tokener_parse(originalText.c_str());
5579 int scaledWidth = ui->graphicsView->transform().m11() * commentWidth;
5580 commentEditor->
setWidth(scaledWidth);
5584 int scaledHeight = ui->graphicsView->transform().m11() * commentHeight;
5589 QPointF commentTextRightCenterInScene = comment->scenePos() + commentBoundingRect.topRight() + QPointF(0, commentBoundingRect.height()/2.0);
5590 QPoint commentTextRightCenterInView = ui->graphicsView->mapFromScene(commentTextRightCenterInScene);
5591 QPoint commentTextRightCenterGlobal = ui->graphicsView->mapToGlobal(commentTextRightCenterInView);
5593 json_object *newTextAsJson = commentEditor->
show(commentTextRightCenterGlobal, originalTextAsJson, details);
5595 string newText = json_object_to_json_string_ext(newTextAsJson, JSON_C_TO_STRING_PLAIN);
5596 json_object_put(originalTextAsJson);
5597 json_object_put(newTextAsJson);
5599 if (newText != originalText)
5608 comment->setSelected(
true);
5634 void VuoEditorWindow::openEditableSourceForNode(
VuoRendererNode *node)
5641 if (originalGenericNodeClass)
5642 nodeClass = originalGenericNodeClass->
getBase();
5645 QString actionText, sourcePath;
5652 QMainWindow *window =
static_cast<VuoEditor *
>(qApp)->openFileWithName(sourcePath,
false);
5656 if (compositionWindow)
5662 static_cast<VuoEditor *
>(qApp)->openUrl(
"file://" + sourcePath);
5671 this->includeInRecentFileMenu = include;
5678 void VuoEditorWindow::on_insertComment_triggered()
5686 void VuoEditorWindow::insertCommentAtPos(QPointF targetScenePos)
5698 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5699 componentsToAdd.append(comment);
5700 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Comment"));
5703 showCommentEditor(comment);
5709 void VuoEditorWindow::on_insertSubcomposition_triggered()
5722 bool VuoEditorWindow::ensureThisParentCompositionSaved()
5726 QMessageBox messageBox(
this);
5727 messageBox.setWindowFlags(Qt::Sheet);
5728 messageBox.setWindowModality(Qt::WindowModal);
5729 messageBox.setStandardButtons(QMessageBox::Cancel | QMessageBox::Save);
5730 messageBox.setDefaultButton(QMessageBox::Save);
5731 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
5733 messageBox.setText(
"Save before packaging");
5734 messageBox.setInformativeText(
"Please save this composition so Vuo knows where to save your new subcomposition.");
5735 messageBox.setButtonText(QMessageBox::Save, tr(
"Save As…"));
5738 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Cancel))->setAutoDefault(
false);
5739 messageBox.button(QMessageBox::Cancel)->setFocus();
5742 if (messageBox.exec() != QMessageBox::Save)
5746 on_saveCompositionAs_triggered();
5755 void VuoEditorWindow::insertSubcompositionAtPos(QPointF targetScenePos)
5761 if (!ensureThisParentCompositionSaved())
5767 string subcompositionContent =
"digraph G {}";
5768 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent);
5769 if (!subcompositionWindow)
5778 string nodeClassName = subcompositionWindow->installSubcomposition(windowFilePath().toUtf8().constData());
5779 if (!nodeClassName.empty())
5786 targetScenePos.y());
5787 if (!subcompositionNode)
5793 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5795 subcompositionNode);
5798 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5799 componentsToAdd.append(subcompositionNode);
5800 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Subcomposition"));
5807 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
5817 void VuoEditorWindow::refactorSelectedItems()
5823 if (!ensureThisParentCompositionSaved())
5829 string subcompositionContent = getMaximumSubcompositionFromSelection(
false,
false);
5831 QPoint selectedItemsAvgPos = QPoint(0,0);
5832 int selectedItemCount = 0;
5834 set<string> portsToPublish;
5835 __block map<int, string> inputCablesToRestoreFromPort;
5836 __block map<int, string> inputCablesToRestoreToPort;
5837 __block map<int, bool> inputCablesToRestoreEventOnly;
5838 __block map<int, string> outputCablesToRestoreFromPort;
5839 __block map<int, string> outputCablesToRestoreToPort;
5840 __block map<int, bool> outputCablesToRestoreEventOnly;
5842 QList<QGraphicsItem *> selectedItems = composition->selectedItems();
5843 foreach (QGraphicsItem *item, selectedItems)
5854 foreach (
VuoCable *cable, incomingCables)
5862 int cableNum = inputCablesToRestoreEventOnly.size();
5877 bool typecastHasInternalInput =
false;
5878 bool typecastHasExternalInput =
false;
5879 foreach (
VuoCable *typecastInCable, incomingCables)
5883 typecastHasInternalInput =
true;
5885 typecastHasExternalInput =
true;
5891 if (!typecastHasInternalInput)
5894 VuoPort *typecastHostPort = port;
5898 int cableNum = inputCablesToRestoreEventOnly.size();
5901 inputCablesToRestoreEventOnly[cableNum] =
false;
5908 else if (typecastHasExternalInput && typecastHasInternalInput)
5912 foreach (
VuoCable *typecastInCable, incomingCables)
5918 int cableNum = inputCablesToRestoreEventOnly.size();
5921 inputCablesToRestoreEventOnly[cableNum] =
false;
5942 bool connectedTypecastIsExternal =
false;
5949 connectedTypecastIsExternal = ((outCables.size() < 1) || !outCables[0]->getToNode() ||
5950 !outCables[0]->getToNode()->hasRenderer() ||
5951 !outCables[0]->getToNode()->getRenderer()->isSelected());
5952 if (connectedTypecastIsExternal)
5960 int cableNum = outputCablesToRestoreEventOnly.size();
5968 selectedItemsAvgPos += item->scenePos().toPoint();
5969 selectedItemCount++;
5974 selectedItemsAvgPos += item->scenePos().toPoint();
5975 selectedItemCount++;
5979 selectedItemsAvgPos /= selectedItemCount;
5981 string parentCompositionPath = windowFilePath().toStdString();
5984 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent, subcompositionDir);
5990 string nodeClassName = subcompositionWindow->installSubcomposition(parentCompositionPath);
5991 if (!nodeClassName.empty())
5997 selectedItemsAvgPos.x(),
5998 selectedItemsAvgPos.y());
5999 if (!subcompositionNode)
6006 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
6008 subcompositionNode);
6010 undoStack->beginMacro(tr(
"Package as Subcomposition"));
6013 QList<QGraphicsItem *> itemsToRemove;
6015 itemsToRemove.append(node);
6017 itemsToRemove.append(comment);
6019 undoStack->push(
new VuoCommandRemove(itemsToRemove,
this, inputEditorManager,
"Package as Subcomposition",
true));
6022 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
6023 componentsToAdd.append(subcompositionNode);
6024 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"",
true));
6027 QList<QGraphicsItem *> inputCablesToRestore;
6028 for (
int i = 0; i < inputCablesToRestoreEventOnly.size(); ++i)
6035 if (fromNode && fromPort && toNode && toPort &&
6047 inputCablesToRestore.append(cable);
6055 inputCablesToRestoreEventOnly[i],
6056 inputCablesToRestoreFromPort[i],
6063 QList<QGraphicsItem *> outputCablesToRestore;
6064 for (
int i = 0; i < outputCablesToRestoreEventOnly.size(); ++i)
6071 if (fromNode && fromPort && toNode && toPort &&
6083 outputCablesToRestore.append(cable);
6091 outputCablesToRestoreEventOnly[i],
6092 outputCablesToRestoreToPort[i],
6099 undoStack->push(
new VuoCommandAdd(inputCablesToRestore,
this));
6100 undoStack->push(
new VuoCommandAdd(outputCablesToRestore,
this));
6104 string compositionIdentifier =
static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->getCompositionIdentifier(composition);
6106 set<VuoCompilerNode *> nodesMoved;
6107 for (QGraphicsItem *item : itemsToRemove)
6116 string compositionSnapshot = composition->
takeSnapshot();
6119 diffInfo->
addRefactoring(compositionIdentifier, nodesMoved, subcompositionMovedTo);
6123 undoStack->endMacro();
6131 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
6150 return raiseDocumentAction;
6158 return ui->showEvents;
6182 return ui->zoomToFit;
6220 return ownedNodeLibrary;
6239 transitionNodeLibraryConnections(this->nl, library);
6249 transitionNodeLibraryConnections((previousFloaterDestroyed? NULL : this->nl), this->ownedNodeLibrary);
6250 this->nl = this->ownedNodeLibrary;
6258 return ui->menuFile;
6266 return menuOpenRecent;
6291 disconnect(oldLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6292 disconnect(oldLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6295 disconnect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), oldLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6310 connect(newLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6311 connect(newLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6314 connect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), newLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6330 void VuoEditorWindow::restoreDefaultLeftDockedWidgetWidths()
6334 nl->setMinimumWidth(nodeLibraryMinimumWidth);
6335 nl->setMaximumWidth(nodeLibraryMaximumWidth);
6338 if (inputPortSidebar && outputPortSidebar)
6340 inputPortSidebar->setMinimumWidth(outputPortSidebar->minimumWidth());
6341 inputPortSidebar->setMaximumWidth(outputPortSidebar->maximumWidth());
6351 QPoint positionChange =
event->pos() -
event->oldPos();
6352 composition->
movePopoversBy(positionChange.x(), positionChange.y());
6354 QMainWindow::moveEvent(
event);
6365 toolbar->updateTitle();
6368 QMainWindow::resizeEvent(
event);
6376 QList<QGraphicsItem *> VuoEditorWindow::createAnyNecessaryMakeListComponents(
VuoPort *port)
6378 QList<QGraphicsItem *> makeListComponents;
6387 makeListComponents.append(makeListNode);
6388 makeListComponents.append(makeListCable);
6391 return makeListComponents;
6397 void VuoEditorWindow::updateGrid()
6399 QGraphicsView::CacheMode defaultViewportCacheMode = ui->graphicsView->cacheMode();
6401 ui->graphicsView->setCacheMode(QGraphicsView::CacheNone);
6402 ui->graphicsView->viewport()->update();
6404 ui->graphicsView->setCacheMode(defaultViewportCacheMode);
6410 void VuoEditorWindow::updateCanvasOpacity()
6412 int opacity =
static_cast<VuoEditor *
>(qApp)->getCanvasOpacity();
6419 void VuoEditorWindow::updateColor(
bool isDark)
6422 QString backgroundColor = colors->
canvasFill().name();
6423 QString scrollBarColor = isDark ?
"#505050" :
"#dfdfdf";
6424 QString dockwidgetTitleBackgroundColor = isDark ?
"#919191" :
"#efefef";
6426 QString menuStyle = VUO_QSTRINGIFY(
6430 background-color: #404040;
6435 padding-right: 36px;
6438 QMenu::item:disabled {
6441 QMenu::item:selected {
6442 background-color: #1060d0;
6445 QMenu::right-arrow {
6448 QMenu::indicator:checked {
6449 image: url(:/Icons/checkmark.svg);
6452 QMenu::indicator:checked,
6456 QMenu::icon:checked,
6457 QMenu::icon:unchecked {
6462 if (doneInitializing)
6463 setStyleSheet(VUO_QSTRINGIFY(
6464 QMainWindow::separator {
6465 background-color: %1;
6472 .arg(dockwidgetTitleBackgroundColor)
6473 + (isDark ? menuStyle :
""));
6476 ui->graphicsView->setStyleSheet(isDark ? menuStyle :
"");
6478 ui->graphicsView->setStyleSheet(VUO_QSTRINGIFY(
6484 QScrollBar::handle {
6491 QAbstractScrollArea::corner,
6493 QScrollBar::sub-line,
6495 QScrollBar::sub-page {
6500 .arg(backgroundColor)
6501 .arg(scrollBarColor)
6502 + (isDark ? menuStyle :
""));
6505 if (doneInitializing)
6517 void VuoEditorWindow::coalescedUpdateRunningComposition()
6519 if (coalescedOldCompositionSnapshot.empty() != coalescedNewCompositionSnapshot.empty())
6522 foreach (
string nodeID, coalescedNodesToUnlink)
6523 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->unlinkNodeInSupercompositionFromSubcomposition(composition, nodeID);
6525 if (!coalescedOldCompositionSnapshot.empty() && !coalescedNewCompositionSnapshot.empty())
6526 composition->
updateRunningComposition(coalescedOldCompositionSnapshot, coalescedNewCompositionSnapshot, coalescedDiffInfo);
6528 foreach (
string portID, coalescedInternalPortConstantsToSync)
6531 foreach (
string portID, coalescedPublishedPortConstantsToSync)
6534 foreach (
string nodeID, coalescedNodesToRelink)
6535 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->relinkNodeInSupercompositionToSubcomposition(composition, nodeID);
6537 coalescedOldCompositionSnapshot =
"";
6538 coalescedNewCompositionSnapshot =
"";
6539 coalescedInternalPortConstantsToSync.clear();
6540 coalescedPublishedPortConstantsToSync.clear();
6541 coalescedNodesToUnlink.clear();
6542 coalescedNodesToRelink.clear();
6543 coalescedDiffInfo =
nullptr;
6552 if (diffInfo && coalescedDiffInfo)
6553 coalescedUpdateRunningComposition();
6555 if (coalescedOldCompositionSnapshot.empty())
6556 coalescedOldCompositionSnapshot = oldCompositionSnapshot;
6558 coalescedNewCompositionSnapshot = newCompositionSnapshot;
6559 coalescedDiffInfo = diffInfo;
6567 coalescedInternalPortConstantsToSync.push_back(portID);
6575 coalescedPublishedPortConstantsToSync.push_back(portID);
6583 coalescedNodesToUnlink.push_back(nodeID);
6591 coalescedNodesToRelink.push_back(nodeID);
6599 void VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests()
6601 if (protocolComplianceReevaluationPending)
6603 evaluateCompositionForProtocolPromotion();
6604 protocolComplianceReevaluationPending =
false;
6616 void VuoEditorWindow::registerProtocolComplianceEvaluationRequest()
6618 this->protocolComplianceReevaluationPending =
true;
6626 return ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(QCursor::pos()));
6634 return metadataPanel;
6648 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
6649 double targetX = min(max(origPos.x(), viewportRect.left()+leftMargin), viewportRect.right()-rightMargin);
6650 double targetY = min(max(origPos.y(), viewportRect.top()+topMargin), viewportRect.bottom()-bottomMargin);
6653 bool targetPositionClearOfCoincidentNodes =
false;
6654 while (!targetPositionClearOfCoincidentNodes)
6656 QGraphicsItem *preexistingItem = composition->itemAt(QPoint(targetX, targetY), composition->views()[0]->transform());
6657 if (
dynamic_cast<VuoRendererNode *
>(preexistingItem) && (preexistingItem->scenePos() == QPoint(targetX, targetY)))
6659 targetX += pastedComponentOffset;
6660 targetY += pastedComponentOffset;
6663 targetPositionClearOfCoincidentNodes =
true;
6666 return QPointF(targetX, targetY);
6672 void VuoEditorWindow::toggleNodeLibraryDockedState()
6676 bool floatLibrary = !nl->isFloating();
6677 nl->setFloating(floatLibrary);
6678 nl->
fixWidth(!floatLibrary && !inputPortSidebar->isHidden());
6688 undoStack->beginMacro(tr(commandName.toUtf8().constData()));
6696 undoStack->endMacro();