Skip to content

Commit b3829f1

Browse files
committed
add node tangent snapping every 15 degrees, it works for nodes and for keyframe nodes (timeline Graph)
1 parent bdffab3 commit b3829f1

5 files changed

Lines changed: 75 additions & 5 deletions

File tree

src/app/GUI/keysview.cpp

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
#include "timelinehighlightwidget.h"
4343
#include "GUI/dialogsinterface.h"
4444
#include "themesupport.h"
45+
#include <QtMath>
46+
#include <cmath>
4547

4648
KeysView::KeysView(BoxScrollWidget *boxesListVisible,
4749
QWidget *parent) :
@@ -792,7 +794,9 @@ void KeysView::handleMouseMove(const QPoint &pos,
792794
dFrame = dX/mPixelsPerFrame;
793795
mValueInput.setDisplayedValue(dFrame);
794796
}
797+
const auto mods = QApplication::keyboardModifiers();
795798
const bool ctrlPt = mGPressedPoint && mGPressedPoint->isCtrlPt();
799+
const bool shiftPressed = mods & Qt::ShiftModifier;
796800
if(!ctrlPt) dFrame = round(dFrame);
797801
const qreal dDFrame = dFrame - mMoveDFrame;
798802
const int iDDFrame = qRound(dDFrame);
@@ -809,8 +813,31 @@ void KeysView::handleMouseMove(const QPoint &pos,
809813
const QPointF saved = mGPressedPoint->getSavedFrameAndValue();
810814
const qreal rawFrame = saved.x() + dFrameV;
811815
const qreal rawValue = saved.y() + dValue;
812-
const qreal newFrame = qBound(mMinMoveFrame, rawFrame, mMaxMoveFrame);
813-
const qreal newValue = qBound(mMinMoveVal, rawValue, mMaxMoveVal);
816+
qreal newFrame = qBound(mMinMoveFrame, rawFrame, mMaxMoveFrame);
817+
qreal newValue = qBound(mMinMoveVal, rawValue, mMaxMoveVal);
818+
if(shiftPressed) {
819+
if(const auto parentKey = mGPressedPoint->getParentKey()) {
820+
const qreal keyFrame = parentKey->getRelFrame();
821+
const qreal keyValue = parentKey->getValueForGraph();
822+
const qreal dx = newFrame - keyFrame;
823+
const qreal dy = newValue - keyValue;
824+
const qreal dxPx = dx * mPixelsPerFrame;
825+
const qreal dyPx = -dy * mPixelsPerValUnit;
826+
const qreal lengthPx = qSqrt(dxPx*dxPx + dyPx*dyPx);
827+
if(lengthPx > 0.0) {
828+
constexpr qreal snapStep = 15.0;
829+
const qreal angleDeg = qRadiansToDegrees(qAtan2(dyPx, dxPx));
830+
const qreal snappedDeg = std::round(angleDeg / snapStep) * snapStep;
831+
const qreal snappedRad = qDegreesToRadians(snappedDeg);
832+
const qreal snappedDxPx = lengthPx * qCos(snappedRad);
833+
const qreal snappedDyPx = lengthPx * qSin(snappedRad);
834+
newFrame = keyFrame + snappedDxPx / mPixelsPerFrame;
835+
newValue = keyValue - snappedDyPx / mPixelsPerValUnit;
836+
}
837+
}
838+
}
839+
newFrame = qBound(mMinMoveFrame, newFrame, mMaxMoveFrame);
840+
newValue = qBound(mMinMoveVal, newValue, mMaxMoveVal);
814841
mGPressedPoint->setFrameAndValue(newFrame, newValue,
815842
mPixelsPerFrame,
816843
mPixelsPerValUnit);

src/core/MovablePoints/smartctrlpoint.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class CORE_EXPORT SmartCtrlPoint : public NonAnimatedMovablePoint {
3535
SmartCtrlPoint(SmartNodePoint * const parentPoint,
3636
const Type &type);
3737
public:
38+
SmartNodePoint* getParentPoint() const { return mParentPoint_k; }
3839
void drawSk(SkCanvas* const canvas,
3940
const CanvasMode mode,
4041
const float invScale,

src/core/canvas.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,7 @@ bool Canvas::startScalingAction(const eKeyEvent &e)
12191219
}
12201220
mValueInput.clearAndDisableInput();
12211221
mValueInput.setupScale();
1222+
mLastPointMoveBy = QPointF();
12221223

12231224
mRotPivot->setMousePos(e.fPos);
12241225
mTransMode = TransformMode::scale;
@@ -1234,6 +1235,7 @@ bool Canvas::startMovingAction(const eKeyEvent &e)
12341235
mCurrentMode != CanvasMode::pointTransform) { return false; }
12351236
mValueInput.clearAndDisableInput();
12361237
mValueInput.setupMove();
1238+
mLastPointMoveBy = QPointF();
12371239

12381240
mTransMode = TransformMode::move;
12391241
mDoubleClick = false;

src/core/canvas.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,7 @@ class CORE_EXPORT Canvas : public CanvasBase
908908
bool mStartTransform = false;
909909
bool mSelecting = false;
910910
// bool mMoving = false;
911+
QPointF mLastPointMoveBy;
911912

912913
QRectF mSelectionRect;
913914
CanvasMode mCurrentMode = CanvasMode::boxTransform;

src/core/canvasmouseinteractions.cpp

Lines changed: 42 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,11 @@
6161

6262
using namespace Friction::Core;
6363

64+
namespace {
65+
constexpr qreal kDegToRad = static_cast<qreal>(0.017453292519943295769);
66+
constexpr qreal kRadToDeg = static_cast<qreal>(57.2957795130823208768);
67+
}
68+
6469
void Canvas::handleMovePathMousePressEvent(const eMouseEvent& e) {
6570
mPressedBox = mCurrentContainer->getBoxAt(e.fPos);
6671
if(e.shiftMod()) return;
@@ -209,6 +214,7 @@ void Canvas::handleLeftButtonMousePress(const eMouseEvent& e) {
209214
mDoubleClick = false;
210215
//mMovesToSkip = 2;
211216
mStartTransform = true;
217+
mLastPointMoveBy = QPointF();
212218

213219
const qreal invScale = 1/e.fScale;
214220
const qreal invScaleUi = (qApp ? qApp->devicePixelRatio() : 1.0) * invScale;
@@ -726,14 +732,46 @@ void Canvas::handleMovePointMouseMove(const eMouseEvent &e) {
726732
}
727733
}
728734

735+
const QPointF moveBy = getMoveByValueForEvent(e);
736+
QPointF finalMoveBy = moveBy;
737+
if((mods & Qt::ShiftModifier) && mPressedPoint->isCtrlPoint()) {
738+
const auto ctrlPoint = enve_cast<SmartCtrlPoint*>(mPressedPoint.data());
739+
if(ctrlPoint) {
740+
const auto parentPoint = ctrlPoint->getParentPoint();
741+
if(parentPoint) {
742+
const QPointF parentAbs = parentPoint->getAbsolutePos();
743+
const QPointF startAbs = ctrlPoint->getAbsolutePos() - mLastPointMoveBy;
744+
QPointF targetAbs = startAbs + moveBy;
745+
const QPointF dir = targetAbs - parentAbs;
746+
const qreal len = pointToLen(dir);
747+
if(len > 0.0) {
748+
constexpr qreal snapStep = 15.0;
749+
const qreal angleDeg = std::atan2(dir.y(), dir.x()) * kRadToDeg;
750+
const qreal snappedDeg = std::round(angleDeg / snapStep) * snapStep;
751+
const qreal snappedRad = snappedDeg * kDegToRad;
752+
const QPointF snappedVec(len * std::cos(snappedRad),
753+
len * std::sin(snappedRad));
754+
targetAbs = parentAbs + snappedVec;
755+
finalMoveBy = targetAbs - startAbs;
756+
}
757+
}
758+
}
759+
}
760+
729761
if(!mPressedPoint->selectionEnabled()) {
730762
if(mStartTransform) mPressedPoint->startTransform();
731-
mPressedPoint->moveByAbs(getMoveByValueForEvent(e));
763+
mPressedPoint->moveByAbs(finalMoveBy);
764+
mLastPointMoveBy = finalMoveBy;
732765
return;
733766
}
767+
moveSelectedPointsByAbs(finalMoveBy,
768+
mStartTransform);
769+
mLastPointMoveBy = finalMoveBy;
770+
} else {
771+
const QPointF moveBy = getMoveByValueForEvent(e);
772+
moveSelectedPointsByAbs(moveBy, mStartTransform);
773+
mLastPointMoveBy = moveBy;
734774
}
735-
moveSelectedPointsByAbs(getMoveByValueForEvent(e),
736-
mStartTransform);
737775
}
738776
}
739777

@@ -872,6 +910,7 @@ bool Canvas::prepareRotation(const QPointF &startPos,
872910
mTransMode = TransformMode::rotate;
873911
mRotHalfCycles = 0;
874912
mLastDRot = 0;
913+
mLastPointMoveBy = QPointF();
875914

876915
mDoubleClick = false;
877916
mStartTransform = true;

0 commit comments

Comments
 (0)