#include "toonzqt/fxschematicscene.h" // TnzQt includes #include "toonzqt/fxtypes.h" #include "toonzqt/fxschematicnode.h" #include "toonzqt/gutil.h" #include "toonzqt/dvdialog.h" #include "toonzqt/fxselection.h" #include "toonzqt/schematicgroupeditor.h" #include "toonzqt/swatchviewer.h" #include "toonzqt/tselectionhandle.h" // TnzLib includes #include "toonz/txsheet.h" #include "toonz/toonzscene.h" #include "toonz/tcolumnfxset.h" #include "toonz/fxdag.h" #include "toonz/txshlevelcolumn.h" #include "toonz/tcolumnfx.h" #include "toonz/txshpalettecolumn.h" #include "toonz/txshzeraryfxcolumn.h" #include "toonz/fxcommand.h" #include "toonz/txsheethandle.h" #include "toonz/tfxhandle.h" #include "toonz/tscenehandle.h" #include "toonz/tcolumnhandle.h" #include "toonz/tframehandle.h" #include "toonz/tobjecthandle.h" #include "toonz/childstack.h" // TnzBase includes #include "tmacrofx.h" #include "fxdata.h" #include "tpassivecachemanager.h" #include "tfxattributes.h" // TnzCore includes #include "tconst.h" #include "tenv.h" // Qt includes #include #include #include TEnv::IntVar IconifyFxSchematicNodes("IconifyFxSchematicNodes", 0); namespace { class MatchesFx { TFxP m_fx; public: MatchesFx(const TFxP &fx) : m_fx(fx) {} bool operator()(const TFxP &fx) { TZeraryColumnFx *zfx = dynamic_cast(fx.getPointer()); return (m_fx.getPointer() == fx.getPointer()) || (zfx && m_fx.getPointer() == zfx->getZeraryFx()); } }; //----------------------------------------------------------- void keepSubgroup(QMap> &editedGroup) { QMap>::iterator it; for (it = editedGroup.begin(); it != editedGroup.end(); it++) { QList groupedNodes = it.value(); int i; for (i = 0; i < groupedNodes.size(); i++) { FxSchematicNode *node = dynamic_cast(groupedNodes[i]); if (!node) continue; TFx *fx = node->getFx(); assert(fx); QMap>::iterator it2; for (it2 = editedGroup.begin(); it2 != editedGroup.end(); it2++) { if (fx->getAttributes()->isContainedInGroup(it2.key()) && !editedGroup[it2.key()].contains(node)) editedGroup[it2.key()].append(node); } } } } //----------------------------------------------------------- //! Find the input and the output fx contained in \b visitedFxs. //! \b visitedFxs must be a connected fx selection. In \b outputFx is put the //! root of the connected fx selection. //! In \b inputFx is put a leaf of the connected fx selection. void findBoundariesFxs(TFx *&inputFx, TFx *&outputFx, QMap &visitedFxs, TFx *currentFx = 0) { if (visitedFxs.isEmpty()) return; if (!currentFx) currentFx = visitedFxs.begin().key(); int inputPortCount = currentFx->getInputPortCount(); int outputConnectionCount = currentFx->getOutputConnectionCount(); if (inputPortCount > 0 && !visitedFxs[currentFx]) { visitedFxs[currentFx] = true; TFxPort *fxPort = currentFx->getInputPort(0); TFx *fx = fxPort->getFx(); if (fx && visitedFxs.count(fx) == 1) { if (!visitedFxs[fx]) findBoundariesFxs(inputFx, outputFx, visitedFxs, fx); } else inputFx = currentFx; } else inputFx = currentFx; if (!outputFx) { if (outputConnectionCount > 0) { TFx *fx = currentFx->getOutputConnection(0)->getOwnerFx(); if (fx && visitedFxs.count(fx) == 1) { if (!visitedFxs[fx]) findBoundariesFxs(inputFx, outputFx, visitedFxs, fx); } else outputFx = currentFx; } else outputFx = currentFx; } } //----------------------------------------------------------- bool canDisconnectSelection(FxSelection *selection) { QList selectedFx = selection->getFxs(); int i; for (i = 0; i < selectedFx.size(); i++) // ..... { TFx *fx = selectedFx[i].getPointer(); TLevelColumnFx *lcFx = dynamic_cast(fx); TPaletteColumnFx *pfx = dynamic_cast(fx); TXsheetFx *xfx = dynamic_cast(fx); TOutputFx *ofx = dynamic_cast(fx); TZeraryColumnFx *zfx = dynamic_cast(fx); return (!lcFx && !pfx && !xfx && !ofx && (!zfx || zfx->getInputPortCount() > 0)); // !!!!! } return false; } //------------------------------------------------------------------ QList getRoots(const QList &fxs, TFxSet *terminals) { QList roots; int i; for (i = 0; i < fxs.size(); i++) { TFx *fx = fxs[i].getPointer(); int j; bool isRoot = true; for (j = 0; j < fx->getOutputConnectionCount(); j++) { TFx *outFx = fx->getOutputConnection(j)->getOwnerFx(); if (outFx && std::find_if(fxs.begin(), fxs.end(), MatchesFx(outFx)) != fxs.end() && !terminals->containsFx(fx)) isRoot = false; } if (isRoot) roots.append(fx); } return roots; } bool resizingNodes = false; bool updatingScene = false; } // namespace //================================================================== // // FxSchematicScene::SupportLinks // //================================================================== void FxSchematicScene::SupportLinks::addBridgeLink(SchematicLink *link) { if (link && !m_bridges.contains(link)) m_bridges.push_back(link); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::addOutputLink(SchematicLink *link) { if (link && !m_outputs.contains(link)) m_outputs.push_back(link); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::addInputLink(SchematicLink *link) { if (link && !m_inputs.contains(link)) m_inputs.push_back(link); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::hideBridgeLinks() { int i; for (i = 0; i < m_bridges.size(); i++) m_bridges[i]->hide(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::hideInputLinks() { int i; for (i = 0; i < m_inputs.size(); i++) m_inputs[i]->hide(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::hideOutputLinks() { int i; for (i = 0; i < m_outputs.size(); i++) m_outputs[i]->hide(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::showBridgeLinks() { int i; for (i = 0; i < m_bridges.size(); i++) m_bridges[i]->show(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::showInputLinks() { int i; for (i = 0; i < m_inputs.size(); i++) m_inputs[i]->show(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::showOutputLinks() { int i; for (i = 0; i < m_outputs.size(); i++) m_outputs[i]->show(); } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::removeBridgeLinks(bool deleteLink) { int i; for (i = 0; i < m_bridges.size(); i++) { SchematicLink *link = m_bridges[i]; m_bridges.removeAt(i); if (deleteLink) { link->getStartPort()->removeLink(link); link->getEndPort()->removeLink(link); delete link; } } } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::removeInputLinks(bool deleteLink) { int i; for (i = 0; i < m_inputs.size(); i++) { SchematicLink *link = m_inputs[i]; m_inputs.removeAt(i); if (deleteLink) { link->getStartPort()->removeLink(link); link->getEndPort()->removeLink(link); delete link; } } } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::removeOutputLinks(bool deleteLink) { int i; for (i = 0; i < m_outputs.size(); i++) { SchematicLink *link = m_outputs[i]; m_outputs.removeAt(i); if (deleteLink) { link->getStartPort()->removeLink(link); link->getEndPort()->removeLink(link); delete link; } } } //------------------------------------------------------------------ void FxSchematicScene::SupportLinks::clearAll() { m_bridges.clear(); m_inputs.clear(); m_outputs.clear(); } //------------------------------------------------------------------ int FxSchematicScene::SupportLinks::size() { return m_bridges.size() + m_inputs.size() + m_outputs.size(); } //================================================================== // // FxSchematicScene // //================================================================== FxSchematicScene::FxSchematicScene(QWidget *parent) : SchematicScene(parent) , m_firstPoint(sceneRect().center()) , m_xshHandle(0) , m_fxHandle(0) , m_addFxContextMenu() , m_disconnectionLinks() , m_connectionLinks() , m_isConnected(false) , m_linkUnlinkSimulation(false) , m_altPressed(false) , m_lastPos(0, 0) , m_currentFxNode(0) , m_gridDimension(eSmall) , m_isNormalIconView(!IconifyFxSchematicNodes) , m_viewer() { m_viewer = (SchematicViewer *)parent; m_selection = new FxSelection(); m_selection->setFxSchematicScene(this); connect(m_selection, SIGNAL(doCollapse(const QList &)), this, SLOT(onCollapse(const QList &))); connect(m_selection, SIGNAL(doExplodeChild(const QList &)), this, SIGNAL(doExplodeChild(const QList &))); connect(this, SIGNAL(selectionChanged()), this, SLOT(onSelectionChanged())); m_addFxContextMenu.setSelection(m_selection); m_highlightedLinks.clear(); } //------------------------------------------------------------------ FxSchematicScene::~FxSchematicScene() { if (m_selection) delete m_selection; } //------------------------------------------------------------------ void FxSchematicScene::setApplication(TApplication *app) { m_app = app; m_xshHandle = app->getCurrentXsheet(); m_fxHandle = app->getCurrentFx(); m_frameHandle = app->getCurrentFrame(); m_columnHandle = app->getCurrentColumn(); if (m_fxHandle) connect(m_fxHandle, SIGNAL(fxSwitched()), this, SLOT(onCurrentFxSwitched())); m_addFxContextMenu.setApplication(app); m_selection->setXsheetHandle(m_xshHandle); m_selection->setFxHandle(m_fxHandle); } //------------------------------------------------------------------ void FxSchematicScene::updateScene() { if (updatingScene) return; updatingScene = true; if (!views().empty()) m_disconnectionLinks.clearAll(); m_connectionLinks.clearAll(); m_selectionOldPos.clear(); clearSelection(); clearAllItems(); m_table.clear(); m_groupedTable.clear(); m_groupEditorTable.clear(); m_macroEditorTable.clear(); m_currentFxNode = 0; // GroupId->Fx QMap> groupedFxs; QMap> editedGroup; QMap> editedMacro; TXsheet *xsh = m_xshHandle->getXsheet(); m_gridDimension = xsh->getFxDag()->getDagGridDimension(); TFxSet *fxSet = xsh->getFxDag()->getInternalFxs(); int i; FxDag *fxDag = xsh->getFxDag(); // Add XSheetFX node addFxSchematicNode(fxDag->getXsheetFx()); // Add outputFx nodes int k; for (k = 0; k < fxDag->getOutputFxCount(); k++) { TOutputFx *fx = fxDag->getOutputFx(k); if (fx->getAttributes()->isGrouped() && !fx->getAttributes()->isGroupEditing()) { groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx); continue; } SchematicNode *node = addFxSchematicNode(fx); if (fx->getAttributes()->isGrouped()) editedGroup[fx->getAttributes()->getEditingGroupId()].append(node); } // Add columnFx and zeraryFx nodes for (i = 0; i < xsh->getColumnCount(); i++) { TXshColumn *column = xsh->getColumn(i); TFx *fx = 0; if (TXshLevelColumn *lc = column->getLevelColumn()) fx = lc->getLevelColumnFx(); else if (TXshPaletteColumn *pc = dynamic_cast(column)) fx = pc->getPaletteColumnFx(); else if (TXshZeraryFxColumn *zc = dynamic_cast(column)) fx = zc->getZeraryColumnFx(); if (!fx) continue; if (fx->getAttributes()->isGrouped() && !fx->getAttributes()->isGroupEditing()) { groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx); continue; } if (column->isEmpty() && fx && fx->getOutputConnectionCount() == 0) continue; SchematicNode *node = addFxSchematicNode(fx); if (fx->getAttributes()->isGrouped()) editedGroup[fx->getAttributes()->getEditingGroupId()].append(node); } // Add normalFx for (i = 0; i < fxSet->getFxCount(); i++) { TFx *fx = fxSet->getFx(i); TMacroFx *macro = dynamic_cast(fx); if (fx->getAttributes()->isGrouped() && !fx->getAttributes()->isGroupEditing()) { groupedFxs[fx->getAttributes()->getGroupId()].push_back(fx); continue; } else if (macro && macro->isEditing()) { std::vector fxs = macro->getFxs(); int j; for (j = 0; j < (int)fxs.size(); j++) { SchematicNode *node = addFxSchematicNode(fxs[j].getPointer()); editedMacro[macro].append(node); if (fxs[j]->getAttributes()->isGrouped() && macro->getAttributes()->isGroupEditing()) editedGroup[fx->getAttributes()->getEditingGroupId()].append(node); } continue; } SchematicNode *node = addFxSchematicNode(fx); if (fx->getAttributes()->isGrouped()) editedGroup[fx->getAttributes()->getEditingGroupId()].append(node); // If adding an unedited macro and nodes are not yet set, let's position the // internal nodes now if (macro) { double minY = macro->getAttributes()->getDagNodePos().y; double maxX = macro->getAttributes()->getDagNodePos().x; double y = minY; double x = maxX; std::vector fxs = macro->getFxs(); for (int j = 0; j < (int)fxs.size(); j++) { TFx *macroFx = fxs[j].getPointer(); if (macroFx && !m_placedFxs.contains(macroFx)) { placeNodeAndParents(macroFx, x, maxX, minY); y -= (m_gridDimension == eLarge ? 100 : 50); minY = std::min(y, minY); } } } } // grouped node QMap>::const_iterator it; for (it = groupedFxs.begin(); it != groupedFxs.end(); it++) { FxSchematicNode *node = addGroupedFxSchematicNode(it.key(), it.value()); TFx *fx = node->getFx(); assert(fx); int editingGroupId = fx->getAttributes()->getEditingGroupId(); if (editingGroupId != -1) editedGroup[editingGroupId].append(node); } keepSubgroup(editedGroup); updateEditedGroups(editedGroup); updateEditedMacros(editedMacro); updateLink(); m_nodesToPlace.clear(); updatingScene = false; } //------------------------------------------------------------------ void FxSchematicScene::updateEditedGroups( const QMap> &editedGroup) { QMap>::const_iterator it; for (it = editedGroup.begin(); it != editedGroup.end(); it++) { int zValue = 2; QMap>::const_iterator it2 = editedGroup.begin(); while (it2 != editedGroup.end()) { FxSchematicNode *placedFxNode = dynamic_cast(it2.value()[0]); FxSchematicNode *fxNode = dynamic_cast(it.value()[0]); if (!placedFxNode || !fxNode) { it2++; continue; } int placedGroupedId = placedFxNode->getFx()->getAttributes()->getEditingGroupId(); if (fxNode->getFx()->getAttributes()->isContainedInGroup( placedGroupedId) && fxNode->getFx()->getAttributes()->getEditingGroupId() != it2.key()) zValue += 2; it2++; } FxSchematicGroupEditor *node = addEditedGroupedFxSchematicNode(it.key(), it.value()); node->setZValue(zValue); node->setGroupedNodeZValue(zValue + 1); } } //------------------------------------------------------------------ void FxSchematicScene::updateEditedMacros( const QMap> &editedMacro) { QMap>::const_iterator it; for (it = editedMacro.begin(); it != editedMacro.end(); it++) { TMacroFx *macro = it.key(); int zValue = 2; if (macro->getAttributes()->isGrouped()) { FxSchematicGroupEditor *containingGroup = m_groupEditorTable[macro->getAttributes()->getEditingGroupId()]; assert(containingGroup); zValue = containingGroup->zValue() + 2; } FxSchematicMacroEditor *node = addEditedMacroFxSchematicNode(it.key(), it.value()); node->setZValue(zValue); node->setGroupedNodeZValue(zValue + 1); } } //------------------------------------------------------------------ FxSchematicNode *FxSchematicScene::addFxSchematicNode(TFx *fx) { FxSchematicNode *node = createFxSchematicNode(fx); if (!node) return 0; connect(node, SIGNAL(sceneChanged()), this, SLOT(onSceneChanged())); connect(node, SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())); connect(node, SIGNAL(switchCurrentFx(TFx *)), this, SLOT(onSwitchCurrentFx(TFx *))); connect(node, SIGNAL(currentColumnChanged(int)), this, SLOT(onCurrentColumnChanged(int))); connect(node, SIGNAL(fxNodeDoubleClicked()), this, SLOT(onFxNodeDoubleClicked())); connect(node, SIGNAL(nodeChangedSize()), this, SLOT(onNodeChangedSize())); if (fx->getAttributes()->getDagNodePos() == TConst::nowhere) { node->resize(m_gridDimension == 0); placeNode(node); } else updatePosition(node, fx->getAttributes()->getDagNodePos()); m_table[fx] = node; return node; } //------------------------------------------------------------------ FxSchematicNode *FxSchematicScene::addGroupedFxSchematicNode( int groupId, const QList &groupedFxs) { TFxSet *terminals = getXsheet()->getFxDag()->getTerminalFxs(); QList roots = getRoots(groupedFxs, terminals); if (roots.isEmpty()) return 0; std::wstring name = roots[0]->getAttributes()->getGroupName(false); FxGroupNode *node = new FxGroupNode(this, groupedFxs, roots, groupId, name); if (!node) return 0; connect(node, SIGNAL(sceneChanged()), this, SLOT(onSceneChanged())); connect(node, SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())); connect(node, SIGNAL(switchCurrentFx(TFx *)), this, SLOT(onSwitchCurrentFx(TFx *))); connect(node, SIGNAL(currentColumnChanged(int)), this, SLOT(onCurrentColumnChanged(int))); connect(node, SIGNAL(fxNodeDoubleClicked()), this, SLOT(onFxNodeDoubleClicked())); m_groupedTable[groupId] = node; return node; } //------------------------------------------------------------------ FxSchematicGroupEditor *FxSchematicScene::addEditedGroupedFxSchematicNode( int groupId, const QList &groupedFxs) { FxSchematicGroupEditor *editorGroup = new FxSchematicGroupEditor(groupId, groupedFxs, this); m_groupEditorTable[groupId] = editorGroup; return editorGroup; } //------------------------------------------------------------------ FxSchematicMacroEditor *FxSchematicScene::addEditedMacroFxSchematicNode( TMacroFx *macro, const QList &groupedFxs) { FxSchematicMacroEditor *editorMacro = new FxSchematicMacroEditor(macro, groupedFxs, this); m_macroEditorTable[macro] = editorMacro; return editorMacro; } //------------------------------------------------------------------ void FxSchematicScene::updatePosition(FxSchematicNode *node, const TPointD &pos) { node->setPos(QPointF(pos.x, pos.y)); node->getFx()->getAttributes()->setDagNodePos(pos); QVector placedNodes = getPlacedNode(node); int step = m_gridDimension == eLarge ? 100 : 50; TPointD offset(0, -step); int i; for (i = 0; i < placedNodes.size(); i++) { FxSchematicNode *placedNode = dynamic_cast(placedNodes[i]); assert(placedNode); TPointD newPos = placedNode->getFx()->getAttributes()->getDagNodePos() + offset; updatePosition(placedNode, newPos); } } //------------------------------------------------------------------ /*! create node depends on the fx type */ FxSchematicNode *FxSchematicScene::createFxSchematicNode(TFx *fx) { if (TLevelColumnFx *lcFx = dynamic_cast(fx)) return new FxSchematicColumnNode(this, lcFx); else if (TPaletteColumnFx *pfx = dynamic_cast(fx)) return new FxSchematicPaletteNode(this, pfx); else if (TZeraryColumnFx *zfx = dynamic_cast(fx)) return new FxSchematicZeraryNode(this, zfx); else if (TXsheetFx *xfx = dynamic_cast(fx)) return new FxSchematicXSheetNode(this, xfx); else if (TOutputFx *ofx = dynamic_cast(fx)) return new FxSchematicOutputNode(this, ofx); else return new FxSchematicNormalFxNode(this, fx); } //------------------------------------------------------------------ /*! place nodes of which positions are not specified manually */ void FxSchematicScene::placeNode(FxSchematicNode *node) { if (!node) return; int step = m_gridDimension == eLarge ? 100 : 50; FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); QRectF nodeRect = node->boundingRect(); if (node->isA(eOutpuFx)) { // I'm placing an output node TFx *xsheetFx = fxDag->getXsheetFx(); TFxPort *outPort = xsheetFx->getOutputConnection(0); TFx *connectedOutput = outPort ? outPort->getOwnerFx() : 0; if (connectedOutput && connectedOutput == node->getFx()) { // The output node is connected to the xsheet node TPointD pos = xsheetFx->getAttributes()->getDagNodePos(); if (pos != TConst::nowhere) nodeRect.translate(pos.x + 120, pos.y); else nodeRect.translate(sceneRect().center()); while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, step); } else { // The output node is not connected to the xsheet node TFx *fx = node->getFx(); TFxPort *port = fx->getInputPort(0); TFx *inputFx = port->getFx(); if (inputFx) { // The output node is connected to another node TPointD pos = inputFx->getAttributes()->getDagNodePos(); if (pos != TConst::nowhere) nodeRect.translate(pos.x + 120, pos.y); else { m_nodesToPlace[inputFx].append(node); return; } } else { // The output node is not connected QPointF pos = sceneRect().center(); nodeRect.translate(pos); } } while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, step); QPointF newPos = nodeRect.topLeft(); node->getFx()->getAttributes()->setDagNodePos( TPointD(newPos.x(), newPos.y())); node->setPos(newPos); return; } else if (node->isA(eXSheetFx)) { // I'm placing the xsheet node TFxSet *terminalFxs = fxDag->getTerminalFxs(); int i; double maxX = m_firstPoint.x(); for (i = 0; i < terminalFxs->getFxCount(); i++) { TFx *terminalFx = terminalFxs->getFx(i); if (terminalFx->getAttributes()->getDagNodePos() == TConst::nowhere) continue; maxX = std::max(maxX, terminalFx->getAttributes()->getDagNodePos().x); } TPointD oldPos = node->getFx()->getAttributes()->getDagNodePos(); QPointF pos; if (oldPos == TConst::nowhere) pos = QPointF(maxX + 120, m_firstPoint.y()); else pos = QPointF(maxX + 120 > oldPos.x ? maxX + 120 : oldPos.x, oldPos.y); node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y())); node->setPos(pos); return; } else if (node->isA(eMacroFx)) { double minX = TConst::nowhere.x, minY = TConst::nowhere.y, maxY; QPointF pos; TMacroFx *macroFx = dynamic_cast(node->getFx()); std::vector fxs = macroFx->getFxs(); int k; for (k = 0; k < (int)fxs.size(); k++) { TFx *fx = fxs[k].getPointer(); if (fx->getAttributes()->getDagNodePos() == TConst::nowhere) continue; if (QPointF(minX, minY) == QPointF(TConst::nowhere.x, TConst::nowhere.y)) { minX = fx->getAttributes()->getDagNodePos().x; minY = maxY = fx->getAttributes()->getDagNodePos().y; continue; } minX = std::min(fx->getAttributes()->getDagNodePos().x, minX); minY = std::min(fx->getAttributes()->getDagNodePos().y, minY); maxY = std::max(fx->getAttributes()->getDagNodePos().y, maxY); } if (QPointF(minX, minY) == QPointF(TConst::nowhere.x, TConst::nowhere.y)) { TFx *inputFx = node->getFx()->getInputPort(0)->getFx(); if (inputFx && inputFx->getAttributes()->getDagNodePos() != TConst::nowhere) { TPointD dagPos = inputFx->getAttributes()->getDagNodePos() + TPointD(150, 0); pos = QPointF(dagPos.x, dagPos.y); } else pos = sceneRect().center(); nodeRect.moveTopLeft(pos); while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step); pos = nodeRect.topLeft(); } else { pos.setX(minX); pos.setY((maxY + minY) / 2); } node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y())); node->setPos(QPointF(pos)); if (m_nodesToPlace.contains(node->getFx())) { QList nodes = m_nodesToPlace[node->getFx()]; int i; for (i = 0; i < nodes.size(); i++) placeNode(nodes[i]); } return; } else if (node->isA(eNormalFx) || node->isA(eNormalLayerBlendingFx) || node->isA(eNormalMatteFx) || node->isA(eNormalImageAdjustFx)) { // I'm placing an effect or a macro TFx *inputFx = node->getFx()->getInputPort(0)->getFx(); QPointF pos; if (inputFx) { if (inputFx->getAttributes()->getDagNodePos() != TConst::nowhere) { TPointD dagPos = inputFx->getAttributes()->getDagNodePos() + TPointD(150, 0); pos = QPointF(dagPos.x, dagPos.y); nodeRect.moveTopLeft(pos); while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step); pos = nodeRect.topLeft(); } else { m_nodesToPlace[inputFx].append(node); return; } } else { pos = sceneRect().center(); nodeRect.moveTopLeft(pos); while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step); pos = nodeRect.topLeft(); } node->getFx()->getAttributes()->setDagNodePos(TPointD(pos.x(), pos.y())); node->setPos(QPointF(pos)); if (m_nodesToPlace.contains(node->getFx())) { QList nodes = m_nodesToPlace[node->getFx()]; int i; for (i = 0; i < nodes.size(); i++) placeNode(nodes[i]); } return; } else if (node->isA(eZeraryFx) || node->isA(eColumnFx) || node->isA(eGroupedFx)) { // I'm placing a column nodeRect.translate(m_firstPoint); nodeRect.translate(10, 10); while (!isAnEmptyZone(nodeRect)) nodeRect.translate(0, -step); QPointF newPos = nodeRect.topLeft(); node->getFx()->getAttributes()->setDagNodePos( TPointD(newPos.x(), newPos.y())); node->setPos(QPointF(newPos)); return; } } //------------------------------------------------------------------ void FxSchematicScene::updateLink() { TXsheet *xsh = m_xshHandle->getXsheet(); // Iterate the fxs table QMap::iterator it; for (it = m_table.begin(); it != m_table.end(); ++it) { FxSchematicNode *node = it.value(); if (!node) continue; // Should be asserted? Is it legal? TFx *fx = it.key(); TFx *inputPortsFx = fx; if (TZeraryColumnFx *fx2 = dynamic_cast(fx)) { inputPortsFx = fx2->getZeraryFx(); if (!inputPortsFx) return; // Should really never happen. Should be asserted... } for (int i = 0; i != inputPortsFx->getInputPortCount(); ++i) { TFxPort *port = inputPortsFx->getInputPort(i); if (TFx *linkedFx = port->getFx()) { if (!linkedFx->getAttributes()->isGrouped() || linkedFx->getAttributes()->isGroupEditing()) { // Not in a group / open group case assert(m_table.contains(linkedFx)); if (m_table.contains(linkedFx)) { FxSchematicNode *linkedNode = m_table[linkedFx]; SchematicPort *p0 = linkedNode->getOutputPort(); SchematicPort *p1 = node->getInputPort(i); if (p0 && p1) p0->makeLink(p1); } } else { assert( m_groupedTable.contains(linkedFx->getAttributes()->getGroupId())); if (m_groupedTable.contains( linkedFx->getAttributes()->getGroupId())) { FxSchematicNode *linkedNode = m_groupedTable[linkedFx->getAttributes()->getGroupId()]; SchematicPort *p0 = linkedNode->getOutputPort(); SchematicPort *p1 = node->getInputPort(i); if (p0 && p1) p0->makeLink(p1); } } } } if (xsh->getFxDag()->getTerminalFxs()->containsFx(fx)) { SchematicPort *p0 = node->getOutputPort(); SchematicPort *p1 = m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0); p0->makeLink(p1); } } QMap::iterator it2; for (it2 = m_groupedTable.begin(); it2 != m_groupedTable.end(); it2++) { FxGroupNode *node = it2.value(); if (!node) continue; int i, fxCount = node->getFxCount(); bool xsheetConnected = false; for (i = 0; i < fxCount; i++) { TFx *fx = node->getFx(i); if (xsh->getFxDag()->getTerminalFxs()->containsFx(fx) && !xsheetConnected) { SchematicPort *p0 = node->getOutputPort(); SchematicPort *p1 = m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0); p0->makeLink(p1); xsheetConnected = true; } TZeraryColumnFx *zfx = dynamic_cast(fx); if (zfx) fx = zfx->getZeraryFx(); if (fx) { int j; for (j = 0; j < fx->getInputPortCount(); j++) { TFx *linkedFx = fx->getInputPort(j)->getFx(); if (!linkedFx) continue; if (!linkedFx->getAttributes()->isGrouped() || linkedFx->getAttributes()->isGroupEditing()) { assert(m_table.contains(linkedFx)); if (m_table.contains(linkedFx)) { FxSchematicNode *linkedNode = m_table[linkedFx]; SchematicPort *p0 = linkedNode->getOutputPort(); SchematicPort *p1 = node->getInputPort(0); if (p0 && p1) p0->makeLink(p1); } } else { int linkedGroupId = linkedFx->getAttributes()->getGroupId(); assert(m_groupedTable.contains(linkedGroupId)); if (m_groupedTable.contains(linkedGroupId)) { FxGroupNode *linkedNode = m_groupedTable[linkedGroupId]; if (linkedNode == node) continue; SchematicPort *p0 = linkedNode->getOutputPort(); SchematicPort *p1 = node->getInputPort(0); if (p0 && p1 && !p0->isLinkedTo(p1)) p0->makeLink(p1); } } } } } } // to solve an edit macro problem: create a dummy link QMap::iterator it3; for (it3 = m_macroEditorTable.begin(); it3 != m_macroEditorTable.end(); it3++) { TMacroFx *macro = it3.key(); int i; FxSchematicNode *root = m_table[macro->getRoot()]; SchematicPort *p0 = root->getOutputPort(); for (i = 0; i < macro->getOutputConnectionCount(); i++) { TFxPort *outConnection = macro->getOutputConnection(i); TFx *outFx = outConnection->getOwnerFx(); TMacroFx *outMacroFx = dynamic_cast(outFx); if (outMacroFx && outMacroFx->isEditing()) { std::vector fxs = outMacroFx->getFxs(); int k; for (k = 0; k < (int)fxs.size(); k++) { TFx *fx = fxs[k].getPointer(); int j; for (j = 0; j < fx->getInputPortCount(); j++) if (outConnection == fx->getInputPort(j)) { outFx = fx; break; } if (outFx != outMacroFx) break; } } int j; for (j = 0; j < outFx->getInputPortCount(); j++) if (outFx->getInputPort(j)->getFx() == macro) { SchematicPort *p1 = m_table[outFx]->getInputPort(j); p0->makeLink(p1); break; } } if (xsh->getFxDag()->getTerminalFxs()->containsFx(macro)) { assert(root); if (!root) continue; SchematicPort *p1 = m_table[xsh->getFxDag()->getXsheetFx()]->getInputPort(0); p0->makeLink(p1); } } updateDuplcatedNodesLink(); } //------------------------------------------------------------------ void FxSchematicScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *cme) { QPointF scenePos = cme->scenePos(); QList itemList = items(scenePos); if (!itemList.isEmpty()) { SchematicScene::contextMenuEvent(cme); return; } QMenu menu(views()[0]); if (cme->modifiers() & Qt::ControlModifier) { menu.addAction(m_addFxContextMenu.getAgainCommand(AddFxContextMenu::Add)); if (!menu.actions().isEmpty()) { menu.exec(cme->screenPos()); return; } } QAction *addOutputFx = CommandManager::instance()->getAction("MI_NewOutputFx"); QAction *copy = CommandManager::instance()->getAction("MI_Copy"); QAction *cut = CommandManager::instance()->getAction("MI_Cut"); QAction *paste = CommandManager::instance()->getAction("MI_Paste"); m_addFxContextMenu.setCurrentCursorScenePos(cme->scenePos()); menu.addMenu(m_addFxContextMenu.getAddMenu()); if (addOutputFx) menu.addAction(addOutputFx); // Close sub xsheet and move to parent sheet ToonzScene *scene = getXsheet()->getScene(); ChildStack *childStack = scene->getChildStack(); if (childStack && childStack->getAncestorCount() > 0) { menu.addSeparator(); menu.addAction(CommandManager::instance()->getAction("MI_CloseChild")); } menu.addSeparator(); menu.addAction(copy); menu.addAction(cut); menu.addAction(paste); m_selection->setPastePosition(TPointD(scenePos.x(), scenePos.y())); menu.exec(cme->screenPos()); m_selection->setPastePosition(TConst::nowhere); } //------------------------------------------------------------------ QPointF FxSchematicScene::nearestPoint(const QPointF &point) { QRectF rect(0, 0, 0.1, 0.1); rect.moveCenter(point); QList itemList = items(rect); while (itemList.isEmpty()) { rect.adjust(-0.1, -0.1, 0.1, 0.1); itemList = items(rect); } #if QT_VERSION >= 0x050000 /* FIXME: QTransform() のデフォルトは Qt4.8 の itemAt() と比べて equivant だろうか? */ QGraphicsItem *item = itemAt(rect.bottomLeft(), QTransform()); if (item) return rect.bottomLeft(); item = itemAt(rect.bottomRight(), QTransform()); if (item) return rect.bottomRight(); item = itemAt(rect.topLeft(), QTransform()); if (item) return rect.topLeft(); item = itemAt(rect.topRight(), QTransform()); #else QGraphicsItem *item = itemAt(rect.bottomLeft()); if (item) return rect.bottomLeft(); item = itemAt(rect.bottomRight()); if (item) return rect.bottomRight(); item = itemAt(rect.topLeft()); if (item) return rect.topLeft(); item = itemAt(rect.topRight()); #endif if (item) return rect.topRight(); return QPointF(); } //------------------------------------------------------------------ FxSchematicNode *FxSchematicScene::getFxNodeFromPosition(const QPointF &pos) { QList pickedItems = items(pos); for (int i = 0; i < pickedItems.size(); i++) { FxSchematicNode *fxNode = dynamic_cast(pickedItems.at(i)); if (fxNode) return fxNode; FxSchematicPort *fxPort = dynamic_cast(pickedItems.at(i)); if (fxPort) return fxPort->getDock()->getNode(); } return 0; } //------------------------------------------------------------------ void FxSchematicScene::updateDuplcatedNodesLink() { QMap::iterator it; // fx2node contains only duplicated nodes // and zerary duplicated node s QMap fx2node; for (it = m_table.begin(); it != m_table.end(); ++it) { TFx *fx = it.key(); FxSchematicNode *node = it.value(); if (TZeraryColumnFx *zcfx = dynamic_cast(fx)) { fx = zcfx->getZeraryFx(); if (!fx) return; } assert(fx2node.count(fx) == 0); if (fx->getLinkedFx() == fx) continue; fx2node[fx] = node; } // trovo i link std::set visited; for (it = fx2node.begin(); it != fx2node.end(); ++it) { TFx *fx = it.key(); FxSchematicNode *node = it.value(); assert(fx->getLinkedFx() != fx); if (visited.count(fx) > 0) continue; visited.insert(fx); FxSchematicNode *lastNode = node; assert(lastNode); FxSchematicPort *lastPort = lastNode->getLinkPort(); assert(lastPort); for (fx = fx->getLinkedFx(); fx != it.key(); fx = fx->getLinkedFx()) { assert(visited.count(fx) == 0); if (visited.count(fx) > 0) break; visited.insert(fx); QMap::iterator h; h = fx2node.find(fx); if (h == fx2node.end()) continue; assert(h != fx2node.end()); FxSchematicNode *node = h.value(); assert(node); FxSchematicPort *port = node->getLinkPort(); assert(port); if (port && lastPort) port->makeLink(lastPort); lastNode = node; lastPort = port; } } } //------------------------------------------------------------------ QGraphicsItem *FxSchematicScene::getCurrentNode() { QList allItems = items(); for (auto const item : allItems) { FxSchematicNode *node = dynamic_cast(item); if (node && node->getFx() == m_fxHandle->getFx()) return node; } return 0; } //------------------------------------------------------------------ void FxSchematicScene::onSelectionSwitched(TSelection *oldSel, TSelection *newSel) { if (m_selection == oldSel && m_selection != newSel) clearSelection(); } //------------------------------------------------------------------ void FxSchematicScene::onSelectionChanged() { m_selection->selectNone(); int i, size = m_highlightedLinks.size(); for (i = 0; i < size; i++) { SchematicLink *link = m_highlightedLinks[i]; link->setHighlighted(false); link->update(); } m_highlightedLinks.clear(); QList slcItems = selectedItems(); QList::iterator it; for (it = slcItems.begin(); it != slcItems.end(); it++) { FxSchematicNode *node = dynamic_cast(*it); if (node) { if (!node->isA(eGroupedFx)) { if (node->isA(eXSheetFx)) continue; m_selection->select(node->getFx()); if (node->isA(eColumnFx)) { FxSchematicColumnNode *columnNode = dynamic_cast(node); if (columnNode) m_selection->select(columnNode->getColumnIndex()); else { FxSchematicPaletteNode *paletteNode = dynamic_cast(node); if (paletteNode) m_selection->select(paletteNode->getColumnIndex()); } } } else { FxGroupNode *groupNode = dynamic_cast(node); assert(groupNode); QList fxs = groupNode->getGroupedFxs(); for (i = 0; i < fxs.size(); i++) { m_selection->select(fxs[i].getPointer()); TLevelColumnFx *colFx = dynamic_cast(fxs[i].getPointer()); if (colFx) { if (TXshLevelColumn *column = colFx->getColumn()) { int colIndex = column->getIndex(); m_selection->select(colIndex); } } } } highlightLinks(node, true); } SchematicLink *link = dynamic_cast(*it); if (link) m_selection->select(link); } m_selection->makeCurrent(); TSelectionHandle *selHandle = TSelectionHandle::getCurrent(); selHandle->notifySelectionChanged(); } //------------------------------------------------------------------ void FxSchematicScene::reorderScene() { int step = m_gridDimension == eLarge ? 100 : 50; m_placedFxs.clear(); QPointF sceneCenter = sceneRect().center(); double minY = sceneCenter.y(); double maxX = sceneCenter.x(); double y = minY; double x = maxX; TXsheet *xsh = m_xshHandle->getXsheet(); int i = 0; FxDag *fxDag = xsh->getFxDag(); TFxSet *fxSet = fxDag->getInternalFxs(); // Let's reset every position to nowhere first fxDag->getXsheetFx()->getAttributes()->setDagNodePos(TConst::nowhere); for (i = 0; i < fxDag->getOutputFxCount(); i++) { TOutputFx *fx = fxDag->getOutputFx(i); if (!fx) continue; fx->getAttributes()->setDagNodePos(TConst::nowhere); } for (i = 0; i < xsh->getColumnCount(); i++) { TXshColumn *column = xsh->getColumn(i); TFx *fx = column->getFx(); if (!fx) continue; fx->getAttributes()->setDagNodePos(TConst::nowhere); } for (i = 0; i < fxSet->getFxCount(); i++) { TFx *fx = fxSet->getFx(i); fx->getAttributes()->setDagNodePos(TConst::nowhere); TMacroFx *macro = dynamic_cast(fx); if (macro && macro->isEditing()) { std::vector fxs = macro->getFxs(); int j; for (j = 0; j < (int)fxs.size(); j++) { fxs[j]->getAttributes()->setDagNodePos(TConst::nowhere); } } } // Let's start placing them now for (i = 0; i < xsh->getColumnCount(); i++) { TXshColumn *column = xsh->getColumn(i); TFx *fx = column->getFx(); if (column->isEmpty() || !fx) continue; TZeraryColumnFx *zfx = dynamic_cast(fx); if (zfx && (zfx->getZeraryFx()->getInputPortCount() > 0)) { TFxPort *port = zfx->getZeraryFx()->getInputPort(0); if (port && port->getFx()) continue; } if (zfx && m_placedFxs.contains(zfx->getZeraryFx())) continue; x = sceneCenter.x(); placeNodeAndParents(fx, x, maxX, minY); y -= step; minY = std::min(y, minY); } // remove retrolink for (i = 0; i < xsh->getColumnCount(); i++) { TXshColumn *column = xsh->getColumn(i); TFx *fx = column->getFx(); if (column->isEmpty() || !fx) continue; TZeraryColumnFx *zfx = dynamic_cast(fx); if (zfx && m_placedFxs.contains(zfx->getZeraryFx())) continue; if (zfx && (zfx->getZeraryFx()->getInputPortCount() > 0)) { TFxPort *port = zfx->getZeraryFx()->getInputPort(0); if (port && port->getFx()) continue; } for (int j = 0; j < fx->getOutputConnectionCount(); j++) { TFx *outFx = fx->getOutputConnection(j)->getOwnerFx(); removeRetroLinks(outFx, maxX); } } double middleY = (sceneCenter.y() + minY + step) * 0.5; placeNodeAndParents(xsh->getFxDag()->getXsheetFx(), maxX, maxX, middleY); y -= step; minY = std::min(y, minY); for (i = 0; i < fxSet->getFxCount(); i++) { TFx *fx = fxSet->getFx(i); if (m_placedFxs.contains(fx)) continue; placeNodeAndParents(fx, (sceneCenter.x() + 120), maxX, minY); y -= step; minY = std::min(y, minY); } updateScene(); } //------------------------------------------------------------------ void FxSchematicScene::removeRetroLinks(TFx *fx, double &maxX) { if (!fx) return; for (int i = 0; i < fx->getInputPortCount(); i++) { TFx *inFx = fx->getInputPort(i)->getFx(); if (!inFx) continue; TPointD inFxPos = inFx->getAttributes()->getDagNodePos(); TPointD fxPos = fx->getAttributes()->getDagNodePos(); if (inFxPos != TConst::nowhere && fxPos != TConst::nowhere && fxPos.x <= inFxPos.x) { while (fxPos.x <= inFxPos.x) fxPos.x += 150; maxX = std::max(fxPos.x + 150, maxX); fx->getAttributes()->setDagNodePos(fxPos); for (int j = 0; j < fx->getOutputConnectionCount(); j++) { TFx *outFx = fx->getOutputConnection(j)->getOwnerFx(); removeRetroLinks(outFx, maxX); } } } } //------------------------------------------------------------------ void FxSchematicScene::placeNodeAndParents(TFx *fx, double x, double &maxX, double &minY) { int step = m_gridDimension == eLarge ? 100 : 50; if (!fx) return; m_placedFxs.append(fx); if (fx->getFxType() == "STD_particlesFx" || fx->getFxType() == "STD_Iwa_ParticlesFx") { TXsheet *xsh = m_xshHandle->getXsheet(); int i = 0; for (i = 0; i < xsh->getColumnCount(); i++) { TFx *columnFx = xsh->getColumn(i)->getFx(); TZeraryColumnFx *zfx = dynamic_cast(columnFx); if (zfx && zfx->getZeraryFx() == fx) { fx = zfx; break; } } } double y = minY; TMacroFx *macro = dynamic_cast(fx); if (macro) { int tmpY = y; std::vector fxs = macro->getFxs(); for (int j = 0; j < (int)fxs.size(); j++) { TFx *macroFx = fxs[j].getPointer(); if (macroFx && !m_placedFxs.contains(macroFx)) { placeNodeAndParents(macroFx, x, maxX, minY); y -= step; minY = std::min(y, minY); } } tmpY = (minY + tmpY + step) * 0.5; fx->getAttributes()->setDagNodePos(TPointD(x, tmpY)); } else fx->getAttributes()->setDagNodePos(TPointD(x, y)); if (fx->getOutputConnectionCount() == 0) minY -= step; x += 120; maxX = std::max(maxX, x); int i; for (i = 0; i < fx->getOutputConnectionCount(); i++) { TFx *outputFx = fx->getOutputConnection(i)->getOwnerFx(); // controllo se e' una porta sorgente TFxPort *port = outputFx->getInputPort(0); if (port && port->getFx() != fx) continue; if (!m_placedFxs.contains(outputFx) || outputFx->getAttributes()->getDagNodePos().x < x) { placeNodeAndParents(outputFx, x, maxX, minY); y -= step; minY = std::min(y, minY); } } } //------------------------------------------------------------------ void FxSchematicScene::onDisconnectFromXSheet() { std::list> list = m_selection->getFxs().toStdList(); TFxCommand::disconnectNodesFromXsheet(list, m_xshHandle); } //------------------------------------------------------------------ void FxSchematicScene::onConnectToXSheet() { std::list> list = m_selection->getFxs().toStdList(); TFxCommand::connectNodesToXsheet(list, m_xshHandle); } //------------------------------------------------------------------ void FxSchematicScene::onDeleteFx() { std::list> fxList = m_selection->getFxs().toStdList(); std::list linkList = m_selection->getLinks().toStdList(); std::list columnIndexList = m_selection->getColumnIndexes().toStdList(); TFxCommand::deleteSelection(fxList, linkList, columnIndexList, m_xshHandle, m_fxHandle); } //------------------------------------------------------------------ void FxSchematicScene::onDuplicateFx() { QList fxs = m_selection->getFxs(); if (fxs.empty()) return; TUndoManager::manager()->beginBlock(); int i, size = fxs.size(); for (i = 0; i != size; ++i) TFxCommand::duplicateFx(fxs[i].getPointer(), m_xshHandle, m_fxHandle); TUndoManager::manager()->endBlock(); } //------------------------------------------------------------------ void FxSchematicScene::onUnlinkFx() { QList fxs = m_selection->getFxs(); if (fxs.empty()) return; TUndoManager::manager()->beginBlock(); int i, size = fxs.size(); for (i = 0; i != size; ++i) TFxCommand::unlinkFx(fxs[i].getPointer(), m_fxHandle, m_xshHandle); TUndoManager::manager()->endBlock(); } //------------------------------------------------------------------ void FxSchematicScene::onMacroFx() { TFxCommand::makeMacroFx(m_selection->getFxs().toVector().toStdVector(), m_app); } //------------------------------------------------------------------ void FxSchematicScene::onExplodeMacroFx() { if (TMacroFx *macroFx = dynamic_cast(m_fxHandle->getFx())) TFxCommand::explodeMacroFx(macroFx, m_app); } //------------------------------------------------------------------ void FxSchematicScene::onOpenMacroFx() { if (TMacroFx *macroFx = dynamic_cast(m_fxHandle->getFx())) { macroFx->editMacro(true); updateScene(); } } //------------------------------------------------------------------ void FxSchematicScene::onSavePresetFx() { CommandManager::instance()->getAction("MI_SavePreset")->trigger(); } //------------------------------------------------------------------ void FxSchematicScene::onRemoveOutput() { TFxCommand::removeOutputFx(m_fxHandle->getFx(), m_xshHandle, m_fxHandle); } //------------------------------------------------------------------ void FxSchematicScene::onActivateOutput() { TFxCommand::makeOutputFxCurrent(m_fxHandle->getFx(), m_xshHandle); } //------------------------------------------------------------------ void FxSchematicScene::onPreview() { emit showPreview(m_fxHandle->getFx()); } //------------------------------------------------------------------ void FxSchematicScene::onCacheFx() { setEnableCache(true); } //------------------------------------------------------------------ void FxSchematicScene::onUncacheFx() { setEnableCache(false); } //------------------------------------------------------------------ void FxSchematicScene::setEnableCache(bool toggle) { QList selectedFxs = m_selection->getFxs(); for (int i = 0; i < selectedFxs.size(); i++) { TFx *fx = selectedFxs[i].getPointer(); TZeraryColumnFx *zcfx = dynamic_cast(fx); if (zcfx) fx = zcfx->getZeraryFx(); TFxAttributes *attr = fx->getAttributes(); if (!attr->isGrouped() || attr->isGroupEditing()) { if (toggle) { TPassiveCacheManager::instance()->enableCache(fx); } else { TPassiveCacheManager::instance()->disableCache(fx); } } else { QMap::iterator it; for (it = m_groupedTable.begin(); it != m_groupedTable.end(); it++) { FxGroupNode *group = it.value(); QList roots = group->getRootFxs(); for (int j = 0; j < roots.size(); j++) { if (fx == roots[j].getPointer()) { if (toggle) { TPassiveCacheManager::instance()->enableCache(fx); } else { TPassiveCacheManager::instance()->disableCache(fx); } } } group->update(); } } } } //------------------------------------------------------------------ void FxSchematicScene::onCollapse(const QList &fxs) { emit doCollapse(fxs); } //------------------------------------------------------------------ TXsheet *FxSchematicScene::getXsheet() { return m_xshHandle->getXsheet(); } //------------------------------------------------------------------ void FxSchematicScene::onXsheetChanged() { m_xshHandle->notifyXsheetChanged(); } //------------------------------------------------------------------ void FxSchematicScene::onSceneChanged() { m_app->getCurrentScene()->notifySceneChanged(); } //------------------------------------------------------------------ void FxSchematicScene::onSwitchCurrentFx(TFx *fx) { if (m_fxHandle->getFx() == fx) return; if (fx) { // Forbid update of the swatch upon column switch. This could generate // a further useless render... SwatchViewer::suspendRendering(true, false); int columnIndex = fx->getReferenceColumnIndex(); if (columnIndex >= 0) { m_columnHandle->setColumnIndex(columnIndex); m_app->getCurrentObject()->setObjectId( TStageObjectId::ColumnId(columnIndex)); } SwatchViewer::suspendRendering(false); m_fxHandle->setFx(fx, false); // Setting the fx updates the swatch emit editObject(); } else { m_fxHandle->setFx(0, false); } } //------------------------------------------------------------------ void FxSchematicScene::onFxNodeDoubleClicked() { // emitting fxSettingsShouldBeSwitched m_fxHandle->onFxNodeDoubleClicked(); } //------------------------------------------------------------------ void FxSchematicScene::onCurrentFxSwitched() { if (m_currentFxNode) m_currentFxNode->setIsCurrentFxLinked(false, 0); if (m_table.contains(m_fxHandle->getFx())) { m_currentFxNode = m_table[m_fxHandle->getFx()]; m_currentFxNode->setIsCurrentFxLinked(true, 0); } else m_currentFxNode = 0; } //------------------------------------------------------------------ void FxSchematicScene::onCurrentColumnChanged(int index) { m_app->getCurrentColumn()->setColumnIndex(index); m_app->getCurrentObject()->setObjectId(TStageObjectId::ColumnId(index)); } //------------------------------------------------------------------ void FxSchematicScene::onIconifyNodesToggled(bool iconified) { m_isNormalIconView = !iconified; IconifyFxSchematicNodes = (iconified) ? 1 : 0; updateScene(); } //------------------------------------------------------------------ TFx *FxSchematicScene::getCurrentFx() { return m_fxHandle->getFx(); } //------------------------------------------------------------------ void FxSchematicScene::mousePressEvent(QGraphicsSceneMouseEvent *me) { QList items = selectedItems(); #if QT_VERSION >= 0x050000 QGraphicsItem *item = itemAt(me->scenePos(), QTransform()); #else QGraphicsItem *item = itemAt(me->scenePos()); #endif FxSchematicPort *port = dynamic_cast(item); FxSchematicLink *link = dynamic_cast(item); SchematicScene::mousePressEvent(me); onSelectionChanged(); if (me->button() == Qt::MidButton) { int i; for (i = 0; i < items.size(); i++) items[i]->setSelected(true); } /* m_selection may not be updated here, so I use QGraphicsScene::selectedItems() instead of m_selection->isEmpty() to check whether any node is selected or not. */ if (selectedItems().isEmpty()) { if (me->button() != Qt::MidButton && !item) m_fxHandle->setFx(0, false); return; } m_isConnected = false; if (!canDisconnectSelection(m_selection)) return; m_selectionOldPos.clear(); QList selectedFxs = m_selection->getFxs(); int i; for (i = 0; i < selectedFxs.size(); i++) { TFxP selectedFx = selectedFxs[i]; TPointD pos = selectedFx->getAttributes()->getDagNodePos(); m_selectionOldPos.append(QPair(selectedFx, pos)); } FxsData fxsData; fxsData.setFxs(m_selection->getFxs(), m_selection->getLinks(), m_selection->getColumnIndexes(), m_xshHandle->getXsheet()); // m_isConnected indicates that the all selected nodes are connected if (fxsData.isConnected() && me->button() == Qt::LeftButton && !port && !link) m_isConnected = true; } //------------------------------------------------------------------ void FxSchematicScene::mouseMoveEvent(QGraphicsSceneMouseEvent *me) { SchematicScene::mouseMoveEvent(me); m_lastPos = me->scenePos(); bool leftButton = (QApplication::mouseButtons() == Qt::LeftButton); bool altButton = (QApplication::keyboardModifiers() == Qt::AltModifier); if (leftButton && m_isConnected && altButton) { m_linkUnlinkSimulation = true; simulateDisconnectSelection(true); m_connectionLinks.showBridgeLinks(); #if QT_VERSION >= 0x050000 SchematicLink *link = dynamic_cast(itemAt(m_lastPos, QTransform())); #else SchematicLink *link = dynamic_cast(itemAt(m_lastPos)); #endif if (link && (link->getEndPort() && link->getStartPort())) { TFxCommand::Link fxLink = m_selection->getBoundingFxs(link); if (fxLink == TFxCommand::Link()) return; TFx *inputFx = fxLink.m_inputFx.getPointer(); TFx *outputFx = fxLink.m_outputFx.getPointer(); TFxSet *internalFxs = getXsheet()->getFxDag()->getInternalFxs(); if (!internalFxs->containsFx(inputFx) && !dynamic_cast(inputFx) && !dynamic_cast(inputFx) && !dynamic_cast(inputFx)) return; if (!internalFxs->containsFx(outputFx) && !dynamic_cast(outputFx) && !dynamic_cast(outputFx) && !dynamic_cast(outputFx)) return; } m_connectionLinks.hideBridgeLinks(); simulateInsertSelection(link, altButton && !!link); } } //------------------------------------------------------------------ void FxSchematicScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *me) { SchematicScene::mouseReleaseEvent(me); m_linkUnlinkSimulation = false; if ((m_disconnectionLinks.size() == 0) && (m_connectionLinks.size() == 0)) return; TUndoManager::manager()->beginBlock(); bool altButton = QApplication::keyboardModifiers() == Qt::AltModifier; if (altButton && m_isConnected) { if (m_connectionLinks.size() > 0) { const QList &bridgeLinks = m_connectionLinks.getBridgeLinks(); assert(bridgeLinks.size() <= 1); SchematicLink *link = bridgeLinks[0]; if (link) { FxSchematicNode *outputNode = dynamic_cast(link->getEndPort()->getNode()); FxSchematicNode *inputNode = dynamic_cast(link->getStartPort()->getNode()); if (inputNode && outputNode) { SchematicPort *port = link->getStartPort(); if (port->getType() == 200 || port->getType() == 204) port = link->getOtherPort(port); int i; for (i = 0; i < outputNode->getInputPortCount(); i++) if (port == outputNode->getInputPort(i)) break; TFxCommand::Link fxLink; fxLink.m_outputFx = outputNode->getFx(); fxLink.m_inputFx = inputNode->getFx(); if (!outputNode->isA(eXSheetFx)) fxLink.m_index = i; TFxCommand::connectFxs(fxLink, m_selection->getFxs().toStdList(), m_xshHandle, m_selectionOldPos); } } } else if (m_disconnectionLinks.size() > 0) { QList fxs = m_selection->getFxs(); TFxCommand::disconnectFxs(fxs.toStdList(), m_xshHandle, m_selectionOldPos); m_selectionOldPos.clear(); } } TUndoManager::manager()->endBlock(); m_isConnected = false; } //------------------------------------------------------------------ bool FxSchematicScene::event(QEvent *e) { bool ret = SchematicScene::event(e); bool altPressed = QApplication::keyboardModifiers() == Qt::AltModifier; if (m_altPressed != altPressed) { // When Alt key is pressed, put the link lines on top of other items // in order to enable to pick them up with itemAt() function. double z = (altPressed) ? 5.0 : 0.0; QList sceneItems = items(); for (int i = 0; i < sceneItems.size(); i++) { SchematicLink *link = dynamic_cast(sceneItems.at(i)); if (link) link->setZValue(z); } if (m_linkUnlinkSimulation) onAltModifierChanged(altPressed); m_altPressed = altPressed; } return ret; } //------------------------------------------------------------------ void FxSchematicScene::onInsertPaste() { if (!m_selection->insertPasteSelection()) DVGui::error( tr("Cannot Paste Insert a selection of unconnected FX nodes.\nSelect " "FX nodes and related links before copying or cutting the selection " "you want to paste.")); } //------------------------------------------------------------------ void FxSchematicScene::onAddPaste() { if (!m_selection->addPasteSelection()) DVGui::error( tr("Cannot Paste Add a selection of unconnected FX nodes.\nSelect FX " "nodes and related links before copying or cutting the selection " "you want to paste.")); } //------------------------------------------------------------------ void FxSchematicScene::onReplacePaste() { if (!m_selection->replacePasteSelection()) DVGui::error( tr("Cannot Paste Replace a selection of unconnected FX nodes.\nSelect " "FX nodes and related links before copying or cutting the selection " "you want to paste.")); } //------------------------------------------------------------------ void FxSchematicScene::onAltModifierChanged(bool altPressed) { if (altPressed) { if (m_disconnectionLinks.size() == 0 && m_linkUnlinkSimulation) simulateDisconnectSelection(altPressed); if (m_connectionLinks.size() == 0 && m_linkUnlinkSimulation) { #if QT_VERSION >= 0x050000 SchematicLink *link = dynamic_cast(itemAt(m_lastPos, QTransform())); #else SchematicLink *link = dynamic_cast(itemAt(m_lastPos)); #endif if (link && (!link->getEndPort() || !link->getStartPort())) return; simulateInsertSelection(link, altPressed && !!link); } } else { if (m_disconnectionLinks.size() > 0 && m_linkUnlinkSimulation) simulateDisconnectSelection(altPressed); if (m_connectionLinks.size() > 0 && m_linkUnlinkSimulation) { m_connectionLinks.showBridgeLinks(); simulateInsertSelection(0, false); } } } //------------------------------------------------------------------ void FxSchematicScene::onEditGroup() { if (m_selection->isEmpty()) return; QList fxs = m_selection->getFxs(); int i; for (i = 0; i < fxs.size(); i++) { if (fxs[i]->getAttributes()->isGrouped() && !fxs[i]->getAttributes()->isGroupEditing()) { fxs[i]->getAttributes()->editGroup(); TMacroFx *macro = dynamic_cast(fxs[i].getPointer()); if (macro) { std::vector macroFxs = macro->getFxs(); int j; for (j = 0; j < (int)macroFxs.size(); j++) macroFxs[j]->getAttributes()->editGroup(); } } } updateScene(); } //------------------------------------------------------------------ void FxSchematicScene::highlightLinks(FxSchematicNode *node, bool value) { int i, portCount = node->getInputPortCount(); // SchematicLink* ghostLink = m_supportLinks.getDisconnectionLink(eGhost); for (i = 0; i < portCount; i++) { FxSchematicPort *port = node->getInputPort(i); int j, linkCount = port->getLinkCount(); for (j = 0; j < linkCount; j++) { SchematicLink *link = port->getLink(j); if (!link) continue; if (m_disconnectionLinks.isABridgeLink(link)) continue; link->setHighlighted(value); link->update(); m_highlightedLinks.push_back(link); } } FxSchematicPort *port = node->getOutputPort(); if (port) { int linkCount = port->getLinkCount(); for (i = 0; i < linkCount; i++) { SchematicLink *link = port->getLink(i); if (!link) continue; if (m_disconnectionLinks.isABridgeLink(link)) continue; link->setHighlighted(value); link->update(); m_highlightedLinks.push_back(link); } } port = node->getLinkPort(); if (port) { SchematicLink *link = port->getLink(0); if (link && !m_disconnectionLinks.isABridgeLink(link)) { link->setHighlighted(value); link->update(); m_highlightedLinks.push_back(link); } } } //------------------------------------------------------------------ void FxSchematicScene::simulateDisconnectSelection(bool disconnect) { if (disconnect) { if (m_selection->isEmpty()) return; QList selectedFxs = m_selection->getFxs(); if (selectedFxs.isEmpty()) return; QMap visitedFxs; int i; for (i = 0; i < selectedFxs.size(); i++) visitedFxs[selectedFxs[i].getPointer()] = false; TFx *inputFx = 0, *outputFx = 0; findBoundariesFxs(inputFx, outputFx, visitedFxs); FxSchematicNode *inputNode = m_table[inputFx]; FxSchematicNode *outputNode = m_table[outputFx]; assert(inputNode && outputNode); FxSchematicPort *inputPort = 0, *outputPort = 0; SchematicPort *otherInputPort = 0; QList otherOutputPorts; if (inputNode->getInputPortCount() > 0) { inputPort = inputNode->getInputPort(0); if (inputPort) { SchematicLink *inputLink = inputPort->getLink(0); if (inputLink && !m_connectionLinks.isAnInputLink(inputLink)) { if (!m_disconnectionLinks.isAnInputLink(inputLink)) m_disconnectionLinks.addInputLink(inputLink); otherInputPort = inputLink->getOtherPort(inputPort); } } } outputPort = outputNode->getOutputPort(); if (outputPort) { for (i = 0; i < outputPort->getLinkCount(); i++) { SchematicLink *outputLink = outputPort->getLink(i); if (outputLink && !m_connectionLinks.isAnOutputLink(outputLink)) { if (!m_disconnectionLinks.isAnOutputLink(outputLink)) m_disconnectionLinks.addOutputLink(outputLink); otherOutputPorts.push_back(outputLink->getOtherPort(outputPort)); } } } m_disconnectionLinks.hideInputLinks(); m_disconnectionLinks.hideOutputLinks(); if (otherInputPort) { for (i = 0; i < otherOutputPorts.size(); i++) m_disconnectionLinks.addBridgeLink( otherOutputPorts[i]->makeLink(otherInputPort)); } } else { m_disconnectionLinks.showInputLinks(); m_disconnectionLinks.showOutputLinks(); m_disconnectionLinks.removeInputLinks(); m_disconnectionLinks.removeOutputLinks(); m_disconnectionLinks.removeBridgeLinks(true); } } //------------------------------------------------------------------ void FxSchematicScene::simulateInsertSelection(SchematicLink *link, bool connect) { if (!link || !connect) { m_connectionLinks.showBridgeLinks(); m_connectionLinks.hideInputLinks(); m_connectionLinks.hideOutputLinks(); m_connectionLinks.removeBridgeLinks(); m_connectionLinks.removeInputLinks(true); m_connectionLinks.removeOutputLinks(true); } else { if (m_disconnectionLinks.isABridgeLink(link) || m_selection->isEmpty()) return; m_connectionLinks.addBridgeLink(link); m_connectionLinks.hideBridgeLinks(); SchematicPort *inputPort = 0, *outputPort = 0; if (link) { if (link->getStartPort()->getType() == eFxInputPort) { inputPort = link->getStartPort(); outputPort = link->getEndPort(); } else { inputPort = link->getEndPort(); outputPort = link->getStartPort(); } } QMap visitedFxs; QList selectedFxs = m_selection->getFxs(); if (selectedFxs.isEmpty()) return; int i; for (i = 0; i < selectedFxs.size(); i++) visitedFxs[selectedFxs[i].getPointer()] = false; TFx *inputFx = 0, *outputFx = 0; findBoundariesFxs(inputFx, outputFx, visitedFxs); FxSchematicNode *inputNode = m_table[inputFx]; FxSchematicNode *outputNode = m_table[outputFx]; assert(inputNode && outputNode); if (inputNode->getInputPortCount() > 0) { SchematicPort *inputNodePort = inputNode->getInputPort(0); if (inputNodePort && outputPort) m_connectionLinks.addInputLink(inputNodePort->makeLink(outputPort)); } SchematicPort *outputNodePort = outputNode->getOutputPort(); if (outputNodePort && inputPort) m_connectionLinks.addOutputLink(inputPort->makeLink(outputNodePort)); m_connectionLinks.showInputLinks(); m_connectionLinks.showOutputLinks(); } } //------------------------------------------------------------ /*! in order to select nods after pasting the copied fx nodes from FxSelection */ void FxSchematicScene::selectNodes(QList &fxs) { clearSelection(); for (int i = 0; i < (int)fxs.size(); i++) { TFx *tempFx = fxs[i].getPointer(); QMap::iterator it; it = m_table.find(tempFx); if (it == m_table.end()) continue; it.value()->setSelected(true); } update(); } //------------------------------------------------------------------ void FxSchematicScene::updateNestedGroupEditors(FxSchematicNode *node, const QPointF &newPos) { if (!node) return; QStack groupIdStack = node->getFx()->getAttributes()->getGroupIdStack(); int i; QRectF rect; for (i = 0; i < groupIdStack.size(); i++) { if (m_groupEditorTable.contains(groupIdStack[i])) { QRectF app = m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect(); if (rect.isEmpty()) rect = app; else #if QT_VERSION >= 0x050000 rect = rect.united(app); #else rect = rect.unite(app); #endif } } QMap::iterator it; for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) { if (it.value()->contains(node)) { QRectF app = it.value()->sceneBoundingRect(); if (rect.isEmpty()) rect = app; else #if QT_VERSION >= 0x050000 rect = rect.united(app); #else rect = rect.unite(app); #endif } } node->setPos(newPos); for (i = 0; i < groupIdStack.size(); i++) { if (!m_groupEditorTable.contains(groupIdStack[i])) continue; #if QT_VERSION >= 0x050000 rect = rect.united(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect()); #else rect = rect.unite(m_groupEditorTable[groupIdStack[i]]->sceneBoundingRect()); #endif QRectF app = m_groupEditorTable[groupIdStack[i]]->boundingSceneRect(); if (m_groupEditorTable[groupIdStack[i]]->scenePos() != app.topLeft()) m_groupEditorTable[groupIdStack[i]]->setPos(app.topLeft()); } for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) { FxSchematicMacroEditor *editor = it.value(); if (editor->contains(node)) { QRectF app = editor->sceneBoundingRect(); #if QT_VERSION >= 0x050000 rect = rect.united(app); #else rect = rect.unite(app); #endif app = editor->boundingSceneRect(); if (editor->scenePos() != app.topLeft()) editor->setPos(app.topLeft()); } } update(rect); } //------------------------------------------------------------------ void FxSchematicScene::closeInnerMacroEditor(int groupId) { assert(m_groupEditorTable.contains(groupId)); QMap::iterator it; for (it = m_macroEditorTable.begin(); it != m_macroEditorTable.end(); it++) { TMacroFx *macro = it.key(); assert(macro); if (macro->getAttributes()->isContainedInGroup(groupId)) { macro->editMacro(false); macro->getAttributes()->closeEditingGroup(groupId); } } } //------------------------------------------------------------------ void FxSchematicScene::resizeNodes(bool maximizedNode) { resizingNodes = true; // resize nodes m_gridDimension = maximizedNode ? eLarge : eSmall; m_xshHandle->getXsheet()->getFxDag()->setDagGridDimension(m_gridDimension); QMap::iterator it1; for (it1 = m_table.begin(); it1 != m_table.end(); it1++) { if (!it1.value()) continue; it1.value()->resize(maximizedNode); TFx *fx = it1.value()->getFx(); updatePositionOnResize(fx, maximizedNode); } QMap::iterator it2; for (it2 = m_groupedTable.begin(); it2 != m_groupedTable.end(); it2++) { if (!it2.value()) continue; it2.value()->resize(maximizedNode); QList groupedFxs = it2.value()->getGroupedFxs(); for (int i = 0; i < groupedFxs.size(); i++) updatePositionOnResize(groupedFxs[i].getPointer(), maximizedNode); } QMap::iterator it3; for (it3 = m_macroEditorTable.begin(); it3 != m_macroEditorTable.end(); it3++) { if (!it3.value()) continue; it3.value()->resizeNodes(maximizedNode); } updateScene(); resizingNodes = false; } //------------------------------------------------------------------ void FxSchematicScene::updatePositionOnResize(TFx *fx, bool maximizedNode) { TPointD oldPos = fx->getAttributes()->getDagNodePos(); if (oldPos == TConst::nowhere) return; double oldPosY = oldPos.y - 25000; double newPosY = maximizedNode ? oldPosY * 2 : oldPosY * 0.5; fx->getAttributes()->setDagNodePos(TPointD(oldPos.x, newPosY + 25000)); } //------------------------------------------------------------------ void FxSchematicScene::onNodeChangedSize() { if (resizingNodes) return; updateScene(); }