diff options
author | Mahmoud Badri <mahmoud.badri@qt.io> | 2018-02-27 14:37:41 +0200 |
---|---|---|
committer | Mahmoud Badri <mahmoud.badri@qt.io> | 2018-03-19 09:03:27 +0000 |
commit | 089ab17e462646dcd9edf785aa6850ad92b3a8e0 (patch) | |
tree | a58f0c08022bb2ca1a0dae672ff796dd1a7a62ac | |
parent | 6741e0b808aef4992c81df1128b8db0f8113f49f (diff) |
Continue timeline work
Split timeline and tree views, implement layer locking, filter rows, start connection to the app data mode.
Task-number: QT3DS-1262
Change-Id: I54fb659e5c4f1103b8cf792b04bcaf012779cf1a
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
44 files changed, 1472 insertions, 884 deletions
diff --git a/src/Authoring/Client/Code/Core/Commands/CmdDataModelRemoveKeyframe.h b/src/Authoring/Client/Code/Core/Commands/CmdDataModelRemoveKeyframe.h index 3677f4f8..696f1d9e 100644 --- a/src/Authoring/Client/Code/Core/Commands/CmdDataModelRemoveKeyframe.h +++ b/src/Authoring/Client/Code/Core/Commands/CmdDataModelRemoveKeyframe.h @@ -42,6 +42,7 @@ #include "Qt3DSDMAnimation.h" #include "CmdDataModelBase.h" #include "Qt3DSDMStudioSystem.h" +#include "Bindings/Qt3DSDMTimelineKeyframe.h" class CCmdDataModelRemoveKeyframe : public CCmd, public qt3dsdm::CmdDataModel { @@ -51,11 +52,12 @@ protected: // Members public: // Construction //@param inTime is in secs - CCmdDataModelRemoveKeyframe(CDoc *inDoc, qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe) + CCmdDataModelRemoveKeyframe(CDoc *inDoc, qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe = 0) : qt3dsdm::CmdDataModel(*inDoc) , m_Doc(inDoc) { - AddKeyframeHandle(inKeyframe); + if (inKeyframe) + AddKeyframeHandle(inKeyframe); } ~CCmdDataModelRemoveKeyframe() {} @@ -64,6 +66,14 @@ public: // Construction m_Keyframes.push_back(inKeyframe); } + void addKeyframeHandles(Qt3DSDMTimelineKeyframe *binding) + { + Qt3DSDMTimelineKeyframe::TKeyframeHandleList kfHandles; + binding->GetKeyframeHandles(kfHandles); + for (auto &&handle : qAsConst(kfHandles)) + m_Keyframes.push_back(handle); + } + //====================================================================== // Do/Redo //====================================================================== diff --git a/src/Authoring/Client/Code/Core/Doc/IKeyframe.h b/src/Authoring/Client/Code/Core/Doc/IKeyframe.h index 52c21264..0c10644d 100644 --- a/src/Authoring/Client/Code/Core/Doc/IKeyframe.h +++ b/src/Authoring/Client/Code/Core/Doc/IKeyframe.h @@ -31,6 +31,8 @@ #pragma once +struct Keyframe; + //============================================================================== /** * Abstraction of a animation keyframe. @@ -51,6 +53,7 @@ public: */ virtual void SetTime(const long inNewTime) = 0; virtual void SetDynamic(bool inIsDynamic) = 0; + virtual void setUI(Keyframe *kfUI) = 0; virtual bool IsDynamic() const = 0; }; diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h index bac7136c..9469981d 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h @@ -37,6 +37,7 @@ #include "SIterator.h" class CBaseStateRow; +class RowTree; class CControlWindowListener; class ITimelineKeyframesManager; @@ -83,7 +84,9 @@ public: virtual ~ITimelineItemBinding() {} virtual ITimelineItem *GetTimelineItem() = 0; - virtual CBaseStateRow *GetRow() = 0; + virtual CBaseStateRow *GetRow() = 0; // Mahmoud_TODO: remove after timeline is complete + virtual RowTree *getRowTree() const = 0; // UI + virtual void setRowTree(RowTree *row) = 0; // Events virtual void SetSelected(bool multiSelect) = 0; diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h index f8ee3fa3..26b00c09 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemProperty.h @@ -36,6 +36,7 @@ #include "Qt3DSDMMetaData.h" #include "Qt3DSString.h" +class RowTree; class CPropertyRow; class IKeyframe; class ITimelineKeyframesManager; @@ -62,7 +63,9 @@ public: virtual void Bind(CPropertyRow *inRow) = 0; virtual void Release() = 0; - virtual CPropertyRow *GetRow() = 0; + virtual void setRowTree(RowTree *row) = 0; + virtual RowTree *getRowTree() const = 0; + virtual CPropertyRow *GetRow() = 0; // Mahmoud_TODO: delete after new timeline is done // Keyframes virtual ITimelineKeyframesManager *GetKeyframesManager() const = 0; diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.cpp index 51fd2377..4626545c 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.cpp @@ -45,6 +45,11 @@ Qt3DSDMAssetTimelineKeyframe::~Qt3DSDMAssetTimelineKeyframe() { } +void Qt3DSDMAssetTimelineKeyframe::setUI(Keyframe *kfUI) +{ + m_ui = kfUI; +} + bool Qt3DSDMAssetTimelineKeyframe::IsSelected() const { return m_Selected; @@ -77,4 +82,4 @@ bool Qt3DSDMAssetTimelineKeyframe::IsDynamic() const void Qt3DSDMAssetTimelineKeyframe::SetSelected(bool inSelected) { m_Selected = inSelected; -}
\ No newline at end of file +} diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.h index c57837da..fc22302c 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMAssetTimelineKeyframe.h @@ -60,10 +60,14 @@ public: long GetTime() const override; void SetTime(const long inNewTime) override; void SetDynamic(bool inIsDynamic) override; + void setUI(Keyframe *kfUI) override; bool IsDynamic() const override; void SetSelected(bool inSelected); void UpdateTime(const long inTime) { m_Time = inTime; } + +private: + Keyframe *m_ui; }; #endif // QT3DSDM_ASSET_KEYFRAME_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp index 02ff7c58..eefe295a 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.cpp @@ -375,11 +375,22 @@ ITimelineItem *Qt3DSDMTimelineItemBinding::GetTimelineItem() return this; } +// Mahmoud_TODO: remove after finishing the new timeline CBaseStateRow *Qt3DSDMTimelineItemBinding::GetRow() { return m_Row; } +RowTree *Qt3DSDMTimelineItemBinding::getRowTree() const +{ + return m_rowTree; +} + +void Qt3DSDMTimelineItemBinding::setRowTree(RowTree *row) +{ + m_rowTree = row; +} + void Qt3DSDMTimelineItemBinding::SetSelected(bool inMultiSelect) { if (!inMultiSelect) @@ -880,12 +891,12 @@ Qt3DSDMTimelineItemBinding::GetOrCreatePropertyBinding(Qt3DSDMPropertyHandle inP * @param inAppend true to skip the check to find where to insert. ( true if this is a * loading/initializing step, where the call is already done in order ) */ -CPropertyRow *Qt3DSDMTimelineItemBinding::AddPropertyRow(Qt3DSDMPropertyHandle inPropertyHandle, +void Qt3DSDMTimelineItemBinding::AddPropertyRow(Qt3DSDMPropertyHandle inPropertyHandle, bool inAppend /*= false */) { ITimelineItemProperty *theTimelineProperty = GetPropertyBinding(inPropertyHandle); if (theTimelineProperty && theTimelineProperty->GetRow()) // if created, bail - return {}; + return; if (!theTimelineProperty) theTimelineProperty = GetOrCreatePropertyBinding(inPropertyHandle); @@ -917,21 +928,8 @@ CPropertyRow *Qt3DSDMTimelineItemBinding::AddPropertyRow(Qt3DSDMPropertyHandle i } } - CPropertyRow *propertyRow = nullptr; - // Create a new property row - if (m_createUIRow) { - propertyRow = m_TransMgr->CreateNewPropertyRow(theTimelineProperty, m_Row, - theNextProperty ? theNextProperty->GetRow() : nullptr); - } else { - propertyRow = new CPropertyRow(theTimelineProperty, m_Row); - m_Row->AddPropertyRow(propertyRow, theNextProperty ? theNextProperty->GetRow() : nullptr); - theTimelineProperty->Bind(propertyRow); - } - // Update keyframes AddKeyframes(theTimelineProperty); - - return propertyRow; } void Qt3DSDMTimelineItemBinding::RemovePropertyRow(Qt3DSDMPropertyHandle inPropertyHandle) @@ -940,16 +938,8 @@ void Qt3DSDMTimelineItemBinding::RemovePropertyRow(Qt3DSDMPropertyHandle inPrope if (theIter != m_PropertyBindingMap.end()) { ITimelineItemProperty *thePropertyBinding = theIter->second; - bool theUpdateUI = DeleteAssetKeyframesWhereApplicable(thePropertyBinding); - - m_TransMgr->RemovePropertyRow(thePropertyBinding); + DeleteAssetKeyframesWhereApplicable(thePropertyBinding); m_PropertyBindingMap.erase(theIter); - - // UI must update - if (m_Row && theUpdateUI) { - m_Row->ForceEmitChildrenChanged(); - m_Row->setDirty(true); - } } } @@ -1243,7 +1233,8 @@ void Qt3DSDMTimelineItemBinding::OnAddChild(Qt3DSDMInstanceHandle inInstance) if (theNextChild != 0) theNextItem = m_TransMgr->GetOrCreate(theNextChild); - m_Row->AddChildRow(m_TransMgr->GetOrCreate(inInstance), theNextItem); + // Mahmoud_TODO: remove +// m_Row->AddChildRow(m_TransMgr->GetOrCreate(inInstance), theNextItem); } } diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.h index 81e0df0b..9b6a5b84 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemBinding.h @@ -54,6 +54,7 @@ class CTimelineTranslationManager; class CBaseStateRow; class Qt3DSDMTimelineItemProperty; class CCmdDataModelSetKeyframeTime; +class RowTree; namespace qt3dsdm { class CStudioSystem; @@ -74,7 +75,8 @@ protected: // Typedef typedef std::vector<Qt3DSDMAssetTimelineKeyframe> TAssetKeyframeList; protected: - CBaseStateRow *m_Row; + CBaseStateRow *m_Row; // TODO: remove after finishing the new timeline + RowTree *m_rowTree = nullptr; CTimelineTranslationManager *m_TransMgr; qt3dsdm::Qt3DSDMInstanceHandle m_DataHandle; ITimelineItemBinding *m_Parent; @@ -121,7 +123,9 @@ public: // ITimelineItemBinding ITimelineItem *GetTimelineItem() override; - CBaseStateRow *GetRow() override; + CBaseStateRow *GetRow() override; // Mahmoud_TODO: remove after finishing the new timeline + RowTree *getRowTree() const override; + void setRowTree(RowTree *row) override; void SetSelected(bool inMultiSelect) override; void OnCollapsed() override; void ClearKeySelection() override; @@ -179,8 +183,8 @@ public: long inInstanceCount) override; void RefreshStateRow(bool inRefreshChildren = false); - virtual CPropertyRow* AddPropertyRow(qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle, - bool inAppend = false); + virtual void AddPropertyRow(qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle, + bool inAppend = false); virtual void RemovePropertyRow(qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle); virtual void RefreshPropertyKeyframe(qt3dsdm::Qt3DSDMPropertyHandle inPropertyHandle, qt3dsdm::Qt3DSDMKeyframeHandle, diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp index eb6f4864..b6e79d5b 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp @@ -143,6 +143,11 @@ void Qt3DSDMTimelineItemProperty::ReleaseKeyframes() m_AnimationHandles.clear(); } +qt3dsdm::Qt3DSDMPropertyHandle Qt3DSDMTimelineItemProperty::getPropertyHandle() const +{ + return m_PropertyHandle; +} + // Type doesn't change and due to the logic required to figure this out, cache it. void Qt3DSDMTimelineItemProperty::InitializeCachedVariables(qt3dsdm::Qt3DSDMInstanceHandle inInstance) { @@ -230,6 +235,11 @@ void Qt3DSDMTimelineItemProperty::Bind(CPropertyRow *inRow) m_Row = inRow; } +RowTree *Qt3DSDMTimelineItemProperty::getRowTree() const +{ + return m_rowTree; +} + void Qt3DSDMTimelineItemProperty::Release() { m_Row = nullptr; @@ -408,6 +418,11 @@ void Qt3DSDMTimelineItemProperty::SelectKeyframes(bool inSelected, long inTime / DoSelectKeyframes(inSelected, inTime, false, theParent); } +void Qt3DSDMTimelineItemProperty::setRowTree(RowTree *rowTree) +{ + m_rowTree = rowTree; +} + CPropertyRow *Qt3DSDMTimelineItemProperty::GetRow() { return m_Row; diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h index 29ba585d..9f304167 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h @@ -37,6 +37,7 @@ #include "Qt3DSDMTimeline.h" #include "Qt3DSDMPropertyDefinition.h" +class RowTree; class CTimelineTranslationManager; class CCmdDataModelSetKeyframeValue; class Qt3DSDMTimelineItemBinding; @@ -78,9 +79,11 @@ public: // IKeyframeSelector void SelectKeyframes(bool inSelected, long inTime = -1) override; + void setRowTree(RowTree *rowTree) override; void Bind(CPropertyRow *inRow) override; + RowTree *getRowTree() const override; void Release() override; - CPropertyRow *GetRow() override; + CPropertyRow *GetRow() override; // Mahmoud_TODO: delete bool RefreshKeyframe(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, ETimelineKeyframeTransaction inTransaction); @@ -90,6 +93,8 @@ public: void RefreshKeyFrames(void); + qt3dsdm::Qt3DSDMPropertyHandle getPropertyHandle() const; + protected: void InitializeCachedVariables(qt3dsdm::Qt3DSDMInstanceHandle inInstance); bool CreateKeyframeIfNonExistent(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe, @@ -114,6 +119,9 @@ protected: qt3dsdm::TDataTypePair m_Type; Q3DStudio::CString m_Name; std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>> m_Signals; + +private: + RowTree *m_rowTree = nullptr; }; #endif // QT3DSDM_TIMELINE_ITEM_PROPERTY_H diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp index b97261fc..072fe8d9 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp @@ -131,6 +131,11 @@ void Qt3DSDMTimelineKeyframe::SetDynamic(bool inIsDynamic) } } +void Qt3DSDMTimelineKeyframe::setUI(Keyframe *kfUI) +{ + m_ui = kfUI; +} + // Only the first key of a track can be dynamic. bool Qt3DSDMTimelineKeyframe::IsDynamic() const { diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h index ccec6ef0..1d6d410e 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h @@ -40,6 +40,7 @@ class IDoc; class CDoc; class CCmdBatch; class COffsetKeyframesCommandHelper; +struct Keyframe; //============================================================================== /** @@ -56,6 +57,7 @@ protected: m_KeyframeHandles; ///< no. corresponds to the channels the animated property has. CDoc *m_Doc; bool m_Selected; + Keyframe *m_ui; public: Qt3DSDMTimelineKeyframe(IDoc *inDoc); @@ -66,6 +68,7 @@ public: long GetTime() const override; void SetTime(const long inNewTime) override; void SetDynamic(bool inIsDynamic) override; + void setUI(Keyframe *kfUI) override; bool IsDynamic() const override; void AddKeyframeHandle(qt3dsdm::Qt3DSDMKeyframeHandle inHandle); diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp index bc10a373..c97a046f 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.cpp @@ -320,25 +320,6 @@ void CTimelineTranslationManager::OnNewPresentation() } //============================================================================== -/** - * Selection events on the old data model was triggered via signals on the actual objects. - * For the new data model, it would be via this OnSelectionChange event. - */ -void CTimelineTranslationManager::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable) -{ - // Deselect all items - TInstanceHandleBindingMap::const_iterator theIter = m_InstanceHandleBindingMap.begin(); - for (; theIter != m_InstanceHandleBindingMap.end(); ++theIter) { - ITimelineItemBinding *theBinding = theIter->second; - CBaseStateRow *theRow = theBinding->GetRow(); - if (theRow) - theRow->OnSelected(false); - } - - // Select new - if (inNewSelectable) - SetSelected(inNewSelectable, true); -} CDoc *CTimelineTranslationManager::GetDoc() const { @@ -523,25 +504,6 @@ void CTimelineTranslationManager::ClearBindingsKeyframeSelection() } //============================================================================== -/** - * Helper function to find the binding that corresponds to inSelectable and set its selection state - */ -void CTimelineTranslationManager::SetSelected(Q3DStudio::SSelectedValue inSelectable, - bool inSelected) -{ - qt3dsdm::TInstanceHandleList theInstances = inSelectable.GetSelectedInstances(); - for (size_t idx = 0, end = theInstances.size(); idx < end; ++idx) { - Qt3DSDMInstanceHandle theInstance(theInstances[idx]); - if (GetStudioSystem()->IsInstance(theInstance)) { - ITimelineItemBinding *theBinding = EnsureLoaded(theInstance); - if (theBinding) { - CBaseStateRow *theRow = theBinding->GetRow(); - if (theRow) - theRow->OnSelected(inSelected); - } - } - } -} ITimelineItemBinding *CTimelineTranslationManager::EnsureLoaded(Qt3DSDMInstanceHandle inHandle) { diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h index 14e34f4b..83443c2c 100644 --- a/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h +++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/TimelineTranslationManager.h @@ -110,7 +110,6 @@ public: void ClearKeyframeSelection(); void OnNewPresentation(); - void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable); qt3dsdm::CStudioSystem *GetStudioSystem() const; diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineObjectModel.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineObjectModel.cpp index 1ff8ee6f..0f908aa9 100644 --- a/src/Authoring/Studio/Palettes/Timeline/TimelineObjectModel.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineObjectModel.cpp @@ -376,8 +376,9 @@ CTimelineRow* TimelineObjectModel::timelineRowForIndex(const QModelIndex &index) if (auto propertyBinding = binding->GetPropertyBinding(handle)) propertyRow = propertyBinding->GetRow(); - if (propertyRow == nullptr) - propertyRow = binding->AddPropertyRow(handle); + // Mahmoud_TODO: this whole class will be removed +// if (propertyRow == nullptr) +// propertyRow = binding->AddPropertyRow(handle); Q_ASSERT(propertyRow); diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp index b1821235..25ce1bcd 100644 --- a/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp +++ b/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp @@ -143,7 +143,6 @@ void TimelineView::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable) m_model->expandTo(QModelIndex(), index); } } - m_translationManager->OnSelectionChange(inNewSelectable); } void TimelineView::OnTimeChanged(long inTime) @@ -269,7 +268,7 @@ void TimelineView::OnActiveSlide(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, in m_translationManager->Clear(); m_activeSlide = inSlide; - qDebug() << "OnActiveSlide"; + auto *theSlideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem(); auto theSlideInstance = theSlideSystem->GetSlideInstance(inSlide); diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h index 99ad423e..16751183 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h @@ -29,8 +29,9 @@ #ifndef KEYFRAME_H #define KEYFRAME_H +#include "Bindings/Qt3DSDMTimelineKeyframe.h" + class RowTimeline; -enum class PropertyType; struct Keyframe { @@ -45,9 +46,10 @@ struct Keyframe double time; double value; bool selected = false; - PropertyType propertyType; + QString propertyType; RowTimeline *rowProperty; RowTimeline *rowMaster; + Qt3DSDMTimelineKeyframe *binding; }; #endif // KEYFRAME_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp index 8912f84b..09ff2f62 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp @@ -36,11 +36,29 @@ #include "PlayHead.h" #include "RowManager.h" #include "TimelineGraphicsScene.h" +#include "StudioObjectTypes.h" +#include "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "CmdDataModelRemoveKeyframe.h" +#include "CmdDataModelInsertKeyframe.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/KeyframesManager.h" +#include "Bindings/Qt3DSDMTimelineKeyframe.h" #include <qglobal.h> #include <QtCore/qhash.h> #include <QtCore/qdebug.h> +// Mahmmoud_TODO: This function is copied from old timeline code. It should be removed after the +// new timeline is done (during cleanup of old timeline) +// legacy stuff that we have to support for animation tracks in the old data model to work +inline void PostExecuteCommand(IDoc *inDoc) +{ + CDoc *theDoc = dynamic_cast<CDoc *>(inDoc); + theDoc->GetCore()->CommitCurrentCommand(); +} + KeyframeManager::KeyframeManager(TimelineGraphicsScene *scene) : m_scene(scene) { } @@ -50,10 +68,10 @@ QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, double time, { QList<Keyframe *> addedKeyframes; QList<RowTimeline *> propRows; - if (row->rowTree()->rowType() != RowType::Property) { + if (!row->rowTree()->isProperty()) { const auto childRows = row->rowTree()->childRows(); for (const auto r : childRows) { - if (r->rowType() == RowType::Property) + if (r->isProperty()) propRows.append(r->rowTimeline()); } } else { @@ -89,6 +107,8 @@ void KeyframeManager::selectKeyframe(Keyframe *keyframe) keyframe->rowMaster->putSelectedKeyframesOnTop(); keyframe->rowMaster->updateKeyframes(); + + keyframe->binding->SetSelected(true); } } @@ -103,8 +123,10 @@ void KeyframeManager::selectKeyframes(const QList<Keyframe *> &keyframes) } } - for (auto keyframe : qAsConst(m_selectedKeyframes)) + for (auto keyframe : qAsConst(m_selectedKeyframes)) { keyframe->selected = true; + keyframe->binding->SetSelected(true); + } for (auto row : qAsConst(m_selectedKeyframesMasterRows)) { row->putSelectedKeyframesOnTop(); @@ -112,6 +134,13 @@ void KeyframeManager::selectKeyframes(const QList<Keyframe *> &keyframes) } } +// update bindings after selected keyframes are moved +void KeyframeManager::commitMoveSelectedKeyframes() +{ + for (auto keyframe : qAsConst(m_selectedKeyframes)) + keyframe->binding->SetTime(keyframe->time * 1000); +} + void KeyframeManager::selectKeyframesInRect(const QRectF &rect) { deselectAllKeyframes(); @@ -122,9 +151,6 @@ void KeyframeManager::selectKeyframesInRect(const QRectF &rect) m_scene->rowManager()->clampIndex(idx1); m_scene->rowManager()->clampIndex(idx2); - // TODO: remove - qDebug() << "idx1=" << idx1 << ", idx2=" << idx2; - RowTimeline *rowTimeline; for (int i = idx1; i <= idx2; ++i) { rowTimeline = m_scene->rowManager()->rowTimelineAt(i); @@ -142,8 +168,10 @@ void KeyframeManager::selectKeyframesInRect(const QRectF &rect) } } - for (auto keyframe : qAsConst(m_selectedKeyframes)) + for (auto keyframe : qAsConst(m_selectedKeyframes)) { keyframe->selected = true; + keyframe->binding->SetSelected(true); + } for (auto row : qAsConst(m_selectedKeyframesMasterRows)) { row->putSelectedKeyframesOnTop(); @@ -158,13 +186,17 @@ void KeyframeManager::deselectKeyframe(Keyframe *keyframe) m_selectedKeyframes.removeAll(keyframe); keyframe->rowMaster->updateKeyframes(); m_selectedKeyframesMasterRows.removeAll(keyframe->rowMaster); + + keyframe->binding->SetSelected(false); } } void KeyframeManager::deselectAllKeyframes() { - for (auto keyframe : qAsConst(m_selectedKeyframes)) + for (auto keyframe : qAsConst(m_selectedKeyframes)) { keyframe->selected = false; + keyframe->binding->SetSelected(false); + } for (auto row : qAsConst(m_selectedKeyframesMasterRows)) row->updateKeyframes(); @@ -176,7 +208,11 @@ void KeyframeManager::deselectAllKeyframes() void KeyframeManager::deleteSelectedKeyframes() { if (!m_selectedKeyframes.empty()) { + CDoc *theDoc = g_StudioApp.GetCore()->GetDoc(); + CCmdDataModelRemoveKeyframe *cmd = new CCmdDataModelRemoveKeyframe(theDoc); for (auto keyframe : qAsConst(m_selectedKeyframes)) { + cmd->addKeyframeHandles(keyframe->binding); + keyframe->rowMaster->removeKeyframe(keyframe); keyframe->rowProperty->removeKeyframe(keyframe); @@ -188,6 +224,9 @@ void KeyframeManager::deleteSelectedKeyframes() m_selectedKeyframes.clear(); m_selectedKeyframesMasterRows.clear(); + + g_StudioApp.GetCore()->ExecuteCommand(cmd); + PostExecuteCommand(theDoc); } } @@ -236,7 +275,7 @@ void KeyframeManager::pasteKeyframes(RowTimeline *row) if (row == nullptr) return; - if (row->rowTree()->rowType() == RowType::Property) + if (row->rowTree()->isProperty()) row = row->parentRow(); if (!m_copiedKeyframes.empty()) { @@ -262,8 +301,8 @@ void KeyframeManager::pasteKeyframes(RowTimeline *row) RowTree *propRow; QList<Keyframe *> addedKeyframes; for (auto keyframe : filteredKeyframes) { - propRow = m_scene->rowManager()->getOrCreatePropertyRow(keyframe->propertyType, - row->rowTree()); + propRow = m_scene->rowManager()->getOrCreatePropertyRow(row->rowTree(), + keyframe->propertyType); addedKeyframes.append(insertKeyframe(propRow->rowTimeline(), keyframe->time + dt, keyframe->value, false)); } @@ -335,83 +374,83 @@ bool KeyframeManager::hasCopiedKeyframes() const return !m_copiedKeyframes.empty(); } -const QHash<RowType, QList<PropertyType>> KeyframeManager::SUPPORTED_ROW_PROPS { - { RowType::Layer, { - PropertyType::Left, - PropertyType::Width, - PropertyType::Top, - PropertyType::Height, - PropertyType::AO, - PropertyType::AODistance, - PropertyType::AOSoftness, - PropertyType::AOThreshold, - PropertyType::AOSamplingRate, - PropertyType::IBLBrightness, - PropertyType::IBLHorizonCutoff, - PropertyType::IBLFOVAngle } +const QHash<int, QList<QString>> KeyframeManager::SUPPORTED_ROW_PROPS = { + { OBJTYPE_LAYER, { + "Left", + "Width", + "Top", + "Height", + "Ambient Occulusion", + "AO Distance", + "AO Softness", + "AO Threshold", + "AO Sampling Rate", + "IBL Brightness", + "IBL Horizon Cutoff", + "IBL FOV Angle" } }, - { RowType::Camera, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::FieldOfView, - PropertyType::ClippingStart, - PropertyType::ClippingEnd } + { OBJTYPE_CAMERA, { + "Position", + "Rotation", + "Scale", + "Pivot", + "FieldOfView", + "ClippingStart", + "ClippingEnd" } }, - { RowType::Light, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::LightColor, - PropertyType::SpecularColor, - PropertyType::AmbientColor, - PropertyType::Brightness, - PropertyType::ShadowDarkness, - PropertyType::ShadowSoftness, - PropertyType::ShadowDepthBias, - PropertyType::ShadowFarClip, - PropertyType::ShadowFOV } + { OBJTYPE_LIGHT, { + "Position", + "Rotation", + "Scale", + "Pivot", + "LightColor", + "SpecularColor", + "AmbientColor", + "Brightness", + "ShadowDarkness", + "ShadowSoftness", + "ShadowDepthBias", + "ShadowFarClip", + "ShadowFOV" } }, - { RowType::Object, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::Opacity, - PropertyType::EdgeTessellation, - PropertyType::InnerTessellation } + { OBJTYPE_MODEL, { + "Position", + "Rotation", + "Scale", + "Pivot", + "Opacity", + "EdgeTessellation", + "InnerTessellation" } }, - { RowType::Text, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::Opacity, - PropertyType::TextColor, - PropertyType::Leading, - PropertyType::Tracking } + { OBJTYPE_TEXT, { + "Position", + "Rotation", + "Scale", + "Pivot", + "Opacity", + "TextColor", + "Leading", + "Tracking" } }, - { RowType::Alias, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::Opacity } + { OBJTYPE_ALIAS, { + "Position", + "Rotation", + "Scale", + "Pivot", + "Opacity" } }, - { RowType::Group, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::Opacity } + { OBJTYPE_GROUP, { + "Position", + "Rotation", + "Scale", + "Pivot", + "Opacity" } }, - { RowType::Component, { - PropertyType::Position, - PropertyType::Rotation, - PropertyType::Scale, - PropertyType::Pivot, - PropertyType::Opacity } + { OBJTYPE_COMPONENT, { + "Position", + "Rotation", + "Scale", + "Pivot", + "Opacity" } } }; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h index 251f5f91..dc78f5e1 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h @@ -30,11 +30,10 @@ #define KEYFRAMEMANAGER_H #include <QtCore/qlist.h> +#include <StudioObjectTypes.h> class RowTimeline; class TimelineGraphicsScene; -enum class RowType; -enum class PropertyType; struct Keyframe; QT_FORWARD_DECLARE_CLASS(QGraphicsSceneContextMenuEvent) @@ -57,6 +56,7 @@ public: void copySelectedKeyframes(); void pasteKeyframes(RowTimeline *row); void moveSelectedKeyframes(double dx); + void commitMoveSelectedKeyframes(); bool oneMasterRowSelected() const; bool hasSelectedKeyframes() const; bool hasCopiedKeyframes() const; @@ -67,9 +67,8 @@ public: QList<Keyframe *> m_copiedKeyframes; // for copy, cut, paste QList<RowTimeline *> m_selectedKeyframesMasterRows; - private: - static const QHash<RowType, QList<PropertyType>> SUPPORTED_ROW_PROPS; + static const QHash<int, QList<QString>> SUPPORTED_ROW_PROPS; QList<Keyframe *> filterKeyframesForRow(RowTimeline *row, const QList<Keyframe *> &keyframes); }; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp index 93227365..5ea10f1f 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp @@ -30,21 +30,101 @@ #include "RowTree.h" #include "TimelineGraphicsScene.h" #include "Ruler.h" +#include "TreeHeader.h" #include "KeyframeManager.h" +#include "Keyframe.h" +#include "StudioObjectTypes.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/Qt3DSDMTimelineItemBinding.h" +#include "Bindings/ITimelineTimebar.h" +#include "Bindings/Qt3DSDMTimelineKeyframe.h" +#include "StudioApp.h" +#include "Core.h" +#include "Doc.h" #include <QtWidgets/qgraphicslinearlayout.h> -#include <QtCore/qdebug.h> RowManager::RowManager(TimelineGraphicsScene *scene, QGraphicsLinearLayout *layoutLabels, QGraphicsLinearLayout *layoutTimeline) : m_scene(scene) - , m_layoutLabels(layoutLabels) + , m_layoutTree(layoutLabels) , m_layoutTimeline(layoutTimeline) { } -RowTree *RowManager::getOrCreatePropertyRow(PropertyType propType, RowTree *masterRow) +void RowManager::recreateRowsFromBinding(ITimelineItemBinding *rootBinding) +{ + removeAllRows(); + createRowsFromBindingRecursive(rootBinding); +} + +void RowManager::removeAllRows() +{ + m_scene->keyframeManager()->deselectAllKeyframes(); + clearSelection(); + + // delete rows + RowTree *row_i; + for (int i = m_layoutTree->count() - 1; i >= 1; --i) { + row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem()); + m_layoutTree->removeAt(i); + m_layoutTimeline->removeAt(i); + delete row_i; // this will also delete the timeline row + } +} + +RowTree *RowManager::createRowFromBinding(ITimelineItemBinding *binding, RowTree *parentRow) +{ + RowTree *newRow = createRow(binding->GetTimelineItem()->GetObjectType(), parentRow, + binding->GetTimelineItem()->GetName().toQString()); + + // connect the new row and its binding + binding->setRowTree(newRow); + newRow->setBinding(binding); + + // set row start/end time + ITimelineTimebar *timebar = binding->GetTimelineItem()->GetTimebar(); + newRow->rowTimeline()->setStartTime(timebar->GetStartTime() * .001); + newRow->rowTimeline()->setEndTime(timebar->GetEndTime() * .001); + + // create property rows + for (int i = 0; i < binding->GetPropertyCount(); i++) { + ITimelineItemProperty *prop_i = binding->GetProperty(i); + RowTree *propRow = getOrCreatePropertyRow(newRow, prop_i->GetName().toQString()); + + // connect the property row and its binding + prop_i->setRowTree(propRow); + propRow->setPropBinding(prop_i); + + // add keyframes + for (int j = 0; j < prop_i->GetKeyframeCount(); j++) { + Qt3DSDMTimelineKeyframe *kf = + static_cast<Qt3DSDMTimelineKeyframe *>(prop_i->GetKeyframeByIndex(j)); + + QList<Keyframe *> addedKeyframes = + m_scene->keyframeManager()->insertKeyframe(propRow->rowTimeline(), + static_cast<double>(kf->GetTime()) * .001, 0, false); + + Keyframe *kfUI = addedKeyframes.at(0); + kf->setUI(kfUI); + kfUI->binding = kf; + } + } + + return newRow; +} + +void RowManager::createRowsFromBindingRecursive(ITimelineItemBinding *binding, RowTree *parentRow) +{ + RowTree *newRow = createRowFromBinding(binding, parentRow); + + // create child rows recursively + for (int i = 0; i < binding->GetChildrenCount(); i++) + createRowsFromBindingRecursive(binding->GetChild(i), newRow); +} + +RowTree *RowManager::getOrCreatePropertyRow(RowTree *masterRow, const QString &propType) { if (masterRow->hasPropertyChildren()) { const auto childRows = masterRow->childRows(); @@ -54,50 +134,60 @@ RowTree *RowManager::getOrCreatePropertyRow(PropertyType propType, RowTree *mast } } - return createRow(RowType::Property, masterRow, 0, propType); + return createRow(OBJTYPE_UNKNOWN, masterRow, 0, propType); } -RowTree *RowManager::createRow(RowType rowType, RowTree *parentRow, const QString &label, - PropertyType propType) +RowTree *RowManager::createRow(EStudioObjectType rowType, RowTree *parentRow, const QString &label, + const QString &propType) { - if (parentRow == nullptr && rowType != RowType::Scene) { - qWarning() << __FUNCTION__ << "Invalid parent. Row must have a valid parent row." - " No row added."; - } else if (parentRow != nullptr && parentRow->rowType() == RowType::Property) { + if (parentRow != nullptr && parentRow->isProperty()) { qWarning() << __FUNCTION__ << "Property row cannot have children. No row added."; } else { - RowTree *rowLabel = nullptr; + // If the row doesnt have a parent, insert it under the scene (first row is the tree header) + if (parentRow == nullptr && rowType != OBJTYPE_SCENE && m_layoutTree->count() > 1) + parentRow = static_cast<RowTree *>(m_layoutTree->itemAt(1)); - if (propType != PropertyType::None) - rowLabel = new RowTree(m_scene->ruler(), propType); + RowTree *rowTree = nullptr; + + if (!propType.isEmpty()) // property row + rowTree = new RowTree(m_scene, propType); else - rowLabel = new RowTree(m_scene->ruler(), rowType, label); + rowTree = new RowTree(m_scene, rowType, label); if (parentRow != nullptr) - parentRow->addChild(rowLabel); - - rowLabel->rowTimeline()->setStartTime(0); - rowLabel->rowTimeline()->setEndTime(qMin(10.0, m_scene->ruler()->duration())); + parentRow->addChild(rowTree); - int index = getRowIndex(parentRow) + 1; - if (index == 0) + int index = getLastChildIndex(parentRow) + 1; + if (index < 1) index = 1; - m_layoutLabels->insertItem(index, rowLabel); - m_layoutTimeline->insertItem(index, rowLabel->rowTimeline()); + m_layoutTree->insertItem(index, rowTree); + m_layoutTimeline->insertItem(index, rowTree->rowTimeline()); - return rowLabel; + return rowTree; } return nullptr; } +void RowManager::reorderPropertiesFromBinding(Qt3DSDMTimelineItemBinding *binding) +{ + int index = getRowIndex(binding->getRowTree()) + 1; + if (index > 1) { + for (int i = binding->GetPropertyCount() - 1; i >= 0; i--) { + RowTree *rowToMove = binding->GetProperty(i)->getRowTree(); + m_layoutTree->insertItem(index, rowToMove); + m_layoutTimeline->insertItem(index, rowToMove->rowTimeline()); + } + } +} + RowTree *RowManager::getRowAbove(RowTree *row) { int rowIndex = getRowIndex(row); if (rowIndex > 1) { - RowTree *rowAbove = static_cast<RowTree *>(m_layoutLabels->itemAt(rowIndex - 1)); + RowTree *rowAbove = static_cast<RowTree *>(m_layoutTree->itemAt(rowIndex - 1)); if (rowAbove != nullptr) { while (rowAbove != nullptr && rowAbove->depth() > row->depth()) @@ -115,7 +205,7 @@ RowTree *RowManager::rowAt(int idx) correctIndex(idx); if (idx != -1) - return static_cast<RowTree *>(m_layoutTimeline->itemAt(idx)->graphicsItem()); + return static_cast<RowTree *>(m_layoutTree->itemAt(idx)->graphicsItem()); return nullptr; } @@ -132,18 +222,64 @@ RowTimeline *RowManager::rowTimelineAt(int idx) void RowManager::selectRow(RowTree *row) { - if (row != nullptr && row != m_selectedRow && row->rowType() != RowType::Property) { - if (m_selectedRow != nullptr) - m_selectedRow->setState(InteractiveTimelineItem::Normal); - + if (row != nullptr && row != m_selectedRow && !row->isProperty()) { + clearSelection(); row->setState(InteractiveTimelineItem::Selected); m_selectedRow = row; + + Qt3DSDMTimelineItemBinding *binding = + static_cast<Qt3DSDMTimelineItemBinding *>(row->getBinding()); + g_StudioApp.GetCore()->GetDoc()->SelectDataModelObject(binding->GetInstance()); } } +void RowManager::clearSelection() +{ + if (m_selectedRow != nullptr) { + m_selectedRow->setState(InteractiveTimelineItem::Normal); + m_selectedRow = nullptr; + } +} + +void RowManager::updateFiltering(RowTree *row) +{ + if (row == nullptr) { // update all rows + RowTree *row_i; + for (int i = 1; i < m_layoutTree->count(); ++i) { + row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem()); + updateRowFilter(row_i); + } + } else { + updateRowFilterRecursive(row); + } +} + +void RowManager::updateRowFilterRecursive(RowTree *row) +{ + updateRowFilter(row); + + if (!row->empty()) { + const auto childRows = row->childRows(); + for (auto child : childRows) + updateRowFilterRecursive(child); + } +} + +void RowManager::updateRowFilter(RowTree *row) +{ + bool parentOk = row->parentRow() == nullptr || (row->parentRow()->expanded() + && row->parentRow()->isVisible()); + bool shyOk = !row->shy() || !m_scene->treeHeader()->filterShy(); + bool visibleOk = row->visible() || !m_scene->treeHeader()->filterHidden(); + bool lockOk = !row->locked() || !m_scene->treeHeader()->filterLocked(); + + row->setVisible(parentOk && shyOk && visibleOk && lockOk); + row->rowTimeline()->setVisible(row->isVisible()); +} + void RowManager::deleteRow(RowTree *row) { - if (row != nullptr && row->rowType() != RowType::Scene) { + if (row != nullptr && row->rowType() != OBJTYPE_SCENE) { if (m_selectedRow == row) selectRow(getRowAbove(row)); @@ -154,7 +290,8 @@ void RowManager::deleteRow(RowTree *row) void RowManager::deleteRowRecursive(RowTree *row) { if (!row->childRows().empty()) { - for (auto child : row->childRows()) + const auto childRows = row->childRows(); + for (auto child : childRows) deleteRowRecursive(child); } @@ -167,8 +304,7 @@ void RowManager::deleteRowRecursive(RowTree *row) m_scene->keyframeManager()->deleteKeyframes(row->rowTimeline()); m_layoutTimeline->removeItem(row->rowTimeline()); - m_layoutLabels->removeItem(row); - delete row->rowTimeline(); + m_layoutTree->removeItem(row); delete row; } @@ -180,8 +316,8 @@ RowTree *RowManager::selectedRow() const int RowManager::getRowIndex(RowTree *row) { if (row != nullptr) { - for (int i = 1; i < m_layoutLabels->count(); ++i) { - if (row == m_layoutLabels->itemAt(i)->graphicsItem()) + for (int i = 1; i < m_layoutTree->count(); ++i) { + if (row == m_layoutTree->itemAt(i)->graphicsItem()) return i; } } @@ -189,18 +325,49 @@ int RowManager::getRowIndex(RowTree *row) return -1; } +bool RowManager::hasProperties(RowTree *row) +{ + if (row != nullptr && !row->empty()) { + int index = getRowIndex(row); + if (index != -1 && index < m_layoutTree->count() - 1) { + RowTree *nextRow = static_cast<RowTree *>(m_layoutTree->itemAt(index + 1) + ->graphicsItem()); + return nextRow->isProperty(); + } + } + + return false; +} + +int RowManager::getLastChildIndex(RowTree *row) +{ + int index = getRowIndex(row); + if (index != -1) { + for (int i = index + 1; i < m_layoutTree->count(); ++i) { + if (static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem())->depth() + <= row->depth()) { + return i - 1; + } + } + + return m_layoutTree->count() - 1; // last row + } + + return -1; +} + void RowManager::clampIndex(int &idx) { if (idx < 1) idx = 1; - else if (idx > m_layoutLabels->count() - 1) - idx = m_layoutLabels->count() - 1; + else if (idx > m_layoutTree->count() - 1) + idx = m_layoutTree->count() - 1; } // Index within rows indices bounds bool RowManager::validIndex(int idx) const { - return idx > 0 && idx < m_layoutLabels->count(); + return idx > 0 && idx < m_layoutTree->count(); } // Adjust index to point to the correct row taking into consideration collaped rows @@ -211,7 +378,7 @@ void RowManager::correctIndex(int &idx) return; } - // adjust for collapsed items (invisible) + // adjust for collapsed and filtered items (invisible) for (int i = 1; i <= idx; ++i) { if (!m_layoutTimeline->itemAt(i)->graphicsItem()->isVisible()) { if (++idx > m_layoutTimeline->count() - 1) { diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h index 929a8ecf..534a36b9 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.h @@ -31,10 +31,13 @@ #include "RowTypes.h" #include <QtCore/qstring.h> +#include <StudioObjectTypes.h> class TimelineGraphicsScene; class RowTree; class RowTimeline; +class ITimelineItemBinding; +class Qt3DSDMTimelineItemBinding; QT_FORWARD_DECLARE_CLASS(QGraphicsLinearLayout) @@ -44,27 +47,38 @@ public: RowManager(TimelineGraphicsScene *scene, QGraphicsLinearLayout *layoutLabels, QGraphicsLinearLayout *layoutTimeline); + void recreateRowsFromBinding(ITimelineItemBinding *rootBinding); void clampIndex(int &idx); void correctIndex(int &idx); void selectRow(RowTree *row); void deleteRow(RowTree *row); - RowTree *getOrCreatePropertyRow(PropertyType propType, RowTree *masterRow); - RowTree *createRow(RowType rowType, RowTree *parentRow = nullptr, const QString &label = {}, - PropertyType propType = PropertyType::None); + void clearSelection(); + void updateFiltering(RowTree *rowTree = nullptr); + void reorderPropertiesFromBinding(Qt3DSDMTimelineItemBinding *binding); + bool hasProperties(RowTree *row); + RowTree *createRowFromBinding(ITimelineItemBinding *binding, RowTree *parentRow = nullptr); + RowTree *getOrCreatePropertyRow(RowTree *masterRow, const QString &propType); + RowTree *createRow(EStudioObjectType rowType, RowTree *parentRow = nullptr, + const QString &label = QString(), const QString &propType = QString()); RowTree *rowAt(int idx); RowTree *getRowAbove(RowTree *row); - RowTimeline *rowTimelineAt(int idx); - RowTree *selectedRow() const; + RowTimeline *rowTimelineAt(int idx); private: int getRowIndex(RowTree *row); + int getLastChildIndex(RowTree *row); bool validIndex(int idx) const; void deleteRowRecursive(RowTree *row); + void updateRowFilter(RowTree *row); + void updateRowFilterRecursive(RowTree *row); + void createRowsFromBindingRecursive(ITimelineItemBinding *binding, + RowTree *parentRow = nullptr); + void removeAllRows(); RowTree *m_selectedRow = nullptr; TimelineGraphicsScene *m_scene; - QGraphicsLinearLayout *m_layoutLabels; + QGraphicsLinearLayout *m_layoutTree; QGraphicsLinearLayout *m_layoutTimeline; }; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp index ed447bb7..44a521dd 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowMover.cpp @@ -37,14 +37,20 @@ RowMover::RowMover() : QGraphicsRectItem() { setZValue(99); - setRect(0, -2, 20, 2); + setRect(0, -5, TimelineConstants::TREE_MAX_W, 10); } void RowMover::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { + painter->save(); + + painter->setPen(QPen(QColor(TimelineConstants::ROW_MOVER_COLOR), 1)); + painter->drawLine(0, -1, TimelineConstants::TREE_BOUND_W, -1); + painter->setPen(QPen(QColor(TimelineConstants::ROW_MOVER_COLOR), 4)); - painter->drawLine(0, -.5, 10, -.5); - painter->fillRect(0, -2.5, rect().width() - x(), 2, QColor(TimelineConstants::ROW_MOVER_COLOR)); + painter->drawLine(0, -2, 5, -2); + + painter->restore(); } RowTree *RowMover::insertionParent() const @@ -123,7 +129,7 @@ void RowMover::updateState(int index, int depth, int rawIndex) { m_targetIndex = index; - setPos(20 + depth * 15, (rawIndex + 1) * TimelineConstants::ROW_H); + setPos(25 + depth * 15, (rawIndex + 1) * TimelineConstants::ROW_H); setVisible(true); } @@ -135,10 +141,9 @@ bool RowMover::isValidMove(int index, RowTree *rowAtIndex) //index != m_currentIndex && // not moving an ancestor into a decendent - !rowAtIndex->isDecendentOf(m_sourceRow) && + !rowAtIndex->isDecendentOf(m_sourceRow) // not at the top of an expanded object with property children - (rowAtIndex->childRows().empty() - || rowAtIndex->childRows().first()->rowType() != RowType::Property - || !rowAtIndex->expanded()); + && (rowAtIndex->childRows().empty() || !rowAtIndex->childRows().first()->isProperty() + || !rowAtIndex->expanded()); } diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowTypes.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowTypes.h index f666c3c2..36f59fc8 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowTypes.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowTypes.h @@ -31,23 +31,9 @@ #include <qglobal.h> -//namespace timeline { - -enum class RowType { - Scene = 90, - Layer, - Camera, - Light, - Object, - Text, - Alias, - Group, - Component, - Property -}; - +// Mahmoud_TODO: to be removed enum class PropertyType { - None = 540, + None = 200, Position, Rotation, Scale, @@ -85,8 +71,20 @@ enum class PropertyType { ProbeCrossfade, // Layer }; -inline uint qHash(RowType key) { - return static_cast<uint>(key); -} +enum class TimelineControlType { + None = 300, + KeyFrame, + Duration, + StartHandle, + EndHandle +}; + +enum class TreeControlType { + None = 400, + Arrow, + Shy, + Hide, + Lock +}; #endif // ROWTYPES_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h index 22494a5a..5d034ba5 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h @@ -34,36 +34,39 @@ namespace TimelineConstants // Dimensions const int ROW_H = 20; const int ROW_SPACING = 2; - const int RULER_SEC_W = 30; // width of 1 second section (at scale 1) - const int RULER_SEC_DIV = 10; // second divisions - const int RULER_DIV_H1 = 5; // height of main divisions - const int RULER_DIV_H2 = 2; // height of secondary divisions - const int RULER_BASE_Y = 18; // baseline Y - const int RULER_EDGE_OFFSET = 15; - const double LABELS_MIN_W = 160; - const double LABELS_MAX_W = 600; - const int LABELS_DEFAULT_W = 250; - const int SEPARATOR_W = 8; + const int RULER_SEC_W = 30; // width of 1 second section (at scale 1) + const int RULER_SEC_DIV = 10; // second divisions + const int RULER_DIV_H1 = 5; // height of main divisions + const int RULER_DIV_H2 = 2; // height of secondary divisions + const int RULER_BASE_Y = 18; // baseline Y + const double RULER_EDGE_OFFSET = 15; + const double TREE_MIN_W = 160; + const double TREE_MAX_W = 600; + const double TREE_DEFAULT_W = 250; + const double TREE_BOUND_W = 10000; // real width of the row (> max possible visible tree area) + const int SPLITTER_W = 8; const int PLAYHEAD_W = 14; - const int DURATION_HANDLE_W = 14; // width of duration end handles in a timeline row + const int DURATION_HANDLE_W = 14; // width of duration end handles in a timeline row // Colors - const char ROW_COLOR_NORMAL[] = "#404040"; - const char ROW_COLOR_NORMAL_PROP[] = "#373737"; - const char ROW_COLOR_OVER[] = "#4d4d4d"; - const char ROW_COLOR_SELECTED[] = "#336699"; - const char ROW_COLOR_DURATION[] = "#66CCFF"; - const char ROW_COLOR_DURATION_OFF1[] = "#3388B3"; - const char ROW_COLOR_DURATION_OFF2[] = "#222222"; - const char ROW_COLOR_DURATION_EDGE[] = "#000000"; - const char ROW_COLOR_DURATION_SELECTED[] = "#4D99CC"; - const char ROW_COLOR_MOVE_SRC[] = "#464600"; - const char ROW_TEXT_COLOR[] = "#bbbbbb"; - const char PLAYHEAD_COLOR[] = "#ff0066"; - const char RULER_COLOR[] = "#666666"; - const char ROW_MOVER_COLOR[] = "#ffff00"; - const char WIDGET_BG_COLOR[] = "#222222"; - const char PLAYHEAD_LINE_COLOR[] = "#b20808"; + const char ROW_COLOR_NORMAL[] = "#404040"; + const char ROW_COLOR_NORMAL_PROP[] = "#373737"; + const char ROW_COLOR_OVER[] = "#4d4d4d"; + const char ROW_COLOR_SELECTED[] = "#336699"; + const char ROW_COLOR_DURATION[] = "#66CCFF"; + const char ROW_COLOR_DURATION_OFF1[] = "#3388B3"; // duration off ancestors' bounds color1 + const char ROW_COLOR_DURATION_OFF2[] = "#222222"; // duration off ancestors' bounds color2 + const char ROW_COLOR_DURATION_EDGE[] = "#000000"; // duration left and right edge lines + const char ROW_COLOR_DURATION_SELECTED[] = "#4D99CC"; + const char ROW_COLOR_MOVE_SRC[] = "#464600"; + const char ROW_TEXT_COLOR[] = "#bbbbbb"; + const char ROW_TEXT_COLOR_DISABLED[] = "#888888"; + const char PLAYHEAD_COLOR[] = "#ff0066"; + const char RULER_COLOR[] = "#666666"; + const char ROW_MOVER_COLOR[] = "#ffff00"; + const char WIDGET_BG_COLOR[] = "#222222"; + const char PLAYHEAD_LINE_COLOR[] = "#b20808"; + const char FILTER_BUTTON_SELECTED_COLOR[] = "#000000"; // TODO: move the colors (and maybe dimensions) to StudioPreferences. } diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp index 05b7c840..2e30e0eb 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp @@ -30,18 +30,20 @@ #include "TimelineItem.h" #include "TreeHeader.h" #include "Ruler.h" -#include "Separator.h" #include "PlayHead.h" #include "RowTree.h" #include "RowMover.h" #include "RowTimeline.h" -#include "Separator.h" #include "TimelineConstants.h" #include "TimelineToolbar.h" #include "SelectionRect.h" #include "RowManager.h" #include "KeyframeManager.h" #include "Keyframe.h" +#include "StudioApp.h" +#include "Core.h" +#include "Doc.h" +#include "Bindings/Qt3DSDMTimelineItemBinding.h" #include <QtWidgets/qcombobox.h> #include <QtWidgets/qgraphicssceneevent.h> @@ -50,106 +52,62 @@ #include <QtWidgets/qgraphicsview.h> #include <QtWidgets/qscrollbar.h> #include <QtWidgets/qmenu.h> +#include <QtWidgets/qaction.h> #include <QtGui/qevent.h> #include <QtCore/qtimer.h> #include <QtCore/qglobal.h> #include <QtCore/qdebug.h> #include <QtWidgets/qaction.h> -TimelineGraphicsScene::TimelineGraphicsScene(QGraphicsView *viewTimelineContent, - TimelineWidget *parent) - : QGraphicsScene (parent) +TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget) + : QGraphicsScene(timelineWidget) , m_layoutRoot(new QGraphicsLinearLayout) - , m_layoutLabels(new QGraphicsLinearLayout(Qt::Vertical)) + , m_layoutTree(new QGraphicsLinearLayout(Qt::Vertical)) , m_layoutTimeline(new QGraphicsLinearLayout(Qt::Vertical)) - , m_separator(new Separator) , m_ruler(new Ruler) , m_playHead(new PlayHead(m_ruler)) , m_selectionRect(new SelectionRect(m_ruler)) , m_rowMover(new RowMover) - , m_widget(parent) - , m_viewTimelineContent(viewTimelineContent) + , m_widgetTimeline(timelineWidget) , m_widgetRoot(new QGraphicsWidget) - , m_rowManager(new RowManager(this, m_layoutLabels, m_layoutTimeline)) + , m_rowManager(new RowManager(this, m_layoutTree, m_layoutTimeline)) , m_keyframeManager(new KeyframeManager(this)) { addItem(m_playHead); addItem(m_selectionRect); addItem(m_rowMover); + addItem(m_widgetRoot); m_rowMover->setVisible(false); - m_rowMover->setRect(0, 0, TimelineConstants::LABELS_MIN_W, TimelineConstants::ROW_H-1); - - // TODO: remove -// m_widgetRoot->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::MinimumExpanding); - addItem(m_widgetRoot); m_layoutRoot->setSpacing(0); m_layoutRoot->setContentsMargins(0, 0, 0, 0); m_layoutRoot->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_widgetRoot->setLayout(m_layoutRoot); - m_layoutLabels->setSpacing(0); - m_layoutLabels->setContentsMargins(0, 0, 0, 0); - m_layoutLabels->setMinimumWidth(TimelineConstants::LABELS_DEFAULT_W); - m_layoutLabels->setMaximumWidth(TimelineConstants::LABELS_DEFAULT_W); - m_layoutLabels->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); + m_layoutTree->setSpacing(0); + m_layoutTree->setContentsMargins(0, 0, 0, 0); + m_layoutTree->setMinimumWidth(TimelineConstants::TREE_BOUND_W); + m_layoutTree->setMaximumWidth(TimelineConstants::TREE_BOUND_W); + m_layoutTree->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); setTimelineScale(m_ruler->timelineScale()); // refresh timeline width m_layoutTimeline->setSpacing(0); m_layoutTimeline->setContentsMargins(0, 0, 0, 0); m_layoutTimeline->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - m_layoutRoot->addItem(m_layoutLabels); - m_layoutRoot->addItem(m_separator); + m_layoutRoot->addItem(m_layoutTree); m_layoutRoot->addItem(m_layoutTimeline); - m_layoutLabels->addItem(new TreeHeader); + m_treeHeader = new TreeHeader; + + m_layoutTree->addItem(m_treeHeader); m_layoutTimeline->addItem(m_ruler); QTimer::singleShot(0, this, [this]() { m_playHead->setPosition(0); + m_widgetTimeline->viewTreeContent()->horizontalScrollBar()->setValue(0); }); - - connect(m_ruler, &Ruler::rulerClicked, [this](const double &posX) { - m_playHead->setPosition(posX); - m_widget->toolbar()->setTime(m_playHead->time()); - }); - - m_sceneRow = m_rowManager->createRow(RowType::Scene); - -// add some test rows - // TODO: remove after connecting the view to the app data model - RowTree *layer1 = m_rowManager->createRow(RowType::Layer, m_sceneRow, tr("layer 1")); - RowTree *layer2 = m_rowManager->createRow(RowType::Layer, m_sceneRow, tr("layer 2")); - - RowTree *obj1 = m_rowManager->createRow(RowType::Object, layer1, tr("Cone")); - RowTree *group1= m_rowManager->createRow(RowType::Group, layer1, tr("group 1")); - RowTree *cam = m_rowManager->createRow(RowType::Camera, layer1, tr("cam 1")); - RowTree *light = m_rowManager->createRow(RowType::Light, layer2); - RowTree *obj2 = m_rowManager->createRow(RowType::Object, layer1, tr("Cube")); - - RowTree *alias = m_rowManager->createRow(RowType::Alias, layer2); - RowTree *comp = m_rowManager->createRow(RowType::Component, layer2); - RowTree *group2= m_rowManager->createRow(RowType::Group, comp, tr("group 2")); - RowTree *obj3 = m_rowManager->createRow(RowType::Object, comp, tr("Sphere")); - RowTree *cam2 = m_rowManager->createRow(RowType::Camera, group2, tr("cam 2")); - RowTree *obj4 = m_rowManager->createRow(RowType::Object, group2, tr("Cylinder")); - RowTree *text = m_rowManager->createRow(RowType::Text, group2); - - // properties - RowTree *prop1 = m_rowManager->getOrCreatePropertyRow(PropertyType::Scale, cam); - RowTree *prop2 = m_rowManager->getOrCreatePropertyRow(PropertyType::Opacity, obj2); - RowTree *prop3 = m_rowManager->getOrCreatePropertyRow(PropertyType::Position, obj3); - RowTree *prop4 = m_rowManager->getOrCreatePropertyRow(PropertyType::Rotation, obj3); - RowTree *prop5 = m_rowManager->getOrCreatePropertyRow(PropertyType::Rotation, obj3); - - // keyframes - m_keyframeManager->insertKeyframe(prop1->rowTimeline(), 5, 7); - m_keyframeManager->insertKeyframe(prop1->rowTimeline(), 3, 52); - m_keyframeManager->insertKeyframe(prop2->rowTimeline(), 12, 34); - m_keyframeManager->insertKeyframe(prop3->rowTimeline(), 4.5, 6); - m_keyframeManager->deselectAllKeyframes(); } void TimelineGraphicsScene::setTimelineScale(int scl) @@ -157,10 +115,10 @@ void TimelineGraphicsScene::setTimelineScale(int scl) m_ruler->setTimelineScale(scl); m_playHead->updatePosition(); - m_layoutTimeline->setMinimumWidth(TimelineConstants::RULER_EDGE_OFFSET * 2 - + m_ruler->duration() * TimelineConstants::RULER_SEC_W * scl); - m_layoutTimeline->setMaximumWidth(TimelineConstants::RULER_EDGE_OFFSET * 2 - + m_ruler->duration() * TimelineConstants::RULER_SEC_W * scl); + double timelineWidth = TimelineConstants::RULER_EDGE_OFFSET * 2 + + m_ruler->duration() * TimelineConstants::RULER_SEC_W * scl; + m_layoutTimeline->setMinimumWidth(timelineWidth); + m_layoutTimeline->setMaximumWidth(timelineWidth); for (int i = 1; i < m_layoutTimeline->count(); i++) static_cast<RowTimeline *>(m_layoutTimeline->itemAt(i)->graphicsItem())->updatePosition(); @@ -168,12 +126,12 @@ void TimelineGraphicsScene::setTimelineScale(int scl) void TimelineGraphicsScene::addNewLayer() { - RowTree *newLayer = m_rowManager->createRow(RowType::Layer, m_sceneRow); - - m_rowManager->selectRow(newLayer); + // TODO: get the update from the data model +// RowTree *newLayer = m_rowManager->createRow(OBJTYPE_LAYER, m_sceneRow); +// m_rowManager->selectRow(newLayer); // scroll to top - m_viewTimelineContent->verticalScrollBar()->setValue(0); + m_widgetTimeline->viewTimelineContent()->verticalScrollBar()->setValue(0); } // TODO: test function, to be removed @@ -188,18 +146,7 @@ void debugPrintRows(RowTree *row) } void TimelineGraphicsScene::deleteSelectedRow() { - // TODO: test code, to be removed -// MainRowLabel *row_i = nullptr; -// for (int i = 1; i < m_layoutLabels->count(); ++i) -// { -// row_i = static_cast<MainRowLabel *>(m_layoutLabels->itemAt(i)->graphicsItem()); -// qDebug().noquote().nospace() << "|" << QString("-").repeated(row_i->depth()) << row_i->label(); -// } -// qDebug() << "------------------------------"; - - debugPrintRows(m_sceneRow); - -// m_rowManager->deleteRow(m_rowManager->selectedRow()); + m_rowManager->deleteRow(m_rowManager->selectedRow()); } void TimelineGraphicsScene::commitMoveRows() @@ -214,14 +161,15 @@ void TimelineGraphicsScene::commitMoveRows() return; } - // TODO: remove -// qDebug() << "sourceIndex=" << sourceIndex << ", targetIndex=" << targetIndex << ", rowSrcDepth=" << rowSrcDepth; + // TODO: remove +// qDebug() << "sourceIndex=" << sourceIndex << ", targetIndex=" << targetIndex +// << ", rowSrcDepth=" << rowSrcDepth; // gather the rows to be moved RowTree *row_i = nullptr; QList<RowTree *> itemsToMove { m_rowMover->sourceRow() }; - for (int i = sourceIndex + 1; i < m_layoutLabels->count();) { - row_i = static_cast<RowTree *>(m_layoutLabels->itemAt(i)->graphicsItem()); + for (int i = sourceIndex + 1; i < m_layoutTree->count();) { + row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem()); // TODO: remove // qDebug() << "i=" << i << ", row_i->depth()=" << row_i->depth(); @@ -229,7 +177,7 @@ void TimelineGraphicsScene::commitMoveRows() if (row_i->depth() <= rowSrcDepth) break; - m_layoutLabels->removeAt(i); + m_layoutTree->removeAt(i); m_layoutTimeline->removeAt(i); itemsToMove.append(row_i); } @@ -245,7 +193,7 @@ void TimelineGraphicsScene::commitMoveRows() for (auto child : qAsConst(itemsToMove)) { ++targetIndex; - m_layoutLabels->insertItem(targetIndex, child); + m_layoutTree->insertItem(targetIndex, child); m_layoutTimeline->insertItem(targetIndex, child->rowTimeline()); } } @@ -256,8 +204,8 @@ void TimelineGraphicsScene::getLastChildRow(RowTree *row, int index, RowTree *ou if (row != nullptr) { RowTree *row_i = nullptr; RowTree *row_i_prev = nullptr; - for (int i = index + 1; i < m_layoutLabels->count() - 1; ++i) { - row_i = static_cast<RowTree *>(m_layoutLabels->itemAt(i)->graphicsItem()); + for (int i = index + 1; i < m_layoutTree->count() - 1; ++i) { + row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem()); if (row_i->depth() <= row->depth()) { outLastChild = row_i_prev; @@ -285,31 +233,44 @@ bool TimelineGraphicsScene::lastRowInAParent(RowTree *rowAtIndex, int index) // not used except in lastRowInAParent() int TimelineGraphicsScene::nextRowDepth(int index) { - if (index < m_layoutLabels->count() - 1) + if (index < m_layoutTree->count() - 1) index ++; - return static_cast<RowTree *>(m_layoutLabels->itemAt(index)->graphicsItem())->depth(); + return static_cast<RowTree *>(m_layoutTree->itemAt(index)->graphicsItem())->depth(); } bool TimelineGraphicsScene::validLayerMove(RowTree *rowAtIndex, RowTree *nextRowAtIndex) { // we don't care about non-layers in this method - if (m_rowMover->sourceRow()->rowType() != RowType::Layer) + if (m_rowMover->sourceRow()->rowType() != OBJTYPE_LAYER) return true; - if (rowAtIndex->rowType() == RowType::Scene) + if (rowAtIndex->rowType() == OBJTYPE_SCENE) return true; - if (rowAtIndex->rowType() == RowType::Layer) + if (rowAtIndex->rowType() == OBJTYPE_LAYER) return rowAtIndex->empty() || !rowAtIndex->expanded(); if (nextRowAtIndex == nullptr || (nextRowAtIndex->depth() <= rowAtIndex->depth() - && nextRowAtIndex->depth() == 2)) + && nextRowAtIndex->depth() == 2)) return true; return false; } +void TimelineGraphicsScene::updateTreeWidth(double treeWidth) +{ + m_treeWidth = treeWidth; + + m_treeHeader->setWidth(treeWidth); + + RowTree *row_i; + for (int i = 1; i < m_layoutTree->count(); ++i) { + row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem()); + row_i->setTreeWidth(treeWidth); + } +} + void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { if (event->button() == Qt::LeftButton) { @@ -321,23 +282,26 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) if (item->type() == TimelineItem::TypePlayHead) item = items(m_pressPos).at(1); - if (item->type() == TimelineItem::TypeSeparator) { - m_separatorPressed = true; - } else if (item->type() == TimelineItem::TypeRuler) { + if (item->type() == TimelineItem::TypeRuler) { m_rulerPressed = true; + double time = m_ruler->distanceToTime(event->scenePos().x() + - m_ruler->durationStartX()) * 1000; + g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(time); + } else if (item->type() == TimelineItem::TypeTreeHeader) { + if (m_treeHeader->handleButtonsClick(m_pressPos) != TreeControlType::None) + m_rowManager->updateFiltering(); } else if (item->type() == TimelineItem::TypeRowTree) { - RowTree *rowLabel = static_cast<RowTree *>(item); - - if (rowLabel->rowType() != RowType::Property) { - if (!rowLabel->handleButtonsClick(event)) { - // dragging layers to reorder + RowTree *rowTree = static_cast<RowTree *>(item); + if (!rowTree->isProperty()) { + m_clickedTreeControlType = rowTree->getClickedControl(m_pressPos); + if (m_clickedTreeControlType != TreeControlType::None) { + m_rowManager->updateFiltering(rowTree); + } else if (!rowTree->locked()) { // dragging layers to reorder int index = event->scenePos().y() / TimelineConstants::ROW_H; m_rowManager->correctIndex(index); - if (rowLabel->rowType() != RowType::Scene - && rowLabel->rowType() != RowType::Property) { - m_rowMover->start(rowLabel, index); - } + if (rowTree->rowType() != OBJTYPE_SCENE && !rowTree->isProperty()) + m_rowMover->start(rowTree, index); } } } else if (item->type() == TimelineItem::TypeRowTimeline) { @@ -361,12 +325,14 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event) m_editedTimelineRow->getClickedControl(m_pressPos); // clicked an empty spot on a timeline row, start selection rect. - if (m_editedTimelineRow->getClickedControl(m_pressPos) == RowTimeline::TypeNone) + if (m_clickedTimelineControlType == TimelineControlType::None) m_selectionRect->start(m_pressPos); } } } else { - if (m_pressPos.x() > m_separator->x() && m_pressPos.y() > TimelineConstants::ROW_H) + m_keyframeManager->deselectAllKeyframes(); + + if (m_pressPos.x() > m_ruler->x() && m_pressPos.y() > TimelineConstants::ROW_H) m_selectionRect->start(m_pressPos); } } @@ -381,24 +347,17 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) m_dragging = true; if (m_rulerPressed) { - m_playHead->setPosition(event->scenePos().x() - m_ruler->pos().x()); - m_widget->toolbar()->setTime(m_playHead->time()); + double time = m_ruler->distanceToTime(event->scenePos().x() - m_ruler->durationStartX()) + * 1000; + g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(time); } else if (m_dragging) { - if (m_separatorPressed) { // resizing labels part - double x = event->scenePos().x() - m_separator->size().width() * .5; - x = qBound(TimelineConstants::LABELS_MIN_W, x, TimelineConstants::LABELS_MAX_W); - m_layoutLabels->setMinimumWidth(x); - m_layoutLabels->setMaximumWidth(x); - m_rowMover->setRect(0, -5, x, 10); - - m_playHead->updatePosition(); - } else if (m_clickedTimelineControlType == RowTimeline::TypeStartHandle) { + if (m_clickedTimelineControlType == TimelineControlType::StartHandle) { // resizing layer timline duration from left m_editedTimelineRow->setStartX(event->scenePos().x() - m_ruler->pos().x()); - } else if (m_clickedTimelineControlType == RowTimeline::TypeEndHandle) { + } else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) { // resizing layer timline duration from right m_editedTimelineRow->setEndX(event->scenePos().x() - m_ruler->pos().x()); - } else if (m_clickedTimelineControlType == RowTimeline::TypeDuration) { + } else if (m_clickedTimelineControlType == TimelineControlType::Duration) { // moving layer timline duration m_editedTimelineRow->moveDurationBy(event->scenePos().x() - m_pressPos.x()); m_pressPos = event->scenePos(); @@ -418,9 +377,9 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) RowTree *lastChildAtIndex; // so far not used if (valid) { // valid row index - rowAtIndex = static_cast<RowTree *>(m_layoutLabels->itemAt(index)->graphicsItem()); - nextRowAtIndex = index > m_layoutLabels->count() - 2 ? nullptr : - static_cast<RowTree *>(m_layoutLabels->itemAt(index + 1)->graphicsItem()); + rowAtIndex = static_cast<RowTree *>(m_layoutTree->itemAt(index)->graphicsItem()); + nextRowAtIndex = index > m_layoutTree->count() - 2 ? nullptr : + static_cast<RowTree *>(m_layoutTree->itemAt(index + 1)->graphicsItem()); if (!rowAtIndex->expanded()) getLastChildRow(rowAtIndex, index, lastChildAtIndex, nextRowAtIndex, index); @@ -429,15 +388,14 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) valid = !rowAtIndex->isDecendentOf(m_rowMover->sourceRow()) // not inserting next to property rows - && !(nextRowAtIndex != nullptr - && nextRowAtIndex->rowType() == RowType::Property) + && !(nextRowAtIndex != nullptr && nextRowAtIndex->isProperty()) // not inserting as a first child of self && !(rowAtIndex == m_rowMover->sourceRow() && !rowAtIndex->empty()) // not inserting non-layer under the scene - && !(m_rowMover->sourceRow()->rowType() != RowType::Layer - && rowAtIndex->rowType() == RowType::Scene) + && !(m_rowMover->sourceRow()->rowType() != OBJTYPE_LAYER + && rowAtIndex->rowType() == OBJTYPE_SCENE) // Layer cases && validLayerMove(rowAtIndex, nextRowAtIndex); @@ -452,14 +410,14 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event) if (rowAtIndex->isContainer() && rowAtIndex->expanded() && rowAtIndex != m_rowMover->sourceRow()) { depth++; // Container: allow insertion as a child - } else if (rowAtIndex->rowType() == RowType::Property) { + } else if (rowAtIndex->isProperty()) { depth--; // Property: prevent insertion as a sibling } depthBasedOnX = qMax(depthBasedOnX, depthNextRow); depth = qBound(3, depth, depthBasedOnX); - if (m_rowMover->sourceRow()->rowType() == RowType::Layer) + if (m_rowMover->sourceRow()->rowType() == OBJTYPE_LAYER) depth = 2; // calc insertion parent @@ -497,25 +455,33 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) if (event->button() == Qt::LeftButton) { QGraphicsItem *item = itemAt(event->scenePos(), QTransform()); - if (item != nullptr && !m_dragging && (item->type() == TimelineItem::TypeRowTree - || item->type() == TimelineItem::TypeRowTimeline)) { - // select row + if (item != nullptr && !m_dragging) { + // select pressed row + RowTree *rowTree = nullptr; if (item->type() == TimelineItem::TypeRowTree) - m_rowManager->selectRow( static_cast<RowTree *>(item) ); + rowTree = static_cast<RowTree *>(item); else if (item->type() == TimelineItem::TypeRowTimeline) - m_rowManager->selectRow( static_cast<RowTimeline *>(item)->rowTree() ); + rowTree = static_cast<RowTimeline *>(item)->rowTree(); + + if (rowTree != nullptr && m_clickedTreeControlType == TreeControlType::None + && !rowTree->locked()) { + m_rowManager->selectRow(rowTree); + } + } else if (m_rowMover->isActive()) { // moving rows (reorder/reparent) if (m_rowMover->insertionParent() != nullptr) // valid row move, commit it commitMoveRows(); + } else if (m_keyframePressed) { + // update keyframe movement (time) to binding + m_keyframeManager->commitMoveSelectedKeyframes(); } // reset mouse drag params m_selectionRect->end(); m_rowMover->end(); - m_separatorPressed = false; m_rulerPressed = false; m_dragging = false; - m_clickedTimelineControlType = RowTimeline::TypeNone; + m_clickedTimelineControlType = TimelineControlType::None; m_keyframePressed = false; m_editedTimelineRow = nullptr; } @@ -559,13 +525,15 @@ void TimelineGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *eve QMenu contextMenu; int index = event->scenePos().y() / TimelineConstants::ROW_H; + RowTree *row = m_rowManager->rowAt(index); - RowTimeline *row = rowManager()->rowTimelineAt(index); + if (row == nullptr) + return; - if (row != nullptr) { // timeline context menu - Keyframe *keyframe = row->getClickedKeyframe(event->scenePos()); - bool propRow = row->rowTree()->rowType() == RowType::Property; - bool hasPropRows = row->rowTree()->hasPropertyChildren(); + if (event->scenePos().x() > TimelineConstants::TREE_BOUND_W) { // timeline context menu + Keyframe *keyframe = row->rowTimeline()->getClickedKeyframe(event->scenePos()); + bool propRow = row->isProperty(); + bool hasPropRows = row->hasPropertyChildren(); bool ctrlPressed = event->modifiers() & Qt::ControlModifier; //TODO: remove @@ -601,11 +569,12 @@ void TimelineGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *eve actionCopySelectedKeyframes ->setEnabled(m_keyframeManager->oneMasterRowSelected()); actionPasteKeyframes ->setEnabled(m_keyframeManager->hasCopiedKeyframes()); actionDeleteSelectedKeyframes->setEnabled(m_keyframeManager->hasSelectedKeyframes()); - actionDeleteRowKeyframes ->setEnabled(!row->keyframes().empty()); + actionDeleteRowKeyframes ->setEnabled(!row->rowTimeline()->keyframes().empty()); // connections connect(actionInsertKeyframe, &QAction::triggered, this, [=]() { - m_keyframeManager->insertKeyframe(row, m_playHead->time(), 0); + row->getBinding()->InsertKeyframe(); + m_keyframeManager->insertKeyframe(row->rowTimeline(), m_playHead->time(), 0, false); }); connect(actionCutSelectedKeyframes, &QAction::triggered, this, [=]() { @@ -618,7 +587,7 @@ void TimelineGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *eve }); connect(actionPasteKeyframes, &QAction::triggered, this, [=]() { - m_keyframeManager->pasteKeyframes(row); + m_keyframeManager->pasteKeyframes(row->rowTimeline()); }); connect(actionDeleteSelectedKeyframes, &QAction::triggered, this, [=]() { @@ -626,10 +595,13 @@ void TimelineGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *eve }); connect(actionDeleteRowKeyframes, &QAction::triggered, this, [=]() { - m_keyframeManager->deleteKeyframes(row); + m_keyframeManager->deleteKeyframes(row->rowTimeline()); }); + } else { // tree context menu + // Mahmoud_TODO: implement tree section context menu } + contextMenu.exec(event->screenPos()); } @@ -649,9 +621,11 @@ bool TimelineGraphicsScene::event(QEvent *event) } } -Ruler *TimelineGraphicsScene::ruler() const { return m_ruler; } -PlayHead *TimelineGraphicsScene::playHead() const { return m_playHead; } -Separator *TimelineGraphicsScene::separator() const { return m_separator; } -RowManager *TimelineGraphicsScene::rowManager() const { return m_rowManager; } -QGraphicsWidget *TimelineGraphicsScene::widgetRoot() const { return m_widgetRoot; } -KeyframeManager *TimelineGraphicsScene::keyframeManager() const { return m_keyframeManager; } +// Getters +Ruler *TimelineGraphicsScene::ruler() const { return m_ruler; } +PlayHead *TimelineGraphicsScene::playHead() const { return m_playHead; } +TreeHeader *TimelineGraphicsScene::treeHeader() const { return m_treeHeader; } +RowManager *TimelineGraphicsScene::rowManager() const { return m_rowManager; } +QGraphicsWidget *TimelineGraphicsScene::widgetRoot() const { return m_widgetRoot; } +KeyframeManager *TimelineGraphicsScene::keyframeManager() const { return m_keyframeManager; } +QGraphicsLinearLayout *TimelineGraphicsScene::layoutTree() const { return m_layoutTree; } diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h index a50e2bbd..09f72db0 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h @@ -32,13 +32,13 @@ #include "TimelineWidget.h" #include "RowTimeline.h" #include "RowTypes.h" +#include "TimelineConstants.h" #include <QtWidgets/qgraphicsscene.h> -class Separator; class Ruler; class PlayHead; -class TimelineItem; +class TreeHeader; class RowTree; class SelectionRect; class RowMover; @@ -54,17 +54,19 @@ class TimelineGraphicsScene : public QGraphicsScene Q_OBJECT public: - explicit TimelineGraphicsScene(QGraphicsView *viewTimelineContent, TimelineWidget *parent); + explicit TimelineGraphicsScene(TimelineWidget *timelineWidget); void setTimelineScale(int scale); void addNewLayer(); void deleteSelectedRow(); Ruler *ruler() const; PlayHead *playHead() const; - Separator *separator() const; RowManager *rowManager() const; QGraphicsWidget *widgetRoot() const; KeyframeManager *keyframeManager() const; + QGraphicsLinearLayout *layoutTree() const; + TreeHeader *treeHeader() const; + void updateTreeWidth(double x); protected: bool event(QEvent *event) override; @@ -87,29 +89,27 @@ private: bool validLayerMove(RowTree *rowAtIndex, RowTree *nextRowAtIndex); QGraphicsLinearLayout *m_layoutRoot; - QGraphicsLinearLayout *m_layoutLabels; + QGraphicsLinearLayout *m_layoutTree; QGraphicsLinearLayout *m_layoutTimeline; - Separator *m_separator; + TreeHeader *m_treeHeader; Ruler *m_ruler; PlayHead *m_playHead; - TimelineWidget *m_widget; + TimelineWidget *m_widgetTimeline; QGraphicsWidget *m_widgetRoot; - QGraphicsView *m_viewTimelineContent; RowMover *m_rowMover = nullptr; - RowTree *m_sceneRow = nullptr; RowTimeline *m_editedTimelineRow = nullptr; SelectionRect *m_selectionRect; RowManager *m_rowManager = nullptr; KeyframeManager *m_keyframeManager = nullptr; QPointF m_pressPos; - bool m_separatorPressed = false; bool m_rulerPressed = false; bool m_keyframePressed = false; bool m_dragging = false; - int m_clickedTimelineControlType = RowTimeline::TypeNone; - + TimelineControlType m_clickedTimelineControlType = TimelineControlType::None; + TreeControlType m_clickedTreeControlType = TreeControlType::None; + double m_treeWidth = TimelineConstants::TREE_DEFAULT_W; }; #endif // TIMELINEGRAPHICSSCENE_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineViewGV.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineSplitter.cpp index 08dc3984..b8c71f26 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineViewGV.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineSplitter.cpp @@ -26,14 +26,27 @@ ** ****************************************************************************/ -#include "TimelineViewGV.h" +#include "TimelineSplitter.h" +#include "TimelineConstants.h" -TimelineViewGV::TimelineViewGV(QWidget *parent) +#include <QtGui/qevent.h> +#include <QtWidgets/qapplication.h> + +TimelineSplitter::TimelineSplitter(QWidget *parent) : QWidget(parent) { - // TODO: to be deleted, not really useful + setFixedWidth(TimelineConstants::SPLITTER_W); + setAttribute(Qt::WA_Hover, true); } -TimelineViewGV::~TimelineViewGV() +void TimelineSplitter::enterEvent(QEvent *event) { + qApp->setOverrideCursor(Qt::SplitHCursor); + QWidget::enterEvent(event); +} +void TimelineSplitter::leaveEvent(QEvent *event) +{ + qApp->changeOverrideCursor(Qt::ArrowCursor); + qApp->restoreOverrideCursor(); + QWidget::leaveEvent(event); } diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineViewGV.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineSplitter.h index 1beedcf4..1be64967 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineViewGV.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineSplitter.h @@ -26,21 +26,23 @@ ** ****************************************************************************/ -#ifndef TIMELINEVIEWGV_H -#define TIMELINEVIEWGV_H +#ifndef TIMELINESPLITTER_H +#define TIMELINESPLITTER_H -#include "TimelineWidget.h" +#include <QtWidgets/qwidget.h> -class TimelineViewGV : public QObject +QT_FORWARD_DECLARE_CLASS(QEvent) + +class TimelineSplitter : public QWidget { Q_OBJECT public: - explicit TimelineViewGV(QWidget *parent = nullptr); - ~TimelineViewGV(); + explicit TimelineSplitter(QWidget *parent = nullptr); -private: - TimelineWidget *m_timelineWidget = nullptr; + protected: + void enterEvent(QEvent *event) override; + void leaveEvent(QEvent *event) override; }; -#endif // TIMELINEVIEWGV_H +#endif // TIMELINESPLITTER_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp index 152f40b0..407946fd 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp @@ -30,27 +30,86 @@ #include "TimelineGraphicsScene.h" #include "TimelineConstants.h" #include "TimelineToolbar.h" +#include "RowManager.h" +#include "KeyframeManager.h" +#include "RowTree.h" #include "PlayHead.h" #include "Ruler.h" -#include "Separator.h" +#include "TimelineSplitter.h" #include "StudioApp.h" #include "Core.h" #include "Doc.h" - -#include <QtWidgets/qgraphicssceneevent.h> +#include "Dispatch.h" +#include "Qt3DSDMStudioSystem.h" +#include "Qt3DSDMSlides.h" +#include "ClientDataModelBridge.h" +#include "Bindings/TimelineTranslationManager.h" +#include "Bindings/ITimelineItemBinding.h" +#include "Bindings/Qt3DSDMTimelineItemBinding.h" +#include "Bindings/Qt3DSDMTimelineItemProperty.h" + +#include <QtGui/qevent.h> #include <QtWidgets/qgraphicslinearlayout.h> #include <QtWidgets/qgraphicsview.h> #include <QtWidgets/qboxlayout.h> #include <QtWidgets/qscrollbar.h> #include <QtWidgets/qslider.h> -#include <QtWidgets/qsplitter.h> #include <QtWidgets/qlabel.h> -class Eventfilter : public QObject { +// Mahmoud_TODO: debug func, to be removed +void printBinding(ITimelineItemBinding *binding, QString padding = " ") +{ + qDebug().noquote().nospace() + << "\x1b[42m \x1b[1m" << __FUNCTION__ + << padding + << binding->GetTimelineItem()->GetName().toQString() + << " (" << static_cast<Qt3DSDMTimelineItemBinding *>(binding)->GetInstance() << ")" + << "\x1b[m"; + + + for (int i = 0; i < binding->GetPropertyCount(); i++) { + ITimelineItemProperty *property = binding->GetProperty(i); + qDebug().noquote().nospace() + << "\x1b[42m \x1b[1m" << __FUNCTION__ + << padding + << "[" << property->GetName().toQString() << "]" + << " (" << static_cast<Qt3DSDMTimelineItemProperty*>(property)->getPropertyHandle() << ")" + << "\x1b[m"; + + for (int j = 0; j < property->GetKeyframeCount(); j++) { + IKeyframe *kf = property->GetKeyframeByIndex(j); + qDebug().noquote().nospace() + << "\x1b[42m \x1b[1m" << __FUNCTION__ + << padding + << " {KF: " << kf->GetTime() << ", selected: " << kf->IsSelected() << "}" + << "\x1b[m"; + } + } + padding = padding.append("-"); + + // create child rows recursively + for (int i = 0; i < binding->GetChildrenCount(); i++) + printBinding(binding->GetChild(i), padding); +} + +// Mahmoud_TODO: debug func, to be removed +void printHandlesMap(std::map<qt3dsdm::Qt3DSDMInstanceHandle, RowTree *> theBindingMap) +{ + for (auto& kv : theBindingMap) + qDebug().noquote().nospace() + << "\x1b[42m \x1b[1m" << __FUNCTION__ + << ", k=" << kv.first + << ", v=" << (kv.second == nullptr ? "--" : kv.second->label()) + << "\x1b[m"; +} + +class Eventfilter : public QObject +{ public: Eventfilter(QObject *parent) : QObject(parent) {} - bool eventFilter(QObject *, QEvent *event) override { + bool eventFilter(QObject *, QEvent *event) override + { if (event->type() == QEvent::Wheel) { event->accept(); return true; @@ -67,48 +126,51 @@ TimelineWidget::TimelineWidget(QWidget *parent) , m_viewTreeContent(new QGraphicsView(this)) , m_viewTimelineHeader(new QGraphicsView(this)) , m_viewTimelineContent(new QGraphicsView(this)) - , m_graphicsScene(new TimelineGraphicsScene(m_viewTimelineContent, this)) { + , m_graphicsScene(new TimelineGraphicsScene(this)) +{ + m_translationManager = new CTimelineTranslationManager(); + setWindowTitle(tr("Timeline", "Title of timeline view")); setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding); - sizePolicy1.setHorizontalStretch(0); - sizePolicy1.setVerticalStretch(0); - sizePolicy1.setHeightForWidth(m_viewTimelineContent->sizePolicy().hasHeightForWidth()); - - m_viewTimelineHeader->setScene(m_graphicsScene); - m_viewTimelineHeader->setFixedHeight(TimelineConstants::ROW_H); - m_viewTimelineHeader->setAlignment(Qt::AlignLeft | Qt::AlignTop); - m_viewTimelineHeader->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_viewTimelineHeader->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_viewTimelineHeader->viewport()->installEventFilter(new Eventfilter(this)); - m_viewTimelineHeader->viewport()->setFocusPolicy(Qt::NoFocus); - - m_viewTimelineContent->setScene(m_graphicsScene); - m_viewTimelineContent->setSizePolicy(sizePolicy1); - m_viewTimelineContent->setAlignment(Qt::AlignLeft | Qt::AlignTop); - m_viewTimelineContent->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); - m_viewTreeHeader->setScene(m_graphicsScene); m_viewTreeHeader->setFixedHeight(TimelineConstants::ROW_H); m_viewTreeHeader->setAlignment(Qt::AlignLeft | Qt::AlignTop); - m_viewTreeHeader->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_viewTreeHeader->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_viewTreeHeader->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_viewTreeHeader->viewport()->installEventFilter(new Eventfilter(this)); m_viewTreeHeader->viewport()->setFocusPolicy(Qt::NoFocus); + m_viewTreeHeader->setFixedWidth(TimelineConstants::TREE_DEFAULT_W); m_viewTreeContent->setScene(m_graphicsScene); m_viewTreeContent->setAlignment(Qt::AlignLeft | Qt::AlignTop); + m_viewTreeContent->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_viewTreeContent->horizontalScrollBar()->hide(); m_viewTreeContent->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - m_viewTreeContent->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_viewTreeContent->setFixedWidth(TimelineConstants::TREE_DEFAULT_W); + + m_viewTimelineHeader->setScene(m_graphicsScene); + m_viewTimelineHeader->setFixedHeight(TimelineConstants::ROW_H); + m_viewTimelineHeader->setAlignment(Qt::AlignLeft | Qt::AlignTop); + m_viewTimelineHeader->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + m_viewTimelineHeader->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_viewTimelineHeader->verticalScrollBar()->hide(); + m_viewTimelineHeader->viewport()->installEventFilter(new Eventfilter(this)); + m_viewTimelineHeader->viewport()->setFocusPolicy(Qt::NoFocus); - setStyleSheet(QStringLiteral("background-color:%1;").arg(TimelineConstants::WIDGET_BG_COLOR)); + m_viewTimelineContent->setScene(m_graphicsScene); + m_viewTimelineContent->setAlignment(Qt::AlignLeft | Qt::AlignTop); + m_viewTimelineContent->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_viewTimelineContent->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_viewTimelineContent->setViewportUpdateMode(QGraphicsView::FullViewportUpdate); auto *layoutTree = new QVBoxLayout; layoutTree->setContentsMargins(QMargins(0, 0, 0, 0)); layoutTree->addWidget(m_viewTreeHeader); layoutTree->addWidget(m_viewTreeContent); + m_splitter = new TimelineSplitter(this); + auto *layoutTimeline = new QVBoxLayout; layoutTimeline->setContentsMargins(QMargins(0, 0, 0, 0)); layoutTimeline->addWidget(m_viewTimelineHeader); @@ -117,35 +179,33 @@ TimelineWidget::TimelineWidget(QWidget *parent) auto *layoutContent = new QHBoxLayout; layoutContent->setContentsMargins(QMargins(0, 0, 0, 10)); layoutContent->addLayout(layoutTree); + layoutContent->addWidget(m_splitter); layoutContent->addLayout(layoutTimeline); - auto *widgetLayout = new QVBoxLayout; - widgetLayout->setContentsMargins(0, 0, 0, 0); - widgetLayout->setSpacing(0); - widgetLayout->addLayout(layoutContent); - widgetLayout->addWidget(m_toolbar); - setLayout(widgetLayout); + auto *layoutRoot = new QVBoxLayout; + layoutRoot->setContentsMargins(0, 0, 0, 0); + layoutRoot->setSpacing(0); + layoutRoot->addLayout(layoutContent); + layoutRoot->addWidget(m_toolbar); + setLayout(layoutRoot); - // connections + // connect graphics scene geometryChanged connect(m_graphicsScene->widgetRoot(), &QGraphicsWidget::geometryChanged, this, [this]() { - // TODO: work in progress - qDebug() << "geometryChanged"; - qDebug() << m_graphicsScene->widgetRoot()->rect(); - m_viewTimelineHeader->setSceneRect(m_graphicsScene->widgetRoot()->rect().adjusted( - m_graphicsScene->ruler()->x(), 0, 0, 0)); + const QRectF rect = m_graphicsScene->widgetRoot()->rect(); - m_viewTimelineContent->setSceneRect(m_graphicsScene->widgetRoot()->rect().adjusted( - m_graphicsScene->ruler()->x(), - TimelineConstants::ROW_H, 0, 0)); + m_viewTreeContent->setSceneRect(QRectF(0, TimelineConstants::ROW_H, + TimelineConstants::TREE_MAX_W, rect.height())); - m_viewTreeContent->setSceneRect(QRectF( - 0, TimelineConstants::ROW_H, - m_graphicsScene->ruler()->x(), 0)); + m_viewTimelineHeader->setSceneRect(QRectF(TimelineConstants::TREE_BOUND_W, 0, + rect.width() - TimelineConstants::TREE_BOUND_W, + TimelineConstants::ROW_H)); - m_graphicsScene->playHead()->setHeight(m_graphicsScene->widgetRoot()->geometry().height()); + m_viewTimelineContent->setSceneRect(QRectF(TimelineConstants::TREE_BOUND_W, + TimelineConstants::ROW_H, + rect.width() - TimelineConstants::TREE_BOUND_W, + rect.height())); - m_viewTreeHeader->setFixedWidth(m_graphicsScene->ruler()->x()); - m_viewTreeContent->setFixedWidth(m_graphicsScene->ruler()->x()); + m_graphicsScene->playHead()->setHeight(m_graphicsScene->widgetRoot()->geometry().height()); }); // connect timeline and ruler horizontalScrollBars @@ -173,20 +233,22 @@ TimelineWidget::TimelineWidget(QWidget *parent) }); connect(m_toolbar, &TimelineToolbar::newLayerTriggered, this, [this]() { - m_graphicsScene->addNewLayer(); + // Mahmoud_TODO: debug code, remove + printHandlesMap(m_handlesMap); +// m_graphicsScene->addNewLayer(); }); connect(m_toolbar, &TimelineToolbar::deleteLayerTriggered, this, [this]() { - m_graphicsScene->deleteSelectedRow(); + // Mahmoud_TODO: debug code, remove + printBinding(m_binding); +// m_graphicsScene->deleteSelectedRow(); }); connect(m_toolbar, &TimelineToolbar::gotoTimeTriggered, this, [this]() { - // TODO: implement + // Mahmoud_TODO: implement }); connect(m_toolbar, &TimelineToolbar::firstFrameTriggered, this, [this]() { - m_graphicsScene->playHead()->setTime(0); - m_toolbar->setTime(0); g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(0); }); @@ -199,15 +261,259 @@ TimelineWidget::TimelineWidget(QWidget *parent) }); connect(m_toolbar, &TimelineToolbar::lastFrameTriggered, this, [this]() { - double dur = m_graphicsScene->ruler()->duration(); - m_graphicsScene->playHead()->setTime(dur); - m_toolbar->setTime(dur); + double dur = m_graphicsScene->ruler()->duration() * 1000; g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(dur); }); connect(m_toolbar, &TimelineToolbar::timelineScaleChanged, this, [this](int scale) { m_graphicsScene->setTimelineScale(scale); }); + + // data model listeners + g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this); + g_StudioApp.GetCore()->GetDispatch()->AddClientPlayChangeListener(this); +} + +void TimelineWidget::OnNewPresentation() +{ + // Register callbacks + qt3dsdm::IStudioFullSystemSignalProvider *theSignalProvider = + g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetFullSystemSignalProvider(); + + m_connections.push_back(theSignalProvider->ConnectActiveSlide( + std::bind(&TimelineWidget::OnActiveSlide, this, std::placeholders::_1, + std::placeholders::_2, std::placeholders::_3))); + + CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch(); + + m_connections.push_back(theDispatch->ConnectSelectionChange( + std::bind(&TimelineWidget::OnSelectionChange, this, std::placeholders::_1))); + + // object created/deleted + m_connections.push_back(theSignalProvider->ConnectInstanceCreated( + std::bind(&TimelineWidget::OnAssetCreated, this, std::placeholders::_1))); + m_connections.push_back(theSignalProvider->ConnectInstanceDeleted( + std::bind(&TimelineWidget::OnAssetDeleted, this, std::placeholders::_1))); + + // animation created/deleted + m_connections.push_back(theSignalProvider->ConnectAnimationCreated( + std::bind(&TimelineWidget::OnAnimationCreated, this, + std::placeholders::_2, std::placeholders::_3))); + m_connections.push_back(theSignalProvider->ConnectAnimationDeleted( + std::bind(&TimelineWidget::OnAnimationDeleted, this, + std::placeholders::_2, std::placeholders::_3))); + + // action created/deleted + m_connections.push_back(theSignalProvider->ConnectActionCreated( + std::bind(&TimelineWidget::OnActionEvent, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); + m_connections.push_back(theSignalProvider->ConnectActionDeleted( + std::bind(&TimelineWidget::OnActionEvent, this, + std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))); +} + +void TimelineWidget::OnClosingPresentation() +{ + m_connections.clear(); +} + +void TimelineWidget::OnTimeChanged(long inTime) +{ + m_graphicsScene->playHead()->setTime(inTime * .001); + m_toolbar->setTime(inTime); +} + +void TimelineWidget::OnActiveSlide(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int inIndex, + const qt3dsdm::Qt3DSDMSlideHandle &inSlide) +{ + Q_UNUSED(inMaster); + Q_UNUSED(inIndex); + + if (m_activeSlide == inSlide) + return; + + m_translationManager->Clear(); + m_activeSlide = inSlide; + + auto *theSlideSystem = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetSlideSystem(); + auto theSlideInstance = theSlideSystem->GetSlideInstance(inSlide); + + m_binding = static_cast<Qt3DSDMTimelineItemBinding *>( + m_translationManager->GetOrCreate(theSlideInstance)); + + m_graphicsScene->rowManager()->recreateRowsFromBinding(m_binding); + m_handlesMap.clear(); + insertToHandlesMapRecursive(m_binding); +} + +void TimelineWidget::insertToHandlesMapRecursive(Qt3DSDMTimelineItemBinding *binding) +{ + if (binding->GetObjectType() != OBJTYPE_MATERIAL) { + m_handlesMap.insert(std::make_pair(binding->GetInstance(), binding->getRowTree())); + + for (int i = 0; i < binding->GetChildrenCount(); i++) { + insertToHandlesMapRecursive( + static_cast<Qt3DSDMTimelineItemBinding *>(binding->GetChild(i))); + } + } +} + +void TimelineWidget::OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable) +{ + qt3dsdm::TInstanceHandleList theInstances = inNewSelectable.GetSelectedInstances(); + for (size_t idx = 0, end = theInstances.size(); idx < end; ++idx) { + qt3dsdm::Qt3DSDMInstanceHandle theInstance(theInstances[idx]); + if (g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->IsInstance(theInstance)) { + // Mahmoud_TODO: remove debug + qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ + << theInstance + << "\x1b[m"; + Qt3DSDMTimelineItemBinding *selectedBinding = getBindingForHandle(theInstance, + m_binding); + m_graphicsScene->rowManager()->selectRow(selectedBinding->getRowTree()); + } + } + + // Mahmoud_TODO: Expand the tree so the selection is visible +} + +void TimelineWidget::OnAssetCreated(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + CClientDataModelBridge *theDataModelBridge = g_StudioApp.GetCore()->GetDoc() + ->GetStudioSystem()->GetClientDataModelBridge(); + + if (theDataModelBridge->IsSceneGraphInstance(inInstance)) { + Qt3DSDMTimelineItemBinding *binding = getBindingForHandle(inInstance, m_binding); + Qt3DSDMTimelineItemBinding *bindingParent = getBindingForHandle(theDataModelBridge + ->GetParentInstance(inInstance), m_binding); + // Mahmoud_TODO: remove debug + qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ + << ", binding=" << binding->GetName().toQString() + << ", bindingParent=" << bindingParent->GetName().toQString() + << "\x1b[m"; + RowTree *newRow = m_graphicsScene->rowManager() + ->createRowFromBinding(binding, bindingParent->getRowTree()); + + m_handlesMap.insert(std::make_pair(inInstance, newRow)); + } +} + +void TimelineWidget::OnAssetDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance) +{ + THandleMap::const_iterator it = m_handlesMap.find(inInstance); + + if (it != m_handlesMap.end()) { // scene object exists + m_graphicsScene->rowManager()->deleteRow(it->second); + m_handlesMap.erase(it); + } +} + +void TimelineWidget::OnAnimationCreated(qt3dsdm::Qt3DSDMInstanceHandle parentInstance, + qt3dsdm::Qt3DSDMPropertyHandle property) +{ + Qt3DSDMTimelineItemBinding *binding = getBindingForHandle(parentInstance, m_binding); + ITimelineItemProperty *propBinding = binding->GetPropertyBinding(property); + + // create the binding if doesn't exist + if (propBinding == nullptr) { + propBinding = binding->GetOrCreatePropertyBinding(property); + + // create the property UI row + RowTree *propRow = m_graphicsScene->rowManager() + ->getOrCreatePropertyRow(binding->getRowTree(), propBinding->GetName().toQString()); + + // connect the row and binding + propBinding->setRowTree(propRow); + propRow->setPropBinding(propBinding); + + // add keyframes + for (int i = 0; i < propBinding->GetKeyframeCount(); i++) { + IKeyframe *kf = propBinding->GetKeyframeByIndex(i); + m_graphicsScene->keyframeManager()->insertKeyframe(propRow->rowTimeline(), + static_cast<double>(kf->GetTime()) * .001, 0, false); + } + + propRow->update(); + } + + // make sure the property rows are in the same order as in the binding + m_graphicsScene->rowManager()->reorderPropertiesFromBinding(binding); +} + +void TimelineWidget::OnAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentInstance, + qt3dsdm::Qt3DSDMPropertyHandle property) +{ + Qt3DSDMTimelineItemBinding *binding = getBindingForHandle(parentInstance, m_binding); + ITimelineItemProperty *propBinding = binding->GetPropertyBinding(property); + + if (propBinding != nullptr) { + m_graphicsScene->rowManager()->deleteRow(propBinding->getRowTree()); + + if (binding) + binding->RemovePropertyRow(property); + } +} + +void TimelineWidget::OnActionEvent(qt3dsdm::Qt3DSDMActionHandle inAction, + qt3dsdm::Qt3DSDMSlideHandle inSlide, + qt3dsdm::Qt3DSDMInstanceHandle inOwner) +{ + Q_UNUSED(inAction); + Q_UNUSED(inSlide); + Q_UNUSED(inOwner); + + // Mahmoud_TODO: implement + qDebug() << "\x1b[42m \x1b[1m" << __FUNCTION__ << "\x1b[m"; +} + +Qt3DSDMTimelineItemBinding *TimelineWidget::getBindingForHandle(int handle, + Qt3DSDMTimelineItemBinding *binding) const +{ + if (binding->GetInstance().GetHandleValue() == handle) + return binding; + + for (int i = 0; i < binding->GetChildrenCount(); i++) { + Qt3DSDMTimelineItemBinding *b = getBindingForHandle(handle, + static_cast<Qt3DSDMTimelineItemBinding *>(binding->GetChild(i))); + + if (b != nullptr) + return b; + } + + return nullptr; +} + +void TimelineWidget::mousePressEvent(QMouseEvent *event) +{ + if (childAt(event->pos()) == m_splitter) + m_splitterPressed = true; +} + +void TimelineWidget::mouseMoveEvent(QMouseEvent *event) +{ + if (m_splitterPressed) { + double treeWidth = event->pos().x() - m_splitter->size().width() * .5; + treeWidth = qBound(TimelineConstants::TREE_MIN_W, treeWidth, TimelineConstants::TREE_MAX_W); + + m_viewTreeHeader->setFixedWidth(treeWidth); + m_viewTreeContent->setFixedWidth(treeWidth); + m_graphicsScene->updateTreeWidth(treeWidth); + } +} + +void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) +{ + m_splitterPressed = false; +} + +QGraphicsView *TimelineWidget::viewTimelineContent() const +{ + return m_viewTimelineContent; +} + +QGraphicsView *TimelineWidget::viewTreeContent() const +{ + return m_viewTreeContent; } TimelineToolbar *TimelineWidget::toolbar() const diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h index 6ed3fe87..0ae48cd0 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h @@ -30,13 +30,26 @@ #define TIMELINEWIDGET_H #include <QtWidgets/qwidget.h> +#include "DispatchListeners.h" +#include "ObjectListModel.h" +#include "Qt3DSDMHandles.h" +#include "Qt3DSDMSignals.h" +#include "SelectedValueImpl.h" +#include "TimelineObjectModel.h" -class TimelineGraphicsScene; +class RowTree; class TimelineToolbar; +class TimelineSplitter; +class TimelineGraphicsScene; +class CTimelineTranslationManager; +class Qt3DSDMTimelineItemBinding; +QT_FORWARD_DECLARE_CLASS(QMouseEvent) QT_FORWARD_DECLARE_CLASS(QGraphicsView) -class TimelineWidget : public QWidget +class TimelineWidget : public QWidget, + public CPresentationChangeListener, + public CClientPlayChangeListener { Q_OBJECT @@ -44,14 +57,57 @@ public: explicit TimelineWidget(QWidget *parent = nullptr); TimelineToolbar *toolbar() const; + QGraphicsView *viewTimelineContent() const; + QGraphicsView *viewTreeContent() const; + + // Presentation Change Listener + void OnNewPresentation() override; + void OnClosingPresentation() override; + void OnSelectionChange(Q3DStudio::SSelectedValue inNewSelectable); + + //CClientPlayChangeListener + void OnTimeChanged(long inTime) override; + +protected: + // DataModel callbacks + virtual void OnActiveSlide(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int inIndex, + const qt3dsdm::Qt3DSDMSlideHandle &inSlide); + void OnAssetCreated(qt3dsdm::Qt3DSDMInstanceHandle inInstance); + void OnAssetDeleted(qt3dsdm::Qt3DSDMInstanceHandle inInstance); + void OnAnimationCreated(qt3dsdm::Qt3DSDMInstanceHandle parentInstance, + qt3dsdm::Qt3DSDMPropertyHandle property); + void OnAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentInstance, + qt3dsdm::Qt3DSDMPropertyHandle property); + void OnActionEvent(qt3dsdm::Qt3DSDMActionHandle inAction, qt3dsdm::Qt3DSDMSlideHandle inSlide, + qt3dsdm::Qt3DSDMInstanceHandle inOwner); + + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; private: + typedef std::map<qt3dsdm::Qt3DSDMInstanceHandle, RowTree *> THandleMap; + + Qt3DSDMTimelineItemBinding *getBindingForHandle(int handle, + Qt3DSDMTimelineItemBinding *binding) const; + void insertToHandlesMapRecursive(Qt3DSDMTimelineItemBinding *binding); QGraphicsView *m_viewTreeHeader = nullptr; QGraphicsView *m_viewTreeContent = nullptr; QGraphicsView *m_viewTimelineHeader = nullptr; QGraphicsView *m_viewTimelineContent = nullptr; TimelineToolbar *m_toolbar = nullptr; TimelineGraphicsScene *m_graphicsScene; + TimelineSplitter *m_splitter = nullptr; + CTimelineTranslationManager *m_translationManager = nullptr; + TimelineObjectModel *m_objectListModel = nullptr; + FlatObjectListModel *m_model = nullptr; + Qt3DSDMTimelineItemBinding *m_binding; + bool m_splitterPressed = false; + + // data model connection + std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>> m_connections; + qt3dsdm::Qt3DSDMSlideHandle m_activeSlide; + THandleMap m_handlesMap; }; #endif // TIMELINEWIDGET_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp index e3bda369..95057c83 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp @@ -72,13 +72,9 @@ void PlayHead::setTime(double time) void PlayHead::setPosition(double posX) { - if (posX < TimelineConstants::RULER_EDGE_OFFSET) { - posX = TimelineConstants::RULER_EDGE_OFFSET; - } else if (posX > m_ruler->duration() * TimelineConstants::RULER_SEC_W - * m_ruler->timelineScale() + TimelineConstants::RULER_EDGE_OFFSET) { - posX = m_ruler->duration() * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale() - + TimelineConstants::RULER_EDGE_OFFSET; - } + posX = qBound(TimelineConstants::RULER_EDGE_OFFSET, posX, m_ruler->duration() + * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale() + + TimelineConstants::RULER_EDGE_OFFSET); setX(m_ruler->x() + posX); m_time = (posX - TimelineConstants::RULER_EDGE_OFFSET) diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp index ae2fba7c..ac04e4bf 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp @@ -35,28 +35,38 @@ #include <QtGui/qpainter.h> #include <QtWidgets/qgraphicssceneevent.h> -RowTimeline::RowTimeline(Ruler *ruler) +RowTimeline::RowTimeline() : InteractiveTimelineItem() - , m_ruler(ruler) { } +RowTimeline::~RowTimeline() +{ + // remove keyframes + if (!m_keyframes.empty()) { + if (m_isProperty) // non-property rows use the same keyframes from property rows. + qDeleteAll(m_keyframes); + + m_keyframes.clear(); + } +} + void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { // Background QColor bgColor; - if (m_state == Selected) + if (m_rowTree->isProperty()) + bgColor = TimelineConstants::ROW_COLOR_NORMAL_PROP; + else if (m_state == Selected) bgColor = TimelineConstants::ROW_COLOR_SELECTED; - else if (m_state == Hovered) + else if (m_state == Hovered && !m_rowTree->m_locked) bgColor = TimelineConstants::ROW_COLOR_OVER; - else if (m_rowTree->rowType() == RowType::Property) - bgColor = TimelineConstants::ROW_COLOR_NORMAL_PROP; else bgColor = TimelineConstants::ROW_COLOR_NORMAL; - painter->fillRect(QRect(0, 0, size().width(), size().height() - 1), bgColor); + painter->fillRect(QRect(0, 0, 10000, size().height() - 1), bgColor); // Duration - if (m_rowTree->rowType() != RowType::Property) { + if (!m_rowTree->isProperty() && m_rowTree->rowType() != OBJTYPE_SCENE) { painter->save(); // fully outside ancestors' limits, draw fully hashed @@ -121,7 +131,7 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio painter->drawPixmap(timeToX(keyframe->time) - 8.5, 2, keyframe->selected ? pixKeyframeMasterSelected : pixKeyframeMasterNormal); } - } else if (m_rowTree->rowType() == RowType::Property) { + } else if (m_rowTree->isProperty()) { static const QPixmap pixKeyframePropertyNormal = QPixmap(":/images/Keyframe-Property-Normal.png"); static const QPixmap pixKeyframePropertySelected @@ -171,7 +181,7 @@ QList<Keyframe *> RowTimeline::getKeyframesInRange(const double left, const doub if (m_rowTree->hasPropertyChildren()) { const auto childRows = m_rowTree->childRows(); for (auto child : childRows) { - if (child->rowType() == RowType::Property) + if (child->isProperty()) keyframes.append(child->rowTimeline()->m_keyframes); } } else { @@ -228,23 +238,23 @@ void RowTimeline::updateKeyframes() } } -int RowTimeline::getClickedControl(const QPointF &scenePos) +TimelineControlType RowTimeline::getClickedControl(const QPointF &scenePos) const { - if (m_rowTree->rowType() == RowType::Property) - return TypeNone; + if (m_rowTree->isProperty()) + return TimelineControlType::None; QPointF p = mapFromScene(scenePos.x(), scenePos.y()); if (p.x() > m_startX - TimelineConstants::DURATION_HANDLE_W * .5 && p.x() < m_startX + TimelineConstants::DURATION_HANDLE_W * .5) { - return TypeStartHandle; + return TimelineControlType::StartHandle; } else if (p.x() > m_endX - TimelineConstants::DURATION_HANDLE_W * .5 && p.x() < m_endX + TimelineConstants::DURATION_HANDLE_W * .5) { - return TypeEndHandle; - } else if (p.x() > m_startX && p.x() < m_endX) { - return TypeDuration; + return TimelineControlType::EndHandle; + } else if (p.x() > m_startX && p.x() < m_endX && !rowTree()->locked()) { + return TimelineControlType::Duration; } - return TypeNone; + return TimelineControlType::None; } // move the duration area (start/end x) @@ -258,8 +268,8 @@ void RowTimeline::moveDurationBy(double dx) if (m_startX < TimelineConstants::RULER_EDGE_OFFSET) { m_startX = TimelineConstants::RULER_EDGE_OFFSET; m_endX = m_startX + dur; - } else if (m_endX > timeToX(m_ruler->duration())) { - m_endX = timeToX(m_ruler->duration()); + } else if (m_endX > timeToX(rowTree()->m_scene->ruler()->duration())) { + m_endX = timeToX(rowTree()->m_scene->ruler()->duration()); m_startX = m_endX - dur; } @@ -280,15 +290,15 @@ void RowTimeline::moveDurationBy(double dx) // convert time values to x double RowTimeline::timeToX(double time) { - return TimelineConstants::RULER_EDGE_OFFSET - + time * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale(); + return TimelineConstants::RULER_EDGE_OFFSET + time * TimelineConstants::RULER_SEC_W + * rowTree()->m_scene->ruler()->timelineScale(); } // convert x values to time double RowTimeline::xToTime(double xPos) { return (xPos - TimelineConstants::RULER_EDGE_OFFSET) - / (TimelineConstants::RULER_SEC_W * m_ruler->timelineScale()); + / (TimelineConstants::RULER_SEC_W * rowTree()->m_scene->ruler()->timelineScale()); } // called after timeline scale is changed to update duration star/end positions @@ -309,7 +319,7 @@ void RowTimeline::setStartX(double startX) m_startX = startX; m_startTime = xToTime(startX); - if (m_rowTree->parentRow() == nullptr) + if (m_rowTree->parentRow() == nullptr || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE) m_minStartX = m_startX; updateChildrenMinStartXRecursive(m_rowTree); @@ -321,13 +331,13 @@ void RowTimeline::setEndX(double endX) { if (endX < m_startX + 1) endX = m_startX + 1; - else if (endX > timeToX(m_ruler->duration())) - endX = timeToX(m_ruler->duration()); + else if (endX > timeToX(rowTree()->m_scene->ruler()->duration())) + endX = timeToX(rowTree()->m_scene->ruler()->duration()); m_endX = endX; m_endTime = xToTime(endX); - if (m_rowTree->parentRow() == nullptr) + if (m_rowTree->parentRow() == nullptr || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE) m_maxEndX = m_endX; updateChildrenMaxEndXRecursive(m_rowTree); @@ -367,7 +377,7 @@ void RowTimeline::setStartTime(double startTime) m_startTime = startTime; m_startX = timeToX(startTime); - if (m_rowTree->parentRow() == nullptr) + if (m_rowTree->parentRow() == nullptr || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE) m_minStartX = m_startX; updateChildrenMinStartXRecursive(m_rowTree); @@ -379,7 +389,7 @@ void RowTimeline::setEndTime(double endTime) m_endTime = endTime; m_endX = timeToX(endTime); - if (m_rowTree->parentRow() == nullptr) + if (m_rowTree->parentRow() == nullptr || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE) m_maxEndX = m_endX; updateChildrenMaxEndXRecursive(m_rowTree); diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h index 50b95838..bcfe8e96 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h @@ -30,9 +30,9 @@ #define ROWTIMELINE_H #include "InteractiveTimelineItem.h" +#include "RowTypes.h" class RowTree; -class Ruler; struct Keyframe; class RowTimeline : public InteractiveTimelineItem @@ -40,15 +40,8 @@ class RowTimeline : public InteractiveTimelineItem Q_OBJECT public: - enum ControlType { - TypeNone, - TypeKeyFrame, - TypeDuration, - TypeStartHandle, - TypeEndHandle - }; - - explicit RowTimeline(Ruler *ruler); + explicit RowTimeline(); + ~RowTimeline(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -64,7 +57,7 @@ public: void updateKeyframes(); void insertKeyframe(Keyframe *keyframe); void removeKeyframe(Keyframe *keyframe); - int getClickedControl(const QPointF &scenePos); + TimelineControlType getClickedControl(const QPointF &scenePos) const; double getStartTime() const; double getEndTime() const; int type() const; @@ -81,13 +74,13 @@ private: double xToTime(double xPos); RowTree *m_rowTree; - Ruler *m_ruler; - double m_startTime; - double m_endTime; - double m_startX; - double m_endX; - double m_minStartX; - double m_maxEndX; + double m_startTime = 0; + double m_endTime = 0; + double m_startX = 0; + double m_endX = 0; + double m_minStartX = 0; + double m_maxEndX = 0; + bool m_isProperty = false; // used in the destructor QList<Keyframe *> m_keyframes; friend class RowTree; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp index ef6b67ea..12888471 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp @@ -28,32 +28,56 @@ #include "RowTree.h" #include "RowTimeline.h" +#include "RowManager.h" #include "TimelineConstants.h" +#include "StudioObjectTypes.h" +#include "Bindings/ITimelineItemBinding.h" #include <QtGui/qpainter.h> +#include <QtWidgets/qgraphicslinearlayout.h> #include <QtWidgets/qgraphicssceneevent.h> -RowTree::RowTree(Ruler *ruler, RowType rowType, const QString &label) +// object row constructor +RowTree::RowTree(TimelineGraphicsScene *timelineScene, EStudioObjectType rowType, + const QString &label) : InteractiveTimelineItem() - , m_rowTimeline(new RowTimeline(ruler)) + , m_rowTimeline(new RowTimeline()) { + m_scene = timelineScene; m_rowType = rowType; m_label = label; setTimelineRow(m_rowTimeline); m_rowTimeline->setRowTree(this); + + if (m_rowType == OBJTYPE_MATERIAL) + m_isProperty = true; +} + +RowTree::~RowTree() +{ + delete m_rowTimeline; // this will also delete the keyframes +} + +ITimelineItemBinding *RowTree::getBinding() const +{ + return m_binding; } -RowTree::RowTree(Ruler *ruler, PropertyType propType) +// property row constructor +RowTree::RowTree(TimelineGraphicsScene *timelineScene, const QString &propType) : InteractiveTimelineItem() - , m_rowTimeline(new RowTimeline(ruler)) + , m_rowTimeline(new RowTimeline()) { - m_rowType = RowType::Property; + m_scene = timelineScene; + m_label = propType; m_propertyType = propType; - updatePropertyLabel(); setTimelineRow(m_rowTimeline); m_rowTimeline->setRowTree(this); + + m_isProperty = true; + m_rowTimeline->m_isProperty = true; } void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) @@ -62,20 +86,20 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q // update button bounds rects m_rectArrow .setRect(offset, size().height() * .5 - 8, 16, 16); - m_rectShy .setRect(size().width() - 16 * 3.3, size().height() * .5 - 8, 16, 16); - m_rectVisible.setRect(size().width() - 16 * 2.2, size().height() * .5 - 8, 16, 16); - m_rectLocked .setRect(size().width() - 16 * 1.1, size().height() * .5 - 8, 16, 16); + m_rectShy .setRect(m_treeWidth - 16 * 3.3, size().height() * .5 - 8, 16, 16); + m_rectVisible.setRect(m_treeWidth - 16 * 2.2, size().height() * .5 - 8, 16, 16); + m_rectLocked .setRect(m_treeWidth - 16 * 1.1, size().height() * .5 - 8, 16, 16); // Background QColor bgColor; if (m_moveSource) bgColor = TimelineConstants::ROW_COLOR_MOVE_SRC; + else if (m_isProperty) + bgColor = TimelineConstants::ROW_COLOR_NORMAL_PROP; else if (m_state == Selected) bgColor = TimelineConstants::ROW_COLOR_SELECTED; - else if (m_state == Hovered) + else if (m_state == Hovered && !m_locked) bgColor = TimelineConstants::ROW_COLOR_OVER; - else if (m_rowType == RowType::Property) - bgColor = TimelineConstants::ROW_COLOR_NORMAL_PROP; else bgColor = TimelineConstants::ROW_COLOR_NORMAL; @@ -93,84 +117,101 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q painter->drawPixmap(m_rectArrow, m_expanded ? pixArrowDown : pixArrow); // Row type icon - static const QPixmap pixScene = QPixmap(":/images/Objects-Scene-Normal.png"); - static const QPixmap pixLayer = QPixmap(":/images/Asset-Layer-Normal.png"); - static const QPixmap pixObject = QPixmap(":/images/Asset-Cube-Normal.png"); - static const QPixmap pixLight = QPixmap(":/images/Asset-Light-Normal.png"); - static const QPixmap pixCamera = QPixmap(":/images/Asset-Camera-Normal.png"); - static const QPixmap pixText = QPixmap(":/images/Asset-Text-Normal.png"); - static const QPixmap pixAlias = QPixmap(":/images/Asset-Alias-Normal.png"); - static const QPixmap pixGroup = QPixmap(":/images/Asset-Group-Normal.png"); - static const QPixmap pixComponent = QPixmap(":/images/Asset-Component-Normal.png"); - static const QPixmap pixProperty = QPixmap(":/images/Objects-Property-Normal.png"); + static const QPixmap pixSceneNormal = QPixmap(":/images/Objects-Scene-Normal.png"); + static const QPixmap pixLayerNormal = QPixmap(":/images/Objects-Layer-Normal.png"); + static const QPixmap pixObjectNormal = QPixmap(":/images/Objects-Model-Normal.png"); + static const QPixmap pixLightNormal = QPixmap(":/images/Objects-Light-Normal.png"); + static const QPixmap pixCameraNormal = QPixmap(":/images/Objects-Camera-Normal.png"); + static const QPixmap pixTextNormal = QPixmap(":/images/Objects-Text-Normal.png"); + static const QPixmap pixAliasNormal = QPixmap(":/images/Objects-Alias-Normal.png"); + static const QPixmap pixGroupNormal = QPixmap(":/images/Objects-Group-Normal.png"); + static const QPixmap pixComponentNormal = QPixmap(":/images/Objects-Component-Normal.png"); + static const QPixmap pixMaterialNormal = QPixmap(":/images/Objects-Material-Normal.png"); + static const QPixmap pixPropertyNormal = QPixmap(":/images/Objects-Property-Normal.png"); + + static const QPixmap pixSceneDisabled = QPixmap(":/images/Objects-Scene-Disabled.png"); + static const QPixmap pixLayerDisabled = QPixmap(":/images/Objects-Layer-Disabled.png"); + static const QPixmap pixObjectDisabled = QPixmap(":/images/Objects-Model-Disabled.png"); + static const QPixmap pixLightDisabled = QPixmap(":/images/Objects-Light-Disabled.png"); + static const QPixmap pixCameraDisabled = QPixmap(":/images/Objects-Camera-Disabled.png"); + static const QPixmap pixTextDisabled = QPixmap(":/images/Objects-Text-Disabled.png"); + static const QPixmap pixAliasDisabled = QPixmap(":/images/Objects-Alias-Disabled.png"); + static const QPixmap pixGroupDisabled = QPixmap(":/images/Objects-Group-Disabled.png"); + static const QPixmap pixComponentDisabled = QPixmap(":/images/Objects-Component-Disabled.png"); + static const QPixmap pixMaterialDisabled = QPixmap(":/images/Objects-Material-Disabled.png"); + static const QPixmap pixPropertyDisabled = QPixmap(":/images/Objects-Property-Disabled.png"); QPixmap pixRowType; QString rowLabel; switch (m_rowType) { - case RowType::Scene: - pixRowType = pixScene; + case OBJTYPE_SCENE: + pixRowType = m_locked ? pixSceneDisabled : pixSceneNormal; rowLabel = tr("Scene"); break; - case RowType::Layer: - pixRowType = pixLayer; + case OBJTYPE_LAYER: + pixRowType = m_locked ? pixLayerDisabled : pixLayerNormal; rowLabel = tr("Layer"); break; - case RowType::Object: - pixRowType = pixObject; + case OBJTYPE_MODEL: + pixRowType = m_locked ? pixObjectDisabled : pixObjectNormal; rowLabel = tr("Object"); break; - case RowType::Light: - pixRowType = pixLight; + case OBJTYPE_LIGHT: + pixRowType = m_locked ? pixLightDisabled : pixLightNormal; rowLabel = tr("Light"); break; - case RowType::Camera: - pixRowType = pixCamera; + case OBJTYPE_CAMERA: + pixRowType = m_locked ? pixCameraDisabled : pixCameraNormal; rowLabel = tr("Camera"); break; - case RowType::Text: - pixRowType = pixText; + case OBJTYPE_TEXT: + pixRowType = m_locked ? pixTextDisabled : pixTextNormal; rowLabel = tr("Text"); break; - case RowType::Alias: - pixRowType = pixAlias; + case OBJTYPE_ALIAS: + pixRowType = m_locked ? pixAliasDisabled : pixAliasNormal; rowLabel = tr("Alias"); break; - case RowType::Group: - pixRowType = pixGroup; + case OBJTYPE_GROUP: + pixRowType = m_locked ? pixGroupDisabled : pixGroupNormal; rowLabel = tr("Group"); break; - case RowType::Component: - pixRowType = pixComponent; + case OBJTYPE_COMPONENT: + pixRowType = m_locked ? pixComponentDisabled : pixComponentNormal; rowLabel = tr("Component"); break; - case RowType::Property: - pixRowType = pixProperty; - rowLabel = tr("Property"); + case OBJTYPE_MATERIAL: + pixRowType = m_locked ? pixMaterialDisabled : pixMaterialNormal; + rowLabel = tr("Default"); break; default: - pixRowType = pixLayer; - rowLabel = tr("Layer"); + break; } - if (m_label == 0) + if (m_isProperty && m_rowType != OBJTYPE_MATERIAL) + pixRowType = m_locked ? pixPropertyDisabled : pixPropertyNormal; + + if (m_label.isEmpty()) m_label = rowLabel; y = (size().height() - 16) * .5; + painter->drawPixmap(offset + 15, y, 16, 16, pixRowType); // Label - painter->setPen(QColor(TimelineConstants::ROW_TEXT_COLOR)); + painter->setPen(QColor(m_locked ? TimelineConstants::ROW_TEXT_COLOR_DISABLED + : TimelineConstants::ROW_TEXT_COLOR)); painter->drawText(offset + 35, size().height() * .5 + 4, tr("%1").arg(m_label)); // Shy, eye, lock BG (to hide the label when overlapping) - painter->fillRect(QRect(size().width() - 53, 0, 53, size().height() - 1), bgColor); + painter->fillRect(QRect(m_treeWidth - 53, 0, 53, size().height() - 1), bgColor); // Shy, eye, lock static const QPixmap pixEmpty = QPixmap(":/images/Toggle-Empty.png"); static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png"); static const QPixmap pixHide = QPixmap(":/images/Toggle-HideShow.png"); static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png"); - if (m_rowType != RowType::Property) { + if (!m_isProperty && m_rowType != OBJTYPE_SCENE) { painter->drawPixmap(m_rectShy , m_shy ? pixShy : pixEmpty); painter->drawPixmap(m_rectVisible, m_visible ? pixHide : pixEmpty); painter->drawPixmap(m_rectLocked , m_locked ? pixLock : pixEmpty); @@ -179,115 +220,29 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q // Candidate parent of a dragged row if (m_moveTarget) { painter->setPen(QPen(QColor(TimelineConstants::ROW_MOVER_COLOR), 1)); - painter->drawRect(QRect(1, 1, size().width()-2, size().height() - 3)); + painter->drawRect(QRect(1, 1, m_treeWidth - 2, size().height() - 3)); } } -void RowTree::updatePropertyLabel() +void RowTree::setTreeWidth(double w) { - switch (m_propertyType) { - case PropertyType::Position: - m_label = tr("Position"); - break; - case PropertyType::Rotation: - m_label = tr("Rotation"); - break; - case PropertyType::Scale: - m_label = tr("Scale"); - break; - case PropertyType::Pivot: - m_label = tr("Pivot"); - break; - case PropertyType::Opacity: - m_label = tr("Opacity"); - break; - case PropertyType::EdgeTessellation: - m_label = tr("Edge Tessellation"); - break; - case PropertyType::InnerTessellation: - m_label = tr("Inner Tessellation"); - break; - case PropertyType::TextColor: - m_label = tr("Text Color"); - break; - case PropertyType::Leading: - m_label = tr("Leading"); - break; - case PropertyType::Tracking: - m_label = tr("Tracking"); - break; - case PropertyType::LightColor: - m_label = tr("Light Color"); - break; - case PropertyType::SpecularColor: - m_label = tr("Specular Color"); - break; - case PropertyType::AmbientColor: - m_label = tr("Ambient Color"); - break; - case PropertyType::Brightness: - m_label = tr("Brightness"); - break; - case PropertyType::ShadowDarkness: - m_label = tr("Shadow Darkness"); - break; - case PropertyType::ShadowSoftness: - m_label = tr("Shadow Softness"); - break; - case PropertyType::ShadowDepthBias: - m_label = tr("Shadow Depth Bias"); - break; - case PropertyType::FieldOfView: - m_label = tr("Field Of View"); - break; - case PropertyType::ClippingStart: - m_label = tr("Clipping Start"); - break; - case PropertyType::ClippingEnd: - m_label = tr("Clipping End"); - break; - case PropertyType::Left: - m_label = tr("Left"); - break; - case PropertyType::Top: - m_label = tr("Top"); - break; - case PropertyType::Width: - m_label = tr("Width"); - break; - case PropertyType::Height: - m_label = tr("Height"); - break; - case PropertyType::AO: - m_label = tr("Ambient Occlusion"); - break; - case PropertyType::AODistance: - m_label = tr("AO Distance"); - break; - case PropertyType::AOSoftness: - m_label = tr("AO Softness"); - break; - case PropertyType::AOThreshold: - m_label = tr("AO Threshold"); - break; - case PropertyType::AOSamplingRate: - m_label = tr("AO Sampling Rate"); - break; - case PropertyType::IBLBrightness: - m_label = tr("IBL Brightness"); - break; - case PropertyType::IBLHorizonCutoff: - m_label = tr("IBL Horizon Cutoff"); - break; - case PropertyType::IBLFOVAngle: - m_label = tr("IBL FOV Angle"); - break; - case PropertyType::ProbeCrossfade: - m_label = tr("Probe Crossfade"); - break; - default: - m_label = tr("Unnamed Property"); - } + m_treeWidth = w; + update(); +} + +void RowTree::setBinding(ITimelineItemBinding *binding) +{ + m_binding = binding; + + // update view (shy, visible, locked) + m_shy = m_binding->GetTimelineItem()->IsShy(); + m_visible = m_binding->GetTimelineItem()->IsVisible(); + m_locked = m_binding->GetTimelineItem()->IsLocked(); +} + +void RowTree::setPropBinding(ITimelineItemProperty *binding) +{ + m_PropBinding = binding; } void RowTree::setState(State state) @@ -314,12 +269,12 @@ int RowTree::depth() const return m_depth; } -RowType RowTree::rowType() const +EStudioObjectType RowTree::rowType() const { return m_rowType; } -PropertyType RowTree::propertyType() const +QString RowTree::propertyType() const { return m_propertyType; } @@ -378,36 +333,48 @@ void RowTree::removeChild(RowTree *child) bool RowTree::hasPropertyChildren() { - return !m_childRows.empty() && m_childRows.first()->rowType() == RowType::Property; + return m_scene->rowManager()->hasProperties(this); } -bool RowTree::handleButtonsClick(QGraphicsSceneMouseEvent *event) +// handle clicked control and return its type +TreeControlType RowTree::getClickedControl(const QPointF &scenePos) { - if (rowType() == RowType::Property) - return false; - - QPointF p = mapFromScene(event->scenePos().x(), event->scenePos().y()); + if (m_isProperty || m_rowType == OBJTYPE_SCENE) + return TreeControlType::None; - if (m_rectArrow.contains(p.x(), p.y())) { + QPointF p = mapFromScene(scenePos.x(), scenePos.y()); + if (m_rectArrow.contains(p.x(), p.y()) && !m_locked) { m_expanded = !m_expanded; updateExpandStatus(m_expanded, true); update(); - return true; + return TreeControlType::Arrow; } else if (m_rectShy.contains(p.x(), p.y())) { m_shy = !m_shy; update(); - return true; + + m_binding->GetTimelineItem()->SetShy(m_shy); + + return TreeControlType::Shy; } else if (m_rectVisible.contains(p.x(), p.y())) { m_visible = !m_visible; update(); - return true; + + m_binding->GetTimelineItem()->SetVisible(m_visible); + + + return TreeControlType::Hide; } else if (m_rectLocked.contains(p.x(), p.y())) { - m_locked = !m_locked; - update(); - return true; + updateLockRecursive(!m_locked); + + m_binding->GetTimelineItem()->SetLocked(m_locked); + + if (m_locked && selected()) + m_scene->rowManager()->clearSelection(); + + return TreeControlType::Lock; } - return false; + return TreeControlType::None; } void RowTree::updateExpandStatus(bool expand, bool childrenOnly) @@ -423,6 +390,17 @@ void RowTree::updateExpandStatus(bool expand, bool childrenOnly) } } +void RowTree::updateLockRecursive(bool state) +{ + m_locked = state; + update(); + + if (!m_childRows.empty()) { + for (auto child : qAsConst(m_childRows)) + child->updateLockRecursive(m_locked); + } +} + bool RowTree::expanded() const { return m_expanded; @@ -454,28 +432,59 @@ void RowTree::setMoveSourceRecursive(bool value) bool RowTree::isContainer() const { - return m_rowType == RowType::Scene - || m_rowType == RowType::Layer - || m_rowType == RowType::Group - || m_rowType == RowType::Component; + return m_rowType == OBJTYPE_SCENE + || m_rowType == OBJTYPE_LAYER + || m_rowType == OBJTYPE_GROUP + || m_rowType == OBJTYPE_COMPONENT; +} + +bool RowTree::isProperty() const +{ + return m_isProperty; } -bool RowTree::empty() const { +bool RowTree::empty() const +{ return m_childRows.empty(); } -void RowTree::setMoveTarget(bool value) { +bool RowTree::selected() const +{ + return m_state == Selected; +} + +void RowTree::setMoveTarget(bool value) +{ m_moveTarget = value; + update(); } -QList<RowTree *> RowTree::childRows() const { +QList<RowTree *> RowTree::childRows() const +{ return m_childRows; } -RowTimeline *RowTree::rowTimeline() const { +RowTimeline *RowTree::rowTimeline() const +{ return m_rowTimeline; } -QString RowTree::label() const { +QString RowTree::label() const +{ return m_label; } + +bool RowTree::shy() const +{ + return m_shy; +} + +bool RowTree::visible() const +{ + return m_visible; +} + +bool RowTree::locked() const +{ + return m_locked; +} diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h index 4b89a02a..cf2a5ab9 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h @@ -30,18 +30,25 @@ #define ROWTREE_H #include "InteractiveTimelineItem.h" +#include "TimelineGraphicsScene.h" +#include "TimelineConstants.h" #include "RowTypes.h" +#include "StudioObjectTypes.h" class RowTimeline; class Ruler; +class ITimelineItemBinding; class RowTree : public InteractiveTimelineItem { Q_OBJECT public: - explicit RowTree(Ruler *ruler, RowType rowType = RowType::Layer, const QString &label = {}); - explicit RowTree(Ruler *ruler, PropertyType propType); // property row constructor + explicit RowTree(TimelineGraphicsScene *timelineScene, + EStudioObjectType rowType = OBJTYPE_UNKNOWN, const QString &label = {}); + // property row constructor + explicit RowTree(TimelineGraphicsScene *timelineScene, const QString &propType); + ~RowTree(); void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; @@ -53,8 +60,10 @@ public: void removeChild(RowTree *child); void setMoveSourceRecursive(bool value); void setMoveTarget(bool value); - - bool handleButtonsClick(QGraphicsSceneMouseEvent *event); + void setTreeWidth(double w); + void setBinding(ITimelineItemBinding *binding); + void setPropBinding(ITimelineItemProperty *binding); // for property rows + TreeControlType getClickedControl(const QPointF &scenePos); bool hasPropertyChildren(); bool shy() const; bool visible() const; @@ -62,36 +71,43 @@ public: bool expanded() const; bool isDecendentOf(RowTree *row) const; bool isContainer() const; + bool isProperty() const; bool empty() const; - + bool selected() const; int depth() const; int type() const; - RowType rowType() const; - PropertyType propertyType() const; - + EStudioObjectType rowType() const; + QString propertyType() const; RowTree *parentRow() const; QList<RowTree *> childRows() const; RowTimeline *rowTimeline() const; QString label() const; + ITimelineItemBinding *getBinding() const; + private: void updateExpandStatus(bool expand, bool childrenOnly = false); void updateDepthRecursive(); - void updatePropertyLabel(); + void updateLockRecursive(bool state); RowTree *m_parentRow = nullptr; RowTimeline *m_rowTimeline = nullptr; int m_depth = 1; + int m_treeWidth = TimelineConstants::TREE_DEFAULT_W; bool m_shy = false; bool m_visible = true; bool m_locked = false; bool m_expanded = true; bool m_moveSource = false; bool m_moveTarget = false; - RowType m_rowType = RowType::Layer; - PropertyType m_propertyType = PropertyType::None; // for property rows - QString m_label = 0; + bool m_isProperty = false; + TimelineGraphicsScene *m_scene; + EStudioObjectType m_rowType = OBJTYPE_UNKNOWN; + QString m_propertyType; // for property rows + QString m_label; QList<RowTree *> m_childRows; + ITimelineItemBinding *m_binding; + ITimelineItemProperty *m_PropBinding; // for property rows QRect m_rectArrow; QRect m_rectShy; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp index 17f26637..884f5fcd 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp @@ -33,7 +33,7 @@ Ruler::Ruler(TimelineItem *parent) : TimelineItem(parent) { - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); + setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); } void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.cpp deleted file mode 100644 index d76949b1..00000000 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt 3D Studio. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "Separator.h" -#include "TimelineConstants.h" - -#include <QtGui/qpainter.h> -#include <QtGui/qcursor.h> -#include <QtWidgets/qapplication.h> - -Separator::Separator(TimelineItem *parent) : TimelineItem(parent) -{ - setMinimumWidth(TimelineConstants::SEPARATOR_W); - setMaximumWidth(TimelineConstants::SEPARATOR_W); - setMaximumHeight(10000); - // TODO: remove -// setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); - setAcceptHoverEvents(true); -} - -void Separator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) -{ - // TODO: remove -// painter->fillRect(0, 0, size().width(), size().height(), QColor("#666666")); -} - -void Separator::hoverEnterEvent(QGraphicsSceneHoverEvent *event) -{ - qApp->setOverrideCursor(Qt::SplitHCursor); -} - -void Separator::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) -{ - qApp->changeOverrideCursor(Qt::ArrowCursor); - qApp->restoreOverrideCursor(); -} - -int Separator::type() const -{ - // Enable the use of qgraphicsitem_cast with this item. - return TypeSeparator; -} diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.h deleted file mode 100644 index e74fe0c5..00000000 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Separator.h +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2018 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt 3D Studio. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef SEPARATOR_H -#define SEPARATOR_H - -#include "TimelineItem.h" - -class Separator : public TimelineItem -{ - Q_OBJECT - -public: - explicit Separator(TimelineItem *parent = nullptr); - - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, - QWidget *widget = nullptr) override; - int type() const; - - protected: - void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; - void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override; -}; - -#endif // SEPARATOR_H diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h index 184795b7..bfbc42f1 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h @@ -45,8 +45,7 @@ public: TypeRowTree, TypeRowTimeline, TypePlayHead, - TypeRuler, - TypeSeparator + TypeRuler }; int type() const; diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp index 3855fb4a..3e9e6a05 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp @@ -46,7 +46,7 @@ TimelineToolbar::TimelineToolbar() : QToolBar() // create actions QAction *actionNewLayer = new QAction(iconLayer, tr("Add New Layer")); QAction *actionDeleteLayer = new QAction(iconDelete, tr("Delete Layer")); - m_actionTime = new QAction("0:00.000"); + m_actionTime = new QAction(tr("0:00.000")); QAction *actionFirst = new QAction(iconFirst, tr("Go to Timeline Start")); QAction *actionStop = new QAction(iconStop, tr("Stop Playing")); QAction *actionPlay = new QAction(iconPlay, tr("Start Playing")); @@ -54,15 +54,13 @@ TimelineToolbar::TimelineToolbar() : QToolBar() m_scaleSlider = new QSlider(); m_scaleSlider->setOrientation(Qt::Horizontal); - m_scaleSlider->setMaximumWidth(200); - m_scaleSlider->setMinimumWidth(100); + m_scaleSlider->setFixedWidth(100); m_scaleSlider->setMinimum(1); m_scaleSlider->setMaximum(8); m_scaleSlider->setPageStep(.1); m_scaleSlider->setValue(2); - m_scaleSlider->setStyleSheet("background-color:0,0,0,0;"); - m_actionDuration = new QAction("0:20"); + m_actionDuration = new QAction(tr("0:20")); // connections connect(actionNewLayer , &QAction::triggered, this, &TimelineToolbar::newLayerTriggered); diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp index 8766ff12..d65fc603 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp @@ -39,15 +39,69 @@ TreeHeader::TreeHeader(TimelineItem *parent) : TimelineItem(parent) void TreeHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { - static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png"); - static const QPixmap pixHide = QPixmap(":/images/Toggle-HideShow.png"); - static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png"); + m_rectShy .setRect(m_treeWidth - 16 * 3.3, size().height() * .5 - 8, 16, 16); + m_rectVisible.setRect(m_treeWidth - 16 * 2.2, size().height() * .5 - 8, 16, 16); + m_rectLock .setRect(m_treeWidth - 16 * 1.1, size().height() * .5 - 8, 16, 16); - double y = (size().height() - pixHide.height()) * .5; + static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png"); + static const QPixmap pixVisible = QPixmap(":/images/Toggle-HideShow.png"); + static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png"); - painter->drawPixmap(size().width() - pixHide.width() * 1.1 * 3, y, pixShy); - painter->drawPixmap(size().width() - pixHide.width() * 1.1 * 2, y, pixHide); - painter->drawPixmap(size().width() - pixHide.width() * 1.1 , y, pixLock); + QColor selectedColor = QColor(TimelineConstants::FILTER_BUTTON_SELECTED_COLOR); + if (m_shy) + painter->fillRect(m_rectShy, selectedColor); + + if (m_visible) + painter->fillRect(m_rectVisible, selectedColor); + + if (m_lock) + painter->fillRect(m_rectLock, selectedColor); + + painter->drawPixmap(m_rectShy , pixShy); + painter->drawPixmap(m_rectVisible, pixVisible); + painter->drawPixmap(m_rectLock , pixLock); +} + +void TreeHeader::setWidth(double w) +{ + m_treeWidth = w; + update(); +} + +TreeControlType TreeHeader::handleButtonsClick(const QPointF &scenePos) +{ + QPointF p = mapFromScene(scenePos.x(), scenePos.y()); + + if (m_rectShy.contains(p.x(), p.y())) { + m_shy = !m_shy; + update(); + return TreeControlType::Shy; + } else if (m_rectVisible.contains(p.x(), p.y())) { + m_visible = !m_visible; + update(); + return TreeControlType::Hide; + } else if (m_rectLock.contains(p.x(), p.y())) { + m_lock = !m_lock; + update(); + return TreeControlType::Lock; + } + + return TreeControlType::None; +} + +bool TreeHeader::filterShy() const +{ + return m_shy; +} + +bool TreeHeader::filterHidden() const +{ + return m_visible; +} + +bool TreeHeader::filterLocked() const +{ + return m_lock; } int TreeHeader::type() const diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.h index 2f90b8fc..1c2d703f 100644 --- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.h +++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.h @@ -30,6 +30,8 @@ #define TREEHEADER_H #include "TimelineItem.h" +#include "TimelineConstants.h" +#include "RowTypes.h" class RowTimeline; @@ -42,8 +44,22 @@ public: void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override; - + void setWidth(double w); + TreeControlType handleButtonsClick(const QPointF &scenePos); + bool filterShy() const; + bool filterHidden() const; + bool filterLocked() const; int type() const; + + int m_treeWidth = TimelineConstants::TREE_DEFAULT_W; + +private: + bool m_shy = false; + bool m_visible = false; + bool m_lock = false; + QRect m_rectShy; + QRect m_rectVisible; + QRect m_rectLock; }; #endif // TREEHEADER_H diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro index 0add9a50..d4948a92 100644 --- a/src/Authoring/Studio/Qt3DStudio.pro +++ b/src/Authoring/Studio/Qt3DStudio.pro @@ -160,9 +160,9 @@ HEADERS += \ Application/DataInputSelectDlg.h \ Palettes/TimelineGraphicsView/TimelineWidget.h \ Palettes/TimelineGraphicsView/TimelineGraphicsScene.h \ + Palettes/TimelineGraphicsView/TimelineSplitter.h \ Palettes/TimelineGraphicsView/ui/TimelineItem.h \ Palettes/TimelineGraphicsView/ui/InteractiveTimelineItem.h \ - Palettes/TimelineGraphicsView/ui/Separator.h \ Palettes/TimelineGraphicsView/ui/Ruler.h \ Palettes/TimelineGraphicsView/ui/PlayHead.h \ Palettes/TimelineGraphicsView/TimelineConstants.h \ @@ -381,9 +381,9 @@ SOURCES += \ Application/DataInputSelectDlg.cpp \ Palettes/TimelineGraphicsView/TimelineWidget.cpp \ Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp \ + Palettes/TimelineGraphicsView/TimelineSplitter.cpp \ Palettes/TimelineGraphicsView/ui/TimelineItem.cpp \ Palettes/TimelineGraphicsView/ui/InteractiveTimelineItem.cpp \ - Palettes/TimelineGraphicsView/ui/Separator.cpp \ Palettes/TimelineGraphicsView/ui/PlayHead.cpp \ Palettes/TimelineGraphicsView/ui/Ruler.cpp \ Palettes/TimelineGraphicsView/ui/TimelineToolbar.cpp \ diff --git a/src/Authoring/Studio/style.qss b/src/Authoring/Studio/style.qss index 3d567508..29e76ed2 100644 --- a/src/Authoring/Studio/style.qss +++ b/src/Authoring/Studio/style.qss @@ -361,3 +361,24 @@ DataInputSelectDlg::item:selected { DataInputSelectDlg::item:hover { background: #23516d; } + +/* QSlider horizontal */ +QSlider { + background: transparent; +} + +QSlider::groove:horizontal { + background: #dddddd; + height: 1px; +} + +QSlider::handle:horizontal { + background: #999A9B; + width: 12px; + margin: -5px 0; + border-radius: 4px; +} + +QSlider::handle:horizontal:hover { + background: #cccccc; +} |