// TnzCore includes
#include "tsystem.h"
#include "tstream.h"
#include "tfilepath_io.h"
#include "tfunctorinvoker.h"
// TnzBase incudes
#include "tunit.h"
#include "tparamcontainer.h"
#include "tparamset.h"
#include "tmacrofx.h"
#include "tparamchange.h"
// TnzExt includes
#include "ext/plasticskeleton.h"
// TnzLib includes
#include "toonz/tstageobjecttree.h"
#include "toonz/txsheet.h"
#include "toonz/txsheethandle.h"
#include "toonz/fxdag.h"
#include "toonz/txshzeraryfxcolumn.h"
#include "toonz/tcolumnfx.h"
#include "toonz/tfxhandle.h"
#include "toonz/tobjecthandle.h"
// TnzQt includes
#include "toonzqt/functionviewer.h"
#include "toonzqt/dvdialog.h"
#include "toonzqt/gutil.h"
#include "toonzqt/plasticvertexselection.h"
#include "tw/stringtable.h"
// Qt includes
#include <QMenu>
#include <QAction>
#include <QFileDialog>
#include <QMouseEvent>
#include <QMetaObject>
#include <QColor>
#include <QApplication> // for drag&drop
#include <QDrag>
#include <QMimeData>
#include "toonzqt/functiontreeviewer.h"
//*************************************************************************************
// ChannelGroup specialization definition
//*************************************************************************************
namespace
{
class ParamChannelGroup : public FunctionTreeModel::ParamWrapper, public FunctionTreeModel::ChannelGroup
{
public:
ParamChannelGroup(TParam *param, const wstring &fxId, string ¶mName);
void refresh();
void *getInternalPointer() const;
};
//=============================================================================
class StageObjectChannelGroup : public FunctionTreeModel::ChannelGroup
{
public:
TStageObject *m_stageObject; //!< (not owned) Referenced stage object
FunctionTreeModel::ChannelGroup *m_plasticGroup; //!< (not owned) Eventual plastic channels group
public:
StageObjectChannelGroup(TStageObject *pegbar);
~StageObjectChannelGroup();
QString getShortName() const;
QString getLongName() const;
QString getIdName() const;
void *getInternalPointer() const { return static_cast<void *>(m_stageObject); }
TStageObject *getStageObject() const { return m_stageObject; }
QVariant data(int role) const;
};
//=============================================================================
class SkVDChannelGroup : public FunctionTreeModel::ChannelGroup
{
public:
StageObjectChannelGroup *m_stageObjectGroup; //!< Parent stage object group
const QString *m_vxName; //!< The associated vertex name
public:
SkVDChannelGroup(const QString *vxName, StageObjectChannelGroup *stageGroup)
: ChannelGroup(*vxName), m_stageObjectGroup(stageGroup), m_vxName(vxName) {}
QString getShortName() const { return m_stageObjectGroup->getShortName(); }
QString getLongName() const { return *m_vxName; }
void *getInternalPointer() const { return (void *)m_vxName; }
static inline bool compareStr(const TreeModel::Item *item, const QString &str)
{
const QString &thisStr = static_cast<const SkVDChannelGroup *>(item)->getLongName();
return (QString::localeAwareCompare(thisStr, str) < 0);
}
QVariant data(int role) const;
};
} // namespace
//=============================================================================
//
// ChannelGroup
//
//-----------------------------------------------------------------------------
FunctionTreeModel::ChannelGroup::ChannelGroup(const QString &name)
: m_name(name), m_showFilter(ShowAllChannels)
{
}
//-----------------------------------------------------------------------------
FunctionTreeModel::ChannelGroup::~ChannelGroup()
{
}
//-----------------------------------------------------------------------------
bool FunctionTreeModel::ChannelGroup::isActive() const
{
// Analyze children. If one is active, this is active too.
int c, childCount = getChildCount();
for (c = 0; c != childCount; ++c)
if (static_cast<Item *>(getChild(c))->isActive())
return true;
return false;
}
//-----------------------------------------------------------------------------
bool FunctionTreeModel::ChannelGroup::isAnimated() const
{
// Same for the animated feature, this is animate if any of its children is.
int c, childCount = getChildCount();
for (c = 0; c != childCount; ++c)
if (static_cast<Item *>(getChild(c))->isAnimated())
return true;
return false;
}
//-----------------------------------------------------------------------------
QVariant FunctionTreeModel::ChannelGroup::data(int role) const
{
if (role == Qt::DisplayRole)
return getLongName();
else if (role == Qt::DecorationRole) {
bool animated = isAnimated();
bool active = isActive();
if (active) {
static QIcon folderAnimOpen(":Resources/folderanim_open.png");
static QIcon folderAnimClose(":Resources/folderanim_close.png");
static QIcon folderOpen(":Resources/folder_open.png");
static QIcon folderClose(":Resources/folder_close.png");
return animated ? isOpen() ? folderAnimOpen : folderAnimClose : isOpen() ? folderOpen : folderClose;
} else {
static QIcon folderAnimOpen(":Resources/folderanim_open_off.png");
static QIcon folderAnimClose(":Resources/folderanim_close_off.png");
static QIcon folderOpen(":Resources/folder_open_off.png");
static QIcon folderClose(":Resources/folder_close_off.png");
return animated ? isOpen() ? folderAnimOpen : folderAnimClose : isOpen() ? folderOpen : folderClose;
}
} else
return Item::data(role);
}
//-----------------------------------------------------------------------------
//! \todo This is \a not recursive - I guess it should be...?
void FunctionTreeModel::ChannelGroup::applyShowFilter()
{
int i, itemCount = getChildCount();
for (i = 0; i < itemCount; i++) {
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(getChild(i));
/*--- ChannelGroupの内部も同じフィルタで更新する ---*/
if (!channel) {
FunctionTreeModel::ChannelGroup *channelGroup =
dynamic_cast<FunctionTreeModel::ChannelGroup *>(getChild(i));
if (!channelGroup)
continue;
channelGroup->setShowFilter(m_showFilter);
continue;
}
bool showItem =
(m_showFilter == ShowAllChannels) || channel->getParam()->hasKeyframes();
QModelIndex modelIndex = createIndex();
getModel()->setRowHidden(i, modelIndex, !showItem);
if (!showItem)
channel->setIsActive(false);
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::ChannelGroup::setShowFilter(ShowFilter showFilter)
{
m_showFilter = showFilter;
applyShowFilter();
}
//-----------------------------------------------------------------------------
QString FunctionTreeModel::ChannelGroup::getIdName() const
{
QString tmpName = QString(m_name);
tmpName.remove(QChar(' '), Qt::CaseInsensitive);
tmpName = tmpName.toLower();
FunctionTreeModel::ChannelGroup *parentGroup =
dynamic_cast<FunctionTreeModel::ChannelGroup *>(getParent());
if (parentGroup) {
return parentGroup->getIdName() + QString(".") + tmpName;
}
return tmpName;
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::ChannelGroup::setChildrenAllActive(bool active)
{
for (int i = 0; i < getChildCount(); i++) {
//for Channel
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(getChild(i));
if (channel) {
channel->setIsActive(active);
continue;
}
//for ChannelGroup
else {
FunctionTreeModel::ChannelGroup *channelGroup = dynamic_cast<FunctionTreeModel::ChannelGroup *>(getChild(i));
if (channelGroup) {
channelGroup->setChildrenAllActive(active);
continue;
}
}
}
}
//=============================================================================
//
// StageObjectChannelGroup
//
//-----------------------------------------------------------------------------
StageObjectChannelGroup::StageObjectChannelGroup(TStageObject *stageObject)
: m_stageObject(stageObject), m_plasticGroup()
{
m_stageObject->addRef();
}
//-----------------------------------------------------------------------------
StageObjectChannelGroup::~StageObjectChannelGroup()
{
m_stageObject->release();
}
//-----------------------------------------------------------------------------
QVariant StageObjectChannelGroup::data(int role) const
{
if (role == Qt::DisplayRole) {
string name = m_stageObject->getName();
string id = m_stageObject->getId().toString();
return (name == id) ? QString::fromStdString(name) : QString::fromStdString(id + " (" + name + ")");
} else if (role == Qt::ForegroundRole) {
FunctionTreeModel *model = dynamic_cast<FunctionTreeModel *>(getModel());
if (!model)
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
FunctionTreeView *view = dynamic_cast<FunctionTreeView *>(model->getView());
if (!view || !model->getCurrentStageObject())
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
TStageObjectId currentId = model->getCurrentStageObject()->getId();
return m_stageObject->getId() == currentId ? view->getCurrentTextColor() : view->getTextColor();
} else
return ChannelGroup::data(role);
}
//-----------------------------------------------------------------------------
QString StageObjectChannelGroup::getShortName() const
{
return QString::fromStdString(m_stageObject->getName());
}
//-----------------------------------------------------------------------------
QString StageObjectChannelGroup::getLongName() const
{
return QString::fromStdString(m_stageObject->getFullName());
}
//-----------------------------------------------------------------------------
QString StageObjectChannelGroup::getIdName() const
{
return QString::fromStdString(m_stageObject->getId().toString()).toLower();
}
//=============================================================================
//
// FxChannelGroup
//
//-----------------------------------------------------------------------------
FxChannelGroup::FxChannelGroup(TFx *fx)
: m_fx(fx)
{
if (m_fx)
m_fx->addRef();
}
//-----------------------------------------------------------------------------
FxChannelGroup::~FxChannelGroup()
{
if (m_fx)
m_fx->release();
m_fx = 0;
}
//-----------------------------------------------------------------------------
QString FxChannelGroup::getShortName() const
{
return QString::fromStdWString(m_fx->getFxId());
}
//-----------------------------------------------------------------------------
QString FxChannelGroup::getLongName() const
{
return QString::fromStdWString(m_fx->getFxId());
}
//-----------------------------------------------------------------------------
QVariant FxChannelGroup::data(int role) const
{
if (role == Qt::DecorationRole) {
bool isAnimated = false;
TParamContainer *paramContainer = m_fx->getParams();
int i;
for (i = 0; i < paramContainer->getParamCount(); i++) {
if (!paramContainer->getParam(i)->hasKeyframes())
continue;
isAnimated = true;
break;
}
bool isOneChildActive = false;
for (i = 0; i < getChildCount(); i++) {
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(getChild(i));
if (!channel || !channel->isActive())
continue;
isOneChildActive = true;
break;
}
if (isOneChildActive) {
static QIcon folderAnimOpen(":Resources/folderanim_open.png");
static QIcon folderAnimClose(":Resources/folderanim_close.png");
static QIcon folderOpen(":Resources/folder_open.png");
static QIcon folderClose(":Resources/folder_close.png");
return isAnimated ? isOpen() ? folderAnimOpen : folderAnimClose : isOpen() ? folderOpen : folderClose;
} else {
static QIcon folderAnimOpen(":Resources/folderanim_open_off.png");
static QIcon folderAnimClose(":Resources/folderanim_close_off.png");
static QIcon folderOpen(":Resources/folder_open_off.png");
static QIcon folderClose(":Resources/folder_close_off.png");
return isAnimated ? isOpen() ? folderAnimOpen : folderAnimClose : isOpen() ? folderOpen : folderClose;
}
} else if (role == Qt::DisplayRole) {
wstring name = m_fx->getName();
wstring id = m_fx->getFxId();
if (name == id)
return QString::fromStdWString(name);
else
return QString::fromStdWString(id + L" (" + name + L")");
} else if (role == Qt::ForegroundRole) {
FunctionTreeModel *model = dynamic_cast<FunctionTreeModel *>(getModel());
if (!model)
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
FunctionTreeView *view = dynamic_cast<FunctionTreeView *>(model->getView());
if (!view)
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
TFx *currentFx = model->getCurrentFx();
return m_fx == currentFx ? view->getCurrentTextColor() : view->getTextColor();
} else
return Item::data(role);
}
//-----------------------------------------------------------------------------
QString FxChannelGroup::getIdName() const
{
return QString::fromStdWString(m_fx->getFxId()).toLower();
}
//-----------------------------------------------------------------------------
void FxChannelGroup::refresh()
{
TMacroFx *macroFx = dynamic_cast<TMacroFx *>(m_fx);
int i, childrenCount = getChildCount();
for (i = 0; i < childrenCount; ++i) {
FunctionTreeModel::ParamWrapper *wrap =
dynamic_cast<FunctionTreeModel::ParamWrapper *>(getChild(i));
assert(wrap);
TParam *param = 0;
{
TParamContainer *paramContainer = 0;
if (macroFx) {
const wstring &fxId = wrap->getFxId();
TFx *subFx = macroFx->getFxById(fxId);
if (!subFx)
continue;
paramContainer = subFx->getParams();
} else
paramContainer = m_fx->getParams();
param = paramContainer->getParam(wrap->getParam()->getName());
}
assert(param);
wrap->setParam(param);
ParamChannelGroup *paramGroup = dynamic_cast<ParamChannelGroup *>(wrap);
if (paramGroup)
paramGroup->refresh();
}
}
//=============================================================================
//
// ParamChannelGroup
//
//-----------------------------------------------------------------------------
ParamChannelGroup::ParamChannelGroup(TParam *param, const wstring &fxId, string ¶mName)
: ParamWrapper(param, fxId), ChannelGroup(param->hasUILabel() ? QString::fromStdString(param->getUILabel()) : QString::fromStdWString(TStringTable::translate(paramName)))
{
}
//-----------------------------------------------------------------------------
void *ParamChannelGroup::getInternalPointer() const
{
return this->m_param.getPointer();
}
//-----------------------------------------------------------------------------
void ParamChannelGroup::refresh()
{
TParamSet *paramSet = dynamic_cast<TParamSet *>(m_param.getPointer());
if (!paramSet)
return;
int c, childrenCount = getChildCount();
for (c = 0; c < childrenCount; ++c) {
FunctionTreeModel::ParamWrapper *wrap =
dynamic_cast<FunctionTreeModel::ParamWrapper *>(getChild(c));
assert(wrap);
TParamP currentParam = wrap->getParam();
assert(currentParam);
int p = paramSet->getParamIdx(wrap->getParam()->getName());
assert(p < paramSet->getParamCount());
TParamP param = paramSet->getParam(p);
wrap->setParam(param);
}
}
//=============================================================================
//
// SkVDChannelGroup
//
//-----------------------------------------------------------------------------
QVariant SkVDChannelGroup::data(int role) const
{
if (role == Qt::ForegroundRole) {
// Check whether current selection is a PlasticVertex one - in case, paint it red
// if this group refers to current vertex
if (PlasticVertexSelection *vxSel = dynamic_cast<PlasticVertexSelection *>(TSelection::getCurrent()))
if (TStageObject *obj = static_cast<FunctionTreeModel *>(getModel())->getCurrentStageObject())
if (obj == m_stageObjectGroup->m_stageObject)
if (const SkDP &sd = obj->getPlasticSkeletonDeformation()) {
int vIdx = *vxSel;
if (vIdx >= 0 && sd->skeleton(vxSel->skeletonId())->vertex(vIdx).name() == getLongName())
#if QT_VERSION >= 0x050000
return QColor(Qt::red);
#else
return Qt::red;
#endif
}
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
} else
return ChannelGroup::data(role);
}
//=============================================================================
//
// Channel
//
//-----------------------------------------------------------------------------
FunctionTreeModel::Channel::Channel(FunctionTreeModel *model, TDoubleParam *param,
string paramNamePref, wstring fxId)
: ParamWrapper(param, fxId), m_model(model), m_group(0), m_isActive(false), m_paramNamePref(paramNamePref)
{
}
//-----------------------------------------------------------------------------
FunctionTreeModel::Channel::~Channel()
{
m_model->onChannelDestroyed(this);
if (m_isActive)
getParam()->removeObserver(this);
}
//-----------------------------------------------------------------------------
void *FunctionTreeModel::Channel::getInternalPointer() const
{
return this->m_param.getPointer();
}
//-----------------------------------------------------------------------------
bool FunctionTreeModel::Channel::isAnimated() const
{
return m_param->hasKeyframes();
}
//-----------------------------------------------------------------------------
QVariant FunctionTreeModel::Channel::data(int role) const
{
if (role == Qt::DecorationRole) {
static QIcon paramAnimOn(":Resources/paramanim_on.png");
static QIcon paramAnimOff(":Resources/paramanim_off.png");
static QIcon paramOn(":Resources/param_on.png");
static QIcon paramOff(":Resources/param_off.png");
return m_param->hasKeyframes() ? isActive() ? paramAnimOn : paramAnimOff : isActive() ? paramOn : paramOff;
} else if (role == Qt::DisplayRole) {
if (m_param->hasUILabel()) {
return QString::fromStdString(m_param->getUILabel());
}
string name = m_paramNamePref + m_param->getName();
wstring translatedName = TStringTable::translate(name);
if (m_fxId.size() > 0)
return QString::fromStdWString(translatedName + L" (" + m_fxId + L")");
return QString::fromStdWString(translatedName);
} else if (role == Qt::ForegroundRole) {
//130221 iwasawa
FunctionTreeView *view = dynamic_cast<FunctionTreeView *>(m_model->m_view);
if (!view)
#if QT_VERSION >= 0x050000
return QColor(Qt::black);
#else
return Qt::black;
#endif
return (isCurrent()) ? view->getCurrentTextColor() : view->getTextColor();
} else
return TreeModel::Item::data(role);
}
//-----------------------------------------------------------------------------
QString FunctionTreeModel::Channel::getShortName() const
{
if (m_param->hasUILabel()) {
return QString::fromStdString(m_param->getUILabel());
}
string name = m_paramNamePref + m_param->getName();
wstring translatedName = TStringTable::translate(name);
return QString::fromStdWString(translatedName);
}
//-----------------------------------------------------------------------------
QString FunctionTreeModel::Channel::getLongName() const
{
QString name = getShortName();
if (getChannelGroup())
name = getChannelGroup()->getLongName() + " " + name;
return name;
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::Channel::setParam(const TParamP ¶m)
{
if (param.getPointer() == m_param.getPointer())
return;
TParamP oldParam = m_param;
m_param = param;
if (m_isActive) {
oldParam->removeObserver(this);
param->addObserver(this);
}
}
//-----------------------------------------------------------------------------
/*! in order to show the expression name in the tooltip
*/
QString FunctionTreeModel::Channel::getExprRefName() const
{
QString tmpName =
QString(QString::fromStdWString(
TStringTable::translate(m_paramNamePref + m_param->getName())));
/*--- stage objectパラメータの場合、TableにあわせてtmpNameを代表的なExpression名にする---*/
StageObjectChannelGroup *stageGroup =
dynamic_cast<StageObjectChannelGroup *>(m_group);
if (stageGroup) {
if (tmpName == "N/S")
tmpName = "ns";
else if (tmpName == "E/W")
tmpName = "ew";
else if (tmpName == "Z")
tmpName = "z";
else if (tmpName == "Rotation")
tmpName = "rot";
else if (tmpName == "Scale H")
tmpName = "sx";
else if (tmpName == "Scale V")
tmpName = "sy";
else if (tmpName == "Shear H")
tmpName = "shx";
else if (tmpName == "Shear V")
tmpName = "shy";
else if (tmpName == "posPath")
tmpName = "path";
else if (tmpName == "Scale")
tmpName = "sc";
else
tmpName = tmpName.toLower();
return stageGroup->getIdName() + QString(".") + tmpName;
}
/*--- Fxパラメータの場合 ---*/
tmpName.remove(QChar(' '), Qt::CaseInsensitive);
tmpName.remove(QChar('/'));
tmpName = tmpName.toLower();
FunctionTreeModel::ChannelGroup *parentGroup =
dynamic_cast<FunctionTreeModel::ChannelGroup *>(getParent());
if (parentGroup) {
return QString("fx.") + parentGroup->getIdName() + QString(".") + tmpName;
} else
return "";
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::Channel::setIsActive(bool active)
{
if (active == m_isActive)
return;
m_isActive = active;
m_model->refreshActiveChannels();
if (m_isActive) {
getParam()->addObserver(this);
/*--- これが最初にVisibleにしたChannelの場合 ---*/
if (!m_model->m_currentChannel) {
setIsCurrent(true);
m_model->emitCurveSelected(getParam());
}
} else {
getParam()->removeObserver(this);
if (isCurrent()) {
setIsCurrent(false);
m_model->emitCurveSelected(0);
}
}
m_model->emitDataChanged(this);
}
//-----------------------------------------------------------------------------
bool FunctionTreeModel::Channel::isCurrent() const
{
return m_model->m_currentChannel == this;
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::Channel::setIsCurrent(bool current)
{
Channel *oldCurrent = m_model->m_currentChannel;
if (current) {
// this channel must become the current
if (oldCurrent == this)
return; // already it is: nothing to do
m_model->m_currentChannel = this;
//change the current fx if the FxChannelGroup is clicked
FxChannelGroup *fxGroup = dynamic_cast<FxChannelGroup *>(m_group);
if (fxGroup && m_model->getFxHandle()) {
m_model->getFxHandle()->setFx(fxGroup->getFx());
}
//or, change the current object if the stageObjectChannelGroup is clicked
else {
StageObjectChannelGroup *stageObjectGroup = dynamic_cast<StageObjectChannelGroup *>(m_group);
if (stageObjectGroup && m_model->getObjectHandle()) {
m_model->getObjectHandle()->setObjectId(stageObjectGroup->getStageObject()->getId());
}
}
// the current channel must be active
if (!m_isActive) {
m_isActive = true;
m_model->refreshActiveChannels();
getParam()->addObserver(this);
}
// refresh the old current (if !=0) and the new one
if (oldCurrent)
m_model->emitDataChanged(oldCurrent);
m_model->emitDataChanged(this);
m_model->emitCurveSelected(getParam());
//scroll the column to ensure visible the current channel
m_model->emitCurrentChannelChanged(this);
} else {
// this channel is not the current anymore
if (oldCurrent != this)
return; // it was not: nothing to do
m_model->m_currentChannel = 0;
// refresh the channel
m_model->emitDataChanged(this);
}
}
//-----------------------------------------------------------------------------
bool FunctionTreeModel::Channel::isHidden() const
{
return getChannelGroup()->getShowFilter() == ChannelGroup::ShowAnimatedChannels &&
!getParam()->hasKeyframes();
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::Channel::onChange(const TParamChange &ch)
{
m_model->onChange(ch);
}
//=============================================================================
//
// FunctionTreeModel
//
//-----------------------------------------------------------------------------
FunctionTreeModel::FunctionTreeModel(FunctionTreeView *parent)
: TreeModel(parent), m_currentChannel(0), m_stageObjects(0), m_fxs(0), m_currentStageObject(0), m_currentFx(0), m_paramsChanged(false)
{
}
//-----------------------------------------------------------------------------
FunctionTreeModel::~FunctionTreeModel()
{
// I must delete items here (not in TreeModel::~TreeModel()).
// Channel::~Channel() refers to the model, which should be alive.
setRootItem(0);
if (m_currentFx)
m_currentFx->release();
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::refreshData(TXsheet *xsh)
{
m_activeChannels.clear();
Channel *currentChannel = m_currentChannel;
beginRefresh();
{
if (!getRootItem()) {
setRootItem(new ChannelGroup("Root"));
if (xsh) {
getRootItem()->appendChild(m_stageObjects = new ChannelGroup("Stage"));
getRootItem()->appendChild(m_fxs = new ChannelGroup("FX"));
assert(getRootItem()->getChildCount() == 2);
assert(getRootItem()->getChild(0) == m_stageObjects);
assert(getRootItem()->getChild(1) == m_fxs);
}
}
if (xsh) {
refreshStageObjects(xsh);
refreshFxs(xsh);
}
refreshActiveChannels();
}
endRefresh();
if (m_currentChannel != currentChannel)
emit curveSelected(0);
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::refreshStageObjects(TXsheet *xsh)
{
static const int channelIds[TStageObject::T_ChannelCount] = {
TStageObject::T_X,
TStageObject::T_Y,
TStageObject::T_Z,
TStageObject::T_SO,
TStageObject::T_Path,
TStageObject::T_Angle,
TStageObject::T_ScaleX,
TStageObject::T_ScaleY,
TStageObject::T_Scale,
TStageObject::T_ShearX,
TStageObject::T_ShearY}; // Explicitly ordered channels
// Retrieve all (not-empty) root stage objects, and add them in the tree model
QList<TreeModel::Item *> newItems;
TStageObjectTree *ptree = xsh->getStageObjectTree();
int i, iCount = ptree->getStageObjectCount();
for (i = 0; i < iCount; ++i) {
TStageObject *pegbar = ptree->getStageObject(i);
TStageObjectId id = pegbar->getId();
if (id.isColumn() && xsh->isColumnEmpty(id.getIndex()))
continue;
newItems.push_back(new StageObjectChannelGroup(pegbar));
}
/*--- newItemsの中で、これまでのChildrenに無いものだけ
m_stageObjectsの子に追加。既に有るものはnewChildrenから除外---*/
m_stageObjects->setChildren(newItems);
// Add channels to the NEW stage entries (see the above call to setChildren())
iCount = newItems.size();
for (i = 0; i < iCount; ++i) {
StageObjectChannelGroup *pegbarItem =
dynamic_cast<StageObjectChannelGroup *>(newItems[i]);
TStageObject *stageObject = pegbarItem->getStageObject();
// Add the standard stage object channels
int j, jCount = TStageObject::T_ChannelCount;
// making each channel of pegbar
for (j = 0; j < jCount; ++j) {
TDoubleParam *param = stageObject->getParam((TStageObject::Channel)channelIds[j]);
Channel *channel = new Channel(this, param);
pegbarItem->appendChild(channel);
channel->setChannelGroup(pegbarItem);
}
pegbarItem->applyShowFilter();
}
// As plastic deformations are stored in stage objects, refresh them if necessary
refreshPlasticDeformations();
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::refreshFxs(TXsheet *xsh)
{
std::vector<TFx *> fxs;
xsh->getFxDag()->getFxs(fxs);
for (int i = 0; i < xsh->getColumnCount(); i++) {
TXshZeraryFxColumn *zc =
dynamic_cast<TXshZeraryFxColumn *>(xsh->getColumn(i));
if (!zc)
continue;
fxs.push_back(zc->getZeraryColumnFx()->getZeraryFx());
}
//sort items by fxId
for (int j = 1; j < (int)fxs.size(); j++) {
int index = j;
while (index > 0 && QString::localeAwareCompare(QString::fromStdWString(fxs[index - 1]->getFxId()), QString::fromStdWString(fxs[index]->getFxId())) > 0) {
std::swap(fxs[index - 1], fxs[index]);
index = index - 1;
}
}
QList<TreeModel::Item *> newItems;
int i;
for (i = 0; i < (int)fxs.size(); i++) {
TFx *fx = fxs[i];
if (!fx)
continue;
TParamContainer *params = fx->getParams();
bool hasChannel = false;
int j;
for (j = 0; j < params->getParamCount(); j++)
if (0 != dynamic_cast<TDoubleParam *>(params->getParam(j)) ||
0 != dynamic_cast<TPointParam *>(params->getParam(j)) ||
0 != dynamic_cast<TRangeParam *>(params->getParam(j)) ||
0 != dynamic_cast<TPixelParam *>(params->getParam(j))) {
hasChannel = true;
break;
}
if (hasChannel)
newItems.push_back(new FxChannelGroup(fxs[i]));
}
m_fxs->setChildren(newItems);
// Add channels to new fxs (only for those actually added: see setChildren())
for (i = 0; i < (int)newItems.size(); i++) {
TreeModel::Item *item = newItems[i];
FxChannelGroup *fxItem = dynamic_cast<FxChannelGroup *>(item);
assert(fxItem);
if (!fxItem)
continue;
TFx *fx = fxItem->getFx();
assert(fx);
if (!fx)
continue;
TMacroFx *macroFx = dynamic_cast<TMacroFx *>(fx);
if (macroFx) {
const vector<TFxP> ¯oFxs = macroFx->getFxs();
int j;
for (j = 0; j < (int)macroFxs.size(); j++) {
TParamContainer *params = macroFxs[j]->getParams();
addChannels(macroFxs[j].getPointer(), fxItem, params);
}
} else {
TParamContainer *params = fx->getParams();
addChannels(fx, fxItem, params);
}
fxItem->applyShowFilter();
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::refreshPlasticDeformations()
{
// Refresh ALL stage object items (including OLD ones)
int i, iCount = m_stageObjects->getChildCount();
for (i = 0; i < iCount; ++i) {
// Add the eventual Plastic channels group
StageObjectChannelGroup *stageItem =
static_cast<StageObjectChannelGroup *>(m_stageObjects->getChild(i));
TStageObject *stageObject = stageItem->getStageObject();
const PlasticSkeletonDeformationP &sd = stageObject->getPlasticSkeletonDeformation();
FunctionTreeModel::ChannelGroup *&plasticGroup = stageItem->m_plasticGroup;
if (sd || plasticGroup) {
if (!plasticGroup) {
// Add a group
plasticGroup = new ChannelGroup("Plastic Skeleton");
stageItem->appendChild(plasticGroup);
}
// Prepare each vertex deformation
QList<TreeModel::Item *> plasticItems;
if (sd) {
SkD::vd_iterator vdt, vdEnd;
sd->vertexDeformations(vdt, vdEnd);
for (; vdt != vdEnd; ++vdt) {
const QString *str = (*vdt).first;
QList<TreeModel::Item *>::iterator it = std::lower_bound(
plasticItems.begin(), plasticItems.end(),
*str, SkVDChannelGroup::compareStr);
plasticItems.insert(it, new SkVDChannelGroup(str, stageItem));
}
// Add the channel corresponding to the skeleton id
{
Channel *skelIdsChannel = new Channel(this, sd->skeletonIdsParam().getPointer());
plasticItems.insert(plasticItems.begin(), skelIdsChannel);
skelIdsChannel->setChannelGroup(plasticGroup);
}
}
if (plasticItems.empty())
plasticGroup->setIsOpen(false);
// Add the vertex deformations group (this needs to be done BEFORE adding the actual
// channels, seemingly due to a limitation in the TreeModel implementation)
plasticGroup->setChildren(plasticItems);
int pi, piCount = plasticItems.size(); // NOTE: plasticItems now stores only PART
for (pi = 0; pi != piCount; ++pi) // of the specified items - those considered
{ // 'new' by internal pointer comparison...
SkVDChannelGroup *vxGroup = dynamic_cast<SkVDChannelGroup *>(plasticItems[pi]);
if (!vxGroup)
continue;
SkVD *skvd = sd->vertexDeformation(vxGroup->ChannelGroup::getShortName());
for (int k = 0; k < SkVD::PARAMS_COUNT; ++k) {
// Add channel in the vertex deformation
Channel *channel = new Channel(this, skvd->m_params[k].getPointer());
channel->setChannelGroup(vxGroup);
vxGroup->appendChild(channel);
}
vxGroup->applyShowFilter();
}
plasticGroup->applyShowFilter();
}
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::addParameter(
ChannelGroup *group,
const std::string &prefixString,
const std::wstring &fxId,
TParam *param)
{
if (TDoubleParam *dp = dynamic_cast<TDoubleParam *>(param)) {
Channel *channel = new Channel(this, dp, prefixString, fxId);
group->appendChild(channel);
channel->setChannelGroup(group);
} else if (dynamic_cast<TPointParam *>(param) ||
dynamic_cast<TRangeParam *>(param) ||
dynamic_cast<TPixelParam *>(param)) {
TParamSet *paramSet = dynamic_cast<TParamSet *>(param);
assert(paramSet);
std::string paramName = prefixString + param->getName();
ChannelGroup *paramChannel = new ParamChannelGroup(param, fxId, paramName);
group->appendChild(paramChannel);
TPixelParam *pixParam = dynamic_cast<TPixelParam *>(param);
int p, paramCount = paramSet->getParamCount();
for (p = 0; p != paramCount; ++p) {
TDoubleParam *dp = dynamic_cast<TDoubleParam *>(paramSet->getParam(p).getPointer());
if (!dp || (pixParam && !pixParam->isMatteEnabled() && p == paramCount - 1))
continue;
Channel *channel = new Channel(this, dp, "", fxId);
paramChannel->appendChild(channel);
channel->setChannelGroup(group);
}
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::addChannels(TFx *fx, ChannelGroup *groupItem, TParamContainer *params)
{
FxChannelGroup *fxItem = static_cast<FxChannelGroup *>(groupItem);
wstring fxId = L"";
TMacroFx *macro = dynamic_cast<TMacroFx *>(fxItem->getFx());
if (macro)
fxId = fx->getFxId();
const string ¶mNamePref = fx->getFxType() + ".";
int p, pCount = params->getParamCount();
for (p = 0; p != pCount; ++p)
addParameter(fxItem, paramNamePref, fxId, params->getParam(p));
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::addActiveChannels(TreeModel::Item *item)
{
assert(item);
if (Channel *channel = dynamic_cast<Channel *>(item)) {
if (channel->isActive())
m_activeChannels.push_back(channel);
} else
for (int i = 0; i < item->getChildCount(); i++)
addActiveChannels(item->getChild(i));
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::refreshActiveChannels()
{
m_activeChannels.clear();
if (m_stageObjects)
addActiveChannels(m_stageObjects);
if (m_fxs)
addActiveChannels(m_fxs);
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::onChannelDestroyed(Channel *channel)
{
if (channel == m_currentChannel)
m_currentChannel = 0;
}
//-----------------------------------------------------------------------------
FunctionTreeModel::Channel *FunctionTreeModel::getActiveChannel(int index) const
{
if (index < 0 || index >= (int)m_activeChannels.size())
return 0;
else
return m_activeChannels[index];
}
//-----------------------------------------------------------------------------
int FunctionTreeModel::getColumnIndexByCurve(TDoubleParam *param) const
{
for (int i = 0; i < (int)m_activeChannels.size(); i++) {
if (m_activeChannels[i]->getParam() == param)
return i;
}
return -1;
}
//-----------------------------------------------------------------------------
FunctionTreeModel::ChannelGroup *FunctionTreeModel::getStageObjectChannel(int index) const
{
if (index < 0 || index >= (int)m_stageObjects->getChildCount())
return 0;
else
return dynamic_cast<FunctionTreeModel::ChannelGroup *>(m_stageObjects->getChild(index));
}
//-----------------------------------------------------------------------------
FunctionTreeModel::ChannelGroup *FunctionTreeModel::getFxChannel(int index) const
{
if (index < 0 || index >= (int)m_fxs->getChildCount())
return 0;
else
return dynamic_cast<FunctionTreeModel::ChannelGroup *>(m_fxs->getChild(index));
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::onChange(const TParamChange &tpc)
{
if (!m_paramsChanged) {
m_paramsChanged = true;
struct Func : public TFunctorInvoker::BaseFunctor {
FunctionTreeModel *m_obj;
const TParamChange *m_tpc;
Func(FunctionTreeModel *obj, const TParamChange *tpc) : m_obj(obj), m_tpc(tpc) {}
void operator()() { m_obj->onParamChange(m_tpc->m_dragging); }
};
QMetaObject::invokeMethod(TFunctorInvoker::instance(), "invoke", Qt::QueuedConnection,
Q_ARG(void *, new Func(this, &tpc)));
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::onParamChange(bool isDragging)
{
m_paramsChanged = false;
emit curveChanged(isDragging);
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::resetAll()
{
#if QT_VERSION >= 0x050000
beginResetModel();
#endif
m_activeChannels.clear();
setRootItem(0);
m_stageObjects = 0;
m_fxs = 0;
#if QT_VERSION < 0x050000
reset();
#endif
beginRefresh();
refreshActiveChannels();
endRefresh();
m_currentChannel = 0;
#if QT_VERSION >= 0x050000
endResetModel();
#endif
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::setCurrentFx(TFx *fx)
{
TZeraryColumnFx *zcfx = dynamic_cast<TZeraryColumnFx *>(fx);
if (zcfx)
fx = zcfx->getZeraryFx();
if (fx != m_currentFx) {
if (fx)
fx->addRef();
if (m_currentFx)
m_currentFx->release();
m_currentFx = fx;
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::applyShowFilters()
{
// WARNING: This is implemented BAD - notice that the get*() functions below
// DO NOT ACTUALLY RETURN CHANNELS, but rather the child ChannelGROUPS!
//
// This means that these show filters are presumably applied only to
// the FIRST LEVEL OF PARAMETERS...!
if (m_stageObjects) {
int so, soCount = m_stageObjects->getChildCount();
for (so = 0; so != soCount; ++so)
getStageObjectChannel(so)->applyShowFilter();
}
if (m_fxs) {
int fx, fxCount = m_fxs->getChildCount();
for (fx = 0; fx != fxCount; ++fx)
getFxChannel(fx)->applyShowFilter();
}
}
//-----------------------------------------------------------------------------
void FunctionTreeModel::addParameter(
TParam *parameter, const TFilePath &folder)
{
struct locals {
static void locateExistingRoot(ChannelGroup *&root, TFilePath &fp)
{
std::wstring firstName;
TFilePath tempFp;
while (!fp.isEmpty()) {
// Get the path's first name
fp.split(firstName, tempFp);
// Search a matching channel group in root's children
int c, cCount = root->getChildCount();
for (c = 0; c != cCount; ++c) {
if (ChannelGroup *group = dynamic_cast<ChannelGroup *>(root->getChild(c))) {
if (group->getShortName().toStdWString() == firstName) {
root = group, fp = tempFp;
break;
}
}
}
if (c == cCount)
break;
}
}
static void addFolders(ChannelGroup *&group, TFilePath &fp)
{
std::wstring firstName;
TFilePath tempFp;
while (!fp.isEmpty()) {
fp.split(firstName, tempFp);
ChannelGroup *newGroup = new ChannelGroup(QString::fromStdWString(firstName));
group->appendChild(newGroup);
group = newGroup, fp = tempFp;
}
}
}; // locals
// Search for the furthest existing channel group chain leading to our folder
ChannelGroup *group = static_cast<ChannelGroup *>(getRootItem());
assert(group);
TFilePath path = folder;
locals::locateExistingRoot(group, path);
// If the chain interrupts prematurely, create new groups up to the required folder
if (!path.isEmpty())
locals::addFolders(group, path);
assert(path.isEmpty());
// Add the parameter to the last group
addParameter(group, "", L"", parameter);
}
//=============================================================================
//
// FunctionTreeView
//
//-----------------------------------------------------------------------------
FunctionTreeView::FunctionTreeView(FunctionViewer *parent)
: TreeView(parent), m_scenePath(), m_clickedItem(0), m_draggingChannel(0)
{
assert(parent);
setModel(new FunctionTreeModel(this));
setObjectName("FunctionEditorTree");
setSelectionMode(QAbstractItemView::NoSelection);
connect(
this, SIGNAL(pressed(const QModelIndex &)),
this, SLOT(onActivated(const QModelIndex &)));
setFocusPolicy(Qt::NoFocus);
setIndentation(14);
setAlternatingRowColors(true);
}
//-----------------------------------------------------------------------------
void FunctionTreeView::onActivated(const QModelIndex &index)
{
enum {
NO_CHANNELS = 0x0,
ACTIVE_CHANNELS = 0x1,
INACTIVE_CHANNELS = 0x2,
HAS_CHANNELS = ACTIVE_CHANNELS | INACTIVE_CHANNELS
};
if (!index.isValid())
return;
FunctionTreeModel *ftModel = (FunctionTreeModel *)model();
if (!ftModel)
return;
std::vector<FunctionTreeModel::Channel *> childChannels;
std::vector<FunctionTreeModel::ChannelGroup *> channelGroups;
// Scan for already active children - to decide whether to activate or deactivate them
int activeFlag = NO_CHANNELS;
TreeModel::Item *item = static_cast<TreeModel::Item *>(index.internalPointer());
if (item) {
int c, cCount = item->getChildCount();
for (c = 0; c != cCount; ++c) {
FunctionTreeModel::Channel *channel =
dynamic_cast<FunctionTreeModel::Channel *>(item->getChild(c));
if (!channel) {
FunctionTreeModel::ChannelGroup *channelGroup =
dynamic_cast<FunctionTreeModel::ChannelGroup *>(item->getChild(c));
if (!channelGroup)
continue;
channelGroups.push_back(channelGroup);
continue;
}
if (channel->isHidden())
continue;
childChannels.push_back(channel);
activeFlag |= (channel->isActive() ? ACTIVE_CHANNELS : INACTIVE_CHANNELS);
}
}
// Open the item (ie show children) if it was closed AND not all its children were active
bool someInactiveChannels = (activeFlag != ACTIVE_CHANNELS);
if (someInactiveChannels && !isExpanded(index)) {
setExpanded(index, true);
ftModel->onExpanded(index);
}
if (item) {
if (!childChannels.empty()) {
// Activate child channels if there is some inactive channel - deactivate otherwise
int c, cCount = childChannels.size();
for (c = 0; c != cCount; ++c)
childChannels[c]->setIsActive(someInactiveChannels);
for (int i = 0; i < (int)channelGroups.size(); i++)
channelGroups[i]->setChildrenAllActive(someInactiveChannels);
update();
} else {
// There was no child channel. Try to activate children groups.
int c, cCount = item->getChildCount();
for (c = 0; c != cCount; ++c)
onActivated(item->getChild(c)->createIndex());
}
}
}
//-----------------------------------------------------------------------------
void FunctionTreeView::onClick(TreeModel::Item *item, const QPoint &itemPos, QMouseEvent *e)
{
m_draggingChannel = 0;
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(item);
FxChannelGroup *fxChannelGroup = dynamic_cast<FxChannelGroup *>(item);
StageObjectChannelGroup *stageObjectChannelGroup = dynamic_cast<StageObjectChannelGroup *>(item);
m_clickedItem = channel;
if (channel) {
fxChannelGroup = dynamic_cast<FxChannelGroup *>(channel->getParent());
stageObjectChannelGroup = dynamic_cast<StageObjectChannelGroup *>(channel->getParent());
int x = itemPos.x();
if (x >= 20)
channel->setIsCurrent(true);
else if (0 <= x && x < 20) {
channel->setIsActive((e->button() == Qt::RightButton) ? true : !channel->isActive());
update();
}
}
if (fxChannelGroup) {
TFx *fx = fxChannelGroup->getFx();
emit switchCurrentFx(fx);
}
if (stageObjectChannelGroup) {
TStageObject *obj = stageObjectChannelGroup->getStageObject();
emit switchCurrentObject(obj);
}
}
//-----------------------------------------------------------------------------
void FunctionTreeView::onMidClick(TreeModel::Item *item, const QPoint &itemPos, QMouseEvent *e)
{
FunctionTreeModel::Channel *channel =
dynamic_cast<FunctionTreeModel::Channel *>(item);
if (channel && e->button() == Qt::MidButton) {
m_draggingChannel = channel;
m_dragStartPosition = e->pos();
} else
m_draggingChannel = 0;
}
//-----------------------------------------------------------------------------
void FunctionTreeView::onDrag(TreeModel::Item *item, const QPoint &itemPos, QMouseEvent *e)
{
//middle drag of the channel item can retrieve expression name
if ((e->buttons() & Qt::MidButton) &&
m_draggingChannel &&
(e->pos() - m_dragStartPosition).manhattanLength() >= QApplication::startDragDistance()) {
QDrag *drag = new QDrag(this);
QMimeData *mimeData = new QMimeData;
mimeData->setText(m_draggingChannel->getExprRefName());
drag->setMimeData(mimeData);
static const QPixmap cursorPixmap(":Resources/dragcursor_exp_text.png");
drag->setDragCursor(cursorPixmap, Qt::MoveAction);
Qt::DropAction dropAction = drag->exec();
return;
}
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(item);
if (!channel || !m_clickedItem)
return;
// i0: item under the current cursor position
// i1: clicked item
QModelIndex i0 = channel->createIndex(), i1 = m_clickedItem->createIndex();
if (!i0.isValid() || !i1.isValid() || i0.parent() != i1.parent())
return;
if (i0.row() > i1.row())
tswap(i0, i1);
FunctionTreeModel *md = static_cast<FunctionTreeModel *>(model());
bool active = m_clickedItem->isActive();
for (int row = i0.row(); row <= i1.row(); ++row) {
if (isRowHidden(row, i0.parent()))
continue;
QModelIndex index = md->index(row, 0, i0.parent());
TreeModel::Item *chItem = static_cast<TreeModel::Item *>(index.internalPointer());
FunctionTreeModel::Channel *ch = dynamic_cast<FunctionTreeModel::Channel *>(chItem);
if (ch && ch->isActive() != active) {
ch->setIsActive(active);
update();
}
}
}
//-----------------------------------------------------------------------------
void FunctionTreeView::onRelease()
{
m_clickedItem = 0;
}
//-----------------------------------------------------------------------------
void FunctionTreeView::openContextMenu(TreeModel::Item *item, const QPoint &globalPos)
{
if (FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(item))
openContextMenu(channel, globalPos);
else if (FunctionTreeModel::ChannelGroup *group = dynamic_cast<FunctionTreeModel::ChannelGroup *>(item))
openContextMenu(group, globalPos);
}
//-----------------------------------------------------------------------------
void FunctionTreeView::openContextMenu(FunctionTreeModel::Channel *channel, const QPoint &globalPos)
{
assert(channel);
QWidget *pw = dynamic_cast<QWidget *>(parentWidget());
if (!pw)
return;
FunctionViewer *fv = dynamic_cast<FunctionViewer *>(pw->parentWidget());
if (!fv) {
assert(fv);
return;
}
QMenu menu;
QAction saveCurveAction(tr("Save Curve"), 0);
QAction loadCurveAction(tr("Load Curve"), 0);
QAction exportDataAction(tr("Export Data"), 0);
menu.addAction(&saveCurveAction);
menu.addAction(&loadCurveAction);
menu.addAction(&exportDataAction);
QAction *action = menu.exec(globalPos);
TDoubleParam *curve = channel->getParam();
if (action == &saveCurveAction)
fv->emitIoCurve((int)FunctionViewer::eSaveCurve, curve, "");
else if (action == &loadCurveAction)
fv->emitIoCurve((int)FunctionViewer::eLoadCurve, curve, "");
else if (action == &exportDataAction)
fv->emitIoCurve((int)FunctionViewer::eExportCurve, curve, channel->getLongName().toStdString());
}
//-----------------------------------------------------------------------------
void FunctionTreeView::openContextMenu(FunctionTreeModel::ChannelGroup *group, const QPoint &globalPos)
{
assert(group);
QMenu menu;
QAction showAnimateOnly(tr("Show Animated Only"), 0);
QAction showAll(tr("Show All"), 0);
menu.addAction(&showAnimateOnly);
menu.addAction(&showAll);
// execute menu
QAction *action = menu.exec(globalPos);
if (action != &showAll && action != &showAnimateOnly)
return;
FunctionTreeModel::ChannelGroup::ShowFilter showFilter =
(action == &showAll) ? FunctionTreeModel::ChannelGroup::ShowAllChannels : FunctionTreeModel::ChannelGroup::ShowAnimatedChannels;
expand(group->createIndex());
group->setShowFilter(showFilter);
}
//-----------------------------------------------------------------------------
void FunctionTreeView::updateAll()
{
FunctionTreeModel *functionTreeModel = dynamic_cast<FunctionTreeModel *>(model());
assert(functionTreeModel);
functionTreeModel->applyShowFilters();
update();
}
//-----------------------------------------------------------------------------
/*! show all the animated channels when the scene switched
*/
void FunctionTreeView::displayAnimatedChannels()
{
FunctionTreeModel *functionTreeModel = dynamic_cast<FunctionTreeModel *>(model());
assert(functionTreeModel);
int i;
for (i = 0; i < functionTreeModel->getStageObjectsChannelCount(); i++)
functionTreeModel->getStageObjectChannel(i)->displayAnimatedChannels();
for (i = 0; i < functionTreeModel->getFxsChannelCount(); i++)
functionTreeModel->getFxChannel(i)->displayAnimatedChannels();
update();
}
//-----------------------------------------------------------------------------
/*! show all the animated channels when the scene switched
*/
void FunctionTreeModel::ChannelGroup::displayAnimatedChannels()
{
int itemCount = getChildCount();
int i;
for (i = 0; i < itemCount; i++) {
FunctionTreeModel::Channel *channel = dynamic_cast<FunctionTreeModel::Channel *>(getChild(i));
if (!channel) {
FunctionTreeModel::ChannelGroup *channelGroup =
dynamic_cast<FunctionTreeModel::ChannelGroup *>(getChild(i));
if (!channelGroup)
continue;
channelGroup->displayAnimatedChannels();
continue;
}
channel->setIsActive(channel->getParam()->hasKeyframes());
}
}