| |
| |
| #include "toonzqt/functionviewer.h" |
| |
| |
| #include "toonzqt/functionselection.h" |
| #include "toonzqt/functionpanel.h" |
| #include "toonzqt/functiontreeviewer.h" |
| #include "toonzqt/functionsheet.h" |
| #include "toonzqt/functionsegmentviewer.h" |
| #include "toonzqt/functiontoolbar.h" |
| #include "toonzqt/swatchviewer.h" |
| #include "toonzqt/dvscrollwidget.h" |
| |
| |
| #include "toonz/tstageobjecttree.h" |
| #include "toonz/txsheet.h" |
| #include "toonz/txsheethandle.h" |
| #include "toonz/tobjecthandle.h" |
| #include "toonz/tfxhandle.h" |
| #include "toonz/tcolumnhandle.h" |
| #include "toonz/fxdag.h" |
| #include "toonz/txshzeraryfxcolumn.h" |
| #include "toonz/tcolumnfx.h" |
| #include "toonz/toonzscene.h" |
| #include "toonz/tproject.h" |
| #include "toonz/tscenehandle.h" |
| #include "toonz/sceneproperties.h" |
| |
| |
| #include "tparamcontainer.h" |
| #include "tunit.h" |
| |
| |
| #include "tstopwatch.h" |
| |
| |
| #include <QPainter> |
| #include <QMouseEvent> |
| #include <QWheelEvent> |
| #include <QBoxLayout> |
| #include <QPushButton> |
| #include <QStackedWidget> |
| #include <QLabel> |
| #include <QToolBar> |
| #include <QAction> |
| |
| using namespace DVGui; |
| |
| |
| |
| |
| |
| |
| |
| #if QT_VERSION >= 0x050500 |
| FunctionViewer::FunctionViewer(QWidget *parent, Qt::WindowFlags flags) |
| #else |
| FunctionViewer::FunctionViewer(QWidget *parent, Qt::WFlags flags) |
| #endif |
| : QSplitter(parent) |
| , m_xshHandle(0) |
| , m_frameHandle(0) |
| , m_objectHandle(0) |
| , m_fxHandle(0) |
| , m_columnHandle(0) |
| , m_curve(0) |
| , m_selection(new FunctionSelection()) |
| , m_sceneHandle(0) { |
| setObjectName("FunctionEditor"); |
| |
| |
| m_localFrame.setFrame(0); |
| setFocusPolicy(Qt::NoFocus); |
| |
| m_treeView = new FunctionTreeView(this); |
| m_functionGraph = new FunctionPanel(this); |
| m_numericalColumns = new FunctionSheet(); |
| m_toolbar = new FunctionToolbar; |
| m_segmentViewer = |
| new FunctionSegmentViewer(this, m_numericalColumns, m_functionGraph); |
| QWidget *leftPanel = new QWidget(); |
| QWidget *rightPanel = new QWidget(); |
| |
| |
| m_treeView->resize(150, m_treeView->size().height()); |
| m_treeView->setMinimumWidth(0); |
| |
| FunctionTreeModel *ftModel = |
| dynamic_cast<FunctionTreeModel *>(m_treeView->model()); |
| m_functionGraph->setModel(ftModel); |
| m_numericalColumns->setModel(ftModel); |
| |
| m_functionGraph->setSelection(getSelection()); |
| m_numericalColumns->setSelection(getSelection()); |
| |
| m_numericalColumns->setViewer(this); |
| |
| m_toolbar->setSelection(m_selection); |
| m_toolbar->setFocusPolicy(Qt::NoFocus); |
| |
| m_toolbar->setFrameHandle( |
| &m_localFrame); |
| m_functionGraph->setFrameHandle( |
| &m_localFrame); |
| m_numericalColumns->setFrameHandle( |
| &m_localFrame); |
| |
| |
| |
| |
| QVBoxLayout *leftLayout = new QVBoxLayout(); |
| leftLayout->setMargin(0); |
| leftLayout->setSpacing(0); |
| { |
| leftLayout->addWidget(m_toolbar); |
| leftLayout->addSpacing(36); |
| leftLayout->addWidget(m_numericalColumns); |
| } |
| leftPanel->setLayout(leftLayout); |
| |
| addWidget(leftPanel); |
| |
| QVBoxLayout *rightLayout = new QVBoxLayout(); |
| rightLayout->setMargin(0); |
| rightLayout->setSpacing(5); |
| { |
| rightLayout->addWidget(m_segmentViewer, 0); |
| rightLayout->addWidget(m_treeView, 1); |
| } |
| rightPanel->setLayout(rightLayout); |
| |
| addWidget(rightPanel); |
| |
| |
| setSizes(QList<int>() << 500 << 200); |
| setStretchFactor(0, 5); |
| setStretchFactor(1, 2); |
| |
| |
| bool ret = true; |
| ret = ret && connect(m_toolbar, SIGNAL(numericalColumnToggled()), this, |
| SLOT(toggleMode())); |
| ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()), |
| m_functionGraph, SLOT(update())); |
| ret = ret && connect(ftModel, SIGNAL(activeChannelsChanged()), |
| m_numericalColumns, SLOT(updateAll())); |
| ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_treeView, |
| SLOT(update())); |
| ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_functionGraph, |
| SLOT(update())); |
| ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_numericalColumns, |
| SLOT(updateAll())); |
| ret = ret && connect(ftModel, SIGNAL(curveSelected(TDoubleParam *)), this, |
| SLOT(onCurveSelected(TDoubleParam *))); |
| ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), m_segmentViewer, |
| SLOT(onCurveChanged())); |
| ret = ret && connect(ftModel, SIGNAL(curveChanged(bool)), this, |
| SLOT(onCurveChanged(bool))); |
| ret = ret && connect(&m_localFrame, SIGNAL(frameSwitched()), this, |
| SLOT(onFrameSwitched())); |
| ret = ret && connect(getSelection(), SIGNAL(selectionChanged()), this, |
| SLOT(onSelectionChanged())); |
| ret = ret && connect(m_functionGraph, SIGNAL(keyframeSelected(double)), |
| m_toolbar, SLOT(setFrame(double))); |
| |
| ret = ret && connect(m_treeView, SIGNAL(switchCurrentObject(TStageObject *)), |
| this, SLOT(doSwitchCurrentObject(TStageObject *))); |
| ret = ret && connect(m_treeView, SIGNAL(switchCurrentFx(TFx *)), this, |
| SLOT(doSwitchCurrentFx(TFx *))); |
| |
| ret = ret && |
| connect(ftModel, |
| SIGNAL(currentChannelChanged(FunctionTreeModel::Channel *)), |
| m_numericalColumns, |
| SLOT(onCurrentChannelChanged(FunctionTreeModel::Channel *))); |
| |
| assert(ret); |
| |
| m_functionGraph->hide(); |
| } |
| |
| |
| |
| FunctionViewer::~FunctionViewer() { |
| delete m_selection; |
| m_toolbar->setFrameHandle(0); |
| } |
| |
| |
| |
| void FunctionViewer::showEvent(QShowEvent *) { |
| refreshModel(); |
| |
| |
| bool ret = true; |
| |
| if (m_xshHandle) { |
| ret = connect(m_xshHandle, SIGNAL(xsheetChanged()), this, |
| SLOT(refreshModel())) && |
| ret; |
| ret = connect(m_xshHandle, SIGNAL(xsheetSwitched()), this, |
| SLOT(rebuildModel())) && |
| ret; |
| } |
| |
| if (m_frameHandle) |
| ret = connect(m_frameHandle, SIGNAL(frameSwitched()), this, |
| SLOT(propagateExternalSetFrame())) && |
| ret; |
| |
| if (m_objectHandle) { |
| ret = connect(m_objectHandle, SIGNAL(objectSwitched()), this, |
| SLOT(onStageObjectSwitched())) && |
| ret; |
| ret = connect(m_objectHandle, SIGNAL(objectChanged(bool)), this, |
| SLOT(onStageObjectChanged(bool))) && |
| ret; |
| } |
| |
| if (m_fxHandle) |
| ret = |
| connect(m_fxHandle, SIGNAL(fxSwitched()), this, SLOT(onFxSwitched())) && |
| ret; |
| |
| |
| if (m_sceneHandle) |
| ret = connect(m_sceneHandle, SIGNAL(sceneSwitched()), m_treeView, |
| SLOT(displayAnimatedChannels())) && |
| ret; |
| |
| assert(ret); |
| |
| m_treeView->setExpanded(m_treeView->model()->index(0, 0), true); |
| m_treeView->setExpanded(m_treeView->model()->index(1, 0), true); |
| |
| FunctionTreeModel *ftm = |
| static_cast<FunctionTreeModel *>(m_treeView->model()); |
| |
| if (m_objectHandle) { |
| assert(m_xshHandle); |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| const TStageObjectId &objId = m_objectHandle->getObjectId(); |
| ftm->setCurrentStageObject((objId == TStageObjectId::NoneId) |
| ? (TStageObject *)0 |
| : xsh->getStageObject(objId)); |
| } |
| |
| if (m_fxHandle) ftm->setCurrentFx(m_fxHandle->getFx()); |
| } |
| |
| |
| |
| void FunctionViewer::hideEvent(QHideEvent *) { |
| if (m_xshHandle) m_xshHandle->disconnect(this); |
| if (m_frameHandle) m_frameHandle->disconnect(this); |
| if (m_objectHandle) m_objectHandle->disconnect(this); |
| if (m_fxHandle) m_fxHandle->disconnect(this); |
| if (m_sceneHandle) m_sceneHandle->disconnect(this); |
| |
| if (m_functionGraph->isVisible()) m_functionGraph->hide(); |
| } |
| |
| |
| |
| void FunctionViewer::openContextMenu(TreeModel::Item *item, |
| const QPoint &globalPos) { |
| m_treeView->openContextMenu(item, globalPos); |
| } |
| |
| |
| |
| void FunctionViewer::rebuildModel() { |
| getSelection()->selectNone(); |
| onCurveSelected(0); |
| m_functionGraph->getModel()->resetAll(); |
| refreshModel(); |
| m_treeView->displayAnimatedChannels(); |
| } |
| |
| |
| |
| void FunctionViewer::refreshModel() { |
| TXsheet *xsh = m_xshHandle ? m_xshHandle->getXsheet() : 0; |
| |
| m_functionGraph->getModel()->refreshData(xsh); |
| |
| if (xsh) { |
| int rowCount = xsh->getFrameCount(); |
| m_numericalColumns->setRowCount(rowCount); |
| m_numericalColumns->updateAll(); |
| |
| ToonzScene *scene = xsh->getScene(); |
| if (!scene) |
| return; |
| |
| TFilePath scenePath = scene->getScenePath().getParentDir(); |
| if (scene->isUntitled()) |
| scenePath = |
| TProjectManager::instance()->getCurrentProject()->getScenesPath(); |
| |
| m_treeView->setCurrentScenePath(scenePath); |
| |
| int distance, offset; |
| scene->getProperties()->getMarkers(distance, offset); |
| m_numericalColumns->setMarkRow(distance, offset); |
| } |
| |
| m_treeView->updateAll(); |
| m_toolbar->setCurve(0); |
| } |
| |
| |
| |
| void FunctionViewer::setXsheetHandle(TXsheetHandle *xshHandle) { |
| if (xshHandle == m_xshHandle) return; |
| |
| if (m_xshHandle) m_xshHandle->disconnect(this); |
| |
| m_xshHandle = xshHandle; |
| m_segmentViewer->setXsheetHandle(xshHandle); |
| |
| if (m_xshHandle && isVisible()) { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| m_functionGraph->getModel()->refreshData(xsh); |
| |
| bool ret = |
| connect(m_xshHandle, SIGNAL(xsheetChanged), this, SLOT(refreshModel())); |
| assert(ret); |
| } |
| } |
| |
| |
| |
| void FunctionViewer::setFrameHandle(TFrameHandle *frameHandle) { |
| if (m_frameHandle == frameHandle) return; |
| |
| if (m_frameHandle) m_frameHandle->disconnect(this); |
| |
| m_frameHandle = frameHandle; |
| |
| if (m_frameHandle && isVisible()) { |
| bool ret = connect(m_frameHandle, SIGNAL(frameSwitched()), this, |
| SLOT(propagateExternalSetFrame())); |
| assert(ret); |
| } |
| } |
| |
| |
| |
| void FunctionViewer::setObjectHandle(TObjectHandle *objectHandle) { |
| if (objectHandle == m_objectHandle) return; |
| |
| if (m_objectHandle) m_objectHandle->disconnect(this); |
| |
| m_objectHandle = objectHandle; |
| |
| if (m_objectHandle && isVisible()) { |
| m_treeView->updateAll(); |
| |
| bool ret = true; |
| ret = connect(m_objectHandle, SIGNAL(objectSwitched()), this, |
| SLOT(onStageObjectSwitched())) && |
| ret; |
| ret = connect(m_objectHandle, SIGNAL(objectChanged(bool)), this, |
| SLOT(onStageObjectChanged(bool))) && |
| ret; |
| |
| assert(ret); |
| } |
| |
| FunctionTreeModel *ftModel = |
| static_cast<FunctionTreeModel *>(m_treeView->model()); |
| if (ftModel) ftModel->setObjectHandle(objectHandle); |
| } |
| |
| |
| void FunctionViewer::setFxHandle(TFxHandle *fxHandle) { |
| if (fxHandle == m_fxHandle) return; |
| |
| if (m_fxHandle) m_fxHandle->disconnect(this); |
| |
| m_fxHandle = fxHandle; |
| |
| if (isVisible()) { |
| m_treeView->updateAll(); |
| |
| bool ret = |
| connect(m_fxHandle, SIGNAL(fxSwitched()), this, SLOT(onFxSwitched())); |
| assert(ret); |
| } |
| |
| FunctionTreeModel *ftModel = |
| static_cast<FunctionTreeModel *>(m_treeView->model()); |
| if (ftModel) ftModel->setFxHandle(fxHandle); |
| } |
| |
| |
| |
| void FunctionViewer::setColumnHandle(TColumnHandle *columnHandle) { |
| if (columnHandle == m_columnHandle) return; |
| |
| m_columnHandle = columnHandle; |
| |
| if (isVisible()) m_treeView->updateAll(); |
| } |
| |
| |
| |
| void FunctionViewer::onFrameSwitched() { |
| int frame = m_localFrame.getFrame(); |
| m_segmentViewer->setSegmentByFrame(m_curve, frame); |
| |
| if (m_frameHandle) m_frameHandle->setFrame(frame); |
| } |
| |
| |
| |
| void FunctionViewer::toggleMode() { |
| if (isHidden()) return; |
| |
| if (m_functionGraph->isVisible()) |
| m_functionGraph->hide(); |
| else |
| m_functionGraph->show(); |
| } |
| |
| |
| |
| void FunctionViewer::onCurveChanged(bool isDragging) { |
| if (m_objectHandle) m_objectHandle->notifyObjectIdChanged(isDragging); |
| |
| |
| |
| if (m_fxHandle) { |
| FunctionTreeModel *ftModel = |
| dynamic_cast<FunctionTreeModel *>(m_treeView->model()); |
| if (ftModel) { |
| FunctionTreeModel::Channel *currChan = ftModel->getCurrentChannel(); |
| if (currChan) { |
| |
| FxChannelGroup *fxChanGroup = |
| dynamic_cast<FxChannelGroup *>(currChan->getChannelGroup()); |
| if (fxChanGroup) m_fxHandle->notifyFxChanged(); |
| } |
| } |
| } |
| } |
| |
| |
| |
| void FunctionViewer::onCurveSelected(TDoubleParam *curve) { |
| m_curve = curve; |
| m_toolbar->setCurve(curve); |
| |
| QPair<TDoubleParam *, int> selectedSegment = |
| getSelection()->getSelectedSegment(); |
| if (selectedSegment.first) |
| m_segmentViewer->setSegment(selectedSegment.first, selectedSegment.second); |
| else |
| m_segmentViewer->setSegment(m_curve, -1); |
| } |
| |
| |
| |
| void FunctionViewer::onValueFieldChanged() {} |
| |
| |
| |
| void FunctionViewer::onXsheetChanged() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| int rowCount = xsh->getFrameCount(); |
| m_numericalColumns->setRowCount(rowCount); |
| } |
| |
| |
| |
| void FunctionViewer::onStageObjectSwitched() { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| const TStageObjectId &objId = m_objectHandle->getObjectId(); |
| TStageObject *obj = (objId == TStageObjectId::NoneId) |
| ? (TStageObject *)0 |
| : xsh->getStageObject(objId); |
| |
| static_cast<FunctionTreeModel *>(m_treeView->model()) |
| ->setCurrentStageObject(obj); |
| |
| m_treeView->updateAll(); |
| m_functionGraph->update(); |
| } |
| |
| |
| |
| void FunctionViewer::onStageObjectChanged(bool isDragging) { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| |
| const TStageObjectId &objId = m_objectHandle->getObjectId(); |
| TStageObject *obj = (objId == TStageObjectId::NoneId) |
| ? (TStageObject *)0 |
| : xsh->getStageObject(objId); |
| |
| static_cast<FunctionTreeModel *>(m_treeView->model()) |
| ->setCurrentStageObject(obj); |
| |
| if (!isDragging) m_treeView->updateAll(); |
| |
| m_functionGraph->update(); |
| } |
| |
| |
| |
| void FunctionViewer::onFxSwitched() { |
| TFx *fx = m_fxHandle->getFx(); |
| TZeraryColumnFx *zfx = dynamic_cast<TZeraryColumnFx *>(fx); |
| if (zfx) fx = zfx->getZeraryFx(); |
| static_cast<FunctionTreeModel *>(m_treeView->model())->setCurrentFx(fx); |
| m_treeView->updateAll(); |
| m_functionGraph->update(); |
| } |
| |
| |
| |
| void FunctionViewer::onSelectionChanged() { |
| QPair<TDoubleParam *, int> selectedSegment = |
| getSelection()->getSelectedSegment(); |
| if (selectedSegment.first) { |
| if (selectedSegment.first != m_curve) { |
| m_curve = selectedSegment.first; |
| m_toolbar->setCurve(selectedSegment.first); |
| } |
| m_segmentViewer->setSegment(selectedSegment.first, selectedSegment.second); |
| } else { |
| m_segmentViewer->setSegment(m_curve, -1); |
| } |
| |
| if (m_functionGraph->isVisible() && !m_functionGraph->hasFocus()) |
| m_functionGraph->update(); |
| } |
| |
| |
| |
| void FunctionViewer::doSwitchCurrentObject(TStageObject *obj) { |
| TStageObjectId id = obj->getId(); |
| if (id.isColumn()) |
| m_columnHandle->setColumnIndex(id.getIndex()); |
| else |
| m_objectHandle->setObjectId(id); |
| } |
| |
| |
| |
| void FunctionViewer::doSwitchCurrentFx(TFx *fx) { |
| if (!fx) { |
| m_fxHandle->setFx(0); |
| return; |
| } |
| if (fx->isZerary()) { |
| TXsheet *xsh = m_xshHandle->getXsheet(); |
| int i, columnCount = xsh->getColumnCount(); |
| for (i = 0; i < columnCount; i++) { |
| TXshColumn *column = xsh->getColumn(i); |
| TXshZeraryFxColumn *zfx = |
| dynamic_cast<TXshZeraryFxColumn *>(xsh->getColumn(i)); |
| if (!zfx) continue; |
| if (zfx->getZeraryColumnFx()->getZeraryFx() == fx) { |
| fx = zfx->getZeraryColumnFx(); |
| m_columnHandle->setColumnIndex(i); |
| break; |
| } |
| } |
| } |
| |
| |
| SwatchViewer::suspendRendering(true, false); |
| |
| int columnIndex = fx->getReferenceColumnIndex(); |
| if (columnIndex >= 0) m_columnHandle->setColumnIndex(columnIndex); |
| |
| SwatchViewer::suspendRendering(false); |
| m_fxHandle->setFx(fx); |
| emit editObject(); |
| } |
| |
| |
| |
| void FunctionViewer::propagateExternalSetFrame() { |
| assert(m_frameHandle); |
| m_localFrame.setFrame(m_frameHandle->getFrame()); |
| } |
| |
| |
| |
| void FunctionViewer::addParameter(TParam *parameter, const TFilePath &folder) { |
| static_cast<FunctionTreeModel *>(m_treeView->model()) |
| ->addParameter(parameter, folder); |
| } |
| |
| |
| |
| void FunctionViewer::setFocusColumnsOrGraph() { |
| m_numericalColumns->setFocus(); |
| } |
| |
| |
| |
| void FunctionViewer::clearFocusColumnsAndGraph() { |
| m_functionGraph->clearFocus(); |
| m_numericalColumns->clearFocus(); |
| } |
| |
| |
| |
| bool FunctionViewer::columnsOrGraphHasFocus() { |
| return m_functionGraph->hasFocus() || |
| m_numericalColumns->anyWidgetHasFocus() || |
| m_toolbar->anyWidgetHasFocus() || m_segmentViewer->anyWidgetHasFocus(); |
| } |
| |
| |
| |
| void FunctionViewer::setSceneHandle(TSceneHandle *sceneHandle) { |
| m_sceneHandle = sceneHandle; |
| } |
| |
| |
| |
| bool FunctionViewer::isExpressionPageActive() { |
| return m_segmentViewer->isExpressionPageActive(); |
| } |
| |