Skip to content

Commit 80d90fa

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

5 files changed

Lines changed: 88 additions & 22 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
@@ -1286,6 +1286,7 @@ bool Canvas::startScalingAction(const eKeyEvent &e)
12861286
}
12871287
mValueInput.clearAndDisableInput();
12881288
mValueInput.setupScale();
1289+
mLastPointMoveBy = QPointF();
12891290

12901291
mRotPivot->setMousePos(e.fPos);
12911292
mTransMode = TransformMode::scale;
@@ -1301,6 +1302,7 @@ bool Canvas::startMovingAction(const eKeyEvent &e)
13011302
mCurrentMode != CanvasMode::pointTransform) { return false; }
13021303
mValueInput.clearAndDisableInput();
13031304
mValueInput.setupMove();
1305+
mLastPointMoveBy = QPointF();
13041306

13051307
mTransMode = TransformMode::move;
13061308
mDoubleClick = false;

src/core/canvas.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -935,6 +935,7 @@ class CORE_EXPORT Canvas : public CanvasBase
935935
bool mStartTransform = false;
936936
bool mSelecting = false;
937937
// bool mMoving = false;
938+
QPointF mLastPointMoveBy;
938939

939940
QRectF mSelectionRect;
940941
CanvasMode mCurrentMode = CanvasMode::boxTransform;

src/core/canvasmouseinteractions.cpp

Lines changed: 55 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,11 @@
6464

6565
using namespace Friction::Core;
6666

67+
namespace {
68+
constexpr qreal kDegToRad = static_cast<qreal>(0.017453292519943295769);
69+
constexpr qreal kRadToDeg = static_cast<qreal>(57.2957795130823208768);
70+
}
71+
6772
void Canvas::handleMovePathMousePressEvent(const eMouseEvent& e)
6873
{
6974
mPressedBox = mCurrentContainer->getBoxAt(e.fPos);
@@ -212,6 +217,7 @@ void Canvas::handleLeftButtonMousePress(const eMouseEvent& e)
212217
//mMovesToSkip = 2;
213218
mStartTransform = true;
214219
mHasCreationPressPos = false;
220+
mLastPointMoveBy = QPointF();
215221

216222
const qreal invScale = 1/e.fScale;
217223
const qreal invScaleUi = (qApp ? qApp->devicePixelRatio() : 1.0) * invScale;
@@ -710,44 +716,72 @@ void Canvas::handleMovePointMouseMove(const eMouseEvent &e)
710716
}
711717
}
712718

719+
QPointF moveBy = getMoveByValueForEvent(e);
720+
QPointF finalMoveBy = moveBy;
721+
if ((mods & Qt::ShiftModifier) && mPressedPoint->isCtrlPoint()) {
722+
const auto ctrlPoint = enve_cast<SmartCtrlPoint*>(mPressedPoint.data());
723+
if (ctrlPoint) {
724+
const auto parentPoint = ctrlPoint->getParentPoint();
725+
if (parentPoint) {
726+
const QPointF parentAbs = parentPoint->getAbsolutePos();
727+
const QPointF startAbs = ctrlPoint->getAbsolutePos() - mLastPointMoveBy;
728+
QPointF targetAbs = startAbs + moveBy;
729+
const QPointF dir = targetAbs - parentAbs;
730+
const qreal len = pointToLen(dir);
731+
if (len > 0.0) {
732+
constexpr qreal snapStep = 15.0;
733+
const qreal angleDeg = std::atan2(dir.y(), dir.x()) * kRadToDeg;
734+
const qreal snappedDeg = std::round(angleDeg / snapStep) * snapStep;
735+
const qreal snappedRad = snappedDeg * kDegToRad;
736+
const QPointF snappedVec(len * std::cos(snappedRad),
737+
len * std::sin(snappedRad));
738+
targetAbs = parentAbs + snappedVec;
739+
finalMoveBy = targetAbs - startAbs;
740+
}
741+
}
742+
}
743+
}
744+
713745
if (!mPressedPoint->selectionEnabled()) {
714746
if (mStartTransform) {
715747
mPressedPoint->startTransform();
716748
mGridMoveStartPivot = mPressedPoint->getAbsolutePos();
717749
}
718-
719-
auto moveBy = getMoveByValueForEvent(e);
720750
if (snappingActive) {
721751
const auto snapped = moveBySnapTargets(e.fModifiers,
722-
moveBy,
752+
finalMoveBy,
723753
gridSettings,
724754
includeSelectedBounds,
725755
false,
726756
false);
727-
if (snapped.first) { moveBy = snapped.second; }
757+
if (snapped.first) { finalMoveBy = snapped.second; }
728758
}
729759

730-
mPressedPoint->moveByAbs(moveBy);
760+
mPressedPoint->moveByAbs(finalMoveBy);
761+
mLastPointMoveBy = finalMoveBy;
731762
return;
732763
}
733-
}
734764

735-
if (mStartTransform && !mSelectedPoints_d.isEmpty()) {
736-
mGridMoveStartPivot = getSelectedPointsAbsPivotPos();
737-
}
765+
if (mStartTransform && !mSelectedPoints_d.isEmpty()) {
766+
mGridMoveStartPivot = getSelectedPointsAbsPivotPos();
767+
}
768+
if (snappingActive && !mSelectedPoints_d.isEmpty()) {
769+
const auto snapped = moveBySnapTargets(e.fModifiers,
770+
finalMoveBy,
771+
gridSettings,
772+
includeSelectedBounds,
773+
false,
774+
false);
775+
if (snapped.first) { finalMoveBy = snapped.second; }
776+
}
738777

739-
auto moveBy = getMoveByValueForEvent(e);
740-
if (snappingActive && !mSelectedPoints_d.isEmpty()) {
741-
const auto snapped = moveBySnapTargets(e.fModifiers,
742-
moveBy,
743-
gridSettings,
744-
includeSelectedBounds,
745-
false,
746-
false);
747-
if (snapped.first) { moveBy = snapped.second; }
778+
moveSelectedPointsByAbs(finalMoveBy, mStartTransform);
779+
mLastPointMoveBy = finalMoveBy;
780+
} else {
781+
const QPointF moveBy = getMoveByValueForEvent(e);
782+
moveSelectedPointsByAbs(moveBy, mStartTransform);
783+
mLastPointMoveBy = moveBy;
748784
}
749-
750-
moveSelectedPointsByAbs(moveBy, mStartTransform);
751785
}
752786
}
753787

@@ -894,6 +928,7 @@ bool Canvas::prepareRotation(const QPointF &startPos,
894928
mTransMode = TransformMode::rotate;
895929
mRotHalfCycles = 0;
896930
mLastDRot = 0;
931+
mLastPointMoveBy = QPointF();
897932

898933
mDoubleClick = false;
899934
mStartTransform = true;

0 commit comments

Comments
 (0)