#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/gutil.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 #include // For Qt translation support #include #include using namespace ToolUtils; class TrackerTool; //============================================================================= namespace { //----------------------------------------------------------------------------- //============================================================================= // TrackerRegionSelection //----------------------------------------------------------------------------- // Ancora da definire. // under construction class TrackerRegionSelection final : public TSelection { TXshLevelP m_level; std::set> 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;igetHookCount();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(); */ return (NULL); } 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(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(); int devPixRatio = getDevicePixelRatio(m_viewer->viewerWidget()); std::vector 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 * devPixRatio, pixelSize * devPixRatio, 1); int objectId = hook->getTrackerObjectId(); std::string text({static_cast('A' + objectId)}); 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(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); } } }