11#include "ui_VuoEditorWindow.h"
86#include <objc/objc-runtime.h>
95const qreal VuoEditorWindow::viewportStepRate = 1;
96const qreal VuoEditorWindow::viewportStepRateMultiplier = 5;
97const qreal VuoEditorWindow::zoomRate = 1.2;
98const qreal VuoEditorWindow::pastedComponentOffset = 20;
99const qreal VuoEditorWindow::compositionMargin = 20;
113 const string &compositionAsString,
118 string nodeClassToHighlight) :
121 doneInitializing =
false;
124 this->compiler =
new VuoCompiler(compositionPath.toStdString());
125 this->composition =
nullptr;
127 this->compositionUpgradedSinceLastSave =
false;
128 this->protocolComplianceReevaluationPending =
false;
129 this->ignoreItemMoveSignals =
false;
130 this->closing =
false;
131 this->containedPrepopulatedContent = (!compositionAsString.empty() || activeProtocol);
132 this->publishedPortNearCursorPreviously =
false;
133 this->zoomOutToFitOnNextShowEvent = nodeClassToHighlight.empty();
134 this->includeInRecentFileMenu =
true;
148 ui->newComposition->setShortcut(QKeySequence(
"Ctrl+N"));
149 ui->openComposition->setShortcut(QKeySequence(
"Ctrl+O"));
150 ui->saveComposition->setShortcut(QKeySequence(
"Ctrl+S"));
151 ui->saveCompositionAs->setShortcut(QKeySequence(
"Ctrl+Shift+S"));
152 ui->closeComposition->setShortcut(QKeySequence(
"Ctrl+W"));
153 ui->selectAll->setShortcut(QKeySequence(
"Ctrl+A"));
154 ui->selectNone->setShortcut(QKeySequence(
"Ctrl+Shift+A"));
155 ui->cutCompositionComponents->setShortcut(QKeySequence(
"Ctrl+X"));
156 ui->copyCompositionComponents->setShortcut(QKeySequence(
"Ctrl+C"));
157 ui->duplicateCompositionComponents->setShortcut(QKeySequence(
"Ctrl+D"));
158 ui->paste->setShortcut(QKeySequence(
"Ctrl+V"));
159 ui->deleteCompositionComponents->setShortcut(QKeySequence(
"Backspace"));
160 ui->zoomIn->setShortcut(QKeySequence(
"Ctrl+="));
161 ui->zoomOut->setShortcut(QKeySequence(
"Ctrl+-"));
162 ui->zoom11->setShortcut(QKeySequence(
"Ctrl+0"));
163 isZoomedToFit =
false;
164 addAction(ui->stopComposition);
165 ui->showNodeLibrary->setShortcut(QKeySequence(
"Ctrl+Return"));
173 QAction *aboutAction =
new QAction(
nullptr);
174 aboutAction->setText(tr(
"About Vuo…"));
176 aboutAction->setMenuRole(QAction::AboutRole);
177 ui->menuFile->addAction(aboutAction);
181 quitAction =
new QAction(
nullptr);
182 quitAction->setText(tr(
"&Quit"));
183 quitAction->setShortcut(QKeySequence(
"Ctrl+Q"));
185 quitAction->setMenuRole(QAction::QuitRole);
186 ui->menuFile->addAction(quitAction);
190 ui->menuView->addSeparator();
194 ui->menuView->addAction(editor->darkInterfaceAction);
201 QMenu *menuGrid =
new QMenu(ui->menuBar);
202 menuGrid->setSeparatorsCollapsible(
false);
203 menuGrid->setTitle(tr(
"&Grid"));
206 menuGrid->addSeparator();
212 ui->menuView->addMenu(menuGrid);
215 QMenu *menuCanvasTransparency =
new QMenu(ui->menuBar);
216 menuCanvasTransparency->setSeparatorsCollapsible(
false);
217 menuCanvasTransparency->setTitle(tr(
"&Canvas Transparency"));
218 ((
VuoEditor *)qApp)->populateCanvasTransparencyMenu(menuCanvasTransparency);
221 ui->menuView->addMenu(menuCanvasTransparency);
224 menuNewCompositionWithTemplate =
new QMenu(tr(
"New Composition from Template"));
225 menuNewCompositionWithTemplate->setSeparatorsCollapsible(
false);
226 ((
VuoEditor *)qApp)->populateNewCompositionWithTemplateMenu(menuNewCompositionWithTemplate);
229 QMenu *menuNewShader =
new QMenu(tr(
"New Shader"));
230 menuNewShader->setSeparatorsCollapsible(
false);
231 ((
VuoEditor *)qApp)->populateNewShaderMenu(menuNewShader);
234 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
236 if (ui->menuFile->actions().at(menuFileIndex) == ui->newComposition)
238 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuNewCompositionWithTemplate);
239 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuNewShader);
252 for (
int menuFileIndex = 0; menuFileIndex < ui->menuFile->actions().count(); ++menuFileIndex)
253 if (ui->menuFile->actions().at(menuFileIndex) == ui->openComposition)
255 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+1), menuOpenRecent);
256 ui->menuFile->insertMenu(ui->menuFile->actions().at(menuFileIndex+2), menuOpenExample);
264 menuProtocols =
new QMenu(tr(
"Protocols"));
265 menuProtocols->setSeparatorsCollapsible(
false);
266 populateProtocolsMenu(menuProtocols);
269 ui->menuEdit->insertMenu(ui->compositionInformation, menuProtocols);
272 ((
VuoEditor *)qApp)->populateHelpMenu(ui->menuHelp);
278 connect(ui->menuHelp, &QMenu::aboutToShow, [editor,
this] { editor->populateHelpMenu(ui->menuHelp); });
291 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->addComposition(
this);
293 if (!compositionAsString.empty())
295 string dir, file, extension;
305 ui->graphicsView->setScene(composition);
306 ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
307 ui->graphicsView->setMouseTracking(
true);
308 composition->installEventFilter(
this);
309 ui->graphicsView->viewport()->installEventFilter(
this);
313 connect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
317 connect(ui->refactor, &QAction::triggered,
this, &VuoEditorWindow::refactorSelectedItems);
322 raiseDocumentAction =
new QAction(
this);
323 raiseDocumentAction->setCheckable(
true);
330 inputEditorSession =
nullptr;
345 undoStack =
new QUndoStack(
this);
346 connect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
348 undoAction = undoStack->createUndoAction(
this);
349 undoAction->setText(tr(
"Undo"));
350 undoAction->setShortcut(QKeySequence::Undo);
352 redoAction = undoStack->createRedoAction(
this);
353 redoAction->setText(tr(
"Redo"));
354 redoAction->setShortcut(QKeySequence::Redo);
357 metadataEditor->setWindowModality(Qt::WindowModal);
358 connect(metadataEditor, &VuoMetadataEditor::finished,
this, &VuoEditorWindow::editMetadata);
360 searchBox =
new VuoSearchBox(composition,
this, Qt::Widget);
361 searchBox->setVisible(
false);
364 canvasDragEnabled =
false;
365 canvasDragInProgress =
false;
366 scrollInProgress =
false;
367 timeOfLastScroll = 0;
368 consumeNextMouseReleaseToCanvas =
false;
369 lastLeftMousePressHadOptionModifier =
false;
370 rubberBandSelectionInProgress =
false;
371 previousDragMoveWasOverSidebar =
false;
372 duplicationMacroInProgress =
false;
373 itemDragMacroInProgress =
false;
377 commentResizeMacroInProgress =
false;
378 commentBeingResized = NULL;
381 forwardingEventsToCanvas =
false;
383 ui->menuEdit->insertAction(ui->menuEdit->actions()[0], redoAction);
384 ui->menuEdit->insertAction(redoAction, undoAction);
387 ui->menuEdit->insertMenu(ui->changeNodePlaceholder, contextMenuTints);
389 menuChangeNode =
new QMenu(ui->menuEdit);
390 menuChangeNode->setTitle(tr(
"Change To"));
393 connect(ui->menuEdit, &QMenu::aboutToShow,
this, &VuoEditorWindow::updateChangeNodeMenu);
395 foreach (QMenu *menu, ui->menuBar->findChildren<QMenu*>())
396 menu->setSeparatorsCollapsible(
false);
442 setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
443 setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
445 connect(ui->toggleNodeLibraryDocking, &QAction::triggered,
this, &VuoEditorWindow::toggleNodeLibraryDockedState);
447 QActionGroup* toggleDisplay=
new QActionGroup(
this);
448 toggleDisplay->addAction(ui->actionShowNodeNames);
449 toggleDisplay->addAction(ui->actionShowNodeClassNames);
454 inputPortSidebar->setVisible(
false);
455 outputPortSidebar->setVisible(
false);
459 connect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
460 connect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
465 connect(inputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
466 connect(outputPortSidebar, &VuoPublishedPortSidebar::visibilityChanged,
this, &VuoEditorWindow::conditionallyShowPublishedPortSidebars);
476 connect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
477 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
478 connect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
479 connect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
480 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
481 connect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
482 connect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
484 connect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
485 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
490 connect(composition, SIGNAL(portPublicationRequested(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
495 connect(composition, SIGNAL(publishedPortModified()), inputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
496 connect(composition, SIGNAL(publishedPortModified()), outputPortSidebar, SLOT(updatePortList()), Qt::QueuedConnection);
503 connect(inputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
504 connect(outputPortSidebar, SIGNAL(portPublicationRequestedViaSidebarPort(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)),
this, SLOT(
internalExternalPortPairPublished(
VuoPort *,
VuoPublishedPort *,
bool,
VuoPort *,
string,
string,
bool)));
523 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
524 connect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
525 connect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
526 connect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
528 connect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()), Qt::QueuedConnection);
531 VuoEditorWindow_Pro();
534 coalescedOldCompositionSnapshot =
"";
535 coalescedNewCompositionSnapshot =
"";
536 coalescedDiffInfo =
nullptr;
544 initializeNodeLibrary(this->compiler, nodeLibraryDisplayMode, nodeLibraryState, floater);
550 connect(composition, &VuoEditorComposition::changed,
this, &VuoEditorWindow::ensureSceneRectContainsRegion);
553 connect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::updateSelectedComponentMenuItems);
562 ui->graphicsView->setCacheMode(QGraphicsView::CacheBackground);
564 ui->graphicsView->setAttribute(Qt::WA_NoBackground,
true);
565 ui->graphicsView->setAttribute(Qt::WA_OpaquePaintEvent);
566 ui->graphicsView->setAttribute(Qt::WA_NoSystemBackground);
570 nl->setAttribute(Qt::WA_NoBackground,
true);
571 nl->setAttribute(Qt::WA_OpaquePaintEvent);
572 nl->setAttribute(Qt::WA_NoSystemBackground);
579 if (compositionAsString.empty())
595 if (compositionAsString.empty())
606 evaluateCompositionForProtocolPromotion();
615 setPublishedPortSidebarVisibility(displayPublishedPorts);
620 doneInitializing =
true;
622 updateCanvasOpacity();
624 string dir, file, ext;
630 setWindowTitle(documentIdentifier +
"[*]");
632 toolbar->updateTitle();
642 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
643 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
644 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
652 setWindowFilePath(documentIdentifier);
664 if (!nodeClassToHighlight.empty())
668 updateRefireAction();
671 QMetaObject::invokeMethod(
this,
"showUpdateHelpDialog", Qt::QueuedConnection);
674VuoEditorWindow::~VuoEditorWindow()
678 disconnect(inputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
679 disconnect(outputPortSidebar->
getRemoveProtocolAction(), &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
692 disconnect(ui->graphicsView, SIGNAL(viewResized()), outputPortSidebar, SLOT(externalMoveEvent()));
694 disconnect(ui->graphicsView->horizontalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
695 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
696 disconnect(ui->graphicsView->horizontalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
697 disconnect(ui->graphicsView->verticalScrollBar(), &QScrollBar::valueChanged,
this, &VuoEditorWindow::viewportFitReset);
698 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(valueChanged(
int)), outputPortSidebar, SLOT(externalMoveEvent()));
699 disconnect(ui->graphicsView->verticalScrollBar(), SIGNAL(rangeChanged(
int,
int)), outputPortSidebar, SLOT(externalMoveEvent()));
700 disconnect(ui->graphicsView, &VuoEditorGraphicsView::rubberBandChanged,
this, &VuoEditorWindow::updateRubberBandSelectionMode);
711 disconnect(ui->duplicateCompositionComponents, &QAction::triggered,
this, &VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem);
715 disconnect(ui->menuEdit, &QMenu::aboutToShow,
this, &VuoEditorWindow::updateChangeNodeMenu);
719 disconnect(undoStack, &QUndoStack::cleanChanged,
this, &VuoEditorWindow::undoStackCleanStateChanged);
721 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::coalescedUpdateRunningComposition);
722 disconnect(undoStack, &QUndoStack::indexChanged,
this, &VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests);
723 disconnect(undoStack, SIGNAL(indexChanged(
int)), inputPortSidebar, SLOT(updatePortList()));
724 disconnect(undoStack, SIGNAL(indexChanged(
int)), outputPortSidebar, SLOT(updatePortList()));
725 disconnect(undoStack, SIGNAL(indexChanged(
int)), composition, SLOT(updateFeedbackErrors()));
727 disconnect(composition, &VuoEditorComposition::sceneRectChanged,
this, &VuoEditorWindow::viewportFitReset);
728 disconnect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::viewportFitReset);
729 disconnect(composition, &VuoEditorComposition::selectionChanged,
this, &VuoEditorWindow::updateSelectedComponentMenuItems);
735 transitionNodeLibraryConnections(nl, NULL);
739 delete metadataPanel;
745 map<string, string> constantPortIdentifiersAndValues;
746 string revertedSourceCode;
751 catch (std::exception
const &e)
759 for (
VuoNode *node : revertedComposition->getBase()->getNodes())
761 for (
VuoPort *port : node->getInputPorts())
763 if (port->hasCompiler())
774 delete revertedComposition;
779 topLevelComposition->getModuleManager()->doNextTimeNodeClassIsLoaded(nodeClassName, ^{
781 for (
auto i : constantPortIdentifiersAndValues)
782 topLevelComposition->updateInternalPortConstantInSubcompositionInstances(subcompositionPath, i.first, i.second);
798 dispatch_sync(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{});
805void VuoEditorWindow::showUpdateHelpDialog()
809 bool foundCommunityNode =
false;
810 for (
VuoNode *node : composition->getBase()->getNodes())
814 foundCommunityNode =
true;
819 if (foundCommunityNode)
821 QString summary = tr(
"This composition was created in an earlier version of Vuo. It might behave differently now.");
822 QString details = tr(
"<p><a href=\"%1\">How do I update my compositions from Vuo 1.x to Vuo 2.0?</a></p>")
823 .arg(
"https://vuo.org/node/2376");
824 QString checkboxLabel = tr(
"Show this window when opening compositions.");
825 QString settingsKey =
"showUpdateHelp";
837 updateSelectedComponentMenuItems();
838 updateToolbarElementUI();
841 ui->compositionInformation->setEnabled(
true);
846 ui->stopComposition->setEnabled(
false);
847 ui->restartComposition->setEnabled(
false);
851 ui->runComposition->setEnabled(
false);
852 ui->stopComposition->setEnabled(
true);
853 ui->restartComposition->setEnabled(
true);
855 else if (toolbar && toolbar->
isRunning())
857 ui->runComposition->setEnabled(
false);
858 ui->stopComposition->setEnabled(
true);
859 ui->restartComposition->setEnabled(
true);
863 ui->runComposition->setEnabled(
true);
864 ui->stopComposition->setEnabled(
false);
865 ui->restartComposition->setEnabled(
false);
874 auto found = std::find_if(openWindows.begin(), openWindows.end(), [](
VuoEditorWindow *w){ return w->metadataEditor->isVisible(); });
875 bool isCompositionInformationOpen = (found != openWindows.end());
876 quitAction->setEnabled(! isCompositionInformationOpen);
879 QString savedPath = windowFilePath();
880 string savedDir, savedFile, savedExt;
884 ui->saveComposition->setEnabled(enableSaveMenuItem);
887 bool hasErrors =
true;
888 if (! alreadyInstalledAsUserSubcomposition)
899 ui->saveComposition->setText(tr(
"Save"));
900 ui->saveCompositionAs->setText(tr(
"Save As…"));
901 ui->installSubcomposition->setEnabled(!alreadyInstalledAsUserSubcomposition && !hasErrors);
903 tr(
"Move to User Library") :
904 tr(
"Save to User Library"));
907 updateProtocolsMenu(menuProtocols);
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();
991void VuoEditorWindow::updateToolbarElementUI()
996 ui->zoom11->setEnabled(! ui->graphicsView->transform().isIdentity());
997 ui->zoomToFit->setEnabled(! isZoomedToFit);
998 ui->showEvents->setText(composition->
getShowEventsMode() ? tr(
"Hide Events") : tr(
"Show Events"));
1004void VuoEditorWindow::updateRefireAction()
1006 __block
bool isTopLevelCompositionRunning =
false;
1007 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->applyToLinkedTopLevelComposition(composition, ^
void (
VuoEditorComposition *topLevelComposition,
string thisCompositionIdentifier)
1009 isTopLevelCompositionRunning = topLevelComposition->
isRunning();
1012 ui->refireEvent->setEnabled(isTopLevelCompositionRunning ? (
bool)composition->
getTriggerPortToRefire() :
false);
1018void VuoEditorWindow::updateWindowForNewCableDrag()
1029void VuoEditorWindow::updateCursor()
1031 QCursor updatedCursor = (canvasDragInProgress? Qt::ClosedHandCursor :
1032 (canvasDragEnabled? Qt::OpenHandCursor :
1037 setCursor(Qt::ArrowCursor);
1039 setCursor(updatedCursor);
1051 foreach (QWidget *widget, qApp->topLevelWidgets())
1054 if (w && w->isVisible() && !w->containedPrepopulatedContent && (w->windowFilePath() ==
"") && (!w->isWindowModified()))
1066 if ((!nodes.empty() || !comments.empty()) && !ignoreItemMoveSignals)
1069 if (movedByDragging && !duplicationMacroInProgress)
1071 itemDragMacroInProgress =
true;
1075 QGraphicsItem *firstItem = (!nodes.empty()?
static_cast<QGraphicsItem *
>(*nodes.begin()) :
1076 static_cast<QGraphicsItem *
>(*comments.begin()));
1078 if (std::find(itemsBeingDragged.begin(), itemsBeingDragged.end(), firstItem) == itemsBeingDragged.end())
1079 itemsBeingDragged.push_back(firstItem);
1081 if (firstItem == itemsBeingDragged[0])
1088 if (!itemDragMacroInProgress)
1089 undoStack->push(
new VuoCommandMove(nodes, comments, dx, dy,
this, movedByDragging));
1099 commentResizeMacroInProgress =
true;
1100 commentBeingResized = comment;
1101 commentResizeDx += dx;
1102 commentResizeDy += dy;
1111 if ((target == composition) && (! components.empty()))
1112 undoStack->push(
new VuoCommandAdd(components,
this,
"Add"));
1119string VuoEditorWindow::getMaximumSubcompositionFromSelection(
bool includePublishedPorts,
bool includeHeader)
1121 QList<QGraphicsItem *> selectedComponents = composition->selectedItems();
1124 QList<QGraphicsItem *> selectedComponentsWithAttachments;
1125 foreach (QGraphicsItem *item, selectedComponents)
1127 selectedComponentsWithAttachments.append(item);
1132 foreach (QGraphicsItem *attachment, dependentAttachments)
1133 selectedComponentsWithAttachments.push_back(attachment);
1137 QList<QGraphicsItem *> selectedNonStrandedCompositionComponents;
1139 QStringList nodeDeclarations;
1140 vector<VuoRendererNode *> nodesToCopy;
1141 vector<QGraphicsItem *> potentialTypecastNodesToCopy;
1142 map<string, bool> nodeRepresented;
1143 vector<VuoRendererComment *> commentsToCopy;
1145 for (QList<QGraphicsItem *>::iterator i = selectedComponentsWithAttachments.begin(); i != selectedComponentsWithAttachments.end(); ++i)
1149 bool strandedAttachment = (attachment && isStrandedAttachment(attachment, selectedComponentsWithAttachments));
1155 nodesToCopy.push_back(rn);
1157 selectedNonStrandedCompositionComponents.append(rn);
1162 for (vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1173 commentsToCopy.push_back(rcomment);
1177 selectedNonStrandedCompositionComponents.append(QList<QGraphicsItem *>::fromVector(QVector<QGraphicsItem *>::fromStdVector(potentialTypecastNodesToCopy)));
1181 for (vector<QGraphicsItem *>::iterator node = potentialTypecastNodesToCopy.begin(); node != potentialTypecastNodesToCopy.end(); ++node)
1183 bool inputCableCopied =
false;
1184 bool childPortIsPublished =
false;
1185 vector<VuoPort *> inputPorts = ((
VuoRendererNode *)(*node))->getBase()->getInputPorts();
1186 for(vector<VuoPort *>::iterator inputPort = inputPorts.begin(); inputPort != inputPorts.end(); ++inputPort)
1188 vector<VuoCable *> inputCables = (*inputPort)->getConnectedCables(
true);
1189 for (vector<VuoCable *>::iterator inputCable = inputCables.begin(); inputCable != inputCables.end(); ++inputCable)
1191 if (std::find(internalCableSet.begin(), internalCableSet.end(), (*inputCable)->getRenderer()) != internalCableSet.end())
1192 inputCableCopied =
true;
1193 if ((*inputCable)->isPublished())
1194 childPortIsPublished =
true;
1200 if (inputCableCopied || (childPortIsPublished && includePublishedPorts))
1202 if (! nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()])
1205 nodeRepresented[((
VuoRendererNode *)(*node))->getBase()->getCompiler()->getGraphvizIdentifier()] =
true;
1212 set<VuoCable *> connectedCables = ((
VuoRendererNode *)(*node))->getConnectedCables(
false);
1213 for (set<VuoCable *>::iterator cable = connectedCables.begin(); cable != connectedCables.end(); ++cable)
1214 internalCableSet.erase((*cable)->getRenderer());
1218 vector<VuoRendererCable *> cablesToCopy(internalCableSet.begin(), internalCableSet.end());
1219 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1221 set<VuoNode *> baseNodesToCopy;
1222 for (vector<VuoRendererNode *>::iterator i = nodesToCopy.begin(); i != nodesToCopy.end(); ++i)
1223 baseNodesToCopy.insert( (*i)->getBase() );
1224 set<VuoCable *> baseCablesToCopy;
1225 for (vector<VuoRendererCable *>::iterator i = cablesToCopy.begin(); i != cablesToCopy.end(); ++i)
1226 baseCablesToCopy.insert( (*i)->getBase() );
1227 set<VuoComment *> baseCommentsToCopy;
1228 for (vector<VuoRendererComment *>::iterator i = commentsToCopy.begin(); i != commentsToCopy.end(); ++i)
1229 baseCommentsToCopy.insert( (*i)->getBase() );
1232 set<VuoPublishedPort *> subcompositionPublishedInputPortSet;
1233 set<VuoPublishedPort *> subcompositionPublishedOutputPortSet;
1235 if (includePublishedPorts)
1241 if (baseNodesToCopy.find(cable->
getToNode()) != baseNodesToCopy.end())
1243 subcompositionPublishedInputPortSet.insert(publishedInputPort);
1244 baseCablesToCopy.insert(cable);
1253 if (baseNodesToCopy.find(cable->
getFromNode()) != baseNodesToCopy.end())
1255 subcompositionPublishedOutputPortSet.insert(publishedOutputPort);
1256 baseCablesToCopy.insert(cable);
1263 vector<VuoPublishedPort *> subcompositionPublishedInputPorts;
1265 if (subcompositionPublishedInputPortSet.find(port) != subcompositionPublishedInputPortSet.end())
1266 subcompositionPublishedInputPorts.push_back(port);
1268 vector<VuoPublishedPort *> subcompositionPublishedOutputPorts;
1270 if (subcompositionPublishedOutputPortSet.find(port) != subcompositionPublishedOutputPortSet.end())
1271 subcompositionPublishedOutputPorts.push_back(port);
1276 subcompositionPublishedInputPorts,
1277 subcompositionPublishedOutputPorts,
1280 -viewportTopLeft.x(),
1281 -viewportTopLeft.y());
1283 return outputCompositionText;
1294 if (!(renderedHostNode && renderedHostNode->
hasRenderer() && selectedItems.contains(renderedHostNode->
getRenderer())))
1298 foreach (
VuoNode *coattachment, coattachments)
1315 QClipboard *clipboard = QApplication::clipboard();
1316 QMimeData *mimeData =
new QMimeData();
1323 mimeData->setText(getMaximumSubcompositionFromSelection(
false,
true).c_str());
1327 clipboard->setMimeData(mimeData);
1340 pasteCompositionComponents();
1341 else if (!clipboardText.isEmpty())
1354void VuoEditorWindow::pasteCompositionComponents()
1356 QClipboard *clipboard = QApplication::clipboard();
1357 const QMimeData *mimeData = clipboard->mimeData();
1362 int publishedCablesBeforePaste = 0;
1368 if (mimeData->hasFormat(
"text/plain"))
1372 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
1374 bool pasteAtCursorLoc = ((cursorPos != cursorPosAtLastComponentCopy) && viewportRect.contains(cursorPos));
1376 QString compositionText = mimeData->text();
1377 mergeCompositionComponentsFromString(compositionText.toUtf8().constData(), pasteAtCursorLoc, !pasteAtCursorLoc,
"Paste");
1383 int publishedCablesAfterPaste = 0;
1390 if ((publishedPortsAfterPaste > publishedPortsBeforePaste) || (publishedCablesAfterPaste > publishedCablesBeforePaste))
1391 setPublishedPortSidebarVisibility(
true);
1403 if (! duplicationMacroInProgress)
1405 undoStack->beginMacro(tr(
"Duplication"));
1406 duplicationMacroInProgress =
true;
1409 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1410 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
false,
"Duplication");
1413 composition->clearSelection();
1414 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1415 (*i)->setSelected(
true);
1427 string genericNodeClassName;
1431 genericNodeClassName = currentNodeClass->
getClassName();
1433 if ((genericNodeClassName == nodeClass) && node->
hasRenderer())
1438 QRectF selectedItemsRect;
1439 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
1440 selectedItemsRect |= selectedComponent->sceneBoundingRect();
1442 if (!selectedItemsRect.isNull())
1443 ui->graphicsView->centerOn(selectedItemsRect.center());
1453void VuoEditorWindow::duplicateSelectedCompositionComponentsByMenuItem()
1455 string subcompositionText = getMaximumSubcompositionFromSelection(
false,
true);
1456 QList<QGraphicsItem *> newComponents = mergeCompositionComponentsFromString(subcompositionText,
false,
true,
"Duplication");
1459 composition->clearSelection();
1460 for (QList<QGraphicsItem *>::iterator i = newComponents.begin(); i != newComponents.end(); ++i)
1461 (*i)->setSelected(
true);
1470 resetUndoStackMacros();
1473 undoAction->trigger();
1484 composition->
clear();
1485 instantiateNewCompositionComponentsFromString(snapshot);
1495void VuoEditorWindow::instantiateNewCompositionComponentsFromString(
string compositionText)
1516 composition->
addCable(cable,
false);
1547QList<QGraphicsItem *> VuoEditorWindow::mergeCompositionComponentsFromString(
string compositionText,
bool pasteAtCursorLoc,
bool pasteWithOffset,
string commandDescription)
1550 QList<QGraphicsItem *> pastedComponents = QList<QGraphicsItem *>();
1552 QPointF startPos = (pasteWithOffset? QPointF(pastedComponentOffset, pastedComponentOffset) : QPointF(0,0));
1555 for (
VuoNode *pastedNode : pastedComposition->getBase()->getNodes())
1557 if (pastedNode->getNodeClass()->hasCompiler())
1559 VuoNode *allowedNode = composition->
createBaseNode(pastedNode->getNodeClass()->getCompiler(), pastedNode);
1562 pastedComposition->
replaceNode(pastedNode, allowedNode);
1569 set<VuoNode *> pastedNodes = pastedComposition->
getBase()->
getNodes();
1570 for (
VuoNode *node : pastedNodes)
1573 pastedComponents.append(rn);
1580 pastedComponents.append(rc);
1583 qreal minX = std::numeric_limits<qreal>::max();
1584 qreal minY = std::numeric_limits<qreal>::max();
1586 if (pasteAtCursorLoc)
1589 for (
VuoNode *node : pastedNodes)
1595 if (node->
getX() < minX)
1596 minX = node->
getX();
1598 if (node->
getY() < minY)
1599 minY = node->
getY();
1604 if (comment->
getX() < minX)
1605 minX = comment->
getX();
1607 if (comment->
getY() < minY)
1608 minY = comment->
getY();
1615 QPointF viewportTopLeft = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect().topLeft();
1616 startPos += viewportTopLeft;
1620 this->ignoreItemMoveSignals =
true;
1621 for (
VuoNode *node : pastedNodes)
1623 node->
setX(startPos.x() + node->
getX());
1624 node->
setY(startPos.y() + node->
getY());
1631 comment->
setX(startPos.x() + comment->
getX());
1632 comment->
setY(startPos.y() + comment->
getY());
1636 this->ignoreItemMoveSignals =
false;
1639 for (
VuoCable *cable : pastedCables)
1644 pastedComponents.append(rc);
1652 map<VuoPublishedPort *, vector<pair<VuoPort *, bool> > > connectionsForPublishedPort;
1653 map<VuoPublishedPort *, bool> publishedPortHadConnectedDataCable;
1657 bool foundConnectedDataCable =
false;
1659 foreach (
VuoCable *cable, publishedInputCables)
1665 bool cableCarriesData = (compilerToPort && compilerToPort->
getDataVuoType() && !alwaysEventOnly);
1666 if (cableCarriesData)
1667 foundConnectedDataCable =
true;
1669 connectionsForPublishedPort[publishedInput].push_back(make_pair(toPort, alwaysEventOnly));
1672 cable->
setTo(NULL, NULL);
1675 publishedPortHadConnectedDataCable[publishedInput] = foundConnectedDataCable;
1680 bool foundConnectedDataCable =
false;
1681 vector<VuoCable *> publishedOutputCables = publishedOutput->
getConnectedCables(
true);
1682 foreach (
VuoCable *cable, publishedOutputCables)
1688 bool cableCarriesData = (compilerFromPort && compilerFromPort->
getDataVuoType() && !alwaysEventOnly);
1689 if (cableCarriesData)
1690 foundConnectedDataCable =
true;
1692 connectionsForPublishedPort[publishedOutput].push_back(make_pair(fromPort, alwaysEventOnly));
1695 cable->
setTo(NULL, NULL);
1698 publishedPortHadConnectedDataCable[publishedOutput] = foundConnectedDataCable;
1703 undoStack->beginMacro(tr(commandDescription.c_str()));
1706 componentsPasted(pastedComponents, commandDescription);
1709 vector<VuoPublishedPort *> unmergedPublishedInputPorts;
1715 string pastedPublishedPortName = publishedInputPort->
getClass()->
getName();
1719 publishedPortHadConnectedDataCable[publishedInputPort]))
1721 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedInputPort];
1722 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1724 VuoPort *connectedPort = i->first;
1725 bool forceEventOnlyPublication = i->second;
1731 unmergedPublishedInputPorts.push_back(publishedInputPort);
1735 foreach (
VuoPublishedPort *unmergedPublishedInputPort, unmergedPublishedInputPorts)
1739 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedInputPort];
1740 if (!internalConnections.empty())
1742 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1744 VuoPort *connectedPort = i->first;
1745 bool forceEventOnlyPublication = i->second;
1753 unmergedPublishedInputPort->
getClass()->
setName(uniquePublishedPortName);
1760 vector<VuoPublishedPort *> unmergedPublishedOutputPorts;
1766 string pastedPublishedPortName = publishedOutputPort->
getClass()->
getName();
1770 publishedPortHadConnectedDataCable[publishedOutputPort]))
1772 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[publishedOutputPort];
1773 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1775 VuoPort *connectedPort = i->first;
1776 bool forceEventOnlyPublication = i->second;
1782 unmergedPublishedOutputPorts.push_back(publishedOutputPort);
1786 foreach (
VuoPublishedPort *unmergedPublishedOutputPort, unmergedPublishedOutputPorts)
1790 vector<pair<VuoPort *, bool> > internalConnections = connectionsForPublishedPort[unmergedPublishedOutputPort];
1791 if (!internalConnections.empty())
1793 for (vector<pair<VuoPort *, bool> >::iterator i = internalConnections.begin(); i != internalConnections.end(); ++i)
1795 VuoPort *connectedPort = i->first;
1796 bool forceEventOnlyPublication = i->second;
1804 unmergedPublishedOutputPort->
getClass()->
setName(uniquePublishedPortName);
1810 delete pastedComposition;
1812 undoStack->endMacro();
1814 return pastedComponents;
1821void VuoEditorWindow::componentsPasted(QList<QGraphicsItem *> components,
string commandDescription)
1823 if (components.empty())
1827 undoStack->push(
new VuoCommandAdd(components,
this, commandDescription));
1830 composition->clearSelection();
1831 for (QList<QGraphicsItem *>::iterator i = components.begin(); i != components.end(); ++i)
1832 (*i)->setSelected(
true);
1866 pair<VuoRendererCable *, VuoRendererCable *> cableArgs,
1868 pair<string, string> typeArgs,
1869 pair<VuoRendererPort *, VuoRendererPort *> portArgs)
1876 string typecastToInsert = typeArgs.first;
1877 string specializedTypeName = typeArgs.second;
1895 set<VuoRendererNode *> emptyNodeSet;
1896 set<VuoRendererComment *> emptyCommentSet;
1897 undoStack->push(
new VuoCommandMove(emptyNodeSet, emptyCommentSet, 0, 0,
this,
false));
1901 cableInProgress->
setTo(NULL, NULL);
1905 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
1907 VuoPort *typecastInPort = NULL;
1908 VuoPort *typecastOutPort = NULL;
1909 if (!typecastToInsert.empty())
1911 typecastNodeToAdd = composition->
createNode(typecastToInsert.c_str(),
"",
1912 targetPort->scenePos().x()+100,
1913 targetPort->scenePos().y()+100);
1915 typecastRelatedComponentsToAdd.append(typecastNodeToAdd);
1921 if (!(typecastInPort && typecastInPort->
hasRenderer() && typecastOutPort && typecastOutPort->
hasRenderer()))
1935 if (portToSpecialize)
1940 if (currentlyGeneric)
1945 if (!specializedNode)
1948 if (portToSpecialize == targetPort)
1956 unadjustedToPort = targetPort;
1960 unadjustedFromPort = targetPort;
1982 if (attachedDrawer && cableWillCarryData)
1984 QList<QGraphicsItem *> drawerRelatedComponentsToRemove;
1985 drawerRelatedComponentsToRemove.append(attachedDrawer);
1986 bool disableAutomaticAttachmentInsertion =
true;
1987 undoStack->push(
new VuoCommandRemove(drawerRelatedComponentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
1992 if (typecastNodeToDelete)
1994 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
1995 typecastRelatedComponentsToRemove.append(typecastNodeToDelete);
1996 typecastRelatedComponentsToRemove.append(dataCableToDisplace);
1998 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
"",
true));
2000 dataCableToDisplace = NULL;
2006 QList<QGraphicsItem *> componentsToReplace = QList<QGraphicsItem *>();
2007 componentsToReplace.append(cableToReplace);
2008 undoStack->push(
new VuoCommandRemove(componentsToReplace,
this, inputEditorManager,
"",
false));
2011 if (! typecastToInsert.empty())
2028 adjustedTargetPort = typecastInPort->
getRenderer();
2031 incomingTypecastCable = cableInProgress;
2045 adjustedTargetPort = typecastOutPort->
getRenderer();
2048 incomingTypecastCable = newCableConnectingTypecast;
2051 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2054 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2057 undoStack->push(
new VuoCommandConnect(cableInProgress, adjustedTargetPort, dataCableToDisplace, portToUnpublish,
this, inputEditorManager));
2061 if (targetPort->
getInput() && previousToPort && (previousToPort != targetPort->
getBase()))
2064 if (previousTypecastToPort)
2071 QList<QGraphicsItem *> typecastRelatedComponentsToRemove = QList<QGraphicsItem *>();
2072 typecastRelatedComponentsToRemove.append(uncollapsedTypecastToPort);
2073 undoStack->push(
new VuoCommandRemove(typecastRelatedComponentsToRemove,
this, inputEditorManager,
""));
2093 if (compatibleSpecializedTypes.size() == 1)
2095 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2107 if (! components.empty())
2108 undoStack->push(
new VuoCommandRemove(components,
this, inputEditorManager, commandDescription));
2129 unsigned long origItemCount;
2130 string itemTypeName;
2134 newNodeClass = compiler->
getNodeClass(newMakeListNodeClassName);
2140 string commandText = (inputPortCountDelta == -1?
"Remove Input Port" : (inputPortCountDelta == 1?
"Add Input Port" :
""));
2143 if (adjustmentedRequestedByDragging)
2148 if (oldMakeListNode)
2150 if (composition->mouseGrabberItem() == oldMakeListNode)
2151 oldMakeListNode->ungrabMouse();
2156 if (newMakeListNode)
2159 newMakeListNode->grabMouse();
2172 if (!newNodeCompilerClass)
2202 string commandText =
"Port Specialization";
2204 if (encapsulateInMacro)
2205 undoStack->beginMacro(tr(commandText.c_str()));
2216 newNode = specializeSinglePort(port, innermostSpecializedTypeName);
2220 map<VuoRendererNode *, VuoRendererNode *> nodesToSpecialize;
2221 nodesToSpecialize[originalNode] = newNode;
2224 for (pair<VuoNode *, VuoPort *> i : networkedGenericPorts)
2226 VuoNode *networkedNode = i.first;
2227 VuoPort *networkedPort = i.second;
2231 VuoRendererNode *mostRecentVersionOfNetworkedNode = originalNetworkedNode;
2232 VuoPort *mostRecentVersionOfNetworkedPort = networkedPort;
2233 auto foundIter = nodesToSpecialize.find(originalNetworkedNode);
2234 if (foundIter != nodesToSpecialize.end())
2237 if (!specializedNode)
2240 tr(
"Couldn't specialize node '%1' to type '%2'.")
2241 .arg(QString::fromStdString(originalNetworkedNode->
getBase()->
getTitle()),
2242 QString::fromStdString(specializedTypeName)).toStdString(),
2243 tr(
"The node might have failed to compile. Check the console log for details.").toStdString());
2249 mostRecentVersionOfNetworkedNode = specializedNode;
2250 mostRecentVersionOfNetworkedPort = networkedPortInSpecializedNode;
2254 if (specializedTypeName != originalTypeName)
2258 VuoRendererNode *newNetworkedNode = specializeSinglePort(mostRecentVersionOfNetworkedPort->
getRenderer(), innermostSpecializedTypeName);
2259 nodesToSpecialize[originalNetworkedNode] = newNetworkedNode;
2262 bool preserveDanglingCables =
true;
2263 undoStack->push(
new VuoCommandReplaceNode(nodesToSpecialize,
this, commandText, preserveDanglingCables));
2271 if (encapsulateInMacro)
2272 undoStack->endMacro();
2289 if (!specializableNodeClass)
2324 QString commandText = tr(
"Port Specialization");
2325 bool preserveDanglingCables =
true;
2326 bool resetConstantValues =
false;
2328 if (encapsulateInMacro)
2329 undoStack->beginMacro(commandText);
2335 map<VuoNode *, string> nodesToReplace;
2336 set<VuoCable *> cablesToDelete;
2340 QList<QGraphicsItem *> rendererCablesToDelete;
2341 foreach (
VuoCable *cableToDelete, cablesToDelete)
2347 rendererCablesToDelete.append(cableToDelete->
getRenderer());
2350 undoStack->push(
new VuoCommandRemove(rendererCablesToDelete,
this, inputEditorManager, commandText.toStdString()));
2355 nodesToReplace.clear();
2358 map<VuoRendererNode *, VuoRendererNode *> nodesToUnspecialize;
2361 for (map<VuoNode *, string>::iterator i = nodesToReplace.begin(); i != nodesToReplace.end(); ++i)
2363 VuoNode *nodeToRevert = i->first;
2364 string revertedNodeClass = i->second;
2367 nodesToUnspecialize[nodeToRevert->
getRenderer()] = revertedNode;
2369 if (nodeToRevert->
getRenderer() == originalParentNode)
2370 unspecializedParentNode = revertedNode;
2373 undoStack->push(
new VuoCommandReplaceNode(nodesToUnspecialize,
this, commandText.toStdString(), preserveDanglingCables, resetConstantValues));
2375 if (encapsulateInMacro)
2376 undoStack->endMacro();
2378 return unspecializedParentNode;
2409 string commandText =
"Port Re-specialization";
2412 if (encapsulateInMacro)
2413 undoStack->beginMacro(tr(commandText.c_str()));
2424 if (encapsulateInMacro)
2425 undoStack->endMacro();
2427 return specializedParentNode;
2439 if (!revertedNodeClass)
2452 undoStack->beginMacro(tr(
"Tint"));
2454 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
2455 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin(); i != selectedCompositionComponents.end(); ++i)
2466 undoStack->endMacro();
2472void VuoEditorWindow::hideSelectedInternalCables()
2480void VuoEditorWindow::hideCables(set<VuoRendererCable *> cables)
2482 undoStack->beginMacro(tr(
"Hide"));
2487 undoStack->endMacro();
2494void VuoEditorWindow::unhideCables(set<VuoRendererCable *> cables)
2496 bool publishedCableToUnhide =
false;
2497 undoStack->beginMacro(tr(
"Unhide"));
2502 publishedCableToUnhide =
true;
2507 if ((inputPortSidebar->isHidden() || outputPortSidebar->isHidden()) && publishedCableToUnhide)
2508 on_showPublishedPorts_triggered();
2510 undoStack->endMacro();
2517void VuoEditorWindow::createIsolatedExternalPublishedPort(
string typeName,
bool isInput)
2520 if (!typeName.empty() && !type)
2523 undoStack->beginMacro(tr(
"Add Published Port"));
2529 showPublishedPortNameEditor(rpp,
true);
2531 undoStack->endMacro();
2540 bool isPublishedOutput = port->
getInput();
2541 (isPublishedOutput? outputPortSidebar : inputPortSidebar)->updatePortList();
2542 string newName = (isPublishedOutput? outputPortSidebar : inputPortSidebar)->showPublishedPortNameEditor(port);
2544 if (originalName != newName)
2545 changePublishedPortName(port, newName, useUndoStack);
2554 internalPortPublished(internalPort, forceEventOnlyPublication, externalPort->
getClass()->
getName(),
true, portToSpecialize, specializedTypeName, typecastToInsert, useUndoStackMacro);
2571 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2572 on_showPublishedPorts_triggered();
2582 vector<VuoRendererPublishedPort *> preexistingPublishedPorts = targetPort->
getPublishedPorts();
2589 if (useUndoStackMacro)
2590 undoStack->beginMacro(tr(
"Publish Port"));
2593 if (portToSpecialize && portToSpecialize->
hasRenderer())
2598 if (currentlyGeneric)
2603 if (specializedNode && (portToSpecialize == targetPort->
getBase()))
2614 bool publishedCableExpectedToHaveData =
false;
2615 bool publishedPortExpectedToBeMerged =
false;
2626 if (publishedPortWithTargetName &&
2629 publishedPortExpectedToBeMerged =
true;
2631 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType && type);
2635 if (!publishedPortExpectedToBeMerged)
2637 publishedCableExpectedToHaveData = (!forceEventOnlyPublication && internalPortDataType);
2649 if (publishedCableExpectedToHaveData)
2655 QList<QGraphicsItem *> componentsToRemove;
2656 componentsToRemove.append(attachedDrawer);
2657 bool disableAutomaticAttachmentInsertion =
true;
2658 undoStack->push(
new VuoCommandRemove(componentsToRemove,
this, inputEditorManager,
"", disableAutomaticAttachmentInsertion));
2665 for (vector<VuoCable *>::iterator cable = connectedCables.begin(); (! displacedCable) && (cable != connectedCables.end()); ++cable)
2666 if ((*cable)->getRenderer()->effectivelyCarriesData())
2667 displacedCable = (*cable)->getRenderer();
2674 QList<QGraphicsItem *> typecastRelatedComponentsToAdd = QList<QGraphicsItem *>();
2675 if (! typecastToInsert.empty())
2679 targetPort->scenePos().x()+100,
2680 targetPort->scenePos().y()+100);
2682 typecastRelatedComponentsToAdd.append(typecast);
2701 adjustedTargetPort = typecastInPort->
getRenderer();
2716 adjustedTargetPort = typecastOutPort->
getRenderer();
2721 typecastRelatedComponentsToAdd.append(newCableConnectingTypecast);
2723 bool disableAutomaticAttachmentInsertion =
true;
2724 undoStack->push(
new VuoCommandAdd(typecastRelatedComponentsToAdd,
this,
"", disableAutomaticAttachmentInsertion));
2727 undoStack->push(
new VuoCommandPublishPort(adjustedTargetPort->
getBase(), displacedCable,
this, forceEventOnlyPublication, name, merge));
2739 if (compatibleSpecializedTypes.size() == 1)
2741 string loneCompatibleSpecializedType = *compatibleSpecializedTypes.begin();
2746 if (useUndoStackMacro)
2747 undoStack->endMacro();
2756 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2757 on_showPublishedPorts_triggered();
2759 undoStack->beginMacro(tr(
"Delete"));
2763 bool isPublishedInput = !port->
getInput();
2764 if (isPublishedInput)
2767 QList<QGraphicsItem *> removedDataCables;
2768 foreach (
VuoCable *cable, publishedInputCables)
2774 if (!removedDataCables.empty())
2775 undoStack->push(
new VuoCommandRemove(removedDataCables,
this, inputEditorManager,
"Delete"));
2779 undoStack->endMacro();
2788 if (inputPortSidebar->isHidden() || outputPortSidebar->isHidden())
2789 on_showPublishedPorts_triggered();
2791 undoStack->beginMacro(tr(
"Delete"));
2796 QList<QGraphicsItem *> makeListComponents = createAnyNecessaryMakeListComponents(port);
2797 if (! makeListComponents.empty())
2798 undoStack->push(
new VuoCommandAdd(makeListComponents,
this,
""));
2801 undoStack->endMacro();
2809 set<VuoPublishedPort *> publishedPortsToRemove,
2810 vector<VuoPublishedPort *> publishedPortsToAdd,
2811 bool beginUndoStackMacro,
2812 bool endUndoStackMacro)
2815 undoStack->beginMacro(tr(
"Protocol Port Modification"));
2818 for (map<VuoPublishedPort *, string>::iterator i = publishedPortsToRename.begin(); i != publishedPortsToRename.end(); ++i)
2821 string name = i->second;
2834 undoStack->endMacro();
2840void VuoEditorWindow::resetUndoStackMacros()
2842 if (itemDragMacroInProgress)
2844 itemDragMacroInProgress =
false;
2846 set<VuoRendererNode *> draggedNodeSet;
2847 set<VuoRendererComment *> draggedCommentSet;
2849 foreach (QGraphicsItem *item, itemsBeingDragged)
2857 undoStack->push(
new VuoCommandMove(draggedNodeSet, draggedCommentSet, itemDragDx, itemDragDy,
this,
true));
2859 itemsBeingDragged.clear();
2865 if (commentResizeMacroInProgress)
2867 commentResizeMacroInProgress =
false;
2869 if (commentBeingResized && ((commentResizeDx != 0) || (commentResizeDy != 0)))
2872 commentBeingResized = NULL;
2874 commentResizeDx = 0;
2875 commentResizeDy = 0;
2878 if (duplicationMacroInProgress)
2880 undoStack->endMacro();
2881 duplicationMacroInProgress =
false;
2890 if (
event->type() == QEvent::Show)
2892 if (zoomOutToFitOnNextShowEvent)
2895 zoomOutToFitOnNextShowEvent =
false;
2899 QMetaObject::invokeMethod(composition,
"updateFeedbackErrors", Qt::QueuedConnection);
2904 if (canvasDragInProgress && (
event->type() == QEvent::MouseMove))
2909 else if (
event->type() == QEvent::WindowActivate)
2916 else if (
event->type() == QEvent::WindowDeactivate)
2919 if (
event->type() == QEvent::WindowStateChange)
2930 else if (
event->type() == QEvent::MouseButtonPress)
2933 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
2934 if (leftMouseButtonPressed)
2937 if (!inputPortSidebar->isHidden())
2940 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
2943 if (publishedPortNearCursor)
2945 QGraphicsSceneMouseEvent mouseEvent;
2946 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
2947 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
2950 forwardingEventsToCanvas =
true;
2960 restoreDefaultLeftDockedWidgetWidths();
2963 else if (
event->type() == QEvent::MouseMove)
2966 if (forwardingEventsToCanvas)
2968 QMouseEvent mouseEvent(QEvent::MouseMove,
2969 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2970 static_cast<QMouseEvent *
>(
event)->screenPos(),
2971 static_cast<QMouseEvent *
>(
event)->button(),
2972 static_cast<QMouseEvent *
>(
event)->buttons(),
2973 static_cast<QMouseEvent *
>(
event)->modifiers());
2975 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2982 else if (
event->type() == QEvent::MouseButtonRelease)
2985 if (forwardingEventsToCanvas)
2987 QMouseEvent mouseEvent(QEvent::MouseButtonRelease,
2988 ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos()),
2989 static_cast<QMouseEvent *
>(
event)->screenPos(),
2990 static_cast<QMouseEvent *
>(
event)->button(),
2991 static_cast<QMouseEvent *
>(
event)->buttons(),
2992 static_cast<QMouseEvent *
>(
event)->modifiers());
2994 QApplication::sendEvent(ui->graphicsView->viewport(), &mouseEvent);
2996 forwardingEventsToCanvas =
false;
3002 return QMainWindow::event(
event);
3012 const double scrollTimeoutSeconds = 0.5;
3015 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);
3016 ui->graphicsView->setInteractive(
true);
3017 scrollInProgress =
false;
3024 if ((canvasDragEnabled || canvasDragInProgress) && (
object == composition) && (
3025 event->type() == QEvent::GraphicsSceneMouseMove ||
3026 event->type() == QEvent::GraphicsSceneMousePress ||
3027 event->type() == QEvent::GraphicsSceneMouseDoubleClick ||
3028 event->type() == QEvent::GraphicsSceneContextMenu ||
3029 event->type() == QEvent::KeyPress))
3034 if ((
object == composition) &&
3035 (
event->type() == QEvent::GraphicsSceneMousePress) &&
3038 consumeNextMouseReleaseToCanvas =
true;
3041 if ((
object == composition) &&
3042 (
event->type() == QEvent::GraphicsSceneMouseRelease) &&
3043 consumeNextMouseReleaseToCanvas)
3045 consumeNextMouseReleaseToCanvas =
false;
3049 if (
event->type() == QEvent::Wheel
3050 && ui->graphicsView->rubberBandRect().isNull()
3051 && !ui->graphicsView->pinchZoomInProgress())
3054 QWheelEvent *wheelEvent =
static_cast<QWheelEvent *
>(
event);
3055 if (wheelEvent->phase() == Qt::ScrollBegin)
3057 ui->graphicsView->setInteractive(
false);
3058 scrollInProgress =
true;
3060 else if (wheelEvent->phase() == Qt::ScrollEnd)
3062 ui->graphicsView->setInteractive(
true);
3063 scrollInProgress =
false;
3068 const double lagLimit = .1;
3073 QInputEvent *filteredInputEvent = (QInputEvent *)(
event);
3074 Qt::KeyboardModifiers modifiersOtherThanShift = (filteredInputEvent->modifiers() & ~Qt::ShiftModifier);
3075 filteredInputEvent->setModifiers(modifiersOtherThanShift);
3076 object->removeEventFilter(
this);
3077 QApplication::sendEvent(
object, filteredInputEvent);
3078 object->installEventFilter(
this);
3086 else if (
event->type() == QEvent::MouseButtonPress)
3088 bool leftMouseButtonPressed = (((QMouseEvent *)(
event))->button() == Qt::LeftButton);
3089 if (leftMouseButtonPressed)
3095 if (canvasDragEnabled && leftMouseButtonPressed && (
object == ui->graphicsView->viewport()))
3097 initiateCanvasDrag();
3103 else if (leftMouseButtonPressed)
3106 if (!inputPortSidebar->isHidden())
3109 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3112 if (publishedPortNearCursor)
3114 QGraphicsSceneMouseEvent mouseEvent;
3115 mouseEvent.setButtons(
static_cast<QMouseEvent *
>(
event)->buttons());
3116 mouseEvent.setScenePos(ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(
static_cast<QMouseEvent *
>(
event)->globalPos())));
3124 else if ((
event->type() == QEvent::MouseMove) &&
3125 canvasDragInProgress &&
3126 (
object == ui->graphicsView->viewport()))
3133 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3134 canvasDragInProgress &&
3135 (((QMouseEvent *)(
event))->button() == Qt::LeftButton) &&
3136 (
object == ui->graphicsView->viewport()))
3138 concludeCanvasDrag();
3145 else if ((((
event->type() == QEvent::MouseButtonRelease) &&
3146 (((QMouseEvent *)(
event))->button() == Qt::LeftButton)) ||
3147 ((
event->type() == QEvent::MouseMove) &&
3148 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton)))
3152 QPoint cursorPosition = ((QMouseEvent *)(
event))->globalPos();
3154 QRect inputPortSidebarRect = inputPortSidebar->geometry();
3155 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()));
3157 QRect outputPortSidebarRect = outputPortSidebar->geometry();
3158 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
3161 if (!inputPortSidebar->isHidden())
3165 if (!outputPortSidebar->isHidden())
3169 if ((
event->type() == QEvent::MouseMove) &&
3170 (((QMouseEvent *)(
event))->buttons() & Qt::LeftButton))
3172 bool dragOverInputPortSidebar = ((! inputPortSidebar->isHidden()) && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor));
3173 bool dragOverOutputPortSidebar = ((! outputPortSidebar->isHidden()) && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor));
3175 if (dragOverInputPortSidebar || dragOverOutputPortSidebar)
3177 if (!previousDragMoveWasOverSidebar)
3180 if (dragOverInputPortSidebar)
3182 else if (dragOverOutputPortSidebar)
3185 previousDragMoveWasOverSidebar =
true;
3190 if (previousDragMoveWasOverSidebar)
3198 previousDragMoveWasOverSidebar =
false;
3203 else if ((
event->type() == QEvent::MouseButtonRelease) &&
3204 (((QMouseEvent *)(
event))->button() == Qt::LeftButton))
3209 if (cableInProgress && !inputPortSidebar->isHidden() && (inputPortSidebarRect.contains(cursorPosition) || publishedInputPortNearCursor))
3213 else if (cableInProgress && !outputPortSidebar->isHidden() && (outputPortSidebarRect.contains(cursorPosition) || publishedOutputPortNearCursor))
3217 object->removeEventFilter(
this);
3218 QApplication::sendEvent(
object,
event);
3219 object->installEventFilter(
this);
3228 if (!inputPortSidebar->isHidden())
3234 if (!outputPortSidebar->isHidden() && !publishedPortNearCursor)
3240 if (publishedPortNearCursor)
3242 if (!publishedPortNearCursorPreviously)
3248 if (publishedPortNearCursorPreviously)
3254 object->removeEventFilter(
this);
3255 QApplication::sendEvent(
object,
event);
3256 object->installEventFilter(
this);
3259 publishedPortNearCursorPreviously = publishedPortNearCursor;
3265 else if (
event->type() == QEvent::KeyPress)
3267 QKeyEvent *keyEvent = (QKeyEvent *)(
event);
3270 if (keyEvent->key() == Qt::Key_Escape)
3274 if ((composition->selectedItems().isEmpty()) &&
3275 ((keyEvent->key() == Qt::Key_Up) ||
3276 (keyEvent->key() == Qt::Key_Down) ||
3277 (keyEvent->key() == Qt::Key_Left) ||
3278 (keyEvent->key() == Qt::Key_Right)))
3284 else if ((
object == composition) && (keyEvent->key() == Qt::Key_Space))
3291 object->removeEventFilter(
this);
3292 QApplication::sendEvent(
object,
event);
3293 object->installEventFilter(
this);
3301 else if (
event->type() == QEvent::ContextMenu)
3306 return QMainWindow::eventFilter(
object,
event);
3314 return scrollInProgress;
3322 return itemDragMacroInProgress;
3338 return latestDragTime;
3346void VuoEditorWindow::enableCanvasDrag()
3348 this->canvasDragEnabled =
true;
3358void VuoEditorWindow::disableCanvasDrag()
3360 this->canvasDragEnabled =
false;
3367void VuoEditorWindow::initiateCanvasDrag()
3369 this->canvasDragInProgress =
true;
3370 QPoint currentCursorPos = QCursor::pos();
3371 this->lastCursorLocationDuringCanvasDrag = currentCursorPos;
3373 int xNegativeScrollPotential = ui->graphicsView->horizontalScrollBar()->value() - ui->graphicsView->horizontalScrollBar()->minimum();
3374 int yNegativeScrollPotential = ui->graphicsView->verticalScrollBar()->value() - ui->graphicsView->verticalScrollBar()->minimum();
3376 int xPositiveScrollPotential = ui->graphicsView->horizontalScrollBar()->maximum() - ui->graphicsView->horizontalScrollBar()->value();
3377 int yPositiveScrollPotential = ui->graphicsView->verticalScrollBar()->maximum() - ui->graphicsView->verticalScrollBar()->value();
3380 this->canvasDragMinCursorPos = QPoint(currentCursorPos.x() - xPositiveScrollPotential, currentCursorPos.y() - yPositiveScrollPotential);
3381 this->canvasDragMaxCursorPos = QPoint(currentCursorPos.x() + xNegativeScrollPotential, currentCursorPos.y() + yNegativeScrollPotential);
3389void VuoEditorWindow::concludeCanvasDrag()
3391 this->canvasDragInProgress =
false;
3392 this->lastCursorLocationDuringCanvasDrag = QPoint();
3401 Qt::KeyboardModifiers modifiers =
event->modifiers();
3402 qreal adjustedViewportStepRate = viewportStepRate;
3403 if (modifiers & Qt::ShiftModifier)
3405 adjustedViewportStepRate *= viewportStepRateMultiplier;
3408 if (
event->key() == Qt::Key_Escape)
3412 else if (arePublishedPortSidebarsVisible())
3413 on_showPublishedPorts_triggered();
3414 else if (isFullScreen())
3419 if (composition->hasFocus())
3421 switch (
event->key())
3425 const int y = ui->graphicsView->verticalScrollBar()->value() -
3426 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3427 ui->graphicsView->verticalScrollBar()->setValue(y);
3432 const int y = ui->graphicsView->verticalScrollBar()->value() +
3433 adjustedViewportStepRate*(ui->graphicsView->verticalScrollBar()->singleStep());
3434 ui->graphicsView->verticalScrollBar()->setValue(y);
3439 const int x = ui->graphicsView->horizontalScrollBar()->value() -
3440 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3441 ui->graphicsView->horizontalScrollBar()->setValue(x);
3446 const int x = ui->graphicsView->horizontalScrollBar()->value() +
3447 adjustedViewportStepRate*(ui->graphicsView->horizontalScrollBar()->singleStep());
3448 ui->graphicsView->horizontalScrollBar()->setValue(x);
3462 composition->sendEvent(nearbyPort,
event);
3466 QMainWindow::keyPressEvent(
event);
3479 switch (
event->key())
3483 disableCanvasDrag();
3488 QMainWindow::keyReleaseEvent(
event);
3499 if (canvasDragInProgress)
3501 QPoint oldPos = lastCursorLocationDuringCanvasDrag;
3502 QPoint currentCursorPos = QCursor::pos();
3506 QPoint effectiveNewPos = QPoint( fmax(canvasDragMinCursorPos.x(), fmin(canvasDragMaxCursorPos.x(), currentCursorPos.x())),
3507 fmax(canvasDragMinCursorPos.y(), fmin(canvasDragMaxCursorPos.y(), currentCursorPos.y())));
3510 int dx = -1 * (effectiveNewPos - oldPos).x();
3511 int dy = -1 * (effectiveNewPos - oldPos).y();
3515 lastCursorLocationDuringCanvasDrag.setX(effectiveNewPos.x());
3517 int xScrollbarMin = ui->graphicsView->horizontalScrollBar()->minimum();
3518 int xScrollbarMax = ui->graphicsView->horizontalScrollBar()->maximum();
3519 int xScrollbarOldValue = ui->graphicsView->horizontalScrollBar()->value();
3520 int xScrollbarNewValue = fmax(xScrollbarMin, fmin(xScrollbarMax, xScrollbarOldValue + dx));
3522 if (xScrollbarNewValue != xScrollbarOldValue)
3523 ui->graphicsView->horizontalScrollBar()->setValue(xScrollbarNewValue);
3528 lastCursorLocationDuringCanvasDrag.setY(effectiveNewPos.y());
3530 int yScrollbarMin = ui->graphicsView->verticalScrollBar()->minimum();
3531 int yScrollbarMax = ui->graphicsView->verticalScrollBar()->maximum();
3532 int yScrollbarOldValue = ui->graphicsView->verticalScrollBar()->value();
3533 int yScrollbarNewValue = fmax(yScrollbarMin, fmin(yScrollbarMax, yScrollbarOldValue + dy));
3536 if (yScrollbarNewValue != yScrollbarOldValue)
3537 ui->graphicsView->verticalScrollBar()->setValue(yScrollbarNewValue);
3541 QMainWindow::mouseMoveEvent(
event);
3552 nl = ownedNodeLibrary;
3553 transitionNodeLibraryConnections(NULL, nl);
3557 addDockWidget(Qt::LeftDockWidgetArea, nl);
3560 nodeLibraryMinimumWidth = nl->minimumWidth();
3561 nodeLibraryMaximumWidth = nl->maximumWidth();
3567void VuoEditorWindow::on_compositionInformation_triggered()
3569 metadataEditor->
show();
3585void VuoEditorWindow::on_zoomIn_triggered()
3587 ui->graphicsView->scale(zoomRate,zoomRate);
3590 QRectF selectedItemsRect;
3591 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3592 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3594 if (!selectedItemsRect.isNull())
3595 ui->graphicsView->centerOn(selectedItemsRect.center());
3597 isZoomedToFit =
false;
3598 updateToolbarElementUI();
3604void VuoEditorWindow::on_zoomOut_triggered()
3606 ui->graphicsView->scale(1/zoomRate,1/zoomRate);
3607 isZoomedToFit =
false;
3608 updateToolbarElementUI();
3614void VuoEditorWindow::on_zoom11_triggered()
3616 bool zoomingIn = (ui->graphicsView->transform().m11() <= 1.0);
3617 ui->graphicsView->setTransform(QTransform());
3622 QRectF selectedItemsRect;
3623 foreach (QGraphicsItem *selectedComponent, composition->selectedItems())
3624 selectedItemsRect |= selectedComponent->sceneBoundingRect();
3626 if (!selectedItemsRect.isNull())
3627 ui->graphicsView->centerOn(selectedItemsRect.center());
3630 isZoomedToFit =
false;
3631 updateToolbarElementUI();
3641 QRectF itemsBoundingRect = itemsTightBoundingRect.adjusted(-VuoEditorWindow::compositionMargin,
3642 -VuoEditorWindow::compositionMargin,
3643 VuoEditorWindow::compositionMargin,
3644 VuoEditorWindow::compositionMargin);
3645 ui->graphicsView->fitInView(itemsBoundingRect, Qt::KeepAspectRatio);
3647 isZoomedToFit =
true;
3648 updateToolbarElementUI();
3659 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
3662 if ((viewportRect.width() < itemsTightBoundingRect.width()) || (viewportRect.height() < itemsTightBoundingRect.height()))
3666 else if (!viewportRect.contains(itemsTightBoundingRect))
3667 ui->graphicsView->ensureVisible(itemsTightBoundingRect, VuoEditorWindow::compositionMargin, VuoEditorWindow::compositionMargin);
3670void VuoEditorWindow::viewportFitReset()
3672 isZoomedToFit =
false;
3674 updateToolbarElementUI();
3677void VuoEditorWindow::on_saveComposition_triggered()
3679 QString savedPath = windowFilePath();
3681 on_saveCompositionAs_triggered();
3685 saveFile(savedPath);
3689void VuoEditorWindow::on_saveCompositionAs_triggered()
3691 string savedPath = saveCompositionAs().toUtf8().constData();
3692 if (savedPath.empty())
3702QString VuoEditorWindow::saveCompositionAs()
3705 QFileDialog d(
this, Qt::Sheet);
3709 d.setDirectory(windowFilePath());
3718 d.setAcceptMode(QFileDialog::AcceptSave);
3728 QString savedPath =
"";
3729 if (d.exec() == QDialog::Accepted)
3731 savedPath = d.selectedFiles()[0];
3732 string dir, file, ext;
3735 saveFileAs(savedPath);
3749bool VuoEditorWindow::saveFileAs(
const QString & savePath)
3751 string dir, file, ext;
3755 QDir newCompositionDir(QFileInfo(savePath).absoluteDir().canonicalPath());
3761 if (!installingAsSubcomposition && (!modifiedPortConstantRelativePaths.empty() || iconPathChanged))
3769 map<VuoPort *, string> pathsToUpdate;
3770 QString copiedFileDetails =
"";
3771 QString updatedPathDetails =
"";
3774 for (map <VuoPort *, string>::iterator i = modifiedPortConstantRelativePaths.begin(); i != modifiedPortConstantRelativePaths.end(); ++i)
3777 string modifiedPath = i->second;
3781 QString origRelativePath = origRelativePathText;
3783 string origRelativeDir, file, ext;
3785 string resourceFileName = file;
3788 resourceFileName +=
".";
3789 resourceFileName += ext;
3791 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3795 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3799 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath, modifiedPathText));
3801 pathsToUpdate[port] = modifiedPath;
3806 if (iconPathChanged)
3811 string origRelativeDir, file, ext;
3813 string resourceFileName = file;
3816 resourceFileName +=
".";
3817 resourceFileName += ext;
3819 QString origAbsolutePath = compositionDir.filePath(QDir(origRelativeDir.c_str()).filePath(resourceFileName.c_str()));
3823 copiedFileDetails.append(QString(
"%1\n").arg(origRelativePath));
3825 updatedPathDetails.append(QString(
"%1 → %2\n").arg(origRelativePath, modifiedIconPath.c_str()));
3828 bool copyFiles = (!copiedFileDetails.isEmpty());
3829 bool updatePaths = (!updatedPathDetails.isEmpty());
3831 const QString updateSummary =
"<p>" + tr(
"You're saving your composition to a different folder.") +
"</p>"
3835 ? tr(
"Do you want to copy the example files used by your composition?")
3837 : tr(
"Do you want to update the paths to files in your composition?"))
3840 QString updateDetails =
"";
3843 updateDetails += tr(
"The following file(s) will be copied",
"", modifiedPortConstantRelativePaths.size()) +
":\n\n" + copiedFileDetails +
"\n";
3847 updateDetails += tr(
"The following path(s) will be updated",
"", pathsToUpdate.size()) +
":\n\n" + updatedPathDetails;
3849 QMessageBox messageBox(
this);
3850 messageBox.setWindowFlags(Qt::Sheet);
3851 messageBox.setWindowModality(Qt::WindowModal);
3852 messageBox.setTextFormat(Qt::RichText);
3853 messageBox.setStandardButtons(QMessageBox::Discard | QMessageBox::Ok);
3854 messageBox.setButtonText(QMessageBox::Discard, (copyFiles? tr(
"Leave files in place") : tr(
"Leave paths unchanged")));
3855 messageBox.setButtonText(QMessageBox::Ok, (copyFiles? tr(
"Copy files") : tr(
"Update paths")));
3856 messageBox.setDefaultButton(QMessageBox::Ok);
3857 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
3859 messageBox.setText(updateSummary);
3860 messageBox.setDetailedText(updateDetails);
3863 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Discard))->setAutoDefault(
false);
3864 messageBox.button(QMessageBox::Discard)->setFocus();
3866 if (messageBox.exec() == QMessageBox::Ok)
3871 bool tmpFilesOnly =
true;
3872 composition->
bundleResourceFiles(newCompositionDir.canonicalPath().toUtf8().constData(), tmpFilesOnly);
3877 undoStack->beginMacro(tr(
"File Path Updates"));
3880 for (map <VuoPort *, string>::iterator i = pathsToUpdate.begin(); i != pathsToUpdate.end(); ++i)
3883 string modifiedPath = i->second;
3885 setPortConstant(port->
getRenderer(), modifiedPath);
3890 if (iconPathChanged)
3895 metadataCopy->
setName(customizedCompositionName);
3902 undoStack->endMacro();
3907 return saveFile(savePath);
3910string VuoEditorWindow::on_installSubcomposition_triggered()
3914 string nodeClassName = installSubcomposition(
"");
3917 oldTitle.toUtf8().data(),
3918 ui->installSubcomposition->text().toUtf8().data(),
3919 nodeClassName.c_str());
3921 if (!nodeClassName.empty())
3922 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
3924 return nodeClassName;
3931string VuoEditorWindow::installSubcomposition(
string parentCompositionPath)
3933 string currentCompositionPath = windowFilePath().toUtf8().constData();
3936 QString operationTitle;
3937 string installedSubcompositionDir;
3938 if (parentCompositionPath.empty())
3940 if (currentCompositionExists)
3941 operationTitle = tr(
"Move Subcomposition to User Library");
3943 operationTitle = tr(
"Save Subcomposition to User Library");
3950 operationTitle = tr(
"Save Subcomposition to User Library");
3955 operationTitle = tr(
"Save Subcomposition to System Library");
3960 operationTitle = tr(
"Save Subcomposition to Composition-Local Library");
3966 string nodeClassName;
3976 QString defaultNodeCategory =
static_cast<VuoEditor *
>(qApp)->getDefaultSubcompositionPrefix();
3980 defaultNodeDisplayName);
3981 QString currentNodeCategory =
static_cast<VuoEditor *
>(qApp)->getSubcompositionPrefix();
3984 defaultNodeDisplayName, defaultNodeCategory,
3985 currentNodeDisplayName, currentNodeCategory);
3990 QString nodeDisplayName = d.nodeTitle();
3991 QString nodeCategory = d.nodeCategory();
3993 if (nodeCategory != currentNodeCategory)
3994 static_cast<VuoEditor *
>(qApp)->updateSubcompositionPrefix(nodeCategory);
3999 newMetadata->
setName(nodeDisplayName.toUtf8().constData());
4009 int documentIdentifierInstanceNum = 1;
4013 std::ostringstream oss;
4014 oss << ++documentIdentifierInstanceNum;
4018 bool saveSucceeded = saveFileAs(copiedCompositionPath.c_str());
4019 if (! saveSucceeded)
4034 if (compositionName.isEmpty())
4038 QString thirdPartyCategory = category.remove(QRegExp(
"^(vuo\\.?)+", Qt::CaseInsensitive));
4041 if (category.isEmpty())
4044 return category +
"." + compositionName;
4057 if (displayName.empty())
4062 CFStringRef cfs = CFStringCreateWithCString(NULL, displayName.c_str(), kCFStringEncodingUTF8);
4065 CFMutableStringRef cfsm = CFStringCreateMutableCopy(NULL, 0, cfs);
4066 CFStringTransform(cfsm, NULL, kCFStringTransformToLatin,
false);
4067 CFStringTransform(cfsm, NULL, kCFStringTransformStripCombiningMarks,
false);
4068 CFStringTransform(cfsm, NULL, kCFStringTransformStripDiacritics,
false);
4069 CFStringTransform(cfsm, NULL, CFSTR(
"ASCII"),
false);
4082void VuoEditorWindow::editMetadata(
int dialogResult)
4084 if (dialogResult == QDialog::Accepted)
4093string VuoEditorWindow::generateCurrentDefaultCopyright()
4095 const string user =
static_cast<VuoEditor *
>(qApp)->getUserName();
4096 const string userProfileURL =
static_cast<VuoEditor *
>(qApp)->getStoredUserProfileURL();
4097 const string userProfileLink = (userProfileURL.empty()? user :
"[" + user +
"](" + userProfileURL +
")");
4098 const string currentYear = QDate::currentDate().toString(
"yyyy").toUtf8().constData();
4100 const string copyright =
"Copyright © " + currentYear +
" " + userProfileLink;
4107bool VuoEditorWindow::confirmReplacingFile(
string path)
4110 QFileInfo fileInfo(QString::fromStdString(path));
4111 QMessageBox d(
this);
4112 d.setWindowFlags(Qt::Sheet);
4113 d.setWindowModality(Qt::WindowModal);
4115 d.setTextFormat(Qt::RichText);
4116 d.setText(tr(
"<b>“%1” already exists. Do you want to replace it?</b>").arg(fileInfo.fileName()));
4118 + 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>")
4120 .arg(fileInfo.dir().dirName()));
4121 d.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
4122 d.setDefaultButton(QMessageBox::Cancel);
4123 d.setButtonText(QMessageBox::Yes, tr(
"Replace"));
4124 d.setIcon(QMessageBox::Warning);
4127 static_cast<QPushButton *
>(d.button(QMessageBox::Yes))->setAutoDefault(
false);
4128 d.button(QMessageBox::Yes)->setFocus();
4130 return d.exec() == QMessageBox::Yes;
4139 addDockWidget(Qt::TopDockWidgetArea, searchBox);
4140 searchBox->setFocus();
4150 if (!searchBox->isHidden())
4159 if (!searchBox->isHidden())
4169bool VuoEditorWindow::saveFile(
const QString & savePath)
4175 bool saveAborted =
false;
4176 QString failureDetails =
"";
4177 QString modifiedSavePath = savePath;
4179 if (!savePath.endsWith(expectedFileExtension))
4181 modifiedSavePath.append(expectedFileExtension);
4185 failureDetails =
"A file or folder with the same name already exists.";
4189 QString existingPath = windowFilePath();
4190 bool saveSucceeded = !saveAborted && saveFile(modifiedSavePath, existingPath);
4199 setWindowFilePath(modifiedSavePath);
4201 toolbar->updateTitle();
4203 compositionUpgradedSinceLastSave =
false;
4204 undoStack->setClean();
4205 setCompositionModified(
false);
4208 string newDir, file, ext;
4211 if (compositionDirChanged)
4214 QStringList compositionLocalModules;
4215 for (
const string &dependency : compiler->getDependenciesForComposition(
getComposition()->getBase()->getCompiler()))
4216 if (compiler->isCompositionLocalModule(dependency))
4217 compositionLocalModules.append(QString::fromStdString(dependency));
4219 if (! compositionLocalModules.empty())
4221 compositionLocalModules.sort();
4223 QString summary = QString(
"<p>You're saving your composition to a different folder.</p>")
4224 .append(
"<p>Where do you want to install the composition's local nodes?</p>");
4226 QString details = QString(
"The following nodes will be moved or copied:\n\n")
4227 .append(compositionLocalModules.join(
"\n"))
4230 QMessageBox messageBox(
this);
4231 messageBox.setWindowFlags(Qt::Sheet);
4232 messageBox.setWindowModality(Qt::WindowModal);
4233 messageBox.setTextFormat(Qt::RichText);
4234 messageBox.setStandardButtons(QMessageBox::No | QMessageBox::Yes);
4235 messageBox.setButtonText(QMessageBox::No,
"Move to User Library");
4236 messageBox.setButtonText(QMessageBox::Yes,
"Copy to new Composition Library");
4237 messageBox.setDefaultButton(QMessageBox::Yes);
4238 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
4240 messageBox.setText(summary);
4241 messageBox.setDetailedText(details);
4244 static_cast<QPushButton *
>(messageBox.button(QMessageBox::No))->setAutoDefault(
false);
4245 messageBox.button(QMessageBox::No)->setFocus();
4247 int ret = messageBox.exec();
4250 QDir oldModulesDir = QDir(QString::fromStdString(oldModulesDirPath));
4252 string newModulesDirPath = (ret == QMessageBox::Yes ?
4256 QDir newModulesDir(QString::fromStdString(newModulesDirPath));
4259 foreach (QString moduleFileName, oldModulesDir.entryList(QDir::Files))
4263 if (compositionLocalModules.contains(QString::fromStdString(moduleKey)))
4265 string oldModulePath = oldModulesDir.filePath(moduleFileName).toStdString();
4266 string newModulePath = newModulesDir.filePath(moduleFileName).toStdString();
4271 if (ret == QMessageBox::Yes)
4284 if (includeInRecentFileMenu)
4285 static_cast<VuoEditor *
>(qApp)->addFileToAllOpenRecentFileMenus(modifiedSavePath);
4290 if (failureDetails.isEmpty())
4291 failureDetails = strerror(error);
4293 QMessageBox fileSaveFailureDialog(
this);
4294 fileSaveFailureDialog.setWindowFlags(Qt::Sheet);
4295 fileSaveFailureDialog.setWindowModality(Qt::WindowModal);
4297 QString errorMessage = tr(
"The composition could not be saved at “%1”.").arg(modifiedSavePath);
4298 fileSaveFailureDialog.setText(tr(errorMessage.toUtf8().constData()));
4299 fileSaveFailureDialog.setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4300 fileSaveFailureDialog.setInformativeText(failureDetails);
4301 fileSaveFailureDialog.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel);
4302 fileSaveFailureDialog.setButtonText(QMessageBox::Save, tr(
"Save As…"));
4303 fileSaveFailureDialog.setIcon(QMessageBox::Warning);
4305 switch(fileSaveFailureDialog.exec()) {
4306 case QMessageBox::Save:
4307 on_saveCompositionAs_triggered();
4309 case QMessageBox::Cancel:
4316 return saveSucceeded;
4322void VuoEditorWindow::populateProtocolsMenu(QMenu *m)
4326 QAction *protocolAction =
new QAction(
this);
4327 protocolAction->setText(VuoEditor::tr(protocol->
getName().c_str()));
4328 protocolAction->setData(QVariant::fromValue(protocol));
4329 protocolAction->setCheckable(
true);
4330 connect(protocolAction, &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
4331 m->addAction(protocolAction);
4336 QAction *protocolAction =
new QAction(
this);
4337 protocolAction->setText(VuoEditor::tr(
"None"));
4338 protocolAction->setCheckable(
true);
4339 connect(protocolAction, &QAction::triggered,
this, &VuoEditorWindow::changeActiveProtocol);
4340 m->addAction(protocolAction);
4346void VuoEditorWindow::updateProtocolsMenu(QMenu *m)
4348 foreach (QAction *protocolAction, m->actions())
4351 protocolAction->setChecked(composition->
getActiveProtocol() == currentProtocol);
4359void VuoEditorWindow::changeActiveProtocol(
void)
4361 QAction *sender = (QAction *)QObject::sender();
4364 if (!selectedProtocol)
4367 if (!selectedProtocol)
4379 selectedProtocol->getName().c_str());
4382 toggleActiveStatusForProtocol(selectedProtocol);
4384 setPublishedPortSidebarVisibility(
true);
4392void VuoEditorWindow::toggleActiveStatusForProtocol(
VuoProtocol *protocol)
4403void VuoEditorWindow::updateActiveProtocolDisplay(
void)
4414void VuoEditorWindow::evaluateCompositionForProtocolPromotion()
4420 string compositionAsString = composition->
takeSnapshot();
4440bool VuoEditorWindow::saveFile(
const QString & savePath, QString & existingPath)
4442 string existingCompositionFooter =
"";
4445 if (! existingPath.isEmpty())
4447 ifstream existingFile(existingPath.toUtf8().constData());
4450 bool graphvizStatementListEndFound =
false;
4451 for (
char c = existingFile.get(); existingFile.good(); c = existingFile.get())
4453 if (existingFile.good())
4457 existingCompositionFooter =
"";
4458 graphvizStatementListEndFound =
true;
4460 else if (graphvizStatementListEndFound)
4461 existingCompositionFooter += c;
4464 existingFile.close();
4475 existingCompositionFooter);
4477 string dir, file, ext;
4478 string finalSavePath = savePath.toUtf8().constData();
4489 mode_t currentUMask = umask(0);
4490 umask(currentUMask);
4492 chmod(tmpSavePath.c_str(), 0666 & ~currentUMask);
4495 ofstream savedFile(tmpSavePath.c_str(), ios::trunc);
4496 savedFile << outputComposition;
4503 bool saveSucceeded = ((! savedFile.fail()) && (! rename(tmpSavePath.c_str(), finalSavePath.c_str())));
4509 this->metadataPanel->
update();
4514 return saveSucceeded;
4520void VuoEditorWindow::undoStackCleanStateChanged(
bool clean)
4524 setCompositionModified(
true);
4529 else if (clean && !compositionUpgradedSinceLastSave)
4530 setCompositionModified(
false);
4536void VuoEditorWindow::setCompositionModified(
bool modified)
4538 setWindowModified(modified);
4552 composition->
run(snapshot);
4567 composition->
stop();
4590void VuoEditorWindow::showBuildActivityIndicator()
4599void VuoEditorWindow::hideBuildActivityIndicator(QString buildError)
4601 if (! buildError.isEmpty())
4605 updateRefireAction();
4607 QString details =
"";
4608 if (buildError.contains(
"Nodes not installed", Qt::CaseInsensitive))
4609 details =
"This composition contains nodes that aren't installed.";
4611 VuoErrorDialog::show(
this, tr(
"There was a problem running the composition."), details, buildError);
4617 updateRefireAction();
4624void VuoEditorWindow::hideStopActivityIndicator()
4628 updateRefireAction();
4631void VuoEditorWindow::on_openUserModulesFolder_triggered()
4636void VuoEditorWindow::on_openSystemModulesFolder_triggered()
4641void VuoEditorWindow::on_showConsole_triggered()
4660void VuoEditorWindow::on_showPublishedPorts_triggered(
void)
4662 setPublishedPortSidebarVisibility(!arePublishedPortSidebarsVisible());
4672 if (!arePublishedPortSidebarsVisible())
4673 on_showPublishedPorts_triggered();
4679bool VuoEditorWindow::arePublishedPortSidebarsVisible()
4681 return !inputPortSidebar->isHidden() && !outputPortSidebar->isHidden();
4687void VuoEditorWindow::on_showHiddenCables_triggered(
void)
4690 if (!previouslyShowingHiddenCables)
4693 on_showPublishedPorts_triggered();
4704void VuoEditorWindow::on_showEvents_triggered(
void)
4706 VUserLog(
"%s: %s Show Events mode",
4717void VuoEditorWindow::closePublishedPortSidebars()
4719 setPublishedPortSidebarVisibility(
false);
4725void VuoEditorWindow::conditionallyShowPublishedPortSidebars(
bool visible)
4728 setPublishedPortSidebarVisibility(
true);
4734void VuoEditorWindow::setPublishedPortSidebarVisibility(
bool visible)
4742 if (nl && (! nl->isHidden()) && (! nl->isFloating()))
4743 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4746 addDockWidget(Qt::LeftDockWidgetArea, inputPortSidebar);
4748 addDockWidget(Qt::RightDockWidgetArea, outputPortSidebar);
4757 if (! nl->isFloating())
4759 nl->setMinimumWidth(nl->width());
4760 nl->setMaximumWidth(nl->minimumWidth());
4764 inputPortSidebar->setVisible(visible);
4765 outputPortSidebar->setVisible(visible);
4767 updatePublishedCableGeometry();
4771 if (!nl->isHidden() && !nl->isFloating())
4784void VuoEditorWindow::updatePublishedCableGeometry()
4793 cable->
getRenderer()->setCacheMode(QGraphicsItem::NoCache);
4795 cable->
getRenderer()->setCacheMode(defaultCacheMode);
4802 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
4803 ui->graphicsView->viewport()->update();
4811void VuoEditorWindow::updatePublishedPortOrder(vector<VuoPublishedPort *> ports,
bool isInput)
4821 bool foundNonProtocolPort =
false;
4825 foundNonProtocolPort =
true;
4828 if (foundNonProtocolPort)
4840void VuoEditorWindow::displayDockedNodeLibrary()
4842 addDockWidget(Qt::LeftDockWidgetArea, nl);
4844 bool publishedPortsDisplayed = (inputPortSidebar && (! inputPortSidebar->isHidden()));
4845 if (publishedPortsDisplayed)
4846 splitDockWidget(nl, inputPortSidebar, Qt::Horizontal);
4848 nl->setFloating(
false);
4849 nl->
fixWidth(publishedPortsDisplayed);
4861 inputPortSidebar->setMinimumWidth(inputPortSidebar->width());
4862 inputPortSidebar->setMaximumWidth(inputPortSidebar->minimumWidth());
4864 if (visibility == VuoNodeLibrary::nodeLibraryDocked)
4867 displayDockedNodeLibrary();
4871 else if (visibility == VuoNodeLibrary::nodeLibraryFloating)
4880 if (ownedNodeLibrary == floater)
4882 if (! nl->isFloating())
4884 nl->setFloating(
true);
4897 ownedNodeLibrary->setVisible(
false);
4903 else if (visibility == VuoNodeLibrary::nodeLibraryHidden)
4906 nl->setVisible(
false);
4922 bool compositionHasOtherCustomizedMetadata = (
4926 bool compositionHasBeenSaved = !windowFilePath().isEmpty();
4927 if (compositionHasCustomizedDescription || compositionHasCustomizedCopyright || compositionHasOtherCustomizedMetadata || compositionHasBeenSaved)
4929 dispatch_async(((
VuoEditor *)qApp)->getDocumentationQueue(), ^{
4930 QMetaObject::invokeMethod(nl,
"displayPopoverInPane", Qt::QueuedConnection, Q_ARG(QWidget *, metadataPanel));
4951 if (inputEditorSession
4952 || metadataEditor->isVisible()
4961 if (isWindowModified())
4963 auto mb =
new QMessageBox(
this);
4964 mb->setWindowFlags(Qt::Sheet);
4965 mb->setWindowModality(Qt::WindowModal);
4970 QString details = tr(
"Your changes will be lost if you don’t save them.");
4971 mb->setText(tr(message.toUtf8().constData()));
4972 mb->setStyleSheet(
"#qt_msgbox_informativelabel { font-weight: normal; font-size: 11pt; }");
4973 mb->setInformativeText(tr(details.toUtf8().constData()));
4976 mb->setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
4977 mb->setDefaultButton(QMessageBox::Save);
4980 static_cast<QPushButton *
>(mb->button(QMessageBox::Discard))->setAutoDefault(
false);
4981 mb->button(QMessageBox::Discard)->setFocus();
4983 if (windowFilePath().isEmpty())
4984 mb->setButtonText(QMessageBox::Save, tr(
"Save As…"));
4986 connect(mb, &QMessageBox::buttonClicked,
this, [=](QAbstractButton *button){
4987 auto editor =
static_cast<VuoEditor *
>(qApp);
4988 auto role = mb->buttonRole(button);
4989 if (role == QMessageBox::AcceptRole)
4991 on_saveComposition_triggered();
4992 if (isWindowModified())
4993 editor->cancelQuit();
4997 editor->continueQuit(
this);
5000 else if (role == QMessageBox::DestructiveRole)
5003 editor->continueQuit(
this);
5006 editor->cancelQuit();
5017 static_cast<VuoEditor *
>(qApp)->continueQuit(
this);
5024void VuoEditorWindow::acceptCloseEvent()
5032 VuoEditorWindow::deleteLater();
5040 static_cast<VuoEditor *
>(qApp)->addFileToRecentlyClosedList(windowFilePath());
5047void VuoEditorWindow::updateSelectedComponentMenuItems()
5049 string cutCommandText = tr(
"Cut").toStdString();
5050 string copyCommandText = tr(
"Copy").toStdString();
5051 string duplicateCommandText = tr(
"Duplicate").toStdString();
5052 string deleteCommandText = tr(
"Delete").toStdString();
5053 string resetCommandText = tr(
"Reset").toStdString();
5055 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
5057 int selectedNodesFound = 0;
5058 int selectedCablesFound = 0;
5059 int selectedListsFound = 0;
5060 int selectedCommentsFound = 0;
5062 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
5063 (! (selectedNodesFound && selectedCablesFound)) &&
5064 (i != selectedCompositionComponents.end());
5067 QGraphicsItem *compositionComponent = *i;
5075 selectedListsFound++;
5078 selectedNodesFound++;
5081 selectedCablesFound++;
5084 selectedCommentsFound++;
5087 int distinctComponentTypesFound = 0;
5088 if (selectedListsFound)
5089 distinctComponentTypesFound++;
5090 if (selectedNodesFound)
5091 distinctComponentTypesFound++;
5092 if (selectedCablesFound)
5093 distinctComponentTypesFound++;
5094 if (selectedCommentsFound)
5095 distinctComponentTypesFound++;
5097 if (selectedListsFound && (distinctComponentTypesFound == 1))
5099 string selectedListText =
"Selected List";
5100 string selectedListsText =
"Selected Lists";
5102 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5103 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5104 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5106 if (selectedListsFound > 1)
5108 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListsText).c_str()));
5113 ui->deleteCompositionComponents->setText(tr((resetCommandText +
" " + selectedListText).c_str()));
5119 ui->cutCompositionComponents->setText(tr(cutCommandText.c_str()));
5120 ui->copyCompositionComponents->setText(tr(copyCommandText.c_str()));
5121 ui->duplicateCompositionComponents->setText(tr(duplicateCommandText.c_str()));
5122 ui->deleteCompositionComponents->setText(tr(deleteCommandText.c_str()));
5126 bool enableSelectedComponentDeleteMenuItem = (!selectedCompositionComponents.isEmpty());
5127 bool enableSelectedComponentCutMenuItem = (!selectedCompositionComponents.isEmpty() &&
5128 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5129 bool enableSelectedComponentDuplicateMenuItem = ((selectedNodesFound || selectedCommentsFound) &&
5130 !(selectedListsFound && (distinctComponentTypesFound == 1)));
5133 bool enableCopyMenuItem = (copyAppliesToNodeLibraryDocumentation || enableSelectedComponentDuplicateMenuItem);
5135 ui->cutCompositionComponents->setEnabled(enableSelectedComponentCutMenuItem);
5136 ui->copyCompositionComponents->setEnabled(enableCopyMenuItem);
5137 ui->duplicateCompositionComponents->setEnabled(enableSelectedComponentDuplicateMenuItem);
5138 ui->deleteCompositionComponents->setEnabled(enableSelectedComponentDeleteMenuItem);
5140 ui->renameNodes->setEnabled(selectedNodesFound);
5141 ui->refactor->setEnabled(selectedNodesFound || selectedCommentsFound);
5142 contextMenuTints->setEnabled(selectedNodesFound || selectedCommentsFound);
5149void VuoEditorWindow::updateChangeNodeMenu()
5151 QList<QGraphicsItem *> selectedCompositionComponents = composition->selectedItems();
5153 int selectedNodesFound = 0;
5154 int selectedCommentsFound = 0;
5158 for (QList<QGraphicsItem *>::iterator i = selectedCompositionComponents.begin();
5159 (selectedNodesFound <= 1) && !selectedCommentsFound &&
5160 (i != selectedCompositionComponents.end());
5163 QGraphicsItem *compositionComponent = *i;
5172 selectedNodesFound++;
5176 selectedCommentsFound++;
5180 ui->menuEdit->removeAction(menuChangeNode->menuAction());
5182 bool menuChangeNodeDisplayed =
false;
5183 if ((selectedNodesFound == 1) && !selectedCommentsFound)
5186 if (!menuChangeNode->actions().isEmpty())
5188 ui->menuEdit->insertMenu(ui->refactor, menuChangeNode);
5189 menuChangeNode->setEnabled(
true);
5190 menuChangeNodeDisplayed =
true;
5195 ui->changeNodePlaceholder->setVisible(!menuChangeNodeDisplayed);
5204 const QString compositionIndicatorText =
"digraph";
5205 return (text.toCaseFolded().contains(compositionIndicatorText.toCaseFolded()));
5212void VuoEditorWindow::ensureSceneRectContainsRegion(
const QList<QRectF> ®ion)
5222 bool regionContained =
true;
5223 QRectF sceneRect = composition->sceneRect();
5224 foreach (QRectF rect, region)
5226 if (!sceneRect.contains(rect))
5228 regionContained =
false;
5233 if (!regionContained)
5243void VuoEditorWindow::updateSceneRect()
5252 const int horizontalMargin = 0.2 * ui->graphicsView->geometry().width();
5253 const int verticalMargin = 0.2 * ui->graphicsView->geometry().height();
5255 int horizontalScrollBarHeight = ui->graphicsView->horizontalScrollBar()->sizeHint().height();
5256 int verticalScrollBarWidth = ui->graphicsView->verticalScrollBar()->sizeHint().width();
5258 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
5259 QRectF itemsBoundingRect = composition->
internalItemsBoundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5260 QRectF viewportItemsUnionRect;
5264 if (viewportRect.left() <= itemsBoundingRect.left() && viewportRect.right() >= itemsBoundingRect.right())
5266 viewportItemsUnionRect.setLeft(viewportRect.left());
5267 viewportItemsUnionRect.setRight(viewportRect.right());
5272 else if (abs(viewportRect.left() - itemsBoundingRect.left()) > abs(itemsBoundingRect.right() - viewportRect.right()))
5274 viewportItemsUnionRect.setRight(itemsBoundingRect.right());
5275 viewportItemsUnionRect.setLeft(itemsBoundingRect.right() - max(itemsBoundingRect.width(), viewportRect.width()));
5282 viewportItemsUnionRect.setLeft(itemsBoundingRect.left());
5283 viewportItemsUnionRect.setRight(itemsBoundingRect.left() + max(itemsBoundingRect.width(), viewportRect.width()));
5288 if (viewportRect.top() <= itemsBoundingRect.top() && viewportRect.bottom() >= itemsBoundingRect.bottom())
5290 viewportItemsUnionRect.setTop(viewportRect.top());
5291 viewportItemsUnionRect.setBottom(viewportRect.bottom());
5296 else if (abs(viewportRect.top() - itemsBoundingRect.top()) > abs(itemsBoundingRect.bottom() - viewportRect.bottom()))
5298 viewportItemsUnionRect.setBottom(itemsBoundingRect.bottom());
5299 viewportItemsUnionRect.setTop(itemsBoundingRect.bottom() - max(itemsBoundingRect.height(), viewportRect.height()));
5306 viewportItemsUnionRect.setTop(itemsBoundingRect.top());
5307 viewportItemsUnionRect.setBottom(itemsBoundingRect.top() + max(itemsBoundingRect.height(), viewportRect.height()));
5310 int viewportItemsUnionRectAdjustedWidth = viewportItemsUnionRect.width();
5311 int viewportItemsUnionRectAdjustedHeight = viewportItemsUnionRect.height();
5313 if ((viewportItemsUnionRect.width() > viewportRect.width()) &&
5314 (viewportItemsUnionRect.width() <= viewportRect.width() + verticalScrollBarWidth))
5317 viewportItemsUnionRectAdjustedWidth = viewportRect.width() + verticalScrollBarWidth + 1;
5320 viewportItemsUnionRectAdjustedHeight -= horizontalScrollBarHeight;
5323 if ((viewportItemsUnionRect.height() > viewportRect.height()) &&
5324 (viewportItemsUnionRect.height() <= viewportRect.height() + horizontalScrollBarHeight))
5327 viewportItemsUnionRectAdjustedHeight = viewportRect.height() + horizontalScrollBarHeight + 1;
5330 viewportItemsUnionRectAdjustedWidth -= verticalScrollBarWidth;
5333 QRectF viewportItemsUnionRectAdjusted(viewportItemsUnionRect.topLeft().x(),
5334 viewportItemsUnionRect.topLeft().y(),
5335 viewportItemsUnionRectAdjustedWidth,
5336 viewportItemsUnionRectAdjustedHeight);
5340 if ((QApplication::mouseButtons() & Qt::LeftButton))
5341 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(composition->sceneRect());
5343 viewportItemsUnionRectAdjusted = viewportItemsUnionRectAdjusted.united(viewportRect);
5348 if (!cableBeingDragged)
5349 composition->setSceneRect(viewportItemsUnionRectAdjusted);
5352 if (cableBeingDragged)
5363 QRect inputPortSidebarRect = inputPortSidebar->geometry();
5364 inputPortSidebarRect.moveTopLeft(inputPortSidebar->parentWidget()->mapToGlobal(inputPortSidebarRect.topLeft()+QPoint(1,0)));
5366 QRect outputPortSidebarRect = outputPortSidebar->geometry();
5367 outputPortSidebarRect.moveTopLeft(outputPortSidebar->parentWidget()->mapToGlobal(outputPortSidebarRect.topLeft()));
5369 QRect viewportRectGlobal = ui->graphicsView->viewport()->geometry();
5370 viewportRectGlobal.moveTopLeft(ui->graphicsView->viewport()->parentWidget()->mapToGlobal(viewportRectGlobal.topLeft()));
5372 QRect noAutoscrollZone = QRect();
5373 if (!inputPortSidebar->isHidden())
5374 noAutoscrollZone |= inputPortSidebarRect;
5375 if (!outputPortSidebar->isHidden())
5376 noAutoscrollZone |= outputPortSidebarRect;
5377 if (!inputPortSidebar->isHidden() || !outputPortSidebar->isHidden())
5378 noAutoscrollZone |= viewportRectGlobal;
5380 QPoint cursorPosition = QCursor::pos();
5381 bool cursorWithinNoAutoscrollZone = noAutoscrollZone.contains(cursorPosition);
5382 bool cursorWithinNoAutoscrollZoneLeft = (cursorWithinNoAutoscrollZone &&
5383 ((cursorPosition.x() - noAutoscrollZone.left()) < (noAutoscrollZone.right() - cursorPosition.x())));
5387 bool autoscrollWouldBringSourceNodeCloser =
false;
5391 QRectF fixedNodeBoundingRect = fixedNode->
boundingRect().adjusted(-horizontalMargin, -verticalMargin, horizontalMargin, verticalMargin);
5392 bool fixedNodeVisible = ((fixedNodeBoundingRect.left()+fixedNode->scenePos().x() >= viewportRect.left()) &&
5393 (fixedNodeBoundingRect.right()+fixedNode->scenePos().x() <= viewportRect.right()));
5395 autoscrollWouldBringSourceNodeCloser = (!fixedNodeVisible && (cursorWithinNoAutoscrollZoneLeft ==
5396 (fixedNodeBoundingRect.left()+fixedNode->scenePos().x() < viewportRect.left())));
5399 bool enableCableDragAutoscroll = (!cursorWithinNoAutoscrollZone || autoscrollWouldBringSourceNodeCloser);
5400 if (enableCableDragAutoscroll)
5402 ui->graphicsView->ensureVisible(cableFloatingEndpointSceneLoc.x(),
5403 cableFloatingEndpointSceneLoc.y(),
5405 VuoEditorWindow::compositionMargin);
5414void VuoEditorWindow::updateRubberBandSelectionMode(QRect rubberBandRect, QPointF fromScenePoint, QPointF toScenePoint)
5416 bool rubberBandSelectionPreviouslyInProgress = this->rubberBandSelectionInProgress;
5417 bool rubberBandSelectionNowInProgress = !(rubberBandRect.isNull() && fromScenePoint.isNull() && toScenePoint.isNull());
5419 bool beginningRubberBandSelection = (!rubberBandSelectionPreviouslyInProgress && rubberBandSelectionNowInProgress);
5420 bool endingRubberBandSelection = (rubberBandSelectionPreviouslyInProgress && !rubberBandSelectionNowInProgress);
5422 if (beginningRubberBandSelection)
5430 if (!lastLeftMousePressHadOptionModifier)
5437 else if (endingRubberBandSelection)
5443 if (!lastLeftMousePressHadOptionModifier)
5451 this->rubberBandSelectionInProgress = rubberBandSelectionNowInProgress;
5457void VuoEditorWindow::setPortConstant(
VuoRendererPort *port,
string value)
5472 showInputEditor(port,
true);
5478void VuoEditorWindow::showInputEditor(
VuoRendererPort *port,
bool forwardTabTraversal)
5483 sidebar = (publishedPort->
getInput() ? outputPortSidebar : inputPortSidebar);
5486 map<VuoRendererPort *, pair<string, string> > originalAndFinalValueForPort = inputEditorSession->
execute(port, forwardTabTraversal);
5488 delete inputEditorSession;
5489 inputEditorSession =
nullptr;
5491 bool startedUndoStackMacro =
false;
5492 for (
auto i : originalAndFinalValueForPort)
5495 string originalEditingSessionValue = i.second.first;
5496 string finalEditingSessionValue = i.second.second;
5500 if (finalEditingSessionValue != originalEditingSessionValue)
5509 if (!startedUndoStackMacro)
5511 undoStack->beginMacro(tr(
"Set Port Constant"));
5512 startedUndoStackMacro =
true;
5532 if (startedUndoStackMacro)
5533 undoStack->endMacro();
5552 QPoint nodeTitleRightCenterInView = ui->graphicsView->mapFromScene(nodeTitleRightCenterInScene);
5553 QPoint nodeTitleRightCenterGlobal = ui->graphicsView->mapToGlobal(nodeTitleRightCenterInView);
5557 int scaledWidth = ui->graphicsView->transform().m11() * nodeWidth;
5558 titleEditor->
setWidth(scaledWidth);
5560 json_object *details = json_object_new_object();
5562 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5564 json_object *originalValueAsJson = json_object_new_string(originalValue.c_str());
5565 json_object *newValueAsJson = titleEditor->
show(nodeTitleRightCenterGlobal, originalValueAsJson, details);
5566 string newValue = json_object_get_string(newValueAsJson);
5567 json_object_put(originalValueAsJson);
5568 json_object_put(newValueAsJson);
5574 if (newValue != originalValue)
5587 json_object *details = json_object_new_object();
5589 json_object_object_add(details,
"isDark", json_object_new_boolean(editor->
isInterfaceDark()));
5591 json_object *originalTextAsJson = json_tokener_parse(originalText.c_str());
5597 int scaledWidth = ui->graphicsView->transform().m11() * commentWidth;
5598 commentEditor->
setWidth(scaledWidth);
5602 int scaledHeight = ui->graphicsView->transform().m11() * commentHeight;
5607 QPointF commentTextRightCenterInScene = comment->scenePos() + commentBoundingRect.topRight() + QPointF(0, commentBoundingRect.height()/2.0);
5608 QPoint commentTextRightCenterInView = ui->graphicsView->mapFromScene(commentTextRightCenterInScene);
5609 QPoint commentTextRightCenterGlobal = ui->graphicsView->mapToGlobal(commentTextRightCenterInView);
5611 json_object *newTextAsJson = commentEditor->
show(commentTextRightCenterGlobal, originalTextAsJson, details);
5613 string newText = json_object_to_json_string_ext(newTextAsJson, JSON_C_TO_STRING_PLAIN);
5614 json_object_put(originalTextAsJson);
5615 json_object_put(newTextAsJson);
5617 if (newText != originalText)
5626 comment->setSelected(
true);
5659 if (originalGenericNodeClass)
5660 nodeClass = originalGenericNodeClass->
getBase();
5663 QString actionText, sourcePath;
5670 QMainWindow *window =
static_cast<VuoEditor *
>(qApp)->openFileWithName(sourcePath,
false);
5674 if (compositionWindow)
5680 static_cast<VuoEditor *
>(qApp)->openUrl(
"file://" + sourcePath);
5689 this->includeInRecentFileMenu = include;
5696void VuoEditorWindow::on_insertComment_triggered()
5704void VuoEditorWindow::insertCommentAtPos(QPointF targetScenePos)
5716 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5717 componentsToAdd.append(comment);
5718 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Comment"));
5721 showCommentEditor(comment);
5727void VuoEditorWindow::on_insertSubcomposition_triggered()
5740bool VuoEditorWindow::ensureThisParentCompositionSaved()
5744 QMessageBox messageBox(
this);
5745 messageBox.setWindowFlags(Qt::Sheet);
5746 messageBox.setWindowModality(Qt::WindowModal);
5747 messageBox.setStandardButtons(QMessageBox::Cancel | QMessageBox::Save);
5748 messageBox.setDefaultButton(QMessageBox::Save);
5749 messageBox.setStyleSheet(
"#qt_msgbox_informativelabel, QMessageBoxDetailsText { font-weight: normal; font-size: 11pt; }");
5751 messageBox.setText(tr(
"Save before packaging"));
5752 messageBox.setInformativeText(tr(
"Please save this composition so Vuo knows where to save your new subcomposition."));
5753 messageBox.setButtonText(QMessageBox::Save, tr(
"Save As…"));
5756 static_cast<QPushButton *
>(messageBox.button(QMessageBox::Cancel))->setAutoDefault(
false);
5757 messageBox.button(QMessageBox::Cancel)->setFocus();
5760 if (messageBox.exec() != QMessageBox::Save)
5764 on_saveCompositionAs_triggered();
5773void VuoEditorWindow::insertSubcompositionAtPos(QPointF targetScenePos)
5779 if (!ensureThisParentCompositionSaved())
5785 string subcompositionContent =
"digraph G {}";
5786 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent);
5787 if (!subcompositionWindow)
5796 string nodeClassName = subcompositionWindow->installSubcomposition(windowFilePath().toUtf8().constData());
5797 if (!nodeClassName.empty())
5803 targetScenePos.y());
5804 if (!subcompositionNode)
5810 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
5812 subcompositionNode);
5815 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
5816 componentsToAdd.append(subcompositionNode);
5817 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"Insert Subcomposition"));
5829 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
5839void VuoEditorWindow::refactorSelectedItems()
5845 if (!ensureThisParentCompositionSaved())
5851 string subcompositionContent = getMaximumSubcompositionFromSelection(
false,
false);
5853 QPoint selectedItemsAvgPos = QPoint(0,0);
5854 int selectedItemCount = 0;
5856 set<string> portsToPublish;
5857 __block map<int, string> inputCablesToRestoreFromPort;
5858 __block map<int, string> inputCablesToRestoreToPort;
5859 __block map<int, bool> inputCablesToRestoreEventOnly;
5860 __block map<int, string> outputCablesToRestoreFromPort;
5861 __block map<int, string> outputCablesToRestoreToPort;
5862 __block map<int, bool> outputCablesToRestoreEventOnly;
5864 QList<QGraphicsItem *> selectedItems = composition->selectedItems();
5865 foreach (QGraphicsItem *item, selectedItems)
5876 foreach (
VuoCable *cable, incomingCables)
5884 int cableNum = inputCablesToRestoreEventOnly.size();
5899 bool typecastHasInternalInput =
false;
5900 bool typecastHasExternalInput =
false;
5901 foreach (
VuoCable *typecastInCable, incomingCables)
5905 typecastHasInternalInput =
true;
5907 typecastHasExternalInput =
true;
5913 if (!typecastHasInternalInput)
5916 VuoPort *typecastHostPort = port;
5920 int cableNum = inputCablesToRestoreEventOnly.size();
5923 inputCablesToRestoreEventOnly[cableNum] =
false;
5930 else if (typecastHasExternalInput && typecastHasInternalInput)
5934 foreach (
VuoCable *typecastInCable, incomingCables)
5940 int cableNum = inputCablesToRestoreEventOnly.size();
5943 inputCablesToRestoreEventOnly[cableNum] =
false;
5964 bool connectedTypecastIsExternal =
false;
5971 connectedTypecastIsExternal = ((outCables.size() < 1) || !outCables[0]->getToNode() ||
5972 !outCables[0]->getToNode()->hasRenderer() ||
5973 !outCables[0]->getToNode()->getRenderer()->isSelected());
5974 if (connectedTypecastIsExternal)
5982 int cableNum = outputCablesToRestoreEventOnly.size();
5990 selectedItemsAvgPos += item->scenePos().toPoint();
5991 selectedItemCount++;
5996 selectedItemsAvgPos += item->scenePos().toPoint();
5997 selectedItemCount++;
6001 selectedItemsAvgPos /= selectedItemCount;
6003 string parentCompositionPath = windowFilePath().toStdString();
6006 VuoEditorWindow *subcompositionWindow =
static_cast<VuoEditor *
>(qApp)->newCompositionWithContent(subcompositionContent, subcompositionDir);
6012 string nodeClassName = subcompositionWindow->installSubcomposition(parentCompositionPath);
6013 if (!nodeClassName.empty())
6018 selectedItemsAvgPos.x(),
6019 selectedItemsAvgPos.y());
6020 if (!subcompositionNode)
6027 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->linkSubcompositionToNodeInSupercomposition(subcompositionWindow->
getComposition(),
6029 subcompositionNode);
6031 undoStack->beginMacro(tr(
"Package as Subcomposition"));
6034 QList<QGraphicsItem *> itemsToRemove;
6036 itemsToRemove.append(node);
6038 itemsToRemove.append(comment);
6040 undoStack->push(
new VuoCommandRemove(itemsToRemove,
this, inputEditorManager,
"Package as Subcomposition",
true));
6043 QList<QGraphicsItem *> componentsToAdd = QList<QGraphicsItem *>();
6044 componentsToAdd.append(subcompositionNode);
6045 undoStack->push(
new VuoCommandAdd(componentsToAdd,
this,
"",
true));
6048 QList<QGraphicsItem *> inputCablesToRestore;
6049 for (
int i = 0; i < inputCablesToRestoreEventOnly.size(); ++i)
6056 if (fromNode && fromPort && toNode && toPort &&
6068 inputCablesToRestore.append(cable);
6076 inputCablesToRestoreEventOnly[i],
6077 inputCablesToRestoreFromPort[i],
6084 QList<QGraphicsItem *> outputCablesToRestore;
6085 for (
int i = 0; i < outputCablesToRestoreEventOnly.size(); ++i)
6092 if (fromNode && fromPort && toNode && toPort &&
6104 outputCablesToRestore.append(cable);
6112 outputCablesToRestoreEventOnly[i],
6113 outputCablesToRestoreToPort[i],
6120 undoStack->push(
new VuoCommandAdd(inputCablesToRestore,
this));
6121 undoStack->push(
new VuoCommandAdd(outputCablesToRestore,
this));
6125 string compositionIdentifier =
static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->getCompositionIdentifier(composition);
6127 set<VuoCompilerNode *> nodesMoved;
6128 for (QGraphicsItem *item : itemsToRemove)
6137 string compositionSnapshot = composition->
takeSnapshot();
6140 diffInfo->
addRefactoring(compositionIdentifier, nodesMoved, subcompositionMovedTo);
6144 undoStack->endMacro();
6157 static_cast<VuoEditor *
>(qApp)->highlightNewNodeClassInAllLibraries(nodeClassName);
6176 return raiseDocumentAction;
6184 return ui->showEvents;
6208 return ui->zoomToFit;
6246 return ownedNodeLibrary;
6265 transitionNodeLibraryConnections(this->nl, library);
6275 transitionNodeLibraryConnections((previousFloaterDestroyed? NULL : this->nl), this->ownedNodeLibrary);
6276 this->nl = this->ownedNodeLibrary;
6284 return ui->menuFile;
6292 return menuOpenRecent;
6317 disconnect(oldLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6318 disconnect(oldLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6321 disconnect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), oldLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6336 connect(newLibrary, &VuoNodeLibrary::visibilityChanged,
this, &VuoEditorWindow::updateSceneRect);
6337 connect(newLibrary, &VuoNodeLibrary::dockLocationChanged,
this, &VuoEditorWindow::updateSceneRect);
6340 connect(composition, SIGNAL(nodePopoverRequestedForClass(
VuoNodeClass *)), newLibrary, SLOT(prepareAndDisplayNodePopoverForClass(
VuoNodeClass *)));
6356void VuoEditorWindow::restoreDefaultLeftDockedWidgetWidths()
6360 nl->setMinimumWidth(nodeLibraryMinimumWidth);
6361 nl->setMaximumWidth(nodeLibraryMaximumWidth);
6364 if (inputPortSidebar && outputPortSidebar)
6366 inputPortSidebar->setMinimumWidth(outputPortSidebar->minimumWidth());
6367 inputPortSidebar->setMaximumWidth(outputPortSidebar->maximumWidth());
6382 QPoint positionChange =
event->pos() -
event->oldPos();
6383 composition->
movePopoversBy(positionChange.x(), positionChange.y());
6386 QMainWindow::moveEvent(
event);
6397 toolbar->updateTitle();
6400 QMainWindow::resizeEvent(
event);
6408QList<QGraphicsItem *> VuoEditorWindow::createAnyNecessaryMakeListComponents(
VuoPort *port)
6410 QList<QGraphicsItem *> makeListComponents;
6419 makeListComponents.append(makeListNode);
6420 makeListComponents.append(makeListCable);
6423 return makeListComponents;
6429void VuoEditorWindow::updateGrid()
6431 QGraphicsView::CacheMode defaultViewportCacheMode = ui->graphicsView->cacheMode();
6433 ui->graphicsView->setCacheMode(QGraphicsView::CacheNone);
6434 ui->graphicsView->viewport()->update();
6436 ui->graphicsView->setCacheMode(defaultViewportCacheMode);
6442void VuoEditorWindow::updateCanvasOpacity()
6444 int opacity =
static_cast<VuoEditor *
>(qApp)->getCanvasOpacity();
6451void VuoEditorWindow::updateColor(
bool isDark)
6454 QString backgroundColor = colors->
canvasFill().name();
6455 QString scrollBarColor = isDark ?
"#505050" :
"#dfdfdf";
6456 QString dockwidgetTitleBackgroundColor = isDark ?
"#919191" :
"#efefef";
6460 if (doneInitializing)
6461 setStyleSheet(VUO_QSTRINGIFY(
6463 background-color: %2;
6465 QMainWindow::separator {
6466 background-color: %1;
6473 .arg(dockwidgetTitleBackgroundColor)
6474 .arg(backgroundColor)
6478 ui->graphicsView->setStyleSheet(styles);
6480 ui->graphicsView->setStyleSheet(VUO_QSTRINGIFY(
6486 QScrollBar::handle {
6493 QAbstractScrollArea::corner,
6494 QScrollBar::add-line,
6495 QScrollBar::sub-line,
6496 QScrollBar::add-page,
6497 QScrollBar::sub-page {
6502 .arg(backgroundColor)
6503 .arg(scrollBarColor)
6507 if (doneInitializing)
6519void VuoEditorWindow::coalescedUpdateRunningComposition()
6521 if (coalescedOldCompositionSnapshot.empty() != coalescedNewCompositionSnapshot.empty())
6524 foreach (
string nodeID, coalescedNodesToUnlink)
6525 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->unlinkNodeInSupercompositionFromSubcomposition(composition, nodeID);
6527 if (!coalescedOldCompositionSnapshot.empty() && !coalescedNewCompositionSnapshot.empty())
6528 composition->
updateRunningComposition(coalescedOldCompositionSnapshot, coalescedNewCompositionSnapshot, coalescedDiffInfo);
6530 foreach (
string portID, coalescedInternalPortConstantsToSync)
6533 foreach (
string portID, coalescedPublishedPortConstantsToSync)
6536 foreach (
string nodeID, coalescedNodesToRelink)
6537 static_cast<VuoEditor *
>(qApp)->getSubcompositionRouter()->relinkNodeInSupercompositionToSubcomposition(composition, nodeID);
6539 coalescedOldCompositionSnapshot =
"";
6540 coalescedNewCompositionSnapshot =
"";
6541 coalescedInternalPortConstantsToSync.clear();
6542 coalescedPublishedPortConstantsToSync.clear();
6543 coalescedNodesToUnlink.clear();
6544 coalescedNodesToRelink.clear();
6545 coalescedDiffInfo =
nullptr;
6554 if (diffInfo && coalescedDiffInfo)
6555 coalescedUpdateRunningComposition();
6557 if (coalescedOldCompositionSnapshot.empty())
6558 coalescedOldCompositionSnapshot = oldCompositionSnapshot;
6560 coalescedNewCompositionSnapshot = newCompositionSnapshot;
6561 coalescedDiffInfo = diffInfo;
6569 coalescedInternalPortConstantsToSync.push_back(portID);
6577 coalescedPublishedPortConstantsToSync.push_back(portID);
6585 coalescedNodesToUnlink.push_back(nodeID);
6593 coalescedNodesToRelink.push_back(nodeID);
6601void VuoEditorWindow::handlePendingProtocolComplianceReevaluationRequests()
6603 if (protocolComplianceReevaluationPending)
6605 evaluateCompositionForProtocolPromotion();
6606 protocolComplianceReevaluationPending =
false;
6618void VuoEditorWindow::registerProtocolComplianceEvaluationRequest()
6620 this->protocolComplianceReevaluationPending =
true;
6628 return ui->graphicsView->mapToScene(ui->graphicsView->mapFromGlobal(QCursor::pos()));
6636 return metadataPanel;
6650 QRectF viewportRect = ui->graphicsView->mapToScene(ui->graphicsView->viewport()->rect()).boundingRect();
6651 double targetX = min(max(origPos.x(), viewportRect.left()+leftMargin), viewportRect.right()-rightMargin);
6652 double targetY = min(max(origPos.y(), viewportRect.top()+topMargin), viewportRect.bottom()-bottomMargin);
6655 bool targetPositionClearOfCoincidentNodes =
false;
6656 while (!targetPositionClearOfCoincidentNodes)
6658 QGraphicsItem *preexistingItem = composition->itemAt(QPoint(targetX, targetY), composition->views()[0]->transform());
6659 if (
dynamic_cast<VuoRendererNode *
>(preexistingItem) && (preexistingItem->scenePos() == QPoint(targetX, targetY)))
6661 targetX += pastedComponentOffset;
6662 targetY += pastedComponentOffset;
6665 targetPositionClearOfCoincidentNodes =
true;
6668 return QPointF(targetX, targetY);
6674void VuoEditorWindow::toggleNodeLibraryDockedState()
6678 bool floatLibrary = !nl->isFloating();
6679 nl->setFloating(floatLibrary);
6680 nl->
fixWidth(!floatLibrary && !inputPortSidebar->isHidden());
6690 undoStack->beginMacro(tr(commandName.toUtf8().constData()));
6698 undoStack->endMacro();