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::updateSceneRect);
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();
837 ui->zoom11->setEnabled(! ui->graphicsView->transform().isIdentity());
838 ui->zoomToFit->setEnabled(! isZoomedToFit);
839 ui->compositionInformation->setEnabled(
true);
844 ui->stopComposition->setEnabled(
false);
845 ui->restartComposition->setEnabled(
false);
849 ui->runComposition->setEnabled(
false);
850 ui->stopComposition->setEnabled(
true);
851 ui->restartComposition->setEnabled(
true);
853 else if (toolbar && toolbar->
isRunning())
855 ui->runComposition->setEnabled(
false);
856 ui->stopComposition->setEnabled(
true);
857 ui->restartComposition->setEnabled(
true);
861 ui->runComposition->setEnabled(
true);
862 ui->stopComposition->setEnabled(
false);
863 ui->restartComposition->setEnabled(
false);
872 auto found = std::find_if(openWindows.begin(), openWindows.end(), [](
VuoEditorWindow *w){ return w->metadataEditor->isVisible(); });
873 bool isCompositionInformationOpen = (found != openWindows.end());
874 quitAction->setEnabled(! isCompositionInformationOpen);
877 QString savedPath = windowFilePath();
878 string savedDir, savedFile, savedExt;
882 ui->saveComposition->setEnabled(enableSaveMenuItem);
885 bool hasErrors =
true;
886 if (! alreadyInstalledAsUserSubcomposition)
897 ui->saveComposition->setText(tr(
"Save"));
898 ui->saveCompositionAs->setText(tr(
"Save As…"));
899 ui->installSubcomposition->setEnabled(!alreadyInstalledAsUserSubcomposition && !hasErrors);
901 tr(
"Move to User Library") :
902 tr(
"Save to User Library"));
905 updateProtocolsMenu(menuProtocols);
909 ui->showEvents->setText(composition->
getShowEventsMode() ? tr(
"Hide Events") : tr(
"Show Events"));
914 ui->actionShowNodeNames->setChecked(
true);
916 ui->actionShowNodeClassNames->setChecked(
true);
918 ui->toggleNodeLibraryDocking->setEnabled(!nl->isHidden());
919 ui->toggleNodeLibraryDocking->setText(nl->isFloating() ? tr(
"Attach to Editor Window") : tr(
"Detach from Editor Window"));
922 if (inputPortSidebar && outputPortSidebar)
924 bool publishedPortSidebarsDisplayed = (! inputPortSidebar->isHidden());
925 ui->showPublishedPorts->setText(publishedPortSidebarsDisplayed ? tr(
"Hide Published Ports") : tr(
"Show Published Ports"));
926 ui->graphicsView->setVerticalScrollBarPolicy(publishedPortSidebarsDisplayed? Qt::ScrollBarAlwaysOff : Qt::ScrollBarAsNeeded);
930 ui->findNext->setEnabled(displaySearchTraversalOptions);
931 ui->findPrevious->setEnabled(displaySearchTraversalOptions);
934 undoAction->setEnabled(!cableDragInProgress && undoStack->canUndo());
935 redoAction->setEnabled(!cableDragInProgress && undoStack->canRedo());
938 if (!showingHiddenCables)
940 ui->showHiddenCables->setText(tr(
"Show Hidden Cables"));
948 ui->showHiddenCables->setText(tr(
"Hide Hidden Cables"));
952 ui->showHiddenCables->setEnabled(
true);
958 ui->exportMovie->setEnabled(
false);
959 ui->exportMacScreenSaver->setEnabled(
false);
960 ui->exportMacFFGL->setEnabled(
false);
961 ui->exportFxPlug->setEnabled(
false);
968 ui->menuWindow->clear();
969 static_cast<VuoEditor *
>(qApp)->populateWindowMenu(ui->menuWindow,
this);
980 if (editorWindow && editorWindow !=
this)
981 editorWindow->updateRefireAction();
990 void VuoEditorWindow::updateRefireAction()
992 __block
bool isTopLevelCompositionRunning =
false;
993 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(composition, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
995 isTopLevelCompositionRunning = topLevelComposition->
isRunning();
998 ui->refireEvent->setEnabled(isTopLevelCompositionRunning ? composition->
getTriggerPortToRefire() :
false);
1004 void VuoEditorWindow::updateWindowForNewCableDrag()
1015 void VuoEditorWindow::updateCursor()
1017 QCursor updatedCursor = (canvasDragInProgress? Qt::ClosedHandCursor :
1018 (canvasDragEnabled? Qt::OpenHandCursor :
1023 setCursor(Qt::ArrowCursor);
1025 setCursor(updatedCursor);
1037 foreach (QWidget *widget, qApp->topLevelWidgets())
1040 if (w && w->isVisible() && !w->containedPrepopulatedContent && (w->windowFilePath() ==
"") && (!w->isWindowModified()))
1052 if ((!nodes.empty() || !comments.empty()) && !ignoreItemMoveSignals)
1055 if (movedByDragging && !duplicationMacroInProgress)
1057 itemDragMacroInProgress =
true;
1061 QGraphicsItem *firstItem = (!nodes.empty()?
static_cast<QGraphicsItem *
>(*nodes.begin()) :
1062 static_cast<QGraphicsItem *
>(*comments.begin()));
1064 if (std::find(itemsBeingDragged.begin(), itemsBeingDragged.end(), firstItem) == itemsBeingDragged.end())
1065 itemsBeingDragged.push_back(firstItem);
1067 if (firstItem == itemsBeingDragged[0])
1074 if (!itemDragMacroInProgress)
1075 undoStack->push(
new VuoCommandMove(nodes, comments, dx, dy,
this, movedByDragging));
1085 commentResizeMacroInProgress =
true;
1086 commentBeingResized = comment;
1087 commentResizeDx += dx;
1088 commentResizeDy += dy;
1097 if ((target == composition) && (! components.empty()))
1098 undoStack->push(
new VuoCommandAdd(components,
this,
"Add"));
1105 string VuoEditorWindow::getMaximumSubcompositionFromSelection(
bool includePublishedPorts,
bool includeHeader)
1109 foreach (QGraphicsItem *item, composition->selectedItems())
1113 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
1114 QList<QGraphicsItem *> selectedNonStrandedCompositionComponents;
1116 QStringList nodeDeclarations;
1117 vector<VuoRendererNode *> nodesToCopy;
1118 vector<QGraphicsItem *> potentialTypecastNodesToCopy;
1119 map<string, bool> nodeRepresented;
1120 vector<VuoRendererComment *> commentsToCopy;
1122 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
1126 bool strandedAttachment = (attachment && isStrandedAttachment(attachment, selectedCompositionComponents));
1132 nodesToCopy.push_back(rn);
1134 selectedNonStrandedCompositionComponents.append(rn);
1139 for (vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1150 commentsToCopy.push_back(rcomment);
1154 selectedNonStrandedCompositionComponents.append(QList<QGraphicsItem *>::fromVector(QVector<QGraphicsItem *>::fromStdVector(potentialTypecastNodesToCopy)));
1158 for (vector<QGraphicsItem *>::iterator node = potentialTypecastNodesToCopy.begin(); node != potentialTypecastNodesToCopy.end(); ++node)
1160 bool inputCableCopied =
false;
1161 bool childPortIsPublished =
false;
1162 vector<VuoPort *> inputPorts = ((
VuoRendererNode *)(*node))->getBase()->getInputPorts();
1163 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1165 vector<VuoCable *> inputCables = (*inputPort)->getConnectedCables(
true);
1166 for (vector<VuoCable *>::iterator inputCable = inputCables.begin(); inputCable != inputCables.end(); ++inputCable)
1168 if (std::find(internalCableSet.begin(), internalCableSet.end(), (*inputCable)->getRenderer()) != internalCableSet.end())
1169 inputCableCopied =
true;
1170 if ((*inputCable)->isPublished())
1171 childPortIsPublished =
true;
1177 if (inputCableCopied || (childPortIsPublished && includePublishedPorts))
1179 if (! nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()])
1182 nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()] =
true;
1189 set<VuoCable *> connectedCables = ((
VuoRendererNode *)(*node))->getConnectedCables(
false);
1190 for (set<VuoCable *>::iterator cable = connectedCables.begin(); cable != connectedCables.end(); ++cable)
1191 internalCableSet.erase((*cable)->getRenderer());
1195 vector<VuoRendererCable *> cablesToCopy(internalCableSet.begin(), internalCableSet.end());
1196 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1198 set<VuoNode *> baseNodesToCopy;
1199 for (vector<VuoRendererNode *>::iterator i = nodesToCopy.begin(); i != nodesToCopy.end(); ++i)
1200 baseNodesToCopy.insert( (*i)->getBase() );
1201 set<VuoCable *> baseCablesToCopy;
1202 for (vector<VuoRendererCable *>::iterator i = cablesToCopy.begin(); i != cablesToCopy.end(); ++i)
1203 baseCablesToCopy.insert( (*i)->getBase() );
1204 set<VuoComment *> baseCommentsToCopy;
1205 for (vector<VuoRendererComment *>::iterator i = commentsToCopy.begin(); i != commentsToCopy.end(); ++i)
1206 baseCommentsToCopy.insert( (*i)->getBase() );
1209 set<VuoPublishedPort *> subcompositionPublishedInputPortSet;
1210 set<VuoPublishedPort *> subcompositionPublishedOutputPortSet;
1212 if (includePublishedPorts)
1218 if (baseNodesToCopy.find(cable->
getToNode()) != baseNodesToCopy.end())
1220 subcompositionPublishedInputPortSet.insert(publishedInputPort);
1221 baseCablesToCopy.insert(cable);
1230 if (baseNodesToCopy.find(cable->
getFromNode()) != baseNodesToCopy.end())
1232 subcompositionPublishedOutputPortSet.insert(publishedOutputPort);
1233 baseCablesToCopy.insert(cable);
1240 vector<VuoPublishedPort *> subcompositionPublishedInputPorts;
1242 if (subcompositionPublishedInputPortSet.find(port) != subcompositionPublishedInputPortSet.end())
1243 subcompositionPublishedInputPorts.push_back(port);
1245 vector<VuoPublishedPort *> subcompositionPublishedOutputPorts;
1247 if (subcompositionPublishedOutputPortSet.find(port) != subcompositionPublishedOutputPortSet.end())
1248 subcompositionPublishedOutputPorts.push_back(port);
1253 subcompositionPublishedInputPorts,
1254 subcompositionPublishedOutputPorts,
1257 -viewportTopLeft.x(),
1258 -viewportTopLeft.y());
1260 return outputCompositionText;
1271 if (!(renderedHostNode && renderedHostNode->
hasRenderer() && selectedItems.contains(renderedHostNode->
getRenderer())))
1275 foreach (
VuoNode *coattachment, coattachments)
1292 QClipboard *clipboard = QApplication::clipboard();
1293 QMimeData *mimeData =
new QMimeData();
1300 mimeData->setText(getMaximumSubcompositionFromSelection(
false,
true).c_str());
1304 clipboard->setMimeData(mimeData);
1316 if (containsLikelyVuoComposition(clipboardText))
1317 pasteCompositionComponents();
1318 else if (!clipboardText.isEmpty())
1328 void VuoEditorWindow::pasteCompositionComponents()
1330 QClipboard *clipboard = QApplication::clipboard();
1331 const QMimeData *mimeData = clipboard->mimeData();
1336 int publishedCablesBeforePaste = 0;
1342 if (mimeData->hasFormat(
"text/plain"))
1346 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
1348 bool pasteAtCursorLoc = ((cursorPos != cursorPosAtLastComponentCopy) && viewportRect.contains(cursorPos));
1350 QString compositionText = mimeData->text();
1351 mergeCompositionComponentsFromString(compositionText.toUtf8().constData(), pasteAtCursorLoc, !pasteAtCursorLoc,
"Paste");
1357 int publishedCablesAfterPaste = 0;
1364 if ((publishedPortsAfterPaste > publishedPortsBeforePaste) || (publishedCablesAfterPaste > publishedCablesBeforePaste))
1365 setPublishedPortSidebarVisibility(
true);
1377 if (! duplicationMacroInProgress)
1379 undoStack->beginMacro(tr(
"Duplication"));
1380 duplicationMacroInProgress =
true;
1383 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1384 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
false,
"Duplication");
1387 composition->clearSelection();
1388 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1389 (*i)->setSelected(
true);
1401 string genericNodeClassName;
1405 genericNodeClassName = currentNodeClass->
getClassName();
1407 if ((genericNodeClassName == nodeClass) && node->
hasRenderer())
1412 QRectF selectedItemsRect;
1413 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
1414 selectedItemsRect |= selectedComponent->sceneBoundingRect();
1416 if (!selectedItemsRect.isNull())
1417 ui->graphicsView->centerOn(selectedItemsRect.center());
1427 void VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem()
1429 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1430 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
true,
"Duplication");
1433 composition->clearSelection();
1434 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1435 (*i)->setSelected(
true);
1444 resetUndoStackMacros();
1447 undoAction->trigger();
1458 composition->
clear();
1459 instantiateNewCompositionComponentsFromString(snapshot);
1469 void VuoEditorWindow::instantiateNewCompositionComponentsFromString(
string compositionText)
1490 composition->
addCable(cable,
false);
1521 QList<QGraphicsItem *> VuoEditorWindow::mergeCompositionComponentsFromString(
string compositionText,
bool pasteAtCursorLoc,
bool pasteWithOffset,
string commandDescription)
1524 QList<QGraphicsItem *> pastedComponents = QList<QGraphicsItem *>();
1526 QPointF startPos = (pasteWithOffset? QPointF(pastedComponentOffset, pastedComponentOffset) : QPointF(0,0));
1531 if (pastedNode->getNodeClass()->hasCompiler())
1533 VuoNode *allowedNode = composition->
createBaseNode(pastedNode->getNodeClass()->getCompiler(), pastedNode);
1536 pastedComposition->
replaceNode(pastedNode, allowedNode);
1543 set<VuoNode *> pastedNodes = pastedComposition->
getBase()->
getNodes();
1544 for (
VuoNode *node : pastedNodes)
1547 pastedComponents.append(rn);
1554 pastedComponents.append(rc);
1557 qreal minX = std::numeric_limits<qreal>::max();
1558 qreal minY = std::numeric_limits<qreal>::max();
1560 if (pasteAtCursorLoc)
1563 for (
VuoNode *node : pastedNodes)
1569 if (node->
getX() < minX)
1570 minX = node->
getX();
1572 if (node->
getY() < minY)
1573 minY = node->
getY();
1578 if (comment->
getX() < minX)
1579 minX = comment->
getX();
1581 if (comment->
getY() < minY)
1582 minY = comment->
getY();
1589 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1590 startPos += viewportTopLeft;
1594 this->ignoreItemMoveSignals =
true;
1595 for (
VuoNode *node : pastedNodes)
1597 node->
setX(startPos.x() + node->
getX());
1598 node->
setY(startPos.y() + node->
getY());
1605 comment->
setX(startPos.x() + comment->
getX());
1606 comment->
setY(startPos.y() + comment->
getY());
1610 this->ignoreItemMoveSignals =
false;
1613 for (
VuoCable *cable : pastedCables)
1618 pastedComponents.append(rc);
1626 map<VuoPublishedPort *, vector<pair<VuoPort *, bool> > > connectionsForPublishedPort;
1627 map<VuoPublishedPort *, bool> publishedPortHadConnectedDataCable;
1631 bool foundConnectedDataCable =
false;
1633 foreach (
VuoCable *cable, publishedInputCables)
1639 bool cableCarriesData = (compilerToPort && compilerToPort->
getDataVuoType() && !alwaysEventOnly);
1640 if (cableCarriesData)
1641 foundConnectedDataCable =
true;
1643 connectionsForPublishedPort[publishedInput].push_back(make_pair(toPort, alwaysEventOnly));
1646 cable->
setTo(NULL, NULL);
1649 publishedPortHadConnectedDataCable[publishedInput] = foundConnectedDataCable;
1654 bool foundConnectedDataCable =
false;
1655 vector<VuoCable *> publishedOutputCables = publishedOutput->
getConnectedCables(
true);
1656 foreach (
VuoCable *cable, publishedOutputCables)
1662 bool cableCarriesData = (compilerFromPort && compilerFromPort->
getDataVuoType() && !alwaysEventOnly);
1663 if (cableCarriesData)
1664 foundConnectedDataCable =
true;
1666 connectionsForPublishedPort[publishedOutput].push_back(make_pair(fromPort, alwaysEventOnly));
1669 cable->
setTo(NULL, NULL);
1672 publishedPortHadConnectedDataCable[publishedOutput] = foundConnectedDataCable;
1677 undoStack->beginMacro(tr(commandDescription.c_str()));
1680 componentsPasted(pastedComponents, commandDescription);
1683 vector<VuoPublishedPort *> unmergedPublishedInputPorts;
1689 string pastedPublishedPortName = publishedInputPort->
getClass()->
getName();
1693 publishedPortHadConnectedDataCable[publishedInputPort]))
1695 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedInputPort];
1696 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1698 VuoPort *connectedPort = i->first;
1699 bool forceEventOnlyPublication = i->second;
1705 unmergedPublishedInputPorts.push_back(publishedInputPort);
1709 foreach (
VuoPublishedPort *unmergedPublishedInputPort, unmergedPublishedInputPorts)
1713 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedInputPort];
1714 if (!internalConnections.empty())
1716 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1718 VuoPort *connectedPort = i->first;
1719 bool forceEventOnlyPublication = i->second;
1727 unmergedPublishedInputPort->
getClass()->
setName(uniquePublishedPortName);
1734 vector<VuoPublishedPort *> unmergedPublishedOutputPorts;
1740 string pastedPublishedPortName = publishedOutputPort->
getClass()->
getName();
1744 publishedPortHadConnectedDataCable[publishedOutputPort]))
1746 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedOutputPort];
1747 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1749 VuoPort *connectedPort = i->first;
1750 bool forceEventOnlyPublication = i->second;
1756 unmergedPublishedOutputPorts.push_back(publishedOutputPort);
1760 foreach (
VuoPublishedPort *unmergedPublishedOutputPort, unmergedPublishedOutputPorts)
1764 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedOutputPort];
1765 if (!internalConnections.empty())
1767 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1769 VuoPort *connectedPort = i->first;
1770 bool forceEventOnlyPublication = i->second;
1778 unmergedPublishedOutputPort->
getClass()->
setName(uniquePublishedPortName);
1784 delete pastedComposition;
1786 undoStack->endMacro();
1788 return pastedComponents;
1795 void VuoEditorWindow::componentsPasted(QList<QGraphicsItem *> components,
string commandDescription)
1797 if (components.empty())
1801 undoStack->push(
new VuoCommandAdd(components,
this, commandDescription));
1804 composition->clearSelection();
1805 for (QList<QGraphicsItem *>::iterator i = components.begin(); i != components.end(); ++i)
1806 (*i)->setSelected(
true);
1840 pair<VuoRendererCable *, VuoRendererCable *> cableArgs,
1842 pair<string, string> typeArgs,
1843 pair<VuoRendererPort *, VuoRendererPort *> portArgs)
1850 string typecastToInsert = typeArgs.first;
1851 string specializedTypeName = typeArgs.second;
1869 set<VuoRendererNode *> emptyNodeSet;
1870 set<VuoRendererComment *> emptyCommentSet;
1871 undoStack->push(
new VuoCommandMove(emptyNodeSet, emptyCommentSet, 0, 0,
this,
false));
1875 cableInProgress->
setTo(NULL, NULL);
1879 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
1881 VuoPort *typecastInPort = NULL;
1882 VuoPort *typecastOutPort = NULL;
1883 if (!typecastToInsert.empty())
1885 typecastNodeToAdd = composition->
createNode(typecastToInsert.c_str(),
"",
1886 targetPort->scenePos().x()+100,
1887 targetPort->scenePos().y()+100);
1889 typecastRelatedComponentsToAdd.append(typecastNodeToAdd);
1895 if (!(typecastInPort && typecastInPort->
hasRenderer() && typecastOutPort && typecastOutPort->
hasRenderer()))
1909 if (portToSpecialize)
1914 if (currentlyGeneric)
1919 if (!specializedNode)
1922 if (portToSpecialize == targetPort)
1930 unadjustedToPort = targetPort;
1934 unadjustedFromPort = targetPort;
1956 if (attachedDrawer && cableWillCarryData)
1958 QList<QGraphicsItem *> drawerRelatedComponentsToRemove;
1959 drawerRelatedComponentsToRemove.append(attachedDrawer);
1960 bool disableAutomaticAttachmentInsertion =
true;
1961 undoStack->push(
new VuoCommandRemove(drawerRelatedComponentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
1966 if (typecastNodeToDelete)
1968 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
1969 typecastRelatedComponentsToRemove.append(typecastNodeToDelete);
1970 typecastRelatedComponentsToRemove.append(dataCableToDisplace);
1972 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
"",
true));
1974 dataCableToDisplace = NULL;
1980 QList<QGraphicsItem *> componentsToReplace = QList<QGraphicsItem *>();
1981 componentsToReplace.append(cableToReplace);
1982 undoStack->push(
new VuoCommandRemove(componentsToReplace,
this, inputEditorManager,
"",
false));
1985 if (! typecastToInsert.empty())
2002 adjustedTargetPort = typecastInPort->
getRenderer();
2005 incomingTypecastCable = cableInProgress;
2019 adjustedTargetPort = typecastOutPort->
getRenderer();
2022 incomingTypecastCable = newCableConnectingTypecast;
2025 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2028 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2031 undoStack->push(
new VuoCommandConnect(cableInProgress, adjustedTargetPort, dataCableToDisplace, portToUnpublish,
this, inputEditorManager));
2035 if (targetPort->
getInput() && previousToPort && (previousToPort != targetPort->
getBase()))
2038 if (previousTypecastToPort)
2045 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
2046 typecastRelatedComponentsToRemove.append(uncollapsedTypecastToPort);
2047 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
""));
2067 if (compatibleSpecializedTypes.size() == 1)
2069 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2081 if (! components.empty())
2082 undoStack->push(
new VuoCommandRemove(components,
this, inputEditorManager, commandDescription));
2109 newNodeClass = compiler->
getNodeClass(newMakeListNodeClassName);
2115 string commandText = (inputPortCountDelta == -1?
"Remove Input Port" : (inputPortCountDelta == 1?
"Add Input Port" :
""));
2118 if (adjustmentedRequestedByDragging)
2123 if (oldMakeListNode)
2125 if (composition->mouseGrabberItem() == oldMakeListNode)
2126 oldMakeListNode->ungrabMouse();
2131 if (newMakeListNode)
2134 newMakeListNode->grabMouse();
2147 if (!newNodeCompilerClass)
2177 string commandText =
"Port Specialization";
2179 if (encapsulateInMacro)
2180 undoStack->beginMacro(tr(commandText.c_str()));
2190 newNode = specializeSinglePort(port, innermostSpecializedTypeName);
2194 map<VuoRendererNode *, VuoRendererNode *> nodesToSpecialize;
2195 nodesToSpecialize[originalNode] = newNode;
2198 foreach (
VuoPort *networkedPort, networkedGenericPorts)
2202 VuoRendererNode *mostRecentVersionOfNetworkedNode = originalNetworkedNode;
2203 VuoPort *mostRecentVersionOfNetworkedPort = networkedPort;
2204 map<VuoRendererNode *, VuoRendererNode *>::iterator i = nodesToSpecialize.find(originalNetworkedNode);
2205 if (i != nodesToSpecialize.end())
2211 mostRecentVersionOfNetworkedNode = specializedNode;
2212 mostRecentVersionOfNetworkedPort = networkedPortInSpecializedNode;
2216 if (specializedTypeName != originalTypeName)
2220 VuoRendererNode *newNetworkedNode = specializeSinglePort(mostRecentVersionOfNetworkedPort->
getRenderer(), innermostSpecializedTypeName);
2221 nodesToSpecialize[originalNetworkedNode] = newNetworkedNode;
2224 bool preserveDanglingCables =
true;
2225 undoStack->push(
new VuoCommandReplaceNode(nodesToSpecialize,
this, commandText, preserveDanglingCables));
2233 if (encapsulateInMacro)
2234 undoStack->endMacro();
2251 if (!specializableNodeClass)
2286 QString commandText = tr(
"Port Specialization");
2287 bool preserveDanglingCables =
true;
2288 bool resetConstantValues =
false;
2290 if (encapsulateInMacro)
2291 undoStack->beginMacro(commandText);
2297 map<VuoNode *, string> nodesToReplace;
2298 set<VuoCable *> cablesToDelete;
2302 QList<QGraphicsItem *> rendererCablesToDelete;
2303 foreach (
VuoCable *cableToDelete, cablesToDelete)
2309 rendererCablesToDelete.append(cableToDelete->
getRenderer());
2312 undoStack->push(
new VuoCommandRemove(rendererCablesToDelete,
this, inputEditorManager, commandText.toStdString()));
2317 nodesToReplace.clear();
2320 map<VuoRendererNode *, VuoRendererNode *> nodesToUnspecialize;
2323 for (map<VuoNode *, string>::iterator i = nodesToReplace.begin(); i != nodesToReplace.end(); ++i)
2325 VuoNode *nodeToRevert = i->first;
2326 string revertedNodeClass = i->second;
2329 nodesToUnspecialize[nodeToRevert->
getRenderer()] = revertedNode;
2331 if (nodeToRevert->
getRenderer() == originalParentNode)
2332 unspecializedParentNode = revertedNode;
2335 undoStack->push(
new VuoCommandReplaceNode(nodesToUnspecialize,
this, commandText.toStdString(), preserveDanglingCables, resetConstantValues));
2337 if (encapsulateInMacro)
2338 undoStack->endMacro();
2340 return unspecializedParentNode;
2371 string commandText =
"Port Re-specialization";
2374 if (encapsulateInMacro)
2375 undoStack->beginMacro(tr(commandText.c_str()));
2386 if (encapsulateInMacro)
2387 undoStack->endMacro();
2389 return specializedParentNode;
2401 if (!revertedNodeClass)
2414 undoStack->beginMacro(tr(
"Tint"));
2416 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
2417 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
2428 undoStack->endMacro();
2434 void VuoEditorWindow::hideSelectedInternalCables()
2442 void VuoEditorWindow::hideCables(set<VuoRendererCable *> cables)
2444 undoStack->beginMacro(tr(
"Hide"));
2449 undoStack->endMacro();
2456 void VuoEditorWindow::unhideCables(set<VuoRendererCable *> cables)
2458 bool publishedCableToUnhide =
false;
2459 undoStack->beginMacro(tr(
"Unhide"));
2464 publishedCableToUnhide =
true;
2469 if ((inputPortSidebar->isHidden() || outputPortSidebar->isHidden()) && publishedCableToUnhide)
2470 on_showPublishedPorts_triggered();
2472 undoStack->endMacro();
2479 void VuoEditorWindow::createIsolatedExternalPublishedPort(
string typeName,
bool isInput)
2482 if (!typeName.empty() && !type)
2485 undoStack->beginMacro(tr(
"Add Published Port"));
2491 showPublishedPortNameEditor(rpp,
true);
2493 undoStack->endMacro();
2502 bool isPublishedOutput = port->
getInput();
2503 (isPublishedOutput? outputPortSidebar : inputPortSidebar)->updatePortList();
2504 string newName = (isPublishedOutput? outputPortSidebar : inputPortSidebar)->showPublishedPortNameEditor(port);
2506 if (originalName != newName)
2507 changePublishedPortName(port, newName, useUndoStack);
2516 internalPortPublished(internalPort, forceEventOnlyPublication, externalPort->
getClass()->
getName(),
true, portToSpecialize, specializedTypeName, typecastToInsert, useUndoStackMacro);
2533 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2534 on_showPublishedPorts_triggered();
2544 vector<VuoRendererPublishedPort *> preexistingPublishedPorts = targetPort->
getPublishedPorts();
2551 if (useUndoStackMacro)
2552 undoStack->beginMacro(tr(
"Publish Port"));
2555 if (portToSpecialize && portToSpecialize->
hasRenderer())
2560 if (currentlyGeneric)
2565 if (specializedNode && (portToSpecialize == targetPort->
getBase()))
2576 bool publishedCableExpectedToHaveData =
false;
2577 bool publishedPortExpectedToBeMerged =
false;
2588 if (publishedPortWithTargetName &&
2591 publishedPortExpectedToBeMerged =
true;
2593 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType && type);
2597 if (!publishedPortExpectedToBeMerged)
2599 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType);
2611 if (publishedCableExpectedToHaveData)
2617 QList<QGraphicsItem *> componentsToRemove;
2618 componentsToRemove.append(attachedDrawer);
2619 bool disableAutomaticAttachmentInsertion =
true;
2620 undoStack->push(
new VuoCommandRemove(componentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
2627 for (vector<VuoCable *>::iterator cable = connectedCables.begin(); (! displacedCable) && (cable != connectedCables.end()); ++cable)
2628 if ((*cable)->getRenderer()->effectivelyCarriesData())
2629 displacedCable = (*cable)->getRenderer();
2636 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
2637 if (! typecastToInsert.empty())
2641 targetPort->scenePos().x()+100,
2642 targetPort->scenePos().y()+100);
2644 typecastRelatedComponentsToAdd.append(typecast);
2663 adjustedTargetPort = typecastInPort->
getRenderer();
2678 adjustedTargetPort = typecastOutPort->
getRenderer();
2683 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2685 bool disableAutomaticAttachmentInsertion =
true;
2686 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2689 undoStack->push(
new VuoCommandPublishPort(adjustedTargetPort->
getBase(), displacedCable,
this, forceEventOnlyPublication, name, merge));
2701 if (compatibleSpecializedTypes.size() == 1)
2703 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2708 if (useUndoStackMacro)
2709 undoStack->endMacro();
2718 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2719 on_showPublishedPorts_triggered();
2721 undoStack->beginMacro(tr(
"Delete"));
2725 bool isPublishedInput = !port->
getInput();
2726 if (isPublishedInput)
2729 QList<QGraphicsItem *> removedDataCables;
2730 foreach (
VuoCable *cable, publishedInputCables)
2736 if (!removedDataCables.empty())
2737 undoStack->push(
new VuoCommandRemove(removedDataCables,
this, inputEditorManager,
"Delete"));
2741 undoStack->endMacro();
2750 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2751 on_showPublishedPorts_triggered();
2753 undoStack->beginMacro(tr(
"Delete"));
2758 QList<QGraphicsItem *> makeListComponents = createAnyNecessaryMakeListComponents(port);
2759 if (! makeListComponents.empty())
2760 undoStack->push(
new VuoCommandAdd(makeListComponents,
this,
""));
2763 undoStack->endMacro();
2771 set<VuoPublishedPort *> publishedPortsToRemove,
2772 vector<VuoPublishedPort *> publishedPortsToAdd,
2773 bool beginUndoStackMacro,
2774 bool endUndoStackMacro)
2777 undoStack->beginMacro(tr(
"Protocol Port Modification"));
2780 for (map<VuoPublishedPort *, string>::iterator i = publishedPortsToRename.begin(); i != publishedPortsToRename.end(); ++i)
2783 string name = i->second;
2796 undoStack->endMacro();
2802 void VuoEditorWindow::resetUndoStackMacros()
2804 if (itemDragMacroInProgress)
2806 itemDragMacroInProgress =
false;
2808 set<VuoRendererNode *> draggedNodeSet;
2809 set<VuoRendererComment *> draggedCommentSet;
2811 foreach (QGraphicsItem *item, itemsBeingDragged)
2819 undoStack->push(
new VuoCommandMove(draggedNodeSet, draggedCommentSet, itemDragDx, itemDragDy,
this,
true));
2821 itemsBeingDragged.clear();
2827 if (commentResizeMacroInProgress)
2829 commentResizeMacroInProgress =
false;
2831 if (commentBeingResized && ((commentResizeDx != 0) || (commentResizeDy != 0)))
2834 commentBeingResized = NULL;
2836 commentResizeDx = 0;
2837 commentResizeDy = 0;
2840 if (duplicationMacroInProgress)
2842 undoStack->endMacro();
2843 duplicationMacroInProgress =
false;
2852 if (
event->type() == QEvent::Show)
2854 if (zoomOutToFitOnNextShowEvent)
2857 zoomOutToFitOnNextShowEvent =
false;
2861 QMetaObject::invokeMethod(composition,
"updateFeedbackErrors", Qt::QueuedConnection);
2866 if (canvasDragInProgress && (
event->type() == QEvent::MouseMove))
2871 else if (
event->type() == QEvent::WindowActivate)
2878 else if (
event->type() == QEvent::WindowDeactivate)
2881 if (
event->type() == QEvent::WindowStateChange)
2892 else if (
event->type() == QEvent::MouseButtonPress)
2895 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
2896 if (leftMouseButtonPressed)
2899 if (!inputPortSidebar->isHidden())
2902 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
2905 if (publishedPortNearCursor)
2907 QGraphicsSceneMouseEvent mouseEvent;
2908 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
2909 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
2912 forwardingEventsToCanvas =
true;
2922 restoreDefaultLeftDockedWidgetWidths();
2925 else if (
event->type() == QEvent::MouseMove)
2928 if (forwardingEventsToCanvas)
2930 QMouseEvent mouseEvent(QEvent::MouseMove,
2931 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2932 static_cast<QMouseEvent *
>(
event)->screenPos(),
2933 static_cast<QMouseEvent *
>(
event)->button(),
2934 static_cast<QMouseEvent *
>(
event)->buttons(),
2935 static_cast<QMouseEvent *
>(
event)->modifiers());
2937 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2944 else if (
event->type() == QEvent::MouseButtonRelease)
2947 if (forwardingEventsToCanvas)
2949 QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
2950 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2951 static_cast<QMouseEvent *
>(
event)->screenPos(),
2952 static_cast<QMouseEvent *
>(
event)->button(),
2953 static_cast<QMouseEvent *
>(
event)->buttons(),
2954 static_cast<QMouseEvent *
>(
event)->modifiers());
2956 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2958 forwardingEventsToCanvas =
false;
2964 return QMainWindow::event(
event);
2974 const double scrollTimeoutSeconds = 0.5;
2977 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);
2978 ui->graphicsView->setInteractive(
true);
2979 scrollInProgress =
false;
2986 if ((canvasDragEnabled || canvasDragInProgress) && (
object == composition) && (
2987 event->type() == QEvent::GraphicsSceneMouseMove ||
2988 event->type() == QEvent::GraphicsSceneMousePress ||
2989 event->type() == QEvent::GraphicsSceneMouseDoubleClick ||
2990 event->type() == QEvent::GraphicsSceneContextMenu ||
2991 event->type() == QEvent::KeyPress))
2996 if ((
object == composition) &&
2997 (
event->type() == QEvent::GraphicsSceneMousePress) &&
3000 consumeNextMouseReleaseToCanvas =
true;
3003 if ((
object == composition) &&
3004 (
event->type() == QEvent::GraphicsSceneMouseRelease) &&
3005 consumeNextMouseReleaseToCanvas)
3007 consumeNextMouseReleaseToCanvas =
false;
3011 if (
event->type() == QEvent::Wheel
3012 && ui->graphicsView->rubberBandRect().isNull()
3013 && !ui->graphicsView->pinchZoomInProgress())
3016 QWheelEvent *wheelEvent =
static_cast<QWheelEvent *
>(
event);
3017 if (wheelEvent->phase() == Qt::ScrollBegin)
3019 ui->graphicsView->setInteractive(
false);
3020 scrollInProgress =
true;
3022 else if (wheelEvent->phase() == Qt::ScrollEnd)
3024 ui->graphicsView->setInteractive(
true);
3025 scrollInProgress =
false;
3030 const double lagLimit = .1;
3035 QInputEvent *filteredInputEvent = (QInputEvent *)(
event);
3036 Qt::KeyboardModifiers modifiersOtherThanShift = (filteredInputEvent->modifiers() & ~Qt::ShiftModifier);
3037 filteredInputEvent->setModifiers(modifiersOtherThanShift);
3038 object->removeEventFilter(
this);
3039 QApplication::sendEvent(
object, filteredInputEvent);
3040 object->installEventFilter(
this);
3048 else if (
event->type() == QEvent::MouseButtonPress)
3050 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
3051 if (leftMouseButtonPressed)
3057 if (canvasDragEnabled && leftMouseButtonPressed && (
object == ui->graphicsView->viewport()))
3059 initiateCanvasDrag();
3065 else if (leftMouseButtonPressed)
3068 if (!inputPortSidebar->isHidden())
3071 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3074 if (publishedPortNearCursor)
3076 QGraphicsSceneMouseEvent mouseEvent;
3077 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
3078 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
3086 else if ((
event->type() == QEvent::MouseMove) &&
3087 canvasDragInProgress &&
3088 (
object == ui->graphicsView->viewport()))
3095 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3096 canvasDragInProgress &&
3097 (((QMouseEvent *)(
event))->button() == Qt::LeftButton) &&
3098 (
object == ui->graphicsView->viewport()))
3100 concludeCanvasDrag();
3107 else if ((((
event->type() == QEvent::MouseButtonRelease) &&
3108 (((QMouseEvent *)(
event))->button() == Qt::LeftButton)) ||
3109 ((
event->type() == QEvent::MouseMove) &&
3110 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton)))
3114 QPoint cursorPosition = ((QMouseEvent *)(
event))->globalPos();
3116 QRect inputPortSidebarRect = inputPortSidebar->geometry();
3117 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()));
3119 QRect outputPortSidebarRect = outputPortSidebar->geometry();
3120 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
3123 if (!inputPortSidebar->isHidden())
3127 if (!outputPortSidebar->isHidden())
3131 if ((
event->type() == QEvent::MouseMove) &&
3132 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton))
3134 bool dragOverInputPortSidebar = ((! inputPortSidebar->isHidden()) && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor));
3135 bool dragOverOutputPortSidebar = ((! outputPortSidebar->isHidden()) && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor));
3137 if (dragOverInputPortSidebar || dragOverOutputPortSidebar)
3139 if (!previousDragMoveWasOverSidebar)
3142 if (dragOverInputPortSidebar)
3144 else if (dragOverOutputPortSidebar)
3147 previousDragMoveWasOverSidebar =
true;
3152 if (previousDragMoveWasOverSidebar)
3160 previousDragMoveWasOverSidebar =
false;
3165 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3166 (((QMouseEvent *)(
event))->button() == Qt::LeftButton))
3171 if (cableInProgress && !inputPortSidebar->isHidden() && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor))
3175 else if (cableInProgress && !outputPortSidebar->isHidden() && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor))
3179 object->removeEventFilter(
this);
3180 QApplication::sendEvent(
object,
event);
3181 object->installEventFilter(
this);
3190 if (!inputPortSidebar->isHidden())
3196 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3202 if (publishedPortNearCursor)
3204 if (!publishedPortNearCursorPreviously)
3210 if (publishedPortNearCursorPreviously)
3216 object->removeEventFilter(
this);
3217 QApplication::sendEvent(
object,
event);
3218 object->installEventFilter(
this);
3221 publishedPortNearCursorPreviously = publishedPortNearCursor;
3227 else if (
event->type() == QEvent::KeyPress)
3229 QKeyEvent *keyEvent = (QKeyEvent *)(
event);
3232 if (keyEvent->key() == Qt::Key_Escape)
3236 if ((composition->selectedItems().isEmpty()) &&
3237 ((keyEvent->key() == Qt::Key_Up) ||
3238 (keyEvent->key() == Qt::Key_Down) ||
3239 (keyEvent->key() == Qt::Key_Left) ||
3240 (keyEvent->key() == Qt::Key_Right)))
3246 else if ((
object == composition) && (keyEvent->key() == Qt::Key_Space))
3253 object->removeEventFilter(
this);
3254 QApplication::sendEvent(
object,
event);
3255 object->installEventFilter(
this);
3263 else if (
event->type() == QEvent::ContextMenu)
3268 return QMainWindow::eventFilter(
object,
event);
3276 return scrollInProgress;
3284 return itemDragMacroInProgress;
3300 return latestDragTime;
3308 void VuoEditorWindow::enableCanvasDrag()
3310 this->canvasDragEnabled =
true;
3320 void VuoEditorWindow::disableCanvasDrag()
3322 this->canvasDragEnabled =
false;
3329 void VuoEditorWindow::initiateCanvasDrag()
3331 this->canvasDragInProgress =
true;
3332 QPoint currentCursorPos = QCursor::pos();
3333 this->lastCursorLocationDuringCanvasDrag = currentCursorPos;
3335 int xNegativeScrollPotential = ui->graphicsView->horizontalScrollBar()->value() - ui->graphicsView->horizontalScrollBar()->minimum();
3336 int yNegativeScrollPotential = ui->graphicsView->verticalScrollBar()->value() - ui->graphicsView->verticalScrollBar()->minimum();
3338 int xPositiveScrollPotential = ui->graphicsView->horizontalScrollBar()->maximum() - ui->graphicsView->horizontalScrollBar()->value();
3339 int yPositiveScrollPotential = ui->graphicsView->verticalScrollBar()->maximum() - ui->graphicsView->verticalScrollBar()->value();
3342 this->canvasDragMinCursorPos = QPoint(currentCursorPos.x() - xPositiveScrollPotential, currentCursorPos.y() - yPositiveScrollPotential);
3343 this->canvasDragMaxCursorPos = QPoint(currentCursorPos.x() + xNegativeScrollPotential, currentCursorPos.y() + yNegativeScrollPotential);
3351 void VuoEditorWindow::concludeCanvasDrag()
3353 this->canvasDragInProgress =
false;
3354 this->lastCursorLocationDuringCanvasDrag = QPoint();
3363 Qt::KeyboardModifiers modifiers =
event->modifiers();
3364 qreal adjustedViewportStepRate = viewportStepRate;
3365 if (modifiers & Qt::ShiftModifier)
3367 adjustedViewportStepRate *= viewportStepRateMultiplier;
3370 if (
event->key() == Qt::Key_Escape)
3374 else if (arePublishedPortSidebarsVisible())
3375 on_showPublishedPorts_triggered();
3379 if (composition->hasFocus())
3381 switch (
event->key())
3385 const int y = ui->graphicsView->verticalScrollBar()->value() -
3386 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3387 ui->graphicsView->verticalScrollBar()->setValue(y);
3392 const int y = ui->graphicsView->verticalScrollBar()->value() +
3393 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3394 ui->graphicsView->verticalScrollBar()->setValue(y);
3399 const int x = ui->graphicsView->horizontalScrollBar()->value() -
3400 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3401 ui->graphicsView->horizontalScrollBar()->setValue(x);
3406 const int x = ui->graphicsView->horizontalScrollBar()->value() +
3407 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3408 ui->graphicsView->horizontalScrollBar()->setValue(x);
3422 composition->sendEvent(nearbyPort,
event);
3426 QMainWindow::keyPressEvent(
event);
3439 switch (
event->key())
3443 disableCanvasDrag();
3448 QMainWindow::keyReleaseEvent(
event);
3459 if (canvasDragInProgress)
3461 QPoint oldPos = lastCursorLocationDuringCanvasDrag;
3462 QPoint currentCursorPos = QCursor::pos();
3466 QPoint effectiveNewPos = QPoint( fmax(canvasDragMinCursorPos.x(), fmin(canvasDragMaxCursorPos.x(), currentCursorPos.x())),
3467 fmax(canvasDragMinCursorPos.y(), fmin(canvasDragMaxCursorPos.y(), currentCursorPos.y())));
3470 int dx = -1 * (effectiveNewPos - oldPos).x();
3471 int dy = -1 * (effectiveNewPos - oldPos).y();
3475 lastCursorLocationDuringCanvasDrag.setX(effectiveNewPos.x());
3477 int xScrollbarMin = ui->graphicsView->horizontalScrollBar()->minimum();
3478 int xScrollbarMax = ui->graphicsView->horizontalScrollBar()->maximum();
3479 int xScrollbarOldValue = ui->graphicsView->horizontalScrollBar()->value();
3480 int xScrollbarNewValue = fmax(xScrollbarMin, fmin(xScrollbarMax, xScrollbarOldValue + dx));
3482 if (xScrollbarNewValue != xScrollbarOldValue)
3483 ui->graphicsView->horizontalScrollBar()->setValue(xScrollbarNewValue);
3488 lastCursorLocationDuringCanvasDrag.setY(effectiveNewPos.y());
3490 int yScrollbarMin = ui->graphicsView->verticalScrollBar()->minimum();
3491 int yScrollbarMax = ui->graphicsView->verticalScrollBar()->maximum();
3492 int yScrollbarOldValue = ui->graphicsView->verticalScrollBar()->value();
3493 int yScrollbarNewValue = fmax(yScrollbarMin, fmin(yScrollbarMax, yScrollbarOldValue + dy));
3496 if (yScrollbarNewValue != yScrollbarOldValue)
3497 ui->graphicsView->verticalScrollBar()->setValue(yScrollbarNewValue);
3501 QMainWindow::mouseMoveEvent(
event);
3509 ownedNodeLibrary =
new VuoNodeLibrary(nodeLibraryCompiler,
this, nodeLibraryDisplayMode);
3512 nl = ownedNodeLibrary;
3513 transitionNodeLibraryConnections(NULL, nl);
3517 addDockWidget(Qt::LeftDockWidgetArea, nl);
3520 nodeLibraryMinimumWidth = nl->minimumWidth();
3521 nodeLibraryMaximumWidth = nl->maximumWidth();
3527 void VuoEditorWindow::on_compositionInformation_triggered()
3529 metadataEditor->
show();
3544 void VuoEditorWindow::on_zoomIn_triggered()
3546 ui->graphicsView->scale(zoomRate,zoomRate);
3549 QRectF selectedItemsRect;
3550 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3551 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3553 if (!selectedItemsRect.isNull())
3554 ui->graphicsView->centerOn(selectedItemsRect.center());
3556 isZoomedToFit =
false;
3563 void VuoEditorWindow::on_zoomOut_triggered()
3565 ui->graphicsView->scale(1/zoomRate,1/zoomRate);
3566 isZoomedToFit =
false;
3573 void VuoEditorWindow::on_zoom11_triggered()
3575 ui->graphicsView->setTransform(QTransform());
3576 isZoomedToFit =
false;
3587 QRectF itemsBoundingRect = itemsTightBoundingRect.adjusted(-VuoEditorWindow::compositionMargin,
3588 -VuoEditorWindow::compositionMargin,
3589 VuoEditorWindow::compositionMargin,
3590 VuoEditorWindow::compositionMargin);
3591 ui->graphicsView->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
3593 isZoomedToFit =
true;
3605 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
3608 if ((viewportRect.width() < itemsTightBoundingRect.width()) || (viewportRect.height() < itemsTightBoundingRect.height()))
3612 else if (!viewportRect.contains(itemsTightBoundingRect))
3613 ui->graphicsView->ensureVisible(itemsTightBoundingRect, VuoEditorWindow::compositionMargin, VuoEditorWindow::compositionMargin);
3616 void VuoEditorWindow::viewportFitReset()
3618 isZoomedToFit =
false;
3622 ui->zoomToFit->setEnabled(! isZoomedToFit);
3626 void VuoEditorWindow::on_saveComposition_triggered()
3628 QString savedPath = windowFilePath();
3630 on_saveCompositionAs_triggered();
3634 saveFile(savedPath);
3638 void VuoEditorWindow::on_saveCompositionAs_triggered()
3640 string savedPath = saveCompositionAs().toUtf8().constData();
3641 if (savedPath.empty())
3651 QString VuoEditorWindow::saveCompositionAs()
3654 QFileDialog d(
this, Qt::Sheet);
3658 d.setDirectory(windowFilePath());
3667 d.setAcceptMode(QFileDialog::AcceptSave);
3677 QString savedPath =
"";
3678 if (d.exec() == QDialog::Accepted)
3680 savedPath = d.selectedFiles()[0];
3681 string dir, file, ext;
3684 saveFileAs(savedPath);
3698 bool VuoEditorWindow::saveFileAs(
const QString & savePath)
3700 string dir, file, ext;
3704 QDir newCompositionDir(QFileInfo(savePath).absoluteDir().canonicalPath());
3710 if (!installingAsSubcomposition && (!modifiedPortConstantRelativePaths.empty() || iconPathChanged))
3718 map<VuoPort *, string> pathsToUpdate;
3719 QString copiedFileDetails =
"";
3720 QString updatedPathDetails =
"";
3723 for (map <VuoPort *, string>::iterator i = modifiedPortConstantRelativePaths.begin(); i != modifiedPortConstantRelativePaths.end(); ++i)
3726 string modifiedPath = i->second;
3730 string origRelativeDir, file, ext;
3732 string resourceFileName = file;
3735 resourceFileName +=
".";
3736 resourceFileName += ext;
3738 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3742 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3745 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath,
VuoText_makeFromString(modifiedPath.c_str())));
3746 pathsToUpdate[port] = modifiedPath;
3751 if (iconPathChanged)
3756 string origRelativeDir, file, ext;
3758 string resourceFileName = file;
3761 resourceFileName +=
".";
3762 resourceFileName += ext;
3764 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3768 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3770 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath, modifiedIconPath.c_str()));
3773 bool copyFiles = (!copiedFileDetails.isEmpty());
3774 bool updatePaths = (!updatedPathDetails.isEmpty());
3776 const QString updateSummary =
"<p>" + tr(
"You're saving your composition to a different folder.") +
"</p>"
3780 ? tr(
"Do you want to copy the example files used by your composition?")
3782 : tr(
"Do you want to update the paths to files in your composition?"))
3785 QString updateDetails =
"";
3788 updateDetails += tr(
"The following file(s) will be copied",
"", modifiedPortConstantRelativePaths.size()) +
":\n\n" + copiedFileDetails +
"\n";
3792 updateDetails += tr(
"The following path(s) will be updated",
"", pathsToUpdate.size()) +
":\n\n" + updatedPathDetails;
3794 QMessageBox messageBox(
this);
3795 messageBox.setWindowFlags(Qt::Sheet);
3796 messageBox.setWindowModality(Qt::WindowModal);
3797 messageBox.setTextFormat(Qt::RichText);
3798 messageBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok);
3799 messageBox.setButtonText(QMessageBox::Discard, (copyFiles? tr(
"Leave files in place") : tr(
"Leave paths unchanged")));
3800 messageBox.setButtonText(QMessageBox::Ok, (copyFiles? tr(
"Copy files") : tr(
"Update paths")));
3801 messageBox.setDefaultButton(QMessageBox::Ok);
3802 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
3804 messageBox.setText(updateSummary);
3805 messageBox.setDetailedText(updateDetails);
3808 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Discard))->setAutoDefault(
false);
3809 messageBox.button(QMessageBox::Discard)->setFocus();
3811 if (messageBox.exec() == QMessageBox::Ok)
3816 bool tmpFilesOnly =
true;
3817 composition->
bundleResourceFiles(newCompositionDir.canonicalPath().toUtf8().constData(), tmpFilesOnly);
3822 undoStack->beginMacro(tr(
"File Path Updates"));
3825 for (map <VuoPort *, string>::iterator i = pathsToUpdate.begin(); i != pathsToUpdate.end(); ++i)
3828 string modifiedPath = i->second;
3831 setPortConstant(port->
getRenderer(), modifiedPath);
3836 if (iconPathChanged)
3841 metadataCopy->
setName(customizedCompositionName);
3848 undoStack->endMacro();
3853 return saveFile(savePath);
3856 string VuoEditorWindow::on_installSubcomposition_triggered()
3860 string nodeClassName = installSubcomposition(
"");
3863 oldTitle.toUtf8().data(),
3864 ui->installSubcomposition->text().toUtf8().data(),
3865 nodeClassName.c_str());
3867 if (!nodeClassName.empty())
3868 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
3870 return nodeClassName;
3877 string VuoEditorWindow::installSubcomposition(
string parentCompositionPath)
3879 string currentCompositionPath = windowFilePath().toUtf8().constData();
3882 QString operationTitle;
3883 string installedSubcompositionDir;
3884 if (parentCompositionPath.empty())
3886 if (currentCompositionExists)
3887 operationTitle = tr(
"Move Subcomposition to User Library");
3889 operationTitle = tr(
"Save Subcomposition to User Library");
3896 operationTitle = tr(
"Save Subcomposition to User Library");
3901 operationTitle = tr(
"Save Subcomposition to System Library");
3906 operationTitle = tr(
"Save Subcomposition to Composition-Local Library");
3912 string nodeClassName;
3922 QString defaultNodeCategory =
static_cast<VuoEditor *
>(qApp)->getDefaultSubcompositionPrefix();
3926 defaultNodeDisplayName);
3927 QString currentNodeCategory =
static_cast<VuoEditor *
>(qApp)->getSubcompositionPrefix();
3930 defaultNodeDisplayName, defaultNodeCategory,
3931 currentNodeDisplayName, currentNodeCategory);
3936 QString nodeDisplayName = d.nodeTitle();
3937 QString nodeCategory = d.nodeCategory();
3939 if (nodeCategory != currentNodeCategory)
3940 static_cast<VuoEditor *
>(qApp)->updateSubcompositionPrefix(nodeCategory);
3945 newMetadata->
setName(nodeDisplayName.toUtf8().constData());
3955 int documentIdentifierInstanceNum = 1;
3959 std::ostringstream oss;
3960 oss << ++documentIdentifierInstanceNum;
3964 bool saveSucceeded = saveFileAs(copiedCompositionPath.c_str());
3965 if (! saveSucceeded)
3980 if (compositionName.isEmpty())
3984 QString thirdPartyCategory = category.remove(QRegExp(
"^(vuo\\.?)+", Qt::CaseInsensitive));
3987 if (category.isEmpty())
3990 return category +
"." + compositionName;
4003 if (displayName.empty())
4008 CFStringRef cfs = CFStringCreateWithCString(NULL, displayName.c_str(), kCFStringEncodingUTF8);
4011 CFMutableStringRef cfsm = CFStringCreateMutableCopy(NULL, 0, cfs);
4012 CFStringTransform(cfsm, NULL, kCFStringTransformToLatin,
false);
4013 CFStringTransform(cfsm, NULL, kCFStringTransformStripCombiningMarks,
false);
4014 CFStringTransform(cfsm, NULL, kCFStringTransformStripDiacritics,
false);
4015 CFStringTransform(cfsm, NULL, CFSTR(
"ASCII"),
false);
4028 void VuoEditorWindow::editMetadata(
int dialogResult)
4030 if (dialogResult == QDialog::Accepted)
4037 string VuoEditorWindow::generateCurrentDefaultCopyright()
4039 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
4040 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
4041 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
4042 const string currentYear = QDate::currentDate().toString(
"yyyy").toUtf8().constData();
4044 const string copyright =
"Copyright © " + currentYear +
" " + userProfileLink;
4051 bool VuoEditorWindow::confirmReplacingFile(
string path)
4054 QFileInfo fileInfo(QString::fromStdString(path));
4055 QMessageBox d(
this);
4056 d.setWindowFlags(Qt::Sheet);
4057 d.setWindowModality(Qt::WindowModal);
4059 d.setTextFormat(Qt::RichText);
4060 d.setText(tr(
"<b>“%1” already exists. Do you want to replace it?</b>").arg(fileInfo.fileName()));
4062 + 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>")
4064 .arg(fileInfo.dir().dirName()));
4065 d.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
4066 d.setDefaultButton(QMessageBox::Cancel);
4067 d.setButtonText(QMessageBox::Yes, tr(
"Replace"));
4068 d.setIcon(QMessageBox::Warning);
4071 static_cast<QPushButton *
>(d.button(QMessageBox::Yes))->setAutoDefault(
false);
4072 d.button(QMessageBox::Yes)->setFocus();
4074 return d.exec() == QMessageBox::Yes;
4083 addDockWidget(Qt::TopDockWidgetArea, searchBox);
4084 searchBox->setFocus();
4094 if (!searchBox->isHidden())
4103 if (!searchBox->isHidden())
4113 bool VuoEditorWindow::saveFile(
const QString & savePath)
4119 bool saveAborted =
false;
4120 QString failureDetails =
"";
4121 QString modifiedSavePath = savePath;
4123 if (!savePath.endsWith(expectedFileExtension))
4125 modifiedSavePath.append(expectedFileExtension);
4129 failureDetails =
"A file or folder with the same name already exists.";
4133 QString existingPath = windowFilePath();
4134 bool saveSucceeded = !saveAborted && saveFile(modifiedSavePath, existingPath);
4143 setWindowFilePath(modifiedSavePath);
4145 toolbar->updateTitle();
4147 compositionUpgradedSinceLastSave =
false;
4148 undoStack->setClean();
4149 setCompositionModified(
false);
4152 string newDir, file, ext;
4155 if (compositionDirChanged)
4158 QStringList compositionLocalModules;
4159 for (
const string &dependency : compiler->getDependenciesForComposition(
getComposition()->getBase()->getCompiler()))
4161 compositionLocalModules.append(QString::fromStdString(dependency));
4163 if (! compositionLocalModules.empty())
4165 compositionLocalModules.sort();
4167 QString summary = QString(
"<p>You're saving your composition to a different folder.</p>")
4168 .append(
"<p>Where do you want to install the composition's local nodes?</p>");
4170 QString details = QString(
"The following nodes will be moved or copied:\n\n")
4171 .append(compositionLocalModules.join(
"\n"))
4174 QMessageBox messageBox(
this);
4175 messageBox.setWindowFlags(Qt::Sheet);
4176 messageBox.setWindowModality(Qt::WindowModal);
4177 messageBox.setTextFormat(Qt::RichText);
4178 messageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
4179 messageBox.setButtonText(QMessageBox::No,
"Move to User Library");
4180 messageBox.setButtonText(QMessageBox::Yes,
"Copy to new Composition Library");
4181 messageBox.setDefaultButton(QMessageBox::Yes);
4182 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
4184 messageBox.setText(summary);
4185 messageBox.setDetailedText(details);
4188 static_cast<QPushButton *
>(messageBox.button(QMessageBox::No))->setAutoDefault(
false);
4189 messageBox.button(QMessageBox::No)->setFocus();
4191 int ret = messageBox.exec();
4194 QDir oldModulesDir = QDir(QString::fromStdString(oldModulesDirPath));
4196 string newModulesDirPath = (ret == QMessageBox::Yes ?
4200 QDir newModulesDir(QString::fromStdString(newModulesDirPath));
4203 foreach (QString moduleFileName, oldModulesDir.entryList(QDir::Files))
4207 if (compositionLocalModules.contains(QString::fromStdString(moduleKey)))
4209 string oldModulePath = oldModulesDir.filePath(moduleFileName).toStdString();
4210 string newModulePath = newModulesDir.filePath(moduleFileName).toStdString();
4215 if (ret == QMessageBox::Yes)
4228 if (includeInRecentFileMenu)
4229 static_cast<VuoEditor *
>(qApp)->addFileToAllOpenRecentFileMenus(modifiedSavePath);
4234 if (failureDetails.isEmpty())
4235 failureDetails = strerror(error);
4237 QMessageBox fileSaveFailureDialog(
this);
4238 fileSaveFailureDialog.setWindowFlags(Qt::Sheet);
4239 fileSaveFailureDialog.setWindowModality(Qt::WindowModal);
4241 QString errorMessage = tr(
"The composition could not be saved at “%1”.").arg(modifiedSavePath);
4242 fileSaveFailureDialog.setText(tr(errorMessage.toUtf8().constData()));
4243 fileSaveFailureDialog.setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4244 fileSaveFailureDialog.setInformativeText(failureDetails);
4245 fileSaveFailureDialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
4246 fileSaveFailureDialog.setButtonText(QMessageBox::Save, tr(
"Save As…"));
4247 fileSaveFailureDialog.setIcon(QMessageBox::Warning);
4249 switch(fileSaveFailureDialog.exec()) {
4250 case QMessageBox::Save:
4251 on_saveCompositionAs_triggered();
4253 case QMessageBox::Cancel:
4260 return saveSucceeded;
4266 void VuoEditorWindow::populateProtocolsMenu(QMenu *m)
4270 QAction *protocolAction =
new QAction(
this);
4271 protocolAction->setText(VuoEditor::tr(protocol->
getName().c_str()));
4272 protocolAction->setData(qVariantFromValue(
static_cast<void *
>(protocol)));
4273 protocolAction->setCheckable(
true);
4274 connect(protocolAction, &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
4275 m->addAction(protocolAction);
4282 void VuoEditorWindow::updateProtocolsMenu(QMenu *m)
4284 foreach (QAction *protocolAction, m->actions())
4287 protocolAction->setChecked(composition->
getActiveProtocol() == currentProtocol);
4295 void VuoEditorWindow::changeActiveProtocol(
void)
4297 QAction *sender = (QAction *)QObject::sender();
4303 selectedProtocol->
getName().c_str());
4306 toggleActiveStatusForProtocol(selectedProtocol);
4314 void VuoEditorWindow::toggleActiveStatusForProtocol(
VuoProtocol *protocol)
4325 void VuoEditorWindow::updateActiveProtocolDisplay(
void)
4329 setPublishedPortSidebarVisibility(
true);
4337 void VuoEditorWindow::evaluateCompositionForProtocolPromotion()
4343 string compositionAsString = composition->
takeSnapshot();
4363 bool VuoEditorWindow::saveFile(
const QString & savePath, QString & existingPath)
4365 string existingCompositionFooter =
"";
4368 if (! existingPath.isEmpty())
4370 ifstream existingFile(existingPath.toUtf8().constData());
4373 bool graphvizStatementListEndFound =
false;
4374 for (
char c = existingFile.get(); existingFile.good(); c = existingFile.get())
4376 if (existingFile.good())
4380 existingCompositionFooter =
"";
4381 graphvizStatementListEndFound =
true;
4383 else if (graphvizStatementListEndFound)
4384 existingCompositionFooter += c;
4387 existingFile.close();
4398 existingCompositionFooter);
4400 string dir, file, ext;
4401 string finalSavePath = savePath.toUtf8().constData();
4412 mode_t currentUMask = umask(0);
4413 umask(currentUMask);
4415 chmod(tmpSavePath.c_str(), 0666 & ~currentUMask);
4418 ofstream savedFile(tmpSavePath.c_str(), ios::trunc);
4419 savedFile << outputComposition;
4426 bool saveSucceeded = ((! savedFile.fail()) && (! rename(tmpSavePath.c_str(), finalSavePath.c_str())));
4432 this->metadataPanel->
update();
4437 return saveSucceeded;
4443 void VuoEditorWindow::undoStackCleanStateChanged(
bool clean)
4447 setCompositionModified(
true);
4452 else if (clean && !compositionUpgradedSinceLastSave)
4453 setCompositionModified(
false);
4459 void VuoEditorWindow::setCompositionModified(
bool modified)
4461 setWindowModified(modified);
4475 composition->
run(snapshot);
4490 composition->
stop();
4513 void VuoEditorWindow::showBuildActivityIndicator()
4522 void VuoEditorWindow::hideBuildActivityIndicator(QString buildError)
4524 if (! buildError.isEmpty())
4528 updateRefireAction();
4530 QString details =
"";
4531 if (buildError.contains(
"Nodes not installed", Qt::CaseInsensitive))
4532 details =
"This composition contains nodes that aren't installed.";
4534 VuoErrorDialog::show(
this, tr(
"There was a problem running the composition."), details, buildError);
4540 updateRefireAction();
4547 void VuoEditorWindow::hideStopActivityIndicator()
4551 updateRefireAction();
4554 void VuoEditorWindow::on_openUserModulesFolder_triggered()
4559 void VuoEditorWindow::on_openSystemModulesFolder_triggered()
4578 void VuoEditorWindow::on_showPublishedPorts_triggered(
void)
4580 setPublishedPortSidebarVisibility(!arePublishedPortSidebarsVisible());
4590 if (!arePublishedPortSidebarsVisible())
4591 on_showPublishedPorts_triggered();
4597 bool VuoEditorWindow::arePublishedPortSidebarsVisible()
4599 return !inputPortSidebar->isHidden() && !outputPortSidebar->isHidden();
4605 void VuoEditorWindow::on_showHiddenCables_triggered(
void)
4608 if (!previouslyShowingHiddenCables)
4611 on_showPublishedPorts_triggered();
4622 void VuoEditorWindow::on_showEvents_triggered(
void)
4624 VUserLog(
"%s: %s Show Events mode",
4635 void VuoEditorWindow::closePublishedPortSidebars()
4637 setPublishedPortSidebarVisibility(
false);
4643 void VuoEditorWindow::conditionallyShowPublishedPortSidebars(
bool visible)
4646 setPublishedPortSidebarVisibility(
true);
4652 void VuoEditorWindow::setPublishedPortSidebarVisibility(
bool visible)
4660 if (nl && (! nl->isHidden()) && (! nl->isFloating()))
4661 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4664 addDockWidget(Qt::LeftDockWidgetArea, inputPortSidebar);
4666 addDockWidget(Qt::RightDockWidgetArea, outputPortSidebar);
4675 if (! nl->isFloating())
4677 nl->setMinimumWidth(nl->width());
4678 nl->setMaximumWidth(nl->minimumWidth());
4682 inputPortSidebar->setVisible(visible);
4683 outputPortSidebar->setVisible(visible);
4685 updatePublishedCableGeometry();
4689 if (!nl->isHidden() && !nl->isFloating())
4702 void VuoEditorWindow::updatePublishedCableGeometry()
4711 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
4713 cable->
getRenderer()->setCacheMode(defaultCacheMode);
4720 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
4721 ui->graphicsView->viewport()->update();
4729 void VuoEditorWindow::updatePublishedPortOrder(vector<VuoPublishedPort *> ports,
bool isInput)
4739 bool foundNonProtocolPort =
false;
4743 foundNonProtocolPort =
true;
4746 if (foundNonProtocolPort)
4758 void VuoEditorWindow::displayDockedNodeLibrary()
4760 addDockWidget(Qt::LeftDockWidgetArea, nl);
4762 bool publishedPortsDisplayed = (inputPortSidebar && (! inputPortSidebar->isHidden()));
4763 if (publishedPortsDisplayed)
4764 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4766 nl->setFloating(
false);
4767 nl->
fixWidth(publishedPortsDisplayed);
4779 inputPortSidebar->setMinimumWidth(inputPortSidebar->width());
4780 inputPortSidebar->setMaximumWidth(inputPortSidebar->minimumWidth());
4782 if (visibility == VuoNodeLibrary::nodeLibraryDocked)
4785 displayDockedNodeLibrary();
4789 else if (visibility == VuoNodeLibrary::nodeLibraryFloating)
4798 if (ownedNodeLibrary == floater)
4800 if (! nl->isFloating())
4802 nl->setFloating(
true);
4815 ownedNodeLibrary->setVisible(
false);
4821 else if (visibility == VuoNodeLibrary::nodeLibraryHidden)
4824 nl->setVisible(
false);
4840 bool compositionHasOtherCustomizedMetadata = (
4844 bool compositionHasBeenSaved = !windowFilePath().isEmpty();
4845 if (compositionHasCustomizedDescription || compositionHasCustomizedCopyright || compositionHasOtherCustomizedMetadata || compositionHasBeenSaved)
4847 dispatch_async(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{
4848 QMetaObject::invokeMethod(nl,
"displayPopoverInPane", Qt::QueuedConnection, Q_ARG(QWidget *, metadataPanel));
4869 if (inputEditorSession
4878 if (isWindowModified())
4880 auto mb =
new QMessageBox(
this);
4881 mb->setWindowFlags(Qt::Sheet);
4882 mb->setWindowModality(Qt::WindowModal);
4887 QString details = tr(
"Your changes will be lost if you don’t save them.");
4888 mb->setText(tr(message.toUtf8().constData()));
4889 mb->setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4890 mb->setInformativeText(tr(details.toUtf8().constData()));
4893 mb->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
4894 mb->setDefaultButton(QMessageBox::Save);
4897 static_cast<QPushButton *
>(mb->button(QMessageBox::Discard))->setAutoDefault(
false);
4898 mb->button(QMessageBox::Discard)->setFocus();
4900 if (windowFilePath().isEmpty())
4901 mb->setButtonText(QMessageBox::Save, tr(
"Save As…"));
4903 connect(mb, &QMessageBox::buttonClicked,
this, [=](QAbstractButton *button){
4904 auto editor =
static_cast<VuoEditor *
>(qApp);
4905 auto role = mb->buttonRole(button);
4906 if (role == QMessageBox::AcceptRole)
4908 on_saveComposition_triggered();
4909 if (isWindowModified())
4910 editor->cancelQuit();
4914 editor->continueQuit(
this);
4917 else if (role == QMessageBox::DestructiveRole)
4920 editor->continueQuit(
this);
4923 editor->cancelQuit();
4934 static_cast<VuoEditor *
>(qApp)->continueQuit(
this);
4941 void VuoEditorWindow::acceptCloseEvent()
4949 VuoEditorWindow::deleteLater();
4957 static_cast<VuoEditor *
>(qApp)->addFileToRecentlyClosedList(windowFilePath());
4964 void VuoEditorWindow::updateSelectedComponentMenuItems()
4966 string cutCommandText = tr(
"Cut").toStdString();
4967 string copyCommandText = tr(
"Copy").toStdString();
4968 string duplicateCommandText = tr(
"Duplicate").toStdString();
4969 string deleteCommandText = tr(
"Delete").toStdString();
4970 string resetCommandText = tr(
"Reset").toStdString();
4972 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
4974 int selectedNodesFound = 0;
4975 int selectedCablesFound = 0;
4976 int selectedListsFound = 0;
4977 int selectedCommentsFound = 0;
4981 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
4982 (! (selectedNodesFound && selectedCablesFound)) &&
4983 (i != selectedCompositionComponents.end());
4986 QGraphicsItem *compositionComponent = *i;
4994 selectedListsFound++;
4999 selectedNodesFound++;
5003 selectedCablesFound++;
5006 selectedCommentsFound++;
5009 int distinctComponentTypesFound = 0;
5010 if (selectedListsFound)
5011 distinctComponentTypesFound++;
5012 if (selectedNodesFound)
5013 distinctComponentTypesFound++;
5014 if (selectedCablesFound)
5015 distinctComponentTypesFound++;
5016 if (selectedCommentsFound)
5017 distinctComponentTypesFound++;
5019 if (selectedListsFound && (distinctComponentTypesFound == 1))
5021 string selectedListText =
"Selected List";
5022 string selectedListsText =
"Selected Lists";
5024 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5025 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5026 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5028 if (selectedListsFound > 1)
5030 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListsText).c_str()));
5035 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListText).c_str()));
5041 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5042 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5043 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5044 ui->deleteCompositionComponents->setText(tr(deleteCommandText.c_str()));
5048 bool enableSelectedComponentDeleteMenuItem = (!selectedCompositionComponents.isEmpty());
5049 bool enableSelectedComponentCutMenuItem = (!selectedCompositionComponents.isEmpty() &&
5050 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5051 bool enableSelectedComponentDuplicateMenuItem = ((selectedNodesFound || selectedCommentsFound) &&
5052 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5055 bool enableCopyMenuItem = (copyAppliesToNodeLibraryDocumentation || enableSelectedComponentDuplicateMenuItem);
5057 ui->cutCompositionComponents->setEnabled(enableSelectedComponentCutMenuItem);
5058 ui->copyCompositionComponents->setEnabled(enableCopyMenuItem);
5059 ui->duplicateCompositionComponents->setEnabled(enableSelectedComponentDuplicateMenuItem);
5060 ui->deleteCompositionComponents->setEnabled(enableSelectedComponentDeleteMenuItem);
5062 ui->renameNodes->setEnabled(selectedNodesFound);
5063 ui->refactor->setEnabled(selectedNodesFound || selectedCommentsFound);
5064 contextMenuTints->setEnabled(selectedNodesFound || selectedCommentsFound);
5067 ui->menuEdit->removeAction(menuChangeNode->menuAction());
5069 bool menuChangeNodeDisplayed =
false;
5070 if ((selectedNodesFound == 1) && !selectedCommentsFound)
5073 if (menuChangeNode->actions().size() > 0)
5075 ui->menuEdit->insertMenu(ui->refactor, menuChangeNode);
5076 menuChangeNode->setEnabled(
true);
5077 menuChangeNodeDisplayed =
true;
5082 ui->changeNodePlaceholder->setVisible(!menuChangeNodeDisplayed);
5089 bool VuoEditorWindow::containsLikelyVuoComposition(QString text)
5091 const QString compositionIndicatorText =
"digraph";
5092 return (text.toCaseFolded().contains(compositionIndicatorText.toCaseFolded()));
5099 void VuoEditorWindow::updateSceneRect()
5108 const int horizontalMargin = 0.2 * ui->graphicsView->geometry().width();
5109 const int verticalMargin = 0.2 * ui->graphicsView->geometry().height();
5111 int horizontalScrollBarHeight = ui->graphicsView->horizontalScrollBar()->sizeHint().height();
5112 int verticalScrollBarWidth = ui->graphicsView->verticalScrollBar()->sizeHint().width();
5114 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
5115 QRectF itemsBoundingRect = composition->
internalItemsBoundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5116 QRectF viewportItemsUnionRect;
5120 if (viewportRect.left() <= itemsBoundingRect.left() && viewportRect.right() >= itemsBoundingRect.right())
5122 viewportItemsUnionRect.setLeft(viewportRect.left());
5123 viewportItemsUnionRect.setRight(viewportRect.right());
5128 else if (abs(viewportRect.left() - itemsBoundingRect.left()) > abs(itemsBoundingRect.right() - viewportRect.right()))
5130 viewportItemsUnionRect.setRight(itemsBoundingRect.right());
5131 viewportItemsUnionRect.setLeft(itemsBoundingRect.right() - max(itemsBoundingRect.width(), viewportRect.width()));
5138 viewportItemsUnionRect.setLeft(itemsBoundingRect.left());
5139 viewportItemsUnionRect.setRight(itemsBoundingRect.left() + max(itemsBoundingRect.width(), viewportRect.width()));
5144 if (viewportRect.top() <= itemsBoundingRect.top() && viewportRect.bottom() >= itemsBoundingRect.bottom())
5146 viewportItemsUnionRect.setTop(viewportRect.top());
5147 viewportItemsUnionRect.setBottom(viewportRect.bottom());
5152 else if (abs(viewportRect.top() - itemsBoundingRect.top()) > abs(itemsBoundingRect.bottom() - viewportRect.bottom()))
5154 viewportItemsUnionRect.setBottom(itemsBoundingRect.bottom());
5155 viewportItemsUnionRect.setTop(itemsBoundingRect.bottom() - max(itemsBoundingRect.height(), viewportRect.height()));
5162 viewportItemsUnionRect.setTop(itemsBoundingRect.top());
5163 viewportItemsUnionRect.setBottom(itemsBoundingRect.top() + max(itemsBoundingRect.height(), viewportRect.height()));
5166 int viewportItemsUnionRectAdjustedWidth = viewportItemsUnionRect.width();
5167 int viewportItemsUnionRectAdjustedHeight = viewportItemsUnionRect.height();
5169 if ((viewportItemsUnionRect.width() > viewportRect.width()) &&
5170 (viewportItemsUnionRect.width() <= viewportRect.width() + verticalScrollBarWidth))
5173 viewportItemsUnionRectAdjustedWidth = viewportRect.width() + verticalScrollBarWidth + 1;
5176 viewportItemsUnionRectAdjustedHeight -= horizontalScrollBarHeight;
5179 if ((viewportItemsUnionRect.height() > viewportRect.height()) &&
5180 (viewportItemsUnionRect.height() <= viewportRect.height() + horizontalScrollBarHeight))
5183 viewportItemsUnionRectAdjustedHeight = viewportRect.height() + horizontalScrollBarHeight + 1;
5186 viewportItemsUnionRectAdjustedWidth -= verticalScrollBarWidth;
5189 QRectF viewportItemsUnionRectAdjusted(viewportItemsUnionRect.topLeft().x(),
5190 viewportItemsUnionRect.topLeft().y(),
5191 viewportItemsUnionRectAdjustedWidth,
5192 viewportItemsUnionRectAdjustedHeight);
5196 if ((QApplication::mouseButtons() & Qt::LeftButton))
5197 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(composition->sceneRect());
5199 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(viewportRect);
5204 if (!cableBeingDragged)
5205 composition->setSceneRect(viewportItemsUnionRectAdjusted);
5208 if (cableBeingDragged)
5219 QRect inputPortSidebarRect = inputPortSidebar->geometry();
5220 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()+QPoint(1,0)));
5222 QRect outputPortSidebarRect = outputPortSidebar->geometry();
5223 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
5225 QRect viewportRectGlobal = ui->graphicsView->viewport()->geometry();
5226 viewportRectGlobal.moveTopLeft(ui->graphicsView->viewport()->parentWidget()->mapToGlobal(viewportRectGlobal.topLeft()));
5228 QRect noAutoscrollZone = QRect();
5229 if (!inputPortSidebar->isHidden())
5230 noAutoscrollZone |= inputPortSidebarRect;
5231 if (!outputPortSidebar->isHidden())
5232 noAutoscrollZone |= outputPortSidebarRect;
5233 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
5234 noAutoscrollZone |= viewportRectGlobal;
5236 QPoint cursorPosition = QCursor::pos();
5237 bool cursorWithinNoAutoscrollZone = noAutoscrollZone.contains(cursorPosition);
5238 bool cursorWithinNoAutoscrollZoneLeft = (cursorWithinNoAutoscrollZone &&
5239 ((cursorPosition.x() - noAutoscrollZone.left()) < (noAutoscrollZone.right() - cursorPosition.x())));
5243 bool autoscrollWouldBringSourceNodeCloser =
false;
5247 QRectF fixedNodeBoundingRect = fixedNode->
boundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5248 bool fixedNodeVisible = ((fixedNodeBoundingRect.left()+fixedNode->scenePos().x() >= viewportRect.left()) &&
5249 (fixedNodeBoundingRect.right()+fixedNode->scenePos().x() <= viewportRect.right()));
5251 autoscrollWouldBringSourceNodeCloser = (!fixedNodeVisible && (cursorWithinNoAutoscrollZoneLeft ==
5252 (fixedNodeBoundingRect.left()+fixedNode->scenePos().x() < viewportRect.left())));
5255 bool enableCableDragAutoscroll = (!cursorWithinNoAutoscrollZone || autoscrollWouldBringSourceNodeCloser);
5256 if (enableCableDragAutoscroll)
5258 ui->graphicsView->ensureVisible(cableFloatingEndpointSceneLoc.x(),
5259 cableFloatingEndpointSceneLoc.y(),
5261 VuoEditorWindow::compositionMargin);
5270 void VuoEditorWindow::updateRubberBandSelectionMode(QRect rubberBandRect, QPointF fromScenePoint, QPointF toScenePoint)
5272 bool rubberBandSelectionPreviouslyInProgress = this->rubberBandSelectionInProgress;
5273 bool rubberBandSelectionNowInProgress = !(rubberBandRect.isNull() && fromScenePoint.isNull() && toScenePoint.isNull());
5275 bool beginningRubberBandSelection = (!rubberBandSelectionPreviouslyInProgress && rubberBandSelectionNowInProgress);
5276 bool endingRubberBandSelection = (rubberBandSelectionPreviouslyInProgress && !rubberBandSelectionNowInProgress);
5278 if (beginningRubberBandSelection)
5286 if (!lastLeftMousePressHadOptionModifier)
5293 else if (endingRubberBandSelection)
5299 if (!lastLeftMousePressHadOptionModifier)
5307 this->rubberBandSelectionInProgress = rubberBandSelectionNowInProgress;
5313 void VuoEditorWindow::setPortConstant(
VuoRendererPort *port,
string value)
5328 showInputEditor(port,
true);
5334 void VuoEditorWindow::showInputEditor(
VuoRendererPort *port,
bool forwardTabTraversal)
5339 sidebar = (publishedPort->
getInput() ? outputPortSidebar : inputPortSidebar);
5342 map<VuoRendererPort *, pair<string, string> > originalAndFinalValueForPort = inputEditorSession->
execute(port, forwardTabTraversal);
5344 delete inputEditorSession;
5345 inputEditorSession =
nullptr;
5347 bool startedUndoStackMacro =
false;
5348 for (
auto i : originalAndFinalValueForPort)
5351 string originalEditingSessionValue = i.second.first;
5352 string finalEditingSessionValue = i.second.second;
5356 if (finalEditingSessionValue != originalEditingSessionValue)
5365 if (!startedUndoStackMacro)
5367 undoStack->beginMacro(tr(
"Set Port Constant"));
5368 startedUndoStackMacro =
true;
5384 if (inputVariablesBeforeEditing != inputVariablesAfterEditing)
5390 QList<QGraphicsItem *> attachmentsToRemove;
5397 attachmentsToRemove.append(attachment);
5409 if (oldValueList && oldDictionary && oldKeyList)
5411 set<VuoRendererNode *> nodesToAdd;
5412 set<VuoRendererCable *> cablesToAdd;
5430 undoStack->push(
new VuoCommandReplaceNode(oldValueList, newValueList,
this,
"Set Port Constant",
false,
false));
5431 undoStack->push(
new VuoCommandReplaceNode(oldKeyList, newKeyList,
this,
"Set Port Constant",
false,
true));
5432 undoStack->push(
new VuoCommandReplaceNode(oldDictionary, newDictionary,
this,
"Set Port Constant",
false,
true));
5436 cable->
setFrom(
nullptr,
nullptr);
5437 cable->
setTo(
nullptr,
nullptr);
5456 if (startedUndoStackMacro)
5457 undoStack->endMacro();
5476 QPoint nodeTitleRightCenterInView = ui->graphicsView->mapFromScene(nodeTitleRightCenterInScene);
5477 QPoint nodeTitleRightCenterGlobal = ui->graphicsView->mapToGlobal(nodeTitleRightCenterInView);
5481 int scaledWidth = ui->graphicsView->transform().m11() * nodeWidth;
5482 titleEditor->
setWidth(scaledWidth);
5486 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5488 json_object *originalValueAsJson = json_object_new_string(originalValue.c_str());
5489 json_object *newValueAsJson = titleEditor->
show(nodeTitleRightCenterGlobal, originalValueAsJson, details);
5490 string newValue = json_object_get_string(newValueAsJson);
5491 json_object_put(originalValueAsJson);
5492 json_object_put(newValueAsJson);
5498 if (newValue != originalValue)
5513 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5515 json_object *originalTextAsJson = json_tokener_parse(originalText.c_str());
5521 int scaledWidth = ui->graphicsView->transform().m11() * commentWidth;
5522 commentEditor->
setWidth(scaledWidth);
5526 int scaledHeight = ui->graphicsView->transform().m11() * commentHeight;
5531 QPointF commentTextRightCenterInScene = comment->scenePos() + commentBoundingRect.topRight() + QPointF(0, commentBoundingRect.height()/2.0);
5532 QPoint commentTextRightCenterInView = ui->graphicsView->mapFromScene(commentTextRightCenterInScene);
5533 QPoint commentTextRightCenterGlobal = ui->graphicsView->mapToGlobal(commentTextRightCenterInView);
5535 json_object *newTextAsJson = commentEditor->
show(commentTextRightCenterGlobal, originalTextAsJson, details);
5537 string newText = json_object_to_json_string_ext(newTextAsJson, JSON_C_TO_STRING_PLAIN);
5538 json_object_put(originalTextAsJson);
5539 json_object_put(newTextAsJson);
5541 if (newText != originalText)
5550 comment->setSelected(
true);
5576 void VuoEditorWindow::openEditableSourceForNode(
VuoRendererNode *node)
5583 if (originalGenericNodeClass)
5584 nodeClass = originalGenericNodeClass->
getBase();
5587 QString actionText, sourcePath;
5594 QMainWindow *window =
static_cast<VuoEditor *
>(qApp)->openFileWithName(sourcePath,
false);
5598 if (compositionWindow)
5604 static_cast<VuoEditor *
>(qApp)->openUrl(
"file://" + sourcePath);
5613 this->includeInRecentFileMenu = include;
5620 void VuoEditorWindow::on_insertComment_triggered()
5628 void VuoEditorWindow::insertCommentAtPos(QPointF targetScenePos)
5640 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5641 componentsToAdd.append(comment);
5642 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Comment"));
5645 showCommentEditor(comment);
5651 void VuoEditorWindow::on_insertSubcomposition_triggered()
5664 bool VuoEditorWindow::ensureThisParentCompositionSaved()
5668 QMessageBox messageBox(
this);
5669 messageBox.setWindowFlags(Qt::Sheet);
5670 messageBox.setWindowModality(Qt::WindowModal);
5671 messageBox.setStandardButtons(QMessageBox::Cancel | QMessageBox::Save);
5672 messageBox.setDefaultButton(QMessageBox::Save);
5673 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
5675 messageBox.setText(
"Save before packaging");
5676 messageBox.setInformativeText(
"Please save this composition so Vuo knows where to save your new subcomposition.");
5677 messageBox.setButtonText(QMessageBox::Save, tr(
"Save As…"));
5680 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Cancel))->setAutoDefault(
false);
5681 messageBox.button(QMessageBox::Cancel)->setFocus();
5684 if (messageBox.exec() != QMessageBox::Save)
5688 on_saveCompositionAs_triggered();
5697 void VuoEditorWindow::insertSubcompositionAtPos(QPointF targetScenePos)
5703 if (!ensureThisParentCompositionSaved())
5709 string subcompositionContent =
"digraph G {}";
5710 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent);
5715 string nodeClassName = subcompositionWindow->installSubcomposition(windowFilePath().toUtf8().constData());
5716 if (!nodeClassName.empty())
5723 targetScenePos.y());
5724 if (!subcompositionNode)
5730 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5732 subcompositionNode);
5735 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5736 componentsToAdd.append(subcompositionNode);
5737 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Subcomposition"));
5744 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
5754 void VuoEditorWindow::refactorSelectedItems()
5760 if (!ensureThisParentCompositionSaved())
5766 string subcompositionContent = getMaximumSubcompositionFromSelection(
false,
false);
5768 QPoint selectedItemsAvgPos = QPoint(0,0);
5769 int selectedItemCount = 0;
5771 set<string> portsToPublish;
5772 __block map<int, string> inputCablesToRestoreFromPort;
5773 __block map<int, string> inputCablesToRestoreToPort;
5774 __block map<int, bool> inputCablesToRestoreEventOnly;
5775 __block map<int, string> outputCablesToRestoreFromPort;
5776 __block map<int, string> outputCablesToRestoreToPort;
5777 __block map<int, bool> outputCablesToRestoreEventOnly;
5779 QList<QGraphicsItem *> selectedItems = composition->selectedItems();
5780 foreach (QGraphicsItem *item, selectedItems)
5791 foreach (
VuoCable *cable, incomingCables)
5799 int cableNum = inputCablesToRestoreEventOnly.size();
5814 bool typecastHasInternalInput =
false;
5815 bool typecastHasExternalInput =
false;
5816 foreach (
VuoCable *typecastInCable, incomingCables)
5820 typecastHasInternalInput =
true;
5822 typecastHasExternalInput =
true;
5828 if (!typecastHasInternalInput)
5831 VuoPort *typecastHostPort = port;
5835 int cableNum = inputCablesToRestoreEventOnly.size();
5838 inputCablesToRestoreEventOnly[cableNum] =
false;
5845 else if (typecastHasExternalInput && typecastHasInternalInput)
5849 foreach (
VuoCable *typecastInCable, incomingCables)
5855 int cableNum = inputCablesToRestoreEventOnly.size();
5858 inputCablesToRestoreEventOnly[cableNum] =
false;
5879 bool connectedTypecastIsExternal =
false;
5886 connectedTypecastIsExternal = ((outCables.size() < 1) || !outCables[0]->getToNode() ||
5887 !outCables[0]->getToNode()->hasRenderer() ||
5888 !outCables[0]->getToNode()->getRenderer()->isSelected());
5889 if (connectedTypecastIsExternal)
5897 int cableNum = outputCablesToRestoreEventOnly.size();
5905 selectedItemsAvgPos += item->scenePos().toPoint();
5906 selectedItemCount++;
5911 selectedItemsAvgPos += item->scenePos().toPoint();
5912 selectedItemCount++;
5916 selectedItemsAvgPos /= selectedItemCount;
5918 string parentCompositionPath = windowFilePath().toStdString();
5921 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent, subcompositionDir);
5927 string nodeClassName = subcompositionWindow->installSubcomposition(parentCompositionPath);
5928 if (!nodeClassName.empty())
5934 selectedItemsAvgPos.x(),
5935 selectedItemsAvgPos.y());
5936 if (!subcompositionNode)
5943 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5945 subcompositionNode);
5947 undoStack->beginMacro(tr(
"Package as Subcomposition"));
5950 QList<QGraphicsItem *> itemsToRemove;
5952 itemsToRemove.append(node);
5954 itemsToRemove.append(comment);
5956 undoStack->push(
new VuoCommandRemove(itemsToRemove,
this, inputEditorManager,
"Package as Subcomposition",
true));
5959 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5960 componentsToAdd.append(subcompositionNode);
5961 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"",
true));
5964 QList<QGraphicsItem *> inputCablesToRestore;
5965 for (
int i = 0; i < inputCablesToRestoreEventOnly.size(); ++i)
5972 if (fromNode && fromPort && toNode && toPort &&
5984 inputCablesToRestore.append(cable);
5992 inputCablesToRestoreEventOnly[i],
5993 inputCablesToRestoreFromPort[i],
6000 QList<QGraphicsItem *> outputCablesToRestore;
6001 for (
int i = 0; i < outputCablesToRestoreEventOnly.size(); ++i)
6008 if (fromNode && fromPort && toNode && toPort &&
6020 outputCablesToRestore.append(cable);
6028 outputCablesToRestoreEventOnly[i],
6029 outputCablesToRestoreToPort[i],
6036 undoStack->push(
new VuoCommandAdd(inputCablesToRestore,
this));
6037 undoStack->push(
new VuoCommandAdd(outputCablesToRestore,
this));
6041 string compositionIdentifier =
static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->getCompositionIdentifier(composition);
6043 set<VuoCompilerNode *> nodesMoved;
6044 for (QGraphicsItem *item : itemsToRemove)
6053 string compositionSnapshot = composition->
takeSnapshot();
6056 diffInfo->
addRefactoring(compositionIdentifier, nodesMoved, subcompositionMovedTo);
6060 undoStack->endMacro();
6068 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
6087 return raiseDocumentAction;
6095 return ui->showEvents;
6119 return ui->zoomToFit;
6157 return ownedNodeLibrary;
6176 transitionNodeLibraryConnections(this->nl, library);
6186 transitionNodeLibraryConnections((previousFloaterDestroyed? NULL : this->nl), this->ownedNodeLibrary);
6187 this->nl = this->ownedNodeLibrary;
6195 return ui->menuFile;
6203 return menuOpenRecent;
6228 disconnect(oldLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6229 disconnect(oldLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6232 disconnect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), oldLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6247 connect(newLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6248 connect(newLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6251 connect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), newLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6267 void VuoEditorWindow::restoreDefaultLeftDockedWidgetWidths()
6271 nl->setMinimumWidth(nodeLibraryMinimumWidth);
6272 nl->setMaximumWidth(nodeLibraryMaximumWidth);
6275 if (inputPortSidebar && outputPortSidebar)
6277 inputPortSidebar->setMinimumWidth(outputPortSidebar->minimumWidth());
6278 inputPortSidebar->setMaximumWidth(outputPortSidebar->maximumWidth());
6288 QPoint positionChange =
event->pos() -
event->oldPos();
6289 composition->
movePopoversBy(positionChange.x(), positionChange.y());
6291 QMainWindow::moveEvent(
event);
6302 toolbar->updateTitle();
6305 QMainWindow::resizeEvent(
event);
6313 QList<QGraphicsItem *> VuoEditorWindow::createAnyNecessaryMakeListComponents(
VuoPort *port)
6315 QList<QGraphicsItem *> makeListComponents;
6324 makeListComponents.append(makeListNode);
6325 makeListComponents.append(makeListCable);
6328 return makeListComponents;
6334 void VuoEditorWindow::updateGrid()
6336 QGraphicsView::CacheMode defaultViewportCacheMode = ui->graphicsView->cacheMode();
6338 ui->graphicsView->setCacheMode(QGraphicsView::CacheNone);
6339 ui->graphicsView->viewport()->update();
6341 ui->graphicsView->setCacheMode(defaultViewportCacheMode);
6347 void VuoEditorWindow::updateCanvasOpacity()
6349 int opacity =
static_cast<VuoEditor *
>(qApp)->getCanvasOpacity();
6356 void VuoEditorWindow::updateColor(
bool isDark)
6359 QString backgroundColor = colors->
canvasFill().name();
6360 QString scrollBarColor = isDark ?
"#505050" :
"#dfdfdf";
6361 QString dockwidgetTitleBackgroundColor = isDark ?
"#919191" :
"#efefef";
6363 QString menuStyle = VUO_QSTRINGIFY(
6367 background-color: #404040;
6372 padding-right: 36px;
6375 QMenu::item:disabled {
6378 QMenu::item:selected {
6379 background-color: #1060d0;
6382 QMenu::right-arrow {
6385 QMenu::indicator:checked {
6386 image: url(:/Icons/checkmark.svg);
6389 QMenu::indicator:checked,
6393 QMenu::icon:checked,
6394 QMenu::icon:unchecked {
6399 if (doneInitializing)
6400 setStyleSheet(VUO_QSTRINGIFY(
6401 QMainWindow::separator {
6402 background-color: %1;
6409 .arg(dockwidgetTitleBackgroundColor)
6410 + (isDark ? menuStyle :
""));
6413 ui->graphicsView->setStyleSheet(isDark ? menuStyle :
"");
6415 ui->graphicsView->setStyleSheet(VUO_QSTRINGIFY(
6421 QScrollBar::handle {
6428 QAbstractScrollArea::corner,
6430 QScrollBar::sub-line,
6432 QScrollBar::sub-page {
6437 .arg(backgroundColor)
6438 .arg(scrollBarColor)
6439 + (isDark ? menuStyle :
""));
6442 if (doneInitializing)
6454 void VuoEditorWindow::coalescedUpdateRunningComposition()
6456 if (coalescedOldCompositionSnapshot.empty() != coalescedNewCompositionSnapshot.empty())
6459 foreach (
string nodeID, coalescedNodesToUnlink)
6460 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->unlinkNodeInSupercompositionFromSubcomposition(composition, nodeID);
6462 if (!coalescedOldCompositionSnapshot.empty() && !coalescedNewCompositionSnapshot.empty())
6463 composition->
updateRunningComposition(coalescedOldCompositionSnapshot, coalescedNewCompositionSnapshot, coalescedDiffInfo);
6465 foreach (
string portID, coalescedInternalPortConstantsToSync)
6468 foreach (
string portID, coalescedPublishedPortConstantsToSync)
6471 foreach (
string nodeID, coalescedNodesToRelink)
6472 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->relinkNodeInSupercompositionToSubcomposition(composition, nodeID);
6474 coalescedOldCompositionSnapshot =
"";
6475 coalescedNewCompositionSnapshot =
"";
6476 coalescedInternalPortConstantsToSync.clear();
6477 coalescedPublishedPortConstantsToSync.clear();
6478 coalescedNodesToUnlink.clear();
6479 coalescedNodesToRelink.clear();
6480 coalescedDiffInfo =
nullptr;
6489 if (diffInfo && coalescedDiffInfo)
6490 coalescedUpdateRunningComposition();
6492 if (coalescedOldCompositionSnapshot.empty())
6493 coalescedOldCompositionSnapshot = oldCompositionSnapshot;
6495 coalescedNewCompositionSnapshot = newCompositionSnapshot;
6496 coalescedDiffInfo = diffInfo;
6504 coalescedInternalPortConstantsToSync.push_back(portID);
6512 coalescedPublishedPortConstantsToSync.push_back(portID);
6520 coalescedNodesToUnlink.push_back(nodeID);
6528 coalescedNodesToRelink.push_back(nodeID);
6536 void VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests()
6538 if (protocolComplianceReevaluationPending)
6540 evaluateCompositionForProtocolPromotion();
6541 protocolComplianceReevaluationPending =
false;
6553 void VuoEditorWindow::registerProtocolComplianceEvaluationRequest()
6555 this->protocolComplianceReevaluationPending =
true;
6563 return ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(QCursor::pos()));
6571 return metadataPanel;
6585 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
6586 double targetX = min(max(origPos.x(), viewportRect.left()+leftMargin), viewportRect.right()-rightMargin);
6587 double targetY = min(max(origPos.y(), viewportRect.top()+topMargin), viewportRect.bottom()-bottomMargin);
6590 bool targetPositionClearOfCoincidentNodes =
false;
6591 while (!targetPositionClearOfCoincidentNodes)
6593 QGraphicsItem *preexistingItem = composition->itemAt(QPoint(targetX, targetY), composition->views()[0]->transform());
6594 if (
dynamic_cast<VuoRendererNode *
>(preexistingItem) && (preexistingItem->scenePos() == QPoint(targetX, targetY)))
6596 targetX += pastedComponentOffset;
6597 targetY += pastedComponentOffset;
6600 targetPositionClearOfCoincidentNodes =
true;
6603 return QPointF(targetX, targetY);
6609 void VuoEditorWindow::toggleNodeLibraryDockedState()
6613 bool floatLibrary = !nl->isFloating();
6614 nl->setFloating(floatLibrary);
6615 nl->
fixWidth(!floatLibrary && !inputPortSidebar->isHidden());
6625 undoStack->beginMacro(tr(commandName.toUtf8().constData()));
6633 undoStack->endMacro();