Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonz/doubleparamcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/preferences.h"
Toshihiro Shimizu 890ddd
#include "tdoubleparam.h"
Toshihiro Shimizu 890ddd
#include "tdoublekeyframe.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
#include "tunit.h"
Toshihiro Shimizu 890ddd
#include <qstring></qstring>
Toshihiro Shimizu 890ddd
#include <map></map>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DV_IMPORT_API void splitSpeedInOutSegment(
Toshihiro Shimizu 890ddd
	TDoubleKeyframe &k,
Toshihiro Shimizu 890ddd
	TDoubleKeyframe &k0,
Toshihiro Shimizu 890ddd
	TDoubleKeyframe &k1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// Keyframes Undo
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class KeyframesUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TDoubleParamP m_param;
Toshihiro Shimizu 890ddd
	typedef std::map<int, tdoublekeyframe=""> Keyframes;</int,>
Toshihiro Shimizu 890ddd
	Keyframes m_oldKeyframes;
Toshihiro Shimizu 890ddd
	Keyframes m_newKeyframes;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	KeyframesUndo(TDoubleParam *param) : m_param(param) {}
Toshihiro Shimizu 890ddd
	void addKeyframe(int kIndex)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_oldKeyframes.count(kIndex) > 0)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		assert(0 <= kIndex && kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
		m_oldKeyframes[kIndex] = m_param->getKeyframe(kIndex);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int createKeyframe(double frame)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TDoubleKeyframe oldKeyframe = m_param->getKeyframeAt(frame);
Toshihiro Shimizu 890ddd
		if (oldKeyframe.m_isKeyframe) {
Toshihiro Shimizu 890ddd
			int kIndex = m_param->getClosestKeyframe(oldKeyframe.m_frame);
Toshihiro Shimizu 890ddd
			assert(0 <= kIndex && kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
			assert(m_param->keyframeIndexToFrame(kIndex) == oldKeyframe.m_frame);
Toshihiro Shimizu 890ddd
			return kIndex;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(oldKeyframe);
Toshihiro Shimizu 890ddd
		int kIndex = m_param->getClosestKeyframe(oldKeyframe.m_frame);
Toshihiro Shimizu 890ddd
		assert(0 <= kIndex && kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
		assert(m_param->keyframeIndexToFrame(kIndex) == oldKeyframe.m_frame);
Toshihiro Shimizu 890ddd
		assert(m_oldKeyframes.count(kIndex) == 0);
Toshihiro Shimizu 890ddd
		m_oldKeyframes[kIndex] = oldKeyframe;
Toshihiro Shimizu 890ddd
		return kIndex;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void onAdd()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		Keyframes::iterator it;
Toshihiro Shimizu 890ddd
		for (it = m_oldKeyframes.begin(); it != m_oldKeyframes.end(); ++it) {
Toshihiro Shimizu 890ddd
			int kIndex = it->first;
Toshihiro Shimizu 890ddd
			assert(0 <= kIndex && kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
			m_newKeyframes[kIndex] = m_param->getKeyframe(kIndex);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(m_oldKeyframes);
Toshihiro Shimizu 890ddd
		Keyframes::const_iterator it;
Toshihiro Shimizu 890ddd
		for (it = m_oldKeyframes.begin(); it != m_oldKeyframes.end(); ++it)
Toshihiro Shimizu 890ddd
			if (!it->second.m_isKeyframe)
Toshihiro Shimizu 890ddd
				m_param->deleteKeyframe(it->second.m_frame);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		Keyframes::const_iterator it;
Toshihiro Shimizu 890ddd
		for (it = m_oldKeyframes.begin(); it != m_oldKeyframes.end(); ++it)
Toshihiro Shimizu 890ddd
			if (!it->second.m_isKeyframe)
Toshihiro Shimizu 890ddd
				m_param->setKeyframe(it->second);
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(m_newKeyframes);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int getSize() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return sizeof(*this) + sizeof(*m_oldKeyframes.begin()) * 2 * m_oldKeyframes.size();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	QString getHistoryString()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return QObject::tr("Set Keyframe");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
// KeyframeSetter
Toshihiro Shimizu 890ddd
//
Toshihiro Shimizu 890ddd
//-----------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
KeyframeSetter::KeyframeSetter(TDoubleParam *param, int kIndex, bool enableUndo)
Toshihiro Shimizu 890ddd
	: m_param(param), m_kIndex(-1), m_extraDFrame(0), m_enableUndo(enableUndo), m_undo(new KeyframesUndo(param)), m_changed(false), m_pixelRatio(1)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (kIndex >= 0)
Toshihiro Shimizu 890ddd
		selectKeyframe(kIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
KeyframeSetter::~KeyframeSetter()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_enableUndo)
Toshihiro Shimizu 890ddd
		addUndo();
Toshihiro Shimizu 890ddd
	else if (m_undo) {
Toshihiro Shimizu 890ddd
		delete m_undo;
Toshihiro Shimizu 890ddd
		m_undo = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::addUndo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_undo) {
Toshihiro Shimizu 890ddd
		if (m_changed)
Toshihiro Shimizu 890ddd
			TUndoManager::manager()->add(m_undo);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			delete m_undo;
Toshihiro Shimizu 890ddd
		m_undo = 0;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::selectKeyframe(int kIndex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_indices.count(kIndex) == 0) {
Toshihiro Shimizu 890ddd
		m_indices.insert(kIndex);
Toshihiro Shimizu 890ddd
		m_undo->addKeyframe(kIndex);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_kIndex = kIndex;
Toshihiro Shimizu 890ddd
	m_keyframe = m_param->getKeyframe(m_kIndex);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// set key frame at frame and returns its index
Toshihiro Shimizu 890ddd
int KeyframeSetter::createKeyframe(double frame)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	/*--- すでにそこにキーフレームがある場合はそのIndexを返すだけ ---*/
Toshihiro Shimizu 890ddd
	int kIndex = m_param->getClosestKeyframe(frame);
Toshihiro Shimizu 890ddd
	if (kIndex >= 0 && m_param->getKeyframe(kIndex).m_frame == frame) {
Toshihiro Shimizu 890ddd
		selectKeyframe(kIndex);
Toshihiro Shimizu 890ddd
		return kIndex;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	kIndex = m_undo->createKeyframe(frame);
Toshihiro Shimizu 890ddd
	m_indices.insert(kIndex);
Toshihiro Shimizu 890ddd
	m_kIndex = kIndex;
Toshihiro Shimizu 890ddd
	m_keyframe = m_param->getKeyframe(m_kIndex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	setStep(Preferences::instance()->getAnimationStep());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int kCount = m_param->getKeyframeCount();
Toshihiro Shimizu 890ddd
	if (kCount <= 1) {
Toshihiro Shimizu 890ddd
		// a single keyframe created in a empty curve
Toshihiro Shimizu 890ddd
	} else if (kCount == 2) {
Toshihiro Shimizu 890ddd
		// two keyframes => a linear segment
Toshihiro Shimizu 890ddd
		TDoubleKeyframe::Type type = TDoubleKeyframe::Type(Preferences::instance()->getKeyframeType());
Toshihiro Shimizu 890ddd
		setType(0, type);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// there are at least other two keyframes (and therefore at least a segment)
Toshihiro Shimizu 890ddd
		if (m_kIndex == 0) {
Toshihiro Shimizu 890ddd
			// a new segment added before the others. use the preference value
Toshihiro Shimizu 890ddd
			setType(TDoubleKeyframe::Type(Preferences::instance()->getKeyframeType()));
Toshihiro Shimizu 890ddd
		} else if (m_kIndex == kCount - 1) {
Toshihiro Shimizu 890ddd
			// a new segment added after the others. use the preference value too
Toshihiro Shimizu 890ddd
			setType(m_kIndex - 1, TDoubleKeyframe::Type(Preferences::instance()->getKeyframeType()));
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			// a new point in a segment
Toshihiro Shimizu 890ddd
			TDoubleKeyframe ka = m_param->getKeyframe(m_kIndex - 1);
Toshihiro Shimizu 890ddd
			TDoubleKeyframe kb = m_param->getKeyframe(m_kIndex + 1);
Toshihiro Shimizu 890ddd
			TDoubleKeyframe::Type segmentType = ka.m_type;
Toshihiro Shimizu 890ddd
			m_keyframe.m_type = ka.m_type;
Toshihiro Shimizu 890ddd
			m_keyframe.m_step = ka.m_step; //An existing segment step should prevail over the preference
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			/*---Segment内にKeyを打った場合は、Step値も元のSegmentの値を引き継ぐようにする---*/
Toshihiro Shimizu 890ddd
			m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (segmentType == TDoubleKeyframe::SpeedInOut ||
Toshihiro Shimizu 890ddd
				segmentType == TDoubleKeyframe::EaseInOut ||
Toshihiro Shimizu 890ddd
				segmentType == TDoubleKeyframe::EaseInOutPercentage) {
Toshihiro Shimizu 890ddd
				std::map<int, tdoublekeyframe=""> keyframes;</int,>
Toshihiro Shimizu 890ddd
				if (segmentType == TDoubleKeyframe::SpeedInOut) {
Toshihiro Shimizu 890ddd
					splitSpeedInOutSegment(m_keyframe, ka, kb);
Toshihiro Shimizu 890ddd
				} else if (segmentType == TDoubleKeyframe::EaseInOut) {
Toshihiro Shimizu 890ddd
					m_keyframe.m_speedIn = m_keyframe.m_speedOut = TPointD();
Toshihiro Shimizu 890ddd
					if (ka.m_frame + ka.m_speedOut.x > m_keyframe.m_frame)
Toshihiro Shimizu 890ddd
						ka.m_speedOut.x = m_keyframe.m_frame - ka.m_frame;
Toshihiro Shimizu 890ddd
					if (kb.m_frame + kb.m_speedIn.x < m_keyframe.m_frame)
Toshihiro Shimizu 890ddd
						ka.m_speedIn.x = m_keyframe.m_frame - kb.m_frame;
Toshihiro Shimizu 890ddd
				} else // easeinpercentage
Toshihiro Shimizu 890ddd
				{
Toshihiro Shimizu 890ddd
					m_keyframe.m_speedIn = m_keyframe.m_speedOut = TPointD();
Toshihiro Shimizu 890ddd
					double segmentWidth = kb.m_frame - ka.m_frame;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				keyframes[m_kIndex - 1] = ka;
Toshihiro Shimizu 890ddd
				keyframes[m_kIndex] = m_keyframe;
Toshihiro Shimizu 890ddd
				keyframes[m_kIndex + 1] = kb;
Toshihiro Shimizu 890ddd
				m_undo->addKeyframe(m_kIndex - 1);
Toshihiro Shimizu 890ddd
				m_undo->addKeyframe(m_kIndex + 1);
Toshihiro Shimizu 890ddd
				m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
			} else if (segmentType == TDoubleKeyframe::Expression || segmentType == TDoubleKeyframe::SimilarShape) {
Shinya Kitaoka 3bfa54
				std::string expressionText = ka.m_expressionText;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				setExpression(expressionText);
Toshihiro Shimizu 890ddd
				setType(ka.m_type);
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				setType(ka.m_type);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return kIndex;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool KeyframeSetter::isSpeedInOut(int segmentIndex) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return 0 <= segmentIndex && segmentIndex + 1 < m_param->getKeyframeCount() &&
Toshihiro Shimizu 890ddd
		   m_param->getKeyframe(segmentIndex).m_type == TDoubleKeyframe::SpeedInOut;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool KeyframeSetter::isEaseInOut(int segmentIndex) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (0 <= segmentIndex && segmentIndex + 1 < m_param->getKeyframeCount()) {
Toshihiro Shimizu 890ddd
		TDoubleKeyframe::Type type = m_param->getKeyframe(segmentIndex).m_type;
Toshihiro Shimizu 890ddd
		if (type == TDoubleKeyframe::EaseInOut || type == TDoubleKeyframe::EaseInOutPercentage)
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// find the speedInOut handles which will change when moving keyframe kIndex
Toshihiro Shimizu 890ddd
// rotatingSpeeds: { <speed, index="" keyframe=""> }</speed,>
Toshihiro Shimizu 890ddd
void KeyframeSetter::getRotatingSpeedHandles(
Toshihiro Shimizu 890ddd
	std::vector<std::pair<double, int="">> &rotatingSpeeds,</std::pair<double,>
Toshihiro Shimizu 890ddd
	TDoubleParam *param,
Toshihiro Shimizu 890ddd
	int kIndex) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double epsilon = 1.0e-7;
Toshihiro Shimizu 890ddd
	int ty[4] = {0, 0, 0, 0};
Toshihiro Shimizu 890ddd
	// ty[] refers to segments around the kIndex keyframe
Toshihiro Shimizu 890ddd
	// 1 ==> linear or exponential (they can cause speed handle rotation)
Toshihiro Shimizu 890ddd
	// 2 ==> speedinout
Toshihiro Shimizu 890ddd
	for (int i = 0; i < 4; i++) {
Toshihiro Shimizu 890ddd
		int k = kIndex + i - 2;
Toshihiro Shimizu 890ddd
		if (0 <= k && k < param->getKeyframeCount()) {
Toshihiro Shimizu 890ddd
			TDoubleKeyframe::Type type = param->getKeyframe(k).m_type;
Toshihiro Shimizu 890ddd
			if (type == TDoubleKeyframe::Linear || type == TDoubleKeyframe::Exponential)
Toshihiro Shimizu 890ddd
				ty[i] = 1;
Toshihiro Shimizu 890ddd
			else if (type == TDoubleKeyframe::SpeedInOut)
Toshihiro Shimizu 890ddd
				ty[i] = 2;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	// SpeedInOut * Linear *
Michał Janiszewski b1cc3c
	if ((ty[0] == 2 && ty[1] == 1) || (ty[1] == 2 && ty[2] == 1)) {
Toshihiro Shimizu 890ddd
		int k = ty[1] == 1 ? kIndex - 1 : kIndex;
Toshihiro Shimizu 890ddd
		double speed = getNorm(param->getSpeedIn(k));
Toshihiro Shimizu 890ddd
		if (speed > epsilon)
Toshihiro Shimizu 890ddd
			rotatingSpeeds.push_back(std::make_pair(-speed, k));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	// * Linear * SpeedInOut
Michał Janiszewski b1cc3c
	if ((ty[1] == 1 && ty[2] == 2) || (ty[2] == 1 && ty[3] == 2)) {
Toshihiro Shimizu 890ddd
		int k = ty[2] == 2 ? kIndex : kIndex + 1;
Toshihiro Shimizu 890ddd
		double speed = getNorm(param->getSpeedOut(k));
Toshihiro Shimizu 890ddd
		if (speed > epsilon)
Toshihiro Shimizu 890ddd
			rotatingSpeeds.push_back(std::make_pair(speed, k));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::moveKeyframes(int dFrame, double dValue)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int n = m_param->getKeyframeCount();
Toshihiro Shimizu 890ddd
	if (n == 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// to keep constant the "length" of speed handles which are modified as side effects
Toshihiro Shimizu 890ddd
	std::vector<std::pair<double, int="">> rotatingSpeedHandles;</std::pair<double,>
Toshihiro Shimizu 890ddd
	if (m_indices.size() == 1)
Toshihiro Shimizu 890ddd
		getRotatingSpeedHandles(rotatingSpeedHandles, m_param.getPointer(), *m_indices.begin());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// update the frame change (m_extraDFrame represent old moves
Toshihiro Shimizu 890ddd
	// which has not performed, e.g.  because of keyframe collisions)
Toshihiro Shimizu 890ddd
	dFrame += m_extraDFrame;
Toshihiro Shimizu 890ddd
	m_extraDFrame = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (dFrame != 0) {
Toshihiro Shimizu 890ddd
		// check frame constraints (keyframe collisions and segment type swaps)
Toshihiro Shimizu 890ddd
		double preferredDFrame = dFrame;
Toshihiro Shimizu 890ddd
		double dFrameSgn = dFrame < 0 ? -1 : 1;
Toshihiro Shimizu 890ddd
		dFrame *= dFrameSgn;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		typedef std::pair<tdoublekeyframe::type, tdoublekeyframe::type=""> TypePair;</tdoublekeyframe::type,>
Toshihiro Shimizu 890ddd
		std::vector<std::pair<double, typepair="">> keyframes(n);</std::pair<double,>
Toshihiro Shimizu 890ddd
		keyframes[0].second.first = TDoubleKeyframe::None;
Toshihiro Shimizu 890ddd
		for (int i = 0; i < n; i++) {
Toshihiro Shimizu 890ddd
			TDoubleKeyframe kf = m_param->getKeyframe(i);
Toshihiro Shimizu 890ddd
			keyframes[i].first = kf.m_frame;
Toshihiro Shimizu 890ddd
			if (i < n - 1) {
Toshihiro Shimizu 890ddd
				keyframes[i].second.second = kf.m_type;
Toshihiro Shimizu 890ddd
				keyframes[i + 1].second.first = kf.m_type;
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				keyframes[i].second.second = TDoubleKeyframe::None;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		while (dFrame > 0) {
Toshihiro Shimizu 890ddd
			std::vector<std::pair<double, typepair="">> mk(keyframes); // mk = moved keyframes</std::pair<double,>
Toshihiro Shimizu 890ddd
			std::set<int>::iterator it;</int>
Toshihiro Shimizu 890ddd
			for (it = m_indices.begin(); it != m_indices.end(); ++it)
Toshihiro Shimizu 890ddd
				mk[*it].first += dFrame * dFrameSgn;
Toshihiro Shimizu 890ddd
			std::sort(mk.begin(), mk.end());
Toshihiro Shimizu 890ddd
			bool ok = true;
Toshihiro Shimizu 890ddd
			int i;
Toshihiro Shimizu 890ddd
			for (i = 0; i + 1 < n && ok; i++) {
Toshihiro Shimizu 890ddd
				// check keyframe collisions
Toshihiro Shimizu 890ddd
				if (fabs(mk[i + 1].first - mk[i].first) < 1.e-8)
Toshihiro Shimizu 890ddd
					ok = false;
Toshihiro Shimizu 890ddd
				// check segment type swaps
Toshihiro Shimizu 890ddd
				if (mk[i].second.second != mk[i + 1].second.first &&
Toshihiro Shimizu 890ddd
					mk[i].second.second != TDoubleKeyframe::None &&
Toshihiro Shimizu 890ddd
					mk[i + 1].second.first != TDoubleKeyframe::None)
Toshihiro Shimizu 890ddd
					ok = false;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (ok)
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			dFrame -= 1;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		dFrame = dFrameSgn * tmax(0, dFrame);
Toshihiro Shimizu 890ddd
		if (dFrame != preferredDFrame)
Toshihiro Shimizu 890ddd
			m_extraDFrame = preferredDFrame - dFrame;
Toshihiro Shimizu 890ddd
		// at this point dFrame (possibly ==0) is ok (no keyframe collisions, no segment type mismatches)
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::map<int, tdoublekeyframe=""> change;</int,>
Toshihiro Shimizu 890ddd
	if (dFrame == 0) {
Toshihiro Shimizu 890ddd
		// only value changes
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::set<int>::iterator it;</int>
Toshihiro Shimizu 890ddd
		int i = 0;
Toshihiro Shimizu 890ddd
		m_changed = true;
Toshihiro Shimizu 890ddd
		for (it = m_indices.begin(); it != m_indices.end(); ++it, i++) {
Toshihiro Shimizu 890ddd
			TDoubleKeyframe keyframe = m_param->getKeyframe(*it);
Toshihiro Shimizu 890ddd
			keyframe.m_value += dValue;
Toshihiro Shimizu 890ddd
			change[*it] = keyframe;
Toshihiro Shimizu 890ddd
			m_undo->addKeyframe(i);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// frame+value changes
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int n = m_param->getKeyframeCount();
Toshihiro Shimizu 890ddd
		std::vector<std::pair<tdoublekeyframe, int="">> keyframes(n); // (keyframe, index)</std::pair<tdoublekeyframe,>
Toshihiro Shimizu 890ddd
		for (int i = 0; i < n; i++)
Toshihiro Shimizu 890ddd
			keyframes[i] = std::make_pair(m_param->getKeyframe(i), i);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// change frame and value of selected keyframes
Toshihiro Shimizu 890ddd
		std::set<int>::iterator it;</int>
Toshihiro Shimizu 890ddd
		for (it = m_indices.begin(); it != m_indices.end(); ++it) {
Toshihiro Shimizu 890ddd
			int i = *it;
Toshihiro Shimizu 890ddd
			keyframes[i].first.m_frame += dFrame;
Toshihiro Shimizu 890ddd
			keyframes[i].first.m_value += dValue;
Toshihiro Shimizu 890ddd
			// keyframes[i].second = -1;  // to mark keyframes involved in the move
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		// keyframes.back().first.m_type = TDoubleKeyframe::None;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// clear selection (indices can change: we have to rebuild it)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::set<int> oldSelection(m_indices);</int>
Toshihiro Shimizu 890ddd
		m_indices.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// sort keyframes (according to their - updated - frames)
Toshihiro Shimizu 890ddd
		std::sort(keyframes.begin(), keyframes.end());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (std::set<int>::iterator it = oldSelection.begin(); it != oldSelection.end(); ++it)</int>
Toshihiro Shimizu 890ddd
			m_indices.insert(keyframes[*it].second);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// update segment types (because of swaps)
Toshihiro Shimizu 890ddd
		/*
Toshihiro Shimizu 890ddd
    for(int i=0;i+1
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      TDoubleKeyframe &kfa = keyframes[i].first;
Toshihiro Shimizu 890ddd
      TDoubleKeyframe &kfb = keyframes[i+1].first;
Toshihiro Shimizu 890ddd
      if(kfa.m_type == TDoubleKeyframe::None)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        kfa.m_type = TDoubleKeyframe::SpeedInOut;
Toshihiro Shimizu 890ddd
        kfa.m_speedOut = TPointD(0,0);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
      if(kfb.m_prevType == TDoubleKeyframe::None)
Toshihiro Shimizu 890ddd
      {
Toshihiro Shimizu 890ddd
        kfa.m_prevType = TDoubleKeyframe::SpeedInOut;
Toshihiro Shimizu 890ddd
        kfa.m_speedIn = TPointD(0,0);
Toshihiro Shimizu 890ddd
      }
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
    */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_changed = true;
Toshihiro Shimizu 890ddd
		for (int i = 0; i < n; i++) {
Toshihiro Shimizu 890ddd
			if (keyframes[i].second != i) {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				/*
Toshihiro Shimizu 890ddd
        // i-th keyframe has changed is order position
Toshihiro Shimizu 890ddd
        if(keyframes[i].first.m_type == TDoubleKeyframe::None)
Toshihiro Shimizu 890ddd
        {
Toshihiro Shimizu 890ddd
          if(i==n-1) keyframes[i].first.m_type = TDoubleKeyframe::Linear;
Toshihiro Shimizu 890ddd
          else keyframes[i].first.m_type = keyframes[i+1].first.m_type;
Toshihiro Shimizu 890ddd
        }
Toshihiro Shimizu 890ddd
        */
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				m_undo->addKeyframe(i);
Toshihiro Shimizu 890ddd
				change[i] = keyframes[i].first;
Toshihiro Shimizu 890ddd
			} else if (m_indices.count(i) > 0)
Toshihiro Shimizu 890ddd
				change[i] = keyframes[i].first;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_param->setKeyframes(change);
Toshihiro Shimizu 890ddd
	/*
Toshihiro Shimizu 890ddd
  if(!rotatingSpeedHandles.empty())
Toshihiro Shimizu 890ddd
  {
Toshihiro Shimizu 890ddd
    for(int i=0;i<(int)rotatingSpeedHandles.size();i++)
Toshihiro Shimizu 890ddd
    {
Toshihiro Shimizu 890ddd
      double speedLength = rotatingSpeedHandles[i].first;
Toshihiro Shimizu 890ddd
      int kIndex = rotatingSpeedHandles[i].second;
Toshihiro Shimizu 890ddd
      TDoubleKeyframe kf = m_param->getKeyframe(kIndex);
Toshihiro Shimizu 890ddd
      TPointD speed = speedLength<0 ? m_param->getSpeedIn(kIndex) : m_param->getSpeedOut(kIndex);
Toshihiro Shimizu 890ddd
      speed = fabs(speedLength/getNorm(speed)) * speed;
Toshihiro Shimizu 890ddd
      if(speedLength<0)
Toshihiro Shimizu 890ddd
        kf.m_speedIn = speed;
Toshihiro Shimizu 890ddd
      else
Toshihiro Shimizu 890ddd
        kf.m_speedOut = speed;
Toshihiro Shimizu 890ddd
      m_param->setKeyframe(kf);
Toshihiro Shimizu 890ddd
    }
Toshihiro Shimizu 890ddd
  }
Toshihiro Shimizu 890ddd
  */
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setType(int kIndex, TDoubleKeyframe::Type type)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(0 <= kIndex && kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
	// get the current keyframe value
Toshihiro Shimizu 890ddd
	TDoubleKeyframe keyframe = m_param->getKeyframe(kIndex);
Toshihiro Shimizu 890ddd
	// get the next keyframe (if any) and compute the segment length
Toshihiro Shimizu 890ddd
	TDoubleKeyframe nextKeyframe;
Toshihiro Shimizu 890ddd
	double segmentWidth = 1;
Toshihiro Shimizu 890ddd
	if (kIndex + 1 < m_param->getKeyframeCount()) {
Toshihiro Shimizu 890ddd
		nextKeyframe = m_param->getKeyframe(kIndex + 1);
Toshihiro Shimizu 890ddd
		segmentWidth = nextKeyframe.m_frame - keyframe.m_frame;
Toshihiro Shimizu 890ddd
	} else if (kIndex + 1 > m_param->getKeyframeCount()) {
Toshihiro Shimizu 890ddd
		// kIndex is the last keyframe. no segment is defined (therefore no segment type)
Toshihiro Shimizu 890ddd
		type = TDoubleKeyframe::Linear;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (type == keyframe.m_type)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// I'm going to change kIndex. Make sure it is selected. set the dirty flag
Toshihiro Shimizu 890ddd
	m_undo->addKeyframe(kIndex);
Toshihiro Shimizu 890ddd
	// m_indices.insert(kIndex);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	double ease0 = 0, ease1 = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::map<int, tdoublekeyframe=""> keyframes;</int,>
Toshihiro Shimizu 890ddd
	switch (type) {
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::SpeedInOut:
Toshihiro Shimizu 890ddd
		keyframe.m_speedOut = TPointD(segmentWidth / 3, 0);
Toshihiro Shimizu 890ddd
		nextKeyframe.m_speedIn = TPointD(-segmentWidth / 3, 0);
Toshihiro Shimizu 890ddd
		if (nextKeyframe.m_linkedHandles && nextKeyframe.m_speedOut.x > 0.01)
Toshihiro Shimizu 890ddd
			nextKeyframe.m_speedIn = -nextKeyframe.m_speedOut;
Toshihiro Shimizu 890ddd
		if (keyframe.m_linkedHandles && keyframe.m_speedIn.x < -0.01)
Toshihiro Shimizu 890ddd
			keyframe.m_speedOut = -keyframe.m_speedIn;
Toshihiro Shimizu 890ddd
		keyframe.m_type = type;
Toshihiro Shimizu 890ddd
		keyframes[kIndex] = keyframe;
Toshihiro Shimizu 890ddd
		keyframes[kIndex + 1] = nextKeyframe;
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::EaseInOut:
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::EaseInOutPercentage:
Toshihiro Shimizu 890ddd
		if (keyframe.m_type == TDoubleKeyframe::EaseInOut) {
Toshihiro Shimizu 890ddd
			// absolute -> percentage
Toshihiro Shimizu 890ddd
			ease0 = keyframe.m_speedOut.x * 100.0 / segmentWidth;
Toshihiro Shimizu 890ddd
			ease1 = -nextKeyframe.m_speedIn.x * 100.0 / segmentWidth;
Toshihiro Shimizu 890ddd
			// rounding could break constraints. crop parameters
Toshihiro Shimizu 890ddd
			ease0 = tcrop(ease0, 0.0, 100.0);
Toshihiro Shimizu 890ddd
			ease1 = tcrop(ease1, 0.0, 100.0 - ease0);
Toshihiro Shimizu 890ddd
		} else if (keyframe.m_type == TDoubleKeyframe::EaseInOutPercentage) {
Toshihiro Shimizu 890ddd
			// percentage -> absolute
Toshihiro Shimizu 890ddd
			ease0 = keyframe.m_speedOut.x * 0.01 * segmentWidth;
Toshihiro Shimizu 890ddd
			ease1 = -nextKeyframe.m_speedIn.x * 0.01 * segmentWidth;
Toshihiro Shimizu 890ddd
			// rounding could break constraints. crop parameters
Toshihiro Shimizu 890ddd
			ease0 = tcrop(ease0, 0.0, segmentWidth);
Toshihiro Shimizu 890ddd
			ease1 = tcrop(ease1, 0.0, segmentWidth - ease0);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			ease1 = ease0 = segmentWidth / 3;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		keyframe.m_speedOut = TPointD(ease0, 0);
Toshihiro Shimizu 890ddd
		nextKeyframe.m_speedIn = TPointD(-ease1, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		keyframe.m_type = type;
Toshihiro Shimizu 890ddd
		keyframes[kIndex] = keyframe;
Toshihiro Shimizu 890ddd
		keyframes[kIndex + 1] = nextKeyframe;
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::Expression:
Toshihiro Shimizu 890ddd
		keyframe.m_type = type;
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			double value = m_param->getValue(keyframe.m_frame);
Toshihiro Shimizu 890ddd
			const TUnit *unit = 0;
Toshihiro Shimizu 890ddd
			if (m_param->getMeasure())
Toshihiro Shimizu 890ddd
				unit = m_param->getMeasure()->getCurrentUnit();
Toshihiro Shimizu 890ddd
			if (unit)
Toshihiro Shimizu 890ddd
				value = unit->convertTo(value);
Toshihiro Shimizu 890ddd
			keyframe.m_expressionText = QString::number(value).toStdString();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(kIndex, keyframe);
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	default:
Toshihiro Shimizu 890ddd
		keyframe.m_type = type;
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(kIndex, keyframe);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setType(TDoubleKeyframe::Type type)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	setType(m_kIndex, type);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setStep(int step)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_step == step)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_step = step;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setExpression(std::string expression)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_expressionText = expression;
Toshihiro Shimizu 890ddd
	m_keyframe.m_type = TDoubleKeyframe::Expression;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setSimilarShape(std::string expression, double offset)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_expressionText = expression;
Toshihiro Shimizu 890ddd
	m_keyframe.m_similarShapeOffset = offset;
Toshihiro Shimizu 890ddd
	m_keyframe.m_type = TDoubleKeyframe::SimilarShape;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setFile(const TDoubleKeyframe::FileParams ¶ms)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_fileParams = params;
Toshihiro Shimizu 890ddd
	m_keyframe.m_type = TDoubleKeyframe::File;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setUnitName(std::string unitName)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_unitName = unitName;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setValue(double value)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_value == value)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_value = value;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::linkHandles()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_linkedHandles)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_linkedHandles = true;
Toshihiro Shimizu 890ddd
	if (isSpeedInOut(m_kIndex) && isSpeedInOut(m_kIndex - 1)) {
Toshihiro Shimizu 890ddd
		// keyframe is between two speedin/out segments (and therefore linkHandles makes sense)
Toshihiro Shimizu 890ddd
		TPointD d = -m_keyframe.m_speedIn + m_keyframe.m_speedOut;
Toshihiro Shimizu 890ddd
		const double eps = 0.1e-3;
Toshihiro Shimizu 890ddd
		if (d.x <= eps) {
Toshihiro Shimizu 890ddd
			m_keyframe.m_speedIn = m_keyframe.m_speedOut = TPointD(0, 0);
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			m_keyframe.m_speedIn.y = d.y * m_keyframe.m_speedIn.x / d.x;
Toshihiro Shimizu 890ddd
			m_keyframe.m_speedOut.y = d.y * m_keyframe.m_speedOut.x / d.x;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::unlinkHandles()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	if (!m_keyframe.m_linkedHandles)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_linkedHandles = false;
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setSpeedIn(const TPointD &speedIn)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double eps = 0.00001;
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	assert(isSpeedInOut(m_kIndex - 1));
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_speedIn = speedIn;
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_speedIn.x > 0)
Toshihiro Shimizu 890ddd
		m_keyframe.m_speedIn.x = 0;
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_linkedHandles && m_kIndex + 1 <= m_param->getKeyframeCount()) {
Toshihiro Shimizu 890ddd
		double outNorm = getNorm(m_keyframe.m_speedOut);
Toshihiro Shimizu 890ddd
		if (m_kIndex + 1 == m_param->getKeyframeCount() ||
Toshihiro Shimizu 890ddd
			isSpeedInOut(m_kIndex) ||
Shinya Kitaoka 3bfa54
			(m_keyframe.m_type == TDoubleKeyframe::Expression && m_keyframe.m_expressionText.find("cycle") != std::string::npos)) {
Toshihiro Shimizu 890ddd
			// update next segment speed vector
Toshihiro Shimizu 890ddd
			double inNorm = getNorm(m_keyframe.m_speedIn);
Toshihiro Shimizu 890ddd
			if (inNorm < eps)
Toshihiro Shimizu 890ddd
				m_keyframe.m_speedOut = TPointD(outNorm, 0);
Toshihiro Shimizu 890ddd
			else
Toshihiro Shimizu 890ddd
				m_keyframe.m_speedOut = -(outNorm / inNorm) * m_keyframe.m_speedIn;
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			// can't change next segment speed vector => adjust speedIn to be collinear
Toshihiro Shimizu 890ddd
			TPointD w = rotate90(m_keyframe.m_speedOut);
Toshihiro Shimizu 890ddd
			double wNorm2 = norm2(w);
Toshihiro Shimizu 890ddd
			if (wNorm2 > eps * eps)
Toshihiro Shimizu 890ddd
				m_keyframe.m_speedIn -= (1.0 / wNorm2) * (w * m_keyframe.m_speedIn) * w;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setSpeedOut(const TPointD &speedOut)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const double eps = 0.00001;
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	assert(isSpeedInOut(m_kIndex));
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	m_keyframe.m_speedOut = speedOut;
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_speedOut.x < 0)
Toshihiro Shimizu 890ddd
		m_keyframe.m_speedOut.x = 0;
Toshihiro Shimizu 890ddd
	if (m_keyframe.m_linkedHandles && m_kIndex > 0) {
Toshihiro Shimizu 890ddd
		double inNorm = getNorm(m_keyframe.m_speedIn);
Toshihiro Shimizu 890ddd
		if (isSpeedInOut(m_kIndex - 1)) {
Toshihiro Shimizu 890ddd
			// update previous segment speed vector
Toshihiro Shimizu 890ddd
			double outNorm = getNorm(m_keyframe.m_speedOut);
Toshihiro Shimizu 890ddd
			if (outNorm > eps)
Toshihiro Shimizu 890ddd
				m_keyframe.m_speedIn = -inNorm / outNorm * m_keyframe.m_speedOut;
Toshihiro Shimizu 890ddd
			//else
Toshihiro Shimizu 890ddd
			//  m_keyframe.m_speedIn = TPointD(inNorm,0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		} else {
Toshihiro Shimizu 890ddd
			// can't change previous segment speed vector => adjust speedOut to be collinear
Toshihiro Shimizu 890ddd
			double h = 0.00001;
Toshihiro Shimizu 890ddd
			double f = m_keyframe.m_frame;
Toshihiro Shimizu 890ddd
			double v = (m_param->getValue(f) - m_param->getValue(f - h)) / h;
Toshihiro Shimizu 890ddd
			TPointD w(-v, 1);
Toshihiro Shimizu 890ddd
			double wNorm2 = norm2(w);
Toshihiro Shimizu 890ddd
			if (wNorm2 > eps * eps)
Toshihiro Shimizu 890ddd
				m_keyframe.m_speedOut -= (1.0 / wNorm2) * (w * m_keyframe.m_speedOut) * w;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setEaseIn(double easeIn)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// easeIn <=0
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 1 && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	assert(isEaseInOut(m_kIndex - 1));
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	TDoubleKeyframe prevKeyframe = m_param->getKeyframe(m_kIndex - 1);
Toshihiro Shimizu 890ddd
	bool isPercentage = prevKeyframe.m_type == TDoubleKeyframe::EaseInOutPercentage;
Toshihiro Shimizu 890ddd
	if (!isPercentage)
Toshihiro Shimizu 890ddd
		easeIn = floor(easeIn + 0.5);
Toshihiro Shimizu 890ddd
	double segmentWidth = isPercentage ? 100.0 : m_keyframe.m_frame - prevKeyframe.m_frame;
Toshihiro Shimizu 890ddd
	easeIn = -tcrop(-easeIn, 0.0, segmentWidth);
Toshihiro Shimizu 890ddd
	m_keyframe.m_speedIn = TPointD(easeIn, 0);
Toshihiro Shimizu 890ddd
	if (prevKeyframe.m_speedOut.x - easeIn > segmentWidth) {
Toshihiro Shimizu 890ddd
		m_undo->addKeyframe(m_kIndex - 1);
Toshihiro Shimizu 890ddd
		prevKeyframe.m_speedOut.x = segmentWidth + easeIn;
Toshihiro Shimizu 890ddd
		std::map<int, tdoublekeyframe=""> keyframes;</int,>
Toshihiro Shimizu 890ddd
		keyframes[m_kIndex - 1] = prevKeyframe;
Toshihiro Shimizu 890ddd
		keyframes[m_kIndex] = m_keyframe;
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::setEaseOut(double easeOut)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_kIndex >= 0 && m_kIndex + 1 < m_param->getKeyframeCount() && m_indices.size() == 1);
Toshihiro Shimizu 890ddd
	assert(isEaseInOut(m_kIndex));
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
	TDoubleKeyframe nextKeyframe = m_param->getKeyframe(m_kIndex + 1);
Toshihiro Shimizu 890ddd
	bool isPercentage = m_keyframe.m_type == TDoubleKeyframe::EaseInOutPercentage;
Toshihiro Shimizu 890ddd
	if (!isPercentage)
Toshihiro Shimizu 890ddd
		easeOut = floor(easeOut + 0.5);
Toshihiro Shimizu 890ddd
	double segmentWidth = isPercentage ? 100.0 : nextKeyframe.m_frame - m_keyframe.m_frame;
Toshihiro Shimizu 890ddd
	easeOut = tcrop(easeOut, 0.0, segmentWidth);
Toshihiro Shimizu 890ddd
	m_keyframe.m_speedOut = TPointD(easeOut, 0);
Toshihiro Shimizu 890ddd
	if (-nextKeyframe.m_speedIn.x + easeOut > segmentWidth) {
Toshihiro Shimizu 890ddd
		m_undo->addKeyframe(m_kIndex + 1);
Toshihiro Shimizu 890ddd
		nextKeyframe.m_speedIn.x = easeOut - segmentWidth;
Toshihiro Shimizu 890ddd
		std::map<int, tdoublekeyframe=""> keyframes;</int,>
Toshihiro Shimizu 890ddd
		keyframes[m_kIndex + 1] = nextKeyframe;
Toshihiro Shimizu 890ddd
		keyframes[m_kIndex] = m_keyframe;
Toshihiro Shimizu 890ddd
		m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(m_kIndex, m_keyframe);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// set the curve params adaptively by clicking apply button
Toshihiro Shimizu 890ddd
void KeyframeSetter::setAllParams(int step,
Toshihiro Shimizu 890ddd
								  TDoubleKeyframe::Type comboType,
Toshihiro Shimizu 890ddd
								  const TPointD &speedIn,
Toshihiro Shimizu 890ddd
								  const TPointD &speedOut,
Toshihiro Shimizu 890ddd
								  std::string expressionText,
Toshihiro Shimizu 890ddd
								  std::string unitName,
Toshihiro Shimizu 890ddd
								  const TDoubleKeyframe::FileParams &fileParam,
Toshihiro Shimizu 890ddd
								  double similarShapeOffset)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(0 <= m_kIndex && m_kIndex < m_param->getKeyframeCount());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TDoubleKeyframe keyframe = m_param->getKeyframe(m_kIndex);
Toshihiro Shimizu 890ddd
	TDoubleKeyframe nextKeyframe;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//get the next key
Toshihiro Shimizu 890ddd
	if (m_kIndex + 1 < m_param->getKeyframeCount())
Toshihiro Shimizu 890ddd
		nextKeyframe = m_param->getKeyframe(m_kIndex + 1);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		comboType = TDoubleKeyframe::Linear;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// I'm going to change kIndex. Make sure it is selected. set the dirty flag
Toshihiro Shimizu 890ddd
	m_undo->addKeyframe(m_kIndex);
Toshihiro Shimizu 890ddd
	m_indices.insert(m_kIndex);
Toshihiro Shimizu 890ddd
	m_changed = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//set step
Toshihiro Shimizu 890ddd
	if (step < 1)
Toshihiro Shimizu 890ddd
		step = 1;
Toshihiro Shimizu 890ddd
	keyframe.m_step = step;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//set type
Toshihiro Shimizu 890ddd
	keyframe.m_type = comboType;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//set parameters according to the type
Toshihiro Shimizu 890ddd
	std::map<int, tdoublekeyframe=""> keyframes;</int,>
Toshihiro Shimizu 890ddd
	switch (comboType) {
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::SpeedInOut:
Toshihiro Shimizu 890ddd
		keyframe.m_speedOut = speedOut;
Toshihiro Shimizu 890ddd
		nextKeyframe.m_speedIn = speedIn;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (keyframe.m_speedOut.x < 0)
Toshihiro Shimizu 890ddd
			keyframe.m_speedOut.x = 0;
Toshihiro Shimizu 890ddd
		if (nextKeyframe.m_speedIn.x > 0)
Toshihiro Shimizu 890ddd
			nextKeyframe.m_speedIn.x = 0;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::EaseInOut:
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::EaseInOutPercentage:
Toshihiro Shimizu 890ddd
		keyframe.m_speedOut = speedOut;
Toshihiro Shimizu 890ddd
		nextKeyframe.m_speedIn = speedIn;
Toshihiro Shimizu 890ddd
		if (keyframe.m_type == TDoubleKeyframe::EaseInOut) {
Toshihiro Shimizu 890ddd
			keyframe.m_speedOut.x = floor(speedOut.x + 0.5);
Toshihiro Shimizu 890ddd
			nextKeyframe.m_speedIn.x = floor(speedIn.x + 0.5);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::Expression:
Toshihiro Shimizu 890ddd
		keyframe.m_expressionText = expressionText;
Toshihiro Shimizu 890ddd
		keyframe.m_unitName = unitName;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::File:
Toshihiro Shimizu 890ddd
		keyframe.m_fileParams = fileParam;
Toshihiro Shimizu 890ddd
		keyframe.m_unitName = unitName;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	case TDoubleKeyframe::SimilarShape:
Toshihiro Shimizu 890ddd
		keyframe.m_expressionText = expressionText;
Toshihiro Shimizu 890ddd
		keyframe.m_similarShapeOffset = similarShapeOffset;
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	default:
Toshihiro Shimizu 890ddd
		break;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*--- リンクされたカーブの処理 ---*/
Toshihiro Shimizu 890ddd
	const double eps = 0.00001;
Toshihiro Shimizu 890ddd
	if (m_kIndex != 0 && keyframe.m_linkedHandles && keyframe.m_prevType == TDoubleKeyframe::SpeedInOut) {
Toshihiro Shimizu 890ddd
		double inNorm = getNorm(keyframe.m_speedIn);
Toshihiro Shimizu 890ddd
		// update previous segment speed vector
Toshihiro Shimizu 890ddd
		double outNorm = getNorm(keyframe.m_speedOut);
Toshihiro Shimizu 890ddd
		if (outNorm > eps)
Toshihiro Shimizu 890ddd
			keyframe.m_speedIn = -inNorm / outNorm * keyframe.m_speedOut;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	//Next curve
Toshihiro Shimizu 890ddd
	if (m_kIndex + 2 < m_param->getKeyframeCount() && nextKeyframe.m_linkedHandles && nextKeyframe.m_type == TDoubleKeyframe::SpeedInOut) {
Toshihiro Shimizu 890ddd
		double outNorm = getNorm(nextKeyframe.m_speedOut);
Toshihiro Shimizu 890ddd
		// update next segment speed vector
Toshihiro Shimizu 890ddd
		double inNorm = getNorm(nextKeyframe.m_speedIn);
Toshihiro Shimizu 890ddd
		if (inNorm < eps)
Toshihiro Shimizu 890ddd
			nextKeyframe.m_speedOut = TPointD(outNorm, 0);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			nextKeyframe.m_speedOut = -(outNorm / inNorm) * nextKeyframe.m_speedIn;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// set modified keyframe
Toshihiro Shimizu 890ddd
	keyframes[m_kIndex] = keyframe;
Toshihiro Shimizu 890ddd
	if (m_kIndex + 1 < m_param->getKeyframeCount())
Toshihiro Shimizu 890ddd
		keyframes[m_kIndex + 1] = nextKeyframe;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_param->setKeyframes(keyframes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RemoveKeyframeUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TDoubleParam *m_param;
Toshihiro Shimizu 890ddd
	TDoubleKeyframe m_keyframe;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RemoveKeyframeUndo(TDoubleParam *param, int kIndex)
Toshihiro Shimizu 890ddd
		: m_param(param)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->addRef();
Toshihiro Shimizu 890ddd
		m_keyframe = m_param->getKeyframe(kIndex);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	~RemoveKeyframeUndo()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->release();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->setKeyframe(m_keyframe);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->deleteKeyframe(m_keyframe.m_frame);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int getSize() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return sizeof(*this);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QString getHistoryString()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return QObject::tr("Remove Keyframe");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::removeKeyframeAt(TDoubleParam *curve, double frame)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int kIndex = curve->getClosestKeyframe(frame);
Toshihiro Shimizu 890ddd
	if (kIndex < 0 || kIndex >= curve->getKeyframeCount() ||
Toshihiro Shimizu 890ddd
		curve->keyframeIndexToFrame(kIndex) != frame)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(new RemoveKeyframeUndo(curve, kIndex));
Toshihiro Shimizu 890ddd
	curve->deleteKeyframe(frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class EnableCycleUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TDoubleParam *m_param;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	EnableCycleUndo(TDoubleParam *param)
Toshihiro Shimizu 890ddd
		: m_param(param)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->addRef();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	~EnableCycleUndo()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_param->release();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void invertCycleEnabled() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		bool isEnabled = m_param->isCycleEnabled();
Toshihiro Shimizu 890ddd
		m_param->enableCycle(!isEnabled);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		invertCycleEnabled();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		invertCycleEnabled();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	int getSize() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return sizeof(*this);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QString getHistoryString()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return QObject::tr("Cycle");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void KeyframeSetter::enableCycle(TDoubleParam *curve, bool enabled)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	curve->enableCycle(enabled);
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(new EnableCycleUndo(curve));
Toshihiro Shimizu 890ddd
}