Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tdoubleparam.h"
Toshihiro Shimizu 890ddd
#include "tparamcontainer.h"
Toshihiro Shimizu 890ddd
#include "tparamset.h"
Toshihiro Shimizu 890ddd
#include "texpression.h"
Toshihiro Shimizu 890ddd
#include "tparser.h"
Toshihiro Shimizu 890ddd
#include "tfx.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "tw/stringtable.h"
Toshihiro Shimizu 890ddd
#include "tunit.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txsheet.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobjectid.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
#include "toonz/fxdag.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Boost includes
Toshihiro Shimizu 890ddd
#include "boost/noncopyable.hpp"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qstring></qstring>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/txsheetexpr.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace TSyntax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ParamDependencyFinder : public TSyntax::CalculatorNodeVisitor
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TDoubleParam *m_possiblyDependentParam;
Toshihiro Shimizu 890ddd
	bool m_found;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ParamDependencyFinder(TDoubleParam *possiblyDependentParam)
Toshihiro Shimizu 890ddd
		: m_possiblyDependentParam(possiblyDependentParam), m_found(false) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void check(TDoubleParam *param)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (param == m_possiblyDependentParam)
Toshihiro Shimizu 890ddd
			m_found = true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool found() const { return m_found; }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// Calculator Nodes
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ParamCalculatorNode : public CalculatorNode, public TParamObserver, public boost::noncopyable
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TDoubleParamP m_param;
Toshihiro Shimizu 890ddd
	std::auto_ptr<calculatornode> m_frame;</calculatornode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	ParamCalculatorNode(Calculator *calculator,
Toshihiro Shimizu 890ddd
						const TDoubleParamP ¶m,
Toshihiro Shimizu 890ddd
						std::auto_ptr<calculatornode> frame)</calculatornode>
Toshihiro Shimizu 890ddd
		: CalculatorNode(calculator), m_param(param), m_frame(frame)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		param->addObserver(this);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	~ParamCalculatorNode()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->removeObserver(this);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double compute(double vars[3]) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		double value = m_param->getValue(m_frame->compute(vars) - 1);
Toshihiro Shimizu 890ddd
		TMeasure *measure = m_param->getMeasure();
Toshihiro Shimizu 890ddd
		if (measure) {
Toshihiro Shimizu 890ddd
			const TUnit *unit = measure->getCurrentUnit();
Toshihiro Shimizu 890ddd
			if (unit)
Toshihiro Shimizu 890ddd
				value = unit->convertTo(value);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		return value;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void accept(TSyntax::CalculatorNodeVisitor &visitor)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		ParamDependencyFinder *pdf = dynamic_cast<paramdependencyfinder *="">(&visitor);</paramdependencyfinder>
Toshihiro Shimizu 890ddd
		pdf->check(m_param.getPointer());
Toshihiro Shimizu 890ddd
		m_param->accept(visitor);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onChange(const TParamChange ¶mChange)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		// The referenced parameter changed. This means the parameter owning the
Toshihiro Shimizu 890ddd
		// expression this node is part of, changes too.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// A param change is thus propagated for this parameter, with the 'keyframe'
Toshihiro Shimizu 890ddd
		// parameter turned off - since no keyframe value is actually altered.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (TDoubleParam *ownerParam = getCalculator()->getOwnerParameter()) {
Toshihiro Shimizu 890ddd
			const std::set<tparamobserver *=""> &observers = ownerParam->observers();</tparamobserver>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TParamChange propagatedChange(
Toshihiro Shimizu 890ddd
				ownerParam, 0, 0, false, paramChange.m_dragging, paramChange.m_undoing);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			std::set<tparamobserver *="">::const_iterator ot, oEnd = observers.end();</tparamobserver>
Toshihiro Shimizu 890ddd
			for (ot = observers.begin(); ot != oEnd; ++ot)
Toshihiro Shimizu 890ddd
				(*ot)->onChange(propagatedChange);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class XsheetDrawingCalculatorNode : public CalculatorNode, public boost::noncopyable
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *m_xsh;
Toshihiro Shimizu 890ddd
	int m_columnIndex;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::auto_ptr<calculatornode> m_frame;</calculatornode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	XsheetDrawingCalculatorNode(
Toshihiro Shimizu 890ddd
		Calculator *calc,
Toshihiro Shimizu 890ddd
		TXsheet *xsh,
Toshihiro Shimizu 890ddd
		int columnIndex,
Toshihiro Shimizu 890ddd
		std::auto_ptr<calculatornode> frame)</calculatornode>
Toshihiro Shimizu 890ddd
		: CalculatorNode(calc), m_xsh(xsh), m_columnIndex(columnIndex), m_frame(frame) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double compute(double vars[3]) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		double f = m_frame->compute(vars);
Toshihiro Shimizu 890ddd
		int i = tfloor(f);
Toshihiro Shimizu 890ddd
		f = f - (double)i;
Toshihiro Shimizu 890ddd
		TXshCell cell;
Toshihiro Shimizu 890ddd
		cell = m_xsh->getCell(i, m_columnIndex);
Toshihiro Shimizu 890ddd
		int d0 = cell.isEmpty() ? 0 : cell.m_frameId.getNumber();
Toshihiro Shimizu 890ddd
		cell = m_xsh->getCell(i + 1, m_columnIndex);
Toshihiro Shimizu 890ddd
		int d1 = cell.isEmpty() ? 0 : cell.m_frameId.getNumber();
Toshihiro Shimizu 890ddd
		double d = (1 - f) * d0 + f * d1;
Toshihiro Shimizu 890ddd
		return d;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void accept(TSyntax::CalculatorNodeVisitor &) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// Patterns
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class XsheetReferencePattern : public Pattern
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *m_xsh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	XsheetReferencePattern(TXsheet *xsh) : m_xsh(xsh)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		setDescription(
Toshihiro Shimizu 890ddd
			string("object.action\nTransformation reference\n") +
Toshihiro Shimizu 890ddd
			"object can be: tab, table, cam<n>, camera<n>, col<n>, peg<n>, pegbar<n>\n" +</n></n></n></n></n>
Toshihiro Shimizu 890ddd
			"action can be: ns,ew,rot,ang,angle,z,zdepth,sx,sy,sc,scale,scalex,scaley,path,pos,shx,shy");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStageObjectId matchObjectName(const Token &token) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		string s = toLower(token.getText());
Toshihiro Shimizu 890ddd
		int len = (int)s.length(), i, j;
Toshihiro Shimizu 890ddd
		for (i = 0; i < len && isascii(s[i]) && isalpha(s[i]); i++) {
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		if (i == 0)
Toshihiro Shimizu 890ddd
			return TStageObjectId::NoneId;
Toshihiro Shimizu 890ddd
		string a = s.substr(0, i);
Toshihiro Shimizu 890ddd
		int index = 0;
Toshihiro Shimizu 890ddd
		for (j = i; j < len && isascii(s[j]) && isdigit(s[j]); j++)
Toshihiro Shimizu 890ddd
			index = index * 10 + (s[j] - '0');
Toshihiro Shimizu 890ddd
		if (j < len)
Toshihiro Shimizu 890ddd
			return TStageObjectId::NoneId;
Toshihiro Shimizu 890ddd
		if (i == j)
Toshihiro Shimizu 890ddd
			index = -1;
Toshihiro Shimizu 890ddd
		if ((a == "table" || a == "tab") && index < 0)
Toshihiro Shimizu 890ddd
			return TStageObjectId::TableId;
Toshihiro Shimizu 890ddd
		else if (a == "col" && index >= 1)
Toshihiro Shimizu 890ddd
			return TStageObjectId::ColumnId(index - 1);
Toshihiro Shimizu 890ddd
		else if ((a == "cam" || a == "camera") && index >= 1)
Toshihiro Shimizu 890ddd
			return TStageObjectId::CameraId(index - 1);
Toshihiro Shimizu 890ddd
		else if ((a == "peg" || a == "pegbar") && index >= 1)
Toshihiro Shimizu 890ddd
			return TStageObjectId::PegbarId(index - 1);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			return TStageObjectId::NoneId;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStageObject::Channel matchChannelName(const Token &token) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		string s = toLower(token.getText());
Toshihiro Shimizu 890ddd
		if (s == "ns")
Toshihiro Shimizu 890ddd
			return TStageObject::T_Y;
Toshihiro Shimizu 890ddd
		else if (s == "ew")
Toshihiro Shimizu 890ddd
			return TStageObject::T_X;
Toshihiro Shimizu 890ddd
		else if (s == "rot" || s == "ang" || s == "angle")
Toshihiro Shimizu 890ddd
			return TStageObject::T_Angle;
Toshihiro Shimizu 890ddd
		else if (s == "z" || s == "zdepth")
Toshihiro Shimizu 890ddd
			return TStageObject::T_Z;
Toshihiro Shimizu 890ddd
		else if (s == "sx" || s == "scalex" || s == "xscale" || s == "xs" || s == "sh" || s == "scaleh" || s == "hscale" || s == "hs")
Toshihiro Shimizu 890ddd
			return TStageObject::T_ScaleX;
Toshihiro Shimizu 890ddd
		else if (s == "sy" || s == "scaley" || s == "yscale" || s == "ys" || s == "sv" || s == "scalev" || s == "vscale" || s == "vs")
Toshihiro Shimizu 890ddd
			return TStageObject::T_ScaleY;
Toshihiro Shimizu 890ddd
		else if (s == "sc" || s == "scale")
Toshihiro Shimizu 890ddd
			return TStageObject::T_Scale;
Toshihiro Shimizu 890ddd
		else if (s == "path" || s == "pos")
Toshihiro Shimizu 890ddd
			return TStageObject::T_Path;
Toshihiro Shimizu 890ddd
		else if (s == "shearx" || s == "shx" || s == "shearh" || s == "shh")
Toshihiro Shimizu 890ddd
			return TStageObject::T_ShearX;
Toshihiro Shimizu 890ddd
		else if (s == "sheary" || s == "shy" || s == "shearv" || s == "shv")
Toshihiro Shimizu 890ddd
			return TStageObject::T_ShearY;
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			return TStageObject::T_ChannelCount;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool expressionExpected(const std::vector<token> &previousTokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return previousTokens.size() == 4;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool matchToken(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int i = (int)previousTokens.size();
Toshihiro Shimizu 890ddd
		if (i == 0)
Toshihiro Shimizu 890ddd
			return matchObjectName(token) != TStageObjectId::NoneId;
Toshihiro Shimizu 890ddd
		else if (i == 1 && token.getText() == "." || i == 3 && token.getText() == "(" || i == 5 && token.getText() == ")")
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		else if (i == 2) {
Toshihiro Shimizu 890ddd
			if (matchChannelName(token) < TStageObject::T_ChannelCount)
Toshihiro Shimizu 890ddd
				return true;
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				return token.getText() == "cell" &&
Toshihiro Shimizu 890ddd
					   matchObjectName(previousTokens[0]).isColumn();
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool isFinished(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return previousTokens.size() >= 6;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool isComplete(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return previousTokens.size() >= 6 || previousTokens.size() == 3;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TSyntax::TokenType getTokenType(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return TSyntax::Operator;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void getAcceptableKeywords(std::vector<std::string> &keywords) const</std::string>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const string ks[] = {"table", "tab", "col", "cam", "camera", "peg", "pegbar"};
Toshihiro Shimizu 890ddd
		for (int i = 0; i < tArrayCount(ks); i++)
Toshihiro Shimizu 890ddd
			keywords.push_back(ks[i]);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void createNode(
Toshihiro Shimizu 890ddd
		Calculator *calc,
Toshihiro Shimizu 890ddd
		std::vector<calculatornode *=""> &stack,</calculatornode>
Toshihiro Shimizu 890ddd
		const std::vector<token> &tokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(tokens.size() >= 3);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::auto_ptr<calculatornode> frameNode((tokens.size() == 6) ? popNode(stack) : new VariableNode(calc, CalculatorNode::FRAME));</calculatornode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TStageObjectId objectId = matchObjectName(tokens[0]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		string field = toLower(tokens[2].getText());
Toshihiro Shimizu 890ddd
		if (field == "cell" || field == "cel" || field == "cels") {
Toshihiro Shimizu 890ddd
			int columnIndex = objectId.getIndex();
Toshihiro Shimizu 890ddd
			stack.push_back(new XsheetDrawingCalculatorNode(calc, m_xsh, columnIndex, frameNode));
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			TStageObject *object = m_xsh->getStageObject(objectId);
Toshihiro Shimizu 890ddd
			TStageObject::Channel channelName = matchChannelName(tokens[2]);
Toshihiro Shimizu 890ddd
			TDoubleParam *channel = object->getParam(channelName);
Toshihiro Shimizu 890ddd
			if (channel)
Toshihiro Shimizu 890ddd
				stack.push_back(new ParamCalculatorNode(calc, channel, frameNode));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class FxReferencePattern : public Pattern
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *m_xsh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	FxReferencePattern(TXsheet *xsh) : m_xsh(xsh) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TFx *getFx(const Token &token) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return m_xsh->getFxDag()->getFxById(toWideString(toLower(token.getText())));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TParam *getParam(const TFx *fx, const Token &token) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int i;
Toshihiro Shimizu 890ddd
		for (i = 0; i < fx->getParams()->getParamCount(); i++) {
Toshihiro Shimizu 890ddd
			TParam *param = fx->getParams()->getParam(i);
Toshihiro Shimizu 890ddd
			string paramName = toString(TStringTable::translate(fx->getFxType() + "." + param->getName()));
Toshihiro Shimizu 890ddd
			int i = paramName.find(" ");
Toshihiro Shimizu 890ddd
			while (i != string::npos) {
Toshihiro Shimizu 890ddd
				paramName.erase(i, 1);
Toshihiro Shimizu 890ddd
				i = paramName.find(" ");
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			string paramNameToCheck = token.getText();
Toshihiro Shimizu 890ddd
			if (paramName == paramNameToCheck || toLower(paramName) == toLower(paramNameToCheck))
Toshihiro Shimizu 890ddd
				return param;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TParam *getLeafParam(const TFx *fx, const TParamSet *paramSet, const Token &token) const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int i;
Toshihiro Shimizu 890ddd
		for (i = 0; i < paramSet->getParamCount(); i++) {
Toshihiro Shimizu 890ddd
			TParam *param = paramSet->getParam(i).getPointer();
Toshihiro Shimizu 890ddd
			string paramName = param->getName();
Toshihiro Shimizu 890ddd
			int i = paramName.find(" ");
Toshihiro Shimizu 890ddd
			while (i != string::npos) {
Toshihiro Shimizu 890ddd
				paramName.erase(i, 1);
Toshihiro Shimizu 890ddd
				i = paramName.find(" ");
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			string paramNameToCheck = token.getText();
Toshihiro Shimizu 890ddd
			if (paramName == paramNameToCheck || toLower(paramName) == toLower(paramNameToCheck))
Toshihiro Shimizu 890ddd
				return param;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	string getFirstKeyword() const { return "fx"; }
Toshihiro Shimizu 890ddd
	bool expressionExpected(const std::vector<token> &previousTokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return !previousTokens.empty() && previousTokens.back().getText() == "(";
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool matchToken(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int i = (int)previousTokens.size();
Toshihiro Shimizu 890ddd
		string s = toLower(token.getText());
Toshihiro Shimizu 890ddd
		if (i == 0 && s == "fx")
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		else if (i == 1)
Toshihiro Shimizu 890ddd
			return s == ".";
Toshihiro Shimizu 890ddd
		else if (i & 1) {
Toshihiro Shimizu 890ddd
			if (previousTokens[i - 2].getText() == "(")
Toshihiro Shimizu 890ddd
				return s == ")";
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				return s == "." || s == "(";
Toshihiro Shimizu 890ddd
		} else if (i == 2) {
Toshihiro Shimizu 890ddd
			// nome fx
Toshihiro Shimizu 890ddd
			return getFx(token) != 0;
Toshihiro Shimizu 890ddd
		} else if (i == 4) {
Toshihiro Shimizu 890ddd
			TFx *fx = getFx(previousTokens[2]);
Toshihiro Shimizu 890ddd
			if (!fx)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			TParam *param = getParam(fx, token);
Toshihiro Shimizu 890ddd
			return !!param;
Toshihiro Shimizu 890ddd
		} else if (i == 6) {
Toshihiro Shimizu 890ddd
			TFx *fx = getFx(previousTokens[2]);
Toshihiro Shimizu 890ddd
			if (!fx)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			TParam *param = getParam(fx, previousTokens[4]);
Toshihiro Shimizu 890ddd
			TParamSet *paramSet = dynamic_cast<tparamset *="">(param);</tparamset>
Toshihiro Shimizu 890ddd
			if (!paramSet)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
			TParam *leafParam = getLeafParam(fx, paramSet, token);
Toshihiro Shimizu 890ddd
			return !!param;
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool isFinished(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return !previousTokens.empty() && previousTokens.back().getText() == ")";
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	bool isComplete(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int n = (int)previousTokens.size();
Toshihiro Shimizu 890ddd
		return n >= 2 && (n & 1) == 1 && previousTokens[n - 2].getText() != "(";
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	TSyntax::TokenType getTokenType(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return TSyntax::Operator;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void createNode(
Toshihiro Shimizu 890ddd
		Calculator *calc,
Toshihiro Shimizu 890ddd
		std::vector<calculatornode *=""> &stack,</calculatornode>
Toshihiro Shimizu 890ddd
		const std::vector<token> &tokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		int tokenSize = tokens.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::auto_ptr<calculatornode> frameNode((tokenSize > 0 && tokens.back().getText() == ")") ? popNode(stack) : new VariableNode(calc, CalculatorNode::FRAME));</calculatornode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TFx *fx = getFx(tokens[2]);
Toshihiro Shimizu 890ddd
		if (!fx || tokenSize < 4)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TParamP param = getParam(fx, tokens[4]);
Toshihiro Shimizu 890ddd
		if (!param.getPointer())
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TDoubleParamP channel;
Toshihiro Shimizu 890ddd
		TParamSet *paramSet = dynamic_cast<tparamset *="">(param.getPointer());</tparamset>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (paramSet && tokenSize > 6)
Toshihiro Shimizu 890ddd
			channel = dynamic_cast<tdoubleparam *="">(getLeafParam(fx, paramSet, tokens[6]));</tdoubleparam>
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			channel = param;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (channel.getPointer())
Toshihiro Shimizu 890ddd
			stack.push_back(new ParamCalculatorNode(calc, channel, frameNode));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class PlasticVertexPattern : public Pattern
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *m_xsh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
    Full pattern layout:
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
      vertex ( columnNumber , " vertexName " ) . component (  expr )
Toshihiro Shimizu 890ddd
         0   1      2       3 4      5     6 7 8     9     10  11  12
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	enum Positions {
Toshihiro Shimizu 890ddd
		OBJECT,
Toshihiro Shimizu 890ddd
		L1,
Toshihiro Shimizu 890ddd
		COLUMN_NUMBER,
Toshihiro Shimizu 890ddd
		COMMA,
Toshihiro Shimizu 890ddd
		QUOTE1,
Toshihiro Shimizu 890ddd
		VERTEX_NAME,
Toshihiro Shimizu 890ddd
		QUOTE2,
Toshihiro Shimizu 890ddd
		R1,
Toshihiro Shimizu 890ddd
		SELECTOR,
Toshihiro Shimizu 890ddd
		COMPONENT,
Toshihiro Shimizu 890ddd
		L2,
Toshihiro Shimizu 890ddd
		EXPR,
Toshihiro Shimizu 890ddd
		R2,
Toshihiro Shimizu 890ddd
		POSITIONS_COUNT
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	PlasticVertexPattern(TXsheet *xsh)
Toshihiro Shimizu 890ddd
		: m_xsh(xsh)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		setDescription(
Toshihiro Shimizu 890ddd
			"vertex(columnNumber, \"vertexName\").action\nVertex data\n"
Toshihiro Shimizu 890ddd
			"columnNumber must be the number of the column containing the desired skeleton\n"
Toshihiro Shimizu 890ddd
			"vertexName must be the name of a Plastic Skeleton vertex\n"
Toshihiro Shimizu 890ddd
			"action must be one of the parameter names available for a Plastic Skeleton vertex");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual string getFirstKeyword() const { return "vertex"; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool expressionExpected(const std::vector<token> &previousTokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (previousTokens.size() == EXPR);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool matchToken(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		struct {
Toshihiro Shimizu 890ddd
			const PlasticVertexPattern *m_this;
Toshihiro Shimizu 890ddd
			const SkD *skdp(const Token &columnToken)
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				int colIdx = columnToken.getIntValue() - 1; // The first column (1) actually starts at index 0
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (!m_this->m_xsh->isColumnEmpty(colIdx)) {
Toshihiro Shimizu 890ddd
					TStageObject *obj = m_this->m_xsh->getStageObject(TStageObjectId::ColumnId(colIdx));
Toshihiro Shimizu 890ddd
					assert(obj);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (const SkDP &skdp = obj->getPlasticSkeletonDeformation())
Toshihiro Shimizu 890ddd
						return skdp.getPointer();
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				return 0;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		} locals = {this};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const std::string &text = token.getText();
Toshihiro Shimizu 890ddd
		int pos = previousTokens.size();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!m_fixedTokens[pos].empty())
Toshihiro Shimizu 890ddd
			return (text == m_fixedTokens[pos]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		switch (pos) {
Toshihiro Shimizu 890ddd
		case COLUMN_NUMBER:
Toshihiro Shimizu 890ddd
			return (token.getType() == Token::Number && locals.skdp(token));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE VERTEX_NAME:
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				if (const SkD *skdp = locals.skdp(previousTokens[COLUMN_NUMBER])) {
Toshihiro Shimizu 890ddd
					const QString &vertexName = QString::fromStdString(text);
Toshihiro Shimizu 890ddd
					return (skdp->vertexDeformation(vertexName) != 0);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE COMPONENT : return std::count(
Toshihiro Shimizu 890ddd
								 m_components, m_components + sizeof(m_components) / sizeof(Component),
Toshihiro Shimizu 890ddd
								 text) > 0;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isFinished(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (previousTokens.size() >= POSITIONS_COUNT);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool isComplete(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (previousTokens.size() >= POSITIONS_COUNT || previousTokens.size() == L2);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TSyntax::TokenType getTokenType(const std::vector<token> &previousTokens, const Token &token) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return TSyntax::Operator;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void createNode(Calculator *calc, std::vector<calculatornode *=""> &stack,</calculatornode>
Toshihiro Shimizu 890ddd
					const std::vector<token> &tokens) const</token>
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(tokens.size() > COMPONENT);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::auto_ptr<calculatornode> frameNode((tokens.size() == POSITIONS_COUNT) ? popNode(stack) : new VariableNode(calc, CalculatorNode::FRAME));</calculatornode>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int colIdx = tokens[COLUMN_NUMBER].getIntValue() - 1;
Toshihiro Shimizu 890ddd
		if (!m_xsh->isColumnEmpty(colIdx)) {
Toshihiro Shimizu 890ddd
			TStageObject *obj = m_xsh->getStageObject(TStageObjectId::ColumnId(colIdx));
Toshihiro Shimizu 890ddd
			assert(obj);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (const SkDP &skdp = obj->getPlasticSkeletonDeformation()) {
Toshihiro Shimizu 890ddd
				const QString &vertexName = QString::fromStdString(tokens[VERTEX_NAME].getText());
Toshihiro Shimizu 890ddd
				if (SkVD *skvd = skdp->vertexDeformation(vertexName)) {
Toshihiro Shimizu 890ddd
					const Component *componentsEnd = m_components + sizeof(m_components) / sizeof(Component),
Toshihiro Shimizu 890ddd
									*component = std::find(m_components, componentsEnd, tokens[COMPONENT].getText());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					if (component != componentsEnd) {
Toshihiro Shimizu 890ddd
						const TDoubleParamP ¶m = skvd->m_params[component->m_paramId].getPointer();
Toshihiro Shimizu 890ddd
						stack.push_back(new ParamCalculatorNode(calc, param, frameNode));
Toshihiro Shimizu 890ddd
					}
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	struct Component {
Toshihiro Shimizu 890ddd
		std::string m_name;
Toshihiro Shimizu 890ddd
		SkVD::Params m_paramId;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool operator==(const std::string &name) const
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return (m_name == name);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Toshihiro Shimizu 890ddd
	static const std::string m_fixedTokens[POSITIONS_COUNT];
Toshihiro Shimizu 890ddd
	static const Component m_components[5];
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const std::string PlasticVertexPattern::m_fixedTokens[POSITIONS_COUNT] = {
Toshihiro Shimizu 890ddd
	"vertex", "(", "", ",", "\"", "", "\"", ")", ".", "", "(", "", ")"};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const PlasticVertexPattern::Component PlasticVertexPattern::m_components[] = {
Toshihiro Shimizu 890ddd
	{"ang", SkVD::ANGLE}, {"angle", SkVD::ANGLE}, {"dist", SkVD::DISTANCE}, {"distance", SkVD::DISTANCE}, {"so", SkVD::SO}};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
//    API functions
Toshihiro Shimizu 890ddd
//******************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TSyntax::Grammar *createXsheetGrammar(TXsheet *xsh)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Grammar *grammar = new Grammar();
Toshihiro Shimizu 890ddd
	grammar->addPattern(new XsheetReferencePattern(xsh));
Toshihiro Shimizu 890ddd
	grammar->addPattern(new FxReferencePattern(xsh));
Toshihiro Shimizu 890ddd
	grammar->addPattern(new PlasticVertexPattern(xsh));
Toshihiro Shimizu 890ddd
	return grammar;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool dependsOn(TExpression &expr, TDoubleParam *possiblyDependentParam)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ParamDependencyFinder pdf(possiblyDependentParam);
Toshihiro Shimizu 890ddd
	expr.accept(pdf);
Toshihiro Shimizu 890ddd
	return pdf.found();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool dependsOn(TDoubleParam *param, TDoubleParam *possiblyDependentParam)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	ParamDependencyFinder pdf(possiblyDependentParam);
Toshihiro Shimizu 890ddd
	param->accept(pdf);
Toshihiro Shimizu 890ddd
	return pdf.found();
Toshihiro Shimizu 890ddd
}