summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Authoring/Client/Code/Core/Core/Core.cpp1
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.cpp14
-rw-r--r--src/Authoring/Client/Code/Core/Doc/Doc.h5
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp37
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h16
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h17
-rw-r--r--src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp15
-rw-r--r--src/Authoring/Client/Code/Core/Utility/StudioPreferences.h3
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp15
-rw-r--r--src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h37
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.cpp34
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.h4
-rw-r--r--src/Authoring/Studio/Application/DataInputDlg.ui42
-rw-r--r--src/Authoring/Studio/Application/DataInputListDlg.cpp41
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.cpp214
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.h35
-rw-r--r--src/Authoring/Studio/Application/DurationEditDlg.ui59
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.cpp677
-rw-r--r--src/Authoring/Studio/Application/ProjectFile.h25
-rw-r--r--src/Authoring/Studio/Application/StudioApp.cpp13
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.cpp210
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.h29
-rw-r--r--src/Authoring/Studio/Application/TimeEditDlg.ui68
-rw-r--r--src/Authoring/Studio/Info.plist6
-rw-r--r--src/Authoring/Studio/MainFrm.cpp7
-rw-r--r--src/Authoring/Studio/MainFrm.h2
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp66
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h14
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp92
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h5
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml215
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp27
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp8
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h1
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp106
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h73
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui113
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp237
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h85
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp108
-rw-r--r--src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h (renamed from src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h)51
-rw-r--r--src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.cpp64
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideModel.h6
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.cpp86
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.h5
-rw-r--r--src/Authoring/Studio/Palettes/Slide/SlideView.qml11
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h1
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h4
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp115
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h25
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp22
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp18
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h4
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp133
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h6
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp146
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h10
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp22
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h8
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp277
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h26
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp302
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h5
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp43
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h24
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h2
-rw-r--r--src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp16
-rw-r--r--src/Authoring/Studio/Qt3DStudio.pro28
-rw-r--r--src/Authoring/Studio/UI/StudioAppPrefsPage.cpp1
-rw-r--r--src/Authoring/Studio/Utils/StudioUtils.cpp17
-rw-r--r--src/Authoring/Studio/Utils/StudioUtils.h1
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.cpp49
-rw-r--r--src/Authoring/Studio/Workspace/Dialogs.h8
-rw-r--r--src/Authoring/Studio/images.qrc23
-rw-r--r--src/Authoring/Studio/images/Action-Action@2x.pngbin0 -> 599 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ChildAction@2x.pngbin0 -> 341 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ChildMasterAction@2x.pngbin0 -> 344 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ComponentAction@2x.pngbin0 -> 325 bytes
-rw-r--r--src/Authoring/Studio/images/Action-ComponentMasterAction@2x.pngbin0 -> 314 bytes
-rw-r--r--src/Authoring/Studio/images/Action-MasterAction@2x.pngbin0 -> 639 bytes
-rw-r--r--src/Authoring/Studio/images/Insert-Left@2x.pngbin0 -> 314 bytes
-rw-r--r--src/Authoring/Studio/images/Insert-Right@2x.pngbin0 -> 324 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Disabled.pngbin3009 -> 2946 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.pngbin0 -> 606 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Normal.pngbin2924 -> 2937 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Normal@2x.pngbin0 -> 578 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Selected.pngbin2985 -> 2947 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Master-Selected@2x.pngbin0 -> 498 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.pngbin617 -> 263 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.pngbin0 -> 580 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.pngbin3010 -> 2959 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.pngbin0 -> 578 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.pngbin2981 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.pngbin0 -> 561 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Disabled.pngbin2989 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.pngbin0 -> 435 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Normal.pngbin2924 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Normal@2x.pngbin0 -> 428 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Selected.pngbin2981 -> 2951 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-Property-Selected@2x.pngbin0 -> 424 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.pngbin593 -> 291 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.pngbin0 -> 428 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.pngbin2971 -> 2949 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.pngbin0 -> 427 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~bin0 -> 427 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.pngbin2973 -> 2947 bytes
-rw-r--r--src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.pngbin0 -> 424 bytes
-rw-r--r--src/Authoring/Studio/images/Toggle-Empty@2x.pngbin0 -> 286 bytes
-rw-r--r--src/Authoring/Studio/images/keyframe-hidden-normal@2x.pngbin0 -> 226 bytes
-rw-r--r--src/Authoring/Studio/images/playback_tools_low-04@2x.pngbin0 -> 315 bytes
m---------src/Runtime/qt3d-runtime0
-rw-r--r--src/shared/header/foundation/ConvertUTF.h34
-rw-r--r--src/shared/header/foundation/StrConvertUTF.h12
-rw-r--r--src/shared/qt-breakpad/qtcrashhandler/mainwidget.h6
-rw-r--r--src/shared/source/ConvertUTF.cpp14
122 files changed, 3312 insertions, 1138 deletions
diff --git a/src/Authoring/Client/Code/Core/Core/Core.cpp b/src/Authoring/Client/Code/Core/Core/Core.cpp
index e4e31267..46e4c646 100644
--- a/src/Authoring/Client/Code/Core/Core/Core.cpp
+++ b/src/Authoring/Client/Code/Core/Core/Core.cpp
@@ -274,6 +274,7 @@ bool CCore::OnNewDocument(const QString &inDocument, bool isNewProject, bool sil
// write a new presentation node to the uia file
m_projectFile.addPresentationNode(theDocument);
m_projectFile.updateDocPresentationId();
+ m_projectFile.loadVariants();
m_projectFile.loadSubpresentationsAndDatainputs(g_StudioApp.m_subpresentations,
g_StudioApp.m_dataInputDialogItems);
g_StudioApp.getRenderer().RegisterSubpresentations(g_StudioApp.m_subpresentations);
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.cpp b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
index 599e0306..a59529d5 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.cpp
@@ -719,18 +719,14 @@ qt3dsdm::Qt3DSDMInstanceHandle CDoc::GetFirstSelectableLayer()
QVector<qt3dsdm::Qt3DSDMInstanceHandle> CDoc::getLayers()
{
- CClientDataModelBridge *bridge = m_StudioSystem->GetClientDataModelBridge();
-
Q3DStudio::CGraphIterator layerIterator;
GetAssetChildren(this, m_SceneInstance, layerIterator, OBJTYPE_LAYER);
QVector<qt3dsdm::Qt3DSDMInstanceHandle> layerList;
for (; !layerIterator.IsDone(); ++layerIterator) {
- if (m_StudioSystem->IsInstance(layerIterator.GetCurrent())
- && !bridge->IsLockedAtAll(layerIterator.GetCurrent())) {
+ if (m_StudioSystem->IsInstance(layerIterator.GetCurrent()))
layerList.append(layerIterator.GetCurrent());
- }
}
return layerList;
@@ -2373,7 +2369,7 @@ std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateSerializer()
*theCoreSystem.GetActionCore(), *m_AssetGraph, *theFullSystem.GetSlideSystem(),
*theFullSystem.GetActionSystem(), *theCoreSystem.GetSlideGraphCore(),
theClientBridge.GetObjectDefinitions(), m_ImportFailedHandler,
- *theCoreSystem.GetGuideSystem());
+ *theCoreSystem.GetGuideSystem(), *theFullSystem.GetPropertySystem());
}
std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateTransactionlessSerializer()
@@ -2390,9 +2386,9 @@ std::shared_ptr<Q3DStudio::IComposerSerializer> CDoc::CreateTransactionlessSeria
*theCoreSystem.GetTransactionlessAnimationCore(),
*theCoreSystem.GetTransactionlessActionCore(), *m_AssetGraph,
*theFullSystem.GetSlideSystem(), *theFullSystem.GetActionSystem(),
- *theCoreSystem.GetTransactionlessSlideGraphCore(), theClientBridge.GetObjectDefinitions(),
- m_ImportFailedHandler, *theCoreSystem.GetGuideSystem());
-
+ *theCoreSystem.GetTransactionlessSlideGraphCore(),
+ theClientBridge.GetObjectDefinitions(), m_ImportFailedHandler,
+ *theCoreSystem.GetGuideSystem(), *theFullSystem.GetPropertySystem());
}
std::shared_ptr<qt3dsdm::IDOMWriter> CDoc::CreateDOMWriter()
diff --git a/src/Authoring/Client/Code/Core/Doc/Doc.h b/src/Authoring/Client/Code/Core/Doc/Doc.h
index dad6b365..1cf64168 100644
--- a/src/Authoring/Client/Code/Core/Doc/Doc.h
+++ b/src/Authoring/Client/Code/Core/Doc/Doc.h
@@ -182,6 +182,11 @@ public:
QString name;
int type;
QVector<ControlledItem> ctrldElems;
+ // As per QT3DS-2992 we currently need only a single key-value pair per datainput.
+ // For efficiency we use separate QStrings for both, as there is no need for more
+ // elaborate containers.
+ QString metaDataKey;
+ QString metaData;
// Bindings in other subpresentations, of QMap format
// QMultiMap<subpresentation_id, QPair<datatype, strict>>.
diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
index 3a1907b7..4307b310 100644
--- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.cpp
@@ -335,6 +335,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
SComposerObjectDefinitions &m_ObjectDefinitions;
qt3dsdm::IStringTable &m_StringTable;
std::shared_ptr<Q3DStudio::IImportFailedHandler> m_ImportFailedHandler;
+ IPropertySystem &m_propertySystem;
// The instances we have discovered when we are writing
THandleToIdMap m_HandleToIdMap;
@@ -390,7 +391,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
IActionSystem &inActionSystem, ISlideGraphCore &inSlideGraphCore,
SComposerObjectDefinitions &inObjectDefinitions,
std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
- IGuideSystem &inGuideSystem)
+ IGuideSystem &inGuideSystem, IPropertySystem &inPropSystem)
: m_DataCore(inDataCore)
, m_MetaData(inMetaData)
, m_SlideCore(inSlideCore)
@@ -404,6 +405,7 @@ struct SComposerSerializerImpl : public IComposerSerializer
, m_ObjectDefinitions(inObjectDefinitions)
, m_StringTable(inDataCore.GetStringTable())
, m_ImportFailedHandler(inFailedHandler)
+ , m_propertySystem(inPropSystem)
, m_Foundation(Q3DStudio::Foundation::SStudioFoundation::Create())
, m_InputStreamFactory(Q3DStudio::IInputStreamFactory::Create())
, m_PreserveFileIds(true)
@@ -942,8 +944,11 @@ struct SComposerSerializerImpl : public IComposerSerializer
const pair<Qt3DSDMPropertyHandle, SValue> &theValue(inList[idx]);
QString theName(m_DataCore.GetProperty(theValue.first).m_Name);
WriteDataModelValue(theValue.second, theValueStr);
- if (GetValueType(theValue.second) == DataModelDataType::String || theValueStr.size())
- inWriter.Att(theName, theValueStr);
+ if (GetValueType(theValue.second) == DataModelDataType::String || theValueStr.size()) {
+ // this property is saved under the <Graph> node
+ if (theName != QStringLiteral("variants"))
+ inWriter.Att(theName, theValueStr);
+ }
}
}
@@ -1627,7 +1632,16 @@ struct SComposerSerializerImpl : public IComposerSerializer
}
IDOMWriter::Scope __instanceScope(inWriter, theType);
- inWriter.Att(L"id", GetInstanceId(inInstance));
+ inWriter.Att(QStringLiteral("id"), GetInstanceId(inInstance));
+
+ // for layers, save the variants property under the <Graph>
+ if (theType.getValue() == QStringLiteral("Layer")) {
+ auto prop = m_propertySystem.GetAggregateInstancePropertyByName(
+ inInstance, QStringLiteral("variants"));
+ SValue sVal;
+ if (m_propertySystem.GetInstancePropertyValue(inInstance, prop, sVal))
+ inWriter.Att(QStringLiteral("variants"), get<QString>(sVal));
+ }
m_InstanceSet.insert(inInstance);
@@ -2832,12 +2846,15 @@ struct SComposerSerializerImpl : public IComposerSerializer
std::shared_ptr<IComposerSerializer> IComposerSerializer::CreateGraphSlideSerializer(
IDataCore &inDataCore, IMetaData &inMetaData, ISlideCore &inSlideCore,
IAnimationCore &inAnimationCore, IActionCore &inActionCore, CGraph &inAssetGraph,
- ISlideSystem &inSlideSystem, IActionSystem &inActionSystem, ISlideGraphCore &inSlideGraphCore,
+ ISlideSystem &inSlideSystem, IActionSystem &inActionSystem,
+ ISlideGraphCore &inSlideGraphCore,
SComposerObjectDefinitions &inObjectDefinitions,
- std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler, IGuideSystem &inGuideSystem)
+ std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
+ IGuideSystem &inGuideSystem, IPropertySystem &inPropSystem)
{
- return std::shared_ptr<SComposerSerializerImpl>(new SComposerSerializerImpl(
- inDataCore, inMetaData, inSlideCore, inAnimationCore, inActionCore, inAssetGraph,
- inSlideSystem, inActionSystem, inSlideGraphCore, inObjectDefinitions, inFailedHandler,
- inGuideSystem));
+ return std::shared_ptr<SComposerSerializerImpl>(
+ new SComposerSerializerImpl(
+ inDataCore, inMetaData, inSlideCore, inAnimationCore, inActionCore,
+ inAssetGraph, inSlideSystem, inActionSystem, inSlideGraphCore,
+ inObjectDefinitions, inFailedHandler, inGuideSystem, inPropSystem));
}
diff --git a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
index 301a8144..1a18b262 100644
--- a/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
+++ b/src/Authoring/Client/Code/Core/Doc/IComposerSerializer.h
@@ -49,6 +49,7 @@ class IActionSystem;
class ISlideGraphCore;
class IGuideSystem;
class SComposerObjectDefinitions;
+class IPropertySystem;
};
namespace Q3DStudio {
@@ -102,13 +103,14 @@ public:
friend class std::shared_ptr<IComposerSerializer>;
static std::shared_ptr<IComposerSerializer> CreateGraphSlideSerializer(
- qt3dsdm::IDataCore &inDataCore, qt3dsdm::IMetaData &inMetaData, qt3dsdm::ISlideCore &inSlideCore,
- qt3dsdm::IAnimationCore &inAnimationCore, qt3dsdm::IActionCore &inActionCore,
- CGraph &inAssetGraph, qt3dsdm::ISlideSystem &inSlideSystem,
- qt3dsdm::IActionSystem &inActionSystem, qt3dsdm::ISlideGraphCore &inSlideGraphCore,
- qt3dsdm::SComposerObjectDefinitions &inObjectDefinitions,
- std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
- qt3dsdm::IGuideSystem &inGuideSystem);
+ qt3dsdm::IDataCore &inDataCore, qt3dsdm::IMetaData &inMetaData,
+ qt3dsdm::ISlideCore &inSlideCore,
+ qt3dsdm::IAnimationCore &inAnimationCore, qt3dsdm::IActionCore &inActionCore,
+ CGraph &inAssetGraph, qt3dsdm::ISlideSystem &inSlideSystem,
+ qt3dsdm::IActionSystem &inActionSystem, qt3dsdm::ISlideGraphCore &inSlideGraphCore,
+ qt3dsdm::SComposerObjectDefinitions &inObjectDefinitions,
+ std::shared_ptr<Q3DStudio::IImportFailedHandler> inFailedHandler,
+ qt3dsdm::IGuideSystem &inGuideSystem, qt3dsdm::IPropertySystem &inPropSystem);
};
}
diff --git a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
index da45d8a7..df028c3f 100644
--- a/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
+++ b/src/Authoring/Client/Code/Core/Doc/IKeyframesManager.h
@@ -28,21 +28,14 @@
****************************************************************************/
#ifndef INCLUDED_IKEYFRAMES_MANAGER_H
-#define INCLUDED_IKEYFRAMES_MANAGER_H 1
+#define INCLUDED_IKEYFRAMES_MANAGER_H
-#pragma once
-
-//=============================================================================
-/**
- * Interface to manage keyframes related actions
- */
-//=============================================================================
class IKeyframesManager
{
public:
virtual ~IKeyframesManager() {}
- virtual bool HasSelectedKeyframes(bool inOnlyDynamic = false) = 0;
+ virtual bool HasSelectedKeyframes() = 0;
virtual bool HasDynamicKeyframes() = 0;
virtual bool CanPerformKeyframeCopy() = 0;
virtual bool CanPerformKeyframePaste() = 0;
@@ -50,9 +43,13 @@ public:
virtual bool RemoveKeyframes(bool inPerformCopy) = 0;
virtual void PasteKeyframes() = 0;
virtual void SetKeyframeInterpolation() = 0;
- virtual void SelectAllKeyframes() = 0;
virtual void DeselectAllKeyframes() = 0;
virtual void SetChangedKeyframes() = 0;
+
+ virtual void SetKeyframeTime(long inTime) = 0;
+ virtual void SetKeyframesDynamic(bool inDynamic) = 0;
+ virtual void CommitChangedKeyframes() = 0;
+ virtual void RollbackChangedKeyframes() = 0;
};
#endif // INCLUDED_IKEYFRAMES_MANAGER_H
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
index 810f9f3d..36d4956b 100644
--- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
+++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.cpp
@@ -83,6 +83,8 @@ static QColor s_timelinePlayheadLineColor;
static QColor s_timelineFilterButtonSelectedColor;
static QColor s_timelineFilterButtonHoveredColor;
static QColor s_timelineRowCommentBgColor;
+static QColor s_timelinePressedKeyframeColor; // pressed keyframe from multiple selection
+static QColor s_invalidDataInputIndicatorColor;
static int s_fontSize;
static int s_controlBaseHeight;
@@ -195,6 +197,9 @@ void CStudioPreferences::loadPreferences(const QString &filePath)
s_timelineRowSubpColor = QColor("#e2ceff");
s_timelineRowSubpDescendantColor = QColor("#a263ff");
s_timelineRowCommentBgColor = QColor("#d0000000");
+ s_timelinePressedKeyframeColor = QColor("#ffff00");
+
+ s_invalidDataInputIndicatorColor = QColor("#ff2121");
s_fontSize = 12;
s_controlBaseHeight = 22;
@@ -1053,6 +1058,16 @@ QColor CStudioPreferences::timelineRowCommentBgColor()
return s_timelineRowCommentBgColor;
}
+QColor CStudioPreferences::timelinePressedKeyframeColor()
+{
+ return s_timelinePressedKeyframeColor;
+}
+
+QColor CStudioPreferences::invalidDataInputIndicatorColor()
+{
+ return s_invalidDataInputIndicatorColor;
+}
+
int CStudioPreferences::fontSize()
{
return s_fontSize;
diff --git a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
index a138bd5c..ed9da243 100644
--- a/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
+++ b/src/Authoring/Client/Code/Core/Utility/StudioPreferences.h
@@ -197,6 +197,9 @@ public:
static QColor timelineRowSubpColor();
static QColor timelineRowSubpDescendantColor();
static QColor timelineRowCommentBgColor();
+ static QColor timelinePressedKeyframeColor();
+
+ static QColor invalidDataInputIndicatorColor();
static int fontSize();
static int controlBaseHeight();
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
index 83e9384b..e3f3e97b 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.cpp
@@ -316,6 +316,7 @@ struct DataConstructor<SObjectRefType>
#define QT3DS_PROPNAME_lightmapradiosity "lightmapradiosity"
#define QT3DS_PROPNAME_lightmapshadow "lightmapshadow"
#define QT3DS_PROPNAME_controlledproperty "controlledproperty"
+#define QT3DS_PROPNAME_variants "variants"
QString ComposerObjectTypes::Convert(ComposerObjectTypes::Enum inType)
{
@@ -337,7 +338,7 @@ ComposerObjectTypes::Enum ComposerObjectTypes::Convert(const QString &inType)
{
#define HANDLE_COMPOSER_OBJECT_TYPE(name, propmacro) \
- if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
+ if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
return ComposerObjectTypes::name;
ITERATE_COMPOSER_OBJECT_TYPES
#undef HANDLE_COMPOSER_OBJECT_TYPE
@@ -372,7 +373,7 @@ ComposerPropertyNames::Enum ComposerPropertyNames::Convert(const QString &inType
{
#define HANDLE_COMPOSER_PROPERTY_DUPLICATE(name, memberName, type, defaultValue)
#define HANDLE_COMPOSER_PROPERTY_NO_DEFAULT(name, memberName, type) \
- if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
+ if (inType == QLatin1String(QT3DS_PROPNAME_##name)) \
return name;
#define HANDLE_COMPOSER_PROPERTY(name, memberName, type, defaultValue) \
HANDLE_COMPOSER_PROPERTY_NO_DEFAULT(name, memberName, type)
@@ -397,11 +398,11 @@ ComposerPropertyNames::Enum ComposerPropertyNames::Convert(const QString &inType
#define HANDLE_COMPOSER_OBJECT_TYPE(name, propmacro) \
SComposerTypePropertyDefinition<ComposerObjectTypes::name>::SComposerTypePropertyDefinition( \
- IDataCore &inCore, Qt3DSDMInstanceHandle inInstance) \
- : reserved(false) propmacro \
- { \
- Q_UNUSED(inCore);\
- Q_UNUSED(inInstance);\
+ IDataCore &inCore, Qt3DSDMInstanceHandle inInstance) \
+ : reserved(false) propmacro \
+ { \
+ Q_UNUSED(inCore); \
+ Q_UNUSED(inInstance); \
}
ITERATE_COMPOSER_OBJECT_TYPES
#undef HANDLE_COMPOSER_OBJECT_TYPE
diff --git a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
index 4d54ea07..172e53ab 100644
--- a/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
+++ b/src/Authoring/QT3DSDM/Systems/Qt3DSDMComposerTypeDefinitions.h
@@ -70,7 +70,7 @@ class IPropertySystem;
HANDLE_COMPOSER_OBJECT_TYPE(Model, ITERATE_COMPOSER_MODEL_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Light, ITERATE_COMPOSER_LIGHT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Camera, ITERATE_COMPOSER_CAMERA_PROPERTIES) \
- HANDLE_COMPOSER_OBJECT_TYPE(Component, ITERATE_COMPOSER_COMPONENT_PROPERTIES) \
+ HANDLE_COMPOSER_OBJECT_TYPE(Component, ITERATE_COMPOSER_COMPONENT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Text, ITERATE_COMPOSER_TEXT_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(RenderPlugin, ITERATE_COMPOSER_NO_ADDITIONAL_PROPERTIES) \
HANDLE_COMPOSER_OBJECT_TYPE(Alias, ITERATE_COMPOSER_ALIAS_PROPERTIES) \
@@ -93,8 +93,8 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(importid, m_ImportId, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY(importfile, m_ImportFile, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY(fileid, m_FileId, TDataStrPtr, L"") \
- HANDLE_COMPOSER_PROPERTY(starttime, m_StartTime, qt3ds::QT3DSI32, 0) \
- HANDLE_COMPOSER_PROPERTY(endtime, m_EndTime, qt3ds::QT3DSI32, 10000) \
+ HANDLE_COMPOSER_PROPERTY(starttime, m_StartTime, qt3ds::QT3DSI32, 0) \
+ HANDLE_COMPOSER_PROPERTY(endtime, m_EndTime, qt3ds::QT3DSI32, 10000) \
HANDLE_COMPOSER_PROPERTY(eyeball, m_Eyeball, bool, true) \
HANDLE_COMPOSER_PROPERTY(shy, m_Shy, bool, false) \
HANDLE_COMPOSER_PROPERTY(locked, m_Locked, bool, false) \
@@ -118,12 +118,12 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(opacity, m_Opacity, float, 100.f) \
HANDLE_COMPOSER_PROPERTY(rotationorder, m_RotationOrder, TDataStrPtr, L"YXZ") \
HANDLE_COMPOSER_PROPERTY(orientation, m_Orientation, TDataStrPtr, L"Left Handed") \
- HANDLE_COMPOSER_PROPERTY(boneid, m_BoneId, qt3ds::QT3DSI32, 0) \
+ HANDLE_COMPOSER_PROPERTY(boneid, m_BoneId, qt3ds::QT3DSI32, 0) \
HANDLE_COMPOSER_PROPERTY(ignoresparent, m_IgnoresParent, bool, false) \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
#define ITERATE_COMPOSER_MODEL_PROPERTIES \
- HANDLE_COMPOSER_PROPERTY(poseroot, m_PoseRoot, qt3ds::QT3DSI32, -1) \
+ HANDLE_COMPOSER_PROPERTY(poseroot, m_PoseRoot, qt3ds::QT3DSI32, -1) \
HANDLE_COMPOSER_PROPERTY(tessellation, m_Tessellation, TDataStrPtr, L"None") \
HANDLE_COMPOSER_PROPERTY(edgetess, m_EdgeTess, float, 1.0) \
HANDLE_COMPOSER_PROPERTY(innertess, m_InnerTess, float, 1.0) \
@@ -219,7 +219,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(aodistance, m_AoDistance, float, 0) \
HANDLE_COMPOSER_PROPERTY(aosoftness, m_AoSoftness, float, 0) \
HANDLE_COMPOSER_PROPERTY(aobias, m_AoBias, float, 0) \
- HANDLE_COMPOSER_PROPERTY(aosamplerate, m_AoSamplerate, qt3ds::QT3DSI32, 1) \
+ HANDLE_COMPOSER_PROPERTY(aosamplerate, m_AoSamplerate, qt3ds::QT3DSI32, 1) \
HANDLE_COMPOSER_PROPERTY(aodither, m_AoDither, bool, false) \
HANDLE_COMPOSER_PROPERTY(shadowstrength, m_ShadowStrength, float, 0) \
HANDLE_COMPOSER_PROPERTY(shadowdist, m_ShadowDist, float, 0) \
@@ -234,6 +234,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(probe2fade, m_Probe2Fade, float, 1) \
HANDLE_COMPOSER_PROPERTY(probe2window, m_Probe2Window, float, 1) \
HANDLE_COMPOSER_PROPERTY(probe2pos, m_Probe2Pos, float, 0.5f) \
+ HANDLE_COMPOSER_PROPERTY(variants, m_variants, TDataStrPtr, L"") \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
#define ITERATE_COMPOSER_LIGHT_PROPERTIES \
@@ -250,7 +251,7 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(castshadow, m_CastShadow, bool, false) \
HANDLE_COMPOSER_PROPERTY(shdwbias, m_ShadowBias, float, 0.0f) \
HANDLE_COMPOSER_PROPERTY(shdwfactor, m_ShadowFactor, float, 5.0f) \
- HANDLE_COMPOSER_PROPERTY(shdwmapres, m_ShadowMapRes, qt3ds::QT3DSI32, 9) \
+ HANDLE_COMPOSER_PROPERTY(shdwmapres, m_ShadowMapRes, qt3ds::QT3DSI32, 9) \
HANDLE_COMPOSER_PROPERTY(shdwmapfar, m_ShadowMapFar, float, 5000.0f) \
HANDLE_COMPOSER_PROPERTY(shdwmapfov, m_ShadowMapFov, float, 90.0f) \
HANDLE_COMPOSER_PROPERTY(shdwfilter, m_ShadowFilter, float, 35.0f) \
@@ -280,13 +281,13 @@ class IPropertySystem;
HANDLE_COMPOSER_PROPERTY(dropshadow, m_DropShadow, bool, false) \
HANDLE_COMPOSER_PROPERTY(dropshadowstrength, m_DropShadowStrength, float, 80.f) \
HANDLE_COMPOSER_PROPERTY(dropshadowoffset, m_DropShadowOffset, float, 10.f) \
- HANDLE_COMPOSER_PROPERTY(dropshadowoffsetx, m_DropShadowOffsetX, float, 0.f) \
- HANDLE_COMPOSER_PROPERTY(dropshadowoffsety, m_DropShadowOffsetY, float, 0.f) \
- HANDLE_COMPOSER_PROPERTY(dropshadowhorzalign, m_DropShadowHorizontalAlignment, TDataStrPtr, L"Right") \
- HANDLE_COMPOSER_PROPERTY(dropshadowvertalign, m_DropShadowVerticalAlignment, TDataStrPtr, L"Bottom") \
+ HANDLE_COMPOSER_PROPERTY(dropshadowoffsetx, m_DropShadowOffsetX, float, 0.f) \
+ HANDLE_COMPOSER_PROPERTY(dropshadowoffsety, m_DropShadowOffsetY, float, 0.f) \
+ HANDLE_COMPOSER_PROPERTY(dropshadowhorzalign, m_DropShadowHorizontalAlignment, TDataStrPtr, L"Right") \
+ HANDLE_COMPOSER_PROPERTY(dropshadowvertalign, m_DropShadowVerticalAlignment, TDataStrPtr, L"Bottom") \
HANDLE_COMPOSER_PROPERTY(wordwrap, m_WordWrap, TDataStrPtr, L"WrapWord") \
HANDLE_COMPOSER_PROPERTY(boundingbox, m_BoundingBox, SFloat2, SFloat2(0, 0)) \
- HANDLE_COMPOSER_PROPERTY(elide, m_Elide, bool, false) \
+ HANDLE_COMPOSER_PROPERTY(elide, m_Elide, TDataStrPtr, L"ElideNone") \
HANDLE_COMPOSER_PROPERTY(enableacceleratedfont, m_EnableAcceleratedFont, bool, false) \
HANDLE_COMPOSER_PROPERTY_DUPLICATE(controlledproperty, m_ControlledProperty, TDataStrPtr, L"")
@@ -373,14 +374,14 @@ struct DataTypeToTypeMap
bool force_compile_error;
};
-#define QT3DSDM_DEFINE_TYPE_TO_DATA_TYPE(enumName, type) \
+#define QT3DSDM_DEFINE_TYPE_TO_DATA_TYPE(enumName, type) \
template <> \
struct TypeToDataTypeMap<type> \
{ \
- static DataModelDataType::Value GetDataType() { return enumName; } \
+ static DataModelDataType::Value GetDataType() { return enumName; } \
}; \
template <> \
- struct DataTypeToTypeMap<enumName> \
+ struct DataTypeToTypeMap<enumName> \
{ \
typedef type TDataType; \
};
@@ -449,9 +450,9 @@ struct SComposerTypePropertyDefinition
template <> \
struct SComposerTypePropertyDefinition<ComposerObjectTypes::name> \
{ \
- bool reserved; \
+ bool reserved; \
propmacro SComposerTypePropertyDefinition(IDataCore &inCore, \
- Qt3DSDMInstanceHandle inInstance); \
+ Qt3DSDMInstanceHandle inInstance); \
};
ITERATE_COMPOSER_OBJECT_TYPES
@@ -933,7 +934,7 @@ public:
IDataCore &inDataCore,
IMetaData &inMetaData /*, ISlideCore& inSlideCore, IPropertySystem& inPropertySystem */);
- ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ ////////////////////////////////////////////////////////////////////////////////////////////////
// RTTI API
bool IsA(Qt3DSDMInstanceHandle inInstance, ComposerObjectTypes::Enum inType);
// Could easily return None, meaning we can't identify the object type.
diff --git a/src/Authoring/Studio/Application/DataInputDlg.cpp b/src/Authoring/Studio/Application/DataInputDlg.cpp
index 0a31424d..9bfec2a0 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.cpp
+++ b/src/Authoring/Studio/Application/DataInputDlg.cpp
@@ -28,6 +28,7 @@
#include "DataInputDlg.h"
#include "ui_DataInputDlg.h"
+#include "Qt3DSMessageBox.h"
#include <QtWidgets/qabstractbutton.h>
#include <QtGui/qstandarditemmodel.h>
@@ -43,6 +44,8 @@ CDataInputDlg::CDataInputDlg(CDataInputDialogItem **datainput, QStandardItemMode
, m_type(0)
, m_min(0.0)
, m_max(10.0)
+ , m_metadataKey(m_dataInput->metaDataKey)
+ , m_metadata(m_dataInput->metaData)
, m_acceptedTypes(acceptedTypes)
{
m_ui->setupUi(this);
@@ -87,6 +90,10 @@ CDataInputDlg::CDataInputDlg(CDataInputDialogItem **datainput, QStandardItemMode
this, &CDataInputDlg::onMaxChanged);
connect(m_ui->lineEditInputName, &QLineEdit::textChanged, this, &CDataInputDlg::onNameChanged);
connect(m_ui->lineEditEvaluation, &QLineEdit::textChanged, this, &CDataInputDlg::onTextChanged);
+ connect(m_ui->lineEditMetadata, &QLineEdit::textChanged, this,
+ &CDataInputDlg::onMetadataChanged);
+ connect(m_ui->lineEditMetadataKey, &QLineEdit::textChanged, this,
+ &CDataInputDlg::onMetadataKeyChanged);
}
CDataInputDlg::~CDataInputDlg()
@@ -127,11 +134,20 @@ void CDataInputDlg::initDialog()
m_ui->doubleSpinBoxMax->setValue(m_dataInput->maxValue);
}
+ m_metadata = m_dataInput->metaData;
+ m_metadataKey = m_dataInput->metaDataKey;
+ m_ui->lineEditMetadata->setText(m_metadata);
+ m_ui->lineEditMetadataKey->setText(m_metadataKey);
updateVisibility(m_dataInput->type);
}
void CDataInputDlg::accept()
{
+ if (m_metadataKey.isEmpty() && !m_metadata.isEmpty()) {
+ Qt3DSMessageBox::Show(tr("Metadata Error"), tr("Metadata key cannot be empty."),
+ Qt3DSMessageBox::ICON_WARNING, false, this);
+ return;
+ }
if (m_dataInput->name != m_name)
m_dataInput->name = getUniqueId(m_name);
@@ -145,6 +161,8 @@ void CDataInputDlg::accept()
m_dataInput->valueString = m_text;
}
#endif
+ m_dataInput->metaData = m_metadata;
+ m_dataInput->metaDataKey = m_metadataKey;
QDialog::accept();
}
@@ -181,6 +199,22 @@ void CDataInputDlg::onTextChanged(const QString &text)
m_text = text;
}
+void CDataInputDlg::onMetadataChanged(const QString &metadata)
+{
+ int cursorPos = m_ui->lineEditMetadata->cursorPosition();
+ m_metadata = metadata;
+ m_ui->lineEditMetadata->setText(metadata);
+ m_ui->lineEditMetadata->setCursorPosition(cursorPos);
+}
+
+void CDataInputDlg::onMetadataKeyChanged(const QString &metadataKey)
+{
+ int cursorPos = m_ui->lineEditMetadataKey->cursorPosition();
+ m_metadataKey = metadataKey;
+ m_ui->lineEditMetadataKey->setText(metadataKey);
+ m_ui->lineEditMetadataKey->setCursorPosition(cursorPos);
+}
+
QString CDataInputDlg::getUniqueId(const QString &id)
{
QString retval = QStringLiteral("%1").arg(id);
diff --git a/src/Authoring/Studio/Application/DataInputDlg.h b/src/Authoring/Studio/Application/DataInputDlg.h
index b560c7cc..49593cd4 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.h
+++ b/src/Authoring/Studio/Application/DataInputDlg.h
@@ -99,6 +99,8 @@ private Q_SLOTS:
void onMaxChanged(float max);
void onNameChanged(const QString &name);
void onTextChanged(const QString &text);
+ void onMetadataChanged(const QString &metadata);
+ void onMetadataKeyChanged(const QString &metadataKey);
private:
Ui::DataInputDlg *m_ui;
@@ -109,6 +111,8 @@ private:
float m_min;
int m_type;
QString m_text;
+ QString m_metadataKey;
+ QString m_metadata;
QVector<EDataType> m_acceptedTypes;
};
diff --git a/src/Authoring/Studio/Application/DataInputDlg.ui b/src/Authoring/Studio/Application/DataInputDlg.ui
index b27218c4..982e2d4f 100644
--- a/src/Authoring/Studio/Application/DataInputDlg.ui
+++ b/src/Authoring/Studio/Application/DataInputDlg.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>533</width>
- <height>244</height>
+ <height>300</height>
</rect>
</property>
<property name="windowTitle">
@@ -133,6 +133,32 @@
</spacer>
</item>
<item>
+ <widget class="QLabel" name="labelMetadataKey">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Metadata Key</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="labelMetadata">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>24</height>
+ </size>
+ </property>
+ <property name="text">
+ <string>Metadata</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLabel" name="labelEvaluation">
<property name="minimumSize">
<size>
@@ -261,6 +287,20 @@
</spacer>
</item>
<item>
+ <widget class="QLineEdit" name="lineEditMetadataKey">
+ <property name="toolTip">
+ <string>Key for accessing the metadata for this Data Input</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditMetadata">
+ <property name="toolTip">
+ <string>Metadata associated with this Data Input</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QLineEdit" name="lineEditEvaluation">
<property name="toolTip">
<string/>
diff --git a/src/Authoring/Studio/Application/DataInputListDlg.cpp b/src/Authoring/Studio/Application/DataInputListDlg.cpp
index 4ba31ca9..dbf8d5e5 100644
--- a/src/Authoring/Studio/Application/DataInputListDlg.cpp
+++ b/src/Authoring/Studio/Application/DataInputListDlg.cpp
@@ -141,7 +141,7 @@ void CDataInputListDlg::initDialog()
m_ui->elementInfo->setFocusPolicy(Qt::NoFocus);
m_ui->elementInfo->resizeColumnsToContents();
m_ui->elementInfo->horizontalHeader()->setStretchLastSection(true);
- m_ui->elementInfo->horizontalHeader()->setMinimumSectionSize(125);
+ m_ui->elementInfo->horizontalHeader()->setMinimumSectionSize(140);
m_ui->elementInfo->setModel(m_infoContents);
m_ui->elementInfo->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft);
@@ -190,7 +190,7 @@ void CDataInputListDlg::updateContents()
for (auto &it : qAsConst(m_dataInputs)) {
dataInput.clear();
- int dataInputType = it->type;
+ EDataType dataInputType = (EDataType)it->type;
if ((dataInputType == m_typeFilter || m_typeFilter == -1)
&& it->name.contains(m_searchString)){
@@ -235,6 +235,26 @@ void CDataInputListDlg::updateContents()
// highlight datainputs that are in use
if (it->ctrldElems.size() || it->externalPresBoundTypes.size())
dataInput.first()->setForeground(QBrush(CStudioPreferences::dataInputColor()));
+
+ // warn if any datainputs have mismatching datatype with an icon after datatype
+ // indicator
+ static QString warning(tr("Data Input type is not matching with one "
+ "or several bound properties"));
+ for (const auto &ctrlElem : qAsConst(it->ctrldElems)) {
+ if (!CDataInputDlg::getAcceptedTypes(ctrlElem.dataType.first)
+ .contains(dataInputType)) {
+ dataInput[1]->setIcon(QIcon(":/images/warning.png"));
+ dataInput[1]->setToolTip(warning);
+ }
+ }
+
+ for (const auto &extBoundType : qAsConst(it->externalPresBoundTypes)) {
+ if (!CDataInputDlg::getAcceptedTypes(extBoundType.first).contains(dataInputType)) {
+ dataInput[1]->setIcon(QIcon(":/images/warning.png"));
+ dataInput[1]->setToolTip(warning);
+ }
+ }
+
m_tableContents->appendRow(dataInput);
}
}
@@ -260,6 +280,7 @@ void CDataInputListDlg::updateInfo()
if (m_ui->tableView->selectionModel()->selectedRows(0).size() == 1) {
for (auto allCtrldElemsIt = m_dataInputs[m_currentDataInputName]->ctrldElems.begin();
allCtrldElemsIt != m_dataInputs[m_currentDataInputName]->ctrldElems.end();) {
+ bool typeNotMatching = false;
QStandardItem *item = new QStandardItem(
g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()
->GetClientDataModelBridge()->GetName(
@@ -297,6 +318,13 @@ void CDataInputListDlg::updateInfo()
}
count++;
+
+ // Check if there is a non-matching datatype binding with one or several
+ // properties for this element.
+ if (!CDataInputDlg::getAcceptedTypes(allCtrldElemsIt->dataType.first).contains(
+ (EDataType)(m_dataInputs[m_currentDataInputName]->type))) {
+ typeNotMatching = true;
+ }
// Advance main iterator so that after the inner loop we end up
// at the start of next instance's batch of controlleditems.
allCtrldElemsIt++;
@@ -310,6 +338,15 @@ void CDataInputListDlg::updateInfo()
QStandardItem *item3 = new QStandardItem(propNames);
item3->setToolTip(propNames);
item3->setEditable(false);
+
+ // Highlight the entire property name item if a non-match was found.
+ if (typeNotMatching) {
+ item3->setForeground(
+ QBrush(CStudioPreferences::invalidDataInputIndicatorColor()));
+ static QString warning(tr("\n\nData Input type is not matching with one or "
+ "several bound properties"));
+ item3->setToolTip(propNames + warning);
+ }
m_infoContents->appendRow(QList<QStandardItem *>({item, item2, item3}));
}
}
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.cpp b/src/Authoring/Studio/Application/DurationEditDlg.cpp
index 0d7c4899..f0707a56 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.cpp
+++ b/src/Authoring/Studio/Application/DurationEditDlg.cpp
@@ -29,33 +29,15 @@
#include "ui_DurationEditDlg.h"
#include "DurationEditDlg.h"
-#include "IDoc.h"
-#include "Bindings/ITimelineKeyframesManager.h"
-
+#include "TimeEnums.h"
#include <QtGui/qvalidator.h>
-//=============================================================================
-/**
- * Constructor
- */
-CDurationEditDlg::CDurationEditDlg(QWidget *pParent)
- : QDialog(pParent)
+CDurationEditDlg::CDurationEditDlg(QWidget *parent)
+ : QDialog(parent)
, m_ui(new Ui::DurationEditDlg)
- , m_Doc(nullptr)
- , m_KeyframesManager(nullptr)
- , m_Callback(nullptr)
- , m_MaxTime(0)
- , m_MaxTimeDisplay(0)
- , m_MinTimeDisplay(0)
- , m_InitialTimeStart(0)
- , m_InitialTimeEnd(0)
- , m_minStart(-1)
- , m_secStart(-1)
- , m_minEnd(-1)
- , m_secEnd(-1)
{
m_ui->setupUi(this);
- setAutoFillBackground(true);
+ setWindowFlag(Qt::WindowContextHelpButtonHint, false); // remove '?' from the dialog title bar
QIntValidator *minValidator = new QIntValidator(this);
minValidator->setRange(0, 9999);
@@ -83,8 +65,6 @@ CDurationEditDlg::CDurationEditDlg(QWidget *pParent)
this, &CDurationEditDlg::onEndTimeChanged);
connect(m_ui->lineEditEndMilliseconds, &QLineEdit::textEdited,
this, &CDurationEditDlg::onEndTimeChanged);
-
- window()->setFixedSize(size());
}
CDurationEditDlg::~CDurationEditDlg()
@@ -92,72 +72,50 @@ CDurationEditDlg::~CDurationEditDlg()
delete m_ui;
}
-void CDurationEditDlg::setKeyframesManager(ITimelineKeyframesManager *inKeyframesManager)
-{
- m_KeyframesManager = inKeyframesManager;
-}
-
-//=============================================================================
/**
- * showDialog: Initializes and shows the Duration Edit Dialog Box.
+ * Initializes and shows the Duration Edit Dialog Box.
* @param startTime is the initial start time, which will be shown when the time edit
* dialog box pops up
* @param endTime is the initial end time, which will be shown when the time edit
* dialog box pops up
- * @param inDoc this can be nullptr where its not applicable
* @param inCallback is the target object for the callbacks
*/
-void CDurationEditDlg::showDialog(long startTime, long endTime, IDoc *inDoc,
- ITimeChangeCallback *inCallback)
+void CDurationEditDlg::showDialog(long startTime, long endTime, ITimeChangeCallback *inCallback)
{
- m_InitialTimeStart = startTime;
- m_InitialTimeEnd = endTime;
- m_Doc = inDoc;
m_Callback = inCallback;
- m_MinTimeDisplay = 0;
- // if it is a Timebar, this will be adjusted, else this should be initialized to some value at
- // least, for OverflowHandling to work correctly
- m_MaxTimeDisplay = LONG_MAX;
-
- // 9999:59:999 converted to milliseconds
- m_MaxTime = timeConversion(9999, CONVERT_MIN_TO_MSEC)
- + timeConversion(59, CONVERT_SEC_TO_MSEC) + 999;
-
// Set initial values to dialog
- formatTime(m_InitialTimeStart, true);
- formatTime(m_InitialTimeEnd, false);
+ formatTime(startTime, true);
+ formatTime(endTime, false);
- // Present the dialog
exec();
}
void CDurationEditDlg::formatTime(long inTime, bool startTime)
{
- long theTime = inTime;
- long min = 0;
- long sec = 0;
- long msec = 0;
+ long mins = 0;
+ long secs = 0;
+ long mils = 0;
- // Translates the m_initialTime (in milliseconds) into Minutes, Seconds and Milliseconds
if (inTime != 0) {
- min = timeConversion(theTime, CONVERT_MSEC_TO_MIN);
- theTime = theTime - timeConversion(min, CONVERT_MIN_TO_MSEC);
- sec = timeConversion(theTime, CONVERT_MSEC_TO_SEC);
- theTime = theTime - timeConversion(sec, CONVERT_SEC_TO_MSEC);
- msec = theTime;
+ mins = inTime % 3600000 / 60000;
+ secs = inTime % 60000 / 1000;
+ mils = inTime % 1000;
}
+ // display milliseconds in 3 digits (5 -> 005)
+ QString milsStr = QString("%1").arg(mils, 3, 10, QChar('0'));
+
if (startTime) {
- m_ui->lineEditMinutes->setText(QString::number(min));
- m_ui->lineEditSeconds->setText(QString::number(sec));
- m_ui->lineEditMilliseconds->setText(QString::number(msec));
+ m_ui->lineEditMinutes->setText(QString::number(mins));
+ m_ui->lineEditSeconds->setText(QString::number(secs));
+ m_ui->lineEditMilliseconds->setText(milsStr);
// Select the biggest non-zero unit
- if (min > 0) {
+ if (mins > 0) {
m_ui->lineEditMinutes->setFocus();
m_ui->lineEditMinutes->selectAll();
- } else if (sec > 0) {
+ } else if (secs > 0) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
} else {
@@ -165,17 +123,12 @@ void CDurationEditDlg::formatTime(long inTime, bool startTime)
m_ui->lineEditMilliseconds->selectAll();
}
} else {
- m_ui->lineEditEndMinutes->setText(QString::number(min));
- m_ui->lineEditEndSeconds->setText(QString::number(sec));
- m_ui->lineEditEndMilliseconds->setText(QString::number(msec));
+ m_ui->lineEditEndMinutes->setText(QString::number(mins));
+ m_ui->lineEditEndSeconds->setText(QString::number(secs));
+ m_ui->lineEditEndMilliseconds->setText(milsStr);
}
}
-void CDurationEditDlg::showEvent(QShowEvent *ev)
-{
- QDialog::showEvent(ev);
-}
-
void CDurationEditDlg::accept()
{
m_Callback->Commit();
@@ -188,94 +141,6 @@ void CDurationEditDlg::reject()
QDialog::reject();
}
-long CDurationEditDlg::numberOfDigits(long number)
-{
- long theNumberOfDigits = 0;
- for (long theNumber = number; theNumber >= 1; theNumber = theNumber / 10)
- theNumberOfDigits++;
- return theNumberOfDigits;
-}
-
-//==============================================================================
-/**
- * timeConversion: Converts inTime to the format specified by inFlags.
- * For example:
- * inTime = 5 sec inFlags = CONVERT_SEC_TO_MSEC
- * The method will convert 5 sec into 5000 msec and
- * returns the result.
- * @param inTime stores the time to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inTime.
- * @return theResult stores the result of the time conversion.
- */
-long CDurationEditDlg::timeConversion(long inTime, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_MIN_TO_MSEC:
- theResult = inTime * 60 * 1000;
- break;
- case CONVERT_SEC_TO_MSEC:
- theResult = inTime * 1000;
- break;
- case CONVERT_MSEC_TO_MIN:
- theResult = inTime / (60 * 1000);
- break;
- case CONVERT_MSEC_TO_SEC:
- theResult = inTime / 1000;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in mins:secs:msec and convert it to
- * the corresponding time in msec.
- * @param inMin stores the minutes to be converted.
- * inSec stores the seconds to be converted.
- * inMsec stores the milliseconds to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inMin, inSec and inMsec.
- * @return theResult stores the result of the time conversion.
- */
-long CDurationEditDlg::timeConversion(long inMin, long inSec, long inMsec, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_TIME_TO_MSEC:
- theResult = timeConversion(inMin, CONVERT_MIN_TO_MSEC)
- + timeConversion(inSec, CONVERT_SEC_TO_MSEC) + inMsec;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in milliseconds and converts them
- * to min : sec : msec.
- * @param inTotalTime stores the total time in msec.
- * ioMin stores the mins result of the time conversion
- * ioSec stores the secs result of the time conversion
- * ioMsec stores the msecs result of the time conversion
- * inOperationCode determines the type of time conversion to be done on the
- * inTotalTime.
- */
-void CDurationEditDlg::timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode)
-{
- switch (inOperationCode) {
- case CONVERT_MSEC_TO_MIN_SEC_MSEC:
- *ioMin = timeConversion(inTotalTime, CONVERT_MSEC_TO_MIN);
- *ioSec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC);
- *ioSec = timeConversion(*ioSec, CONVERT_MSEC_TO_SEC);
- *ioMsec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC)
- - timeConversion(*ioSec, CONVERT_SEC_TO_MSEC);
- break;
- }
-}
-
void CDurationEditDlg::updateObjectTime(long inTime, bool startTime)
{
if (m_Callback) {
@@ -288,59 +153,42 @@ void CDurationEditDlg::updateObjectTime(long inTime, bool startTime)
void CDurationEditDlg::onStartTimeChanged()
{
- // Making sure that the start time is not greater than the end time, when
- // the user modifies the start time of the timebar
- m_MaxTimeDisplay = m_InitialTimeEnd; // the initial end time
- m_MinTimeDisplay = 0;
-
long min = m_ui->lineEditMinutes->text().toInt();
long sec = m_ui->lineEditSeconds->text().toInt();
long msec = m_ui->lineEditMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
// Go to the time specified in the start time edit display
updateObjectTime(theGoToTime, true);
// If max number of digits reached in a number field, select the next
- if (m_minStart != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditMinutes->hasFocus() && min > 999) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
- } else if (m_secStart != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditSeconds->hasFocus() && sec > 9) {
m_ui->lineEditMilliseconds->setFocus();
m_ui->lineEditMilliseconds->selectAll();
}
-
- m_minStart = min;
- m_secStart = sec;
}
void CDurationEditDlg::onEndTimeChanged()
{
- // Let the end time of the time bar go as far as possible
- m_MaxTimeDisplay = m_MaxTime;
- m_MinTimeDisplay = m_InitialTimeStart; // the initial start time
-
long min = m_ui->lineEditEndMinutes->text().toInt();
long sec = m_ui->lineEditEndSeconds->text().toInt();
long msec = m_ui->lineEditEndMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
// Go to the time specified in the end time edit display
updateObjectTime(theGoToTime, false);
// If max number of digits reached in a number field, select the next
- if (m_minEnd != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditEndMinutes->hasFocus() && min > 999) {
m_ui->lineEditEndSeconds->setFocus();
m_ui->lineEditEndSeconds->selectAll();
- } else if (m_secEnd != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditEndSeconds->hasFocus() && sec > 9) {
m_ui->lineEditEndMilliseconds->setFocus();
m_ui->lineEditEndMilliseconds->selectAll();
}
-
- m_minEnd = min;
- m_secEnd = sec;
}
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.h b/src/Authoring/Studio/Application/DurationEditDlg.h
index 7630b02a..ddb42ec0 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.h
+++ b/src/Authoring/Studio/Application/DurationEditDlg.h
@@ -30,12 +30,9 @@
#ifndef DURATION_EDIT_DIALOG_H
#define DURATION_EDIT_DIALOG_H
-#include "TimeEnums.h"
#include <QtWidgets/qdialog.h>
-class CTimebarControl;
class IDoc;
-class ITimelineKeyframesManager;
class ITimeChangeCallback
{
@@ -62,43 +59,23 @@ class CDurationEditDlg : public QDialog
Q_OBJECT
public:
- CDurationEditDlg(QWidget *pParent = nullptr); // standard constructor
- virtual ~CDurationEditDlg();
- void setKeyframesManager(ITimelineKeyframesManager *inKeyframeManager);
- void showDialog(long startTime, long endTime, IDoc *inDoc,
- ITimeChangeCallback *inCallback = nullptr);
+ CDurationEditDlg(QWidget *parent = nullptr);
+ ~CDurationEditDlg() override;
+
+ void showDialog(long startTime, long endTime, ITimeChangeCallback *inCallback = nullptr);
public Q_SLOTS:
void accept() override;
void reject() override;
-protected:
- void showEvent(QShowEvent *) override;
-
+private:
void onStartTimeChanged();
void onEndTimeChanged();
void formatTime(long inTime, bool startTime);
- long numberOfDigits(long number);
- long timeConversion(long inTime, long inOperationCode);
- long timeConversion(long inMin, long inSec, long inMsec, long inOperationCode);
- void timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode);
void updateObjectTime(long inTime, bool startTime);
-protected:
Ui::DurationEditDlg *m_ui;
- IDoc *m_Doc;
- ITimelineKeyframesManager *m_KeyframesManager;
- ITimeChangeCallback *m_Callback;
- long m_MaxTime;
- long m_MaxTimeDisplay;
- long m_MinTimeDisplay;
- long m_InitialTimeStart;
- long m_InitialTimeEnd;
- int m_minStart;
- int m_secStart;
- int m_minEnd;
- int m_secEnd;
+ ITimeChangeCallback *m_Callback = nullptr;
};
#endif // DURATION_EDIT_DIALOG_H
diff --git a/src/Authoring/Studio/Application/DurationEditDlg.ui b/src/Authoring/Studio/Application/DurationEditDlg.ui
index 062a5051..4f6bb7de 100644
--- a/src/Authoring/Studio/Application/DurationEditDlg.ui
+++ b/src/Authoring/Studio/Application/DurationEditDlg.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>300</width>
+ <width>343</width>
<height>152</height>
</rect>
</property>
@@ -14,6 +14,9 @@
<string>Set Timebar Start / End Time</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
<property name="leftMargin">
<number>0</number>
</property>
@@ -70,7 +73,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMinutes"/>
+ <widget class="QLineEdit" name="lineEditMinutes">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_2">
@@ -80,7 +90,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditSeconds"/>
+ <widget class="QLineEdit" name="lineEditSeconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_3">
@@ -90,7 +107,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditMilliseconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
@@ -124,7 +148,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndMinutes"/>
+ <widget class="QLineEdit" name="lineEditEndMinutes">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_7">
@@ -134,7 +165,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndSeconds"/>
+ <widget class="QLineEdit" name="lineEditEndSeconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_8">
@@ -144,7 +182,14 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditEndMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditEndMilliseconds">
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
diff --git a/src/Authoring/Studio/Application/ProjectFile.cpp b/src/Authoring/Studio/Application/ProjectFile.cpp
index a2792049..a4b5b9c0 100644
--- a/src/Authoring/Studio/Application/ProjectFile.cpp
+++ b/src/Authoring/Studio/Application/ProjectFile.cpp
@@ -43,6 +43,8 @@
#include <QtCore/qdiriterator.h>
#include <QtCore/qsavefile.h>
#include <QtCore/qtimer.h>
+#include <QtCore/qrandom.h>
+#include <QtWidgets/qmessagebox.h>
ProjectFile::ProjectFile()
{
@@ -493,6 +495,8 @@ void ProjectFile::parseDataInputElem(const QDomElement &elem,
item->valueString = elem.attribute(QStringLiteral("evaluator"));
}
#endif
+ item->metaDataKey = elem.attribute((QStringLiteral("metadatakey")));
+ item->metaData = elem.attribute((QStringLiteral("metadata")));
dataInputs.insert(item->name, item);
}
}
@@ -926,3 +930,676 @@ ProjectFile::getDiBindingtypesFromSubpresentations() const
return map;
}
+
+/**
+ * Load variants data to m_variantsDef
+ *
+ * @param filePath the file path to load the variants from. If empty, variants are loaded from the
+ * project file and replace m_variantsDef. If a filePath is specified, the loaded
+ * variants are merged with m_variantsDef
+ */
+void ProjectFile::loadVariants(const QString &filePath)
+{
+ if (!m_fileInfo.exists())
+ return;
+
+ bool isProj = filePath.isEmpty() || filePath == getProjectFilePath();
+ QFile file(isProj ? getProjectFilePath() : filePath);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return;
+ }
+
+ if (isProj)
+ m_variantsDef.clear();
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ VariantGroup *currentGroup = nullptr;
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("variantgroup")) {
+ QString groupId = reader.attributes().value(QLatin1String("id")).toString();
+ QString groupColor = reader.attributes().value(QLatin1String("color")).toString();
+ currentGroup = &m_variantsDef[groupId];
+ currentGroup->m_color = groupColor;
+ } else if (reader.name() == QLatin1String("variant")) {
+ if (currentGroup) {
+ QString tagId = reader.attributes().value(QLatin1String("id")).toString();
+ if (!currentGroup->m_tags.contains(tagId))
+ currentGroup->m_tags.append(tagId);
+ } else {
+ qWarning() << "Error parsing variant tags.";
+ }
+ } else if (currentGroup) {
+ break;
+ }
+ }
+ }
+
+ if (!isProj) {
+ // if loading variants from a file, update the uia
+ QDomDocument domDoc;
+ QSaveFile fileProj(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(fileProj, domDoc))
+ return;
+
+ QDomElement vElem = domDoc.documentElement().firstChildElement(QStringLiteral("variants"));
+ if (!vElem.isNull())
+ domDoc.documentElement().removeChild(vElem);
+
+ vElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.documentElement().appendChild(vElem);
+
+ const auto keys = m_variantsDef.keys();
+ for (auto &g : keys) {
+ QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ gElem.setAttribute(QStringLiteral("id"), g);
+ gElem.setAttribute(QStringLiteral("color"), m_variantsDef[g].m_color);
+ vElem.appendChild(gElem);
+
+ for (auto &t : qAsConst(m_variantsDef[g].m_tags)) {
+ QDomElement tElem = domDoc.createElement(QStringLiteral("variant"));
+ tElem.setAttribute(QStringLiteral("id"), t);
+ gElem.appendChild(tElem);
+ }
+ }
+
+ StudioUtils::commitDomDocumentSave(fileProj, domDoc);
+ }
+}
+
+// Add a new tag to a variants group
+void ProjectFile::addVariantTag(const QString &group, const QString &newTag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomElement newTagElem = domDoc.createElement(QStringLiteral("variant"));
+ newTagElem.setAttribute(QStringLiteral("id"), newTag);
+
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ // update and save the uia
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ gElem.appendChild(newTagElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_tags.append(newTag);
+}
+
+// Add a new group, it is assumes that the new group name is unique
+void ProjectFile::addVariantGroup(const QString &newGroup)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomElement variantsElem = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"));
+
+ if (variantsElem.isNull()) {
+ QDomElement newVariantsElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.documentElement().appendChild(newVariantsElem);
+ variantsElem = newVariantsElem;
+ }
+
+ // generate random semi-bright color
+ int r = 0x555555 + QRandomGenerator::global()->generate() % 0x555555; // 0x555555 = 0xffffff / 3
+ QString newColor = QLatin1Char('#') + QString::number(r, 16);
+
+ QDomElement newGroupElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ newGroupElem.setAttribute(QStringLiteral("id"), newGroup);
+ newGroupElem.setAttribute(QStringLiteral("color"), newColor);
+ variantsElem.appendChild(newGroupElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+
+ // update m_variantsDef
+ VariantGroup g;
+ g.m_color = newColor;
+ m_variantsDef[newGroup] = g;
+}
+
+void ProjectFile::renameVariantTag(const QString &group, const QString &oldTag,
+ const QString &newTag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // rename the tag in all uip files
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ renameTagInUip(pPath, group, oldTag, newTag);
+ }
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ bool renamed = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ QDomNodeList tagsElems = gElem.childNodes();
+ for (int j = 0; j < tagsElems.count(); ++j) {
+ QDomElement tElem = tagsElems.at(j).toElement();
+ if (tElem.attribute(QStringLiteral("id")) == oldTag) {
+ tElem.setAttribute(QStringLiteral("id"), newTag);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ renamed = true;
+ break;
+ }
+ }
+ if (renamed)
+ break;
+ }
+ }
+
+ // update the property
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QString oldGroupTagPair = QStringLiteral("%1:%2").arg(group).arg(oldTag);
+ if (propVal.contains(oldGroupTagPair)) {
+ propVal.replace(oldGroupTagPair, QStringLiteral("%1:%2").arg(group).arg(newTag));
+ qt3dsdm::SValue sVal
+ = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update m_variantsDef
+ for (auto &t : m_variantsDef[group].m_tags) {
+ if (t == oldTag) {
+ t = newTag;
+ renamed = true;
+ break;
+ }
+ }
+}
+
+// rename a variant group, newGroup is assumed to be unique
+void ProjectFile::renameVariantGroup(const QString &oldGroup, const QString &newGroup)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // rename the group in all uip files
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ renameGroupInUip(pPath, oldGroup, newGroup);
+ }
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == oldGroup) {
+ gElem.setAttribute(QStringLiteral("id"), newGroup);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update the property
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QString oldGroupWithColon = QStringLiteral("%1:").arg(oldGroup);
+ if (propVal.contains(oldGroupWithColon)) {
+ propVal.replace(oldGroupWithColon, QStringLiteral("%1:").arg(newGroup));
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[newGroup] = m_variantsDef[oldGroup];
+ m_variantsDef.remove(oldGroup);
+}
+
+void ProjectFile::deleteVariantGroup(const QString &group)
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // check if group is in use in other presentations in the porject
+ int inUseIdx = -1; // index of first presentation that has the group in-use
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath() && groupExistsInUip(pPath, group)) {
+ inUseIdx = i;
+ break;
+ }
+ }
+
+ if (inUseIdx != -1) {
+ QMessageBox box;
+ box.setWindowTitle(tr("Group tags in use"));
+ box.setText(tr("Some tags in the Group '%1' are in use in the project, are you sure you"
+ " want to delete the group?").arg(group));
+ box.setIcon(QMessageBox::Warning);
+ box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete"));
+ switch (box.exec()) {
+ case QMessageBox::Yes:
+ // delete the group from all uips that use it
+ for (int i = inUseIdx; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath())
+ deleteGroupFromUip(pPath, group);
+ }
+ break;
+
+ default:
+ // abort deletion
+ return;
+ }
+ }
+
+ // delete the group from current uip, if exists
+ deleteGroupFromUip(doc->GetDocumentPath(), group);
+
+ // delete the group from the property (if set)
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (propVal.contains(QStringLiteral("%1:").arg(group))) {
+ // property has the deleted group, need to update it, else the deleted group
+ // will be saved the uip if the user saves the presentation.
+ QRegExp rgx(QStringLiteral("%1:\\w*,*|,%1:\\w*").arg(group));
+ propVal.replace(rgx, {});
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update and save the uia
+ QDomElement variantsElem = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"));
+ QDomNodeList groupsElems = variantsElem.elementsByTagName(QStringLiteral("variantgroup"));
+
+ bool deleted = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ variantsElem.removeChild(gElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ deleted = true;
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef.remove(group);
+}
+
+void ProjectFile::changeVariantGroupColor(const QString &group, const QString &newColor)
+{
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // update and save the uia
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ gElem.setAttribute(QStringLiteral("color"), newColor);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_color = newColor;
+}
+
+bool ProjectFile::tagExistsInUip(const QString &src, const QString &group, const QString &tag) const
+{
+ QFile file(src);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return false;
+ }
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("Layer")
+ && reader.attributes().hasAttribute(QLatin1String("variants"))) {
+ QStringRef v = reader.attributes().value(QLatin1String("variants"));
+ if (v.contains(group + QLatin1Char(':') + tag))
+ return true;
+ } else if (reader.name() == QLatin1String("Logic")) {
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ProjectFile::groupExistsInUip(const QString &src, const QString &group) const
+{
+ QFile file(src);
+ if (!file.open(QFile::Text | QFile::ReadOnly)) {
+ qWarning() << file.errorString();
+ return false;
+ }
+
+ QXmlStreamReader reader(&file);
+ reader.setNamespaceProcessing(false);
+
+ while (!reader.atEnd()) {
+ if (reader.readNextStartElement()) {
+ if (reader.name() == QLatin1String("Layer")
+ && reader.attributes().hasAttribute(QLatin1String("variants"))) {
+ QStringRef v = reader.attributes().value(QLatin1String("variants"));
+ if (v.contains(group + QLatin1Char(':')))
+ return true;
+ } else if (reader.name() == QLatin1String("Logic")) {
+ break;
+ }
+ }
+ }
+
+ return false;
+}
+
+// renames a tag (if exists) in all layers in a uip file
+void ProjectFile::renameTagInUip(const QString &src, const QString &group, const QString &tag,
+ const QString &newName)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QStringList tagPairs = lElem.attribute(QStringLiteral("variants"))
+ .split(QLatin1Char(','));
+ QString tagFrom = group + QLatin1Char(':') + tag;
+ QString tagTo = group + QLatin1Char(':') + newName;
+
+ if (tagPairs.contains(tagFrom)) {
+ tagPairs.replaceInStrings(tagFrom, tagTo);
+ lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(',')));
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+void ProjectFile::renameGroupInUip(const QString &src, const QString &group, const QString &newName)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QString variants = lElem.attribute(QStringLiteral("variants"));
+ if (variants.contains(group + QLatin1Char(':'))) {
+ variants.replace(group + QLatin1Char(':'), newName + QLatin1Char(':'));
+ lElem.setAttribute(QStringLiteral("variants"), variants);
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+// deletes a tag (if exists) from all layers in a uip file
+void ProjectFile::deleteTagFromUip(const QString &src, const QString &group, const QString &tag)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QStringList tagPairs = lElem.attribute(QStringLiteral("variants"))
+ .split(QLatin1Char(','));
+ QString tagPair = group + QLatin1Char(':') + tag;
+ if (tagPairs.contains(tagPair)) {
+ tagPairs.removeOne(tagPair);
+ lElem.setAttribute(QStringLiteral("variants"), tagPairs.join(QLatin1Char(',')));
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+// deletes a group (if exists) from all layers in a uip file
+void ProjectFile::deleteGroupFromUip(const QString &src, const QString &group)
+{
+ QDomDocument domDoc;
+ QSaveFile file(src);
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ QDomNodeList layerElems = domDoc.documentElement()
+ .elementsByTagName(QStringLiteral("Layer"));
+ bool needSave = false;
+ QRegExp rgx(group + ":\\w*,*|," + group + ":\\w*");
+ for (int i = 0; i < layerElems.count(); ++i) {
+ QDomElement lElem = layerElems.at(i).toElement();
+ if (lElem.hasAttribute(QStringLiteral("variants"))) {
+ QString val = lElem.attribute(QStringLiteral("variants"));
+ if (rgx.indexIn(val) != -1) {
+ val.replace(rgx, "");
+ lElem.setAttribute(QStringLiteral("variants"), val);
+ needSave = true;
+ }
+ }
+ }
+
+ if (needSave)
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+bool ProjectFile::isVariantGroupUnique(const QString &group) const
+{
+ return !m_variantsDef.contains(group);
+}
+
+bool ProjectFile::isVariantTagUnique(const QString &group, const QString &tag) const
+{
+ if (!m_variantsDef.contains(group))
+ return true;
+
+ return !m_variantsDef[group].m_tags.contains(tag);
+}
+
+void ProjectFile::deleteVariantTag(const QString &group, const QString &tag)
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ QDomDocument domDoc;
+ QSaveFile file(getProjectFilePath());
+ if (!StudioUtils::openDomDocumentSave(file, domDoc))
+ return;
+
+ // check if tag is in use in other presentations in the porject
+ int inUseIdx = -1; // list of presentations that has the tag in use
+ QDomNodeList presElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("assets"))
+ .elementsByTagName(QStringLiteral("presentation"));
+ for (int i = 0; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath()
+ && tagExistsInUip(pPath, group, tag)) {
+ inUseIdx = i;
+ break;
+ }
+ }
+
+ if (inUseIdx != -1) {
+ QMessageBox box;
+ box.setWindowTitle(tr("Tag in use"));
+ box.setText(tr("The tag '%1' is in use in another presentation, are you sure you want to"
+ " delete it?").arg(tag));
+ box.setIcon(QMessageBox::Warning);
+ box.setStandardButtons(QMessageBox::Yes | QMessageBox::Cancel);
+ box.setButtonText(QMessageBox::Yes, QStringLiteral("Delete"));
+ switch (box.exec()) {
+ case QMessageBox::Yes:
+ // delete the tag from all uips that use it
+ for (int i = inUseIdx; i < presElems.count(); ++i) {
+ QString pPath = m_fileInfo.path() + QLatin1Char('/')
+ + presElems.at(i).toElement().attribute(QStringLiteral("src"));
+ if (pPath != doc->GetDocumentPath())
+ deleteTagFromUip(pPath, group, tag);
+ }
+ break;
+
+ default:
+ // abort deletion
+ return;
+ }
+ }
+
+ // delete the tag from current doc, if exists
+ deleteTagFromUip(doc->GetDocumentPath(), group, tag);
+
+ QDomNodeList groupsElems = domDoc.documentElement()
+ .firstChildElement(QStringLiteral("variants"))
+ .elementsByTagName(QStringLiteral("variantgroup"));
+
+ // delete the tag from the property (if set)
+ const auto propertySystem = doc->GetStudioSystem()->GetPropertySystem();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ const auto layers = doc->getLayers();
+ auto property = bridge->GetLayer().m_variants;
+ for (auto layer : layers) {
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, property, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (propVal.contains(QStringLiteral("%1:%2").arg(group).arg(tag))) {
+ // property has the deleted tag, need to update it, else the deleted tag will be
+ // saved in the uip if the user saves the presentation.
+ QRegExp rgx(QStringLiteral("%1:%2,*|,%1:%2").arg(group).arg(tag));
+ propVal.replace(rgx, {});
+ qt3dsdm::SValue sVal = std::make_shared<qt3dsdm::CDataStr>(
+ Q3DStudio::CString::fromQString(propVal));
+ propertySystem->SetInstancePropertyValue(layer, property, sVal);
+ }
+ }
+ }
+
+ // update and save the uia
+ bool deleted = false;
+ for (int i = 0; i < groupsElems.count(); ++i) {
+ QDomElement gElem = groupsElems.at(i).toElement();
+ if (gElem.attribute(QStringLiteral("id")) == group) {
+ QDomNodeList tagsElems = gElem.childNodes();
+ for (int j = 0; j < tagsElems.count(); ++j) {
+ QDomElement tElem = tagsElems.at(j).toElement();
+ if (tElem.attribute(QStringLiteral("id")) == tag) {
+ gElem.removeChild(tElem);
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+ deleted = true;
+ break;
+ }
+ }
+ if (deleted)
+ break;
+ }
+ }
+
+ // update m_variantsDef
+ m_variantsDef[group].m_tags.removeOne(tag);
+}
diff --git a/src/Authoring/Studio/Application/ProjectFile.h b/src/Authoring/Studio/Application/ProjectFile.h
index 3e47da28..78ecc6d6 100644
--- a/src/Authoring/Studio/Application/ProjectFile.h
+++ b/src/Authoring/Studio/Application/ProjectFile.h
@@ -46,6 +46,11 @@ class ProjectFile : public QObject
public:
ProjectFile();
+ struct VariantGroup {
+ QString m_color;
+ QStringList m_tags;
+ };
+
void create(const QString &uiaPath);
void ensureProjectFile();
void initProjectFile(const QString &presPath);
@@ -81,6 +86,18 @@ public:
void deletePresentationFile(const QString &filePath);
void renameMaterial(const QString &oldName, const QString &newName);
bool duplicatePresentation(const QString &oldPres, const QString &newPres);
+ void loadVariants(const QString &filePath = {});
+ void addVariantTag(const QString &group, const QString &newTag);
+ void renameVariantTag(const QString &group, const QString &oldTag, const QString &newTag);
+ void deleteVariantTag(const QString &group, const QString &tag);
+ void addVariantGroup(const QString &newGroup);
+ void renameVariantGroup(const QString &oldGroup, const QString &newGroup);
+ void deleteVariantGroup(const QString &group);
+ void changeVariantGroupColor(const QString &group, const QString &newColor);
+ bool isVariantGroupUnique(const QString &group) const;
+ bool isVariantTagUnique(const QString &group, const QString &tag) const;
+
+ QHash<QString, VariantGroup> variantsDef() const { return m_variantsDef; }
Q_SIGNALS:
void presentationIdChanged(const QString &path, const QString &id);
@@ -88,9 +105,17 @@ Q_SIGNALS:
private:
QString ensureUniquePresentationId(const QString &id) const;
+ bool tagExistsInUip(const QString &src, const QString &group, const QString &tag) const;
+ bool groupExistsInUip(const QString &src, const QString &group) const;
+ void deleteTagFromUip(const QString &src, const QString &group, const QString &tag);
+ void deleteGroupFromUip(const QString &src, const QString &group);
+ void renameTagInUip(const QString &src, const QString &group, const QString &tag,
+ const QString &newName);
+ void renameGroupInUip(const QString &src, const QString &group, const QString &newName);
QFileInfo m_fileInfo; // uia file info
QString m_initialPresentation;
+ QHash<QString, VariantGroup> m_variantsDef; // definition of variants
};
#endif // PROJECTFILE_H
diff --git a/src/Authoring/Studio/Application/StudioApp.cpp b/src/Authoring/Studio/Application/StudioApp.cpp
index d6e589a4..c0fa435e 100644
--- a/src/Authoring/Studio/Application/StudioApp.cpp
+++ b/src/Authoring/Studio/Application/StudioApp.cpp
@@ -84,11 +84,15 @@ int main(int argc, char *argv[])
bool isOpenGLES = false;
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
#if !defined(Q_OS_MACOS)
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
#endif
SharedTools::QtSingleApplication guiApp(QStringLiteral("Qt3DStudio"), argc, argv);
+ // Fix for uia and uip file attribute random ordering (see QTBUG-8158)
+ qSetGlobalQHashSeed(1720419);
+
#if defined(Q_OS_MACOS)
QSurfaceFormat openGL33Format;
openGL33Format.setRenderableType(QSurfaceFormat::OpenGL);
@@ -1726,6 +1730,8 @@ bool CStudioApp::OnLoadDocument(const QString &inDocument, bool inShowStartupDia
m_core->getProjectFile().updateDocPresentationId();
m_core->getProjectFile().loadSubpresentationsAndDatainputs(m_subpresentations,
m_dataInputDialogItems);
+ m_core->getProjectFile().loadVariants();
+ GetViews()->getMainFrame()->getSlideView()->refreshVariants();
getRenderer().RegisterSubpresentations(m_subpresentations);
m_authorZoom = false;
@@ -1786,6 +1792,13 @@ void CStudioApp::saveDataInputsToProjectFile()
diNode.setAttribute(QStringLiteral("evaluator"), item->valueString);
}
#endif
+ // Let's allow storing key even if actual metadata is empty, as we
+ // do not know how the user code is going to interpret metadata contents.
+ if (!item->metaDataKey.isEmpty()) {
+ diNode.setAttribute(QStringLiteral("metadatakey"), item->metaDataKey);
+ if (!item->metaData.isEmpty())
+ diNode.setAttribute(QStringLiteral("metadata"), item->metaData);
+ }
assetsNode.appendChild(diNode);
}
StudioUtils::commitDomDocumentSave(file, doc);
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.cpp b/src/Authoring/Studio/Application/TimeEditDlg.cpp
index 499d6d57..eb9d0324 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.cpp
+++ b/src/Authoring/Studio/Application/TimeEditDlg.cpp
@@ -29,24 +29,17 @@
#include "ui_TimeEditDlg.h"
#include "TimeEditDlg.h"
+#include "KeyframeManager.h"
#include "IDoc.h"
-#include "Bindings/ITimelineKeyframesManager.h"
-
+#include "TimeEnums.h"
#include <QtGui/qvalidator.h>
-CTimeEditDlg::CTimeEditDlg(QWidget *pParent)
- : QDialog(pParent)
- , m_ui(new Ui::TimeEditDlg)
- , m_Doc(nullptr)
- , m_KeyframesManager(nullptr)
- , m_InitialTime(0)
- , m_ObjectAssociation(0)
- , m_OffsetFromInitialTime(0)
- , m_min(-1)
- , m_sec(-1)
+CTimeEditDlg::CTimeEditDlg(KeyframeManager *keyframeManager)
+ : m_ui(new Ui::TimeEditDlg)
+ , m_keyframeManager(keyframeManager)
{
m_ui->setupUi(this);
- setAutoFillBackground(true);
+ setWindowFlag(Qt::WindowContextHelpButtonHint, false); // remove '?' from the dialog title bar
QIntValidator *minValidator = new QIntValidator(this);
minValidator->setRange(0, 9999);
@@ -61,8 +54,6 @@ CTimeEditDlg::CTimeEditDlg(QWidget *pParent)
connect(m_ui->lineEditMinutes, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
connect(m_ui->lineEditSeconds, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
connect(m_ui->lineEditMilliseconds, &QLineEdit::textEdited, this, &CTimeEditDlg::onTimeChanged);
-
- window()->setFixedSize(size());
}
CTimeEditDlg::~CTimeEditDlg()
@@ -70,57 +61,48 @@ CTimeEditDlg::~CTimeEditDlg()
delete m_ui;
}
-void CTimeEditDlg::setKeyframesManager(ITimelineKeyframesManager *inKeyframesManager)
-{
- m_KeyframesManager = inKeyframesManager;
-}
-
-//=============================================================================
/**
- * showDialog: Initializes and shows the Time Edit Dialog Box.
- * @param inTime is the initial time, which will be shown when the time edit
- * dialog box pops up
+ * Initializes and shows the dialog
+ * @param inTime the initial time which will be shown when the dialog pops up
* @param inDoc this can be nullptr where its not applicable
- * @param inObjectAssociation is the identifier for that identifies the object
- * associated with the time edit dialog
- * (e.g. playhead, keyframe)
+ * @param inObjectAssociation the identifier for the object associated with the dialog (playhead
+ * or keyframe)
*/
void CTimeEditDlg::showDialog(long inTime, IDoc *inDoc, long inObjectAssociation)
{
- m_InitialTime = inTime;
- m_ObjectAssociation = inObjectAssociation;
+ m_initialTime = inTime;
+ m_objectAssociation = inObjectAssociation;
m_Doc = inDoc;
// Set initial values to dialog
- formatTime(m_InitialTime);
+ formatTime(m_initialTime);
exec();
}
void CTimeEditDlg::formatTime(long inTime)
{
- long theTime = inTime;
- long min = 0;
- long sec = 0;
- long msec = 0;
+ long mins = 0;
+ long secs = 0;
+ long mils = 0;
- // Translates the m_initialTime (in milliseconds) into Minutes, Seconds and Milliseconds
if (inTime != 0) {
- min = timeConversion(theTime, CONVERT_MSEC_TO_MIN);
- theTime = theTime - timeConversion(min, CONVERT_MIN_TO_MSEC);
- sec = timeConversion(theTime, CONVERT_MSEC_TO_SEC);
- theTime = theTime - timeConversion(sec, CONVERT_SEC_TO_MSEC);
- msec = theTime;
+ mins = inTime % 3600000 / 60000;
+ secs = inTime % 60000 / 1000;
+ mils = inTime % 1000;
}
- m_ui->lineEditMinutes->setText(QString::number(min));
- m_ui->lineEditSeconds->setText(QString::number(sec));
- m_ui->lineEditMilliseconds->setText(QString::number(msec));
+
+ // display milliseconds in 3 digits (5 -> 005)
+ QString milsStr = QString("%1").arg(mils, 3, 10, QChar('0'));
+ m_ui->lineEditMinutes->setText(QString::number(mins));
+ m_ui->lineEditSeconds->setText(QString::number(secs));
+ m_ui->lineEditMilliseconds->setText(milsStr);
// Select the biggest non-zero unit
- if (min > 0) {
+ if (mins > 0) {
m_ui->lineEditMinutes->setFocus();
m_ui->lineEditMinutes->selectAll();
- } else if (sec > 0) {
+ } else if (secs > 0) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
} else {
@@ -129,22 +111,23 @@ void CTimeEditDlg::formatTime(long inTime)
}
}
-void CTimeEditDlg::showEvent(QShowEvent *ev)
+void CTimeEditDlg::showEvent(QShowEvent *e)
{
onInitDialog();
- QDialog::showEvent(ev);
+ QDialog::showEvent(e);
}
void CTimeEditDlg::onInitDialog()
{
QString title;
// Display the window captions for the correct object type
- switch (m_ObjectAssociation) {
+ switch (m_objectAssociation) {
case PLAYHEAD:
title = QObject::tr("Go To Time");
break;
case ASSETKEYFRAME:
title = QObject::tr("Set Keyframe Time");
+ Q_ASSERT(m_keyframeManager != nullptr);
break;
}
setWindowTitle(title);
@@ -154,11 +137,11 @@ void CTimeEditDlg::onInitDialog()
void CTimeEditDlg::accept()
{
// Only commit here, cos dup keyframes will be deleted.
- if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager) {
- if (m_OffsetFromInitialTime == 0)
- m_KeyframesManager->RollbackChangedKeyframes();
+ if (m_objectAssociation == ASSETKEYFRAME && m_Doc) {
+ if (m_endTime == m_initialTime)
+ m_keyframeManager->RollbackChangedKeyframes();
else
- m_KeyframesManager->CommitChangedKeyframes();
+ m_keyframeManager->CommitChangedKeyframes();
}
QDialog::accept();
@@ -167,119 +150,26 @@ void CTimeEditDlg::accept()
void CTimeEditDlg::reject()
{
// Only commit here, cos dup keyframes will be deleted.
- if (m_ObjectAssociation == ASSETKEYFRAME && m_Doc && m_KeyframesManager)
- m_KeyframesManager->RollbackChangedKeyframes();
+ if (m_objectAssociation == ASSETKEYFRAME && m_Doc)
+ m_keyframeManager->RollbackChangedKeyframes();
QDialog::reject();
}
-int CTimeEditDlg::numberOfDigits(long number)
-{
- long theNumberOfDigits = 0;
- for (long theNumber = number; theNumber >= 1; theNumber = theNumber / 10)
- theNumberOfDigits++;
- return theNumberOfDigits;
-}
-
-//==============================================================================
/**
- * timeConversion: Converts inTime to the format specified by inFlags.
- * For example:
- * inTime = 5 sec inFlags = CONVERT_SEC_TO_MSEC
- * The method will convert 5 sec into 5000 msec and
- * returns the result.
- * @param inTime stores the time to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inTime.
- * @return theResult stores the result of the time conversion.
- */
-long CTimeEditDlg::timeConversion(long inTime, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_MIN_TO_MSEC:
- theResult = inTime * 60 * 1000;
- break;
- case CONVERT_SEC_TO_MSEC:
- theResult = inTime * 1000;
- break;
- case CONVERT_MSEC_TO_MIN:
- theResult = inTime / (60 * 1000);
- break;
- case CONVERT_MSEC_TO_SEC:
- theResult = inTime / 1000;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in mins:secs:msec and convert it to
- * the corresponding time in msec.
- * @param inMin stores the minutes to be converted.
- * inSec stores the seconds to be converted.
- * inMsec stores the milliseconds to be converted.
- * inOperationCode determines the type of time conversion to be done on the
- * inMin, inSec and inMsec.
- * @return theResult stores the result of the time conversion.
- */
-long CTimeEditDlg::timeConversion(long inMin, long inSec, long inMsec, long inOperationCode)
-{
- long theResult = 0;
- switch (inOperationCode) {
- case CONVERT_TIME_TO_MSEC:
- theResult = timeConversion(inMin, CONVERT_MIN_TO_MSEC)
- + timeConversion(inSec, CONVERT_SEC_TO_MSEC) + inMsec;
- break;
- }
- return theResult;
-}
-
-//==============================================================================
-/**
- * timeConversion: Takes in the time in milliseconds and converts them
- * to min : sec : msec.
- * @param inTotalTime stores the total time in msec.
- * ioMin stores the mins result of the time conversion
- * ioSec stores the secs result of the time conversion
- * ioMsec stores the msecs result of the time conversion
- * inOperationCode determines the type of time conversion to be done on the
- * inTotalTime.
- */
-void CTimeEditDlg::timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode)
-{
- switch (inOperationCode) {
- case CONVERT_MSEC_TO_MIN_SEC_MSEC:
- *ioMin = timeConversion(inTotalTime, CONVERT_MSEC_TO_MIN);
- *ioSec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC);
- *ioSec = timeConversion(*ioSec, CONVERT_MSEC_TO_SEC);
- *ioMsec = inTotalTime - timeConversion(*ioMin, CONVERT_MIN_TO_MSEC)
- - timeConversion(*ioSec, CONVERT_SEC_TO_MSEC);
- break;
- }
-}
-
-//==============================================================================
-/**
- * updateObjectTime: It updates the playhead or keyframe time according
- * to the time displayed in the time edit dialogue.
- * @param inTime is the time that will be updated.
+ * Updates the playhead or keyframe time according to the time displayed in the time edit dialogue.
+ * @param inTime the time that will be updated.
*/
void CTimeEditDlg::updateObjectTime(long inTime)
{
- long theDiff = 0;
- switch (m_ObjectAssociation) {
+ switch (m_objectAssociation) {
case PLAYHEAD: // Update the playhead time
if (m_Doc)
m_Doc->NotifyTimeChanged(inTime);
break;
case ASSETKEYFRAME: // Update the keyframe time
if (m_Doc) {
- theDiff = inTime - m_OffsetFromInitialTime - m_InitialTime;
- m_OffsetFromInitialTime = m_OffsetFromInitialTime + theDiff;
- if (theDiff != 0 && m_KeyframesManager)
- m_KeyframesManager->OffsetSelectedKeyframes(theDiff);
+ m_endTime = inTime;
+ m_keyframeManager->moveSelectedKeyframes(inTime);
}
break;
}
@@ -291,21 +181,23 @@ void CTimeEditDlg::onTimeChanged()
long sec = m_ui->lineEditSeconds->text().toInt();
long msec = m_ui->lineEditMilliseconds->text().toInt();
- long theGoToTime = timeConversion(min, CONVERT_MIN_TO_MSEC)
- + timeConversion(sec, CONVERT_SEC_TO_MSEC) + msec;
+ long theGoToTime = min * 60000 + sec * 1000 + msec;
+ // make sure min keyframe time doesn't go below zero
+ long offset = m_keyframeManager->getPressedKeyframeOffset();
+ if (theGoToTime - offset < 0) {
+ theGoToTime = offset;
+ formatTime(theGoToTime);
+ }
// Go to the time specified in the time edit display
updateObjectTime(theGoToTime);
// If max number of digits reached in a number field, select the next
- if (m_min != min && numberOfDigits(min) == 4) {
+ if (m_ui->lineEditMinutes->hasFocus() && min > 999) {
m_ui->lineEditSeconds->setFocus();
m_ui->lineEditSeconds->selectAll();
- } else if (m_sec != sec && numberOfDigits(sec) == 2) {
+ } else if (m_ui->lineEditSeconds->hasFocus() && sec > 9) {
m_ui->lineEditMilliseconds->setFocus();
m_ui->lineEditMilliseconds->selectAll();
}
-
- m_min = min;
- m_sec = sec;
}
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.h b/src/Authoring/Studio/Application/TimeEditDlg.h
index 8d8ed08f..ef4f8d1a 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.h
+++ b/src/Authoring/Studio/Application/TimeEditDlg.h
@@ -30,12 +30,11 @@
#ifndef TIME_EDIT_DIALOG_H
#define TIME_EDIT_DIALOG_H
-#include "TimeEnums.h"
#include <QtWidgets/qdialog.h>
class CTimebarControl;
class IDoc;
-class ITimelineKeyframesManager;
+class KeyframeManager;
#ifdef QT_NAMESPACE
using namespace QT_NAMESPACE;
@@ -52,9 +51,8 @@ class CTimeEditDlg : public QDialog
Q_OBJECT
public:
- CTimeEditDlg(QWidget *pParent = nullptr); // standard constructor
- virtual ~CTimeEditDlg();
- void setKeyframesManager(ITimelineKeyframesManager *inKeyframeManager);
+ CTimeEditDlg(KeyframeManager *keyframeManager);
+ virtual ~CTimeEditDlg() override;
void showDialog(long inTime, IDoc *inDoc, long inObjectAssociation);
public Q_SLOTS:
@@ -64,25 +62,18 @@ public Q_SLOTS:
protected:
void showEvent(QShowEvent *) override;
+private:
void onInitDialog();
void onTimeChanged();
void formatTime(long inTime);
- int numberOfDigits(long number);
- long timeConversion(long inTime, long inOperationCode);
- long timeConversion(long inMin, long inSec, long inMsec, long inOperationCode);
- void timeConversion(long inTotalTime, long *ioMin, long *ioSec, long *ioMsec,
- long inOperationCode);
void updateObjectTime(long inTime);
-protected:
- Ui::TimeEditDlg *m_ui;
- IDoc *m_Doc;
- ITimelineKeyframesManager *m_KeyframesManager;
- long m_InitialTime;
- long m_ObjectAssociation;
- long m_OffsetFromInitialTime;
- int m_min;
- int m_sec;
+ Ui::TimeEditDlg *m_ui = nullptr;
+ IDoc *m_Doc = nullptr;
+ KeyframeManager *m_keyframeManager = nullptr;
+ long m_initialTime = 0;
+ long m_endTime = 0;
+ long m_objectAssociation = 0;
};
#endif // TIME_EDIT_DIALOG_H
diff --git a/src/Authoring/Studio/Application/TimeEditDlg.ui b/src/Authoring/Studio/Application/TimeEditDlg.ui
index 6bcb11b3..54a8dbd7 100644
--- a/src/Authoring/Studio/Application/TimeEditDlg.ui
+++ b/src/Authoring/Studio/Application/TimeEditDlg.ui
@@ -6,14 +6,29 @@
<rect>
<x>0</x>
<y>0</y>
- <width>300</width>
- <height>114</height>
+ <width>343</width>
+ <height>119</height>
</rect>
</property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>535</width>
+ <height>119</height>
+ </size>
+ </property>
<property name="windowTitle">
<string>Set Keyframe Time</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetFixedSize</enum>
+ </property>
<property name="leftMargin">
<number>0</number>
</property>
@@ -70,7 +85,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMinutes"/>
+ <widget class="QLineEdit" name="lineEditMinutes">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_2">
@@ -80,7 +108,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditSeconds"/>
+ <widget class="QLineEdit" name="lineEditSeconds">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
<item>
<widget class="QLabel" name="label_3">
@@ -90,7 +131,20 @@
</widget>
</item>
<item>
- <widget class="QLineEdit" name="lineEditMilliseconds"/>
+ <widget class="QLineEdit" name="lineEditMilliseconds">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>50</width>
+ <height>16777215</height>
+ </size>
+ </property>
+ </widget>
</item>
</layout>
</widget>
@@ -152,7 +206,7 @@
<widget class="QLabel" name="label_4">
<property name="minimumSize">
<size>
- <width>40</width>
+ <width>0</width>
<height>0</height>
</size>
</property>
@@ -174,7 +228,7 @@
<widget class="QLabel" name="label">
<property name="minimumSize">
<size>
- <width>40</width>
+ <width>0</width>
<height>0</height>
</size>
</property>
diff --git a/src/Authoring/Studio/Info.plist b/src/Authoring/Studio/Info.plist
index 6d81aee3..22709e99 100644
--- a/src/Authoring/Studio/Info.plist
+++ b/src/Authoring/Studio/Info.plist
@@ -54,7 +54,7 @@
</dict>
</array>
<key>NSHumanReadableCopyright</key>
- <string>(C) 2018 The Qt Company Ltd</string>
+ <string>(C) 2019 The Qt Company Ltd</string>
<key>CFBundleExecutable</key>
<string>Qt3DStudio</string>
<key>CFBundleIconFile</key>
@@ -62,7 +62,9 @@
<key>CFBundleIdentifier</key>
<string>org.qt-project.qt3dstudio</string>
<key>CFBundleVersion</key>
- <string>2.0</string>
+ <string>2.3.0</string>
+ <key>CFBundleShortVersionString</key>
+ <string>2.3</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleSignature</key>
diff --git a/src/Authoring/Studio/MainFrm.cpp b/src/Authoring/Studio/MainFrm.cpp
index 2fc6ad91..9bf14265 100644
--- a/src/Authoring/Studio/MainFrm.cpp
+++ b/src/Authoring/Studio/MainFrm.cpp
@@ -59,6 +59,7 @@
#include "ProjectView.h"
#include "RowTree.h"
#include "WidgetControl.h"
+#include "SlideView.h"
#include <QtGui/qevent.h>
#include <QtGui/qdesktopservices.h>
@@ -1901,6 +1902,12 @@ TimelineWidget *CMainFrame::getTimelineWidget() const
return static_cast<TimelineWidget *>(control->getControl());
}
+SlideView *CMainFrame::getSlideView() const
+{
+ return static_cast<SlideView *>(m_paletteManager->GetControl(CPaletteManager::CONTROLTYPE_SLIDE)
+ ->widget());
+}
+
CRecentItems *CMainFrame::GetRecentItems()
{
return m_recentItems.data();
diff --git a/src/Authoring/Studio/MainFrm.h b/src/Authoring/Studio/MainFrm.h
index 275ea8c2..d81e9b12 100644
--- a/src/Authoring/Studio/MainFrm.h
+++ b/src/Authoring/Studio/MainFrm.h
@@ -56,6 +56,7 @@ class ITimelineTimebar;
class RemoteDeploymentSender;
class TimelineWidget;
class CStudioPreferencesPropSheet;
+class SlideView;
#ifdef QT_NAMESPACE
using namespace QT_NAMESPACE;
@@ -234,6 +235,7 @@ public:
void onCtrlNPressed();
TimelineWidget *getTimelineWidget() const;
+ SlideView *getSlideView() const;
void EditPreferences(short inPageIndex);
diff --git a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
index 84e31178..3a1a008b 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ChooserModelBase.cpp
@@ -231,6 +231,24 @@ void ChooserModelBase::expand(const QModelIndex &modelIndex)
void ChooserModelBase::setRootPath(const QString &path)
{
+ // Delete the old model. If the new project is in a totally different directory tree, not
+ // doing this will result in unexplicable crashes when trying to parse something that should
+ // not be parsed.
+ disconnect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ChooserModelBase::modelRowsInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ChooserModelBase::modelRowsRemoved);
+ disconnect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ChooserModelBase::modelLayoutChanged);
+ delete m_model;
+ m_model = new QFileSystemModel(this);
+ connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ChooserModelBase::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ChooserModelBase::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ChooserModelBase::modelLayoutChanged);
+
setRootIndex(m_model->setRootPath(path));
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
index 48cdfe1c..1e94d85a 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.cpp
@@ -62,6 +62,7 @@
#include "foundation/Qt3DSLogging.h"
#include "Dialogs.h"
#include "Dispatch.h"
+#include "VariantsGroupModel.h"
static QStringList renderableItems()
{
@@ -108,8 +109,9 @@ static std::pair<bool, bool> getSlideCharacteristics(qt3dsdm::Qt3DSDMInstanceHan
return std::make_pair(hasNextSlide, hasPreviousSlide);
}
-InspectorControlModel::InspectorControlModel(QObject *parent)
- : QAbstractListModel(parent)
+InspectorControlModel::InspectorControlModel(VariantsGroupModel *variantsModel, QObject *parent)
+ : m_variantsModel(variantsModel)
+ , QAbstractListModel(parent)
, m_UpdatableEditor(*g_StudioApp.GetCore()->GetDoc())
{
m_modifiedProperty.first = 0;
@@ -129,7 +131,7 @@ void InspectorControlModel::setInspectable(CInspectableBase *inInspectable)
if (m_notifier.get() == nullptr) {
m_notifier = signalProvider->ConnectInstancePropertyValue(
- std::bind(&InspectorControlModel::notifyInstancePropertyValue,
+ std::bind(&InspectorControlModel::onPropertyChanged,
this, std::placeholders::_1, std::placeholders::_2));
}
if (m_slideNotifier.get() == nullptr) {
@@ -172,14 +174,20 @@ CInspectableBase *getReferenceMaterialInspectable(CInspectableBase *inspectBase)
return nullptr;
}
-void InspectorControlModel::notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstanceHandle inHandle,
- qt3dsdm::Qt3DSDMPropertyHandle inProperty)
+void InspectorControlModel::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty)
{
auto doc = g_StudioApp.GetCore()->GetDoc();
- const auto bridge = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()
- ->GetClientDataModelBridge();
- if (!bridge->IsSceneGraphInstance(inHandle))
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+ if (!bridge->IsSceneGraphInstance(inInstance))
return;
+
+ if (inProperty == bridge->GetLayer().m_variants) {
+ // only update the variants model if its property changes
+ m_variantsModel->refresh();
+ return;
+ }
+
bool changed = false;
for (int row = 0; row < m_groupElements.count(); ++row) {
auto group = m_groupElements[row];
@@ -192,7 +200,7 @@ void InspectorControlModel::notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstance
imageInstance = doc->GetDocumentReader().GetImageInstanceForProperty(
property->m_instance, property->m_property);
}
- if (property->m_property == inProperty || imageInstance == inHandle) {
+ if (property->m_property == inProperty || imageInstance == inInstance) {
updatePropertyValue(property);
changed = true;
}
@@ -621,6 +629,31 @@ QString InspectorControlModel::getDefaultMaterialString() const
return QObject::tr("Default");
}
+bool InspectorControlModel::isGroupCollapsed(int groupIdx) const
+{
+ const auto inspectable = dynamic_cast<Qt3DSDMInspectable *>(m_inspectableBase);
+ if (inspectable && groupIdx > -1 && groupIdx < m_groupElements.size()) {
+ auto instance = inspectable->GetGroupInstance(0);
+
+ if (m_collapseMap.contains(instance))
+ return m_collapseMap[instance].contains(groupIdx);
+ }
+
+ return false;
+}
+
+void InspectorControlModel::updateGroupCollapseState(int groupIdx, bool isCollapsed)
+{
+ const auto inspectable = dynamic_cast<Qt3DSDMInspectable *>(m_inspectableBase);
+ if (inspectable && groupIdx > -1 && groupIdx < m_groupElements.size()) {
+ auto instance = inspectable->GetGroupInstance(0);
+ if (isCollapsed)
+ m_collapseMap[instance][groupIdx] = true;
+ else
+ m_collapseMap[instance].remove(groupIdx);
+ }
+}
+
void InspectorControlModel::updateFontValues(InspectorControlBase *element) const
{
// Find if there are any font items and update the values of those
@@ -968,10 +1001,8 @@ bool InspectorControlModel::isTreeRebuildRequired(CInspectableBase* inspectBase)
long theCount = m_inspectableBase->GetGroupCount();
auto refMaterial = getReferenceMaterial(inspectBase);
- if (refMaterial != m_refMaterial) {
- m_refMaterial = refMaterial;
+ if (refMaterial != m_refMaterial)
return true;
- }
long refMaterialGroupCount = 0;
if (refMaterial.Valid())
refMaterialGroupCount = 1; // Only the last group of the refMaterial is used
@@ -1163,6 +1194,8 @@ void InspectorControlModel::rebuildTree()
// Clean the old objects after reset is done so that qml will not freak out about null pointers
for (int i = 0; i < deleteVector.count(); ++i)
deleteVector[i]->deleteLater();
+
+ m_refMaterial = getReferenceMaterial(m_inspectableBase);
}
int InspectorControlModel::rowCount(const QModelIndex &parent) const
@@ -1198,7 +1231,6 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
metaDataProvider->GetMetaDataProperty(instance, element->m_property));
}
-
bool skipEmits = false;
switch (element->m_dataType) {
case qt3dsdm::DataModelDataType::String: {
@@ -1208,6 +1240,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
if (index != -1)
stringValue = stringValue.mid(index + 1);
}
+
element->m_value = stringValue;
} // intentional fall-through for other String-derived datatypes
case qt3dsdm::DataModelDataType::StringOrInt:
@@ -1223,7 +1256,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
}
auto slideSystem = studioSystem->GetSlideSystem();
- if (element->m_title == QStringLiteral("Play Mode")) {
+ if (element->m_title == QLatin1String("Play Mode")) {
std::pair<bool, bool> slideData(
getSlideCharacteristics(element->m_instance, *studioSystem->GetSlideCore(),
*slideSystem));
@@ -1231,7 +1264,7 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
bool hasPreviousSlide(slideData.second);
if (!hasNextSlide && !hasPreviousSlide)
stringlist.removeAll("Play Through To...");
- } else if (element->m_title == QStringLiteral("Play Through To")) {
+ } else if (element->m_title == QLatin1String("Play Through To")) {
// the code duplication is intentional as we may ask for slide characteristics
// only if the property refers to slides
std::pair<bool, bool> slideData(
@@ -1274,7 +1307,8 @@ void InspectorControlModel::updatePropertyValue(InspectorControlBase *element) c
}
element->m_value = QString(selectedIndex > 0 ? stringlist[selectedIndex]
- : stringlist.first()).replace("|separator", "");
+ : stringlist.first()).replace(QLatin1String("|separator"),
+ QString());
}
element->m_values = stringlist;
} else if (element->m_propertyType == qt3dsdm::AdditionalMetaDataType::Import) {
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
index 13413bb4..300247c7 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlModel.h
@@ -42,6 +42,7 @@
class CInspectableBase;
class Qt3DSDMInspectable;
class SGuideInspectableImpl;
+class VariantsGroupModel;
namespace qt3dsdm {
class ISignalConnection;
@@ -107,7 +108,7 @@ class InspectorControlModel : public QAbstractListModel
{
Q_OBJECT
public:
- explicit InspectorControlModel(QObject *parent);
+ explicit InspectorControlModel(VariantsGroupModel *variantsModel, QObject *parent);
~InspectorControlModel() = default;
enum Roles {
@@ -153,6 +154,8 @@ public:
Q_INVOKABLE bool isDefaultMaterial() const;
Q_INVOKABLE void addMaterial();
Q_INVOKABLE void duplicateMaterial();
+ Q_INVOKABLE bool isGroupCollapsed(int groupIdx) const;
+ Q_INVOKABLE void updateGroupCollapseState(int groupIdx, bool state);
private:
void onSlideRearranged(const qt3dsdm::Qt3DSDMSlideHandle &inMaster, int inOldIndex,
@@ -168,7 +171,7 @@ private:
}
};
- mutable QVector<GroupInspectorControl> m_groupElements;
+ QVector<GroupInspectorControl> m_groupElements;
CInspectableBase *m_inspectableBase = nullptr;
SGuideInspectableImpl *m_guideInspectable = nullptr;
@@ -197,6 +200,8 @@ private:
qt3dsdm::SValue m_previouslyCommittedValue;
+ QHash<int, QHash<int, bool> > m_collapseMap;
+
QString getBasicMaterialString() const;
QString getAnimatableMaterialString() const;
QString getReferencedMaterialString() const;
@@ -215,7 +220,8 @@ private:
void updatePropertyValue(InspectorControlBase *element) const;
void rebuildTree();
void refreshTree();
- void notifyInstancePropertyValue(qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMPropertyHandle inProperty);
+ void onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty);
void updateAnimateToggleState(InspectorControlBase *inItem);
void updateControlledToggleState(InspectorControlBase *inItem) const;
@@ -243,6 +249,8 @@ private:
bool isGroupRebuildRequired(CInspectableBase *inspectable, int theIndex) const;
static int handleToGuidePropIndex(int handle) { return handle - 1; }
+
+ VariantsGroupModel *m_variantsModel = nullptr;
};
#endif // INSPECTORCONTROLMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
index b6037011..5b2a69d9 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.cpp
@@ -57,6 +57,13 @@
#include "ProjectFile.h"
#include "MaterialRefView.h"
#include "BasicObjectsModel.h"
+#include "Qt3DSDMSlides.h"
+#include "VariantsGroupModel.h"
+#include "VariantTagDialog.h"
+#include "Views.h"
+#include "MainFrm.h"
+#include "SlideView.h"
+#include "TimelineWidget.h"
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
@@ -68,7 +75,8 @@
InspectorControlView::InspectorControlView(const QSize &preferredSize, QWidget *parent)
: QQuickWidget(parent),
TabNavigable(),
- m_inspectorControlModel(new InspectorControlModel(this)),
+ m_variantsGroupModel(new VariantsGroupModel(this)),
+ m_inspectorControlModel(new InspectorControlModel(m_variantsGroupModel, this)),
m_meshChooserView(new MeshChooserView(this)),
m_instance(0),
m_handle(0),
@@ -235,6 +243,7 @@ void InspectorControlView::initialize()
CStudioPreferences::setQmlContextProperties(rootContext());
rootContext()->setContextProperty(QStringLiteral("_parentView"), this);
rootContext()->setContextProperty(QStringLiteral("_inspectorModel"), m_inspectorControlModel);
+ rootContext()->setContextProperty(QStringLiteral("_variantsGroupModel"), m_variantsGroupModel);
rootContext()->setContextProperty(QStringLiteral("_resDir"), StudioUtils::resourceImageUrl());
rootContext()->setContextProperty(QStringLiteral("_tabOrderHandler"), tabOrderHandler());
rootContext()->setContextProperty(QStringLiteral("_mouseHelper"), &m_mouseHelper);
@@ -288,6 +297,8 @@ bool InspectorControlView::canLinkProperty(int instance, int handle) const
&& (type & (OBJTYPE_CUSTOMMATERIAL | OBJTYPE_MATERIAL | OBJTYPE_REFERENCEDMATERIAL))) {
return false;
}
+ if (doc->GetStudioSystem()->GetPropertySystem()->GetName(handle) == QStringLiteral("eyeball"))
+ return false;
return doc->GetDocumentReader().CanPropertyBeLinked(instance, handle);
}
@@ -372,6 +383,17 @@ QString InspectorControlView::titleIcon() const
return {};
}
+bool InspectorControlView::isEditable(int handle) const
+{
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ if (doc->GetStudioSystem()->GetSlideSystem()->IsMasterSlide(doc->GetActiveSlide())
+ && doc->GetStudioSystem()->GetPropertySystem()->GetName(handle)
+ == QStringLiteral("eyeball")) {
+ return false;
+ }
+ return true;
+}
+
void InspectorControlView::OnSelectionSet(Q3DStudio::SSelectedValue inSelectable)
{
updateInspectable(g_StudioApp.GetInspectableFromSelectable(inSelectable));
@@ -394,6 +416,8 @@ void InspectorControlView::setInspectable(CInspectableBase *inInspectable)
m_inspectorControlModel->setInspectable(inInspectable);
Q_EMIT titleChanged();
+
+ m_variantsGroupModel->refresh();
}
}
@@ -434,6 +458,72 @@ void InspectorControlView::showContextMenu(int x, int y, int handle, int instanc
m_handle = 0;
}
+// context menu for the variants tags
+void InspectorControlView::showTagContextMenu(int x, int y, const QString &group,
+ const QString &tag)
+{
+ QMenu theContextMenu;
+
+ auto actionRename = theContextMenu.addAction(QObject::tr("Rename Tag"));
+ connect(actionRename, &QAction::triggered, this, [&]() {
+ VariantTagDialog dlg(VariantTagDialog::RenameTag, group, tag);
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().renameVariantTag(group, dlg.getNames().first,
+ dlg.getNames().second);
+ m_variantsGroupModel->refresh();
+ }
+ });
+
+ auto actionDelete = theContextMenu.addAction(QObject::tr("Delete Tag"));
+ connect(actionDelete, &QAction::triggered, this, [&]() {
+ g_StudioApp.GetCore()->getProjectFile().deleteVariantTag(group, tag);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ theContextMenu.exec(mapToGlobal({x, y}));
+}
+
+// context menu for the variants groups
+void InspectorControlView::showGroupContextMenu(int x, int y, const QString &group)
+{
+ QMenu theContextMenu;
+
+ ProjectFile &projectFile = g_StudioApp.GetCore()->getProjectFile();
+
+ auto actionRename = theContextMenu.addAction(QObject::tr("Rename Group"));
+ connect(actionRename, &QAction::triggered, this, [&]() {
+ VariantTagDialog dlg(VariantTagDialog::RenameGroup, {}, group);
+ if (dlg.exec() == QDialog::Accepted) {
+ projectFile.renameVariantGroup(dlg.getNames().first, dlg.getNames().second);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ }
+ });
+
+ auto actionColor = theContextMenu.addAction(QObject::tr("Change Group Color"));
+ connect(actionColor, &QAction::triggered, this, [&]() {
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ QColor newColor = this->showColorDialog(variantsDef[group].m_color);
+ projectFile.changeVariantGroupColor(group, newColor.name());
+ // no need to refresh variants in the timeline widget as it references the group color in
+ // the project file m_variants, and a redraw is triggered upon color selection dialog close.
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ auto actionDelete = theContextMenu.addAction(QObject::tr("Delete Group"));
+ connect(actionDelete, &QAction::triggered, this, [&]() {
+ projectFile.deleteVariantGroup(group);
+ g_StudioApp.GetViews()->getMainFrame()->getTimelineWidget()->refreshVariants();
+ g_StudioApp.GetViews()->getMainFrame()->getSlideView()->refreshVariants();
+ m_variantsGroupModel->refresh();
+ });
+
+ theContextMenu.exec(mapToGlobal({x, y}));
+}
+
void InspectorControlView::toggleMasterLink()
{
Q3DStudio::ScopedDocumentEditor editor(*g_StudioApp.GetCore()->GetDoc(),
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
index 6cb7fd21..14936b57 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.h
@@ -39,6 +39,7 @@
#include "DataInputSelectView.h"
class InspectorControlModel;
+class VariantsGroupModel;
class CInspectableBase;
class ImageChooserView;
class DataInputSelectView;
@@ -72,6 +73,8 @@ public:
QString titleIcon() const;
Q_INVOKABLE void showContextMenu(int x, int y, int handle, int instance);
+ Q_INVOKABLE void showTagContextMenu(int x, int y, const QString &group, const QString &tag);
+ Q_INVOKABLE void showGroupContextMenu(int x, int y, const QString &group);
Q_INVOKABLE QObject *showImageChooser(int handle, int instance, const QPoint &point);
Q_INVOKABLE QObject *showFilesChooser(int handle, int instance, const QPoint &point);
Q_INVOKABLE QObject *showMeshChooser(int handle, int instance, const QPoint &point);
@@ -84,6 +87,7 @@ public:
Q_INVOKABLE QString convertPathToProjectRoot(const QString &presentationPath);
Q_INVOKABLE bool isRefMaterial(int instance) const;
Q_INVOKABLE QString noneString() const;
+ Q_INVOKABLE bool isEditable(int handle) const;
// IDataModelListener
void OnBeginDataModelNotifications() override;
@@ -125,6 +129,7 @@ private:
std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>> m_connections;
QColor m_backgroundColor;
+ VariantsGroupModel *m_variantsGroupModel = nullptr;
InspectorControlModel *m_inspectorControlModel = nullptr;
CInspectableBase *m_inspectableBase = nullptr;
QPointer<ImageChooserView> m_imageChooserView;
diff --git a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
index 3677bc0e..ab0b8db3 100644
--- a/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
+++ b/src/Authoring/Studio/Palettes/Inspector/InspectorControlView.qml
@@ -28,6 +28,8 @@
import QtQuick 2.8
import QtQuick.Layouts 1.1
import QtQuick.Controls 2.2
+import QtQuick.Controls.Styles 1.4
+import QtQuick.Extras 1.4
import Qt3DStudio 1.0
import "../controls"
@@ -205,12 +207,45 @@ Rectangle {
width: parent.width - x
spacing: 4
- StyledLabel {
- text: model.title
+ Rectangle { // group header
+ x: -10
+ width: delegateItem.width
+ height: 25
+ color: "#111111"
+
+ StyledLabel {
+ x: 30
+ text: model.title
+ anchors.verticalCenter: parent.verticalCenter
+ }
+
+ Image {
+ id: collapseButton
+ x: 10
+ anchors.verticalCenter: parent.verticalCenter
+ source: {
+ _resDir + (groupItems.visible ? "arrow_down.png" : "arrow.png")
+ }
+ }
+
+ MouseArea {
+ id: collapseButtonMouseArea
+ anchors.fill: parent
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ groupItems.visible = !groupItems.visible;
+ _inspectorModel.updateGroupCollapseState(indexOfThisDelegate,
+ !groupItems.visible)
+ }
+ }
+ }
}
Column {
spacing: 4
+ id: groupItems
+
+ visible: !_inspectorModel.isGroupCollapsed(indexOfThisDelegate)
Repeater {
model: delegateItem.values
@@ -237,6 +272,7 @@ Rectangle {
RowLayout {
id: groupDelegateItem
spacing: 0
+ enabled: _parentView.isEditable(modelData.handle)
property alias loadedItem: loader.item
@@ -252,6 +288,7 @@ Rectangle {
ColumnLayout { // Property row and datainput control
Layout.alignment: Qt.AlignTop
+ visible: modelData.title !== "variants"
spacing: 0
RowLayout { // Property row
Layout.alignment: Qt.AlignLeft
@@ -281,7 +318,7 @@ Rectangle {
anchors.fill: parent
acceptedButtons: Qt.RightButton | Qt.LeftButton
hoverEnabled: true
- onClicked: {
+ onClicked: {
if (mouse.button === Qt.LeftButton) {
_inspectorModel.setPropertyAnimated(
model.modelData.instance,
@@ -389,6 +426,9 @@ Rectangle {
opacity: enabled ? 1 : .5
Layout.alignment: Qt.AlignTop
sourceComponent: {
+ if (modelData.title === "variants")
+ return variantTagsComponent;
+
const dataType = modelData.dataType;
switch (dataType) {
case DataModelDataType.Long:
@@ -1064,4 +1104,173 @@ Rectangle {
}
}
}
+
+ Component {
+ id: variantTagsComponent
+
+ Column {
+ width: root.width - 10
+ spacing: 10
+
+ Row {
+ anchors.right: parent.right
+ anchors.rightMargin: 5
+ spacing: 5
+
+ ToolButton {
+ id: importButton
+ text: qsTr("Import...")
+ width: 70
+ height: 20
+
+ onClicked: {
+ _variantsGroupModel.importVariants()
+ }
+ }
+
+ ToolButton {
+ id: exportButton
+ text: qsTr("Export...")
+ width: 70
+ height: 20
+ enabled: !_variantsGroupModel.variantsEmpty
+
+ onClicked: {
+ _variantsGroupModel.exportVariants()
+ }
+ }
+ }
+
+ Text {
+ text: qsTr("There are no variant tags yet. Click [+ Group] to add a new tags group and start adding tags.")
+ color: "#ffffff"
+ visible: _variantsGroupModel.variantsEmpty
+ }
+
+ Repeater {
+ id: tagsRepeater
+ model: _variantsGroupModel
+ property int maxGroupLabelWidth;
+
+ onItemAdded: {
+ // make all group labels have equal width as the widest one
+ if (index == 0)
+ maxGroupLabelWidth = 20; // min group label width
+
+ if (item.groupLabelWidth > maxGroupLabelWidth) {
+ maxGroupLabelWidth = item.groupLabelWidth;
+
+ if (maxGroupLabelWidth > 150) // max group label width
+ maxGroupLabelWidth = 150;
+ }
+ }
+
+ Row {
+ id: variantTagsRow
+ spacing: 5
+
+ readonly property var tagsModel: model.tags
+ readonly property var groupModel: model
+ readonly property int groupLabelWidth: tLabel.implicitWidth
+
+ Text {
+ id: tLabel
+ text: model.group
+ color: model.color
+ width: tagsRepeater.maxGroupLabelWidth;
+ elide: Text.ElideRight
+ anchors.top: parent.top
+ anchors.topMargin: 5
+
+ MouseArea {
+ anchors.fill: parent;
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ if (mouse.button === Qt.RightButton) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ _parentView.showGroupContextMenu(coords.x, coords.y, model.group);
+ }
+ }
+ }
+ }
+
+ Flow {
+ width: root.width - 110
+ spacing: 5
+
+ Repeater {
+ model: tagsModel
+
+ Loader {
+ readonly property var tagsModel: model
+ readonly property var grpModel: groupModel
+ sourceComponent: tagComponent
+ }
+ }
+
+ ToolButton {
+ id: addTagButton
+ text: qsTr("+ Tag")
+ height: 25
+
+ onClicked: {
+ _variantsGroupModel.addNewTag(groupModel.group)
+ }
+
+ }
+ }
+ }
+ }
+
+ Item { width: 1; height: 5 } // vertical spacer
+
+ ToolButton {
+ id: addGroupButton
+ text: qsTr("+ Group")
+ width: 60
+ height: 25
+ onClicked: {
+ _variantsGroupModel.addNewGroup()
+ }
+ }
+
+ Item { width: 1; height: 5 } // vertical spacer
+ }
+ }
+
+ Component {
+ id: tagComponent
+
+ Rectangle {
+ property bool toggled: tagsModel.selected
+ property string grpColor: grpModel ? grpModel.color : ""
+
+ width: Math.max(tLabel.width + 10, 60)
+ height: 25
+ color: toggled ? grpColor : "#2e2f30"
+ border.color: "#959596"
+
+ Text {
+ id: tLabel
+ anchors.centerIn: parent
+ text: tagsModel.tag
+ color: toggled ? "#ffffff" : "#959596"
+ }
+
+ MouseArea {
+ anchors.fill: parent;
+ acceptedButtons: Qt.RightButton | Qt.LeftButton
+ onClicked: {
+ if (mouse.button === Qt.LeftButton) {
+ toggled = !toggled;
+ _variantsGroupModel.setTagState(grpModel.group, tagsModel.tag, toggled);
+ } else if (mouse.button === Qt.RightButton) {
+ const coords = mapToItem(root, mouse.x, mouse.y);
+ _parentView.showTagContextMenu(coords.x, coords.y, grpModel.group,
+ tagsModel.tag);
+ }
+ }
+ }
+ }
+ }
}
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
index 0b6db847..41be5767 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectBrowserView.cpp
@@ -30,6 +30,10 @@
#include "ObjectListModel.h"
#include "StudioPreferences.h"
#include "StudioUtils.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
@@ -50,10 +54,29 @@ QAbstractItemModel *ObjectBrowserView::model() const
void ObjectBrowserView::setModel(ObjectListModel *model)
{
- if (!m_model) {
+ if (!m_model)
m_model = new FlatObjectListModel(model, this);
- }
m_model->setSourceModel(model);
+
+ const auto doc = g_StudioApp.GetCore()->GetDoc();
+ const auto bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
+
+ // Remove "Scene.__Container" and "materials//Default" entries
+ QModelIndexList list = m_model->match(m_model->index(0, 0),
+ ObjectListModel::AbsolutePathRole,
+ QStringLiteral("Scene.")
+ + bridge->getMaterialContainerName(), 1,
+ Qt::MatchFlags(Qt::MatchWrap | Qt::MatchExactly
+ | Qt::MatchRecursive));
+ list.append(m_model->match(m_model->index(0, 0),
+ ObjectListModel::NameRole,
+ QStringLiteral("materials/") + bridge->getDefaultMaterialName(), 1,
+ Qt::MatchFlags(Qt::MatchWrap | Qt::MatchExactly
+ | Qt::MatchRecursive)));
+
+ for (int i = list.size(); i > 0; i--)
+ m_model->removeRow(list.at(i - 1).row(), m_model->index(0, 0));
+
m_ownerInstance = 0;
m_selection = -1;
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
index c1a5fd95..b91727f5 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.cpp
@@ -407,6 +407,14 @@ int FlatObjectListModel::rowCount(const QModelIndex &parent) const
return m_sourceInfo.count();
}
+bool FlatObjectListModel::removeRows(int row, int count, const QModelIndex &parent)
+{
+ beginRemoveRows(parent, row, row + count - 1);
+ m_sourceInfo.remove(row, count);
+ endRemoveRows();
+ return true;
+}
+
void FlatObjectListModel::setSourceModel(ObjectListModel *sourceModel)
{
beginResetModel();
diff --git a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
index 89b5a93c..4013f15c 100644
--- a/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
+++ b/src/Authoring/Studio/Palettes/Inspector/ObjectListModel.h
@@ -118,6 +118,7 @@ public:
int role = Qt::DisplayRole) const;
bool setData(const QModelIndex &index, const QVariant &data, int role = Qt::EditRole) override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ bool removeRows(int row, int count, const QModelIndex &parent = QModelIndex()) override;
void setSourceModel(ObjectListModel *sourceModel);
ObjectListModel *sourceModel() const { return m_sourceModel; }
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp
new file mode 100644
index 00000000..83e72e7b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.cpp
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "VariantTagDialog.h"
+#include "ui_VariantTagDialog.h"
+#include "Dialogs.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "ProjectFile.h"
+
+VariantTagDialog::VariantTagDialog(DialogType type, const QString &group, const QString &name,
+ QWidget *parent)
+ : QDialog(parent)
+ , m_type(type)
+ , m_group(group)
+ , m_ui(new Ui::VariantTagDialog)
+{
+ m_ui->setupUi(this);
+
+ m_names.first = name;
+
+ if (type == AddGroup) {
+ setWindowTitle(tr("Add new Group"));
+ m_ui->label->setText(tr("Group name"));
+ } else if (type == RenameGroup) {
+ setWindowTitle(tr("Rename Group"));
+ m_ui->label->setText(tr("Group name"));
+ m_ui->lineEditTagName->setText(name);
+ m_ui->lineEditTagName->selectAll();
+ } else if (type == RenameTag) {
+ m_ui->lineEditTagName->setText(name);
+ m_ui->lineEditTagName->selectAll();
+ }
+}
+
+void VariantTagDialog::accept()
+{
+ QString name = m_ui->lineEditTagName->text();
+
+ if (name.isEmpty()) {
+ displayWarning(EmptyWarning);
+ } else if (name == m_names.first) { // no change
+ QDialog::reject();
+ } else if (((m_type == AddGroup || m_type == RenameGroup)
+ && !g_StudioApp.GetCore()->getProjectFile().isVariantGroupUnique(name))
+ || (!g_StudioApp.GetCore()->getProjectFile().isVariantTagUnique(m_group, name))) {
+ displayWarning(UniqueWarning);
+ } else {
+ m_names.second = name;
+ QDialog::accept();
+ }
+}
+
+std::pair<QString, QString> VariantTagDialog::getNames() const
+{
+ return m_names;
+}
+
+void VariantTagDialog::displayWarning(WarningType warningType)
+{
+ QString warning;
+ if (warningType == EmptyWarning) {
+ if (m_type == AddGroup || m_type == RenameGroup)
+ warning = tr("The group name must not be empty.");
+ else
+ warning = tr("The tag name must not be empty.");
+ } else if (warningType == UniqueWarning) {
+ if (m_type == AddGroup || m_type == RenameGroup)
+ warning = tr("The group name must be unique.");
+ else
+ warning = tr("The tag name must be unique within the tag group.");
+ }
+
+ g_StudioApp.GetDialogs()->DisplayMessageBox(tr("Warning"), warning,
+ Qt3DSMessageBox::ICON_WARNING, false);
+}
+
+VariantTagDialog::~VariantTagDialog()
+{
+ delete m_ui;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h
new file mode 100644
index 00000000..b5e3989f
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 VARIANTTAGDIALOG_H
+#define VARIANTTAGDIALOG_H
+
+#include <QtWidgets/qdialog.h>
+
+#ifdef QT_NAMESPACE
+using namespace QT_NAMESPACE;
+#endif
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class VariantTagDialog;
+}
+QT_END_NAMESPACE
+
+class VariantTagDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ enum DialogType { AddTag, RenameTag, AddGroup, RenameGroup };
+
+ explicit VariantTagDialog(DialogType type, const QString &group = {}, const QString &name = {},
+ QWidget *parent = nullptr);
+ ~VariantTagDialog() override;
+
+public Q_SLOTS:
+ void accept() override;
+ std::pair<QString, QString> getNames() const;
+
+private:
+ enum WarningType {
+ EmptyWarning,
+ UniqueWarning
+ };
+
+ void displayWarning(WarningType warningType);
+
+ DialogType m_type;
+ QString m_group;
+ Ui::VariantTagDialog *m_ui;
+ std::pair<QString, QString> m_names; // holds the tags values before and after rename
+};
+
+#endif // VARIANTTAGDIALOG_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui
new file mode 100644
index 00000000..aa5d24ef
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantTagDialog.ui
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VariantTagDialog</class>
+ <widget class="QDialog" name="VariantTagDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>241</width>
+ <height>89</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Add new Tag</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QWidget" name="labelEditLayout" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout" stretch="0">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Tag name</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="lineEditTagName"/>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>VariantTagDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>248</x>
+ <y>254</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>157</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>VariantTagDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>316</x>
+ <y>260</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>286</x>
+ <y>274</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp
new file mode 100644
index 00000000..a122889b
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.cpp
@@ -0,0 +1,237 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "VariantsGroupModel.h"
+#include "VariantsTagModel.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "ClientDataModelBridge.h"
+#include "IDocumentEditor.h"
+#include "VariantTagDialog.h"
+#include "StudioUtils.h"
+#include "Dialogs.h"
+
+#include <QtCore/qsavefile.h>
+
+VariantsGroupModel::VariantsGroupModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+
+}
+
+void VariantsGroupModel::refresh()
+{
+ int instance = g_StudioApp.GetCore()->GetDoc()->GetSelectedInstance();
+ auto bridge = g_StudioApp.GetCore()->GetDoc()->GetStudioSystem()->GetClientDataModelBridge();
+
+ if (instance == 0 || !bridge->IsLayerInstance(instance)) {
+ m_instance = 0;
+ m_property = 0;
+ return;
+ }
+
+ auto propertySystem = g_StudioApp.GetCore()->GetDoc()->GetPropertySystem();
+ m_instance = instance;
+ m_property = bridge->GetLayer().m_variants.m_Property;
+
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(m_instance, m_property, sValue)) {
+ beginResetModel();
+ m_data.clear();
+
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ QHash<QString, QStringList> propTags;
+ if (!propVal.isEmpty()) {
+ const QStringList propTagsList = propVal.split(QChar(','));
+ for (auto &propTag : propTagsList) {
+ const QStringList propTagPair = propTag.split(QChar(':'));
+ propTags[propTagPair[0]].append(propTagPair[1]);
+ }
+ }
+
+ // build the variants data model
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ const auto keys = variantsDef.keys();
+ for (auto &group : keys) {
+ TagGroupData g;
+ g.m_title = group;
+ g.m_color = variantsDef[group].m_color;
+
+ VariantsTagModel *m = new VariantsTagModel(this);
+ QVector<std::pair<QString, bool> > tags;
+ for (int i = 0; i < variantsDef[group].m_tags.length(); ++i)
+ tags.append({variantsDef[group].m_tags[i],
+ propTags[group].contains(variantsDef[group].m_tags[i])});
+
+ m->init(tags);
+ g.m_tagsModel = m;
+
+ m_data.push_back(g);
+ }
+
+ endResetModel();
+
+ bool isVariantsEmpty = rowCount() == 0;
+ if (m_variantsEmpty != isVariantsEmpty) {
+ m_variantsEmpty = isVariantsEmpty;
+ Q_EMIT varaintsEmptyChanged();
+ }
+ }
+}
+
+int VariantsGroupModel::rowCount(const QModelIndex &parent) const
+{
+ // For list models only the root node (an invalid parent) should return the list's size. For all
+ // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
+ if (parent.isValid())
+ return 0;
+
+ return m_data.size();
+}
+
+QVariant VariantsGroupModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == GroupTitleRole)
+ return m_data.at(index.row()).m_title;
+ else if (role == GroupColorRole)
+ return m_data.at(index.row()).m_color;
+ else if (role == TagRole)
+ return QVariant::fromValue(m_data.at(index.row()).m_tagsModel);
+
+ return QVariant();
+}
+
+void VariantsGroupModel::setTagState(const QString &group, const QString &tag, bool selected)
+{
+ QString val;
+ QString tagsStr;
+ bool skipFirst = false;
+ for (auto &g : qAsConst(m_data)) {
+ if (g.m_title == group)
+ g.m_tagsModel->updateTagState(tag, selected);
+
+ tagsStr = g.m_tagsModel->serialize(g.m_title);
+ if (!tagsStr.isEmpty()) {
+ if (skipFirst)
+ val.append(QChar(','));
+ val.append(tagsStr);
+ skipFirst = true;
+ }
+ }
+
+ auto sVal = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(val));
+ Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), QObject::tr("Set Property"))
+ ->SetInstancePropertyValue(m_instance, m_property, sVal);
+}
+
+void VariantsGroupModel::addNewTag(const QString &group)
+{
+ VariantTagDialog dlg(VariantTagDialog::AddTag, group);
+
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().addVariantTag(group, dlg.getNames().second);
+ refresh();
+ }
+}
+
+void VariantsGroupModel::importVariants()
+{
+ QString importFilePath = g_StudioApp.GetDialogs()->getImportVariantsDlg();
+
+ if (!importFilePath.isEmpty()) {
+ g_StudioApp.GetCore()->getProjectFile().loadVariants(importFilePath);
+ refresh();
+ }
+}
+
+void VariantsGroupModel::exportVariants()
+{
+ QString exportFilePath = g_StudioApp.GetDialogs()->getExportVariantsDlg();
+
+ if (exportFilePath.isEmpty())
+ return;
+
+ QDomDocument domDoc;
+ domDoc.appendChild(domDoc.createProcessingInstruction(QStringLiteral("xml"),
+ QStringLiteral("version=\"1.0\""
+ " encoding=\"utf-8\"")));
+
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ const auto keys = variantsDef.keys();
+ QDomElement vElem = domDoc.createElement(QStringLiteral("variants"));
+ domDoc.appendChild(vElem);
+ for (auto &g : keys) {
+ const auto group = variantsDef[g];
+ QDomElement gElem = domDoc.createElement(QStringLiteral("variantgroup"));
+ gElem.setAttribute(QStringLiteral("id"), g);
+ gElem.setAttribute(QStringLiteral("color"), group.m_color);
+ vElem.appendChild(gElem);
+
+ for (auto &t : qAsConst(group.m_tags)) {
+ QDomElement tElem = domDoc.createElement(QStringLiteral("variant"));;
+ tElem.setAttribute(QStringLiteral("id"), t);
+ gElem.appendChild(tElem);
+ }
+ }
+
+ QSaveFile file(exportFilePath);
+ if (StudioUtils::openTextSave(file))
+ StudioUtils::commitDomDocumentSave(file, domDoc);
+}
+
+void VariantsGroupModel::addNewGroup()
+{
+ VariantTagDialog dlg(VariantTagDialog::AddGroup);
+
+ if (dlg.exec() == QDialog::Accepted) {
+ g_StudioApp.GetCore()->getProjectFile().addVariantGroup(dlg.getNames().second);
+ refresh();
+ }
+}
+
+QHash<int, QByteArray> VariantsGroupModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(GroupTitleRole, "group");
+ names.insert(GroupColorRole, "color");
+ names.insert(TagRole, "tags");
+ return names;
+}
+
+Qt::ItemFlags VariantsGroupModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ return Qt::ItemIsEditable;
+}
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h
new file mode 100644
index 00000000..75a218f7
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsGroupModel.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 VARIANTSGROUPMODEL_H
+#define VARIANTSGROUPMODEL_H
+
+#include <QtCore/qabstractitemmodel.h>
+
+class VariantsTagModel;
+
+class VariantsGroupModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(bool variantsEmpty MEMBER m_variantsEmpty NOTIFY varaintsEmptyChanged)
+
+public:
+Q_SIGNALS:
+ void varaintsEmptyChanged();
+
+public:
+ explicit VariantsGroupModel(QObject *parent = nullptr);
+
+ enum Roles {
+ GroupTitleRole = Qt::UserRole + 1,
+ GroupColorRole,
+ TagRole
+ };
+
+ struct TagGroupData
+ {
+ QString m_title;
+ QString m_color;
+ VariantsTagModel *m_tagsModel = nullptr;
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = GroupTitleRole) const override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ void refresh();
+
+ Q_INVOKABLE void setTagState(const QString &group, const QString &tag, bool selected);
+ Q_INVOKABLE void addNewTag(const QString &group);
+ Q_INVOKABLE void addNewGroup();
+ Q_INVOKABLE void importVariants();
+ Q_INVOKABLE void exportVariants();
+
+
+protected:
+ QHash<int, QByteArray> roleNames() const override;
+
+private:
+ QVector<TagGroupData> m_data;
+ int m_instance = 0; // selected layer instance
+ int m_property = 0; // variant tags property handler
+ bool m_variantsEmpty = true; // no groups (nor tags)
+};
+
+#endif // VARIANTSGROUPMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp
new file mode 100644
index 00000000..910b4f09
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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 "VariantsTagModel.h"
+
+VariantsTagModel::VariantsTagModel(QObject *parent)
+ : QAbstractListModel(parent)
+{
+
+}
+
+void VariantsTagModel::init(const QVector<std::pair<QString, bool> > &data)
+{
+ m_data = data;
+}
+
+void VariantsTagModel::updateTagState(const QString &tag, bool selected)
+{
+ for (auto &t : m_data) {
+ if (t.first == tag) {
+ t.second = selected;
+ break;
+ }
+ }
+}
+
+// return the tags in a formatted string to be saved to the property
+QString VariantsTagModel::serialize(const QString &groupName) const
+{
+ QString ret;
+ bool skipFirst = false;
+ for (auto &t : qAsConst(m_data)) {
+ if (t.second) {
+ if (skipFirst)
+ ret.append(QLatin1Char(','));
+
+ ret.append(groupName + QLatin1Char(':') + t.first);
+
+ skipFirst = true;
+ }
+ }
+
+ return ret;
+}
+
+int VariantsTagModel::rowCount(const QModelIndex &parent) const
+{
+ // For list models only the root node (an invalid parent) should return the list's size. For all
+ // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
+ if (parent.isValid())
+ return 0;
+
+ return m_data.size();
+}
+
+QVariant VariantsTagModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == TagRole)
+ return m_data.at(index.row()).first;
+ else if (role == SelectedRole)
+ return m_data.at(index.row()).second;
+
+ return QVariant();
+}
+
+QHash<int, QByteArray> VariantsTagModel::roleNames() const
+{
+ auto names = QAbstractListModel::roleNames();
+ names.insert(TagRole, "tag");
+ names.insert(SelectedRole, "selected");
+ return names;
+}
+
+Qt::ItemFlags VariantsTagModel::flags(const QModelIndex &index) const
+{
+ if (!index.isValid())
+ return Qt::NoItemFlags;
+
+ return Qt::ItemIsEditable; // FIXME: Implement me!
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h
index e1a6914f..01bb4e73 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineKeyframesManager.h
+++ b/src/Authoring/Studio/Palettes/Inspector/VariantsTagModel.h
@@ -1,7 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2008 NVIDIA Corporation.
-** Copyright (C) 2017 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt 3D Studio.
@@ -27,29 +26,37 @@
**
****************************************************************************/
-#ifndef INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H
-#define INCLUDED_ITIMELINE_KEYFRAMES_MANAGER_H 1
+#ifndef VARIANTSTAGMODEL_H
+#define VARIANTSTAGMODEL_H
-#pragma once
+#include <QtCore/qabstractitemmodel.h>
-#include "IKeyframesManager.h"
-
-//=============================================================================
-/**
- * Interface to manage keyframes related actions in the Timeline
- */
-//=============================================================================
-class ITimelineKeyframesManager : public IKeyframesManager
+class VariantsTagModel : public QAbstractListModel
{
+ Q_OBJECT
+
public:
- virtual ~ITimelineKeyframesManager() {}
-
- virtual void SetKeyframeTime(long inTime) = 0;
- virtual void SetKeyframesDynamic(bool inDynamic) = 0;
- virtual long OffsetSelectedKeyframes(long inOffset) = 0;
- virtual bool CanMakeSelectedKeyframesDynamic() = 0;
- virtual void CommitChangedKeyframes() = 0;
- virtual void RollbackChangedKeyframes() = 0;
+ explicit VariantsTagModel(QObject *parent = nullptr);
+
+ enum Roles {
+ TagRole = Qt::UserRole + 1,
+ SelectedRole,
+ };
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = TagRole) const override;
+
+ Qt::ItemFlags flags(const QModelIndex& index) const override;
+
+ void init(const QVector<std::pair<QString, bool> > &data);
+ void updateTagState(const QString &tag, bool selected);
+ QString serialize(const QString &groupName) const;
+
+protected:
+ QHash<int, QByteArray> roleNames() const override;
+
+private:
+ QVector<std::pair<QString, bool> > m_data; // [{tagName, selectedState}, ...]
};
-#endif // INCLUDED_IKEYFRAMES_MANAGER_H
+#endif // VARIANTSTAGMODEL_H
diff --git a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
index 0a098a5b..f6d498f2 100644
--- a/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
+++ b/src/Authoring/Studio/Palettes/Project/ProjectFileSystemModel.cpp
@@ -454,6 +454,24 @@ void ProjectFileSystemModel::setRootPath(const QString &path)
m_projectReferencesUpdateMap.clear();
m_projectReferencesUpdateTimer.stop();
+ // Delete the old model. If the new project is in a totally different directory tree, not
+ // doing this will result in unexplicable crashes when trying to parse something that should
+ // not be parsed.
+ disconnect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ProjectFileSystemModel::modelRowsInserted);
+ disconnect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ProjectFileSystemModel::modelRowsRemoved);
+ disconnect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ProjectFileSystemModel::modelLayoutChanged);
+ delete m_model;
+ m_model = new QFileSystemModel(this);
+ connect(m_model, &QAbstractItemModel::rowsInserted,
+ this, &ProjectFileSystemModel::modelRowsInserted);
+ connect(m_model, &QAbstractItemModel::rowsAboutToBeRemoved,
+ this, &ProjectFileSystemModel::modelRowsRemoved);
+ connect(m_model, &QAbstractItemModel::layoutChanged,
+ this, &ProjectFileSystemModel::modelLayoutChanged);
+
setRootIndex(m_model->setRootPath(path));
// Open the presentations folder by default
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
index 710dd4b8..9229e519 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.cpp
@@ -56,6 +56,10 @@ QVariant SlideModel::data(const QModelIndex &index, int role) const
return slideName(m_slides[row]);
case SelectedRole:
return row == m_selectedRow;
+ case VariantsRole:
+ int slideIdx = GetDoc()->GetStudioSystem()->GetSlideSystem()->GetSlideIndex(m_slides[row]);
+ if (slideIdx < m_variants.size())
+ return m_variants.at(slideIdx);
}
return {};
@@ -91,7 +95,7 @@ bool SlideModel::setData(const QModelIndex &index, const QVariant &value, int ro
}
Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {role});
- return true;
+ break;
}
default:
return false;
@@ -112,6 +116,7 @@ QHash<int, QByteArray> SlideModel::roleNames() const
{
auto names = QAbstractListModel::roleNames();
names.insert(NameRole, "name");
+ names.insert(VariantsRole, "variants");
names.insert(SelectedRole, "selected");
return names;
@@ -347,6 +352,61 @@ void SlideModel::setSlideName(const qt3dsdm::Qt3DSDMSlideHandle &handle, const Q
}
}
+void SlideModel::refreshVariants(const QStringList &variants)
+{
+ m_variants.clear();
+
+ if (variants.isEmpty()) {
+ const auto *slideSystem = GetDoc()->GetStudioSystem()->GetSlideSystem();
+ int slideCount = slideSystem->GetSlideCount(slideSystem->GetMasterSlide(
+ GetDoc()->GetActiveSlide()));
+
+ QString vTemplate = QStringLiteral(" <font color='%1'>%2</font>");
+ QVector<QHash<QString, int>> counts(slideCount); // <group, total count tags>
+
+ const auto propertySystem = GetDoc()->GetPropertySystem();
+ const auto layers = GetDoc()->getLayers();
+ for (auto layer : layers) {
+ int slideIdx = slideIndex(slideSystem->GetAssociatedSlide(layer));
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, GetBridge()->GetLayer().m_variants,
+ sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ ++counts[slideIdx][group];
+ }
+ }
+ }
+ }
+
+ // add master slide layers counts to other layers
+ const auto keys = counts[0].keys();
+ for (int i = 1; i < slideCount; ++i) {
+ for (auto g : keys)
+ counts[i][g] += counts[0][g];
+ }
+
+ // update the variants counts model (m_variants)
+ auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ for (int i = 0; i < counts.size(); ++i) { // slides indexes
+ QString slideVariants;
+ const auto keys = counts[i].keys();
+ for (auto g : keys) // variants groups
+ slideVariants.append(vTemplate.arg(variantsDef[g].m_color).arg(counts[i][g]));
+
+ m_variants << slideVariants;
+ }
+ } else {
+ m_variants = variants;
+ }
+
+ Q_EMIT dataChanged(this->index(0, 0), this->index(rowCount() - 1, 0), {VariantsRole});
+}
+
CDoc *SlideModel::GetDoc() const
{
return g_StudioApp.GetCore()->GetDoc();
@@ -375,10 +435,10 @@ void SlideModel::refreshSlideLabel(qt3dsdm::Qt3DSDMInstanceHandle instanceHandle
if (m_slides[i] == slideHandle) {
setData(index(i, 0), GetBridge()->GetName(instanceHandle),
SlideModel::NameRole);
+ break;
}
}
}
-
}
// Set selected slide highlight on UI
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideModel.h b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
index 1de717cd..6f2de22f 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideModel.h
+++ b/src/Authoring/Studio/Palettes/Slide/SlideModel.h
@@ -44,7 +44,8 @@ public:
enum Roles {
NameRole = Qt::DisplayRole,
HandleRole = Qt::UserRole + 1,
- SelectedRole
+ SelectedRole,
+ VariantsRole
};
SlideModel(int slideCount, QObject *parent = nullptr);
@@ -76,6 +77,8 @@ public:
void refreshSlideLabel(qt3dsdm::Qt3DSDMInstanceHandle instanceHandle,
qt3dsdm::Qt3DSDMPropertyHandle propertyHandle);
void setSelectedSlideIndex(const QModelIndex &index);
+ void refreshVariants(const QStringList &variants = {});
+ QStringList variants() const { return m_variants; }
private:
bool hasSlideWithName(const QString &name) const;
@@ -89,6 +92,7 @@ private:
int m_selectedRow = -1;
int m_rearrangeStartRow = -1;
int m_rearrangeEndRow = -1;
+ QStringList m_variants; // model for variants tags display
QHash<qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMSlideHandle> m_slideLookupHash;
};
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
index 5bb5aa67..51f90372 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.cpp
@@ -27,11 +27,9 @@
****************************************************************************/
#include "SlideView.h"
-#include <QtGui/qcolor.h>
#include "Core.h"
#include "Dispatch.h"
#include "Doc.h"
-#include "Literals.h"
#include "StudioPreferences.h"
#include "SlideModel.h"
#include "StudioApp.h"
@@ -45,22 +43,19 @@
#include "Qt3DSDMSlides.h"
#include "Dialogs.h"
-#include <QtCore/qcoreapplication.h>
#include <QtCore/qtimer.h>
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
-#include <QtWidgets/qdesktopwidget.h>
-#include <QtWidgets/qdockwidget.h>
SlideView::SlideView(QWidget *parent) : QQuickWidget(parent)
, m_MasterSlideModel(new SlideModel(1, this))
, m_SlidesModel(new SlideModel(0, this))
+ , m_CurrentModel(m_SlidesModel)
, m_ActiveRoot(0)
, m_toolTip(tr("No Controller"))
{
g_StudioApp.GetCore()->GetDispatch()->AddPresentationChangeListener(this);
setResizeMode(QQuickWidget::SizeRootObjectToView);
- m_CurrentModel = m_SlidesModel;
QTimer::singleShot(0, this, &SlideView::initialize);
}
@@ -82,10 +77,7 @@ void SlideView::setShowMasterSlide(bool show)
if (show == currentIsMaster)
return;
- if (show)
- m_CurrentModel = m_MasterSlideModel;
- else
- m_CurrentModel = m_SlidesModel;
+ m_CurrentModel = show ? m_MasterSlideModel : m_SlidesModel;
// We need to get the first slide in the correct master mode
CDoc *theDoc = GetDoc();
@@ -124,8 +116,6 @@ void SlideView::showControllerDialog(const QPoint &point)
m_dataInputSelector->setData(dataInputList, currCtr);
CDialogs::showWidgetBrowser(this, m_dataInputSelector, point,
CDialogs::WidgetBrowserAlign::ToolButton);
-
- return;
}
bool SlideView::toolTipsEnabled()
@@ -142,7 +132,7 @@ QSize SlideView::minimumSizeHint() const
{
// prevent datainput control indicator from overlapping
// with slide name too much when panel is minimised
- return {80, 0};
+ return {100, 0};
}
void SlideView::deselectAll()
@@ -209,8 +199,9 @@ void SlideView::OnNewPresentation()
// Set up listener for the name changes to slide
m_Connections.push_back(theSignalProvider->ConnectInstancePropertyValue(
- std::bind(&SlideModel::refreshSlideLabel, m_SlidesModel,
+ std::bind(&SlideView::onPropertyChanged, this,
std::placeholders::_1, std::placeholders::_2)));
+
// Set up listener for undo/redo changes in order to update
// slide datainput control
CDispatch *theDispatch = g_StudioApp.GetCore()->GetDispatch();
@@ -290,18 +281,16 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
m_toolTip = tr("No Controller");
}
qt3dsdm::Qt3DSDMPropertyHandle ctrldProp;
- if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE) {
+ if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE)
ctrldProp = bridge->GetObjectDefinitions().m_Scene.m_ControlledProperty;
- } else if (bridge->GetObjectType(slideRoot) ==
- EStudioObjectType::OBJTYPE_COMPONENT) {
+ else if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_COMPONENT)
ctrldProp = bridge->GetObjectDefinitions().m_Component.m_ControlledProperty;
- } else {
+ else
Q_ASSERT(false);
- }
qt3dsdm::SValue controlledPropertyVal;
- doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(
- slideRoot, ctrldProp, controlledPropertyVal);
+ doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(slideRoot, ctrldProp,
+ controlledPropertyVal);
// To indicate that slide transitions are controlled by data input,
// we set "controlled property" of this scene to contain the name of
@@ -309,27 +298,27 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
// If we have existing slide control in this root element, replace it.
// Otherwise just append slide control string to controlledproperty
// (it might already contain timeline control information)
- auto existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
- if (existingCtrl.contains("@slide")) {
- int slideStrPos = existingCtrl.indexOf("@slide");
+ QString existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
+ if (existingCtrl.contains(QLatin1String("@slide"))) {
+ int slideStrPos = existingCtrl.indexOf(QLatin1String("@slide"));
// find the controlling datainput name and build the string to replace
- int ctrStrPos = existingCtrl.lastIndexOf("$", slideStrPos - 2);
+ int ctrStrPos = existingCtrl.lastIndexOf(QLatin1Char('$'), slideStrPos - 2);
QString prevCtrler = existingCtrl.mid(ctrStrPos, slideStrPos - ctrStrPos - 1);
- existingCtrl.replace(prevCtrler + " @slide", fullSlideControlStr);
+ existingCtrl.replace(prevCtrler + QLatin1String(" @slide"), fullSlideControlStr);
} else {
- (!existingCtrl.isEmpty() && m_controlled) ? existingCtrl.append(" ") : 0;
+ if (!existingCtrl.isEmpty() && m_controlled)
+ existingCtrl.append(QLatin1Char(' '));
existingCtrl.append(fullSlideControlStr);
}
- if (existingCtrl.endsWith(" "))
+ if (existingCtrl.endsWith(QLatin1Char(' ')))
existingCtrl.chop(1);
- if (existingCtrl.startsWith(" "))
+ if (existingCtrl.startsWith(QLatin1Char(' ')))
existingCtrl.remove(0, 1);
qt3dsdm::SValue fullCtrlPropVal
- = std::make_shared<qt3dsdm::CDataStr>(
- Q3DStudio::CString::fromQString(existingCtrl));
+ = std::make_shared<qt3dsdm::CDataStr>(Q3DStudio::CString::fromQString(existingCtrl));
Q3DStudio::SCOPED_DOCUMENT_EDITOR(*doc, QObject::tr("Set Slide control"))
->SetInstancePropertyValue(slideRoot, ctrldProp, fullCtrlPropVal);
@@ -338,6 +327,17 @@ void SlideView::onDataInputChange(int handle, int instance, const QString &dataI
Q_EMIT controlledChanged();
}
+void SlideView::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty)
+{
+ // refresh slide name
+ m_SlidesModel->refreshSlideLabel(inInstance, inProperty);
+
+ // refresh variants
+ if (inProperty == GetBridge()->GetLayer().m_variants)
+ refreshVariants();
+}
+
void SlideView::onDockLocationChange(Qt::DockWidgetArea area)
{
m_dockArea = area;
@@ -353,24 +353,22 @@ void SlideView::updateDataInputStatus()
qt3dsdm::Qt3DSDMInstanceHandle slideRoot = doc->GetActiveRootInstance();
qt3dsdm::Qt3DSDMPropertyHandle ctrldProp;
- if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE) {
+ if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_SCENE)
ctrldProp = bridge->GetObjectDefinitions().m_Scene.m_ControlledProperty;
- } else if (bridge->GetObjectType(slideRoot) ==
- EStudioObjectType::OBJTYPE_COMPONENT) {
+ else if (bridge->GetObjectType(slideRoot) == EStudioObjectType::OBJTYPE_COMPONENT)
ctrldProp = bridge->GetObjectDefinitions().m_Component.m_ControlledProperty;
- } else {
+ else
Q_ASSERT(false);
- }
qt3dsdm::SValue controlledPropertyVal;
- doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(
- slideRoot, ctrldProp, controlledPropertyVal);
- auto existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
+ doc->GetStudioSystem()->GetPropertySystem()->GetInstancePropertyValue(slideRoot, ctrldProp,
+ controlledPropertyVal);
+ QString existingCtrl = qt3dsdm::get<QString>(controlledPropertyVal);
QString newController;
- int slideStrPos = existingCtrl.indexOf("@slide");
+ int slideStrPos = existingCtrl.indexOf(QLatin1String("@slide"));
if (slideStrPos != -1) {
- int ctrStrPos = existingCtrl.lastIndexOf("$", slideStrPos - 2);
+ int ctrStrPos = existingCtrl.lastIndexOf(QLatin1Char('$'), slideStrPos - 2);
newController = existingCtrl.mid(ctrStrPos + 1, slideStrPos - ctrStrPos - 2);
}
if (newController != m_currentController) {
@@ -505,6 +503,12 @@ bool SlideView::isMaster(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle)
return (0 == GetSlideIndex(inSlideHandle));
}
+void SlideView::refreshVariants()
+{
+ m_SlidesModel->refreshVariants();
+ m_MasterSlideModel->refreshVariants(m_SlidesModel->variants());
+}
+
void SlideView::OnBeginDataModelNotifications()
{
}
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.h b/src/Authoring/Studio/Palettes/Slide/SlideView.h
index e95ac314..18c4d1d7 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.h
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.h
@@ -67,6 +67,7 @@ public:
QSize minimumSizeHint() const override;
void onDataInputChange(int handle, int instance, const QString &dataInputName);
void onDockLocationChange(Qt::DockWidgetArea area);
+ void refreshVariants();
Q_INVOKABLE void deselectAll();
Q_INVOKABLE void addNewSlide(int row);
@@ -120,10 +121,12 @@ private:
long GetSlideIndex(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle);
bool isMaster(const qt3dsdm::Qt3DSDMSlideHandle &inSlideHandle);
void rebuildSlideList(const qt3dsdm::Qt3DSDMSlideHandle &inActiveSlideHandle);
+ void onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
+ qt3dsdm::Qt3DSDMPropertyHandle inProperty);
- SlideModel *m_CurrentModel = nullptr;
SlideModel *m_MasterSlideModel = nullptr;
SlideModel *m_SlidesModel = nullptr;
+ SlideModel *m_CurrentModel = nullptr;
DataInputSelectView *m_dataInputSelector = nullptr;
QColor m_BaseColor = QColor::fromRgb(75, 75, 75);
std::vector<std::shared_ptr<qt3dsdm::ISignalConnection>>
diff --git a/src/Authoring/Studio/Palettes/Slide/SlideView.qml b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
index c8f409d0..4113c947 100644
--- a/src/Authoring/Studio/Palettes/Slide/SlideView.qml
+++ b/src/Authoring/Studio/Palettes/Slide/SlideView.qml
@@ -263,6 +263,17 @@ Rectangle {
}
}
+ Label { // variants
+ width: slideImage.width
+ font.pixelSize: _fontSize
+ padding: 3
+ verticalAlignment: Text.AlignVCenter
+ background: Rectangle { color:"#111111" }
+ wrapMode: Text.WordWrap
+ visible: model.variants !== ""
+ text: model.variants
+ }
+
Item {
anchors.horizontalCenter: slideImage.horizontalCenter
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
index e8cdd767..a01e5e48 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/ITimelineItemBinding.h
@@ -37,7 +37,6 @@
class RowTree;
class CControlWindowListener;
-class ITimelineKeyframesManager;
// Data model specific ??
class CDropTarget;
diff --git a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
index ba6dd622..fdeb7338 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
+++ b/src/Authoring/Studio/Palettes/Timeline/Bindings/Qt3DSDMTimelineTimebar.cpp
@@ -37,7 +37,6 @@
#include "Doc.h"
#include "Dispatch.h"
#include "Core.h"
-#include "DurationEditDlg.h"
#include "IDocumentEditor.h"
#include "StudioFullSystem.h"
#include "StudioPreferences.h"
@@ -218,6 +217,5 @@ void Qt3DSDMTimelineTimebar::SetTimebarComment(const Q3DStudio::CString &inComme
void Qt3DSDMTimelineTimebar::SetTimebarTime(ITimeChangeCallback *inCallback /*= nullptr*/)
{
g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(GetStartTime(), GetEndTime(),
- m_TimelineTranslationManager->GetDoc(),
inCallback);
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
index c803ef2c..7e4ea614 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/Keyframe.h
@@ -35,7 +35,7 @@
struct Keyframe
{
- Keyframe(double time, RowTimeline *propRow)
+ Keyframe(long time, RowTimeline *propRow)
: time(time)
, rowProperty(propRow)
, rowMaster(propRow->parentRow())
@@ -47,7 +47,7 @@ struct Keyframe
return binding && binding->IsSelected();
}
- double time;
+ long time;
QString propertyType;
RowTimeline *rowProperty = nullptr;
RowTimeline *rowMaster = nullptr;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
index 936d60ae..9a12aab3 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.cpp
@@ -30,13 +30,8 @@
#include "RowTree.h"
#include "RowTimeline.h"
#include "Keyframe.h"
-#include "RowTypes.h"
-#include "TimelineConstants.h"
-#include "Ruler.h"
-#include "PlayHead.h"
#include "RowManager.h"
#include "TimelineGraphicsScene.h"
-#include "StudioObjectTypes.h"
#include "StudioApp.h"
#include "Core.h"
#include "Doc.h"
@@ -44,26 +39,16 @@
#include "CmdDataModelRemoveKeyframe.h"
#include "CmdDataModelInsertKeyframe.h"
#include "CmdDataModelChangeKeyframe.h"
-#include "Qt3DSDMAnimation.h"
#include "ClientDataModelBridge.h"
-#include "Bindings/ITimelineItemBinding.h"
#include "Bindings/OffsetKeyframesCommandHelper.h"
-#include "Bindings/Qt3DSDMTimelineKeyframe.h"
+#include "Bindings/PasteKeyframesCommandHelper.h"
#include "StudioPreferences.h"
-#include "Qt3DSDMAnimation.h"
#include "Dialogs.h"
-#include "TimeEditDlg.h"
-#include "Bindings/PasteKeyframesCommandHelper.h"
-
-#include <qglobal.h>
-#include <QtCore/qhash.h>
-#include <QtCore/qdebug.h>
+#include "TimeEnums.h"
using namespace qt3dsdm;
-KeyframeManager::KeyframeManager(TimelineGraphicsScene *scene)
- : m_scene(scene)
- , m_pasteKeyframeCommandHelper(nullptr)
+KeyframeManager::KeyframeManager(TimelineGraphicsScene *scene) : m_scene(scene)
{
}
@@ -72,7 +57,7 @@ KeyframeManager::~KeyframeManager()
delete m_pasteKeyframeCommandHelper;
}
-QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, double time,
+QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, long time,
bool selectInsertedKeyframes)
{
QList<Keyframe *> addedKeyframes;
@@ -88,9 +73,8 @@ QList<Keyframe *> KeyframeManager::insertKeyframe(RowTimeline *row, double time,
}
if (!propRows.empty()) {
- Keyframe *keyframe = nullptr;
for (const auto &r : qAsConst(propRows)) {
- keyframe = new Keyframe(time, r);
+ Keyframe *keyframe = new Keyframe(time, r);
r->insertKeyframe(keyframe);
r->parentRow()->insertKeyframe(keyframe);
addedKeyframes.append(keyframe);
@@ -159,10 +143,9 @@ void KeyframeManager::commitMoveSelectedKeyframes()
{
CDoc *theDoc = g_StudioApp.GetCore()->GetDoc();
COffsetKeyframesCommandHelper h(*theDoc);
- for (Keyframe *keyframe : qAsConst(m_selectedKeyframes)) {
- const long msTime = round(keyframe->time * 1000);
- keyframe->binding->UpdateKeyframesTime(&h, msTime);
- }
+
+ for (Keyframe *keyframe : qAsConst(m_selectedKeyframes))
+ keyframe->binding->UpdateKeyframesTime(&h, keyframe->time);
}
void KeyframeManager::selectKeyframesInRect(const QRectF &rect)
@@ -300,7 +283,7 @@ void KeyframeManager::copySelectedKeyframes()
m_pasteKeyframeCommandHelper = new CPasteKeyframeCommandHelper();
// calc min copied frames time
- double minTime = 999999.0; // in seconds (~277.78 hrs)
+ long minTime = LONG_MAX;
for (auto keyframe : qAsConst(m_selectedKeyframes)) {
if (keyframe->time < minTime)
minTime = keyframe->time;
@@ -331,9 +314,9 @@ void KeyframeManager::copySelectedKeyframes()
break;
}
- double dt = Qt3DSDMTimelineKeyframe::GetTimeInSecs(kf->GetTime()) - minTime;
- qt3dsdm::Qt3DSDMAnimationHandle animation =
- animationCore->GetAnimationForKeyframe(theKeyframeHandles[0]);
+ float dt = Qt3DSDMTimelineKeyframe::GetTimeInSecs(kf->GetTime() - minTime);
+ qt3dsdm::Qt3DSDMAnimationHandle animation
+ = animationCore->GetAnimationForKeyframe(theKeyframeHandles[0]);
m_pasteKeyframeCommandHelper->AddKeyframeData(
animationCore->GetAnimationInfo(animation).m_Property, dt, info, infoCount);
}
@@ -373,28 +356,47 @@ void KeyframeManager::pasteKeyframes()
}
}
-void KeyframeManager::moveSelectedKeyframes(double dx)
+void KeyframeManager::moveSelectedKeyframes(long newTime)
{
- double dt = m_scene->ruler()->distanceToTime(dx);
+ Keyframe *pressedKeyframe = m_scene->pressedKeyframe();
- if (dt < 0) { // check min limit
- double minTime = 999999; // seconds (~277.78 hrs)
- for (auto keyframe : qAsConst(m_selectedKeyframes)) {
- if (keyframe->time < minTime)
- minTime = keyframe->time;
- }
+ Q_ASSERT(pressedKeyframe);
- if (minTime + dt < 0)
- dt = -minTime;
- }
+ // make sure the min-time keyframe doesn't go below zero
+ long minTime = getMinSelectedKeyframesTime();
+ if (pressedKeyframe->time - minTime > newTime)
+ newTime = pressedKeyframe->time - minTime;
- for (auto keyframe : qAsConst(m_selectedKeyframes))
- keyframe->time += dt;
+ for (auto keyframe : qAsConst(m_selectedKeyframes)) {
+ if (keyframe != pressedKeyframe)
+ keyframe->time = newTime - (pressedKeyframe->time - keyframe->time);
+ }
+ pressedKeyframe->time = newTime;
for (auto row : qAsConst(m_selectedKeyframesMasterRows))
row->updateKeyframes();
}
+long KeyframeManager::getMinSelectedKeyframesTime() const
+{
+ long minTime = LONG_MAX;
+ for (auto keyframe : qAsConst(m_selectedKeyframes)) {
+ if (keyframe->time < minTime)
+ minTime = keyframe->time;
+ }
+
+ return minTime;
+}
+
+// returns the distance between the pressed keyframe and the min-time keyframe in a multiselection
+long KeyframeManager::getPressedKeyframeOffset() const
+{
+ if (m_scene->pressedKeyframe())
+ return m_scene->pressedKeyframe()->time - getMinSelectedKeyframesTime();
+
+ return 0;
+}
+
// selected keyframes belong to only one master row
bool KeyframeManager::oneMasterRowSelected() const
{
@@ -422,9 +424,7 @@ bool KeyframeManager::hasDynamicKeyframes(RowTree *row) const
return false;
}
-// IKeyframesManager interface to connect Doc and KeyframeManager
-// Mahmoud_TODO: rewrite a better interface for the new timeline
-// ITimelineKeyframesManager interface
+// IKeyframesManager interface
void KeyframeManager::SetKeyframeTime(long inTime)
{
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(inTime, g_StudioApp.GetCore()->GetDoc(),
@@ -459,35 +459,25 @@ void KeyframeManager::SetKeyframesDynamic(bool inDynamic)
g_StudioApp.GetCore()->ExecuteCommand(cmd);
}
-long KeyframeManager::OffsetSelectedKeyframes(long inOffset)
-{
- double dx = m_scene->ruler()->timeToDistance(inOffset / 1000.0);
- moveSelectedKeyframes(dx);
- return 0;
-}
-
-bool KeyframeManager::CanMakeSelectedKeyframesDynamic()
-{
- // Mahmoud_TODO: implement if needed
- return false;
-}
-
void KeyframeManager::CommitChangedKeyframes()
{
+ m_scene->resetPressedKeyframe();
commitMoveSelectedKeyframes();
}
void KeyframeManager::RollbackChangedKeyframes()
{
+ m_scene->resetPressedKeyframe();
+
for (Keyframe *keyframe : qAsConst(m_selectedKeyframes))
- keyframe->time = keyframe->binding->GetTime() / 1000.0;
+ keyframe->time = keyframe->binding->GetTime();
for (auto row : qAsConst(m_selectedKeyframesMasterRows))
row->updateKeyframes();
}
// IKeyframesManager interface
-bool KeyframeManager::HasSelectedKeyframes(bool inOnlyDynamic)
+bool KeyframeManager::HasSelectedKeyframes()
{
return hasSelectedKeyframes();
}
@@ -571,11 +561,6 @@ void KeyframeManager::SetKeyframeInterpolation()
}
}
-void KeyframeManager::SelectAllKeyframes()
-{
- // Mahmoud_TODO: implement if needed
-}
-
void KeyframeManager::DeselectAllKeyframes()
{
deselectAllKeyframes();
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
index 6af9896f..9c160687 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/KeyframeManager.h
@@ -29,10 +29,10 @@
#ifndef KEYFRAMEMANAGER_H
#define KEYFRAMEMANAGER_H
-#include "Bindings/ITimelineKeyframesManager.h"
+#include "IKeyframesManager.h"
+#include "Qt3DSDMAnimation.h"
#include <QtCore/qlist.h>
#include <StudioObjectTypes.h>
-#include "Qt3DSDMAnimation.h"
class RowTimeline;
class RowTree;
@@ -43,13 +43,13 @@ struct Keyframe;
QT_FORWARD_DECLARE_CLASS(QGraphicsSceneContextMenuEvent)
QT_FORWARD_DECLARE_CLASS(QRectF)
-class KeyframeManager : public ITimelineKeyframesManager
+class KeyframeManager : public IKeyframesManager
{
public:
KeyframeManager(TimelineGraphicsScene *m_scene);
- virtual ~KeyframeManager();
+ virtual ~KeyframeManager() override;
- QList<Keyframe *> insertKeyframe(RowTimeline *row, double time,
+ QList<Keyframe *> insertKeyframe(RowTimeline *row, long time,
bool selectInsertedKeyframes = true);
void selectKeyframe(Keyframe *keyframe);
void selectConnectedKeyframes(Keyframe *keyframe);
@@ -63,7 +63,7 @@ public:
void deleteKeyframes(RowTimeline *row, bool repaint = true);
void copySelectedKeyframes();
void pasteKeyframes();
- void moveSelectedKeyframes(double dx);
+ void moveSelectedKeyframes(long newTime);
void commitMoveSelectedKeyframes();
bool deleteSelectedKeyframes();
bool oneMasterRowSelected() const;
@@ -72,16 +72,11 @@ public:
bool hasDynamicKeyframes(RowTree *row) const;
// IKeyframesManager interface
- // Mahmoud_TODO: rewrite a better interface for the new timeline
- // ITimelineKeyframesManager interface
void SetKeyframeTime(long inTime) override;
void SetKeyframesDynamic(bool inDynamic) override;
- long OffsetSelectedKeyframes(long inOffset) override;
- bool CanMakeSelectedKeyframesDynamic() override;
void CommitChangedKeyframes() override;
void RollbackChangedKeyframes() override;
- // IKeyframesManager interface
- bool HasSelectedKeyframes(bool inOnlyDynamic) override;
+ bool HasSelectedKeyframes() override;
bool HasDynamicKeyframes() override;
bool CanPerformKeyframeCopy() override;
bool CanPerformKeyframePaste() override;
@@ -89,14 +84,16 @@ public:
bool RemoveKeyframes(bool inPerformCopy) override;
void PasteKeyframes() override;
void SetKeyframeInterpolation() override;
- void SelectAllKeyframes() override;
void DeselectAllKeyframes() override;
void SetChangedKeyframes() override;
+ long getPressedKeyframeOffset() const;
private:
qt3dsdm::SGetOrSetKeyframeInfo setKeyframeInfo(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe,
qt3dsdm::IAnimationCore &inCore);
- CPasteKeyframeCommandHelper *m_pasteKeyframeCommandHelper;
+ long getMinSelectedKeyframesTime() const;
+
+ CPasteKeyframeCommandHelper *m_pasteKeyframeCommandHelper = nullptr;
TimelineGraphicsScene *m_scene;
QList<Keyframe *> m_selectedKeyframes;
QList<RowTimeline *> m_selectedKeyframesMasterRows;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
index dae3d80a..6854b49b 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/RowManager.cpp
@@ -98,8 +98,8 @@ RowTree *RowManager::createRowFromBinding(ITimelineItemBinding *binding, RowTree
ITimelineTimebar *timebar = binding->GetTimelineItem()->GetTimebar();
RowTimeline *rowTimeline = newRow->rowTimeline();
rowTimeline->clearBoundChildren();
- rowTimeline->setStartTime(timebar->GetStartTime() * .001);
- rowTimeline->setEndTime(timebar->GetEndTime() * .001);
+ rowTimeline->setStartTime(timebar->GetStartTime());
+ rowTimeline->setEndTime(timebar->GetEndTime());
rowTimeline->setBarColor(timebar->GetTimebarColor());
// create property rows
@@ -113,12 +113,12 @@ RowTree *RowManager::createRowFromBinding(ITimelineItemBinding *binding, RowTree
// add keyframes
for (int j = 0; j < prop_i->GetKeyframeCount(); j++) {
- Qt3DSDMTimelineKeyframe *kf =
- static_cast<Qt3DSDMTimelineKeyframe *>(prop_i->GetKeyframeByIndex(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, false);
+ QList<Keyframe *> addedKeyframes
+ = m_scene->keyframeManager()->insertKeyframe(propRow->rowTimeline(),
+ kf->GetTime(), false);
Keyframe *kfUI = addedKeyframes.at(0);
kf->setUI(kfUI);
@@ -151,7 +151,7 @@ RowTree *RowManager::getOrCreatePropertyRow(RowTree *masterRow, const QString &p
{
RowTree *propertyRow = masterRow->getPropertyRow(propType);
if (!propertyRow)
- propertyRow = createRow(OBJTYPE_UNKNOWN, masterRow, 0, propType, index);
+ propertyRow = createRow(OBJTYPE_UNKNOWN, masterRow, {}, propType, index);
propertyRow->updateLock(masterRow->locked());
@@ -270,14 +270,14 @@ void RowManager::clearSelection()
// set updateMaxDuration to false.
void RowManager::updateRulerDuration(bool updateMaxDuration)
{
- double duration = 0;
- double maxDuration = 0; // for setting correct size for the view so scrollbars appear correctly
+ long duration = 0;
+ long maxDuration = 0; // for setting correct size for the view so scrollbars appear correctly
if (m_layoutTree->count() > 1) {
auto rootRow = static_cast<RowTree *>(m_layoutTree->itemAt(1)->graphicsItem());
bool isComponent = rootRow->rowType() == OBJTYPE_COMPONENT;
for (int i = 1; i < m_layoutTree->count(); ++i) {
RowTree *row_i = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem());
- double dur_i = row_i->rowTimeline()->getEndTime();
+ long dur_i = row_i->rowTimeline()->getEndTime();
if (((isComponent && i != 1) || row_i->rowType() == OBJTYPE_LAYER) && dur_i > duration)
duration = dur_i;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
index ae5aa2cb..61525718 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineConstants.h
@@ -36,7 +36,8 @@ namespace TimelineConstants
const int ROW_H_EXPANDED = 120; // property rows height when graph is shown
const int ROW_SPACING = 2;
const int ROW_DEPTH_STEP = 15; // x-distance between 2 consecutive depths
- const int RULER_SEC_W = 30; // width of 1 second section (at scale 1)
+ const double RULER_SEC_W = 30; // width of 1 second section (at scale 1)
+ const double RULER_MILLI_W = RULER_SEC_W / 1000.0; // width of 1 millisecond 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 = 3; // height of secondary divisions
@@ -69,7 +70,7 @@ namespace TimelineConstants
const int AUTO_SCROLL_DELTA = 8; // increment in scroll at each time step
const int AUTO_SCROLL_TRIGGER = 500; // time after which auto scroll starts (millis)
const int AUTO_EXPAND_TIME = 500; // auto expand a hovered row (while DnD-ing)
- const double MAX_SLIDE_TIME = 3599.0; // seconds
+ const long MAX_SLIDE_TIME = 3599000; // milliseconds
const int TIMELINE_SCROLL_MAX_DELTA = 25; // Maximum amount of pixels to scroll per frame
const int TIMELINE_SCROLL_DIVISOR = 6; // Divisor for timeline autoscroll distance
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
index 03764b13..378b20da 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.cpp
@@ -31,11 +31,8 @@
#include "RowManager.h"
#include "RowTree.h"
#include "Bindings/ITimelineItemBinding.h"
-#include "DurationEditDlg.h"
#include "StudioApp.h"
#include "Dialogs.h"
-#include "Core.h"
-#include "Doc.h"
TimelineControl::TimelineControl(TimelineGraphicsScene *scene)
: m_scene(scene)
@@ -54,29 +51,24 @@ void TimelineControl::setRowTimeline(RowTimeline *rowTimeline)
void TimelineControl::showDurationEditDialog()
{
- g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(m_startTime * 1000, m_endTime * 1000,
- g_StudioApp.GetCore()->GetDoc(), this);
+ g_StudioApp.GetDialogs()->asyncDisplayDurationEditDialog(m_startTime, m_endTime, this);
}
void TimelineControl::ChangeStartTime(long inTime)
{
- double time = (double)inTime / 1000;
- m_rowTimeline->setStartTime(time);
+ m_rowTimeline->setStartTime(inTime);
}
void TimelineControl::ChangeEndTime(long inTime)
{
- double time = (double)inTime / 1000;
- m_rowTimeline->setEndTime(time);
+ m_rowTimeline->setEndTime(inTime);
m_scene->rowManager()->updateRulerDuration();
}
void TimelineControl::Commit()
{
- long startTime = m_rowTimeline->getStartTime() * 1000;
- m_timebar->ChangeTime(startTime, true);
- long endTime = m_rowTimeline->getEndTime() * 1000;
- m_timebar->ChangeTime(endTime, false);
+ m_timebar->ChangeTime(m_rowTimeline->getStartTime(), true);
+ m_timebar->ChangeTime(m_rowTimeline->getEndTime(), false);
m_timebar->CommitTimeChange();
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
index 981b6db7..3c348016 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineControl.h
@@ -53,8 +53,8 @@ private:
TimelineGraphicsScene *m_scene = nullptr;
RowTimeline *m_rowTimeline = nullptr;
ITimelineTimebar *m_timebar = nullptr;
- double m_startTime = 0;
- double m_endTime = 0;
+ long m_startTime = 0;
+ long m_endTime = 0;
};
#endif // TIMELINECONTROL_H
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
index e8c6730a..67e1c897 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
@@ -50,7 +50,7 @@
#include "RowTreeContextMenu.h"
#include "RowTimelineContextMenu.h"
#include "StudioPreferences.h"
-#include "TimeEditDlg.h"
+#include "TimeEnums.h"
#include "StudioClipboard.h"
#include "Dialogs.h"
#include "Qt3DSDMStudioSystem.h"
@@ -80,16 +80,15 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
, m_layoutTimeline(new QGraphicsLinearLayout(Qt::Vertical))
, m_ruler(new Ruler)
, m_playHead(new PlayHead(m_ruler))
- , m_selectionRect(new SelectionRect())
- , m_rowMover(new RowMover(this))
, m_widgetTimeline(timelineWidget)
, m_widgetRoot(new QGraphicsWidget)
+ , m_rowMover(new RowMover(this))
+ , m_selectionRect(new SelectionRect())
, m_rowManager(new RowManager(this, m_layoutTree, m_layoutTimeline))
, m_keyframeManager(new KeyframeManager(this))
, m_pressPos(invalidPoint)
, m_pressScreenPos(invalidPoint)
, m_timelineControl(new TimelineControl(this))
- , m_currentCursor(-1)
{
addItem(m_playHead);
addItem(m_selectionRect);
@@ -164,8 +163,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
}
if (m_selectionRect->isActive()) {
- p -= QPoint(0, m_widgetTimeline->navigationBar()->height()
- + TimelineConstants::ROW_H);
+ p -= QPoint(0, m_widgetTimeline->navigationBar()->height() + TimelineConstants::ROW_H);
const double bottom = timelineContent->contentsRect().height() - scrollBarOffsets.y();
if (m_lastAutoScrollX != p.x() || p.x() <= 0 || p.x() >= right
|| m_lastAutoScrollY != p.y() || p.y() <= 0 || p.y() >= bottom) {
@@ -200,7 +198,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
if (scroll != 0)
scroll -= TimelineConstants::TREE_BOUND_W;
- double distance = p.x() + scroll;
+ double distance = p.x() + scroll - TimelineConstants::RULER_EDGE_OFFSET;
if (m_clickedTimelineControlType == TimelineControlType::Duration
&& !m_editedTimelineRow.isNull()) {
distance -= m_editedTimelineRow->getDurationMoveOffsetX();
@@ -210,8 +208,7 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
snap(distance, !m_rulerPressed);
if (m_rulerPressed) {
- long time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET) * 1000;
+ long time = m_ruler->distanceToTime(distance);
if (time < 0)
time = 0;
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(time);
@@ -223,22 +220,21 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
if (m_dragging) {
if (m_clickedTimelineControlType == TimelineControlType::StartHandle) {
- double visiblePtX = distance > TimelineConstants::RULER_EDGE_OFFSET
- ? m_editedTimelineRow->getStartX() : 0;
+ double visiblePtX = distance > 0 ? m_editedTimelineRow->getStartX() : 0;
if (distance > m_editedTimelineRow->getEndX())
visiblePtX += TimelineConstants::RULER_EDGE_OFFSET;
m_editedTimelineRow->setStartX(distance);
m_editedTimelineRow->showToolTip(QCursor::pos());
- timelineContent->ensureVisible(TimelineConstants::TREE_BOUND_W + visiblePtX,
+ timelineContent->ensureVisible(TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET
+ + visiblePtX,
m_editedTimelineRow->y(), 0, 0, 0, 0);
} else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) {
- double time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET);
+ long time = m_ruler->distanceToTime(distance);
double edgeMargin = 0;
if (time > TimelineConstants::MAX_SLIDE_TIME) {
- distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME)
- + TimelineConstants::RULER_EDGE_OFFSET;
+ distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME);
edgeMargin = TimelineConstants::RULER_EDGE_OFFSET;
} else if (time < m_editedTimelineRow->getStartTime()) {
edgeMargin = -TimelineConstants::RULER_EDGE_OFFSET;
@@ -248,27 +244,27 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *timelineWidget)
rowManager()->updateRulerDuration(p.x() > right);
timelineContent->ensureVisible(
TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET
+ m_editedTimelineRow->getEndX() + edgeMargin,
m_editedTimelineRow->y(), 0, 0, 0, 0);
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
- double time = m_ruler->distanceToTime(
- distance - TimelineConstants::RULER_EDGE_OFFSET)
- + m_editedTimelineRow->getDuration(); // seconds
+ long time = m_ruler->distanceToTime(distance)
+ + m_editedTimelineRow->getDuration(); // milliseconds
double visiblePtX = distance
- + m_editedTimelineRow->getDurationMoveOffsetX();
+ + m_editedTimelineRow->getDurationMoveOffsetX();
if (time > TimelineConstants::MAX_SLIDE_TIME) {
distance = m_ruler->timeToDistance(TimelineConstants::MAX_SLIDE_TIME
- - m_editedTimelineRow->getDuration())
- + TimelineConstants::RULER_EDGE_OFFSET;
+ - m_editedTimelineRow->getDuration());
visiblePtX = m_editedTimelineRow->getEndX()
- + TimelineConstants::RULER_EDGE_OFFSET;
+ + TimelineConstants::RULER_EDGE_OFFSET;
}
m_editedTimelineRow->moveDurationTo(distance);
m_editedTimelineRow->showToolTip(QCursor::pos());
rowManager()->updateRulerDuration(p.x() > right);
timelineContent->ensureVisible(
- TimelineConstants::TREE_BOUND_W + visiblePtX,
+ TimelineConstants::TREE_BOUND_W
+ + TimelineConstants::RULER_EDGE_OFFSET + visiblePtX,
m_editedTimelineRow->y(), 0, 0, 0, 0);
}
}
@@ -365,8 +361,8 @@ void TimelineGraphicsScene::setControllerText(const QString &controller)
void TimelineGraphicsScene::updateTimelineLayoutWidth()
{
double timelineWidth = TimelineConstants::RULER_EDGE_OFFSET * 2
- + m_ruler->maxDuration() * TimelineConstants::RULER_SEC_W
- * m_ruler->timelineScale();
+ + m_ruler->maxDuration() * TimelineConstants::RULER_MILLI_W
+ * m_ruler->timelineScale();
m_layoutTimeline->setMinimumWidth(timelineWidth);
m_layoutTimeline->setMaximumWidth(timelineWidth);
@@ -547,12 +543,12 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
m_pressPosInKeyframe = (m_pressPos.x() - m_ruler->x())
- (TimelineConstants::RULER_EDGE_OFFSET
+ m_ruler->timeToDistance(keyframe->time));
- m_keyframePressed = true;
+ m_pressedKeyframe = keyframe;
}
} else {
m_keyframeManager->deselectAllKeyframes();
- m_clickedTimelineControlType =
- m_editedTimelineRow->getClickedControl(m_pressPos);
+ m_clickedTimelineControlType
+ = m_editedTimelineRow->getClickedControl(m_pressPos);
// clicked an empty spot on a timeline row, start selection rect.
if (m_clickedTimelineControlType == TimelineControlType::None) {
@@ -560,7 +556,7 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
if (!ctrlKeyDown
&& m_rowManager->isRowSelected(m_editedTimelineRow->rowTree())
- && !m_rowManager->isSingleSelected() ) {
+ && !m_rowManager->isSingleSelected()) {
m_releaseSelectRow = m_editedTimelineRow->rowTree();
}
@@ -631,16 +627,16 @@ void TimelineGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
m_rowMover->updateTargetRow(event->scenePos());
updateAutoScrolling(event->scenePos().y());
}
- } else if (m_keyframePressed) { // moving selected keyframes
- double newX = event->scenePos().x() - m_ruler->x() - m_pressPosInKeyframe;
+ } else if (m_pressedKeyframe) { // moving selected keyframes
+ double newX = event->scenePos().x() - m_ruler->x()
+ - TimelineConstants::RULER_EDGE_OFFSET - m_pressPosInKeyframe;
- if (newX < TimelineConstants::RULER_EDGE_OFFSET)
- newX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (newX < 0)
+ newX = 0;
if (shift)
snap(newX);
- newX += m_ruler->x() + m_pressPosInKeyframe;
- double dx = newX - m_pressPos.x();
- m_keyframeManager->moveSelectedKeyframes(dx);
+
+ m_keyframeManager->moveSelectedKeyframes(ruler()->distanceToTime(newX));
m_pressPos.setX(newX);
}
@@ -690,23 +686,23 @@ void TimelineGraphicsScene::stopAutoScroll() {
void TimelineGraphicsScene::updateSnapSteps()
{
m_snapSteps.clear();
- // i = 1 is always the scene row
+ // i = 1 is always the scene row (or component root)
for (int i = 2; i < m_layoutTimeline->count(); i++) {
- RowTree *rowTree = static_cast<RowTree *>
- (m_layoutTree->itemAt(i)->graphicsItem());
+ RowTree *rowTree = static_cast<RowTree *>(m_layoutTree->itemAt(i)->graphicsItem());
if (rowTree->hasDurationBar() && rowTree->isVisible()) {
- if (!m_snapSteps.contains(rowTree->rowTimeline()->getStartX()))
- m_snapSteps.push_back(rowTree->rowTimeline()->getStartX());
+ double startX = rowTree->rowTimeline()->getStartX();
+ if (!m_snapSteps.contains(startX))
+ m_snapSteps.push_back(startX);
- if (!m_snapSteps.contains(rowTree->rowTimeline()->getEndX()))
- m_snapSteps.push_back(rowTree->rowTimeline()->getEndX());
+ double endX = rowTree->rowTimeline()->getEndX();
+ if (!m_snapSteps.contains(endX))
+ m_snapSteps.push_back(endX);
// add keyframes times
if (rowTree->hasPropertyChildren()) {
const QList<Keyframe *> keyframes = rowTree->rowTimeline()->keyframes();
for (Keyframe *k : keyframes) {
- double kX = m_ruler->timeToDistance(k->time)
- + TimelineConstants::RULER_EDGE_OFFSET;
+ double kX = m_ruler->timeToDistance(k->time);
if (!m_snapSteps.contains(kX))
m_snapSteps.push_back(kX);
}
@@ -730,7 +726,7 @@ void TimelineGraphicsScene::resetMousePressParams()
m_timelinePanning = false;
m_startRowMoverOnNextDrag = false;
m_rulerPressed = false;
- m_keyframePressed = false;
+ m_pressedKeyframe = nullptr;
m_clickedTimelineControlType = TimelineControlType::None;
m_editedTimelineRow.clear();
m_releaseSelectRow.clear();
@@ -743,6 +739,11 @@ void TimelineGraphicsScene::resetMousePressParams()
m_lastAutoScrollY = -1.0;
}
+void TimelineGraphicsScene::resetPressedKeyframe()
+{
+ m_pressedKeyframe = nullptr;
+}
+
QLabel *TimelineGraphicsScene::timebarTooltip()
{
return m_timebarToolTip;
@@ -752,7 +753,8 @@ void TimelineGraphicsScene::snap(double &value, bool snapToPlayHead)
{
// snap to play head
if (snapToPlayHead) {
- double playHeadX = m_playHead->x() - m_ruler->x();
+ double playHeadX = m_playHead->x() - TimelineConstants::TREE_BOUND_W
+ - TimelineConstants::RULER_EDGE_OFFSET;
if (abs(value - playHeadX) < CStudioPreferences::GetSnapRange()) {
value = playHeadX;
return;
@@ -775,8 +777,7 @@ void TimelineGraphicsScene::snap(double &value, bool snapToPlayHead)
else if (CStudioPreferences::GetTimelineSnappingGridResolution() == SNAPGRID_TICKMARKS)
snapStep *= .1;
- double snapValue = TimelineConstants::RULER_EDGE_OFFSET
- + round((value - TimelineConstants::RULER_EDGE_OFFSET) / snapStep) * snapStep;
+ double snapValue = round(value / snapStep) * snapStep;
if (abs(value - snapValue) < CStudioPreferences::GetSnapRange())
value = snapValue;
}
@@ -788,37 +789,33 @@ void TimelineGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
if (m_dragging) {
if (m_rowMover->isActive()) { // moving rows (reorder/reparent)
commitMoveRows();
- } else if (m_keyframePressed) {
+ } else if (m_pressedKeyframe) {
// update keyframe movement (time) to binding
m_keyframeManager->commitMoveSelectedKeyframes();
} else if (m_clickedTimelineControlType == TimelineControlType::StartHandle) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
->GetTimelineItem()->GetTimebar();
- timebar->ChangeTime(m_editedTimelineRow->getStartTime() * 1000, true);
+ timebar->ChangeTime(m_editedTimelineRow->getStartTime(), true);
timebar->CommitTimeChange();
}
} else if (m_clickedTimelineControlType == TimelineControlType::EndHandle) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
- ->GetTimelineItem()->GetTimebar();
- timebar->ChangeTime(m_editedTimelineRow->getEndTime() * 1000, false);
+ ->GetTimelineItem()->GetTimebar();
+ timebar->ChangeTime(m_editedTimelineRow->getEndTime(), false);
timebar->CommitTimeChange();
- if (m_playHead->time() > ruler()->duration()) {
- g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration()
- * 1000);
- }
+ if (m_playHead->time() > ruler()->duration())
+ g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration());
}
} else if (m_clickedTimelineControlType == TimelineControlType::Duration) {
if (!m_editedTimelineRow.isNull()) {
ITimelineTimebar *timebar = m_editedTimelineRow->rowTree()->getBinding()
->GetTimelineItem()->GetTimebar();
- timebar->OffsetTime(m_editedTimelineRow->getDurationMoveTime() * 1000);
+ timebar->OffsetTime(m_editedTimelineRow->getDurationMoveTime());
timebar->CommitTimeChange();
- if (m_playHead->time() > ruler()->duration()) {
- g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration()
- * 1000);
- }
+ if (m_playHead->time() > ruler()->duration())
+ g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(ruler()->duration());
}
}
} else if (!m_rulerPressed && (!m_releaseSelectRow.isNull() || !itemAt(event->scenePos(),
@@ -849,7 +846,8 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even
|| itemBelowPlayhead->type() == TimelineItem::TypeRuler) {
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(doc->GetCurrentViewTime(),
- doc, PLAYHEAD);
+ doc, PLAYHEAD,
+ m_keyframeManager);
} else {
item = itemBelowPlayhead;
if (item->type() == TimelineItem::TypeRowTree) {
@@ -880,8 +878,9 @@ void TimelineGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *even
RowTimeline *rowTimeline = static_cast<RowTimeline *>(item);
Keyframe *clickedKeyframe = rowTimeline->getClickedKeyframe(scenePos);
if (clickedKeyframe) {
+ m_pressedKeyframe = clickedKeyframe;
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(
- clickedKeyframe->time * 1000, g_StudioApp.GetCore()->GetDoc(),
+ clickedKeyframe->time, g_StudioApp.GetCore()->GetDoc(),
ASSETKEYFRAME, m_keyframeManager);
} else {
if (!rowTimeline->rowTree()->locked())
@@ -980,8 +979,7 @@ void TimelineGraphicsScene::updateHoverStatus(const QPointF &scenePos)
item = getItemBelowType(TimelineItem::TypePlayHead, item, scenePos);
if (item->type() == TimelineItem::TypeRowTimeline) {
RowTimeline *timelineItem = static_cast<RowTimeline *>(item);
- TimelineControlType controlType =
- timelineItem->getClickedControl(scenePos);
+ TimelineControlType controlType = timelineItem->getClickedControl(scenePos);
if (controlType == TimelineControlType::StartHandle
|| controlType == TimelineControlType::EndHandle) {
setMouseCursor(CMouseCursor::CURSOR_RESIZE_LEFTRIGHT);
@@ -1120,3 +1118,4 @@ KeyframeManager *TimelineGraphicsScene::keyframeManager() const { return m
QGraphicsLinearLayout *TimelineGraphicsScene::layoutTree() const { return m_layoutTree; }
QGraphicsLinearLayout *TimelineGraphicsScene::layoutTimeline() const { return m_layoutTimeline; }
TimelineWidget *TimelineGraphicsScene::widgetTimeline() const { return m_widgetTimeline; }
+Keyframe *TimelineGraphicsScene::pressedKeyframe() const { return m_pressedKeyframe; }
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
index e8eda8f3..8a41ea49 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.h
@@ -95,6 +95,8 @@ public:
QPoint getScrollbarOffsets() const;
void handleShowDISelector(const QString &propertyname, qt3dsdm::Qt3DSDMInstanceHandle inInst,
const QPoint &pos);
+ void resetPressedKeyframe();
+ Keyframe *pressedKeyframe() const;
protected:
bool event(QEvent *event) override;
@@ -140,13 +142,13 @@ private:
QPointF m_pressPos;
QPointF m_pressScreenPos;
QList<double> m_snapSteps;
- CMouseCursor::Qt3DSMouseCursor m_currentCursor;
+ CMouseCursor::Qt3DSMouseCursor m_currentCursor = -1;
TimelineControl *m_timelineControl = nullptr;
DataInputSelectView *m_dataInputSelector = nullptr; // triggered by context menu but owned by
// rowtree
bool m_rulerPressed = false;
- bool m_keyframePressed = false;
+ Keyframe *m_pressedKeyframe = nullptr;
bool m_dragging = false;
bool m_startRowMoverOnNextDrag = false;
bool m_timelineZooming = false;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
index 6240fc34..73f5e155 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.cpp
@@ -52,12 +52,12 @@
#include "Bindings/Qt3DSDMTimelineItemBinding.h"
#include "Bindings/Qt3DSDMTimelineItemProperty.h"
#include "Bindings/TimelineBreadCrumbProvider.h"
-#include "TimeEditDlg.h"
#include "IDocumentEditor.h"
#include "Control.h"
#include "TimelineDropTarget.h"
#include "StudioPreferences.h"
#include "Dialogs.h"
+#include "TimeEnums.h"
#include <QtGui/qevent.h>
#include <QtWidgets/qgraphicslinearlayout.h>
@@ -84,7 +84,7 @@ public:
};
TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
- : QWidget()
+ : QWidget(parent)
, m_toolbar(new TimelineToolbar())
, m_viewTreeHeader(new TreeHeaderView(this))
, m_viewTreeContent(new QGraphicsView(this))
@@ -247,17 +247,18 @@ TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
connect(m_toolbar, &TimelineToolbar::deleteLayerTriggered,
[=](){ doc->DeleteSelectedObject(); });
- connect(m_toolbar, &TimelineToolbar::gotoTimeTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::gotoTimeTriggered, this, [=]() {
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
g_StudioApp.GetDialogs()->asyncDisplayTimeEditDialog(doc->GetCurrentViewTime(),
- doc, PLAYHEAD);
+ doc, PLAYHEAD,
+ m_graphicsScene->keyframeManager());
});
- connect(m_toolbar, &TimelineToolbar::firstFrameTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::firstFrameTriggered, this, []() {
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(0);
});
- connect(m_toolbar, &TimelineToolbar::stopTriggered, this, [this]() {
+ connect(m_toolbar, &TimelineToolbar::stopTriggered, this, []() {
g_StudioApp.PlaybackStopNoRestore();
});
@@ -270,7 +271,7 @@ TimelineWidget::TimelineWidget(const QSize &preferredSize, QWidget *parent)
});
connect(m_toolbar, &TimelineToolbar::lastFrameTriggered, this, [this]() {
- double dur = m_graphicsScene->ruler()->duration() * 1000;
+ long dur = m_graphicsScene->ruler()->duration();
g_StudioApp.GetCore()->GetDoc()->NotifyTimeChanged(dur);
});
@@ -305,15 +306,13 @@ Q3DStudio::CString TimelineWidget::getPlaybackMode()
CDoc *doc = g_StudioApp.GetCore()->GetDoc();
qt3dsdm::Qt3DSDMSlideHandle theActiveSlide(doc->GetActiveSlide());
// clock has passed the end, check whether needs to switch slide
- qt3dsdm::Qt3DSDMInstanceHandle theInstanceHandle = doc->GetStudioSystem()->GetSlideSystem()
- ->GetSlideInstance(theActiveSlide);
+ qt3dsdm::Qt3DSDMInstanceHandle instance = doc->GetStudioSystem()->GetSlideSystem()
+ ->GetSlideInstance(theActiveSlide);
- CClientDataModelBridge *clientDataModelBridge = doc->GetStudioSystem()
- ->GetClientDataModelBridge();
+ CClientDataModelBridge *bridge = doc->GetStudioSystem()->GetClientDataModelBridge();
qt3dsdm::IPropertySystem *propertySystem = doc->GetStudioSystem()->GetPropertySystem();
qt3dsdm::SValue theValue;
- propertySystem->GetInstancePropertyValue(theInstanceHandle, clientDataModelBridge->GetSlide()
- .m_PlayMode, theValue);
+ propertySystem->GetInstancePropertyValue(instance, bridge->GetSlide().m_PlayMode, theValue);
return qt3dsdm::get<qt3dsdm::TDataStrPtr>(theValue)->GetData();
}
@@ -377,7 +376,7 @@ void TimelineWidget::OnNewPresentation()
std::placeholders::_1, std::placeholders::_2)));
m_connections.push_back(theSignalProvider->ConnectFirstKeyframeDynamicSet(
std::bind(&TimelineWidget::onFirstKeyframeDynamicSet, this,
- std::placeholders::_1, std::placeholders::_2)));
+ std::placeholders::_1)));
// action created/deleted
m_connections.push_back(theSignalProvider->ConnectActionCreated(
@@ -426,7 +425,7 @@ void TimelineWidget::OnClosingPresentation()
void TimelineWidget::OnTimeChanged(long inTime)
{
- m_graphicsScene->playHead()->setTime(inTime * .001);
+ m_graphicsScene->playHead()->setTime(inTime);
m_toolbar->setTime(inTime);
double left = m_viewTimelineHeader->horizontalScrollBar()->value()
@@ -474,6 +473,7 @@ void TimelineWidget::insertToHandlesMapRecursive(Qt3DSDMTimelineItemBinding *bin
return;
insertToHandlesMap(binding);
+
const QList<ITimelineItemBinding *> children = binding->GetChildren();
for (auto child : children)
insertToHandlesMapRecursive(static_cast<Qt3DSDMTimelineItemBinding *>(child));
@@ -596,8 +596,7 @@ void TimelineWidget::onAnimationCreated(qt3dsdm::Qt3DSDMInstanceHandle parentIns
for (int i = 0; i < propBinding->GetKeyframeCount(); i++) {
IKeyframe *kf = propBinding->GetKeyframeByIndex(i);
Keyframe *kfUI = m_graphicsScene->keyframeManager()->insertKeyframe(
- propRow->rowTimeline(), static_cast<double>(kf->GetTime()) * .001, false)
- .at(0);
+ propRow->rowTimeline(), kf->GetTime(), false).at(0);
kf->setUI(kfUI);
kfUI->binding = static_cast<Qt3DSDMTimelineKeyframe *>(kf);
@@ -685,10 +684,8 @@ void TimelineWidget::refreshKeyframe(qt3dsdm::Qt3DSDMAnimationHandle inAnimation
}
}
-void TimelineWidget::onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation,
- bool inDynamic)
+void TimelineWidget::onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation)
{
- Q_UNUSED(inDynamic)
refreshKeyframe(inAnimation, 0, ETimelineKeyframeTransaction_DynamicChanged);
}
@@ -755,6 +752,28 @@ void TimelineWidget::onPropertyChanged(qt3dsdm::Qt3DSDMInstanceHandle inInstance
m_subpresentationChanges.insert(inInstance);
if (!m_asyncUpdateTimer.isActive())
m_asyncUpdateTimer.start();
+ } else if (inProperty == m_bridge->GetLayer().m_variants) {
+ qt3dsdm::SValue sValue;
+ if (doc->GetPropertySystem()->GetInstancePropertyValue(inInstance, inProperty, sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ QStringList groups;
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ if (!groups.contains(group))
+ groups.append(group);
+ }
+
+ m_variantsMap[inInstance] = groups;
+ } else {
+ m_variantsMap[inInstance].clear();
+ }
+
+ if (!m_asyncUpdateTimer.isActive())
+ m_asyncUpdateTimer.start();
+ }
}
}
@@ -778,11 +797,11 @@ void TimelineWidget::onAsyncUpdate()
m_graphicsScene->updateController();
onSelectionChange(doc->GetSelectedValue());
m_toolbar->setNewLayerEnabled(!m_graphicsScene->rowManager()->isComponentRoot());
+ refreshVariants();
- // update suppresentation indicators
- for (auto *row : m_handlesMap)
+ // update sub-presentation indicators
+ for (auto *row : qAsConst(m_handlesMap))
row->updateSubpresentations();
-
} else {
if (!m_moveMap.isEmpty()) {
// Flip the hash around so that we collect moves by parent.
@@ -926,10 +945,22 @@ void TimelineWidget::onAsyncUpdate()
}
m_graphicsScene->updateSnapSteps();
}
+
+ if (!m_variantsMap.isEmpty()) {
+ const auto instances = m_variantsMap.keys();
+ for (int instance : instances) {
+ if (m_handlesMap.contains(instance)) {
+ RowTree *row = m_handlesMap[instance];
+ if (row)
+ row->updateVariants(m_variantsMap[instance]); // variants groups names
+ }
+ }
+ }
}
m_dirtyProperties.clear();
m_moveMap.clear();
m_actionChanges.clear();
+ m_variantsMap.clear();
m_subpresentationChanges.clear();
m_keyframeChangesMap.clear();
m_graphicsScene->rowManager()->finalizeRowDeletions();
@@ -977,8 +1008,7 @@ void TimelineWidget::onPropertyLinked(qt3dsdm::Qt3DSDMInstanceHandle inInstance,
for (int i = 0; i < propBinding->GetKeyframeCount(); i++) {
IKeyframe *kf = propBinding->GetKeyframeByIndex(i);
Keyframe *kfUI = m_graphicsScene->keyframeManager()->insertKeyframe(
- propRow->rowTimeline(), static_cast<double>(kf->GetTime()) * .001,
- false).at(0);
+ propRow->rowTimeline(), kf->GetTime(), false).at(0);
kf->setUI(kfUI);
kfUI->binding = static_cast<Qt3DSDMTimelineKeyframe *>(kf);
@@ -1030,21 +1060,6 @@ void TimelineWidget::onChildMoved(int inParent, int inChild, long inOldIndex,
onChildAdded(inParent, inChild, inNewIndex);
}
-void TimelineWidget::OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation)
-{
-
-}
-
-void TimelineWidget::Draw(CRenderer *inRenderer)
-{
-
-}
-
-void TimelineWidget::OnGainFocus()
-{
-
-}
-
CDropTarget *TimelineWidget::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
EStudioObjectType objectType,
Q3DStudio::DocumentEditorFileType::Enum fileType)
@@ -1079,12 +1094,6 @@ CDropTarget *TimelineWidget::FindDropCandidate(CPt &inMousePoint, Qt::KeyboardMo
return theTarget;
}
-bool TimelineWidget::OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
- return true;
-}
-
-
void TimelineWidget::OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags)
{
Q_UNUSED(inFlags)
@@ -1103,14 +1112,6 @@ bool TimelineWidget::blockMousePress() const
return m_blockMousePress;
}
-void TimelineWidget::OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
-}
-
-void TimelineWidget::OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags)
-{
-}
-
CPt TimelineWidget::GetPreferredSize()
{
return CPt(m_preferredSize.width(), m_preferredSize.height());
@@ -1150,7 +1151,7 @@ Qt3DSDMTimelineItemBinding *TimelineWidget::getBindingForHandle(int handle,
const QList<ITimelineItemBinding *> children = binding->GetChildren();
for (auto child : children) {
Qt3DSDMTimelineItemBinding *b = getBindingForHandle(handle,
- static_cast<Qt3DSDMTimelineItemBinding *>(child));
+ static_cast<Qt3DSDMTimelineItemBinding *>(child));
if (b)
return b;
@@ -1174,6 +1175,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event)
void TimelineWidget::mouseReleaseEvent(QMouseEvent *event)
{
+ Q_UNUSED(event)
m_splitterPressed = false;
}
@@ -1232,8 +1234,8 @@ void TimelineWidget::onTimeBarColorChanged(const QColor &color)
void TimelineWidget::setSelectedTimeBarsColor(const QColor &color, bool preview)
{
using namespace Q3DStudio; // Needed for SCOPED_DOCUMENT_EDITOR macro
- auto rows = selectedRows();
- for (RowTree *row : qAsConst(rows)) {
+ const auto rows = selectedRows();
+ for (RowTree *row : rows) {
row->rowTimeline()->setBarColor(color);
if (!preview) {
Qt3DSDMTimelineItemBinding *timelineItemBinding =
@@ -1244,3 +1246,33 @@ void TimelineWidget::setSelectedTimeBarsColor(const QColor &color, bool preview)
}
}
}
+
+void TimelineWidget::refreshVariants()
+{
+ const auto propertySystem = g_StudioApp.GetCore()->GetDoc()->GetPropertySystem();
+ const auto layers = g_StudioApp.GetCore()->GetDoc()->getLayers();
+ for (auto layer : layers) {
+ if (!m_handlesMap.contains(layer))
+ continue;
+
+ qt3dsdm::SValue sValue;
+ if (propertySystem->GetInstancePropertyValue(layer, m_bridge->GetLayer().m_variants,
+ sValue)) {
+ QString propVal = QString::fromWCharArray(qt3dsdm::get<qt3dsdm::TDataStrPtr>(sValue)
+ ->GetData());
+ if (!propVal.isEmpty()) {
+ QStringList tagPairs = propVal.split(QLatin1Char(','));
+ QStringList groups;
+ for (int i = 0; i < tagPairs.size(); ++i) {
+ QString group = tagPairs[i].left(tagPairs[i].indexOf(QLatin1Char(':')));
+ if (!groups.contains(group))
+ groups.append(group);
+ }
+
+ m_handlesMap[layer]->updateVariants(groups);
+ } else {
+ m_handlesMap[layer]->updateVariants({});
+ }
+ }
+ }
+}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
index 26c9a66b..ac01367a 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/TimelineWidget.h
@@ -73,6 +73,7 @@ public:
void openBarColorDialog();
void onTimeBarColorChanged(const QColor &color);
void setSelectedTimeBarsColor(const QColor &color, bool preview);
+ void refreshVariants();
void enableDnD(bool b = true);
bool dndActive() const;
bool blockMousePress() const;
@@ -87,16 +88,10 @@ public:
bool hasSelectedKeyframes() const;
// CControl
- void OnDraw(CRenderer *inRenderer, CRct &inDirtyRect, bool inIgnoreValidation = false) override;
- void Draw(CRenderer *inRenderer) override;
- void OnGainFocus() override;
CDropTarget *FindDropCandidate(CPt &inMousePoint, Qt::KeyboardModifiers inFlags,
EStudioObjectType objectType,
Q3DStudio::DocumentEditorFileType::Enum fileType) override;
- bool OnMouseHover(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
void OnMouseMove(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
- void OnMouseOut(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
- void OnMouseUp(CPt inPoint, Qt::KeyboardModifiers inFlags) override;
CPt GetPreferredSize() override;
void SetSize(long inX, long inY) override;
bool isFullReconstructPending() const { return m_fullReconstruct; }
@@ -115,7 +110,7 @@ protected:
void onKeyframeDeleted(qt3dsdm::Qt3DSDMAnimationHandle inAnimation,
qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe);
void onKeyframeUpdated(qt3dsdm::Qt3DSDMKeyframeHandle inKeyframe);
- void onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation, bool inDynamic);
+ void onFirstKeyframeDynamicSet(qt3dsdm::Qt3DSDMAnimationHandle inAnimation);
void onAnimationDeleted(qt3dsdm::Qt3DSDMInstanceHandle parentInstance,
qt3dsdm::Qt3DSDMPropertyHandle property);
void onActionEvent(qt3dsdm::Qt3DSDMActionHandle inAction, qt3dsdm::Qt3DSDMSlideHandle inSlide,
@@ -164,6 +159,7 @@ private:
QSize m_preferredSize;
QMultiHash<qt3dsdm::Qt3DSDMInstanceHandle, qt3dsdm::Qt3DSDMPropertyHandle> m_dirtyProperties;
QHash<int, int> m_moveMap; // key: child handle, value: parent handle
+ QHash<int, QStringList> m_variantsMap; // key: obj handle, value: variant groups
QSet<int> m_actionChanges; // key: object handle
QSet<int> m_subpresentationChanges; // key: object handle
QMultiHash<int, int> m_keyframeChangesMap; // key: object handle, value: property handle
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
index 35787462..3ddfdcad 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.cpp
@@ -30,9 +30,11 @@
#include "Ruler.h"
#include "TimelineConstants.h"
#include "StudioPreferences.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include <QtGui/qcursor.h>
+#include <QtWidgets/qwidget.h>
PlayHead::PlayHead(Ruler *ruler)
: QGraphicsRectItem()
@@ -47,24 +49,22 @@ void PlayHead::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
static const QPixmap pixHead = QPixmap(":/images/PlaybackHead.png");
+ static const QPixmap pixHead2x = QPixmap(":/images/PlaybackHead@2x.png");
static const int PLAY_HEAD_H = 999999; // theoretically big enough height
- painter->drawPixmap(-TimelineConstants::PLAYHEAD_W * .5, 0, pixHead);
+ painter->drawPixmap(-TimelineConstants::PLAYHEAD_W * .5, 0, hiResIcons ? pixHead2x : pixHead);
painter->setPen(CStudioPreferences::timelinePlayheadLineColor());
painter->drawLine(0, 0, 0, PLAY_HEAD_H);
}
void PlayHead::setHeight(int height)
{
- setRect(
- rect().x(),
- rect().y(),
- rect().width(),
- height);
+ setRect(rect().x(), rect().y(), rect().width(), height);
}
-void PlayHead::setTime(double time)
+void PlayHead::setTime(long time)
{
if (time < 0)
time = 0;
@@ -78,21 +78,21 @@ void PlayHead::setTime(double time)
void PlayHead::setPosition(double posX)
{
posX = qBound(TimelineConstants::RULER_EDGE_OFFSET, posX, m_ruler->duration()
- * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale()
+ * TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale()
+ TimelineConstants::RULER_EDGE_OFFSET);
setX(m_ruler->x() + posX);
m_time = (posX - TimelineConstants::RULER_EDGE_OFFSET)
- / (TimelineConstants::RULER_SEC_W * m_ruler->timelineScale());
+ / (TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale());
}
void PlayHead::updatePosition()
{
setX(m_ruler->x() + TimelineConstants::RULER_EDGE_OFFSET
- + m_time * TimelineConstants::RULER_SEC_W * m_ruler->timelineScale());
+ + m_time * TimelineConstants::RULER_MILLI_W * m_ruler->timelineScale());
}
-double PlayHead::time() const
+long PlayHead::time() const
{
return m_time;
}
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
index ef628f51..395e6317 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/PlayHead.h
@@ -44,14 +44,14 @@ public:
void setHeight(int height);
void setPosition(double posX); // set x poisiotn
void updatePosition(); // sync x poisiotn based on time value
- void setTime(double time); // set time (sets x based on time input)
+ void setTime(long time); // set time (sets x based on time (ms) input)
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr) override;
- double time() const;
- int type() const;
+ long time() const;
+ int type() const override;
private:
- double m_time = 0;
+ long m_time = 0;
Ruler *m_ruler;
};
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
index 196cedde..a0b689f4 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.cpp
@@ -41,6 +41,7 @@
#include "AppFonts.h"
#include "StudioPreferences.h"
#include "TimelineToolbar.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include <QtGui/qbrush.h>
@@ -101,6 +102,8 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
{
Q_UNUSED(option)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
if (!y()) // prevents flickering when the row is just inserted to the layout
return;
@@ -122,6 +125,8 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
painter->fillRect(0, 0, size().width(), currentHeight, bgColor);
}
+ const double edgeOffset = TimelineConstants::RULER_EDGE_OFFSET;
+
// Duration. Draw duration bar (for scene/component root) also if it has
// datainput controller
if (m_rowTree->hasDurationBar() || m_controllerDataInput.size()) {
@@ -132,17 +137,17 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
painter->setBrush(QBrush(CStudioPreferences::timelineRowColorDurationOff1(),
Qt::BDiagPattern));
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_startX, 0, m_endX - m_startX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_startX, 0, m_endX - m_startX, currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_startX, 0, m_endX - m_startX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_startX, 0, m_endX - m_startX, currentHeight));
painter->setPen(QPen(CStudioPreferences::timelineRowColorDurationEdge(), 2));
- painter->drawLine(m_startX, 0, m_startX, currentHeight);
- painter->drawLine(m_endX, 0, m_endX, currentHeight);
+ painter->drawLine(edgeOffset + m_startX, 0, edgeOffset + m_startX, currentHeight);
+ painter->drawLine(edgeOffset + m_endX, 0, edgeOffset + m_endX, currentHeight);
} else {
// draw main duration part
- double x = qMax(m_startX, m_minStartX);
- double w = qMin(m_endX, m_maxEndX) - x;
+ double x = edgeOffset + qMax(m_startX, m_minStartX);
+ double w = edgeOffset + qMin(m_endX, m_maxEndX) - x;
static const int marginY = 3;
painter->setPen(Qt::NoPen);
@@ -161,8 +166,9 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
}
if (m_controllerDataInput.size()) {
- static const QPixmap pixDataInput
- = QPixmap(":/images/Objects-DataInput-White.png");
+ static const QPixmap pixDataInput = QPixmap(":/images/Objects-DataInput-White.png");
+ static const QPixmap pixDataInput2x
+ = QPixmap(":/images/Objects-DataInput-White@2x.png");
static const QFontMetrics fm(painter->font());
// need clip region to limit datainput icon visibility to the same rect as we use
@@ -178,8 +184,7 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
int iconx = x + (w - textwidth) / 2;
if (iconx < x)
iconx = x;
- painter->drawPixmap(iconx, marginY, pixDataInput.width(), pixDataInput.height(),
- pixDataInput);
+ painter->drawPixmap(iconx, marginY, hiResIcons ? pixDataInput2x : pixDataInput);
painter->setPen(Qt::NoPen);
painter->setClipping(false);
}
@@ -189,37 +194,40 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
Qt::BDiagPattern));
if (m_startX < m_minStartX) {
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_startX, 0, m_minStartX - m_startX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_startX, 0, m_minStartX - m_startX,
+ currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_startX, 0, m_minStartX - m_startX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_startX, 0, m_minStartX - m_startX,
+ currentHeight));
painter->setPen(CStudioPreferences::timelineRowColorDurationEdge());
- painter->drawLine(m_minStartX, 0, m_minStartX, currentHeight);
+ painter->drawLine(edgeOffset + m_minStartX, 0, edgeOffset + m_minStartX,
+ currentHeight);
}
// draw hashed part after
if (m_endX > m_maxEndX) {
painter->setPen(Qt::NoPen);
- painter->fillRect(QRect(m_maxEndX, 0, m_endX - m_maxEndX, currentHeight),
+ painter->fillRect(QRect(edgeOffset + m_maxEndX, 0, m_endX - m_maxEndX,
+ currentHeight),
CStudioPreferences::timelineRowColorDurationOff2());
- painter->drawRect(QRect(m_maxEndX, 0, m_endX - m_maxEndX, currentHeight));
+ painter->drawRect(QRect(edgeOffset + m_maxEndX, 0, m_endX - m_maxEndX,
+ currentHeight));
painter->setPen(CStudioPreferences::timelineRowColorDurationEdge());
- painter->drawLine(m_maxEndX, 0, m_maxEndX, currentHeight);
+ painter->drawLine(edgeOffset + m_maxEndX, 0, edgeOffset + m_maxEndX, currentHeight);
}
if (m_rowTree->indexInLayout() != 1) {
painter->setPen(QPen(CStudioPreferences::timelineRowColorDurationEdge(), 2));
- painter->drawLine(m_startX, 0, m_startX, currentHeight);
- painter->drawLine(m_endX, 0, m_endX, currentHeight);
+ painter->drawLine(edgeOffset + m_startX, 0, edgeOffset + m_startX, currentHeight);
+ painter->drawLine(edgeOffset + m_endX, 0, edgeOffset + m_endX, currentHeight);
}
}
painter->restore();
}
- if (m_propertyGraph) {
- // Property graph
- QRectF graphRect(TimelineConstants::RULER_EDGE_OFFSET, 0,
- widget->width(), currentHeight);
+ if (m_propertyGraph) { // Property graph
+ QRectF graphRect(edgeOffset, 0, widget->width(), currentHeight);
m_propertyGraph->paintGraphs(painter, graphRect);
}
@@ -228,23 +236,28 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
const qreal keyFrameHalfH = keyFrameH / 2.0;
const qreal keyFrameY = (qMin(currentHeight, TimelineConstants::ROW_H) / 2.0) - keyFrameHalfH;
const qreal hiddenKeyFrameY = keyFrameY + (keyFrameH * 2.0 / 3.0) + 2.0;
+ const qreal keyFrameOffset = hiResIcons ? 8 : 7.5;
// Hidden descendant keyframe indicators
if (!m_rowTree->expanded()) {
static const QPixmap pixKeyframeHidden = QPixmap(":/images/keyframe-hidden-normal.png");
- QVector<double> childKeyframeTimes;
+ static const QPixmap pixKeyframeHidden2x
+ = QPixmap(":/images/keyframe-hidden-normal@2x.png");
+ QVector<long> childKeyframeTimes;
collectChildKeyframeTimes(childKeyframeTimes);
const qreal oldOpacity = painter->opacity();
painter->setOpacity(0.75);
for (const auto time : qAsConst(childKeyframeTimes)) {
- const qreal xCoord = timeToX(time) - 2.5;
- painter->drawPixmap(QPointF(xCoord, hiddenKeyFrameY), pixKeyframeHidden);
+ const qreal xCoord = edgeOffset + m_rowTree->m_scene->ruler()->timeToDistance(time)
+ - 2.5;
+ painter->drawPixmap(QPointF(xCoord, hiddenKeyFrameY), hiResIcons ? pixKeyframeHidden2x
+ : pixKeyframeHidden);
}
painter->setOpacity(oldOpacity);
}
- if (m_rowTree->hasPropertyChildren()) { // master keyframes
+ if (m_rowTree->hasPropertyChildren()) { // object row keyframes
static const QPixmap pixKeyframeMasterDisabled
= QPixmap(":/images/Keyframe-Master-Disabled.png");
static const QPixmap pixKeyframeMasterNormal
@@ -257,27 +270,60 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
= QPixmap(":/images/Keyframe-MasterDynamic-Normal.png");
static const QPixmap pixKeyframeMasterDynamicSelected
= QPixmap(":/images/Keyframe-MasterDynamic-Selected.png");
+ static const QPixmap pixKeyframeMasterDisabled2x
+ = QPixmap(":/images/Keyframe-Master-Disabled@2x.png");
+ static const QPixmap pixKeyframeMasterNormal2x
+ = QPixmap(":/images/Keyframe-Master-Normal@2x.png");
+ static const QPixmap pixKeyframeMasterSelected2x
+ = QPixmap(":/images/Keyframe-Master-Selected@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicDisabled2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Disabled@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicNormal2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Normal@2x.png");
+ static const QPixmap pixKeyframeMasterDynamicSelected2x
+ = QPixmap(":/images/Keyframe-MasterDynamic-Selected@2x.png");
for (auto keyframe : qAsConst(m_keyframes)) {
QPixmap pixmap;
if (m_rowTree->locked()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicDisabled;
- else
- pixmap = pixKeyframeMasterDisabled;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicDisabled2x
+ : pixKeyframeMasterDynamicDisabled;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterDisabled2x
+ : pixKeyframeMasterDisabled;
+ }
} else if (keyframe->selected()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicSelected;
- else
- pixmap = pixKeyframeMasterSelected;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicSelected2x
+ : pixKeyframeMasterDynamicSelected;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterSelected2x
+ : pixKeyframeMasterSelected;
+ }
} else {
- if (keyframe->dynamic)
- pixmap = pixKeyframeMasterDynamicNormal;
- else
- pixmap = pixKeyframeMasterNormal;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframeMasterDynamicNormal2x
+ : pixKeyframeMasterDynamicNormal;
+ } else {
+ pixmap = hiResIcons ? pixKeyframeMasterNormal2x
+ : pixKeyframeMasterNormal;
+ }
+ }
+ painter->drawPixmap(QPointF(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - keyFrameOffset,
+ keyFrameY), pixmap);
+
+ // highlight the pressed keyframe in a multi-selection (the keyframe that is affected
+ // by snapping, and setting time dialog)
+ if (m_rowTree->m_scene->keyframeManager()->selectedKeyframes().size() > 1
+ && m_rowTree->m_scene->pressedKeyframe() == keyframe) {
+ painter->setPen(QPen(CStudioPreferences::timelinePressedKeyframeColor(), 1));
+ painter->drawArc(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - 4, keyFrameY + 4, 9, 9, 0,
+ 5760);
}
- painter->drawPixmap(QPointF(timeToX(keyframe->time) - 8.5, keyFrameY), pixmap);
}
- } else if (m_rowTree->isProperty()) {
+ } else if (m_rowTree->isProperty()) { // property row keyframes
static const QPixmap pixKeyframePropertyDisabled
= QPixmap(":/images/Keyframe-Property-Disabled.png");
static const QPixmap pixKeyframePropertyNormal
@@ -290,26 +336,51 @@ void RowTimeline::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio
= QPixmap(":/images/Keyframe-PropertyDynamic-Normal.png");
static const QPixmap pixKeyframePropertyDynamicSelected
= QPixmap(":/images/Keyframe-PropertyDynamic-Selected.png");
+ static const QPixmap pixKeyframePropertyDisabled2x
+ = QPixmap(":/images/Keyframe-Property-Disabled@2x.png");
+ static const QPixmap pixKeyframePropertyNormal2x
+ = QPixmap(":/images/Keyframe-Property-Normal@2x.png");
+ static const QPixmap pixKeyframePropertySelected2x
+ = QPixmap(":/images/Keyframe-Property-Selected@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicDisabled2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Disabled@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicNormal2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Normal@2x.png");
+ static const QPixmap pixKeyframePropertyDynamicSelected2x
+ = QPixmap(":/images/Keyframe-PropertyDynamic-Selected@2x.png");
for (auto keyframe : qAsConst(m_keyframes)) {
QPixmap pixmap;
if (m_rowTree->locked()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicDisabled;
- else
- pixmap = pixKeyframePropertyDisabled;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicDisabled2x
+ : pixKeyframePropertyDynamicDisabled;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertyDisabled2x
+ : pixKeyframePropertyDisabled;
+ }
} else if (keyframe->selected()) {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicSelected;
- else
- pixmap = pixKeyframePropertySelected;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicSelected2x
+ : pixKeyframePropertyDynamicSelected;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertySelected2x
+ : pixKeyframePropertySelected;
+ }
} else {
- if (keyframe->dynamic)
- pixmap = pixKeyframePropertyDynamicNormal;
- else
- pixmap = pixKeyframePropertyNormal;
+ if (keyframe->dynamic) {
+ pixmap = hiResIcons ? pixKeyframePropertyDynamicNormal2x
+ : pixKeyframePropertyDynamicNormal;
+
+ } else {
+ pixmap = hiResIcons ? pixKeyframePropertyNormal2x
+ : pixKeyframePropertyNormal;
+ }
}
- painter->drawPixmap(QPointF(timeToX(keyframe->time) - (keyframe->selected() ? 7.5 : 5.5),
- keyFrameY), pixmap);
+ painter->drawPixmap(QPointF(edgeOffset + m_rowTree->m_scene->ruler()
+ ->timeToDistance(keyframe->time) - keyFrameOffset,
+ keyFrameY), pixmap);
}
}
}
@@ -340,15 +411,14 @@ void RowTimeline::drawColorPropertyGradient(QPainter *painter, int width)
QLinearGradient bgGradient(0, 0, width, 0);
for (auto keyframe : qAsConst(m_keyframes)) {
- double xPos = timeToX(keyframe->time);
+ double xPos = m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
double gradPos = xPos / width;
gradPos = qBound(0.0, gradPos, 1.0);
- long timeMs = keyframe->time * 1000;
QColor currentColor;
// Get the color at the specified time.
- currentColor.setRed(propBinding->GetChannelValueAtTime(0, timeMs));
- currentColor.setGreen(propBinding->GetChannelValueAtTime(1, timeMs));
- currentColor.setBlue(propBinding->GetChannelValueAtTime(2, timeMs));
+ currentColor.setRed(propBinding->GetChannelValueAtTime(0, keyframe->time));
+ currentColor.setGreen(propBinding->GetChannelValueAtTime(1, keyframe->time));
+ currentColor.setBlue(propBinding->GetChannelValueAtTime(2, keyframe->time));
bgGradient.setColorAt(gradPos, currentColor);
}
painter->fillRect(TimelineConstants::RULER_EDGE_OFFSET, 0,
@@ -373,7 +443,8 @@ Keyframe *RowTimeline::getClickedKeyframe(const QPointF &scenePos)
}
for (const auto keyframe : qAsConst(keyframes)) {
- x = timeToX(keyframe->time);
+ x = TimelineConstants::RULER_EDGE_OFFSET
+ + m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
if (p.x() > x - 5 && p.x() < x + 5 && p.y() > 3 && p.y() < 16)
return keyframe;
@@ -391,7 +462,8 @@ QList<Keyframe *> RowTimeline::getKeyframesInRange(const QRectF &rect) const
static const int KF_CENTER_Y = 10;
for (auto keyframe : qAsConst(m_keyframes)) {
- x = timeToX(keyframe->time);
+ x = TimelineConstants::RULER_EDGE_OFFSET
+ + m_rowTree->m_scene->ruler()->timeToDistance(keyframe->time);
if (localRect.left() < x && localRect.right() > x
&& localRect.top() < KF_CENTER_Y && localRect.bottom() > KF_CENTER_Y) {
@@ -409,8 +481,8 @@ void RowTimeline::updateDurationFromBinding()
ITimelineTimebar *timebar = m_rowTree->m_binding->GetTimelineItem()->GetTimebar();
clearBoundChildren();
- setStartTime(timebar->GetStartTime() * .001);
- setEndTime(timebar->GetEndTime() * .001);
+ setStartTime(timebar->GetStartTime());
+ setEndTime(timebar->GetEndTime());
}
void RowTimeline::updateKeyframesFromBinding(const QList<int> &properties)
@@ -430,8 +502,7 @@ void RowTimeline::updateKeyframesFromBinding(const QList<int> &properties)
Qt3DSDMTimelineKeyframe *kf = static_cast<Qt3DSDMTimelineKeyframe *>
(child->m_PropBinding->GetKeyframeByIndex(i));
- Keyframe *kfUI = new Keyframe(static_cast<double>(kf->GetTime() * .001),
- child->rowTimeline());
+ Keyframe *kfUI = new Keyframe(kf->GetTime(), child->rowTimeline());
kfUI->binding = kf;
kfUI->dynamic = kf->IsDynamic();
kf->setUI(kfUI);
@@ -504,10 +575,12 @@ TimelineControlType RowTimeline::getClickedControl(const QPointF &scenePos) cons
if (!m_rowTree->locked()) {
QPointF p = mapFromScene(scenePos.x(), scenePos.y());
+ p.setX(p.x() - TimelineConstants::RULER_EDGE_OFFSET);
+
const int halfHandle = TimelineConstants::DURATION_HANDLE_W * .5;
// Never choose start handle if end time is zero, as you cannot adjust it in that case
bool startHandle = p.x() > m_startX - halfHandle && p.x() < m_startX + halfHandle
- && !qFuzzyIsNull(m_endTime);
+ && m_endTime > 0;
bool endHandle = p.x() > m_endX - halfHandle && p.x() < m_endX + halfHandle;
if (startHandle && endHandle) {
// If handles overlap, choose the handle based on the side of the click relative to start
@@ -566,8 +639,8 @@ void RowTimeline::clearBoundChildren()
// move the duration area (start/end x)
void RowTimeline::moveDurationBy(double dx)
{
- if (m_startX + dx < TimelineConstants::RULER_EDGE_OFFSET)
- dx = TimelineConstants::RULER_EDGE_OFFSET - m_startX;
+ if (m_startX + dx < 0)
+ dx = -m_startX;
m_startX += dx;
m_endX += dx;
@@ -578,8 +651,9 @@ void RowTimeline::moveDurationBy(double dx)
m_maxEndX = m_endX;
}
- m_startTime = xToTime(m_startX);
- m_endTime = xToTime(m_endX);
+ Ruler *ruler = m_rowTree->m_scene->ruler();
+ m_startTime = ruler->distanceToTime(m_startX);
+ m_endTime = ruler->distanceToTime(m_endX);
// move keyframes with the row
if (!m_rowTree->isProperty()) { // make sure we don't move the keyframes twice
@@ -602,8 +676,8 @@ void RowTimeline::moveDurationBy(double dx)
void RowTimeline::moveDurationTo(double newX)
{
- if (newX < TimelineConstants::RULER_EDGE_OFFSET)
- newX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (newX < 0)
+ newX = 0;
double dx = newX - m_startX;
double durationX = m_endX - m_startX;
@@ -617,13 +691,14 @@ void RowTimeline::moveDurationTo(double newX)
m_maxEndX = m_endX;
}
- m_startTime = xToTime(m_startX);
- m_endTime = xToTime(m_endX);
+ Ruler *ruler = m_rowTree->m_scene->ruler();
+ m_startTime = ruler->distanceToTime(m_startX);
+ m_endTime = ruler->distanceToTime(m_endX);
// move keyframes with the row
if (!m_rowTree->isProperty()) { // make sure we don't move the keyframes twice
for (Keyframe *keyframe : qAsConst(m_keyframes))
- keyframe->time += rowTree()->m_scene->ruler()->distanceToTime(dx);
+ keyframe->time += ruler->distanceToTime(dx);
}
update();
@@ -639,7 +714,7 @@ void RowTimeline::moveDurationTo(double newX)
}
}
-double RowTimeline::getDurationMoveTime() const
+long RowTimeline::getDurationMoveTime() const
{
return m_startTime - m_startDurationMoveStartTime;
}
@@ -649,26 +724,12 @@ double RowTimeline::getDurationMoveOffsetX() const
return m_startDurationMoveOffsetX;
}
-double RowTimeline::getDuration() const
+long RowTimeline::getDuration() const
{
return m_endTime - m_startTime;
}
-// convert time (seconds) values to x
-double RowTimeline::timeToX(double time) const
-{
- return TimelineConstants::RULER_EDGE_OFFSET + time * TimelineConstants::RULER_SEC_W
- * rowTree()->m_scene->ruler()->timelineScale();
-}
-
-// convert x values to time (seconds)
-double RowTimeline::xToTime(double xPos) const
-{
- return (xPos - TimelineConstants::RULER_EDGE_OFFSET)
- / (TimelineConstants::RULER_SEC_W * rowTree()->m_scene->ruler()->timelineScale());
-}
-
-void RowTimeline::collectChildKeyframeTimes(QVector<double> &childKeyframeTimes)
+void RowTimeline::collectChildKeyframeTimes(QVector<long> &childKeyframeTimes)
{
const auto childRows = m_rowTree->childRows();
for (const auto row : childRows) {
@@ -690,13 +751,13 @@ void RowTimeline::updatePosition()
// Set the position of the start of the row duration
void RowTimeline::setStartX(double startX)
{
- if (startX < TimelineConstants::RULER_EDGE_OFFSET)
- startX = TimelineConstants::RULER_EDGE_OFFSET;
+ if (startX < 0)
+ startX = 0;
else if (startX > m_endX)
startX = m_endX;
m_startX = startX;
- m_startTime = xToTime(startX);
+ m_startTime = m_rowTree->m_scene->ruler()->distanceToTime(startX);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -715,7 +776,7 @@ void RowTimeline::setEndX(double endX)
endX = m_startX;
m_endX = endX;
- m_endTime = xToTime(endX);
+ m_endTime = m_rowTree->m_scene->ruler()->distanceToTime(endX);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -832,10 +893,10 @@ void RowTimeline::updateCommentItemPos()
-TimelineConstants::ROW_TEXT_OFFSET_Y);
}
-void RowTimeline::setStartTime(double startTime)
+void RowTimeline::setStartTime(long startTime)
{
m_startTime = startTime;
- m_startX = timeToX(startTime);
+ m_startX = m_rowTree->m_scene->ruler()->timeToDistance(startTime);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -847,10 +908,10 @@ void RowTimeline::setStartTime(double startTime)
update();
}
-void RowTimeline::setEndTime(double endTime)
+void RowTimeline::setEndTime(long endTime)
{
m_endTime = endTime;
- m_endX = timeToX(endTime);
+ m_endX = m_rowTree->m_scene->ruler()->timeToDistance(endTime);
if (!m_rowTree->parentRow() || m_rowTree->parentRow()->rowType() == OBJTYPE_SCENE
|| m_rowTree->hasComponentAncestor()) {
@@ -862,22 +923,24 @@ void RowTimeline::setEndTime(double endTime)
update();
}
+// duration start x in local space (x=0 at time=0)
double RowTimeline::getStartX() const
{
return m_startX;
}
+// duration end x in local space
double RowTimeline::getEndX() const
{
return m_endX;
}
-double RowTimeline::getStartTime() const
+long RowTimeline::getStartTime() const
{
return m_startTime;
}
-double RowTimeline::getEndTime() const
+long RowTimeline::getEndTime() const
{
return m_endTime;
}
@@ -912,16 +975,16 @@ QList<Keyframe *> RowTimeline::keyframes() const
return m_keyframes;
}
-QString RowTimeline::formatTime(double seconds) const
+QString RowTimeline::formatTime(long millis) const
{
static const QString timeTemplate = tr("%1:%2.%3");
static const QChar fillChar = tr("0").at(0);
- long mins = seconds / 60;
- long secs = seconds - mins * 60;
- long millis = qRound((seconds - (int)seconds) * 1000);
+ long mins = millis % 3600000 / 60000;
+ long secs = millis % 60000 / 1000;
+ long mils = millis % 1000;
- return timeTemplate.arg(mins).arg(secs, 2, 10, fillChar).arg(millis, 3, 10, fillChar);
+ return timeTemplate.arg(mins).arg(secs, 2, 10, fillChar).arg(mils, 3, 10, fillChar);
}
void RowTimeline::showToolTip(const QPointF &pos)
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
index 32dab1bc..00c81696 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimeline.h
@@ -57,8 +57,8 @@ public:
void clearBoundChildren();
void moveDurationBy(double dx);
void moveDurationTo(double newX);
- void setStartTime(double startTime);
- void setEndTime(double endTime);
+ void setStartTime(long startTime);
+ void setEndTime(long endTime);
void setStartX(double startX);
void setEndX(double endX);
void setBarColor(const QColor &color);
@@ -72,13 +72,13 @@ public:
TimelineControlType getClickedControl(const QPointF &scenePos) const;
double getStartX() const;
double getEndX() const;
- double getStartTime() const;
- double getEndTime() const;
- double getDurationMoveTime() const; // the time a row duration has moved (to commit to binding)
+ long getStartTime() const;
+ long getEndTime() const;
+ long getDurationMoveTime() const; // the time a row duration has moved (to commit to binding)
double getDurationMoveOffsetX() const;
- double getDuration() const;
+ long getDuration() const;
QColor barColor() const;
- int type() const;
+ int type() const override;
RowTimeline *parentRow() const;
RowTree *rowTree() const;
Keyframe *getClickedKeyframe(const QPointF &scenePos);
@@ -99,18 +99,16 @@ private:
void updateCommentItemPos();
void drawColorPropertyGradient(QPainter *painter, int width);
bool isColorProperty() const;
- QString formatTime(double seconds) const;
- double timeToX(double time) const;
- double xToTime(double xPos) const;
- void collectChildKeyframeTimes(QVector<double> &childKeyframeTimes);
+ QString formatTime(long millis) const;
+ void collectChildKeyframeTimes(QVector<long> &childKeyframeTimes);
RowTree *m_rowTree;
RowTimelinePropertyGraph *m_propertyGraph = nullptr;
RowTimelineCommentItem *m_commentItem = nullptr;
- double m_startTime = 0;
- double m_startDurationMoveStartTime = 0;
+ long m_startTime = 0;
+ long m_startDurationMoveStartTime = 0;
double m_startDurationMoveOffsetX = 0;
- double m_endTime = 0;
+ long m_endTime = 0;
double m_startX = 0;
double m_endX = 0;
double m_minStartX = 0;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
index ecd31b9a..7861bb19 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelineContextMenu.cpp
@@ -232,7 +232,7 @@ void RowTimelineContextMenu::setInterpolation()
void RowTimelineContextMenu::setKeyframeTime()
{
- m_keyframeManager->SetKeyframeTime(m_keyframe->time * 1000.0);
+ m_keyframeManager->SetKeyframeTime(m_keyframe->time);
}
void RowTimelineContextMenu::changeTimeBarColor()
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
index a65e235d..3c82d73b 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
@@ -85,7 +85,7 @@ void RowTimelinePropertyGraph::paintSingleChannel(QPainter *painter, long inChan
QPainterPath path;
for (int i = 0; i < m_rect.width(); i += interval) {
// Value time in ms
- long time = 1000 * (i / (TimelineConstants::RULER_SEC_W * timelineScale));
+ long time = i / (TimelineConstants::RULER_MILLI_W * timelineScale);
float value = m_propBinding->GetChannelValueAtTime(inChannelIndex, time);
float yPos = graphY + (1.0 - (value - minVal) / (maxVal - minVal)) * graphHeight;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
index 0056d90e..db313ca9 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
@@ -38,6 +38,12 @@
#include "TreeHeader.h"
#include "StudioPreferences.h"
#include "KeyframeManager.h"
+#include "StudioApp.h"
+#include "Core.h"
+#include "Doc.h"
+#include "Qt3DSDMStudioSystem.h"
+#include "Qt3DSDMSlides.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
#include "QtGui/qtextcursor.h"
@@ -53,6 +59,9 @@ RowTree::RowTree(TimelineGraphicsScene *timelineScene, EStudioObjectType rowType
m_scene = timelineScene;
m_rowType = rowType;
m_label = label;
+ CDoc *doc = g_StudioApp.GetCore()->GetDoc();
+ m_onMasterSlide = doc->GetStudioSystem()->GetSlideSystem()->IsMasterSlide(
+ doc->GetActiveSlide());
initialize();
}
@@ -173,6 +182,8 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
if (!y()) // prevents flickering when the row is just inserted to the layout
return;
@@ -220,24 +231,45 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
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 pixHideDisabled = QPixmap(":/images/Toggle-HideShow-disabled.png");
static const QPixmap pixHideCtrld = QPixmap(":/images/Toggle-HideShowControlled.png");
static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png");
+ static const QPixmap pixEmpty2x = QPixmap(":/images/Toggle-Empty@2x.png");
+ static const QPixmap pixShy2x = QPixmap(":/images/Toggle-Shy@2x.png");
+ static const QPixmap pixHide2x = QPixmap(":/images/Toggle-HideShow@2x.png");
+ static const QPixmap pixHideDisabled2x = QPixmap(":/images/Toggle-HideShow-disabled@2x.png");
+ static const QPixmap pixHideCtrld2x = QPixmap(":/images/Toggle-HideShowControlled@2x.png");
+ static const QPixmap pixLock2x = QPixmap(":/images/Toggle-Lock@2x.png");
if (hasActionButtons()) {
- painter->drawPixmap(m_rectShy , m_shy ? pixShy : pixEmpty);
+ painter->drawPixmap(m_rectShy, hiResIcons ? (m_shy ? pixShy2x : pixEmpty2x)
+ : (m_shy ? pixShy : pixEmpty));
// Eyeball visibility follows the visibility setting for the object even if it has
// datainput controller
- if (m_visibilityCtrld)
- painter->drawPixmap(m_rectVisible, m_visible ? pixHideCtrld : pixEmpty);
- else
- painter->drawPixmap(m_rectVisible, m_visible ? pixHide : pixEmpty);
- painter->drawPixmap(m_rectLocked , m_locked ? pixLock : pixEmpty);
+ // Disable eyeball from master slide
+ if (m_onMasterSlide) {
+ painter->drawPixmap(m_rectVisible, hiResIcons ? pixHideDisabled2x
+ : pixHideDisabled);
+ } else if (m_visibilityCtrld) {
+ painter->drawPixmap(m_rectVisible, hiResIcons
+ ? (m_visible ? pixHideCtrld2x : pixEmpty2x)
+ : (m_visible ? pixHideCtrld : pixEmpty));
+ } else {
+ painter->drawPixmap(m_rectVisible, hiResIcons
+ ? (m_visible ? pixHide2x : pixEmpty2x)
+ : (m_visible ? pixHide : pixEmpty));
+ }
+ painter->drawPixmap(m_rectLocked, hiResIcons ? (m_locked ? pixLock2x : pixEmpty2x)
+ : (m_locked ? pixLock : pixEmpty));
}
static const QPixmap pixInsertLeft = QPixmap(":/images/Insert-Left.png");
static const QPixmap pixInsertRight = QPixmap(":/images/Insert-Right.png");
+ static const QPixmap pixInsertLeft2x = QPixmap(":/images/Insert-Left@2x.png");
+ static const QPixmap pixInsertRight2x = QPixmap(":/images/Insert-Right@2x.png");
if (m_dndState == DnDState::SP_TARGET) { // Candidate target of a subpresentation drop
- painter->drawPixmap(19, 2, pixInsertLeft);
- painter->drawPixmap(treeWidth() - TimelineConstants::TREE_ICONS_W - 8, 2, pixInsertRight);
+ painter->drawPixmap(19, 2, hiResIcons ? pixInsertLeft2x : pixInsertLeft);
+ painter->drawPixmap(treeWidth() - TimelineConstants::TREE_ICONS_W - 8, 2, hiResIcons
+ ? pixInsertRight2x : pixInsertRight);
} else if (m_dndState == DnDState::Parent) { // Candidate parent of a dragged row
painter->setPen(QPen(CStudioPreferences::timelineRowMoverColor(), 1));
painter->drawRect(QRect(1, 1, treeWidth() - 2, size().height() - 3));
@@ -250,6 +282,14 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
static const QPixmap pixChildAction = QPixmap(":/images/Action-ChildAction.png");
static const QPixmap pixCompMasterAction = QPixmap(":/images/Action-ComponentMasterAction.png");
static const QPixmap pixCompAction = QPixmap(":/images/Action-ComponentAction.png");
+ static const QPixmap pixMasterAction2x = QPixmap(":/images/Action-MasterAction@2x.png");
+ static const QPixmap pixAction2x = QPixmap(":/images/Action-Action@2x.png");
+ static const QPixmap pixChildMasterAction2x
+ = QPixmap(":/images/Action-ChildMasterAction@2x.png");
+ static const QPixmap pixChildAction2x = QPixmap(":/images/Action-ChildAction@2x.png");
+ static const QPixmap pixCompMasterAction2x
+ = QPixmap(":/images/Action-ComponentMasterAction@2x.png");
+ static const QPixmap pixCompAction2x = QPixmap(":/images/Action-ComponentAction@2x.png");
if (!isProperty()) {
// subpresentation indicators
@@ -262,116 +302,185 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
}
if (m_actionStates & ActionState::MasterAction) // has master action
- painter->drawPixmap(0, 0, pixMasterAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixMasterAction2x : pixMasterAction);
else if (m_actionStates & ActionState::Action) // has action
- painter->drawPixmap(0, 0, pixAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixAction2x : pixAction);
if (!expanded()) {
- if (m_actionStates & ActionState::MasterChildAction) // children have master action
- painter->drawPixmap(0, 0, pixChildMasterAction);
- else if (m_actionStates & ActionState::ChildAction) // children have action
- painter->drawPixmap(0, 0, pixChildAction);
+ if (m_actionStates & ActionState::MasterChildAction) {
+ // children have master action
+ painter->drawPixmap(0, 0, hiResIcons ? pixChildMasterAction2x
+ : pixChildMasterAction);
+ } else if (m_actionStates & ActionState::ChildAction) {
+ // children have action
+ painter->drawPixmap(0, 0, hiResIcons ? pixChildAction2x : pixChildAction);
+ }
}
if (m_actionStates & ActionState::MasterComponentAction) // component has master action
- painter->drawPixmap(0, 0, pixCompMasterAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixCompMasterAction2x : pixCompMasterAction);
else if (m_actionStates & ActionState::ComponentAction) // component has action
- painter->drawPixmap(0, 0, pixCompAction);
+ painter->drawPixmap(0, 0, hiResIcons ? pixCompAction2x : pixCompAction);
+ }
+
+ // variants indicator
+ if (m_variantsGroups.size() > 0) {
+ const auto variantsDef = g_StudioApp.GetCore()->getProjectFile().variantsDef();
+ for (int i = 0; i < m_variantsGroups.size(); ++i) {
+ painter->fillRect(QRect(clipX() + 2 + i * 9, 6, 6, 6),
+ variantsDef[m_variantsGroups[i]].m_color);
+ }
}
// The following items need to be clipped so that they do not draw overlapping shy etc. buttons
- painter->setClipRect(0, 0, treeWidth() - TimelineConstants::TREE_ICONS_W,
- TimelineConstants::ROW_H);
+ painter->setClipRect(0, 0, clipX(), TimelineConstants::ROW_H);
// expand/collapse arrow
static const QPixmap pixArrow = QPixmap(":/images/arrow.png");
static const QPixmap pixArrowDown = QPixmap(":/images/arrow_down.png");
- if (m_arrowVisible)
- painter->drawPixmap(m_rectArrow, expanded() ? pixArrowDown : pixArrow);
+ static const QPixmap pixArrow2x = QPixmap(":/images/arrow@2x.png");
+ static const QPixmap pixArrowDown2x = QPixmap(":/images/arrow_down@2x.png");
+ if (m_arrowVisible) {
+ painter->drawPixmap(m_rectArrow, hiResIcons ? (expanded() ? pixArrowDown2x : pixArrow2x)
+ : (expanded() ? pixArrowDown : pixArrow));
+ }
// Row type icon
- 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 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 pixImageNormal = QPixmap(":/images/Objects-Image-Normal.png");
- static const QPixmap pixBehaviorNormal = QPixmap(":/images/Objects-Behavior-Normal.png");
- static const QPixmap pixEffectNormal = QPixmap(":/images/Objects-Effect-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 pixMaterialNormal = QPixmap(":/images/Objects-Material-Normal.png");
+ static const QPixmap pixPropertyNormal = QPixmap(":/images/Objects-Property-Normal.png");
+ static const QPixmap pixImageNormal = QPixmap(":/images/Objects-Image-Normal.png");
+ static const QPixmap pixBehaviorNormal = QPixmap(":/images/Objects-Behavior-Normal.png");
+ static const QPixmap pixEffectNormal= QPixmap(":/images/Objects-Effect-Normal.png");
+ static const QPixmap pixSceneNormal2x = QPixmap(":/images/Objects-Scene-Normal@2x.png");
+ static const QPixmap pixLayerNormal2x = QPixmap(":/images/Objects-Layer-Normal@2x.png");
+ static const QPixmap pixObjectNormal2x = QPixmap(":/images/Objects-Model-Normal@2x.png");
+ static const QPixmap pixLightNormal2x = QPixmap(":/images/Objects-Light-Normal@2x.png");
+ static const QPixmap pixCameraNormal2x = QPixmap(":/images/Objects-Camera-Normal@2x.png");
+ static const QPixmap pixTextNormal2x = QPixmap(":/images/Objects-Text-Normal@2x.png");
+ static const QPixmap pixAliasNormal2x = QPixmap(":/images/Objects-Alias-Normal@2x.png");
+ static const QPixmap pixGroupNormal2x = QPixmap(":/images/Objects-Group-Normal@2x.png");
+ static const QPixmap pixComponentNormal2x = QPixmap(":/images/Objects-Component-Normal@2x.png");
+ static const QPixmap pixMaterialNormal2x = QPixmap(":/images/Objects-Material-Normal@2x.png");
+ static const QPixmap pixPropertyNormal2x = QPixmap(":/images/Objects-Property-Normal@2x.png");
+ static const QPixmap pixImageNormal2x = QPixmap(":/images/Objects-Image-Normal@2x.png");
+ static const QPixmap pixBehaviorNormal2x = QPixmap(":/images/Objects-Behavior-Normal@2x.png");
+ static const QPixmap pixEffectNormal2x = QPixmap(":/images/Objects-Effect-Normal@2x.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");
- static const QPixmap pixImageDisabled = QPixmap(":/images/Objects-Image-Disabled.png");
- static const QPixmap pixBehaviorDisabled = QPixmap(":/images/Objects-Behavior-Disabled.png");
- static const QPixmap pixEffectDisabled = QPixmap(":/images/Objects-Effect-Disabled.png");
+ static const QPixmap pixMaterialDisabled = QPixmap(":/images/Objects-Material-Disabled.png");
+ static const QPixmap pixPropertyDisabled = QPixmap(":/images/Objects-Property-Disabled.png");
+ static const QPixmap pixImageDisabled = QPixmap(":/images/Objects-Image-Disabled.png");
+ static const QPixmap pixBehaviorDisabled = QPixmap(":/images/Objects-Behavior-Disabled.png");
+ static const QPixmap pixEffectDisabled = QPixmap(":/images/Objects-Effect-Disabled.png");
+ static const QPixmap pixSceneDisabled2x = QPixmap(":/images/Objects-Scene-Disabled@2x.png");
+ static const QPixmap pixLayerDisabled2x = QPixmap(":/images/Objects-Layer-Disabled@2x.png");
+ static const QPixmap pixObjectDisabled2x = QPixmap(":/images/Objects-Model-Disabled@2x.png");
+ static const QPixmap pixLightDisabled2x = QPixmap(":/images/Objects-Light-Disabled@2x.png");
+ static const QPixmap pixCameraDisabled2x = QPixmap(":/images/Objects-Camera-Disabled@2x.png");
+ static const QPixmap pixTextDisabled2x = QPixmap(":/images/Objects-Text-Disabled@2x.png");
+ static const QPixmap pixAliasDisabled2x = QPixmap(":/images/Objects-Alias-Disabled@2x.png");
+ static const QPixmap pixGroupDisabled2x = QPixmap(":/images/Objects-Group-Disabled@2x.png");
+ static const QPixmap pixComponentDisabled2x
+ = QPixmap(":/images/Objects-Component-Disabled@2x.png");
+ static const QPixmap pixMaterialDisabled2x
+ = QPixmap(":/images/Objects-Material-Disabled@2x.png");
+ static const QPixmap pixPropertyDisabled2x
+ = QPixmap(":/images/Objects-Property-Disabled@2x.png");
+ static const QPixmap pixImageDisabled2x = QPixmap(":/images/Objects-Image-Disabled@2x.png");
+ static const QPixmap pixBehaviorDisabled2x
+ = QPixmap(":/images/Objects-Behavior-Disabled@2x.png");
+ static const QPixmap pixEffectDisabled2x = QPixmap(":/images/Objects-Effect-Disabled@2x.png");
QPixmap pixRowType;
- switch (m_rowType) {
- case OBJTYPE_SCENE:
- pixRowType = m_locked ? pixSceneDisabled : pixSceneNormal;
- break;
- case OBJTYPE_LAYER:
- pixRowType = m_locked ? pixLayerDisabled : pixLayerNormal;
- break;
- case OBJTYPE_MODEL:
- pixRowType = m_locked ? pixObjectDisabled : pixObjectNormal;
- break;
- case OBJTYPE_LIGHT:
- pixRowType = m_locked ? pixLightDisabled : pixLightNormal;
- break;
- case OBJTYPE_CAMERA:
- pixRowType = m_locked ? pixCameraDisabled : pixCameraNormal;
- break;
- case OBJTYPE_TEXT:
- pixRowType = m_locked ? pixTextDisabled : pixTextNormal;
- break;
- case OBJTYPE_ALIAS:
- pixRowType = m_locked ? pixAliasDisabled : pixAliasNormal;
- break;
- case OBJTYPE_GROUP:
- pixRowType = m_locked ? pixGroupDisabled : pixGroupNormal;
- break;
- case OBJTYPE_COMPONENT:
- pixRowType = m_locked ? pixComponentDisabled : pixComponentNormal;
- break;
- case OBJTYPE_MATERIAL:
- pixRowType = m_locked ? pixMaterialDisabled : pixMaterialNormal;
- break;
- case OBJTYPE_IMAGE:
- pixRowType = m_locked ? pixImageDisabled : pixImageNormal;
- break;
- case OBJTYPE_BEHAVIOR:
- pixRowType = m_locked ? pixBehaviorDisabled : pixBehaviorNormal;
- break;
- case OBJTYPE_EFFECT:
- pixRowType = m_locked ? pixEffectDisabled : pixEffectNormal;
- break;
- default:
- break;
+ if (m_isProperty) {
+ pixRowType = hiResIcons ? (m_locked ? pixPropertyDisabled2x : pixPropertyNormal2x)
+ : (m_locked ? pixPropertyDisabled : pixPropertyNormal);
+ } else {
+ switch (m_rowType) {
+ case OBJTYPE_SCENE:
+ pixRowType = hiResIcons ? (m_locked ? pixSceneDisabled2x : pixSceneNormal2x)
+ : (m_locked ? pixSceneDisabled : pixSceneNormal);
+ break;
+ case OBJTYPE_LAYER:
+ pixRowType = hiResIcons ? (m_locked ? pixLayerDisabled2x : pixLayerNormal2x)
+ : (m_locked ? pixLayerDisabled : pixLayerNormal);
+ break;
+ case OBJTYPE_MODEL:
+ pixRowType = hiResIcons ? (m_locked ? pixObjectDisabled2x : pixObjectNormal2x)
+ : (m_locked ? pixObjectDisabled : pixObjectNormal);
+ break;
+ case OBJTYPE_LIGHT:
+ pixRowType = hiResIcons ? (m_locked ? pixLightDisabled2x : pixLightNormal2x)
+ : (m_locked ? pixLightDisabled : pixLightNormal);
+ break;
+ case OBJTYPE_CAMERA:
+ pixRowType = hiResIcons ? (m_locked ? pixCameraDisabled2x : pixCameraNormal2x)
+ : (m_locked ? pixCameraDisabled : pixCameraNormal);
+ break;
+ case OBJTYPE_TEXT:
+ pixRowType = hiResIcons ? (m_locked ? pixTextDisabled2x : pixTextNormal2x)
+ : (m_locked ? pixTextDisabled : pixTextNormal);
+ break;
+ case OBJTYPE_ALIAS:
+ pixRowType = hiResIcons ? (m_locked ? pixAliasDisabled2x : pixAliasNormal2x)
+ : (m_locked ? pixAliasDisabled : pixAliasNormal);
+ break;
+ case OBJTYPE_GROUP:
+ pixRowType = hiResIcons ? (m_locked ? pixGroupDisabled2x : pixGroupNormal2x)
+ : (m_locked ? pixGroupDisabled : pixGroupNormal);
+ break;
+ case OBJTYPE_COMPONENT:
+ pixRowType = hiResIcons ? (m_locked ? pixComponentDisabled2x : pixComponentNormal2x)
+ : (m_locked ? pixComponentDisabled : pixComponentNormal);
+ break;
+ case OBJTYPE_MATERIAL:
+ pixRowType = hiResIcons ? (m_locked ? pixMaterialDisabled2x : pixMaterialNormal2x)
+ : (m_locked ? pixMaterialDisabled : pixMaterialNormal);
+ break;
+ case OBJTYPE_IMAGE:
+ pixRowType = hiResIcons ? (m_locked ? pixImageDisabled2x : pixImageNormal2x)
+ : (m_locked ? pixImageDisabled : pixImageNormal);
+ break;
+ case OBJTYPE_BEHAVIOR:
+ pixRowType = hiResIcons ? (m_locked ? pixBehaviorDisabled2x : pixBehaviorNormal2x)
+ : (m_locked ? pixBehaviorDisabled : pixBehaviorNormal);
+ break;
+ case OBJTYPE_EFFECT:
+ pixRowType = hiResIcons ? (m_locked ? pixEffectDisabled2x : pixEffectNormal2x)
+ : (m_locked ? pixEffectDisabled : pixEffectNormal);
+ break;
+ default:
+ break;
+ }
}
- if (m_isProperty)
- pixRowType = m_locked ? pixPropertyDisabled : pixPropertyNormal;
-
painter->drawPixmap(m_rectType, pixRowType);
}
+void RowTree::updateVariants(const QStringList &groups)
+{
+ m_variantsGroups = groups;
+ update();
+}
+
int RowTree::treeWidth() const
{
return m_scene->treeWidth() - m_scene->getScrollbarOffsets().x();
@@ -415,6 +524,12 @@ void RowTree::setBinding(ITimelineItemBinding *binding)
updateFromBinding();
}
+// x value where label should clip
+int RowTree::clipX() const
+{
+ return treeWidth() - TimelineConstants::TREE_ICONS_W - m_variantsGroups.size() * 9 - 2;
+}
+
ITimelineItemProperty *RowTree::propBinding()
{
return m_PropBinding;
@@ -793,7 +908,8 @@ TreeControlType RowTree::getClickedControl(const QPointF &scenePos)
if (m_rectShy.contains(p.x(), p.y())) {
toggleShy();
return TreeControlType::Shy;
- } else if (m_rectVisible.contains(p.x(), p.y())) {
+ } else if (!m_onMasterSlide && m_rectVisible.contains(p.x(), p.y())) {
+ // Prevent toggling hide on master slide
toggleVisible();
return TreeControlType::Hide;
} else if (m_rectLocked.contains(p.x(), p.y())) {
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
index bde2da48..4524f345 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTree.h
@@ -140,6 +140,7 @@ public:
void updateLabel();
void setRowVisible(bool visible);
void setDnDHover(bool val);
+ void updateVariants(const QStringList &groups);
DnDState getDnDState() const;
ITimelineItemBinding *getBinding() const;
@@ -148,6 +149,8 @@ public:
void updateFilter();
void updateLock(bool state);
void updateSubpresentations(int updateParentsOnlyVal = 0);
+ int clipX() const;
+
protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
@@ -181,6 +184,7 @@ private:
bool m_arrowVisible = false;
bool m_dndHover = false;
bool m_visibilityCtrld = false;
+ bool m_onMasterSlide = false;
DnDState m_dndState = DnDState::None;
ActionStates m_actionStates = ActionState::None;
bool m_hasSubpresentation = false;
@@ -193,6 +197,7 @@ private:
QString m_label;
QList<RowTree *> m_childRows;
QList<RowTree *> m_childProps;
+ QStringList m_variantsGroups;
ITimelineItemBinding *m_binding = nullptr;
ITimelineItemProperty *m_PropBinding = nullptr; // for property rows
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
index cfd0ddd8..1029c00a 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/RowTreeLabelItem.cpp
@@ -146,7 +146,7 @@ QRectF RowTreeLabelItem::boundingRect() const
if (!m_rowTree)
return QGraphicsTextItem::boundingRect();
- double w = m_rowTree->treeWidth() - x() - TimelineConstants::TREE_ICONS_W;
+ double w = m_rowTree->clipX() - x();
// Bounding rect width must be at least 1
w = std::max(w, 1.0);
return QRectF(0, 0, w, TimelineConstants::ROW_H);
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
index 86a250f4..62c6de01 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.cpp
@@ -32,7 +32,6 @@
#include <QtGui/qpainter.h>
#include <QtWidgets/qwidget.h>
-#include <QtCore/qdebug.h>
Ruler::Ruler(TimelineItem *parent) : TimelineItem(parent)
{
@@ -45,9 +44,9 @@ void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
double xStep = TimelineConstants::RULER_SEC_W / TimelineConstants::RULER_SEC_DIV * m_timeScale;
double activeSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_duration * xStep * TimelineConstants::RULER_SEC_DIV;
+ + m_duration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
double totalSegmentsWidth = TimelineConstants::RULER_EDGE_OFFSET
- + m_maxDuration * xStep * TimelineConstants::RULER_SEC_DIV;
+ + m_maxDuration / 1000.0 * xStep * TimelineConstants::RULER_SEC_DIV;
// Ruler painted width to be at least widget width
double minRulerWidth = widget->width();
@@ -80,9 +79,9 @@ void Ruler::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi
if (rowX < (m_viewportX - margin) || rowX > (m_viewportX + minRulerWidth + margin))
continue;
- const int h = i % secDiv == 0 ? TimelineConstants::RULER_DIV_H1 :
- i % secDiv == secDiv * 0.5 ? TimelineConstants::RULER_DIV_H2 :
- TimelineConstants::RULER_DIV_H3;
+ const int h = i % secDiv == 0 ? TimelineConstants::RULER_DIV_H1
+ : i % secDiv == secDiv * 0.5 ? TimelineConstants::RULER_DIV_H2
+ : TimelineConstants::RULER_DIV_H3;
if (!useDisabledColor && rowX > activeSegmentsWidth) {
painter->setPen(CStudioPreferences::timelineRulerColorDisabled());
@@ -122,28 +121,16 @@ void Ruler::setTimelineScale(double scl)
update();
}
-// convert distance values to time (seconds)
-double Ruler::distanceToTime(double distance) const
+// convert distance values to time (milliseconds)
+long Ruler::distanceToTime(double distance) const
{
- return distance / (TimelineConstants::RULER_SEC_W * m_timeScale);
+ return distance / (TimelineConstants::RULER_MILLI_W * m_timeScale);
}
-// convert time (seconds) values to distance
-double Ruler::timeToDistance(double time) const
+// convert time (milliseconds) values to distance
+double Ruler::timeToDistance(long time) const
{
- return time * TimelineConstants::RULER_SEC_W * m_timeScale;
-}
-
-// x position of ruler value 0
-double Ruler::durationStartX() const
-{
- return x() + TimelineConstants::RULER_EDGE_OFFSET;
-}
-
-// x position of ruler max value (duration)
-double Ruler::durationEndX() const
-{
- return durationStartX() + timeToDistance(m_duration);
+ return time * TimelineConstants::RULER_MILLI_W * m_timeScale;
}
double Ruler::timelineScale() const
@@ -154,7 +141,7 @@ double Ruler::timelineScale() const
// Returns end of right-most layer/component row.
// Active color of ruler is used up to this point.
// Slide plays up to this point.
-double Ruler::duration() const
+long Ruler::duration() const
{
return m_duration;
}
@@ -162,12 +149,12 @@ double Ruler::duration() const
// Returns end of right-most row.
// Ruler steps & labels are drawn up to this point.
// Timeline scrollbar allows scrolling up to this point.
-double Ruler::maxDuration() const
+long Ruler::maxDuration() const
{
return m_maxDuration;
}
-void Ruler::setDuration(double duration)
+void Ruler::setDuration(long duration)
{
if (m_duration != duration) {
m_duration = duration;
@@ -176,7 +163,7 @@ void Ruler::setDuration(double duration)
}
}
-void Ruler::setMaxDuration(double maxDuration)
+void Ruler::setMaxDuration(long maxDuration)
{
if (m_maxDuration != maxDuration) {
m_maxDuration = maxDuration;
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
index a234b72b..005a23c3 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/Ruler.h
@@ -42,33 +42,31 @@ public:
explicit Ruler(TimelineItem *parent = nullptr);
void setTimelineScale(double scl);
- double distanceToTime(double distance) const;
- double timeToDistance(double time) const;
- double durationStartX() const;
- double durationEndX() const;
+ long distanceToTime(double distance) const;
+ double timeToDistance(long time) const;
double timelineScale() const;
- double duration() const;
- double maxDuration() const;
- void setDuration(double duration);
- void setMaxDuration(double maxDuration);
+ long duration() const;
+ long maxDuration() const;
+ void setDuration(long duration);
+ void setMaxDuration(long maxDuration);
void setViewportX(int viewportX);
int viewportX() const;
- int type() const;
+ int type() const override;
protected:
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget = nullptr) override;
signals:
- void maxDurationChanged(double maxDuration);
- void durationChanged(double duration);
+ void maxDurationChanged(long maxDuration);
+ void durationChanged(long duration);
void viewportXChanged(int viewportX);
private:
const QString timestampString(int timeMs);
double m_timeScale = 2;
- double m_duration = 0; // in seconds
- double m_maxDuration = 0; // in seconds
+ long m_duration = 0; // milliseconds
+ long m_maxDuration = 0; // milliseconds
int m_viewportX = 0;
};
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
index 76af75ef..71d26c0d 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TimelineItem.h
@@ -51,7 +51,7 @@ public:
TypeRowMover
};
- int type() const;
+ int type() const override;
};
#endif // TIMELINEITEM_H
diff --git a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
index 295a5273..f3232b9d 100644
--- a/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
+++ b/src/Authoring/Studio/Palettes/TimelineGraphicsView/ui/TreeHeader.cpp
@@ -28,6 +28,7 @@
#include "TreeHeader.h"
#include "StudioPreferences.h"
+#include "StudioUtils.h"
#include <QtGui/qpainter.h>
@@ -45,14 +46,19 @@ void TreeHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
Q_UNUSED(option)
Q_UNUSED(widget)
+ bool hiResIcons = StudioUtils::devicePixelRatio(widget->window()->windowHandle()) > 1.0;
+
double treeWidth = m_scene->treeWidth() - m_scene->getScrollbarOffsets().x();
m_rectShy .setRect(treeWidth - 16 * 3.3, size().height() * .5 - 8, 16, 16);
m_rectVisible.setRect(treeWidth - 16 * 2.2, size().height() * .5 - 8, 16, 16);
m_rectLock .setRect(treeWidth - 16 * 1.1, size().height() * .5 - 8, 16, 16);
- static const QPixmap pixShy = QPixmap(":/images/Toggle-Shy.png");
+ 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");
+ static const QPixmap pixLock = QPixmap(":/images/Toggle-Lock.png");
+ static const QPixmap pixShy2x = QPixmap(":/images/Toggle-Shy@2x.png");
+ static const QPixmap pixVisible2x = QPixmap(":/images/Toggle-HideShow@2x.png");
+ static const QPixmap pixLock2x = QPixmap(":/images/Toggle-Lock@2x.png");
const QColor selectedColor = CStudioPreferences::timelineFilterButtonSelectedColor();
const QColor hoveredColor = CStudioPreferences::timelineFilterButtonHoveredColor();
@@ -74,9 +80,9 @@ void TreeHeader::paint(QPainter *painter, const QStyleOptionGraphicsItem *option
else if (m_hoveredItem == 2)
painter->fillRect(m_rectLock, hoveredColor);
- painter->drawPixmap(m_rectShy , pixShy);
- painter->drawPixmap(m_rectVisible, pixVisible);
- painter->drawPixmap(m_rectLock , pixLock);
+ painter->drawPixmap(m_rectShy , hiResIcons ? pixShy2x : pixShy);
+ painter->drawPixmap(m_rectVisible, hiResIcons ? pixVisible2x : pixVisible);
+ painter->drawPixmap(m_rectLock , hiResIcons ? pixLock2x : pixLock);
}
TreeControlType TreeHeader::handleButtonsClick(const QPointF &scenePos)
diff --git a/src/Authoring/Studio/Qt3DStudio.pro b/src/Authoring/Studio/Qt3DStudio.pro
index 28704bd3..16f850c4 100644
--- a/src/Authoring/Studio/Qt3DStudio.pro
+++ b/src/Authoring/Studio/Qt3DStudio.pro
@@ -201,7 +201,6 @@ HEADERS += \
Palettes/Timeline/Bindings/ITimelineItem.h \
Palettes/Timeline/Bindings/ITimelineItemBinding.h \
Palettes/Timeline/Bindings/ITimelineItemProperty.h \
- Palettes/Timeline/Bindings/ITimelineKeyframesManager.h \
Palettes/Timeline/Bindings/ITimelineTimebar.h \
Palettes/Timeline/Bindings/IBreadCrumbProvider.h \
Palettes/TimelineGraphicsView/Keyframe.h \
@@ -261,15 +260,18 @@ HEADERS += \
UI/Q3DSPlayerWidget.h \
Render/StudioEnums.h \
Render/Q3DSTranslators.h \
- Palettes/Inspector/MaterialRefView.h \
+ Render/Q3DSSelectionWidget.h \
+ Render/Q3DSVisualAidWidget.h \
+ Render/Q3DSWidgetUtils.h \
+ Render/Q3DSManipulationWidget.h \
Palettes/scenecamera/scenecameraview.h \
Palettes/scenecamera/scenecamerascrollarea.h \
Palettes/scenecamera/scenecameraglwidget.h \
+ Palettes/Inspector/MaterialRefView.h \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.h \
- Render/Q3DSSelectionWidget.h \
- Render/Q3DSVisualAidWidget.h \
- Render/Q3DSWidgetUtils.h \
- Render/Q3DSManipulationWidget.h
+ Palettes/Inspector/VariantsGroupModel.h \
+ Palettes/Inspector/VariantsTagModel.h \
+ Palettes/Inspector/VariantTagDialog.h
FORMS += \
MainFrm.ui \
@@ -289,7 +291,8 @@ FORMS += \
UI/StartupDlg.ui \
Palettes/Project/EditPresentationIdDlg.ui \
Palettes/Project/ChooseImagePropertyDlg.ui \
- Palettes/scenecamera/scenecameraview.ui
+ Palettes/scenecamera/scenecameraview.ui \
+ Palettes/Inspector/VariantTagDialog.ui
SOURCES += \
Application/AboutDlg.cpp \
@@ -434,15 +437,18 @@ SOURCES += \
UI/Q3DSPlayerWidget.cpp \
Render/Q3DSEditCamera.cpp \
Render/Q3DSTranslators.cpp \
+ Render/Q3DSSelectionWidget.cpp \
+ Render/Q3DSVisualAidWidget.cpp \
+ Render/Q3DSWidgetUtils.cpp \
+ Render/Q3DSManipulationWidget.cpp \
Palettes/Inspector/MaterialRefView.cpp \
Palettes/scenecamera/scenecameraview.cpp \
Palettes/scenecamera/scenecamerascrollarea.cpp \
Palettes/scenecamera/scenecameraglwidget.cpp \
Palettes/TimelineGraphicsView/ui/RowTimelineCommentItem.cpp \
- Render/Q3DSSelectionWidget.cpp \
- Render/Q3DSVisualAidWidget.cpp \
- Render/Q3DSWidgetUtils.cpp \
- Render/Q3DSManipulationWidget.cpp
+ Palettes/Inspector/VariantsGroupModel.cpp \
+ Palettes/Inspector/VariantsTagModel.cpp \
+ Palettes/Inspector/VariantTagDialog.cpp
RESOURCES += \
MainFrm.qrc \
diff --git a/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp b/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
index c20b6727..5e8f0e96 100644
--- a/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
+++ b/src/Authoring/Studio/UI/StudioAppPrefsPage.cpp
@@ -43,7 +43,6 @@
#include "Core.h"
#include "IStudioRenderer.h"
-#include <QtWidgets/qcolordialog.h>
#include <QtWidgets/qmessagebox.h>
#include <QtGui/qstandarditemmodel.h>
#include <QtCore/qdiriterator.h>
diff --git a/src/Authoring/Studio/Utils/StudioUtils.cpp b/src/Authoring/Studio/Utils/StudioUtils.cpp
index c0063ebe..43126de1 100644
--- a/src/Authoring/Studio/Utils/StudioUtils.cpp
+++ b/src/Authoring/Studio/Utils/StudioUtils.cpp
@@ -70,12 +70,16 @@ qreal StudioUtils::devicePixelRatio(QWindow *window)
{
qreal pixelRatio = 1.0;
- QWindow *w = window ? window : g_StudioApp.m_pMainWnd->windowHandle();
+ QWindow *w = window ? window
+ : g_StudioApp.m_pMainWnd
+ ? g_StudioApp.m_pMainWnd->windowHandle() : nullptr;
+
if (w) {
QScreen *s = w->screen();
if (s)
pixelRatio = s->devicePixelRatio();
}
+
return pixelRatio;
}
@@ -83,7 +87,8 @@ qreal StudioUtils::devicePixelRatio(QWindow *window)
bool StudioUtils::readFileToDomDocument(const QString &filePath, QDomDocument &domDoc)
{
QFile file(filePath);
- if (!file.open(QFile::Text | QIODevice::ReadOnly)) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString() << "'" << filePath << "'";
return false;
}
@@ -96,7 +101,8 @@ bool StudioUtils::openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc)
{
if (!readFileToDomDocument(file.fileName(), domDoc))
return false;
- if (!file.open(QFile::Text | QIODevice::WriteOnly)) {
+ if (!file.open(QIODevice::WriteOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString();
return false;
}
@@ -106,6 +112,8 @@ bool StudioUtils::openDomDocumentSave(QSaveFile &file, QDomDocument &domDoc)
// Saves contents of a QDomDocument into a previously opened text file
bool StudioUtils::commitDomDocumentSave(QSaveFile &file, const QDomDocument &domDoc)
{
+ // Disable end-of-line conversions
+ file.setTextModeEnabled(false);
// Overwrites entire file
if (file.resize(0) && file.write(domDoc.toByteArray(4)) != -1 && file.commit())
return true;
@@ -117,7 +125,8 @@ bool StudioUtils::commitDomDocumentSave(QSaveFile &file, const QDomDocument &dom
// Opens text file for saving without reading its contents
bool StudioUtils::openTextSave(QSaveFile &file)
{
- if (!file.open(QFile::Text | QIODevice::WriteOnly)) {
+ if (!file.open(QIODevice::WriteOnly)) {
+ file.setTextModeEnabled(false);
qWarning() << __FUNCTION__ << file.errorString();
return false;
}
diff --git a/src/Authoring/Studio/Utils/StudioUtils.h b/src/Authoring/Studio/Utils/StudioUtils.h
index 945ffeb2..f1db4c57 100644
--- a/src/Authoring/Studio/Utils/StudioUtils.h
+++ b/src/Authoring/Studio/Utils/StudioUtils.h
@@ -33,6 +33,7 @@
#include <QtXml/qdom.h>
#include <QtCore/qsavefile.h>
#include <QtCore/qxmlstream.h>
+#include <QtGui/qwindow.h>
QT_FORWARD_DECLARE_CLASS(QWindow)
diff --git a/src/Authoring/Studio/Workspace/Dialogs.cpp b/src/Authoring/Studio/Workspace/Dialogs.cpp
index c32d1568..a6e9f605 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.cpp
+++ b/src/Authoring/Studio/Workspace/Dialogs.cpp
@@ -1037,6 +1037,42 @@ QString CDialogs::GetSaveAsChoice(const QString &inDialogTitle, bool isProject,
return theFile;
}
+QString CDialogs::getImportVariantsDlg()
+{
+ QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath();
+
+ QFileDialog dlg;
+ dlg.setDirectory(docDir);
+ dlg.setWindowTitle(tr("Import variants"));
+ dlg.setDefaultSuffix(QStringLiteral(".variants"));
+ dlg.setNameFilters({tr("All supported files (*.variants *.uia)"),
+ tr("Variants files (*.variants)"), tr("Project files (*.uia)")});
+ dlg.exec();
+
+ if (!dlg.selectedFiles().empty())
+ return dlg.selectedFiles().front();
+
+ return {};
+}
+
+QString CDialogs::getExportVariantsDlg()
+{
+ QString docDir = QFileInfo(g_StudioApp.GetCore()->GetDoc()->GetDocumentPath()).absolutePath();
+
+ QFileDialog dlg;
+ dlg.setDirectory(docDir);
+ dlg.setAcceptMode(QFileDialog::AcceptSave);
+ dlg.setWindowTitle(tr("Export variants"));
+ dlg.setDefaultSuffix(QStringLiteral(".variants"));
+ dlg.setNameFilters({QObject::tr("Variants files (*.variants)")});
+ dlg.exec();
+
+ if (!dlg.selectedFiles().empty())
+ return dlg.selectedFiles().front();
+
+ return {};
+}
+
//==============================================================================
/**
* Prompt the user for a file to create.
@@ -1225,21 +1261,20 @@ void CDialogs::DisplayGLVersionWarning(const Q3DStudio::CString &inGLVersion,
}
void CDialogs::asyncDisplayTimeEditDialog(long time, IDoc *doc, long objectAssociation,
- ITimelineKeyframesManager *keyframesManager) const
+ KeyframeManager *keyframesManager) const
{
QTimer::singleShot(0, [time, doc, objectAssociation, keyframesManager]() {
- CTimeEditDlg timeEditDlg;
- timeEditDlg.setKeyframesManager(keyframesManager);
+ CTimeEditDlg timeEditDlg(keyframesManager);
timeEditDlg.showDialog(time, doc, objectAssociation);
});
}
-void CDialogs::asyncDisplayDurationEditDialog(long startTime, long endTime, IDoc *doc,
+void CDialogs::asyncDisplayDurationEditDialog(long startTime, long endTime,
ITimeChangeCallback *callback) const
{
- QTimer::singleShot(0, [startTime, endTime, doc, callback]() {
+ QTimer::singleShot(0, [startTime, endTime, callback]() {
CDurationEditDlg durationEditDlg;
- durationEditDlg.showDialog(startTime, endTime, doc, callback);
+ durationEditDlg.showDialog(startTime, endTime, callback);
});
}
@@ -1380,8 +1415,8 @@ QStringList CDialogs::qmlStreamExtensions()
QColor CDialogs::displayColorDialog(const QColor &color) const
{
QColorDialog theColorDlg;
- theColorDlg.setCurrentColor(color);
theColorDlg.setOption(QColorDialog::DontUseNativeDialog, true);
+ theColorDlg.setCurrentColor(color);
connect(&theColorDlg, &QColorDialog::currentColorChanged, this, &CDialogs::onColorChanged);
int result = theColorDlg.exec();
disconnect(&theColorDlg, &QColorDialog::currentColorChanged, this, &CDialogs::onColorChanged);
diff --git a/src/Authoring/Studio/Workspace/Dialogs.h b/src/Authoring/Studio/Workspace/Dialogs.h
index d8163eb8..c54f17a1 100644
--- a/src/Authoring/Studio/Workspace/Dialogs.h
+++ b/src/Authoring/Studio/Workspace/Dialogs.h
@@ -55,7 +55,7 @@ class CStudioApp;
class CControl;
class CDialogControl;
class CProgressView;
-class ITimelineKeyframesManager;
+class KeyframeManager;
class ITimeChangeCallback;
class CDialogs : public QObject
@@ -120,6 +120,8 @@ public:
bool isCopy = false);
QString GetNewDocumentChoice(const QString &inInitialDirectory = {}, bool isProject = true);
QString GetFileOpenChoice(const QString &inInitialDirectory = {});
+ QString getExportVariantsDlg();
+ QString getImportVariantsDlg();
void DisplayImportFailed(const QUrl &inURL, const QString &inDescription, bool inWarningsOnly);
void DisplayLoadingPresentationFailed(const QFileInfo &loadFileInfo,
@@ -166,8 +168,8 @@ public:
const Q3DStudio::CString &inRecommendedVersion);
void asyncDisplayTimeEditDialog(long time, IDoc *doc, long objectAssociation,
- ITimelineKeyframesManager *keyframesManager = nullptr) const;
- void asyncDisplayDurationEditDialog(long startTime, long endTime, IDoc *doc,
+ KeyframeManager *keyframesManager = nullptr) const;
+ void asyncDisplayDurationEditDialog(long startTime, long endTime,
ITimeChangeCallback *callback) const;
enum class WidgetBrowserAlign {
diff --git a/src/Authoring/Studio/images.qrc b/src/Authoring/Studio/images.qrc
index e57eee1d..0c6e16f5 100644
--- a/src/Authoring/Studio/images.qrc
+++ b/src/Authoring/Studio/images.qrc
@@ -286,6 +286,29 @@
<file>images/matdef-active@2x.png</file>
<file>images/matdef-disabled.png</file>
<file>images/matdef-disabled@2x.png</file>
+ <file>images/playback_tools_low-04@2x.png</file>
+ <file>images/Action-Action@2x.png</file>
+ <file>images/Action-ChildAction@2x.png</file>
+ <file>images/Action-ChildMasterAction@2x.png</file>
+ <file>images/Action-ComponentAction@2x.png</file>
+ <file>images/Action-ComponentMasterAction@2x.png</file>
+ <file>images/Action-MasterAction@2x.png</file>
+ <file>images/Insert-Left@2x.png</file>
+ <file>images/Insert-Right@2x.png</file>
+ <file>images/Toggle-Empty@2x.png</file>
+ <file>images/keyframe-hidden-normal@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Selected@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Normal@2x.png</file>
+ <file>images/Keyframe-MasterDynamic-Disabled@2x.png</file>
+ <file>images/Keyframe-Master-Selected@2x.png</file>
+ <file>images/Keyframe-Master-Normal@2x.png</file>
+ <file>images/Keyframe-Master-Disabled@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Selected@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Normal@2x.png</file>
+ <file>images/Keyframe-PropertyDynamic-Disabled@2x.png</file>
+ <file>images/Keyframe-Property-Selected@2x.png</file>
+ <file>images/Keyframe-Property-Normal@2x.png</file>
+ <file>images/Keyframe-Property-Disabled@2x.png</file>
</qresource>
<qresource prefix="/startup">
<file alias="open_dialog.png">images/open_dialog.png</file>
diff --git a/src/Authoring/Studio/images/Action-Action@2x.png b/src/Authoring/Studio/images/Action-Action@2x.png
new file mode 100644
index 00000000..affa6c01
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-Action@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ChildAction@2x.png b/src/Authoring/Studio/images/Action-ChildAction@2x.png
new file mode 100644
index 00000000..ba066860
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ChildAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png b/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png
new file mode 100644
index 00000000..f0c8a1da
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ChildMasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ComponentAction@2x.png b/src/Authoring/Studio/images/Action-ComponentAction@2x.png
new file mode 100644
index 00000000..26a2c36c
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ComponentAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png b/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png
new file mode 100644
index 00000000..fa40fb4b
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-ComponentMasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Action-MasterAction@2x.png b/src/Authoring/Studio/images/Action-MasterAction@2x.png
new file mode 100644
index 00000000..c3b8e2e5
--- /dev/null
+++ b/src/Authoring/Studio/images/Action-MasterAction@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Insert-Left@2x.png b/src/Authoring/Studio/images/Insert-Left@2x.png
new file mode 100644
index 00000000..ad0696c6
--- /dev/null
+++ b/src/Authoring/Studio/images/Insert-Left@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Insert-Right@2x.png b/src/Authoring/Studio/images/Insert-Right@2x.png
new file mode 100644
index 00000000..d7a20850
--- /dev/null
+++ b/src/Authoring/Studio/images/Insert-Right@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Disabled.png b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
index 7e66cd27..41c7bbe3 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png
new file mode 100644
index 00000000..a1291e92
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Normal.png b/src/Authoring/Studio/images/Keyframe-Master-Normal.png
index 9fb6281b..af88c894 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png
new file mode 100644
index 00000000..503942c8
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Selected.png b/src/Authoring/Studio/images/Keyframe-Master-Selected.png
index 5d3806ba..7e27743c 100644
--- a/src/Authoring/Studio/images/Keyframe-Master-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-Master-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png
new file mode 100644
index 00000000..e86bacf5
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Master-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
index 734f8e2c..d6abe9f1 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png
new file mode 100644
index 00000000..0b90181d
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
index 919c310f..6d6dab76 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png
new file mode 100644
index 00000000..4a1f83fc
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
index 7712d96f..6e00aeba 100644
--- a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png
new file mode 100644
index 00000000..c402defc
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-MasterDynamic-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Disabled.png b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
index 87e5dde9..2bba3f4b 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png
new file mode 100644
index 00000000..957fb36e
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Normal.png b/src/Authoring/Studio/images/Keyframe-Property-Normal.png
index 7afc5b09..aaebda90 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png
new file mode 100644
index 00000000..06919fa3
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Selected.png b/src/Authoring/Studio/images/Keyframe-Property-Selected.png
index 7eb45ab3..456a4b90 100644
--- a/src/Authoring/Studio/images/Keyframe-Property-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-Property-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png
new file mode 100644
index 00000000..b2008a29
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-Property-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
index 8f23ea26..84263b0d 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png
new file mode 100644
index 00000000..229fddf2
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Disabled@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
index 2231a10c..733e0718 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png
new file mode 100644
index 00000000..aa24ccac
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~
new file mode 100644
index 00000000..aa24ccac
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Normal@2x.png~
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
index 02186956..ef1cf1bd 100644
--- a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png
new file mode 100644
index 00000000..ad155725
--- /dev/null
+++ b/src/Authoring/Studio/images/Keyframe-PropertyDynamic-Selected@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/Toggle-Empty@2x.png b/src/Authoring/Studio/images/Toggle-Empty@2x.png
new file mode 100644
index 00000000..94c695c6
--- /dev/null
+++ b/src/Authoring/Studio/images/Toggle-Empty@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png b/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png
new file mode 100644
index 00000000..040d281d
--- /dev/null
+++ b/src/Authoring/Studio/images/keyframe-hidden-normal@2x.png
Binary files differ
diff --git a/src/Authoring/Studio/images/playback_tools_low-04@2x.png b/src/Authoring/Studio/images/playback_tools_low-04@2x.png
new file mode 100644
index 00000000..0f74d37e
--- /dev/null
+++ b/src/Authoring/Studio/images/playback_tools_low-04@2x.png
Binary files differ
diff --git a/src/Runtime/qt3d-runtime b/src/Runtime/qt3d-runtime
-Subproject 34e028b916fb1d215cdbb20fe1fecb677145cb5
+Subproject 72c4b5fc9d7fde2a2bdf730eab22ffb99b9c2ca
diff --git a/src/shared/header/foundation/ConvertUTF.h b/src/shared/header/foundation/ConvertUTF.h
index 14b88c7c..e5a917bd 100644
--- a/src/shared/header/foundation/ConvertUTF.h
+++ b/src/shared/header/foundation/ConvertUTF.h
@@ -146,25 +146,33 @@ typedef enum { strictConversion = 0, lenientConversion } ConversionFlags;
extern "C" {
#endif
-ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
- UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+// Note: Functions renamed from original Unicode functions to avoid conflicting with the same
+// functions in breakpad implementation which is also statically linked
+ConversionResult Unicode_ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
- UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
- UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
- UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF8 **targetStart, UTF8 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
- UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ UTF32 **targetStart, UTF32 *targetEnd,
+ ConversionFlags flags);
-ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
- UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags);
+ConversionResult Unicode_ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ UTF16 **targetStart, UTF16 *targetEnd,
+ ConversionFlags flags);
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
+Boolean Unicode_isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd);
#ifdef __cplusplus
}
diff --git a/src/shared/header/foundation/StrConvertUTF.h b/src/shared/header/foundation/StrConvertUTF.h
index 678411e2..81428fef 100644
--- a/src/shared/header/foundation/StrConvertUTF.h
+++ b/src/shared/header/foundation/StrConvertUTF.h
@@ -91,7 +91,7 @@ namespace foundation {
UTF16 **targetStart, UTF16 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF8toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
@@ -102,7 +102,7 @@ namespace foundation {
UTF32 **targetStart, UTF32 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF8toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF8toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -111,7 +111,7 @@ namespace foundation {
static ConversionResult Convert(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
- return ConvertUTF16toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF16toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -121,7 +121,7 @@ namespace foundation {
UTF32 **targetStart, UTF32 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF16toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF16toUTF32(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -130,7 +130,7 @@ namespace foundation {
static ConversionResult Convert(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
- return ConvertUTF32toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF32toUTF8(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
template <>
@@ -140,7 +140,7 @@ namespace foundation {
UTF16 **targetStart, UTF16 *targetEnd,
ConversionFlags flags)
{
- return ConvertUTF32toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
+ return Unicode_ConvertUTF32toUTF16(sourceStart, sourceEnd, targetStart, targetEnd, flags);
}
};
diff --git a/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h b/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
index 4cb00a38..bd727997 100644
--- a/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
+++ b/src/shared/qt-breakpad/qtcrashhandler/mainwidget.h
@@ -34,7 +34,13 @@
#include <QtWidgets/qwidget.h>
#include <QtCore/qpointer.h>
+#ifdef QT_NAMESPACE
+using namespace QT_NAMESPACE;
+#endif
+
+QT_BEGIN_NAMESPACE
namespace Ui { class MainWidget; }
+QT_END_NAMESPACE
class MainWidget : public QWidget
{
diff --git a/src/shared/source/ConvertUTF.cpp b/src/shared/source/ConvertUTF.cpp
index 14017948..d00040e6 100644
--- a/src/shared/source/ConvertUTF.cpp
+++ b/src/shared/source/ConvertUTF.cpp
@@ -89,7 +89,7 @@ static const UTF32 halfMask = 0x3FFUL;
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ConversionResult Unicode_ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -141,7 +141,7 @@ ConversionResult ConvertUTF32toUTF16(const UTF32 **sourceStart, const UTF32 *sou
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ConversionResult Unicode_ConvertUTF16toUTF32(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -247,7 +247,7 @@ static const UTF8 firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
+ConversionResult Unicode_ConvertUTF16toUTF8(const UTF16 **sourceStart, const UTF16 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -399,7 +399,7 @@ static Boolean isLegalUTF8(const UTF8 *source, int length)
* Exported function to return whether a UTF-8 sequence is legal or not.
* This is not used here; it's just exported.
*/
-Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
+Boolean Unicode_isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
{
int length = trailingBytesForUTF8[*source] + 1;
if (source + length > sourceEnd) {
@@ -410,7 +410,7 @@ Boolean isLegalUTF8Sequence(const UTF8 *source, const UTF8 *sourceEnd)
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ConversionResult Unicode_ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *sourceEnd,
UTF16 **targetStart, UTF16 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -497,7 +497,7 @@ ConversionResult ConvertUTF8toUTF16(const UTF8 **sourceStart, const UTF8 *source
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
+ConversionResult Unicode_ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sourceEnd,
UTF8 **targetStart, UTF8 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;
@@ -564,7 +564,7 @@ ConversionResult ConvertUTF32toUTF8(const UTF32 **sourceStart, const UTF32 *sour
/* --------------------------------------------------------------------- */
-ConversionResult ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
+ConversionResult Unicode_ConvertUTF8toUTF32(const UTF8 **sourceStart, const UTF8 *sourceEnd,
UTF32 **targetStart, UTF32 *targetEnd, ConversionFlags flags)
{
ConversionResult result = conversionOK;