123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086 |
- /*
- * Copyright (c) Contributors to the Open 3D Engine Project.
- * For complete copyright and license terms please see the LICENSE at the root of this distribution.
- *
- * SPDX-License-Identifier: Apache-2.0 OR MIT
- *
- */
- #include "EditorDefs.h"
- #include "TrackViewSplineCtrl.h"
- // Qt
- #include <QRubberBand>
- // Editor
- #include "AnimationContext.h"
- // AzCore
- #include <AzCore/std/algorithm.h>
- #include <AzCore/std/containers/list.h>
- class CUndoTrackViewSplineCtrl
- : public ISplineCtrlUndo
- {
- public:
- CUndoTrackViewSplineCtrl(CTrackViewSplineCtrl* pCtrl, std::vector<ISplineInterpolator*>& splineContainer)
- {
- if (GetIEditor()->GetAnimation()->GetSequence())
- {
- m_sequenceEntityId = GetIEditor()->GetAnimation()->GetSequence()->GetSequenceComponentEntityId();
- }
- m_pCtrl = pCtrl;
- // Loop over all affected splines
- for (size_t splineIndex = 0; splineIndex < splineContainer.size(); ++splineIndex)
- {
- AddSpline(splineContainer[splineIndex]);
- }
- SerializeSplines(&CSplineEntry::m_undo, false);
- }
- protected:
- void AddSpline(ISplineInterpolator* pSpline)
- {
- // Find corresponding track and remember it
- for (size_t trackIndex = 0; trackIndex < m_pCtrl->m_tracks.size(); ++trackIndex)
- {
- CTrackViewTrack* pTrack = m_pCtrl->m_tracks[trackIndex];
- if (pTrack->GetSpline() == pSpline)
- {
- CSplineEntry entry;
- entry.m_trackId = pTrack->GetId();
- m_splineEntries.push_back(entry);
- }
- }
- }
- int GetSize() override { return sizeof(*this); }
- void Undo(bool bUndo) override
- {
- CTrackViewSplineCtrl* pCtrl = FindControl(m_pCtrl);
- if (pCtrl)
- {
- pCtrl->SendNotifyEvent(SPLN_BEFORE_CHANGE);
- }
- const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
- CTrackViewSequence* sequence = sequenceManager->GetSequenceByEntityId(m_sequenceEntityId);
- AZ_Assert(sequence, "Expected valid sequence.");
- if (!sequence)
- {
- return;
- }
- CTrackViewSequenceNotificationContext context(sequence);
- if (bUndo)
- {
- // Save key selection states for redo if necessary
- m_redoKeyStates = sequence->SaveKeyStates();
- SerializeSplines(&CSplineEntry::m_redo, false);
- }
- SerializeSplines(&CSplineEntry::m_undo, true);
- // Undo key selection state
- sequence->RestoreKeyStates(m_undoKeyStates);
- if (pCtrl && bUndo)
- {
- pCtrl->m_bKeyTimesDirty = true;
- pCtrl->SendNotifyEvent(SPLN_CHANGE);
- pCtrl->update();
- }
- if (bUndo)
- {
- sequence->OnKeySelectionChanged();
- }
- }
- void Redo() override
- {
- const CTrackViewSequenceManager* pSequenceManager = GetIEditor()->GetSequenceManager();
- CTrackViewSequence* sequence = pSequenceManager->GetSequenceByEntityId(m_sequenceEntityId);
- AZ_Assert(sequence, "Expected valid sequence.");
- if (!sequence)
- {
- return;
- }
- CTrackViewSequenceNotificationContext context(sequence);
- CTrackViewSplineCtrl* pCtrl = FindControl(m_pCtrl);
- if (pCtrl)
- {
- pCtrl->SendNotifyEvent(SPLN_BEFORE_CHANGE);
- }
- SerializeSplines(&CSplineEntry::m_redo, true);
- // Redo key selection state
- sequence->RestoreKeyStates(m_redoKeyStates);
- if (pCtrl)
- {
- pCtrl->m_bKeyTimesDirty = true;
- pCtrl->SendNotifyEvent(SPLN_CHANGE);
- pCtrl->update();
- }
- sequence->OnKeySelectionChanged();
- }
- bool IsSelectionChanged() const override
- {
- const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
- CTrackViewSequence* sequence = sequenceManager->GetSequenceByEntityId(m_sequenceEntityId);
- AZ_Assert(sequence, "Expected valid sequence.");
- if (!sequence)
- {
- return false;
- }
- const AZStd::vector<bool> currentKeyState = sequence->SaveKeyStates();
- return m_undoKeyStates != currentKeyState;
- }
- public:
- using CTrackViewSplineCtrls = AZStd::list<CTrackViewSplineCtrl*>;
- static CTrackViewSplineCtrl* FindControl(CTrackViewSplineCtrl* pCtrl)
- {
- if (!pCtrl)
- {
- return nullptr;
- }
- auto iter = AZStd::find(s_activeCtrls.begin(), s_activeCtrls.end(), pCtrl);
- if (iter == s_activeCtrls.end())
- {
- return nullptr;
- }
- return *iter;
- }
- static void RegisterControl(CTrackViewSplineCtrl* pCtrl)
- {
- if (!FindControl(pCtrl))
- {
- s_activeCtrls.push_back(pCtrl);
- }
- }
- static void UnregisterControl(CTrackViewSplineCtrl* pCtrl)
- {
- if (FindControl(pCtrl))
- {
- s_activeCtrls.remove(pCtrl);
- }
- }
- static CTrackViewSplineCtrls s_activeCtrls;
- private:
- class CSplineEntry
- {
- public:
- _smart_ptr<ISplineBackup> m_undo;
- _smart_ptr<ISplineBackup> m_redo;
- unsigned int m_trackId;
- };
- void SerializeSplines(_smart_ptr<ISplineBackup> CSplineEntry::* backup, bool bLoading)
- {
- const CTrackViewSequenceManager* sequenceManager = GetIEditor()->GetSequenceManager();
- CTrackViewSequence* sequence = sequenceManager->GetSequenceByEntityId(m_sequenceEntityId);
- AZ_Assert(sequence, "Expected valid sequence");
- if (!sequence)
- {
- return;
- }
- for (auto it = m_splineEntries.begin(); it != m_splineEntries.end(); ++it)
- {
- CSplineEntry& entry = *it;
- CTrackViewTrack* track = sequence->FindTrackById(entry.m_trackId);
- if (track)
- {
- ISplineInterpolator* pSpline = track->GetSpline();
- if (pSpline && bLoading)
- {
- pSpline->Restore(entry.*backup);
- }
- else if (pSpline)
- {
- (entry.*backup) = pSpline->Backup();
- }
- }
- }
- }
- AZ::EntityId m_sequenceEntityId;
- CTrackViewSplineCtrl* m_pCtrl;
- AZStd::vector<CSplineEntry> m_splineEntries;
- AZStd::vector<float> m_keyTimes;
- AZStd::vector<bool> m_undoKeyStates;
- AZStd::vector<bool> m_redoKeyStates;
- };
- CUndoTrackViewSplineCtrl::CTrackViewSplineCtrls CUndoTrackViewSplineCtrl::s_activeCtrls;
- CTrackViewSplineCtrl::CTrackViewSplineCtrl(QWidget* parent)
- : SplineWidget(parent)
- , m_bKeysFreeze(false)
- , m_bTangentsFreeze(false)
- , m_stashedRecordModeWhenDraggingTime(false)
- {
- CUndoTrackViewSplineCtrl::RegisterControl(this);
- }
- CTrackViewSplineCtrl::~CTrackViewSplineCtrl()
- {
- CUndoTrackViewSplineCtrl::UnregisterControl(this);
- }
- bool CTrackViewSplineCtrl::GetTangentHandlePts(QPoint& inTangentPt, QPoint& pt, QPoint& outTangentPt,
- int nSpline, int nKey, int nDimension)
- {
- ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
- CTrackViewTrack* pTrack = m_tracks[nSpline];
- float time = pSpline->GetKeyTime(nKey);
- ISplineInterpolator::ValueType value, tin, tout;
- ISplineInterpolator::ZeroValue(value);
- pSpline->GetKeyValue(nKey, value);
- pSpline->GetKeyTangents(nKey, tin, tout);
- const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(nKey);
- if (pTrack->GetCurveType() == eAnimCurveType_TCBFloat)
- {
- ITcbKey tcbKey;
- keyHandle.GetKey(&tcbKey);
- Vec2 va, vb, vc;
- va.x = time - 1.0f;
- va.y = value[nDimension] - tin[nDimension];
- vb.x = time;
- vb.y = value[nDimension];
- vc.x = time + 1.0f;
- vc.y = value[nDimension] + tout[nDimension];
- inTangentPt = WorldToClient(va);
- pt = WorldToClient(vb);
- outTangentPt = WorldToClient(vc);
- Vec2 tinv, toutv;
- float maxLength = float(outTangentPt.x() - pt.x());
- tinv.x = float(inTangentPt.x() - pt.x());
- tinv.y = float(inTangentPt.y() - pt.y());
- toutv.x = float(outTangentPt.x() - pt.x());
- toutv.y = float(outTangentPt.y() - pt.y());
- tinv.Normalize();
- toutv.Normalize();
- tinv *= maxLength / (2 - tcbKey.easeto);
- toutv *= maxLength / (2 - tcbKey.easefrom);
- inTangentPt = pt + QPoint(int(tinv.x), int(tinv.y));
- outTangentPt = pt + QPoint(int(toutv.x), int(toutv.y));
- }
- else
- {
- AZ_Assert(pTrack->GetCurveType() == eAnimCurveType_BezierFloat, "Unexpected curve type %i", pTrack->GetCurveType());
- AZ_Assert(nDimension == 0, "Dimension is not zero");
- I2DBezierKey bezierKey;
- keyHandle.GetKey(&bezierKey);
- Vec2 va, vb, vc;
- va.x = time - tin[0];
- va.y = value[0] - tin[1];
- vb.x = time;
- vb.y = value[0];
- vc.x = time + tout[0];
- vc.y = value[0] + tout[1];
- inTangentPt = WorldToClient(va);
- pt = WorldToClient(vb);
- outTangentPt = WorldToClient(vc);
- }
- return true;
- }
- void CTrackViewSplineCtrl::ComputeIncomingTangentAndEaseTo(float& ds, float& easeTo, QPoint inTangentPt,
- int nSpline, int nKey, int nDimension)
- {
- ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
- CTrackViewTrack* pTrack = m_tracks[nSpline];
- float time = pSpline->GetKeyTime(nKey);
- ISplineInterpolator::ValueType value, tin, tout;
- ISplineInterpolator::ZeroValue(value);
- pSpline->GetKeyValue(nKey, value);
- pSpline->GetKeyTangents(nKey, tin, tout);
- const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(nKey);
- ITcbKey tcbKey;
- keyHandle.GetKey(&tcbKey);
- // Get the control point.
- Vec2 tinv, vb;
- vb.x = time;
- vb.y = value[nDimension];
- QPoint pt = WorldToClient(vb);
- // Get the max length to compute the 'ease' value.
- float maxLength = float(WorldToClient(Vec2(vb.x + 1, vb.y)).x() - pt.x());
- QPoint tmp = inTangentPt - pt;
- tinv.x = float(tmp.x());
- tinv.y = float(tmp.y());
- // Compute the 'easeTo'.
- easeTo = 2.0f - maxLength / tinv.GetLength();
- // Compute the 'ds'.
- Vec2 va = ClientToWorld(inTangentPt);
- if (time < va.x + 0.000001f)
- {
- if (value[nDimension] > va.y)
- {
- ds = 1000000.0f;
- }
- else
- {
- ds = -1000000.0f;
- }
- }
- else
- {
- ds = (value[nDimension] - va.y) / (time - va.x);
- }
- }
- void CTrackViewSplineCtrl::ComputeOutgoingTangentAndEaseFrom(float& dd, float& easeFrom, QPoint outTangentPt,
- int nSpline, int nKey, int nDimension)
- {
- ISplineInterpolator* pSpline = m_splines[nSpline].pSpline;
- CTrackViewTrack* pTrack = m_tracks[nSpline];
- float time = pSpline->GetKeyTime(nKey);
- ISplineInterpolator::ValueType value, tin, tout;
- ISplineInterpolator::ZeroValue(value);
- pSpline->GetKeyValue(nKey, value);
- pSpline->GetKeyTangents(nKey, tin, tout);
- const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(nKey);
- ITcbKey tcbKey;
- keyHandle.GetKey(&tcbKey);
- // Get the control point.
- Vec2 toutv, vb;
- vb.x = time;
- vb.y = value[nDimension];
- QPoint pt = WorldToClient(vb);
- // Get the max length to comute the 'ease' value.
- float maxLength = float(WorldToClient(Vec2(vb.x + 1, vb.y)).x() - pt.x());
- QPoint tmp = outTangentPt - pt;
- toutv.x = float(tmp.x());
- toutv.y = float(tmp.y());
- // Compute the 'easeFrom'.
- easeFrom = 2.0f - maxLength / toutv.GetLength();
- // Compute the 'dd'.
- Vec2 vc = ClientToWorld(outTangentPt);
- if (vc.x < time + 0.000001f)
- {
- if (value[nDimension] < vc.y)
- {
- dd = 1000000.0f;
- }
- else
- {
- dd = -1000000.0f;
- }
- }
- else
- {
- dd = (vc.y - value[nDimension]) / (vc.x - time);
- }
- }
- void CTrackViewSplineCtrl::AddSpline(ISplineInterpolator* pSpline, CTrackViewTrack* pTrack, const QColor& color)
- {
- QColor colorArray[4];
- colorArray[0] = colorArray[1] = colorArray[2] = colorArray[3] = color;
- AddSpline(pSpline, pTrack, colorArray);
- }
- void CTrackViewSplineCtrl::AddSpline(ISplineInterpolator* pSpline, CTrackViewTrack* pTrack, QColor anColorArray[4])
- {
- for (int i = 0; i < (int)m_splines.size(); i++)
- {
- if (m_splines[i].pSpline == pSpline)
- {
- return;
- }
- }
- SSplineInfo si;
- for (int nCurrentDimension = 0; nCurrentDimension < pSpline->GetNumDimensions(); nCurrentDimension++)
- {
- si.anColorArray[nCurrentDimension] = anColorArray[nCurrentDimension];
- }
- si.pSpline = pSpline;
- si.pDetailSpline = nullptr;
- m_splines.push_back(si);
- m_tracks.push_back(pTrack);
- m_bKeyTimesDirty = true;
- update();
- }
- void CTrackViewSplineCtrl::RemoveAllSplines()
- {
- m_tracks.clear();
- SplineWidget::RemoveAllSplines();
- }
- void CTrackViewSplineCtrl::MoveSelectedTangentHandleTo(const QPoint& point)
- {
- AZ_Assert(m_pHitSpline, "m_pHitSpline is null");
- AZ_Assert(m_nHitKeyIndex >= 0, "m_nHitKeyIndex is negative");
- AZ_Assert(m_bHitIncomingHandle >= 0, "m_bHitIncomingHandle is negative")
- // Set the custom flag to the key.
- int nRemoveFlags, nAddFlags;
- if (m_bHitIncomingHandle)
- {
- nRemoveFlags = SPLINE_KEY_TANGENT_IN_MASK;
- nAddFlags = SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_IN_SHIFT;
- }
- else
- {
- nRemoveFlags = SPLINE_KEY_TANGENT_OUT_MASK;
- nAddFlags = SPLINE_KEY_TANGENT_CUSTOM << SPLINE_KEY_TANGENT_OUT_SHIFT;
- }
- int flags = m_pHitSpline->GetKeyFlags(m_nHitKeyIndex);
- flags &= ~nRemoveFlags;
- flags |= nAddFlags;
- m_pHitSpline->SetKeyFlags(m_nHitKeyIndex, flags);
- // Adjust the incoming or outgoing tangent.
- int splineIndex;
- for (splineIndex = 0; splineIndex < m_splines.size(); ++splineIndex)
- {
- if (m_pHitSpline == m_splines[splineIndex].pSpline)
- {
- break;
- }
- }
- AZ_Assert(splineIndex < m_splines.size(), "splineIndex %i is out of range", splineIndex);
- CTrackViewTrack* pTrack = m_tracks[splineIndex];
- CTrackViewKeyHandle keyHandle = pTrack->GetKey(m_nHitKeyIndex);
- if (pTrack->GetCurveType() == eAnimCurveType_TCBFloat)
- {
- if (m_bHitIncomingHandle)
- {
- float ds, easeTo;
- ComputeIncomingTangentAndEaseTo(ds, easeTo, point, splineIndex, m_nHitKeyIndex, m_nHitDimension);
- // ease-to
- ITcbKey key;
- keyHandle.GetKey(&key);
- key.easeto += easeTo;
- if (key.easeto > 1)
- {
- key.easeto = 1.0f;
- }
- else if (key.easeto < 0)
- {
- key.easeto = 0;
- }
- keyHandle.SetKey(&key);
- // tin
- ISplineInterpolator::ValueType tin, tout;
- m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
- tin[m_nHitDimension] = ds;
- m_pHitSpline->SetKeyInTangent(m_nHitKeyIndex, tin);
- }
- else
- {
- float dd, easeFrom;
- ComputeOutgoingTangentAndEaseFrom(dd, easeFrom, point, splineIndex, m_nHitKeyIndex, m_nHitDimension);
- // ease-from
- ITcbKey key;
- keyHandle.GetKey(&key);
- key.easefrom += easeFrom;
- if (key.easefrom > 1)
- {
- key.easefrom = 1.0f;
- }
- else if (key.easefrom < 0)
- {
- key.easefrom = 0;
- }
- keyHandle.SetKey(&key);
- // tout
- ISplineInterpolator::ValueType tin, tout;
- m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
- tout[m_nHitDimension] = dd;
- m_pHitSpline->SetKeyOutTangent(m_nHitKeyIndex, tout);
- }
- }
- else
- {
- AZ_Assert(pTrack->GetCurveType() == eAnimCurveType_BezierFloat, "Unexpected curve type %i", pTrack->GetCurveType());
- AZ_Assert(m_nHitDimension == 0, "Hit dimension is not zero");
- Vec2 tp = ClientToWorld(point);
- if (m_bHitIncomingHandle)
- {
- // tin
- ISplineInterpolator::ValueType value, tin, tout;
- float time = m_pHitSpline->GetKeyTime(m_nHitKeyIndex);
- m_pHitSpline->GetKeyValue(m_nHitKeyIndex, value);
- m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
- tin[0] = time - tp.x;
- // Constrain the time range so that the time curve is always monotonically increasing.
- if (tin[0] < 0)
- {
- tin[0] = 0;
- }
- else if (m_nHitKeyIndex > 0
- && tin[0] > (time - m_pHitSpline->GetKeyTime(m_nHitKeyIndex - 1)))
- {
- tin[0] = time - m_pHitSpline->GetKeyTime(m_nHitKeyIndex - 1);
- }
- tin[1] = value[0] - tp.y;
- m_pHitSpline->SetKeyInTangent(m_nHitKeyIndex, tin);
- }
- else
- {
- // tout
- ISplineInterpolator::ValueType value, tin, tout;
- float time = m_pHitSpline->GetKeyTime(m_nHitKeyIndex);
- m_pHitSpline->GetKeyValue(m_nHitKeyIndex, value);
- m_pHitSpline->GetKeyTangents(m_nHitKeyIndex, tin, tout);
- tout[0] = tp.x - time;
- // Constrain the time range so that the time curve is always monotonically increasing.
- if (tout[0] < 0)
- {
- tout[0] = 0;
- }
- else if (m_nHitKeyIndex < m_pHitSpline->GetKeyCount() - 1
- && tout[0] > (m_pHitSpline->GetKeyTime(m_nHitKeyIndex + 1) - time))
- {
- tout[0] = m_pHitSpline->GetKeyTime(m_nHitKeyIndex + 1) - time;
- }
- tout[1] = tp.y - value[0];
- m_pHitSpline->SetKeyOutTangent(m_nHitKeyIndex, tout);
- }
- }
- SendNotifyEvent(SPLN_CHANGE);
- update();
- }
- void CTrackViewSplineCtrl::mouseMoveEvent(QMouseEvent* event)
- {
- const QPoint point = event->pos();
- CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
- if (!pSequence)
- {
- return;
- }
- CTrackViewSequenceNotificationContext context(pSequence);
- m_cMousePos = point;
- if (m_editMode == NothingMode)
- {
- switch (HitTest(point))
- {
- case HIT_SPLINE:
- setCursor(CMFCUtils::LoadCursor(IDC_ARRWHITE));
- break;
- case HIT_KEY:
- case HIT_TANGENT_HANDLE:
- setCursor(CMFCUtils::LoadCursor(IDC_ARRBLCK));
- break;
- default:
- unsetCursor();
- break;
- }
- }
- if (m_editMode == SelectMode)
- {
- unsetCursor();
- QRect rc(m_cMouseDownPos, point);
- rc = rc.normalized().intersected(m_rcSpline);
- m_rcSelect = rc;
- m_rubberBand->setGeometry(m_rcSelect);
- m_rubberBand->setVisible(true);
- }
- if (m_editMode == TimeMarkerMode)
- {
- unsetCursor();
- SetTimeMarker(XOfsToTime(point.x()));
- SendNotifyEvent(SPLN_TIME_CHANGE);
- }
- if (m_boLeftMouseButtonDown)
- {
- if (m_editMode == TrackingMode && point != m_cMouseDownPos)
- {
- m_startedDragging = true;
- GetIEditor()->RestoreUndo();
- m_pCurrentUndo = nullptr;
- StoreUndo();
- bool bAltClick = CheckVirtualKey(Qt::Key_Menu);
- bool bShiftClick = CheckVirtualKey(Qt::Key_Shift);
- bool bSpaceClick = CheckVirtualKey(Qt::Key_Space);
- Vec2 v0 = ClientToWorld(m_cMouseDownPos);
- Vec2 v1 = ClientToWorld(point);
- if (m_hitCode == HIT_TANGENT_HANDLE)
- {
- if (!m_bTangentsFreeze)
- {
- MoveSelectedTangentHandleTo(point);
- }
- }
- else if (!m_bKeysFreeze)
- {
- if (bAltClick && bShiftClick)
- {
- ValueScaleKeys(v0.y, v1.y);
- }
- else if (bAltClick)
- {
- TimeScaleKeys(m_fTimeMarker, v0.x, v1.x);
- }
- else if (bShiftClick)
- {
- // Constrains the move to the vertical direction.
- MoveSelectedKeys(Vec2(0, v1.y - v0.y), false);
- }
- else if (bSpaceClick)
- {
- // Reset to the original position.
- MoveSelectedKeys(Vec2(0, 0), false);
- }
- else
- {
- MoveSelectedKeys(v1 - v0, m_copyKeys);
- }
- }
- }
- }
- if (m_editMode == TrackingMode && GetNumSelected() == 1)
- {
- float time = 0;
- ISplineInterpolator::ValueType afValue;
- QString tipText;
- bool boFoundTheSelectedKey(false);
- for (size_t splineIndex = 0, endSpline = m_splines.size(); splineIndex < endSpline; ++splineIndex)
- {
- ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
- CTrackViewTrack* pTrack = m_tracks[splineIndex];
- for (int i = 0; i < pSpline->GetKeyCount(); i++)
- {
- const CTrackViewKeyHandle& keyHandle = pTrack->GetKey(i);
- for (int nCurrentDimension = 0; nCurrentDimension < pSpline->GetNumDimensions(); nCurrentDimension++)
- {
- if (pSpline->IsKeySelectedAtDimension(i, nCurrentDimension))
- {
- time = pSpline->GetKeyTime(i);
- pSpline->GetKeyValue(i, afValue);
- if (pTrack->GetCurveType() == eAnimCurveType_TCBFloat)
- {
- ITcbKey key;
- keyHandle.GetKey(&key);
- tipText = QStringLiteral("t=%1 v=%2 / T=%3 C=%4 B=%5")
- .arg(time * m_fTooltipScaleX, 3, 'f').arg(afValue[nCurrentDimension] * m_fTooltipScaleY, 3, 'f', 2)
- .arg(key.tens, 3, 'f').arg(key.cont, 3, 'f').arg(key.bias, 3, 'f');
- }
- else
- {
- AZ_Assert(pTrack->GetCurveType() == eAnimCurveType_BezierFloat, "Unexpected curve type %i", pTrack->GetCurveType());
- ISplineInterpolator::ValueType tin, tout;
- pSpline->GetKeyTangents(i, tin, tout);
- tipText = QStringLiteral("t=%1 v=%2 / tin=(%3,%4) tout=(%5,%6)")
- .arg(time * m_fTooltipScaleX, 3, 'f').arg(afValue[0] * m_fTooltipScaleY, 3, 'f', 2)
- .arg(tin[0], 3, 'f').arg(tin[1], 3, 'f', 2).arg(tout[0], 3, 'f').arg(tout[1], 3, 'f', 2);
- }
- boFoundTheSelectedKey = true;
- break;
- }
- }
- if (boFoundTheSelectedKey)
- {
- break;
- }
- }
- }
- if (point != m_lastToolTipPos)
- {
- m_lastToolTipPos = point;
- m_tooltipText = tipText;
- update();
- }
- }
- switch (m_editMode)
- {
- case ScrollMode:
- {
- // Set the new scrolled coordinates
- const float ofsx = m_grid.origin.GetX() - (point.x() - m_cMouseDownPos.x()) / m_grid.zoom.GetX();
- const float ofsy = m_grid.origin.GetY() + (point.y() - m_cMouseDownPos.y()) / m_grid.zoom.GetY();
- SetScrollOffset(Vec2(ofsx, ofsy));
- m_cMouseDownPos = point;
- }
- break;
- case ZoomMode:
- {
- float ofsx = (point.x() - m_cMouseDownPos.x()) * 0.01f;
- float ofsy = (point.y() - m_cMouseDownPos.y()) * 0.01f;
- AZ::Vector2 z = m_grid.zoom;
- if (ofsx != 0)
- {
- z.SetX(max(z.GetX() * (1.0f + ofsx), 0.001f));
- }
- if (ofsy != 0)
- {
- z.SetY(max(z.GetY() * (1.0f + ofsy), 0.001f));
- }
- SetZoom(Vec2(z.GetX(), z.GetY()), m_cMouseDownPos);
- m_cMouseDownPos = point;
- }
- break;
- }
- }
- void CTrackViewSplineCtrl::AdjustTCB(float d_tension, float d_continuity, float d_bias)
- {
- CUndo undo("Modify Spline Keys TCB");
- ConditionalStoreUndo();
- SendNotifyEvent(SPLN_BEFORE_CHANGE);
- for (size_t splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex)
- {
- ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
- CTrackViewTrack* pTrack = m_tracks[splineIndex];
- if (pTrack->GetCurveType() != eAnimCurveType_TCBFloat)
- {
- continue;
- }
- for (int i = 0; i < (int)pSpline->GetKeyCount(); i++)
- {
- CTrackViewKeyHandle keyHandle = pTrack->GetKey(i);
- // If the key is selected in any dimension...
- for (
- int nCurrentDimension = 0;
- nCurrentDimension < pSpline->GetNumDimensions();
- nCurrentDimension++
- )
- {
- if (IsKeySelected(pSpline, i, nCurrentDimension))
- {
- ITcbKey key;
- keyHandle.GetKey(&key);
- // tension
- key.tens += d_tension;
- if (key.tens > 1)
- {
- key.tens = 1.0f;
- }
- else if (key.tens < -1)
- {
- key.tens = -1.0f;
- }
- // continuity
- key.cont += d_continuity;
- if (key.cont > 1)
- {
- key.cont = 1.0f;
- }
- else if (key.cont < -1)
- {
- key.cont = -1.0f;
- }
- // bias
- key.bias += d_bias;
- if (key.bias > 1)
- {
- key.bias = 1.0f;
- }
- else if (key.bias < -1)
- {
- key.bias = -1.0f;
- }
- keyHandle.SetKey(&key);
- OnUserCommand(ID_TANGENT_AUTO);
- break;
- }
- }
- }
- }
- SendNotifyEvent(SPLN_CHANGE);
- update();
- }
- void CTrackViewSplineCtrl::OnUserCommand(UINT cmd)
- {
- if (cmd == ID_TANGENT_UNIFY)
- {
- if (IsUnifiedKeyCurrentlySelected() == false)
- {
- ModifySelectedKeysFlags(SPLINE_KEY_TANGENT_ALL_MASK, SPLINE_KEY_TANGENT_UNIFIED);
- }
- else
- {
- ModifySelectedKeysFlags(SPLINE_KEY_TANGENT_ALL_MASK, SPLINE_KEY_TANGENT_BROKEN);
- }
- }
- else if (cmd == ID_FREEZE_KEYS)
- {
- m_bKeysFreeze = !m_bKeysFreeze;
- }
- else if (cmd == ID_FREEZE_TANGENTS)
- {
- m_bTangentsFreeze = !m_bTangentsFreeze;
- }
- else
- {
- SplineWidget::OnUserCommand(cmd);
- }
- }
- bool CTrackViewSplineCtrl::IsUnifiedKeyCurrentlySelected() const
- {
- for (size_t splineIndex = 0, splineCount = m_splines.size(); splineIndex < splineCount; ++splineIndex)
- {
- ISplineInterpolator* pSpline = m_splines[splineIndex].pSpline;
- if (pSpline == nullptr)
- {
- continue;
- }
- for (int i = 0; i < (int)pSpline->GetKeyCount(); i++)
- {
- // If the key is selected in any dimension...
- for (
- int nCurrentDimension = 0;
- nCurrentDimension < pSpline->GetNumDimensions();
- nCurrentDimension++
- )
- {
- if (IsKeySelected(pSpline, i, nCurrentDimension))
- {
- int flags = pSpline->GetKeyFlags(i);
- if ((flags & SPLINE_KEY_TANGENT_ALL_MASK) != SPLINE_KEY_TANGENT_UNIFIED)
- {
- return false;
- }
- }
- }
- }
- }
- return true;
- }
- void CTrackViewSplineCtrl::ClearSelection()
- {
- // In this case, we should deselect all keys, even ones in other tracks.
- // So this overriding is necessary.
- CTrackViewSequence* pSequence = GetIEditor()->GetAnimation()->GetSequence();
- if (pSequence)
- {
- pSequence->DeselectAllKeys();
- }
- }
- ISplineCtrlUndo* CTrackViewSplineCtrl::CreateSplineCtrlUndoObject(std::vector<ISplineInterpolator*>& splineContainer)
- {
- return new CUndoTrackViewSplineCtrl(this, splineContainer);
- }
- void CTrackViewSplineCtrl::mousePressEvent(QMouseEvent* event)
- {
- if (GetIEditor()->GetAnimation()->GetSequence())
- {
- SplineWidget::mousePressEvent(event);
- if (m_editMode == TimeMarkerMode)
- {
- // turn off recording when dragging time
- m_stashedRecordModeWhenDraggingTime = GetIEditor()->GetAnimation()->IsRecordMode();
- GetIEditor()->GetAnimation()->SetRecording(false);
- }
- }
- }
- void CTrackViewSplineCtrl::mouseReleaseEvent(QMouseEvent* event)
- {
- if (GetIEditor()->GetAnimation()->GetSequence())
- {
- bool restoreRecordModeToTrue = (m_editMode == TimeMarkerMode && m_stashedRecordModeWhenDraggingTime);
- SplineWidget::mouseReleaseEvent(event);
- if (restoreRecordModeToTrue)
- {
- // restore recording when dragging time
- GetIEditor()->GetAnimation()->SetRecording(true);
- m_stashedRecordModeWhenDraggingTime = false; // reset stashed value
- }
- }
- }
- void CTrackViewSplineCtrl::mouseDoubleClickEvent(QMouseEvent* event)
- {
- CTrackViewSequence* sequence = GetIEditor()->GetAnimation()->GetSequence();
- if (sequence)
- {
- SplineWidget::mouseDoubleClickEvent(event);
- if (m_hitCode == HIT_SPLINE)
- {
- // HIT_SPLINE results in an added key that gets selected.
- // Use the selected keys to notify the sequence, key by key, of newly added keys
- CTrackViewKeyBundle addedKeys = sequence->GetSelectedKeys();
- for (int keyIdx = addedKeys.GetKeyCount(); --keyIdx >= 0; )
- {
- CTrackViewKeyHandle addedKey = addedKeys.GetKey(keyIdx);
- sequence->OnKeyAdded(addedKey);
- }
- }
- }
- }
- void CTrackViewSplineCtrl::keyPressEvent(QKeyEvent* event)
- {
- auto sequence = GetIEditor()->GetAnimation()->GetSequence();
- if (sequence)
- {
- // HAVE TO INCLUDE CASES FOR THESE IN THE ShortcutOverride handler in ::event() below
- if (event->key() == Qt::Key_S && m_playCallback)
- {
- m_playCallback();
- }
- else if (event->matches(QKeySequence::Delete))
- {
- CUndo undo("Delete Keys");
- SendNotifyEvent(SPLN_BEFORE_CHANGE);
- sequence->DeleteSelectedKeys();
- SendNotifyEvent(SPLN_CHANGE);
- update();
- }
- else if (event->matches(QKeySequence::Undo))
- {
- GetIEditor()->Undo();
- }
- else if (event->matches(QKeySequence::Redo))
- {
- GetIEditor()->Redo();
- }
- else
- {
- SplineWidget::keyPressEvent(event);
- }
- }
- }
- bool CTrackViewSplineCtrl::event(QEvent* e)
- {
- if (e->type() == QEvent::ShortcutOverride)
- {
- // since we respond to the following things, let Qt know so that shortcuts don't override us
- bool respondsToEvent = false;
- QKeyEvent* keyEvent = static_cast<QKeyEvent*>(e);
- if (keyEvent->key() == Qt::Key_S)
- {
- respondsToEvent = true;
- }
- else
- {
- respondsToEvent = keyEvent->matches(QKeySequence::Delete) ||
- keyEvent->matches(QKeySequence::Undo) ||
- keyEvent->matches(QKeySequence::Redo);
- }
- if (respondsToEvent)
- {
- e->accept();
- return true;
- }
- }
- return SplineWidget::event(e);
- }
- void CTrackViewSplineCtrl::wheelEvent(QWheelEvent* event)
- {
- if (GetIEditor()->GetAnimation()->GetSequence())
- {
- SplineWidget::wheelEvent(event);
- }
- }
- void CTrackViewSplineCtrl::SelectKey(ISplineInterpolator* pSpline, int nKey, int nDimension, bool bSelect)
- {
- SplineWidget::SelectKey(pSpline, nKey, nDimension, bSelect);
- GetIEditor()->GetAnimation()->GetSequence()->OnKeySelectionChanged();
- }
- void CTrackViewSplineCtrl::SelectRectangle(const QRect& rc, bool bSelect)
- {
- SplineWidget::SelectRectangle(rc, bSelect);
- GetIEditor()->GetAnimation()->GetSequence()->OnKeySelectionChanged();
- }
- void CTrackViewSplineCtrl::SetPlayCallback(const std::function<void()>& callback)
- {
- m_playCallback = callback;
- }
|