Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/functionselection.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/doubleparamcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheetexpr.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzBase includes
Toshihiro Shimizu 890ddd
#include "tdoubleparam.h"
Toshihiro Shimizu 890ddd
#include "tdoublekeyframe.h"
Toshihiro Shimizu 890ddd
#include "texpression.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tcommon.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qmimedata></qmimedata>
Toshihiro Shimizu 890ddd
#include <qclipboard></qclipboard>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// Function clipboard operations undo
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class KeyframesCopyUndo final : public TUndo {
Shinya Kitaoka 120a6e
  QMimeData *m_oldData, *m_newData;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  KeyframesCopyUndo(const QMimeData *oldData, const QMimeData *newData)
Shinya Kitaoka 120a6e
      : m_oldData(cloneData(oldData)), m_newData(cloneData(newData)) {}
Shinya Kitaoka 120a6e
  ~KeyframesCopyUndo() {
Shinya Kitaoka 120a6e
    delete m_oldData;
Shinya Kitaoka 120a6e
    delete m_newData;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    QApplication::clipboard()->setMimeData(cloneData(m_oldData));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    QApplication::clipboard()->setMimeData(cloneData(m_newData));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) + sizeof(QMimeData) * 2;  // approx
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Copy Keyframe"); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class KeyframesPasteUndo final : public TUndo {
Shinya Kitaoka 120a6e
  struct Column {
Shinya Kitaoka 120a6e
    TDoubleParam *m_param;
Shinya Kitaoka 120a6e
    std::map<int, tdoublekeyframe=""> m_oldKeyframes;</int,>
Shinya Kitaoka 120a6e
    std::set<double> m_created;</double>
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  std::vector<column> m_columns;</column>
Shinya Kitaoka 120a6e
  FunctionKeyframesData *m_data;
Shinya Kitaoka 120a6e
  double m_frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  KeyframesPasteUndo(std::vector<tdoubleparam *=""> ¶ms,</tdoubleparam>
Shinya Kitaoka 120a6e
                     const FunctionKeyframesData *data, double frame)
Shinya Kitaoka 120a6e
      : m_data(dynamic_cast<functionkeyframesdata *="">(data->clone()))</functionkeyframesdata>
Shinya Kitaoka 120a6e
      , m_frame(frame) {
Shinya Kitaoka 120a6e
    assert((int)params.size() <= data->getColumnCount());
Shinya Kitaoka 120a6e
    int columnCount = std::min((int)(params.size()), data->getColumnCount());
Shinya Kitaoka 120a6e
    m_columns.resize(columnCount);
Shinya Kitaoka 120a6e
    for (int col = 0; col < columnCount; col++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param    = params[col];
Shinya Kitaoka 120a6e
      m_columns[col].m_param = param;
Shinya Kitaoka 120a6e
      param->addRef();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      const FunctionKeyframesData::Keyframes &keyframes =
Shinya Kitaoka 120a6e
          data->getKeyframes(col);
Shinya Kitaoka 120a6e
      FunctionKeyframesData::Keyframes::const_iterator it;
Shinya Kitaoka 120a6e
      for (it = keyframes.begin(); it != keyframes.end(); ++it) {
Shinya Kitaoka 120a6e
        double f = it->m_frame + frame;
Shinya Kitaoka 120a6e
        int k    = param->getClosestKeyframe(f);
Shinya Kitaoka 120a6e
        if (0 <= k && k < param->getKeyframeCount() &&
Shinya Kitaoka 120a6e
            param->keyframeIndexToFrame(k) == f)
Shinya Kitaoka 120a6e
          m_columns[col].m_oldKeyframes[k] = param->getKeyframe(k);
Shinya Kitaoka 120a6e
        else
Shinya Kitaoka 120a6e
          m_columns[col].m_created.insert(f);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~KeyframesPasteUndo() {
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_columns.size(); i++)
Shinya Kitaoka 120a6e
      m_columns[i].m_param->release();
Shinya Kitaoka 120a6e
    delete m_data;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    int columnCount = (int)m_columns.size();
Shinya Kitaoka 120a6e
    for (int col = 0; col < columnCount; col++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param = m_columns[col].m_param;
Shinya Kitaoka 120a6e
      for (std::set<double>::const_iterator it =</double>
Shinya Kitaoka 120a6e
               m_columns[col].m_created.begin();
Shinya Kitaoka 120a6e
           it != m_columns[col].m_created.end(); ++it)
Shinya Kitaoka 120a6e
        param->deleteKeyframe(*it);
Shinya Kitaoka 120a6e
      param->setKeyframes(m_columns[col].m_oldKeyframes);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    for (int col = 0; col < (int)m_columns.size(); col++) {
Shinya Kitaoka 120a6e
      m_data->setData(col, m_columns[col].m_param, m_frame);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) + 100;  // approx
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  QString getHistoryString() override {
Shinya Kitaoka 120a6e
    return QObject::tr("Paste Keyframe  at Frame : %1")
Shinya Kitaoka 120a6e
        .arg(QString::number((int)m_frame + 1));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class KeyframesDeleteUndo final : public TUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  struct ColumnKeyframes {
Shinya Kitaoka 120a6e
    TDoubleParam *m_param;
Shinya Kitaoka 120a6e
    std::vector<tdoublekeyframe> m_keyframes;</tdoublekeyframe>
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  struct Column {
Shinya Kitaoka 120a6e
    TDoubleParam *m_param;
Shinya Kitaoka 120a6e
    QSet<int> m_keyframes;</int>
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  KeyframesDeleteUndo(const std::vector<column> &columns) {</column>
Shinya Kitaoka 120a6e
    m_columns.resize(columns.size());
Shinya Kitaoka 120a6e
    for (int col = 0; col < (int)m_columns.size(); col++) {
Shinya Kitaoka 120a6e
      TDoubleParam *param    = columns[col].m_param;
Shinya Kitaoka 120a6e
      m_columns[col].m_param = param;
Shinya Kitaoka 120a6e
      if (!param) continue;
Shinya Kitaoka 120a6e
      param->addRef();
Shinya Kitaoka 120a6e
      const QSet<int> &keyframes = columns[col].m_keyframes;</int>
Shinya Kitaoka 120a6e
      for (QSet<int>::const_iterator it = keyframes.begin();</int>
Shinya Kitaoka 120a6e
           it != keyframes.end(); ++it)
Shinya Kitaoka 120a6e
        m_columns[col].m_keyframes.push_back(param->getKeyframe(*it));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  ~KeyframesDeleteUndo() {
Shinya Kitaoka 120a6e
    for (int col = 0; col < (int)m_columns.size(); col++)
Shinya Kitaoka 120a6e
      m_columns[col].m_param->release();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    for (int col = 0; col < (int)m_columns.size(); col++)
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)m_columns[col].m_keyframes.size(); i++)
Shinya Kitaoka 120a6e
        m_columns[col].m_param->setKeyframe(m_columns[col].m_keyframes[i]);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    for (int col = 0; col < (int)m_columns.size(); col++)
Shinya Kitaoka 120a6e
      for (int i = 0; i < (int)m_columns[col].m_keyframes.size(); i++)
Shinya Kitaoka 120a6e
        m_columns[col].m_param->deleteKeyframe(
Shinya Kitaoka 120a6e
            m_columns[col].m_keyframes[i].m_frame);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) +
Shinya Kitaoka 120a6e
           sizeof(TDoubleKeyframe) * m_columns.size();  // sbagliato!
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Delete Keyframe"); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  std::vector<columnkeyframes> m_columns;</columnkeyframes>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class KeyframesMoveUndo final : public TUndo {
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  KeyframesMoveUndo() {}
Shinya Kitaoka 120a6e
  ~KeyframesMoveUndo() {
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_movements.size(); i++)
Shinya Kitaoka 120a6e
      m_movements[i].m_param->release();
Shinya Kitaoka 120a6e
    m_movements.clear();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  void addMovement(TDoubleParam *param, int kIndex, double frameDelta) {
Shinya Kitaoka 120a6e
    m_movements.push_back(KeyframeMovement(param, kIndex, frameDelta));
Shinya Kitaoka 120a6e
    param->addRef();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    for (int i = (int)m_movements.size() - 1; i >= 0; i--) {
Shinya Kitaoka 120a6e
      TDoubleKeyframe kf =
Shinya Kitaoka 120a6e
          m_movements[i].m_param->getKeyframe(m_movements[i].m_kIndex);
Shinya Kitaoka 120a6e
      kf.m_frame -= m_movements[i].m_frameDelta;
Shinya Kitaoka 120a6e
      m_movements[i].m_param->setKeyframe(m_movements[i].m_kIndex, kf);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    for (int i = 0; i < (int)m_movements.size(); i++) {
Shinya Kitaoka 120a6e
      TDoubleKeyframe kf =
Shinya Kitaoka 120a6e
          m_movements[i].m_param->getKeyframe(m_movements[i].m_kIndex);
Shinya Kitaoka 120a6e
      kf.m_frame += m_movements[i].m_frameDelta;
Shinya Kitaoka 120a6e
      m_movements[i].m_param->setKeyframe(m_movements[i].m_kIndex, kf);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 473e70
  int getSize() const override {
Shinya Kitaoka 120a6e
    return sizeof(*this) + sizeof(m_movements[0]) * m_movements.size();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  int getCount() const { return (int)m_movements.size(); }
Shinya Kitaoka 473e70
  QString getHistoryString() override { return QObject::tr("Move Keyframe"); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
private:
Shinya Kitaoka 120a6e
  struct KeyframeMovement {
Shinya Kitaoka 120a6e
    TDoubleParam *m_param;
Shinya Kitaoka 120a6e
    int m_kIndex;
Shinya Kitaoka 120a6e
    double m_frameDelta;
Shinya Kitaoka 120a6e
    KeyframeMovement(TDoubleParam *param, int kIndex, double frameDelta)
Shinya Kitaoka 120a6e
        : m_param(param), m_kIndex(kIndex), m_frameDelta(frameDelta) {}
Shinya Kitaoka 120a6e
  };
Shinya Kitaoka 120a6e
  std::vector<keyframemovement> m_movements;</keyframemovement>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// FunctionSelection
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
FunctionSelection::FunctionSelection()
Shinya Kitaoka 120a6e
    : m_selectedCells()
Shinya Kitaoka 120a6e
    , m_selectedKeyframes()
Shinya Kitaoka 120a6e
    , m_selectedSegment(-1)
Shinya Kitaoka 120a6e
    , m_frameHandle(0)
Shinya Kitaoka 120a6e
    , m_columnToCurveMapper(0) {}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
FunctionSelection::~FunctionSelection() {
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    if (m_selectedKeyframes[i].first) m_selectedKeyframes[i].first->release();
Shinya Kitaoka 120a6e
  m_selectedKeyframes.clear();
Shinya Kitaoka 120a6e
  delete m_columnToCurveMapper;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::setColumnToCurveMapper(ColumnToCurveMapper *mapper) {
Shinya Kitaoka 120a6e
  if (mapper != m_columnToCurveMapper) {
Shinya Kitaoka 120a6e
    delete m_columnToCurveMapper;
Shinya Kitaoka 120a6e
    m_columnToCurveMapper = mapper;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::selectCurve(TDoubleParam *curve) {
Shinya Kitaoka 120a6e
  if (m_selectedKeyframes.size() == 1 && m_selectedKeyframes[0].first == curve)
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  curve->addRef();
Shinya Kitaoka 120a6e
  deselectAllKeyframes();
Shinya Kitaoka 120a6e
  m_selectedKeyframes.push_back(qMakePair(curve, QSet<int>()));</int>
Shinya Kitaoka 120a6e
  m_selectedCells = QRect();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::deselectAllKeyframes() {
Shinya Kitaoka 120a6e
  if (getSelectedKeyframeCount() == 0) return;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    m_selectedKeyframes[i].second.clear();
Shinya Kitaoka 120a6e
  emit selectionChanged();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int FunctionSelection::getCurveIndex(TDoubleParam *curve) const {
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    if (m_selectedKeyframes[i].first == curve) return i;
Shinya Kitaoka 120a6e
  return -1;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int FunctionSelection::touchCurveIndex(TDoubleParam *curve) {
Shinya Kitaoka 120a6e
  int i = getCurveIndex(curve);
Shinya Kitaoka 120a6e
  if (i < 0) {
Shinya Kitaoka 120a6e
    i = m_selectedKeyframes.size();
Shinya Kitaoka 120a6e
    m_selectedKeyframes.push_back(qMakePair(curve, QSet<int>()));</int>
Shinya Kitaoka 120a6e
    curve->addRef();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return i;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::selectNone() {
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    if (m_selectedKeyframes[i].first) m_selectedKeyframes[i].first->release();
Shinya Kitaoka 120a6e
  m_selectedKeyframes.clear();
Shinya Kitaoka 120a6e
  m_selectedSegment = -1;
Shinya Kitaoka 120a6e
  m_selectedCells   = QRect();
Shinya Kitaoka 120a6e
  emit selectionChanged();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
// called from FunctionSheet::selectCells
Shinya Kitaoka 120a6e
void FunctionSelection::selectCells(const QRect &selectedCells,
Shinya Kitaoka 120a6e
                                    const QList<tdoubleparam *=""> &curves) {</tdoubleparam>
Shinya Kitaoka 120a6e
  assert(selectedCells.width() == curves.size());
Shinya Kitaoka 120a6e
  for (int i = 0; i < curves.size(); i++)
Shinya Kitaoka 120a6e
    if (curves[i]) curves[i]->addRef();
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    if (m_selectedKeyframes[i].first) m_selectedKeyframes[i].first->release();
Shinya Kitaoka 120a6e
  m_selectedKeyframes.clear();
Shinya Kitaoka 120a6e
  double r0 = selectedCells.top();
Shinya Kitaoka 120a6e
  double r1 = selectedCells.bottom();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Update selected keyframes
Shinya Kitaoka 120a6e
  for (int i = 0; i < curves.size(); i++) {
Shinya Kitaoka 120a6e
    TDoubleParam *curve = curves[i];
Shinya Kitaoka 120a6e
    m_selectedKeyframes.push_back(qMakePair(curve, QSet<int>()));</int>
Shinya Kitaoka 120a6e
    if (curve)
Shinya Kitaoka 120a6e
      for (int j = 0; j < curve->getKeyframeCount(); j++) {
Shinya Kitaoka 120a6e
        double f = curve->keyframeIndexToFrame(j);
Shinya Kitaoka 120a6e
        if (r0 <= f && f <= r1) m_selectedKeyframes[i].second.insert(j);
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Update selected segment
Shinya Kitaoka 120a6e
  if (curves.size() != 1)
Shinya Kitaoka 120a6e
    m_selectedSegment = -1;
Shinya Kitaoka 120a6e
  else if (!curves[0])  // curves[0] may be zero
Shinya Kitaoka 120a6e
    m_selectedSegment = -1;
Shinya Kitaoka 120a6e
  else {
Shinya Kitaoka 120a6e
    int r0 = selectedCells.top();
Shinya Kitaoka 120a6e
    int r1 = selectedCells.bottom();
Shinya Kitaoka 120a6e
    int k0 = curves[0]->getPrevKeyframe(r0);
Shinya Kitaoka 120a6e
    int k1 = curves[0]->getPrevKeyframe(r1);
Shinya Kitaoka 120a6e
    // PrevKeyFrame does NOT include itself if the specified row is keyframe
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (k0 ==
Shinya Kitaoka 120a6e
        curves[0]->getKeyframeCount() - 1)  // select bottom of the segments
Shinya Kitaoka 120a6e
      m_selectedSegment = -1;
Shinya Kitaoka 120a6e
    else if (k0 != k1)  // select over a keyframe
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      // then select the segment on top in the selection
Shinya Kitaoka 120a6e
      if (curves[0]->isKeyframe(r0))
Shinya Kitaoka 120a6e
        m_selectedSegment = k0 + 1;
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        m_selectedSegment = k0;
Shinya Kitaoka 120a6e
    } else  // select single segment
Shinya Kitaoka 120a6e
      m_selectedSegment = k0;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_selectedCells = selectedCells;
Shinya Kitaoka 120a6e
  makeCurrent();
Shinya Kitaoka 120a6e
  emit selectionChanged();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::selectCells(const QRect &selectedCells) {
Shinya Kitaoka 120a6e
  QList<tdoubleparam *=""> curves;</tdoubleparam>
Shinya Kitaoka 120a6e
  for (int c = selectedCells.left(); c <= selectedCells.right(); c++)
Shinya Kitaoka 120a6e
    curves.append(getCurveFromColumn(c));
Shinya Kitaoka 120a6e
  selectCells(selectedCells, curves);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::select(TDoubleParam *curve, int k) {
Shinya Kitaoka 120a6e
  int i = touchCurveIndex(curve);
Shinya Kitaoka 120a6e
  m_selectedKeyframes[i].second.insert(k);
Shinya Kitaoka 120a6e
  double row = curve->keyframeIndexToFrame(k);
Shinya Kitaoka 120a6e
  if (row < (double)m_selectedCells.top()) m_selectedCells.setTop(floor(row));
Shinya Kitaoka 120a6e
  if (row > (double)m_selectedCells.bottom())
Shinya Kitaoka 120a6e
    m_selectedCells.setBottom(ceil(row));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_selectedSegment >= 0  // if a segment is selected
Shinya Kitaoka 120a6e
      && (m_selectedKeyframes.size() !=
Shinya Kitaoka 120a6e
              1  // and there is not a single curve selected
Shinya Kitaoka 120a6e
          || m_selectedSegment != k ||
Shinya Kitaoka 120a6e
          m_selectedSegment + 1 != k))  // or the new selected keyframe
Shinya Kitaoka 120a6e
                                        // is not a selected segment end
Shinya Kitaoka 120a6e
    m_selectedSegment = -1;             // then clear the segment selection
Shinya Kitaoka 120a6e
  makeCurrent();
Shinya Kitaoka 120a6e
  emit selectionChanged();
Shinya Kitaoka 120a6e
  m_selectedCells = QRect();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool FunctionSelection::isSelected(TDoubleParam *curve, int k) const {
Shinya Kitaoka 120a6e
  int i = getCurveIndex(curve);
Shinya Kitaoka 120a6e
  if (i < 0)
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return m_selectedKeyframes[i].second.contains(k);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
int FunctionSelection::getSelectedKeyframeCount() const {
Shinya Kitaoka 120a6e
  int count = 0;
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
    count += m_selectedKeyframes[i].second.size();
Shinya Kitaoka 120a6e
  return count;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
QPair<tdoubleparam *,="" int=""> FunctionSelection::getSelectedKeyframe(</tdoubleparam>
Shinya Kitaoka 120a6e
    int index) const {
Shinya Kitaoka 120a6e
  if (index < 0) return QPair<tdoubleparam *,="" int="">(0, -1);</tdoubleparam>
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++) {
Shinya Kitaoka 120a6e
    int count = m_selectedKeyframes[i].second.size();
Shinya Kitaoka 120a6e
    if (index < count) {
Shinya Kitaoka 120a6e
      TDoubleParam *curve          = m_selectedKeyframes[i].first;
Shinya Kitaoka 120a6e
      QSet<int>::const_iterator it = m_selectedKeyframes[i].second.begin();</int>
shun-iwasawa 443318
      std::advance(it, index);
Shinya Kitaoka 120a6e
      return QPair<tdoubleparam *,="" int="">(curve, *it);</tdoubleparam>
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    index -= count;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return QPair<tdoubleparam *,="" int="">(0, -1);</tdoubleparam>
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
// called from FunctionCurve::MousePressEvent() and
Shinya Kitaoka 120a6e
// NumericalColumns::SelectCells()
Shinya Kitaoka 120a6e
void FunctionSelection::selectSegment(TDoubleParam *curve, int k,
Shinya Kitaoka 120a6e
                                      QRect selectedCells) {
Shinya Kitaoka 120a6e
  if (curve == 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // if a different curve is selected the clear the old selection
Shinya Kitaoka 120a6e
  if (m_selectedKeyframes.size() != 1 ||
Shinya Kitaoka 120a6e
      m_selectedKeyframes[0].first != curve) {
Shinya Kitaoka 120a6e
    curve->addRef();
Shinya Kitaoka 120a6e
    for (int i = 0; i < m_selectedKeyframes.size(); i++)
Shinya Kitaoka 120a6e
      if (m_selectedKeyframes[i].first) m_selectedKeyframes[i].first->release();
Shinya Kitaoka 120a6e
    m_selectedKeyframes.clear();
Shinya Kitaoka 120a6e
    m_selectedKeyframes.push_back(qMakePair(curve, QSet<int>()));</int>
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  m_selectedKeyframes[0].second.clear();
Shinya Kitaoka 120a6e
  m_selectedKeyframes[0].second.insert(k);  // k is keyframe id
Shinya Kitaoka 120a6e
  m_selectedKeyframes[0].second.insert(k + 1);
Shinya Kitaoka 120a6e
  m_selectedSegment = k;
Shinya Kitaoka 120a6e
  m_selectedCells   = selectedCells;
Shinya Kitaoka 120a6e
  makeCurrent();
Shinya Kitaoka 120a6e
  emit selectionChanged();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
bool FunctionSelection::isSegmentSelected(TDoubleParam *curve, int k) const {
Shinya Kitaoka 120a6e
  return m_selectedKeyframes.size() == 1 &&
Shinya Kitaoka 120a6e
         m_selectedKeyframes[0].first == curve && m_selectedSegment == k;
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
QPair<tdoubleparam *,="" int=""> FunctionSelection::getSelectedSegment() const {</tdoubleparam>
Shinya Kitaoka 120a6e
  if (m_selectedKeyframes.size() == 1 && m_selectedSegment >= 0)
Shinya Kitaoka 120a6e
    return qMakePair(m_selectedKeyframes[0].first, m_selectedSegment);
Shinya Kitaoka 120a6e
  else
Shinya Kitaoka 120a6e
    return qMakePair<tdoubleparam *,="" int="">(0, -1);</tdoubleparam>
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::enableCommands() {
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Copy", &FunctionSelection::doCopy);
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Paste", &FunctionSelection::doPaste);
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Cut", &FunctionSelection::doCut);
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Clear", &FunctionSelection::doDelete);
Shinya Kitaoka 120a6e
  enableCommand(this, "MI_Insert", &FunctionSelection::insertCells);
shun-iwasawa 298c96
shun-iwasawa 298c96
  enableCommand(this, "MI_ResetStep", &FunctionSelection::setStep1);
shun-iwasawa 298c96
  enableCommand(this, "MI_Step2", &FunctionSelection::setStep2);
shun-iwasawa 298c96
  enableCommand(this, "MI_Step3", &FunctionSelection::setStep3);
shun-iwasawa 298c96
  enableCommand(this, "MI_Step4", &FunctionSelection::setStep4);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
void FunctionSelection::doCopy() {
Shinya Kitaoka 120a6e
  if (isEmpty()) return;
Shinya Kitaoka 120a6e
  FunctionKeyframesData *data = new FunctionKeyframesData();
Shinya Kitaoka 120a6e
  int columnCount             = m_selectedKeyframes.size();
Shinya Kitaoka 120a6e
  data->setColumnCount(columnCount);
Shinya Kitaoka 120a6e
  for (int col = 0; col < columnCount; col++)
Shinya Kitaoka 120a6e
    data->getData(col, m_selectedKeyframes[col].first, m_selectedCells.top(),
Shinya Kitaoka 120a6e
                  m_selectedKeyframes[col].second);
Shinya Kitaoka 120a6e
  const QMimeData *oldData = QApplication::clipboard()->mimeData();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(new KeyframesCopyUndo(oldData, data));
Shinya Kitaoka 120a6e
  QApplication::clipboard()->setMimeData(data);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::doPaste() {
Shinya Kitaoka 120a6e
  const FunctionKeyframesData *data =
Shinya Kitaoka 120a6e
      dynamic_cast<const *="" functionkeyframesdata="">(</const>
Shinya Kitaoka 120a6e
          QApplication::clipboard()->mimeData());
Shinya Kitaoka 120a6e
  if (!data) return;
Shinya Kitaoka 120a6e
  int rowCount = data->getRowCount();
Shinya Kitaoka 120a6e
  if (rowCount <= 0) return;
Shinya Kitaoka 120a6e
  int columnCount = data->getColumnCount();
Shinya Kitaoka 120a6e
  double frame    = 0;
Shinya Kitaoka 120a6e
  int col         = 0;
Shinya Kitaoka 120a6e
  std::vector<tdoubleparam *=""> params;</tdoubleparam>
Shinya Kitaoka 120a6e
  if (!m_selectedCells.isEmpty()) {
Shinya Kitaoka 120a6e
    col = m_selectedCells.left();
Shinya Kitaoka 120a6e
    // numeric columns
Shinya Kitaoka 120a6e
    for (int c = 0; c < columnCount; c++) {
Shinya Kitaoka 120a6e
      TDoubleParam *curve = getCurveFromColumn(col + c);
Shinya Kitaoka 120a6e
      if (curve) params.push_back(curve);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    columnCount = (int)params.size();
Shinya Kitaoka 120a6e
    if (columnCount <= 0) return;
Shinya Kitaoka 120a6e
    frame = m_selectedCells.top();
Shinya Kitaoka 120a6e
    col   = m_selectedCells.left();
Shinya Kitaoka 120a6e
    selectCells(QRect(col, frame, columnCount, rowCount));
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // curves
Shinya Kitaoka 120a6e
    // only single curve selection supported
Shinya Kitaoka 120a6e
    columnCount = 1;
Shinya Kitaoka 120a6e
    if (m_selectedKeyframes.empty()) return;
Shinya Kitaoka 120a6e
    TDoubleParam *curve = m_selectedKeyframes[0].first;
Shinya Kitaoka 120a6e
    if (curve == 0) return;
Shinya Kitaoka 120a6e
    int kIndex = *(m_selectedKeyframes[0].second.begin());
Shinya Kitaoka 120a6e
    frame      = curve->keyframeIndexToFrame(kIndex);
Shinya Kitaoka 120a6e
    params.push_back(curve);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  /*--- カーブの貼り付け時に循環参照をチェックして、駄目ならアラートを返す ---*/
Shinya Kitaoka 120a6e
  for (int c = 0; c < columnCount; c++) {
Shinya Kitaoka 120a6e
    if (!data->isCircularReferenceFree(c, params[c])) {
Shinya Kitaoka 120a6e
      DVGui::warning(
Shinya Kitaoka 120a6e
          tr("There is a circular reference in the definition of the "
Shinya Kitaoka 120a6e
             "interpolation."));
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(new KeyframesPasteUndo(params, data, frame));
Shinya Kitaoka 120a6e
  for (int c = 0; c < columnCount; c++) data->setData(c, params[c], frame);
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::doCut() {
Shinya Kitaoka 120a6e
  TUndoManager::manager()->beginBlock();
Shinya Kitaoka 120a6e
  doCopy();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool cellsSelection = !m_selectedCells.isEmpty();
Shinya Kitaoka 120a6e
  int bottomRow       = m_selectedCells.bottom();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  KeyframesMoveUndo *moveUndo = new KeyframesMoveUndo();
Shinya Kitaoka 120a6e
  for (int i = 0; i < m_selectedKeyframes.size(); i++) {
shun-iwasawa 298c96
    TDoubleParam *curve = m_selectedKeyframes[i].first;
shun-iwasawa 298c96
    QSet<int> &kk       = m_selectedKeyframes[i].second;</int>
shun-iwasawa 298c96
    double delta        = 0;
Shinya Kitaoka 120a6e
    if (cellsSelection) delta = -m_selectedCells.height();
shun-iwasawa 298c96
    int n = curve ? curve->getKeyframeCount() : 0;
shun-iwasawa 298c96
    int j = 0;
Shinya Kitaoka 120a6e
    for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
      if (kk.contains(i)) {
Shinya Kitaoka 120a6e
        if (i + 1 < n && kk.contains(i + 1) && !cellsSelection)
Shinya Kitaoka 120a6e
          delta += curve->keyframeIndexToFrame(i) -
Shinya Kitaoka 120a6e
                   curve->keyframeIndexToFrame(i + 1);
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        if ((cellsSelection && bottomRow <= curve->keyframeIndexToFrame(i)) ||
Shinya Kitaoka 120a6e
            (!cellsSelection && delta != 0))
Shinya Kitaoka 120a6e
          moveUndo->addMovement(curve, j, delta);
Shinya Kitaoka 120a6e
        j++;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  doDelete();
Shinya Kitaoka 120a6e
  if (moveUndo->getCount()) {
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(moveUndo);
Shinya Kitaoka 120a6e
    moveUndo->redo();
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    delete moveUndo;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  TUndoManager::manager()->endBlock();
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::doDelete() {
Shinya Kitaoka 120a6e
  if (isEmpty()) return;
Shinya Kitaoka 120a6e
  std::vector<keyframesdeleteundo::column> columns;</keyframesdeleteundo::column>
Shinya Kitaoka 120a6e
  for (int col = 0; col < (int)m_selectedKeyframes.size(); col++) {
Shinya Kitaoka 120a6e
    KeyframesDeleteUndo::Column column;
Shinya Kitaoka 120a6e
    TDoubleParam *param = m_selectedKeyframes[col].first;
Shinya Kitaoka 120a6e
    if (!param || !param->hasKeyframes()) continue;
Shinya Kitaoka 120a6e
    column.m_param     = param;
Shinya Kitaoka 120a6e
    column.m_keyframes = m_selectedKeyframes[col].second;
Shinya Kitaoka 120a6e
    columns.push_back(column);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  if (columns.empty()) return;
Shinya Kitaoka 120a6e
  KeyframesDeleteUndo *undo = new KeyframesDeleteUndo(columns);
Shinya Kitaoka 120a6e
  undo->redo();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Shinya Kitaoka 120a6e
  selectNone();
Shinya Kitaoka 120a6e
}
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void FunctionSelection::insertCells() {
Shinya Kitaoka 120a6e
  if (isEmpty()) return;
Shinya Kitaoka 120a6e
  QRect selectedCells     = getSelectedCells();
Shinya Kitaoka 120a6e
  int frameDelta          = selectedCells.height();
Shinya Kitaoka 120a6e
  int row                 = selectedCells.top();
Shinya Kitaoka 120a6e
  KeyframesMoveUndo *undo = new KeyframesMoveUndo();
Shinya Kitaoka 120a6e
  for (int c = selectedCells.left(); c <= selectedCells.right(); c++) {
Shinya Kitaoka 120a6e
    TDoubleParam *param = getCurveFromColumn(c);
Shinya Kitaoka 120a6e
    if (param && param->hasKeyframes()) {
Shinya Kitaoka 120a6e
      // Move keyframes in reverse, so their ordering remains consistent at each
Shinya Kitaoka 120a6e
      // step
Shinya Kitaoka 120a6e
      int k = param->getKeyframeCount() - 1;
Shinya Kitaoka 120a6e
      for (; k >= 0 && param->keyframeIndexToFrame(k) >= row; --k)
Shinya Kitaoka 120a6e
        undo->addMovement(param, k, frameDelta);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  undo->redo();
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
shun-iwasawa 298c96
void FunctionSelection::setStep(int step, bool inclusive) {
shun-iwasawa 298c96
  if (isEmpty()) return;
shun-iwasawa 298c96
  TUndoManager::manager()->beginBlock();
shun-iwasawa 298c96
shun-iwasawa 298c96
  int row = getSelectedCells().top();
shun-iwasawa 298c96
  for (const auto &col : m_selectedKeyframes) {
shun-iwasawa 298c96
    TDoubleParam *curve = col.first;
shun-iwasawa 298c96
    // need to have at least one segment
shun-iwasawa 298c96
    if (!curve || curve->getKeyframeCount() <= 1) continue;
shun-iwasawa 298c96
shun-iwasawa 298c96
    // consider the keyframe just before the top row of the selected cells
shun-iwasawa 298c96
    if (inclusive) {
shun-iwasawa 298c96
      int topIndex = curve->getPrevKeyframe(row);
shun-iwasawa 298c96
      if (topIndex != -1 && topIndex != curve->getKeyframeCount() - 1 &&
shun-iwasawa 298c96
          !col.second.contains(topIndex))
shun-iwasawa 298c96
        KeyframeSetter(curve, topIndex).setStep(step);
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
shun-iwasawa 298c96
    for (const int &kIndex : col.second) {
shun-iwasawa 298c96
      // ignore the last key
shun-iwasawa 298c96
      if (kIndex == curve->getKeyframeCount() - 1) continue;
shun-iwasawa 298c96
      KeyframeSetter(curve, kIndex).setStep(step);
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
  }
shun-iwasawa 298c96
shun-iwasawa 298c96
  TUndoManager::manager()->endBlock();
shun-iwasawa 298c96
}
shun-iwasawa 298c96
shun-iwasawa 298c96
int FunctionSelection::getCommonStep(bool inclusive) {
shun-iwasawa 298c96
  if (isEmpty()) return -1;
shun-iwasawa 298c96
shun-iwasawa 298c96
  int step = -1;
shun-iwasawa 298c96
  int row  = getSelectedCells().top();
shun-iwasawa 298c96
  for (const auto &col : m_selectedKeyframes) {
shun-iwasawa 298c96
    TDoubleParam *curve = col.first;
shun-iwasawa 298c96
    // need to have at least one segment
shun-iwasawa 298c96
    if (!curve || curve->getKeyframeCount() <= 1) continue;
shun-iwasawa 298c96
shun-iwasawa 298c96
    // consider the keyframe just before the top row of the selected cells
shun-iwasawa 298c96
    if (inclusive) {
shun-iwasawa 298c96
      int topIndex = curve->getPrevKeyframe(row);
shun-iwasawa 298c96
      if (topIndex != -1 && topIndex != curve->getKeyframeCount() - 1 &&
shun-iwasawa 298c96
          !col.second.contains(topIndex))
shun-iwasawa 298c96
        step = curve->getKeyframe(topIndex).m_step;
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
shun-iwasawa 298c96
    for (const int &kIndex : col.second) {
shun-iwasawa 298c96
      // ignore the last key
shun-iwasawa 298c96
      if (kIndex == curve->getKeyframeCount() - 1) continue;
shun-iwasawa 298c96
      int tmpStep = curve->getKeyframe(kIndex).m_step;
shun-iwasawa 298c96
      if (step == -1)
shun-iwasawa 298c96
        step = tmpStep;
shun-iwasawa 298c96
      else if (step != tmpStep)
shun-iwasawa 298c96
        return 0;
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
  }
shun-iwasawa 298c96
  return step;
shun-iwasawa 298c96
}
shun-iwasawa 298c96
shun-iwasawa 298c96
void FunctionSelection::setSegmentType(TDoubleKeyframe::Type type,
shun-iwasawa 298c96
                                       bool inclusive) {
shun-iwasawa 298c96
  if (isEmpty()) return;
shun-iwasawa 298c96
  TUndoManager::manager()->beginBlock();
shun-iwasawa 298c96
shun-iwasawa 298c96
  int row = getSelectedCells().top();
shun-iwasawa 298c96
  for (const auto &col : m_selectedKeyframes) {
shun-iwasawa 298c96
    TDoubleParam *curve = col.first;
shun-iwasawa 298c96
    // need to have at least one segment
shun-iwasawa 298c96
    if (!curve || curve->getKeyframeCount() <= 1) continue;
shun-iwasawa 298c96
shun-iwasawa 298c96
    // consider the keyframe just before the top row of the selected cells
shun-iwasawa 298c96
    if (inclusive) {
shun-iwasawa 298c96
      int topIndex = curve->getPrevKeyframe(row);
shun-iwasawa 298c96
      if (topIndex != -1 && topIndex != curve->getKeyframeCount() - 1 &&
shun-iwasawa 298c96
          !col.second.contains(topIndex))
shun-iwasawa 298c96
        KeyframeSetter(curve, topIndex).setType(type);
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
shun-iwasawa 298c96
    for (const int &kIndex : col.second) {
shun-iwasawa 298c96
      // ignore the last key
shun-iwasawa 298c96
      if (kIndex == curve->getKeyframeCount() - 1) continue;
shun-iwasawa 298c96
      KeyframeSetter(curve, kIndex).setType(type);
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
  }
shun-iwasawa 298c96
shun-iwasawa 298c96
  TUndoManager::manager()->endBlock();
shun-iwasawa 298c96
}
shun-iwasawa 298c96
shun-iwasawa 298c96
int FunctionSelection::getCommonSegmentType(bool inclusive) {
shun-iwasawa 298c96
  if (isEmpty()) return -1;
shun-iwasawa 298c96
shun-iwasawa 298c96
  int type = -1;
shun-iwasawa 298c96
  int row  = getSelectedCells().top();
shun-iwasawa 298c96
  for (const auto &col : m_selectedKeyframes) {
shun-iwasawa 298c96
    TDoubleParam *curve = col.first;
shun-iwasawa 298c96
    // need to have at least one segment
shun-iwasawa 298c96
    if (!curve || curve->getKeyframeCount() <= 1) continue;
shun-iwasawa 298c96
shun-iwasawa 298c96
    // consider the keyframe just before the top row of the selected cells
shun-iwasawa 298c96
    if (inclusive) {
shun-iwasawa 298c96
      int topIndex = curve->getPrevKeyframe(row);
shun-iwasawa 298c96
      if (topIndex != -1 && topIndex != curve->getKeyframeCount() - 1 &&
shun-iwasawa 298c96
          !col.second.contains(topIndex))
shun-iwasawa 298c96
        type = (int)(curve->getKeyframe(topIndex).m_type);
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
shun-iwasawa 298c96
    for (const int &kIndex : col.second) {
shun-iwasawa 298c96
      // ignore the last key
shun-iwasawa 298c96
      if (kIndex == curve->getKeyframeCount() - 1) continue;
shun-iwasawa 298c96
      int tmpType = (int)(curve->getKeyframe(kIndex).m_type);
shun-iwasawa 298c96
      if (type == -1)
shun-iwasawa 298c96
        type = tmpType;
shun-iwasawa 298c96
      else if (type != tmpType)
shun-iwasawa 298c96
        return 0;
shun-iwasawa 298c96
    }
shun-iwasawa 298c96
  }
shun-iwasawa 298c96
  return type;
shun-iwasawa 298c96
}
shun-iwasawa 298c96
shun-iwasawa 23df06
QList<int> FunctionSelection::getSelectedKeyIndices(TDoubleParam *curve) {</int>
shun-iwasawa 23df06
  for (auto selectedParam : m_selectedKeyframes) {
shun-iwasawa 23df06
    if (curve == selectedParam.first) {
shun-iwasawa 23df06
      QList<int> ret = selectedParam.second.toList();</int>
shun-iwasawa 23df06
      std::sort(ret.begin(), ret.end());
shun-iwasawa 23df06
      return ret;
shun-iwasawa 23df06
    }
shun-iwasawa 23df06
  }
shun-iwasawa 23df06
  return QList<int>();</int>
shun-iwasawa 23df06
}
shun-iwasawa 23df06
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// FunctionKeyframesData
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
FunctionKeyframesData::FunctionKeyframesData() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
FunctionKeyframesData::~FunctionKeyframesData() {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionKeyframesData::setColumnCount(int columnCount) {
Shinya Kitaoka 120a6e
  m_keyframes.resize(columnCount);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionKeyframesData::getData(int columnIndex, TDoubleParam *curve,
Shinya Kitaoka 120a6e
                                    double frame, const QSet<int> &kIndices) {</int>
Shinya Kitaoka 120a6e
  assert(0 <= columnIndex && columnIndex < (int)m_keyframes.size());
Shinya Kitaoka 120a6e
  Keyframes &keyframes = m_keyframes[columnIndex];
Shinya Kitaoka 120a6e
  keyframes.clear();
Shinya Kitaoka 120a6e
  if (!kIndices.empty()) {
Shinya Kitaoka 120a6e
    double dFrame = -frame;
Shinya Kitaoka 120a6e
    QSet<int>::const_iterator it;</int>
Shinya Kitaoka 120a6e
    for (it = kIndices.begin(); it != kIndices.end(); ++it) {
Shinya Kitaoka 120a6e
      TDoubleKeyframe keyframe = curve->getKeyframe(*it);
Shinya Kitaoka 120a6e
      keyframe.m_frame += dFrame;
Shinya Kitaoka 120a6e
      keyframes.push_back(keyframe);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void FunctionKeyframesData::setData(int columnIndex, TDoubleParam *curve,
Shinya Kitaoka 120a6e
                                    double frame) const {
Shinya Kitaoka 120a6e
  assert(0 <= columnIndex && columnIndex < (int)m_keyframes.size());
Shinya Kitaoka 120a6e
  const Keyframes &keyframes = m_keyframes[columnIndex];
Shinya Kitaoka 120a6e
  int n                      = (int)keyframes.size();
Shinya Kitaoka 120a6e
  for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    TDoubleKeyframe keyframe(keyframes[i]);
Shinya Kitaoka 120a6e
    keyframe.m_frame += frame;
Shinya Kitaoka 120a6e
    if (i == 0 || i == n - 1) keyframe.m_linkedHandles = false;
Shinya Kitaoka 120a6e
    curve->setKeyframe(keyframe);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
const FunctionKeyframesData::Keyframes &FunctionKeyframesData::getKeyframes(
Shinya Kitaoka 120a6e
    int columnIndex) const {
Shinya Kitaoka 120a6e
  assert(0 <= columnIndex && columnIndex < (int)m_keyframes.size());
Shinya Kitaoka 120a6e
  return m_keyframes[columnIndex];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DvMimeData *FunctionKeyframesData::clone() const {
Shinya Kitaoka 120a6e
  FunctionKeyframesData *data = new FunctionKeyframesData();
Shinya Kitaoka 120a6e
  data->m_keyframes           = m_keyframes;
Shinya Kitaoka 120a6e
  return data;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
int FunctionKeyframesData::getRowCount() const {
Shinya Kitaoka 120a6e
  int rowCount = 0;
Shinya Kitaoka 120a6e
  for (int c = 0; c < (int)m_keyframes.size(); c++) {
Shinya Kitaoka 120a6e
    const Keyframes &keyframes = m_keyframes[c];
Shinya Kitaoka 120a6e
    if (!keyframes.empty()) {
shun-iwasawa 298c96
      int row = (int)(keyframes.rbegin()->m_frame);
Shinya Kitaoka 120a6e
      if (row + 1 > rowCount) rowCount = row + 1;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return rowCount;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*---- カーブの貼り付け時に循環参照をチェックして、駄目ならfalseを返す ----*/
Shinya Kitaoka 120a6e
bool FunctionKeyframesData::isCircularReferenceFree(int columnIndex,
Shinya Kitaoka 120a6e
                                                    TDoubleParam *curve) const {
Shinya Kitaoka 120a6e
  const Keyframes &keyframes = m_keyframes[columnIndex];
Shinya Kitaoka 120a6e
  int n                      = (int)keyframes.size();
Shinya Kitaoka 120a6e
  // for each key frame
Shinya Kitaoka 120a6e
  for (int i = 0; i < n; i++) {
Shinya Kitaoka 120a6e
    TDoubleKeyframe keyframe(keyframes[i]);
Shinya Kitaoka 120a6e
    // only check Expression type
Shinya Kitaoka 120a6e
    if (keyframe.m_type != TDoubleKeyframe::Expression) continue;
Shinya Kitaoka 120a6e
    // check circular reference
Shinya Kitaoka 120a6e
    TExpression expr;
Shinya Kitaoka 120a6e
    expr.setGrammar(curve->getGrammar());
Shinya Kitaoka 120a6e
    expr.setText(keyframe.m_expressionText);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (dependsOn(expr, curve)) return false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}