Blob Blame Raw
#include "rulertool.h"

#include "tools/toolhandle.h"
#include "toonz/tscenehandle.h"
#include "toonz/txshlevelhandle.h"
#include "tools/toolutils.h"

#include "tvectorimage.h"
#include "ttoonzimage.h"
#include "tools/cursors.h"
#include "trasterimage.h"
#include "tgl.h"
#include "toonz/stage2.h"
#include "toonz/txshsimplelevel.h"
#include "toonzqt/icongenerator.h"
#include "tenv.h"

#include "tconst.h"
#include "toonz/tframehandle.h"

//----------------------------------------------------------------------------------------------

RulerTool::RulerTool()
	: TTool("T_Ruler"), m_firstPos(TConst::nowhere), m_secondPos(TConst::nowhere), m_mousePos(TConst::nowhere), m_dragMode(MakeNewRuler), m_justClicked(false)
{
	bind(TTool::AllTargets);
}

//---------------------------------------------------------

void RulerTool::setToolOptionsBox(RulerToolOptionsBox *toolOptionsBox)
{
	m_toolOptionsBox.push_back(toolOptionsBox);
}

//----------------------------------------------------------------------------------------------

void RulerTool::onImageChanged()
{
	/*--位置をリセット--*/
	m_firstPos = TConst::nowhere;
	m_secondPos = TConst::nowhere;

	for (int i = 0; i < (int)m_toolOptionsBox.size(); i++) {
		m_toolOptionsBox[i]->resetValues();
	}
}

//----------------------------------------------------------------------------------------------

void RulerTool::draw()
{
	/*--- 始点が設定されていたら、描画 ---*/
	if (m_firstPos != TConst::nowhere) {
		tglColor((m_dragMode == MoveFirstPos) ? TPixel32(51, 204, 26) : TPixel32::Red);
		tglDrawCircle(m_firstPos, 4);
		tglDrawCircle(m_firstPos, 2);
		/*--- 終点が設定されていたら、その区間を描画 ---*/
		if (m_secondPos != TConst::nowhere) {
			tglColor((m_dragMode == MoveRuler) ? TPixel32(51, 204, 26) : TPixel32::Red);
			glBegin(GL_LINE_STRIP);
			tglVertex(m_firstPos);
			tglVertex(m_secondPos);
			glEnd();
			tglColor((m_dragMode == MoveSecondPos) ? TPixel32(51, 204, 26) : TPixel32::Red);
			tglDrawCircle(m_secondPos, 4);
		}
	}
}

//----------------------------------------------------------------------------------------------

void RulerTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e)
{
	if (m_dragMode == MakeNewRuler)
		m_justClicked = true;
}

//----------------------------------------------------------------------------------------------

void RulerTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &e)
{
	/*-- 最初のドラッグ --*/
	if (m_justClicked && m_dragMode == MakeNewRuler) {
		m_firstPos = m_mousePos;
		m_justClicked = false;
	}

	/*-- ドラッグモードがMakeNewRuler/MoveSecondPosのとき、secondPosを更新 --*/
	if (m_dragMode == MakeNewRuler || m_dragMode == MoveSecondPos) {
		/*-- Shiftキーが押されていたら:0,45,90度に角度固定の直線を引く --*/
		if (e.isShiftPressed())
			m_secondPos = getHVCoordinatedPos(pos, m_firstPos);
		else
			m_secondPos = pos;
	}

	/*-- ドラッグモードがMoveFirstPosのとき、firstPosを更新 --*/
	else if (m_dragMode == MoveFirstPos) {
		/*-- Shiftキーが押されていたら:0,45,90度に角度固定の直線を引く --*/
		if (e.isShiftPressed())
			m_firstPos = getHVCoordinatedPos(pos, m_secondPos);
		else
			m_firstPos = pos;
	}

	/*-- Ruler全体を移動するモード --*/
	else {
		TPointD d = pos - m_mousePos;
		m_firstPos += d;
		m_secondPos += d;
		/*-- マウス位置を更新 --*/
		m_mousePos = pos;
	}

	updateToolOption(); /*-- ToolOptionの表示を更新 --*/

	invalidate();
}

//----------------------------------------------------------------------------------------------

void RulerTool::leftButtonUp(const TPointD &pos, const TMouseEvent &e)
{
	m_justClicked = false;
	invalidate();
}

//----------------------------------------------------------------------------------------------

void RulerTool::mouseMove(const TPointD &pos, const TMouseEvent &e)
{
	/*-- マウス位置を更新 --*/
	m_mousePos = pos;

	/*-- マウスクリックしてたら無視 --*/
	if (e.isLeftButtonPressed())
		return;

	/*-- マウスがRulerの端点/Rulerそのものに近い場合はドラッグモードを変更する。--*/
	if (m_firstPos != TConst::nowhere && tdistance2(pos, m_firstPos) < 16)
		m_dragMode = MoveFirstPos;
	else if (m_secondPos != TConst::nowhere && tdistance2(pos, m_secondPos) < 16)
		m_dragMode = MoveSecondPos;
	else if (isNearRuler())
		m_dragMode = MoveRuler;
	else
		m_dragMode = MakeNewRuler;

	invalidate();
}

//----------------------------------------------------------------------------------------------

void RulerTool::onActivate()
{
	/*-- 位置をリセット --*/
	m_firstPos = TConst::nowhere;
	m_secondPos = TConst::nowhere;

	for (int i = 0; i < (int)m_toolOptionsBox.size(); i++) {
		m_toolOptionsBox[i]->resetValues();
	}
}

//----------------------------------------------------------------------------------------------

int RulerTool::getCursorId() const
{

	if (m_dragMode == MakeNewRuler)
		return ToolCursor::RulerNewCursor;
	else
		return ToolCursor::RulerModifyCursor;
}

//----------------------------------------------------------------------------------------------
/*-- ToolOptionの表示を更新 --*/
void RulerTool::updateToolOption()
{
	TTool::Application *app = TTool::getApplication();
	TFrameHandle *currentFrame = app->getCurrentFrame();

	double x, y, w, h, a, l;

	/*-- Level編集モードのとき、そのLevelのDPIに合わせてInchの値を得る。Pixelの値も出力する。 --*/
	if (currentFrame->isEditingLevel()) {
		TXshLevelHandle *currentLevel = app->getCurrentLevel();
		TXshLevel *xl = currentLevel->getLevel();
		if (xl) {
			TXshSimpleLevel *sl = xl->getSimpleLevel();
			if (sl) {
				int subsampling = sl->getImageSubsampling(getCurrentFid());

				TPointD dpiScale = getViewer()->getDpiScale();
				TPointD pp1 = TPointD(m_firstPos.x / dpiScale.x, m_firstPos.y / dpiScale.y);
				TPointD pp2 = TPointD(m_secondPos.x / dpiScale.x, m_secondPos.y / dpiScale.y);

				TPointD p1 = TScale(1.0 / subsampling) * pp1 + TPointD(-0.5, -0.5);
				TPointD p2 = TScale(1.0 / subsampling) * pp2 + TPointD(-0.5, -0.5);

				TImageP image = getImage(false);

				TPoint pix1, pix2;

				TToonzImageP ti = image;
				TRasterImageP ri = image;

				if (ti || ri) {
					if (ti) {
						TDimension size = ti->getSize();
						pix1 = TPoint(tround(0.5 * size.lx + p1.x), tround(0.5 * size.ly + p1.y));
						pix2 = TPoint(tround(0.5 * size.lx + p2.x), tround(0.5 * size.ly + p2.y));
					} else if (ri) {
						TDimension size = ri->getRaster()->getSize();
						pix1 = TPoint(tround(0.5 * size.lx + p1.x), tround(0.5 * size.ly + p1.y));
						pix2 = TPoint(tround(0.5 * size.lx + p2.x), tround(0.5 * size.ly + p2.y));
					}
					int xPix, yPix, wPix, hPix;
					TPointD dpi = sl->getDpi(getCurrentFid());
					xPix = pix1.x;
					yPix = pix1.y;
					wPix = pix2.x - pix1.x;
					hPix = pix2.y - pix1.y;

					x = (double)xPix / dpi.x;
					y = (double)yPix / dpi.y;
					w = (double)wPix / dpi.x;
					h = (double)hPix / dpi.y;
					a = atan2(h, w) * 180.0 / 3.14159264;
					l = sqrt(w * w + h * h);

					for (int i = 0; i < (int)m_toolOptionsBox.size(); i++) {
						m_toolOptionsBox[i]->updateValues(true, x, y, w, h, a, l,
														  xPix, yPix, wPix, hPix);
					}
					return;
				}
			}
		}
	}

	/*-- シーン編集モードのとき、Stage::inchで割った値がInch値となる --*/
	x = m_firstPos.x / Stage::inch;
	y = m_firstPos.y / Stage::inch;
	w = (m_secondPos.x - m_firstPos.x) / Stage::inch;
	h = (m_secondPos.y - m_firstPos.y) / Stage::inch;
	a = atan2(h, w) * 180.0 / 3.14159264;
	l = sqrt(w * w + h * h);

	for (int i = 0; i < (int)m_toolOptionsBox.size(); i++) {
		m_toolOptionsBox[i]->updateValues(false, x, y, w, h, a, l);
	}
}

//----------------------------------------------------------------------------------------------
/*! 現在のマウス位置がRulerに十分近ければTrueを返す
*/
bool RulerTool::isNearRuler()
{
	double a, b, c;

	TPointD vec = m_secondPos - m_firstPos;

	a = -vec.y;
	b = vec.x;
	c = -a * m_firstPos.x - b * m_firstPos.y;

	double k = a * m_mousePos.x + b * m_mousePos.y + c;
	double d2 = k * k / (a * a + b * b);

	/*-- 距離が4より遠ければfalse --*/
	if (d2 > 16)
		return false;

	/*-- 垂線の足がRuler上にあるかを判断。Rulerを対角線とするRectにマウス位置が収まるかどうか --*/
	TRectD rect = TRectD(m_firstPos, m_secondPos).enlarge(4);
	return rect.contains(m_mousePos);
}

//----------------------------------------------------------------------------------------------

//----------------------------------------------------------------------------------------------
/*! 基準点に対し、マウス位置を0,45,90度にフィットさせた位置を返す
	斜め方向では、X/Yの値のうち絶対値の小さいほうに合わせる。
*/
//----------------------------------------------------------------------------------------------
TPointD RulerTool::getHVCoordinatedPos(TPointD p, TPointD centerPos)
{
	TPointD vec = p - centerPos;
	double degree = (vec.x == 0.0) ? 90.0 : atan(vec.y / vec.x) * 180.0 / 3.1415926536;

	TPointD outPoint;

	if (degree <= -67.5) /*--垂直--*/
	{
		outPoint.x = centerPos.x;
		outPoint.y = p.y;
	} else if (degree < -22.5) /*--右斜め下--*/
	{
		if (abs(vec.x) > abs(vec.y))
			outPoint = centerPos + TPointD(-vec.y, vec.y);
		else
			outPoint = centerPos + TPointD(vec.x, -vec.x);
	} else if (degree <= 22.5) /*--水平--*/
	{
		outPoint.x = p.x;
		outPoint.y = centerPos.y;
	} else if (degree < 67.5) /*--右斜め上--*/
	{
		if (abs(vec.x) > abs(vec.y))
			outPoint = centerPos + TPointD(vec.y, vec.y);
		else
			outPoint = centerPos + TPointD(vec.x, vec.x);
	} else /*--再び垂直--*/
	{
		outPoint.x = centerPos.x;
		outPoint.y = p.y;
	}

	return outPoint;
}

//----------------------------------------------------------------------------------------------
RulerTool RulerTool;