void ProjectGuiSerialization::initialize(const ProjectGui* projectGui) { NodesList activeNodes; projectGui->getInternalProject()->getActiveNodesExpandGroups(&activeNodes); _serializedNodes.clear(); for (NodesList::iterator it = activeNodes.begin(); it != activeNodes.end(); ++it) { boost::shared_ptr<NodeGuiI> nodegui_i = (*it)->getNodeGui(); if (!nodegui_i) { continue; } NodeGuiPtr nodegui = boost::dynamic_pointer_cast<NodeGui>(nodegui_i); if ( nodegui->isVisible() ) { boost::shared_ptr<NodeCollection> isInCollection = (*it)->getGroup(); NodeGroup* isCollectionAGroup = dynamic_cast<NodeGroup*>( isInCollection.get() ); if (!isCollectionAGroup) { ///Nodes within a group will be serialized recursively in the node group serialization NodeGuiSerialization state; nodegui->serialize(&state); _serializedNodes.push_back(state); } ViewerInstance* viewer = (*it)->isEffectViewer(); if (viewer) { ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer); assert(tab); ViewerData viewerData; double zoompar; tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &zoompar); viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest(); viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled(); viewerData.isClippedToProject = tab->isClippedToProject(); viewerData.autoContrastEnabled = tab->isAutoContrastEnabled(); viewerData.gain = tab->getGain(); viewerData.gamma = tab->getGamma(); viewerData.colorSpace = tab->getColorSpace(); viewerData.channels = tab->getChannelsString(); viewerData.renderScaleActivated = tab->getRenderScaleActivated(); viewerData.mipMapLevel = tab->getMipMapLevel(); viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit(); viewerData.wipeCompositingOp = (int)tab->getCompositingOperator(); viewerData.leftToolbarVisible = tab->isLeftToolbarVisible(); viewerData.rightToolbarVisible = tab->isRightToolbarVisible(); viewerData.topToolbarVisible = tab->isTopToolbarVisible(); viewerData.infobarVisible = tab->isInfobarVisible(); viewerData.playerVisible = tab->isPlayerVisible(); viewerData.timelineVisible = tab->isTimelineVisible(); viewerData.checkerboardEnabled = tab->isCheckerboardEnabled(); viewerData.fps = tab->getDesiredFps(); viewerData.fpsLocked = tab->isFPSLocked(); viewerData.isPauseEnabled[0] = tab->isViewerPaused(0); viewerData.isPauseEnabled[1] = tab->isViewerPaused(1); viewerData.layerName = tab->getCurrentLayerName().toStdString(); viewerData.alphaLayerName = tab->getCurrentAlphaLayerName().toStdString(); tab->getTimelineBounds(&viewerData.leftBound, &viewerData.rightBound); tab->getActiveInputs(&viewerData.aChoice, &viewerData.bChoice); viewerData.version = VIEWER_DATA_SERIALIZATION_VERSION; _viewersData.insert( std::make_pair(viewer->getNode()->getScriptName_mt_safe(), viewerData) ); } } } ///Init windows _layoutSerialization.initialize( projectGui->getGui() ); ///save histograms std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe(); for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) { _histograms.push_back( (*it)->objectName().toStdString() ); } ///save opened panels by order std::list<DockablePanel*> panels = projectGui->getGui()->getVisiblePanels_mt_safe(); for (std::list<DockablePanel*>::iterator it = panels.begin(); it != panels.end(); ++it) { if ( (*it)->isVisible() ) { KnobHolder* holder = (*it)->getHolder(); assert(holder); EffectInstance* isEffect = dynamic_cast<EffectInstance*>(holder); Project* isProject = dynamic_cast<Project*>(holder); if (isProject) { _openedPanelsOrdered.push_back(kNatronProjectSettingsPanelSerializationName); } else if (isEffect) { _openedPanelsOrdered.push_back( isEffect->getNode()->getFullyQualifiedName() ); } } } _scriptEditorInput = projectGui->getGui()->getScriptEditor()->getAutoSavedScript().toStdString(); std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string> pythonPanels = projectGui->getGui()->getPythonPanels(); for (std::map<NATRON_PYTHON_NAMESPACE::PyPanel*, std::string>::iterator it = pythonPanels.begin(); it != pythonPanels.end(); ++it) { boost::shared_ptr<PythonPanelSerialization> s(new PythonPanelSerialization); s->initialize(it->first, it->second); _pythonPanels.push_back(s); } } // initialize
void ProjectGuiSerialization::initialize(const ProjectGui* projectGui) { std::list<boost::shared_ptr<NodeGui> > activeNodes = projectGui->getVisibleNodes(); _serializedNodes.clear(); for (std::list<boost::shared_ptr<NodeGui> >::iterator it = activeNodes.begin();it!=activeNodes.end();++it) { NodeGuiSerialization state; (*it)->serialize(&state); _serializedNodes.push_back(state); if ((*it)->getNode()->pluginID() == "Viewer") { ViewerInstance* viewer = dynamic_cast<ViewerInstance*>((*it)->getNode()->getLiveInstance()); assert(viewer); ViewerTab* tab = projectGui->getGui()->getViewerTabForInstance(viewer); assert(tab); ViewerData viewerData; tab->getViewer()->getProjection(&viewerData.zoomLeft, &viewerData.zoomBottom, &viewerData.zoomFactor, &viewerData.zoomPAR); viewerData.userRoI = tab->getViewer()->getUserRegionOfInterest(); viewerData.userRoIenabled = tab->getViewer()->isUserRegionOfInterestEnabled(); viewerData.isClippedToProject = tab->isClippedToProject(); viewerData.autoContrastEnabled = tab->isAutoContrastEnabled(); viewerData.gain = tab->getGain(); viewerData.colorSpace = tab->getColorSpace(); viewerData.channels = tab->getChannelsString(); viewerData.renderScaleActivated = tab->getRenderScaleActivated(); viewerData.mipMapLevel = tab->getMipMapLevel(); viewerData.zoomOrPanSinceLastFit = tab->getZoomOrPannedSinceLastFit(); viewerData.wipeCompositingOp = (int)tab->getCompositingOperator(); _viewersData.insert(std::make_pair(viewer->getNode()->getName_mt_safe(),viewerData)); } } std::list<TabWidget*> tabWidgets = projectGui->getGui()->getPanes_mt_safe(); for (std::list<TabWidget*>::const_iterator it = tabWidgets.begin(); it!= tabWidgets.end(); ++it) { QString widgetName = (*it)->objectName_mt_safe(); if(widgetName.isEmpty()){ qDebug() << "Warning: attempting to save the layout of an unnamed TabWidget, discarding."; continue; } PaneLayout layout; layout.parentingCreated = false; std::map<TabWidget*,bool> userSplits = (*it)->getUserSplits(); for (std::map<TabWidget*,bool>::const_iterator split = userSplits.begin(); split!=userSplits.end(); ++split) { layout.splits.push_back(split->second); } layout.floating = (*it)->isFloating(); if(layout.floating){ QPoint pos = (*it)->pos_mt_safe(); layout.posx = pos.x(); layout.posy = pos.y(); }else{ //not releveant since the tab is not floating layout.posx = -1; layout.posy = -1; } QStringList tabNames = (*it)->getTabNames(); for (int i = 0; i < tabNames.size(); ++i) { if(tabNames[i].isEmpty()){ qDebug() << "Warning: attempting to save the position of an unnamed tab, discarding."; continue; } layout.tabs.push_back(tabNames[i].toStdString()); } _layout.insert(std::make_pair(widgetName.toStdString(),layout)); } ///now we do a second pass to insert for each layout what are its children splits for (std::map<std::string,PaneLayout>::iterator it = _layout.begin(); it!= _layout.end(); ++it) { if(!it->second.parentingCreated){ createParenting(it); } } ///save application's splitters states std::list<Splitter*> splitters = projectGui->getGui()->getSplitters(); for (std::list<Splitter*>::const_iterator it = splitters.begin(); it!= splitters.end(); ++it) { QByteArray ba = (*it)->saveState(); ba = ba.toBase64(); QString str(ba); _splittersStates.insert(std::make_pair((*it)->objectName_mt_safe().toStdString(),str.toStdString())); } _arePreviewTurnedOffGlobally = projectGui->getGui()->getNodeGraph()->areAllPreviewTurnedOff(); ///save histograms std::list<Histogram*> histograms = projectGui->getGui()->getHistograms_mt_safe(); for (std::list<Histogram*>::const_iterator it = histograms.begin(); it != histograms.end(); ++it) { _histograms.push_back((*it)->objectName().toStdString()); } std::list<NodeBackDrop*> backdrops = projectGui->getGui()->getNodeGraph()->getActiveBackDrops(); for (std::list<NodeBackDrop*>::iterator it = backdrops.begin(); it!=backdrops.end();++it) { NodeBackDropSerialization s; s.initialize(*it); _backdrops.push_back(s); } }
ViewerTab* Gui::addNewViewerTab(const NodeGuiPtr& node, TabWidget* where) { if (!node) { return 0; } ViewerNodePtr viewer = node->getNode()->isEffectViewerNode(); NodesGuiList activeNodeViewerUi, nodeViewerUi; //Don't create tracker & roto interface for file dialog preview viewer NodeCollectionPtr group = viewer->getNode()->getGroup(); if (group) { if ( !_imp->_viewerTabs.empty() ) { ( *_imp->_viewerTabs.begin() )->getNodesViewerInterface(&nodeViewerUi, &activeNodeViewerUi); } else { NodeGraph* graph = dynamic_cast<NodeGraph*>( group->getNodeGraph() ); if (!graph) { graph = _imp->_nodeGraphArea; } if (graph) { const NodesGuiList & allNodes = graph->getAllActiveNodes(); std::set<std::string> activeNodesPluginID; for (NodesGuiList::const_iterator it = allNodes.begin(); it != allNodes.end(); ++it) { nodeViewerUi.push_back( *it ); std::string pluginID = (*it)->getNode()->getPluginID(); std::set<std::string>::iterator found = activeNodesPluginID.find(pluginID); if ( found == activeNodesPluginID.end() ) { activeNodesPluginID.insert(pluginID); activeNodeViewerUi.push_back(*it); } } } } } std::string nodeName = node->getNode()->getFullyQualifiedName(); for (std::size_t i = 0; i < nodeName.size(); ++i) { if (nodeName[i] == '.') { nodeName[i] = '_'; } } std::string label; NodeGraph::makeFullyQualifiedLabel(node->getNode(), &label); ViewerTab* tab = new ViewerTab(nodeName, nodeViewerUi, activeNodeViewerUi, this, node, where); tab->setLabel(label); QObject::connect( tab->getViewer(), SIGNAL(imageChanged(int,bool)), this, SLOT(onViewerImageChanged(int,bool)) ); { QMutexLocker l(&_imp->_viewerTabsMutex); _imp->_viewerTabs.push_back(tab); if (!_imp->_activeViewer) { _imp->_activeViewer = tab; } } where->appendTab(tab, tab); Q_EMIT viewersChanged(); return tab; } // Gui::addNewViewerTab
NATRON_NAMESPACE_ENTER ViewerTab::ViewerTab(const std::string& scriptName, const std::list<NodeGuiPtr> & existingNodesContext, const std::list<NodeGuiPtr>& activePluginsContext, Gui* gui, const NodeGuiPtr& node_ui, QWidget* parent) : QWidget(parent) , PanelWidget(scriptName, this, gui) , _imp( new ViewerTabPrivate(this, node_ui) ) { ViewerNodePtr node = node_ui->getNode()->isEffectViewerNode(); installEventFilter(this); setMouseTracking(true); NodePtr internalNode = node->getNode(); QObject::connect( internalNode.get(), SIGNAL(scriptNameChanged(QString)), this, SLOT(onInternalNodeScriptNameChanged(QString)) ); QObject::connect( internalNode.get(), SIGNAL(labelChanged(QString,QString)), this, SLOT(onInternalNodeLabelChanged(QString,QString)) ); QObject::connect( node.get(), SIGNAL(internalViewerCreated()), this, SLOT(onInternalViewerCreated())); _imp->mainLayout = new QVBoxLayout(this); setLayout(_imp->mainLayout); _imp->mainLayout->setSpacing(0); _imp->mainLayout->setContentsMargins(0, 0, 0, 0); QFontMetrics fm(font(), 0); _imp->viewerContainer = new QWidget(this); _imp->viewerLayout = new QHBoxLayout(_imp->viewerContainer); _imp->viewerLayout->setContentsMargins(0, 0, 0, 0); _imp->viewerLayout->setSpacing(0); _imp->viewerSubContainer = new QWidget(_imp->viewerContainer); _imp->viewerSubContainerLayout = new QVBoxLayout(_imp->viewerSubContainer); _imp->viewerSubContainerLayout->setContentsMargins(0, 0, 0, 0); _imp->viewerSubContainerLayout->setSpacing(1); // Info bars QString inputNames[2] = { QString::fromUtf8("A:"), QString::fromUtf8("B:") }; bool infobarvisible = node->isInfoBarVisible(); for (int i = 0; i < 2; ++i) { _imp->infoWidget[i] = new InfoViewerWidget(inputNames[i], this); } // Viewer _imp->viewer = new ViewerGL(this); GuiAppInstancePtr app = gui->getApp(); // Init viewer to project format { Format projectFormat; app->getProject()->getProjectDefaultFormat(&projectFormat); RectD canonicalFormat = projectFormat.toCanonicalFormat(); for (int i = 0; i < 2; ++i) { _imp->viewer->setInfoViewer(_imp->infoWidget[i], i); _imp->viewer->setRegionOfDefinition(canonicalFormat, projectFormat.getPixelAspectRatio(), i); setInfoBarAndViewerResolution(projectFormat, canonicalFormat, projectFormat.getPixelAspectRatio(), i); } _imp->viewer->resetWipeControls(); } _imp->viewerSubContainerLayout->addWidget(_imp->viewer); for (int i = 0; i < 2; ++i) { _imp->viewerSubContainerLayout->addWidget(_imp->infoWidget[i]); _imp->viewer->setInfoViewer(_imp->infoWidget[i], i); if (i == 1 || !infobarvisible) { _imp->infoWidget[i]->hide(); } } manageSlotsForInfoWidget(0, true); _imp->viewerLayout->addWidget(_imp->viewerSubContainer); _imp->mainLayout->addWidget(_imp->viewerContainer); TimeLinePtr timeline = app->getTimeLine(); _imp->timeLineGui = new TimeLineGui(node, timeline, getGui(), this); QObject::connect( _imp->timeLineGui, SIGNAL(boundariesChanged(SequenceTime,SequenceTime)), this, SLOT(onTimelineBoundariesChanged(SequenceTime,SequenceTime)) ); QObject::connect( app->getProject().get(), SIGNAL(frameRangeChanged(int,int)), _imp->timeLineGui, SLOT(onProjectFrameRangeChanged(int,int)) ); _imp->timeLineGui->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum); if (!node->isTimelineVisible()) { _imp->timeLineGui->hide(); } //Add some spacing because the timeline might be black as the info _imp->mainLayout->addSpacing( TO_DPIY(5) ); _imp->mainLayout->addWidget(_imp->timeLineGui); double leftBound, rightBound; leftBound = node->getPlaybackInPointKnob()->getValue(); rightBound = node->getPlaybackOutPointKnob()->getValue(); TimeValue projectLeft, projectRight; app->getProject()->getFrameRange(&projectLeft, &projectRight); _imp->timeLineGui->setBoundaries(leftBound, rightBound); onTimelineBoundariesChanged(leftBound, rightBound); _imp->timeLineGui->setFrameRangeEdited(projectLeft != leftBound || projectRight != rightBound);; manageTimelineSlot(false, timeline); QObject::connect( node.get(), SIGNAL(renderStatsAvailable(int,double,RenderStatsMap)), this, SLOT(onRenderStatsAvailable(int,double,RenderStatsMap)) ); QObject::connect( _imp->viewer, SIGNAL(zoomChanged(int)), this, SLOT(updateZoomComboBox(int)) ); QObject::connect( node.get(), SIGNAL(viewerDisconnected()), this, SLOT(disconnectViewer()) ); createNodeViewerInterface(node_ui); setPluginViewerInterface(node_ui); for (std::list<NodeGuiPtr>::const_iterator it = existingNodesContext.begin(); it != existingNodesContext.end(); ++it) { ViewerNodePtr isViewerNode = (*it)->getNode()->isEffectViewerNode(); // For viewers, create the viewer interface separately if (!isViewerNode) { createNodeViewerInterface(*it); } } for (std::list<NodeGuiPtr>::const_iterator it = activePluginsContext.begin(); it != activePluginsContext.end(); ++it) { ViewerNodePtr isViewerNode = (*it)->getNode()->isEffectViewerNode(); // For viewers, create the viewer interface separately if (!isViewerNode) { setPluginViewerInterface(*it); } } setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Preferred); _imp->viewerNode.lock()->setUiContext( getViewer() ); QTimer::singleShot( 25, _imp->timeLineGui, SLOT(recenterOnBounds()) ); //Refresh the viewport lock state const std::list<ViewerTab*>& viewers = getGui()->getViewersList(); if ( !viewers.empty() ) { ViewerTab* other = viewers.front(); if ( other->getInternalNode()->isViewersSynchroEnabled() ) { double left, bottom, factor, par; other->getViewer()->getProjection(&left, &bottom, &factor, &par); _imp->viewer->setProjection(left, bottom, factor, par); node->setViewersSynchroEnabled(true); } } _imp->cachedFramesThread.reset(new CachedFramesThread(this)); _imp->cachedFramesThread->start(); }
void NodeGraph::connectCurrentViewerToSelection(int inputNB) { ViewerTab* lastUsedViewer = getLastSelectedViewer(); if (lastUsedViewer) { boost::shared_ptr<NodeCollection> collection = lastUsedViewer->getInternalNode()->getNode()->getGroup(); if (collection && collection->getNodeGraph() != this) { //somehow the group doesn't belong to this nodegraph , pick another one const std::list<ViewerTab*>& tabs = getGui()->getViewersList(); lastUsedViewer = 0; for (std::list<ViewerTab*>::const_iterator it = tabs.begin(); it!=tabs.end(); ++it) { boost::shared_ptr<NodeCollection> otherCollection = (*it)->getInternalNode()->getNode()->getGroup(); if (otherCollection && otherCollection->getNodeGraph() == this) { lastUsedViewer = *it; break; } } } } boost::shared_ptr<InspectorNode> v; if ( lastUsedViewer ) { v = boost::dynamic_pointer_cast<InspectorNode>( lastUsedViewer-> getInternalNode()->getNode() ); } else { CreateNodeArgs args(QString::fromUtf8(PLUGINID_NATRON_VIEWER), eCreateNodeReasonUserCreate, getGroup()); NodePtr viewerNode = getGui()->getApp()->createNode(args); if (!viewerNode) { return; } v = boost::dynamic_pointer_cast<InspectorNode>(viewerNode); } if (!v) { return; } ///if the node is no longer active (i.e: it was deleted by the user), don't do anything. if ( !v->isActivated() ) { return; } ///get a ptr to the NodeGui boost::shared_ptr<NodeGuiI> gui_i = v->getNodeGui(); NodeGuiPtr gui = boost::dynamic_pointer_cast<NodeGui>(gui_i); assert(gui); ///if there's no selected node or the viewer is selected, then try refreshing that input nb if it is connected. bool viewerAlreadySelected = std::find(_imp->_selection.begin(),_imp->_selection.end(),gui) != _imp->_selection.end(); if (_imp->_selection.empty() || (_imp->_selection.size() > 1) || viewerAlreadySelected) { v->setActiveInputAndRefresh(inputNB, false); gui->refreshEdges(); return; } NodeGuiPtr selected = _imp->_selection.front(); if ( !selected->getNode()->canOthersConnectToThisNode() ) { return; } ///if the node doesn't have the input 'inputNb' created yet, populate enough input ///so it can be created. Edge* foundInput = gui->getInputArrow(inputNB); assert(foundInput); ///and push a connect command to the selected node. pushUndoCommand( new ConnectCommand(this,foundInput,foundInput->getSource(),selected) ); ///Set the viewer as the selected node (also wipe the current selection) selectNode(gui,false); } // connectCurrentViewerToSelection