#include "tools/tool.h"
#include "tools/toolutils.h"
#include "tools/cursors.h"
#include "toonz/tframehandle.h"
#include "toonz/txshlevelhandle.h"
#include "toonz/tscenehandle.h"
#include "toonzqt/selectioncommandids.h"
#include "toonzqt/selection.h"
#include "tproperty.h"
#include "tdata.h"
#include "tconvert.h"
#include "tgl.h"
#include "tstroke.h"
#include "tvectorimage.h"
#include "toonz/hook.h"
#include "toonz/txshlevel.h"
#include "toonz/toonzscene.h"
#include "toonz/txsheet.h"
#include "toonz/txshcell.h"
#include "toonz/txshcolumn.h"
#include "toonz/tstageobjecttree.h"
#include "toonz/txshsimplelevel.h"
#include "toonz/levelproperties.h"
#include "toonz/txsheethandle.h"
#include <QMessageBox>
#include <math.h>
// For Qt translation support
#include <QCoreApplication>
#include <QKeyEvent>
using namespace ToolUtils;
class TrackerTool;
//=============================================================================
namespace {
//-----------------------------------------------------------------------------
//=============================================================================
// TrackerRegionSelection
//-----------------------------------------------------------------------------
// Ancora da definire.
// under construction
class TrackerRegionSelection final : public TSelection {
TXshLevelP m_level;
std::set<std::pair<int, int>>
m_objtp; // objtp: 1=ObjectId 2=Tracker Region Index
TrackerTool *m_tool;
public:
TrackerRegionSelection() : m_tool(0) {}
void setTool(TrackerTool *tool) { m_tool = tool; }
TSelection *clone() const { return new TrackerRegionSelection(*this); }
void setLevel(const TXshLevelP &level) { m_level = level; }
void select(int objectId, int trackerRegionIndex) {
m_objtp.insert(std::make_pair(objectId, trackerRegionIndex));
}
void deselect(int objectId, int trackerRegionIndex) {
m_objtp.erase(std::make_pair(objectId, trackerRegionIndex));
}
bool isSelected(int objectId, int trackerRegionIndex) const {
return m_objtp.count(std::make_pair(objectId, trackerRegionIndex)) > 0;
}
void invertSelection(int objectId, int trackerRegionIndex) {
if (isSelected(objectId, trackerRegionIndex))
deselect(objectId, trackerRegionIndex);
else
select(objectId, trackerRegionIndex);
}
bool isEmpty() const override { return m_objtp.empty(); }
void selectNone() override { m_objtp.clear(); }
HookSet *getHookSet() const {
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
// TXshLevel *xl = m_level.getPointer();
if (!xl) return 0;
return xl->getHookSet();
}
TDataP getData() { return TDataP(); }
TDataP cutData() { return TDataP(); }
TDataP clearData() {
/*
//HookData *data = new HookData();
HookSet *hookSet = getHookSet();
TFrameId fid = TTool::getApplication()->getCurrentFrame()->getFid();
if(!hookSet) return TDataP();
for(int i=0;i<hookSet->getHookCount();i++)
{
Hook *hook = hookSet->getHook(i);
if(!hook || hook->isEmpty()) continue;
if(isSelected(i,1) && isSelected(i,2))
hookSet->clearHook(hook);
else if(isSelected(i,2))
hook->setBPos(fid, hook->getAPos(fid));
else if(isSelected(i,1))
hook->setAPos(fid, hook->getBPos(fid));
}
makeCurrent();
return TDataP(); */
}
TDataP pasteData(const TDataP &data) { return TDataP(); }
void resetData(const TDataP &data, bool insert) {}
bool select(const TSelection *s) {
if (const TrackerRegionSelection *hs =
dynamic_cast<const TrackerRegionSelection *>(s)) {
m_level = hs->m_level;
m_objtp = hs->m_objtp;
return true;
} else
return false;
}
void enableCommands() override;
void convertToRegion();
};
} // namespace
//=============================================================================
// TrackerTool class declaration
//-----------------------------------------------------------------------------
class TrackerTool final : public TTool {
Q_DECLARE_TR_FUNCTIONS(TrackerTool)
TrackerRegionSelection m_selection;
TPointD m_firstPos, m_lastPos;
int m_hookSelectedIndex;
int m_lastHookSelectedIndex;
bool m_deselectArmed;
bool m_newObjectAdded; // serve al buttonUp per sapere se l'ultima tracker
// region
// aggiunta è un oggetto nuovo oppure no
TPropertyGroup m_prop;
TDoubleProperty m_toolSizeWidth;
TDoubleProperty m_toolSizeHeight;
TIntProperty m_toolPosX;
TIntProperty m_toolPosY;
TRectD m_shapeBBox;
bool m_buttonDown;
bool m_dragged;
bool m_picked;
TPointD m_pos; // posizione del mouse
TPointD m_oldPos;
int m_what;
enum {
Outside,
Inside,
P00,
P01,
P10,
P11,
P1M,
PM1,
P0M,
PM0,
ADD_OBJECT,
NormalHook
};
public:
TrackerTool();
ToolType getToolType() const override { return TTool::LevelReadTool; }
void updateTranslation() override;
TrackerObjectsSet *getTrackerObjectsSet() const;
HookSet *getHookSet() const;
void draw() override;
void deleteSelectedTrackerRegion();
void leftButtonDown(const TPointD &pos, const TMouseEvent &e) override;
void leftButtonDrag(const TPointD &pos, const TMouseEvent &e) override;
void leftButtonUp(const TPointD &pos, const TMouseEvent &) override;
void mouseMove(const TPointD &pos, const TMouseEvent &e) override;
bool keyDown(QKeyEvent *event) override;
// bool moveCursor(const TPointD &pos){}
void onEnter() override;
void onLeave() override;
void onActivate() override;
void onDeactivate() override;
void onImageChanged() override {}
void reset() override;
TPropertyGroup *getProperties(int targetType) override { return &m_prop; }
void onSelectionChanged() { invalidate(); }
bool onPropertyChanged(std::string propertyName) override;
bool select(const TSelection *) { return false; }
bool pick(int &hookIndex, const TPointD &pos);
int getCursorId() const override;
// returns true if the pressed key is recognized and processed.
bool isEventAcceptable(QEvent *e) override;
} trackerTool;
//=============================================================================
// TrackerTool implementation
//-----------------------------------------------------------------------------
TrackerTool::TrackerTool()
: TTool("T_Tracker")
, m_hookSelectedIndex(-1)
, m_lastHookSelectedIndex(-1)
, m_deselectArmed(false)
, m_toolSizeWidth("Width:", 0, 1000, 10) // W_ToolOptions
, m_toolSizeHeight("Height:", 0, 1000, 10) // W_ToolOptions
, m_toolPosX("X:", -9000, 9000, 10) // W_ToolOptions
, m_toolPosY("Y:", -9000, 9000, 10) // W_ToolOptions
, m_shapeBBox()
, m_buttonDown(false)
, m_dragged(false)
, m_oldPos(TPointD(0, 0))
, m_newObjectAdded(false) {
bind(TTool::CommonLevels);
m_prop.bind(m_toolSizeWidth);
m_prop.bind(m_toolSizeHeight);
m_prop.bind(m_toolPosX);
m_prop.bind(m_toolPosY);
m_selection.setTool(this);
}
//-----------------------------------------------------------------------------
void TrackerTool::updateTranslation() {
m_toolSizeWidth.setQStringName(tr("Width:"));
m_toolSizeHeight.setQStringName(tr("Height:"));
m_toolPosX.setQStringName(tr("X:"));
m_toolPosY.setQStringName(tr("Y:"));
}
//-----------------------------------------------------------------------------
TrackerObjectsSet *TrackerTool::getTrackerObjectsSet() const {
HookSet *hookSet = getHookSet();
if (!hookSet) return 0;
return hookSet->getTrackerObjectsSet();
}
HookSet *TrackerTool::getHookSet() const {
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl) return 0;
return xl->getHookSet();
}
//-----------------------------------------------------------------------------
void TrackerTool::draw() {
HookSet *hookSet = getHookSet();
if (!hookSet) return;
if (hookSet->getHookCount() <= m_hookSelectedIndex) m_hookSelectedIndex = -1;
TFrameId fid = getCurrentFid();
int selectedObjectId;
if (m_hookSelectedIndex >= 0 && hookSet->getHook(m_hookSelectedIndex))
selectedObjectId =
hookSet->getHook(m_hookSelectedIndex)->getTrackerObjectId();
else
selectedObjectId = -1;
int i = 0;
double pixelSize = getPixelSize();
std::vector<TRectD> balloons; // this is used to avoid balloons overlapping
// draw hooks
for (i = 0; i < hookSet->getHookCount(); i++) {
Hook *hook = hookSet->getHook(i);
if (!hook || hook->isEmpty()) continue;
assert(hook);
// Se l'Hook ha una TrackerRegion allora la disegno
if (hook->getTrackerObjectId() >= 0) {
TRectD rect;
rect = hook->getTrackerRegion(fid);
TPixel32 textColor(127, 127, 127);
TPixel32 trackerObjectColor(0, 0, 0);
if (hook->getTrackerObjectId() == selectedObjectId) {
if (m_hookSelectedIndex == i) {
TPixel32 frameColor(127, 127, 127);
drawSquare(0.5 * (rect.getP01() + rect.getP11()), pixelSize * 4,
frameColor); // scalaY
drawSquare(0.5 * (rect.getP11() + rect.getP10()), pixelSize * 4,
frameColor); // scalaX
drawSquare(rect.getP00(), pixelSize * 4, frameColor); // scala
drawSquare(rect.getP10(), pixelSize * 4, frameColor); // ridimensiona
trackerObjectColor = TPixel32(183, 227, 0);
textColor = TPixel32(155, 213, 219);
} else {
textColor = TPixel32(183, 227, 0);
trackerObjectColor = TPixel32(155, 213, 219);
}
} else
trackerObjectColor = TPixel32(0, 0, 0);
tglColor(trackerObjectColor);
tglDrawRect(rect);
tglColor(textColor);
glPushMatrix();
glTranslated(hook->getPos(fid).x, hook->getPos(fid).y, 0);
glScaled(pixelSize, pixelSize, 1);
int objectId = hook->getTrackerObjectId();
char *objectChar = (char *)malloc(2);
objectChar[0] = (char)(objectId + 65);
objectChar[1] = '\0';
std::string text(objectChar);
tglDrawText(TPointD(-15, 10), text);
glPopMatrix();
}
TPointD p0 = hook->getAPos(fid);
TPointD p1 = hook->getBPos(fid);
bool linked = p0 == p1;
drawHook(p0, linked ? ToolUtils::NormalHook : ToolUtils::PassHookA,
m_hookSelectedIndex == i);
std::string hookName = std::to_string(i + 1);
TPixel32 balloonColor(200, 220, 205, 200);
TPoint balloonOffset(20, 20);
drawBalloon(p0, hookName, balloonColor, balloonOffset, pixelSize, false,
&balloons);
if (!linked) {
drawHook(p1, PassHookB, m_selection.isSelected(i, 2));
drawBalloon(p1, hookName, balloonColor, balloonOffset, pixelSize, false,
&balloons);
}
}
}
//-----------------------------------------------------------------------------
bool TrackerTool::pick(int &hookIndex, const TPointD &pos) {
double minDistance = -1;
m_what = Outside;
HookSet *hookSet = getHookSet();
if (!hookSet) return false;
TFrameId fid = getCurrentFid();
double pixelSize = getPixelSize();
int i = 0;
for (i = 0; i < (int)hookSet->getHookCount(); i++) {
Hook *hook = hookSet->getHook(i);
if (!hook || hook->isEmpty()) continue;
int trackerObjectId = hook->getTrackerObjectId();
if (trackerObjectId < 0) // se non è una trackeRregion
{
TPointD hookPos = hook->getPos(fid);
TRectD overArea =
TRectD(hookPos.x - 20 * pixelSize, hookPos.y - 20 * pixelSize,
hookPos.x + 20 * pixelSize, hookPos.y + 20 * pixelSize);
if (overArea.contains(pos)) {
hookIndex = i; // setto l'indice dell'hook
m_what = NormalHook;
return true;
}
} else {
/*
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
if(!trackerObjectsSet) return false;
TrackerObject *trackerObject = trackerObjectsSet->getObjectFromIndex(i);
int j=0;
for(j=0;j<(int)trackerObject->getHooksCount();j++)
{*/
TPointD centerPos = hook->getPos(fid);
double width = hook->getTrackerRegionWidth();
double height = hook->getTrackerRegionHeight();
double distance = tdistance2(centerPos, pos);
TPointD localPos = pos - centerPos;
TRectD rect = hook->getTrackerRegion(fid);
TRectD overArea = TRectD(
rect.getP00().x - 4 * pixelSize, rect.getP00().y - 4 * pixelSize,
rect.getP11().x + 4 * pixelSize, rect.getP11().y + 4 * pixelSize);
// se pos è all'interno del'area sensibile del rettangolo
if (overArea.contains(pos)) {
if (distance < minDistance || minDistance == -1) {
minDistance = distance;
hookIndex = i;
m_what = Inside;
// scale Y Area
double x =
0.5 * (rect.getP01().x + rect.getP11().x); // ascissa punto medio
TPointD my = TPointD(x, rect.getP11().y);
TRectD scaleYArea =
TRectD(my.x - 4 * pixelSize, my.y - 4 * pixelSize,
my.x + 4 * pixelSize, my.y + 4 * pixelSize);
if (scaleYArea.contains(pos)) m_what = PM1;
// scale X Area
double y = 0.5 * (rect.getP11().y +
rect.getP10().y); // ordinata punto medio
TPointD mx = TPointD(rect.getP10().x, y);
TRectD scaleXArea =
TRectD(mx.x - 4 * pixelSize, mx.y - 4 * pixelSize,
mx.x + 4 * pixelSize, mx.y + 4 * pixelSize);
if (scaleXArea.contains(pos)) m_what = P1M;
// resize area (scale X and Y)
TRectD resizeArea = TRectD(
rect.getP10().x - 4 * pixelSize, rect.getP10().y - 4 * pixelSize,
rect.getP10().x + 4 * pixelSize, rect.getP10().y + 4 * pixelSize);
if (resizeArea.contains(pos)) m_what = P10;
// scale area
TRectD scaleArea = TRectD(
rect.getP00().x - 4 * pixelSize, rect.getP00().y - 4 * pixelSize,
rect.getP00().x + 4 * pixelSize, rect.getP00().y + 4 * pixelSize);
if (scaleArea.contains(pos)) m_what = P00;
}
}
//}
}
}
return (minDistance != -1);
}
//-----------------------------------------------------------------------------
void TrackerTool::leftButtonDown(const TPointD &pos, const TMouseEvent &e) {
m_buttonDown = true;
m_picked = true;
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl) return;
m_selection.setLevel(xl);
m_firstPos = m_lastPos = pos;
m_deselectArmed = false;
m_oldPos = pos;
double pixelSize = getPixelSize();
HookSet *hookSet = xl->getHookSet();
if (!hookSet) return;
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
TFrameId fid = getCurrentFid();
if (!trackerObjectsSet) return;
if (pick(m_hookSelectedIndex, pos)) {
if (m_what == NormalHook) {
invalidate();
return;
}
Hook *hook = hookSet->getHook(m_hookSelectedIndex);
if (!hook) return;
m_selection.selectNone();
m_selection.select(m_hookSelectedIndex, m_hookSelectedIndex);
m_toolSizeWidth.setValue(hook->getTrackerRegionWidth());
m_toolSizeHeight.setValue(hook->getTrackerRegionHeight());
m_toolPosX.setValue(hook->getPos(fid).x);
m_toolPosY.setValue(hook->getPos(fid).y);
m_toolSizeWidth.notifyListeners();
m_toolSizeHeight.notifyListeners();
m_toolPosX.notifyListeners();
m_toolPosY.notifyListeners();
} else {
m_selection.selectNone();
if (xl->getSimpleLevel() && !xl->getSimpleLevel()->isReadOnly()) {
TFrameId fid = getCurrentFid();
m_what = P10;
// Se non è selezionato alcun oggetto allora aggiungo un nuovo oggetto e a
// questo
// aggiungo una trackerRegion
int trackerObjectId;
if (m_hookSelectedIndex == -1 ||
hookSet->getHook(m_hookSelectedIndex) == 0) {
trackerObjectId = trackerObjectsSet->addObject();
m_newObjectAdded = true;
} else
trackerObjectId =
hookSet->getHook(m_hookSelectedIndex)->getTrackerObjectId();
// se l'oggetto selezionato è un semplice Hook (senza region)
// allora creo un nuovo hook con region
if (trackerObjectId == -1) {
trackerObjectId = trackerObjectsSet->addObject();
m_newObjectAdded = true;
}
// aggiungo un Hook all'oggetto selezionato
Hook *newHook = hookSet->addHook();
if (newHook) {
newHook->setTrackerObjectId(trackerObjectId);
newHook->setAPos(fid, pos);
newHook->setTrackerRegionHeight(pixelSize * 10);
newHook->setTrackerRegionWidth(pixelSize * 10);
// setto l'indice della trackerRegion corrente
m_hookSelectedIndex = newHook->getId(); // hookSet->getHookCount()-1;
} else {
if (hookSet->getHookCount() >= 20)
QMessageBox::warning(0, "TrackerTool Error",
"Hooks number must be at most 20");
m_hookSelectedIndex = -1;
}
}
}
m_selection.makeCurrent();
invalidate();
return;
}
//-----------------------------------------------------------------------------
void TrackerTool::leftButtonDrag(const TPointD &pp, const TMouseEvent &e) {
if (!m_buttonDown) return;
if (m_hookSelectedIndex < 0 && m_what != NormalHook) return;
HookSet *hookSet = getHookSet();
if (!hookSet) return;
assert(hookSet->getHook(m_hookSelectedIndex) != 0);
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
TFrameId fid = getCurrentFid();
if (!trackerObjectsSet) return;
if (m_dragged == false) {
m_dragged = true;
}
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (xl->getSimpleLevel() && xl->getSimpleLevel()->isReadOnly() &&
m_what != Inside && m_what != NormalHook)
return;
if (m_dragged == true) {
Hook *hook = new Hook();
hook = getHookSet()->getHook(m_hookSelectedIndex);
if (!hook || hook->isEmpty()) return;
TPointD deltaPos = pp - m_oldPos;
m_oldPos = pp;
double newWidth = hook->getTrackerRegionWidth();
double newHeight = hook->getTrackerRegionHeight();
TAffine aff;
const double epsilon = 1e-2;
TPointD posCenter = hook->getPos(fid);
double a = norm2(pp - posCenter);
double b = norm2(pp - deltaPos - posCenter);
switch (m_what) {
case Inside: // Traslazione
hook->setAPos(fid, hook->getPos(fid) + deltaPos);
break;
case NormalHook: // Traslazione Hook
{
hook->setAPos(fid, hook->getPos(fid) + deltaPos);
invalidate();
return;
}
case P00: // Scalatura
{
if (a <= epsilon || b <= epsilon) return;
aff = TScale(posCenter, sqrt(a / b));
TRectD rect = hook->getTrackerRegion(fid);
TPointD av(hook->getTrackerRegion(fid).getP00());
TPointD av2(hook->getTrackerRegion(fid).getP11());
av = aff * av;
av2 = aff * av2;
rect = TRectD(av, av2);
newWidth = rect.getLx();
newHeight = rect.getLy();
break;
}
case P10: // Scalatura X e Y
{
TPointD pos = hook->getPos(fid);
TPointD diffPos = pp - pos;
int signumx = 1;
int signumy = 1;
if (diffPos.x < 0) signumx = -1;
if (diffPos.y < 0) signumy = -1;
newWidth = fabs(hook->getTrackerRegionWidth() + 2 * signumx * deltaPos.x);
newHeight =
fabs(hook->getTrackerRegionHeight() + 2 * signumy * deltaPos.y);
// double newWidth = fabs(2*diffPos.x-fabs(2*signumx*deltaPos.x));
// double newHeight = fabs(2*diffPos.y-fabs(2*signumy*deltaPos.y));
break;
}
case P1M: // Ridimensiono X
{
TRectD rect = hook->getTrackerRegion(fid);
rect = rect.enlarge(deltaPos.x, 0);
newWidth = rect.getLx();
break;
}
case PM1: // Ridimensiono Y
{
TRectD rect = hook->getTrackerRegion(fid);
rect = rect.enlarge(0, deltaPos.y);
newHeight = rect.getLy();
break;
}
default:
break;
}
if (newWidth > m_toolSizeWidth.getRange().second ||
newHeight > m_toolSizeHeight.getRange().second)
return;
hook->setTrackerRegionWidth(newWidth);
hook->setTrackerRegionHeight(newHeight);
m_toolSizeWidth.setValue(hook->getTrackerRegionWidth());
m_toolSizeHeight.setValue(hook->getTrackerRegionHeight());
m_toolPosX.setValue(hook->getPos(fid).x);
m_toolPosY.setValue(hook->getPos(fid).y);
m_toolPosX.notifyListeners();
m_toolPosY.notifyListeners();
m_toolSizeWidth.notifyListeners();
m_toolSizeHeight.notifyListeners();
}
// TTool::Application *app = TTool::getApplication());
// app->getCurrentScene()->getScene()->getXsheet()->getPegbarTree()->invalidateAll();
invalidate();
}
//-----------------------------------------------------------------------------
void TrackerTool::leftButtonUp(const TPointD &pos, const TMouseEvent &) {
// note: apparently sometimes (when the user triple-clicks) we receive this
// event twice
if (!m_buttonDown) return;
// se clicco su una TrackerRegion già selezionato lo deseleziono (per
// permettere
// poi l'aggiunta di un nuovo TrackerObject
if (m_dragged == false && m_hookSelectedIndex == m_lastHookSelectedIndex) {
m_hookSelectedIndex = -1;
}
if (m_newObjectAdded) {
m_hookSelectedIndex = -1;
m_newObjectAdded = false;
// emit signal in order to update schematic
TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
}
m_lastHookSelectedIndex = m_hookSelectedIndex;
m_dragged = false;
m_buttonDown = false;
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl || !xl->getSimpleLevel()) return;
xl->getSimpleLevel()->getProperties()->setDirtyFlag(true);
// m_selection.selectNone();
return;
}
//-----------------------------------------------------------------------------
void TrackerTool::deleteSelectedTrackerRegion() {
TTool::Application *app = TTool::getApplication();
TXshLevel *xl = app->getCurrentLevel()->getLevel();
HookSet *hookSet = xl->getHookSet();
if (!xl || !xl->getSimpleLevel() || !hookSet ||
xl->getSimpleLevel()->isReadOnly())
return;
// HookUndo *undo = new HookUndo(xl->getSimpleLevel());
TFrameId fid = getCurrentFid();
Hook *hook = hookSet->getHook(m_hookSelectedIndex);
m_hookSelectedIndex = -1;
if (!hook || hook->isEmpty()) return;
hookSet->clearHook(hook);
// TUndoManager::manager()->add(undo);
app->getCurrentScene()
->getScene()
->getXsheet()
->getStageObjectTree()
->invalidateAll();
invalidate();
// emit signal in order to update schematic
TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
/*
int a = m_selectedObjectId;
int b = m_selectedTrackerRegionIndex;
if(m_selectedObjectId<0 ||m_selectedTrackerRegionIndex<0) return;
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
TFrameId fid = getCurrentFid();
if(!trackerObjectsSet) return;
TrackerObject *trackerObject=
trackerObjectsSet->getObject(m_selectedObjectId);
if(trackerObject==NULL) return;
if(trackerObject->getHooksCount()==0)
{
trackerObjectsSet->removeObject(m_selectedObjectId);
m_selectedObjectId = -1;
m_selectedTrackerRegionIndex = -1;
return;
}
trackerObject->removeHook(m_selectedTrackerRegionIndex);
m_selectedTrackerRegionIndex = trackerObject->getHooksCount()-1;
invalidate(); */
}
//-----------------------------------------------------------------------------
void TrackerTool::mouseMove(const TPointD &pos, const TMouseEvent &e) {
m_picked = true;
if (m_dragged == false) {
int hookSelectedIndex;
pick(hookSelectedIndex, pos);
if (hookSelectedIndex < 0) {
m_pos = pos;
m_picked = false;
}
invalidate();
}
}
//-----------------------------------------------------------------------------
bool TrackerTool::onPropertyChanged(std::string propertyName) {
HookSet *hookSet = getHookSet();
if (!hookSet || m_hookSelectedIndex < 0) return false;
TFrameId fid = getCurrentFid();
Hook *hook = hookSet->getHook(m_hookSelectedIndex);
if (!hook || hook->isEmpty()) return false;
if (propertyName == "Width:") {
double width = m_toolSizeWidth.getValue();
hook->setTrackerRegionWidth(width);
}
if (propertyName == "Height:") {
double height = m_toolSizeHeight.getValue();
hook->setTrackerRegionHeight(height);
}
if (propertyName == "X:") {
double x = m_toolPosX.getValue();
TPointD pos = hook->getPos(fid);
pos.x = x;
hook->setAPos(fid, pos);
}
if (propertyName == "Y:") {
double y = m_toolPosY.getValue();
TPointD pos = hook->getPos(fid);
pos.y = y;
hook->setAPos(fid, pos);
}
invalidate();
return true;
}
void TrackerTool::reset() { m_hookSelectedIndex = -1; }
int TrackerTool::getCursorId() const {
switch (m_what) {
case Outside:
return ToolCursor::TrackerCursor;
case Inside:
return ToolCursor::MoveCursor;
case NormalHook:
return ToolCursor::MoveCursor;
case P00:
return ToolCursor::ScaleCursor;
case P01:
return ToolCursor::MoveCursor;
case P10:
return ToolCursor::ScaleCursor;
case P1M:
return ToolCursor::ScaleHCursor;
case PM1:
return ToolCursor::ScaleVCursor;
case ADD_OBJECT:
return ToolCursor::SplineEditorCursorAdd;
default:
return ToolCursor::TrackerCursor;
}
return ToolCursor::TrackerCursor;
}
bool TrackerTool::keyDown(QKeyEvent *event) {
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl) return false;
HookSet *hookSet = xl->getHookSet();
if (!hookSet) return false;
TFrameId fid = getCurrentFid();
Hook *hook = hookSet->getHook(m_hookSelectedIndex);
if (!hook || hook->isEmpty()) return false;
TPointD hookPos = hook->getPos(fid);
TPointD delta(0, 0);
double pixelSize = getPixelSize();
switch (event->key()) {
case Qt::Key_Up:
delta.y = 1;
break;
case Qt::Key_Down:
delta.y = -1;
break;
case Qt::Key_Left:
delta.x = -1;
break;
case Qt::Key_0:
delta.x = 1;
break;
case Qt::Key_PageUp: // converto in Hook
hook->setTrackerObjectId(-1);
break;
case Qt::Key_PageDown: // converto in trackerRegion
{
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
if (!trackerObjectsSet) return false;
int trackerObjectId = hook->getTrackerObjectId();
if (trackerObjectId != -1) return false;
trackerObjectId = trackerObjectsSet->addObject();
hook->setTrackerObjectId(trackerObjectId);
hook->setTrackerRegionHeight(pixelSize * 20);
hook->setTrackerRegionWidth(pixelSize * 20);
} break;
default:
return false;
break;
}
hookPos += delta;
hook->setAPos(fid, hookPos);
// TTool::getApplication()->getCurrentTool()->getTool()->notifyImageChanged();
// TNotifier::instance()->notify(TLevelChange());
return true;
}
// bool moveCursor(const TPointD &pos){}
void TrackerTool::onEnter() {
HookSet *hookSet = getHookSet();
if (!hookSet || hookSet->getHookCount() <= m_hookSelectedIndex)
m_hookSelectedIndex = -1;
}
//-----------------------------------------------------------------------------
void TrackerTool::onLeave() {
TrackerObjectsSet *trackerObjectsSet = getTrackerObjectsSet();
if (trackerObjectsSet) trackerObjectsSet->clearAll();
}
//-----------------------------------------------------------------------------
void TrackerTool::onActivate() {}
//-----------------------------------------------------------------------------
void TrackerTool::onDeactivate() {
// m_selection.selectNone();
// TSelection::setCurrent(0);
}
//-----------------------------------------------------------------------------
// returns true if the pressed key is recognized and processed in the tool
// instead of triggering the shortcut command.
bool TrackerTool::isEventAcceptable(QEvent *e) {
if (!isEnabled()) return false;
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl) return false;
HookSet *hookSet = xl->getHookSet();
if (!hookSet) return false;
Hook *hook = hookSet->getHook(m_hookSelectedIndex);
if (!hook || hook->isEmpty()) return false;
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(e);
// shift + arrow will not be recognized for now
if (keyEvent->modifiers() & Qt::ShiftModifier) return false;
int key = keyEvent->key();
return (key == Qt::Key_Up || key == Qt::Key_Down || key == Qt::Key_Left ||
key == Qt::Key_Right);
// no need to override page up & down keys since they cannot be
// used as shortcut key for now
}
//=============================================================================
static TTool *getTrackerToolTool() { return &trackerTool; }
//=============================================================================
void TrackerRegionSelection::enableCommands() {
enableCommand(m_tool, MI_Clear, &TrackerTool::deleteSelectedTrackerRegion);
// enableCommand(m_tool, MI_ConvertToRegion,
// &TrackerRegionSelection::convertToRegion);
}
void TrackerRegionSelection::convertToRegion() {
int i = 0;
TXshLevel *xl = TTool::getApplication()->getCurrentLevel()->getLevel();
if (!xl) return;
HookSet *hookSet = xl->getHookSet();
if (!hookSet) return;
for (i = 0; i < hookSet->getHookCount(); i++) {
if (isSelected(i, i)) {
int trackerObjectId = hookSet->getTrackerObjectsSet()->addObject();
Hook *hook = hookSet->getHook(i);
if (!hook || hook->isEmpty()) continue;
hook->setTrackerObjectId(trackerObjectId);
}
}
}