| |
| |
| #include "toonz/fxcommand.h" |
| |
| |
| #include "toonz/txsheet.h" |
| #include "toonz/tcolumnfx.h" |
| #include "toonz/fxdag.h" |
| #include "toonz/tcolumnfxset.h" |
| #include "toonz/txshzeraryfxcolumn.h" |
| #include "toonz/tstageobjecttree.h" |
| #include "toonz/txshlevelcolumn.h" |
| #include "toonz/txshpalettecolumn.h" |
| #include "toonz/toonzscene.h" |
| #include "toonz/txsheethandle.h" |
| #include "toonz/tfxhandle.h" |
| #include "toonz/tcolumnhandle.h" |
| #include "toonz/tscenehandle.h" |
| #include "historytypes.h" |
| |
| |
| #include "tparamcontainer.h" |
| #include "tparamset.h" |
| #include "tfxattributes.h" |
| #include "tmacrofx.h" |
| #include "tpassivecachemanager.h" |
| |
| |
| #include "tundo.h" |
| #include "tconst.h" |
| |
| |
| #include <QMap> |
| |
| |
| #include "tcg/tcg_macros.h" |
| #include "tcg/tcg_base.h" |
| #include "tcg/tcg_function_types.h" |
| #include "tcg/tcg_iterator_ops.h" |
| |
| #include <memory> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| namespace { |
| |
| |
| |
| inline TFx *getActualIn(TFx *fx) { |
| TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx); |
| return zcfx ? (assert(zcfx->getZeraryFx()), zcfx->getZeraryFx()) : fx; |
| } |
| |
| |
| |
| inline TFx *getActualOut(TFx *fx) { |
| TZeraryFx *zfx = dynamic_cast<TZeraryFx *>(fx); |
| return (zfx && zfx->getColumnFx()) ? zfx->getColumnFx() : fx; |
| } |
| |
| |
| |
| inline int inputPortIndex(TFx *fx, TFxPort *port) { |
| int p, pCount = fx->getInputPortCount(); |
| for (p = 0; p != pCount; ++p) |
| if (fx->getInputPort(p) == port) break; |
| return p; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| bool isInsideAMacroFx(TFx *fx, TXsheet *xsh) { |
| if (!fx) return false; |
| |
| TColumnFx *cfx = dynamic_cast<TColumnFx *>(fx); |
| TXsheetFx *xfx = dynamic_cast<TXsheetFx *>(fx); |
| TOutputFx *ofx = dynamic_cast<TOutputFx *>(fx); |
| |
| return !cfx && !xfx && !ofx && |
| !(xsh->getFxDag()->getInternalFxs()->containsFx(fx)); |
| } |
| |
| |
| |
| template <typename ParamCont> |
| void setParamsToCurrentScene(TXsheet *xsh, const ParamCont *cont) { |
| for (int p = 0; p != cont->getParamCount(); ++p) { |
| TParam ¶m = *cont->getParam(p); |
| |
| if (TDoubleParam *dp = dynamic_cast<TDoubleParam *>(¶m)) |
| xsh->getStageObjectTree()->setGrammar(dp); |
| else if (TParamSet *paramSet = dynamic_cast<TParamSet *>(¶m)) |
| setParamsToCurrentScene(xsh, paramSet); |
| } |
| } |
| |
| |
| |
| inline void setFxParamToCurrentScene(TFx *fx, TXsheet *xsh) { |
| setParamsToCurrentScene(xsh, fx->getParams()); |
| } |
| |
| |
| |
| void initializeFx(TXsheet *xsh, TFx *fx) { |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) |
| fx = zcfx->getZeraryFx(); |
| |
| xsh->getFxDag()->assignUniqueId(fx); |
| setFxParamToCurrentScene(fx, xsh); |
| } |
| |
| |
| |
| void showFx(TXsheet *xsh, TFx *fx) { |
| fx->getAttributes()->setIsOpened(xsh->getFxDag()->getDagGridDimension() == 0); |
| |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) |
| fx = zcfx->getZeraryFx(); |
| fx->getAttributes()->passiveCacheDataIdx() = -1; |
| } |
| |
| |
| |
| void hideFx(TXsheet *xsh, TFx *fx) { |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) |
| fx = zcfx->getZeraryFx(); |
| TPassiveCacheManager::instance()->disableCache(fx); |
| } |
| |
| |
| |
| void addFxToCurrentScene(TFx *fx, TXsheet *xsh, bool isNewFx = true) { |
| if (isNewFx) initializeFx(xsh, fx); |
| |
| xsh->getFxDag()->getInternalFxs()->addFx(fx); |
| |
| showFx(xsh, fx); |
| } |
| |
| |
| |
| void removeFxFromCurrentScene(TFx *fx, TXsheet *xsh) { |
| xsh->getFxDag()->getInternalFxs()->removeFx(fx); |
| xsh->getFxDag()->getTerminalFxs()->removeFx(fx); |
| |
| hideFx(xsh, fx); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| struct FilterInsideAMacro { |
| TXsheet *m_xsh; |
| inline bool operator()(const TFxP &fx) { |
| return ::isInsideAMacroFx(fx.getPointer(), m_xsh); |
| } |
| |
| inline bool operator()(const TFxCommand::Link &link) { |
| return ::isInsideAMacroFx(link.m_inputFx.getPointer(), m_xsh) || |
| ::isInsideAMacroFx(link.m_outputFx.getPointer(), m_xsh); |
| } |
| }; |
| |
| struct FilterNonTerminalFxs { |
| TXsheet *xsh; |
| inline bool operator()(const TFxP &fx) { |
| return !xsh->getFxDag()->getTerminalFxs()->containsFx(fx.getPointer()); |
| } |
| }; |
| |
| struct FilterTerminalFxs { |
| TXsheet *xsh; |
| inline bool operator()(const TFxP &fx) { |
| return xsh->getFxDag()->getTerminalFxs()->containsFx(fx.getPointer()); |
| } |
| }; |
| |
| struct FilterColumnFxs { |
| inline bool operator()(const TFxP &fx) { |
| return dynamic_cast<TLevelColumnFx *>(fx.getPointer()); |
| } |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| struct CloneFxFunctor { |
| TFxP m_src; |
| bool m_ownsSrc; |
| TFx *operator()() { |
| if (m_ownsSrc) |
| m_ownsSrc = false; |
| else |
| { |
| assert(m_src->getRefCount() > |
| 1); |
| |
| TFx *src = m_src.getPointer(); |
| m_src = m_src->clone(false); |
| m_src->linkParams(src); |
| } |
| |
| return m_src.getPointer(); |
| } |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| class FxCommandUndo : public TUndo { |
| public: |
| virtual ~FxCommandUndo() {} |
| |
| virtual bool isConsistent() const = 0; |
| |
| public: |
| template <typename Pred> |
| static TFx *leftmostConnectedFx(TFx *fx, Pred pred); |
| template <typename Pred> |
| static TFx *rightmostConnectedFx(TFx *fx, Pred pred); |
| |
| static TFx *leftmostConnectedFx(TFx *fx); |
| static TFx *rightmostConnectedFx(TFx *fx); |
| |
| static std::vector<TFxCommand::Link> inputLinks(TXsheet *xsh, TFx *fx); |
| static std::vector<TFxCommand::Link> outputLinks(TXsheet *xsh, TFx *fx); |
| |
| int getHistoryType() override { return HistoryType::Schematic; } |
| |
| protected: |
| static TXshZeraryFxColumn *createZeraryFxColumn(TXsheet *xsh, TFx *zfx, |
| int row = 0); |
| static void cloneGroupStack(const QStack<int> &groupIds, |
| const QStack<std::wstring> &groupNames, |
| TFx *toFx); |
| static void cloneGroupStack(TFx *fromFx, TFx *toFx); |
| static void copyGroupEditLevel(int editGroupId, TFx *toFx); |
| static void copyGroupEditLevel(TFx *fromFx, TFx *toFx); |
| static void copyDagPosition(TFx *fromFx, TFx *toFx); |
| static void attach(TXsheet *xsh, TFx *inputFx, TFx *outputFx, int port, |
| bool copyGroupData); |
| static void attach(TXsheet *xsh, const TFxCommand::Link &link, |
| bool copyGroupData); |
| static void attachOutputs(TXsheet *xsh, TFx *insertedFx, TFx *inputFx); |
| static void detachFxs(TXsheet *xsh, TFx *fxLeft, TFx *fxRight, |
| bool detachLeft = true); |
| static void insertFxs(TXsheet *xsh, const TFxCommand::Link &link, TFx *fxLeft, |
| TFx *fxRight); |
| static void insertColumn(TXsheet *xsh, TXshColumn *column, int colIdx, |
| bool removeHole = false, bool autoTerminal = false); |
| static void removeFxOrColumn(TXsheet *xsh, TFx *fx, int colIdx, |
| bool insertHole = false, |
| bool unlinkParams = true); |
| static void linkParams(TFx *fx, TFx *linkedFx); |
| static void unlinkParams(TFx *fx); |
| static void makeNotCurrent(TFxHandle *fxHandle, TFx *fx); |
| |
| private: |
| static void removeColumn(TXsheet *xsh, int colIdx, bool insertHole); |
| static void removeNormalFx(TXsheet *xsh, TFx *fx); |
| static void removeOutputFx(TXsheet *xsh, TOutputFx *outputFx); |
| }; |
| |
| |
| |
| TXshZeraryFxColumn *FxCommandUndo::createZeraryFxColumn(TXsheet *xsh, TFx *zfx, |
| int row) { |
| int frameCount = xsh->getScene()->getFrameCount() - row; |
| |
| TXshZeraryFxColumn *column = |
| new TXshZeraryFxColumn(frameCount > 0 ? frameCount : 100); |
| column->getZeraryColumnFx()->setZeraryFx(zfx); |
| column->insertEmptyCells(0, row); |
| |
| return column; |
| } |
| |
| |
| |
| void FxCommandUndo::cloneGroupStack(const QStack<int> &groupIds, |
| const QStack<std::wstring> &groupNames, |
| TFx *toFx) { |
| toFx->getAttributes()->removeFromAllGroup(); |
| |
| for (int i = 0; i < groupIds.size(); ++i) { |
| toFx->getAttributes()->setGroupId(groupIds[i]); |
| toFx->getAttributes()->setGroupName(groupNames[i]); |
| } |
| } |
| |
| |
| |
| void FxCommandUndo::cloneGroupStack(TFx *fromFx, TFx *toFx) { |
| if (fromFx->getAttributes()->isGrouped()) { |
| cloneGroupStack(fromFx->getAttributes()->getGroupIdStack(), |
| fromFx->getAttributes()->getGroupNameStack(), toFx); |
| } |
| } |
| |
| |
| |
| void FxCommandUndo::copyGroupEditLevel(int editGroupId, TFx *toFx) { |
| toFx->getAttributes()->closeAllGroups(); |
| while (editGroupId != toFx->getAttributes()->getEditingGroupId() && |
| toFx->getAttributes()->editGroup()) |
| ; |
| |
| assert(editGroupId == toFx->getAttributes()->getEditingGroupId()); |
| } |
| |
| |
| |
| void FxCommandUndo::copyGroupEditLevel(TFx *fromFx, TFx *toFx) { |
| assert(toFx); |
| if (fromFx && fromFx->getAttributes()->isGrouped()) |
| copyGroupEditLevel(fromFx->getAttributes()->getEditingGroupId(), toFx); |
| } |
| |
| |
| |
| void FxCommandUndo::copyDagPosition(TFx *fromFx, TFx *toFx) { |
| assert(toFx); |
| if (fromFx) |
| toFx->getAttributes()->setDagNodePos( |
| fromFx->getAttributes()->getDagNodePos()); |
| } |
| |
| |
| |
| void FxCommandUndo::attach(TXsheet *xsh, TFx *inputFx, TFx *outputFx, int link, |
| bool copyGroupData) { |
| if (outputFx) { |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| inputFx = ::getActualOut(inputFx); |
| outputFx = ::getActualIn(outputFx); |
| |
| if (inputFx && link < 0) { |
| assert(dynamic_cast<TXsheetFx *>(outputFx)); |
| fxDag->addToXsheet(inputFx); |
| } else { |
| int ipCount = outputFx->getInputPortCount(); |
| if (ipCount > 0 && link < ipCount) |
| outputFx->getInputPort(link)->setFx(inputFx); |
| |
| if (copyGroupData) copyGroupEditLevel(inputFx, outputFx); |
| } |
| } |
| } |
| |
| |
| |
| void FxCommandUndo::attach(TXsheet *xsh, const TFxCommand::Link &link, |
| bool copyGroupData) { |
| attach(xsh, link.m_inputFx.getPointer(), link.m_outputFx.getPointer(), |
| link.m_index, copyGroupData); |
| } |
| |
| |
| |
| void FxCommandUndo::attachOutputs(TXsheet *xsh, TFx *insertedFx, TFx *inputFx) { |
| TCG_ASSERT(inputFx, return ); |
| |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| insertedFx = ::getActualOut(insertedFx); |
| inputFx = ::getActualOut(inputFx); |
| |
| int p, pCount = inputFx->getOutputConnectionCount(); |
| for (p = pCount - 1; p >= 0; |
| --p) |
| { |
| TFxPort *port = inputFx->getOutputConnection( |
| p); |
| port->setFx( |
| insertedFx); |
| } |
| |
| if (fxDag->getTerminalFxs()->containsFx(inputFx)) { |
| fxDag->removeFromXsheet(inputFx); |
| fxDag->addToXsheet(insertedFx); |
| } |
| } |
| |
| |
| |
| void FxCommandUndo::detachFxs(TXsheet *xsh, TFx *fxLeft, TFx *fxRight, |
| bool detachLeft) { |
| assert(fxLeft && fxRight); |
| |
| fxLeft = ::getActualIn(fxLeft); |
| fxRight = ::getActualOut(fxRight); |
| |
| int ipCount = fxLeft->getInputPortCount(); |
| |
| |
| TFx *inputFx0 = (ipCount > 0) ? fxLeft->getInputPort(0)->getFx() : 0; |
| |
| int p, opCount = fxRight->getOutputConnectionCount(); |
| for (p = opCount - 1; p >= 0; |
| --p) |
| { |
| TFxPort *outPort = fxRight->getOutputConnection(p); |
| assert(outPort && outPort->getFx() == fxRight); |
| |
| outPort->setFx(inputFx0); |
| } |
| |
| |
| FxDag *fxDag = xsh->getFxDag(); |
| if (fxDag->getTerminalFxs()->containsFx(fxRight)) { |
| fxDag->removeFromXsheet(fxRight); |
| |
| for (int p = 0; p != ipCount; ++p) |
| if (TFx *inputFx = fxLeft->getInputPort(p)->getFx()) |
| fxDag->addToXsheet(inputFx); |
| } |
| |
| if (detachLeft) fxLeft->disconnectAll(); |
| } |
| |
| |
| |
| void FxCommandUndo::insertFxs(TXsheet *xsh, const TFxCommand::Link &link, |
| TFx *fxLeft, TFx *fxRight) { |
| assert(fxLeft && fxRight); |
| |
| if (link.m_inputFx && link.m_outputFx) { |
| FxCommandUndo::attach(xsh, link.m_inputFx.getPointer(), fxLeft, 0, false); |
| FxCommandUndo::attach(xsh, fxRight, link.m_outputFx.getPointer(), |
| link.m_index, false); |
| |
| if (link.m_index < 0) |
| xsh->getFxDag()->removeFromXsheet( |
| ::getActualOut(link.m_inputFx.getPointer())); |
| } |
| } |
| |
| |
| |
| void FxCommandUndo::insertColumn(TXsheet *xsh, TXshColumn *column, int col, |
| bool removeHole, bool autoTerminal) { |
| FxDag *fxDag = xsh->getFxDag(); |
| TFx *fx = column->getFx(); |
| bool terminal = false; |
| |
| if (fx) { |
| ::showFx(xsh, fx); |
| terminal = fxDag->getTerminalFxs()->containsFx(fx); |
| } |
| |
| if (removeHole) xsh->removeColumn(col); |
| |
| xsh->insertColumn(col, column); |
| |
| if (!autoTerminal) { |
| |
| |
| |
| fxDag->removeFromXsheet(fx); |
| if (terminal) fxDag->addToXsheet(fx); |
| } |
| |
| xsh->updateFrameCount(); |
| } |
| |
| |
| |
| void FxCommandUndo::removeColumn(TXsheet *xsh, int col, bool insertHole) { |
| if (TFx *colFx = xsh->getColumn(col)->getFx()) { |
| detachFxs(xsh, colFx, colFx); |
| ::hideFx(xsh, colFx); |
| } |
| |
| xsh->removeColumn(col); |
| if (insertHole) |
| xsh->insertColumn(col); |
| |
| xsh->updateFrameCount(); |
| } |
| |
| |
| |
| void FxCommandUndo::removeNormalFx(TXsheet *xsh, TFx *fx) { |
| detachFxs(xsh, fx, fx); |
| ::removeFxFromCurrentScene(fx, xsh); |
| } |
| |
| |
| |
| void FxCommandUndo::removeOutputFx(TXsheet *xsh, TOutputFx *outputFx) { |
| detachFxs(xsh, outputFx, outputFx); |
| xsh->getFxDag()->removeOutputFx(outputFx); |
| } |
| |
| |
| |
| void FxCommandUndo::linkParams(TFx *fx, TFx *linkedFx) { |
| if (linkedFx) ::getActualIn(fx)->linkParams(::getActualIn(linkedFx)); |
| } |
| |
| |
| |
| void FxCommandUndo::unlinkParams(TFx *fx) { |
| if (fx = ::getActualIn(fx), fx->getLinkedFx()) fx->unlinkParams(); |
| } |
| |
| |
| |
| void FxCommandUndo::makeNotCurrent(TFxHandle *fxHandle, TFx *fx) { |
| if (fx = ::getActualOut(fx), fx == fxHandle->getFx()) fxHandle->setFx(0); |
| } |
| |
| |
| |
| void FxCommandUndo::removeFxOrColumn(TXsheet *xsh, TFx *fx, int colIdx, |
| bool insertHole, bool unlinkParams) { |
| assert(fx || colIdx >= 0); |
| |
| if (!fx) |
| fx = xsh->getColumn(colIdx)->getFx(); |
| else if (TColumnFx *colFx = dynamic_cast<TColumnFx *>(fx)) |
| colIdx = colFx->getColumnIndex(); |
| else if (TZeraryFx *zfx = dynamic_cast<TZeraryFx *>(fx)) { |
| if (zfx->getColumnFx()) |
| fx = zfx->getColumnFx(), |
| colIdx = static_cast<TColumnFx *>(fx)->getColumnIndex(); |
| } |
| |
| if (fx) { |
| |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) { |
| |
| fx = zcfx->getZeraryFx(); |
| } else if (TOutputFx *outputFx = dynamic_cast<TOutputFx *>(fx)) { |
| assert(xsh->getFxDag()->getOutputFxCount() > 1); |
| FxCommandUndo::removeOutputFx(xsh, outputFx); |
| } else if (colIdx < 0) |
| FxCommandUndo::removeNormalFx(xsh, fx); |
| |
| if (unlinkParams) FxCommandUndo::unlinkParams(fx); |
| } |
| |
| if (colIdx >= 0) FxCommandUndo::removeColumn(xsh, colIdx, insertHole); |
| } |
| |
| |
| |
| template <typename Pred> |
| TFx *FxCommandUndo::leftmostConnectedFx(TFx *fx, Pred pred) { |
| assert(fx); |
| |
| fx = rightmostConnectedFx( |
| fx, pred); |
| |
| do { |
| fx = ::getActualIn(fx); |
| |
| if (!((fx->getInputPortCount() > 0) && fx->getInputPort(0)->isConnected() && |
| pred(fx->getInputPort(0)->getFx()))) |
| break; |
| |
| fx = fx->getInputPort(0)->getFx(); |
| } while (true); |
| |
| return fx; |
| } |
| |
| |
| |
| template <typename Pred> |
| TFx *FxCommandUndo::rightmostConnectedFx(TFx *fx, Pred pred) { |
| assert(fx); |
| |
| do { |
| fx = ::getActualOut(fx); |
| |
| if (!(fx->getOutputConnectionCount() > 0 && |
| pred(fx->getOutputConnection(0)->getOwnerFx()))) |
| break; |
| |
| fx = fx->getOutputConnection(0)->getOwnerFx(); |
| } while (true); |
| |
| return fx; |
| } |
| |
| |
| |
| namespace { |
| struct True_pred { |
| bool operator()(TFx *fx) { return true; } |
| }; |
| } |
| |
| TFx *FxCommandUndo::leftmostConnectedFx(TFx *fx) { |
| return leftmostConnectedFx(fx, ::True_pred()); |
| } |
| |
| |
| |
| TFx *FxCommandUndo::rightmostConnectedFx(TFx *fx) { |
| return rightmostConnectedFx(fx, ::True_pred()); |
| } |
| |
| |
| |
| std::vector<TFxCommand::Link> FxCommandUndo::inputLinks(TXsheet *xsh, TFx *fx) { |
| std::vector<TFxCommand::Link> result; |
| |
| fx = ::getActualIn(fx); |
| |
| int il, ilCount = fx->getInputPortCount(); |
| for (il = 0; il != ilCount; ++il) { |
| TFxPort *port = fx->getInputPort(il); |
| |
| assert(port); |
| if (port->isConnected()) |
| result.push_back(TFxCommand::Link(port->getFx(), fx, il)); |
| } |
| |
| return result; |
| } |
| |
| |
| |
| std::vector<TFxCommand::Link> FxCommandUndo::outputLinks(TXsheet *xsh, |
| TFx *fx) { |
| std::vector<TFxCommand::Link> result; |
| |
| fx = ::getActualOut(fx); |
| |
| int ol, olCount = fx->getOutputConnectionCount(); |
| for (ol = 0; ol != olCount; ++ol) { |
| TFxPort *port = fx->getOutputConnection(ol); |
| TFx *ownerFx = port->getOwnerFx(); |
| int portIndex = ::inputPortIndex(ownerFx, port); |
| |
| result.push_back(TFxCommand::Link(fx, ownerFx, portIndex)); |
| } |
| |
| FxDag *fxDag = xsh->getFxDag(); |
| if (fxDag->getTerminalFxs()->containsFx(fx)) |
| result.push_back(TFxCommand::Link(fx, fxDag->getXsheetFx(), -1)); |
| |
| return result; |
| } |
| |
| |
| |
| |
| |
| class InsertFxUndo final : public FxCommandUndo { |
| QList<TFxP> m_selectedFxs; |
| QList<TFxCommand::Link> m_selectedLinks; |
| |
| TApplication *m_app; |
| |
| QList<TFxP> m_insertedFxs; |
| TXshZeraryFxColumnP m_insertedColumn; |
| int m_colIdx; |
| bool m_columnReplacesHole; |
| bool m_attachOutputs; |
| |
| public: |
| InsertFxUndo(const TFxP &fx, int row, int col, const QList<TFxP> &selectedFxs, |
| QList<TFxCommand::Link> selectedLinks, TApplication *app, |
| bool attachOutputs = true) |
| : m_selectedFxs(selectedFxs) |
| , m_selectedLinks(selectedLinks) |
| , m_insertedColumn(0) |
| , m_app(app) |
| , m_colIdx(col) |
| , m_columnReplacesHole(false) |
| , m_attachOutputs(attachOutputs) { |
| initialize(fx, row, col); |
| } |
| |
| bool isConsistent() const override { return !m_insertedFxs.isEmpty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| private: |
| void initialize(const TFxP &newFx, int row, int col); |
| }; |
| |
| |
| |
| inline bool has_fx_column(TFx *fx) { |
| if (TPluginInterface *plgif = dynamic_cast<TPluginInterface *>(fx)) |
| return plgif->isPluginZerary(); |
| else if (TZeraryFx *zfx = dynamic_cast<TZeraryFx *>(fx)) |
| return zfx->isZerary(); |
| return false; |
| } |
| |
| namespace { |
| |
| bool containsInputFx(const QList<TFxP> &fxs, const TFxCommand::Link &link) { |
| return fxs.contains(link.m_inputFx); |
| } |
| typedef tcg::function<bool (*)(const QList<TFxP> &, const TFxCommand::Link &), |
| containsInputFx> |
| ContainsInputFx_fun; |
| |
| } |
| |
| void InsertFxUndo::initialize(const TFxP &newFx, int row, int col) { |
| struct Locals { |
| InsertFxUndo *m_this; |
| inline void storeFx(TXsheet *xsh, TFx *fx) { |
| ::initializeFx(xsh, fx); |
| m_this->m_insertedFxs.push_back(fx); |
| } |
| |
| } locals = {this}; |
| |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| TFx *fx = newFx.getPointer(); |
| |
| assert(!dynamic_cast<TZeraryColumnFx *>(fx)); |
| |
| TZeraryFx *zfx = dynamic_cast<TZeraryFx *>(fx); |
| if (has_fx_column(fx)) { |
| m_insertedColumn = InsertFxUndo::createZeraryFxColumn(xsh, fx, row); |
| |
| locals.storeFx(xsh, fx); |
| |
| if (xsh->getColumn(col) && xsh->getColumn(col)->isEmpty()) |
| m_columnReplacesHole = true; |
| } else { |
| if (m_selectedFxs.isEmpty() && m_selectedLinks.isEmpty()) { |
| |
| if (TFx *currentFx = m_app->getCurrentFx()->getFx()) |
| m_selectedFxs.push_back(currentFx); |
| else { |
| |
| locals.storeFx(xsh, fx); |
| return; |
| } |
| } |
| |
| |
| ::FilterInsideAMacro filterInMacroFxs = {xsh}; |
| m_selectedFxs.erase(std::remove_if(m_selectedFxs.begin(), |
| m_selectedFxs.end(), filterInMacroFxs), |
| m_selectedFxs.end()); |
| |
| |
| |
| m_selectedLinks.erase( |
| std::remove_if(m_selectedLinks.begin(), m_selectedLinks.end(), |
| filterInMacroFxs), |
| m_selectedLinks.end()); |
| m_selectedLinks.erase( |
| std::remove_if(m_selectedLinks.begin(), m_selectedLinks.end(), |
| tcg::bind1st(::ContainsInputFx_fun(), m_selectedFxs)), |
| m_selectedLinks.end()); |
| |
| |
| ::CloneFxFunctor cloneFx = {fx, true}; |
| |
| int f, fCount = m_selectedFxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *fx = cloneFx(); |
| FxCommandUndo::cloneGroupStack(m_selectedFxs[f].getPointer(), fx); |
| locals.storeFx(xsh, fx); |
| } |
| |
| fCount = m_selectedLinks.size(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *fx = cloneFx(); |
| FxCommandUndo::cloneGroupStack(m_selectedLinks[f].m_inputFx.getPointer(), |
| fx); |
| locals.storeFx(xsh, fx); |
| } |
| } |
| } |
| |
| |
| |
| void InsertFxUndo::redo() const { |
| struct OnExit { |
| const InsertFxUndo *m_this; |
| ~OnExit() { |
| m_this->m_app->getCurrentFx()->setFx( |
| m_this->m_insertedFxs.back().getPointer()); |
| m_this->m_app->getCurrentXsheet()->notifyXsheetChanged(); |
| m_this->m_app->getCurrentScene()->setDirtyFlag(true); |
| } |
| } onExit = {this}; |
| |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| |
| |
| if (m_insertedColumn) { |
| FxCommandUndo::insertColumn(xsh, m_insertedColumn.getPointer(), m_colIdx, |
| m_columnReplacesHole, true); |
| return; |
| } |
| |
| |
| if (m_selectedLinks.isEmpty() && m_selectedFxs.isEmpty()) { |
| assert(m_insertedFxs.size() == 1); |
| ::addFxToCurrentScene(m_insertedFxs.back().getPointer(), xsh, |
| false); |
| } else { |
| |
| int i; |
| for (i = 0; i < m_selectedLinks.size(); ++i) { |
| const TFxCommand::Link &link = m_selectedLinks[i]; |
| TFx *insertedFx = m_insertedFxs[i].getPointer(); |
| |
| ::addFxToCurrentScene(insertedFx, xsh, false); |
| FxCommandUndo::insertFxs(xsh, link, insertedFx, insertedFx); |
| FxCommandUndo::copyGroupEditLevel(link.m_inputFx.getPointer(), |
| insertedFx); |
| } |
| |
| |
| int j, t; |
| for (j = 0, t = 0; j < m_selectedFxs.size(); j++) { |
| TFx *fx = m_selectedFxs[j].getPointer(); |
| assert(fx); |
| |
| TFx *insertedFx = m_insertedFxs[i + t].getPointer(); |
| t++; |
| |
| assert(insertedFx); |
| ::addFxToCurrentScene(insertedFx, xsh, false); |
| |
| if (m_attachOutputs) FxCommandUndo::attachOutputs(xsh, insertedFx, fx); |
| |
| FxCommandUndo::attach(xsh, fx, insertedFx, 0, true); |
| } |
| } |
| } |
| |
| |
| |
| void InsertFxUndo::undo() const { |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| |
| int i, iCount = m_insertedFxs.size(); |
| for (i = 0; i != iCount; ++i) { |
| TFx *insertedFx = m_insertedFxs[i].getPointer(); |
| |
| FxCommandUndo::removeFxOrColumn(xsh, insertedFx, -1, m_columnReplacesHole, |
| false); |
| FxCommandUndo::makeNotCurrent(m_app->getCurrentFx(), insertedFx); |
| } |
| |
| m_app->getCurrentFx()->setFx(0); |
| m_app->getCurrentXsheet()->notifyXsheetChanged(); |
| m_app->getCurrentScene()->setDirtyFlag(true); |
| } |
| |
| |
| |
| QString InsertFxUndo::getHistoryString() { |
| QString str = (m_selectedLinks.isEmpty()) ? QObject::tr("Add Fx : ") |
| : QObject::tr("Insert Fx : "); |
| QList<TFxP>::iterator it; |
| for (it = m_insertedFxs.begin(); it != m_insertedFxs.end(); it++) { |
| if (it != m_insertedFxs.begin()) str += QString(", "); |
| |
| str += QString::fromStdWString((*it)->getFxId()); |
| } |
| return str; |
| } |
| |
| |
| |
| void TFxCommand::insertFx(TFx *newFx, const QList<TFxP> &fxs, |
| const QList<Link> &links, TApplication *app, int col, |
| int row) { |
| if (!newFx) return; |
| |
| std::unique_ptr<FxCommandUndo> undo( |
| new InsertFxUndo(newFx, row, col, fxs, links, app)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| void TFxCommand::addFx(TFx *newFx, const QList<TFxP> &fxs, TApplication *app, |
| int col, int row) { |
| if (!newFx) return; |
| |
| std::unique_ptr<FxCommandUndo> undo( |
| new InsertFxUndo(newFx, row, col, fxs, QList<Link>(), app, false)); |
| if (!undo->isConsistent()) return; |
| |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| |
| |
| |
| |
| |
| class DuplicateFxUndo final : public FxCommandUndo { |
| TFxP m_fx, m_dupFx; |
| TXshColumnP m_column; |
| int m_colIdx; |
| |
| TXsheetHandle *m_xshHandle; |
| TFxHandle *m_fxHandle; |
| |
| public: |
| DuplicateFxUndo(const TFxP &originalFx, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) |
| : m_fx(originalFx) |
| , m_colIdx(-1) |
| , m_xshHandle(xshHandle) |
| , m_fxHandle(fxHandle) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return bool(m_dupFx); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void DuplicateFxUndo::initialize() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| TFx *fx = m_fx.getPointer(); |
| |
| fx = ::getActualOut(fx); |
| |
| if (isInsideAMacroFx(fx, xsh) || dynamic_cast<TXsheetFx *>(fx) || |
| dynamic_cast<TOutputFx *>(fx) || |
| (dynamic_cast<TColumnFx *>(fx) && !dynamic_cast<TZeraryColumnFx *>(fx))) |
| return; |
| |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx)) { |
| m_column = new TXshZeraryFxColumn(*zcfx->getColumn()); |
| m_colIdx = xsh->getFirstFreeColumnIndex(); |
| |
| TZeraryColumnFx *dupZcfx = |
| static_cast<TZeraryColumnFx *>(m_column->getFx()); |
| ::initializeFx(xsh, dupZcfx->getZeraryFx()); |
| |
| FxCommandUndo::cloneGroupStack(zcfx, dupZcfx); |
| |
| m_dupFx = dupZcfx; |
| } else { |
| fx = fx->clone(false); |
| ::initializeFx(xsh, fx); |
| |
| FxCommandUndo::cloneGroupStack(m_fx.getPointer(), fx); |
| |
| m_dupFx = fx; |
| } |
| } |
| |
| |
| |
| void DuplicateFxUndo::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| if (m_column) { |
| |
| TZeraryColumnFx *zcfx = static_cast<TZeraryColumnFx *>(m_fx.getPointer()); |
| TZeraryColumnFx *dupZcfx = |
| static_cast<TZeraryColumnFx *>(m_dupFx.getPointer()); |
| |
| FxCommandUndo::insertColumn(xsh, m_column.getPointer(), m_colIdx, true, |
| true); |
| FxCommandUndo::copyGroupEditLevel(zcfx, dupZcfx); |
| |
| dupZcfx->getZeraryFx()->linkParams(zcfx->getZeraryFx()); |
| } else { |
| |
| addFxToCurrentScene(m_dupFx.getPointer(), m_xshHandle->getXsheet(), false); |
| FxCommandUndo::copyGroupEditLevel(m_fx.getPointer(), m_dupFx.getPointer()); |
| |
| m_dupFx->linkParams(m_fx.getPointer()); |
| } |
| |
| m_fxHandle->setFx(m_dupFx.getPointer()); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void DuplicateFxUndo::undo() const { |
| FxCommandUndo::removeFxOrColumn(m_xshHandle->getXsheet(), |
| m_dupFx.getPointer(), -1, true, true); |
| |
| m_fxHandle->setFx(0); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| QString DuplicateFxUndo::getHistoryString() { |
| if (TZeraryColumnFx *zDup = |
| dynamic_cast<TZeraryColumnFx *>(m_dupFx.getPointer())) |
| return QObject::tr("Create Linked Fx : %1") |
| .arg(QString::fromStdWString(zDup->getZeraryFx()->getFxId())); |
| |
| return QObject::tr("Create Linked Fx : %1") |
| .arg(QString::fromStdWString(m_dupFx->getFxId())); |
| } |
| |
| |
| |
| void TFxCommand::duplicateFx(TFx *src, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new DuplicateFxUndo(src, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class ReplaceFxUndo final : public FxCommandUndo { |
| TFxP m_fx, m_repFx, m_linkedFx; |
| TXshColumnP m_column, m_repColumn; |
| int m_colIdx, m_repColIdx; |
| |
| std::vector<std::pair<int, TFx *>> m_inputLinks; |
| |
| TXsheetHandle *m_xshHandle; |
| TFxHandle *m_fxHandle; |
| |
| public: |
| ReplaceFxUndo(const TFxP &replacementFx, const TFxP &replacedFx, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) |
| : m_fx(replacedFx) |
| , m_repFx(replacementFx) |
| , m_xshHandle(xshHandle) |
| , m_fxHandle(fxHandle) |
| , m_colIdx(-1) |
| , m_repColIdx(-1) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return bool(m_repFx); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| private: |
| void initialize(); |
| static void replace(TXsheet *xsh, TFx *fx, TFx *repFx, TXshColumn *column, |
| TXshColumn *repColumn, int colIdx, int repColIdx); |
| }; |
| |
| |
| |
| void ReplaceFxUndo::initialize() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| TFx *fx = m_fx.getPointer(); |
| TFx *repFx = m_repFx.getPointer(); |
| |
| fx = ::getActualOut(fx); |
| |
| if (isInsideAMacroFx(fx, xsh) || dynamic_cast<TXsheetFx *>(fx) || |
| dynamic_cast<TOutputFx *>(fx) || |
| (dynamic_cast<TColumnFx *>(fx) && !dynamic_cast<TZeraryColumnFx *>(fx))) { |
| m_repFx = TFxP(); |
| return; |
| } |
| |
| if (dynamic_cast<TXsheetFx *>(repFx) || dynamic_cast<TOutputFx *>(repFx) || |
| dynamic_cast<TColumnFx *>(repFx)) { |
| m_repFx = TFxP(); |
| return; |
| } |
| |
| ::initializeFx(xsh, repFx); |
| |
| TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx); |
| if (zcfx) { |
| TXshZeraryFxColumn *zfColumn = zcfx->getColumn(); |
| |
| m_column = zfColumn; |
| m_colIdx = zfColumn->getIndex(); |
| |
| fx = zcfx->getZeraryFx(); |
| } |
| |
| if (has_fx_column(fx)) { |
| if (zcfx) { |
| |
| m_repColumn = new TXshZeraryFxColumn(*zcfx->getColumn()); |
| m_repColIdx = m_colIdx; |
| |
| |
| TZeraryColumnFx *repZcfx = |
| static_cast<TZeraryColumnFx *>(m_repColumn->getFx()); |
| repZcfx->setZeraryFx(repFx); |
| |
| FxCommandUndo::cloneGroupStack(zcfx, repZcfx); |
| m_repFx = repZcfx; |
| } else { |
| m_repColumn = FxCommandUndo::createZeraryFxColumn(xsh, repFx); |
| m_repColIdx = xsh->getFirstFreeColumnIndex(); |
| m_repFx = static_cast<TZeraryColumnFx *>(m_repColumn->getFx()); |
| } |
| } |
| |
| FxCommandUndo::cloneGroupStack(fx, m_repFx.getPointer()); |
| |
| |
| |
| int p, ipCount = fx->getInputPortCount(); |
| for (p = 0; p != ipCount; ++p) { |
| TFxPort *port = fx->getInputPort(p); |
| if (TFx *inputFx = port->getFx()) |
| m_inputLinks.push_back(std::make_pair(p, inputFx)); |
| } |
| |
| |
| m_linkedFx = fx->getLinkedFx(); |
| } |
| |
| |
| |
| void ReplaceFxUndo::replace(TXsheet *xsh, TFx *fx, TFx *repFx, |
| TXshColumn *column, TXshColumn *repColumn, |
| int colIdx, int repColIdx) { |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| TZeraryColumnFx *zcfx = column ? static_cast<TZeraryColumnFx *>(fx) : 0; |
| TZeraryColumnFx *repZcfx = |
| repColumn ? static_cast<TZeraryColumnFx *>(repFx) : 0; |
| |
| TFx *ifx = zcfx ? zcfx->getZeraryFx() : fx; |
| TFx *irepFx = repZcfx ? repZcfx->getZeraryFx() : repFx; |
| |
| |
| int p, ipCount = ifx->getInputPortCount(), |
| ripCount = irepFx->getInputPortCount(); |
| for (p = 0; p != ipCount && p != ripCount; ++p) { |
| TFxPort *ifxPort = ifx->getInputPort(p); |
| TFxPort *irepFxPort = irepFx->getInputPort(p); |
| |
| FxCommandUndo::attach(xsh, ifxPort->getFx(), irepFx, p, true); |
| } |
| |
| int opCount = fx->getOutputConnectionCount(); |
| for (p = opCount - 1; p >= 0; --p) { |
| TFxPort *port = fx->getOutputConnection(p); |
| port->setFx(repFx); |
| } |
| |
| if (fxDag->getTerminalFxs()->containsFx(fx)) { |
| fxDag->removeFromXsheet(fx); |
| fxDag->addToXsheet(repFx); |
| } |
| |
| |
| FxCommandUndo::removeFxOrColumn(xsh, fx, colIdx, bool(repColumn), false); |
| |
| |
| if (repColumn) |
| FxCommandUndo::insertColumn(xsh, repColumn, repColIdx, |
| column); |
| else |
| ::addFxToCurrentScene(repFx, xsh, false); |
| |
| FxCommandUndo::copyGroupEditLevel(fx, repFx); |
| FxCommandUndo::copyDagPosition(fx, repFx); |
| } |
| |
| |
| |
| void ReplaceFxUndo::redo() const { |
| ReplaceFxUndo::replace(m_xshHandle->getXsheet(), m_fx.getPointer(), |
| m_repFx.getPointer(), m_column.getPointer(), |
| m_repColumn.getPointer(), m_colIdx, m_repColIdx); |
| FxCommandUndo::unlinkParams(m_fx.getPointer()); |
| |
| m_fxHandle->setFx(0); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void ReplaceFxUndo::undo() const { |
| ReplaceFxUndo::replace(m_xshHandle->getXsheet(), m_repFx.getPointer(), |
| m_fx.getPointer(), m_repColumn.getPointer(), |
| m_column.getPointer(), m_repColIdx, m_colIdx); |
| |
| |
| m_fx->disconnectAll(); |
| |
| size_t l, lCount = m_inputLinks.size(); |
| for (l = 0; l != lCount; ++l) |
| m_fx->getInputPort(m_inputLinks[l].first)->setFx(m_inputLinks[l].second); |
| |
| |
| FxCommandUndo::linkParams(m_fx.getPointer(), m_linkedFx.getPointer()); |
| |
| m_fxHandle->setFx(0); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| QString ReplaceFxUndo::getHistoryString() { |
| QString str = QObject::tr("Replace Fx : "); |
| str += QString("%1 > %2") |
| .arg(QString::fromStdWString(m_fx->getFxId())) |
| .arg(QString::fromStdWString(m_repFx->getFxId())); |
| |
| return str; |
| } |
| |
| |
| |
| void TFxCommand::replaceFx(TFx *newFx, const QList<TFxP> &fxs, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) { |
| if (!newFx) return; |
| |
| TUndoManager *undoManager = TUndoManager::manager(); |
| ::CloneFxFunctor cloneFx = {newFx, true}; |
| |
| undoManager->beginBlock(); |
| |
| TFxP clonedFx; |
| |
| int f, fCount = fxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| if (!clonedFx) clonedFx = cloneFx(); |
| |
| std::unique_ptr<FxCommandUndo> undo( |
| new ReplaceFxUndo(clonedFx, fxs[f], xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| undoManager->add(undo.release()); |
| |
| clonedFx = TFxP(); |
| } |
| } |
| |
| undoManager->endBlock(); |
| } |
| |
| |
| |
| |
| |
| class UnlinkFxUndo final : public FxCommandUndo { |
| TFxP m_fx, m_linkedFx; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| UnlinkFxUndo(const TFxP &fx, TXsheetHandle *xshHandle) |
| : m_fx(fx), m_linkedFx(fx->getLinkedFx()), m_xshHandle(xshHandle) {} |
| |
| bool isConsistent() const override { return bool(m_linkedFx); } |
| |
| void undo() const override { |
| FxCommandUndo::linkParams(m_fx.getPointer(), m_linkedFx.getPointer()); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| void redo() const override { |
| FxCommandUndo::unlinkParams(m_fx.getPointer()); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Unlink Fx : %1 - - %2") |
| .arg(QString::fromStdWString(m_fx->getFxId())) |
| .arg(QString::fromStdWString(m_linkedFx->getFxId())); |
| } |
| }; |
| |
| |
| |
| void TFxCommand::unlinkFx(TFx *fx, TFxHandle *fxHandle, |
| TXsheetHandle *xshHandle) { |
| if (!fx) return; |
| |
| std::unique_ptr<FxCommandUndo> undo(new UnlinkFxUndo(fx, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class MakeMacroUndo : public FxCommandUndo { |
| protected: |
| TFxP m_macroFx; |
| TApplication *m_app; |
| |
| public: |
| MakeMacroUndo(const std::vector<TFxP> &fxs, TApplication *app) : m_app(app) { |
| initialize(fxs); |
| } |
| |
| bool isConsistent() const override { return bool(m_macroFx); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Make Macro Fx : %1") |
| .arg(QString::fromStdWString(m_macroFx->getFxId())); |
| } |
| |
| private: |
| void initialize(const std::vector<TFxP> &fxs); |
| |
| protected: |
| MakeMacroUndo(TMacroFx *macroFx, TApplication *app) |
| : m_macroFx(macroFx), m_app(app) {} |
| }; |
| |
| |
| |
| void MakeMacroUndo::initialize(const std::vector<TFxP> &fxs) { |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| |
| size_t f, fCount = fxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| |
| TFx *fx = fxs[f].getPointer(); |
| |
| if (isInsideAMacroFx(fx, xsh) || fx->isZerary() || |
| dynamic_cast<TZeraryColumnFx *>(fx) || dynamic_cast<TMacroFx *>(fx) || |
| dynamic_cast<TLevelColumnFx *>(fx) || |
| dynamic_cast<TPaletteColumnFx *>(fx) || dynamic_cast<TXsheetFx *>(fx) || |
| dynamic_cast<TOutputFx *>(fx)) |
| return; |
| } |
| |
| TMacroFx *macroFx = TMacroFx::create(fxs); |
| if (!macroFx) return; |
| |
| ::initializeFx(xsh, macroFx); |
| m_macroFx = TFxP(macroFx); |
| |
| |
| |
| |
| |
| m_app->getCurrentFx()->setFx(0); |
| } |
| |
| |
| |
| void MakeMacroUndo::redo() const { |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| TFxSet *terminalFxs = fxDag->getTerminalFxs(); |
| TMacroFx *macroFx = static_cast<TMacroFx *>(m_macroFx.getPointer()); |
| |
| ::addFxToCurrentScene(macroFx, xsh, false); |
| |
| |
| TFx *rootFx = macroFx->getRoot(); |
| if (terminalFxs->containsFx(rootFx)) fxDag->addToXsheet(macroFx); |
| |
| int p, opCount = rootFx->getOutputConnectionCount(); |
| for (p = opCount - 1; p >= 0; --p) |
| rootFx->getOutputConnection(p)->setFx(macroFx); |
| |
| |
| const std::vector<TFxP> &fxs = macroFx->getFxs(); |
| |
| size_t f, fCount = fxs.size(); |
| for (f = 0; f != fCount; ++f) |
| ::removeFxFromCurrentScene(fxs[f].getPointer(), xsh); |
| |
| |
| |
| int ipCount = macroFx->getInputPortCount(); |
| for (p = 0; p != ipCount; ++p) macroFx->getInputPort(p)->setOwnerFx(macroFx); |
| |
| m_app->getCurrentFx()->setFx(macroFx); |
| m_app->getCurrentXsheet()->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void MakeMacroUndo::undo() const { |
| TXsheet *xsh = m_app->getCurrentXsheet()->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| TFxSet *terminalFxs = fxDag->getTerminalFxs(); |
| TMacroFx *macroFx = static_cast<TMacroFx *>(m_macroFx.getPointer()); |
| |
| |
| TFx *rootFx = macroFx->getRoot(); |
| if (terminalFxs->containsFx(macroFx)) fxDag->addToXsheet(rootFx); |
| |
| |
| int p, opCount = macroFx->getOutputConnectionCount(); |
| for (p = opCount - 1; p >= 0; --p) |
| macroFx->getOutputConnection(p)->setFx(rootFx); |
| |
| |
| ::removeFxFromCurrentScene(macroFx, xsh); |
| |
| |
| const std::vector<TFxP> &fxs = macroFx->getFxs(); |
| |
| size_t f, fCount = fxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *fx = fxs[f].getPointer(); |
| |
| ::addFxToCurrentScene(fx, xsh, false); |
| |
| int p, ipCount = fx->getInputPortCount(); |
| for (p = 0; p != ipCount; ++p) fx->getInputPort(p)->setOwnerFx(fx); |
| } |
| |
| m_app->getCurrentFx()->setFx(0); |
| m_app->getCurrentXsheet()->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void TFxCommand::makeMacroFx(const std::vector<TFxP> &fxs, TApplication *app) { |
| if (fxs.empty()) return; |
| |
| std::unique_ptr<FxCommandUndo> undo(new MakeMacroUndo(fxs, app)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class ExplodeMacroUndo final : public MakeMacroUndo { |
| public: |
| ExplodeMacroUndo(TMacroFx *macro, TApplication *app) |
| : MakeMacroUndo(macro, app) { |
| initialize(); |
| } |
| |
| void redo() const override { MakeMacroUndo::undo(); } |
| void undo() const override { MakeMacroUndo::redo(); } |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Explode Macro Fx : %1") |
| .arg(QString::fromStdWString(m_macroFx->getFxId())); |
| } |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void ExplodeMacroUndo::initialize() { |
| if (!static_cast<TMacroFx *>(m_macroFx.getPointer())->getRoot()) |
| m_macroFx = TFxP(); |
| } |
| |
| |
| |
| void TFxCommand::explodeMacroFx(TMacroFx *macroFx, TApplication *app) { |
| if (!macroFx) return; |
| |
| std::unique_ptr<FxCommandUndo> undo(new ExplodeMacroUndo(macroFx, app)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class CreateOutputFxUndo final : public FxCommandUndo { |
| TFxP m_outputFx; |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| CreateOutputFxUndo(TFx *fx, TXsheetHandle *xshHandle) |
| : m_outputFx(new TOutputFx), m_xshHandle(xshHandle) { |
| initialize(fx); |
| } |
| |
| bool isConsistent() const override { return true; } |
| |
| void redo() const override { |
| FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); |
| TOutputFx *outputFx = static_cast<TOutputFx *>(m_outputFx.getPointer()); |
| |
| fxDag->addOutputFx(outputFx); |
| fxDag->setCurrentOutputFx(outputFx); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| void undo() const override { |
| TOutputFx *outputFx = static_cast<TOutputFx *>(m_outputFx.getPointer()); |
| |
| m_xshHandle->getXsheet()->getFxDag()->removeOutputFx(outputFx); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Create Output Fx"); |
| } |
| |
| private: |
| void initialize(TFx *fx) { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| TOutputFx *outputFx = static_cast<TOutputFx *>(m_outputFx.getPointer()); |
| |
| if (fx && !dynamic_cast<TOutputFx *>(fx)) |
| outputFx->getInputPort(0)->setFx(fx); |
| else { |
| TOutputFx *currentOutputFx = xsh->getFxDag()->getCurrentOutputFx(); |
| const TPointD &pos = currentOutputFx->getAttributes()->getDagNodePos(); |
| outputFx->getAttributes()->setDagNodePos(pos + TPointD(20, 20)); |
| } |
| } |
| }; |
| |
| |
| |
| void TFxCommand::createOutputFx(TXsheetHandle *xshHandle, TFx *currentFx) { |
| TUndo *undo = new CreateOutputFxUndo(currentFx, xshHandle); |
| |
| undo->redo(); |
| TUndoManager::manager()->add(undo); |
| } |
| |
| |
| |
| |
| |
| void TFxCommand::makeOutputFxCurrent(TFx *fx, TXsheetHandle *xshHandle) { |
| TOutputFx *outputFx = dynamic_cast<TOutputFx *>(fx); |
| if (!outputFx) return; |
| |
| TXsheet *xsh = xshHandle->getXsheet(); |
| if (xsh->getFxDag()->getCurrentOutputFx() == outputFx) return; |
| |
| xsh->getFxDag()->setCurrentOutputFx(outputFx); |
| xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| |
| |
| class ConnectNodesToXsheetUndo : public FxCommandUndo { |
| protected: |
| std::vector<TFxP> m_fxs; |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| ConnectNodesToXsheetUndo(const std::list<TFxP> &fxs, TXsheetHandle *xshHandle) |
| : m_fxs(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return !m_fxs.empty(); } |
| |
| void redo() const override { |
| |
| |
| |
| |
| |
| |
| redo_(); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| void redo_() const { |
| FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); |
| |
| size_t f, fCount = m_fxs.size(); |
| for (f = 0; f != fCount; ++f) fxDag->addToXsheet(m_fxs[f].getPointer()); |
| } |
| |
| void undo() const override { |
| FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); |
| |
| size_t f, fCount = m_fxs.size(); |
| for (f = 0; f != fCount; ++f) |
| fxDag->removeFromXsheet(m_fxs[f].getPointer()); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| QString str = QObject::tr("Connect to Xsheet : "); |
| std::vector<TFxP>::iterator it; |
| for (it = m_fxs.begin(); it != m_fxs.end(); it++) { |
| if (it != m_fxs.begin()) str += QString(", "); |
| str += QString::fromStdWString((*it)->getFxId()); |
| } |
| return str; |
| } |
| |
| protected: |
| ConnectNodesToXsheetUndo(const std::list<TFxP> &fxs, TXsheetHandle *xshHandle, |
| bool) |
| : m_fxs(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) {} |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void ConnectNodesToXsheetUndo::initialize() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| ::FilterInsideAMacro filterInMacro = {xsh}; |
| m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterInMacro), |
| m_fxs.end()); |
| |
| ::FilterTerminalFxs filterTerminalFxs = {xsh}; |
| m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterTerminalFxs), |
| m_fxs.end()); |
| } |
| |
| |
| |
| void TFxCommand::connectNodesToXsheet(const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new ConnectNodesToXsheetUndo(fxs, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class DisconnectNodesFromXsheetUndo final : public ConnectNodesToXsheetUndo { |
| public: |
| DisconnectNodesFromXsheetUndo(const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle) |
| : ConnectNodesToXsheetUndo(fxs, xshHandle, true) { |
| initialize(); |
| } |
| |
| void redo() const override { ConnectNodesToXsheetUndo::undo(); } |
| void undo() const override { ConnectNodesToXsheetUndo::redo(); } |
| |
| QString getHistoryString() override { |
| QString str = QObject::tr("Disconnect from Xsheet : "); |
| std::vector<TFxP>::iterator it; |
| for (it = m_fxs.begin(); it != m_fxs.end(); it++) { |
| if (it != m_fxs.begin()) str += QString(", "); |
| str += QString::fromStdWString((*it)->getFxId()); |
| } |
| return str; |
| } |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void DisconnectNodesFromXsheetUndo::initialize() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| ::FilterInsideAMacro filterInMacro = {xsh}; |
| m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterInMacro), |
| m_fxs.end()); |
| |
| ::FilterNonTerminalFxs filterNonTerminalFxs = {xsh}; |
| m_fxs.erase(std::remove_if(m_fxs.begin(), m_fxs.end(), filterNonTerminalFxs), |
| m_fxs.end()); |
| } |
| |
| |
| |
| void TFxCommand::disconnectNodesFromXsheet(const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new DisconnectNodesFromXsheetUndo(fxs, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class DeleteLinksUndo : public FxCommandUndo { |
| struct DynamicLink { |
| int m_groupIndex; |
| std::string m_portName; |
| TFx *m_inputFx; |
| }; |
| |
| typedef std::vector<DynamicLink> DynamicLinksVector; |
| |
| protected: |
| std::list<TFxCommand::Link> m_links; |
| |
| private: |
| std::list<TFxCommand::Link> |
| m_normalLinks; |
| std::list<TFx *> m_terminalFxs; |
| |
| |
| std::map<TFx *, DynamicLinksVector> |
| m_dynamicLinks; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| DeleteLinksUndo(const std::list<TFxCommand::Link> &links, |
| TXsheetHandle *xshHandle) |
| : m_links(links), m_xshHandle(xshHandle) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return !m_links.empty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return 10 << 10; } |
| |
| QString getHistoryString() override; |
| |
| protected: |
| DeleteLinksUndo(TXsheetHandle *xshHandle) : m_xshHandle(xshHandle) {} |
| |
| void initialize(); |
| }; |
| |
| |
| |
| void DeleteLinksUndo::initialize() { |
| struct locals { |
| static bool isInvalid(FxDag *fxDag, const TFxCommand::Link &link) { |
| if (link.m_index < 0) |
| return !fxDag->getTerminalFxs()->containsFx( |
| link.m_inputFx.getPointer()); |
| |
| TFx *inFx = ::getActualOut(link.m_inputFx.getPointer()); |
| TFx *outFx = ::getActualIn(link.m_outputFx.getPointer()); |
| |
| return (link.m_index >= outFx->getInputPortCount()) |
| ? true |
| : (outFx->getInputPort(link.m_index)->getFx() != inFx); |
| } |
| }; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| |
| ::FilterInsideAMacro filterInMacro = {xsh}; |
| m_links.erase(std::remove_if(m_links.begin(), m_links.end(), filterInMacro), |
| m_links.end()); |
| |
| |
| m_links.erase(std::remove_if(m_links.begin(), m_links.end(), |
| tcg::bind1st(&locals::isInvalid, fxDag)), |
| m_links.end()); |
| |
| std::list<TFxCommand::Link>::iterator lt, lEnd(m_links.end()); |
| for (lt = m_links.begin(); lt != lEnd; ++lt) { |
| const TFxCommand::Link &link = *lt; |
| |
| if (TXsheetFx *xsheetFx = |
| dynamic_cast<TXsheetFx *>(link.m_outputFx.getPointer())) { |
| |
| m_terminalFxs.push_back(link.m_inputFx.getPointer()); |
| continue; |
| } |
| |
| TFx *outputFx = link.m_outputFx.getPointer(); |
| |
| |
| |
| if (TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(outputFx)) |
| outputFx = zfx->getZeraryFx(); |
| |
| TFxPort *port = outputFx->getInputPort(link.m_index); |
| |
| int portGroup = port->getGroupIndex(); |
| if (portGroup < 0) m_normalLinks.push_back(link); |
| |
| if (outputFx->hasDynamicPortGroups()) |
| m_dynamicLinks.insert(std::make_pair(outputFx, DynamicLinksVector())); |
| } |
| |
| m_normalLinks.sort(); |
| |
| |
| |
| |
| std::map<TFx *, DynamicLinksVector>::iterator dlt, |
| dlEnd(m_dynamicLinks.end()); |
| for (dlt = m_dynamicLinks.begin(); dlt != dlEnd; ++dlt) { |
| TFx *outputFx = dlt->first; |
| DynamicLinksVector &dynLinks = dlt->second; |
| |
| int p, pCount = outputFx->getInputPortCount(); |
| for (p = 0; p != pCount; ++p) { |
| TFxPort *port = outputFx->getInputPort(p); |
| |
| int g = port->getGroupIndex(); |
| if (g >= 0) { |
| DynamicLink dLink = {g, outputFx->getInputPortName(p), port->getFx()}; |
| dynLinks.push_back(dLink); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void DeleteLinksUndo::redo() const { |
| FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); |
| |
| |
| std::list<TFxCommand::Link>::const_iterator lt, lEnd(m_links.end()); |
| for (lt = m_links.begin(); lt != lEnd; ++lt) { |
| const TFxCommand::Link &link = *lt; |
| |
| TFx *outputFx = lt->m_outputFx.getPointer(); |
| |
| if (TXsheetFx *xsheetFx = dynamic_cast<TXsheetFx *>(outputFx)) { |
| |
| fxDag->removeFromXsheet(link.m_inputFx.getPointer()); |
| continue; |
| } |
| |
| |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(outputFx)) |
| outputFx = zcfx->getZeraryFx(); |
| |
| int index = lt->m_index; |
| |
| assert(index < outputFx->getInputPortCount()); |
| if (index < outputFx->getInputPortCount()) |
| outputFx->getInputPort(index)->setFx(0); |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void DeleteLinksUndo::undo() const { |
| FxDag *fxDag = m_xshHandle->getXsheet()->getFxDag(); |
| |
| |
| std::list<TFx *>::const_iterator ft; |
| for (ft = m_terminalFxs.begin(); ft != m_terminalFxs.end(); ++ft) { |
| if (fxDag->checkLoop(*ft, fxDag->getXsheetFx())) { |
| assert(fxDag->checkLoop(*ft, fxDag->getXsheetFx())); |
| continue; |
| } |
| |
| fxDag->addToXsheet(*ft); |
| } |
| |
| |
| std::list<TFxCommand::Link>::const_iterator lt, lEnd(m_normalLinks.end()); |
| for (lt = m_normalLinks.begin(); lt != lEnd; ++lt) { |
| const TFxCommand::Link &link = *lt; |
| |
| int index = link.m_index; |
| TFx *inputFx = link.m_inputFx.getPointer(); |
| TFx *outputFx = link.m_outputFx.getPointer(); |
| |
| if (TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(outputFx)) |
| outputFx = zcfx->getZeraryFx(); |
| |
| if (fxDag->checkLoop(inputFx, outputFx)) { |
| assert(fxDag->checkLoop(inputFx, outputFx)); |
| continue; |
| } |
| |
| assert(index < outputFx->getInputPortCount()); |
| |
| if (index < outputFx->getInputPortCount()) |
| outputFx->getInputPort(index)->setFx(inputFx); |
| } |
| |
| |
| std::map<TFx *, DynamicLinksVector>::const_iterator dlt, |
| dlEnd(m_dynamicLinks.end()); |
| for (dlt = m_dynamicLinks.begin(); dlt != dlEnd; ++dlt) { |
| TFx *outputFx = dlt->first; |
| const DynamicLinksVector &dynLinks = dlt->second; |
| |
| { |
| int g, gCount = outputFx->dynamicPortGroupsCount(); |
| for (g = 0; g != gCount; ++g) outputFx->clearDynamicPortGroup(g); |
| } |
| |
| size_t d, dCount = dynLinks.size(); |
| for (d = 0; d != dCount; ++d) { |
| const DynamicLink &link = dynLinks[d]; |
| |
| TFxPort *port = new TRasterFxPort; |
| port->setFx(link.m_inputFx); |
| |
| outputFx->addInputPort(link.m_portName, port, link.m_groupIndex); |
| } |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| QString DeleteLinksUndo::getHistoryString() { |
| QString str = QObject::tr("Delete Link"); |
| if (!m_normalLinks.empty()) { |
| str += QString(" : "); |
| std::list<TFxCommand::Link>::const_iterator it; |
| for (it = m_normalLinks.begin(); it != m_normalLinks.end(); it++) { |
| if (it != m_normalLinks.begin()) str += QString(", "); |
| TFxCommand::Link boundingFxs = *it; |
| str += |
| QString("%1- -%2") |
| .arg(QString::fromStdWString(boundingFxs.m_inputFx->getName())) |
| .arg(QString::fromStdWString(boundingFxs.m_outputFx->getName())); |
| } |
| } |
| |
| if (!m_terminalFxs.empty()) { |
| str += QString(" : "); |
| std::list<TFx *>::const_iterator ft; |
| for (ft = m_terminalFxs.begin(); ft != m_terminalFxs.end(); ++ft) { |
| if (ft != m_terminalFxs.begin()) str += QString(", "); |
| str += |
| QString("%1- -Xsheet").arg(QString::fromStdWString((*ft)->getName())); |
| } |
| } |
| |
| return str; |
| } |
| |
| |
| |
| static void deleteLinks(const std::list<TFxCommand::Link> &links, |
| TXsheetHandle *xshHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new DeleteLinksUndo(links, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class DeleteFxOrColumnUndo final : public DeleteLinksUndo { |
| protected: |
| TFxP m_fx; |
| TXshColumnP m_column; |
| int m_colIdx; |
| |
| TFxP m_linkedFx; |
| std::vector<TFx *> m_nonTerminalInputs; |
| |
| mutable std::unique_ptr<TStageObjectParams> m_columnData; |
| |
| TXsheetHandle *m_xshHandle; |
| TFxHandle *m_fxHandle; |
| |
| using DeleteLinksUndo::m_links; |
| |
| public: |
| DeleteFxOrColumnUndo(const TFxP &fx, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle); |
| DeleteFxOrColumnUndo(int colIdx, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle); |
| |
| bool isConsistent() const override; |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| DeleteFxOrColumnUndo::DeleteFxOrColumnUndo(const TFxP &fx, |
| TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) |
| : DeleteLinksUndo(xshHandle) |
| , m_fx(fx) |
| , m_colIdx(-1) |
| , m_xshHandle(xshHandle) |
| , m_fxHandle(fxHandle) { |
| initialize(); |
| } |
| |
| |
| |
| DeleteFxOrColumnUndo::DeleteFxOrColumnUndo(int colIdx, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) |
| : DeleteLinksUndo(xshHandle) |
| , m_colIdx(colIdx) |
| , m_xshHandle(xshHandle) |
| , m_fxHandle(fxHandle) { |
| initialize(); |
| } |
| |
| |
| |
| void DeleteFxOrColumnUndo::initialize() { |
| struct { |
| DeleteFxOrColumnUndo *m_this; |
| inline void getActualData(TXsheet *xsh, TFx *&ifx, TFx *&ofx) { |
| TFx *fx = m_this->m_fx.getPointer(); |
| |
| if (!fx) fx = xsh->getColumn(m_this->m_colIdx)->getFx(); |
| |
| if (fx) { |
| ifx = ::getActualIn(fx); |
| ofx = ::getActualOut(fx); |
| |
| if (TColumnFx *colFx = dynamic_cast<TColumnFx *>(ofx)) |
| m_this->m_colIdx = colFx->getColumnIndex(); |
| } |
| |
| m_this->m_fx = ofx; |
| } |
| } locals = {this}; |
| |
| assert(m_fx || m_colIdx >= 0); |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| TFx *ifx = 0, *ofx = 0; |
| |
| locals.getActualData(xsh, ifx, ofx); |
| |
| if (ofx && isInsideAMacroFx(ofx, xsh)) |
| { |
| m_fx = TFxP(), m_colIdx = -1; |
| return; |
| } |
| |
| |
| if (m_colIdx >= 0) { |
| m_column = xsh->getColumn(m_colIdx); |
| assert(m_column); |
| |
| |
| |
| |
| |
| if (!m_column->inColumnsSet()) { |
| m_fx = TFxP(), m_colIdx = -1; |
| return; |
| } |
| } else if (TOutputFx *outputFx = dynamic_cast<TOutputFx *>(ofx)) { |
| if (xsh->getFxDag()->getOutputFxCount() <= 1) { |
| |
| m_fx = TFxP(); |
| assert(m_colIdx < 0); |
| return; |
| } |
| } |
| |
| |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| if (ofx) { |
| |
| if (fxDag->getTerminalFxs()->containsFx(ofx)) |
| m_links.push_back(TFxCommand::Link(ofx, fxDag->getXsheetFx(), -1)); |
| |
| |
| int p, opCount = ofx->getOutputConnectionCount(); |
| for (p = 0; p != opCount; ++p) { |
| if (TFx *outFx = ofx->getOutputConnection(p)->getOwnerFx()) { |
| int ip, ipCount = outFx->getInputPortCount(); |
| for (ip = 0; ip != ipCount; ++ip) |
| if (outFx->getInputPort(ip)->getFx() == ofx) break; |
| |
| assert(ip < ipCount); |
| if (ip < ipCount) m_links.push_back(TFxCommand::Link(m_fx, outFx, ip)); |
| } |
| } |
| } |
| |
| if (ifx) { |
| m_linkedFx = ifx->getLinkedFx(); |
| |
| |
| int p, ipCount = ifx->getInputPortCount(); |
| for (p = 0; p != ipCount; ++p) { |
| if (TFx *inputFx = ifx->getInputPort(p)->getFx()) { |
| m_links.push_back(TFxCommand::Link(inputFx, m_fx, p)); |
| if (!fxDag->getTerminalFxs()->containsFx( |
| inputFx)) |
| m_nonTerminalInputs.push_back( |
| inputFx); |
| } |
| } |
| } |
| |
| DeleteLinksUndo::initialize(); |
| } |
| |
| |
| |
| bool DeleteFxOrColumnUndo::isConsistent() const { |
| return (bool(m_fx) || (m_colIdx >= 0)); |
| |
| |
| |
| |
| } |
| |
| |
| |
| void DeleteFxOrColumnUndo::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| if (m_colIdx >= 0) { |
| assert(!m_columnData.get()); |
| |
| m_columnData.reset( |
| xsh->getStageObject(TStageObjectId::ColumnId( |
| m_colIdx)) |
| ->getParams()); |
| } |
| |
| |
| FxCommandUndo::removeFxOrColumn(xsh, m_fx.getPointer(), m_colIdx); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void DeleteFxOrColumnUndo::undo() const { |
| struct Locals { |
| const DeleteFxOrColumnUndo *m_this; |
| |
| void insertColumnIn(TXsheet *xsh) { |
| m_this->insertColumn(xsh, m_this->m_column.getPointer(), |
| m_this->m_colIdx); |
| |
| |
| TStageObject *sObj = |
| xsh->getStageObject(TStageObjectId::ColumnId(m_this->m_colIdx)); |
| assert(sObj); |
| |
| sObj->assignParams(m_this->m_columnData.get(), false); |
| m_this->m_columnData.reset(); |
| } |
| |
| } locals = {this}; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| TFx *fx = m_fx.getPointer(); |
| |
| if (m_column) |
| locals.insertColumnIn(xsh); |
| else if (TOutputFx *outFx = dynamic_cast<TOutputFx *>(fx)) |
| xsh->getFxDag()->addOutputFx(outFx); |
| else |
| addFxToCurrentScene(fx, xsh, false); |
| |
| if (fx) { |
| |
| |
| size_t ti, tiCount = m_nonTerminalInputs.size(); |
| for (ti = 0; ti != tiCount; ++ti) |
| fxDag->removeFromXsheet(m_nonTerminalInputs[ti]); |
| |
| |
| TFx *ifx = ::getActualIn(fx); |
| |
| if (m_linkedFx) ifx->linkParams(m_linkedFx.getPointer()); |
| |
| |
| DeleteLinksUndo::undo(); |
| } else |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| QString DeleteFxOrColumnUndo::getHistoryString() { |
| return QObject::tr("Delete Fx Node : %1") |
| .arg(QString::fromStdWString(m_fx->getFxId())); |
| } |
| |
| |
| |
| static void deleteFxs(const std::list<TFxP> &fxs, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| TUndoManager *undoManager = TUndoManager::manager(); |
| TXsheet *xsh = xshHandle->getXsheet(); |
| |
| undoManager->beginBlock(); |
| |
| std::list<TFxP>::const_iterator ft, fEnd = fxs.end(); |
| for (ft = fxs.begin(); ft != fEnd; ++ft) { |
| |
| |
| |
| |
| if (dynamic_cast<TLevelColumnFx *>(ft->getPointer())) continue; |
| |
| std::unique_ptr<FxCommandUndo> undo( |
| new DeleteFxOrColumnUndo(*ft, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| undoManager->endBlock(); |
| } |
| |
| |
| |
| |
| |
| void TFxCommand::removeOutputFx(TFx *fx, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| TOutputFx *outputFx = dynamic_cast<TOutputFx *>(fx); |
| if (!outputFx) return; |
| |
| std::unique_ptr<FxCommandUndo> undo( |
| new DeleteFxOrColumnUndo(fx, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| static void deleteColumns(const std::list<int> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) { |
| TUndoManager *undoManager = TUndoManager::manager(); |
| |
| undoManager->beginBlock(); |
| |
| |
| |
| |
| TXsheet *xsh = xshHandle->getXsheet(); |
| |
| typedef tcg::function<TXshColumn *(TXsheet::*)(int)const, &TXsheet::getColumn> |
| getColumn_fun; |
| tcg::binder1st<getColumn_fun> getCol(getColumn_fun(), *xsh); |
| |
| std::vector<TXshColumn *> cols(tcg::make_cast_it(columns.begin(), getCol), |
| tcg::make_cast_it(columns.end(), getCol)); |
| |
| size_t c, cCount = cols.size(); |
| for (c = 0; c != cCount; ++c) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new DeleteFxOrColumnUndo(cols[c]->getIndex(), xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| undoManager->add(undo.release()); |
| } |
| } |
| |
| undoManager->endBlock(); |
| } |
| |
| |
| |
| |
| |
| void TFxCommand::deleteSelection(const std::list<TFxP> &fxs, |
| const std::list<Link> &links, |
| const std::list<int> &columns, |
| TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| |
| |
| |
| ::FilterColumnFxs filterColumnFxs; |
| |
| std::list<TFxP> filteredFxs(fxs); |
| filteredFxs.erase( |
| std::remove_if(filteredFxs.begin(), filteredFxs.end(), filterColumnFxs), |
| filteredFxs.end()); |
| |
| |
| TUndoManager::manager()->beginBlock(); |
| |
| deleteColumns(columns, xshHandle, fxHandle); |
| deleteFxs(filteredFxs, xshHandle, fxHandle); |
| deleteLinks(links, xshHandle); |
| |
| TUndoManager::manager()->endBlock(); |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| class UndoPasteFxs : public FxCommandUndo { |
| protected: |
| std::list<TFxP> m_fxs; |
| std::list<TXshColumnP> m_columns; |
| std::vector<TFxCommand::Link> |
| m_links; |
| |
| TXsheetHandle *m_xshHandle; |
| TFxHandle *m_fxHandle; |
| |
| public: |
| UndoPasteFxs(const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, const TPointD &pos, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle, |
| bool addOffset = true) |
| : m_fxs(fxs) |
| , m_columns(columns) |
| , m_xshHandle(xshHandle) |
| , m_fxHandle(fxHandle) { |
| initialize(zeraryFxColumnSize, pos, addOffset); |
| } |
| |
| bool isConsistent() const override { |
| return !(m_fxs.empty() && m_columns.empty()); |
| } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| protected: |
| template <typename Func> |
| void for_each_fx(Func func) const; |
| |
| private: |
| void initialize(const std::map<TFx *, int> &zeraryFxColumnSize, |
| const TPointD &pos, bool addOffset); |
| }; |
| |
| |
| |
| void UndoPasteFxs::initialize(const std::map<TFx *, int> &zeraryFxColumnSize, |
| const TPointD &pos, bool addOffset) { |
| struct locals { |
| static void buildDagPos(TFx *fromFx, TFx *toFx, bool copyPos, |
| bool addOffset) { |
| TPointD dagPos = TConst::nowhere; |
| if (copyPos) { |
| static const TPointD offset(30, 30); |
| |
| dagPos = fromFx->getAttributes()->getDagNodePos(); |
| if (addOffset && |
| (dagPos != TConst::nowhere)) |
| dagPos += offset; |
| } |
| |
| toFx->getAttributes()->setDagNodePos(dagPos); |
| } |
| |
| static void renamePort(TFx *fx, int p, const std::wstring &oldId, |
| const std::wstring &newId) { |
| const QString &qOldId = QString::fromStdWString(oldId); |
| const QString &qNewId = QString::fromStdWString(newId); |
| const QString &qPortName = |
| QString::fromStdString(fx->getInputPortName(p)); |
| |
| if (qPortName.endsWith(qOldId)) { |
| QString qNewPortName = qPortName; |
| qNewPortName.replace(qOldId, qNewId); |
| fx->renamePort(qPortName.toStdString(), qNewPortName.toStdString()); |
| } |
| } |
| |
| static bool circularSubxsheet(TXsheet *xsh, const TXshColumnP &col) { |
| return xsh->checkCircularReferences(col.getPointer()); |
| } |
| |
| static void push_back(std::vector<TFx *> &fxs, TFx *fx) { |
| fxs.push_back(fx); |
| } |
| }; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| bool copyDagPos = (pos != TConst::nowhere); |
| |
| |
| std::list<TFxP>::iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd;) { |
| TFx *fx = ft->getPointer(); |
| |
| assert(!dynamic_cast<TZeraryColumnFx *>(fx)); |
| |
| if (has_fx_column(fx)) { |
| |
| |
| |
| |
| |
| std::map<TFx *, int>::const_iterator it = zeraryFxColumnSize.find(fx); |
| int rows = (it == zeraryFxColumnSize.end()) ? 100 : it->second; |
| |
| TXshZeraryFxColumn *column = new TXshZeraryFxColumn(rows); |
| TZeraryColumnFx *zcfx = column->getZeraryColumnFx(); |
| |
| zcfx->setZeraryFx(fx); |
| |
| int op, opCount = fx->getOutputConnectionCount(); |
| for (op = opCount - 1; op >= 0; |
| --op) |
| { |
| TFxPort *outPort = |
| fx->getOutputConnection(op); |
| outPort->setFx(zcfx); |
| } |
| |
| zcfx->getAttributes()->setDagNodePos( |
| fx->getAttributes()->getDagNodePos()); |
| m_columns.push_front(column); |
| |
| ft = m_fxs.erase(ft); |
| continue; |
| } |
| |
| |
| if (TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx)) { |
| const std::vector<TFxP> &inMacroFxs = macroFx->getFxs(); |
| |
| size_t f, fCount = inMacroFxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *inFx = inMacroFxs[f].getPointer(); |
| const std::wstring &oldFxId = inFx->getFxId(); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| ::initializeFx(xsh, inFx); |
| const std::wstring &newFxId = inFx->getFxId(); |
| |
| int ip, ipCount = macroFx->getInputPortCount(); |
| for (ip = 0; ip != ipCount; ++ip) |
| locals::renamePort(macroFx, ip, oldFxId, newFxId); |
| } |
| } |
| |
| ::initializeFx(xsh, fx); |
| locals::buildDagPos(fx, fx, copyDagPos, addOffset); |
| |
| ++ft; |
| } |
| |
| |
| m_columns.erase(std::remove_if(m_columns.begin(), m_columns.end(), |
| tcg::bind1st(&locals::circularSubxsheet, xsh)), |
| m_columns.end()); |
| |
| |
| std::list<TXshColumnP>::const_iterator ct, cEnd(m_columns.end()); |
| for (ct = m_columns.begin(); ct != cEnd; ++ct) { |
| if (TFx *cfx = (*ct)->getFx()) { |
| ::initializeFx(xsh, cfx); |
| locals::buildDagPos(cfx, cfx, copyDagPos, addOffset); |
| } |
| } |
| |
| |
| |
| std::vector<TFx *> fxs; |
| fxs.reserve(m_fxs.size() + m_columns.size()); |
| |
| for_each_fx(tcg::bind1st(&locals::push_back, fxs)); |
| |
| |
| size_t f, fCount = fxs.size(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *fx = fxs[f]; |
| |
| TFx *ofx = ::getActualIn(fx); |
| fx = ::getActualOut(fx); |
| |
| int il, ilCount = ofx->getInputPortCount(); |
| for (il = 0; il != ilCount; ++il) { |
| if (TFx *ifx = ofx->getInputPort(il)->getFx()) |
| m_links.push_back(TFxCommand::Link(ifx, ofx, il)); |
| } |
| } |
| |
| |
| if (pos != TConst::nowhere) { |
| |
| |
| TPointD middlePos; |
| int fxsCount = 0; |
| |
| std::vector<TFx *>::const_iterator ft, fEnd = fxs.end(); |
| for (ft = fxs.begin(); ft != fEnd; ++ft) { |
| TFx *fx = *ft; |
| |
| const TPointD &fxPos = fx->getAttributes()->getDagNodePos(); |
| if (fxPos != TConst::nowhere) { |
| middlePos += fxPos; |
| ++fxsCount; |
| } |
| } |
| |
| if (fxsCount > 0) { |
| middlePos = TPointD(middlePos.x / fxsCount, middlePos.y / fxsCount); |
| const TPointD &offset = pos - middlePos; |
| |
| for (ft = fxs.begin(); ft != fEnd; ++ft) { |
| TFx *fx = *ft; |
| |
| const TPointD &fxPos = fx->getAttributes()->getDagNodePos(); |
| fx->getAttributes()->setDagNodePos(fxPos + offset); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void UndoPasteFxs::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| std::list<TFxP>::const_iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd; ++ft) { |
| |
| addFxToCurrentScene(ft->getPointer(), xsh, false); |
| } |
| |
| |
| std::list<TXshColumnP>::const_iterator ct, cEnd = m_columns.end(); |
| for (ct = m_columns.begin(); ct != cEnd; ++ct) { |
| |
| FxCommandUndo::insertColumn(xsh, ct->getPointer(), |
| xsh->getFirstFreeColumnIndex(), true, false); |
| } |
| |
| |
| size_t l, lCount = m_links.size(); |
| for (l = 0; l != lCount; ++l) FxCommandUndo::attach(xsh, m_links[l], false); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void UndoPasteFxs::undo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| std::list<TFxP>::const_iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd; ++ft) { |
| TFx *fx = ft->getPointer(); |
| |
| FxCommandUndo::removeFxOrColumn(xsh, fx, -1, true, |
| false); |
| FxCommandUndo::makeNotCurrent(m_fxHandle, fx); |
| } |
| |
| std::list<TXshColumnP>::const_iterator ct, cEnd = m_columns.end(); |
| for (ct = m_columns.begin(); ct != cEnd; ++ct) { |
| FxCommandUndo::removeFxOrColumn(xsh, 0, (*ct)->getIndex(), true, |
| false); |
| FxCommandUndo::makeNotCurrent(m_fxHandle, (*ct)->getFx()); |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| template <typename Func> |
| void UndoPasteFxs::for_each_fx(Func func) const { |
| std::list<TFxP>::const_iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd; ++ft) func(ft->getPointer()); |
| |
| std::list<TXshColumnP>::const_iterator ct, cEnd = m_columns.end(); |
| for (ct = m_columns.begin(); ct != cEnd; ++ct) |
| if (TFx *cfx = (*ct)->getFx()) func(cfx); |
| } |
| |
| |
| |
| QString UndoPasteFxs::getHistoryString() { |
| QString str = QObject::tr("Paste Fx : "); |
| std::list<TFxP>::const_iterator it; |
| for (it = m_fxs.begin(); it != m_fxs.end(); it++) { |
| if (it != m_fxs.begin()) str += QString(", "); |
| str += QString("%1").arg(QString::fromStdWString((*it)->getName())); |
| } |
| return str; |
| } |
| |
| |
| |
| void TFxCommand::pasteFxs(const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| const TPointD &pos, TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoPasteFxs( |
| fxs, zeraryFxColumnSize, columns, pos, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoAddPasteFxs : public UndoPasteFxs { |
| protected: |
| TFxCommand::Link m_linkIn; |
| |
| public: |
| UndoAddPasteFxs(TFx *inFx, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) |
| : UndoPasteFxs(fxs, zeraryFxColumnSize, columns, TConst::nowhere, |
| xshHandle, fxHandle) { |
| initialize(inFx); |
| } |
| |
| void redo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| private: |
| void initialize(TFx *inFx); |
| }; |
| |
| |
| |
| void UndoAddPasteFxs::initialize(TFx *inFx) { |
| if (!(inFx && UndoPasteFxs::isConsistent())) return; |
| |
| |
| |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| if (::isInsideAMacroFx(inFx, xsh)) { |
| m_fxs.clear(), m_columns.clear(); |
| return; |
| } |
| |
| |
| |
| TFx *ifx = FxCommandUndo::leftmostConnectedFx(m_fxs.front().getPointer()); |
| |
| |
| m_linkIn = TFxCommand::Link(inFx, ifx, 0); |
| |
| |
| typedef tcg::function<void (*)(TFx *, TFx *), FxCommandUndo::cloneGroupStack> |
| clone_fun; |
| for_each_fx(tcg::bind1st(clone_fun(), inFx)); |
| } |
| |
| |
| |
| void UndoAddPasteFxs::redo() const { |
| if (m_linkIn.m_inputFx) { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| FxCommandUndo::attach(xsh, m_linkIn, false); |
| |
| |
| typedef tcg::function<void (*)(TFx *, TFx *), |
| FxCommandUndo::copyGroupEditLevel> |
| copy_fun; |
| for_each_fx( |
| tcg::binder1st<copy_fun>(copy_fun(), m_linkIn.m_inputFx.getPointer())); |
| } |
| |
| UndoPasteFxs::redo(); |
| } |
| |
| |
| |
| void TFxCommand::addPasteFxs(TFx *inFx, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoAddPasteFxs( |
| inFx, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| |
| |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoInsertPasteFxs final : public UndoAddPasteFxs { |
| TFxCommand::Link m_linkOut; |
| |
| public: |
| UndoInsertPasteFxs(const TFxCommand::Link &link, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) |
| : UndoAddPasteFxs(link.m_inputFx.getPointer(), fxs, zeraryFxColumnSize, |
| columns, xshHandle, fxHandle) { |
| initialize(link); |
| } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| private: |
| void initialize(const TFxCommand::Link &link); |
| }; |
| |
| |
| |
| void UndoInsertPasteFxs::initialize(const TFxCommand::Link &link) { |
| if (!UndoPasteFxs::isConsistent()) return; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| TFx *inFx = link.m_inputFx.getPointer(); |
| TFx *outFx = link.m_outputFx.getPointer(); |
| |
| |
| if (!(inFx && outFx) || ::isInsideAMacroFx(outFx, xsh)) { |
| m_fxs.clear(), m_columns.clear(); |
| return; |
| } |
| |
| |
| |
| TFx *ofx = FxCommandUndo::rightmostConnectedFx(m_fxs.front().getPointer()); |
| |
| |
| m_linkOut = TFxCommand::Link(ofx, outFx, link.m_index); |
| } |
| |
| |
| |
| void UndoInsertPasteFxs::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| FxCommandUndo::attach(xsh, m_linkOut, false); |
| |
| if (m_linkOut.m_index < 0) |
| xsh->getFxDag()->removeFromXsheet(m_linkIn.m_inputFx.getPointer()); |
| |
| UndoAddPasteFxs::redo(); |
| } |
| |
| |
| |
| void UndoInsertPasteFxs::undo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| TFxCommand::Link orig(m_linkIn.m_inputFx, m_linkOut.m_outputFx, |
| m_linkOut.m_index); |
| FxCommandUndo::attach(xsh, orig, false); |
| |
| UndoAddPasteFxs::undo(); |
| } |
| |
| |
| |
| void TFxCommand::insertPasteFxs(const Link &link, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoInsertPasteFxs( |
| link, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoReplacePasteFxs final : public UndoAddPasteFxs { |
| std::unique_ptr<DeleteFxOrColumnUndo> m_deleteFxUndo; |
| |
| TFx *m_fx, *m_rightmostFx; |
| |
| public: |
| UndoReplacePasteFxs(TFx *fx, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, TFxHandle *fxHandle) |
| : UndoAddPasteFxs(inFx(fx), fxs, zeraryFxColumnSize, columns, xshHandle, |
| fxHandle) |
| , m_deleteFxUndo(new DeleteFxOrColumnUndo(fx, xshHandle, fxHandle)) |
| , m_fx(fx) |
| , m_rightmostFx() { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { |
| return UndoAddPasteFxs::isConsistent() && m_deleteFxUndo->isConsistent(); |
| } |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| private: |
| static TFx *inFx(const TFx *fx) { |
| return (fx && fx->getInputPortCount() > 0) ? fx->getInputPort(0)->getFx() |
| : 0; |
| } |
| |
| void initialize(); |
| }; |
| |
| |
| |
| void UndoReplacePasteFxs::initialize() { |
| if (m_fxs.empty()) return; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| |
| m_rightmostFx = |
| FxCommandUndo::rightmostConnectedFx(this->m_fxs.front().getPointer()); |
| |
| |
| int ol, olCount = m_fx->getOutputConnectionCount(); |
| for (ol = 0; ol != olCount; ++ol) { |
| TFxPort *port = m_fx->getOutputConnection(ol); |
| TFx *ownerFx = port->getOwnerFx(); |
| |
| TCG_ASSERT(port && ownerFx, continue); |
| |
| int p = ::inputPortIndex(ownerFx, port); |
| TCG_ASSERT(p < ownerFx->getInputPortCount(), continue); |
| |
| this->m_links.push_back(TFxCommand::Link(m_rightmostFx, ownerFx, p)); |
| } |
| |
| if (fxDag->getTerminalFxs()->containsFx(m_fx)) |
| this->m_links.push_back( |
| TFxCommand::Link(m_rightmostFx, fxDag->getXsheetFx(), -1)); |
| } |
| |
| |
| |
| void UndoReplacePasteFxs::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| |
| |
| fxDag->removeFromXsheet(m_fx); |
| |
| |
| |
| m_deleteFxUndo->redo(); |
| UndoAddPasteFxs::redo(); |
| } |
| |
| |
| |
| void UndoReplacePasteFxs::undo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| |
| |
| int ol, olCount = m_rightmostFx->getOutputConnectionCount(); |
| for (ol = olCount - 1; ol >= 0; --ol) |
| if (TFxPort *port = m_rightmostFx->getOutputConnection(ol)) port->setFx(0); |
| |
| fxDag->removeFromXsheet(m_rightmostFx); |
| |
| |
| |
| |
| UndoAddPasteFxs::undo(); |
| |
| m_deleteFxUndo->undo(); |
| } |
| |
| |
| |
| void TFxCommand::replacePasteFxs(TFx *inFx, const std::list<TFxP> &fxs, |
| const std::map<TFx *, int> &zeraryFxColumnSize, |
| const std::list<TXshColumnP> &columns, |
| TXsheetHandle *xshHandle, |
| TFxHandle *fxHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoReplacePasteFxs( |
| inFx, fxs, zeraryFxColumnSize, columns, xshHandle, fxHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoDisconnectFxs : public FxCommandUndo { |
| protected: |
| std::list<TFxP> m_fxs; |
| TFx *m_leftFx, *m_rightFx; |
| |
| |
| |
| |
| std::vector<TFxCommand::Link> m_undoLinksIn, m_undoLinksOut, |
| m_undoTerminalLinks; |
| std::vector<QPair<TFxP, TPointD>> m_undoDagPos, m_redoDagPos; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| UndoDisconnectFxs(const std::list<TFxP> &fxs, |
| const QList<QPair<TFxP, TPointD>> &oldFxPos, |
| TXsheetHandle *xshHandle) |
| : m_fxs(fxs) |
| , m_xshHandle(xshHandle) |
| , m_undoDagPos(oldFxPos.begin(), oldFxPos.end()) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return !m_fxs.empty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { return QObject::tr("Disconnect Fx"); } |
| |
| private: |
| void initialize(); |
| |
| static void applyPos(const QPair<TFxP, TPointD> &pair) { |
| pair.first->getAttributes()->setDagNodePos(pair.second); |
| } |
| |
| static void attach(TXsheet *xsh, const TFxCommand::Link &link) { |
| FxCommandUndo::attach(xsh, link, false); |
| } |
| static void detachXsh(TXsheet *xsh, const TFxCommand::Link &link) { |
| xsh->getFxDag()->removeFromXsheet(link.m_inputFx.getPointer()); |
| } |
| }; |
| |
| |
| |
| void UndoDisconnectFxs::initialize() { |
| struct locals { |
| static QPair<TFxP, TPointD> originalPos(const QPair<TFxP, TPointD> &pair) { |
| return QPair<TFxP, TPointD>(pair.first, |
| pair.first->getAttributes()->getDagNodePos()); |
| } |
| |
| static bool contains(const std::list<TFxP> &fxs, TFx *fx) { |
| tcg::function<TFx *(TFxP::*)() const, &TFxP::getPointer> getPointer_fun; |
| |
| return (std::count(tcg::make_cast_it(fxs.begin(), getPointer_fun), |
| tcg::make_cast_it(fxs.end(), getPointer_fun), fx) > 0); |
| } |
| }; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| ::FilterInsideAMacro insideAMacro_fun = {xsh}; |
| if (std::find_if(m_fxs.begin(), m_fxs.end(), insideAMacro_fun) != m_fxs.end()) |
| m_fxs.clear(); |
| |
| if (m_fxs.empty()) return; |
| |
| |
| tcg::binder1st<bool (*)(const std::list<TFxP> &, TFx *)> contains_fun( |
| &locals::contains, m_fxs); |
| |
| m_leftFx = FxCommandUndo::leftmostConnectedFx(m_fxs.front().getPointer(), |
| contains_fun); |
| m_rightFx = FxCommandUndo::rightmostConnectedFx(m_fxs.front().getPointer(), |
| contains_fun); |
| |
| |
| m_undoLinksIn = FxCommandUndo::inputLinks(xsh, m_leftFx); |
| m_undoLinksOut = FxCommandUndo::outputLinks(xsh, m_rightFx); |
| |
| std::vector<TFxCommand::Link>::const_iterator lt, lEnd = m_undoLinksIn.end(); |
| for (lt = m_undoLinksIn.begin(); lt != lEnd; ++lt) |
| if (fxDag->getTerminalFxs()->containsFx(lt->m_inputFx.getPointer())) |
| m_undoTerminalLinks.push_back(TFxCommand::Link(lt->m_inputFx.getPointer(), |
| fxDag->getXsheetFx(), -1)); |
| |
| std::vector<QPair<TFxP, TPointD>>( |
| tcg::make_cast_it(m_undoDagPos.begin(), &locals::originalPos), |
| tcg::make_cast_it(m_undoDagPos.end(), &locals::originalPos)) |
| .swap(m_redoDagPos); |
| } |
| |
| |
| |
| void UndoDisconnectFxs::redo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| |
| |
| |
| |
| FxCommandUndo::detachFxs(xsh, m_leftFx, m_rightFx, false); |
| if (m_leftFx->getInputPortCount() > 0) m_leftFx->getInputPort(0)->setFx(0); |
| |
| |
| |
| |
| |
| |
| |
| std::for_each(m_redoDagPos.begin(), m_redoDagPos.end(), applyPos); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void UndoDisconnectFxs::undo() const { |
| typedef void (*LinkFun)(TXsheet * xsh, const TFxCommand::Link &); |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| tcg::binder1st<LinkFun> attacher(&UndoDisconnectFxs::attach, xsh); |
| tcg::binder1st<LinkFun> xshDetacher(&UndoDisconnectFxs::detachXsh, xsh); |
| |
| std::for_each(m_undoLinksIn.begin(), m_undoLinksIn.end(), attacher); |
| std::for_each(m_undoLinksOut.begin(), m_undoLinksOut.end(), attacher); |
| |
| std::for_each(m_undoLinksIn.begin(), m_undoLinksIn.end(), xshDetacher); |
| std::for_each(m_undoTerminalLinks.begin(), m_undoTerminalLinks.end(), |
| attacher); |
| |
| |
| std::for_each(m_undoDagPos.begin(), m_undoDagPos.end(), applyPos); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void TFxCommand::disconnectFxs(const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle, |
| const QList<QPair<TFxP, TPointD>> &fxPos) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new UndoDisconnectFxs(fxs, fxPos, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoConnectFxs final : public UndoDisconnectFxs { |
| struct GroupData; |
| |
| private: |
| TFxCommand::Link m_link; |
| std::vector<GroupData> m_undoGroupDatas; |
| |
| public: |
| UndoConnectFxs(const TFxCommand::Link &link, const std::list<TFxP> &fxs, |
| const QList<QPair<TFxP, TPointD>> &fxPos, |
| TXsheetHandle *xshHandle) |
| : UndoDisconnectFxs(fxs, fxPos, xshHandle), m_link(link) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return !m_fxs.empty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override; |
| |
| private: |
| void initialize(); |
| |
| static void applyPos(const QPair<TFxP, TPointD> &pair) { |
| pair.first->getAttributes()->setDagNodePos(pair.second); |
| } |
| }; |
| |
| |
| |
| struct UndoConnectFxs::GroupData { |
| TFx *m_fx; |
| QStack<int> m_groupIds; |
| QStack<std::wstring> m_groupNames; |
| int m_editingGroup; |
| |
| public: |
| GroupData(TFx *fx); |
| void restore() const; |
| }; |
| |
| |
| |
| UndoConnectFxs::GroupData::GroupData(TFx *fx) |
| : m_fx(fx) |
| , m_groupIds(fx->getAttributes()->getGroupIdStack()) |
| , m_groupNames(fx->getAttributes()->getGroupNameStack()) |
| , m_editingGroup(fx->getAttributes()->getEditingGroupId()) {} |
| |
| |
| |
| void UndoConnectFxs::GroupData::restore() const { |
| assert(!m_groupIds.empty()); |
| |
| FxCommandUndo::cloneGroupStack(m_groupIds, m_groupNames, m_fx); |
| FxCommandUndo::copyGroupEditLevel(m_editingGroup, m_fx); |
| } |
| |
| |
| |
| void UndoConnectFxs::initialize() { |
| if (!UndoDisconnectFxs::isConsistent()) return; |
| |
| TCG_ASSERT(m_link.m_inputFx && m_link.m_outputFx, m_fxs.clear(); return ); |
| |
| |
| m_undoGroupDatas.reserve(m_fxs.size()); |
| |
| std::list<TFxP>::const_iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd; ++ft) { |
| if ((*ft)->getAttributes()->isGrouped()) |
| m_undoGroupDatas.push_back(GroupData((*ft).getPointer())); |
| } |
| } |
| |
| |
| |
| void UndoConnectFxs::redo() const { |
| UndoDisconnectFxs::redo(); |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| FxCommandUndo::insertFxs(xsh, m_link, m_leftFx, m_rightFx); |
| |
| |
| TFx *inFx = m_link.m_inputFx.getPointer(); |
| |
| std::list<TFxP>::const_iterator ft, fEnd = m_fxs.end(); |
| for (ft = m_fxs.begin(); ft != fEnd; ++ft) { |
| TFx *fx = (*ft).getPointer(); |
| |
| FxCommandUndo::cloneGroupStack(inFx, fx); |
| FxCommandUndo::copyGroupEditLevel(inFx, fx); |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void UndoConnectFxs::undo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| |
| FxCommandUndo::detachFxs(xsh, m_leftFx, m_rightFx); |
| FxCommandUndo::attach(xsh, m_link, false); |
| |
| |
| tcg::function<void (GroupData::*)() const, &GroupData::restore> restore_fun; |
| std::for_each(m_undoGroupDatas.begin(), m_undoGroupDatas.end(), restore_fun); |
| |
| UndoDisconnectFxs::undo(); |
| } |
| |
| |
| |
| QString UndoConnectFxs::getHistoryString() { |
| return QObject::tr("Connect Fx : %1 - %2") |
| .arg(QString::fromStdWString(m_leftFx->getName())) |
| .arg(QString::fromStdWString(m_rightFx->getName())); |
| } |
| |
| |
| |
| void TFxCommand::connectFxs(const Link &link, const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle, |
| const QList<QPair<TFxP, TPointD>> &fxPos) { |
| std::unique_ptr<FxCommandUndo> undo( |
| new UndoConnectFxs(link, fxs, fxPos, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class SetParentUndo final : public FxCommandUndo { |
| TFxP m_oldFx, m_newFx, m_parentFx; |
| int m_parentPort; |
| |
| bool m_removeFromXsheet; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| SetParentUndo(TFx *fx, TFx *parentFx, int parentFxPort, |
| TXsheetHandle *xshHandle) |
| : m_newFx(fx) |
| , m_parentFx(parentFx) |
| , m_parentPort(parentFxPort) |
| , m_xshHandle(xshHandle) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return m_parentFx; } |
| |
| void redo() const override; |
| void redo_() const; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void SetParentUndo::initialize() { |
| if (!m_parentFx) return; |
| |
| |
| |
| TFx *parentFx = ::getActualIn(m_parentFx.getPointer()); |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| assert(m_parentPort < parentFx->getInputPortCount()); |
| assert(m_parentPort >= 0); |
| |
| m_oldFx = parentFx->getInputPort(m_parentPort)->getFx(); |
| |
| m_removeFromXsheet = |
| (m_newFx && |
| (m_newFx->getOutputConnectionCount() == |
| 0) && |
| fxDag->getTerminalFxs()->containsFx( |
| m_newFx.getPointer()) && |
| |
| m_parentFx != fxDag->getXsheetFx()); |
| |
| |
| if (::isInsideAMacroFx(m_parentFx.getPointer(), xsh) || |
| ::isInsideAMacroFx(m_oldFx.getPointer(), xsh) || |
| ::isInsideAMacroFx(m_newFx.getPointer(), xsh)) |
| m_parentFx = TFxP(); |
| } |
| |
| |
| |
| void SetParentUndo::redo() const { |
| |
| |
| |
| |
| |
| |
| redo_(); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void SetParentUndo::redo_() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| TFx *parentFx = ::getActualIn(m_parentFx.getPointer()); |
| FxCommandUndo::attach(xsh, m_newFx.getPointer(), parentFx, m_parentPort, |
| false); |
| |
| if (m_removeFromXsheet) |
| xsh->getFxDag()->removeFromXsheet(m_newFx.getPointer()); |
| } |
| |
| |
| |
| void SetParentUndo::undo() const { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| TFx *parentFx = ::getActualIn(m_parentFx.getPointer()); |
| FxCommandUndo::attach(xsh, m_oldFx.getPointer(), parentFx, m_parentPort, |
| false); |
| |
| if (m_removeFromXsheet) xsh->getFxDag()->addToXsheet(m_newFx.getPointer()); |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void TFxCommand::setParent(TFx *fx, TFx *parentFx, int parentFxPort, |
| TXsheetHandle *xshHandle) { |
| if (dynamic_cast<TXsheetFx *>(parentFx) || parentFxPort < 0) { |
| std::unique_ptr<ConnectNodesToXsheetUndo> undo( |
| new ConnectNodesToXsheetUndo(std::list<TFxP>(1, fx), xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo_(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } else { |
| std::unique_ptr<SetParentUndo> undo( |
| new SetParentUndo(fx, parentFx, parentFxPort, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo_(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoRenameFx final : public FxCommandUndo { |
| TFxP m_fx; |
| std::wstring m_newName, m_oldName; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| UndoRenameFx(TFx *fx, const std::wstring &newName, TXsheetHandle *xshHandle) |
| : m_fx(fx) |
| , m_newName(newName) |
| , m_oldName(::getActualIn(fx)->getName()) |
| , m_xshHandle(xshHandle) { |
| assert(fx); |
| } |
| |
| bool isConsistent() const override { return true; } |
| |
| void redo() const override { |
| redo_(); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| void redo_() const { ::getActualIn(m_fx.getPointer())->setName(m_newName); } |
| |
| void undo() const override { |
| ::getActualIn(m_fx.getPointer())->setName(m_oldName); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Rename Fx : %1 > %2") |
| .arg(QString::fromStdWString(m_oldName)) |
| .arg(QString::fromStdWString(m_newName)); |
| } |
| }; |
| |
| |
| |
| void TFxCommand::renameFx(TFx *fx, const std::wstring &newName, |
| TXsheetHandle *xshHandle) { |
| if (!fx) return; |
| |
| std::unique_ptr<UndoRenameFx> undo(new UndoRenameFx(fx, newName, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo_(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoGroupFxs : public FxCommandUndo { |
| public: |
| struct GroupData { |
| TFxP m_fx; |
| mutable int m_groupIndex; |
| |
| GroupData(const TFxP &fx, int groupIdx = -1) |
| : m_fx(fx), m_groupIndex(groupIdx) {} |
| }; |
| |
| protected: |
| std::vector<GroupData> m_groupData; |
| int m_groupId; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| UndoGroupFxs(const std::list<TFxP> &fxs, TXsheetHandle *xshHandle) |
| : m_groupData(fxs.begin(), fxs.end()), m_xshHandle(xshHandle) { |
| initialize(); |
| } |
| |
| bool isConsistent() const override { return !m_groupData.empty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { return QObject::tr("Group Fx"); } |
| |
| protected: |
| UndoGroupFxs(int groupId, TXsheetHandle *xshHandle) |
| : m_groupId(groupId), m_xshHandle(xshHandle) {} |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void UndoGroupFxs::initialize() { |
| struct locals { |
| inline static bool isXsheetFx(const GroupData &gd) { |
| return dynamic_cast<TXsheet *>(gd.m_fx.getPointer()); |
| } |
| }; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| m_groupId = fxDag->getNewGroupId(); |
| |
| |
| m_groupData.erase(std::remove_if(m_groupData.begin(), m_groupData.end(), |
| &locals::isXsheetFx), |
| m_groupData.end()); |
| |
| |
| |
| |
| |
| size_t g, gCount = m_groupData.size(); |
| for (g = 0; g != gCount; ++g) { |
| if (TMacroFx *macro = |
| dynamic_cast<TMacroFx *>(m_groupData[g].m_fx.getPointer())) { |
| const std::vector<TFxP> &internalFxs = macro->getFxs(); |
| |
| std::vector<TFxP>::const_iterator ft, fEnd = internalFxs.end(); |
| for (ft = internalFxs.begin(); ft != fEnd; ++ft) |
| m_groupData.push_back(*ft); |
| } |
| } |
| } |
| |
| |
| |
| void UndoGroupFxs::redo() const { |
| const std::wstring groupName = L"Group " + std::to_wstring(m_groupId); |
| |
| std::vector<GroupData>::const_iterator gt, gEnd = m_groupData.end(); |
| for (gt = m_groupData.begin(); gt != gEnd; ++gt) { |
| |
| gt->m_groupIndex = gt->m_fx->getAttributes()->setGroupId(m_groupId); |
| gt->m_fx->getAttributes()->setGroupName(groupName); |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void UndoGroupFxs::undo() const { |
| std::vector<GroupData>::const_iterator gt, gEnd = m_groupData.end(); |
| for (gt = m_groupData.begin(); gt != gEnd; ++gt) { |
| TCG_ASSERT(gt->m_groupIndex >= 0, continue); |
| |
| |
| gt->m_fx->getAttributes()->removeGroupId(gt->m_groupIndex); |
| gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex); |
| |
| gt->m_groupIndex = -1; |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void TFxCommand::groupFxs(const std::list<TFxP> &fxs, |
| TXsheetHandle *xshHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoGroupFxs(fxs, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoUngroupFxs final : public UndoGroupFxs { |
| public: |
| UndoUngroupFxs(int groupId, TXsheetHandle *xshHandle) |
| : UndoGroupFxs(groupId, xshHandle) { |
| initialize(); |
| } |
| |
| void redo() const override { UndoGroupFxs::undo(); } |
| void undo() const override { UndoGroupFxs::redo(); } |
| |
| QString getHistoryString() override { return QObject::tr("Ungroup Fx"); } |
| |
| private: |
| void initialize(); |
| }; |
| |
| |
| |
| void UndoUngroupFxs::initialize() { |
| struct { |
| UndoUngroupFxs *m_this; |
| |
| void scanFxForGroup(TFx *fx) { |
| if (fx) { |
| const QStack<int> &groupStack = fx->getAttributes()->getGroupIdStack(); |
| |
| int groupIdx = |
| groupStack.indexOf(m_this->m_groupId); |
| if (groupIdx >= 0) |
| m_this->m_groupData.push_back(GroupData(fx, groupIdx)); |
| } |
| } |
| |
| } locals = {this}; |
| |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| FxDag *fxDag = xsh->getFxDag(); |
| |
| |
| |
| |
| |
| int c, cCount = xsh->getColumnCount(); |
| for (c = 0; c != cCount; ++c) { |
| TXshColumn *column = xsh->getColumn(c); |
| assert(column); |
| |
| locals.scanFxForGroup(column->getFx()); |
| } |
| |
| |
| TFxSet *internalFxs = fxDag->getInternalFxs(); |
| |
| int f, fCount = internalFxs->getFxCount(); |
| for (f = 0; f != fCount; ++f) { |
| TFx *fx = internalFxs->getFx(f); |
| locals.scanFxForGroup(fx); |
| |
| if (TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx)) { |
| |
| const std::vector<TFxP> &fxs = macroFx->getFxs(); |
| |
| std::vector<TFxP>::const_iterator ft, fEnd = fxs.end(); |
| for (ft = fxs.begin(); ft != fEnd; ++ft) |
| locals.scanFxForGroup(ft->getPointer()); |
| } |
| } |
| |
| |
| int o, oCount = fxDag->getOutputFxCount(); |
| for (o = 0; o != oCount; ++o) locals.scanFxForGroup(fxDag->getOutputFx(o)); |
| } |
| |
| |
| |
| void TFxCommand::ungroupFxs(int groupId, TXsheetHandle *xshHandle) { |
| std::unique_ptr<FxCommandUndo> undo(new UndoUngroupFxs(groupId, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |
| |
| |
| |
| |
| class UndoRenameGroup final : public FxCommandUndo { |
| std::vector<UndoGroupFxs::GroupData> m_groupData; |
| std::wstring m_oldGroupName, m_newGroupName; |
| |
| TXsheetHandle *m_xshHandle; |
| |
| public: |
| UndoRenameGroup(const std::list<TFxP> &fxs, const std::wstring &newGroupName, |
| bool fromEditor, TXsheetHandle *xshHandle) |
| : m_groupData(fxs.begin(), fxs.end()) |
| , m_newGroupName(newGroupName) |
| , m_xshHandle(xshHandle) { |
| initialize(fromEditor); |
| } |
| |
| bool isConsistent() const override { return !m_groupData.empty(); } |
| |
| void redo() const override; |
| void undo() const override; |
| |
| void redo_() const; |
| |
| int getSize() const override { return sizeof(*this); } |
| |
| QString getHistoryString() override { |
| return QObject::tr("Rename Group : %1 > %2") |
| .arg(QString::fromStdWString(m_oldGroupName)) |
| .arg(QString::fromStdWString(m_newGroupName)); |
| } |
| |
| private: |
| void initialize(bool fromEditor); |
| }; |
| |
| |
| |
| void UndoRenameGroup::initialize(bool fromEditor) { |
| struct locals { |
| inline static bool isInvalid(const UndoGroupFxs::GroupData &gd) { |
| return (gd.m_groupIndex < 0); |
| } |
| }; |
| |
| if (!m_groupData.empty()) { |
| m_oldGroupName = |
| m_groupData.front().m_fx->getAttributes()->getGroupName(fromEditor); |
| |
| |
| std::vector<UndoGroupFxs::GroupData>::const_iterator gt, |
| gEnd = m_groupData.end(); |
| for (gt = m_groupData.begin(); gt != gEnd; ++gt) { |
| const QStack<std::wstring> &groupNamesStack = |
| gt->m_fx->getAttributes()->getGroupNameStack(); |
| |
| gt->m_groupIndex = |
| groupNamesStack.indexOf(m_oldGroupName); |
| assert(gt->m_groupIndex >= 0); |
| } |
| } |
| |
| m_groupData.erase(std::remove_if(m_groupData.begin(), m_groupData.end(), |
| &locals::isInvalid), |
| m_groupData.end()); |
| } |
| |
| |
| |
| void UndoRenameGroup::redo() const { |
| redo_(); |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void UndoRenameGroup::redo_() const { |
| std::vector<UndoGroupFxs::GroupData>::const_iterator gt, |
| gEnd = m_groupData.end(); |
| for (gt = m_groupData.begin(); gt != gEnd; ++gt) { |
| gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex); |
| gt->m_fx->getAttributes()->setGroupName(m_newGroupName, gt->m_groupIndex); |
| } |
| } |
| |
| |
| |
| void UndoRenameGroup::undo() const { |
| std::vector<UndoGroupFxs::GroupData>::const_iterator gt, |
| gEnd = m_groupData.end(); |
| for (gt = m_groupData.begin(); gt != gEnd; ++gt) { |
| gt->m_fx->getAttributes()->removeGroupName(gt->m_groupIndex); |
| gt->m_fx->getAttributes()->setGroupName(m_oldGroupName, gt->m_groupIndex); |
| } |
| |
| m_xshHandle->notifyXsheetChanged(); |
| } |
| |
| |
| |
| void TFxCommand::renameGroup(const std::list<TFxP> &fxs, |
| const std::wstring &name, bool fromEditor, |
| TXsheetHandle *xshHandle) { |
| std::unique_ptr<UndoRenameGroup> undo( |
| new UndoRenameGroup(fxs, name, fromEditor, xshHandle)); |
| if (undo->isConsistent()) { |
| undo->redo_(); |
| TUndoManager::manager()->add(undo.release()); |
| } |
| } |
| |