diff options
Diffstat (limited to 'src')
41 files changed, 1185 insertions, 649 deletions
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdDataModelInsertKeyframe.h b/src/Authoring/Client/Code/Core/Commands/CmdDataModelInsertKeyframe.h index a1182280..f2ea635f 100644 --- a/src/Authoring/Client/Code/Core/Commands/CmdDataModelInsertKeyframe.h +++ b/src/Authoring/Client/Code/Core/Commands/CmdDataModelInsertKeyframe.h @@ -28,13 +28,8 @@ ****************************************************************************/ #ifndef INCLUDED_CMD_DATAMODEL_INSERTKEYFRAME_H -#define INCLUDED_CMD_DATAMODEL_INSERTKEYFRAME_H 1 +#define INCLUDED_CMD_DATAMODEL_INSERTKEYFRAME_H -#pragma once - -//============================================================================== -// Include -//============================================================================== #include "Cmd.h" #include "CmdDataModel.h" #include "Doc.h" @@ -51,7 +46,7 @@ public: struct STimeKeyframeData { qt3dsdm::Qt3DSDMPropertyHandle m_Property; - float m_KeyframeTime; + float m_KeyframeTime; // seconds qt3dsdm::SGetOrSetKeyframeInfo m_Infos[4]; size_t m_ValidInfoCount; @@ -69,22 +64,15 @@ public: protected: typedef std::vector<STimeKeyframeData> TKeyframeDataList; -protected: // Members CDoc *m_Doc; qt3dsdm::Qt3DSDMInstanceHandle m_Instance; TKeyframeDataList m_KeyframeDataList; -public: // Construction - //@param inTime is in secs - CCmdDataModelInsertKeyframe(CDoc *inDoc, qt3dsdm::Qt3DSDMInstanceHandle inInstance, - qt3dsdm::Qt3DSDMPropertyHandle inProperty, float inKeyframeTime, - qt3dsdm::SGetOrSetKeyframeInfo *inInfos, size_t inInfoCount) +public: + CCmdDataModelInsertKeyframe(CDoc *inDoc, qt3dsdm::Qt3DSDMInstanceHandle inInstance) : qt3dsdm::CmdDataModel(*inDoc) , m_Doc(inDoc) - , m_Instance(inInstance) - { - AddKeyframeData(inProperty, inKeyframeTime, inInfos, inInfoCount); - } + , m_Instance(inInstance) {} ~CCmdDataModelInsertKeyframe() {} void AddKeyframeData(qt3dsdm::Qt3DSDMPropertyHandle inProperty, float inTime, @@ -93,31 +81,25 @@ public: // Construction m_KeyframeDataList.push_back(STimeKeyframeData(inProperty, inTime, inInfos, inInfoCount)); } - //====================================================================== - // Do/Redo - //====================================================================== unsigned long Do() override { if (!ConsumerExists()) { qt3dsdm::SScopedDataModelConsumer __scopedConsumer(*this); qt3dsdm::IStudioAnimationSystem *theAnimationSystem = m_Doc->GetStudioSystem()->GetAnimationSystem(); - // if there are existing keyframes exist at the same times, the values are overridden. ( - // That's how it always work in studio anyways ) - for (size_t i = 0; i < m_KeyframeDataList.size(); ++i) + // Keyframes at same time are overridden (only 1 keyframe allowed at a point in time) + for (size_t i = 0; i < m_KeyframeDataList.size(); ++i) { theAnimationSystem->SetOrCreateKeyframe( m_Instance, m_KeyframeDataList[i].m_Property, m_KeyframeDataList[i].m_KeyframeTime, m_KeyframeDataList[i].m_Infos, m_KeyframeDataList[i].m_ValidInfoCount); + } } else { DataModelRedo(); } return 0; } - //====================================================================== - // Undo - //====================================================================== unsigned long Undo() override { if (ConsumerExists()) { @@ -126,9 +108,6 @@ public: // Construction return 0; } - //====================================================================== - // ToString - //====================================================================== QString ToString() override { return QObject::tr("Insert Keyframe"); diff --git a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp index f6beca04..51256fe5 100644 --- a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp +++ b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.cpp @@ -288,6 +288,7 @@ qt3dsdm::Qt3DSDMPropertyHandle CClientDataModelBridge::GetImportId() { return m_SceneAsset.m_ImportId; } + qt3dsdm::Qt3DSDMPropertyHandle CClientDataModelBridge::GetNameProperty() const { return GetObjectDefinitions().m_Named.m_NameProp; @@ -2246,3 +2247,9 @@ CClientDataModelBridge::GetAggregateInstancePropertyByName(Qt3DSDMInstanceHandle { return m_DataCore->GetAggregateInstancePropertyByName(inInstance, inPropertyName); } + +bool CClientDataModelBridge::hasAggregateInstanceProperty(Qt3DSDMInstanceHandle inInstance, + Qt3DSDMPropertyHandle inProperty) const +{ + return m_DataCore->HasAggregateInstanceProperty(inInstance, inProperty); +} diff --git a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.h b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.h index aa7a5dee..10841259 100644 --- a/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.h +++ b/src/Authoring/Client/Code/Core/Doc/ClientDataModelBridge/ClientDataModelBridge.h @@ -37,6 +37,7 @@ #include "Graph.h" #include "Pt.h" #include "Qt3DSDMMetaData.h" +#include "Qt3DSDMAnimation.h" #include "Qt3DSDMComposerTypeDefinitions.h" class CDoc; @@ -294,6 +295,8 @@ public: qt3dsdm::Qt3DSDMPropertyHandle GetAggregateInstancePropertyByName( qt3dsdm::Qt3DSDMInstanceHandle inInstance, const qt3dsdm::TCharStr &inStr); + bool hasAggregateInstanceProperty(qt3dsdm::Qt3DSDMInstanceHandle inInstance, + qt3dsdm::Qt3DSDMPropertyHandle inProperty) const; // helpers void BeginRender(); // enable cache to increase performance diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.cpp b/src/Authoring/Client/Code/Core/Doc/Doc.cpp index c2cc681f..75643a94 100644 --- a/src/Authoring/Client/Code/Core/Doc/Doc.cpp +++ b/src/Authoring/Client/Code/Core/Doc/Doc.cpp @@ -2501,6 +2501,14 @@ void CDoc::SavePresentationFile(CBufferedOutputStream *inOutputStream) CDOMSerializer::Write(*theWriter.GetTopElement(), theStream); } +bool CDoc::canSetKeyframeInterpolation() const +{ + if (m_KeyframesManager) + return m_KeyframesManager->canSetKeyframeInterpolation(); + + return false; +} + void CDoc::SetKeyframeInterpolation() { if (m_KeyframesManager) diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.h b/src/Authoring/Client/Code/Core/Doc/Doc.h index 47f25fc8..a12df7cb 100644 --- a/src/Authoring/Client/Code/Core/Doc/Doc.h +++ b/src/Authoring/Client/Code/Core/Doc/Doc.h @@ -277,6 +277,7 @@ public: bool canPasteObjects() const; bool canPasteKeyframes() const; bool canPasteActions() const; + bool canSetKeyframeInterpolation() const; bool canPaste() const; // objects, keyframes, or actions bool canCopy() const; // objects, keyframes, or actions diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp index 6231e48e..d0be8e64 100644 --- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp +++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp @@ -92,6 +92,7 @@ #include "StudioProjectSettings.h" #include "StudioApp.h" #include "StudioUtils.h" +#include "Qt3DSDMHandles.h" namespace { @@ -2827,15 +2828,25 @@ public: void SetKeyframeTime(TKeyframeHandle inKeyframe, long inTime) override { - float theTimeinSecs = static_cast<float>(inTime) / 1000.f; + float timeInSecs = static_cast<float>(inTime) / 1000.f; // round off to 4 decimal place to workaround precision issues // TODO: fix this, either all talk float OR long. choose one. - theTimeinSecs = ceilf(theTimeinSecs * 10000.0f) / 10000.0f; - TKeyframe theData = m_AnimationCore.GetKeyframeData(inKeyframe); - // Function programming paradigm, returns new value instead of changing - // current value. - theData = qt3dsdm::SetKeyframeSeconds(theData, theTimeinSecs); - m_AnimationCore.SetKeyframeData(inKeyframe, theData); + timeInSecs = ceilf(timeInSecs * 10000.0f) / 10000.0f; + TKeyframe kfData = m_AnimationCore.GetKeyframeData(inKeyframe); + + // offset control points for bezier keyframes + offsetBezier(kfData, timeInSecs - GetKeyframeSeconds(kfData)); + + // Functional programming paradigm, returns new value instead of changing current value. + kfData = qt3dsdm::SetKeyframeSeconds(kfData, timeInSecs); + m_AnimationCore.SetKeyframeData(inKeyframe, kfData); + } + + void setBezierKeyframeValues(const QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, + TKeyframe>> &changedKfs) override + { + for (auto kf : changedKfs) + m_AnimationCore.SetKeyframeData(kf.first, kf.second); } void DeleteAllKeyframes(Qt3DSDMAnimationHandle inAnimation) override @@ -2854,31 +2865,31 @@ public: const wchar_t *propName, long subIndex, EAnimationType animType, const float *keyframeValues, long numValues, bool /*inUserEdited*/) override { - Qt3DSDMPropertyHandle propHdl = - m_DataCore.GetAggregateInstancePropertyByName(instance, propName); - if (propHdl.Valid() == false) { + Qt3DSDMPropertyHandle property = m_DataCore.GetAggregateInstancePropertyByName(instance, + propName); + if (!property.Valid()) { QT3DS_ASSERT(false); return 0; } - if (inSlide.Valid() == false) { + if (!inSlide.Valid()) { Qt3DSDMSlideHandle theSlide = m_SlideSystem.GetAssociatedSlide(instance); - if (theSlide.Valid() == false) { + if (!theSlide.Valid()) { assert(0); return 0; } - if (m_SlideSystem.IsPropertyLinked(instance, propHdl)) + if (m_SlideSystem.IsPropertyLinked(instance, property)) theSlide = m_SlideSystem.GetMasterSlide(theSlide); inSlide = theSlide; } Qt3DSDMAnimationHandle animHandle = - m_AnimationCore.GetAnimation(inSlide, instance, propHdl, subIndex); + m_AnimationCore.GetAnimation(inSlide, instance, property, subIndex); - if (animHandle.Valid() == true) + if (animHandle.Valid()) m_AnimationCore.DeleteAnimation(animHandle); animHandle = - m_AnimationCore.CreateAnimation(inSlide, instance, propHdl, subIndex, animType, false); + m_AnimationCore.CreateAnimation(inSlide, instance, property, subIndex, animType, false); long theStartTime = GetTimeRange(instance).first; long theTimeOffsetInSeconds = long(theStartTime / 1000.f); diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp index e11a441e..b0d4c626 100644 --- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp +++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp @@ -121,7 +121,7 @@ template <typename TOperator> static void HandleKeyframe(SLinearKeyframe &inKeyframe, TOperator &inOperator) { inOperator(inKeyframe.m_KeyframeSeconds); - inOperator(inKeyframe.m_KeyframeSeconds); + inOperator(inKeyframe.m_KeyframeValue); } template <typename TOperator> diff --git a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h index d49f8062..d1b655de 100644 --- a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h +++ b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h @@ -307,6 +307,8 @@ public: virtual bool RemoveAnimation(TSlideHandle inSlide, TInstanceHandle instance, const wchar_t *propName, long subIndex) = 0; virtual void SetKeyframeTime(TKeyframeHandle inKeyframe, long inTimeInMilliseconds) = 0; + virtual void setBezierKeyframeValues(const QVector<std::pair<TKeyframeHandle, + qt3dsdm::TKeyframe>> &changedKfs) = 0; virtual void DeleteAllKeyframes(Qt3DSDMAnimationHandle inAnimation) = 0; virtual void KeyframeProperty(Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty, bool inDoDiffValue) = 0; diff --git a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h index df028c3f..692e7d0c 100644 --- a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h +++ b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h @@ -35,10 +35,11 @@ class IKeyframesManager public: virtual ~IKeyframesManager() {} - virtual bool HasSelectedKeyframes() = 0; - virtual bool HasDynamicKeyframes() = 0; - virtual bool CanPerformKeyframeCopy() = 0; - virtual bool CanPerformKeyframePaste() = 0; + virtual bool HasSelectedKeyframes() const = 0; + virtual bool HasDynamicKeyframes() const = 0; + virtual bool CanPerformKeyframeCopy() const = 0; + virtual bool CanPerformKeyframePaste() const = 0; + virtual bool canSetKeyframeInterpolation() const = 0; virtual void CopyKeyframes() = 0; virtual bool RemoveKeyframes(bool inPerformCopy) = 0; virtual void PasteKeyframes() = 0; diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp index d9ed32c4..6d07d23b 100644 --- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp +++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp @@ -811,6 +811,11 @@ QColor CStudioPreferences::GetZAxisColor() return s_zAxisColor; } +QColor CStudioPreferences::getBezierControlColor() +{ + return QColor("#f4bd04"); +} + /** * Colors for rulers and guides */ diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h index 99e2d02f..494b2c05 100644 --- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h +++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h @@ -149,6 +149,7 @@ public: static QColor GetXAxisColor(); static QColor GetYAxisColor(); static QColor GetZAxisColor(); + static QColor getBezierControlColor(); static ::CColor GetRulerBackgroundColor(); static ::CColor GetRulerTickColor(); diff --git a/src/Authoring/Qt3DStudio/Application/StudioApp.cpp b/src/Authoring/Qt3DStudio/Application/StudioApp.cpp index cc8b07cb..7bf9c93c 100644 --- a/src/Authoring/Qt3DStudio/Application/StudioApp.cpp +++ b/src/Authoring/Qt3DStudio/Application/StudioApp.cpp @@ -39,7 +39,6 @@ #include "qtlocalpeer.h" #include "TimelineWidget.h" #include "SlideView.h" -#include "IKeyframesManager.h" #include "PresentationFile.h" #include "EditPresentationIdDlg.h" #include "Qt3DSDMWStrOps.h" diff --git a/src/Authoring/Qt3DStudio/MainFrm.cpp b/src/Authoring/Qt3DStudio/MainFrm.cpp index 7626d408..3773feba 100644 --- a/src/Authoring/Qt3DStudio/MainFrm.cpp +++ b/src/Authoring/Qt3DStudio/MainFrm.cpp @@ -32,7 +32,6 @@ #include "StudioConst.h" #include "SceneView.h" #include "StudioApp.h" -#include "IKeyframesManager.h" #include "Dialogs.h" #include "StudioPreferencesPropSheet.h" #include "StudioPreferences.h" @@ -677,7 +676,8 @@ void CMainFrame::OnUpdateTimelineDeleteSelectedKeyframes() */ void CMainFrame::OnUpdateTimelineSetInterpolation() { - m_ui->actionSet_Interpolation->setEnabled(getTimelineWidget()->hasSelectedKeyframes()); + bool enabled = g_StudioApp.GetCore()->GetDoc()->canSetKeyframeInterpolation(); + m_ui->actionSet_Interpolation->setEnabled(enabled); } /** diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h index 72488480..4754bb0d 100644 --- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h +++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h @@ -28,12 +28,11 @@ ****************************************************************************/ #ifndef INCLUDED_ITIMELINE_ITEM_PROPERTY_H -#define INCLUDED_ITIMELINE_ITEM_PROPERTY_H 1 - -#pragma once +#define INCLUDED_ITIMELINE_ITEM_PROPERTY_H #include "Qt3DSDMMetaData.h" #include "Qt3DSString.h" +#include "Qt3DSDMAnimation.h" class RowTree; class IKeyframe; @@ -60,11 +59,15 @@ public: virtual void setRowTree(RowTree *row) = 0; virtual RowTree *getRowTree() const = 0; + virtual qt3dsdm::Qt3DSDMPropertyHandle getPropertyHandle() const = 0; + virtual std::vector<qt3dsdm::Qt3DSDMAnimationHandle> animationHandles() const = 0; + virtual qt3dsdm::EAnimationType animationType() const = 0; + // Keyframes virtual IKeyframe *GetKeyframeByTime(long inTime) const = 0; virtual IKeyframe *GetKeyframeByIndex(long inIndex) const = 0; virtual long GetKeyframeCount() const = 0; - virtual long GetChannelCount() const = 0; + virtual size_t GetChannelCount() const = 0; virtual float GetChannelValueAtTime(long inChannelIndex, long inTime) = 0; virtual void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) = 0; virtual bool IsDynamicAnimation() = 0; diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h index ead15d2e..f6330cc0 100644 --- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h +++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/PasteKeyframesCommandHelper.h @@ -28,13 +28,8 @@ ****************************************************************************/ #ifndef INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H -#define INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H 1 +#define INCLUDED_PASTE_KEYFRAME_COMMAND_HELPER_H -#pragma once - -//============================================================================== -// Include -//============================================================================== #include "CmdDataModelInsertKeyframe.h" #include "Qt3DSDMPropertyDefinition.h" #include "Qt3DSDMDataCore.h" @@ -48,7 +43,7 @@ protected: typedef std::vector<CCmdDataModelInsertKeyframe::STimeKeyframeData> TCopiedKeyframeList; TCopiedKeyframeList m_CopiedKeyframeList; -public: // Construction +public: CPasteKeyframeCommandHelper() {} ~CPasteKeyframeCommandHelper() {} @@ -76,40 +71,24 @@ public: // Construction { using namespace qt3dsdm; - CCmdDataModelInsertKeyframe *theInsertKeyframesCommand = nullptr; - TCopiedKeyframeList::iterator theIter = m_CopiedKeyframeList.begin(); - qt3dsdm::IPropertySystem *thePropertySystem = inDoc->GetStudioSystem()->GetPropertySystem(); - CClientDataModelBridge *theBridge = inDoc->GetStudioSystem()->GetClientDataModelBridge(); + CCmdDataModelInsertKeyframe *insertKeyframesCmd = nullptr; + qt3dsdm::IPropertySystem *propSys = inDoc->GetStudioSystem()->GetPropertySystem(); + CClientDataModelBridge *bridge = inDoc->GetStudioSystem()->GetClientDataModelBridge(); - for (; theIter != m_CopiedKeyframeList.end(); ++theIter) { - TCharStr thePropertyName = thePropertySystem->GetName(theIter->m_Property); - DataModelDataType::Value thePropertyType = - thePropertySystem->GetDataType(theIter->m_Property); - Qt3DSDMPropertyHandle theTargetPropertyHandle = - theBridge->GetAggregateInstancePropertyByName(inTargetInstance, thePropertyName); - if (theTargetPropertyHandle.Valid()) // property exists on target - { - // sanity check for type match - DataModelDataType::Value theTargetPropertyType = - thePropertySystem->GetDataType(theTargetPropertyHandle); - if (theTargetPropertyType == thePropertyType) { - // 2. Offset keyframe time by current view time - double milliseconds = theIter->m_KeyframeTime * 1000.0; - double theTimeInMilliseconds = milliseconds + inTimeOffsetInMilliseconds; - float theTimeInSeconds = static_cast<float>(theTimeInMilliseconds / 1000.0); + for (auto &kfData : m_CopiedKeyframeList) { + // check property exists on target + if (bridge->hasAggregateInstanceProperty(inTargetInstance, kfData.m_Property)) { + if (!insertKeyframesCmd) + insertKeyframesCmd = new CCmdDataModelInsertKeyframe(inDoc, inTargetInstance); - if (!theInsertKeyframesCommand) - theInsertKeyframesCommand = new CCmdDataModelInsertKeyframe( - inDoc, inTargetInstance, theTargetPropertyHandle, theTimeInSeconds, - theIter->m_Infos, theIter->m_ValidInfoCount); - else - theInsertKeyframesCommand->AddKeyframeData( - theTargetPropertyHandle, theTimeInSeconds, theIter->m_Infos, - theIter->m_ValidInfoCount); - } + // Offset keyframe time by current view time (time in seconds) + float time = kfData.m_KeyframeTime + inTimeOffsetInMilliseconds / 1000.f; + insertKeyframesCmd->AddKeyframeData(kfData.m_Property, time, kfData.m_Infos, + kfData.m_ValidInfoCount); } } - return theInsertKeyframesCommand; + + return insertKeyframesCmd; } void Clear() { m_CopiedKeyframeList.clear(); } diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp index 0249bd13..f863435c 100644 --- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp @@ -131,6 +131,11 @@ qt3dsdm::Qt3DSDMPropertyHandle Qt3DSDMTimelineItemProperty::getPropertyHandle() return m_PropertyHandle; } +std::vector<qt3dsdm::Qt3DSDMAnimationHandle> Qt3DSDMTimelineItemProperty::animationHandles() const +{ + return m_AnimationHandles; +} + // Type doesn't change and due to the logic required to figure this out, cache it. void Qt3DSDMTimelineItemProperty::InitializeCachedVariables(qt3dsdm::Qt3DSDMInstanceHandle inInstance) { @@ -190,7 +195,8 @@ void CompareAndSet(const Qt3DSDMTimelineKeyframe *inKeyframe, float &outRetValue outRetValue = theValue; } -// return the max value of the current set of keyframes +// returns the max keyframe value in a property. For bezier keyframes this includes the control +// points values as well float Qt3DSDMTimelineItemProperty::GetMaximumValue() const { float theRetVal = FLT_MIN; @@ -200,7 +206,8 @@ float Qt3DSDMTimelineItemProperty::GetMaximumValue() const return theRetVal; } -// return the min value of the current set of keyframes +// returns the min keyframe value in a property. For bezier keyframes this includes the control +// points values as well float Qt3DSDMTimelineItemProperty::GetMinimumValue() const { float theRetVal = FLT_MAX; @@ -267,9 +274,9 @@ long Qt3DSDMTimelineItemProperty::GetKeyframeCount() const return (long)m_Keyframes.size(); } -long Qt3DSDMTimelineItemProperty::GetChannelCount() const +size_t Qt3DSDMTimelineItemProperty::GetChannelCount() const { - return (long)m_AnimationHandles.size(); + return m_AnimationHandles.size(); } float Qt3DSDMTimelineItemProperty::GetChannelValueAtTime(long inChannelIndex, long inTime) @@ -357,7 +364,15 @@ bool Qt3DSDMTimelineItemProperty::IsDynamicAnimation() return m_Keyframes.size() > 0 && m_Keyframes[0]->IsDynamic(); } -//============================================================================= +EAnimationType Qt3DSDMTimelineItemProperty::animationType() const +{ + if (m_AnimationHandles.empty()) + return EAnimationTypeNone; + + IAnimationCore *animCore = m_TransMgr->GetStudioSystem()->GetAnimationCore(); + return animCore->GetAnimationInfo(m_AnimationHandles[0]).m_AnimationType; +} + /** * For updating the UI when keyframes are added/updated/deleted. */ diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h index 1b1524e4..ff508ae8 100644 --- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h +++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h @@ -36,6 +36,7 @@ #include "Qt3DSDMTimelineKeyframe.h" #include "Qt3DSDMTimeline.h" #include "Qt3DSDMPropertyDefinition.h" +#include "Qt3DSDMAnimation.h" class RowTree; class CTimelineTranslationManager; @@ -52,8 +53,8 @@ class Qt3DSDMTimelineItemProperty : public ITimelineItemProperty { public: Qt3DSDMTimelineItemProperty(CTimelineTranslationManager *inTransMgr, - qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle, - qt3dsdm::Qt3DSDMInstanceHandle inInstance); + qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle, + qt3dsdm::Qt3DSDMInstanceHandle inInstance); virtual ~Qt3DSDMTimelineItemProperty(); // ITimelineProperty @@ -67,23 +68,25 @@ public: IKeyframe *GetKeyframeByTime(long inTime) const override; IKeyframe *GetKeyframeByIndex(long inIndex) const override; long GetKeyframeCount() const override; - long GetChannelCount() const override; + size_t GetChannelCount() const override; float GetChannelValueAtTime(long inChannelIndex, long inTime) override; void SetChannelValueAtTime(long inChannelIndex, long inTime, float inValue) override; bool IsDynamicAnimation() override; - void setRowTree(RowTree *rowTree) override; RowTree *getRowTree() const override; + qt3dsdm::Qt3DSDMPropertyHandle getPropertyHandle() const override; + std::vector<qt3dsdm::Qt3DSDMAnimationHandle> animationHandles() const override; bool RefreshKeyframe(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, ETimelineKeyframeTransaction inTransaction); IKeyframe *GetKeyframeByHandle(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe); void RefreshKeyFrames(void); - - qt3dsdm::Qt3DSDMPropertyHandle getPropertyHandle() const; + qt3dsdm::EAnimationType animationType() const override; protected: + using TKeyframeList = std::vector<Qt3DSDMTimelineKeyframe *>; + void InitializeCachedVariables(qt3dsdm::Qt3DSDMInstanceHandle inInstance); bool CreateKeyframeIfNonExistent(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, qt3dsdm::Qt3DSDMAnimationHandle inOwningAnimation); @@ -93,9 +96,6 @@ protected: void CreateKeyframes(); void ReleaseKeyframes(); -protected: - typedef std::vector<Qt3DSDMTimelineKeyframe *> TKeyframeList; - qt3dsdm::Qt3DSDMInstanceHandle m_InstanceHandle; qt3dsdm::Qt3DSDMPropertyHandle m_PropertyHandle; CTimelineTranslationManager *m_TransMgr; diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp index ae7e2035..d8d7aad3 100644 --- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp @@ -194,30 +194,52 @@ void Qt3DSDMTimelineKeyframe::GetKeyframeHandles(TKeyframeHandleList &outList) c } void CompareAndSet(Qt3DSDMKeyframeHandle inKeyframe, IAnimationCore *inAnimationCore, - float &outRetValue, bool inGreaterThan) -{ - TKeyframe theKeyframeData = inAnimationCore->GetKeyframeData(inKeyframe); - float theValue = KeyframeValueValue(theKeyframeData); - if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue)) - outRetValue = theValue; + float &ioRetValue, bool inGreaterThan) +{ + TKeyframe keyframeData = inAnimationCore->GetKeyframeData(inKeyframe); + float value = KeyframeValueValue(keyframeData); + if ((inGreaterThan && value > ioRetValue) || (!inGreaterThan && value < ioRetValue)) + ioRetValue = value; + + // for bezier keyframes compare tangents in/out also + if (keyframeData.getType() == qt3dsdm::EAnimationTypeBezier) { + float inTime, inValue, outTime, outValue; + getBezierValues(keyframeData, inTime, inValue, outTime, outValue); + + if (!inAnimationCore->IsFirstKeyframe(inKeyframe) // check tangent-in value + && ((inGreaterThan && inValue > ioRetValue) + || (!inGreaterThan && inValue < ioRetValue))) { + ioRetValue = inValue; + } + + if (!inAnimationCore->IsLastKeyframe(inKeyframe) // check tangent-out value + && ((inGreaterThan && outValue > ioRetValue) + || (!inGreaterThan && outValue < ioRetValue))) { + ioRetValue = outValue; + } + } } +// returns the max keyframe channel value. For bezier keyframes this includes the control +// points values as well float Qt3DSDMTimelineKeyframe::GetMaxValue() const { - IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + IAnimationCore *animCore = m_Doc->GetStudioSystem()->GetAnimationCore(); float theRetVal = FLT_MIN; do_all(m_KeyframeHandles, - std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore, - std::ref(theRetVal), true)); + std::bind(CompareAndSet, std::placeholders::_1, animCore, std::ref(theRetVal), true)); + return theRetVal; } +// returns the min keyframe channel value. For bezier keyframes this includes the control +// points values as well float Qt3DSDMTimelineKeyframe::GetMinValue() const { - IAnimationCore *theAnimationCore = m_Doc->GetStudioSystem()->GetAnimationCore(); + IAnimationCore *animCore = m_Doc->GetStudioSystem()->GetAnimationCore(); float theRetVal = FLT_MAX; do_all(m_KeyframeHandles, - std::bind(CompareAndSet, std::placeholders::_1, theAnimationCore, - std::ref(theRetVal), false)); + std::bind(CompareAndSet, std::placeholders::_1, animCore, std::ref(theRetVal), false)); + return theRetVal; } diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/Keyframe.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/Keyframe.h index 7e4ea614..3cbd9383 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/Keyframe.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/Keyframe.h @@ -37,9 +37,9 @@ struct Keyframe { Keyframe(long time, RowTimeline *propRow) : time(time) + , propertyType(propRow->rowTree()->propertyType()) , rowProperty(propRow) , rowMaster(propRow->parentRow()) - , propertyType(propRow->rowTree()->propertyType()) {} bool selected() const @@ -47,7 +47,7 @@ struct Keyframe return binding && binding->IsSelected(); } - long time; + long time; // millis QString propertyType; RowTimeline *rowProperty = nullptr; RowTimeline *rowMaster = nullptr; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.cpp index 7b39b272..2432ce77 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.cpp @@ -35,6 +35,7 @@ #include "StudioApp.h" #include "Core.h" #include "Doc.h" +#include "SlideSystem.h" #include "StudioClipboard.h" #include "CmdDataModelRemoveKeyframe.h" #include "CmdDataModelInsertKeyframe.h" @@ -42,6 +43,7 @@ #include "ClientDataModelBridge.h" #include "Bindings/OffsetKeyframesCommandHelper.h" #include "Bindings/PasteKeyframesCommandHelper.h" +#include "Bindings/ITimelineItemBinding.h" #include "StudioPreferences.h" #include "Dialogs.h" #include "TimeEnums.h" @@ -332,19 +334,14 @@ void KeyframeManager::copySelectedKeyframes() } qt3dsdm::SGetOrSetKeyframeInfo KeyframeManager::setKeyframeInfo( - qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, qt3dsdm::IAnimationCore &inCore) -{ - qt3dsdm::TKeyframe theKeyframeData = inCore.GetKeyframeData(inKeyframe); - qt3dsdm::SEaseInEaseOutKeyframe keyframe = - qt3dsdm::get<qt3dsdm::SEaseInEaseOutKeyframe>(theKeyframeData); - bool isDynamic = false; - if (inCore.IsFirstKeyframe(inKeyframe)) { - isDynamic = inCore.GetAnimationInfo(inCore.GetAnimationForKeyframe(inKeyframe)) - .m_DynamicFirstKeyframe; - } + qt3dsdm::Qt3DSDMKeyframeHandle keyframeHandle, qt3dsdm::IAnimationCore &animCore) +{ + qt3dsdm::TKeyframe keyframeData = animCore.GetKeyframeData(keyframeHandle); + + bool isDynamic = animCore.IsFirstKeyframe(keyframeHandle) && animCore.GetAnimationInfo( + animCore.GetAnimationForKeyframe(keyframeHandle)).m_DynamicFirstKeyframe; - return qt3dsdm::SGetOrSetKeyframeInfo(keyframe.m_KeyframeValue, keyframe.m_EaseIn, - keyframe.m_EaseOut, isDynamic); + return qt3dsdm::SGetOrSetKeyframeInfo(keyframeData, isDynamic); } void KeyframeManager::pasteKeyframes() @@ -483,23 +480,33 @@ void KeyframeManager::RollbackChangedKeyframes() row->updateKeyframes(); } -// IKeyframesManager interface -bool KeyframeManager::HasSelectedKeyframes() +bool KeyframeManager::HasSelectedKeyframes() const { return hasSelectedKeyframes(); } -bool KeyframeManager::HasDynamicKeyframes() +bool KeyframeManager::HasDynamicKeyframes() const { return false; // Mahmoud_TODO: implement } -bool KeyframeManager::CanPerformKeyframeCopy() +bool KeyframeManager::CanPerformKeyframeCopy() const { return !m_selectedKeyframes.empty() && m_selectedKeyframesMasterRows.count() == 1; } -bool KeyframeManager::CanPerformKeyframePaste() +bool KeyframeManager::canSetKeyframeInterpolation() const +{ + for (Keyframe *kf : qAsConst(m_selectedKeyframes)) { + auto animType = kf->rowProperty->rowTree()->propBinding()->animationType(); + if (animType == qt3dsdm::EAnimationTypeEaseInOut) + return true; + } + + return false; +} + +bool KeyframeManager::CanPerformKeyframePaste() const { if (m_pasteKeyframeCommandHelper && m_pasteKeyframeCommandHelper->HasCopiedKeyframes()) { qt3dsdm::Qt3DSDMInstanceHandle theSelectedInstance = @@ -533,36 +540,36 @@ void KeyframeManager::SetKeyframeInterpolation() if (!hasSelectedKeyframes()) return; - float theEaseIn = 0; - float theEaseOut = 0; - if (CStudioPreferences::GetInterpolation()) - theEaseIn = theEaseOut = 100; - - CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); - IAnimationCore *theAnimationCore = theDoc->GetStudioSystem()->GetAnimationCore(); + CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + IAnimationCore *animCore = doc->GetStudioSystem()->GetAnimationCore(); - if (!m_selectedKeyframes.empty()) { - Qt3DSDMTimelineKeyframe *theTimelineKeyframe = m_selectedKeyframes.front()->binding; - Qt3DSDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; - theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles); - TKeyframe theKeyframeData = theAnimationCore->GetKeyframeData(theKeyframeHandles[0]); - GetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut); + // find the first easing keyframe and use it to get the current easing values + auto firstEaseKeyframeIter = m_selectedKeyframes.begin(); + while ((*firstEaseKeyframeIter)->rowProperty->rowTree()->propBinding()->animationType() + != EAnimationTypeEaseInOut) { + firstEaseKeyframeIter++; } - if (g_StudioApp.GetDialogs()->PromptForKeyframeInterpolation(theEaseIn, theEaseOut)) { - // Note: Having "editor" variable here is important as its destructor - // creates proper transaction - Q3DStudio::ScopedDocumentEditor editor(*theDoc, QObject::tr("Set Keyframe Interpolation"), + Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; + (*firstEaseKeyframeIter)->binding->GetKeyframeHandles(keyframeHandles); + + TKeyframe keyframeData = animCore->GetKeyframeData(keyframeHandles[0]); + + float easeIn = CStudioPreferences::GetInterpolation() ? 100 : 0; + float easeOut = CStudioPreferences::GetInterpolation() ? 100 : 0; + GetEaseInOutValues(keyframeData, easeIn, easeOut); + + if (g_StudioApp.GetDialogs()->displayKeyframeInterpolation(easeIn, easeOut)) { + // Having "editor" variable here is important as its destructor creates proper transaction + Q3DStudio::ScopedDocumentEditor editor(*doc, QObject::tr("Set Keyframe Interpolation"), __FILE__, __LINE__); for (Keyframe *keyframe : qAsConst(m_selectedKeyframes)) { - Qt3DSDMTimelineKeyframe *theTimelineKeyframe = keyframe->binding; - Qt3DSDMTimelineKeyframe::TKeyframeHandleList theKeyframeHandles; - theTimelineKeyframe->GetKeyframeHandles(theKeyframeHandles); - for (size_t i = 0; i < theKeyframeHandles.size(); ++i) { - TKeyframe theKeyframeData = - theAnimationCore->GetKeyframeData(theKeyframeHandles[i]); - SetEaseInOutValues(theKeyframeData, theEaseIn, theEaseOut); - theAnimationCore->SetKeyframeData(theKeyframeHandles[i], theKeyframeData); + Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; + keyframe->binding->GetKeyframeHandles(keyframeHandles); + for (size_t i = 0; i < keyframeHandles.size(); ++i) { + TKeyframe keyframeData = animCore->GetKeyframeData(keyframeHandles[i]); + SetEaseInOutValues(keyframeData, easeIn, easeOut); + animCore->SetKeyframeData(keyframeHandles[i], keyframeData); } } } diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.h index 9c160687..0012c047 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/KeyframeManager.h @@ -76,10 +76,11 @@ public: void SetKeyframesDynamic(bool inDynamic) override; void CommitChangedKeyframes() override; void RollbackChangedKeyframes() override; - bool HasSelectedKeyframes() override; - bool HasDynamicKeyframes() override; - bool CanPerformKeyframeCopy() override; - bool CanPerformKeyframePaste() override; + bool HasSelectedKeyframes() const override; + bool HasDynamicKeyframes() const override; + bool CanPerformKeyframeCopy() const override; + bool CanPerformKeyframePaste() const override; + bool canSetKeyframeInterpolation() const override; void CopyKeyframes() override; bool RemoveKeyframes(bool inPerformCopy) override; void PasteKeyframes() override; @@ -89,12 +90,12 @@ public: long getPressedKeyframeOffset() const; private: - qt3dsdm::SGetOrSetKeyframeInfo setKeyframeInfo(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, - qt3dsdm::IAnimationCore &inCore); + qt3dsdm::SGetOrSetKeyframeInfo setKeyframeInfo(qt3dsdm::Qt3DSDMKeyframeHandle keyframeHandle, + qt3dsdm::IAnimationCore &animCore); long getMinSelectedKeyframesTime() const; CPasteKeyframeCommandHelper *m_pasteKeyframeCommandHelper = nullptr; - TimelineGraphicsScene *m_scene; + TimelineGraphicsScene *m_scene = nullptr; QList<Keyframe *> m_selectedKeyframes; QList<RowTimeline *> m_selectedKeyframesMasterRows; }; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowTypes.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowTypes.h index 58a93115..5facc147 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowTypes.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowTypes.h @@ -35,8 +35,10 @@ enum class TimelineControlType { None, KeyFrame, Duration, - StartHandle, - EndHandle + DurationStartHandle, + DurationEndHandle, + BezierInHandle, + BezierOutHandle }; enum class TreeControlType { diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineConstants.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineConstants.h index 61525718..c9036aba 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineConstants.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineConstants.h @@ -33,7 +33,8 @@ namespace TimelineConstants { // Dimensions const int ROW_H = 20; - const int ROW_H_EXPANDED = 120; // property rows height when graph is shown + const int ROW_GRAPH_H = 120; // property row height when graph is shown + const int ROW_GRAPH_H_MAX = 300; // property row height when graph is shown maximized const int ROW_SPACING = 2; const int ROW_DEPTH_STEP = 15; // x-distance between 2 consecutive depths const double RULER_SEC_W = 30; // width of 1 second section (at scale 1) diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp index b4a52760..f33cf263 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp @@ -32,6 +32,7 @@ #include "Ruler.h" #include "PlayHead.h" #include "RowTree.h" +#include "RowTimelinePropertyGraph.h" #include "RowMover.h" #include "RowTimeline.h" #include "TimelineConstants.h" @@ -226,7 +227,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget) } if (m_dragging) { - if (m_clickedTimelineControlType == TimelineControlType::StartHandle) { + if (m_clickedTimelineControlType == TimelineControlType::DurationStartHandle) { double visiblePtX = distance > 0 ? m_editedTimelineRow->getStartX() : 0; if (distance > m_editedTimelineRow->getEndX()) visiblePtX += TimelineConstants::RULER_EDGE_OFFSET; @@ -237,7 +238,8 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget) + TimelineConstants::RULER_EDGE_OFFSET + visiblePtX, m_editedTimelineRow->y(), 0, 0, 0, 0); - } else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) { + } else if (m_clickedTimelineControlType + == TimelineControlType::DurationEndHandle) { long time = m_ruler->distanceToTime(distance); double edgeMargin = 0; if (time > TimelineConstants::MAX_SLIDE_TIME) { @@ -466,19 +468,36 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { g_StudioApp.setLastActiveView(m_widgetTimeline); - if ((event->modifiers() & Qt::AltModifier) && !m_dragging) { - if (event->button() == Qt::RightButton && !m_timelinePanning) { - // Start zooming - m_timelineZooming = true; + if ((event->modifiers() & Qt::AltModifier) && !m_dragging + && m_timelineAltModifierMode == TimelineAltModifierMode::None) { + if (event->button() == Qt::RightButton) { + // Start scaling + m_timelineAltModifierMode = TimelineAltModifierMode::ScaleTimeline; m_pressScreenPos = event->screenPos(); event->accept(); return; - } else if (event->button() == Qt::MiddleButton && !m_timelineZooming) { + } else if (event->button() == Qt::MiddleButton) { // Start panning - m_timelinePanning = true; + m_timelineAltModifierMode = TimelineAltModifierMode::PanTimeline; m_pressPos = event->scenePos(); event->accept(); return; + } else if (event->button() == Qt::LeftButton) { + // Start property graph panning + m_pressPos = event->scenePos(); + QGraphicsItem *item = getItemBelowType(TimelineItem::TypePlayHead, + itemAt(m_pressPos, {}), m_pressPos); + if (item && item->type() == TimelineItem::TypeRowTimeline) { + RowTimeline *rowTimeline = static_cast<RowTimeline *>(item); + if (rowTimeline->propertyGraph()) { + m_timelineAltModifierMode = TimelineAltModifierMode::PanPropertyGraph; + m_panProperyGraph = rowTimeline->propertyGraph(); + m_panProperyGraph->startPan(); + event->accept(); + return; + } + } + } } @@ -570,11 +589,13 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) m_rowManager->selectRow(m_editedTimelineRow->rowTree(), ctrlKeyDown); // click position in ruler space m_editedTimelineRow->startDurationMove(m_pressPos.x() - m_ruler->x()); - } else if (m_clickedTimelineControlType == TimelineControlType::StartHandle - || m_clickedTimelineControlType == TimelineControlType::EndHandle) { + } else if (m_clickedTimelineControlType + == TimelineControlType::DurationStartHandle + || m_clickedTimelineControlType + == TimelineControlType::DurationEndHandle) { m_editedTimelineRow->updateBoundChildren( m_clickedTimelineControlType - == TimelineControlType::StartHandle); + == TimelineControlType::DurationStartHandle); } m_autoScrollTimelineTimer.start(); } @@ -594,9 +615,9 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) { - if (m_timelineZooming) { - int deltaY = event->screenPos().y() - m_pressScreenPos.y(); + if (m_timelineAltModifierMode == TimelineAltModifierMode::ScaleTimeline) { int deltaX = event->screenPos().x() - m_pressScreenPos.x(); + int deltaY = event->screenPos().y() - m_pressScreenPos.y(); // Zooming in when moving down/right. int delta = -deltaX - deltaY; const int threshold = 20; @@ -607,24 +628,32 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) m_widgetTimeline->toolbar()->onZoomOutButtonClicked(); m_pressScreenPos = event->screenPos(); } - } else if (m_timelinePanning) { + } else if (m_timelineAltModifierMode == TimelineAltModifierMode::PanTimeline) { int deltaX = event->scenePos().x() - m_pressPos.x(); QScrollBar *scrollbar = m_widgetTimeline->viewTimelineContent()->horizontalScrollBar(); scrollbar->setValue(scrollbar->value() - deltaX); + } else if (m_timelineAltModifierMode == TimelineAltModifierMode::PanPropertyGraph) { + qreal deltaY = event->scenePos().y() - m_pressPos.y(); + m_panProperyGraph->pan(deltaY); } if (m_editedTimelineRow.isNull()) updateHoverStatus(event->scenePos()); - if (!m_dragging && !m_timelineZooming && !m_timelinePanning - && m_pressPos != invalidPoint - && (event->scenePos() - m_pressPos).manhattanLength() > 10) { + if (!m_dragging && m_timelineAltModifierMode == TimelineAltModifierMode::None + && m_pressPos != invalidPoint && (event->scenePos() - m_pressPos).manhattanLength() > 10) { m_dragging = true; } bool shift = event->modifiers() & Qt::ShiftModifier; if (m_dragging) { - if (m_startRowMoverOnNextDrag || m_rowMover->isActive()) { + if (m_clickedTimelineControlType == TimelineControlType::BezierInHandle + || m_clickedTimelineControlType == TimelineControlType::BezierOutHandle) { + if (m_editedTimelineRow && m_editedTimelineRow->propertyGraph()) { + m_editedTimelineRow->propertyGraph()->updateBezierControlValue( + m_clickedTimelineControlType, event->scenePos()); + } + } else if (m_startRowMoverOnNextDrag || m_rowMover->isActive()) { // moving rows vertically (reorder/reparent) if (m_startRowMoverOnNextDrag) { m_startRowMoverOnNextDrag = false; @@ -729,11 +758,11 @@ void TimelineGraphicsScene::resetMousePressParams() m_selectionRect->end(); m_rowMover->end(); m_dragging = false; - m_timelineZooming = false; - m_timelinePanning = false; m_startRowMoverOnNextDrag = false; m_rulerPressed = false; m_pressedKeyframe = nullptr; + m_panProperyGraph = nullptr; + m_timelineAltModifierMode = TimelineAltModifierMode::None; m_clickedTimelineControlType = TimelineControlType::None; m_editedTimelineRow.clear(); m_releaseSelectRow.clear(); @@ -797,16 +826,15 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (m_rowMover->isActive()) { // moving rows (reorder/reparent) commitMoveRows(); } else if (m_pressedKeyframe) { - // update keyframe movement (time) to binding m_keyframeManager->commitMoveSelectedKeyframes(); - } else if (m_clickedTimelineControlType == TimelineControlType::StartHandle) { + } else if (m_clickedTimelineControlType == TimelineControlType::DurationStartHandle) { if (!m_editedTimelineRow.isNull()) { ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding() ->GetTimelineItem()->GetTimebar(); timebar->ChangeTime(m_editedTimelineRow->getStartTime(), true); timebar->CommitTimeChange(); } - } else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) { + } else if (m_clickedTimelineControlType == TimelineControlType::DurationEndHandle) { if (!m_editedTimelineRow.isNull()) { ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding() ->GetTimelineItem()->GetTimebar(); @@ -824,6 +852,9 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (m_playHead->time() > ruler()->duration()) g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration()); } + } else if (m_clickedTimelineControlType == TimelineControlType::BezierInHandle + || m_clickedTimelineControlType == TimelineControlType::BezierOutHandle) { + m_editedTimelineRow->propertyGraph()->commitBezierEdit(); } } else if (!m_rulerPressed && (!m_releaseSelectRow.isNull() || !itemAt(event->scenePos(), QTransform()))) { @@ -833,7 +864,7 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) } } - if (m_timelineZooming) + if (m_timelineAltModifierMode == TimelineAltModifierMode::ScaleTimeline) updateSnapSteps(); resetMousePressParams(); @@ -860,7 +891,7 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even if (item->type() == TimelineItem::TypeRowTree) { RowTree *treeItem = static_cast<RowTree *>(item); if (treeItem->isProperty()) - treeItem->togglePropertyExpanded(); + treeItem->togglePropertyExpanded(scenePos); } else if (item->type() == TimelineItem::TypeRowTreeLabelItem) { RowTreeLabelItem *treeLabelItem = static_cast<RowTreeLabelItem *>(item); if (treeLabelItem->parentRow()->isProperty()) { @@ -901,6 +932,17 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even void TimelineGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent) { + // adjust property graph scale + if (wheelEvent->modifiers() & Qt::AltModifier) { + const QPointF pos = wheelEvent->scenePos(); + QGraphicsItem *item = getItemBelowType(TimelineItem::TypePlayHead, itemAt(pos, {}), pos); + if (item && item->type() == TimelineItem::TypeRowTimeline) { + RowTimeline *rowTimeline = static_cast<RowTimeline *>(item); + if (rowTimeline->propertyGraph()) + rowTimeline->propertyGraph()->adjustScale(wheelEvent->delta() > 0); + } + } + // Make sure drag states update on wheel scrolls done during drag m_lastAutoScrollX = -1.0; m_lastAutoScrollY = -1.0; @@ -988,8 +1030,8 @@ void TimelineGraphicsScene::updateHoverStatus(const QPointF &scenePos) if (item->type() == TimelineItem::TypeRowTimeline) { RowTimeline *timelineItem = static_cast<RowTimeline *>(item); TimelineControlType controlType = timelineItem->getClickedControl(scenePos); - if (controlType == TimelineControlType::StartHandle - || controlType == TimelineControlType::EndHandle) { + if (controlType == TimelineControlType::DurationStartHandle + || controlType == TimelineControlType::DurationEndHandle) { setMouseCursor(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT); } else { resetMouseCursor(); @@ -1071,6 +1113,9 @@ QGraphicsItem *TimelineGraphicsScene::getItemBelowType(TimelineItem::ItemType ty QGraphicsItem *item, const QPointF &scenePos) const { + if (!item) + return nullptr; + if (item->type() == type) { const QList<QGraphicsItem *> hoverItems = items(scenePos); if (hoverItems.size() > 1) diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h index 146009ee..6de45ef9 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h @@ -50,7 +50,6 @@ class RowMover; class RowManager; class KeyframeManager; class TimelineControl; -class IKeyframesManager; struct Keyframe; QT_FORWARD_DECLARE_CLASS(QGraphicsLinearLayout) @@ -111,6 +110,8 @@ protected: void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; private: + enum class TimelineAltModifierMode {None, ScaleTimeline, PanTimeline, PanPropertyGraph}; + void commitMoveRows(); void updateHoverStatus(const QPointF &scenePos); void snap(double &value, bool snapToPlayHead = true); @@ -149,10 +150,10 @@ private: bool m_rulerPressed = false; Keyframe *m_pressedKeyframe = nullptr; + RowTimelinePropertyGraph *m_panProperyGraph = nullptr; bool m_dragging = false; bool m_startRowMoverOnNextDrag = false; - bool m_timelineZooming = false; - bool m_timelinePanning = false; + TimelineAltModifierMode m_timelineAltModifierMode = TimelineAltModifierMode::None; TimelineControlType m_clickedTimelineControlType = TimelineControlType::None; TreeControlType m_clickedTreeControlType = TreeControlType::None; double m_pressPosInKeyframe; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineWidget.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineWidget.cpp index 967da5cb..5a2dca4d 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineWidget.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineWidget.cpp @@ -164,8 +164,7 @@ TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent) layoutRoot->addWidget(m_toolbar); setLayout(layoutRoot); - g_StudioApp.GetCore()->GetDoc()->SetKeyframesManager( - static_cast<IKeyframesManager *>(m_graphicsScene->keyframeManager())); + g_StudioApp.GetCore()->GetDoc()->SetKeyframesManager(m_graphicsScene->keyframeManager()); // connect graphics scene geometryChanged connect(m_graphicsScene->widgetRoot(), &QGraphicsWidget::geometryChanged, this, [this]() { @@ -585,7 +584,6 @@ void TimelineWidget::onAnimationCreated(qt3dsdm::Qt3DSDMInstanceHandle parentIns Qt3DSDMTimelineItemBinding *binding = getBindingForHandle(parentInstance, m_binding); if (binding) { ITimelineItemProperty *propBinding = binding->GetPropertyBinding(property); - // create the binding if doesn't exist if (!propBinding) { propBinding = binding->GetOrCreatePropertyBinding(property); @@ -624,6 +622,8 @@ void TimelineWidget::onAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentIns Qt3DSDMTimelineItemBinding *binding = getBindingForHandle(parentInstance, m_binding); if (binding) { ITimelineItemProperty *propBinding = binding->GetPropertyBinding(property); + // this is needed because onAnimationDeleted can be triggered for unlinked property on + // different slide in undo/redo situations bool propAnimated = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem() ->GetAnimationSystem()->IsPropertyAnimated(parentInstance, property); diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp index 25b66911..c7cb5c51 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp @@ -224,7 +224,8 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio } if (m_propertyGraph) { // Property graph - QRectF graphRect(edgeOffset, 0, widget->width(), currentHeight); + QRectF graphRect(rowTree()->m_scene->ruler()->viewportX(), 0, + widget->width(), currentHeight); m_propertyGraph->paintGraphs(painter, graphRect); } @@ -498,7 +499,6 @@ void RowTimeline::updateKeyframesFromBinding(const QList<int> &properties) for (int i = 0; i < child->m_PropBinding->GetKeyframeCount(); i++) { Qt3DSDMTimelineKeyframe *kf = static_cast<Qt3DSDMTimelineKeyframe *> (child->m_PropBinding->GetKeyframeByIndex(i)); - Keyframe *kfUI = new Keyframe(kf->GetTime(), child->rowTimeline()); kfUI->binding = kf; kfUI->dynamic = kf->IsDynamic(); @@ -567,12 +567,17 @@ void RowTimeline::updateKeyframes() TimelineControlType RowTimeline::getClickedControl(const QPointF &scenePos) const { - if (!m_rowTree->hasDurationBar()) + QPointF p = mapFromScene(scenePos.x(), scenePos.y()); + p.setX(p.x() - TimelineConstants::RULER_EDGE_OFFSET); + + if (!m_rowTree->hasDurationBar()) { + if (m_propertyGraph) + return m_propertyGraph->getClickedBezierControl(p); + return TimelineControlType::None; + } if (!m_rowTree->locked()) { - QPointF p = mapFromScene(scenePos.x(), scenePos.y()); - p.setX(p.x() - TimelineConstants::RULER_EDGE_OFFSET); const int halfHandle = TimelineConstants::DURATION_HANDLE_W * .5; // Never choose start handle if end time is zero, as you cannot adjust it in that case @@ -585,10 +590,10 @@ TimelineControlType RowTimeline::getClickedControl(const QPointF &scenePos) cons endHandle = !startHandle; } if (startHandle) - return TimelineControlType::StartHandle; + return TimelineControlType::DurationStartHandle; else if (endHandle) - return TimelineControlType::EndHandle; - else if (p.x() > m_startX && p.x() < m_endX && !rowTree()->locked()) + return TimelineControlType::DurationEndHandle; + else if (p.x() > m_startX && p.x() < m_endX) return TimelineControlType::Duration; } diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.h index 00c81696..30d60260 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimeline.h @@ -85,6 +85,7 @@ public: QList<Keyframe *> getKeyframesInRange(const QRectF &rect) const; QList<Keyframe *> keyframes() const; void showToolTip(const QPointF &pos); + RowTimelinePropertyGraph *propertyGraph() const { return m_propertyGraph; } protected: void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp index 7861bb19..02a7bf6c 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp @@ -32,6 +32,12 @@ #include "KeyframeManager.h" #include "MainFrm.h" #include "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "IDocumentEditor.h" +#include "Qt3DSDMStudioSystem.h" +#include "SlideSystem.h" +#include "StudioPreferences.h" #include "TimelineControl.h" #include "Bindings/ITimelineItemBinding.h" #include "TimelineGraphicsScene.h" @@ -140,6 +146,26 @@ void RowTimelineContextMenu::initialize() &RowTimelineContextMenu::setKeyframeTime); addAction(m_setKeyframeTimeAction); } else { + m_animType = addMenu(tr("Animation type")); + QAction *actionLinear = m_animType->addAction(tr("Linear")); + QAction *actionEase = m_animType->addAction(tr("Ease In/Out")); + QAction *actionBezier = m_animType->addAction(tr("Bezier")); + actionLinear->setData(qt3dsdm::EAnimationTypeLinear); + actionLinear->setCheckable(true); + actionEase->setData(qt3dsdm::EAnimationTypeEaseInOut); + actionEase->setCheckable(true); + actionBezier->setData(qt3dsdm::EAnimationTypeBezier); + actionBezier->setCheckable(true); + connect(m_animType, &QMenu::triggered, this, &RowTimelineContextMenu::onAnimTypeChange); + if (m_rowTree->isProperty()) { + qt3dsdm::EAnimationType animaType = m_rowTree->propBinding()->animationType(); + if (animaType == qt3dsdm::EAnimationTypeLinear) + actionLinear->setChecked(true); + else if (animaType == qt3dsdm::EAnimationTypeEaseInOut) + actionEase->setChecked(true); + else if (animaType == qt3dsdm::EAnimationTypeBezier) + actionBezier->setChecked(true); + } m_setTimeBarColorAction = new QAction(tr("Change Time Bar Color..."), this); connect(m_setTimeBarColorAction, &QAction::triggered, this, &RowTimelineContextMenu::changeTimeBarColor); @@ -170,7 +196,12 @@ void RowTimelineContextMenu::showEvent(QShowEvent *event) m_pasteKeyframesAction->setEnabled(m_keyframeManager->hasCopiedKeyframes()); m_deleteSelectedKeyframesAction->setEnabled(m_keyframeManager->hasSelectedKeyframes()); m_deleteRowKeyframesAction->setEnabled(!m_rowTree->rowTimeline()->keyframes().empty()); - if (!m_keyframe) { + if (m_keyframe) { + RowTree *row = propRow ? m_rowTree : m_keyframe->rowProperty->rowTree(); + qt3dsdm::EAnimationType animaType = row->propBinding()->animationType(); + m_setInterpolationAction->setEnabled(animaType == qt3dsdm::EAnimationTypeEaseInOut); + } else { + m_animType->setEnabled(propRow); m_setTimeBarColorAction->setEnabled(m_rowTree->hasDurationBar()); m_setTimeBarTimeAction->setEnabled(m_rowTree->hasDurationBar()); } @@ -178,6 +209,81 @@ void RowTimelineContextMenu::showEvent(QShowEvent *event) QMenu::showEvent(event); } +void RowTimelineContextMenu::onAnimTypeChange(QAction *action) +{ + if (!action->isChecked()) + return; + + using namespace qt3dsdm; + + // m_rowTree in this method is guaranteed to be a property row + + CDoc *doc = g_StudioApp.GetCore()->GetDoc(); + IAnimationCore *animCore = doc->GetAnimationCore(); + ISlideSystem *slideSys = doc->GetStudioSystem()->GetSlideSystem(); + + Q3DStudio::ScopedDocumentEditor editor(*doc, tr("Set Animation Type"), __FILE__, __LINE__); + + EAnimationType animType = EAnimationType(action->data().toInt()); + Qt3DSDMInstanceHandle instance = m_rowTree->parentRow()->instance(); + Qt3DSDMPropertyHandle property = m_rowTree->propBinding()->getPropertyHandle(); + Qt3DSDMSlideHandle slide = slideSys->GetAssociatedSlide(instance); + TCharStr propType = doc->GetStudioSystem()->GetPropertySystem()->GetName(property); + + std::vector<qt3dsdm::Qt3DSDMAnimationHandle> animHandles + = m_rowTree->propBinding()->animationHandles(); + for (size_t i = 0; i < animHandles.size(); ++i) { + qt3dsdm::TKeyframeHandleList keyframeHandles; + animCore->GetKeyframes(animHandles[i], keyframeHandles); + if (animType == EAnimationTypeLinear) { + QVector<SLinearKeyframe> keyframes; + for (Qt3DSDMKeyframeHandle kfHandle : keyframeHandles) { + TKeyframe kfData = animCore->GetKeyframeData(kfHandle); + keyframes.append(SLinearKeyframe(KeyframeTime(kfData), + KeyframeValueValue(kfData))); + } + long numFloatsPerKeyframe = sizeof(SLinearKeyframe) / sizeof(float); + long numValues = long(keyframeHandles.size()) * numFloatsPerKeyframe; + editor->CreateOrSetAnimation(slide, instance, propType.wide_str(), long(i), + animType, + reinterpret_cast<float *>(keyframes.begin()), + numValues); + } else if (animType == EAnimationTypeEaseInOut) { + float easeIn = CStudioPreferences::GetInterpolation() ? 100 : 0; + float easeOut = CStudioPreferences::GetInterpolation() ? 100 : 0; + QVector<SEaseInEaseOutKeyframe> keyframes; + for (Qt3DSDMKeyframeHandle kfHandle : keyframeHandles) { + TKeyframe kfData = animCore->GetKeyframeData(kfHandle); + keyframes.append(SEaseInEaseOutKeyframe(KeyframeTime(kfData), + KeyframeValueValue(kfData), + easeIn, easeOut)); + } + long numFloatsPerKeyframe = sizeof(SEaseInEaseOutKeyframe) / sizeof(float); + long numValues = long(keyframeHandles.size()) * numFloatsPerKeyframe; + editor->CreateOrSetAnimation(slide, instance, propType.wide_str(), long(i), + animType, + reinterpret_cast<float *>(keyframes.begin()), + numValues); + } else if (animType == EAnimationTypeBezier) { + QVector<SBezierKeyframe> keyframes; + for (Qt3DSDMKeyframeHandle kfHandle : keyframeHandles) { + TKeyframe kfData = animCore->GetKeyframeData(kfHandle); + float kfTime = KeyframeTime(kfData); + float kfValue = KeyframeValueValue(kfData); + keyframes.append(SBezierKeyframe(kfTime, kfValue, + kfTime - .5f, kfValue, + kfTime + .5f, kfValue)); + } + long numFloatsPerKeyframe = sizeof(SBezierKeyframe) / sizeof(float); + long numValues = long(keyframeHandles.size()) * numFloatsPerKeyframe; + editor->CreateOrSetAnimation(slide, instance, propType.wide_str(), long(i), + animType, + reinterpret_cast<float *>(keyframes.begin()), + numValues); + } + } +} + void RowTimelineContextMenu::insertKeyframe() { RowTree *destinationRowTree = nullptr; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.h index b8c2f922..d6b4a97f 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.h @@ -65,6 +65,7 @@ private: void changeTimeBarColor(); void setTimeBarTime(); void toggleDynamicKeyframes(); + void onAnimTypeChange(QAction *action); RowTree *m_rowTree = nullptr; Keyframe *m_keyframe = nullptr; @@ -81,6 +82,7 @@ private: QAction *m_setTimeBarColorAction = nullptr; QAction *m_setTimeBarTimeAction = nullptr; QAction *m_dynamicKeyframesAction = nullptr; + QMenu *m_animType = nullptr; TimelineControl *m_timelineControl = nullptr; bool m_hasDynamicKeyframes = false; }; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp index 3c82d73b..6c6c6f86 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp @@ -29,72 +29,355 @@ #include "RowTimelinePropertyGraph.h" #include "RowTimeline.h" #include "RowTree.h" +#include "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "IDocumentEditor.h" +#include "Qt3DSDMAnimation.h" +#include "Keyframe.h" #include "Ruler.h" #include "TimelineGraphicsScene.h" +#include "StudioPreferences.h" +#include "HotKeys.h" #include "Bindings/ITimelineItemProperty.h" +using namespace qt3dsdm; +using namespace TimelineConstants; + RowTimelinePropertyGraph::RowTimelinePropertyGraph(QObject *parent) : QObject(parent) + , m_rowTimeline(static_cast<RowTimeline *>(parent)) + , m_animCore(g_StudioApp.GetCore()->GetDoc()->GetAnimationCore()) { - m_rowTimeline = static_cast<RowTimeline *>(parent); + m_fitCurveTimer.setInterval(10); + + // smooth animation for when curve height change + connect(&m_fitCurveTimer, &QTimer::timeout, [this]() { + fitGraph(); + if (m_rowTimeline->size().height() == m_expandHeight) + m_fitCurveTimer.stop(); + }); } void RowTimelinePropertyGraph::paintGraphs(QPainter *painter, const QRectF &rect) { - m_rect = rect; m_propBinding = m_rowTimeline->rowTree()->propBinding(); - // Animate alpha 0..255 while expanding - int alpha = 255 * (m_rect.height() - TimelineConstants::ROW_H) - / (TimelineConstants::ROW_H_EXPANDED - TimelineConstants::ROW_H); - alpha = std::max(0, alpha); - - if (alpha == 0) + if (rect.height() < ROW_H) // rect height = row height - 1 return; - // Available line colors - QColor colors[6] = { QColor(255, 0, 0, alpha), QColor(0, 255, 0, alpha), - QColor(0, 0, 255, alpha), QColor(255, 255, 0, alpha), - QColor(255, 0, 255, alpha), QColor(0, 255, 255, alpha) }; + painter->setRenderHint(QPainter::Antialiasing); + painter->setClipRect(rect); + + const QPointF edgeOffset(RULER_EDGE_OFFSET, 0); + double timelineScale = m_rowTimeline->rowTree()->m_scene->ruler()->timelineScale(); - long channelCount = m_propBinding->GetChannelCount(); + // draw graph base line (graph_Y) + painter->setPen(QPen(CStudioPreferences::studioColor3())); + painter->drawLine(edgeOffset.x(), m_graphY, rect.right(), m_graphY); - // Don't want to overflow the color array - if (channelCount <= 6) { - // For each channel graph it. - for (long i = 0; i < channelCount; ++i) - paintSingleChannel(painter, i, colors[i]); + // draw channel curves + auto animHandles = m_propBinding->animationHandles(); + for (size_t channelIndex = 0; channelIndex < animHandles.size(); ++channelIndex) { + // Mahmoud_TODO: this block will draw the channel curves without sampling which is more + // efficient, but it cannot be used till the bezier equation is fixed (check:QT3DS-3777) + //-------------------------------draw using cubicTo -------------------------------------- +// QPainterPath path2; +// Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; +// m_animCore->GetKeyframes(animHandles[channelIndex], keyframeHandles); +// if (!keyframeHandles.empty()) { +// TKeyframe kf0 = m_animCore->GetKeyframeData(keyframeHandles[0]); +// path2.moveTo(getKeyframePosition(GetKeyframeSeconds(kf0), KeyframeValueValue(kf0)) +// + edgeOffset); + +// for (int i = 1; i < keyframeHandles.size(); ++i) { +// TKeyframe kf1 = m_animCore->GetKeyframeData(keyframeHandles[i]); +// float kf0InTime = -1, kf0InValue, kf0OutTime, kf0OutValue; +// float kf1InTime = -1, kf1InValue, kf1OutTime, kf1OutValue; +// getBezierValues(kf0, kf0InTime, kf0InValue, kf0OutTime, kf0OutValue); +// getBezierValues(kf1, kf1InTime, kf1InValue, kf1OutTime, kf1OutValue); +// if (kf0InTime != -1) { +// path2.cubicTo(getKeyframePosition(kf0OutTime, kf0OutValue) + edgeOffset, +// getKeyframePosition(kf1InTime, kf1InValue) + edgeOffset, +// getKeyframePosition(GetKeyframeSeconds(kf1), +// KeyframeValueValue(kf1)) +// + edgeOffset); +// } else { +// path2.lineTo(getKeyframePosition(GetKeyframeSeconds(kf1), +// KeyframeValueValue(kf1)) +// + edgeOffset); +// } +// // Mahmoud_TODO: handle ease in/out curves as well +// kf0 = kf1; +// } +// painter->setPen(QPen(QColor("#ff0000"), 1)); +// painter->drawPath(path2); +// } + //-------------------------------draw using cubicTo -------------------------------------- + + QPainterPath path; + int start_i = qMax(rect.x(), edgeOffset.x()); + for (int i = start_i; i < rect.right(); i += 5) { // 5 = sampling step in pixels + // Value time in ms + long time = (i - edgeOffset.x()) / (TimelineConstants::RULER_MILLI_W * timelineScale); + qreal value = m_propBinding->GetChannelValueAtTime(channelIndex, time); + qreal yPos = m_graphY - value * m_valScale; + if (i == start_i) + path.moveTo(i, yPos); + else + path.lineTo(i, yPos); + } + QColor channelColor; + if (channelIndex == 0) + channelColor = CStudioPreferences::GetXAxisColor(); + else if (channelIndex == 1) + channelColor = CStudioPreferences::GetYAxisColor(); + else if (channelIndex == 2) + channelColor = CStudioPreferences::GetZAxisColor(); + painter->setPen(QPen(channelColor, 2)); + painter->drawPath(path); + } + + // draw bezier controls + if (m_rowTimeline->rowTree()->propBinding()->animationType() == EAnimationTypeBezier) { + static const QPixmap pixBezierHandle = QPixmap("://images/breadcrumb_component_button.png"); + static const QPixmap pixBezierHandlePressed = QPixmap("://images/breadcrumb_component_grey" + "_button.png"); + + Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; + m_animCore->GetKeyframes(animHandles[0], keyframeHandles); + + size_t kfHandlesSize = keyframeHandles.size(); + for (size_t i = 0; i < kfHandlesSize; ++i) { + SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData( + keyframeHandles[i])); + + QPointF centerPos = getBezierControlPosition(kf) + edgeOffset; + const QPointF PIX_HALF_W = QPointF(8.0, 8.0); + + // draw vertical keyframe separator line + painter->setPen(QPen(CStudioPreferences::studioColor2(), 1)); + painter->drawLine(centerPos.x(), rect.y(), centerPos.x(), rect.height()); + + // draw tangent-in part + painter->setPen(CStudioPreferences::getBezierControlColor()); + if (i > 0) { + QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In) + edgeOffset; + painter->drawLine(cInPos, centerPos); + painter->drawPixmap(cInPos - PIX_HALF_W, pixBezierHandle); + } + + // draw tangent-out part + if (i < kfHandlesSize - 1) { + QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out) + edgeOffset; + painter->drawLine(cOutPos, centerPos); + painter->drawPixmap(cOutPos - PIX_HALF_W, pixBezierHandle); + } + + // draw center point + painter->setPen(QPen(CStudioPreferences::getBezierControlColor(), 3)); + painter->drawPoint(centerPos); + } } } -void RowTimelinePropertyGraph::paintSingleChannel(QPainter *painter, long inChannelIndex, - const QColor &inColor) +/** + * This method is called when the user mouse-presses the property graph. If the press is on a + * bezier keyframe handle, it returns the handle type and saves the list of keyframe channels + * handles to be precessed while the user drags the handle (in updateBezierControlValue()) + * + * @param pos press position in local coordinate system + * @return the pressed handle type, or None if no handle is pressed + */ +TimelineControlType RowTimelinePropertyGraph::getClickedBezierControl(const QPointF &pos) { - float maxVal = m_propBinding->GetMaximumValue(); - float minVal = m_propBinding->GetMinimumValue(); + if (m_rowTimeline->rowTree()->propBinding()->animationType() != EAnimationTypeBezier) + return TimelineControlType::None; - double timelineScale = m_rowTimeline->rowTree()->m_scene->ruler()->timelineScale(); + m_currKeyframeHandles.clear(); + m_currKeyframeData.clear(); + + auto animHandles = m_propBinding->animationHandles(); + Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; + m_animCore->GetKeyframes(animHandles[0], keyframeHandles); + const double CONTROL_RADIUS = 8; + for (auto kfHandle : keyframeHandles) { + SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(kfHandle)); + + QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In); + QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out); + bool clickedInHandle = QLineF(cInPos, pos).length() < CONTROL_RADIUS; + bool clickedOutHandle = QLineF(cOutPos, pos).length() < CONTROL_RADIUS; + if (clickedInHandle || clickedOutHandle) { + m_rowTimeline->rowTree()->propBinding()->GetKeyframeByTime(kf.m_KeyframeSeconds * 1000) + ->getUI()->binding->GetKeyframeHandles(m_currKeyframeHandles); + for (auto h : m_currKeyframeHandles) + m_currKeyframeData.append({h, m_animCore->GetKeyframeData(h)}); + + return clickedInHandle ? TimelineControlType::BezierInHandle + : TimelineControlType::BezierOutHandle; + } + } + + return TimelineControlType::None; +} + +QPointF RowTimelinePropertyGraph::getBezierControlPosition(const SBezierKeyframe &kf, + BezierControlType type) const +{ + float time = 0; // seconds + float value = 0; + if (type == BezierControlType::None) { + time = kf.m_KeyframeSeconds; + value = kf.m_KeyframeValue; + } else if (type == BezierControlType::In) { + time = kf.m_InTangentTime; + value = kf.m_InTangentValue; + } else if (type == BezierControlType::Out) { + time = kf.m_OutTangentTime; + value = kf.m_OutTangentValue; + } + + return getKeyframePosition(time, value); +} + +// time is in seconds +QPointF RowTimelinePropertyGraph::getKeyframePosition(float time, float value) const +{ + return QPointF(m_rowTimeline->rowTree()->m_scene->ruler()->timeToDistance(time * 1000), + m_graphY - value * m_valScale); +} + +/** + * This method is called when the user drags a bezier handle. It updates the bezier keyframe + * tangent value based on the current position of the handle. + * + * @param controlType which handle is being dragged? (BezierInHandle or BezierOutHandle) + * @param scenePos handle position in timeline scene coordinates + */ +void RowTimelinePropertyGraph::updateBezierControlValue(TimelineControlType controlType, + const QPointF &scenePos) +{ + QPointF p = m_rowTimeline->mapFromScene(scenePos.x() - TimelineConstants::RULER_EDGE_OFFSET, + scenePos.y()); - // Step in pixels - int interval = 5; - // Margin at top & bottom of graph - float marginY = 10; - float graphY = m_rect.y() + marginY; - float graphHeight = m_rect.height() - marginY * 2; - - QPainterPath path; - for (int i = 0; i < m_rect.width(); i += interval) { - // Value time in ms - long time = i / (TimelineConstants::RULER_MILLI_W * timelineScale); - float value = m_propBinding->GetChannelValueAtTime(inChannelIndex, time); - float yPos = graphY + (1.0 - (value - minVal) / (maxVal - minVal)) * graphHeight; - - if (i == 0) - path.moveTo(m_rect.x() + i, yPos); - else - path.lineTo(m_rect.x() + i, yPos); + float time = m_rowTimeline->rowTree()->m_scene->ruler()->distanceToTime(p.x()) / 1000.f; // secs + float value = (m_graphY - p.y()) / m_valScale; + + // first channel keyframe + SBezierKeyframe kf0 = get<SBezierKeyframe>(m_animCore->GetKeyframeData( + m_currKeyframeHandles[0])); + bool isBezierIn = controlType == TimelineControlType::BezierInHandle; + + // prevent handles from moving to the other side of the keyframe + if ((isBezierIn && time > kf0.m_KeyframeSeconds) + || (!isBezierIn && time < kf0.m_KeyframeSeconds)) { + time = kf0.m_KeyframeSeconds; + } + + // prevent handles from going beyond prev. and next keyframes + auto animHandles = m_propBinding->animationHandles(); + Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles; + m_animCore->GetKeyframes(animHandles[0], keyframeHandles); + for (size_t i = 0; i < keyframeHandles.size(); ++i) { + if (keyframeHandles[i] == m_currKeyframeHandles[0]) { + float currKfTime = KeyframeTime(m_animCore->GetKeyframeData(keyframeHandles[i])); + float prevKfTime = i > 0 + ? KeyframeTime(m_animCore->GetKeyframeData(keyframeHandles[i - 1])) : -FLT_MAX; + float nextKfTime = i < keyframeHandles.size() - 1 + ? KeyframeTime(m_animCore->GetKeyframeData(keyframeHandles[i + 1])) : FLT_MAX; + if (isBezierIn) { + if (time < prevKfTime) + time = prevKfTime; + if (!CHotKeys::IsKeyDown(Qt::ControlModifier) + && time < currKfTime * 2 - nextKfTime) { + time = currKfTime * 2 - nextKfTime; + } + } else { // bezier out + if (time > nextKfTime) + time = nextKfTime; + if (!CHotKeys::IsKeyDown(Qt::ControlModifier) + && time > currKfTime * 2 - prevKfTime) { + time = currKfTime * 2 - prevKfTime; + } + } + break; + } + } + + for (size_t i = 0; i < m_currKeyframeHandles.size(); ++i) { + SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData( + m_currKeyframeHandles[i])); + float &currHandleTime = isBezierIn ? kf.m_InTangentTime : kf.m_OutTangentTime; + float &currHandleValue = isBezierIn ? kf.m_InTangentValue : kf.m_OutTangentValue; + float &otherHandleTime = isBezierIn ? kf.m_OutTangentTime : kf.m_InTangentTime; + float &otherHandleValue = isBezierIn ? kf.m_OutTangentValue : kf.m_InTangentValue; + + currHandleTime = time; + currHandleValue = value + (kf.m_KeyframeValue - kf0.m_KeyframeValue); + + if (!CHotKeys::IsKeyDown(Qt::ControlModifier)) { + otherHandleTime = kf.m_KeyframeSeconds + (kf.m_KeyframeSeconds - time); + otherHandleValue = kf.m_KeyframeValue + (kf.m_KeyframeValue - currHandleValue); + } + + m_animCore->SetKeyframeData(m_currKeyframeHandles[i], kf); } - painter->setPen(QPen(inColor, 2)); - painter->drawPath(path); +} + +// adjust graph scale and y so that all keyframe and control points are visible +void RowTimelinePropertyGraph::fitGraph() +{ + const qreal MARGIN_Y = 10; // margin at top & bottom of graph + m_graphY = m_rowTimeline->size().height() - MARGIN_Y; + m_graphH = m_rowTimeline->size().height() - MARGIN_Y * 2; + + m_valScale = m_graphH / (m_propBinding->GetMaximumValue() - m_propBinding->GetMinimumValue()); + m_graphY += m_propBinding->GetMinimumValue() * m_valScale; + + m_rowTimeline->update(); +} + +void RowTimelinePropertyGraph::adjustScale(bool isIncrement) +{ + float pitch = m_valScale * .3f; + m_valScale += isIncrement ? pitch : -pitch; + + if (m_valScale > 10.f) + m_valScale = 10.f; + else if (m_valScale < .01f) + m_valScale = .01f; + + m_rowTimeline->update(); +} + +void RowTimelinePropertyGraph::startPan() +{ + m_graphYPanInit = m_graphY; +} + +void RowTimelinePropertyGraph::pan(qreal dy) +{ + m_graphY = m_graphYPanInit + dy; + m_rowTimeline->update(); +} + +void RowTimelinePropertyGraph::commitBezierEdit() +{ + // reset the changed keyframes and commit the changes, so the undo/redo works correctly + QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, TKeyframe>> changedKfs; + for (auto data : qAsConst(m_currKeyframeData)) { + changedKfs.append({data.first, m_animCore->GetKeyframeData(data.first)}); + m_animCore->SetKeyframeData(data.first, data.second); + } + + Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), tr("Edit Bezier curve")) + ->setBezierKeyframeValues(changedKfs); +} + +void RowTimelinePropertyGraph::setExpandHeight(int h) +{ + m_expandHeight = h; + m_fitCurveTimer.start(); } diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h index 275c24e2..5c3f1a71 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h @@ -29,26 +29,56 @@ #ifndef ROWTIMELINEPROPERTYGRAPH_H #define ROWTIMELINEPROPERTYGRAPH_H +#include "Qt3DSDMAnimation.h" +#include "RowTypes.h" +#include "TimelineConstants.h" +#include "Bindings/Qt3DSDMTimelineKeyframe.h" + #include <QtCore/qobject.h> +#include <QtCore/qtimer.h> #include <QtGui/qpainter.h> class RowTimeline; class ITimelineItemProperty; +namespace qt3dsdm { +class IAnimationCore; +class Qt3DSDMAnimationHandle; +} class RowTimelinePropertyGraph : public QObject { Q_OBJECT + public: explicit RowTimelinePropertyGraph(QObject *parent = nullptr); + TimelineControlType getClickedBezierControl(const QPointF &pos); void paintGraphs(QPainter *painter, const QRectF &rect); + void updateBezierControlValue(TimelineControlType controlType, const QPointF &scenePos); + void adjustScale(bool isIncrement); + void startPan(); + void pan(qreal dy); + void fitGraph(); + void commitBezierEdit(); + void setExpandHeight(int h); private: - void paintSingleChannel(QPainter *painter, long inChannelIndex, - const QColor &inColor); + enum class BezierControlType {None, In, Out}; + + QPointF getBezierControlPosition(const qt3dsdm::SBezierKeyframe &kf, + BezierControlType type = BezierControlType::None) const; + QPointF getKeyframePosition(float time, float value) const; + Qt3DSDMTimelineKeyframe::TKeyframeHandleList m_currKeyframeHandles; + QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, qt3dsdm::TKeyframe>> m_currKeyframeData; RowTimeline *m_rowTimeline = nullptr; ITimelineItemProperty *m_propBinding = nullptr; - QRectF m_rect; + qt3dsdm::IAnimationCore *m_animCore = nullptr; + float m_valScale = .5f; + qreal m_graphY = 0; + qreal m_graphYPanInit = 0; // value of graph_y when panning starts + qreal m_graphH = 0; + int m_expandHeight = TimelineConstants::ROW_GRAPH_H; // height when expanded + QTimer m_fitCurveTimer; }; #endif // ROWTIMELINEPROPERTYGRAPH_H diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp index e15258cd..9dace42b 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp @@ -28,6 +28,7 @@ #include "RowTree.h" #include "RowTimeline.h" +#include "RowTimelinePropertyGraph.h" #include "RowManager.h" #include "TimelineConstants.h" #include "StudioObjectTypes.h" @@ -169,8 +170,7 @@ void RowTree::animateExpand(ExpandState state) int endHeight = 0; // hidden states float endOpacity = 0; if (state == ExpandState::Expanded) { - endHeight = m_isPropertyExpanded ? TimelineConstants::ROW_H_EXPANDED - : TimelineConstants::ROW_H; + endHeight = m_propGraphExpanded ? m_propGraphHeight : TimelineConstants::ROW_H; endOpacity = 1; } else if (state == ExpandState::Collapsed) { endHeight = TimelineConstants::ROW_H; @@ -179,7 +179,6 @@ void RowTree::animateExpand(ExpandState state) // Changing end values while animation is running does not affect currently running animation, // so let's make sure the animation is stopped first. m_expandAnimation.stop(); - m_expandHeightAnimation->setEndValue(QSizeF(size().width(), endHeight)); m_expandTimelineHeightAnimation->setEndValue(QSizeF(m_rowTimeline->size().width(), endHeight)); @@ -201,15 +200,15 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q static const int ICON_SIZE = 16; static const int LEFT_DIVIDER = 18; + static const int ICON_Y = (TimelineConstants::ROW_H - ICON_SIZE) / 2; const int offset = 5 + m_depth * TimelineConstants::ROW_DEPTH_STEP; - const int iconY = (TimelineConstants::ROW_H / 2) - (ICON_SIZE / 2); // update button bounds rects - m_rectArrow .setRect(offset, iconY, ICON_SIZE, ICON_SIZE); - m_rectType .setRect(offset + ICON_SIZE, iconY, ICON_SIZE, ICON_SIZE); - m_rectShy .setRect(treeWidth() - 16 * 3.3, iconY, ICON_SIZE, ICON_SIZE); - m_rectVisible.setRect(treeWidth() - 16 * 2.2, iconY, ICON_SIZE, ICON_SIZE); - m_rectLocked .setRect(treeWidth() - 16 * 1.1, iconY, ICON_SIZE, ICON_SIZE); + m_rectArrow .setRect(offset, ICON_Y, ICON_SIZE, ICON_SIZE); + m_rectType .setRect(offset + ICON_SIZE, ICON_Y, ICON_SIZE, ICON_SIZE); + m_rectShy .setRect(treeWidth() - 16 * 3.3, ICON_Y, ICON_SIZE, ICON_SIZE); + m_rectVisible.setRect(treeWidth() - 16 * 2.2, ICON_Y, ICON_SIZE, ICON_SIZE); + m_rectLocked .setRect(treeWidth() - 16 * 1.1, ICON_Y, ICON_SIZE, ICON_SIZE); // Background QColor bgColor; @@ -235,8 +234,7 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q painter->drawLine(LEFT_DIVIDER, 0, LEFT_DIVIDER, size().height() - 1); // Shy, eye, lock separator - painter->fillRect(QRect(treeWidth() - TimelineConstants::TREE_ICONS_W, - 0, 1, size().height()), + painter->fillRect(QRect(rightDividerX(), 0, 1, size().height()), CStudioPreferences::timelineWidgetBgColor()); // Shy, eye, lock @@ -280,8 +278,7 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q static const QPixmap pixInsertRight2x = QPixmap(":/images/Insert-Right@2x.png"); if (m_dndState == DnDState::SP_TARGET) { // Candidate target of a subpresentation drop painter->drawPixmap(19, 2, hiResIcons ? pixInsertLeft2x : pixInsertLeft); - painter->drawPixmap(treeWidth() - TimelineConstants::TREE_ICONS_W - 8, 2, hiResIcons - ? pixInsertRight2x : pixInsertRight); + painter->drawPixmap(rightDividerX() - 8, 2, hiResIcons ? pixInsertRight2x : pixInsertRight); } else if (m_dndState == DnDState::Parent) { // Candidate parent of a dragged row painter->setPen(QPen(CStudioPreferences::timelineRowMoverColor(), 1)); painter->drawRect(QRect(1, 1, treeWidth() - 2, size().height() - 3)); @@ -333,6 +330,17 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q painter->drawPixmap(0, 0, hiResIcons ? pixCompMasterAction2x : pixCompMasterAction); else if (m_actionStates & ActionState::ComponentAction) // component has action painter->drawPixmap(0, 0, hiResIcons ? pixCompAction2x : pixCompAction); + } else { // property row + if (m_propGraphExpanded + && m_PropBinding->animationType() == qt3dsdm::EAnimationTypeBezier) { + const int PROP_GRAPH_CONTROLS_Y = int(TimelineConstants::ROW_H * 1.5); + m_rectMaximizePropGraph.setRect(rightDividerX() - 16 * 1.1, PROP_GRAPH_CONTROLS_Y, + ICON_SIZE, ICON_SIZE); + m_rectFitPropGraph.setRect(rightDividerX() - 16 * 2.2, PROP_GRAPH_CONTROLS_Y, + ICON_SIZE, ICON_SIZE); + painter->drawPixmap(m_rectMaximizePropGraph, pixShy); + painter->drawPixmap(m_rectFitPropGraph, pixShy); + } } // variants indicator @@ -541,7 +549,12 @@ void RowTree::setBinding(ITimelineItemBinding *binding) // x value where label should clip int RowTree::clipX() const { - return treeWidth() - TimelineConstants::TREE_ICONS_W - m_variantsGroups.size() * 8 - 2; + return rightDividerX() - m_variantsGroups.size() * 8 - 2; +} + +int RowTree::rightDividerX() const +{ + return treeWidth() - TimelineConstants::TREE_ICONS_W; } ITimelineItemProperty *RowTree::propBinding() @@ -947,8 +960,7 @@ bool RowTree::hasPropertyChildren() const void RowTree::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { - QPointF p = event->pos(); - if (m_rectType.contains(p.x(), p.y()) && !m_locked) + if (m_rectType.contains(event->pos().toPoint()) && !m_locked) if (m_binding) m_binding->OpenAssociatedEditor(); } @@ -956,8 +968,8 @@ void RowTree::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) // handle clicked control and return its type TreeControlType RowTree::getClickedControl(const QPointF &scenePos) { - QPointF p = mapFromScene(scenePos.x(), scenePos.y()); - if (m_arrowVisible && m_rectArrow.contains(p.x(), p.y())) { + QPoint p = mapFromScene(scenePos).toPoint(); + if (m_arrowVisible && m_rectArrow.contains(p)) { updateExpandStatus(m_expandState == ExpandState::Expanded ? ExpandState::Collapsed : ExpandState::Expanded, false); update(); @@ -965,19 +977,30 @@ TreeControlType RowTree::getClickedControl(const QPointF &scenePos) } if (hasActionButtons()) { - if (m_rectShy.contains(p.x(), p.y())) { + if (m_rectShy.contains(p)) { toggleShy(); return TreeControlType::Shy; - } else if (!m_onMasterSlide && m_rectVisible.contains(p.x(), p.y())) { + } else if (!m_onMasterSlide && m_rectVisible.contains(p)) { // Prevent toggling hide on master slide toggleVisible(); return TreeControlType::Hide; - } else if (m_rectLocked.contains(p.x(), p.y())) { + } else if (m_rectLocked.contains(p)) { toggleLocked(); return TreeControlType::Lock; } } + if (isProperty()) { + if (m_rectFitPropGraph.contains(p)) { + m_rowTimeline->propertyGraph()->fitGraph(); + } else if (m_rectMaximizePropGraph.contains(p)) { + m_propGraphHeight = m_propGraphHeight == TimelineConstants::ROW_GRAPH_H + ? TimelineConstants::ROW_GRAPH_H_MAX : TimelineConstants::ROW_GRAPH_H; + m_rowTimeline->propertyGraph()->setExpandHeight(m_propGraphHeight); + animateExpand(ExpandState::Expanded); + } + } + return TreeControlType::None; } @@ -1306,21 +1329,33 @@ bool RowTree::hasDurationBar() const bool RowTree::propertyExpanded() const { - return m_isPropertyExpanded; + return m_propGraphExpanded; } -void RowTree::togglePropertyExpanded() +/** + * toggle property graph if the mouse isn't over other buttons + * + * @param scenePos mouse position in graphics scene coordinates + */ +void RowTree::togglePropertyExpanded(const QPointF &scenePos) { - setPropertyExpanded(!m_isPropertyExpanded); + QPoint p = mapFromScene(scenePos).toPoint(); + if (!m_rectFitPropGraph.contains(p) && !m_rectMaximizePropGraph.contains(p)) + setPropertyExpanded(!m_propGraphExpanded); } void RowTree::setPropertyExpanded(bool expand) { - m_isPropertyExpanded = expand; - if (m_isPropertyExpanded) + m_propGraphExpanded = expand; + if (m_propGraphExpanded) { + // start graph in normal (not maximized) size + m_propGraphHeight = TimelineConstants::ROW_GRAPH_H; + m_rowTimeline->propertyGraph()->setExpandHeight(m_propGraphHeight); + m_rowTimeline->propertyGraph()->fitGraph(); animateExpand(ExpandState::Expanded); - else + } else { animateExpand(ExpandState::Collapsed); + } } void RowTree::showDataInputSelector(const QString &propertyname, const QPoint &pos) diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h index b028e94d..75afcaf0 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h @@ -97,7 +97,7 @@ public: void setBinding(ITimelineItemBinding *binding); void setPropBinding(ITimelineItemProperty *binding); // for property rows void selectLabel(); - void togglePropertyExpanded(); + void togglePropertyExpanded(const QPointF &scenePos = {}); void setPropertyExpanded(bool expand); void showDataInputSelector(const QString &propertyname, const QPoint &pos); ITimelineItemProperty *propBinding(); @@ -152,6 +152,7 @@ public: void updateFilter(); void updateLock(bool state); void updateSubpresentations(int updateParentsOnlyVal = 0); + int rightDividerX() const; int clipX() const; qt3dsdm::Qt3DSDMInstanceHandle instance() const; @@ -183,7 +184,8 @@ private: bool m_visible = true; bool m_locked = false; bool m_isProperty = false; - bool m_isPropertyExpanded = false; + bool m_propGraphExpanded = false; + int m_propGraphHeight = TimelineConstants::ROW_GRAPH_H; bool m_master = false; bool m_filtered = false; bool m_arrowVisible = false; @@ -211,6 +213,8 @@ private: QRect m_rectVisible; QRect m_rectLocked; QRect m_rectType; + QRect m_rectMaximizePropGraph; + QRect m_rectFitPropGraph; QParallelAnimationGroup m_expandAnimation; QPropertyAnimation *m_expandHeightAnimation; diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/TimelineItem.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/TimelineItem.cpp index 866d8109..205158e1 100644 --- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/TimelineItem.cpp +++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/TimelineItem.cpp @@ -33,7 +33,7 @@ TimelineItem::TimelineItem(TimelineItem *parent) : QGraphicsWidget(parent) { - setPreferredHeight(TimelineConstants::ROW_H_EXPANDED); + setPreferredHeight(TimelineConstants::ROW_GRAPH_H_MAX); setMaximumHeight(TimelineConstants::ROW_H); } diff --git a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.cpp b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.cpp index 9c4c5c38..be69bed6 100644 --- a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.cpp +++ b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.cpp @@ -27,22 +27,18 @@ ** ****************************************************************************/ -#include "Qt3DSCommonPrecompile.h" #include "InterpolationDlg.h" #include "ui_InterpolationDlg.h" -/** - * Constructor: Creates a CInterpolationDlg. - * - * @param parent Pointer to the parent of this dialog (defaults to NULL) - */ -//============================================================================== -CInterpolationDlg::CInterpolationDlg(QWidget *parent) +CInterpolationDlg::CInterpolationDlg(float easeIn, float easeOut, QWidget *parent) : QDialog(parent) , m_ui(new Ui::InterpolationDlg) { m_ui->setupUi(this); window()->setFixedSize(size()); + + m_ui->easeInSlider->setValue(int(easeIn)); + m_ui->easeOutSlider->setValue(int(easeOut)); } CInterpolationDlg::~CInterpolationDlg() @@ -51,22 +47,13 @@ CInterpolationDlg::~CInterpolationDlg() m_ui = nullptr; } -void CInterpolationDlg::setEaseIn(uint value) -{ - m_ui->easeInSlider->setValue(value); -} - -void CInterpolationDlg::setEaseOut(uint value) -{ - m_ui->easeOutSlider->setValue(value); -} -int CInterpolationDlg::easeIn() const +float CInterpolationDlg::easeIn() const { return m_ui->easeInSlider->value(); } -int CInterpolationDlg::easeOut() const +float CInterpolationDlg::easeOut() const { return m_ui->easeOutSlider->value(); } diff --git a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.h b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.h index 0b324bd3..ebff86de 100644 --- a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.h +++ b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.h @@ -27,16 +27,10 @@ ** ****************************************************************************/ -//============================================================================== -// Prefix -//============================================================================== - #ifndef INCLUDED_INTERPOLATION_DLG -#define INCLUDED_INTERPOLATION_DLG 1 - -#pragma once +#define INCLUDED_INTERPOLATION_DLG -#include <QDialog> +#include <QtWidgets/qdialog.h> QT_BEGIN_NAMESPACE namespace Ui { @@ -44,22 +38,19 @@ class InterpolationDlg; } QT_END_NAMESPACE -//============================================================================== /** - * CInterpolationDlg: Dialog class for editing the ease-in/ease-out values of keyframes. + * CInterpolationDlg: Dialog class for editing keyframes interpolation */ -//============================================================================== class CInterpolationDlg : public QDialog { Q_OBJECT + public: - explicit CInterpolationDlg(QWidget *parent = nullptr); // standard constructor + explicit CInterpolationDlg(float easeIn, float easeOut, QWidget *parent = nullptr); ~CInterpolationDlg(); - void setEaseIn(uint value); - void setEaseOut(uint value); - int easeIn() const; - int easeOut() const; + float easeIn() const; + float easeOut() const; protected: QT_PREPEND_NAMESPACE(Ui::InterpolationDlg) *m_ui = nullptr; diff --git a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.ui b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.ui index 0d27d777..710fee6b 100644 --- a/src/Authoring/Qt3DStudio/UI/InterpolationDlg.ui +++ b/src/Authoring/Qt3DStudio/UI/InterpolationDlg.ui @@ -1,311 +1,316 @@ <?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> - <class>InterpolationDlg</class> - <widget class="QDialog" name="InterpolationDlg"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>425</width> - <height>195</height> - </rect> - </property> - <property name="windowTitle"> - <string>Set Keyframe Interpolation</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="1" colspan="2"> - <widget class="QSlider" name="easeOutSlider"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksBelow</enum> - </property> - <property name="tickInterval"> - <number>10</number> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Ease In:</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QLabel" name="label_4"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Smooth</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="0" column="1" colspan="2"> - <widget class="QSlider" name="easeInSlider"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="maximum"> - <number>100</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksBelow</enum> - </property> - <property name="tickInterval"> - <number>10</number> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLabel" name="label_3"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Linear</string> - </property> - </widget> - </item> - <item row="3" column="1"> - <widget class="QLabel" name="label_5"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Linear</string> - </property> - </widget> - </item> - <item row="3" column="2"> - <widget class="QLabel" name="label_6"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Smooth</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="text"> - <string>Ease Out:</string> - </property> - </widget> - </item> - <item row="0" column="3"> - <widget class="QSpinBox" name="easeInSpinBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="buttonSymbols"> - <enum>QAbstractSpinBox::NoButtons</enum> - </property> - <property name="maximum"> - <number>100</number> - </property> - </widget> - </item> - <item row="2" column="3"> - <widget class="QSpinBox" name="easeOutSpinBox"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="buttonSymbols"> - <enum>QAbstractSpinBox::NoButtons</enum> - </property> - <property name="maximum"> - <number>100</number> - </property> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QDialogButtonBox" name="buttonBox"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="standardButtons"> - <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>easeInSlider</tabstop> - <tabstop>easeInSpinBox</tabstop> - <tabstop>easeOutSlider</tabstop> - <tabstop>easeOutSpinBox</tabstop> - </tabstops> - <resources/> - <connections> - <connection> - <sender>buttonBox</sender> - <signal>accepted()</signal> - <receiver>InterpolationDlg</receiver> - <slot>accept()</slot> - <hints> - <hint type="sourcelabel"> - <x>224</x> - <y>272</y> - </hint> - <hint type="destinationlabel"> - <x>157</x> - <y>274</y> - </hint> - </hints> - </connection> - <connection> - <sender>buttonBox</sender> - <signal>rejected()</signal> - <receiver>InterpolationDlg</receiver> - <slot>reject()</slot> - <hints> - <hint type="sourcelabel"> - <x>316</x> - <y>260</y> - </hint> - <hint type="destinationlabel"> - <x>286</x> - <y>274</y> - </hint> - </hints> - </connection> - <connection> - <sender>easeInSlider</sender> - <signal>valueChanged(int)</signal> - <receiver>easeInSpinBox</receiver> - <slot>setValue(int)</slot> - <hints> - <hint type="sourcelabel"> - <x>331</x> - <y>21</y> - </hint> - <hint type="destinationlabel"> - <x>542</x> - <y>35</y> - </hint> - </hints> - </connection> - <connection> - <sender>easeOutSlider</sender> - <signal>valueChanged(int)</signal> - <receiver>easeOutSpinBox</receiver> - <slot>setValue(int)</slot> - <hints> - <hint type="sourcelabel"> - <x>210</x> - <y>93</y> - </hint> - <hint type="destinationlabel"> - <x>545</x> - <y>93</y> - </hint> - </hints> - </connection> - <connection> - <sender>easeInSpinBox</sender> - <signal>valueChanged(int)</signal> - <receiver>easeInSlider</receiver> - <slot>setValue(int)</slot> - <hints> - <hint type="sourcelabel"> - <x>533</x> - <y>24</y> - </hint> - <hint type="destinationlabel"> - <x>408</x> - <y>18</y> - </hint> - </hints> - </connection> - <connection> - <sender>easeOutSpinBox</sender> - <signal>valueChanged(int)</signal> - <receiver>easeOutSlider</receiver> - <slot>setValue(int)</slot> - <hints> - <hint type="sourcelabel"> - <x>546</x> - <y>98</y> - </hint> - <hint type="destinationlabel"> - <x>338</x> - <y>84</y> - </hint> - </hints> - </connection> - </connections> + <class>InterpolationDlg</class> + <widget class="QDialog" name="InterpolationDlg"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>425</width> + <height>195</height> + </rect> + </property> + <property name="windowTitle"> + <string>Set Keyframe Interpolation</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + + <layout class="QGridLayout" name="gridLayout"> + <item row="1" column="0"> + <widget class="QLabel" name="label"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Ease In:</string> + </property> + </widget> + </item> + <item row="1" column="1" colspan="2"> + <widget class="QSlider" name="easeInSlider"> + <property name="enabled"> + <bool>true</bool> + </property> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBelow</enum> + </property> + <property name="tickInterval"> + <number>10</number> + </property> + </widget> + </item> + <item row="1" column="3"> + <widget class="QSpinBox" name="easeInSpinBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>100</number> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QLabel" name="label_3"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Linear</string> + </property> + </widget> + </item> + <item row="2" column="2"> + <widget class="QLabel" name="label_4"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Smooth</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_2"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Ease Out:</string> + </property> + </widget> + </item> + <item row="3" column="1" colspan="2"> + <widget class="QSlider" name="easeOutSlider"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="maximum"> + <number>100</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksBelow</enum> + </property> + <property name="tickInterval"> + <number>10</number> + </property> + </widget> + </item> + <item row="3" column="3"> + <widget class="QSpinBox" name="easeOutSpinBox"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Maximum" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="buttonSymbols"> + <enum>QAbstractSpinBox::NoButtons</enum> + </property> + <property name="maximum"> + <number>100</number> + </property> + </widget> + </item> + <item row="4" column="1"> + <widget class="QLabel" name="label_5"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Linear</string> + </property> + </widget> + </item> + <item row="4" column="2"> + <widget class="QLabel" name="label_6"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Preferred" vsizetype="Maximum"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Smooth</string> + </property> + <property name="alignment"> + <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> + </property> + </widget> + </item> + </layout> + + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set> + </property> + </widget> + </item> + </layout> + </widget> + <tabstops> + <tabstop>easeInSlider</tabstop> + <tabstop>easeInSpinBox</tabstop> + <tabstop>easeOutSlider</tabstop> + <tabstop>easeOutSpinBox</tabstop> + </tabstops> + <resources/> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>InterpolationDlg</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>233</x> + <y>211</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>InterpolationDlg</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>325</x> + <y>211</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>easeInSlider</sender> + <signal>valueChanged(int)</signal> + <receiver>easeInSpinBox</receiver> + <slot>setValue(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>108</x> + <y>58</y> + </hint> + <hint type="destinationlabel"> + <x>406</x> + <y>72</y> + </hint> + </hints> + </connection> + <connection> + <sender>easeOutSlider</sender> + <signal>valueChanged(int)</signal> + <receiver>easeOutSpinBox</receiver> + <slot>setValue(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>171</x> + <y>136</y> + </hint> + <hint type="destinationlabel"> + <x>406</x> + <y>132</y> + </hint> + </hints> + </connection> + <connection> + <sender>easeInSpinBox</sender> + <signal>valueChanged(int)</signal> + <receiver>easeInSlider</receiver> + <slot>setValue(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>406</x> + <y>72</y> + </hint> + <hint type="destinationlabel"> + <x>108</x> + <y>55</y> + </hint> + </hints> + </connection> + <connection> + <sender>easeOutSpinBox</sender> + <signal>valueChanged(int)</signal> + <receiver>easeOutSlider</receiver> + <slot>setValue(int)</slot> + <hints> + <hint type="sourcelabel"> + <x>406</x> + <y>132</y> + </hint> + <hint type="destinationlabel"> + <x>171</x> + <y>136</y> + </hint> + </hints> + </connection> + </connections> </ui> diff --git a/src/Authoring/Qt3DStudio/Workspace/Dialogs.cpp b/src/Authoring/Qt3DStudio/Workspace/Dialogs.cpp index 2a5a6780..5ba8abe6 100644 --- a/src/Authoring/Qt3DStudio/Workspace/Dialogs.cpp +++ b/src/Authoring/Qt3DStudio/Workspace/Dialogs.cpp @@ -229,27 +229,21 @@ CDialogs::~CDialogs() * * @param ioEaseIn value to be set as the ease in default - passes back the value chosen by the user * @param ioEaseOut value to be set as the ease out default - passes back the value chosen by the - * user * @return true if the user clicked OK on the dialog (indicating that the values should be updated * on the track) */ -bool CDialogs::PromptForKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut) +bool CDialogs::displayKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut) { - bool theReturnValue = false; + CInterpolationDlg interpolationDialog(ioEaseIn, ioEaseOut); - CInterpolationDlg theInterpolationDialog; - theInterpolationDialog.setEaseIn(ioEaseIn); - theInterpolationDialog.setEaseOut(ioEaseOut); - - // If the user presses the OK button - if (theInterpolationDialog.exec() == QDialog::Accepted) { + if (interpolationDialog.exec() == QDialog::Accepted) { // Retrieve the new interpolation values - ioEaseIn = theInterpolationDialog.easeIn(); - ioEaseOut = theInterpolationDialog.easeOut(); - theReturnValue = true; + ioEaseIn = interpolationDialog.easeIn(); + ioEaseOut = interpolationDialog.easeOut(); + return true; } - return theReturnValue; + return false; } /** diff --git a/src/Authoring/Qt3DStudio/Workspace/Dialogs.h b/src/Authoring/Qt3DStudio/Workspace/Dialogs.h index 02f0b8d3..b10922cb 100644 --- a/src/Authoring/Qt3DStudio/Workspace/Dialogs.h +++ b/src/Authoring/Qt3DStudio/Workspace/Dialogs.h @@ -145,7 +145,7 @@ public: QColor displayColorDialog(const QColor &color, bool showAlpha = false) const; ESavePromptResult PromptForSave(); - bool PromptForKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut); + bool displayKeyframeInterpolation(float &ioEaseIn, float &ioEaseOut); bool ConfirmRevert(); diff --git a/src/Runtime/ogl-runtime b/src/Runtime/ogl-runtime -Subproject e13ab913d2fe4d1b8d687713693b5a8bb5856e7 +Subproject 3bcd2a4e81ffced186b060de8eee905b5c65f78 |