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